diff --git a/[refs] b/[refs] index f32159e3272f..16b145a75a63 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b7405e16435f710edfae6ba32bef4ca20d3de145 +refs/heads/master: 7ab3f8d595a1b1e5cf8d726b72fd476fe0d0226c diff --git a/trunk/.mailmap b/trunk/.mailmap index ebf9bf84da0a..bf62dbea88e6 100644 --- a/trunk/.mailmap +++ b/trunk/.mailmap @@ -67,8 +67,6 @@ Koushik Leonid I Ananiev Linas Vepstas Matthieu CASTET -Michael Buesch -Michael Buesch Michel Dänzer Mitesh shah Morten Welinder diff --git a/trunk/CREDITS b/trunk/CREDITS index c5f819bacda3..6bd8ab86b5bd 100644 --- a/trunk/CREDITS +++ b/trunk/CREDITS @@ -317,12 +317,6 @@ S: 2322 37th Ave SW S: Seattle, Washington 98126-2010 S: USA -N: Johannes Berg -E: johannes@sipsolutions.net -W: http://johannes.sipsolutions.net/ -P: 1024D/9AB78CA5 AD02 0176 4E29 C137 1DF6 08D2 FC44 CF86 9AB7 8CA5 -D: powerpc & 802.11 hacker - N: Stephen R. van den Berg (AKA BuGless) E: berg@pool.informatik.rwth-aachen.de D: General kernel, gcc, and libc hacker @@ -1745,9 +1739,8 @@ S: D-64295 S: Germany N: Andi Kleen -E: andi@firstfloor.org -U: http://www.halobates.de -D: network, x86, NUMA, various hacks +E: ak@muc.de +D: network hacker, syncookies S: Schwalbenstr. 96 S: 85551 Ottobrunn S: Germany @@ -2293,14 +2286,14 @@ S: D-90453 Nuernberg S: Germany N: Arnaldo Carvalho de Melo +E: acme@mandriva.com E: acme@ghostprotocols.net -E: arnaldo.melo@gmail.com -E: acme@redhat.com W: http://oops.ghostprotocols.net:81/blog/ P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01 D: IPX, LLC, DCCP, cyc2x, wl3501_cs, net/ hacks -S: R. Brasílio Itiberê, 4270/1010 - Água Verde -S: 80240-060 - Curitiba - Paraná +S: Mandriva +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná S: Brazil N: Karsten Merker @@ -3302,14 +3295,6 @@ S: 12725 SW Millikan Way, Suite 400 S: Beaverton, Oregon 97005 S: USA -N: Li Yang -E: leoli@freescale.com -D: Freescale Highspeed USB device driver -D: Freescale QE SoC support and Ethernet driver -S: B-1206 Jingmao Guojigongyu -S: 16 Baliqiao Nanjie, Beijing 101100 -S: People's Repulic of China - N: Marcelo Tosatti E: marcelo@kvack.org D: v2.4 kernel maintainer diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-usb b/trunk/Documentation/ABI/testing/sysfs-bus-usb deleted file mode 100644 index f9937add033d..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-bus-usb +++ /dev/null @@ -1,41 +0,0 @@ -What: /sys/bus/usb/devices/.../power/autosuspend -Date: March 2007 -KernelVersion: 2.6.21 -Contact: Alan Stern -Description: - Each USB device directory will contain a file named - power/autosuspend. This file holds the time (in seconds) - the device must be idle before it will be autosuspended. - 0 means the device will be autosuspended as soon as - possible. Negative values will prevent the device from - being autosuspended at all, and writing a negative value - will resume the device if it is already suspended. - - The autosuspend delay for newly-created devices is set to - the value of the usbcore.autosuspend module parameter. - -What: /sys/bus/usb/devices/.../power/level -Date: March 2007 -KernelVersion: 2.6.21 -Contact: Alan Stern -Description: - Each USB device directory will contain a file named - power/level. This file holds a power-level setting for - the device, one of "on", "auto", or "suspend". - - "on" means that the device is not allowed to autosuspend, - although normal suspends for system sleep will still - be honored. "auto" means the device will autosuspend - and autoresume in the usual manner, according to the - capabilities of its driver. "suspend" means the device - is forced into a suspended state and it will not autoresume - in response to I/O requests. However remote-wakeup requests - from the device may still be enabled (the remote-wakeup - setting is controlled separately by the power/wakeup - attribute). - - During normal use, devices should be left in the "auto" - level. The other levels are meant for administrative uses. - If you want to suspend a device immediately but leave it - free to wake up in response to I/O requests, you should - write "0" to power/autosuspend. diff --git a/trunk/Documentation/DocBook/kernel-api.tmpl b/trunk/Documentation/DocBook/kernel-api.tmpl index b61dfc79e1b8..0bb90237e230 100644 --- a/trunk/Documentation/DocBook/kernel-api.tmpl +++ b/trunk/Documentation/DocBook/kernel-api.tmpl @@ -236,12 +236,6 @@ X!Ilib/string.c !Enet/core/dev.c !Enet/ethernet/eth.c !Iinclude/linux/etherdevice.h -!Edrivers/net/phy/phy.c -!Idrivers/net/phy/phy.c -!Edrivers/net/phy/phy_device.c -!Idrivers/net/phy/phy_device.c -!Edrivers/net/phy/mdio_bus.c -!Idrivers/net/phy/mdio_bus.c diff --git a/trunk/Documentation/dontdiff b/trunk/Documentation/dontdiff index 64e9f6c4826b..63c2d0c55aa2 100644 --- a/trunk/Documentation/dontdiff +++ b/trunk/Documentation/dontdiff @@ -55,8 +55,8 @@ aic7*seq.h* aicasm aicdb.h* asm -asm-offsets.h -asm_offsets.h +asm-offsets.* +asm_offsets.* autoconf.h* bbootsect bin2c diff --git a/trunk/Documentation/driver-model/devres.txt b/trunk/Documentation/driver-model/devres.txt index 6c8d8f27db34..5163b85308f5 100644 --- a/trunk/Documentation/driver-model/devres.txt +++ b/trunk/Documentation/driver-model/devres.txt @@ -182,7 +182,7 @@ For example, you can do something like the following. ... - devres_close_group(dev, my_midlayer_create_something); + devres_close_group(dev, my_midlayer_something); return 0; } diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 5f96cb33743e..19b4c96b2a49 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -6,18 +6,6 @@ be removed from this file. --------------------------- -What: V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP -When: October 2007 -Why: Broken attempt to set MPEG compression parameters. These ioctls are - not able to implement the wide variety of parameters that can be set - by hardware MPEG encoders. A new MPEG control mechanism was created - in kernel 2.6.18 that replaces these ioctls. See the V4L2 specification - (section 1.9: Extended controls) for more information on this topic. -Who: Hans Verkuil and - Mauro Carvalho Chehab - ---------------------------- - What: /sys/devices/.../power/state dev->power.power_state dpm_runtime_{suspend,resume)() @@ -117,6 +105,13 @@ Who: Adrian Bunk --------------------------- +What: pci_module_init(driver) +When: January 2007 +Why: Is replaced by pci_register_driver(pci_driver). +Who: Richard Knutsson and Greg Kroah-Hartman + +--------------------------- + What: Usage of invalid timevals in setitimer When: March 2007 Why: POSIX requires to validate timevals in the setitimer call. This @@ -139,6 +134,15 @@ Who: Arjan van de Ven --------------------------- +What: mount/umount uevents +When: February 2007 +Why: These events are not correct, and do not properly let userspace know + when a file system has been mounted or unmounted. Userspace should + poll the /proc/mounts file instead to detect this properly. +Who: Greg Kroah-Hartman + +--------------------------- + What: USB driver API moves to EXPORT_SYMBOL_GPL When: February 2008 Files: include/linux/usb.h, drivers/usb/core/driver.c @@ -183,10 +187,18 @@ Who: Jean Delvare --------------------------- -What: i2c_adapter.list +What: i2c_adapter.dev + i2c_adapter.list When: July 2007 -Why: Superfluous, this list duplicates the one maintained by the driver - core. +Why: Superfluous, given i2c_adapter.class_dev: + * The "dev" was a stand-in for the physical device node that legacy + drivers would not have; but now it's almost always present. Any + remaining legacy drivers must upgrade (they now trigger warnings). + * The "list" duplicates class device children. + The delay in removing this is so upgraded lm_sensors and libsensors + can get deployed. (Removal causes minor changes in the sysfs layout, + notably the location of the adapter type name and parenting the i2c + client hardware directly from their controller.) Who: Jean Delvare , David Brownell @@ -199,6 +211,15 @@ Who: Adrian Bunk --------------------------- +What: IPv4 only connection tracking/NAT/helpers +When: 2.6.22 +Why: The new layer 3 independant connection tracking replaces the old + IPv4 only version. After some stabilization of the new code the + old one will be removed. +Who: Patrick McHardy + +--------------------------- + What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver When: December 2006 Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are @@ -273,6 +294,18 @@ Who: Richard Purdie --------------------------- +What: Wireless extensions over netlink (CONFIG_NET_WIRELESS_RTNETLINK) +When: with the merge of wireless-dev, 2.6.22 or later +Why: The option/code is + * not enabled on most kernels + * not required by any userspace tools (except an experimental one, + and even there only for some parts, others use ioctl) + * pointless since wext is no longer evolving and the ioctl + interface needs to be kept +Who: Johannes Berg + +--------------------------- + What: i8xx_tco watchdog driver When: in 2.6.22 Why: the i8xx_tco watchdog driver has been replaced by the iTCO_wdt @@ -280,46 +313,3 @@ Why: the i8xx_tco watchdog driver has been replaced by the iTCO_wdt Who: Wim Van Sebroeck --------------------------- - -What: Multipath cached routing support in ipv4 -When: in 2.6.23 -Why: Code was merged, then submitter immediately disappeared leaving - us with no maintainer and lots of bugs. The code should not have - been merged in the first place, and many aspects of it's - implementation are blocking more critical core networking - development. It's marked EXPERIMENTAL and no distribution - enables it because it cause obscure crashes due to unfixable bugs - (interfaces don't return errors so memory allocation can't be - handled, calling contexts of these interfaces make handling - errors impossible too because they get called after we've - totally commited to creating a route object, for example). - This problem has existed for years and no forward progress - has ever been made, and nobody steps up to try and salvage - this code, so we're going to finally just get rid of it. -Who: David S. Miller - ---------------------------- - -What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer) -When: December 2007 -Why: These functions are a leftover from 2.4 times. They have several - problems: - - Duplication of checks that are done in the device driver's - interrupt handler - - common I/O layer can't do device specific error recovery - - device driver can't be notified for conditions happening during - execution of the function - Device drivers should issue the read device characteristics and read - configuration data ccws and do the appropriate error handling - themselves. -Who: Cornelia Huck - ---------------------------- - -What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers -When: September 2007 -Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific - I2C-over-GPIO drivers. -Who: Jean Delvare - ---------------------------- diff --git a/trunk/Documentation/filesystems/afs.txt b/trunk/Documentation/filesystems/afs.txt index 12ad6c7f4e50..2f4237dfb8c7 100644 --- a/trunk/Documentation/filesystems/afs.txt +++ b/trunk/Documentation/filesystems/afs.txt @@ -1,82 +1,31 @@ - ==================== kAFS: AFS FILESYSTEM ==================== -Contents: - - - Overview. - - Usage. - - Mountpoints. - - Proc filesystem. - - The cell database. - - Security. - - Examples. - - -======== -OVERVIEW -======== - -This filesystem provides a fairly simple secure AFS filesystem driver. It is -under development and does not yet provide the full feature set. The features -it does support include: - - (*) Security (currently only AFS kaserver and KerberosIV tickets). - - (*) File reading. - - (*) Automounting. - -It does not yet support the following AFS features: - - (*) Write support. - - (*) Local caching. - - (*) pioctl() system call. - - -=========== -COMPILATION -=========== - -The filesystem should be enabled by turning on the kernel configuration -options: - - CONFIG_AF_RXRPC - The RxRPC protocol transport - CONFIG_RXKAD - The RxRPC Kerberos security handler - CONFIG_AFS - The AFS filesystem - -Additionally, the following can be turned on to aid debugging: - - CONFIG_AF_RXRPC_DEBUG - Permit AF_RXRPC debugging to be enabled - CONFIG_AFS_DEBUG - Permit AFS debugging to be enabled +ABOUT +===== -They permit the debugging messages to be turned on dynamically by manipulating -the masks in the following files: +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: - /sys/module/af_rxrpc/parameters/debug - /sys/module/afs/parameters/debug + (*) 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 af_rxrpc.o - insmod rxkad.o + insmod rxrpc.o insmod kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91 -The first module is the AF_RXRPC network protocol driver. This provides the -RxRPC remote operation protocol and may also be accessed from userspace. See: - - Documentation/networking/rxrpc.txt - -The second module is the kerberos RxRPC security driver, and the third module -is the actual filesystem driver for the AFS filesystem. +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: @@ -84,7 +33,7 @@ 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, with the latter separated by colons. +volume location servers within that cell. Filesystems can be mounted anywhere by commands similar to the following: @@ -93,6 +42,11 @@ Filesystems can be mounted anywhere by commands similar to the following: 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). @@ -106,66 +60,55 @@ 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. In AFS terms, 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 a follow-link capability -(ie: symbolic link semantics). If anyone attempts to access them, they will -automatically cause the target volume to be mounted (if possible) on that site. +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: -Automatically mounted filesystems will be automatically unmounted approximately -twenty minutes after they were last used. Alternatively they can be unmounted -directly with the umount() system call. + (*) They cannot be listed. Running a program like "ls" on them will incur an + EREMOTE error (Object is remote). -Manually unmounting an AFS volume will cause any idle submounts upon it to be -culled first. If all are culled, then the requested volume will also be -unmounted, otherwise error EBUSY will be returned. + (*) Other objects can't be looked up inside of them. This also incurs an + EREMOTE error. -This can be used by the administrator to attempt to unmount the whole AFS tree -mounted on /afs in one go by doing: + (*) 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. - umount /afs + (*) They can be mounted on (which symbolic links can't). -=============== PROC FILESYSTEM =============== -The AFS modules creates a "/proc/fs/afs/" directory and populates it: +The rxrpc module creates a number of files in various places in the /proc +filesystem: - (*) A "cells" file that lists cells currently known to the afs module and - their usage counts: + (*) 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: - [root@andromeda ~]# cat /proc/fs/afs/cells - USE NAME - 3 cambridge.redhat.com + (*) 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. - [root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/servers - USE ADDR STATE - 4 172.16.18.91 0 - [root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/vlservers - ADDRESS - 172.16.18.91 - [root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/volumes - USE STT VLID[0] VLID[1] VLID[2] NAME - 1 Val 20000000 20000001 20000002 root.afs - -================= 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 system belongs is added to the database when insmod is performed by the -"rootcell=" argument or, if compiled in, using a "kafs.rootcell=" argument on -the kernel command line. +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: @@ -175,65 +118,20 @@ Further cells can be added by commands similar to the following: No other cell database operations are available at this time. -======== -SECURITY -======== - -Secure operations are initiated by acquiring a key using the klog program. A -very primitive klog program is available at: - - http://people.redhat.com/~dhowells/rxrpc/klog.c - -This should be compiled by: - - make klog LDLIBS="-lcrypto -lcrypt -lkrb4 -lkeyutils" - -And then run as: - - ./klog - -Assuming it's successful, this adds a key of type RxRPC, named for the service -and cell, eg: "afs@". This can be viewed with the keyctl program or -by cat'ing /proc/keys: - - [root@andromeda ~]# keyctl show - Session Keyring - -3 --alswrv 0 0 keyring: _ses.3268 - 2 --alswrv 0 0 \_ keyring: _uid.0 - 111416553 --als--v 0 0 \_ rxrpc: afs@CAMBRIDGE.REDHAT.COM - -Currently the username, realm, password and proposed ticket lifetime are -compiled in to the program. - -It is not required to acquire a key before using AFS facilities, but if one is -not acquired then all operations will be governed by the anonymous user parts -of the ACLs. - -If a key is acquired, then all AFS operations, including mounts and automounts, -made by a possessor of that key will be secured with that key. - -If a file is opened with a particular key and then the file descriptor is -passed to a process that doesn't have that key (perhaps over an AF_UNIX -socket), then the operations on the file will be made with key that was used to -open the file. - - -======== 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 +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 /tmp/rxrpc.o -insmod /tmp/rxkad.o -insmod /tmp/kafs.o rootcell=cambridge.redhat.com:172.16.18.91 +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 +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 @@ -243,7 +141,15 @@ 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 rxkad rmmod rxrpc diff --git a/trunk/Documentation/filesystems/proc.txt b/trunk/Documentation/filesystems/proc.txt index 7aaf09b86a55..5484ab5efd4f 100644 --- a/trunk/Documentation/filesystems/proc.txt +++ b/trunk/Documentation/filesystems/proc.txt @@ -1421,15 +1421,6 @@ fewer messages that will be written. Message_burst controls when messages will be dropped. The default settings limit warning messages to one every five seconds. -warnings --------- - -This controls console messages from the networking stack that can occur because -of problems on the network like duplicate address or bad checksums. Normally, -this should be enabled, but if the problem persists the messages can be -disabled. - - netdev_max_backlog ------------------ diff --git a/trunk/Documentation/i2c/busses/i2c-nforce2 b/trunk/Documentation/i2c/busses/i2c-nforce2 index fae3495bcbaf..7f61fbc03f7f 100644 --- a/trunk/Documentation/i2c/busses/i2c-nforce2 +++ b/trunk/Documentation/i2c/busses/i2c-nforce2 @@ -9,8 +9,6 @@ Supported adapters: * nForce4 MCP-04 10de:0034 * nForce4 MCP51 10de:0264 * nForce4 MCP55 10de:0368 - * nForce4 MCP61 10de:03EB - * nForce4 MCP65 10de:0446 Datasheet: not publicly available, but seems to be similar to the AMD-8111 SMBus 2.0 adapter. diff --git a/trunk/Documentation/i2c/porting-clients b/trunk/Documentation/i2c/porting-clients index 7bf82c08f6ca..ca272b263a92 100644 --- a/trunk/Documentation/i2c/porting-clients +++ b/trunk/Documentation/i2c/porting-clients @@ -1,4 +1,4 @@ -Revision 7, 2007-04-19 +Revision 6, 2005-11-20 Jean Delvare Greg KH @@ -20,10 +20,6 @@ yours for best results. Technical changes: -* [Driver type] Any driver that was relying on i2c-isa has to be - converted to a proper isa, platform or pci driver. This is not - covered by this guide. - * [Includes] Get rid of "version.h" and . Includes typically look like that: #include @@ -31,10 +27,12 @@ Technical changes: #include #include #include + #include /* for ISA drivers */ #include /* for hardware monitoring drivers */ #include #include /* if you need VRM support */ #include /* for class registration */ + #include /* if you have I/O operations */ Please respect this inclusion order. Some extra headers may be required for a given driver (e.g. "lm75.h"). @@ -71,16 +69,20 @@ Technical changes: sensors mailing list by providing a patch to the Documentation/hwmon/sysfs-interface file. -* [Attach] The attach function should make sure that the adapter's - class has I2C_CLASS_HWMON (or whatever class is suitable for your - driver), using the following construct: +* [Attach] For I2C drivers, the attach function should make sure + that the adapter's class has I2C_CLASS_HWMON (or whatever class is + suitable for your driver), using the following construct: if (!(adapter->class & I2C_CLASS_HWMON)) return 0; + ISA-only drivers of course don't need this. Call i2c_probe() instead of i2c_detect(). * [Detect] As mentioned earlier, the flags parameter is gone. The type_name and client_name strings are replaced by a single name string, which will be filled with a lowercase, short string. + In i2c-only drivers, drop the i2c_is_isa_adapter check, it's + useless. Same for isa-only drivers, as the test would always be + true. Only hybrid drivers (which are quite rare) still need it. The labels used for error paths are reduced to the number needed. It is advised that the labels are given descriptive names such as exit and exit_free. Don't forget to properly set err before diff --git a/trunk/Documentation/i2c/summary b/trunk/Documentation/i2c/summary index aea60bf7e8f0..41dde8776791 100644 --- a/trunk/Documentation/i2c/summary +++ b/trunk/Documentation/i2c/summary @@ -4,23 +4,17 @@ I2C and SMBus ============= I2C (pronounce: I squared C) is a protocol developed by Philips. It is a -slow two-wire protocol (variable speed, up to 400 kHz), with a high speed -extension (3.4 MHz). It provides an inexpensive bus for connecting many -types of devices with infrequent or low bandwidth communications needs. -I2C is widely used with embedded systems. Some systems use variants that -don't meet branding requirements, and so are not advertised as being I2C. +slow two-wire protocol (10-400 kHz), but it suffices for many types of +devices. -SMBus (System Management Bus) is based on the I2C protocol, and is mostly -a subset of I2C protocols and signaling. Many I2C devices will work on an -SMBus, but some SMBus protocols add semantics beyond what is required to -achieve I2C branding. Modern PC mainboards rely on SMBus. The most common -devices connected through SMBus are RAM modules configured using I2C EEPROMs, -and hardware monitoring chips. +SMBus (System Management Bus) is a subset of the I2C protocol. Many +modern mainboards have a System Management Bus. There are a lot of +devices which can be connected to a SMBus; the most notable are modern +memory chips with EEPROM memories and chips for hardware monitoring. -Because the SMBus is mostly a subset of the generalized I2C bus, we can -use its protocols on many I2C systems. However, there are systems that don't -meet both SMBus and I2C electrical constraints; and others which can't -implement all the common SMBus protocol semantics or messages. +Because the SMBus is just a special case of the generalized I2C bus, we +can simulate the SMBus protocol on plain I2C busses. The reverse is +regretfully impossible. Terminology @@ -35,7 +29,6 @@ When we talk about I2C, we use the following terms: An Algorithm driver contains general code that can be used for a whole class of I2C adapters. Each specific adapter driver depends on one algorithm driver. - A Driver driver (yes, this sounds ridiculous, sorry) contains the general code to access some type of device. Each detected device gets its own data in the Client structure. Usually, Driver and Client are more closely @@ -47,10 +40,6 @@ a separate Adapter and Algorithm driver), and drivers for your I2C devices in this package. See the lm_sensors project http://www.lm-sensors.nu for device drivers. -At this time, Linux only operates I2C (or SMBus) in master mode; you can't -use these APIs to make a Linux system behave as a slave/device, either to -speak a custom protocol or to emulate some other device. - Included Bus Drivers ==================== diff --git a/trunk/Documentation/i2c/writing-clients b/trunk/Documentation/i2c/writing-clients index 3d8d36b0ad12..fbcff96f4ca1 100644 --- a/trunk/Documentation/i2c/writing-clients +++ b/trunk/Documentation/i2c/writing-clients @@ -1,5 +1,5 @@ This is a small guide for those who want to write kernel drivers for I2C -or SMBus devices, using Linux as the protocol host/master (not slave). +or SMBus devices. To set up a driver, you need to do several things. Some are optional, and some things can be done slightly or completely different. Use this as a @@ -29,16 +29,8 @@ static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, - - /* iff driver uses driver model ("new style") binding model: */ - .probe = foo_probe, - .remove = foo_remove, - - /* else, driver uses "legacy" binding model: */ .attach_adapter = foo_attach_adapter, .detach_client = foo_detach_client, - - /* these may be used regardless of the driver binding model */ .shutdown = foo_shutdown, /* optional */ .suspend = foo_suspend, /* optional */ .resume = foo_resume, /* optional */ @@ -48,8 +40,7 @@ static struct i2c_driver foo_driver = { The name field is the driver name, and must not contain spaces. It should match the module name (if the driver can be compiled as a module), although you can use MODULE_ALIAS (passing "foo" in this example) to add -another name for the module. If the driver name doesn't match the module -name, the module won't be automatically loaded (hotplug/coldplug). +another name for the module. All other fields are for call-back functions which will be explained below. @@ -74,13 +65,16 @@ An example structure is below. struct foo_data { struct i2c_client client; + struct semaphore lock; /* For ISA access in `sensors' drivers. */ + int sysctl_id; /* To keep the /proc directory entry for + `sensors' drivers. */ enum chips type; /* To keep the chips type for `sensors' drivers. */ /* Because the i2c bus is slow, it is often useful to cache the read information of a chip for some time (for example, 1 or 2 seconds). It depends of course on the device whether this is really worthwhile or even sensible. */ - struct mutex update_lock; /* When we are reading lots of information, + struct semaphore update_lock; /* When we are reading lots of information, another process should not update the below information */ char valid; /* != 0 if the following fields are valid. */ @@ -101,7 +95,8 @@ some obscure clients). But we need generic reading and writing routines. I have found it useful to define foo_read and foo_write function for this. For some cases, it will be easier to call the i2c functions directly, but many chips have some kind of register-value idea that can easily -be encapsulated. +be encapsulated. Also, some chips have both ISA and I2C interfaces, and +it useful to abstract from this (only for `sensors' drivers). The below functions are simple examples, and should not be copied literally. @@ -124,101 +119,28 @@ literally. return i2c_smbus_write_word_data(client,reg,value); } +For sensors code, you may have to cope with ISA registers too. Something +like the below often works. Note the locking! + + int foo_read_value(struct i2c_client *client, u8 reg) + { + int res; + if (i2c_is_isa_client(client)) { + down(&(((struct foo_data *) (client->data)) -> lock)); + outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET); + res = inb_p(client->addr + FOO_DATA_REG_OFFSET); + up(&(((struct foo_data *) (client->data)) -> lock)); + return res; + } else + return i2c_smbus_read_byte_data(client,reg); + } + +Writing is done the same way. + Probing and attaching ===================== -The Linux I2C stack was originally written to support access to hardware -monitoring chips on PC motherboards, and thus it embeds some assumptions -that are more appropriate to SMBus (and PCs) than to I2C. One of these -assumptions is that most adapters and devices drivers support the SMBUS_QUICK -protocol to probe device presence. Another is that devices and their drivers -can be sufficiently configured using only such probe primitives. - -As Linux and its I2C stack became more widely used in embedded systems -and complex components such as DVB adapters, those assumptions became more -problematic. Drivers for I2C devices that issue interrupts need more (and -different) configuration information, as do drivers handling chip variants -that can't be distinguished by protocol probing, or which need some board -specific information to operate correctly. - -Accordingly, the I2C stack now has two models for associating I2C devices -with their drivers: the original "legacy" model, and a newer one that's -fully compatible with the Linux 2.6 driver model. These models do not mix, -since the "legacy" model requires drivers to create "i2c_client" device -objects after SMBus style probing, while the Linux driver model expects -drivers to be given such device objects in their probe() routines. - - -Standard Driver Model Binding ("New Style") -------------------------------------------- - -System infrastructure, typically board-specific initialization code or -boot firmware, reports what I2C devices exist. For example, there may be -a table, in the kernel or from the boot loader, identifying I2C devices -and linking them to board-specific configuration information about IRQs -and other wiring artifacts, chip type, and so on. That could be used to -create i2c_client objects for each I2C device. - -I2C device drivers using this binding model work just like any other -kind of driver in Linux: they provide a probe() method to bind to -those devices, and a remove() method to unbind. - - static int foo_probe(struct i2c_client *client); - static int foo_remove(struct i2c_client *client); - -Remember that the i2c_driver does not create those client handles. The -handle may be used during foo_probe(). If foo_probe() reports success -(zero not a negative status code) it may save the handle and use it until -foo_remove() returns. That binding model is used by most Linux drivers. - -Drivers match devices when i2c_client.driver_name and the driver name are -the same; this approach is used in several other busses that don't have -device typing support in the hardware. The driver and module name should -match, so hotplug/coldplug mechanisms will modprobe the driver. - - -Device Creation (Standard driver model) ---------------------------------------- - -If you know for a fact that an I2C device is connected to a given I2C bus, -you can instantiate that device by simply filling an i2c_board_info -structure with the device address and driver name, and calling -i2c_new_device(). This will create the device, then the driver core will -take care of finding the right driver and will call its probe() method. -If a driver supports different device types, you can specify the type you -want using the type field. You can also specify an IRQ and platform data -if needed. - -Sometimes you know that a device is connected to a given I2C bus, but you -don't know the exact address it uses. This happens on TV adapters for -example, where the same driver supports dozens of slightly different -models, and I2C device addresses change from one model to the next. In -that case, you can use the i2c_new_probed_device() variant, which is -similar to i2c_new_device(), except that it takes an additional list of -possible I2C addresses to probe. A device is created for the first -responsive address in the list. If you expect more than one device to be -present in the address range, simply call i2c_new_probed_device() that -many times. - -The call to i2c_new_device() or i2c_new_probed_device() typically happens -in the I2C bus driver. You may want to save the returned i2c_client -reference for later use. - - -Device Deletion (Standard driver model) ---------------------------------------- - -Each I2C device which has been created using i2c_new_device() or -i2c_new_probed_device() can be unregistered by calling -i2c_unregister_device(). If you don't call it explicitly, it will be -called automatically before the underlying I2C bus itself is removed, as a -device can't survive its parent in the device driver model. - - -Legacy Driver Binding Model ---------------------------- - Most i2c devices can be present on several i2c addresses; for some this is determined in hardware (by soldering some chip pins to Vcc or Ground), for others this can be changed in software (by writing to specific client @@ -235,9 +157,13 @@ detection algorithm. You do not have to use this parameter interface; but don't try to use function i2c_probe() if you don't. +NOTE: If you want to write a `sensors' driver, the interface is slightly + different! See below. + -Probing classes (Legacy model) ------------------------------- + +Probing classes +--------------- All parameters are given as lists of unsigned 16-bit integers. Lists are terminated by I2C_CLIENT_END. @@ -284,8 +210,8 @@ Note that you *have* to call the defined variable `normal_i2c', without any prefix! -Attaching to an adapter (Legacy model) --------------------------------------- +Attaching to an adapter +----------------------- Whenever a new adapter is inserted, or for all adapters if the driver is being registered, the callback attach_adapter() is called. Now is the @@ -311,13 +237,17 @@ them (unless a `force' parameter was used). In addition, addresses that are already in use (by some other registered client) are skipped. -The detect client function (Legacy model) ------------------------------------------ +The detect client function +-------------------------- The detect client function is called by i2c_probe. The `kind' parameter contains -1 for a probed detection, 0 for a forced detection, or a positive number for a forced detection with a chip type forced. +Below, some things are only needed if this is a `sensors' driver. Those +parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ +markers. + Returning an error different from -ENODEV in a detect function will cause the detection to stop: other addresses and adapters won't be scanned. This should only be done on fatal or internal errors, such as a memory @@ -326,20 +256,64 @@ shortage or i2c_attach_client failing. For now, you can ignore the `flags' parameter. It is there for future use. int foo_detect_client(struct i2c_adapter *adapter, int address, - int kind) + unsigned short flags, int kind) { int err = 0; int i; - struct i2c_client *client; + struct i2c_client *new_client; struct foo_data *data; - const char *name = ""; + const char *client_name = ""; /* For non-`sensors' drivers, put the real + name here! */ /* Let's see whether this adapter can support what we need. - Please substitute the things you need here! */ + Please substitute the things you need here! + For `sensors' drivers, add `! is_isa &&' to the if statement */ if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE)) goto ERROR0; + /* SENSORS ONLY START */ + const char *type_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + /* Do this only if the chip can additionally be found on the ISA bus + (hybrid chip). */ + + if (is_isa) { + + /* Discard immediately if this ISA range is already used */ + /* FIXME: never use check_region(), only request_region() */ + if (check_region(address,FOO_EXTENT)) + goto ERROR0; + + /* Probe whether there is anything on this address. + Some example code is below, but you will have to adapt this + for your own driver */ + + if (kind < 0) /* Only if no force parameter was used */ { + /* We may need long timeouts at least for some chips. */ + #define REALLY_SLOW_IO + i = inb_p(address + 1); + if (inb_p(address + 2) != i) + goto ERROR0; + if (inb_p(address + 3) != i) + goto ERROR0; + if (inb_p(address + 7) != i) + goto ERROR0; + #undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f,address+5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i,address+5); + return 0; + } + } + } + + /* SENSORS ONLY END */ + /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access several i2c functions safely */ @@ -349,12 +323,13 @@ For now, you can ignore the `flags' parameter. It is there for future use. goto ERROR0; } - client = &data->client; - i2c_set_clientdata(client, data); + new_client = &data->client; + i2c_set_clientdata(new_client, data); - client->addr = address; - client->adapter = adapter; - client->driver = &foo_driver; + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &foo_driver; + new_client->flags = 0; /* Now, we do the remaining detection. If no `force' parameter is used. */ @@ -362,17 +337,19 @@ For now, you can ignore the `flags' parameter. It is there for future use. parameter was used. */ if (kind < 0) { /* The below is of course bogus */ - if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE) + if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE) goto ERROR1; } + /* SENSORS ONLY START */ + /* Next, specific detection. This is especially important for `sensors' devices. */ /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter was used. */ if (kind <= 0) { - i = foo_read(client, FOO_REG_CHIPTYPE); + i = foo_read(new_client,FOO_REG_CHIPTYPE); if (i == FOO_TYPE_1) kind = chip1; /* As defined in the enum */ else if (i == FOO_TYPE_2) @@ -386,31 +363,63 @@ For now, you can ignore the `flags' parameter. It is there for future use. /* Now set the type and chip names */ if (kind == chip1) { - name = "chip1"; + type_name = "chip1"; /* For /proc entry */ + client_name = "CHIP 1"; } else if (kind == chip2) { - name = "chip2"; + type_name = "chip2"; /* For /proc entry */ + client_name = "CHIP 2"; } + /* Reserve the ISA region */ + if (is_isa) + request_region(address,FOO_EXTENT,type_name); + + /* SENSORS ONLY END */ + /* Fill in the remaining client fields. */ - strlcpy(client->name, name, I2C_NAME_SIZE); + strcpy(new_client->name,client_name); + + /* SENSORS ONLY BEGIN */ data->type = kind; - mutex_init(&data->update_lock); /* Only if you use this field */ + /* SENSORS ONLY END */ - /* Any other initializations in data must be done here too. */ + data->valid = 0; /* Only if you use this field */ + init_MUTEX(&data->update_lock); /* Only if you use this field */ - /* This function can write default values to the client registers, if - needed. */ - foo_init_client(client); + /* Any other initializations in data must be done here too. */ /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto ERROR1; + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* SENSORS ONLY BEGIN */ + /* Register a new directory entry with module sensors. See below for + the `template' structure. */ + if ((i = i2c_register_entry(new_client, type_name, + foo_dir_table_template,THIS_MODULE)) < 0) { + err = i; + goto ERROR4; + } + data->sysctl_id = i; + + /* SENSORS ONLY END */ + /* This function can write default values to the client registers, if + needed. */ + foo_init_client(new_client); return 0; /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ + ERROR4: + i2c_detach_client(new_client); + ERROR3: + ERROR2: + /* SENSORS ONLY START */ + if (is_isa) + release_region(address,FOO_EXTENT); + /* SENSORS ONLY END */ ERROR1: kfree(data); ERROR0: @@ -418,8 +427,8 @@ For now, you can ignore the `flags' parameter. It is there for future use. } -Removing the client (Legacy model) -================================== +Removing the client +=================== The detach_client call back function is called when a client should be removed. It may actually fail, but only when panicking. This code is @@ -427,12 +436,22 @@ much simpler than the attachment code, fortunately! int foo_detach_client(struct i2c_client *client) { - int err; + int err,i; + + /* SENSORS ONLY START */ + /* Deregister with the `i2c-proc' module. */ + i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); + /* SENSORS ONLY END */ /* Try to detach the client from i2c space */ if ((err = i2c_detach_client(client))) return err; + /* HYBRID SENSORS CHIP ONLY START */ + if i2c_is_isa_client(client) + release_region(client->addr,LM78_EXTENT); + /* HYBRID SENSORS CHIP ONLY END */ + kfree(i2c_get_clientdata(client)); return 0; } @@ -445,34 +464,45 @@ When the kernel is booted, or when your foo driver module is inserted, you have to do some initializing. Fortunately, just attaching (registering) the driver module is usually enough. + /* Keep track of how far we got in the initialization process. If several + things have to initialized, and we fail halfway, only those things + have to be cleaned up! */ + static int __initdata foo_initialized = 0; + static int __init foo_init(void) { int res; + printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE); if ((res = i2c_add_driver(&foo_driver))) { printk("foo: Driver registration failed, module not inserted.\n"); + foo_cleanup(); return res; } + foo_initialized ++; return 0; } - static void __exit foo_cleanup(void) + void foo_cleanup(void) { - i2c_del_driver(&foo_driver); + if (foo_initialized == 1) { + if ((res = i2c_del_driver(&foo_driver))) { + printk("foo: Driver registration failed, module not removed.\n"); + return; + } + foo_initialized --; + } } /* Substitute your own name and email address */ MODULE_AUTHOR("Frodo Looijaard " MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); - /* a few non-GPL license types are also allowed */ - MODULE_LICENSE("GPL"); - module_init(foo_init); module_exit(foo_cleanup); Note that some functions are marked by `__init', and some data structures -by `__initdata'. These functions and structures can be removed after +by `__init_data'. Hose functions and structures can be removed after kernel booting (or module loading) is completed. @@ -602,7 +632,110 @@ General purpose routines Below all general purpose routines are listed, that were not mentioned before. - /* This call returns a unique low identifier for each registered adapter. + /* This call returns a unique low identifier for each registered adapter, + * or -1 if the adapter was not registered. */ extern int i2c_adapter_id(struct i2c_adapter *adap); + +The sensors sysctl/proc interface +================================= + +This section only applies if you write `sensors' drivers. + +Each sensors driver creates a directory in /proc/sys/dev/sensors for each +registered client. The directory is called something like foo-i2c-4-65. +The sensors module helps you to do this as easily as possible. + +The template +------------ + +You will need to define a ctl_table template. This template will automatically +be copied to a newly allocated structure and filled in where necessary when +you call sensors_register_entry. + +First, I will give an example definition. + static ctl_table foo_dir_table_template[] = { + { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real,NULL,&foo_func }, + { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real,NULL,&foo_func }, + { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real,NULL,&foo_data }, + { 0 } + }; + +In the above example, three entries are defined. They can either be +accessed through the /proc interface, in the /proc/sys/dev/sensors/* +directories, as files named func1, func2 and data, or alternatively +through the sysctl interface, in the appropriate table, with identifiers +FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA. + +The third, sixth and ninth parameters should always be NULL, and the +fourth should always be 0. The fifth is the mode of the /proc file; +0644 is safe, as the file will be owned by root:root. + +The seventh and eighth parameters should be &i2c_proc_real and +&i2c_sysctl_real if you want to export lists of reals (scaled +integers). You can also use your own function for them, as usual. +Finally, the last parameter is the call-back to gather the data +(see below) if you use the *_proc_real functions. + + +Gathering the data +------------------ + +The call back functions (foo_func and foo_data in the above example) +can be called in several ways; the operation parameter determines +what should be done: + + * If operation == SENSORS_PROC_REAL_INFO, you must return the + magnitude (scaling) in nrels_mag; + * If operation == SENSORS_PROC_REAL_READ, you must read information + from the chip and return it in results. The number of integers + to display should be put in nrels_mag; + * If operation == SENSORS_PROC_REAL_WRITE, you must write the + supplied information to the chip. nrels_mag will contain the number + of integers, results the integers themselves. + +The *_proc_real functions will display the elements as reals for the +/proc interface. If you set the magnitude to 2, and supply 345 for +SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would +write 45.6 to the /proc file, it would be returned as 4560 for +SENSORS_PROC_REAL_WRITE. A magnitude may even be negative! + +An example function: + + /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and + register values. Note the use of the read cache. */ + void foo_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) + { + struct foo_data *data = client->data; + int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + /* Update the readings cache (if necessary) */ + foo_update_client(client); + /* Get the readings from the cache */ + results[0] = FOO_FROM_REG(data->foo_func_base[nr]); + results[1] = FOO_FROM_REG(data->foo_func_more[nr]); + results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + /* Update the cache */ + data->foo_base[nr] = FOO_TO_REG(results[0]); + /* Update the chip */ + foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]); + } + if (*nrels_mag >= 2) { + /* Update the cache */ + data->foo_more[nr] = FOO_TO_REG(results[1]); + /* Update the chip */ + foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]); + } + } + } diff --git a/trunk/Documentation/i386/boot.txt b/trunk/Documentation/i386/boot.txt index 6498666ea330..38fe1f03fb14 100644 --- a/trunk/Documentation/i386/boot.txt +++ b/trunk/Documentation/i386/boot.txt @@ -2,7 +2,7 @@ ---------------------------- H. Peter Anvin - Last update 2007-03-06 + Last update 2007-01-26 On the i386 platform, the Linux kernel uses a rather complicated boot convention. This has evolved partially due to historical aspects, as @@ -35,13 +35,9 @@ Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible initrd address available to the bootloader. Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes. - Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Introduce relocatable_kernel and kernel_alignment fields. -Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of - the boot command line - **** MEMORY LAYOUT @@ -137,8 +133,6 @@ Offset Proto Name Meaning 022C/4 2.03+ initrd_addr_max Highest legal initrd address 0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel 0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not -0235/3 N/A pad2 Unused -0238/4 2.06+ cmdline_size Maximum size of the kernel command line (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -239,12 +233,6 @@ filled out, however: if your ramdisk is exactly 131072 bytes long and this field is 0x37FFFFFF, you can start your ramdisk at 0x37FE0000.) - cmdline_size: - The maximum size of the command line without the terminating - zero. This means that the command line can contain at most - cmdline_size characters. With protocol version 2.05 and - earlier, the maximum size was 255. - **** THE KERNEL COMMAND LINE @@ -253,10 +241,11 @@ loader to communicate with the kernel. Some of its options are also relevant to the boot loader itself, see "special command line options" below. -The kernel command line is a null-terminated string. The maximum -length can be retrieved from the field cmdline_size. Before protocol -version 2.06, the maximum was 255 characters. A string that is too -long will be automatically truncated by the kernel. +The kernel command line is a null-terminated string currently up to +255 characters long, plus the final null. A string that is too long +will be automatically truncated by the kernel, a boot loader may allow +a longer command line to be passed to permit future kernels to extend +this limit. If the boot protocol version is 2.02 or later, the address of the kernel command line is given by the header field cmd_line_ptr (see diff --git a/trunk/Documentation/thinkpad-acpi.txt b/trunk/Documentation/ibm-acpi.txt similarity index 60% rename from trunk/Documentation/thinkpad-acpi.txt rename to trunk/Documentation/ibm-acpi.txt index 2d4803359a04..0132d363feb5 100644 --- a/trunk/Documentation/thinkpad-acpi.txt +++ b/trunk/Documentation/ibm-acpi.txt @@ -1,22 +1,16 @@ - ThinkPad ACPI Extras Driver + IBM ThinkPad ACPI Extras Driver - Version 0.14 - April 21st, 2007 + Version 0.12 + 17 August 2005 Borislav Deianov - Henrique de Moraes Holschuh http://ibm-acpi.sf.net/ -This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It -supports various features of these laptops which are accessible -through the ACPI and ACPI EC framework, but not otherwise fully -supported by the generic Linux ACPI drivers. - -This driver used to be named ibm-acpi until kernel 2.6.21 and release -0.13-20070314. It used to be in the drivers/acpi tree, but it was -moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel -2.6.22, and release 0.14. +This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports +various features of these laptops which are accessible through the +ACPI framework but not otherwise supported by the generic Linux ACPI +drivers. Status @@ -27,7 +21,7 @@ detailed description): - Fn key combinations - Bluetooth enable and disable - - video output switching, expansion control + - video output switching, expansion control - ThinkLight on and off - limited docking and undocking - UltraBay eject @@ -38,7 +32,7 @@ detailed description): - Experimental: embedded controller register dump - LCD brightness control - Volume control - - Fan control and monitoring: fan speed, fan enable/disable + - Experimental: fan speed, fan enable/disable - Experimental: WAN enable and disable A compatibility table by model and feature is maintained on the web @@ -48,8 +42,6 @@ Please include the following information in your report: - ThinkPad model name - a copy of your DSDT, from /proc/acpi/dsdt - - a copy of the output of dmidecode, with serial numbers - and UUIDs masked off - which driver features work and which don't - the observed behavior of non-working features @@ -60,85 +52,25 @@ Installation ------------ If you are compiling this driver as included in the Linux kernel -sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally -enable the CONFIG_THINKPAD_ACPI_BAY option if you want the -thinkpad-specific bay functionality. +sources, simply enable the CONFIG_ACPI_IBM option (Power Management / +ACPI / IBM ThinkPad Laptop Extras). Features -------- -The driver exports two different interfaces to userspace, which can be -used to access the features it provides. One is a legacy procfs-based -interface, which will be removed at some time in the distant future. -The other is a new sysfs-based interface which is not complete yet. - -The procfs interface creates the /proc/acpi/ibm directory. There is a -file under that directory for each feature it supports. The procfs -interface is mostly frozen, and will change very little if at all: it -will not be extended to add any new functionality in the driver, instead -all new functionality will be implemented on the sysfs interface. - -The sysfs interface tries to blend in the generic Linux sysfs subsystems -and classes as much as possible. Since some of these subsystems are not -yet ready or stabilized, it is expected that this interface will change, -and any and all userspace programs must deal with it. - - -Notes about the sysfs interface: - -Unlike what was done with the procfs interface, correctness when talking -to the sysfs interfaces will be enforced, as will correctness in the -thinkpad-acpi's implementation of sysfs interfaces. - -Also, any bugs in the thinkpad-acpi sysfs driver code or in the -thinkpad-acpi's implementation of the sysfs interfaces will be fixed for -maximum correctness, even if that means changing an interface in -non-compatible ways. As these interfaces mature both in the kernel and -in thinkpad-acpi, such changes should become quite rare. - -Applications interfacing to the thinkpad-acpi sysfs interfaces must -follow all sysfs guidelines and correctly process all errors (the sysfs -interface makes extensive use of errors). File descriptors and open / -close operations to the sysfs inodes must also be properly implemented. - -The version of thinkpad-acpi's sysfs interface is exported by the driver -as a driver attribute (see below). +The driver creates the /proc/acpi/ibm directory. There is a file under +that directory for each feature described below. Note that while the +driver is still in the alpha stage, the exact proc file format and +commands supported by the various features is guaranteed to change +frequently. -Sysfs driver attributes are on the driver's sysfs attribute space, -for 2.6.20 this is /sys/bus/platform/drivers/thinkpad-acpi/. - -Sysfs device attributes are on the driver's sysfs attribute space, -for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/. - -Driver version --------------- - -procfs: /proc/acpi/ibm/driver -sysfs driver attribute: version +Driver version -- /proc/acpi/ibm/driver +--------------------------------------- The driver name and version. No commands can be written to this file. -Sysfs interface version ------------------------ - -sysfs driver attribute: interface_version - -Version of the thinkpad-acpi sysfs interface, as an unsigned long -(output in hex format: 0xAAAABBCC), where: - AAAA - major revision - BB - minor revision - CC - bugfix revision - -The sysfs interface version changelog for the driver can be found at the -end of this document. Changes to the sysfs interface done by the kernel -subsystems are not documented here, nor are they tracked by this -attribute. - -Hot keys --------- - -procfs: /proc/acpi/ibm/hotkey -sysfs device attribute: hotkey/* +Hot keys -- /proc/acpi/ibm/hotkey +--------------------------------- Without this driver, only the Fn-F4 key (sleep button) generates an ACPI event. With the driver loaded, the hotkey feature enabled and the @@ -152,6 +84,15 @@ All labeled Fn-Fx key combinations generate distinct events. In addition, the lid microswitch and some docking station buttons may also generate such events. +The following commands can be written to this file: + + echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature + echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature + echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys + echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys + ... any other 4-hex-digit mask ... + echo reset > /proc/acpi/ibm/hotkey -- restore the original mask + The bit mask allows some control over which hot keys generate ACPI events. Not all bits in the mask can be modified. Not all bits that can be modified do anything. Not all hot keys can be individually @@ -183,77 +124,15 @@ buttons do not generate ACPI events even with this driver. They *can* be used through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/ -procfs notes: - -The following commands can be written to the /proc/acpi/ibm/hotkey file: - - echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature - echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature - echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys - echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys - ... any other 4-hex-digit mask ... - echo reset > /proc/acpi/ibm/hotkey -- restore the original mask - -sysfs notes: - - The hot keys attributes are in a hotkey/ subdirectory off the - thinkpad device. - - bios_enabled: - Returns the status of the hot keys feature when - thinkpad-acpi was loaded. Upon module unload, the hot - key feature status will be restored to this value. - - 0: hot keys were disabled - 1: hot keys were enabled - - bios_mask: - Returns the hot keys mask when thinkpad-acpi was loaded. - Upon module unload, the hot keys mask will be restored - to this value. - - enable: - Enables/disables the hot keys feature, and reports - current status of the hot keys feature. - - 0: disables the hot keys feature / feature disabled - 1: enables the hot keys feature / feature enabled - - mask: - bit mask to enable ACPI event generation for each hot - key (see above). Returns the current status of the hot - keys mask, and allows one to modify it. - +Bluetooth -- /proc/acpi/ibm/bluetooth +------------------------------------- -Bluetooth ---------- - -procfs: /proc/acpi/ibm/bluetooth -sysfs device attribute: bluetooth/enable - -This feature shows the presence and current state of a ThinkPad -Bluetooth device in the internal ThinkPad CDC slot. - -Procfs notes: - -If Bluetooth is installed, the following commands can be used: +This feature shows the presence and current state of a Bluetooth +device. If Bluetooth is installed, the following commands can be used: echo enable > /proc/acpi/ibm/bluetooth echo disable > /proc/acpi/ibm/bluetooth -Sysfs notes: - - If the Bluetooth CDC card is installed, it can be enabled / - disabled through the "bluetooth/enable" thinkpad-acpi device - attribute, and its current status can also be queried. - - enable: - 0: disables Bluetooth / Bluetooth is disabled - 1: enables Bluetooth / Bluetooth is enabled. - - Note: this interface will be probably be superseeded by the - generic rfkill class. - Video output control -- /proc/acpi/ibm/video -------------------------------------------- @@ -330,7 +209,7 @@ hot plugging of devices in the Linux ACPI framework. If the laptop was booted while not in the dock, the following message is shown in the logs: - Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present + Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present In this case, no dock-related events are generated but the dock and undock commands described below still work. They can be executed @@ -390,7 +269,7 @@ This is due to the current lack of support for hot plugging of devices in the Linux ACPI framework. If the laptop was booted without the UltraBay, the following message is shown in the logs: - Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present + Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present In this case, no bay-related events are generated but the eject command described below still works. It can be executed manually or @@ -434,19 +313,23 @@ supported. Use "eject2" instead of "eject" for the second bay. Note: the UltraBay eject support on the 600e/x, A22p and A3x is EXPERIMENTAL and may not work as expected. USE WITH CAUTION! -CMOS control ------------- - -procfs: /proc/acpi/ibm/cmos -sysfs device attribute: cmos_command +CMOS control -- /proc/acpi/ibm/cmos +----------------------------------- This feature is used internally by the ACPI firmware to control the ThinkLight on most newer ThinkPad models. It may also control LCD brightness, sounds volume and more, but only on some models. -The range of valid cmos command numbers is 0 to 21, but not all have an -effect and the behavior varies from model to model. Here is the behavior -on the X40 (tpb is the ThinkPad Buttons utility): +The commands are non-negative integer numbers: + + echo 0 >/proc/acpi/ibm/cmos + echo 1 >/proc/acpi/ibm/cmos + echo 2 >/proc/acpi/ibm/cmos + ... + +The range of valid numbers is 0 to 21, but not all have an effect and +the behavior varies from model to model. Here is the behavior on the +X40 (tpb is the ThinkPad Buttons utility): 0 - no effect but tpb reports "Volume down" 1 - no effect but tpb reports "Volume up" @@ -459,9 +342,6 @@ on the X40 (tpb is the ThinkPad Buttons utility): 13 - ThinkLight off 14 - no effect but tpb reports ThinkLight status change -The cmos command interface is prone to firmware split-brain problems, as -in newer ThinkPads it is just a compatibility layer. - LED control -- /proc/acpi/ibm/led --------------------------------- @@ -513,17 +393,17 @@ X40: 16 - one medium-pitched beep repeating constantly, stop with 17 17 - stop 16 -Temperature sensors -------------------- - -procfs: /proc/acpi/ibm/thermal -sysfs device attributes: (hwmon) temp*_input +Temperature sensors -- /proc/acpi/ibm/thermal +--------------------------------------------- Most ThinkPads include six or more separate temperature sensors but only expose the CPU temperature through the standard ACPI methods. This feature shows readings from up to eight different sensors on older ThinkPads, and it has experimental support for up to sixteen different -sensors on newer ThinkPads. +sensors on newer ThinkPads. Readings from sensors that are not available +return -128. + +No commands can be written to this file. EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the implementation directly accesses hardware registers and may not work as @@ -580,20 +460,6 @@ The A31 has a very atypical layout for the thermal sensors 8: Bay Battery: secondary sensor -Procfs notes: - Readings from sensors that are not available return -128. - No commands can be written to this file. - -Sysfs notes: - Sensors that are not available return the ENXIO error. This - status may change at runtime, as there are hotplug thermal - sensors, like those inside the batteries and docks. - - thinkpad-acpi thermal sensors are reported through the hwmon - subsystem, and follow all of the hwmon guidelines at - Documentation/hwmon. - - EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump ------------------------------------------------------------------------ @@ -606,7 +472,7 @@ This feature dumps the values of 256 embedded controller registers. Values which have changed since the last time the registers were dumped are marked with a star: -[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump +[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00 EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00 @@ -637,7 +503,7 @@ vary. The second ensures that the fan-related values do vary, since the fan speed fluctuates a bit. The third will (hopefully) mark the fan register with a star: -[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump +[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00 EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00 @@ -667,59 +533,19 @@ registers contain the current battery capacity, etc. If you experiment with this, do send me your results (including some complete dumps with a description of the conditions when they were taken.) -LCD brightness control ----------------------- - -procfs: /proc/acpi/ibm/brightness -sysfs backlight device "thinkpad_screen" +LCD brightness control -- /proc/acpi/ibm/brightness +--------------------------------------------------- This feature allows software control of the LCD brightness on ThinkPad -models which don't have a hardware brightness slider. - -It has some limitations: the LCD backlight cannot be actually turned on or off -by this interface, and in many ThinkPad models, the "dim while on battery" -functionality will be enabled by the BIOS when this interface is used, and -cannot be controlled. - -The backlight control has eight levels, ranging from 0 to 7. Some of the -levels may not be distinct. - -Procfs notes: - - The available commands are: +models which don't have a hardware brightness slider. The available +commands are: echo up >/proc/acpi/ibm/brightness echo down >/proc/acpi/ibm/brightness echo 'level ' >/proc/acpi/ibm/brightness -Sysfs notes: - -The interface is implemented through the backlight sysfs class, which is poorly -documented at this time. - -Locate the thinkpad_screen device under /sys/class/backlight, and inside it -there will be the following attributes: - - max_brightness: - Reads the maximum brightness the hardware can be set to. - The minimum is always zero. - - actual_brightness: - Reads what brightness the screen is set to at this instant. - - brightness: - Writes request the driver to change brightness to the given - value. Reads will tell you what brightness the driver is trying - to set the display to when "power" is set to zero and the display - has not been dimmed by a kernel power management event. - - power: - power management mode, where 0 is "display on", and 1 to 3 will - dim the display backlight to brightness level 0 because - thinkpad-acpi cannot really turn the backlight off. Kernel - power management events can temporarily increase the current - power management level, i.e. they can dim the display. - +The number range is 0 to 7, although not all of them may be +distinct. The current brightness level is shown in the file. Volume control -- /proc/acpi/ibm/volume --------------------------------------- @@ -737,42 +563,41 @@ distinct. The unmute the volume after the mute command, use either the up or down command (the level command will not unmute the volume). The current volume level and mute state is shown in the file. -Fan control and monitoring: fan speed, fan enable/disable ---------------------------------------------------------- +EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan +----------------------------------------------------------------- -procfs: /proc/acpi/ibm/fan -sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable - -NOTE NOTE NOTE: fan control operations are disabled by default for -safety reasons. To enable them, the module parameter "fan_control=1" -must be given to thinkpad-acpi. +This feature is marked EXPERIMENTAL because the implementation +directly accesses hardware registers and may not work as expected. USE +WITH CAUTION! To use this feature, you need to supply the +experimental=1 parameter when loading the module. This feature attempts to show the current fan speed, control mode and other fan data that might be available. The speed is read directly from the hardware registers of the embedded controller. This is known -to work on later R, T, X and Z series ThinkPads but may show a bogus +to work on later R, T and X series ThinkPads but may show a bogus value on other models. -Fan levels: +Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher +the level, the higher the fan speed, although adjacent levels often map +to the same fan speed. 7 is the highest level, where the fan reaches +the maximum recommended speed. Level "auto" means the EC changes the +fan level according to some internal algorithm, usually based on +readings from the thermal sensors. Level "disengaged" means the EC +disables the speed-locked closed-loop fan control, and drives the fan as +fast as it can go, which might exceed hardware limits, so use this level +with caution. -Most ThinkPad fans work in "levels" at the firmware interface. Level 0 -stops the fan. The higher the level, the higher the fan speed, although -adjacent levels often map to the same fan speed. 7 is the highest -level, where the fan reaches the maximum recommended speed. +The fan usually ramps up or down slowly from one speed to another, +and it is normal for the EC to take several seconds to react to fan +commands. -Level "auto" means the EC changes the fan level according to some -internal algorithm, usually based on readings from the thermal sensors. +The fan may be enabled or disabled with the following commands: -There is also a "full-speed" level, also known as "disengaged" level. -In this level, the EC disables the speed-locked closed-loop fan control, -and drives the fan as fast as it can go, which might exceed hardware -limits, so use this level with caution. + echo enable >/proc/acpi/ibm/fan + echo disable >/proc/acpi/ibm/fan -The fan usually ramps up or down slowly from one speed to another, and -it is normal for the EC to take several seconds to react to fan -commands. The full-speed level may take up to two minutes to ramp up to -maximum speed, and in some ThinkPads, the tachometer readings go stale -while the EC is transitioning to the full-speed level. +Placing a fan on level 0 is the same as disabling it. Enabling a fan +will try to place it in a safe level if it is too slow or disabled. WARNING WARNING WARNING: do not leave the fan disabled unless you are monitoring all of the temperature sensor readings and you are ready to @@ -790,146 +615,46 @@ fan is turned off when the CPU temperature drops to 49 degrees and the HDD temperature drops to 41 degrees. These thresholds cannot currently be controlled. -The ThinkPad's ACPI DSDT code will reprogram the fan on its own when -certain conditions are met. It will override any fan programming done -through thinkpad-acpi. - -The thinkpad-acpi kernel driver can be programmed to revert the fan -level to a safe setting if userspace does not issue one of the procfs -fan commands: "enable", "disable", "level" or "watchdog", or if there -are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is -set to 1, manual mode) within a configurable amount of time of up to -120 seconds. This functionality is called fan safety watchdog. - -Note that the watchdog timer stops after it enables the fan. It will be -rearmed again automatically (using the same interval) when one of the -above mentioned fan commands is received. The fan watchdog is, -therefore, not suitable to protect against fan mode changes made through -means other than the "enable", "disable", and "level" procfs fan -commands, or the hwmon fan control sysfs interface. - -Procfs notes: - -The fan may be enabled or disabled with the following commands: - - echo enable >/proc/acpi/ibm/fan - echo disable >/proc/acpi/ibm/fan - -Placing a fan on level 0 is the same as disabling it. Enabling a fan -will try to place it in a safe level if it is too slow or disabled. - The fan level can be controlled with the command: - echo 'level ' > /proc/acpi/ibm/fan + echo 'level ' > /proc/acpi/ibm/thermal -Where is an integer from 0 to 7, or one of the words "auto" or -"full-speed" (without the quotes). Not all ThinkPads support the "auto" -and "full-speed" levels. The driver accepts "disengaged" as an alias for -"full-speed", and reports it as "disengaged" for backwards -compatibility. +Where is an integer from 0 to 7, or one of the words "auto" +or "disengaged" (without the quotes). Not all ThinkPads support the +"auto" and "disengaged" levels. On the X31 and X40 (and ONLY on those models), the fan speed can be -controlled to a certain degree. Once the fan is running, it can be +controlled to a certain degree. Once the fan is running, it can be forced to run faster or slower with the following command: - echo 'speed ' > /proc/acpi/ibm/fan - -The sustainable range of fan speeds on the X40 appears to be from about -3700 to about 7350. Values outside this range either do not have any -effect or the fan speed eventually settles somewhere in that range. The -fan cannot be stopped or started with this command. This functionality -is incomplete, and not available through the sysfs interface. - -To program the safety watchdog, use the "watchdog" command. - - echo 'watchdog ' > /proc/acpi/ibm/fan - -If you want to disable the watchdog, use 0 as the interval. - -Sysfs notes: - -The sysfs interface follows the hwmon subsystem guidelines for the most -part, and the exception is the fan safety watchdog. - -Writes to any of the sysfs attributes may return the EINVAL error if -that operation is not supported in a given ThinkPad or if the parameter -is out-of-bounds, and EPERM if it is forbidden. They may also return -EINTR (interrupted system call), and EIO (I/O error while trying to talk -to the firmware). + echo 'speed ' > /proc/acpi/ibm/thermal -Features not yet implemented by the driver return ENOSYS. +The sustainable range of fan speeds on the X40 appears to be from +about 3700 to about 7350. Values outside this range either do not have +any effect or the fan speed eventually settles somewhere in that +range. The fan cannot be stopped or started with this command. -hwmon device attribute pwm1_enable: - 0: PWM offline (fan is set to full-speed mode) - 1: Manual PWM control (use pwm1 to set fan level) - 2: Hardware PWM control (EC "auto" mode) - 3: reserved (Software PWM control, not implemented yet) - - Modes 0 and 2 are not supported by all ThinkPads, and the - driver is not always able to detect this. If it does know a - mode is unsupported, it will return -EINVAL. - -hwmon device attribute pwm1: - Fan level, scaled from the firmware values of 0-7 to the hwmon - scale of 0-255. 0 means fan stopped, 255 means highest normal - speed (level 7). - - This attribute only commands the fan if pmw1_enable is set to 1 - (manual PWM control). - -hwmon device attribute fan1_input: - Fan tachometer reading, in RPM. May go stale on certain - ThinkPads while the EC transitions the PWM to offline mode, - which can take up to two minutes. May return rubbish on older - ThinkPads. - -driver attribute fan_watchdog: - Fan safety watchdog timer interval, in seconds. Minimum is - 1 second, maximum is 120 seconds. 0 disables the watchdog. - -To stop the fan: set pwm1 to zero, and pwm1_enable to 1. - -To start the fan in a safe mode: set pwm1_enable to 2. If that fails -with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255 -would be the safest choice, though). - - -EXPERIMENTAL: WAN ------------------ +The ThinkPad's ACPI DSDT code will reprogram the fan on its own when +certain conditions are met. It will override any fan programming done +through ibm-acpi. -procfs: /proc/acpi/ibm/wan -sysfs device attribute: wwan/enable +EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan +--------------------------------------- This feature is marked EXPERIMENTAL because the implementation directly accesses hardware registers and may not work as expected. USE WITH CAUTION! To use this feature, you need to supply the experimental=1 parameter when loading the module. -This feature shows the presence and current state of a W-WAN (Sierra -Wireless EV-DO) device. - -It was tested on a Lenovo Thinkpad X60. It should probably work on other -Thinkpad models which come with this module installed. - -Procfs notes: - -If the W-WAN card is installed, the following commands can be used: +This feature shows the presence and current state of a WAN (Sierra +Wireless EV-DO) device. If WAN is installed, the following commands can +be used: echo enable > /proc/acpi/ibm/wan echo disable > /proc/acpi/ibm/wan -Sysfs notes: - - If the W-WAN card is installed, it can be enabled / - disabled through the "wwan/enable" thinkpad-acpi device - attribute, and its current status can also be queried. - - enable: - 0: disables WWAN card / WWAN card is disabled - 1: enables WWAN card / WWAN card is enabled. - - Note: this interface will be probably be superseeded by the - generic rfkill class. +It was tested on a Lenovo Thinkpad X60. It should probably work on other +Thinkpad models which come with this module installed. Multiple Commands, Module Parameters ------------------------------------ @@ -940,42 +665,64 @@ separating them with commas, for example: echo enable,0xffff > /proc/acpi/ibm/hotkey echo lcd_disable,crt_enable > /proc/acpi/ibm/video -Commands can also be specified when loading the thinkpad-acpi module, -for example: - - modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable - -Enabling debugging output -------------------------- - -The module takes a debug paramater which can be used to selectively -enable various classes of debugging output, for example: - - modprobe ibm_acpi debug=0xffff - -will enable all debugging output classes. It takes a bitmask, so -to enable more than one output class, just add their values. - - Debug bitmask Description - 0x0001 Initialization and probing - 0x0002 Removal - -There is also a kernel build option to enable more debugging -information, which may be necessary to debug driver problems. - -The level of debugging information output by the driver can be changed -at runtime through sysfs, using the driver attribute debug_level. The -attribute takes the same bitmask as the debug module parameter above. - -Force loading of module ------------------------ - -If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify -the module parameter force_load=1. Regardless of whether this works or -not, please contact ibm-acpi-devel@lists.sourceforge.net with a report. - - -Sysfs interface changelog: - -0x000100: Initial sysfs support, as a single platform driver and - device. +Commands can also be specified when loading the ibm_acpi module, for +example: + + modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable + +The ibm-acpi kernel driver can be programmed to revert the fan level +to a safe setting if userspace does not issue one of the fan commands: +"enable", "disable", "level" or "watchdog" within a configurable +ammount of time. To do this, use the "watchdog" command. + + echo 'watchdog ' > /proc/acpi/ibm/fan + +Interval is the ammount of time in seconds to wait for one of the +above mentioned fan commands before reseting the fan level to a safe +one. If set to zero, the watchdog is disabled (default). When the +watchdog timer runs out, it does the exact equivalent of the "enable" +fan command. + +Note that the watchdog timer stops after it enables the fan. It will +be rearmed again automatically (using the same interval) when one of +the above mentioned fan commands is received. The fan watchdog is, +therefore, not suitable to protect against fan mode changes made +through means other than the "enable", "disable", and "level" fan +commands. + + +Example Configuration +--------------------- + +The ACPI support in the kernel is intended to be used in conjunction +with a user-space daemon, acpid. The configuration files for this +daemon control what actions are taken in response to various ACPI +events. An example set of configuration files are included in the +config/ directory of the tarball package available on the web +site. Note that these are provided for illustration purposes only and +may need to be adapted to your particular setup. + +The following utility scripts are used by the example action +scripts (included with ibm-acpi for completeness): + + /usr/local/sbin/idectl -- from the hdparm source distribution, + see http://www.ibiblio.org/pub/Linux/system/hardware + /usr/local/sbin/laptop_mode -- from the Linux kernel source + distribution, see Documentation/laptop-mode.txt + /sbin/service -- comes with Redhat/Fedora distributions + /usr/sbin/hibernate -- from the Software Suspend 2 distribution, + see http://softwaresuspend.berlios.de/ + +Toan T Nguyen notes that Suse uses the +powersave program to suspend ('powersave --suspend-to-ram') or +hibernate ('powersave --suspend-to-disk'). This means that the +hibernate script is not needed on that distribution. + +Henrik Brix Andersen has written a Gentoo ACPI event +handler script for the X31. You can get the latest version from +http://dev.gentoo.org/~brix/files/x31.sh + +David Schweikert has written an alternative blank.sh +script which works on Debian systems. This scripts has now been +extended to also work on Fedora systems and included as the default +blank.sh in the distribution. diff --git a/trunk/Documentation/infiniband/user_mad.txt b/trunk/Documentation/infiniband/user_mad.txt index 8ec54b974b67..750fe5e80ebc 100644 --- a/trunk/Documentation/infiniband/user_mad.txt +++ b/trunk/Documentation/infiniband/user_mad.txt @@ -91,14 +91,6 @@ Sending MADs if (ret != sizeof *mad + mad_length) perror("write"); -Transaction IDs - - Users of the umad devices can use the lower 32 bits of the - transaction ID field (that is, the least significant half of the - field in network byte order) in MADs being sent to match - request/response pairs. The upper 32 bits are reserved for use by - the kernel and will be overwritten before a MAD is sent. - Setting IsSM Capability Bit To set the IsSM capability bit for a port, simply open the diff --git a/trunk/Documentation/input/input-programming.txt b/trunk/Documentation/input/input-programming.txt index d9d523099bb7..180e0689676c 100644 --- a/trunk/Documentation/input/input-programming.txt +++ b/trunk/Documentation/input/input-programming.txt @@ -1,3 +1,5 @@ +$Id: input-programming.txt,v 1.4 2001/05/04 09:47:14 vojtech Exp $ + Programming input drivers ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -18,51 +20,28 @@ pressed or released a BUTTON_IRQ happens. The driver could look like: #include #include -static struct input_dev *button_dev; - static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) { - input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1); - input_sync(button_dev); + input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1); + input_sync(&button_dev); } static int __init button_init(void) { - int error; - if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) { printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq); return -EBUSY; } - - button_dev = input_allocate_device(); - if (!button_dev) { - printk(KERN_ERR "button.c: Not enough memory\n"); - error = -ENOMEM; - goto err_free_irq; - } - - button_dev->evbit[0] = BIT(EV_KEY); - button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); - - error = input_register_device(button_dev); - if (error) { - printk(KERN_ERR "button.c: Failed to register device\n"); - goto err_free_dev; - } - - return 0; - - err_free_dev: - input_free_device(button_dev); - err_free_irq: - free_irq(BUTTON_IRQ, button_interrupt); - return error; + + button_dev.evbit[0] = BIT(EV_KEY); + button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0); + + input_register_device(&button_dev); } static void __exit button_exit(void) { - input_unregister_device(button_dev); + input_unregister_device(&button_dev); free_irq(BUTTON_IRQ, button_interrupt); } @@ -79,18 +58,17 @@ In the _init function, which is called either upon module load or when booting the kernel, it grabs the required resources (it should also check for the presence of the device). -Then it allocates a new input device structure with input_aloocate_device() -and sets up input bitfields. This way the device driver tells the other +Then it sets the input bitfields. This way the device driver tells the other parts of the input systems what it is - what events can be generated or -accepted by this input device. Our example device can only generate EV_KEY -type events, and from those only BTN_0 event code. Thus we only set these -two bits. We could have used +accepted by this input device. Our example device can only generate EV_KEY type +events, and from those only BTN_0 event code. Thus we only set these two +bits. We could have used set_bit(EV_KEY, button_dev.evbit); set_bit(BTN_0, button_dev.keybit); as well, but with more than single bits the first approach tends to be -shorter. +shorter. Then the example driver registers the input device structure by calling @@ -98,15 +76,16 @@ Then the example driver registers the input device structure by calling This adds the button_dev structure to linked lists of the input driver and calls device handler modules _connect functions to tell them a new input -device has appeared. input_register_device() may sleep and therefore must -not be called from an interrupt or with a spinlock held. +device has appeared. Because the _connect functions may call kmalloc(, +GFP_KERNEL), which can sleep, input_register_device() must not be called +from an interrupt or with a spinlock held. While in use, the only used function of the driver is button_interrupt() which upon every interrupt from the button checks its state and reports it -via the +via the input_report_key() @@ -134,10 +113,16 @@ can use the open and close callback to know when it can stop polling or release the interrupt and when it must resume polling or grab the interrupt again. To do that, we would add this to our example driver: +int button_used = 0; + static int button_open(struct input_dev *dev) { + if (button_used++) + return 0; + if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) { printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq); + button_used--; return -EBUSY; } @@ -146,21 +131,20 @@ static int button_open(struct input_dev *dev) static void button_close(struct input_dev *dev) { - free_irq(IRQ_AMIGA_VERTB, button_interrupt); + if (!--button_used) + free_irq(IRQ_AMIGA_VERTB, button_interrupt); } static int __init button_init(void) { ... - button_dev->open = button_open; - button_dev->close = button_close; + button_dev.open = button_open; + button_dev.close = button_close; ... } -Note that input core keeps track of number of users for the device and -makes sure that dev->open() is called only when the first user connects -to the device and that dev->close() is called when the very last user -disconnects. Calls to both callbacks are serialized. +Note the button_used variable - we have to track how many times the open +function was called to know when exactly our device stops being used. The open() callback should return a 0 in case of success or any nonzero value in case of failure. The close() callback (which is void) must always succeed. @@ -191,7 +175,7 @@ set the corresponding bits and call the input_report_rel(struct input_dev *dev, int code, int value) -function. Events are generated only for nonzero value. +function. Events are generated only for nonzero value. However EV_ABS requires a little special care. Before calling input_register_device, you have to fill additional fields in the input_dev @@ -203,10 +187,6 @@ the ABS_X axis: button_dev.absfuzz[ABS_X] = 4; button_dev.absflat[ABS_X] = 8; -Or, you can just say: - - input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8); - This setting would be appropriate for a joystick X axis, with the minimum of 0, maximum of 255 (which the joystick *must* be able to reach, no problem if it sometimes reports more, but it must be able to always reach the min and @@ -217,7 +197,14 @@ If you don't need absfuzz and absflat, you can set them to zero, which mean that the thing is precise and always returns to exactly the center position (if it has any). -1.4 NBITS(), LONG(), BIT() +1.4 The void *private field +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This field in the input structure can be used to point to any private data +structures in the input device driver, in case the driver handles more than +one device. You'll need it in the open and close callbacks. + +1.5 NBITS(), LONG(), BIT() ~~~~~~~~~~~~~~~~~~~~~~~~~~ These three macros from input.h help some bitfield computations: @@ -226,9 +213,13 @@ These three macros from input.h help some bitfield computations: LONG(x) - returns the index in the array in longs for bit x BIT(x) - returns the index in a long for bit x -1.5 The id* and name fields +1.6 The number, id* and name fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The dev->number is assigned by the input system to the input device when it +is registered. It has no use except for identifying the device to the user +in system messages. + The dev->name should be set before registering the input device by the input device driver. It's a string like 'Generic button device' containing a user friendly name of the device. @@ -243,25 +234,15 @@ driver. The id and name fields can be passed to userland via the evdev interface. -1.6 The keycode, keycodemax, keycodesize fields +1.7 The keycode, keycodemax, keycodesize fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These three fields should be used by input devices that have dense keymaps. -The keycode is an array used to map from scancodes to input system keycodes. -The keycode max should contain the size of the array and keycodesize the -size of each entry in it (in bytes). - -Userspace can query and alter current scancode to keycode mappings using -EVIOCGKEYCODE and EVIOCSKEYCODE ioctls on corresponding evdev interface. -When a device has all 3 aforementioned fields filled in, the driver may -rely on kernel's default implementation of setting and querying keycode -mappings. - -1.7 dev->getkeycode() and dev->setkeycode() -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -getkeycode() and setkeycode() callbacks allow drivers to override default -keycode/keycodesize/keycodemax mapping mechanism provided by input core -and implement sparse keycode maps. +These two fields will be used for any input devices that report their data +as scancodes. If not all scancodes can be known by autodetection, they may +need to be set by userland utilities. The keycode array then is an array +used to map from scancodes to input system keycodes. The keycode max will +contain the size of the array and keycodesize the size of each entry in it +(in bytes). 1.8 Key autorepeat ~~~~~~~~~~~~~~~~~~ @@ -285,7 +266,7 @@ direction - from the system to the input device driver. If your input device driver can handle these events, it has to set the respective bits in evbit, *and* also the callback routine: - button_dev->event = button_event; + button_dev.event = button_event; int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); { diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 38d7db3262c7..12533a958c51 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -64,7 +64,6 @@ parameter is applicable: GENERIC_TIME The generic timeofday code is enabled. NFS Appropriate NFS support is enabled. OSS OSS sound support is enabled. - PV_OPS A paravirtualized kernel PARIDE The ParIDE subsystem is enabled. PARISC The PA-RISC architecture is enabled. PCI PCI bus support is enabled. @@ -182,41 +181,19 @@ and is between 256 and 4096 characters. It is defined in the file that require a timer override, but don't have HPET - acpi.debug_layer= [HW,ACPI] + acpi_dbg_layer= [HW,ACPI] Format: Each bit of the indicates an ACPI debug layer, 1: enable, 0: disable. It is useful for boot time debugging. After system has booted up, it can be set - via /sys/module/acpi/parameters/debug_layer. - CONFIG_ACPI_DEBUG must be enabled for this to produce any output. - Available bits (add the numbers together) to enable debug output - for specific parts of the ACPI subsystem: - 0x01 utilities 0x02 hardware 0x04 events 0x08 tables - 0x10 namespace 0x20 parser 0x40 dispatcher - 0x80 executer 0x100 resources 0x200 acpica debugger - 0x400 os services 0x800 acpica disassembler. - The number can be in decimal or prefixed with 0x in hex. - Warning: Many of these options can produce a lot of - output and make your system unusable. Be very careful. - - acpi.debug_level= [HW,ACPI] + via /proc/acpi/debug_layer. + + acpi_dbg_level= [HW,ACPI] Format: Each bit of the indicates an ACPI debug level, 1: enable, 0: disable. It is useful for boot time debugging. After system has booted up, it can be set - via /sys/module/acpi/parameters/debug_level. - CONFIG_ACPI_DEBUG must be enabled for this to produce any output. - Available bits (add the numbers together) to enable different - debug output levels of the ACPI subsystem: - 0x01 error 0x02 warn 0x04 init 0x08 debug object - 0x10 info 0x20 init names 0x40 parse 0x80 load - 0x100 dispatch 0x200 execute 0x400 names 0x800 operation region - 0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects - 0x10000 resources 0x20000 user requests 0x40000 package. - The number can be in decimal or prefixed with 0x in hex. - Warning: Many of these options can produce a lot of - output and make your system unusable. Be very careful. - + via /proc/acpi/debug_level. acpi_fake_ecdt [HW,ACPI] Workaround failure due to BIOS lacking ECDT @@ -696,15 +673,8 @@ and is between 256 and 4096 characters. It is defined in the file idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed See Documentation/ide.txt. - idle= [X86] - Format: idle=poll or idle=mwait - Poll forces a polling idle loop that can slightly improves the performance - of waking up a idle CPU, but will use a lot of power and make the system - run hot. Not recommended. - idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose - to not use it because it doesn't save as much power as a normal idle - loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same - as idle=poll. + idle= [HW] + Format: idle=poll or idle=halt ignore_loglevel [KNL] Ignore loglevel setting - this will print /all/ @@ -1165,11 +1135,6 @@ and is between 256 and 4096 characters. It is defined in the file nomce [IA-32] Machine Check Exception - noreplace-paravirt [IA-32,PV_OPS] Don't patch paravirt_ops - - noreplace-smp [IA-32,SMP] Don't replace SMP instructions - with UP alternatives - noresidual [PPC] Don't use residual data on PReP machines. noresume [SWSUSP] Disables resume and restores original swap @@ -1575,9 +1540,6 @@ and is between 256 and 4096 characters. It is defined in the file smart2= [HW] Format: [,[,...,]] - smp-alt-once [IA-32,SMP] On a hotplug CPU system, only - attempt to substitute SMP alternatives once at boot. - snd-ad1816a= [HW,ALSA] snd-ad1848= [HW,ALSA] @@ -1830,13 +1792,12 @@ and is between 256 and 4096 characters. It is defined in the file for newly-detected USB devices (default 2). This is the time required before an idle device will be autosuspended. Devices for which the delay is set - to a negative value won't be autosuspended at all. + to 0 won't be autosuspended at all. usbhid.mousepoll= [USBHID] The interval which mice are to be polled at. vdso= [IA-32,SH] - vdso=2: enable compat VDSO (default with COMPAT_VDSO) vdso=1: enable VDSO (default) vdso=0: disable VDSO mapping diff --git a/trunk/Documentation/keys.txt b/trunk/Documentation/keys.txt index 81d9aa097298..60c665d9cfaa 100644 --- a/trunk/Documentation/keys.txt +++ b/trunk/Documentation/keys.txt @@ -859,18 +859,6 @@ payload contents" for more information. void unregister_key_type(struct key_type *type); -Under some circumstances, it may be desirable to desirable to deal with a -bundle of keys. The facility provides access to the keyring type for managing -such a bundle: - - struct key_type key_type_keyring; - -This can be used with a function such as request_key() to find a specific -keyring in a process's keyrings. A keyring thus found can then be searched -with keyring_search(). Note that it is not possible to use request_key() to -search a specific keyring, so using keyrings in this way is of limited utility. - - =================================== NOTES ON ACCESSING PAYLOAD CONTENTS =================================== diff --git a/trunk/Documentation/networking/bcm43xx.txt b/trunk/Documentation/networking/bcm43xx.txt index a136721499bf..28541d2bee1e 100644 --- a/trunk/Documentation/networking/bcm43xx.txt +++ b/trunk/Documentation/networking/bcm43xx.txt @@ -2,88 +2,35 @@ BCM43xx Linux Driver Project ============================ -Introduction ------------- - -Many of the wireless devices found in modern notebook computers are -based on the wireless chips produced by Broadcom. These devices have -been a problem for Linux users as there is no open-source driver -available. In addition, Broadcom has not released specifications -for the device, and driver availability has been limited to the -binary-only form used in the GPL versions of AP hardware such as the -Linksys WRT54G, and the Windows and OS X drivers. Before this project -began, the only way to use these devices were to use the Windows or -OS X drivers with either the Linuxant or ndiswrapper modules. There -is a strong penalty if this method is used as loading the binary-only -module "taints" the kernel, and no kernel developer will help diagnose -any kernel problems. - -Development ------------ +About this software +------------------- -This driver has been developed using -a clean-room technique that is described at -http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal -reasons, none of the clean-room crew works on the on the Linux driver, -and none of the Linux developers sees anything but the specifications, -which are the ultimate product of the reverse-engineering group. +The goal of this project is to develop a linux driver for Broadcom +BCM43xx chips, based on the specification at +http://bcm-specs.sipsolutions.net/ -Software --------- +The project page is http://bcm43xx.berlios.de/ -Since the release of the 2.6.17 kernel, the bcm43xx driver has been -distributed with the kernel source, and is prebuilt in most, if not -all, distributions. There is, however, additional software that is -required. The firmware used by the chip is the intellectual property -of Broadcom and they have not given the bcm43xx team redistribution -rights to this firmware. Since we cannot legally redistribute -the firwmare we cannot include it with the driver. Furthermore, it -cannot be placed in the downloadable archives of any distributing -organization; therefore, the user is responsible for obtaining the -firmware and placing it in the appropriate location so that the driver -can find it when initializing. -To help with this process, the bcm43xx developers provide a separate -program named bcm43xx-fwcutter to "cut" the firmware out of a -Windows or OS X driver and write the extracted files to the proper -location. This program is usually provided with the distribution; -however, it may be downloaded from - -http://developer.berlios.de/project/showfiles.php?group_id=4547 +Requirements +------------ -The firmware is available in two versions. V3 firmware is used with -the in-kernel bcm43xx driver that uses a software MAC layer called -SoftMAC, and will have a microcode revision of 0x127 or smaller. The -V4 firmware is used by an out-of-kernel driver employing a variation of -the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches -a satisfactory level of development, it will replace bcm43xx-softmac -in the kernel as it is much more flexible and powerful. +1) Linux Kernel 2.6.16 or later + http://www.kernel.org/ -A source for the latest V3 firmware is + You may want to configure your kernel with: -http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o + CONFIG_DEBUG_FS (optional): + -> Kernel hacking + -> Debug Filesystem -Once this file is downloaded, the command -'bcm43xx-fwcutter -w ' -will extract the microcode and write it to directory -. The correct directory will depend on your distribution; -however, most use '/lib/firmware'. Once this step is completed, -the bcm3xx driver should load when the system is booted. To see -any messages relating to the driver, issue the command 'dmesg | -grep bcm43xx' from a terminal window. If there are any problems, -please send that output to Bcm43xx-dev@lists.berlios.de. +2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 + modules: + http://softmac.sipsolutions.net/ -Although the driver has been in-kernel since 2.6.17, the earliest -version is quite limited in its capability. Patches that include -all features of later versions are available for the stable kernel -versions from 2.6.18. These will be needed if you use a BCM4318, -or a PCI Express version (BCM4311 and BCM4312). In addition, if you -have an early BCM4306 and more than 1 GB RAM, your kernel will need -to be patched. These patches, which are being updated regularly, -are available at ftp://lwfinger.dynalias.org/patches. Look for -combined_2.6.YY.patch. Of course you will need kernel source downloaded -from kernel.org, or the source from your distribution. +3) Firmware Files -If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG -and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is -essential for solving any problems. + Please try fwcutter. Fwcutter can extract the firmware from various + binary driver files. It supports driver files from Windows, MacOS and + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. + Also, fwcutter comes with a README file for further instructions. diff --git a/trunk/Documentation/networking/bonding.txt b/trunk/Documentation/networking/bonding.txt index 1da566630831..de809e58092f 100644 --- a/trunk/Documentation/networking/bonding.txt +++ b/trunk/Documentation/networking/bonding.txt @@ -920,9 +920,40 @@ options, you may wish to use the "max_bonds" module parameter, documented above. To create multiple bonding devices with differing options, it -is necessary to use bonding parameters exported by sysfs, documented -in the section below. +is necessary to load the bonding driver multiple times. Note that +current versions of the sysconfig network initialization scripts +handle this automatically; if your distro uses these scripts, no +special action is needed. See the section Configuring Bonding +Devices, above, if you're not sure about your network initialization +scripts. + + To load multiple instances of the module, it is necessary to +specify a different name for each instance (the module loading system +requires that every loaded module, even multiple instances of the same +module, have a unique name). This is accomplished by supplying +multiple sets of bonding options in /etc/modprobe.conf, for example: + +alias bond0 bonding +options bond0 -o bond0 mode=balance-rr miimon=100 + +alias bond1 bonding +options bond1 -o bond1 mode=balance-alb miimon=50 + + will load the bonding module two times. The first instance is +named "bond0" and creates the bond0 device in balance-rr mode with an +miimon of 100. The second instance is named "bond1" and creates the +bond1 device in balance-alb mode with an miimon of 50. + + In some circumstances (typically with older distributions), +the above does not work, and the second bonding instance never sees +its options. In that case, the second options line can be substituted +as follows: + +install bond1 /sbin/modprobe --ignore-install bonding -o bond1 \ + mode=balance-alb miimon=50 + This may be repeated any number of times, specifying a new and +unique name in place of bond1 for each subsequent instance. 3.4 Configuring Bonding Manually via Sysfs ------------------------------------------ diff --git a/trunk/Documentation/networking/dccp.txt b/trunk/Documentation/networking/dccp.txt index 4504cc59e405..387482e46c47 100644 --- a/trunk/Documentation/networking/dccp.txt +++ b/trunk/Documentation/networking/dccp.txt @@ -57,16 +57,6 @@ DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it coverage value are also acceptable. The higher the number, the more restrictive this setting (see [RFC 4340, sec. 9.2.1]). -The following two options apply to CCID 3 exclusively and are getsockopt()-only. -In either case, a TFRC info struct (defined in ) is returned. -DCCP_SOCKOPT_CCID_RX_INFO - Returns a `struct tfrc_rx_info' in optval; the buffer for optval and - optlen must be set to at least sizeof(struct tfrc_rx_info). -DCCP_SOCKOPT_CCID_TX_INFO - Returns a `struct tfrc_tx_info' in optval; the buffer for optval and - optlen must be set to at least sizeof(struct tfrc_tx_info). - - Sysctl variables ================ Several DCCP default parameters can be managed by the following sysctls diff --git a/trunk/Documentation/networking/ip-sysctl.txt b/trunk/Documentation/networking/ip-sysctl.txt index af6a63ab9026..d3aae1f9b4c1 100644 --- a/trunk/Documentation/networking/ip-sysctl.txt +++ b/trunk/Documentation/networking/ip-sysctl.txt @@ -179,31 +179,11 @@ tcp_fin_timeout - INTEGER because they eat maximum 1.5K of memory, but they tend to live longer. Cf. tcp_max_orphans. -tcp_frto - INTEGER +tcp_frto - BOOLEAN Enables F-RTO, an enhanced recovery algorithm for TCP retransmission timeouts. It is particularly beneficial in wireless environments where packet loss is typically due to random radio interference - rather than intermediate router congestion. If set to 1, basic - version is enabled. 2 enables SACK enhanced F-RTO, which is - EXPERIMENTAL. The basic version can be used also when SACK is - enabled for a flow through tcp_sack sysctl. - -tcp_frto_response - INTEGER - When F-RTO has detected that a TCP retransmission timeout was - spurious (i.e, the timeout would have been avoided had TCP set a - longer retransmission timeout), TCP has several options what to do - next. Possible values are: - 0 Rate halving based; a smooth and conservative response, - results in halved cwnd and ssthresh after one RTT - 1 Very conservative response; not recommended because even - though being valid, it interacts poorly with the rest of - Linux TCP, halves cwnd and ssthresh immediately - 2 Aggressive response; undoes congestion control measures - that are now known to be unnecessary (ignoring the - possibility of a lost retransmission that would require - TCP to be more cautious), cwnd and ssthresh are restored - to the values prior timeout - Default: 0 (rate halving based) + rather than intermediate router congestion. tcp_keepalive_time - INTEGER How often TCP sends out keepalive messages when keepalive is enabled. @@ -871,15 +851,6 @@ accept_redirects - BOOLEAN Functional default: enabled if local forwarding is disabled. disabled if local forwarding is enabled. -accept_source_route - INTEGER - Accept source routing (routing extension header). - - > 0: Accept routing header. - = 0: Accept only routing header type 2. - < 0: Do not accept routing header. - - Default: 0 - autoconf - BOOLEAN Autoconfigure addresses using Prefix Information in Router Advertisements. @@ -1015,12 +986,7 @@ bridge-nf-call-ip6tables - BOOLEAN Default: 1 bridge-nf-filter-vlan-tagged - BOOLEAN - 1 : pass bridged vlan-tagged ARP/IP/IPv6 traffic to {arp,ip,ip6}tables. - 0 : disable this. - Default: 1 - -bridge-nf-filter-pppoe-tagged - BOOLEAN - 1 : pass bridged pppoe-tagged IP/IPv6 traffic to {ip,ip6}tables. + 1 : pass bridged vlan-tagged ARP/IP traffic to arptables/iptables. 0 : disable this. Default: 1 diff --git a/trunk/Documentation/networking/rxrpc.txt b/trunk/Documentation/networking/rxrpc.txt deleted file mode 100644 index cae231b1c134..000000000000 --- a/trunk/Documentation/networking/rxrpc.txt +++ /dev/null @@ -1,859 +0,0 @@ - ====================== - RxRPC NETWORK PROTOCOL - ====================== - -The RxRPC protocol driver provides a reliable two-phase transport on top of UDP -that can be used to perform RxRPC remote operations. This is done over sockets -of AF_RXRPC family, using sendmsg() and recvmsg() with control data to send and -receive data, aborts and errors. - -Contents of this document: - - (*) Overview. - - (*) RxRPC protocol summary. - - (*) AF_RXRPC driver model. - - (*) Control messages. - - (*) Socket options. - - (*) Security. - - (*) Example client usage. - - (*) Example server usage. - - (*) AF_RXRPC kernel interface. - - -======== -OVERVIEW -======== - -RxRPC is a two-layer protocol. There is a session layer which provides -reliable virtual connections using UDP over IPv4 (or IPv6) as the transport -layer, but implements a real network protocol; and there's the presentation -layer which renders structured data to binary blobs and back again using XDR -(as does SunRPC): - - +-------------+ - | Application | - +-------------+ - | XDR | Presentation - +-------------+ - | RxRPC | Session - +-------------+ - | UDP | Transport - +-------------+ - - -AF_RXRPC provides: - - (1) Part of an RxRPC facility for both kernel and userspace applications by - making the session part of it a Linux network protocol (AF_RXRPC). - - (2) A two-phase protocol. The client transmits a blob (the request) and then - receives a blob (the reply), and the server receives the request and then - transmits the reply. - - (3) Retention of the reusable bits of the transport system set up for one call - to speed up subsequent calls. - - (4) A secure protocol, using the Linux kernel's key retention facility to - manage security on the client end. The server end must of necessity be - more active in security negotiations. - -AF_RXRPC does not provide XDR marshalling/presentation facilities. That is -left to the application. AF_RXRPC only deals in blobs. Even the operation ID -is just the first four bytes of the request blob, and as such is beyond the -kernel's interest. - - -Sockets of AF_RXRPC family are: - - (1) created as type SOCK_DGRAM; - - (2) provided with a protocol of the type of underlying transport they're going - to use - currently only PF_INET is supported. - - -The Andrew File System (AFS) is an example of an application that uses this and -that has both kernel (filesystem) and userspace (utility) components. - - -====================== -RXRPC PROTOCOL SUMMARY -====================== - -An overview of the RxRPC protocol: - - (*) RxRPC sits on top of another networking protocol (UDP is the only option - currently), and uses this to provide network transport. UDP ports, for - example, provide transport endpoints. - - (*) RxRPC supports multiple virtual "connections" from any given transport - endpoint, thus allowing the endpoints to be shared, even to the same - remote endpoint. - - (*) Each connection goes to a particular "service". A connection may not go - to multiple services. A service may be considered the RxRPC equivalent of - a port number. AF_RXRPC permits multiple services to share an endpoint. - - (*) Client-originating packets are marked, thus a transport endpoint can be - shared between client and server connections (connections have a - direction). - - (*) Up to a billion connections may be supported concurrently between one - local transport endpoint and one service on one remote endpoint. An RxRPC - connection is described by seven numbers: - - Local address } - Local port } Transport (UDP) address - Remote address } - Remote port } - Direction - Connection ID - Service ID - - (*) Each RxRPC operation is a "call". A connection may make up to four - billion calls, but only up to four calls may be in progress on a - connection at any one time. - - (*) Calls are two-phase and asymmetric: the client sends its request data, - which the service receives; then the service transmits the reply data - which the client receives. - - (*) The data blobs are of indefinite size, the end of a phase is marked with a - flag in the packet. The number of packets of data making up one blob may - not exceed 4 billion, however, as this would cause the sequence number to - wrap. - - (*) The first four bytes of the request data are the service operation ID. - - (*) Security is negotiated on a per-connection basis. The connection is - initiated by the first data packet on it arriving. If security is - requested, the server then issues a "challenge" and then the client - replies with a "response". If the response is successful, the security is - set for the lifetime of that connection, and all subsequent calls made - upon it use that same security. In the event that the server lets a - connection lapse before the client, the security will be renegotiated if - the client uses the connection again. - - (*) Calls use ACK packets to handle reliability. Data packets are also - explicitly sequenced per call. - - (*) There are two types of positive acknowledgement: hard-ACKs and soft-ACKs. - A hard-ACK indicates to the far side that all the data received to a point - has been received and processed; a soft-ACK indicates that the data has - been received but may yet be discarded and re-requested. The sender may - not discard any transmittable packets until they've been hard-ACK'd. - - (*) Reception of a reply data packet implicitly hard-ACK's all the data - packets that make up the request. - - (*) An call is complete when the request has been sent, the reply has been - received and the final hard-ACK on the last packet of the reply has - reached the server. - - (*) An call may be aborted by either end at any time up to its completion. - - -===================== -AF_RXRPC DRIVER MODEL -===================== - -About the AF_RXRPC driver: - - (*) The AF_RXRPC protocol transparently uses internal sockets of the transport - protocol to represent transport endpoints. - - (*) AF_RXRPC sockets map onto RxRPC connection bundles. Actual RxRPC - connections are handled transparently. One client socket may be used to - make multiple simultaneous calls to the same service. One server socket - may handle calls from many clients. - - (*) Additional parallel client connections will be initiated to support extra - concurrent calls, up to a tunable limit. - - (*) Each connection is retained for a certain amount of time [tunable] after - the last call currently using it has completed in case a new call is made - that could reuse it. - - (*) Each internal UDP socket is retained [tunable] for a certain amount of - time [tunable] after the last connection using it discarded, in case a new - connection is made that could use it. - - (*) A client-side connection is only shared between calls if they have have - the same key struct describing their security (and assuming the calls - would otherwise share the connection). Non-secured calls would also be - able to share connections with each other. - - (*) A server-side connection is shared if the client says it is. - - (*) ACK'ing is handled by the protocol driver automatically, including ping - replying. - - (*) SO_KEEPALIVE automatically pings the other side to keep the connection - alive [TODO]. - - (*) If an ICMP error is received, all calls affected by that error will be - aborted with an appropriate network error passed through recvmsg(). - - -Interaction with the user of the RxRPC socket: - - (*) A socket is made into a server socket by binding an address with a - non-zero service ID. - - (*) In the client, sending a request is achieved with one or more sendmsgs, - followed by the reply being received with one or more recvmsgs. - - (*) The first sendmsg for a request to be sent from a client contains a tag to - be used in all other sendmsgs or recvmsgs associated with that call. The - tag is carried in the control data. - - (*) connect() is used to supply a default destination address for a client - socket. This may be overridden by supplying an alternate address to the - first sendmsg() of a call (struct msghdr::msg_name). - - (*) If connect() is called on an unbound client, a random local port will - bound before the operation takes place. - - (*) A server socket may also be used to make client calls. To do this, the - first sendmsg() of the call must specify the target address. The server's - transport endpoint is used to send the packets. - - (*) Once the application has received the last message associated with a call, - the tag is guaranteed not to be seen again, and so it can be used to pin - client resources. A new call can then be initiated with the same tag - without fear of interference. - - (*) In the server, a request is received with one or more recvmsgs, then the - the reply is transmitted with one or more sendmsgs, and then the final ACK - is received with a last recvmsg. - - (*) When sending data for a call, sendmsg is given MSG_MORE if there's more - data to come on that call. - - (*) When receiving data for a call, recvmsg flags MSG_MORE if there's more - data to come for that call. - - (*) When receiving data or messages for a call, MSG_EOR is flagged by recvmsg - to indicate the terminal message for that call. - - (*) A call may be aborted by adding an abort control message to the control - data. Issuing an abort terminates the kernel's use of that call's tag. - Any messages waiting in the receive queue for that call will be discarded. - - (*) Aborts, busy notifications and challenge packets are delivered by recvmsg, - and control data messages will be set to indicate the context. Receiving - an abort or a busy message terminates the kernel's use of that call's tag. - - (*) The control data part of the msghdr struct is used for a number of things: - - (*) The tag of the intended or affected call. - - (*) Sending or receiving errors, aborts and busy notifications. - - (*) Notifications of incoming calls. - - (*) Sending debug requests and receiving debug replies [TODO]. - - (*) When the kernel has received and set up an incoming call, it sends a - message to server application to let it know there's a new call awaiting - its acceptance [recvmsg reports a special control message]. The server - application then uses sendmsg to assign a tag to the new call. Once that - is done, the first part of the request data will be delivered by recvmsg. - - (*) The server application has to provide the server socket with a keyring of - secret keys corresponding to the security types it permits. When a secure - connection is being set up, the kernel looks up the appropriate secret key - in the keyring and then sends a challenge packet to the client and - receives a response packet. The kernel then checks the authorisation of - the packet and either aborts the connection or sets up the security. - - (*) The name of the key a client will use to secure its communications is - nominated by a socket option. - - -Notes on recvmsg: - - (*) If there's a sequence of data messages belonging to a particular call on - the receive queue, then recvmsg will keep working through them until: - - (a) it meets the end of that call's received data, - - (b) it meets a non-data message, - - (c) it meets a message belonging to a different call, or - - (d) it fills the user buffer. - - If recvmsg is called in blocking mode, it will keep sleeping, awaiting the - reception of further data, until one of the above four conditions is met. - - (2) MSG_PEEK operates similarly, but will return immediately if it has put any - data in the buffer rather than sleeping until it can fill the buffer. - - (3) If a data message is only partially consumed in filling a user buffer, - then the remainder of that message will be left on the front of the queue - for the next taker. MSG_TRUNC will never be flagged. - - (4) If there is more data to be had on a call (it hasn't copied the last byte - of the last data message in that phase yet), then MSG_MORE will be - flagged. - - -================ -CONTROL MESSAGES -================ - -AF_RXRPC makes use of control messages in sendmsg() and recvmsg() to multiplex -calls, to invoke certain actions and to report certain conditions. These are: - - MESSAGE ID SRT DATA MEANING - ======================= === =========== =============================== - RXRPC_USER_CALL_ID sr- User ID App's call specifier - RXRPC_ABORT srt Abort code Abort code to issue/received - RXRPC_ACK -rt n/a Final ACK received - RXRPC_NET_ERROR -rt error num Network error on call - RXRPC_BUSY -rt n/a Call rejected (server busy) - RXRPC_LOCAL_ERROR -rt error num Local error encountered - RXRPC_NEW_CALL -r- n/a New call received - RXRPC_ACCEPT s-- n/a Accept new call - - (SRT = usable in Sendmsg / delivered by Recvmsg / Terminal message) - - (*) RXRPC_USER_CALL_ID - - This is used to indicate the application's call ID. It's an unsigned long - that the app specifies in the client by attaching it to the first data - message or in the server by passing it in association with an RXRPC_ACCEPT - message. recvmsg() passes it in conjunction with all messages except - those of the RXRPC_NEW_CALL message. - - (*) RXRPC_ABORT - - This is can be used by an application to abort a call by passing it to - sendmsg, or it can be delivered by recvmsg to indicate a remote abort was - received. Either way, it must be associated with an RXRPC_USER_CALL_ID to - specify the call affected. If an abort is being sent, then error EBADSLT - will be returned if there is no call with that user ID. - - (*) RXRPC_ACK - - This is delivered to a server application to indicate that the final ACK - of a call was received from the client. It will be associated with an - RXRPC_USER_CALL_ID to indicate the call that's now complete. - - (*) RXRPC_NET_ERROR - - This is delivered to an application to indicate that an ICMP error message - was encountered in the process of trying to talk to the peer. An - errno-class integer value will be included in the control message data - indicating the problem, and an RXRPC_USER_CALL_ID will indicate the call - affected. - - (*) RXRPC_BUSY - - This is delivered to a client application to indicate that a call was - rejected by the server due to the server being busy. It will be - associated with an RXRPC_USER_CALL_ID to indicate the rejected call. - - (*) RXRPC_LOCAL_ERROR - - This is delivered to an application to indicate that a local error was - encountered and that a call has been aborted because of it. An - errno-class integer value will be included in the control message data - indicating the problem, and an RXRPC_USER_CALL_ID will indicate the call - affected. - - (*) RXRPC_NEW_CALL - - This is delivered to indicate to a server application that a new call has - arrived and is awaiting acceptance. No user ID is associated with this, - as a user ID must subsequently be assigned by doing an RXRPC_ACCEPT. - - (*) RXRPC_ACCEPT - - This is used by a server application to attempt to accept a call and - assign it a user ID. It should be associated with an RXRPC_USER_CALL_ID - to indicate the user ID to be assigned. If there is no call to be - accepted (it may have timed out, been aborted, etc.), then sendmsg will - return error ENODATA. If the user ID is already in use by another call, - then error EBADSLT will be returned. - - -============== -SOCKET OPTIONS -============== - -AF_RXRPC sockets support a few socket options at the SOL_RXRPC level: - - (*) RXRPC_SECURITY_KEY - - This is used to specify the description of the key to be used. The key is - extracted from the calling process's keyrings with request_key() and - should be of "rxrpc" type. - - The optval pointer points to the description string, and optlen indicates - how long the string is, without the NUL terminator. - - (*) RXRPC_SECURITY_KEYRING - - Similar to above but specifies a keyring of server secret keys to use (key - type "keyring"). See the "Security" section. - - (*) RXRPC_EXCLUSIVE_CONNECTION - - This is used to request that new connections should be used for each call - made subsequently on this socket. optval should be NULL and optlen 0. - - (*) RXRPC_MIN_SECURITY_LEVEL - - This is used to specify the minimum security level required for calls on - this socket. optval must point to an int containing one of the following - values: - - (a) RXRPC_SECURITY_PLAIN - - Encrypted checksum only. - - (b) RXRPC_SECURITY_AUTH - - Encrypted checksum plus packet padded and first eight bytes of packet - encrypted - which includes the actual packet length. - - (c) RXRPC_SECURITY_ENCRYPTED - - Encrypted checksum plus entire packet padded and encrypted, including - actual packet length. - - -======== -SECURITY -======== - -Currently, only the kerberos 4 equivalent protocol has been implemented -(security index 2 - rxkad). This requires the rxkad module to be loaded and, -on the client, tickets of the appropriate type to be obtained from the AFS -kaserver or the kerberos server and installed as "rxrpc" type keys. This is -normally done using the klog program. An example simple klog program can be -found at: - - http://people.redhat.com/~dhowells/rxrpc/klog.c - -The payload provided to add_key() on the client should be of the following -form: - - struct rxrpc_key_sec2_v1 { - uint16_t security_index; /* 2 */ - uint16_t ticket_length; /* length of ticket[] */ - uint32_t expiry; /* time at which expires */ - uint8_t kvno; /* key version number */ - uint8_t __pad[3]; - uint8_t session_key[8]; /* DES session key */ - uint8_t ticket[0]; /* the encrypted ticket */ - }; - -Where the ticket blob is just appended to the above structure. - - -For the server, keys of type "rxrpc_s" must be made available to the server. -They have a description of ":" (eg: "52:2" for an -rxkad key for the AFS VL service). When such a key is created, it should be -given the server's secret key as the instantiation data (see the example -below). - - add_key("rxrpc_s", "52:2", secret_key, 8, keyring); - -A keyring is passed to the server socket by naming it in a sockopt. The server -socket then looks the server secret keys up in this keyring when secure -incoming connections are made. This can be seen in an example program that can -be found at: - - http://people.redhat.com/~dhowells/rxrpc/listen.c - - -==================== -EXAMPLE CLIENT USAGE -==================== - -A client would issue an operation by: - - (1) An RxRPC socket is set up by: - - client = socket(AF_RXRPC, SOCK_DGRAM, PF_INET); - - Where the third parameter indicates the protocol family of the transport - socket used - usually IPv4 but it can also be IPv6 [TODO]. - - (2) A local address can optionally be bound: - - struct sockaddr_rxrpc srx = { - .srx_family = AF_RXRPC, - .srx_service = 0, /* we're a client */ - .transport_type = SOCK_DGRAM, /* type of transport socket */ - .transport.sin_family = AF_INET, - .transport.sin_port = htons(7000), /* AFS callback */ - .transport.sin_address = 0, /* all local interfaces */ - }; - bind(client, &srx, sizeof(srx)); - - This specifies the local UDP port to be used. If not given, a random - non-privileged port will be used. A UDP port may be shared between - several unrelated RxRPC sockets. Security is handled on a basis of - per-RxRPC virtual connection. - - (3) The security is set: - - const char *key = "AFS:cambridge.redhat.com"; - setsockopt(client, SOL_RXRPC, RXRPC_SECURITY_KEY, key, strlen(key)); - - This issues a request_key() to get the key representing the security - context. The minimum security level can be set: - - unsigned int sec = RXRPC_SECURITY_ENCRYPTED; - setsockopt(client, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, - &sec, sizeof(sec)); - - (4) The server to be contacted can then be specified (alternatively this can - be done through sendmsg): - - struct sockaddr_rxrpc srx = { - .srx_family = AF_RXRPC, - .srx_service = VL_SERVICE_ID, - .transport_type = SOCK_DGRAM, /* type of transport socket */ - .transport.sin_family = AF_INET, - .transport.sin_port = htons(7005), /* AFS volume manager */ - .transport.sin_address = ..., - }; - connect(client, &srx, sizeof(srx)); - - (5) The request data should then be posted to the server socket using a series - of sendmsg() calls, each with the following control message attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - - MSG_MORE should be set in msghdr::msg_flags on all but the last part of - the request. Multiple requests may be made simultaneously. - - If a call is intended to go to a destination other then the default - specified through connect(), then msghdr::msg_name should be set on the - first request message of that call. - - (6) The reply data will then be posted to the server socket for recvmsg() to - pick up. MSG_MORE will be flagged by recvmsg() if there's more reply data - for a particular call to be read. MSG_EOR will be set on the terminal - read for a call. - - All data will be delivered with the following control message attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - - If an abort or error occurred, this will be returned in the control data - buffer instead, and MSG_EOR will be flagged to indicate the end of that - call. - - -==================== -EXAMPLE SERVER USAGE -==================== - -A server would be set up to accept operations in the following manner: - - (1) An RxRPC socket is created by: - - server = socket(AF_RXRPC, SOCK_DGRAM, PF_INET); - - Where the third parameter indicates the address type of the transport - socket used - usually IPv4. - - (2) Security is set up if desired by giving the socket a keyring with server - secret keys in it: - - keyring = add_key("keyring", "AFSkeys", NULL, 0, - KEY_SPEC_PROCESS_KEYRING); - - const char secret_key[8] = { - 0xa7, 0x83, 0x8a, 0xcb, 0xc7, 0x83, 0xec, 0x94 }; - add_key("rxrpc_s", "52:2", secret_key, 8, keyring); - - setsockopt(server, SOL_RXRPC, RXRPC_SECURITY_KEYRING, "AFSkeys", 7); - - The keyring can be manipulated after it has been given to the socket. This - permits the server to add more keys, replace keys, etc. whilst it is live. - - (2) A local address must then be bound: - - struct sockaddr_rxrpc srx = { - .srx_family = AF_RXRPC, - .srx_service = VL_SERVICE_ID, /* RxRPC service ID */ - .transport_type = SOCK_DGRAM, /* type of transport socket */ - .transport.sin_family = AF_INET, - .transport.sin_port = htons(7000), /* AFS callback */ - .transport.sin_address = 0, /* all local interfaces */ - }; - bind(server, &srx, sizeof(srx)); - - (3) The server is then set to listen out for incoming calls: - - listen(server, 100); - - (4) The kernel notifies the server of pending incoming connections by sending - it a message for each. This is received with recvmsg() on the server - socket. It has no data, and has a single dataless control message - attached: - - RXRPC_NEW_CALL - - The address that can be passed back by recvmsg() at this point should be - ignored since the call for which the message was posted may have gone by - the time it is accepted - in which case the first call still on the queue - will be accepted. - - (5) The server then accepts the new call by issuing a sendmsg() with two - pieces of control data and no actual data: - - RXRPC_ACCEPT - indicate connection acceptance - RXRPC_USER_CALL_ID - specify user ID for this call - - (6) The first request data packet will then be posted to the server socket for - recvmsg() to pick up. At that point, the RxRPC address for the call can - be read from the address fields in the msghdr struct. - - Subsequent request data will be posted to the server socket for recvmsg() - to collect as it arrives. All but the last piece of the request data will - be delivered with MSG_MORE flagged. - - All data will be delivered with the following control message attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - - (8) The reply data should then be posted to the server socket using a series - of sendmsg() calls, each with the following control messages attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - - MSG_MORE should be set in msghdr::msg_flags on all but the last message - for a particular call. - - (9) The final ACK from the client will be posted for retrieval by recvmsg() - when it is received. It will take the form of a dataless message with two - control messages attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - RXRPC_ACK - indicates final ACK (no data) - - MSG_EOR will be flagged to indicate that this is the final message for - this call. - -(10) Up to the point the final packet of reply data is sent, the call can be - aborted by calling sendmsg() with a dataless message with the following - control messages attached: - - RXRPC_USER_CALL_ID - specifies the user ID for this call - RXRPC_ABORT - indicates abort code (4 byte data) - - Any packets waiting in the socket's receive queue will be discarded if - this is issued. - -Note that all the communications for a particular service take place through -the one server socket, using control messages on sendmsg() and recvmsg() to -determine the call affected. - - -========================= -AF_RXRPC KERNEL INTERFACE -========================= - -The AF_RXRPC module also provides an interface for use by in-kernel utilities -such as the AFS filesystem. This permits such a utility to: - - (1) Use different keys directly on individual client calls on one socket - rather than having to open a whole slew of sockets, one for each key it - might want to use. - - (2) Avoid having RxRPC call request_key() at the point of issue of a call or - opening of a socket. Instead the utility is responsible for requesting a - key at the appropriate point. AFS, for instance, would do this during VFS - operations such as open() or unlink(). The key is then handed through - when the call is initiated. - - (3) Request the use of something other than GFP_KERNEL to allocate memory. - - (4) Avoid the overhead of using the recvmsg() call. RxRPC messages can be - intercepted before they get put into the socket Rx queue and the socket - buffers manipulated directly. - -To use the RxRPC facility, a kernel utility must still open an AF_RXRPC socket, -bind an addess as appropriate and listen if it's to be a server socket, but -then it passes this to the kernel interface functions. - -The kernel interface functions are as follows: - - (*) Begin a new client call. - - struct rxrpc_call * - rxrpc_kernel_begin_call(struct socket *sock, - struct sockaddr_rxrpc *srx, - struct key *key, - unsigned long user_call_ID, - gfp_t gfp); - - This allocates the infrastructure to make a new RxRPC call and assigns - call and connection numbers. The call will be made on the UDP port that - the socket is bound to. The call will go to the destination address of a - connected client socket unless an alternative is supplied (srx is - non-NULL). - - If a key is supplied then this will be used to secure the call instead of - the key bound to the socket with the RXRPC_SECURITY_KEY sockopt. Calls - secured in this way will still share connections if at all possible. - - The user_call_ID is equivalent to that supplied to sendmsg() in the - control data buffer. It is entirely feasible to use this to point to a - kernel data structure. - - If this function is successful, an opaque reference to the RxRPC call is - returned. The caller now holds a reference on this and it must be - properly ended. - - (*) End a client call. - - void rxrpc_kernel_end_call(struct rxrpc_call *call); - - This is used to end a previously begun call. The user_call_ID is expunged - from AF_RXRPC's knowledge and will not be seen again in association with - the specified call. - - (*) Send data through a call. - - int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, - size_t len); - - This is used to supply either the request part of a client call or the - reply part of a server call. msg.msg_iovlen and msg.msg_iov specify the - data buffers to be used. msg_iov may not be NULL and must point - exclusively to in-kernel virtual addresses. msg.msg_flags may be given - MSG_MORE if there will be subsequent data sends for this call. - - The msg must not specify a destination address, control data or any flags - other than MSG_MORE. len is the total amount of data to transmit. - - (*) Abort a call. - - void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code); - - This is used to abort a call if it's still in an abortable state. The - abort code specified will be placed in the ABORT message sent. - - (*) Intercept received RxRPC messages. - - typedef void (*rxrpc_interceptor_t)(struct sock *sk, - unsigned long user_call_ID, - struct sk_buff *skb); - - void - rxrpc_kernel_intercept_rx_messages(struct socket *sock, - rxrpc_interceptor_t interceptor); - - This installs an interceptor function on the specified AF_RXRPC socket. - All messages that would otherwise wind up in the socket's Rx queue are - then diverted to this function. Note that care must be taken to process - the messages in the right order to maintain DATA message sequentiality. - - The interceptor function itself is provided with the address of the socket - and handling the incoming message, the ID assigned by the kernel utility - to the call and the socket buffer containing the message. - - The skb->mark field indicates the type of message: - - MARK MEANING - =============================== ======================================= - RXRPC_SKB_MARK_DATA Data message - RXRPC_SKB_MARK_FINAL_ACK Final ACK received for an incoming call - RXRPC_SKB_MARK_BUSY Client call rejected as server busy - RXRPC_SKB_MARK_REMOTE_ABORT Call aborted by peer - RXRPC_SKB_MARK_NET_ERROR Network error detected - RXRPC_SKB_MARK_LOCAL_ERROR Local error encountered - RXRPC_SKB_MARK_NEW_CALL New incoming call awaiting acceptance - - The remote abort message can be probed with rxrpc_kernel_get_abort_code(). - The two error messages can be probed with rxrpc_kernel_get_error_number(). - A new call can be accepted with rxrpc_kernel_accept_call(). - - Data messages can have their contents extracted with the usual bunch of - socket buffer manipulation functions. A data message can be determined to - be the last one in a sequence with rxrpc_kernel_is_data_last(). When a - data message has been used up, rxrpc_kernel_data_delivered() should be - called on it.. - - Non-data messages should be handled to rxrpc_kernel_free_skb() to dispose - of. It is possible to get extra refs on all types of message for later - freeing, but this may pin the state of a call until the message is finally - freed. - - (*) Accept an incoming call. - - struct rxrpc_call * - rxrpc_kernel_accept_call(struct socket *sock, - unsigned long user_call_ID); - - This is used to accept an incoming call and to assign it a call ID. This - function is similar to rxrpc_kernel_begin_call() and calls accepted must - be ended in the same way. - - If this function is successful, an opaque reference to the RxRPC call is - returned. The caller now holds a reference on this and it must be - properly ended. - - (*) Reject an incoming call. - - int rxrpc_kernel_reject_call(struct socket *sock); - - This is used to reject the first incoming call on the socket's queue with - a BUSY message. -ENODATA is returned if there were no incoming calls. - Other errors may be returned if the call had been aborted (-ECONNABORTED) - or had timed out (-ETIME). - - (*) Record the delivery of a data message and free it. - - void rxrpc_kernel_data_delivered(struct sk_buff *skb); - - This is used to record a data message as having been delivered and to - update the ACK state for the call. The socket buffer will be freed. - - (*) Free a message. - - void rxrpc_kernel_free_skb(struct sk_buff *skb); - - This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC - socket. - - (*) Determine if a data message is the last one on a call. - - bool rxrpc_kernel_is_data_last(struct sk_buff *skb); - - This is used to determine if a socket buffer holds the last data message - to be received for a call (true will be returned if it does, false - if not). - - The data message will be part of the reply on a client call and the - request on an incoming call. In the latter case there will be more - messages, but in the former case there will not. - - (*) Get the abort code from an abort message. - - u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb); - - This is used to extract the abort code from a remote abort message. - - (*) Get the error number from a local or network error message. - - int rxrpc_kernel_get_error_number(struct sk_buff *skb); - - This is used to extract the error number from a message indicating either - a local error occurred or a network error occurred. diff --git a/trunk/Documentation/networking/wan-router.txt b/trunk/Documentation/networking/wan-router.txt index 07dd6d9930a1..653978dcea7f 100644 --- a/trunk/Documentation/networking/wan-router.txt +++ b/trunk/Documentation/networking/wan-router.txt @@ -250,6 +250,7 @@ PRODUCT COMPONENTS AND RELATED FILES sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions if_wanpipe.h WANPIPE Socket definitions + if_wanpipe_common.h WANPIPE Socket/Driver common definitions. sdlapci.h WANPIPE PCI definitions diff --git a/trunk/Documentation/pci.txt b/trunk/Documentation/pci.txt index e2c9d0a0c43d..cdf2f3c0ab14 100644 --- a/trunk/Documentation/pci.txt +++ b/trunk/Documentation/pci.txt @@ -124,6 +124,10 @@ initialization with a pointer to a structure describing the driver err_handler See Documentation/pci-error-recovery.txt + multithread_probe Enable multi-threaded probe/scan. Driver must + provide its own locking/syncronization for init + operations if this is enabled. + The ID table is an array of struct pci_device_id entries ending with an all-zero entry. Each entry consists of: @@ -159,9 +163,9 @@ echo "vendor device subvendor subdevice class class_mask driver_data" > \ /sys/bus/pci/drivers/{driver}/new_id All fields are passed in as hexadecimal values (no leading 0x). -The vendor and device fields are mandatory, the others are optional. Users -need pass only as many optional fields as necessary: - o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF) +Users need pass only as many fields as necessary: + o vendor, device, subvendor, and subdevice fields default + to PCI_ANY_ID (FFFFFFFF), o class and classmask fields default to 0 o driver_data defaults to 0UL. @@ -545,6 +549,8 @@ pci_find_slot() Find pci_dev corresponding to given bus and pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) pci_find_capability() Find specified capability in device's capability list. +pci_module_init() Inline helper function for ensuring correct + pci_driver initialization and error handling. pci_resource_start() Returns bus start address for a given PCI region pci_resource_end() Returns bus end address for a given PCI region pci_resource_len() Returns the byte length of a PCI region diff --git a/trunk/Documentation/power/interface.txt b/trunk/Documentation/power/interface.txt index 8c5b41bf3f36..74311d7e0f3c 100644 --- a/trunk/Documentation/power/interface.txt +++ b/trunk/Documentation/power/interface.txt @@ -18,10 +18,17 @@ states. /sys/power/disk controls the operating mode of the suspend-to-disk -mechanism. Suspend-to-disk can be handled in several ways. We have a -few options for putting the system to sleep - using the platform driver -(e.g. ACPI or other pm_ops), powering off the system or rebooting the -system (for testing). +mechanism. Suspend-to-disk can be handled in several ways. The +greatest distinction is who writes memory to disk - the firmware or +the kernel. If the firmware does it, we assume that it also handles +suspending the system. + +If the kernel does it, then we have three options for putting the system +to sleep - using the platform driver (e.g. ACPI or other PM +registers), powering off the system or rebooting the system (for +testing). The system will support either 'firmware' or 'platform', and +that is known a priori. But, the user may choose 'shutdown' or +'reboot' as alternatives. Additionally, /sys/power/disk can be used to turn on one of the two testing modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the @@ -37,12 +44,16 @@ is being slow and which device drivers are misbehaving. Reading from this file will display what the mode is currently set to. Writing to this file will accept one of - 'platform' (only if the platform supports it) + 'firmware' + 'platform' 'shutdown' 'reboot' 'testproc' 'test' +It will only change to 'firmware' or 'platform' if the system supports +it. + /sys/power/image_size controls the size of the image created by the suspend-to-disk mechanism. It can be written a string representing a non-negative integer that will be used as an upper diff --git a/trunk/Documentation/power/pci.txt b/trunk/Documentation/power/pci.txt index e00b099a4b86..b6a3cbf7e846 100644 --- a/trunk/Documentation/power/pci.txt +++ b/trunk/Documentation/power/pci.txt @@ -203,7 +203,7 @@ resume Usage: -if (dev->driver && dev->driver->resume) +if (dev->driver && dev->driver->suspend) dev->driver->resume(dev) The resume callback may be called from any power state, and is always meant to diff --git a/trunk/Documentation/power/states.txt b/trunk/Documentation/power/states.txt index 34800cc521bf..0931a330d362 100644 --- a/trunk/Documentation/power/states.txt +++ b/trunk/Documentation/power/states.txt @@ -62,18 +62,17 @@ setup via another operating system for it to use. Despite the inconvenience, this method requires minimal work by the kernel, since the firmware will also handle restoring memory contents on resume. -For suspend-to-disk, a mechanism called swsusp called 'swsusp' (Swap -Suspend) is used to write memory contents to free swap space. -swsusp has some restrictive requirements, but should work in most -cases. Some, albeit outdated, documentation can be found in -Documentation/power/swsusp.txt. Alternatively, userspace can do most -of the actual suspend to disk work, see userland-swsusp.txt. +If the kernel is responsible for persistently saving state, a mechanism +called 'swsusp' (Swap Suspend) is used to write memory contents to +free swap space. swsusp has some restrictive requirements, but should +work in most cases. Some, albeit outdated, documentation can be found +in Documentation/power/swsusp.txt. Once memory state is written to disk, the system may either enter a low-power state (like ACPI S4), or it may simply power down. Powering down offers greater savings, and allows this mechanism to work on any system. However, entering a real low-power state allows the user to -trigger wake up events (e.g. pressing a key or opening a laptop lid). +trigger wake up events (e.g. pressing a key or opening a laptop lid). A transition from Suspend-to-Disk to the On state should take about 30 seconds, though it's typically a bit more with the current diff --git a/trunk/Documentation/power/swsusp.txt b/trunk/Documentation/power/swsusp.txt index c55bd5079b90..0761ff6c57ed 100644 --- a/trunk/Documentation/power/swsusp.txt +++ b/trunk/Documentation/power/swsusp.txt @@ -156,7 +156,8 @@ instead set the PF_NOFREEZE process flag when creating the thread (and be very careful). -Q: What is the difference between "platform" and "shutdown"? +Q: What is the difference between "platform", "shutdown" and +"firmware" in /sys/power/disk? A: @@ -165,8 +166,11 @@ shutdown: save state in linux, then tell bios to powerdown platform: save state in linux, then tell bios to powerdown and blink "suspended led" -"platform" is actually right thing to do where supported, but -"shutdown" is most reliable (except on ACPI systems). +firmware: tell bios to save state itself [needs BIOS-specific suspend + partition, and has very little to do with swsusp] + +"platform" is actually right thing to do, but "shutdown" is most +reliable. Q: I do not understand why you have such strong objections to idea of selective suspend. @@ -384,8 +388,8 @@ while the system is asleep, maintaining the connection, using true sleep modes like "suspend-to-RAM" or "standby". (Don't write "disk" to the /sys/power/state file; write "standby" or "mem".) We've not seen any hardware that can use these modes through software suspend, although in -theory some systems might support "platform" modes that won't break the -USB connections. +theory some systems might support "platform" or "firmware" modes that +won't break the USB connections. Remember that it's always a bad idea to unplug a disk drive containing a mounted filesystem. That's true even when your system is asleep! The diff --git a/trunk/Documentation/powerpc/booting-without-of.txt b/trunk/Documentation/powerpc/booting-without-of.txt index 033a3f3b3ab7..b41397d6430a 100644 --- a/trunk/Documentation/powerpc/booting-without-of.txt +++ b/trunk/Documentation/powerpc/booting-without-of.txt @@ -39,7 +39,7 @@ and property data. The old style variable alignment would make it impossible to do "simple" insertion of properties using - memmove (thanks Milton for + memove (thanks Milton for noticing). Updated kernel patch as well - Correct a few more alignment constraints - Add a chapter about the device-tree @@ -55,7 +55,7 @@ ToDo: - Add some definitions of interrupt tree (simple/complex) - - Add some definitions for PCI host bridges + - Add some definitions for pci host bridges - Add some common address format examples - Add definitions for standard properties and "compatible" names for cells that are not already defined by the existing @@ -114,7 +114,7 @@ it with special cases. forth words isn't required), you can enter the kernel with: r5 : OF callback pointer as defined by IEEE 1275 - bindings to powerpc. Only the 32-bit client interface + bindings to powerpc. Only the 32 bit client interface is currently supported r3, r4 : address & length of an initrd if any or 0 @@ -194,7 +194,7 @@ it with special cases. for this is to keep kernels on embedded systems small and efficient; part of this is due to the fact the code is already that way. In the future, a kernel may support multiple platforms, but only if the - platforms feature the same core architecture. A single kernel build + platforms feature the same core architectire. A single kernel build cannot support both configurations with Book E and configurations with classic Powerpc architectures. @@ -215,7 +215,7 @@ of the boot sequences.... someone speak up if this is wrong! enable another config option to select the specific board supported. -NOTE: If Ben doesn't merge the setup files, may need to change this to +NOTE: If ben doesn't merge the setup files, may need to change this to point to setup_32.c @@ -256,7 +256,7 @@ struct boot_param_header { u32 off_dt_struct; /* offset to structure */ u32 off_dt_strings; /* offset to strings */ u32 off_mem_rsvmap; /* offset to memory reserve map - */ +*/ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ @@ -265,9 +265,6 @@ struct boot_param_header { booting on */ /* version 3 fields below */ u32 size_dt_strings; /* size of the strings block */ - - /* version 17 fields below */ - u32 size_dt_struct; /* size of the DT structure block */ }; Along with the constants: @@ -276,7 +273,7 @@ struct boot_param_header { #define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name - */ +*/ #define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_PROP 0x3 /* Property: name off, size, content */ @@ -313,8 +310,9 @@ struct boot_param_header { - off_mem_rsvmap This is an offset from the beginning of the header to the start - of the reserved memory map. This map is a list of pairs of 64- + of the reserved memory map. This map is a list of pairs of 64 bit integers. Each pair is a physical address and a size. The + list is terminated by an entry of size 0. This map provides the kernel with a list of physical memory areas that are "reserved" and thus not to be used for memory allocations, especially during @@ -327,7 +325,7 @@ struct boot_param_header { contain _at least_ this DT block itself (header,total_size). If you are passing an initrd to the kernel, you should reserve it as well. You do not need to reserve the kernel image itself. The map - should be 64-bit aligned. + should be 64 bit aligned. - version @@ -337,13 +335,10 @@ struct boot_param_header { to reallocate it easily at boot and free up the unused flattened structure after expansion. Version 16 introduces a new more "compact" format for the tree itself that is however not backward - compatible. Version 17 adds an additional field, size_dt_struct, - allowing it to be reallocated or moved more easily (this is - particularly useful for bootloaders which need to make - adjustments to a device tree based on probed information). You - should always generate a structure of the highest version defined - at the time of your implementation. Currently that is version 17, - unless you explicitly aim at being backward compatible. + compatible. You should always generate a structure of the highest + version defined at the time of your implementation. Currently + that is version 16, unless you explicitly aim at being backward + compatible. - last_comp_version @@ -352,7 +347,7 @@ struct boot_param_header { is backward compatible with version 1 (that is, a kernel build for version 1 will be able to boot with a version 2 format). You should put a 1 in this field if you generate a device tree of - version 1 to 3, or 16 if you generate a tree of version 16 or 17 + version 1 to 3, or 0x10 if you generate a tree of version 0x10 using the new unit name format. - boot_cpuid_phys @@ -365,17 +360,6 @@ struct boot_param_header { point (see further chapters for more informations on the required device-tree contents) - - size_dt_strings - - This field only exists on version 3 and later headers. It - gives the size of the "strings" section of the device tree (which - starts at the offset given by off_dt_strings). - - - size_dt_struct - - This field only exists on version 17 and later headers. It gives - the size of the "structure" section of the device tree (which - starts at the offset given by off_dt_struct). So the typical layout of a DT block (though the various parts don't need to be in that order) looks like this (addresses go from top to @@ -433,7 +417,7 @@ root node who has no parent. A node has 2 names. The actual node name is generally contained in a property of type "name" in the node property list whose value is a zero terminated string and is mandatory for version 1 to 3 of the -format definition (as it is in Open Firmware). Version 16 makes it +format definition (as it is in Open Firmware). Version 0x10 makes it optional as it can generate it from the unit name defined below. There is also a "unit name" that is used to differentiate nodes with @@ -477,7 +461,7 @@ referencing another node via "phandle" is when laying out the interrupt tree which will be described in a further version of this document. -This "linux, phandle" property is a 32-bit value that uniquely +This "linux, phandle" property is a 32 bit value that uniquely identifies a node. You are free to use whatever values or system of values, internal pointers, or whatever to generate these, the only requirement is that every node for which you provide that property has @@ -487,7 +471,7 @@ Here is an example of a simple device-tree. In this example, an "o" designates a node followed by the node unit name. Properties are presented with their name followed by their content. "content" represents an ASCII string (zero terminated) value, while -represents a 32-bit hexadecimal value. The various nodes in this +represents a 32 bit hexadecimal value. The various nodes in this example will be discussed in a later chapter. At this point, it is only meant to give you a idea of what a device-tree looks like. I have purposefully kept the "name" and "linux,phandle" properties which @@ -559,15 +543,15 @@ Here's the basic structure of a single node: * [align gap to next 4 bytes boundary] * for each property: * token OF_DT_PROP (that is 0x00000003) - * 32-bit value of property value size in bytes (or 0 if no - value) - * 32-bit value of offset in string block of property name + * 32 bit value of property value size in bytes (or 0 of no + * value) + * 32 bit value of offset in string block of property name * property value data if any * [align gap to next 4 bytes boundary] * [child nodes if any] * token OF_DT_END_NODE (that is 0x00000002) -So the node content can be summarized as a start token, a full path, +So the node content can be summarised as a start token, a full path, a list of properties, a list of child nodes, and an end token. Every child node is a full node structure itself as defined above. @@ -599,7 +583,7 @@ provide those properties yourself. ---------------------------------------------- The general rule is documented in the various Open Firmware -documentations. If you choose to describe a bus with the device-tree +documentations. If you chose to describe a bus with the device-tree and there exist an OF bus binding, then you should follow the specification. However, the kernel does not require every single device or bus to be described by the device tree. @@ -612,9 +596,9 @@ those properties defining addresses format for devices directly mapped on the processor bus. Those 2 properties define 'cells' for representing an address and a -size. A "cell" is a 32-bit number. For example, if both contain 2 +size. A "cell" is a 32 bit number. For example, if both contain 2 like the example tree given above, then an address and a size are both -composed of 2 cells, and each is a 64-bit number (cells are +composed of 2 cells, and each is a 64 bit number (cells are concatenated and expected to be in big endian format). Another example is the way Apple firmware defines them, with 2 cells for an address and one cell for a size. Most 32-bit implementations should define @@ -648,7 +632,7 @@ prom_parse.c file of the recent kernels for your bus type. The "reg" property only defines addresses and sizes (if #size-cells is non-0) within a given bus. In order to translate addresses upward -(that is into parent bus addresses, and possibly into CPU physical +(that is into parent bus addresses, and possibly into cpu physical addresses), all busses must contain a "ranges" property. If the "ranges" property is missing at a given level, it's assumed that translation isn't possible. The format of the "ranges" property for a @@ -664,9 +648,9 @@ example, for a PCI host controller, that would be a CPU address. For a PCI<->ISA bridge, that would be a PCI address. It defines the base address in the parent bus where the beginning of that range is mapped. -For a new 64-bit powerpc board, I recommend either the 2/2 format or +For a new 64 bit powerpc board, I recommend either the 2/2 format or Apple's 2/1 format which is slightly more compact since sizes usually -fit in a single 32-bit word. New 32-bit powerpc boards should use a +fit in a single 32 bit word. New 32 bit powerpc boards should use a 1/1 format, unless the processor supports physical addresses greater than 32-bits, in which case a 2/1 format is recommended. @@ -780,7 +764,7 @@ address which can extend beyond that limit. Required properties: - device_type : has to be "cpu" - - reg : This is the physical CPU number, it's a single 32-bit cell + - reg : This is the physical cpu number, it's a single 32 bit cell and is also used as-is as the unit number for constructing the unit name in the full path. For example, with 2 CPUs, you would have the full path: @@ -801,7 +785,7 @@ address which can extend beyond that limit. the kernel timebase/decrementer calibration based on this value. - clock-frequency : a cell indicating the CPU core clock frequency - in Hz. A new property will be defined for 64-bit values, but if + in Hz. A new property will be defined for 64 bit values, but if your frequency is < 4Ghz, one cell is enough. Here as well as for the above, the common code doesn't use that property, but you are welcome to re-use the pSeries or Maple one. A future @@ -848,7 +832,8 @@ address which can extend beyond that limit. This node is a bit "special". Normally, that's where open firmware puts some variable environment information, like the arguments, or - the default input/output devices. + phandle pointers to nodes like the main interrupt controller, or the + default input/output devices. This specification makes a few of these mandatory, but also defines some linux-specific properties that would be normally constructed by @@ -868,14 +853,14 @@ address which can extend beyond that limit. that the kernel tries to find out the default console and has knowledge of various types like 8250 serial ports. You may want to extend this function to add your own. + - interrupt-controller : This is one cell containing a phandle + value that matches the "linux,phandle" property of your main + interrupt controller node. May be used for interrupt routing. + Note that u-boot creates and fills in the chosen node for platforms that use it. - (Note: a practice that is now obsolete was to include a property - under /chosen called interrupt-controller which had a phandle value - that pointed to the main interrupt controller) - f) the /soc node This node is used to represent a system-on-a-chip (SOC) and must be @@ -923,7 +908,8 @@ address which can extend beyond that limit. The SOC node may contain child nodes for each SOC device that the platform uses. Nodes should not be created for devices which exist on the SOC but are not used by a particular platform. See chapter VI - for more information on how to specify devices that are part of a SOC. + for more information on how to specify devices that are part of an +SOC. Example SOC node for the MPC8540: @@ -986,7 +972,7 @@ The syntax of the dtc tool is [-o output-filename] [-V output_version] input_filename -The "output_version" defines what version of the "blob" format will be +The "output_version" defines what versio of the "blob" format will be generated. Supported versions are 1,2,3 and 16. The default is currently version 3 but that may change in the future to version 16. @@ -1008,12 +994,12 @@ supported currently at the toplevel. */ property2 = <1234abcd>; /* define a property containing a - * numerical 32-bit value (hexadecimal) + * numerical 32 bits value (hexadecimal) */ property3 = <12345678 12345678 deadbeef>; /* define a property containing 3 - * numerical 32-bit values (cells) in + * numerical 32 bits values (cells) in * hexadecimal */ property4 = [0a 0b 0c 0d de ea ad be ef]; @@ -1082,7 +1068,7 @@ while all this has been defined and implemented. its usage in early_init_devtree(), and the corresponding various early_init_dt_scan_*() callbacks. That code can be re-used in a GPL bootloader, and as the author of that code, I would be happy - to discuss possible free licensing to any vendor who wishes to + to discuss possible free licencing to any vendor who wishes to integrate all or part of this code into a non-GPL bootloader. @@ -1091,7 +1077,7 @@ VI - System-on-a-chip devices and nodes ======================================= Many companies are now starting to develop system-on-a-chip -processors, where the processor core (CPU) and many peripheral devices +processors, where the processor core (cpu) and many peripheral devices exist on a single piece of silicon. For these SOCs, an SOC node should be used that defines child nodes for the devices that make up the SOC. While platforms are not required to use this model in @@ -1123,7 +1109,42 @@ See appendix A for an example partial SOC node definition for the MPC8540. -2) Representing devices without a current OF specification +2) Specifying interrupt information for SOC devices +--------------------------------------------------- + +Each device that is part of an SOC and which generates interrupts +should have the following properties: + + - interrupt-parent : contains the phandle of the interrupt + controller which handles interrupts for this device + - interrupts : a list of tuples representing the interrupt + number and the interrupt sense and level for each interrupt + for this device. + +This information is used by the kernel to build the interrupt table +for the interrupt controllers in the system. + +Sense and level information should be encoded as follows: + + Devices connected to openPIC-compatible controllers should encode + sense and polarity as follows: + + 0 = low to high edge sensitive type enabled + 1 = active low level sensitive type enabled + 2 = active high level sensitive type enabled + 3 = high to low edge sensitive type enabled + + ISA PIC interrupt controllers should adhere to the ISA PIC + encodings listed below: + + 0 = active low level sensitive type enabled + 1 = active high level sensitive type enabled + 2 = high to low edge sensitive type enabled + 3 = low to high edge sensitive type enabled + + + +3) Representing devices without a current OF specification ---------------------------------------------------------- Currently, there are many devices on SOCs that do not have a standard @@ -1180,13 +1201,6 @@ platforms are moved over to use the flattened-device-tree model. - phy-handle : The phandle for the PHY connected to this ethernet controller. - Recommended properties: - - - linux,network-index : This is the intended "index" of this - network device. This is used by the bootwrapper to interpret - MAC addresses passed by the firmware when no information other - than indices is available to associate an address with a device. - Example: ethernet@24000 { @@ -1298,10 +1312,10 @@ platforms are moved over to use the flattened-device-tree model. and additions : Required properties : - - compatible : Should be "fsl-usb2-mph" for multi port host USB - controllers, or "fsl-usb2-dr" for dual role USB controllers - - phy_type : For multi port host USB controllers, should be one of - "ulpi", or "serial". For dual role USB controllers, should be + - compatible : Should be "fsl-usb2-mph" for multi port host usb + controllers, or "fsl-usb2-dr" for dual role usb controllers + - phy_type : For multi port host usb controllers, should be one of + "ulpi", or "serial". For dual role usb controllers, should be one of "ulpi", "utmi", "utmi_wide", or "serial". - reg : Offset and length of the register set for the device - port0 : boolean; if defined, indicates port0 is connected for @@ -1325,7 +1339,7 @@ platforms are moved over to use the flattened-device-tree model. - interrupt-parent : the phandle for the interrupt controller that services interrupts for this device. - Example multi port host USB controller device node : + Example multi port host usb controller device node : usb@22000 { device_type = "usb"; compatible = "fsl-usb2-mph"; @@ -1339,7 +1353,7 @@ platforms are moved over to use the flattened-device-tree model. port1; }; - Example dual role USB controller device node : + Example dual role usb controller device node : usb@23000 { device_type = "usb"; compatible = "fsl-usb2-dr"; @@ -1373,7 +1387,7 @@ platforms are moved over to use the flattened-device-tree model. - channel-fifo-len : An integer representing the number of descriptor pointers each channel fetch fifo can hold. - exec-units-mask : The bitmask representing what execution units - (EUs) are available. It's a single 32-bit cell. EU information + (EUs) are available. It's a single 32 bit cell. EU information should be encoded following the SEC's Descriptor Header Dword EU_SEL0 field documentation, i.e. as follows: @@ -1389,7 +1403,7 @@ platforms are moved over to use the flattened-device-tree model. bits 8 through 31 are reserved for future SEC EUs. - descriptor-types-mask : The bitmask representing what descriptors - are available. It's a single 32-bit cell. Descriptor type + are available. It's a single 32 bit cell. Descriptor type information should be encoded following the SEC's Descriptor Header Dword DESC_TYPE field documentation, i.e. as follows: @@ -1478,7 +1492,7 @@ platforms are moved over to use the flattened-device-tree model. Required properties: - device_type : should be "spi". - compatible : should be "fsl_spi". - - mode : the SPI operation mode, it can be "cpu" or "qe". + - mode : the spi operation mode, it can be "cpu" or "qe". - reg : Offset and length of the register set for the device - interrupts : where a is the interrupt number and b is a field that represents an encoding of the sense and level @@ -1555,12 +1569,6 @@ platforms are moved over to use the flattened-device-tree model. - mac-address : list of bytes representing the ethernet address. - phy-handle : The phandle for the PHY connected to this controller. - Recommended properties: - - linux,network-index : This is the intended "index" of this - network device. This is used by the bootwrapper to interpret - MAC addresses passed by the firmware when no information other - than indices is available to associate an address with a device. - Example: ucc@2000 { device_type = "network"; @@ -1704,7 +1712,7 @@ platforms are moved over to use the flattened-device-tree model. - partitions : Several pairs of 32-bit values where the first value is partition's offset from the start of the device and the second one is partition size in bytes with LSB used to signify a read only - partition (so, the partition size should always be an even number). + partition (so, the parition size should always be an even number). - partition-names : The list of concatenated zero terminated strings representing the partition names. - probe-type : The type of probe which should be done for the chip @@ -1725,92 +1733,6 @@ platforms are moved over to use the flattened-device-tree model. More devices will be defined as this spec matures. -VII - Specifying interrupt information for devices -=================================================== - -The device tree represents the busses and devices of a hardware -system in a form similar to the physical bus topology of the -hardware. - -In addition, a logical 'interrupt tree' exists which represents the -hierarchy and routing of interrupts in the hardware. - -The interrupt tree model is fully described in the -document "Open Firmware Recommended Practice: Interrupt -Mapping Version 0.9". The document is available at: -. - -1) interrupts property ----------------------- - -Devices that generate interrupts to a single interrupt controller -should use the conventional OF representation described in the -OF interrupt mapping documentation. - -Each device which generates interrupts must have an 'interrupt' -property. The interrupt property value is an arbitrary number of -of 'interrupt specifier' values which describe the interrupt or -interrupts for the device. - -The encoding of an interrupt specifier is determined by the -interrupt domain in which the device is located in the -interrupt tree. The root of an interrupt domain specifies in -its #interrupt-cells property the number of 32-bit cells -required to encode an interrupt specifier. See the OF interrupt -mapping documentation for a detailed description of domains. - -For example, the binding for the OpenPIC interrupt controller -specifies an #interrupt-cells value of 2 to encode the interrupt -number and level/sense information. All interrupt children in an -OpenPIC interrupt domain use 2 cells per interrupt in their interrupts -property. - -The PCI bus binding specifies a #interrupt-cell value of 1 to encode -which interrupt pin (INTA,INTB,INTC,INTD) is used. - -2) interrupt-parent property ----------------------------- - -The interrupt-parent property is specified to define an explicit -link between a device node and its interrupt parent in -the interrupt tree. The value of interrupt-parent is the -phandle of the parent node. - -If the interrupt-parent property is not defined for a node, it's -interrupt parent is assumed to be an ancestor in the node's -_device tree_ hierarchy. - -3) OpenPIC Interrupt Controllers --------------------------------- - -OpenPIC interrupt controllers require 2 cells to encode -interrupt information. The first cell defines the interrupt -number. The second cell defines the sense and level -information. - -Sense and level information should be encoded as follows: - - 0 = low to high edge sensitive type enabled - 1 = active low level sensitive type enabled - 2 = active high level sensitive type enabled - 3 = high to low edge sensitive type enabled - -4) ISA Interrupt Controllers ----------------------------- - -ISA PIC interrupt controllers require 2 cells to encode -interrupt information. The first cell defines the interrupt -number. The second cell defines the sense and level -information. - -ISA PIC interrupt controllers should adhere to the ISA PIC -encodings listed below: - - 0 = active low level sensitive type enabled - 1 = active high level sensitive type enabled - 2 = high to low edge sensitive type enabled - 3 = low to high edge sensitive type enabled - Appendix A - Sample SOC node for MPC8540 ======================================== diff --git a/trunk/Documentation/s390/crypto/crypto-API.txt b/trunk/Documentation/s390/crypto/crypto-API.txt new file mode 100644 index 000000000000..71ae6ca9f2c2 --- /dev/null +++ b/trunk/Documentation/s390/crypto/crypto-API.txt @@ -0,0 +1,83 @@ +crypto-API support for z990 Message Security Assist (MSA) instructions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +AUTHOR: Thomas Spatzier (tspat@de.ibm.com) + + +1. Introduction crypto-API +~~~~~~~~~~~~~~~~~~~~~~~~~~ +See Documentation/crypto/api-intro.txt for an introduction/description of the +kernel crypto API. +According to api-intro.txt support for z990 crypto instructions has been added +in the algorithm api layer of the crypto API. Several files containing z990 +optimized implementations of crypto algorithms are placed in the +arch/s390/crypto directory. + + +2. Probing for availability of MSA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It should be possible to use Kernels with the z990 crypto implementations both +on machines with MSA available and on those without MSA (pre z990 or z990 +without MSA). Therefore a simple probing mechanism has been implemented: +In the init function of each crypto module the availability of MSA and of the +respective crypto algorithm in particular will be tested. If the algorithm is +available the module will load and register its algorithm with the crypto API. + +If the respective crypto algorithm is not available, the init function will +return -ENOSYS. In that case a fallback to the standard software implementation +of the crypto algorithm must be taken ( -> the standard crypto modules are +also built when compiling the kernel). + + +3. Ensuring z990 crypto module preference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If z990 crypto instructions are available the optimized modules should be +preferred instead of standard modules. + +3.1. compiled-in modules +~~~~~~~~~~~~~~~~~~~~~~~~ +For compiled-in modules it has to be ensured that the z990 modules are linked +before the standard crypto modules. Then, on system startup the init functions +of z990 crypto modules will be called first and query for availability of z990 +crypto instructions. If instruction is available, the z990 module will register +its crypto algorithm implementation -> the load of the standard module will fail +since the algorithm is already registered. +If z990 crypto instruction is not available the load of the z990 module will +fail -> the standard module will load and register its algorithm. + +3.2. dynamic modules +~~~~~~~~~~~~~~~~~~~~ +A system administrator has to take care of giving preference to z990 crypto +modules. If MSA is available appropriate lines have to be added to +/etc/modprobe.conf. + +Example: z990 crypto instruction for SHA1 algorithm is available + + add the following line to /etc/modprobe.conf (assuming the + z990 crypto modules for SHA1 is called sha1_z990): + + alias sha1 sha1_z990 + + -> when the sha1 algorithm is requested through the crypto API + (which has a module autoloader) the z990 module will be loaded. + +TBD: a userspace module probing mechanism + something like 'probe sha1 sha1_z990 sha1' in modprobe.conf + -> try module sha1_z990, if it fails to load standard module sha1 + the 'probe' statement is currently not supported in modprobe.conf + + +4. Currently implemented z990 crypto algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following crypto algorithms with z990 MSA support are currently implemented. +The name of each algorithm under which it is registered in crypto API and the +name of the respective module is given in square brackets. + +- SHA1 Digest Algorithm [sha1 -> sha1_z990] +- DES Encrypt/Decrypt Algorithm (64bit key) [des -> des_z990] +- Triple DES Encrypt/Decrypt Algorithm (128bit key) [des3_ede128 -> des_z990] +- Triple DES Encrypt/Decrypt Algorithm (192bit key) [des3_ede -> des_z990] + +In order to load, for example, the sha1_z990 module when the sha1 algorithm is +requested (see 3.2.) add 'alias sha1 sha1_z990' to /etc/modprobe.conf. + diff --git a/trunk/Documentation/s390/zfcpdump.txt b/trunk/Documentation/s390/zfcpdump.txt deleted file mode 100644 index cf45d27c4608..000000000000 --- a/trunk/Documentation/s390/zfcpdump.txt +++ /dev/null @@ -1,87 +0,0 @@ -s390 SCSI dump tool (zfcpdump) - -System z machines (z900 or higher) provide hardware support for creating system -dumps on SCSI disks. The dump process is initiated by booting a dump tool, which -has to create a dump of the current (probably crashed) Linux image. In order to -not overwrite memory of the crashed Linux with data of the dump tool, the -hardware saves some memory plus the register sets of the boot cpu before the -dump tool is loaded. There exists an SCLP hardware interface to obtain the saved -memory afterwards. Currently 32 MB are saved. - -This zfcpdump implementation consists of a Linux dump kernel together with -a userspace dump tool, which are loaded together into the saved memory region -below 32 MB. zfcpdump is installed on a SCSI disk using zipl (as contained in -the s390-tools package) to make the device bootable. The operator of a Linux -system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump -resides on. - -The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem", -which exports memory and registers of the crashed Linux in an s390 -standalone dump format. It can be used in the same way as e.g. /dev/mem. The -dump format defines a 4K header followed by plain uncompressed memory. The -register sets are stored in the prefix pages of the respective cpus. To build a -dump enabled kernel with the zcore driver, the kernel config option -CONFIG_ZFCPDUMP has to be set. When reading from "zcore/mem", the part of -memory, which has been saved by hardware is read by the driver via the SCLP -hardware interface. The second part is just copied from the non overwritten real -memory. - -The userspace application of zfcpdump can reside e.g. in an intitramfs or an -initrd. It reads from zcore/mem and writes the system dump to a file on a -SCSI disk. - -To build a zfcpdump kernel use the following settings in your kernel -configuration: - * CONFIG_ZFCPDUMP=y - * Enable ZFCP driver - * Enable SCSI driver - * Enable ext2 and ext3 filesystems - * Disable as many features as possible to keep the kernel small. - E.g. network support is not needed at all. - -To use the zfcpdump userspace application in an initramfs you have to do the -following: - - * Copy the zfcpdump executable somewhere into your Linux tree. - E.g. to "arch/s390/boot/zfcpdump. If you do not want to include - shared libraries, compile the tool with the "-static" gcc option. - * If you want to include e2fsck, add it to your source tree, too. The zfcpdump - application attempts to start /sbin/e2fsck from the ramdisk. - * Use an initramfs config file like the following: - - dir /dev 755 0 0 - nod /dev/console 644 0 0 c 5 1 - nod /dev/null 644 0 0 c 1 3 - nod /dev/sda1 644 0 0 b 8 1 - nod /dev/sda2 644 0 0 b 8 2 - nod /dev/sda3 644 0 0 b 8 3 - nod /dev/sda4 644 0 0 b 8 4 - nod /dev/sda5 644 0 0 b 8 5 - nod /dev/sda6 644 0 0 b 8 6 - nod /dev/sda7 644 0 0 b 8 7 - nod /dev/sda8 644 0 0 b 8 8 - nod /dev/sda9 644 0 0 b 8 9 - nod /dev/sda10 644 0 0 b 8 10 - nod /dev/sda11 644 0 0 b 8 11 - nod /dev/sda12 644 0 0 b 8 12 - nod /dev/sda13 644 0 0 b 8 13 - nod /dev/sda14 644 0 0 b 8 14 - nod /dev/sda15 644 0 0 b 8 15 - file /init arch/s390/boot/zfcpdump 755 0 0 - file /sbin/e2fsck arch/s390/boot/e2fsck 755 0 0 - dir /proc 755 0 0 - dir /sys 755 0 0 - dir /mnt 755 0 0 - dir /sbin 755 0 0 - - * Issue "make image" to build the zfcpdump image with initramfs. - -In a Linux distribution the zfcpdump enabled kernel image must be copied to -/usr/share/zfcpdump/zfcpdump.image, where the s390 zipl tool is looking for the -dump kernel when preparing a SCSI dump disk. - -If you use a ramdisk copy it to "/usr/share/zfcpdump/zfcpdump.rd". - -For more information on how to use zfcpdump refer to the s390 'Using the Dump -Tools book', which is available from -http://www.ibm.com/developerworks/linux/linux390. diff --git a/trunk/Documentation/scsi/aacraid.txt b/trunk/Documentation/scsi/aacraid.txt index 2368e7e4a8cf..dc8e44fc650f 100644 --- a/trunk/Documentation/scsi/aacraid.txt +++ b/trunk/Documentation/scsi/aacraid.txt @@ -37,11 +37,7 @@ Supported Cards/Chipsets 9005:0286:9005:029d Adaptec 2420SA (Intruder HP release) 9005:0286:9005:02ac Adaptec 1800 (Typhoon44) 9005:0285:9005:02b5 Adaptec 5445 (Voodoo44) - 9005:0285:15d9:02b5 SMC AOC-USAS-S4i - 9005:0285:15d9:02c9 SMC AOC-USAS-S4iR 9005:0285:9005:02b6 Adaptec 5805 (Voodoo80) - 9005:0285:15d9:02b6 SMC AOC-USAS-S8i - 9005:0285:15d9:02ca SMC AOC-USAS-S8iR 9005:0285:9005:02b7 Adaptec 5085 (Voodoo08) 9005:0285:9005:02bb Adaptec 3405 (Marauder40LP) 9005:0285:9005:02bc Adaptec 3805 (Marauder80LP) @@ -97,9 +93,6 @@ Supported Cards/Chipsets 9005:0286:9005:02ae (Aurora Lite ARK) 9005:0285:9005:02b0 (Sunrise Lake ARK) 9005:0285:9005:02b1 Adaptec (Voodoo 8 internal 8 external) - 9005:0285:108e:7aac SUN STK RAID REM (Voodoo44 Coyote) - 9005:0285:108e:0286 SUN SG-XPCIESAS-R-IN (Cougar) - 9005:0285:108e:0287 SUN SG-XPCIESAS-R-EX (Prometheus) People ------------------------- diff --git a/trunk/Documentation/scsi/ncr53c8xx.txt b/trunk/Documentation/scsi/ncr53c8xx.txt index 88ef88b949f7..caf10b155185 100644 --- a/trunk/Documentation/scsi/ncr53c8xx.txt +++ b/trunk/Documentation/scsi/ncr53c8xx.txt @@ -562,6 +562,11 @@ if only one has a flaw for some SCSI feature, you can disable the support by the driver of this feature at linux start-up and enable this feature after boot-up only for devices that support it safely. +CONFIG_SCSI_NCR53C8XX_PROFILE_SUPPORT (default answer: n) + This option must be set for profiling information to be gathered + and printed out through the proc file system. This features may + impact performances. + CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n) Answer "y" if you suspect your mother board to not allow memory mapped I/O. May slow down performance a little. This option is required by diff --git a/trunk/Documentation/sony-laptop.txt b/trunk/Documentation/sony-laptop.txt index 7a5c1a81905c..dfd26df056f4 100644 --- a/trunk/Documentation/sony-laptop.txt +++ b/trunk/Documentation/sony-laptop.txt @@ -3,18 +3,12 @@ Sony Notebook Control Driver (SNC) Readme Copyright (C) 2004- 2005 Stelian Pop Copyright (C) 2007 Mattia Dongili -This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the -Sony Vaio laptops. This driver mixes both devices functions under the same -(hopefully consistent) interface. This also means that the sonypi driver is -obsoleted by sony-laptop now. +This mini-driver drives the SNC device present in the ACPI BIOS of +the Sony Vaio laptops. -Fn keys (hotkeys): ------------------- -Some models report hotkeys through the SNC or SPIC devices, such events are -reported both through the ACPI subsystem as acpi events and through the INPUT -subsystem. See the logs of acpid or /proc/acpi/event and -/proc/bus/input/devices to find out what those events are and which input -devices are created by the driver. +It gives access to some extra laptop functionalities. In its current +form, this driver let the user set or query the screen brightness +through the backlight subsystem and remove/apply power to some devices. Backlight control: ------------------ @@ -45,8 +39,6 @@ The files are: audiopower power on/off the internal sound card lanpower power on/off the internal ethernet card (only in debug mode) - bluetoothpower power on/off the internal bluetooth device - fanspeed get/set the fan speed Note that some files may be missing if they are not supported by your particular laptop model. @@ -84,9 +76,9 @@ The sony-laptop driver creates, for some of those methods (the most current ones found on several Vaio models), an entry under /sys/devices/platform/sony-laptop, just like the 'cdpower' one. You can create other entries corresponding to your own laptop methods by -further editing the source (see the 'sony_nc_values' table, and add a new +further editing the source (see the 'sony_acpi_values' table, and add a new entry to this table with your get/set method names using the -SNC_HANDLE_NAMES macro). +HANDLE_NAMES macro). Your mission, should you accept it, is to try finding out what those entries are for, by reading/writing random values from/to those @@ -95,9 +87,6 @@ files and find out what is the impact on your laptop. Should you find anything interesting, please report it back to me, I will not disavow all knowledge of your actions :) -See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other -useful info. - Bugs/Limitations: ----------------- diff --git a/trunk/Documentation/usb/usb-serial.txt b/trunk/Documentation/usb/usb-serial.txt index b18e86a22506..d61f6e7865de 100644 --- a/trunk/Documentation/usb/usb-serial.txt +++ b/trunk/Documentation/usb/usb-serial.txt @@ -42,7 +42,7 @@ ConnectTech WhiteHEAT 4 port converter http://www.connecttech.com For any questions or problems with this driver, please contact - Connect Tech's Support Department at support@connecttech.com + Stuart MacDonald at stuartm@connecttech.com HandSpring Visor, Palm USB, and Clié USB driver diff --git a/trunk/Documentation/usb/usbmon.txt b/trunk/Documentation/usb/usbmon.txt index 53ae866ae37b..0f6808abd612 100644 --- a/trunk/Documentation/usb/usbmon.txt +++ b/trunk/Documentation/usb/usbmon.txt @@ -16,7 +16,7 @@ situation as with tcpdump. Unlike the packet socket, usbmon has an interface which provides traces in a text format. This is used for two purposes. First, it serves as a -common trace exchange format for tools while more sophisticated formats +common trace exchange format for tools while most sophisticated formats are finalized. Second, humans can read it in case tools are not available. To collect a raw text trace, execute following steps. @@ -34,7 +34,7 @@ if usbmon is built into the kernel. Verify that bus sockets are present. # ls /sys/kernel/debug/usbmon -1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u +1s 1t 2s 2t 3s 3t 4s 4t # 2. Find which bus connects to the desired device @@ -54,7 +54,7 @@ Bus=03 means it's bus 3. 3. Start 'cat' -# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out +# cat /sys/kernel/debug/usbmon/3t > /tmp/1.mon.out This process will be reading until killed. Naturally, the output can be redirected to a desirable location. This is preferred, because it is going @@ -75,80 +75,46 @@ that the file size is not excessive for your favourite editor. * Raw text data format -Two formats are supported currently: the original, or '1t' format, and -the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u' -format adds a few fields, such as ISO frame descriptors, interval, etc. -It produces slightly longer lines, but otherwise is a perfect superset -of '1t' format. - -If it is desired to recognize one from the other in a program, look at the -"address" word (see below), where '1u' format adds a bus number. If 2 colons -are present, it's the '1t' format, otherwise '1u'. - -Any text format data consists of a stream of events, such as URB submission, +The '1t' type data consists of a stream of events, such as URB submission, URB callback, submission error. Every event is a text line, which consists of whitespace separated words. The number or position of words may depend on the event type, but there is a set of words, common for all types. Here is the list of words, from left to right: - - URB Tag. This is used to identify URBs is normally a kernel mode address of the URB structure in hexadecimal. - - Timestamp in microseconds, a decimal number. The timestamp's resolution depends on available clock, and so it can be much worse than a microsecond (if the implementation uses jiffies, for example). - - Event Type. This type refers to the format of the event, not URB type. Available types are: S - submission, C - callback, E - submission error. - -- "Address" word (formerly a "pipe"). It consists of four fields, separated by - colons: URB type and direction, Bus number, Device address, Endpoint number. +- "Pipe". The pipe concept is deprecated. This is a composite word, used to + be derived from information in pipes. It consists of three fields, separated + by colons: URB type and direction, Device address, Endpoint number. Type and direction are encoded with two bytes in the following manner: Ci Co Control input and output Zi Zo Isochronous input and output Ii Io Interrupt input and output Bi Bo Bulk input and output - Bus number, Device address, and Endpoint are decimal numbers, but they may - have leading zeros, for the sake of human readers. - -- URB Status word. This is either a letter, or several numbers separated - by colons: URB status, interval, start frame, and error count. Unlike the - "address" word, all fields save the status are optional. Interval is printed - only for interrupt and isochronous URBs. Start frame is printed only for - isochronous URBs. Error count is printed only for isochronous callback - events. - - The status field is a decimal number, sometimes negative, which represents - a "status" field of the URB. This field makes no sense for submissions, but - is present anyway to help scripts with parsing. When an error occurs, the - field contains the error code. - - In case of a submission of a Control packet, this field contains a Setup Tag - instead of an group of numbers. It is easy to tell whether the Setup Tag is - present because it is never a number. Thus if scripts find a set of numbers - in this word, they proceed to read Data Length (except for isochronous URBs). - If they find something else, like a letter, they read the setup packet before - reading the Data Length or isochronous descriptors. - + Device address and Endpoint number are 3-digit and 2-digit (respectively) + decimal numbers, with leading zeroes. +- URB Status. In most cases, this field contains a number, sometimes negative, + which represents a "status" field of the URB. This field makes no sense for + submissions, but is present anyway to help scripts with parsing. When an + error occurs, the field contains the error code. In case of a submission of + a Control packet, this field contains a Setup Tag instead of an error code. + It is easy to tell whether the Setup Tag is present because it is never a + number. Thus if scripts find a number in this field, they proceed to read + Data Length. If they find something else, like a letter, they read the setup + packet before reading the Data Length. - Setup packet, if present, consists of 5 words: one of each for bmRequestType, bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0. These words are safe to decode if Setup Tag was 's'. Otherwise, the setup packet was present, but not captured, and the fields contain filler. - -- Number of isochronous frame descriptors and descriptors themselves. - If an Isochronous transfer event has a set of descriptors, a total number - of them in an URB is printed first, then a word per descriptor, up to a - total of 5. The word consists of 3 colon-separated decimal numbers for - status, offset, and length respectively. For submissions, initial length - is reported. For callbacks, actual length is reported. - - Data Length. For submissions, this is the requested length. For callbacks, this is the actual length. - - Data tag. The usbmon may not always capture data, even if length is nonzero. The data words are present only if this tag is '='. - - Data words follow, in big endian hexadecimal format. Notice that they are not machine words, but really just a byte stream split into words to make it easier to read. Thus, the last word may contain from one to four bytes. @@ -187,18 +153,20 @@ class ParsedLine { } } +This format may be changed in the future. + Examples: An input control transfer to get a port status. -d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 < -d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000 +d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 < +d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000 An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper to a storage device at address 5: -dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000 -dd65f0e8 4128379808 C Bo:1:005:2 0 31 > +dd65f0e8 4128379752 S Bo:005:02 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000 +dd65f0e8 4128379808 C Bo:005:02 0 31 > * Raw binary format and API diff --git a/trunk/Documentation/video4linux/CARDLIST.bttv b/trunk/Documentation/video4linux/CARDLIST.bttv index b60639130a51..fc2fe9bc6713 100644 --- a/trunk/Documentation/video4linux/CARDLIST.bttv +++ b/trunk/Documentation/video4linux/CARDLIST.bttv @@ -143,5 +143,3 @@ 142 -> Sabrent TV-FM (bttv version) 143 -> Hauppauge ImpactVCB (bt878) [0070:13eb] 144 -> MagicTV -145 -> SSAI Security Video Interface [4149:5353] -146 -> SSAI Ultrasound Video Interface [414a:5353] diff --git a/trunk/Documentation/video4linux/CARDLIST.cx88 b/trunk/Documentation/video4linux/CARDLIST.cx88 index 60f838beb9c8..62e32b49cec9 100644 --- a/trunk/Documentation/video4linux/CARDLIST.cx88 +++ b/trunk/Documentation/video4linux/CARDLIST.cx88 @@ -37,7 +37,7 @@ 36 -> AVerTV 303 (M126) [1461:000a] 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] - 39 -> KWorld DVB-S 100 [17de:08b2,1421:0341] + 39 -> KWorld DVB-S 100 [17de:08b2] 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402] 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802] 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019] diff --git a/trunk/Documentation/video4linux/CARDLIST.ivtv b/trunk/Documentation/video4linux/CARDLIST.ivtv deleted file mode 100644 index ddd76a0eb100..000000000000 --- a/trunk/Documentation/video4linux/CARDLIST.ivtv +++ /dev/null @@ -1,18 +0,0 @@ - 1 -> Hauppauge WinTV PVR-250 - 2 -> Hauppauge WinTV PVR-350 - 3 -> Hauppauge WinTV PVR-150 or PVR-500 - 4 -> AVerMedia M179 [1461:a3ce,1461:a3cf] - 5 -> Yuan MPG600/Kuroutoshikou iTVC16-STVLP [12ab:fff3,12ab:ffff] - 6 -> Yuan MPG160/Kuroutoshikou iTVC15-STVLP [12ab:0000,10fc:40a0] - 7 -> Yuan PG600/DiamondMM PVR-550 [ff92:0070,ffab:0600] - 8 -> Adaptec AVC-2410 [9005:0093] - 9 -> Adaptec AVC-2010 [9005:0092] -10 -> NAGASE TRANSGEAR 5000TV [1461:bfff] -11 -> AOpen VA2000MAX-STN6 [0000:ff5f] -12 -> YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP [12ab:0600,fbab:0600,1154:0523] -13 -> I/O Data GV-MVP/RX [10fc:d01e,10fc:d038,10fc:d039] -14 -> I/O Data GV-MVP/RX2E [10fc:d025] -15 -> GOTVIEW PCI DVD (partial support only) [12ab:0600] -16 -> GOTVIEW PCI DVD2 Deluxe [ffac:0600] -17 -> Yuan MPC622 [ff01:d998] -18 -> Digital Cowboy DCT-MTVP1 [1461:bfff] diff --git a/trunk/Documentation/video4linux/CARDLIST.saa7134 b/trunk/Documentation/video4linux/CARDLIST.saa7134 index d7bb2e2e4d9b..a12246a9bf23 100644 --- a/trunk/Documentation/video4linux/CARDLIST.saa7134 +++ b/trunk/Documentation/video4linux/CARDLIST.saa7134 @@ -53,7 +53,7 @@ 52 -> AverMedia AverTV/305 [1461:2108] 53 -> ASUS TV-FM 7135 [1043:4845] 54 -> LifeView FlyTV Platinum FM / Gold [5168:0214,1489:0214,5168:0304] - 55 -> LifeView FlyDVB-T DUO / MSI TV@nywhere Duo [5168:0306,4E42:0306] + 55 -> LifeView FlyDVB-T DUO [5168:0306] 56 -> Avermedia AVerTV 307 [1461:a70a] 57 -> Avermedia AVerTV GO 007 FM [1461:f31f] 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370] @@ -76,7 +76,7 @@ 75 -> AVerMedia AVerTVHD MCE A180 [1461:1044] 76 -> SKNet MonsterTV Mobile [1131:4ee9] 77 -> Pinnacle PCTV 40i/50i/110i (saa7133) [11bd:002e] - 78 -> ASUSTeK P7131 Dual [1043:4862,1043:4857] + 78 -> ASUSTeK P7131 Dual [1043:4862,1043:4876] 79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B) 80 -> ASUS Digimatrix TV [1043:0210] 81 -> Philips Tiger reference design [1131:2018] @@ -107,7 +107,3 @@ 106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344] 107 -> Encore ENLTV-FM [1131:230f] 108 -> Terratec Cinergy HT PCI [153b:1175] -109 -> Philips Tiger - S Reference design -110 -> Avermedia M102 [1461:f31e] -111 -> ASUS P7131 4871 [1043:4871] -112 -> ASUSTeK P7131 Hybrid [1043:4876] diff --git a/trunk/Documentation/video4linux/CARDLIST.usbvision b/trunk/Documentation/video4linux/CARDLIST.usbvision deleted file mode 100644 index 3d6850ef0245..000000000000 --- a/trunk/Documentation/video4linux/CARDLIST.usbvision +++ /dev/null @@ -1,64 +0,0 @@ - 0 -> Xanboo [0a6f:0400] - 1 -> Belkin USB VideoBus II Adapter [050d:0106] - 2 -> Belkin Components USB VideoBus [050d:0207] - 3 -> Belkin USB VideoBus II [050d:0208] - 4 -> echoFX InterView Lite [0571:0002] - 5 -> USBGear USBG-V1 resp. HAMA USB [0573:0003] - 6 -> D-Link V100 [0573:0400] - 7 -> X10 USB Camera [0573:2000] - 8 -> Hauppauge WinTV USB Live (PAL B/G) [0573:2d00] - 9 -> Hauppauge WinTV USB Live Pro (NTSC M/N) [0573:2d01] - 10 -> Zoran Co. PMD (Nogatech) AV-grabber Manhattan [0573:2101] - 11 -> Nogatech USB-TV (NTSC) FM [0573:4100] - 12 -> PNY USB-TV (NTSC) FM [0573:4110] - 13 -> PixelView PlayTv-USB PRO (PAL) FM [0573:4450] - 14 -> ZTV ZT-721 2.4GHz USB A/V Receiver [0573:4550] - 15 -> Hauppauge WinTV USB (NTSC M/N) [0573:4d00] - 16 -> Hauppauge WinTV USB (PAL B/G) [0573:4d01] - 17 -> Hauppauge WinTV USB (PAL I) [0573:4d02] - 18 -> Hauppauge WinTV USB (PAL/SECAM L) [0573:4d03] - 19 -> Hauppauge WinTV USB (PAL D/K) [0573:4d04] - 20 -> Hauppauge WinTV USB (NTSC FM) [0573:4d10] - 21 -> Hauppauge WinTV USB (PAL B/G FM) [0573:4d11] - 22 -> Hauppauge WinTV USB (PAL I FM) [0573:4d12] - 23 -> Hauppauge WinTV USB (PAL D/K FM) [0573:4d14] - 24 -> Hauppauge WinTV USB Pro (NTSC M/N) [0573:4d2a] - 25 -> Hauppauge WinTV USB Pro (NTSC M/N) V2 [0573:4d2b] - 26 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L) [0573:4d2c] - 27 -> Hauppauge WinTV USB Pro (NTSC M/N) V3 [0573:4d20] - 28 -> Hauppauge WinTV USB Pro (PAL B/G) [0573:4d21] - 29 -> Hauppauge WinTV USB Pro (PAL I) [0573:4d22] - 30 -> Hauppauge WinTV USB Pro (PAL/SECAM L) [0573:4d23] - 31 -> Hauppauge WinTV USB Pro (PAL D/K) [0573:4d24] - 32 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) [0573:4d25] - 33 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2 [0573:4d26] - 34 -> Hauppauge WinTV USB Pro (PAL B/G) V2 [0573:4d27] - 35 -> Hauppauge WinTV USB Pro (PAL B/G,D/K) [0573:4d28] - 36 -> Hauppauge WinTV USB Pro (PAL I,D/K) [0573:4d29] - 37 -> Hauppauge WinTV USB Pro (NTSC M/N FM) [0573:4d30] - 38 -> Hauppauge WinTV USB Pro (PAL B/G FM) [0573:4d31] - 39 -> Hauppauge WinTV USB Pro (PAL I FM) [0573:4d32] - 40 -> Hauppauge WinTV USB Pro (PAL D/K FM) [0573:4d34] - 41 -> Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM) [0573:4d35] - 42 -> Hauppauge WinTV USB Pro (Temic PAL B/G FM) [0573:4d36] - 43 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM) [0573:4d37] - 44 -> Hauppauge WinTV USB Pro (NTSC M/N FM) V2 [0573:4d38] - 45 -> Camtel Technology USB TV Genie Pro FM Model TVB330 [0768:0006] - 46 -> Digital Video Creator I [07d0:0001] - 47 -> Global Village GV-007 (NTSC) [07d0:0002] - 48 -> Dazzle Fusion Model DVC-50 Rev 1 (NTSC) [07d0:0003] - 49 -> Dazzle Fusion Model DVC-80 Rev 1 (PAL) [07d0:0004] - 50 -> Dazzle Fusion Model DVC-90 Rev 1 (SECAM) [07d0:0005] - 51 -> Eskape Labs MyTV2Go [07f8:9104] - 52 -> Pinnacle Studio PCTV USB (PAL) [2304:010d] - 53 -> Pinnacle Studio PCTV USB (SECAM) [2304:0109] - 54 -> Pinnacle Studio PCTV USB (PAL) FM [2304:0110] - 55 -> Miro PCTV USB [2304:0111] - 56 -> Pinnacle Studio PCTV USB (NTSC) FM [2304:0112] - 57 -> Pinnacle Studio PCTV USB (PAL) FM V2 [2304:0210] - 58 -> Pinnacle Studio PCTV USB (NTSC) FM V2 [2304:0212] - 59 -> Pinnacle Studio PCTV USB (PAL) FM V3 [2304:0214] - 60 -> Pinnacle Studio Linx Video input cable (NTSC) [2304:0300] - 61 -> Pinnacle Studio Linx Video input cable (PAL) [2304:0301] - 62 -> Pinnacle PCTV Bungee USB (PAL) FM [2304:0419] - 63 -> Hauppauge WinTv-USB [2400:4200] diff --git a/trunk/Documentation/video4linux/README.ivtv b/trunk/Documentation/video4linux/README.ivtv deleted file mode 100644 index 73df22c40bfe..000000000000 --- a/trunk/Documentation/video4linux/README.ivtv +++ /dev/null @@ -1,187 +0,0 @@ - -ivtv release notes -================== - -This is a v4l2 device driver for the Conexant cx23415/6 MPEG encoder/decoder. -The cx23415 can do both encoding and decoding, the cx23416 can only do MPEG -encoding. Currently the only card featuring full decoding support is the -Hauppauge PVR-350. - -NOTE: this driver requires the latest encoder firmware (version 2.06.039, size -376836 bytes). Get the firmware from here: - -http://dl.ivtvdriver.org/ivtv/firmware/firmware.tar.gz - -NOTE: 'normal' TV applications do not work with this driver, you need -an application that can handle MPEG input such as mplayer, xine, MythTV, -etc. - -The primary goal of the IVTV project is to provide a "clean room" Linux -Open Source driver implementation for video capture cards based on the -iCompression iTVC15 or Conexant CX23415/CX23416 MPEG Codec. - -Features: - * Hardware mpeg2 capture of broadcast video (and sound) via the tuner or - S-Video/Composite and audio line-in. - * Hardware mpeg2 capture of FM radio where hardware support exists - * Supports NTSC, PAL, SECAM with stereo sound - * Supports SAP and bilingual transmissions. - * Supports raw VBI (closed captions and teletext). - * Supports sliced VBI (closed captions and teletext) and is able to insert - this into the captured MPEG stream. - * Supports raw YUV and PCM input. - -Additional features for the PVR-350 (CX23415 based): - * Provides hardware mpeg2 playback - * Provides comprehensive OSD (On Screen Display: ie. graphics overlaying the - video signal) - * Provides a framebuffer (allowing X applications to appear on the video - device) (this framebuffer is not yet part of the kernel. In the meantime it - is available from www.ivtvdriver.org). - * Supports raw YUV output. - -IMPORTANT: In case of problems first read this page: - http://www.ivtvdriver.org/index.php/Troubleshooting - -See also: - -Homepage + Wiki -http://www.ivtvdriver.org - -IRC -irc://irc.freenode.net/ivtv-dev - ----------------------------------------------------------- - -Devices -======= - -A maximum of 12 ivtv boards are allowed at the moment. - -Cards that don't have a video output capability (i.e. non PVR350 cards) -lack the vbi8, vbi16, video16 and video48 devices. They also do not -support the framebuffer device /dev/fbx for OSD. - -The radio0 device may or may not be present, depending on whether the -card has a radio tuner or not. - -Here is a list of the base v4l devices: -crw-rw---- 1 root video 81, 0 Jun 19 22:22 /dev/video0 -crw-rw---- 1 root video 81, 16 Jun 19 22:22 /dev/video16 -crw-rw---- 1 root video 81, 24 Jun 19 22:22 /dev/video24 -crw-rw---- 1 root video 81, 32 Jun 19 22:22 /dev/video32 -crw-rw---- 1 root video 81, 48 Jun 19 22:22 /dev/video48 -crw-rw---- 1 root video 81, 64 Jun 19 22:22 /dev/radio0 -crw-rw---- 1 root video 81, 224 Jun 19 22:22 /dev/vbi0 -crw-rw---- 1 root video 81, 228 Jun 19 22:22 /dev/vbi8 -crw-rw---- 1 root video 81, 232 Jun 19 22:22 /dev/vbi16 - -Base devices -============ - -For every extra card you have the numbers increased by one. For example, -/dev/video0 is listed as the 'base' encoding capture device so we have: - - /dev/video0 is the encoding capture device for the first card (card 0) - /dev/video1 is the encoding capture device for the second card (card 1) - /dev/video2 is the encoding capture device for the third card (card 2) - -Note that if the first card doesn't have a feature (eg no decoder, so no -video16, the second card will still use video17. The simple rule is 'add -the card number to the base device number'. If you have other capture -cards (e.g. WinTV PCI) that are detected first, then you have to tell -the ivtv module about it so that it will start counting at 1 (or 2, or -whatever). Otherwise the device numbers can get confusing. The ivtv -'ivtv_first_minor' module option can be used for that. - - -/dev/video0 -The encoding capture device(s). -Read-only. - -Reading from this device gets you the MPEG1/2 program stream. -Example: - -cat /dev/video0 > my.mpg (you need to hit ctrl-c to exit) - - -/dev/video16 -The decoder output device(s) -Write-only. Only present if the MPEG decoder (i.e. CX23415) exists. - -An mpeg2 stream sent to this device will appear on the selected video -display, audio will appear on the line-out/audio out. It is only -available for cards that support video out. Example: - -cat my.mpg >/dev/video16 - - -/dev/video24 -The raw audio capture device(s). -Read-only - -The raw audio PCM stereo stream from the currently selected -tuner or audio line-in. Reading from this device results in a raw -(signed 16 bit Little Endian, 48000 Hz, stereo pcm) capture. -This device only captures audio. This should be replaced by an ALSA -device in the future. -Note that there is no corresponding raw audio output device, this is -not supported in the decoder firmware. - - -/dev/video32 -The raw video capture device(s) -Read-only - -The raw YUV video output from the current video input. The YUV format -is non-standard (V4L2_PIX_FMT_HM12). - -Note that the YUV and PCM streams are not synchronized, so they are of -limited use. - - -/dev/video48 -The raw video display device(s) -Write-only. Only present if the MPEG decoder (i.e. CX23415) exists. - -Writes a YUV stream to the decoder of the card. - - -/dev/radio0 -The radio tuner device(s) -Cannot be read or written. - -Used to enable the radio tuner and tune to a frequency. You cannot -read or write audio streams with this device. Once you use this -device to tune the radio, use /dev/video24 to read the raw pcm stream -or /dev/video0 to get an mpeg2 stream with black video. - - -/dev/vbi0 -The 'vertical blank interval' (Teletext, CC, WSS etc) capture device(s) -Read-only - -Captures the raw (or sliced) video data sent during the Vertical Blank -Interval. This data is used to encode teletext, closed captions, VPS, -widescreen signalling, electronic program guide information, and other -services. - - -/dev/vbi8 -Processed vbi feedback device(s) -Read-only. Only present if the MPEG decoder (i.e. CX23415) exists. - -The sliced VBI data embedded in an MPEG stream is reproduced on this -device. So while playing back a recording on /dev/video16, you can -read the embedded VBI data from /dev/vbi8. - - -/dev/vbi16 -The vbi 'display' device(s) -Write-only. Only present if the MPEG decoder (i.e. CX23415) exists. - -Can be used to send sliced VBI data to the video-out connector. - ---------------------------------- - -Hans Verkuil diff --git a/trunk/Documentation/video4linux/cx2341x/fw-decoder-regs.txt b/trunk/Documentation/video4linux/cx2341x/fw-decoder-regs.txt index cf52c8f20b9e..db2366c634e8 100644 --- a/trunk/Documentation/video4linux/cx2341x/fw-decoder-regs.txt +++ b/trunk/Documentation/video4linux/cx2341x/fw-decoder-regs.txt @@ -624,11 +624,11 @@ out what values are bad when it hangs. 2A00 bits 0:2 osd colour mode - 000 = 8 bit indexed 001 = 16 bit (565) 010 = 15 bit (555) 011 = 12 bit (444) 100 = 32 bit (8888) + 101 = 8 bit indexed bits 4:5 osd display bpp @@ -676,11 +676,9 @@ out what values are bad when it hangs. completely transparent. When using 565, 555 or 444 colour modes, the colour key is always 16 bits wide. The colour to key on is set in Reg 2A18. - Local alpha works differently depending on the colour mode. For 32bpp & 8 - bit indexed, local alpha is a per-pixel 256 step transparency, with 0 being - transparent and 255 being solid. For the 16bpp modes 555 & 444, the unused - bit(s) act as a simple transparency switch, with 0 being solid & 1 being - fully transparent. There is no local alpha support for 16bit 565. + Local alpha is a per-pixel 256 step transparency, with 0 being transparent + and 255 being solid. This is only available in 32 bit & 8 bit indexed + colour modes. Global alpha is a 256 step transparency that applies to the entire osd, with 0 being transparent & 255 being solid. @@ -813,5 +811,5 @@ out what values are bad when it hangs. -------------------------------------------------------------------------------- -v0.4 - 12 March 2007 - Ian Armstrong (ian@iarmst.demon.co.uk) +v0.3 - 2 February 2007 - Ian Armstrong (ian@iarmst.demon.co.uk) diff --git a/trunk/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/trunk/Documentation/video4linux/cx2341x/fw-encoder-api.txt index 5dd3109a8b3f..242104ce5b61 100644 --- a/trunk/Documentation/video4linux/cx2341x/fw-encoder-api.txt +++ b/trunk/Documentation/video4linux/cx2341x/fw-encoder-api.txt @@ -663,13 +663,12 @@ Param[0] ------------------------------------------------------------------------------- -Name CX2341X_ENC_SET_VERT_CROP_LINE +Name CX2341X_ENC_UNKNOWN Enum 219/0xDB Description - Something to do with 'Vertical Crop Line' + Unknown API, it's used by Hauppauge though. Param[0] - If saa7114 and raw VBI capture and 60 Hz, then set to 10001. - Else 0. + 0 This is the value Hauppauge uses, Unknown what it means. ------------------------------------------------------------------------------- @@ -683,9 +682,11 @@ Param[0] Command number: 1=set initial SCR value when starting encoding (works). 2=set quality mode (apparently some test setting). - 3=setup advanced VIM protection handling. - Always 1 for the cx23416 and 0 for cx23415. - 4=generate DVD compatible PTS timestamps + 3=setup advanced VIM protection handling (supposedly only for the cx23416 + for raw YUV). + Actually it looks like this should be 0 for saa7114/5 based card and 1 + for cx25840 based cards. + 4=generate artificial PTS timestamps 5=USB flush mode 6=something to do with the quantization matrix 7=set navigation pack insertion for DVD: adds 0xbf (private stream 2) @@ -697,9 +698,7 @@ Param[0] 9=set history parameters of the video input module 10=set input field order of VIM 11=set quantization matrix - 12=reset audio interface after channel change or input switch (has no argument). - Needed for the cx2584x, not needed for the mspx4xx, but it doesn't seem to - do any harm calling it regardless. + 12=reset audio interface 13=set audio volume delay 14=set audio delay diff --git a/trunk/Documentation/video4linux/cx2341x/fw-osd-api.txt b/trunk/Documentation/video4linux/cx2341x/fw-osd-api.txt index 89c4601042c1..0a602f3e601b 100644 --- a/trunk/Documentation/video4linux/cx2341x/fw-osd-api.txt +++ b/trunk/Documentation/video4linux/cx2341x/fw-osd-api.txt @@ -21,11 +21,7 @@ Enum 66/0x42 Description Query OSD format Result[0] - 0=8bit index - 1=16bit RGB 5:6:5 - 2=16bit ARGB 1:5:5:5 - 3=16bit ARGB 1:4:4:4 - 4=32bit ARGB 8:8:8:8 + 0=8bit index, 4=AlphaRGB 8:8:8:8 ------------------------------------------------------------------------------- @@ -34,11 +30,7 @@ Enum 67/0x43 Description Assign pixel format Param[0] - 0=8bit index - 1=16bit RGB 5:6:5 - 2=16bit ARGB 1:5:5:5 - 3=16bit ARGB 1:4:4:4 - 4=32bit ARGB 8:8:8:8 + 0=8bit index, 4=AlphaRGB 8:8:8:8 ------------------------------------------------------------------------------- diff --git a/trunk/Documentation/video4linux/meye.txt b/trunk/Documentation/video4linux/meye.txt index 5e51c59bf2b0..ecb34160e61d 100644 --- a/trunk/Documentation/video4linux/meye.txt +++ b/trunk/Documentation/video4linux/meye.txt @@ -5,9 +5,10 @@ Vaio Picturebook Motion Eye Camera Driver Readme Copyright (C) 2000 Andrew Tridgell This driver enable the use of video4linux compatible applications with the -Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which -can be found in the "Misc devices" section of the kernel configuration utility) -to be compiled and installed (using its "camera=1" parameter). +Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O +Control Device" driver (which can be found in the "Character drivers" +section of the kernel configuration utility) to be compiled and installed +(using its "camera=1" parameter). It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480. diff --git a/trunk/Documentation/video4linux/sn9c102.txt b/trunk/Documentation/video4linux/sn9c102.txt index 5fe0ad7dfc20..2913da3d0878 100644 --- a/trunk/Documentation/video4linux/sn9c102.txt +++ b/trunk/Documentation/video4linux/sn9c102.txt @@ -25,7 +25,7 @@ Index 1. Copyright ============ -Copyright (C) 2004-2007 by Luca Risolia +Copyright (C) 2004-2006 by Luca Risolia 2. Disclaimer @@ -216,10 +216,10 @@ Description: Debugging information level, from 0 to 3: 1 = critical errors 2 = significant informations 3 = more verbose messages - Level 3 is useful for testing only. It also shows some more - informations about the hardware being detected. - This parameter can be changed at runtime thanks to the /sys - filesystem interface. + Level 3 is useful for testing only, when only one device + is used. It also shows some more informations about the + hardware being detected. This parameter can be changed at + runtime thanks to the /sys filesystem interface. Default: 2 ------------------------------------------------------------------------------- @@ -235,7 +235,7 @@ created in the /sys/class/video4linux/videoX directory. You can set the green channel's gain by writing the desired value to it. The value may range from 0 to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103, SN9C105 and SN9C120 bridges. -Similarly, only for the SN9C103, SN9C105 and SN9C120 controllers, blue and red +Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red gain control files are available in the same directory, for which accepted values may range from 0 to 127. @@ -402,49 +402,38 @@ Vendor ID Product ID 0x0c45 0x60bc 0x0c45 0x60be 0x0c45 0x60c0 -0x0c45 0x60c2 0x0c45 0x60c8 0x0c45 0x60cc 0x0c45 0x60ea 0x0c45 0x60ec -0x0c45 0x60ef 0x0c45 0x60fa 0x0c45 0x60fb 0x0c45 0x60fc 0x0c45 0x60fe -0x0c45 0x6102 -0x0c45 0x6108 -0x0c45 0x610f 0x0c45 0x6130 -0x0c45 0x6138 0x0c45 0x613a 0x0c45 0x613b 0x0c45 0x613c 0x0c45 0x613e The list above does not imply that all those devices work with this driver: up -until now only the ones that assemble the following pairs of SN9C1xx bridges -and image sensors are supported; kernel messages will always tell you whether -this is the case (see "Module loading" paragraph): - -Image sensor / SN9C1xx bridge | SN9C10[12] SN9C103 SN9C105 SN9C120 -------------------------------------------------------------------------------- -HV7131D Hynix Semiconductor | Yes No No No -HV7131R Hynix Semiconductor | No Yes Yes Yes -MI-0343 Micron Technology | Yes No No No -MI-0360 Micron Technology | No Yes No No -OV7630 OmniVision Technologies | Yes Yes No No -OV7660 OmniVision Technologies | No No Yes Yes -PAS106B PixArt Imaging | Yes No No No -PAS202B PixArt Imaging | Yes Yes No No -TAS5110C1B Taiwan Advanced Sensor | Yes No No No -TAS5110D Taiwan Advanced Sensor | Yes No No No -TAS5130D1B Taiwan Advanced Sensor | Yes No No No - -"Yes" means that the pair is supported by the driver, while "No" means that the -pair does not exist or is not supported by the driver. - -Only some of the available control settings of each image sensor are supported +until now only the ones that assemble the following image sensors are +supported; kernel messages will always tell you whether this is the case (see +"Module loading" paragraph): + +Model Manufacturer +----- ------------ +HV7131D Hynix Semiconductor, Inc. +MI-0343 Micron Technology, Inc. +OV7630 OmniVision Technologies, Inc. +OV7660 OmniVision Technologies, Inc. +PAS106B PixArt Imaging, Inc. +PAS202BCA PixArt Imaging, Inc. +PAS202BCB PixArt Imaging, Inc. +TAS5110C1B Taiwan Advanced Sensor Corporation +TAS5130D1B Taiwan Advanced Sensor Corporation + +Some of the available control settings of each image sensor are supported through the V4L2 interface. Donations of new models for further testing and support would be much @@ -493,8 +482,8 @@ The SN9C1xx PC Camera Controllers can send images in two possible video formats over the USB: either native "Sequential RGB Bayer" or compressed. The compression is used to achieve high frame rates. With regard to the SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding -algorithm described below, while with regard to the SN9C105 and SN9C120 the -compression is based on the JPEG standard. +algorithm described below, while the SN9C105 and SN9C120 the compression is +based on the JPEG standard. The current video format may be selected or queried from the user application by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API specifications. @@ -584,5 +573,4 @@ order): - Mizuno Takafumi for the donation of a webcam; - an "anonymous" donator (who didn't want his name to be revealed) for the donation of a webcam. -- an anonymous donator for the donation of four webcams and two boards with ten - image sensors. +- an anonymous donator for the donation of four webcams. diff --git a/trunk/Documentation/video4linux/zr364xx.txt b/trunk/Documentation/video4linux/zr364xx.txt deleted file mode 100644 index c76992d0ff4d..000000000000 --- a/trunk/Documentation/video4linux/zr364xx.txt +++ /dev/null @@ -1,65 +0,0 @@ -Zoran 364xx based USB webcam module version 0.72 -site: http://royale.zerezo.com/zr364xx/ -mail: royale@zerezo.com - -introduction: -This brings support under Linux for the Aiptek PocketDV 3300 in webcam mode. -If you just want to get on your PC the pictures and movies on the camera, you should use the usb-storage module instead. -The driver works with several other cameras in webcam mode (see the list below). -Maybe this code can work for other JPEG/USB cams based on the Coach chips from Zoran? -Possible chipsets are : ZR36430 (ZR36430BGC) and maybe ZR36431, ZR36440, ZR36442... -You can try the experience changing the vendor/product ID values (look at the source code). -You can get these values by looking at /var/log/messages when you plug your camera, or by typing : cat /proc/bus/usb/devices. -If you manage to use your cam with this code, you can send me a mail (royale@zerezo.com) with the name of your cam and a patch if needed. -This is a beta release of the driver. -Since version 0.70, this driver is only compatible with V4L2 API and 2.6.x kernels. -If you need V4L1 or 2.4x kernels support, please use an older version, but the code is not maintained anymore. -Good luck! - -install: -In order to use this driver, you must compile it with your kernel. -Location: Device Drivers -> Multimedia devices -> Video For Linux -> Video Capture Adapters -> V4L USB devices - -usage: -modprobe zr364xx debug=X mode=Y - - debug : set to 1 to enable verbose debug messages - - mode : 0 = 320x240, 1 = 160x120, 2 = 640x480 -You can then use the camera with V4L2 compatible applications, for example Ekiga. -To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1 count=1 - -links : -http://mxhaard.free.fr/ (support for many others cams including some Aiptek PocketDV) -http://www.harmwal.nl/pccam880/ (this project also supports cameras based on this chipset) - -supported devices: ------- ------- ----------- ----- -Vendor Product Distributor Model ------- ------- ----------- ----- -0x08ca 0x0109 Aiptek PocketDV 3300 -0x08ca 0x0109 Maxell Maxcam PRO DV3 -0x041e 0x4024 Creative PC-CAM 880 -0x0d64 0x0108 Aiptek Fidelity 3200 -0x0d64 0x0108 Praktica DCZ 1.3 S -0x0d64 0x0108 Genius Digital Camera (?) -0x0d64 0x0108 DXG Technology Fashion Cam -0x0546 0x3187 Polaroid iON 230 -0x0d64 0x3108 Praktica Exakta DC 2200 -0x0d64 0x3108 Genius G-Shot D211 -0x0595 0x4343 Concord Eye-Q Duo 1300 -0x0595 0x4343 Concord Eye-Q Duo 2000 -0x0595 0x4343 Fujifilm EX-10 -0x0595 0x4343 Ricoh RDC-6000 -0x0595 0x4343 Digitrex DSC 1300 -0x0595 0x4343 Firstline FDC 2000 -0x0bb0 0x500d Concord EyeQ Go Wireless -0x0feb 0x2004 CRS Electronic 3.3 Digital Camera -0x0feb 0x2004 Packard Bell DSC-300 -0x055f 0xb500 Mustek MDC 3000 -0x08ca 0x2062 Aiptek PocketDV 5700 -0x052b 0x1a18 Chiphead Megapix V12 -0x04c8 0x0729 Konica Revio 2 -0x04f2 0xa208 Creative PC-CAM 850 -0x0784 0x0040 Traveler Slimline X5 -0x06d6 0x0034 Trust Powerc@m 750 -0x0a17 0x0062 Pentax Optio 50L - diff --git a/trunk/Documentation/x86_64/boot-options.txt b/trunk/Documentation/x86_64/boot-options.txt index 6177d881983f..625a21db0c2a 100644 --- a/trunk/Documentation/x86_64/boot-options.txt +++ b/trunk/Documentation/x86_64/boot-options.txt @@ -149,19 +149,7 @@ NUMA numa=noacpi Don't parse the SRAT table for NUMA setup - numa=fake=CMDLINE - If a number, fakes CMDLINE nodes and ignores NUMA setup of the - actual machine. Otherwise, system memory is configured - depending on the sizes and coefficients listed. For example: - numa=fake=2*512,1024,4*256,*128 - gives two 512M nodes, a 1024M node, four 256M nodes, and the - rest split into 128M chunks. If the last character of CMDLINE - is a *, the remaining memory is divided up equally among its - coefficient: - numa=fake=2*512,2* - gives two 512M nodes and the rest split into two nodes. - Otherwise, the remaining system RAM is allocated to an - additional node. + numa=fake=X Fake X nodes and ignore NUMA setup of the actual machine. numa=hotadd=percent Only allow hotadd memory to preallocate page structures upto @@ -305,3 +293,7 @@ Debugging stuck (default) Miscellaneous + + noreplacement Don't replace instructions with more appropriate ones + for the CPU. This may be useful on asymmetric MP systems + where some CPUs have less capabilities than others. diff --git a/trunk/Documentation/x86_64/fake-numa-for-cpusets b/trunk/Documentation/x86_64/fake-numa-for-cpusets deleted file mode 100644 index d1a985c5b00a..000000000000 --- a/trunk/Documentation/x86_64/fake-numa-for-cpusets +++ /dev/null @@ -1,66 +0,0 @@ -Using numa=fake and CPUSets for Resource Management -Written by David Rientjes - -This document describes how the numa=fake x86_64 command-line option can be used -in conjunction with cpusets for coarse memory management. Using this feature, -you can create fake NUMA nodes that represent contiguous chunks of memory and -assign them to cpusets and their attached tasks. This is a way of limiting the -amount of system memory that are available to a certain class of tasks. - -For more information on the features of cpusets, see Documentation/cpusets.txt. -There are a number of different configurations you can use for your needs. For -more information on the numa=fake command line option and its various ways of -configuring fake nodes, see Documentation/x86_64/boot-options.txt. - -For the purposes of this introduction, we'll assume a very primitive NUMA -emulation setup of "numa=fake=4*512,". This will split our system memory into -four equal chunks of 512M each that we can now use to assign to cpusets. As -you become more familiar with using this combination for resource control, -you'll determine a better setup to minimize the number of nodes you have to deal -with. - -A machine may be split as follows with "numa=fake=4*512," as reported by dmesg: - - Faking node 0 at 0000000000000000-0000000020000000 (512MB) - Faking node 1 at 0000000020000000-0000000040000000 (512MB) - Faking node 2 at 0000000040000000-0000000060000000 (512MB) - Faking node 3 at 0000000060000000-0000000080000000 (512MB) - ... - On node 0 totalpages: 130975 - On node 1 totalpages: 131072 - On node 2 totalpages: 131072 - On node 3 totalpages: 131072 - -Now following the instructions for mounting the cpusets filesystem from -Documentation/cpusets.txt, you can assign fake nodes (i.e. contiguous memory -address spaces) to individual cpusets: - - [root@xroads /]# mkdir exampleset - [root@xroads /]# mount -t cpuset none exampleset - [root@xroads /]# mkdir exampleset/ddset - [root@xroads /]# cd exampleset/ddset - [root@xroads /exampleset/ddset]# echo 0-1 > cpus - [root@xroads /exampleset/ddset]# echo 0-1 > mems - -Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for -memory allocations (1G). - -You can now assign tasks to these cpusets to limit the memory resources -available to them according to the fake nodes assigned as mems: - - [root@xroads /exampleset/ddset]# echo $$ > tasks - [root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G - [1] 13425 - -Notice the difference between the system memory usage as reported by -/proc/meminfo between the restricted cpuset case above and the unrestricted -case (i.e. running the same 'dd' command without assigning it to a fake NUMA -cpuset): - Unrestricted Restricted - MemTotal: 3091900 kB 3091900 kB - MemFree: 42113 kB 1513236 kB - -This allows for coarse memory management for the tasks you assign to particular -cpusets. Since cpusets can form a hierarchy, you can create some pretty -interesting combinations of use-cases for various classes of tasks for your -memory management needs. diff --git a/trunk/Documentation/x86_64/machinecheck b/trunk/Documentation/x86_64/machinecheck index feaeaf6f6e4d..068a6d9904b9 100644 --- a/trunk/Documentation/x86_64/machinecheck +++ b/trunk/Documentation/x86_64/machinecheck @@ -36,12 +36,7 @@ between all CPUs. check_interval How often to poll for corrected machine check errors, in seconds - (Note output is hexademical). Default 5 minutes. When the poller - finds MCEs it triggers an exponential speedup (poll more often) on - the polling interval. When the poller stops finding MCEs, it - triggers an exponential backoff (poll less often) on the polling - interval. The check_interval variable is both the initial and - maximum polling interval. + (Note output is hexademical). Default 5 minutes. tolerant Tolerance level. When a machine check exception occurs for a non diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 0492dd88e12a..ef84419ade3a 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -55,7 +55,7 @@ trivial patch so apply some common sense. 8. Happy hacking. - ----------------------------------- + ----------------------------------- Maintainers List (try to look for most precise areas first) @@ -384,7 +384,7 @@ S: Supported APPLETALK NETWORK LAYER P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net +M: acme@conectiva.com.br S: Maintained ARC FRAMEBUFFER DRIVER @@ -656,7 +656,6 @@ S: Supported ATMEL WIRELESS DRIVER P: Simon Kelley M: simon@thekelleys.org.uk -L: linux-wireless@vger.kernel.org W: http://www.thekelleys.org.uk/atmel W: http://atmelwlandriver.sourceforge.net/ S: Maintained @@ -712,7 +711,6 @@ P: Larry Finger M: Larry.Finger@lwfinger.net P: Stefano Brivio M: st3@riseup.net -L: linux-wireless@vger.kernel.org W: http://bcm43xx.berlios.de/ S: Maintained @@ -733,13 +731,6 @@ M: tigran@aivazian.fsnet.co.uk L: linux-kernel@vger.kernel.org S: Maintained -BLACKFIN I2C TWI DRIVER -P: Sonic Zhang -M: sonic.zhang@analog.com -L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) -W: http://blackfin.uclinux.org/ -S: Supported - BLOCK LAYER P: Jens Axboe M: axboe@kernel.dk @@ -880,12 +871,6 @@ W: http://linuxtv.org T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git S: Maintained -CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER -P: Jonathan Corbet -M: corbet@lwn.net -L: video4linux-list@redhat.com -S: Maintained - CALGARY x86-64 IOMMU P: Muli Ben-Yehuda M: muli@il.ibm.com @@ -907,12 +892,6 @@ M: maxextreme@gmail.com L: linux-kernel@vger.kernel.org S: Maintained -CFG80211 and NL80211 -P: Johannes Berg -M: johannes@sipsolutions.net -L: linux-wireless@vger.kernel.org -S: Maintained - COMMON INTERNET FILE SYSTEM (CIFS) P: Steve French M: sfrench@samba.org @@ -920,7 +899,7 @@ L: linux-cifs-client@lists.samba.org L: samba-technical@lists.samba.org W: http://us1.samba.org/samba/Linux_CIFS_client.html T: git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git -S: Supported +S: Supported CONFIGFS P: Joel Becker @@ -988,11 +967,6 @@ M: mhw@wittsend.com W: http://www.wittsend.com/computone.html S: Maintained -CONEXANT ACCESSRUNNER USB DRIVER -P: Simon Arlott -M: cxacru@fire.lp0.eu -S: Maintained - COSA/SRP SYNC SERIAL DRIVER P: Jan "Yenya" Kasprzak M: kas@fi.muni.cz @@ -1060,8 +1034,9 @@ S: Maintained CYCLADES 2X SYNC CARD DRIVER P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net -W: http://oops.ghostprotocols.net:81/blog +M: acme@conectiva.com.br +W: http://advogato.org/person/acme +L: cycsyn-devel@bazar.conectiva.com.br S: Maintained CYCLADES ASYNC MUX DRIVER @@ -1102,7 +1077,7 @@ S: Maintained DCCP PROTOCOL P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net +M: acme@mandriva.com L: dccp@vger.kernel.org W: http://linux-net.osdl.org/index.php/DCCP S: Maintained @@ -1343,7 +1318,7 @@ S: Maintained ETHERNET BRIDGE P: Stephen Hemminger M: shemminger@linux-foundation.org -L: bridge@lists.linux-foundation.org +L: bridge@lists.osdl.org W: http://bridge.sourceforge.net/ S: Maintained @@ -1380,11 +1355,6 @@ M: kevin.curtis@farsite.co.uk W: http://www.farsite.co.uk/ S: Supported -FAULT INJECTION SUPPORT -P: Akinobu Mita -M: akinobu.mita@gmail.com -S: Supported - FRAMEBUFFER LAYER P: Antonino Daplas M: adaplas@gmail.com @@ -1401,13 +1371,6 @@ L: linuxppc-embedded@ozlabs.org L: netdev@vger.kernel.org S: Maintained -FREESCALE HIGHSPEED USB DEVICE DRIVER -P: Li Yang -M: leoli@freescale.com -L: linux-usb-devel@lists.sourceforge.net -L: linuxppc-embedded@ozlabs.org -S: Maintained - FILE LOCKING (flock() and fcntl()/lockf()) P: Matthew Wilcox M: matthew@wil.cx @@ -1466,11 +1429,6 @@ L: linux-scsi@vger.kernel.org W: http://www.icp-vortex.com/ S: Supported -GENERIC GPIO I2C DRIVER -P: Haavard Skinnemoen -M: hskinnemoen@atmel.com -S: Supported - GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl @@ -1579,24 +1537,23 @@ P: Chirag Kantharia M: chirag.kantharia@hp.com L: iss_storagedev@hp.com S: Maintained - + HEWLETT-PACKARD SMART2 RAID DRIVER P: Chirag Kantharia M: chirag.kantharia@hp.com L: iss_storagedev@hp.com S: Maintained - + HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss) P: Mike Miller M: mike.miller@hp.com L: iss_storagedev@hp.com S: Supported - + HOST AP DRIVER P: Jouni Malinen -M: j@w1.fi -L: hostap@shmoo.com (subscribers-only) -L: linux-wireless@vger.kernel.org +M: jkmaline@cc.hut.fi +L: hostap@shmoo.com W: http://hostap.epitest.fi/ S: Maintained @@ -1617,7 +1574,7 @@ S: Maintained HPET: x86_64 P: Andi Kleen and Vojtech Pavlik -M: andi@firstfloor.org and vojtech@suse.cz +M: ak@muc.de and vojtech@suse.cz S: Maintained HPET: ACPI hpet.c @@ -1643,13 +1600,6 @@ L: i2c@lm-sensors.org T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/ S: Maintained -I2C-TINY-USB DRIVER -P: Till Harbaum -M: till@harbaum.org -L: i2c@lm-sensors.org -T: http://www.harbaum.org/till/i2c_tiny_usb -S: Maintained - i386 BOOT CODE P: Riley H. Williams M: Riley@Williams.Name @@ -1677,6 +1627,15 @@ W: http://www.ia64-linux.org/ T: git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git S: Maintained +IBM ACPI EXTRAS DRIVER +P: Henrique de Moraes Holschuh +M: ibm-acpi@hmh.eng.br +L: ibm-acpi-devel@lists.sourceforge.net +W: http://ibm-acpi.sourceforge.net +W: http://thinkwiki.org/wiki/Ibm-acpi +T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git +S: Maintained + SN-IA64 (Itanium) SUB-PLATFORM P: Jes Sorensen M: jes@sgi.com @@ -1701,7 +1660,7 @@ P: Jack Hammer P: Dave Jeffery M: ipslinux@adaptec.com W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html -S: Supported +S: Supported IDE SUBSYSTEM P: Bartlomiej Zolnierkiewicz @@ -1731,7 +1690,7 @@ S: Maintained IEEE 1394 SUBSYSTEM P: Ben Collins -M: ben.collins@ubuntu.com +M: bcollins@debian.org P: Stefan Richter M: stefanr@s5r6.in-berlin.de L: linux1394-devel@lists.sourceforge.net @@ -1739,12 +1698,26 @@ W: http://www.linux1394.org/ T: git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git S: Maintained -IEEE 1394 RAW I/O DRIVER (raw1394) -P: Dan Dennedy -M: dan@dennedy.org +IEEE 1394 IPV4 DRIVER (eth1394) +P: Stefan Richter +M: stefanr@s5r6.in-berlin.de +L: linux1394-devel@lists.sourceforge.net +S: Odd Fixes + +IEEE 1394 PCILYNX DRIVER +P: Jody McIntyre +M: scjody@modernduck.com P: Stefan Richter M: stefanr@s5r6.in-berlin.de L: linux1394-devel@lists.sourceforge.net +S: Odd Fixes + +IEEE 1394 RAW I/O DRIVER +P: Ben Collins +M: bcollins@debian.org +P: Dan Dennedy +M: dan@dennedy.org +L: linux1394-devel@lists.sourceforge.net S: Maintained IMS TWINTURBO FRAMEBUFFER DRIVER @@ -1830,7 +1803,6 @@ P: Jeff Kirsher M: jeffrey.t.kirsher@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com -L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1845,7 +1817,6 @@ P: Jeff Kirsher M: jeffrey.t.kirsher@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com -L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1860,7 +1831,6 @@ P: Jesse Brandeburg M: jesse.brandeburg@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com -L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1869,7 +1839,6 @@ P: Yi Zhu M: yi.zhu@intel.com P: James Ketrenos M: jketreno@linux.intel.com -L: linux-wireless@vger.kernel.org L: ipw2100-devel@lists.sourceforge.net L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2100.sourceforge.net @@ -1880,7 +1849,6 @@ P: Yi Zhu M: yi.zhu@intel.com P: James Ketrenos M: jketreno@linux.intel.com -L: linux-wireless@vger.kernel.org L: ipw2100-devel@lists.sourceforge.net L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2200.sourceforge.net @@ -1912,7 +1880,7 @@ S: Supported IPX NETWORK LAYER P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net +M: acme@conectiva.com.br L: netdev@vger.kernel.org S: Maintained @@ -1983,7 +1951,7 @@ P: Vivek Goyal M: vgoyal@in.ibm.com P: Haren Myneni M: hbabu@us.ibm.com -L: fastboot@lists.linux-foundation.org +L: fastboot@lists.osdl.org L: linux-kernel@vger.kernel.org W: http://lse.sourceforge.net/kdump/ S: Maintained @@ -2006,11 +1974,11 @@ M: kai@germaschewski.name P: Sam Ravnborg M: sam@ravnborg.org T: git kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git -S: Maintained +S: Maintained KERNEL JANITORS P: Several -L: kernel-janitors@lists.linux-foundation.org +L: kernel-janitors@lists.osdl.org W: http://www.kerneljanitors.org/ S: Maintained @@ -2033,7 +2001,7 @@ P: Eric Biederman M: ebiederm@xmission.com W: http://www.xmission.com/~ebiederm/files/kexec/ L: linux-kernel@vger.kernel.org -L: fastboot@lists.linux-foundation.org +L: fastboot@lists.osdl.org S: Maintained KPROBES @@ -2149,7 +2117,7 @@ S: Supported LLC (802.2) P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net +M: acme@conectiva.com.br S: Maintained LINUX FOR 64BIT POWERPC @@ -2186,7 +2154,7 @@ S: Maintained LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks) P: Richard Russon (FlatCap) M: ldm@flatcap.org -L: ldm-devel@lists.sourceforge.net +L: ldm-devel@lists.sourceforge.net W: http://ldm.sourceforge.net S: Maintained @@ -2228,16 +2196,6 @@ M: philb@gnu.org W: http://www.tazenda.demon.co.uk/phil/linux-hp S: Maintained -MAC80211 -P: Jiri Benc -M: jbenc@suse.cz -P: Michael Wu -M: flamingice@sourmilk.net -L: linux-wireless@vger.kernel.org -W: http://linuxwireless.org/ -T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git -S: Maintained - MARVELL YUKON / SYSKONNECT DRIVER P: Mirko Lindner M: mlindner@syskonnect.de @@ -2287,14 +2245,6 @@ L: linux-mtd@lists.infradead.org T: git git://git.infradead.org/mtd-2.6.git S: Maintained -UNSORTED BLOCK IMAGES (UBI) -P: Artem Bityutskiy -M: dedekind@infradead.org -W: http://www.linux-mtd.infradead.org/ -L: linux-mtd@lists.infradead.org -T: git git://git.infradead.org/ubi-2.6.git -S: Maintained - MICROTEK X6 SCANNER P: Oliver Neukum M: oliver@neukum.name @@ -2389,7 +2339,7 @@ S: Maintained NETEM NETWORK EMULATOR P: Stephen Hemminger M: shemminger@linux-foundation.org -L: netem@lists.linux-foundation.org +L: netem@lists.osdl.org S: Maintained NETFILTER/IPTABLES/IPCHAINS @@ -2532,19 +2482,6 @@ M: adaplas@gmail.com L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only) S: Maintained -NETERION (S2IO) Xframe 10GbE DRIVER -P: Ramkrishna Vepa -M: ram.vepa@neterion.com -P: Rastapur Santosh -M: santosh.rastapur@neterion.com -P: Sivakumar Subramani -M: sivakumar.subramani@neterion.com -P: Sreenivasa Honnur -M: sreenivasa.honnur@neterion.com -L: netdev@vger.kernel.org -W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous -S: Supported - OPENCORES I2C BUS DRIVER P: Peter Korsgaard M: jacmet@sunsite.dk @@ -2558,13 +2495,13 @@ P: Kurt Hackel M: kurt.hackel@oracle.com L: ocfs2-devel@oss.oracle.com W: http://oss.oracle.com/projects/ocfs2/ -S: Supported +S: Supported OLYMPIC NETWORK DRIVER P: Peter De Shrijver M: p2@ace.ulyssis.student.kuleuven.ac.be P: Mike Phillips -M: mikep@linuxtr.net +M: mikep@linuxtr.net L: netdev@vger.kernel.org L: linux-tr@linuxtr.net W: http://www.linuxtr.net @@ -2580,12 +2517,6 @@ P: Harald Welte M: laforge@gnumonks.org S: Maintained -OMNIVISION OV7670 SENSOR DRIVER -P: Jonathan Corbet -M: corbet@lwn.net -L: video4linux-list@redhat.com -S: Maintained - ONSTREAM SCSI TAPE DRIVER P: Willem Riede M: osst@riede.org @@ -2610,7 +2541,6 @@ P: Pavel Roskin M: proski@gnu.org P: David Gibson M: hermes@gibson.dropbear.id.au -L: linux-wireless@vger.kernel.org L: orinoco-users@lists.sourceforge.net L: orinoco-devel@lists.sourceforge.net W: http://www.nongnu.org/orinoco/ @@ -2652,19 +2582,6 @@ T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6 S: Maintained -PARAVIRT_OPS INTERFACE -P: Jeremy Fitzhardinge -M: jeremy@xensource.com -P: Chris Wright -M: chrisw@sous-sol.org -P: Zachary Amsden -M: zach@vmware.com -P: Rusty Russell -M: rusty@rustcorp.com.au -L: virtualization@lists.osdl.org -L: linux-kernel@vger.kernel.org -S: Supported - PC87360 HARDWARE MONITORING DRIVER P: Jim Cromie M: jim.cromie@gmail.com @@ -2803,7 +2720,7 @@ S: Supported PRISM54 WIRELESS DRIVER P: Prism54 Development Team M: developers@islsm.org -L: linux-wireless@vger.kernel.org +L: netdev@vger.kernel.org W: http://prism54.org S: Maintained @@ -2874,7 +2791,7 @@ S: Maintained RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER P: Corey Thomas M: corey@world.std.com -L: linux-wireless@vger.kernel.org +L: linux-kernel@vger.kernel.org S: Maintained RANDOM NUMBER DRIVER @@ -3053,10 +2970,8 @@ P: Stephen Smalley M: sds@tycho.nsa.gov P: James Morris M: jmorris@namei.org -P: Eric Paris -M: eparis@parisplace.org L: linux-kernel@vger.kernel.org (kernel issues) -L: selinux@tycho.nsa.gov (subscribers-only, general discussion) +L: selinux@tycho.nsa.gov (general discussion) W: http://www.nsa.gov/selinux S: Supported @@ -3118,7 +3033,7 @@ SIS FRAMEBUFFER DRIVER P: Thomas Winischhofer M: thomas@winischhofer.net W: http://www.winischhofer.net/linuxsisvga.shtml -S: Maintained +S: Maintained SIS USB2VGA DRIVER P: Thomas Winischhofer @@ -3139,7 +3054,7 @@ M: josejx@gentoo.org P: Daniel Drake M: dsd@gentoo.org W: http://softmac.sipsolutions.net/ -L: linux-wireless@vger.kernel.org +L: netdev@vger.kernel.org S: Maintained SOFTWARE RAID (Multiple Disks) SUPPORT @@ -3153,7 +3068,7 @@ S: Supported SOFTWARE SUSPEND: P: Pavel Machek M: pavel@suse.cz -L: linux-pm@lists.linux-foundation.org +L: linux-pm@lists.osdl.org S: Maintained SONIC NETWORK DRIVER @@ -3215,15 +3130,6 @@ P: Chris Zankel M: chris@zankel.net S: Maintained -THINKPAD ACPI EXTRAS DRIVER -P: Henrique de Moraes Holschuh -M: ibm-acpi@hmh.eng.br -L: ibm-acpi-devel@lists.sourceforge.net -W: http://ibm-acpi.sourceforge.net -W: http://thinkwiki.org/wiki/Ibm-acpi -T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git -S: Maintained - UltraSPARC (sparc64): P: David S. Miller M: davem@davemloft.net @@ -3669,14 +3575,14 @@ W: http://www.kroah.com/linux/ S: Maintained USB SERIAL WHITEHEAT DRIVER -P: Support Department -M: support@connecttech.com +P: Stuart MacDonald +M: stuartm@connecttech.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://www.connecttech.com S: Supported -USB SN9C1xx DRIVER +USB SN9C10x DRIVER P: Luca Risolia M: luca.risolia@studio.unibo.it L: linux-usb-devel@lists.sourceforge.net @@ -3731,14 +3637,6 @@ L: linux-usb-devel@lists.sourceforge.net W: http://linux-lc100020.sourceforge.net S: Maintained -USB ZR364XX DRIVER -P: Antoine Jacquet -M: royale@zerezo.com -L: linux-usb-devel@lists.sourceforge.net -L: video4linux-list@redhat.com -W: http://royale.zerezo.com/zr364xx/ -S: Maintained - USER-MODE LINUX P: Jeff Dike M: jdike@karaya.com @@ -3746,7 +3644,7 @@ L: user-mode-linux-devel@lists.sourceforge.net L: user-mode-linux-user@lists.sourceforge.net W: http://user-mode-linux.sourceforge.net S: Maintained - + FAT/VFAT/MSDOS FILESYSTEM: P: OGAWA Hirofumi M: hirofumi@mail.parknet.co.jp @@ -3861,7 +3759,6 @@ S: Maintained WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS P: Jean Tourrilhes M: jt@hpl.hp.com -L: linux-wireless@vger.kernel.org W: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ S: Maintained @@ -3878,9 +3775,8 @@ S: Maintained WL3501 WIRELESS PCMCIA CARD DRIVER P: Arnaldo Carvalho de Melo -M: acme@ghostprotocols.net -L: linux-wireless@vger.kernel.org -W: http://oops.ghostprotocols.net:81/blog +M: acme@conectiva.com.br +W: http://advogato.org/person/acme S: Maintained X.25 NETWORK LAYER @@ -3889,15 +3785,6 @@ M: eis@baty.hanse.de L: linux-x25@vger.kernel.org S: Maintained -XEN HYPERVISOR INTERFACE -P: Jeremy Fitzhardinge -M: jeremy@xensource.com -P: Chris Wright -M: chrisw@sous-sol.org -L: virtualization@lists.osdl.org -L: xen-devel@lists.xensource.com -S: Supported - XFS FILESYSTEM P: Silicon Graphics Inc P: Tim Shimmin, David Chatterton @@ -3952,7 +3839,6 @@ M: dsd@gentoo.org P: Ulrich Kunitz M: kune@deine-taler.de W: http://zd1211.ath.cx/wiki/DriverRewrite -L: linux-wireless@vger.kernel.org L: zd1211-devs@lists.sourceforge.net (subscribers-only) S: Maintained diff --git a/trunk/Makefile b/trunk/Makefile index 387526b69d4f..234bae68cb98 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 21 -EXTRAVERSION = +EXTRAVERSION = -rc7 NAME = Nocturnal Monster Puppy # *DOCUMENTATION* @@ -491,7 +491,7 @@ endif include $(srctree)/arch/$(ARCH)/Makefile ifdef CONFIG_FRAME_POINTER -CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls +CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,) else CFLAGS += -fomit-frame-pointer endif diff --git a/trunk/arch/alpha/boot/misc.c b/trunk/arch/alpha/boot/misc.c index c00646b25f6e..1d65adf5691e 100644 --- a/trunk/arch/alpha/boot/misc.c +++ b/trunk/arch/alpha/boot/misc.c @@ -98,7 +98,7 @@ extern int end; static ulg free_mem_ptr; static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x3000 +#define HEAP_SIZE 0x2000 #include "../../../lib/inflate.c" diff --git a/trunk/arch/alpha/kernel/err_common.c b/trunk/arch/alpha/kernel/err_common.c index 13d53b1c9657..687580b16b41 100644 --- a/trunk/arch/alpha/kernel/err_common.c +++ b/trunk/arch/alpha/kernel/err_common.c @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/trunk/arch/alpha/kernel/err_ev6.c b/trunk/arch/alpha/kernel/err_ev6.c index 11aee012a8ae..69b5f4ea7355 100644 --- a/trunk/arch/alpha/kernel/err_ev6.c +++ b/trunk/arch/alpha/kernel/err_ev6.c @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/trunk/arch/alpha/kernel/err_ev7.c b/trunk/arch/alpha/kernel/err_ev7.c index bc799f72d8c1..95463ab1cf35 100644 --- a/trunk/arch/alpha/kernel/err_ev7.c +++ b/trunk/arch/alpha/kernel/err_ev7.c @@ -7,6 +7,7 @@ */ #include +#include #include #include diff --git a/trunk/arch/alpha/kernel/vmlinux.lds.S b/trunk/arch/alpha/kernel/vmlinux.lds.S index cf1e6fc6c686..4cc44bd33d33 100644 --- a/trunk/arch/alpha/kernel/vmlinux.lds.S +++ b/trunk/arch/alpha/kernel/vmlinux.lds.S @@ -69,7 +69,7 @@ SECTIONS . = ALIGN(8); SECURITY_INIT - . = ALIGN(8192); + . = ALIGN(64); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/alpha/lib/Makefile b/trunk/arch/alpha/lib/Makefile index ea098f3b629f..21cf624d7329 100644 --- a/trunk/arch/alpha/lib/Makefile +++ b/trunk/arch/alpha/lib/Makefile @@ -36,6 +36,7 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \ $(ev6-y)csum_ipv6_magic.o \ $(ev6-y)clear_page.o \ $(ev6-y)copy_page.o \ + strcasecmp.o \ fpreg.o \ callback_srm.o srm_puts.o srm_printk.o diff --git a/trunk/arch/alpha/lib/strcasecmp.c b/trunk/arch/alpha/lib/strcasecmp.c new file mode 100644 index 000000000000..4e57a216feaf --- /dev/null +++ b/trunk/arch/alpha/lib/strcasecmp.c @@ -0,0 +1,26 @@ +/* + * linux/arch/alpha/lib/strcasecmp.c + */ + +#include + + +/* We handle nothing here except the C locale. Since this is used in + only one place, on strings known to contain only 7 bit ASCII, this + is ok. */ + +int strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } while (ca == cb && ca != '\0'); + + return ca - cb; +} diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index db00376aca15..e7baca29f3fb 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -255,7 +255,6 @@ config ARCH_IOP13XX depends on MMU select PLAT_IOP select PCI - select ARCH_SUPPORTS_MSI help Support for Intel's IOP13XX (XScale) family of processors. diff --git a/trunk/arch/arm/boot/compressed/misc.c b/trunk/arch/arm/boot/compressed/misc.c index 9b444022cb9b..283891c736c4 100644 --- a/trunk/arch/arm/boot/compressed/misc.c +++ b/trunk/arch/arm/boot/compressed/misc.c @@ -239,7 +239,7 @@ extern int end; static ulg free_mem_ptr; static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x3000 +#define HEAP_SIZE 0x2000 #include "../../../../lib/inflate.c" diff --git a/trunk/arch/arm/common/sharpsl_pm.c b/trunk/arch/arm/common/sharpsl_pm.c index 5972df2b9af4..a9bc5b52218f 100644 --- a/trunk/arch/arm/common/sharpsl_pm.c +++ b/trunk/arch/arm/common/sharpsl_pm.c @@ -766,10 +766,10 @@ static void sharpsl_apm_get_power_status(struct apm_power_info *info) } static struct pm_ops sharpsl_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, .prepare = pxa_pm_prepare, .enter = corgi_pxa_pm_enter, .finish = pxa_pm_finish, - .valid = pm_valid_only_mem, }; static int __init sharpsl_pm_probe(struct platform_device *pdev) diff --git a/trunk/arch/arm/kernel/irq.c b/trunk/arch/arm/kernel/irq.c index e101846ab7dd..a72b82e727f1 100644 --- a/trunk/arch/arm/kernel/irq.c +++ b/trunk/arch/arm/kernel/irq.c @@ -109,7 +109,7 @@ static struct irq_desc bad_irq_desc = { * come via this function. Instead, they should provide their * own 'handler' */ -asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc *desc = irq_desc + irq; diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 24095601359b..ba1c1884e68e 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -45,7 +45,18 @@ static int __init user_debug_setup(char *str) __setup("user_debug=", user_debug_setup); #endif -void dump_backtrace_entry(unsigned long where, unsigned long from) +static void dump_mem(const char *str, unsigned long bottom, unsigned long top); + +static inline int in_exception_text(unsigned long ptr) +{ + extern char __exception_text_start[]; + extern char __exception_text_end[]; + + return ptr >= (unsigned long)&__exception_text_start && + ptr < (unsigned long)&__exception_text_end; +} + +void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS printk("[<%08lx>] ", where); @@ -55,6 +66,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from) #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif + + if (in_exception_text(where)) + dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); } /* @@ -266,7 +280,7 @@ void unregister_undef_hook(struct undef_hook *hook) spin_unlock_irqrestore(&undef_lock, flags); } -asmlinkage void do_undefinstr(struct pt_regs *regs) +asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { unsigned int correction = thumb_mode(regs) ? 2 : 4; unsigned int instr; diff --git a/trunk/arch/arm/kernel/vmlinux.lds.S b/trunk/arch/arm/kernel/vmlinux.lds.S index d1a6a597ed9a..b295f6a85cf1 100644 --- a/trunk/arch/arm/kernel/vmlinux.lds.S +++ b/trunk/arch/arm/kernel/vmlinux.lds.S @@ -59,7 +59,7 @@ SECTIONS usr/built-in.o(.init.ramfs) __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(64); __per_cpu_start = .; *(.data.percpu) __per_cpu_end = .; @@ -83,6 +83,9 @@ SECTIONS .text : { /* Real text segment */ _text = .; /* Text and read-only data */ + __exception_text_start = .; + *(.exception.text) + __exception_text_end = .; *(.text) SCHED_TEXT LOCK_TEXT diff --git a/trunk/arch/arm/lib/backtrace.S b/trunk/arch/arm/lib/backtrace.S index 74230083cbf4..84dc890d2bf3 100644 --- a/trunk/arch/arm/lib/backtrace.S +++ b/trunk/arch/arm/lib/backtrace.S @@ -17,8 +17,8 @@ @ fp is 0 or stack frame #define frame r4 -#define next r5 -#define save r6 +#define sv_fp r5 +#define sv_pc r6 #define mask r7 #define offset r8 @@ -31,108 +31,106 @@ ENTRY(c_backtrace) #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) mov pc, lr #else - stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... - tst r1, #0x10 @ 26 or 32-bit? - moveq mask, #0xfc000003 - movne mask, #0 - tst mask, r0 - movne r0, #0 - movs frame, r0 -1: moveq r0, #-2 - ldmeqfd sp!, {r4 - r8, pc} - -2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction - ldr r0, [sp], #4 - adr r1, 2b - 4 + movs frame, r0 @ if frame pointer is zero + beq no_frame @ we have no stack frames + + tst r1, #0x10 @ 26 or 32-bit mode? + moveq mask, #0xfc000003 @ mask for 26-bit + movne mask, #0 @ mask for 32-bit + +1: stmfd sp!, {pc} @ calculate offset of PC stored + ldr r0, [sp], #4 @ by stmfd for this CPU + adr r1, 1b sub offset, r0, r1 -3: tst frame, mask @ Check for address exceptions... - bne 1b +/* + * Stack frame layout: + * optionally saved caller registers (r4 - r10) + * saved fp + * saved sp + * saved lr + * frame => saved pc + * optionally saved arguments (r0 - r3) + * saved sp => + * + * Functions start with the following code sequence: + * mov ip, sp + * stmfd sp!, {r0 - r3} (optional) + * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} + */ +for_each_frame: tst frame, mask @ Check for address exceptions + bne no_frame + +1001: ldr sv_pc, [frame, #0] @ get saved pc +1002: ldr sv_fp, [frame, #-12] @ get saved fp -1001: ldr next, [frame, #-12] @ get fp -1002: ldr r2, [frame, #-4] @ get lr -1003: ldr r3, [frame, #0] @ get pc - sub save, r3, offset @ Correct PC for prefetching - bic save, save, mask -1004: ldr r1, [save, #0] @ get instruction at function - mov r1, r1, lsr #10 - ldr r3, .Ldsi+4 - teq r1, r3 - subeq save, save, #4 - mov r0, save - bic r1, r2, mask + sub sv_pc, sv_pc, offset @ Correct PC for prefetching + bic sv_pc, sv_pc, mask @ mask PC/LR for the mode + +1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, + ldr r3, .Ldsi+4 @ adjust saved 'pc' back one + teq r3, r2, lsr #10 @ instruction + subne r0, sv_pc, #4 @ allow for mov + subeq r0, sv_pc, #8 @ allow for mov + stmia + + ldr r1, [frame, #-4] @ get saved lr + mov r2, frame + bic r1, r1, mask @ mask PC/LR for the mode bl dump_backtrace_entry - ldr r0, [frame, #-8] @ get sp - sub r0, r0, #4 -1005: ldr r1, [save, #4] @ get instruction at function+4 - mov r3, r1, lsr #10 - ldr r2, .Ldsi+4 - teq r3, r2 @ Check for stmia sp!, {args} - addeq save, save, #4 @ next instruction - bleq .Ldumpstm - - sub r0, frame, #16 -1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction - mov r3, r1, lsr #10 - ldr r2, .Ldsi - teq r3, r2 - bleq .Ldumpstm - - /* - * A zero next framepointer means we're done. - */ - teq next, #0 - ldmeqfd sp!, {r4 - r8, pc} - - /* - * The next framepointer must be above the - * current framepointer. - */ - cmp next, frame - mov frame, next - bhi 3b - b 1007f + ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, + ldr r3, .Ldsi+4 + teq r3, r1, lsr #10 + ldreq r0, [frame, #-8] @ get sp + subeq r0, r0, #4 @ point at the last arg + bleq .Ldumpstm @ dump saved registers -/* - * Fixup for LDMDB. Note that this must not be in the fixup section. - */ -1007: ldr r0, =.Lbad +1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} + ldr r3, .Ldsi @ instruction exists, + teq r3, r1, lsr #10 + subeq r0, frame, #16 + bleq .Ldumpstm @ dump saved registers + + teq sv_fp, #0 @ zero saved fp means + beq no_frame @ no further frames + + cmp sv_fp, frame @ next frame must be + mov frame, sv_fp @ above the current frame + bhi for_each_frame + +1006: adr r0, .Lbad mov r1, frame bl printk - ldmfd sp!, {r4 - r8, pc} - .ltorg +no_frame: ldmfd sp!, {r4 - r8, pc} .section __ex_table,"a" .align 3 - .long 1001b, 1007b - .long 1002b, 1007b - .long 1003b, 1007b - .long 1004b, 1007b - .long 1005b, 1007b - .long 1006b, 1007b + .long 1001b, 1006b + .long 1002b, 1006b + .long 1003b, 1006b + .long 1004b, 1006b .previous #define instr r4 #define reg r5 #define stack r6 -.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, r8, lr} +.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} mov stack, r0 mov instr, r1 - mov reg, #9 + mov reg, #10 mov r7, #0 1: mov r3, #1 tst instr, r3, lsl reg beq 2f add r7, r7, #1 - teq r7, #4 - moveq r7, #0 - moveq r3, #'\n' - movne r3, #' ' - ldr r2, [stack], #-4 - mov r1, reg + teq r7, #6 + moveq r7, #1 + moveq r1, #'\n' + movne r1, #' ' + ldr r3, [stack], #-4 + mov r2, reg adr r0, .Lfp bl printk 2: subs reg, reg, #1 @@ -140,14 +138,13 @@ ENTRY(c_backtrace) teq r7, #0 adrne r0, .Lcr blne printk - mov r0, stack - ldmfd sp!, {instr, reg, stack, r7, r8, pc} + ldmfd sp!, {instr, reg, stack, r7, pc} -.Lfp: .asciz " r%d = %08X%c" +.Lfp: .asciz "%cr%d:%08x" .Lcr: .asciz "\n" .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" .align -.Ldsi: .word 0x00e92dd8 >> 2 - .word 0x00e92d00 >> 2 +.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc} + .word 0xe92d0000 >> 10 @ stmfd sp!, {} #endif diff --git a/trunk/arch/arm/mach-at91/pm.c b/trunk/arch/arm/mach-at91/pm.c index ff8db29e989e..b49bfda53d7f 100644 --- a/trunk/arch/arm/mach-at91/pm.c +++ b/trunk/arch/arm/mach-at91/pm.c @@ -201,6 +201,7 @@ static int at91_pm_enter(suspend_state_t state) static struct pm_ops at91_pm_ops ={ + .pm_disk_mode = 0, .valid = at91_pm_valid_state, .prepare = at91_pm_prepare, .enter = at91_pm_enter, diff --git a/trunk/arch/arm/mach-omap1/pm.c b/trunk/arch/arm/mach-omap1/pm.c index 6f4ea4bda5e0..49efe903dacd 100644 --- a/trunk/arch/arm/mach-omap1/pm.c +++ b/trunk/arch/arm/mach-omap1/pm.c @@ -72,12 +72,12 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; static unsigned short enable_dyn_sleep = 1; -static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf) +static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf) { return sprintf(buf, "%hu\n", enable_dyn_sleep); } -static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset, +static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys, const char * buf, size_t n) { @@ -100,7 +100,7 @@ static struct subsys_attribute sleep_while_idle_attr = { .store = omap_pm_sleep_while_idle_store, }; -extern struct kset power_subsys; +extern struct subsystem power_subsys; static void (*omap_sram_idle)(void) = NULL; static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; @@ -698,10 +698,10 @@ static struct irqaction omap_wakeup_irq = { static struct pm_ops omap_pm_ops ={ + .pm_disk_mode = 0, .prepare = omap_pm_prepare, .enter = omap_pm_enter, .finish = omap_pm_finish, - .valid = pm_valid_only_mem, }; static int __init omap_pm_init(void) diff --git a/trunk/arch/arm/mach-omap2/pm.c b/trunk/arch/arm/mach-omap2/pm.c index 6f4a5436d0ce..d7eee99b7e3f 100644 --- a/trunk/arch/arm/mach-omap2/pm.c +++ b/trunk/arch/arm/mach-omap2/pm.c @@ -370,10 +370,10 @@ static int omap2_pm_finish(suspend_state_t state) } static struct pm_ops omap_pm_ops = { + .pm_disk_mode = 0, .prepare = omap2_pm_prepare, .enter = omap2_pm_enter, .finish = omap2_pm_finish, - .valid = pm_valid_only_mem, }; int __init omap2_pm_init(void) diff --git a/trunk/arch/arm/mach-pnx4008/pm.c b/trunk/arch/arm/mach-pnx4008/pm.c index 2a137f33f752..3649cd3dfc9a 100644 --- a/trunk/arch/arm/mach-pnx4008/pm.c +++ b/trunk/arch/arm/mach-pnx4008/pm.c @@ -107,19 +107,50 @@ static int pnx4008_pm_enter(suspend_state_t state) case PM_SUSPEND_MEM: pnx4008_suspend(); break; + case PM_SUSPEND_DISK: + return -ENOTSUPP; + default: + return -EINVAL; } return 0; } -static int pnx4008_pm_valid(suspend_state_t state) +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int pnx4008_pm_prepare(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + break; + + default: + return -EINVAL; + break; + } + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static int pnx4008_pm_finish(suspend_state_t state) { - return (state == PM_SUSPEND_STANDBY) || - (state == PM_SUSPEND_MEM); + return 0; } +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ static struct pm_ops pnx4008_pm_ops = { + .prepare = pnx4008_pm_prepare, .enter = pnx4008_pm_enter, - .valid = pnx4008_pm_valid, + .finish = pnx4008_pm_finish, }; static int __init pnx4008_pm_init(void) diff --git a/trunk/arch/arm/mach-pxa/pm.c b/trunk/arch/arm/mach-pxa/pm.c index 6bf15ae73848..b4d8276d6050 100644 --- a/trunk/arch/arm/mach-pxa/pm.c +++ b/trunk/arch/arm/mach-pxa/pm.c @@ -223,11 +223,14 @@ int pxa_pm_finish(suspend_state_t state) EXPORT_SYMBOL_GPL(pxa_pm_finish); +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ static struct pm_ops pxa_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, .prepare = pxa_pm_prepare, .enter = pxa_pm_enter, .finish = pxa_pm_finish, - .valid = pm_valid_only_mem, }; static int __init pxa_pm_init(void) diff --git a/trunk/arch/arm/mach-sa1100/pm.c b/trunk/arch/arm/mach-sa1100/pm.c index d674cf343156..786c8534231f 100644 --- a/trunk/arch/arm/mach-sa1100/pm.c +++ b/trunk/arch/arm/mach-sa1100/pm.c @@ -59,6 +59,9 @@ static int sa11x0_pm_enter(suspend_state_t state) unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE]; struct timespec delta, rtc; + if (state != PM_SUSPEND_MEM) + return -EINVAL; + /* preserve current time */ rtc.tv_sec = RCNR; rtc.tv_nsec = 0; @@ -131,9 +134,12 @@ unsigned long sleep_phys_sp(void *sp) return virt_to_phys(sp); } +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ static struct pm_ops sa11x0_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, .enter = sa11x0_pm_enter, - .valid = pm_valid_only_mem, }; static int __init sa11x0_pm_init(void) diff --git a/trunk/arch/arm/mm/fault.c b/trunk/arch/arm/mm/fault.c index 9fd6d2eafb40..fa2d107f0d44 100644 --- a/trunk/arch/arm/mm/fault.c +++ b/trunk/arch/arm/mm/fault.c @@ -438,7 +438,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *) /* * Dispatch a data abort to the relevant handler. */ -asmlinkage void +asmlinkage void __exception do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); @@ -457,7 +457,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) notify_die("", regs, &info, fsr, 0); } -asmlinkage void +asmlinkage void __exception do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { do_translation_fault(addr, 0, regs); diff --git a/trunk/arch/arm/plat-s3c24xx/pm.c b/trunk/arch/arm/plat-s3c24xx/pm.c index c6b03f8ab260..ecf68d611904 100644 --- a/trunk/arch/arm/plat-s3c24xx/pm.c +++ b/trunk/arch/arm/plat-s3c24xx/pm.c @@ -511,6 +511,11 @@ static int s3c2410_pm_enter(suspend_state_t state) return -EINVAL; } + if (state != PM_SUSPEND_MEM) { + printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); + return -EINVAL; + } + /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) @@ -612,9 +617,30 @@ static int s3c2410_pm_enter(suspend_state_t state) return 0; } +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int s3c2410_pm_prepare(suspend_state_t state) +{ + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static int s3c2410_pm_finish(suspend_state_t state) +{ + return 0; +} + +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ static struct pm_ops s3c2410_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, + .prepare = s3c2410_pm_prepare, .enter = s3c2410_pm_enter, - .valid = pm_valid_only_mem, + .finish = s3c2410_pm_finish, }; /* s3c2410_pm_init diff --git a/trunk/arch/arm26/boot/compressed/misc.c b/trunk/arch/arm26/boot/compressed/misc.c index 0714d19c5776..f17f50e5516f 100644 --- a/trunk/arch/arm26/boot/compressed/misc.c +++ b/trunk/arch/arm26/boot/compressed/misc.c @@ -182,7 +182,7 @@ extern int end; static ulg free_mem_ptr; static ulg free_mem_ptr_end; -#define HEAP_SIZE 0x3000 +#define HEAP_SIZE 0x2000 #include "../../../../lib/inflate.c" diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index 3ec76586877e..ce4013aee59b 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -57,18 +57,16 @@ config ARCH_HAS_ILOG2_U64 bool default n -config GENERIC_HWEIGHT +config GENERIC_BUST_SPINLOCK bool - default y -config GENERIC_CALIBRATE_DELAY +config GENERIC_HWEIGHT bool default y -config GENERIC_BUG +config GENERIC_CALIBRATE_DELAY bool default y - depends on BUG source "init/Kconfig" @@ -108,9 +106,6 @@ choice config BOARD_ATSTK1000 bool "ATSTK1000 evaluation board" select BOARD_ATSTK1002 if CPU_AT32AP7000 - -config BOARD_ATNGW100 - bool "ATNGW100 Network Gateway" endchoice choice @@ -121,8 +116,6 @@ config LOADER_U_BOOT bool "U-Boot (or similar) bootloader" endchoice -source "arch/avr32/mach-at32ap/Kconfig" - config LOAD_ADDRESS hex default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y diff --git a/trunk/arch/avr32/Makefile b/trunk/arch/avr32/Makefile index 6115fc1f0cfa..7b842e98efed 100644 --- a/trunk/arch/avr32/Makefile +++ b/trunk/arch/avr32/Makefile @@ -27,7 +27,6 @@ head-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/head.o head-y += arch/avr32/kernel/head.o core-$(CONFIG_PLATFORM_AT32AP) += arch/avr32/mach-at32ap/ core-$(CONFIG_BOARD_ATSTK1000) += arch/avr32/boards/atstk1000/ -core-$(CONFIG_BOARD_ATNGW100) += arch/avr32/boards/atngw100/ core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/ core-y += arch/avr32/kernel/ core-y += arch/avr32/mm/ diff --git a/trunk/arch/avr32/boards/atngw100/Makefile b/trunk/arch/avr32/boards/atngw100/Makefile deleted file mode 100644 index c740aa116755..000000000000 --- a/trunk/arch/avr32/boards/atngw100/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += setup.o flash.o diff --git a/trunk/arch/avr32/boards/atngw100/flash.c b/trunk/arch/avr32/boards/atngw100/flash.c deleted file mode 100644 index f9b32a8eab9b..000000000000 --- a/trunk/arch/avr32/boards/atngw100/flash.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * ATNGW100 board-specific flash initialization - * - * Copyright (C) 2005-2006 Atmel Corporation - * - * 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 - -static struct smc_config flash_config __initdata = { - .ncs_read_setup = 0, - .nrd_setup = 40, - .ncs_write_setup = 0, - .nwe_setup = 10, - - .ncs_read_pulse = 80, - .nrd_pulse = 40, - .ncs_write_pulse = 65, - .nwe_pulse = 55, - - .read_cycle = 120, - .write_cycle = 120, - - .bus_width = 2, - .nrd_controlled = 1, - .nwe_controlled = 1, - .byte_write = 1, -}; - -static struct mtd_partition flash_parts[] = { - { - .name = "u-boot", - .offset = 0x00000000, - .size = 0x00020000, /* 128 KiB */ - .mask_flags = MTD_WRITEABLE, - }, - { - .name = "root", - .offset = 0x00020000, - .size = 0x007d0000, - }, - { - .name = "env", - .offset = 0x007f0000, - .size = 0x00010000, - .mask_flags = MTD_WRITEABLE, - }, -}; - -static struct physmap_flash_data flash_data = { - .width = 2, - .nr_parts = ARRAY_SIZE(flash_parts), - .parts = flash_parts, -}; - -static struct resource flash_resource = { - .start = 0x00000000, - .end = 0x007fffff, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device flash_device = { - .name = "physmap-flash", - .id = 0, - .resource = &flash_resource, - .num_resources = 1, - .dev = { - .platform_data = &flash_data, - }, -}; - -/* This needs to be called after the SMC has been initialized */ -static int __init atngw100_flash_init(void) -{ - int ret; - - ret = smc_set_configuration(0, &flash_config); - if (ret < 0) { - printk(KERN_ERR "atngw100: failed to set NOR flash timing\n"); - return ret; - } - - platform_device_register(&flash_device); - - return 0; -} -device_initcall(atngw100_flash_init); diff --git a/trunk/arch/avr32/boards/atngw100/setup.c b/trunk/arch/avr32/boards/atngw100/setup.c deleted file mode 100644 index 9bc37d4f6687..000000000000 --- a/trunk/arch/avr32/boards/atngw100/setup.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Board-specific setup code for the ATNGW100 Network Gateway - * - * Copyright (C) 2005-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* Initialized by bootloader-specific startup code. */ -struct tag *bootloader_tags __initdata; - -struct eth_addr { - u8 addr[6]; -}; -static struct eth_addr __initdata hw_addr[2]; -static struct eth_platform_data __initdata eth_data[2]; - -static struct spi_board_info spi0_board_info[] __initdata = { - { - .modalias = "mtd_dataflash", - .max_speed_hz = 10000000, - .chip_select = 0, - }, -}; - -/* - * The next two functions should go away as the boot loader is - * supposed to initialize the macb address registers with a valid - * ethernet address. But we need to keep it around for a while until - * we can be reasonably sure the boot loader does this. - * - * The phy_id is ignored as the driver will probe for it. - */ -static int __init parse_tag_ethernet(struct tag *tag) -{ - int i; - - i = tag->u.ethernet.mac_index; - if (i < ARRAY_SIZE(hw_addr)) - memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address, - sizeof(hw_addr[i].addr)); - - return 0; -} -__tagtable(ATAG_ETHERNET, parse_tag_ethernet); - -static void __init set_hw_addr(struct platform_device *pdev) -{ - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - const u8 *addr; - void __iomem *regs; - struct clk *pclk; - - if (!res) - return; - if (pdev->id >= ARRAY_SIZE(hw_addr)) - return; - - addr = hw_addr[pdev->id].addr; - if (!is_valid_ether_addr(addr)) - return; - - /* - * Since this is board-specific code, we'll cheat and use the - * physical address directly as we happen to know that it's - * the same as the virtual address. - */ - regs = (void __iomem __force *)res->start; - pclk = clk_get(&pdev->dev, "pclk"); - if (!pclk) - return; - - clk_enable(pclk); - __raw_writel((addr[3] << 24) | (addr[2] << 16) - | (addr[1] << 8) | addr[0], regs + 0x98); - __raw_writel((addr[5] << 8) | addr[4], regs + 0x9c); - clk_disable(pclk); - clk_put(pclk); -} - -struct platform_device *at32_usart_map[1]; -unsigned int at32_nr_usarts = 1; - -void __init setup_board(void) -{ - at32_map_usart(1, 0); /* USART 1: /dev/ttyS0, DB9 */ - at32_setup_serial_console(0); -} - -static int __init atngw100_init(void) -{ - /* - * ATNGW100 uses 16-bit SDRAM interface, so we don't need to - * reserve any pins for it. - */ - - at32_add_system_devices(); - - at32_add_device_usart(0); - - set_hw_addr(at32_add_device_eth(0, ð_data[0])); - set_hw_addr(at32_add_device_eth(1, ð_data[1])); - - at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); - - return 0; -} -postcore_initcall(atngw100_init); diff --git a/trunk/arch/avr32/boards/atstk1000/atstk1002.c b/trunk/arch/avr32/boards/atstk1000/atstk1002.c index abe6ca203fa7..5974768a59e5 100644 --- a/trunk/arch/avr32/boards/atstk1000/atstk1002.c +++ b/trunk/arch/avr32/boards/atstk1000/atstk1002.c @@ -33,7 +33,7 @@ struct eth_addr { static struct eth_addr __initdata hw_addr[2]; static struct eth_platform_data __initdata eth_data[2]; -static struct lcdc_platform_data atstk1000_fb0_data; +extern struct lcdc_platform_data atstk1000_fb0_data; static struct spi_board_info spi0_board_info[] __initdata = { { @@ -148,8 +148,6 @@ static int __init atstk1002_init(void) set_hw_addr(at32_add_device_eth(0, ð_data[0])); at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); - atstk1000_fb0_data.fbmem_start = fbmem_start; - atstk1000_fb0_data.fbmem_size = fbmem_size; at32_add_device_lcdc(0, &atstk1000_fb0_data); return 0; diff --git a/trunk/arch/avr32/boards/atstk1000/setup.c b/trunk/arch/avr32/boards/atstk1000/setup.c index 2bc4b88d7edb..272c011802a7 100644 --- a/trunk/arch/avr32/boards/atstk1000/setup.c +++ b/trunk/arch/avr32/boards/atstk1000/setup.c @@ -18,3 +18,33 @@ /* Initialized by bootloader-specific startup code. */ struct tag *bootloader_tags __initdata; + +struct lcdc_platform_data __initdata atstk1000_fb0_data; + +void __init board_setup_fbmem(unsigned long fbmem_start, + unsigned long fbmem_size) +{ + if (!fbmem_size) + return; + + if (!fbmem_start) { + void *fbmem; + + fbmem = alloc_bootmem_low_pages(fbmem_size); + fbmem_start = __pa(fbmem); + } else { + pg_data_t *pgdat; + + for_each_online_pgdat(pgdat) { + if (fbmem_start >= pgdat->bdata->node_boot_start + && fbmem_start <= pgdat->bdata->node_low_pfn) + reserve_bootmem_node(pgdat, fbmem_start, + fbmem_size); + } + } + + printk("%luKiB framebuffer memory at address 0x%08lx\n", + fbmem_size >> 10, fbmem_start); + atstk1000_fb0_data.fbmem_start = fbmem_start; + atstk1000_fb0_data.fbmem_size = fbmem_size; +} diff --git a/trunk/arch/avr32/configs/atngw100_defconfig b/trunk/arch/avr32/configs/atngw100_defconfig deleted file mode 100644 index c254ffcfa458..000000000000 --- a/trunk/arch/avr32/configs/atngw100_defconfig +++ /dev/null @@ -1,1085 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc6 -# Thu Apr 12 16:35:07 2007 -# -CONFIG_AVR32=y -CONFIG_GENERIC_GPIO=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_HARDIRQS_SW_RESEND=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_TIME=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_BUG=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -# CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set -# CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set -CONFIG_SYSFS_DEPRECATED=y -# CONFIG_RELAY is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL=y -CONFIG_EMBEDDED=y -# CONFIG_SYSCTL_SYSCALL is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set -# CONFIG_KALLSYMS_EXTRA_PASS is not set -CONFIG_HOTPLUG=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -# CONFIG_BASE_FULL is not set -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=1 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y - -# -# Block layer -# -CONFIG_BLOCK=y -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -# CONFIG_IOSCHED_DEADLINE is not set -CONFIG_IOSCHED_CFQ=y -# CONFIG_DEFAULT_AS is not set -# CONFIG_DEFAULT_DEADLINE is not set -CONFIG_DEFAULT_CFQ=y -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="cfq" - -# -# System Type and features -# -CONFIG_SUBARCH_AVR32B=y -CONFIG_MMU=y -CONFIG_PERFORMANCE_COUNTERS=y -CONFIG_PLATFORM_AT32AP=y -CONFIG_CPU_AT32AP7000=y -# CONFIG_BOARD_ATSTK1000 is not set -CONFIG_BOARD_ATNGW100=y -CONFIG_LOADER_U_BOOT=y - -# -# Atmel AVR32 AP options -# -# CONFIG_AP7000_32_BIT_SMC is not set -CONFIG_AP7000_16_BIT_SMC=y -# CONFIG_AP7000_8_BIT_SMC is not set -CONFIG_LOAD_ADDRESS=0x10000000 -CONFIG_ENTRY_ADDRESS=0x90000000 -CONFIG_PHYS_OFFSET=0x10000000 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set -# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set -# CONFIG_NEED_NODE_MEMMAP_SIZE is not set -CONFIG_ARCH_FLATMEM_ENABLE=y -# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set -# CONFIG_ARCH_SPARSEMEM_ENABLE is not set -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=0 -# CONFIG_OWNERSHIP_TRACE is not set -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -CONFIG_CMDLINE="" - -# -# Bus options -# - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=y -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set -CONFIG_NET_KEY=y -# CONFIG_NET_KEY_MIGRATE is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_ASK_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_MULTIPLE_TABLES is not set -# CONFIG_IP_ROUTE_MULTIPATH is not set -# CONFIG_IP_ROUTE_VERBOSE is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -# CONFIG_IP_PIMSM_V2 is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_IPCOMP=y -CONFIG_INET_XFRM_TUNNEL=y -CONFIG_INET_TUNNEL=y -CONFIG_INET_XFRM_MODE_TRANSPORT=y -CONFIG_INET_XFRM_MODE_TUNNEL=y -CONFIG_INET_XFRM_MODE_BEET=y -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set - -# -# IP: Virtual Server Configuration -# -# CONFIG_IP_VS is not set -CONFIG_IPV6=y -# CONFIG_IPV6_PRIVACY is not set -# CONFIG_IPV6_ROUTER_PREF is not set -CONFIG_INET6_AH=y -CONFIG_INET6_ESP=y -CONFIG_INET6_IPCOMP=y -# CONFIG_IPV6_MIP6 is not set -CONFIG_INET6_XFRM_TUNNEL=y -CONFIG_INET6_TUNNEL=y -CONFIG_INET6_XFRM_MODE_TRANSPORT=y -CONFIG_INET6_XFRM_MODE_TUNNEL=y -CONFIG_INET6_XFRM_MODE_BEET=y -# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set -CONFIG_IPV6_SIT=y -# CONFIG_IPV6_TUNNEL is not set -# CONFIG_IPV6_MULTIPLE_TABLES is not set -# CONFIG_NETWORK_SECMARK is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set - -# -# Core Netfilter Configuration -# -# CONFIG_NETFILTER_NETLINK is not set -CONFIG_NF_CONNTRACK_ENABLED=m -CONFIG_NF_CONNTRACK_SUPPORT=y -# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CT_ACCT=y -CONFIG_NF_CONNTRACK_MARK=y -# CONFIG_NF_CONNTRACK_EVENTS is not set -CONFIG_NF_CT_PROTO_GRE=m -# CONFIG_NF_CT_PROTO_SCTP is not set -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NETFILTER_XTABLES=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set -# CONFIG_NETFILTER_XT_TARGET_DSCP is not set -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -# CONFIG_NETFILTER_XT_MATCH_DCCP is not set -# CONFIG_NETFILTER_XT_MATCH_DSCP is not set -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -# CONFIG_NETFILTER_XT_MATCH_SCTP is not set -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m - -# -# IP: Netfilter Configuration -# -CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_NF_CONNTRACK_PROC_COMPAT=y -# CONFIG_IP_NF_QUEUE is not set -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -# CONFIG_IP_NF_TARGET_ULOG is not set -CONFIG_NF_NAT=m -CONFIG_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PROTO_GRE=m -CONFIG_NF_NAT_FTP=m -CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m -CONFIG_NF_NAT_SIP=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m - -# -# IPv6: Netfilter Configuration (EXPERIMENTAL) -# -CONFIG_NF_CONNTRACK_IPV6=m -CONFIG_IP6_NF_QUEUE=m -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_OWNER=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_LOG=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_RAW=m - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -CONFIG_VLAN_8021Q=m -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -CONFIG_NET_CLS_ROUTE=y - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_IEEE80211 is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# -# CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# -CONFIG_MTD=y -# CONFIG_MTD_DEBUG is not set -# CONFIG_MTD_CONCAT is not set -CONFIG_MTD_PARTITIONS=y -# CONFIG_MTD_REDBOOT_PARTS is not set -CONFIG_MTD_CMDLINE_PARTS=y - -# -# User Modules And Translation Layers -# -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y -CONFIG_MTD_BLOCK=y -# CONFIG_FTL is not set -# CONFIG_NFTL is not set -# CONFIG_INFTL is not set -# CONFIG_RFD_FTL is not set -# CONFIG_SSFDC is not set - -# -# RAM/ROM/Flash chip drivers -# -CONFIG_MTD_CFI=y -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_GEN_PROBE=y -# CONFIG_MTD_CFI_ADV_OPTIONS is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -# CONFIG_MTD_CFI_I4 is not set -# CONFIG_MTD_CFI_I8 is not set -# CONFIG_MTD_CFI_INTELEXT is not set -CONFIG_MTD_CFI_AMDSTD=y -# CONFIG_MTD_CFI_STAA is not set -CONFIG_MTD_CFI_UTIL=y -# CONFIG_MTD_RAM is not set -# CONFIG_MTD_ROM is not set -# CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set - -# -# Mapping drivers for chip access -# -# CONFIG_MTD_COMPLEX_MAPPINGS is not set -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_PHYSMAP_START=0x80000000 -CONFIG_MTD_PHYSMAP_LEN=0x0 -CONFIG_MTD_PHYSMAP_BANKWIDTH=2 -# CONFIG_MTD_PLATRAM is not set - -# -# Self-contained MTD device drivers -# -CONFIG_MTD_DATAFLASH=y -# CONFIG_MTD_M25P80 is not set -# CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_PHRAM is not set -# CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLOCK2MTD is not set - -# -# Disk-On-Chip Device Drivers -# -# CONFIG_MTD_DOC2000 is not set -# CONFIG_MTD_DOC2001 is not set -# CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# -# CONFIG_MTD_NAND is not set - -# -# OneNAND Flash Device Drivers -# -# CONFIG_MTD_ONENAND is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=m -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_NETLINK is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# -# CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m - -# -# PHY device support -# -# CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MACB=y - -# -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -# CONFIG_PPP_SYNC_TTY is not set -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set -CONFIG_SLHC=m -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -# CONFIG_INPUT is not set - -# -# Hardware I/O ports -# -# CONFIG_SERIO is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -# CONFIG_VT is not set -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -# CONFIG_SERIAL_8250 is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_SERIAL_ATMEL_TTYAT is not set -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -# CONFIG_LEGACY_PTYS is not set - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set -CONFIG_SPI_MASTER=y - -# -# SPI Master Controller Drivers -# -CONFIG_SPI_ATMEL=y -# CONFIG_SPI_BITBANG is not set - -# -# SPI Protocol Masters -# -# CONFIG_SPI_AT25 is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -# CONFIG_FB is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# - -# -# Auxiliary Display support -# - -# -# Virtualization -# - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -# CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_GFS2_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_INOTIFY is not set -# CONFIG_QUOTA is not set -# CONFIG_DNOTIFY is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -CONFIG_FUSE_FS=m - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_CODEPAGE=850 -CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -# CONFIG_PROC_KCORE is not set -CONFIG_PROC_SYSCTL=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -# CONFIG_TMPFS_POSIX_ACL is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -CONFIG_CONFIGFS_FS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=0 -CONFIG_JFFS2_FS_WRITEBUFFER=y -# CONFIG_JFFS2_SUMMARY is not set -# CONFIG_JFFS2_FS_XATTR is not set -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set -CONFIG_JFFS2_ZLIB=y -CONFIG_JFFS2_RTIME=y -# CONFIG_JFFS2_RUBIN is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -CONFIG_SMB_FS=m -# CONFIG_SMB_NLS_DEFAULT is not set -CONFIG_CIFS=m -# CONFIG_CIFS_STATS is not set -# CONFIG_CIFS_WEAK_PW_HASH is not set -# CONFIG_CIFS_XATTR is not set -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_CIFS_EXPERIMENTAL is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -CONFIG_NLS_CODEPAGE_850=y -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=y -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=y - -# -# Distributed Lock Manager -# -# CONFIG_DLM is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -CONFIG_ENABLE_MUST_CHECK=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set -# CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set -CONFIG_DEBUG_BUGVERBOSE=y -# CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_LIST is not set -CONFIG_FRAME_POINTER=y -# CONFIG_FORCED_INLINING is not set -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_FAULT_INJECTION is not set -# CONFIG_KPROBES is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_BLKCIPHER=y -CONFIG_CRYPTO_HASH=y -CONFIG_CRYPTO_MANAGER=y -CONFIG_CRYPTO_HMAC=y -# CONFIG_CRYPTO_XCBC is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_MD4 is not set -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=y -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -# CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_GF128MUL is not set -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_PCBC=m -# CONFIG_CRYPTO_LRW is not set -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_FCRYPT is not set -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_TEA is not set -CONFIG_CRYPTO_ARC4=m -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -CONFIG_CRYPTO_DEFLATE=y -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -CONFIG_BITREVERSE=y -CONFIG_CRC_CCITT=m -# CONFIG_CRC16 is not set -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/avr32/kernel/cpu.c b/trunk/arch/avr32/kernel/cpu.c index 2714cf6452b5..2e72fd2699df 100644 --- a/trunk/arch/avr32/kernel/cpu.c +++ b/trunk/arch/avr32/kernel/cpu.c @@ -209,17 +209,16 @@ static const char *mmu_types[] = { void __init setup_processor(void) { unsigned long config0, config1; - unsigned long features; unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type; unsigned tmp; - config0 = sysreg_read(CONFIG0); - config1 = sysreg_read(CONFIG1); - cpu_id = SYSREG_BFEXT(PROCESSORID, config0); - cpu_rev = SYSREG_BFEXT(PROCESSORREVISION, config0); - arch_id = SYSREG_BFEXT(AT, config0); - arch_rev = SYSREG_BFEXT(AR, config0); - mmu_type = SYSREG_BFEXT(MMUT, config0); + config0 = sysreg_read(CONFIG0); /* 0x0000013e; */ + config1 = sysreg_read(CONFIG1); /* 0x01f689a2; */ + cpu_id = config0 >> 24; + cpu_rev = (config0 >> 16) & 0xff; + arch_id = (config0 >> 13) & 0x07; + arch_rev = (config0 >> 10) & 0x07; + mmu_type = (config0 >> 7) & 0x03; boot_cpu_data.arch_type = arch_id; boot_cpu_data.cpu_type = cpu_id; @@ -227,16 +226,16 @@ void __init setup_processor(void) boot_cpu_data.cpu_revision = cpu_rev; boot_cpu_data.tlb_config = mmu_type; - tmp = SYSREG_BFEXT(ILSZ, config1); + tmp = (config1 >> 13) & 0x07; if (tmp) { - boot_cpu_data.icache.ways = 1 << SYSREG_BFEXT(IASS, config1); - boot_cpu_data.icache.sets = 1 << SYSREG_BFEXT(ISET, config1); + boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07); + boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f); boot_cpu_data.icache.linesz = 1 << (tmp + 1); } - tmp = SYSREG_BFEXT(DLSZ, config1); + tmp = (config1 >> 3) & 0x07; if (tmp) { - boot_cpu_data.dcache.ways = 1 << SYSREG_BFEXT(DASS, config1); - boot_cpu_data.dcache.sets = 1 << SYSREG_BFEXT(DSET, config1); + boot_cpu_data.dcache.ways = 1 << (config1 & 0x07); + boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f); boot_cpu_data.dcache.linesz = 1 << (tmp + 1); } @@ -251,39 +250,16 @@ void __init setup_processor(void) cpu_names[cpu_id], cpu_id, cpu_rev, arch_names[arch_id], arch_rev); printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]); - printk ("CPU: features:"); - features = 0; - if (config0 & SYSREG_BIT(CONFIG0_R)) { - features |= AVR32_FEATURE_RMW; - printk(" rmw"); - } - if (config0 & SYSREG_BIT(CONFIG0_D)) { - features |= AVR32_FEATURE_DSP; - printk(" dsp"); - } - if (config0 & SYSREG_BIT(CONFIG0_S)) { - features |= AVR32_FEATURE_SIMD; - printk(" simd"); - } - if (config0 & SYSREG_BIT(CONFIG0_O)) { - features |= AVR32_FEATURE_OCD; - printk(" ocd"); - } - if (config0 & SYSREG_BIT(CONFIG0_P)) { - features |= AVR32_FEATURE_PCTR; - printk(" perfctr"); - } - if (config0 & SYSREG_BIT(CONFIG0_J)) { - features |= AVR32_FEATURE_JAVA; - printk(" java"); - } - if (config0 & SYSREG_BIT(CONFIG0_F)) { - features |= AVR32_FEATURE_FPU; + if (config0 & (1 << 6)) printk(" fpu"); - } + if (config0 & (1 << 5)) + printk(" java"); + if (config0 & (1 << 4)) + printk(" perfctr"); + if (config0 & (1 << 3)) + printk(" ocd"); printk("\n"); - boot_cpu_data.features = features; } #ifdef CONFIG_PROC_FS diff --git a/trunk/arch/avr32/kernel/entry-avr32b.S b/trunk/arch/avr32/kernel/entry-avr32b.S index 42657f1703b2..eeb66792bc37 100644 --- a/trunk/arch/avr32/kernel/entry-avr32b.S +++ b/trunk/arch/avr32/kernel/entry-avr32b.S @@ -100,49 +100,55 @@ dtlb_miss_write: .global tlb_miss_common tlb_miss_common: - mfsr r0, SYSREG_TLBEAR - mfsr r1, SYSREG_PTBR + mfsr r0, SYSREG_PTBR + mfsr r1, SYSREG_TLBEAR /* Is it the vmalloc space? */ - bld r0, 31 + bld r1, 31 brcs handle_vmalloc_miss /* First level lookup */ pgtbl_lookup: - lsr r2, r0, PGDIR_SHIFT - ld.w r3, r1[r2 << 2] - bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT - bld r3, _PAGE_BIT_PRESENT + lsr r2, r1, PGDIR_SHIFT + ld.w r0, r0[r2 << 2] + bld r0, _PAGE_BIT_PRESENT brcc page_table_not_present + /* TODO: Check access rights on page table if necessary */ + /* Translate to virtual address in P1. */ - andl r3, 0xf000 - sbr r3, 31 + andl r0, 0xf000 + sbr r0, 31 /* Second level lookup */ - ld.w r2, r3[r1 << 2] - mfsr r0, SYSREG_TLBARLO - bld r2, _PAGE_BIT_PRESENT + lsl r1, (32 - PGDIR_SHIFT) + lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT + add r2, r0, r1 << 2 + ld.w r1, r2[0] + bld r1, _PAGE_BIT_PRESENT brcc page_not_present /* Mark the page as accessed */ - sbr r2, _PAGE_BIT_ACCESSED - st.w r3[r1 << 2], r2 + sbr r1, _PAGE_BIT_ACCESSED + st.w r2[0], r1 /* Drop software flags */ - andl r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff - mtsr SYSREG_TLBELO, r2 + andl r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff + mtsr SYSREG_TLBELO, r1 /* Figure out which entry we want to replace */ - mfsr r1, SYSREG_MMUCR + mfsr r0, SYSREG_TLBARLO clz r2, r0 brcc 1f - mov r3, -1 /* All entries have been accessed, */ - mov r2, 0 /* so start at 0 */ - mtsr SYSREG_TLBARLO, r3 /* and reset TLBAR */ - -1: bfins r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE + mov r1, -1 /* All entries have been accessed, */ + mtsr SYSREG_TLBARLO, r1 /* so reset TLBAR */ + mov r2, 0 /* and start at 0 */ +1: mfsr r1, SYSREG_MMUCR + lsl r2, 14 + andl r1, 0x3fff, COH + or r1, r2 mtsr SYSREG_MMUCR, r1 + tlbw tlbmiss_restore @@ -150,8 +156,8 @@ pgtbl_lookup: handle_vmalloc_miss: /* Simply do the lookup in init's page table */ - mov r1, lo(swapper_pg_dir) - orh r1, hi(swapper_pg_dir) + mov r0, lo(swapper_pg_dir) + orh r0, hi(swapper_pg_dir) rjmp pgtbl_lookup @@ -334,34 +340,12 @@ do_bus_error_read: do_nmi_ll: sub sp, 4 stmts --sp, r0-lr - mfsr r9, SYSREG_RSR_NMI - mfsr r8, SYSREG_RAR_NMI - bfextu r0, r9, MODE_SHIFT, 3 - brne 2f - -1: pushm r8, r9 /* PC and SR */ + /* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */ + rcall save_full_context_ex mfsr r12, SYSREG_ECR mov r11, sp rcall do_nmi - popm r8-r9 - mtsr SYSREG_RAR_NMI, r8 - tst r0, r0 - mtsr SYSREG_RSR_NMI, r9 - brne 3f - - ldmts sp++, r0-lr - sub sp, -4 /* skip r12_orig */ - rete - -2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR) - stdsp sp[4], r10 /* replace saved SP */ - rjmp 1b - -3: popm lr - sub sp, -4 /* skip sp */ - popm r0-r12 - sub sp, -4 /* skip r12_orig */ - rete + rjmp bad_return handle_address_fault: sub sp, 4 @@ -646,12 +630,9 @@ irq_level\level: rcall do_IRQ lddsp r4, sp[REG_SR] - bfextu r4, r4, SYSREG_M0_OFFSET, 3 - cp.w r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET - breq 2f - cp.w r4, MODE_USER >> SYSREG_M0_OFFSET + andh r4, (MODE_MASK >> 16), COH #ifdef CONFIG_PREEMPT - brne 3f + brne 2f #else brne 1f #endif @@ -668,18 +649,9 @@ irq_level\level: sub sp, -4 /* ignore r12_orig */ rete -2: get_thread_info r0 - ld.w r1, r0[TI_flags] - bld r1, TIF_CPU_GOING_TO_SLEEP -#ifdef CONFIG_PREEMPT - brcc 3f -#else - brcc 1b -#endif - sub r1, pc, . - cpu_idle_skip_sleep - stdsp sp[REG_PC], r1 #ifdef CONFIG_PREEMPT -3: get_thread_info r0 +2: + get_thread_info r0 ld.w r2, r0[TI_preempt_count] cp.w r2, 0 brne 1b @@ -690,32 +662,12 @@ irq_level\level: bld r4, SYSREG_GM_OFFSET brcs 1b rcall preempt_schedule_irq -#endif rjmp 1b +#endif .endm .section .irq.text,"ax",@progbits -.global cpu_idle_sleep -cpu_idle_sleep: - mask_interrupts - get_thread_info r8 - ld.w r9, r8[TI_flags] - bld r9, TIF_NEED_RESCHED - brcs cpu_idle_enable_int_and_exit - sbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 - unmask_interrupts - sleep 0 -cpu_idle_skip_sleep: - mask_interrupts - ld.w r9, r8[TI_flags] - cbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 -cpu_idle_enable_int_and_exit: - unmask_interrupts - retal r12 - .global irq_level0 .global irq_level1 .global irq_level2 diff --git a/trunk/arch/avr32/kernel/module.c b/trunk/arch/avr32/kernel/module.c index 1167fe9cf6c4..b599eae64576 100644 --- a/trunk/arch/avr32/kernel/module.c +++ b/trunk/arch/avr32/kernel/module.c @@ -12,11 +12,10 @@ * published by the Free Software Foundation. */ -#include -#include -#include -#include #include +#include +#include +#include #include void *module_alloc(unsigned long size) @@ -316,10 +315,10 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, vfree(module->arch.syminfo); module->arch.syminfo = NULL; - return module_bug_finalize(hdr, sechdrs, module); + return 0; } void module_arch_cleanup(struct module *module) { - module_bug_cleanup(module); + } diff --git a/trunk/arch/avr32/kernel/process.c b/trunk/arch/avr32/kernel/process.c index 4e4181ed1c6d..0b4325946a41 100644 --- a/trunk/arch/avr32/kernel/process.c +++ b/trunk/arch/avr32/kernel/process.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -20,8 +19,6 @@ void (*pm_power_off)(void) = NULL; EXPORT_SYMBOL(pm_power_off); -extern void cpu_idle_sleep(void); - /* * This file handles the architecture-dependent parts of process handling.. */ @@ -30,8 +27,9 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ while (1) { + /* TODO: Enter sleep mode */ while (!need_resched()) - cpu_idle_sleep(); + cpu_relax(); preempt_enable_no_resched(); schedule(); preempt_disable(); @@ -116,178 +114,39 @@ void release_thread(struct task_struct *dead_task) /* do nothing */ } -static void dump_mem(const char *str, const char *log_lvl, - unsigned long bottom, unsigned long top) -{ - unsigned long p; - int i; - - printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top); - - for (p = bottom & ~31; p < top; ) { - printk("%s%04lx: ", log_lvl, p & 0xffff); - - for (i = 0; i < 8; i++, p += 4) { - unsigned int val; - - if (p < bottom || p >= top) - printk(" "); - else { - if (__get_user(val, (unsigned int __user *)p)) { - printk("\n"); - goto out; - } - printk("%08x ", val); - } - } - printk("\n"); - } - -out: - return; -} - -static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p) -{ - return (p > (unsigned long)tinfo) - && (p < (unsigned long)tinfo + THREAD_SIZE - 3); -} - -#ifdef CONFIG_FRAME_POINTER -static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp, - struct pt_regs *regs, const char *log_lvl) -{ - unsigned long lr, fp; - struct thread_info *tinfo; - - if (regs) - fp = regs->r7; - else if (tsk == current) - asm("mov %0, r7" : "=r"(fp)); - else - fp = tsk->thread.cpu_context.r7; - - /* - * Walk the stack as long as the frame pointer (a) is within - * the kernel stack of the task, and (b) it doesn't move - * downwards. - */ - tinfo = task_thread_info(tsk); - printk("%sCall trace:\n", log_lvl); - while (valid_stack_ptr(tinfo, fp)) { - unsigned long new_fp; - - lr = *(unsigned long *)fp; -#ifdef CONFIG_KALLSYMS - printk("%s [<%08lx>] ", log_lvl, lr); -#else - printk(" [<%08lx>] ", lr); -#endif - print_symbol("%s\n", lr); - - new_fp = *(unsigned long *)(fp + 4); - if (new_fp <= fp) - break; - fp = new_fp; - } - printk("\n"); -} -#else -static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp, - struct pt_regs *regs, const char *log_lvl) -{ - unsigned long addr; - - printk("%sCall trace:\n", log_lvl); - - while (!kstack_end(sp)) { - addr = *sp++; - if (kernel_text_address(addr)) { -#ifdef CONFIG_KALLSYMS - printk("%s [<%08lx>] ", log_lvl, addr); -#else - printk(" [<%08lx>] ", addr); -#endif - print_symbol("%s\n", addr); - } - } - printk("\n"); -} -#endif - -void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp, - struct pt_regs *regs, const char *log_lvl) -{ - struct thread_info *tinfo; - - if (sp == 0) { - if (tsk) - sp = tsk->thread.cpu_context.ksp; - else - sp = (unsigned long)&tinfo; - } - if (!tsk) - tsk = current; - - tinfo = task_thread_info(tsk); - - if (valid_stack_ptr(tinfo, sp)) { - dump_mem("Stack: ", log_lvl, sp, - THREAD_SIZE + (unsigned long)tinfo); - show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl); - } -} - -void show_stack(struct task_struct *tsk, unsigned long *stack) -{ - show_stack_log_lvl(tsk, (unsigned long)stack, NULL, ""); -} - -void dump_stack(void) -{ - unsigned long stack; - - show_trace_log_lvl(current, &stack, NULL, ""); -} -EXPORT_SYMBOL(dump_stack); - static const char *cpu_modes[] = { "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1", "Interrupt level 2", "Interrupt level 3", "Exception", "NMI" }; -void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl) +void show_regs(struct pt_regs *regs) { unsigned long sp = regs->sp; unsigned long lr = regs->lr; unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT; - if (!user_mode(regs)) { + if (!user_mode(regs)) sp = (unsigned long)regs + FRAME_SIZE_FULL; - printk("%s", log_lvl); - print_symbol("PC is at %s\n", instruction_pointer(regs)); - printk("%s", log_lvl); - print_symbol("LR is at %s\n", lr); - } - - printk("%spc : [<%08lx>] lr : [<%08lx>] %s\n" - "%ssp : %08lx r12: %08lx r11: %08lx\n", - log_lvl, instruction_pointer(regs), lr, print_tainted(), - log_lvl, sp, regs->r12, regs->r11); - printk("%sr10: %08lx r9 : %08lx r8 : %08lx\n", - log_lvl, regs->r10, regs->r9, regs->r8); - printk("%sr7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", - log_lvl, regs->r7, regs->r6, regs->r5, regs->r4); - printk("%sr3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", - log_lvl, regs->r3, regs->r2, regs->r1, regs->r0); - printk("%sFlags: %c%c%c%c%c\n", log_lvl, + print_symbol("PC is at %s\n", instruction_pointer(regs)); + print_symbol("LR is at %s\n", lr); + printk("pc : [<%08lx>] lr : [<%08lx>] %s\n" + "sp : %08lx r12: %08lx r11: %08lx\n", + instruction_pointer(regs), + lr, print_tainted(), sp, regs->r12, regs->r11); + printk("r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->r10, regs->r9, regs->r8); + printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->r7, regs->r6, regs->r5, regs->r4); + printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->r3, regs->r2, regs->r1, regs->r0); + printk("Flags: %c%c%c%c%c\n", regs->sr & SR_Q ? 'Q' : 'q', regs->sr & SR_V ? 'V' : 'v', regs->sr & SR_N ? 'N' : 'n', regs->sr & SR_Z ? 'Z' : 'z', regs->sr & SR_C ? 'C' : 'c'); - printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl, + printk("Mode bits: %c%c%c%c%c%c%c%c%c\n", regs->sr & SR_H ? 'H' : 'h', regs->sr & SR_R ? 'R' : 'r', regs->sr & SR_J ? 'J' : 'j', @@ -297,21 +156,9 @@ void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl) regs->sr & SR_I1M ? '1' : '.', regs->sr & SR_I0M ? '0' : '.', regs->sr & SR_GM ? 'G' : 'g'); - printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]); - printk("%sProcess: %s [%d] (task: %p thread: %p)\n", - log_lvl, current->comm, current->pid, current, - task_thread_info(current)); -} - -void show_regs(struct pt_regs *regs) -{ - unsigned long sp = regs->sp; - - if (!user_mode(regs)) - sp = (unsigned long)regs + FRAME_SIZE_FULL; + printk("CPU Mode: %s\n", cpu_modes[mode]); - show_regs_log_lvl(regs, ""); - show_trace_log_lvl(current, (unsigned long *)sp, regs, ""); + show_trace(NULL, (unsigned long *)sp, regs); } EXPORT_SYMBOL(show_regs); diff --git a/trunk/arch/avr32/kernel/setup.c b/trunk/arch/avr32/kernel/setup.c index b279d66acf5f..a1a7c3c3f522 100644 --- a/trunk/arch/avr32/kernel/setup.c +++ b/trunk/arch/avr32/kernel/setup.c @@ -8,14 +8,12 @@ #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -31,6 +29,13 @@ extern int root_mountflags; +/* + * Bootloader-provided information about physical memory + */ +struct tag_mem_range *mem_phys; +struct tag_mem_range *mem_reserved; +struct tag_mem_range *mem_ramdisk; + /* * Initialize loops_per_jiffy as 5000000 (500MIPS). * Better make it too large than too small... @@ -43,193 +48,48 @@ EXPORT_SYMBOL(boot_cpu_data); static char __initdata command_line[COMMAND_LINE_SIZE]; /* - * Standard memory resources - */ -static struct resource __initdata kernel_data = { - .name = "Kernel data", - .start = 0, - .end = 0, - .flags = IORESOURCE_MEM, -}; -static struct resource __initdata kernel_code = { - .name = "Kernel code", - .start = 0, - .end = 0, - .flags = IORESOURCE_MEM, - .sibling = &kernel_data, -}; - -/* - * Available system RAM and reserved regions as singly linked - * lists. These lists are traversed using the sibling pointer in - * struct resource and are kept sorted at all times. + * Should be more than enough, but if you have a _really_ complex + * setup, you might need to increase the size of this... */ -static struct resource *__initdata system_ram; -static struct resource *__initdata reserved = &kernel_code; +static struct tag_mem_range __initdata mem_range_cache[32]; +static unsigned mem_range_next_free; /* - * We need to allocate these before the bootmem allocator is up and - * running, so we need this "cache". 32 entries are probably enough - * for all but the most insanely complex systems. + * Standard memory resources */ -static struct resource __initdata res_cache[32]; -static unsigned int __initdata res_cache_next_free; - -static void __init resource_init(void) -{ - struct resource *mem, *res; - struct resource *new; - - kernel_code.start = __pa(init_mm.start_code); - - for (mem = system_ram; mem; mem = mem->sibling) { - new = alloc_bootmem_low(sizeof(struct resource)); - memcpy(new, mem, sizeof(struct resource)); - - new->sibling = NULL; - if (request_resource(&iomem_resource, new)) - printk(KERN_WARNING "Bad RAM resource %08x-%08x\n", - mem->start, mem->end); - } - - for (res = reserved; res; res = res->sibling) { - new = alloc_bootmem_low(sizeof(struct resource)); - memcpy(new, res, sizeof(struct resource)); - - new->sibling = NULL; - if (insert_resource(&iomem_resource, new)) - printk(KERN_WARNING - "Bad reserved resource %s (%08x-%08x)\n", - res->name, res->start, res->end); - } -} - -static void __init -add_physical_memory(resource_size_t start, resource_size_t end) -{ - struct resource *new, *next, **pprev; - - for (pprev = &system_ram, next = system_ram; next; - pprev = &next->sibling, next = next->sibling) { - if (end < next->start) - break; - if (start <= next->end) { - printk(KERN_WARNING - "Warning: Physical memory map is broken\n"); - printk(KERN_WARNING - "Warning: %08x-%08x overlaps %08x-%08x\n", - start, end, next->start, next->end); - return; - } - } - - if (res_cache_next_free >= ARRAY_SIZE(res_cache)) { - printk(KERN_WARNING - "Warning: Failed to add physical memory %08x-%08x\n", - start, end); - return; - } - - new = &res_cache[res_cache_next_free++]; - new->start = start; - new->end = end; - new->name = "System RAM"; - new->flags = IORESOURCE_MEM; - - *pprev = new; -} - -static int __init -add_reserved_region(resource_size_t start, resource_size_t end, - const char *name) -{ - struct resource *new, *next, **pprev; - - if (end < start) - return -EINVAL; - - if (res_cache_next_free >= ARRAY_SIZE(res_cache)) - return -ENOMEM; - - for (pprev = &reserved, next = reserved; next; - pprev = &next->sibling, next = next->sibling) { - if (end < next->start) - break; - if (start <= next->end) - return -EBUSY; - } - - new = &res_cache[res_cache_next_free++]; - new->start = start; - new->end = end; - new->name = name; - new->flags = IORESOURCE_MEM; - - *pprev = new; - - return 0; -} - -static unsigned long __init -find_free_region(const struct resource *mem, resource_size_t size, - resource_size_t align) -{ - struct resource *res; - unsigned long target; - - target = ALIGN(mem->start, align); - for (res = reserved; res; res = res->sibling) { - if ((target + size) <= res->start) - break; - if (target <= res->end) - target = ALIGN(res->end + 1, align); - } - - if ((target + size) > (mem->end + 1)) - return mem->end + 1; - - return target; -} - -static int __init -alloc_reserved_region(resource_size_t *start, resource_size_t size, - resource_size_t align, const char *name) -{ - struct resource *mem; - resource_size_t target; - int ret; - - for (mem = system_ram; mem; mem = mem->sibling) { - target = find_free_region(mem, size, align); - if (target <= mem->end) { - ret = add_reserved_region(target, target + size - 1, - name); - if (!ret) - *start = target; - return ret; - } - } +static struct resource mem_res[] = { + { + .name = "Kernel code", + .start = 0, + .end = 0, + .flags = IORESOURCE_MEM + }, + { + .name = "Kernel data", + .start = 0, + .end = 0, + .flags = IORESOURCE_MEM, + }, +}; - return -ENOMEM; -} +#define kernel_code mem_res[0] +#define kernel_data mem_res[1] /* * Early framebuffer allocation. Works as follows: * - If fbmem_size is zero, nothing will be allocated or reserved. * - If fbmem_start is zero when setup_bootmem() is called, - * a block of fbmem_size bytes will be reserved before bootmem - * initialization. It will be aligned to the largest page size - * that fbmem_size is a multiple of. + * fbmem_size bytes will be allocated from the bootmem allocator. * - If fbmem_start is nonzero, an area of size fbmem_size will be - * reserved at the physical address fbmem_start if possible. If - * it collides with other reserved memory, a different block of - * same size will be allocated, just as if fbmem_start was zero. + * reserved at the physical address fbmem_start if necessary. If + * the area isn't in a memory region known to the kernel, it will + * be left alone. * * Board-specific code may use these variables to set up platform data * for the framebuffer driver if fbmem_size is nonzero. */ -resource_size_t __initdata fbmem_start; -resource_size_t __initdata fbmem_size; +static unsigned long __initdata fbmem_start; +static unsigned long __initdata fbmem_size; /* * "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for @@ -243,43 +103,49 @@ resource_size_t __initdata fbmem_size; */ static int __init early_parse_fbmem(char *p) { - int ret; - unsigned long align; - fbmem_size = memparse(p, &p); - if (*p == '@') { + if (*p == '@') fbmem_start = memparse(p, &p); - ret = add_reserved_region(fbmem_start, - fbmem_start + fbmem_size - 1, - "Framebuffer"); - if (ret) { - printk(KERN_WARNING - "Failed to reserve framebuffer memory\n"); - fbmem_start = 0; - } - } - - if (!fbmem_start) { - if ((fbmem_size & 0x000fffffUL) == 0) - align = 0x100000; /* 1 MiB */ - else if ((fbmem_size & 0x0000ffffUL) == 0) - align = 0x10000; /* 64 KiB */ - else - align = 0x1000; /* 4 KiB */ - - ret = alloc_reserved_region(&fbmem_start, fbmem_size, - align, "Framebuffer"); - if (ret) { - printk(KERN_WARNING - "Failed to allocate framebuffer memory\n"); - fbmem_size = 0; - } - } - return 0; } early_param("fbmem", early_parse_fbmem); +static inline void __init resource_init(void) +{ + struct tag_mem_range *region; + + kernel_code.start = __pa(init_mm.start_code); + kernel_code.end = __pa(init_mm.end_code - 1); + kernel_data.start = __pa(init_mm.end_code); + kernel_data.end = __pa(init_mm.brk - 1); + + for (region = mem_phys; region; region = region->next) { + struct resource *res; + unsigned long phys_start, phys_end; + + if (region->size == 0) + continue; + + phys_start = region->addr; + phys_end = phys_start + region->size - 1; + + res = alloc_bootmem_low(sizeof(*res)); + res->name = "System RAM"; + res->start = phys_start; + res->end = phys_end; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + request_resource (&iomem_resource, res); + + if (kernel_code.start >= res->start && + kernel_code.end <= res->end) + request_resource (res, &kernel_code); + if (kernel_data.start >= res->start && + kernel_data.end <= res->end) + request_resource (res, &kernel_data); + } +} + static int __init parse_tag_core(struct tag *tag) { if (tag->hdr.size > 2) { @@ -291,9 +157,11 @@ static int __init parse_tag_core(struct tag *tag) } __tagtable(ATAG_CORE, parse_tag_core); -static int __init parse_tag_mem(struct tag *tag) +static int __init parse_tag_mem_range(struct tag *tag, + struct tag_mem_range **root) { - unsigned long start, end; + struct tag_mem_range *cur, **pprev; + struct tag_mem_range *new; /* * Ignore zero-sized entries. If we're running standalone, the @@ -303,53 +171,34 @@ static int __init parse_tag_mem(struct tag *tag) if (tag->u.mem_range.size == 0) return 0; - start = tag->u.mem_range.addr; - end = tag->u.mem_range.addr + tag->u.mem_range.size - 1; - - add_physical_memory(start, end); - return 0; -} -__tagtable(ATAG_MEM, parse_tag_mem); - -static int __init parse_tag_rdimg(struct tag *tag) -{ -#ifdef CONFIG_INITRD - struct tag_mem_range *mem = &tag->u.mem_range; - int ret; + /* + * Copy the data so the bootmem init code doesn't need to care + * about it. + */ + if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache)) + panic("Physical memory map too complex!\n"); - if (initrd_start) { - printk(KERN_WARNING - "Warning: Only the first initrd image will be used\n"); - return 0; - } + new = &mem_range_cache[mem_range_next_free++]; + *new = tag->u.mem_range; - ret = add_reserved_region(mem->start, mem->start + mem->size - 1, - "initrd"); - if (ret) { - printk(KERN_WARNING - "Warning: Failed to reserve initrd memory\n"); - return ret; + pprev = root; + cur = *root; + while (cur) { + pprev = &cur->next; + cur = cur->next; } - initrd_start = (unsigned long)__va(mem->addr); - initrd_end = initrd_start + mem->size; -#else - printk(KERN_WARNING "RAM disk image present, but " - "no initrd support in kernel, ignoring\n"); -#endif + *pprev = new; + new->next = NULL; return 0; } -__tagtable(ATAG_RDIMG, parse_tag_rdimg); -static int __init parse_tag_rsvd_mem(struct tag *tag) +static int __init parse_tag_mem(struct tag *tag) { - struct tag_mem_range *mem = &tag->u.mem_range; - - return add_reserved_region(mem->addr, mem->addr + mem->size - 1, - "Reserved"); + return parse_tag_mem_range(tag, &mem_phys); } -__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem); +__tagtable(ATAG_MEM, parse_tag_mem); static int __init parse_tag_cmdline(struct tag *tag) { @@ -358,6 +207,12 @@ static int __init parse_tag_cmdline(struct tag *tag) } __tagtable(ATAG_CMDLINE, parse_tag_cmdline); +static int __init parse_tag_rdimg(struct tag *tag) +{ + return parse_tag_mem_range(tag, &mem_ramdisk); +} +__tagtable(ATAG_RDIMG, parse_tag_rdimg); + static int __init parse_tag_clock(struct tag *tag) { /* @@ -368,6 +223,12 @@ static int __init parse_tag_clock(struct tag *tag) } __tagtable(ATAG_CLOCK, parse_tag_clock); +static int __init parse_tag_rsvd_mem(struct tag *tag) +{ + return parse_tag_mem_range(tag, &mem_reserved); +} +__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem); + /* * Scan the tag table for this tag, and call its parse function. The * tag table is built by the linker from all the __tagtable @@ -399,137 +260,10 @@ static void __init parse_tags(struct tag *t) t->hdr.tag); } -/* - * Find a free memory region large enough for storing the - * bootmem bitmap. - */ -static unsigned long __init -find_bootmap_pfn(const struct resource *mem) -{ - unsigned long bootmap_pages, bootmap_len; - unsigned long node_pages = PFN_UP(mem->end - mem->start + 1); - unsigned long bootmap_start; - - bootmap_pages = bootmem_bootmap_pages(node_pages); - bootmap_len = bootmap_pages << PAGE_SHIFT; - - /* - * Find a large enough region without reserved pages for - * storing the bootmem bitmap. We can take advantage of the - * fact that all lists have been sorted. - * - * We have to check that we don't collide with any reserved - * regions, which includes the kernel image and any RAMDISK - * images. - */ - bootmap_start = find_free_region(mem, bootmap_len, PAGE_SIZE); - - return bootmap_start >> PAGE_SHIFT; -} - -#define MAX_LOWMEM HIGHMEM_START -#define MAX_LOWMEM_PFN PFN_DOWN(MAX_LOWMEM) - -static void __init setup_bootmem(void) -{ - unsigned bootmap_size; - unsigned long first_pfn, bootmap_pfn, pages; - unsigned long max_pfn, max_low_pfn; - unsigned node = 0; - struct resource *res; - - printk(KERN_INFO "Physical memory:\n"); - for (res = system_ram; res; res = res->sibling) - printk(" %08x-%08x\n", res->start, res->end); - printk(KERN_INFO "Reserved memory:\n"); - for (res = reserved; res; res = res->sibling) - printk(" %08x-%08x: %s\n", - res->start, res->end, res->name); - - nodes_clear(node_online_map); - - if (system_ram->sibling) - printk(KERN_WARNING "Only using first memory bank\n"); - - for (res = system_ram; res; res = NULL) { - first_pfn = PFN_UP(res->start); - max_low_pfn = max_pfn = PFN_DOWN(res->end + 1); - bootmap_pfn = find_bootmap_pfn(res); - if (bootmap_pfn > max_pfn) - panic("No space for bootmem bitmap!\n"); - - if (max_low_pfn > MAX_LOWMEM_PFN) { - max_low_pfn = MAX_LOWMEM_PFN; -#ifndef CONFIG_HIGHMEM - /* - * Lowmem is memory that can be addressed - * directly through P1/P2 - */ - printk(KERN_WARNING - "Node %u: Only %ld MiB of memory will be used.\n", - node, MAX_LOWMEM >> 20); - printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); -#else -#error HIGHMEM is not supported by AVR32 yet -#endif - } - - /* Initialize the boot-time allocator with low memory only. */ - bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn, - first_pfn, max_low_pfn); - - /* - * Register fully available RAM pages with the bootmem - * allocator. - */ - pages = max_low_pfn - first_pfn; - free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn), - PFN_PHYS(pages)); - - /* Reserve space for the bootmem bitmap... */ - reserve_bootmem_node(NODE_DATA(node), - PFN_PHYS(bootmap_pfn), - bootmap_size); - - /* ...and any other reserved regions. */ - for (res = reserved; res; res = res->sibling) { - if (res->start > PFN_PHYS(max_pfn)) - break; - - /* - * resource_init will complain about partial - * overlaps, so we'll just ignore such - * resources for now. - */ - if (res->start >= PFN_PHYS(first_pfn) - && res->end < PFN_PHYS(max_pfn)) - reserve_bootmem_node( - NODE_DATA(node), res->start, - res->end - res->start + 1); - } - - node_set_online(node); - } -} - void __init setup_arch (char **cmdline_p) { struct clk *cpu_clk; - init_mm.start_code = (unsigned long)_text; - init_mm.end_code = (unsigned long)_etext; - init_mm.end_data = (unsigned long)_edata; - init_mm.brk = (unsigned long)_end; - - /* - * Include .init section to make allocations easier. It will - * be removed before the resource is actually requested. - */ - kernel_code.start = __pa(__init_begin); - kernel_code.end = __pa(init_mm.end_code - 1); - kernel_data.start = __pa(init_mm.end_code); - kernel_data.end = __pa(init_mm.brk - 1); - parse_tags(bootloader_tags); setup_processor(); @@ -555,16 +289,24 @@ void __init setup_arch (char **cmdline_p) ((cpu_hz + 500) / 1000) % 1000); } + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; parse_early_param(); setup_bootmem(); + board_setup_fbmem(fbmem_start, fbmem_size); + #ifdef CONFIG_VT conswitchp = &dummy_con; #endif paging_init(); + resource_init(); } diff --git a/trunk/arch/avr32/kernel/time.c b/trunk/arch/avr32/kernel/time.c index 7014a3571ec0..c10833f2ee0c 100644 --- a/trunk/arch/avr32/kernel/time.c +++ b/trunk/arch/avr32/kernel/time.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Atmel Corporation + * Copyright (C) 2004-2006 Atmel Corporation * * Based on MIPS implementation arch/mips/kernel/time.c * Copyright 2001 MontaVista Software Inc. @@ -20,25 +20,18 @@ #include #include #include -#include #include #include #include #include -/* how many counter cycles in a jiffy? */ -static u32 cycles_per_jiffy; - -/* the count value for the next timer interrupt */ -static u32 expirelo; - -cycle_t __weak read_cycle_count(void) +static cycle_t read_cycle_count(void) { return (cycle_t)sysreg_read(COUNT); } -struct clocksource __weak clocksource_avr32 = { +static struct clocksource clocksource_avr32 = { .name = "avr32", .rating = 350, .read = read_cycle_count, @@ -47,20 +40,12 @@ struct clocksource __weak clocksource_avr32 = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -irqreturn_t __weak timer_interrupt(int irq, void *dev_id); - -struct irqaction timer_irqaction = { - .handler = timer_interrupt, - .flags = IRQF_DISABLED, - .name = "timer", -}; - /* * By default we provide the null RTC ops */ static unsigned long null_rtc_get_time(void) { - return mktime(2007, 1, 1, 0, 0, 0); + return mktime(2004, 1, 1, 0, 0, 0); } static int null_rtc_set_time(unsigned long sec) @@ -71,14 +56,23 @@ static int null_rtc_set_time(unsigned long sec) static unsigned long (*rtc_get_time)(void) = null_rtc_get_time; static int (*rtc_set_time)(unsigned long) = null_rtc_set_time; +/* how many counter cycles in a jiffy? */ +static unsigned long cycles_per_jiffy; + +/* cycle counter value at the previous timer interrupt */ +static unsigned int timerhi, timerlo; + +/* the count value for the next timer interrupt */ +static unsigned int expirelo; + static void avr32_timer_ack(void) { - u32 count; + unsigned int count; /* Ack this timer interrupt and set the next one */ expirelo += cycles_per_jiffy; - /* setting COMPARE to 0 stops the COUNT-COMPARE */ if (expirelo == 0) { + printk(KERN_DEBUG "expirelo == 0\n"); sysreg_write(COMPARE, expirelo + 1); } else { sysreg_write(COMPARE, expirelo); @@ -92,56 +86,27 @@ static void avr32_timer_ack(void) } } -int __weak avr32_hpt_init(void) +static unsigned int avr32_hpt_read(void) { - int ret; - unsigned long mult, shift, count_hz; - - count_hz = clk_get_rate(boot_cpu_data.clk); - shift = clocksource_avr32.shift; - mult = clocksource_hz2mult(count_hz, shift); - clocksource_avr32.mult = mult; - - { - u64 tmp; - - tmp = TICK_NSEC; - tmp <<= shift; - tmp += mult / 2; - do_div(tmp, mult); - - cycles_per_jiffy = tmp; - } - - ret = setup_irq(0, &timer_irqaction); - if (ret) { - pr_debug("timer: could not request IRQ 0: %d\n", ret); - return -ENODEV; - } - - printk(KERN_INFO "timer: AT32AP COUNT-COMPARE at irq 0, " - "%lu.%03lu MHz\n", - ((count_hz + 500) / 1000) / 1000, - ((count_hz + 500) / 1000) % 1000); - - return 0; + return sysreg_read(COUNT); } /* * Taken from MIPS c0_hpt_timer_init(). * - * The reason COUNT is written twice is probably to make sure we don't get any - * timer interrupts while we are messing with the counter. + * Why is it so complicated, and what is "count"? My assumption is + * that `count' specifies the "reference cycle", i.e. the cycle since + * reset that should mean "zero". The reason COUNT is written twice is + * probably to make sure we don't get any timer interrupts while we + * are messing with the counter. */ -int __weak avr32_hpt_start(void) +static void avr32_hpt_init(unsigned int count) { - u32 count = sysreg_read(COUNT); + count = sysreg_read(COUNT) - count; expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy; sysreg_write(COUNT, expirelo - cycles_per_jiffy); sysreg_write(COMPARE, expirelo); sysreg_write(COUNT, count); - - return 0; } /* @@ -150,18 +115,26 @@ int __weak avr32_hpt_start(void) * * In UP mode, it is invoked from the (global) timer_interrupt. */ -void local_timer_interrupt(int irq, void *dev_id) +static void local_timer_interrupt(int irq, void *dev_id) { if (current->pid) profile_tick(CPU_PROFILING); update_process_times(user_mode(get_irq_regs())); } -irqreturn_t __weak timer_interrupt(int irq, void *dev_id) +static irqreturn_t +timer_interrupt(int irq, void *dev_id) { + unsigned int count; + /* ack timer interrupt and try to set next interrupt */ + count = avr32_hpt_read(); avr32_timer_ack(); + /* Update timerhi/timerlo for intra-jiffy calibration */ + timerhi += count < timerlo; /* Wrap around */ + timerlo = count; + /* * Call the generic timer interrupt handler */ @@ -180,37 +153,60 @@ irqreturn_t __weak timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static struct irqaction timer_irqaction = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED, + .name = "timer", +}; + void __init time_init(void) { + unsigned long mult, shift, count_hz; int ret; - /* - * Make sure we don't get any COMPARE interrupts before we can - * handle them. - */ - sysreg_write(COMPARE, 0); - xtime.tv_sec = rtc_get_time(); xtime.tv_nsec = 0; set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - ret = avr32_hpt_init(); - if (ret) { - pr_debug("timer: failed setup: %d\n", ret); - return; + printk("Before time_init: count=%08lx, compare=%08lx\n", + (unsigned long)sysreg_read(COUNT), + (unsigned long)sysreg_read(COMPARE)); + + count_hz = clk_get_rate(boot_cpu_data.clk); + shift = clocksource_avr32.shift; + mult = clocksource_hz2mult(count_hz, shift); + clocksource_avr32.mult = mult; + + printk("Cycle counter: mult=%lu, shift=%lu\n", mult, shift); + + { + u64 tmp; + + tmp = TICK_NSEC; + tmp <<= shift; + tmp += mult / 2; + do_div(tmp, mult); + + cycles_per_jiffy = tmp; } + /* This sets up the high precision timer for the first interrupt. */ + avr32_hpt_init(avr32_hpt_read()); + + printk("After time_init: count=%08lx, compare=%08lx\n", + (unsigned long)sysreg_read(COUNT), + (unsigned long)sysreg_read(COMPARE)); + ret = clocksource_register(&clocksource_avr32); if (ret) - pr_debug("timer: could not register clocksource: %d\n", ret); + printk(KERN_ERR + "timer: could not register clocksource: %d\n", ret); - ret = avr32_hpt_start(); - if (ret) { - pr_debug("timer: failed starting: %d\n", ret); - return; - } + ret = setup_irq(0, &timer_irqaction); + if (ret) + printk("timer: could not request IRQ 0: %d\n", ret); } static struct sysdev_class timer_class = { diff --git a/trunk/arch/avr32/kernel/traps.c b/trunk/arch/avr32/kernel/traps.c index 4f0382d8483f..adc01a12d154 100644 --- a/trunk/arch/avr32/kernel/traps.c +++ b/trunk/arch/avr32/kernel/traps.c @@ -5,25 +5,158 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include +#undef DEBUG +#include #include -#include #include +#include #include -#include -#include +#include +#include #include -#include #include -#include -#include +#include +#include + +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) +{ + unsigned long p; + int i; + + printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); + + for (p = bottom & ~31; p < top; ) { + printk("%04lx: ", p & 0xffff); + + for (i = 0; i < 8; i++, p += 4) { + unsigned int val; + + if (p < bottom || p >= top) + printk(" "); + else { + if (__get_user(val, (unsigned int __user *)p)) { + printk("\n"); + goto out; + } + printk("%08x ", val); + } + } + printk("\n"); + } + +out: + return; +} + +static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p) +{ + return (p > (unsigned long)tinfo) + && (p < (unsigned long)tinfo + THREAD_SIZE - 3); +} + +#ifdef CONFIG_FRAME_POINTER +static inline void __show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + unsigned long lr, fp; + struct thread_info *tinfo; + + tinfo = (struct thread_info *) + ((unsigned long)sp & ~(THREAD_SIZE - 1)); + + if (regs) + fp = regs->r7; + else if (tsk == current) + asm("mov %0, r7" : "=r"(fp)); + else + fp = tsk->thread.cpu_context.r7; + + /* + * Walk the stack as long as the frame pointer (a) is within + * the kernel stack of the task, and (b) it doesn't move + * downwards. + */ + while (valid_stack_ptr(tinfo, fp)) { + unsigned long new_fp; + + lr = *(unsigned long *)fp; + printk(" [<%08lx>] ", lr); + print_symbol("%s\n", lr); + + new_fp = *(unsigned long *)(fp + 4); + if (new_fp <= fp) + break; + fp = new_fp; + } + printk("\n"); +} +#else +static inline void __show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + unsigned long addr; + + while (!kstack_end(sp)) { + addr = *sp++; + if (kernel_text_address(addr)) { + printk(" [<%08lx>] ", addr); + print_symbol("%s\n", addr); + } + } +} +#endif + +void show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs) +{ + if (regs && + (((regs->sr & MODE_MASK) == MODE_EXCEPTION) || + ((regs->sr & MODE_MASK) == MODE_USER))) + return; + + printk ("Call trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + + __show_trace(tsk, sp, regs); + printk("\n"); +} + +void show_stack(struct task_struct *tsk, unsigned long *sp) +{ + unsigned long stack; + + if (!tsk) + tsk = current; + if (sp == 0) { + if (tsk == current) { + register unsigned long *real_sp __asm__("sp"); + sp = real_sp; + } else { + sp = (unsigned long *)tsk->thread.cpu_context.ksp; + } + } + + stack = (unsigned long)sp; + dump_mem("Stack: ", stack, + THREAD_SIZE + (unsigned long)tsk->thread_info); + show_trace(tsk, sp, NULL); +} + +void dump_stack(void) +{ + show_stack(NULL, NULL); +} +EXPORT_SYMBOL(dump_stack); ATOMIC_NOTIFIER_HEAD(avr32_die_chain); int register_die_notifier(struct notifier_block *nb) { + pr_debug("register_die_notifier: %p\n", nb); + return atomic_notifier_chain_register(&avr32_die_chain, nb); } EXPORT_SYMBOL(register_die_notifier); @@ -36,103 +169,93 @@ EXPORT_SYMBOL(unregister_die_notifier); static DEFINE_SPINLOCK(die_lock); -void NORET_TYPE die(const char *str, struct pt_regs *regs, long err) +void __die(const char *str, struct pt_regs *regs, unsigned long err, + const char *file, const char *func, unsigned long line) { + struct task_struct *tsk = current; static int die_counter; console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); - printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG, - str, err, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); -#endif -#ifdef CONFIG_FRAME_POINTER - printk("FRAME_POINTER "); -#endif - if (current_cpu_data.features & AVR32_FEATURE_OCD) { - unsigned long did = __mfdr(DBGREG_DID); - printk("chip: 0x%03lx:0x%04lx rev %lu\n", - (did >> 1) & 0x7ff, - (did >> 12) & 0x7fff, - (did >> 28) & 0xf); - } else { - printk("cpu: arch %u r%u / core %u r%u\n", - current_cpu_data.arch_type, - current_cpu_data.arch_revision, - current_cpu_data.cpu_type, - current_cpu_data.cpu_revision); + printk(KERN_ALERT "%s", str); + if (file && func) + printk(" in %s:%s, line %ld", file, func, line); + printk("[#%d]:\n", ++die_counter); + print_modules(); + show_regs(regs); + printk("Process %s (pid: %d, stack limit = 0x%p)\n", + tsk->comm, tsk->pid, tsk->thread_info + 1); + + if (!user_mode(regs) || in_interrupt()) { + dump_mem("Stack: ", regs->sp, + THREAD_SIZE + (unsigned long)tsk->thread_info); } - print_modules(); - show_regs_log_lvl(regs, KERN_EMERG); - show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG); bust_spinlocks(0); spin_unlock_irq(&die_lock); - - if (in_interrupt()) - panic("Fatal exception in interrupt"); - - if (panic_on_oops) - panic("Fatal exception"); - - do_exit(err); + do_exit(SIGSEGV); } -void _exception(long signr, struct pt_regs *regs, int code, - unsigned long addr) +void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err, + const char *file, const char *func, unsigned long line) { - siginfo_t info; - if (!user_mode(regs)) - die("Unhandled exception in kernel mode", regs, signr); - - memset(&info, 0, sizeof(info)); - info.si_signo = signr; - info.si_code = code; - info.si_addr = (void __user *)addr; - force_sig_info(signr, &info, current); - - /* - * Init gets no signals that it doesn't have a handler for. - * That's all very well, but if it has caused a synchronous - * exception and we ignore the resulting signal, it will just - * generate the same exception over and over again and we get - * nowhere. Better to kill it and let the kernel panic. - */ - if (is_init(current)) { - __sighandler_t handler; - - spin_lock_irq(¤t->sighand->siglock); - handler = current->sighand->action[signr-1].sa.sa_handler; - spin_unlock_irq(¤t->sighand->siglock); - if (handler == SIG_DFL) { - /* init has generated a synchronous exception - and it doesn't have a handler for the signal */ - printk(KERN_CRIT "init has generated signal %ld " - "but has no handler for it\n", signr); - do_exit(signr); - } - } + __die(str, regs, err, file, func, line); } asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs) { - printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n"); - show_regs_log_lvl(regs, KERN_ALERT); - show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT); +#ifdef CONFIG_SUBARCH_AVR32B + /* + * The exception entry always saves RSR_EX. For NMI, this is + * wrong; it should be RSR_NMI + */ + regs->sr = sysreg_read(RSR_NMI); +#endif + + printk("NMI taken!!!!\n"); + die("NMI", regs, ecr); + BUG(); } asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs) { - die("Critical exception", regs, SIGKILL); + printk("Unable to handle critical exception %lu at pc = %08lx!\n", + ecr, regs->pc); + die("Oops", regs, ecr); + BUG(); } asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs) { - _exception(SIGBUS, regs, BUS_ADRALN, regs->pc); + siginfo_t info; + + die_if_kernel("Oops: Address exception in kernel mode", regs, ecr); + +#ifdef DEBUG + if (ecr == ECR_ADDR_ALIGN_X) + pr_debug("Instruction Address Exception at pc = %08lx\n", + regs->pc); + else if (ecr == ECR_ADDR_ALIGN_R) + pr_debug("Data Address Exception (Read) at pc = %08lx\n", + regs->pc); + else if (ecr == ECR_ADDR_ALIGN_W) + pr_debug("Data Address Exception (Write) at pc = %08lx\n", + regs->pc); + else + BUG(); + + show_regs(regs); +#endif + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void __user *)regs->pc; + + force_sig_info(SIGBUS, &info, current); } /* This way of handling undefined instructions is stolen from ARM */ @@ -157,8 +280,7 @@ static int do_cop_absent(u32 insn) { int cop_nr; u32 cpucr; - - if ((insn & 0xfdf00000) == 0xf1900000) + if ( (insn & 0xfdf00000) == 0xf1900000 ) /* LDC0 */ cop_nr = 0; else @@ -170,91 +292,136 @@ static int do_cop_absent(u32 insn) sysreg_write(CPUCR, cpucr); cpucr = sysreg_read(CPUCR); - if (!(cpucr & (1 << (24 + cop_nr)))) - return -ENODEV; + if ( !(cpucr & (1 << (24 + cop_nr))) ){ + printk("Coprocessor #%i not found!\n", cop_nr); + return -1; + } return 0; } -int is_valid_bugaddr(unsigned long pc) +#ifdef CONFIG_BUG +#ifdef CONFIG_DEBUG_BUGVERBOSE +static inline void do_bug_verbose(struct pt_regs *regs, u32 insn) +{ + char *file; + u16 line; + char c; + + if (__get_user(line, (u16 __user *)(regs->pc + 2))) + return; + if (__get_user(file, (char * __user *)(regs->pc + 4)) + || (unsigned long)file < PAGE_OFFSET + || __get_user(c, file)) + file = ""; + + printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line); +} +#else +static inline void do_bug_verbose(struct pt_regs *regs, u32 insn) { - unsigned short opcode; - - if (pc < PAGE_OFFSET) - return 0; - if (probe_kernel_address((u16 *)pc, opcode)) - return 0; - return opcode == AVR32_BUG_OPCODE; } +#endif +#endif asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs) { u32 insn; struct undef_hook *hook; + siginfo_t info; void __user *pc; - long code; - - if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) { - enum bug_trap_type type; - type = report_bug(regs->pc); - switch (type) { - case BUG_TRAP_TYPE_NONE: - break; - case BUG_TRAP_TYPE_WARN: - regs->pc += 2; - return; - case BUG_TRAP_TYPE_BUG: - die("Kernel BUG", regs, SIGKILL); - } - } + if (!user_mode(regs)) + goto kernel_trap; local_irq_enable(); - if (user_mode(regs)) { - pc = (void __user *)instruction_pointer(regs); - if (get_user(insn, (u32 __user *)pc)) - goto invalid_area; + pc = (void __user *)instruction_pointer(regs); + if (__get_user(insn, (u32 __user *)pc)) + goto invalid_area; - if (ecr == ECR_COPROC_ABSENT && !do_cop_absent(insn)) + if (ecr == ECR_COPROC_ABSENT) { + if (do_cop_absent(insn) == 0) return; + } - spin_lock_irq(&undef_lock); - list_for_each_entry(hook, &undef_hook, node) { - if ((insn & hook->insn_mask) == hook->insn_val) { - if (hook->fn(regs, insn) == 0) { - spin_unlock_irq(&undef_lock); - return; - } + spin_lock_irq(&undef_lock); + list_for_each_entry(hook, &undef_hook, node) { + if ((insn & hook->insn_mask) == hook->insn_val) { + if (hook->fn(regs, insn) == 0) { + spin_unlock_irq(&undef_lock); + return; } } - spin_unlock_irq(&undef_lock); } + spin_unlock_irq(&undef_lock); + +invalid_area: +#ifdef DEBUG + printk("Illegal instruction at pc = %08lx\n", regs->pc); + if (regs->pc < TASK_SIZE) { + unsigned long ptbr, pgd, pte, *p; + + ptbr = sysreg_read(PTBR); + p = (unsigned long *)ptbr; + pgd = p[regs->pc >> 22]; + p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000); + pte = p[(regs->pc >> 12) & 0x3ff]; + printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte); + } +#endif + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_addr = (void __user *)regs->pc; switch (ecr) { + case ECR_ILLEGAL_OPCODE: + case ECR_UNIMPL_INSTRUCTION: + info.si_code = ILL_ILLOPC; + break; case ECR_PRIVILEGE_VIOLATION: - code = ILL_PRVOPC; + info.si_code = ILL_PRVOPC; break; case ECR_COPROC_ABSENT: - code = ILL_COPROC; + info.si_code = ILL_COPROC; break; default: - code = ILL_ILLOPC; - break; + BUG(); } - _exception(SIGILL, regs, code, regs->pc); + force_sig_info(SIGILL, &info, current); return; -invalid_area: - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->pc); +kernel_trap: +#ifdef CONFIG_BUG + if (__kernel_text_address(instruction_pointer(regs))) { + insn = *(u16 *)instruction_pointer(regs); + if (insn == AVR32_BUG_OPCODE) { + do_bug_verbose(regs, insn); + die("Kernel BUG", regs, 0); + return; + } + } +#endif + + die("Oops: Illegal instruction in kernel code", regs, ecr); } asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs) { - /* We have no FPU yet */ - _exception(SIGILL, regs, ILL_COPROC, regs->pc); + siginfo_t info; + + printk("Floating-point exception at pc = %08lx\n", regs->pc); + + /* We have no FPU... */ + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_addr = (void __user *)regs->pc; + info.si_code = ILL_COPROC; + + force_sig_info(SIGILL, &info, current); } diff --git a/trunk/arch/avr32/kernel/vmlinux.lds.c b/trunk/arch/avr32/kernel/vmlinux.lds.c index 7ad20cfb48a8..ef13b7c78935 100644 --- a/trunk/arch/avr32/kernel/vmlinux.lds.c +++ b/trunk/arch/avr32/kernel/vmlinux.lds.c @@ -26,12 +26,6 @@ SECTIONS _sinittext = .; *(.text.reset) *(.init.text) - /* - * .exit.text is discarded at runtime, not - * link time, to deal with references from - * __bug_table - */ - *(.exit.text) _einittext = .; . = ALIGN(4); __tagtable_begin = .; @@ -92,8 +86,6 @@ SECTIONS __stop___ex_table = .; } - BUG_TABLE - RODATA . = ALIGN(8192); @@ -134,6 +126,7 @@ SECTIONS * thrown away, as cleanup code is never called unless it's a module. */ /DISCARD/ : { + *(.exit.text) *(.exit.data) *(.exitcall.exit) } diff --git a/trunk/arch/avr32/mach-at32ap/Kconfig b/trunk/arch/avr32/mach-at32ap/Kconfig deleted file mode 100644 index eb307838457b..000000000000 --- a/trunk/arch/avr32/mach-at32ap/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -if PLATFORM_AT32AP - -menu "Atmel AVR32 AP options" - -choice - prompt "AT32AP7000 static memory bus width" - depends on CPU_AT32AP7000 - default AP7000_16_BIT_SMC - help - Define the width of the AP7000 external static memory interface. - This is used to determine how to mangle the address and/or data - when doing little-endian port access. - - The current code can only support a single external memory bus - width for all chip selects, excluding the flash (which is using - raw access and is thus not affected by any of this.) - -config AP7000_32_BIT_SMC - bool "32 bit" - -config AP7000_16_BIT_SMC - bool "16 bit" - -config AP7000_8_BIT_SMC - bool "8 bit" - -endchoice - -endmenu - -endif # PLATFORM_AT32AP diff --git a/trunk/arch/avr32/mach-at32ap/Makefile b/trunk/arch/avr32/mach-at32ap/Makefile index f1d395724ac6..b21bea9af8b1 100644 --- a/trunk/arch/avr32/mach-at32ap/Makefile +++ b/trunk/arch/avr32/mach-at32ap/Makefile @@ -1,3 +1,2 @@ obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o -obj-$(CONFIG_CPU_AT32AP7000) += time-tc.o diff --git a/trunk/arch/avr32/mach-at32ap/at32ap7000.c b/trunk/arch/avr32/mach-at32ap/at32ap7000.c index 56db45b99a0f..472703f90c22 100644 --- a/trunk/arch/avr32/mach-at32ap/at32ap7000.c +++ b/trunk/arch/avr32/mach-at32ap/at32ap7000.c @@ -18,7 +18,6 @@ #include #include "clock.h" -#include "hmatrix.h" #include "pio.h" #include "sm.h" @@ -417,15 +416,7 @@ struct platform_device at32_sm_device = { .resource = sm_resource, .num_resources = ARRAY_SIZE(sm_resource), }; -static struct clk at32_sm_pclk = { - .name = "pclk", - .dev = &at32_sm_device.dev, - .parent = &pbb_clk, - .mode = pbb_clk_mode, - .get_rate = pbb_clk_get_rate, - .users = 1, - .index = 0, -}; +DEV_CLK(pclk, at32_sm, pbb, 0); static struct resource intc0_resource[] = { PBMEM(0xfff00400), @@ -451,7 +442,6 @@ static struct clk hramc_clk = { .mode = hsb_clk_mode, .get_rate = hsb_clk_get_rate, .users = 1, - .index = 3, }; static struct resource smc0_resource[] = { @@ -476,57 +466,6 @@ static struct clk pico_clk = { .users = 1, }; -/* -------------------------------------------------------------------- - * HMATRIX - * -------------------------------------------------------------------- */ - -static struct clk hmatrix_clk = { - .name = "hmatrix_clk", - .parent = &pbb_clk, - .mode = pbb_clk_mode, - .get_rate = pbb_clk_get_rate, - .index = 2, - .users = 1, -}; -#define HMATRIX_BASE ((void __iomem *)0xfff00800) - -#define hmatrix_readl(reg) \ - __raw_readl((HMATRIX_BASE) + HMATRIX_##reg) -#define hmatrix_writel(reg,value) \ - __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg) - -/* - * Set bits in the HMATRIX Special Function Register (SFR) used by the - * External Bus Interface (EBI). This can be used to enable special - * features like CompactFlash support, NAND Flash support, etc. on - * certain chipselects. - */ -static inline void set_ebi_sfr_bits(u32 mask) -{ - u32 sfr; - - clk_enable(&hmatrix_clk); - sfr = hmatrix_readl(SFR4); - sfr |= mask; - hmatrix_writel(SFR4, sfr); - clk_disable(&hmatrix_clk); -} - -/* -------------------------------------------------------------------- - * System Timer/Counter (TC) - * -------------------------------------------------------------------- */ -static struct resource at32_systc0_resource[] = { - PBMEM(0xfff00c00), - IRQ(22), -}; -struct platform_device at32_systc0_device = { - .name = "systc", - .id = 0, - .resource = at32_systc0_resource, - .num_resources = ARRAY_SIZE(at32_systc0_resource), -}; -DEV_CLK(pclk, at32_systc0, pbb, 3); - /* -------------------------------------------------------------------- * PIO * -------------------------------------------------------------------- */ @@ -575,8 +514,6 @@ void __init at32_add_system_devices(void) platform_device_register(&smc0_device); platform_device_register(&pdc_device); - platform_device_register(&at32_systc0_device); - platform_device_register(&pio0_device); platform_device_register(&pio1_device); platform_device_register(&pio2_device); @@ -1013,7 +950,6 @@ struct clk *at32_clock_list[] = { &pbb_clk, &at32_sm_pclk, &at32_intc0_pclk, - &hmatrix_clk, &ebi_clk, &hramc_clk, &smc0_pclk, @@ -1026,7 +962,6 @@ struct clk *at32_clock_list[] = { &pio2_mck, &pio3_mck, &pio4_mck, - &at32_systc0_pclk, &atmel_usart0_usart, &atmel_usart1_usart, &atmel_usart2_usart, @@ -1089,9 +1024,6 @@ void __init at32_clock_init(void) for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { struct clk *clk = at32_clock_list[i]; - if (clk->users == 0) - continue; - if (clk->mode == &cpu_clk_mode) cpu_mask |= 1 << clk->index; else if (clk->mode == &hsb_clk_mode) diff --git a/trunk/arch/avr32/mach-at32ap/hmatrix.h b/trunk/arch/avr32/mach-at32ap/hmatrix.h deleted file mode 100644 index d10bfb60d68d..000000000000 --- a/trunk/arch/avr32/mach-at32ap/hmatrix.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Register definitions for High-Speed Bus Matrix - */ -#ifndef __HMATRIX_H -#define __HMATRIX_H - -/* HMATRIX register offsets */ -#define HMATRIX_MCFG0 0x0000 -#define HMATRIX_MCFG1 0x0004 -#define HMATRIX_MCFG2 0x0008 -#define HMATRIX_MCFG3 0x000c -#define HMATRIX_MCFG4 0x0010 -#define HMATRIX_MCFG5 0x0014 -#define HMATRIX_MCFG6 0x0018 -#define HMATRIX_MCFG7 0x001c -#define HMATRIX_MCFG8 0x0020 -#define HMATRIX_MCFG9 0x0024 -#define HMATRIX_MCFG10 0x0028 -#define HMATRIX_MCFG11 0x002c -#define HMATRIX_MCFG12 0x0030 -#define HMATRIX_MCFG13 0x0034 -#define HMATRIX_MCFG14 0x0038 -#define HMATRIX_MCFG15 0x003c -#define HMATRIX_SCFG0 0x0040 -#define HMATRIX_SCFG1 0x0044 -#define HMATRIX_SCFG2 0x0048 -#define HMATRIX_SCFG3 0x004c -#define HMATRIX_SCFG4 0x0050 -#define HMATRIX_SCFG5 0x0054 -#define HMATRIX_SCFG6 0x0058 -#define HMATRIX_SCFG7 0x005c -#define HMATRIX_SCFG8 0x0060 -#define HMATRIX_SCFG9 0x0064 -#define HMATRIX_SCFG10 0x0068 -#define HMATRIX_SCFG11 0x006c -#define HMATRIX_SCFG12 0x0070 -#define HMATRIX_SCFG13 0x0074 -#define HMATRIX_SCFG14 0x0078 -#define HMATRIX_SCFG15 0x007c -#define HMATRIX_PRAS0 0x0080 -#define HMATRIX_PRBS0 0x0084 -#define HMATRIX_PRAS1 0x0088 -#define HMATRIX_PRBS1 0x008c -#define HMATRIX_PRAS2 0x0090 -#define HMATRIX_PRBS2 0x0094 -#define HMATRIX_PRAS3 0x0098 -#define HMATRIX_PRBS3 0x009c -#define HMATRIX_PRAS4 0x00a0 -#define HMATRIX_PRBS4 0x00a4 -#define HMATRIX_PRAS5 0x00a8 -#define HMATRIX_PRBS5 0x00ac -#define HMATRIX_PRAS6 0x00b0 -#define HMATRIX_PRBS6 0x00b4 -#define HMATRIX_PRAS7 0x00b8 -#define HMATRIX_PRBS7 0x00bc -#define HMATRIX_PRAS8 0x00c0 -#define HMATRIX_PRBS8 0x00c4 -#define HMATRIX_PRAS9 0x00c8 -#define HMATRIX_PRBS9 0x00cc -#define HMATRIX_PRAS10 0x00d0 -#define HMATRIX_PRBS10 0x00d4 -#define HMATRIX_PRAS11 0x00d8 -#define HMATRIX_PRBS11 0x00dc -#define HMATRIX_PRAS12 0x00e0 -#define HMATRIX_PRBS12 0x00e4 -#define HMATRIX_PRAS13 0x00e8 -#define HMATRIX_PRBS13 0x00ec -#define HMATRIX_PRAS14 0x00f0 -#define HMATRIX_PRBS14 0x00f4 -#define HMATRIX_PRAS15 0x00f8 -#define HMATRIX_PRBS15 0x00fc -#define HMATRIX_MRCR 0x0100 -#define HMATRIX_SFR0 0x0110 -#define HMATRIX_SFR1 0x0114 -#define HMATRIX_SFR2 0x0118 -#define HMATRIX_SFR3 0x011c -#define HMATRIX_SFR4 0x0120 -#define HMATRIX_SFR5 0x0124 -#define HMATRIX_SFR6 0x0128 -#define HMATRIX_SFR7 0x012c -#define HMATRIX_SFR8 0x0130 -#define HMATRIX_SFR9 0x0134 -#define HMATRIX_SFR10 0x0138 -#define HMATRIX_SFR11 0x013c -#define HMATRIX_SFR12 0x0140 -#define HMATRIX_SFR13 0x0144 -#define HMATRIX_SFR14 0x0148 -#define HMATRIX_SFR15 0x014c - -/* Bitfields in MCFGx */ -#define HMATRIX_ULBT_OFFSET 0 -#define HMATRIX_ULBT_SIZE 3 - -/* Bitfields in SCFGx */ -#define HMATRIX_SLOT_CYCLE_OFFSET 0 -#define HMATRIX_SLOT_CYCLE_SIZE 8 -#define HMATRIX_DEFMSTR_TYPE_OFFSET 16 -#define HMATRIX_DEFMSTR_TYPE_SIZE 2 -#define HMATRIX_FIXED_DEFMSTR_OFFSET 18 -#define HMATRIX_FIXED_DEFMSTR_SIZE 4 -#define HMATRIX_ARBT_OFFSET 24 -#define HMATRIX_ARBT_SIZE 2 - -/* Bitfields in PRASx */ -#define HMATRIX_M0PR_OFFSET 0 -#define HMATRIX_M0PR_SIZE 4 -#define HMATRIX_M1PR_OFFSET 4 -#define HMATRIX_M1PR_SIZE 4 -#define HMATRIX_M2PR_OFFSET 8 -#define HMATRIX_M2PR_SIZE 4 -#define HMATRIX_M3PR_OFFSET 12 -#define HMATRIX_M3PR_SIZE 4 -#define HMATRIX_M4PR_OFFSET 16 -#define HMATRIX_M4PR_SIZE 4 -#define HMATRIX_M5PR_OFFSET 20 -#define HMATRIX_M5PR_SIZE 4 -#define HMATRIX_M6PR_OFFSET 24 -#define HMATRIX_M6PR_SIZE 4 -#define HMATRIX_M7PR_OFFSET 28 -#define HMATRIX_M7PR_SIZE 4 - -/* Bitfields in PRBSx */ -#define HMATRIX_M8PR_OFFSET 0 -#define HMATRIX_M8PR_SIZE 4 -#define HMATRIX_M9PR_OFFSET 4 -#define HMATRIX_M9PR_SIZE 4 -#define HMATRIX_M10PR_OFFSET 8 -#define HMATRIX_M10PR_SIZE 4 -#define HMATRIX_M11PR_OFFSET 12 -#define HMATRIX_M11PR_SIZE 4 -#define HMATRIX_M12PR_OFFSET 16 -#define HMATRIX_M12PR_SIZE 4 -#define HMATRIX_M13PR_OFFSET 20 -#define HMATRIX_M13PR_SIZE 4 -#define HMATRIX_M14PR_OFFSET 24 -#define HMATRIX_M14PR_SIZE 4 -#define HMATRIX_M15PR_OFFSET 28 -#define HMATRIX_M15PR_SIZE 4 - -/* Bitfields in SFR4 */ -#define HMATRIX_CS1A_OFFSET 1 -#define HMATRIX_CS1A_SIZE 1 -#define HMATRIX_CS3A_OFFSET 3 -#define HMATRIX_CS3A_SIZE 1 -#define HMATRIX_CS4A_OFFSET 4 -#define HMATRIX_CS4A_SIZE 1 -#define HMATRIX_CS5A_OFFSET 5 -#define HMATRIX_CS5A_SIZE 1 -#define HMATRIX_DBPUC_OFFSET 8 -#define HMATRIX_DBPUC_SIZE 1 - -/* Constants for ULBT */ -#define HMATRIX_ULBT_INFINITE 0 -#define HMATRIX_ULBT_SINGLE 1 -#define HMATRIX_ULBT_FOUR_BEAT 2 -#define HMATRIX_ULBT_EIGHT_BEAT 3 -#define HMATRIX_ULBT_SIXTEEN_BEAT 4 - -/* Constants for DEFMSTR_TYPE */ -#define HMATRIX_DEFMSTR_TYPE_NO_DEFAULT 0 -#define HMATRIX_DEFMSTR_TYPE_LAST_DEFAULT 1 -#define HMATRIX_DEFMSTR_TYPE_FIXED_DEFAULT 2 - -/* Constants for ARBT */ -#define HMATRIX_ARBT_ROUND_ROBIN 0 -#define HMATRIX_ARBT_FIXED_PRIORITY 1 - -/* Bit manipulation macros */ -#define HMATRIX_BIT(name) \ - (1 << HMATRIX_##name##_OFFSET) -#define HMATRIX_BF(name,value) \ - (((value) & ((1 << HMATRIX_##name##_SIZE) - 1)) \ - << HMATRIX_##name##_OFFSET) -#define HMATRIX_BFEXT(name,value) \ - (((value) >> HMATRIX_##name##_OFFSET) \ - & ((1 << HMATRIX_##name##_SIZE) - 1)) -#define HMATRIX_BFINS(name,value,old) \ - (((old) & ~(((1 << HMATRIX_##name##_SIZE) - 1) \ - << HMATRIX_##name##_OFFSET)) \ - | HMATRIX_BF(name,value)) - -#endif /* __HMATRIX_H */ diff --git a/trunk/arch/avr32/mach-at32ap/hsmc.c b/trunk/arch/avr32/mach-at32ap/hsmc.c index 5e22a750632b..7691721928a7 100644 --- a/trunk/arch/avr32/mach-at32ap/hsmc.c +++ b/trunk/arch/avr32/mach-at32ap/hsmc.c @@ -75,35 +75,12 @@ int smc_set_configuration(int cs, const struct smc_config *config) return -EINVAL; } - switch (config->nwait_mode) { - case 0: - mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED); - break; - case 1: - mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED); - break; - case 2: - mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN); - break; - case 3: - mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY); - break; - default: - return -EINVAL; - } - - if (config->tdf_cycles) { - mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles); - } - if (config->nrd_controlled) mode |= HSMC_BIT(READ_MODE); if (config->nwe_controlled) mode |= HSMC_BIT(WRITE_MODE); if (config->byte_write) mode |= HSMC_BIT(BAT); - if (config->tdf_mode) - mode |= HSMC_BIT(TDF_MODE); pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n", cs, setup, pulse, cycle, mode); diff --git a/trunk/arch/avr32/mach-at32ap/time-tc.c b/trunk/arch/avr32/mach-at32ap/time-tc.c deleted file mode 100644 index e3070bdd4bb9..000000000000 --- a/trunk/arch/avr32/mach-at32ap/time-tc.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2004-2007 Atmel Corporation - * - * Based on MIPS implementation arch/mips/kernel/time.c - * Copyright 2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* how many counter cycles in a jiffy? */ -static u32 cycles_per_jiffy; - -/* the count value for the next timer interrupt */ -static u32 expirelo; - -/* the I/O registers of the TC module */ -static void __iomem *ioregs; - -cycle_t read_cycle_count(void) -{ - return (cycle_t)timer_read(ioregs, 0, CV); -} - -struct clocksource clocksource_avr32 = { - .name = "avr32", - .rating = 342, - .read = read_cycle_count, - .mask = CLOCKSOURCE_MASK(16), - .shift = 16, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static void avr32_timer_ack(void) -{ - u16 count = expirelo; - - /* Ack this timer interrupt and set the next one, use a u16 - * variable so it will wrap around correctly */ - count += cycles_per_jiffy; - expirelo = count; - timer_write(ioregs, 0, RC, expirelo); - - /* Check to see if we have missed any timer interrupts */ - count = timer_read(ioregs, 0, CV); - if ((count - expirelo) < 0x7fff) { - expirelo = count + cycles_per_jiffy; - timer_write(ioregs, 0, RC, expirelo); - } -} - -u32 avr32_hpt_read(void) -{ - return timer_read(ioregs, 0, CV); -} - -static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk) -{ - unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2; - unsigned int divs[] = { 4, 8, 16, 32 }; - int divs_size = sizeof(divs) / sizeof(*divs); - int i = 0; - unsigned long count_hz; - unsigned long shift; - unsigned long mult; - int clock_div = -1; - u64 tmp; - - shift = clocksource_avr32.shift; - - do { - count_hz = clk_get_rate(pclk) / divs[i]; - mult = clocksource_hz2mult(count_hz, shift); - clocksource_avr32.mult = mult; - - tmp = TICK_NSEC; - tmp <<= shift; - tmp += mult / 2; - do_div(tmp, mult); - - cycles_per_jiffy = tmp; - } while (cycles_per_jiffy > cycles_max && ++i < divs_size); - - clock_div = i + 1; - - if (clock_div > divs_size) { - pr_debug("timer: could not calculate clock divider\n"); - return -EFAULT; - } - - /* Set the clock divider */ - timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div)); - - return 0; -} - -int avr32_hpt_init(unsigned int count) -{ - struct resource *regs; - struct clk *pclk; - int irq = -1; - int ret = 0; - - ret = -ENXIO; - - irq = platform_get_irq(&at32_systc0_device, 0); - if (irq < 0) { - pr_debug("timer: could not get irq\n"); - goto out_error; - } - - pclk = clk_get(&at32_systc0_device.dev, "pclk"); - if (IS_ERR(pclk)) { - pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk)); - goto out_error; - } - clk_enable(pclk); - - regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0); - if (!regs) { - pr_debug("timer: could not get resource\n"); - goto out_error_clk; - } - - ioregs = ioremap(regs->start, regs->end - regs->start + 1); - if (!ioregs) { - pr_debug("timer: could not get ioregs\n"); - goto out_error_clk; - } - - ret = avr32_timer_calc_div_and_set_jiffies(pclk); - if (ret) - goto out_error_io; - - ret = setup_irq(irq, &timer_irqaction); - if (ret) { - pr_debug("timer: could not request irq %d: %d\n", - irq, ret); - goto out_error_io; - } - - expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1) - * cycles_per_jiffy; - - /* Enable clock and interrupts on RC compare */ - timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN)); - timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS)); - /* Set cycles to first interrupt */ - timer_write(ioregs, 0, RC, expirelo); - - printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n", - ioregs, irq); - - return 0; - -out_error_io: - iounmap(ioregs); -out_error_clk: - clk_put(pclk); -out_error: - return ret; -} - -int avr32_hpt_start(void) -{ - timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG)); - return 0; -} - -irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - unsigned int sr = timer_read(ioregs, 0, SR); - - if (sr & TIMER_BIT(SR_CPCS)) { - /* ack timer interrupt and try to set next interrupt */ - avr32_timer_ack(); - - /* - * Call the generic timer interrupt handler - */ - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); - - /* - * In UP mode, we call local_timer_interrupt() to do profiling - * and process accounting. - * - * SMP is not supported yet. - */ - local_timer_interrupt(irq, dev_id); - - return IRQ_HANDLED; - } - - return IRQ_NONE; -} diff --git a/trunk/arch/avr32/mm/fault.c b/trunk/arch/avr32/mm/fault.c index 146ebdbdc302..678557260a35 100644 --- a/trunk/arch/avr32/mm/fault.c +++ b/trunk/arch/avr32/mm/fault.c @@ -16,8 +16,26 @@ #include #include #include -#include #include +#include + +#ifdef DEBUG +static void dump_code(unsigned long pc) +{ + char *p = (char *)pc; + char val; + int i; + + + printk(KERN_DEBUG "Code:"); + for (i = 0; i < 16; i++) { + if (__get_user(val, p + i)) + break; + printk(" %02x", val); + } + printk("\n"); +} +#endif #ifdef CONFIG_KPROBES ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); @@ -50,19 +68,17 @@ static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, } #endif -int exception_trace = 1; - /* * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. * * ecr is the Exception Cause Register. Possible values are: + * 5: Page not found (instruction access) * 6: Protection fault (instruction access) - * 15: Protection fault (read access) - * 16: Protection fault (write access) - * 20: Page not found (instruction access) - * 24: Page not found (read access) - * 28: Page not found (write access) + * 12: Page not found (read access) + * 13: Page not found (write access) + * 14: Protection fault (read access) + * 15: Protection fault (write access) */ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) { @@ -72,9 +88,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) const struct exception_table_entry *fixup; unsigned long address; unsigned long page; - int writeaccess; - long signr; - int code; + int writeaccess = 0; if (notify_page_fault(DIE_PAGE_FAULT, regs, ecr, SIGSEGV) == NOTIFY_STOP) @@ -85,9 +99,6 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) tsk = current; mm = tsk->mm; - signr = SIGSEGV; - code = SEGV_MAPERR; - /* * If we're in an interrupt or have no user context, we must * not take the fault... @@ -114,9 +125,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) * can handle it... */ good_area: - code = SEGV_ACCERR; - writeaccess = 0; - + //pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags); switch (ecr) { case ECR_PROTECTION_X: case ECR_TLB_MISS_X: @@ -167,24 +176,46 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) * map. Fix it, but check if it's kernel or user first... */ bad_area: + pr_debug("Bad area [%s:%u]: addr %08lx, ecr %lu\n", + tsk->comm, tsk->pid, address, ecr); + up_read(&mm->mmap_sem); if (user_mode(regs)) { - if (exception_trace) - printk("%s%s[%d]: segfault at %08lx pc %08lx " - "sp %08lx ecr %lu\n", - is_init(tsk) ? KERN_EMERG : KERN_INFO, - tsk->comm, tsk->pid, address, regs->pc, - regs->sp, ecr); - _exception(SIGSEGV, regs, code, address); + /* Hmm...we have to pass address and ecr somehow... */ + /* tsk->thread.address = address; + tsk->thread.error_code = ecr; */ +#ifdef DEBUG + show_regs(regs); + dump_code(regs->pc); + + page = sysreg_read(PTBR); + printk("ptbr = %08lx", page); + if (page) { + page = ((unsigned long *)page)[address >> 22]; + printk(" pgd = %08lx", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; + printk(" pte = %08lx\n", page); + } + } +#endif + pr_debug("Sending SIGSEGV to PID %d...\n", + tsk->pid); + force_sig(SIGSEGV, tsk); return; } no_context: + pr_debug("No context\n"); + /* Are we prepared to handle this kernel fault? */ fixup = search_exception_tables(regs->pc); if (fixup) { regs->pc = fixup->fixup; + pr_debug("Found fixup at %08lx\n", fixup->fixup); return; } @@ -199,6 +230,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n", address); + printk(KERN_ALERT "pc = %08lx\n", regs->pc); page = sysreg_read(PTBR); printk(KERN_ALERT "ptbr = %08lx", page); @@ -209,20 +241,20 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) page &= PAGE_MASK; address &= 0x003ff000; page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; - printk(" pte = %08lx", page); + printk(" pte = %08lx\n", page); } } - printk("\n"); - die("Kernel access of bad area", regs, signr); - return; + die("\nOops", regs, ecr); + do_exit(SIGKILL); /* * We ran out of memory, or some other thing happened to us * that made us unable to handle the page fault gracefully. */ out_of_memory: + printk("Out of memory\n"); up_read(&mm->mmap_sem); - if (is_init(current)) { + if (current->pid == 1) { yield(); down_read(&mm->mmap_sem); goto survive; @@ -235,20 +267,21 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) do_sigbus: up_read(&mm->mmap_sem); + /* + * Send a sigbus, regardless of whether we were in kernel or + * user mode. + */ + /* address, error_code, trap_no, ... */ +#ifdef DEBUG + show_regs(regs); + dump_code(regs->pc); +#endif + pr_debug("Sending SIGBUS to PID %d...\n", tsk->pid); + force_sig(SIGBUS, tsk); + /* Kernel mode? Handle exceptions or die */ - signr = SIGBUS; - code = BUS_ADRERR; if (!user_mode(regs)) goto no_context; - - if (exception_trace) - printk("%s%s[%d]: bus error at %08lx pc %08lx " - "sp %08lx ecr %lu\n", - is_init(tsk) ? KERN_EMERG : KERN_INFO, - tsk->comm, tsk->pid, address, regs->pc, - regs->sp, ecr); - - _exception(SIGBUS, regs, BUS_ADRERR, address); } asmlinkage void do_bus_error(unsigned long addr, int write_access, @@ -259,7 +292,8 @@ asmlinkage void do_bus_error(unsigned long addr, int write_access, addr, write_access ? "write" : "read"); printk(KERN_INFO "DTLB dump:\n"); dump_dtlb(); - die("Bus Error", regs, SIGKILL); + die("Bus Error", regs, write_access); + do_exit(SIGKILL); } /* diff --git a/trunk/arch/avr32/mm/init.c b/trunk/arch/avr32/mm/init.c index 82cf70854b90..70da6894acc1 100644 --- a/trunk/arch/avr32/mm/init.c +++ b/trunk/arch/avr32/mm/init.c @@ -10,9 +10,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -76,6 +78,242 @@ void show_mem(void) printk ("%d pages swap cached\n", cached); } +static void __init print_memory_map(const char *what, + struct tag_mem_range *mem) +{ + printk ("%s:\n", what); + for (; mem; mem = mem->next) { + printk (" %08lx - %08lx\n", + (unsigned long)mem->addr, + (unsigned long)(mem->addr + mem->size)); + } +} + +#define MAX_LOWMEM HIGHMEM_START +#define MAX_LOWMEM_PFN PFN_DOWN(MAX_LOWMEM) + +/* + * Sort a list of memory regions in-place by ascending address. + * + * We're using bubble sort because we only have singly linked lists + * with few elements. + */ +static void __init sort_mem_list(struct tag_mem_range **pmem) +{ + int done; + struct tag_mem_range **a, **b; + + if (!*pmem) + return; + + do { + done = 1; + a = pmem, b = &(*pmem)->next; + while (*b) { + if ((*a)->addr > (*b)->addr) { + struct tag_mem_range *tmp; + tmp = (*b)->next; + (*b)->next = *a; + *a = *b; + *b = tmp; + done = 0; + } + a = &(*a)->next; + b = &(*a)->next; + } + } while (!done); +} + +/* + * Find a free memory region large enough for storing the + * bootmem bitmap. + */ +static unsigned long __init +find_bootmap_pfn(const struct tag_mem_range *mem) +{ + unsigned long bootmap_pages, bootmap_len; + unsigned long node_pages = PFN_UP(mem->size); + unsigned long bootmap_addr = mem->addr; + struct tag_mem_range *reserved = mem_reserved; + struct tag_mem_range *ramdisk = mem_ramdisk; + unsigned long kern_start = virt_to_phys(_stext); + unsigned long kern_end = virt_to_phys(_end); + + bootmap_pages = bootmem_bootmap_pages(node_pages); + bootmap_len = bootmap_pages << PAGE_SHIFT; + + /* + * Find a large enough region without reserved pages for + * storing the bootmem bitmap. We can take advantage of the + * fact that all lists have been sorted. + * + * We have to check explicitly reserved regions as well as the + * kernel image and any RAMDISK images... + * + * Oh, and we have to make sure we don't overwrite the taglist + * since we're going to use it until the bootmem allocator is + * fully up and running. + */ + while (1) { + if ((bootmap_addr < kern_end) && + ((bootmap_addr + bootmap_len) > kern_start)) + bootmap_addr = kern_end; + + while (reserved && + (bootmap_addr >= (reserved->addr + reserved->size))) + reserved = reserved->next; + + if (reserved && + ((bootmap_addr + bootmap_len) >= reserved->addr)) { + bootmap_addr = reserved->addr + reserved->size; + continue; + } + + while (ramdisk && + (bootmap_addr >= (ramdisk->addr + ramdisk->size))) + ramdisk = ramdisk->next; + + if (!ramdisk || + ((bootmap_addr + bootmap_len) < ramdisk->addr)) + break; + + bootmap_addr = ramdisk->addr + ramdisk->size; + } + + if ((PFN_UP(bootmap_addr) + bootmap_len) >= (mem->addr + mem->size)) + return ~0UL; + + return PFN_UP(bootmap_addr); +} + +void __init setup_bootmem(void) +{ + unsigned bootmap_size; + unsigned long first_pfn, bootmap_pfn, pages; + unsigned long max_pfn, max_low_pfn; + unsigned long kern_start = virt_to_phys(_stext); + unsigned long kern_end = virt_to_phys(_end); + unsigned node = 0; + struct tag_mem_range *bank, *res; + + sort_mem_list(&mem_phys); + sort_mem_list(&mem_reserved); + + print_memory_map("Physical memory", mem_phys); + print_memory_map("Reserved memory", mem_reserved); + + nodes_clear(node_online_map); + + if (mem_ramdisk) { +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = (unsigned long)__va(mem_ramdisk->addr); + initrd_end = initrd_start + mem_ramdisk->size; + + print_memory_map("RAMDISK images", mem_ramdisk); + if (mem_ramdisk->next) + printk(KERN_WARNING + "Warning: Only the first RAMDISK image " + "will be used\n"); + sort_mem_list(&mem_ramdisk); +#else + printk(KERN_WARNING "RAM disk image present, but " + "no initrd support in kernel!\n"); +#endif + } + + if (mem_phys->next) + printk(KERN_WARNING "Only using first memory bank\n"); + + for (bank = mem_phys; bank; bank = NULL) { + first_pfn = PFN_UP(bank->addr); + max_low_pfn = max_pfn = PFN_DOWN(bank->addr + bank->size); + bootmap_pfn = find_bootmap_pfn(bank); + if (bootmap_pfn > max_pfn) + panic("No space for bootmem bitmap!\n"); + + if (max_low_pfn > MAX_LOWMEM_PFN) { + max_low_pfn = MAX_LOWMEM_PFN; +#ifndef CONFIG_HIGHMEM + /* + * Lowmem is memory that can be addressed + * directly through P1/P2 + */ + printk(KERN_WARNING + "Node %u: Only %ld MiB of memory will be used.\n", + node, MAX_LOWMEM >> 20); + printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); +#else +#error HIGHMEM is not supported by AVR32 yet +#endif + } + + /* Initialize the boot-time allocator with low memory only. */ + bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn, + first_pfn, max_low_pfn); + + printk("Node %u: bdata = %p, bdata->node_bootmem_map = %p\n", + node, NODE_DATA(node)->bdata, + NODE_DATA(node)->bdata->node_bootmem_map); + + /* + * Register fully available RAM pages with the bootmem + * allocator. + */ + pages = max_low_pfn - first_pfn; + free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn), + PFN_PHYS(pages)); + + /* + * Reserve space for the kernel image (if present in + * this node)... + */ + if ((kern_start >= PFN_PHYS(first_pfn)) && + (kern_start < PFN_PHYS(max_pfn))) { + printk("Node %u: Kernel image %08lx - %08lx\n", + node, kern_start, kern_end); + reserve_bootmem_node(NODE_DATA(node), kern_start, + kern_end - kern_start); + } + + /* ...the bootmem bitmap... */ + reserve_bootmem_node(NODE_DATA(node), + PFN_PHYS(bootmap_pfn), + bootmap_size); + + /* ...any RAMDISK images... */ + for (res = mem_ramdisk; res; res = res->next) { + if (res->addr > PFN_PHYS(max_pfn)) + break; + + if (res->addr >= PFN_PHYS(first_pfn)) { + printk("Node %u: RAMDISK %08lx - %08lx\n", + node, + (unsigned long)res->addr, + (unsigned long)(res->addr + res->size)); + reserve_bootmem_node(NODE_DATA(node), + res->addr, res->size); + } + } + + /* ...and any other reserved regions. */ + for (res = mem_reserved; res; res = res->next) { + if (res->addr > PFN_PHYS(max_pfn)) + break; + + if (res->addr >= PFN_PHYS(first_pfn)) { + printk("Node %u: Reserved %08lx - %08lx\n", + node, + (unsigned long)res->addr, + (unsigned long)(res->addr + res->size)); + reserve_bootmem_node(NODE_DATA(node), + res->addr, res->size); + } + } + + node_set_online(node); + } +} + /* * paging_init() sets up the page tables * diff --git a/trunk/arch/cris/arch-v32/vmlinux.lds.S b/trunk/arch/cris/arch-v32/vmlinux.lds.S index dfa25e1542b9..e124fcd766d5 100644 --- a/trunk/arch/cris/arch-v32/vmlinux.lds.S +++ b/trunk/arch/cris/arch-v32/vmlinux.lds.S @@ -91,7 +91,6 @@ SECTIONS } SECURITY_INIT - . = ALIGN (8192); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/frv/kernel/vmlinux.lds.S b/trunk/arch/frv/kernel/vmlinux.lds.S index 28eae9735ad6..97910e016825 100644 --- a/trunk/arch/frv/kernel/vmlinux.lds.S +++ b/trunk/arch/frv/kernel/vmlinux.lds.S @@ -57,7 +57,6 @@ SECTIONS __alt_instructions_end = .; .altinstr_replacement : { *(.altinstr_replacement) } - . = ALIGN(4096); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/i386/Kconfig b/trunk/arch/i386/Kconfig index a9af760c7e5f..53d62373a524 100644 --- a/trunk/arch/i386/Kconfig +++ b/trunk/arch/i386/Kconfig @@ -220,7 +220,7 @@ config PARAVIRT config VMI bool "VMI Paravirt-ops support" - depends on PARAVIRT + depends on PARAVIRT && !COMPAT_VDSO help VMI provides a paravirtualized interface to the VMware ESX server (it could be used by other hypervisors in theory too, but is not @@ -571,9 +571,6 @@ choice bool "3G/1G user/kernel split (for full 1G low memory)" config VMSPLIT_2G bool "2G/2G user/kernel split" - config VMSPLIT_2G_OPT - depends on !HIGHMEM - bool "2G/2G user/kernel split (for full 2G low memory)" config VMSPLIT_1G bool "1G/3G user/kernel split" endchoice @@ -581,8 +578,7 @@ endchoice config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT - default 0x80000000 if VMSPLIT_2G - default 0x78000000 if VMSPLIT_2G_OPT + default 0x78000000 if VMSPLIT_2G default 0x40000000 if VMSPLIT_1G default 0xC0000000 @@ -919,9 +915,12 @@ source kernel/power/Kconfig source "drivers/acpi/Kconfig" -menuconfig APM +menu "APM (Advanced Power Management) BIOS Support" +depends on PM && !X86_VISWS + +config APM tristate "APM (Advanced Power Management) BIOS support" - depends on PM && !X86_VISWS + depends on PM ---help--- APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with @@ -978,10 +977,9 @@ menuconfig APM To compile this driver as a module, choose M here: the module will be called apm. -if APM - config APM_IGNORE_USER_SUSPEND bool "Ignore USER SUSPEND" + depends on APM help This option will ignore USER SUSPEND requests. On machines with a compliant APM BIOS, you want to say N. However, on the NEC Versa M @@ -989,6 +987,7 @@ config APM_IGNORE_USER_SUSPEND config APM_DO_ENABLE bool "Enable PM at boot time" + depends on APM ---help--- Enable APM features at boot time. From page 36 of the APM BIOS specification: "When disabled, the APM BIOS does not automatically @@ -1006,6 +1005,7 @@ config APM_DO_ENABLE config APM_CPU_IDLE bool "Make CPU Idle calls when idle" + depends on APM help Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop. On some machines, this can activate improved power savings, such as @@ -1017,6 +1017,7 @@ config APM_CPU_IDLE config APM_DISPLAY_BLANK bool "Enable console blanking using APM" + depends on APM help Enable console blanking using the APM. Some laptops can use this to turn off the LCD backlight when the screen blanker of the Linux @@ -1028,8 +1029,22 @@ config APM_DISPLAY_BLANK backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. +config APM_RTC_IS_GMT + bool "RTC stores time in GMT" + depends on APM + help + Say Y here if your RTC (Real Time Clock a.k.a. hardware clock) + stores the time in GMT (Greenwich Mean Time). Say N if your RTC + stores localtime. + + It is in fact recommended to store GMT in your RTC, because then you + don't have to worry about daylight savings time changes. The only + reason not to use GMT in your RTC is if you also run a broken OS + that doesn't understand GMT. + config APM_ALLOW_INTS bool "Allow interrupts during APM BIOS calls" + depends on APM help Normally we disable external interrupts while we are making calls to the APM BIOS as a measure to lessen the effects of a badly behaving @@ -1040,12 +1055,13 @@ config APM_ALLOW_INTS config APM_REAL_MODE_POWER_OFF bool "Use real mode APM BIOS call to power off" + depends on APM help Use real mode APM BIOS calls to switch off the computer. This is a work-around for a number of buggy BIOSes. Switch this option on if your computer crashes instead of powering off properly. -endif # APM +endmenu source "arch/i386/kernel/cpu/cpufreq/Kconfig" @@ -1057,7 +1073,6 @@ config PCI bool "PCI support" if !X86_VISWS depends on !X86_VOYAGER default y if X86_VISWS - select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC) help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/trunk/arch/i386/Kconfig.cpu b/trunk/arch/i386/Kconfig.cpu index dce6124cb842..b99c0e2a4e63 100644 --- a/trunk/arch/i386/Kconfig.cpu +++ b/trunk/arch/i386/Kconfig.cpu @@ -43,7 +43,6 @@ config M386 - "Geode GX/LX" For AMD Geode GX and LX processors. - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. - "VIA C3-2" for VIA C3-2 "Nehemiah" (model 9 and above). - - "VIA C7" for VIA C7. If you don't know what to do, choose "386". @@ -204,12 +203,6 @@ config MVIAC3_2 of SSE and tells gcc to treat the CPU as a 686. Note, this kernel will not boot on older (pre model 9) C3s. -config MVIAC7 - bool "VIA C7" - help - Select this for a VIA C7. Selecting this uses the correct cache - shift and tells gcc to treat the CPU as a 686. - endchoice config X86_GENERIC @@ -238,21 +231,16 @@ config X86_L1_CACHE_SHIFT default "7" if MPENTIUM4 || X86_GENERIC default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX - default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7 - -config X86_XADD - bool - depends on !M386 - default y + default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 config RWSEM_GENERIC_SPINLOCK bool - depends on !X86_XADD + depends on M386 default y config RWSEM_XCHGADD_ALGORITHM bool - depends on X86_XADD + depends on !M386 default y config ARCH_HAS_ILOG2_U32 @@ -309,7 +297,7 @@ config X86_ALIGNMENT_16 config X86_GOOD_APIC bool - depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 || MVIAC7 + depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 default y config X86_INTEL_USERCOPY @@ -334,18 +322,5 @@ config X86_OOSTORE config X86_TSC bool - depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ + depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ default y - -# this should be set for all -march=.. options where the compiler -# generates cmov. -config X86_CMOV - bool - depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7) - default y - -config X86_MINIMUM_CPU_MODEL - int - default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP - default "0" - diff --git a/trunk/arch/i386/Kconfig.debug b/trunk/arch/i386/Kconfig.debug index b31c0802e1cc..458bc1611933 100644 --- a/trunk/arch/i386/Kconfig.debug +++ b/trunk/arch/i386/Kconfig.debug @@ -85,4 +85,14 @@ config DOUBLEFAULT option saves about 4k and might cause you much additional grey hair. +config DEBUG_PARAVIRT + bool "Enable some paravirtualization debugging" + default n + depends on PARAVIRT && DEBUG_KERNEL + help + Currently deliberately clobbers regs which are allowed to be + clobbered in inlined paravirt hooks, even in native mode. + If turning this off solves a problem, then DISABLE_INTERRUPTS() or + ENABLE_INTERRUPTS() is lying about what registers can be clobbered. + endmenu diff --git a/trunk/arch/i386/Makefile b/trunk/arch/i386/Makefile index 6dc5e5d90fec..bd28f9f9b4b7 100644 --- a/trunk/arch/i386/Makefile +++ b/trunk/arch/i386/Makefile @@ -34,7 +34,7 @@ CHECKFLAGS += -D__i386__ CFLAGS += -pipe -msoft-float -mregparm=3 -freg-struct-return # prevent gcc from keeping the stack 16 byte aligned -CFLAGS += -mpreferred-stack-boundary=4 +CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2) # CPU-specific tuning. Anything which can be shared with UML should go here. include $(srctree)/arch/i386/Makefile.cpu diff --git a/trunk/arch/i386/Makefile.cpu b/trunk/arch/i386/Makefile.cpu index e372b584e919..a32c031c90d7 100644 --- a/trunk/arch/i386/Makefile.cpu +++ b/trunk/arch/i386/Makefile.cpu @@ -4,9 +4,9 @@ #-mtune exists since gcc 3.4 HAS_MTUNE := $(call cc-option-yn, -mtune=i386) ifeq ($(HAS_MTUNE),y) -tune = $(call cc-option,-mtune=$(1),$(2)) +tune = $(call cc-option,-mtune=$(1),) else -tune = $(call cc-option,-mcpu=$(1),$(2)) +tune = $(call cc-option,-mcpu=$(1),) endif align := $(cc-option-align) @@ -32,8 +32,7 @@ cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586) cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586) cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) -cflags-$(CONFIG_MVIAC7) += -march=i686 -cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2) +cflags-$(CONFIG_MCORE2) += -march=i686 $(call cc-option,-mtune=core2,$(call cc-option,-mtune=generic,-mtune=i686)) # AMD Elan support cflags-$(CONFIG_X86_ELAN) += -march=i486 @@ -43,5 +42,5 @@ cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx # add at the end to overwrite eventual tuning options from earlier # cpu entries -cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686)) +cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic) diff --git a/trunk/arch/i386/boot/Makefile b/trunk/arch/i386/boot/Makefile index bfbc32098a4a..e97946626064 100644 --- a/trunk/arch/i386/boot/Makefile +++ b/trunk/arch/i386/boot/Makefile @@ -36,9 +36,9 @@ HOSTCFLAGS_build.o := $(LINUXINCLUDE) # --------------------------------------------------------------------------- $(obj)/zImage: IMAGE_OFFSET := 0x1000 -$(obj)/zImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) +$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) $(obj)/bzImage: IMAGE_OFFSET := 0x100000 -$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ +$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ $(obj)/bzImage: BUILDFLAGS := -b quiet_cmd_image = BUILD $@ diff --git a/trunk/arch/i386/boot/compressed/misc.c b/trunk/arch/i386/boot/compressed/misc.c index b28505c544c9..1ce7017fd627 100644 --- a/trunk/arch/i386/boot/compressed/misc.c +++ b/trunk/arch/i386/boot/compressed/misc.c @@ -189,7 +189,7 @@ static void putstr(const char *); static unsigned long free_mem_ptr; static unsigned long free_mem_end_ptr; -#define HEAP_SIZE 0x4000 +#define HEAP_SIZE 0x3000 static char *vidmem = (char *)0xb8000; static int vidport; diff --git a/trunk/arch/i386/boot/setup.S b/trunk/arch/i386/boot/setup.S index f8b3b9cda2b1..06edf1c66242 100644 --- a/trunk/arch/i386/boot/setup.S +++ b/trunk/arch/i386/boot/setup.S @@ -52,7 +52,6 @@ #include #include #include -#include /* Signature words to ensure LILO loaded us right */ #define SIG1 0xAA55 @@ -82,7 +81,7 @@ start: # This is the setup header, and it must start at %cs:2 (old 0x9020:2) .ascii "HdrS" # header signature - .word 0x0206 # header version number (>= 0x0105) + .word 0x0205 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) realmode_swtch: .word 0, 0 # default_switch, SETUPSEG start_sys_seg: .word SYSSEG @@ -172,10 +171,6 @@ relocatable_kernel: .byte 0 pad2: .byte 0 pad3: .word 0 -cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, - #added with boot protocol - #version 2.06 - trampoline: call start_of_setup .align 16 # The offset at this point is 0x240 @@ -302,24 +297,7 @@ good_sig: loader_panic_mess: .string "Wrong loader, giving up..." -# check minimum cpuid -# we do this here because it is the last place we can actually -# show a user visible error message. Later the video modus -# might be already messed up. loader_ok: - call verify_cpu - testl %eax,%eax - jz cpu_ok - lea cpu_panic_mess,%si - call prtstr -1: jmp 1b - -cpu_panic_mess: - .asciz "PANIC: CPU too old for this kernel." - -#include "../kernel/verify_cpu.S" - -cpu_ok: # Get memory size (extended mem, kB) xorl %eax, %eax diff --git a/trunk/arch/i386/defconfig b/trunk/arch/i386/defconfig index 9da84412a831..f4efd66e1ee5 100644 --- a/trunk/arch/i386/defconfig +++ b/trunk/arch/i386/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-git3 -# Tue May 1 07:30:51 2007 +# Linux kernel version: 2.6.21-rc3 +# Wed Mar 7 15:29:47 2007 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -108,9 +108,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # Processor type and features # -CONFIG_TICK_ONESHOT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set CONFIG_SMP=y # CONFIG_X86_PC is not set # CONFIG_X86_ELAN is not set @@ -146,11 +146,9 @@ CONFIG_MPENTIUMIII=y # CONFIG_MGEODE_LX is not set # CONFIG_MCYRIXIII is not set # CONFIG_MVIAC3_2 is not set -# CONFIG_MVIAC7 is not set CONFIG_X86_GENERIC=y CONFIG_X86_CMPXCHG=y CONFIG_X86_L1_CACHE_SHIFT=7 -CONFIG_X86_XADD=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set @@ -164,8 +162,6 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_INTEL_USERCOPY=y CONFIG_X86_USE_PPRO_CHECKSUM=y CONFIG_X86_TSC=y -CONFIG_X86_CMOV=y -CONFIG_X86_MINIMUM_CPU_MODEL=4 CONFIG_HPET_TIMER=y CONFIG_HPET_EMULATE_RTC=y CONFIG_NR_CPUS=32 @@ -252,6 +248,7 @@ CONFIG_ACPI_FAN=y CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_THERMAL=y # CONFIG_ACPI_ASUS is not set +# CONFIG_ACPI_IBM is not set # CONFIG_ACPI_TOSHIBA is not set CONFIG_ACPI_BLACKLIST_YEAR=2001 CONFIG_ACPI_DEBUG=y @@ -260,7 +257,10 @@ CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y CONFIG_X86_PM_TIMER=y # CONFIG_ACPI_CONTAINER is not set -# CONFIG_ACPI_SBS is not set + +# +# APM (Advanced Power Management) BIOS Support +# # CONFIG_APM is not set # @@ -277,7 +277,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # # CPUFreq processor drivers @@ -349,6 +349,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -387,7 +388,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set -# CONFIG_IPV6_OPTIMISTIC_DAD is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set @@ -443,13 +443,6 @@ CONFIG_IPV6_SIT=y # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_AF_RXRPC is not set - -# -# Wireless -# -# CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_EXT is not set # CONFIG_IEEE80211 is not set # @@ -470,6 +463,10 @@ CONFIG_FW_LOADER=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# # CONFIG_MTD is not set # @@ -516,7 +513,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set # CONFIG_SONY_LAPTOP is not set -# CONFIG_THINKPAD_ACPI is not set # # ATA/ATAPI/MFM/RLL support @@ -552,6 +548,7 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set @@ -583,6 +580,7 @@ CONFIG_BLK_DEV_PIIX=y # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y # CONFIG_BLK_DEV_HD is not set # @@ -671,7 +669,6 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_ESP_CORE is not set # CONFIG_SCSI_SRP is not set # @@ -695,12 +692,12 @@ CONFIG_SATA_SIL=y CONFIG_SATA_VIA=y # CONFIG_SATA_VITESSE is not set # CONFIG_SATA_INIC162X is not set +CONFIG_SATA_INTEL_COMBINED=y CONFIG_SATA_ACPI=y # CONFIG_PATA_ALI is not set # CONFIG_PATA_AMD is not set # CONFIG_PATA_ARTOP is not set # CONFIG_PATA_ATIIXP is not set -# CONFIG_PATA_CMD640_PCI is not set # CONFIG_PATA_CMD64X is not set # CONFIG_PATA_CS5520 is not set # CONFIG_PATA_CS5530 is not set @@ -766,9 +763,10 @@ CONFIG_IEEE1394=y # Subsystem Options # # CONFIG_IEEE1394_VERBOSEDEBUG is not set +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set # -# Controllers +# Device Drivers # # @@ -777,11 +775,10 @@ CONFIG_IEEE1394=y CONFIG_IEEE1394_OHCI1394=y # -# Protocols +# Protocol Drivers # # CONFIG_IEEE1394_VIDEO1394 is not set # CONFIG_IEEE1394_SBP2 is not set -# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set # CONFIG_IEEE1394_ETH1394 is not set # CONFIG_IEEE1394_DV1394 is not set CONFIG_IEEE1394_RAWIO=y @@ -824,9 +821,7 @@ CONFIG_MII=y # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set -CONFIG_NET_VENDOR_3COM=y -CONFIG_VORTEX=y -# CONFIG_TYPHOON is not set +# CONFIG_NET_VENDOR_3COM is not set # # Tulip family network device support @@ -907,10 +902,9 @@ CONFIG_BNX2=y # CONFIG_TR is not set # -# Wireless LAN +# Wireless LAN (non-hamradio) # -# CONFIG_WLAN_PRE80211 is not set -# CONFIG_WLAN_80211 is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces @@ -924,6 +918,7 @@ CONFIG_BNX2=y # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set # CONFIG_NETPOLL_TRAP is not set CONFIG_NET_POLL_CONTROLLER=y @@ -1056,7 +1051,7 @@ CONFIG_MAX_RAW_DEVS=256 CONFIG_HPET=y # CONFIG_HPET_RTC_IRQ is not set CONFIG_HPET_MMAP=y -# CONFIG_HANGCHECK_TIMER is not set +CONFIG_HANGCHECK_TIMER=y # # TPM devices @@ -1147,14 +1142,6 @@ CONFIG_SOUND_ICH=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set -# -# USB Input Devices -# -CONFIG_USB_HID=y -# CONFIG_USB_HIDINPUT_POWERBOOK is not set -# CONFIG_HID_FF is not set -# CONFIG_USB_HIDDEV is not set - # # USB support # @@ -1168,7 +1155,6 @@ CONFIG_USB=y # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set @@ -1219,6 +1205,10 @@ CONFIG_USB_STORAGE=y # # USB Input Devices # +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set # CONFIG_USB_ACECAD is not set @@ -1539,7 +1529,7 @@ CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -CONFIG_TIMER_STATS=y +# CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set diff --git a/trunk/arch/i386/kernel/Makefile b/trunk/arch/i386/kernel/Makefile index 4f98516b9f94..4ae3dcf1d2f0 100644 --- a/trunk/arch/i386/kernel/Makefile +++ b/trunk/arch/i386/kernel/Makefile @@ -39,10 +39,12 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o -obj-$(CONFIG_VMI) += vmi.o vmiclock.o +obj-$(CONFIG_VMI) += vmi.o vmitime.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-y += pcspeaker.o +EXTRA_AFLAGS := -traditional + obj-$(CONFIG_SCx200) += scx200.o # vsyscall.o contains the vsyscall DSO images as __initdata. diff --git a/trunk/arch/i386/kernel/acpi/boot.c b/trunk/arch/i386/kernel/acpi/boot.c index 280898b045b2..9ea5b8ecc7e1 100644 --- a/trunk/arch/i386/kernel/acpi/boot.c +++ b/trunk/arch/i386/kernel/acpi/boot.c @@ -874,7 +874,7 @@ static void __init acpi_process_madt(void) acpi_ioapic = 1; smp_found_config = 1; - setup_apic_routing(); + clustered_apic_check(); } } if (error == -EINVAL) { diff --git a/trunk/arch/i386/kernel/acpi/earlyquirk.c b/trunk/arch/i386/kernel/acpi/earlyquirk.c index 23f78efc577d..a7d22d9f3d7e 100644 --- a/trunk/arch/i386/kernel/acpi/earlyquirk.c +++ b/trunk/arch/i386/kernel/acpi/earlyquirk.c @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI @@ -22,13 +23,10 @@ static int __init nvidia_hpet_check(struct acpi_table_header *header) static int __init check_bridge(int vendor, int device) { #ifdef CONFIG_ACPI - static int warned; /* According to Nvidia all timer overrides are bogus unless HPET is enabled. */ if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) { - if (!warned && acpi_table_parse(ACPI_SIG_HPET, - nvidia_hpet_check)) { - warned = 1; + if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " "detected. Ignoring ACPI " @@ -47,6 +45,24 @@ static int __init check_bridge(int vendor, int device) return 0; } +static void check_intel(void) +{ + u16 vendor, device; + + vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID); + + if (vendor != PCI_VENDOR_ID_INTEL) + return; + + device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID); +#ifdef CONFIG_SMP + if (device == PCI_DEVICE_ID_INTEL_E7320_MCH || + device == PCI_DEVICE_ID_INTEL_E7520_MCH || + device == PCI_DEVICE_ID_INTEL_E7525_MCH) + quirk_intel_irqbalance(); +#endif +} + void __init check_acpi_pci(void) { int num, slot, func; @@ -58,6 +74,8 @@ void __init check_acpi_pci(void) if (!early_pci_allowed()) return; + check_intel(); + /* Poor man's PCI discovery */ for (num = 0; num < 32; num++) { for (slot = 0; slot < 32; slot++) { diff --git a/trunk/arch/i386/kernel/alternative.c b/trunk/arch/i386/kernel/alternative.c index e5cec6685cc5..9eca21b49f6b 100644 --- a/trunk/arch/i386/kernel/alternative.c +++ b/trunk/arch/i386/kernel/alternative.c @@ -5,41 +5,29 @@ #include #include -static int noreplace_smp = 0; +static int no_replacement = 0; static int smp_alt_once = 0; static int debug_alternative = 0; +static int __init noreplacement_setup(char *s) +{ + no_replacement = 1; + return 1; +} static int __init bootonly(char *str) { smp_alt_once = 1; return 1; } -__setup("smp-alt-boot", bootonly); - static int __init debug_alt(char *str) { debug_alternative = 1; return 1; } -__setup("debug-alternative", debug_alt); - -static int __init setup_noreplace_smp(char *str) -{ - noreplace_smp = 1; - return 1; -} -__setup("noreplace-smp", setup_noreplace_smp); - -#ifdef CONFIG_PARAVIRT -static int noreplace_paravirt = 0; -static int __init setup_noreplace_paravirt(char *str) -{ - noreplace_paravirt = 1; - return 1; -} -__setup("noreplace-paravirt", setup_noreplace_paravirt); -#endif +__setup("noreplacement", noreplacement_setup); +__setup("smp-alt-boot", bootonly); +__setup("debug-alternative", debug_alt); #define DPRINTK(fmt, args...) if (debug_alternative) \ printk(KERN_DEBUG fmt, args) @@ -151,8 +139,11 @@ static void nop_out(void *insns, unsigned int len) } extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; +extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[]; extern u8 *__smp_locks[], *__smp_locks_end[]; +extern u8 __smp_alt_begin[], __smp_alt_end[]; + /* Replace instructions with better alternatives for this CPU type. This runs before SMP is initialized to avoid SMP problems with self modifying code. This implies that assymetric systems where @@ -187,6 +178,29 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) #ifdef CONFIG_SMP +static void alternatives_smp_save(struct alt_instr *start, struct alt_instr *end) +{ + struct alt_instr *a; + + DPRINTK("%s: alt table %p-%p\n", __FUNCTION__, start, end); + for (a = start; a < end; a++) { + memcpy(a->replacement + a->replacementlen, + a->instr, + a->instrlen); + } +} + +static void alternatives_smp_apply(struct alt_instr *start, struct alt_instr *end) +{ + struct alt_instr *a; + + for (a = start; a < end; a++) { + memcpy(a->instr, + a->replacement + a->replacementlen, + a->instrlen); + } +} + static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end) { u8 **ptr; @@ -204,9 +218,6 @@ static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end { u8 **ptr; - if (noreplace_smp) - return; - for (ptr = start; ptr < end; ptr++) { if (*ptr < text) continue; @@ -241,7 +252,7 @@ void alternatives_smp_module_add(struct module *mod, char *name, struct smp_alt_module *smp; unsigned long flags; - if (noreplace_smp) + if (no_replacement) return; if (smp_alt_once) { @@ -278,7 +289,7 @@ void alternatives_smp_module_del(struct module *mod) struct smp_alt_module *item; unsigned long flags; - if (smp_alt_once || noreplace_smp) + if (no_replacement || smp_alt_once) return; spin_lock_irqsave(&smp_alt, flags); @@ -309,7 +320,7 @@ void alternatives_smp_switch(int smp) return; #endif - if (noreplace_smp || smp_alt_once) + if (no_replacement || smp_alt_once) return; BUG_ON(!smp && (num_online_cpus() > 1)); @@ -318,6 +329,8 @@ void alternatives_smp_switch(int smp) printk(KERN_INFO "SMP alternatives: switching to SMP code\n"); clear_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability); clear_bit(X86_FEATURE_UP, cpu_data[0].x86_capability); + alternatives_smp_apply(__smp_alt_instructions, + __smp_alt_instructions_end); list_for_each_entry(mod, &smp_alt_modules, next) alternatives_smp_lock(mod->locks, mod->locks_end, mod->text, mod->text_end); @@ -325,6 +338,8 @@ void alternatives_smp_switch(int smp) printk(KERN_INFO "SMP alternatives: switching to UP code\n"); set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability); set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability); + apply_alternatives(__smp_alt_instructions, + __smp_alt_instructions_end); list_for_each_entry(mod, &smp_alt_modules, next) alternatives_smp_unlock(mod->locks, mod->locks_end, mod->text, mod->text_end); @@ -335,37 +350,49 @@ void alternatives_smp_switch(int smp) #endif #ifdef CONFIG_PARAVIRT -void apply_paravirt(struct paravirt_patch_site *start, - struct paravirt_patch_site *end) +void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end) { - struct paravirt_patch_site *p; - - if (noreplace_paravirt) - return; + struct paravirt_patch *p; for (p = start; p < end; p++) { unsigned int used; used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr, p->len); - - BUG_ON(used > p->len); - +#ifdef CONFIG_DEBUG_PARAVIRT + { + int i; + /* Deliberately clobber regs using "not %reg" to find bugs. */ + for (i = 0; i < 3; i++) { + if (p->len - used >= 2 && (p->clobbers & (1 << i))) { + memcpy(p->instr + used, "\xf7\xd0", 2); + p->instr[used+1] |= i; + used += 2; + } + } + } +#endif /* Pad the rest with nops */ nop_out(p->instr + used, p->len - used); } - /* Sync to be conservative, in case we patched following - * instructions */ + /* Sync to be conservative, in case we patched following instructions */ sync_core(); } -extern struct paravirt_patch_site __start_parainstructions[], +extern struct paravirt_patch __start_parainstructions[], __stop_parainstructions[]; #endif /* CONFIG_PARAVIRT */ void __init alternative_instructions(void) { unsigned long flags; + if (no_replacement) { + printk(KERN_INFO "(SMP-)alternatives turned off\n"); + free_init_pages("SMP alternatives", + (unsigned long)__smp_alt_begin, + (unsigned long)__smp_alt_end); + return; + } local_irq_save(flags); apply_alternatives(__alt_instructions, __alt_instructions_end); @@ -386,19 +413,23 @@ void __init alternative_instructions(void) printk(KERN_INFO "SMP alternatives: switching to UP code\n"); set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability); set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability); + apply_alternatives(__smp_alt_instructions, + __smp_alt_instructions_end); alternatives_smp_unlock(__smp_locks, __smp_locks_end, _text, _etext); } free_init_pages("SMP alternatives", - __pa_symbol(&__smp_locks), - __pa_symbol(&__smp_locks_end)); + (unsigned long)__smp_alt_begin, + (unsigned long)__smp_alt_end); } else { + alternatives_smp_save(__smp_alt_instructions, + __smp_alt_instructions_end); alternatives_smp_module_add(NULL, "core kernel", __smp_locks, __smp_locks_end, _text, _etext); alternatives_smp_switch(0); } #endif - apply_paravirt(__parainstructions, __parainstructions_end); + apply_paravirt(__start_parainstructions, __stop_parainstructions); local_irq_restore(flags); } diff --git a/trunk/arch/i386/kernel/apic.c b/trunk/arch/i386/kernel/apic.c index aca054cc0552..93aa911646ad 100644 --- a/trunk/arch/i386/kernel/apic.c +++ b/trunk/arch/i386/kernel/apic.c @@ -129,28 +129,6 @@ static int modern_apic(void) return lapic_get_version() >= 0x14; } -void apic_wait_icr_idle(void) -{ - while (apic_read(APIC_ICR) & APIC_ICR_BUSY) - cpu_relax(); -} - -unsigned long safe_apic_wait_icr_idle(void) -{ - unsigned long send_status; - int timeout; - - timeout = 0; - do { - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; - if (!send_status) - break; - udelay(100); - } while (timeout++ < 1000); - - return send_status; -} - /** * enable_NMI_through_LVT0 - enable NMI through local vector table 0 */ diff --git a/trunk/arch/i386/kernel/apm.c b/trunk/arch/i386/kernel/apm.c index 367ff1d930cb..064bbf2861f4 100644 --- a/trunk/arch/i386/kernel/apm.c +++ b/trunk/arch/i386/kernel/apm.c @@ -233,10 +233,11 @@ #include #include #include -#include #include "io_ports.h" +extern void machine_real_restart(unsigned char *, int); + #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); #endif @@ -383,6 +384,13 @@ static int ignore_sys_suspend; static int ignore_normal_resume; static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL; +#ifdef CONFIG_APM_RTC_IS_GMT +# define clock_cmos_diff 0 +# define got_clock_diff 1 +#else +static long clock_cmos_diff; +static int got_clock_diff; +#endif static int debug __read_mostly; static int smp __read_mostly; static int apm_disabled = -1; diff --git a/trunk/arch/i386/kernel/asm-offsets.c b/trunk/arch/i386/kernel/asm-offsets.c index 27a776c9044d..c37535163bfc 100644 --- a/trunk/arch/i386/kernel/asm-offsets.c +++ b/trunk/arch/i386/kernel/asm-offsets.c @@ -11,11 +11,11 @@ #include #include #include "sigframe.h" -#include #include #include #include #include +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -25,9 +25,6 @@ #define OFFSET(sym, str, mem) \ DEFINE(sym, offsetof(struct str, mem)); -/* workaround for a warning with -Wmissing-prototypes */ -void foo(void); - void foo(void) { OFFSET(SIGCONTEXT_eax, sigcontext, eax); @@ -93,19 +90,18 @@ void foo(void) OFFSET(pbe_next, pbe, next); /* Offset from the sysenter stack to tss.esp0 */ - DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, x86_tss.esp0) - + DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) - sizeof(struct tss_struct)); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); - DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT); - DEFINE(PTRS_PER_PTE, PTRS_PER_PTE); - DEFINE(PTRS_PER_PMD, PTRS_PER_PMD); - DEFINE(PTRS_PER_PGD, PTRS_PER_PGD); - - DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK); + DEFINE(VDSO_PRELINK, VDSO_PRELINK); OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); + BLANK(); + OFFSET(PDA_cpu, i386_pda, cpu_number); + OFFSET(PDA_pcurrent, i386_pda, pcurrent); + #ifdef CONFIG_PARAVIRT BLANK(); OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled); diff --git a/trunk/arch/i386/kernel/cpu/Makefile b/trunk/arch/i386/kernel/cpu/Makefile index 74f27a463db0..010aecfffbc1 100644 --- a/trunk/arch/i386/kernel/cpu/Makefile +++ b/trunk/arch/i386/kernel/cpu/Makefile @@ -2,7 +2,7 @@ # Makefile for x86-compatible CPU details and quirks # -obj-y := common.o proc.o bugs.o +obj-y := common.o proc.o obj-y += amd.o obj-y += cyrix.o @@ -17,5 +17,3 @@ obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ - -obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/trunk/arch/i386/kernel/cpu/amd.c b/trunk/arch/i386/kernel/cpu/amd.c index 4fec702afd7e..2d47db482972 100644 --- a/trunk/arch/i386/kernel/cpu/amd.c +++ b/trunk/arch/i386/kernel/cpu/amd.c @@ -53,8 +53,6 @@ static __cpuinit int amd_apic_timer_broken(void) return 0; } -int force_mwait __cpuinitdata; - static void __cpuinit init_amd(struct cpuinfo_x86 *c) { u32 l, h; @@ -277,9 +275,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) if (amd_apic_timer_broken()) set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability); - - if (c->x86 == 0x10 && !force_mwait) - clear_bit(X86_FEATURE_MWAIT, c->x86_capability); } static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) @@ -319,3 +314,13 @@ int __init amd_init_cpu(void) cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev; return 0; } + +//early_arch_initcall(amd_init_cpu); + +static int __init amd_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_AMD] = NULL; + return 0; +} + +late_initcall(amd_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/bugs.c b/trunk/arch/i386/kernel/cpu/bugs.c deleted file mode 100644 index 54428a2500f3..000000000000 --- a/trunk/arch/i386/kernel/cpu/bugs.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * arch/i386/cpu/bugs.c - * - * Copyright (C) 1994 Linus Torvalds - * - * Cyrix stuff, June 1998 by: - * - Rafael R. Reilova (moved everything from head.S), - * - * - Channing Corn (tests & fixes), - * - Andrew D. Balsa (code cleanup). - */ -#include -#include -#include -#include -#include -#include -#include - -static int __init no_halt(char *s) -{ - boot_cpu_data.hlt_works_ok = 0; - return 1; -} - -__setup("no-hlt", no_halt); - -static int __init mca_pentium(char *s) -{ - mca_pentium_flag = 1; - return 1; -} - -__setup("mca-pentium", mca_pentium); - -static int __init no_387(char *s) -{ - boot_cpu_data.hard_math = 0; - write_cr0(0xE | read_cr0()); - return 1; -} - -__setup("no387", no_387); - -static double __initdata x = 4195835.0; -static double __initdata y = 3145727.0; - -/* - * This used to check for exceptions.. - * However, it turns out that to support that, - * the XMM trap handlers basically had to - * be buggy. So let's have a correct XMM trap - * handler, and forget about printing out - * some status at boot. - * - * We should really only care about bugs here - * anyway. Not features. - */ -static void __init check_fpu(void) -{ - if (!boot_cpu_data.hard_math) { -#ifndef CONFIG_MATH_EMULATION - printk(KERN_EMERG "No coprocessor found and no math emulation present.\n"); - printk(KERN_EMERG "Giving up.\n"); - for (;;) ; -#endif - return; - } - -/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */ - /* Test for the divl bug.. */ - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&boot_cpu_data.fdiv_bug) - : "m" (*&x), "m" (*&y)); - if (boot_cpu_data.fdiv_bug) - printk("Hmm, FPU with FDIV bug.\n"); -} - -static void __init check_hlt(void) -{ - if (paravirt_enabled()) - return; - - printk(KERN_INFO "Checking 'hlt' instruction... "); - if (!boot_cpu_data.hlt_works_ok) { - printk("disabled\n"); - return; - } - halt(); - halt(); - halt(); - halt(); - printk("OK.\n"); -} - -/* - * Most 386 processors have a bug where a POPAD can lock the - * machine even from user space. - */ - -static void __init check_popad(void) -{ -#ifndef CONFIG_X86_POPAD_OK - int res, inp = (int) &res; - - printk(KERN_INFO "Checking for popad bug... "); - __asm__ __volatile__( - "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx " - : "=&a" (res) - : "d" (inp) - : "ecx", "edi" ); - /* If this fails, it means that any user program may lock the CPU hard. Too bad. */ - if (res != 12345678) printk( "Buggy.\n" ); - else printk( "OK.\n" ); -#endif -} - -/* - * Check whether we are able to run this kernel safely on SMP. - * - * - In order to run on a i386, we need to be compiled for i386 - * (for due to lack of "invlpg" and working WP on a i386) - * - In order to run on anything without a TSC, we need to be - * compiled for a i486. - * - In order to support the local APIC on a buggy Pentium machine, - * we need to be compiled with CONFIG_X86_GOOD_APIC disabled, - * which happens implicitly if compiled for a Pentium or lower - * (unless an advanced selection of CPU features is used) as an - * otherwise config implies a properly working local APIC without - * the need to do extra reads from the APIC. -*/ - -static void __init check_config(void) -{ -/* - * We'd better not be a i386 if we're configured to use some - * i486+ only features! (WP works in supervisor mode and the - * new "invlpg" and "bswap" instructions) - */ -#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP) - if (boot_cpu_data.x86 == 3) - panic("Kernel requires i486+ for 'invlpg' and other features"); -#endif - -/* - * If we configured ourselves for a TSC, we'd better have one! - */ -#ifdef CONFIG_X86_TSC - if (!cpu_has_tsc && !tsc_disable) - panic("Kernel compiled for Pentium+, requires TSC feature!"); -#endif - -/* - * If we were told we had a good local APIC, check for buggy Pentia, - * i.e. all B steppings and the C2 stepping of P54C when using their - * integrated APIC (see 11AP erratum in "Pentium Processor - * Specification Update"). - */ -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC) - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL - && cpu_has_apic - && boot_cpu_data.x86 == 5 - && boot_cpu_data.x86_model == 2 - && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11)) - panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!"); -#endif -} - - -void __init check_bugs(void) -{ - identify_boot_cpu(); -#ifndef CONFIG_SMP - printk("CPU: "); - print_cpu_info(&boot_cpu_data); -#endif - check_config(); - check_fpu(); - check_hlt(); - check_popad(); - init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86); - alternative_instructions(); -} diff --git a/trunk/arch/i386/kernel/cpu/centaur.c b/trunk/arch/i386/kernel/cpu/centaur.c index 473eac883c7b..8c25047975c0 100644 --- a/trunk/arch/i386/kernel/cpu/centaur.c +++ b/trunk/arch/i386/kernel/cpu/centaur.c @@ -469,3 +469,13 @@ int __init centaur_init_cpu(void) cpu_devs[X86_VENDOR_CENTAUR] = ¢aur_cpu_dev; return 0; } + +//early_arch_initcall(centaur_init_cpu); + +static int __init centaur_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_CENTAUR] = NULL; + return 0; +} + +late_initcall(centaur_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/common.c b/trunk/arch/i386/kernel/cpu/common.c index 794d593c47eb..dcbbd0a8bfc2 100644 --- a/trunk/arch/i386/kernel/cpu/common.c +++ b/trunk/arch/i386/kernel/cpu/common.c @@ -18,37 +18,15 @@ #include #include #endif +#include #include "cpu.h" -DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { - [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, - [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, - [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, - [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, - /* - * Segments used for calling PnP BIOS have byte granularity. - * They code segments and data segments have fixed 64k limits, - * the transfer segment sizes are set at run time. - */ - [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ - [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ - /* - * The APM segments have byte granularity and their bases - * are set at run time. All have 64k limits. - */ - [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ - /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, - [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ +DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); +EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); - [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, - [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 }, -} }; -EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); +struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(_cpu_pda); static int cachesize_override __cpuinitdata = -1; static int disable_x86_fxsr __cpuinitdata; @@ -390,7 +368,7 @@ __setup("serialnumber", x86_serial_nr_setup); /* * This does the hard work of actually picking apart the CPU stuff... */ -static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) +void __cpuinit identify_cpu(struct cpuinfo_x86 *c) { int i; @@ -501,22 +479,15 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) /* Init Machine Check Exception if available. */ mcheck_init(c); -} -void __init identify_boot_cpu(void) -{ - identify_cpu(&boot_cpu_data); - sysenter_setup(); + if (c == &boot_cpu_data) + sysenter_setup(); enable_sep_cpu(); - mtrr_bp_init(); -} -void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) -{ - BUG_ON(c == &boot_cpu_data); - identify_cpu(c); - enable_sep_cpu(); - mtrr_ap_init(); + if (c == &boot_cpu_data) + mtrr_bp_init(); + else + mtrr_ap_init(); } #ifdef CONFIG_X86_HT @@ -630,36 +601,129 @@ void __init early_cpu_init(void) #endif } -/* Make sure %fs is initialized properly in idle threads */ +/* Make sure %gs is initialized properly in idle threads */ struct pt_regs * __devinit idle_regs(struct pt_regs *regs) { memset(regs, 0, sizeof(struct pt_regs)); - regs->xfs = __KERNEL_PERCPU; + regs->xfs = __KERNEL_PDA; return regs; } -/* Current gdt points %fs at the "master" per-cpu area: after this, - * it's on the real one. */ -void switch_to_new_gdt(void) +static __cpuinit int alloc_gdt(int cpu) { - struct Xgt_desc_struct gdt_descr; + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); + struct desc_struct *gdt; + struct i386_pda *pda; + + gdt = (struct desc_struct *)cpu_gdt_descr->address; + pda = cpu_pda(cpu); + + /* + * This is a horrible hack to allocate the GDT. The problem + * is that cpu_init() is called really early for the boot CPU + * (and hence needs bootmem) but much later for the secondary + * CPUs, when bootmem will have gone away + */ + if (NODE_DATA(0)->bdata->node_bootmem_map) { + BUG_ON(gdt != NULL || pda != NULL); + + gdt = alloc_bootmem_pages(PAGE_SIZE); + pda = alloc_bootmem(sizeof(*pda)); + /* alloc_bootmem(_pages) panics on failure, so no check */ + + memset(gdt, 0, PAGE_SIZE); + memset(pda, 0, sizeof(*pda)); + } else { + /* GDT and PDA might already have been allocated if + this is a CPU hotplug re-insertion. */ + if (gdt == NULL) + gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); + + if (pda == NULL) + pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu)); + + if (unlikely(!gdt || !pda)) { + free_pages((unsigned long)gdt, 0); + kfree(pda); + return 0; + } + } + + cpu_gdt_descr->address = (unsigned long)gdt; + cpu_pda(cpu) = pda; + + return 1; +} - gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); - gdt_descr.size = GDT_SIZE - 1; - load_gdt(&gdt_descr); - asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory"); +/* Initial PDA used by boot CPU */ +struct i386_pda boot_pda = { + ._pda = &boot_pda, + .cpu_number = 0, + .pcurrent = &init_task, +}; + +static inline void set_kernel_fs(void) +{ + /* Set %fs for this CPU's PDA. Memory clobber is to create a + barrier with respect to any PDA operations, so the compiler + doesn't move any before here. */ + asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); } -/* - * cpu_init() initializes state that is per-CPU. Some data is already - * initialized (naturally) in the bootstrap process, such as the GDT - * and IDT. We reload them nevertheless, this function acts as a - * 'CPU state barrier', nothing should get across. - */ -void __cpuinit cpu_init(void) +/* Initialize the CPU's GDT and PDA. The boot CPU does this for + itself, but secondaries find this done for them. */ +__cpuinit int init_gdt(int cpu, struct task_struct *idle) +{ + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); + struct desc_struct *gdt; + struct i386_pda *pda; + + /* For non-boot CPUs, the GDT and PDA should already have been + allocated. */ + if (!alloc_gdt(cpu)) { + printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu); + return 0; + } + + gdt = (struct desc_struct *)cpu_gdt_descr->address; + pda = cpu_pda(cpu); + + BUG_ON(gdt == NULL || pda == NULL); + + /* + * Initialize the per-CPU GDT with the boot GDT, + * and set up the GDT descriptor: + */ + memcpy(gdt, cpu_gdt_table, GDT_SIZE); + cpu_gdt_descr->size = GDT_SIZE - 1; + + pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, + (u32 *)&gdt[GDT_ENTRY_PDA].b, + (unsigned long)pda, sizeof(*pda) - 1, + 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ + + memset(pda, 0, sizeof(*pda)); + pda->_pda = pda; + pda->cpu_number = cpu; + pda->pcurrent = idle; + + return 1; +} + +void __cpuinit cpu_set_gdt(int cpu) +{ + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); + + /* Reinit these anyway, even if they've already been done (on + the boot CPU, this will transition from the boot gdt+pda to + the real ones). */ + load_gdt(cpu_gdt_descr); + set_kernel_fs(); +} + +/* Common CPU init for both boot and secondary CPUs */ +static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) { - int cpu = smp_processor_id(); - struct task_struct *curr = current; struct tss_struct * t = &per_cpu(init_tss, cpu); struct thread_struct *thread = &curr->thread; @@ -680,7 +744,6 @@ void __cpuinit cpu_init(void) } load_idt(&idt_descr); - switch_to_new_gdt(); /* * Set up and load the per-CPU TSS and LDT @@ -720,6 +783,38 @@ void __cpuinit cpu_init(void) mxcsr_feature_mask_init(); } +/* Entrypoint to initialize secondary CPU */ +void __cpuinit secondary_cpu_init(void) +{ + int cpu = smp_processor_id(); + struct task_struct *curr = current; + + _cpu_init(cpu, curr); +} + +/* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process, such as the GDT + * and IDT. We reload them nevertheless, this function acts as a + * 'CPU state barrier', nothing should get across. + */ +void __cpuinit cpu_init(void) +{ + int cpu = smp_processor_id(); + struct task_struct *curr = current; + + /* Set up the real GDT and PDA, so we can transition from the + boot versions. */ + if (!init_gdt(cpu, curr)) { + /* failed to allocate something; not much we can do... */ + for (;;) + local_irq_enable(); + } + + cpu_set_gdt(cpu); + _cpu_init(cpu, curr); +} + #ifdef CONFIG_HOTPLUG_CPU void __cpuinit cpu_uninit(void) { diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/longhaul.c b/trunk/arch/i386/kernel/cpu/cpufreq/longhaul.c index a3df9c039bd4..a1f1b715bcf8 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -590,23 +590,20 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle, static int enable_arbiter_disable(void) { struct pci_dev *dev; - int status; int reg; u8 pci_cmd; - status = 1; /* Find PLE133 host bridge */ reg = 0x78; - dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, - NULL); + dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); /* Find CLE266 host bridge */ if (dev == NULL) { reg = 0x76; - dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_862X_0, NULL); + dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL); /* Find CN400 V-Link host bridge */ if (dev == NULL) - dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); + dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); + } if (dev != NULL) { /* Enable access to port 0x22 */ @@ -618,11 +615,10 @@ static int enable_arbiter_disable(void) if (!(pci_cmd & 1<<7)) { printk(KERN_ERR PFX "Can't enable access to port 0x22.\n"); - status = 0; + return 0; } } - pci_dev_put(dev); - return status; + return 1; } return 0; } @@ -633,7 +629,7 @@ static int longhaul_setup_vt8235(void) u8 pci_cmd; /* Find VT8235 southbridge */ - dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); + dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); if (dev != NULL) { /* Set transition time to max */ pci_read_config_byte(dev, 0xec, &pci_cmd); @@ -645,7 +641,6 @@ static int longhaul_setup_vt8235(void) pci_read_config_byte(dev, 0xe5, &pci_cmd); pci_cmd |= 1 << 7; pci_write_config_byte(dev, 0xe5, pci_cmd); - pci_dev_put(dev); return 1; } return 0; @@ -683,7 +678,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) sizeof(samuel2_eblcr)); break; case 1 ... 15: - longhaul_version = TYPE_LONGHAUL_V1; + longhaul_version = TYPE_LONGHAUL_V2; if (c->x86_mask < 8) { cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; @@ -763,7 +758,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) NULL, (void *)&pr); /* Check ACPI support for C3 state */ - if (pr != NULL && longhaul_version == TYPE_POWERSAVER) { + if (pr != NULL && longhaul_version != TYPE_LONGHAUL_V1) { cx = &pr->power.states[ACPI_STATE_C3]; if (cx->address > 0 && cx->latency <= 1000) { longhaul_flags |= USE_ACPI_C3; diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/trunk/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 4c76b511e194..4786fedca6eb 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -27,6 +27,7 @@ #include #include #include +#include /* current / set_cpus_allowed() */ #include #include @@ -61,7 +62,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; - rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); + rdmsr(MSR_IA32_THERM_STATUS, l, h); if (l & 0x01) dprintk("CPU#%d currently thermal throttled\n", cpu); @@ -69,10 +70,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) newstate = DC_38PT; - rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); + rdmsr(MSR_IA32_THERM_CONTROL, l, h); if (newstate == DC_DISABLE) { dprintk("CPU#%d disabling modulation\n", cpu); - wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { dprintk("CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); @@ -83,7 +84,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) */ l = (l & ~14); l = l | (1<<4) | ((newstate & 0x7)<<1); - wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); + wrmsr(MSR_IA32_THERM_CONTROL, l, h); } return 0; @@ -110,6 +111,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, { unsigned int newstate = DC_RESV; struct cpufreq_freqs freqs; + cpumask_t cpus_allowed; int i; if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) @@ -130,8 +132,17 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ - for_each_cpu_mask(i, policy->cpus) + cpus_allowed = current->cpus_allowed; + + for_each_cpu_mask(i, policy->cpus) { + cpumask_t this_cpu = cpumask_of_cpu(i); + + set_cpus_allowed(current, this_cpu); + BUG_ON(smp_processor_id() != i); + cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); + } + set_cpus_allowed(current, cpus_allowed); /* notifiers */ for_each_cpu_mask(i, policy->cpus) { @@ -245,9 +256,17 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) static unsigned int cpufreq_p4_get(unsigned int cpu) { + cpumask_t cpus_allowed; u32 l, h; - rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); + cpus_allowed = current->cpus_allowed; + + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(smp_processor_id() != cpu); + + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + + set_cpus_allowed(current, cpus_allowed); if (l & 0x10) { l = l >> 1; diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 7cf3d207b6b3..fe3b67005ebb 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -661,8 +661,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); data->powernow_table = powernow_table; - if (first_cpu(cpu_core_map[data->cpu]) == data->cpu) - print_basics(data); + print_basics(data); for (j = 0; j < data->numps; j++) if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid)) @@ -815,8 +814,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) /* fill in data */ data->numps = data->acpi_data.state_count; - if (first_cpu(cpu_core_map[data->cpu]) == data->cpu) - print_basics(data); + print_basics(data); powernow_k8_acpi_pst_values(data, 0); /* notify BIOS that we exist */ diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.h index 95be5013c984..0fb2a3001ba5 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.h +++ b/trunk/arch/i386/kernel/cpu/cpufreq/powernow-k8.h @@ -215,10 +215,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index); -#ifdef CONFIG_X86_POWERNOW_K8_ACPI static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); -#endif #ifdef CONFIG_SMP static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[]) diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 35489fd68852..f43b987f952b 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -720,7 +720,6 @@ static int centrino_target (struct cpufreq_policy *policy, cpu_set(j, set_mask); set_cpus_allowed(current, set_mask); - preempt_disable(); if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { dprintk("couldn't limit to CPUs in this domain\n"); retval = -EAGAIN; @@ -728,7 +727,6 @@ static int centrino_target (struct cpufreq_policy *policy, /* We haven't started the transition yet. */ goto migrate_end; } - preempt_enable(); break; } @@ -763,13 +761,10 @@ static int centrino_target (struct cpufreq_policy *policy, } wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { - preempt_enable(); + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) break; - } cpu_set(j, covered_cpus); - preempt_enable(); } for_each_cpu_mask(k, online_policy_cpus) { @@ -801,11 +796,8 @@ static int centrino_target (struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } } - set_cpus_allowed(current, saved_mask); - return 0; migrate_end: - preempt_enable(); set_cpus_allowed(current, saved_mask); return 0; } diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c index b1acc8ce3167..d59277c00911 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index e1c509aa3054..ff0d89806114 100644 --- a/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/trunk/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -17,10 +17,10 @@ #include #include #include +#include #include #include #include -#include #include "speedstep-lib.h" diff --git a/trunk/arch/i386/kernel/cpu/cyrix.c b/trunk/arch/i386/kernel/cpu/cyrix.c index 0b8411a864fb..de27bd07bc9c 100644 --- a/trunk/arch/i386/kernel/cpu/cyrix.c +++ b/trunk/arch/i386/kernel/cpu/cyrix.c @@ -279,7 +279,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) */ if (vendor == PCI_VENDOR_ID_CYRIX && (device == PCI_DEVICE_ID_CYRIX_5510 || device == PCI_DEVICE_ID_CYRIX_5520)) - mark_tsc_unstable("cyrix 5510/5520 detected"); + pit_latch_buggy = 1; } #endif c->x86_cache_size=16; /* Yep 16K integrated cache thats it */ @@ -448,6 +448,16 @@ int __init cyrix_init_cpu(void) return 0; } +//early_arch_initcall(cyrix_init_cpu); + +static int __init cyrix_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_CYRIX] = NULL; + return 0; +} + +late_initcall(cyrix_exit_cpu); + static struct cpu_dev nsc_cpu_dev __cpuinitdata = { .c_vendor = "NSC", .c_ident = { "Geode by NSC" }, @@ -460,3 +470,12 @@ int __init nsc_init_cpu(void) return 0; } +//early_arch_initcall(nsc_init_cpu); + +static int __init nsc_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_NSC] = NULL; + return 0; +} + +late_initcall(nsc_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/intel.c b/trunk/arch/i386/kernel/cpu/intel.c index dc4e08147b1f..56fe26584957 100644 --- a/trunk/arch/i386/kernel/cpu/intel.c +++ b/trunk/arch/i386/kernel/cpu/intel.c @@ -188,10 +188,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) } #endif - if (c->x86 == 15) { + if (c->x86 == 15) set_bit(X86_FEATURE_P4, c->x86_capability); - set_bit(X86_FEATURE_SYNC_RDTSC, c->x86_capability); - } if (c->x86 == 6) set_bit(X86_FEATURE_P3, c->x86_capability); if ((c->x86 == 0xf && c->x86_model >= 0x03) || diff --git a/trunk/arch/i386/kernel/cpu/mcheck/k7.c b/trunk/arch/i386/kernel/cpu/mcheck/k7.c index f9fa4142551e..b0862af595aa 100644 --- a/trunk/arch/i386/kernel/cpu/mcheck/k7.c +++ b/trunk/arch/i386/kernel/cpu/mcheck/k7.c @@ -75,9 +75,6 @@ void amd_mcheck_init(struct cpuinfo_x86 *c) machine_check_vector = k7_machine_check; wmb(); - if (!cpu_has(c, X86_FEATURE_MCE)) - return; - printk (KERN_INFO "Intel machine check architecture supported.\n"); rdmsr (MSR_IA32_MCG_CAP, l, h); if (l & (1<<8)) /* Control register present ? */ @@ -85,13 +82,9 @@ void amd_mcheck_init(struct cpuinfo_x86 *c) nr_mce_banks = l & 0xff; /* Clear status for MC index 0 separately, we don't touch CTL, - * as some K7 Athlons cause spurious MCEs when its enabled. */ - if (boot_cpu_data.x86 == 6) { - wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0); - i = 1; - } else - i = 0; - for (; ix86_vendor) { case X86_VENDOR_AMD: - amd_mcheck_init(c); + if (c->x86==6 || c->x86==15) + amd_mcheck_init(c); break; case X86_VENDOR_INTEL: diff --git a/trunk/arch/i386/kernel/cpu/mcheck/p4.c b/trunk/arch/i386/kernel/cpu/mcheck/p4.c index 1509edfb2313..504434a46011 100644 --- a/trunk/arch/i386/kernel/cpu/mcheck/p4.c +++ b/trunk/arch/i386/kernel/cpu/mcheck/p4.c @@ -124,10 +124,13 @@ static void intel_init_thermal(struct cpuinfo_x86 *c) /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */ -static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r) +static inline int intel_get_extended_msrs(struct intel_mce_extended_msrs *r) { u32 h; + if (mce_num_extended_msrs == 0) + goto done; + rdmsr (MSR_IA32_MCG_EAX, r->eax, h); rdmsr (MSR_IA32_MCG_EBX, r->ebx, h); rdmsr (MSR_IA32_MCG_ECX, r->ecx, h); @@ -138,6 +141,12 @@ static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r) rdmsr (MSR_IA32_MCG_ESP, r->esp, h); rdmsr (MSR_IA32_MCG_EFLAGS, r->eflags, h); rdmsr (MSR_IA32_MCG_EIP, r->eip, h); + + /* can we rely on kmalloc to do a dynamic + * allocation for the reserved registers? + */ +done: + return mce_num_extended_msrs; } static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) @@ -146,6 +155,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; int i; + struct intel_mce_extended_msrs dbg; rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if (mcgstl & (1<<0)) /* Recoverable ? */ @@ -154,9 +164,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); - if (mce_num_extended_msrs > 0) { - struct intel_mce_extended_msrs dbg; - intel_get_extended_msrs(&dbg); + if (intel_get_extended_msrs(&dbg)) { printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n", smp_processor_id(), dbg.eip, dbg.eflags); printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n", diff --git a/trunk/arch/i386/kernel/cpu/mtrr/generic.c b/trunk/arch/i386/kernel/cpu/mtrr/generic.c index 5367e32e0403..f77fc53db654 100644 --- a/trunk/arch/i386/kernel/cpu/mtrr/generic.c +++ b/trunk/arch/i386/kernel/cpu/mtrr/generic.c @@ -20,25 +20,13 @@ struct mtrr_state { mtrr_type def_type; }; -struct fixed_range_block { - int base_msr; /* start address of an MTRR block */ - int ranges; /* number of MTRRs in this block */ -}; - -static struct fixed_range_block fixed_range_blocks[] = { - { MTRRfix64K_00000_MSR, 1 }, /* one 64k MTRR */ - { MTRRfix16K_80000_MSR, 2 }, /* two 16k MTRRs */ - { MTRRfix4K_C0000_MSR, 8 }, /* eight 4k MTRRs */ - {} -}; - static unsigned long smp_changes_mask; static struct mtrr_state mtrr_state = {}; #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX "mtrr." -static int mtrr_show; +static __initdata int mtrr_show; module_param_named(show, mtrr_show, bool, 0); /* Get the MSR pair relating to a var range */ @@ -49,7 +37,7 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); } -static void +static void __init get_fixed_ranges(mtrr_type * frs) { unsigned int *p = (unsigned int *) frs; @@ -63,18 +51,12 @@ get_fixed_ranges(mtrr_type * frs) rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); } -void mtrr_save_fixed_ranges(void *info) -{ - get_fixed_ranges(mtrr_state.fixed_ranges); -} - -static void __cpuinit print_fixed(unsigned base, unsigned step, const mtrr_type*types) +static void __init print_fixed(unsigned base, unsigned step, const mtrr_type*types) { unsigned i; for (i = 0; i < 8; ++i, ++types, base += step) - printk(KERN_INFO "MTRR %05X-%05X %s\n", - base, base + step - 1, mtrr_attrib_to_str(*types)); + printk(KERN_INFO "MTRR %05X-%05X %s\n", base, base + step - 1, mtrr_attrib_to_str(*types)); } /* Grab all of the MTRR state for this CPU into *state */ @@ -165,44 +147,6 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b) smp_processor_id(), msr, a, b); } -/** - * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs - * see AMD publication no. 24593, chapter 3.2.1 for more information - */ -static inline void k8_enable_fixed_iorrs(void) -{ - unsigned lo, hi; - - rdmsr(MSR_K8_SYSCFG, lo, hi); - mtrr_wrmsr(MSR_K8_SYSCFG, lo - | K8_MTRRFIXRANGE_DRAM_ENABLE - | K8_MTRRFIXRANGE_DRAM_MODIFY, hi); -} - -/** - * Checks and updates an fixed-range MTRR if it differs from the value it - * should have. If K8 extenstions are wanted, update the K8 SYSCFG MSR also. - * see AMD publication no. 24593, chapter 7.8.1, page 233 for more information - * \param msr MSR address of the MTTR which should be checked and updated - * \param changed pointer which indicates whether the MTRR needed to be changed - * \param msrwords pointer to the MSR values which the MSR should have - */ -static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) -{ - unsigned lo, hi; - - rdmsr(msr, lo, hi); - - if (lo != msrwords[0] || hi != msrwords[1]) { - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 15 && - ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) - k8_enable_fixed_iorrs(); - mtrr_wrmsr(msr, msrwords[0], msrwords[1]); - *changed = TRUE; - } -} - int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) /* [SUMMARY] Get a free MTRR. The starting (base) address of the region. @@ -252,21 +196,36 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, *type = base_lo & 0xff; } -/** - * Checks and updates the fixed-range MTRRs if they differ from the saved set - * \param frs pointer to fixed-range MTRR values, saved by get_fixed_ranges() - */ static int set_fixed_ranges(mtrr_type * frs) { - unsigned long long *saved = (unsigned long long *) frs; + unsigned int *p = (unsigned int *) frs; int changed = FALSE; - int block=-1, range; + int i; + unsigned int lo, hi; - while (fixed_range_blocks[++block].ranges) - for (range=0; range < fixed_range_blocks[block].ranges; range++) - set_fixed_range(fixed_range_blocks[block].base_msr + range, - &changed, (unsigned int *) saved++); + rdmsr(MTRRfix64K_00000_MSR, lo, hi); + if (p[0] != lo || p[1] != hi) { + mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } + for (i = 0; i < 2; i++) { + rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { + mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], + p[3 + i * 2]); + changed = TRUE; + } + } + + for (i = 0; i < 8; i++) { + rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { + mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], + p[7 + i * 2]); + changed = TRUE; + } + } return changed; } @@ -469,7 +428,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i } } - if (base < 0x100) { + if (base + size < 0x100) { printk(KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", base, size); return -EINVAL; diff --git a/trunk/arch/i386/kernel/cpu/mtrr/main.c b/trunk/arch/i386/kernel/cpu/mtrr/main.c index 02a2f39e5e0a..0acfb6a5a220 100644 --- a/trunk/arch/i386/kernel/cpu/mtrr/main.c +++ b/trunk/arch/i386/kernel/cpu/mtrr/main.c @@ -729,17 +729,6 @@ void mtrr_ap_init(void) local_irq_restore(flags); } -/** - * Save current fixed-range MTRR state of the BSP - */ -void mtrr_save_state(void) -{ - if (smp_processor_id() == 0) - mtrr_save_fixed_ranges(NULL); - else - smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1); -} - static int __init mtrr_init_finialize(void) { if (!mtrr_if) diff --git a/trunk/arch/i386/kernel/cpu/nexgen.c b/trunk/arch/i386/kernel/cpu/nexgen.c index 961fbe1a748f..8bf23cc80c63 100644 --- a/trunk/arch/i386/kernel/cpu/nexgen.c +++ b/trunk/arch/i386/kernel/cpu/nexgen.c @@ -58,3 +58,13 @@ int __init nexgen_init_cpu(void) cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev; return 0; } + +//early_arch_initcall(nexgen_init_cpu); + +static int __init nexgen_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_NEXGEN] = NULL; + return 0; +} + +late_initcall(nexgen_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/perfctr-watchdog.c b/trunk/arch/i386/kernel/cpu/perfctr-watchdog.c deleted file mode 100644 index 2b04c8f1db62..000000000000 --- a/trunk/arch/i386/kernel/cpu/perfctr-watchdog.c +++ /dev/null @@ -1,658 +0,0 @@ -/* local apic based NMI watchdog for various CPUs. - This file also handles reservation of performance counters for coordination - with other users (like oprofile). - - Note that these events normally don't tick when the CPU idles. This means - the frequency varies with CPU load. - - Original code for K7/P6 written by Keith Owens */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct nmi_watchdog_ctlblk { - unsigned int cccr_msr; - unsigned int perfctr_msr; /* the MSR to reset in NMI handler */ - unsigned int evntsel_msr; /* the MSR to select the events to handle */ -}; - -/* Interface defining a CPU specific perfctr watchdog */ -struct wd_ops { - int (*reserve)(void); - void (*unreserve)(void); - int (*setup)(unsigned nmi_hz); - void (*rearm)(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz); - void (*stop)(void *); - unsigned perfctr; - unsigned evntsel; - u64 checkbit; -}; - -static struct wd_ops *wd_ops; - -/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's - * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now) - */ -#define NMI_MAX_COUNTER_BITS 66 - -/* perfctr_nmi_owner tracks the ownership of the perfctr registers: - * evtsel_nmi_owner tracks the ownership of the event selection - * - different performance counters/ event selection may be reserved for - * different subsystems this reservation system just tries to coordinate - * things a little - */ -static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS); -static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS); - -static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk); - -/* converts an msr to an appropriate reservation bit */ -static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) -{ - return wd_ops ? msr - wd_ops->perfctr : 0; -} - -/* converts an msr to an appropriate reservation bit */ -/* returns the bit offset of the event selection register */ -static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) -{ - return wd_ops ? msr - wd_ops->evntsel : 0; -} - -/* checks for a bit availability (hack for oprofile) */ -int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) -{ - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - return (!test_bit(counter, perfctr_nmi_owner)); -} - -/* checks the an msr for availability */ -int avail_to_resrv_perfctr_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_perfctr_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - return (!test_bit(counter, perfctr_nmi_owner)); -} - -int reserve_perfctr_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_perfctr_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - if (!test_and_set_bit(counter, perfctr_nmi_owner)) - return 1; - return 0; -} - -void release_perfctr_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_perfctr_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - clear_bit(counter, perfctr_nmi_owner); -} - -int reserve_evntsel_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_evntsel_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - if (!test_and_set_bit(counter, evntsel_nmi_owner)) - return 1; - return 0; -} - -void release_evntsel_nmi(unsigned int msr) -{ - unsigned int counter; - - counter = nmi_evntsel_msr_to_bit(msr); - BUG_ON(counter > NMI_MAX_COUNTER_BITS); - - clear_bit(counter, evntsel_nmi_owner); -} - -EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi); -EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit); -EXPORT_SYMBOL(reserve_perfctr_nmi); -EXPORT_SYMBOL(release_perfctr_nmi); -EXPORT_SYMBOL(reserve_evntsel_nmi); -EXPORT_SYMBOL(release_evntsel_nmi); - -void disable_lapic_nmi_watchdog(void) -{ - BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); - - if (atomic_read(&nmi_active) <= 0) - return; - - on_each_cpu(wd_ops->stop, NULL, 0, 1); - wd_ops->unreserve(); - - BUG_ON(atomic_read(&nmi_active) != 0); -} - -void enable_lapic_nmi_watchdog(void) -{ - BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); - - /* are we already enabled */ - if (atomic_read(&nmi_active) != 0) - return; - - /* are we lapic aware */ - if (!wd_ops) - return; - if (!wd_ops->reserve()) { - printk(KERN_ERR "NMI watchdog: cannot reserve perfctrs\n"); - return; - } - - on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1); - touch_nmi_watchdog(); -} - -/* - * Activate the NMI watchdog via the local APIC. - */ - -static unsigned int adjust_for_32bit_ctr(unsigned int hz) -{ - u64 counter_val; - unsigned int retval = hz; - - /* - * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter - * are writable, with higher bits sign extending from bit 31. - * So, we can only program the counter with 31 bit values and - * 32nd bit should be 1, for 33.. to be 1. - * Find the appropriate nmi_hz - */ - counter_val = (u64)cpu_khz * 1000; - do_div(counter_val, retval); - if (counter_val > 0x7fffffffULL) { - u64 count = (u64)cpu_khz * 1000; - do_div(count, 0x7fffffffUL); - retval = count + 1; - } - return retval; -} - -static void -write_watchdog_counter(unsigned int perfctr_msr, const char *descr, unsigned nmi_hz) -{ - u64 count = (u64)cpu_khz * 1000; - - do_div(count, nmi_hz); - if(descr) - Dprintk("setting %s to -0x%08Lx\n", descr, count); - wrmsrl(perfctr_msr, 0 - count); -} - -static void write_watchdog_counter32(unsigned int perfctr_msr, - const char *descr, unsigned nmi_hz) -{ - u64 count = (u64)cpu_khz * 1000; - - do_div(count, nmi_hz); - if(descr) - Dprintk("setting %s to -0x%08Lx\n", descr, count); - wrmsr(perfctr_msr, (u32)(-count), 0); -} - -/* AMD K7/K8/Family10h/Family11h support. AMD keeps this interface - nicely stable so there is not much variety */ - -#define K7_EVNTSEL_ENABLE (1 << 22) -#define K7_EVNTSEL_INT (1 << 20) -#define K7_EVNTSEL_OS (1 << 17) -#define K7_EVNTSEL_USR (1 << 16) -#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 -#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING - -static int setup_k7_watchdog(unsigned nmi_hz) -{ - unsigned int perfctr_msr, evntsel_msr; - unsigned int evntsel; - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - - perfctr_msr = MSR_K7_PERFCTR0; - evntsel_msr = MSR_K7_EVNTSEL0; - - wrmsrl(perfctr_msr, 0UL); - - evntsel = K7_EVNTSEL_INT - | K7_EVNTSEL_OS - | K7_EVNTSEL_USR - | K7_NMI_EVENT; - - /* setup the timer */ - wrmsr(evntsel_msr, evntsel, 0); - write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz); - apic_write(APIC_LVTPC, APIC_DM_NMI); - evntsel |= K7_EVNTSEL_ENABLE; - wrmsr(evntsel_msr, evntsel, 0); - - wd->perfctr_msr = perfctr_msr; - wd->evntsel_msr = evntsel_msr; - wd->cccr_msr = 0; //unused - return 1; -} - -static void single_msr_stop_watchdog(void *arg) -{ - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - - wrmsr(wd->evntsel_msr, 0, 0); -} - -static int single_msr_reserve(void) -{ - if (!reserve_perfctr_nmi(wd_ops->perfctr)) - return 0; - - if (!reserve_evntsel_nmi(wd_ops->evntsel)) { - release_perfctr_nmi(wd_ops->perfctr); - return 0; - } - return 1; -} - -static void single_msr_unreserve(void) -{ - release_evntsel_nmi(wd_ops->perfctr); - release_perfctr_nmi(wd_ops->evntsel); -} - -static void single_msr_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz) -{ - /* start the cycle over again */ - write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz); -} - -static struct wd_ops k7_wd_ops = { - .reserve = single_msr_reserve, - .unreserve = single_msr_unreserve, - .setup = setup_k7_watchdog, - .rearm = single_msr_rearm, - .stop = single_msr_stop_watchdog, - .perfctr = MSR_K7_PERFCTR0, - .evntsel = MSR_K7_EVNTSEL0, - .checkbit = 1ULL<<63, -}; - -/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */ - -#define P6_EVNTSEL0_ENABLE (1 << 22) -#define P6_EVNTSEL_INT (1 << 20) -#define P6_EVNTSEL_OS (1 << 17) -#define P6_EVNTSEL_USR (1 << 16) -#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 -#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED - -static int setup_p6_watchdog(unsigned nmi_hz) -{ - unsigned int perfctr_msr, evntsel_msr; - unsigned int evntsel; - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - - perfctr_msr = MSR_P6_PERFCTR0; - evntsel_msr = MSR_P6_EVNTSEL0; - - wrmsrl(perfctr_msr, 0UL); - - evntsel = P6_EVNTSEL_INT - | P6_EVNTSEL_OS - | P6_EVNTSEL_USR - | P6_NMI_EVENT; - - /* setup the timer */ - wrmsr(evntsel_msr, evntsel, 0); - nmi_hz = adjust_for_32bit_ctr(nmi_hz); - write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz); - apic_write(APIC_LVTPC, APIC_DM_NMI); - evntsel |= P6_EVNTSEL0_ENABLE; - wrmsr(evntsel_msr, evntsel, 0); - - wd->perfctr_msr = perfctr_msr; - wd->evntsel_msr = evntsel_msr; - wd->cccr_msr = 0; //unused - return 1; -} - -static void p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz) -{ - /* P6 based Pentium M need to re-unmask - * the apic vector but it doesn't hurt - * other P6 variant. - * ArchPerfom/Core Duo also needs this */ - apic_write(APIC_LVTPC, APIC_DM_NMI); - /* P6/ARCH_PERFMON has 32 bit counter write */ - write_watchdog_counter32(wd->perfctr_msr, NULL,nmi_hz); -} - -static struct wd_ops p6_wd_ops = { - .reserve = single_msr_reserve, - .unreserve = single_msr_unreserve, - .setup = setup_p6_watchdog, - .rearm = p6_rearm, - .stop = single_msr_stop_watchdog, - .perfctr = MSR_P6_PERFCTR0, - .evntsel = MSR_P6_EVNTSEL0, - .checkbit = 1ULL<<39, -}; - -/* Intel P4 performance counters. By far the most complicated of all. */ - -#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) -#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) -#define P4_ESCR_OS (1<<3) -#define P4_ESCR_USR (1<<2) -#define P4_CCCR_OVF_PMI0 (1<<26) -#define P4_CCCR_OVF_PMI1 (1<<27) -#define P4_CCCR_THRESHOLD(N) ((N)<<20) -#define P4_CCCR_COMPLEMENT (1<<19) -#define P4_CCCR_COMPARE (1<<18) -#define P4_CCCR_REQUIRED (3<<16) -#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) -#define P4_CCCR_ENABLE (1<<12) -#define P4_CCCR_OVF (1<<31) - -/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter - CRU_ESCR0 (with any non-null event selector) through a complemented - max threshold. [IA32-Vol3, Section 14.9.9] */ - -static int setup_p4_watchdog(unsigned nmi_hz) -{ - unsigned int perfctr_msr, evntsel_msr, cccr_msr; - unsigned int evntsel, cccr_val; - unsigned int misc_enable, dummy; - unsigned int ht_num; - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - - rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy); - if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) - return 0; - -#ifdef CONFIG_SMP - /* detect which hyperthread we are on */ - if (smp_num_siblings == 2) { - unsigned int ebx, apicid; - - ebx = cpuid_ebx(1); - apicid = (ebx >> 24) & 0xff; - ht_num = apicid & 1; - } else -#endif - ht_num = 0; - - /* performance counters are shared resources - * assign each hyperthread its own set - * (re-use the ESCR0 register, seems safe - * and keeps the cccr_val the same) - */ - if (!ht_num) { - /* logical cpu 0 */ - perfctr_msr = MSR_P4_IQ_PERFCTR0; - evntsel_msr = MSR_P4_CRU_ESCR0; - cccr_msr = MSR_P4_IQ_CCCR0; - cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4); - } else { - /* logical cpu 1 */ - perfctr_msr = MSR_P4_IQ_PERFCTR1; - evntsel_msr = MSR_P4_CRU_ESCR0; - cccr_msr = MSR_P4_IQ_CCCR1; - cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4); - } - - evntsel = P4_ESCR_EVENT_SELECT(0x3F) - | P4_ESCR_OS - | P4_ESCR_USR; - - cccr_val |= P4_CCCR_THRESHOLD(15) - | P4_CCCR_COMPLEMENT - | P4_CCCR_COMPARE - | P4_CCCR_REQUIRED; - - wrmsr(evntsel_msr, evntsel, 0); - wrmsr(cccr_msr, cccr_val, 0); - write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz); - apic_write(APIC_LVTPC, APIC_DM_NMI); - cccr_val |= P4_CCCR_ENABLE; - wrmsr(cccr_msr, cccr_val, 0); - wd->perfctr_msr = perfctr_msr; - wd->evntsel_msr = evntsel_msr; - wd->cccr_msr = cccr_msr; - return 1; -} - -static void stop_p4_watchdog(void *arg) -{ - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - wrmsr(wd->cccr_msr, 0, 0); - wrmsr(wd->evntsel_msr, 0, 0); -} - -static int p4_reserve(void) -{ - if (!reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR0)) - return 0; -#ifdef CONFIG_SMP - if (smp_num_siblings > 1 && !reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR1)) - goto fail1; -#endif - if (!reserve_evntsel_nmi(MSR_P4_CRU_ESCR0)) - goto fail2; - /* RED-PEN why is ESCR1 not reserved here? */ - return 1; - fail2: -#ifdef CONFIG_SMP - if (smp_num_siblings > 1) - release_perfctr_nmi(MSR_P4_IQ_PERFCTR1); - fail1: -#endif - release_perfctr_nmi(MSR_P4_IQ_PERFCTR0); - return 0; -} - -static void p4_unreserve(void) -{ -#ifdef CONFIG_SMP - if (smp_num_siblings > 1) - release_evntsel_nmi(MSR_P4_IQ_PERFCTR1); -#endif - release_evntsel_nmi(MSR_P4_IQ_PERFCTR0); - release_perfctr_nmi(MSR_P4_CRU_ESCR0); -} - -static void p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz) -{ - unsigned dummy; - /* - * P4 quirks: - * - An overflown perfctr will assert its interrupt - * until the OVF flag in its CCCR is cleared. - * - LVTPC is masked on interrupt and must be - * unmasked by the LVTPC handler. - */ - rdmsrl(wd->cccr_msr, dummy); - dummy &= ~P4_CCCR_OVF; - wrmsrl(wd->cccr_msr, dummy); - apic_write(APIC_LVTPC, APIC_DM_NMI); - /* start the cycle over again */ - write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz); -} - -static struct wd_ops p4_wd_ops = { - .reserve = p4_reserve, - .unreserve = p4_unreserve, - .setup = setup_p4_watchdog, - .rearm = p4_rearm, - .stop = stop_p4_watchdog, - /* RED-PEN this is wrong for the other sibling */ - .perfctr = MSR_P4_BPU_PERFCTR0, - .evntsel = MSR_P4_BSU_ESCR0, - .checkbit = 1ULL<<39, -}; - -/* Watchdog using the Intel architected PerfMon. Used for Core2 and hopefully - all future Intel CPUs. */ - -#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL -#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK - -static int setup_intel_arch_watchdog(unsigned nmi_hz) -{ - unsigned int ebx; - union cpuid10_eax eax; - unsigned int unused; - unsigned int perfctr_msr, evntsel_msr; - unsigned int evntsel; - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - - /* - * Check whether the Architectural PerfMon supports - * Unhalted Core Cycles Event or not. - * NOTE: Corresponding bit = 0 in ebx indicates event present. - */ - cpuid(10, &(eax.full), &ebx, &unused, &unused); - if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || - (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) - return 0; - - perfctr_msr = MSR_ARCH_PERFMON_PERFCTR1; - evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL1; - - wrmsrl(perfctr_msr, 0UL); - - evntsel = ARCH_PERFMON_EVENTSEL_INT - | ARCH_PERFMON_EVENTSEL_OS - | ARCH_PERFMON_EVENTSEL_USR - | ARCH_PERFMON_NMI_EVENT_SEL - | ARCH_PERFMON_NMI_EVENT_UMASK; - - /* setup the timer */ - wrmsr(evntsel_msr, evntsel, 0); - nmi_hz = adjust_for_32bit_ctr(nmi_hz); - write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz); - apic_write(APIC_LVTPC, APIC_DM_NMI); - evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; - wrmsr(evntsel_msr, evntsel, 0); - - wd->perfctr_msr = perfctr_msr; - wd->evntsel_msr = evntsel_msr; - wd->cccr_msr = 0; //unused - wd_ops->checkbit = 1ULL << (eax.split.bit_width - 1); - return 1; -} - -static struct wd_ops intel_arch_wd_ops = { - .reserve = single_msr_reserve, - .unreserve = single_msr_unreserve, - .setup = setup_intel_arch_watchdog, - .rearm = p6_rearm, - .stop = single_msr_stop_watchdog, - .perfctr = MSR_ARCH_PERFMON_PERFCTR0, - .evntsel = MSR_ARCH_PERFMON_EVENTSEL0, -}; - -static void probe_nmi_watchdog(void) -{ - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && - boot_cpu_data.x86 != 16) - return; - wd_ops = &k7_wd_ops; - break; - case X86_VENDOR_INTEL: - if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { - wd_ops = &intel_arch_wd_ops; - break; - } - switch (boot_cpu_data.x86) { - case 6: - if (boot_cpu_data.x86_model > 0xd) - return; - - wd_ops = &p6_wd_ops; - break; - case 15: - if (boot_cpu_data.x86_model > 0x4) - return; - - wd_ops = &p4_wd_ops; - break; - default: - return; - } - break; - } -} - -/* Interface to nmi.c */ - -int lapic_watchdog_init(unsigned nmi_hz) -{ - if (!wd_ops) { - probe_nmi_watchdog(); - if (!wd_ops) - return -1; - } - - if (!(wd_ops->setup(nmi_hz))) { - printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n", - raw_smp_processor_id()); - return -1; - } - - return 0; -} - -void lapic_watchdog_stop(void) -{ - if (wd_ops) - wd_ops->stop(NULL); -} - -unsigned lapic_adjust_nmi_hz(unsigned hz) -{ - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - if (wd->perfctr_msr == MSR_P6_PERFCTR0 || - wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR1) - hz = adjust_for_32bit_ctr(hz); - return hz; -} - -int lapic_wd_event(unsigned nmi_hz) -{ - struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - u64 ctr; - rdmsrl(wd->perfctr_msr, ctr); - if (ctr & wd_ops->checkbit) { /* perfctr still running? */ - return 0; - } - wd_ops->rearm(wd, nmi_hz); - return 1; -} - -int lapic_watchdog_ok(void) -{ - return wd_ops != NULL; -} diff --git a/trunk/arch/i386/kernel/cpu/proc.c b/trunk/arch/i386/kernel/cpu/proc.c index 89d91e6cc972..47e3ebbfb28d 100644 --- a/trunk/arch/i386/kernel/cpu/proc.c +++ b/trunk/arch/i386/kernel/cpu/proc.c @@ -72,7 +72,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) "stc", "100mhzsteps", "hwpstate", - "", /* constant_tsc - moved to flags */ + NULL, + NULL, /* constant_tsc - moved to flags */ /* nothing */ }; struct cpuinfo_x86 *c = v; diff --git a/trunk/arch/i386/kernel/cpu/rise.c b/trunk/arch/i386/kernel/cpu/rise.c index 50076f22e90f..9317f7414989 100644 --- a/trunk/arch/i386/kernel/cpu/rise.c +++ b/trunk/arch/i386/kernel/cpu/rise.c @@ -50,3 +50,12 @@ int __init rise_init_cpu(void) return 0; } +//early_arch_initcall(rise_init_cpu); + +static int __init rise_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_RISE] = NULL; + return 0; +} + +late_initcall(rise_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/transmeta.c b/trunk/arch/i386/kernel/cpu/transmeta.c index 6471a5a13202..5678d46863c6 100644 --- a/trunk/arch/i386/kernel/cpu/transmeta.c +++ b/trunk/arch/i386/kernel/cpu/transmeta.c @@ -112,3 +112,13 @@ int __init transmeta_init_cpu(void) cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev; return 0; } + +//early_arch_initcall(transmeta_init_cpu); + +static int __init transmeta_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_TRANSMETA] = NULL; + return 0; +} + +late_initcall(transmeta_exit_cpu); diff --git a/trunk/arch/i386/kernel/cpu/umc.c b/trunk/arch/i386/kernel/cpu/umc.c index a7a4e75bdcd7..1bf3f87e9c5b 100644 --- a/trunk/arch/i386/kernel/cpu/umc.c +++ b/trunk/arch/i386/kernel/cpu/umc.c @@ -24,3 +24,13 @@ int __init umc_init_cpu(void) cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev; return 0; } + +//early_arch_initcall(umc_init_cpu); + +static int __init umc_exit_cpu(void) +{ + cpu_devs[X86_VENDOR_UMC] = NULL; + return 0; +} + +late_initcall(umc_exit_cpu); diff --git a/trunk/arch/i386/kernel/doublefault.c b/trunk/arch/i386/kernel/doublefault.c index 265c5597efb0..b4d14c2eb345 100644 --- a/trunk/arch/i386/kernel/doublefault.c +++ b/trunk/arch/i386/kernel/doublefault.c @@ -33,7 +33,7 @@ static void doublefault_fn(void) printk("double fault, tss at %08lx\n", tss); if (ptr_ok(tss)) { - struct i386_hw_tss *t = (struct i386_hw_tss *)tss; + struct tss_struct *t = (struct tss_struct *)tss; printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp); @@ -49,21 +49,18 @@ static void doublefault_fn(void) } struct tss_struct doublefault_tss __cacheline_aligned = { - .x86_tss = { - .esp0 = STACK_START, - .ss0 = __KERNEL_DS, - .ldt = 0, - .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, + .esp0 = STACK_START, + .ss0 = __KERNEL_DS, + .ldt = 0, + .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, - .eip = (unsigned long) doublefault_fn, - /* 0x2 bit is always set */ - .eflags = X86_EFLAGS_SF | 0x2, - .esp = STACK_START, - .es = __USER_DS, - .cs = __KERNEL_CS, - .ss = __KERNEL_DS, - .ds = __USER_DS, + .eip = (unsigned long) doublefault_fn, + .eflags = X86_EFLAGS_SF | 0x2, /* 0x2 bit is always set */ + .esp = STACK_START, + .es = __USER_DS, + .cs = __KERNEL_CS, + .ss = __KERNEL_DS, + .ds = __USER_DS, - .__cr3 = __pa(swapper_pg_dir) - } + .__cr3 = __pa(swapper_pg_dir) }; diff --git a/trunk/arch/i386/kernel/e820.c b/trunk/arch/i386/kernel/e820.c index 9645bb51f76a..70f39560846a 100644 --- a/trunk/arch/i386/kernel/e820.c +++ b/trunk/arch/i386/kernel/e820.c @@ -161,27 +161,26 @@ static struct resource standard_io_resources[] = { { static int __init romsignature(const unsigned char *rom) { - const unsigned short * const ptr = (const unsigned short *)rom; unsigned short sig; - return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; + return probe_kernel_address((const unsigned short *)rom, sig) == 0 && + sig == ROMSIGNATURE; } -static int __init romchecksum(const unsigned char *rom, unsigned long length) +static int __init romchecksum(unsigned char *rom, unsigned long length) { - unsigned char sum, c; + unsigned char sum; - for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) - sum += c; - return !length && !sum; + for (sum = 0; length; length--) + sum += *rom++; + return sum == 0; } static void __init probe_roms(void) { - const unsigned char *rom; unsigned long start, length, upper; - unsigned char c; - int i; + unsigned char *rom; + int i; /* video rom */ upper = adapter_rom_resources[0].start; @@ -192,11 +191,8 @@ static void __init probe_roms(void) video_rom_resource.start = start; - if (probe_kernel_address(rom + 2, c) != 0) - continue; - /* 0 < length <= 0x7f * 512, historically */ - length = c * 512; + length = rom[2] * 512; /* if checksum okay, trust length byte */ if (length && romchecksum(rom, length)) @@ -230,11 +226,8 @@ static void __init probe_roms(void) if (!romsignature(rom)) continue; - if (probe_kernel_address(rom + 2, c) != 0) - continue; - /* 0 < length <= 0x7f * 512, historically */ - length = c * 512; + length = rom[2] * 512; /* but accept any length that fits if checksum okay */ if (!length || start + length > upper || !romchecksum(rom, length)) @@ -393,8 +386,10 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) ____________________33__ ______________________4_ */ + printk("sanitize start\n"); /* if there's only one memory region, don't bother */ if (*pnr_map < 2) { + printk("sanitize bail 0\n"); return -1; } @@ -403,6 +398,7 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) /* bail out if we find any unreasonable addresses in bios map */ for (i=0; isize; unsigned long long end = start + size; unsigned long type = biosmap->type; + printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type); /* Overflow in 64 bits? Ignore the memory map. */ if (start > end) @@ -538,11 +536,17 @@ int __init copy_e820_map(struct e820entry * biosmap, int nr_map) * Not right. Fix it up. */ if (type == E820_RAM) { + printk("copy_e820_map() type is E820_RAM\n"); if (start < 0x100000ULL && end > 0xA0000ULL) { - if (start < 0xA0000ULL) + printk("copy_e820_map() lies in range...\n"); + if (start < 0xA0000ULL) { + printk("copy_e820_map() start < 0xA0000ULL\n"); add_memory_region(start, 0xA0000ULL-start, type); - if (end <= 0x100000ULL) + } + if (end <= 0x100000ULL) { + printk("copy_e820_map() end <= 0x100000ULL\n"); continue; + } start = 0x100000ULL; size = end - start; } @@ -814,26 +818,6 @@ void __init limit_regions(unsigned long long size) print_memory_map("limit_regions endfunc"); } -/* - * This function checks if any part of the range is mapped - * with type. - */ -int -e820_any_mapped(u64 start, u64 end, unsigned type) -{ - int i; - for (i = 0; i < e820.nr_map; i++) { - const 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; -} -EXPORT_SYMBOL_GPL(e820_any_mapped); - /* * This function checks if the entire range is mapped with type. * diff --git a/trunk/arch/i386/kernel/efi.c b/trunk/arch/i386/kernel/efi.c index dd9e7faafa7c..8f9c624ace6f 100644 --- a/trunk/arch/i386/kernel/efi.c +++ b/trunk/arch/i386/kernel/efi.c @@ -69,11 +69,13 @@ static void efi_call_phys_prelog(void) __acquires(efi_rt_lock) { unsigned long cr4; unsigned long temp; - struct Xgt_desc_struct gdt_descr; + struct Xgt_desc_struct *cpu_gdt_descr; spin_lock(&efi_rt_lock); local_irq_save(efi_rt_eflags); + cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0); + /* * If I don't have PSE, I should just duplicate two entries in page * directory. If I have PSE, I just need to duplicate one entry in @@ -103,19 +105,17 @@ static void efi_call_phys_prelog(void) __acquires(efi_rt_lock) */ local_flush_tlb(); - gdt_descr.address = __pa(get_cpu_gdt_table(0)); - gdt_descr.size = GDT_SIZE - 1; - load_gdt(&gdt_descr); + cpu_gdt_descr->address = __pa(cpu_gdt_descr->address); + load_gdt(cpu_gdt_descr); } static void efi_call_phys_epilog(void) __releases(efi_rt_lock) { unsigned long cr4; - struct Xgt_desc_struct gdt_descr; + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0); - gdt_descr.address = (unsigned long)get_cpu_gdt_table(0); - gdt_descr.size = GDT_SIZE - 1; - load_gdt(&gdt_descr); + cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address); + load_gdt(cpu_gdt_descr); cr4 = read_cr4(); diff --git a/trunk/arch/i386/kernel/entry.S b/trunk/arch/i386/kernel/entry.S index b1f16ee65e4d..18bddcb8e9e8 100644 --- a/trunk/arch/i386/kernel/entry.S +++ b/trunk/arch/i386/kernel/entry.S @@ -15,7 +15,7 @@ * I changed all the .align's to 4 (16 byte alignment), as that's faster * on a 486. * - * Stack layout in 'syscall_exit': + * Stack layout in 'ret_from_system_call': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be * updated in fork.c:copy_process, signal.c:do_signal, @@ -132,7 +132,7 @@ VM_MASK = 0x00020000 movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ - movl $(__KERNEL_PERCPU), %edx; \ + movl $(__KERNEL_PDA), %edx; \ movl %edx, %fs #define RESTORE_INT_REGS \ @@ -305,12 +305,16 @@ sysenter_past_esp: pushl $(__USER_CS) CFI_ADJUST_CFA_OFFSET 4 /*CFI_REL_OFFSET cs, 0*/ +#ifndef CONFIG_COMPAT_VDSO /* * Push current_thread_info()->sysenter_return to the stack. * A tiny bit of offset fixup is necessary - 4*4 means the 4 words * pushed above; +8 corresponds to copy_thread's esp0 setting. */ pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) +#else + pushl $SYSENTER_RETURN +#endif CFI_ADJUST_CFA_OFFSET 4 CFI_REL_OFFSET eip, 0 @@ -338,7 +342,7 @@ sysenter_past_esp: jae syscall_badsys call *sys_call_table(,%eax,4) movl %eax,PT_EAX(%esp) - DISABLE_INTERRUPTS(CLBR_ANY) + DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX) TRACE_IRQS_OFF movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx @@ -556,7 +560,9 @@ END(syscall_badsys) #define FIXUP_ESPFIX_STACK \ /* since we are on a wrong stack, we cant make it a C code :( */ \ - PER_CPU(gdt_page, %ebx); \ + movl %fs:PDA_cpu, %ebx; \ + PER_CPU(cpu_gdt_descr, %ebx); \ + movl GDS_address(%ebx), %ebx; \ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ addl %esp, %eax; \ pushl $__KERNEL_DS; \ @@ -629,7 +635,7 @@ ENTRY(name) \ SAVE_ALL; \ TRACE_IRQS_OFF \ movl %esp,%eax; \ - call smp_##name; \ + call smp_/**/name; \ jmp ret_from_intr; \ CFI_ENDPROC; \ ENDPROC(name) @@ -637,6 +643,11 @@ ENDPROC(name) /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" +/* This alternate entry is needed because we hijack the apic LVTT */ +#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC) +BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR) +#endif + KPROBE_ENTRY(page_fault) RING0_EC_FRAME pushl $do_page_fault @@ -675,7 +686,7 @@ error_code: pushl %fs CFI_ADJUST_CFA_OFFSET 4 /*CFI_REL_OFFSET fs, 0*/ - movl $(__KERNEL_PERCPU), %ecx + movl $(__KERNEL_PDA), %ecx movl %ecx, %fs UNWIND_ESPFIX_STACK popl %ecx diff --git a/trunk/arch/i386/kernel/head.S b/trunk/arch/i386/kernel/head.S index 9b10af65faaa..3fa7f9389afe 100644 --- a/trunk/arch/i386/kernel/head.S +++ b/trunk/arch/i386/kernel/head.S @@ -34,32 +34,17 @@ /* * This is how much memory *in addition to the memory covered up to - * and including _end* we need mapped initially. - * We need: - * - one bit for each possible page, but only in low memory, which means - * 2^32/4096/8 = 128K worst case (4G/4G split.) - * - enough space to map all low memory, which means - * (2^32/4096) / 1024 pages (worst case, non PAE) - * (2^32/4096) / 512 + 4 pages (worst case for PAE) - * - a few pages for allocator use before the kernel pagetable has - * been set up + * and including _end* we need mapped initially. We need one bit for + * each possible page, but only in low memory, which means + * 2^32/4096/8 = 128K worst case (4G/4G split.) * * Modulo rounding, each megabyte assigned here requires a kilobyte of * memory, which is currently unreclaimed. * * This should be a multiple of a page. */ -LOW_PAGES = 1<<(32-PAGE_SHIFT_asm) +#define INIT_MAP_BEYOND_END (128*1024) -#if PTRS_PER_PMD > 1 -PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD -#else -PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD) -#endif -BOOTBITMAP_SIZE = LOW_PAGES / 8 -ALLOCATOR_SLOP = 4 - -INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm /* * 32-bit kernel entrypoint; only used by the boot CPU. On entry, @@ -162,7 +147,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20); /* * Non-boot CPU entry point; entered from trampoline.S * We can't lgdt here, because lgdt itself uses a data segment, but - * we know the trampoline has already loaded the boot_gdt for us. + * we know the trampoline has already loaded the boot_gdt_table GDT + * for us. * * If cpu hotplug is not supported then this code can go in init section * which will be freed later @@ -332,12 +318,12 @@ is386: movl $2,%ecx # set MP movl %eax,%cr0 call check_x87 + call setup_pda lgdt early_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. - movl %eax,%fs # gets reset once there's real percpu movl $(__USER_DS),%eax # DS/ES contains default USER segment movl %eax,%ds @@ -347,17 +333,16 @@ is386: movl $2,%ecx # set MP movl %eax,%gs lldt %ax + movl $(__KERNEL_PDA),%eax + mov %eax,%fs + cld # gcc2 wants the direction flag cleared at all times pushl $0 # fake return address for unwinder #ifdef CONFIG_SMP movb ready, %cl movb $1, ready cmpb $0,%cl # the first CPU calls start_kernel - je 1f - movl $(__KERNEL_PERCPU), %eax - movl %eax,%fs # set this cpu's percpu - jmp initialize_secondary # all other CPUs call initialize_secondary -1: + jne initialize_secondary # all other CPUs call initialize_secondary #endif /* CONFIG_SMP */ jmp start_kernel @@ -380,6 +365,23 @@ check_x87: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ ret +/* + * Point the GDT at this CPU's PDA. On boot this will be + * cpu_gdt_table and boot_pda; for secondary CPUs, these will be + * that CPU's GDT and PDA. + */ +ENTRY(setup_pda) + /* get the PDA pointer */ + movl start_pda, %eax + + /* slot the PDA address into the GDT */ + mov early_gdt_descr+2, %ecx + mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ + shr $16, %eax + mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ + mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */ + ret + /* * setup_idt * @@ -552,6 +554,9 @@ ENTRY(empty_zero_page) * This starts the data section. */ .data +ENTRY(start_pda) + .long boot_pda + ENTRY(stack_start) .long init_thread_union+THREAD_SIZE .long __BOOT_DS @@ -583,7 +588,7 @@ fault_msg: .word 0 # 32 bit align gdt_desc.address boot_gdt_descr: .word __BOOT_DS+7 - .long boot_gdt - __PAGE_OFFSET + .long boot_gdt_table - __PAGE_OFFSET .word 0 # 32-bit align idt_desc.address idt_descr: @@ -594,14 +599,67 @@ idt_descr: .word 0 # 32 bit align gdt_desc.address ENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 - .long per_cpu__gdt_page /* Overwritten for secondary CPUs */ + .long cpu_gdt_table /* - * The boot_gdt must mirror the equivalent in setup.S and is + * The boot_gdt_table must mirror the equivalent in setup.S and is * used only for booting. */ .align L1_CACHE_BYTES -ENTRY(boot_gdt) +ENTRY(boot_gdt_table) .fill GDT_ENTRY_BOOT_CS,8,0 .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ + +/* + * The Global Descriptor Table contains 28 quadwords, per-CPU. + */ + .align L1_CACHE_BYTES +ENTRY(cpu_gdt_table) + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* 0x0b reserved */ + .quad 0x0000000000000000 /* 0x13 reserved */ + .quad 0x0000000000000000 /* 0x1b reserved */ + .quad 0x0000000000000000 /* 0x20 unused */ + .quad 0x0000000000000000 /* 0x28 unused */ + .quad 0x0000000000000000 /* 0x33 TLS entry 1 */ + .quad 0x0000000000000000 /* 0x3b TLS entry 2 */ + .quad 0x0000000000000000 /* 0x43 TLS entry 3 */ + .quad 0x0000000000000000 /* 0x4b reserved */ + .quad 0x0000000000000000 /* 0x53 reserved */ + .quad 0x0000000000000000 /* 0x5b reserved */ + + .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ + .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ + .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */ + .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */ + + .quad 0x0000000000000000 /* 0x80 TSS descriptor */ + .quad 0x0000000000000000 /* 0x88 LDT descriptor */ + + /* + * Segments used for calling PnP BIOS have byte granularity. + * They code segments and data segments have fixed 64k limits, + * the transfer segment sizes are set at run time. + */ + .quad 0x00409a000000ffff /* 0x90 32-bit code */ + .quad 0x00009a000000ffff /* 0x98 16-bit code */ + .quad 0x000092000000ffff /* 0xa0 16-bit data */ + .quad 0x0000920000000000 /* 0xa8 16-bit data */ + .quad 0x0000920000000000 /* 0xb0 16-bit data */ + + /* + * The APM segments have byte granularity and their bases + * are set at run time. All have 64k limits. + */ + .quad 0x00409a000000ffff /* 0xb8 APM CS code */ + .quad 0x00009a000000ffff /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x004092000000ffff /* 0xc8 APM DS data */ + + .quad 0x00c0920000000000 /* 0xd0 - ESPFIX SS */ + .quad 0x00cf92000000ffff /* 0xd8 - PDA */ + .quad 0x0000000000000000 /* 0xe0 - unused */ + .quad 0x0000000000000000 /* 0xe8 - unused */ + .quad 0x0000000000000000 /* 0xf0 - unused */ + .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ + diff --git a/trunk/arch/i386/kernel/i386_ksyms.c b/trunk/arch/i386/kernel/i386_ksyms.c index e3d4b73bfdb0..4afe26e86260 100644 --- a/trunk/arch/i386/kernel/i386_ksyms.c +++ b/trunk/arch/i386/kernel/i386_ksyms.c @@ -28,3 +28,5 @@ EXPORT_SYMBOL(__read_lock_failed); #endif EXPORT_SYMBOL(csum_partial); + +EXPORT_SYMBOL(_proxy_pda); diff --git a/trunk/arch/i386/kernel/i8253.c b/trunk/arch/i386/kernel/i8253.c index f8a3c4054c70..10cef5ca8a5b 100644 --- a/trunk/arch/i386/kernel/i8253.c +++ b/trunk/arch/i386/kernel/i8253.c @@ -110,7 +110,7 @@ void __init setup_pit_timer(void) * Start pit with the boot cpu mask and make it global after the * IO_APIC has been initialized. */ - pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); + pit_clockevent.cpumask = cpumask_of_cpu(0); pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32); pit_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_clockevent); diff --git a/trunk/arch/i386/kernel/io_apic.c b/trunk/arch/i386/kernel/io_apic.c index 1b623cda3a64..b3ab8ffebd27 100644 --- a/trunk/arch/i386/kernel/io_apic.c +++ b/trunk/arch/i386/kernel/io_apic.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -662,6 +661,8 @@ static int balanced_irq(void *unused) unsigned long prev_balance_time = jiffies; long time_remaining = balanced_irq_interval; + daemonize("kirqd"); + /* push everything to CPU 0 to give us a starting point. */ for (i = 0 ; i < NR_IRQS ; i++) { irq_desc[i].pending_mask = cpumask_of_cpu(0); @@ -721,9 +722,10 @@ static int __init balanced_irq_init(void) } printk(KERN_INFO "Starting balanced_irq\n"); - if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd"))) + if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) return 0; - printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); + else + printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); failed: for_each_possible_cpu(i) { kfree(irq_cpu_data[i].irq_delta); @@ -1401,6 +1403,10 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in enable_8259A_irq(0); } +static inline void UNEXPECTED_IO_APIC(void) +{ +} + void __init print_IO_APIC(void) { int apic, i; @@ -1440,12 +1446,34 @@ void __init print_IO_APIC(void) printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); + if (reg_00.bits.ID >= get_physical_broadcast()) + UNEXPECTED_IO_APIC(); + if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) + UNEXPECTED_IO_APIC(); printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); + if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ + (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ + (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ + (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ + (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ + (reg_01.bits.entries != 0x2E) && + (reg_01.bits.entries != 0x3F) + ) + UNEXPECTED_IO_APIC(); printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); + if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ + (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ + (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ + (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ + ) + UNEXPECTED_IO_APIC(); + if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) + UNEXPECTED_IO_APIC(); /* * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02, @@ -1455,6 +1483,8 @@ void __init print_IO_APIC(void) if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); + if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) + UNEXPECTED_IO_APIC(); } /* @@ -1466,6 +1496,8 @@ void __init print_IO_APIC(void) reg_03.raw != reg_01.raw) { printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); + if (reg_03.bits.__reserved_1) + UNEXPECTED_IO_APIC(); } printk(KERN_DEBUG ".... IRQ redirection table:\n"); @@ -2579,19 +2611,19 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) if (irq < 0) return irq; + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); if (ret < 0) { destroy_irq(irq); return ret; } - set_irq_msi(irq, desc); write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) diff --git a/trunk/arch/i386/kernel/ioport.c b/trunk/arch/i386/kernel/ioport.c index d1e42e0dbe67..498e8bc197d5 100644 --- a/trunk/arch/i386/kernel/ioport.c +++ b/trunk/arch/i386/kernel/ioport.c @@ -16,7 +16,6 @@ #include #include #include -#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) @@ -114,7 +113,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) * Reset the owner so that a process switch will not set * tss->io_bitmap_base to IO_BITMAP_OFFSET. */ - tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; tss->io_bitmap_owner = NULL; put_cpu(); diff --git a/trunk/arch/i386/kernel/irq.c b/trunk/arch/i386/kernel/irq.c index d2daf672f4a2..8db8d514c9c0 100644 --- a/trunk/arch/i386/kernel/irq.c +++ b/trunk/arch/i386/kernel/irq.c @@ -24,9 +24,6 @@ DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); -DEFINE_PER_CPU(struct pt_regs *, irq_regs); -EXPORT_PER_CPU_SYMBOL(irq_regs); - /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. diff --git a/trunk/arch/i386/kernel/mpparse.c b/trunk/arch/i386/kernel/mpparse.c index 0952eccd8f28..4f5983c98669 100644 --- a/trunk/arch/i386/kernel/mpparse.c +++ b/trunk/arch/i386/kernel/mpparse.c @@ -477,7 +477,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } ++mpc_record; } - setup_apic_routing(); + clustered_apic_check(); if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; diff --git a/trunk/arch/i386/kernel/nmi.c b/trunk/arch/i386/kernel/nmi.c index 33cf2f3c444f..9f1e8c1afab7 100644 --- a/trunk/arch/i386/kernel/nmi.c +++ b/trunk/arch/i386/kernel/nmi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,14 +28,30 @@ #include #include #include +#include #include "mach_traps.h" int unknown_nmi_panic; int nmi_watchdog_enabled; -static cpumask_t backtrace_mask = CPU_MASK_NONE; +/* perfctr_nmi_owner tracks the ownership of the perfctr registers: + * evtsel_nmi_owner tracks the ownership of the event selection + * - different performance counters/ event selection may be reserved for + * different subsystems this reservation system just tries to coordinate + * things a little + */ + +/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's + * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now) + */ +#define NMI_MAX_COUNTER_BITS 66 +#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS) +static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]); +static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]); + +static cpumask_t backtrace_mask = CPU_MASK_NONE; /* nmi_active: * >0: the lapic NMI watchdog is active, but can be disabled * <0: the lapic NMI watchdog has not been set up, and cannot @@ -46,11 +63,206 @@ atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ unsigned int nmi_watchdog = NMI_DEFAULT; static unsigned int nmi_hz = HZ; -static DEFINE_PER_CPU(short, wd_enabled); +struct nmi_watchdog_ctlblk { + int enabled; + u64 check_bit; + unsigned int cccr_msr; + unsigned int perfctr_msr; /* the MSR to reset in NMI handler */ + unsigned int evntsel_msr; /* the MSR to select the events to handle */ +}; +static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk); /* local prototypes */ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); +extern void show_registers(struct pt_regs *regs); +extern int unknown_nmi_panic; + +/* converts an msr to an appropriate reservation bit */ +static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) +{ + /* returns the bit offset of the performance counter register */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return (msr - MSR_K7_PERFCTR0); + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return (msr - MSR_ARCH_PERFMON_PERFCTR0); + + switch (boot_cpu_data.x86) { + case 6: + return (msr - MSR_P6_PERFCTR0); + case 15: + return (msr - MSR_P4_BPU_PERFCTR0); + } + } + return 0; +} + +/* converts an msr to an appropriate reservation bit */ +static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) +{ + /* returns the bit offset of the event selection register */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return (msr - MSR_K7_EVNTSEL0); + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return (msr - MSR_ARCH_PERFMON_EVENTSEL0); + + switch (boot_cpu_data.x86) { + case 6: + return (msr - MSR_P6_EVNTSEL0); + case 15: + return (msr - MSR_P4_BSU_ESCR0); + } + } + return 0; +} + +/* checks for a bit availability (hack for oprofile) */ +int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) +{ + int cpu; + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + for_each_possible_cpu (cpu) { + if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 0; + } + return 1; +} + +/* checks the an msr for availability */ +int avail_to_resrv_perfctr_nmi(unsigned int msr) +{ + unsigned int counter; + int cpu; + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + for_each_possible_cpu (cpu) { + if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 0; + } + return 1; +} + +static int __reserve_perfctr_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 1; + return 0; +} + +static void __release_perfctr_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)); +} + +int reserve_perfctr_nmi(unsigned int msr) +{ + int cpu, i; + for_each_possible_cpu (cpu) { + if (!__reserve_perfctr_nmi(cpu, msr)) { + for_each_possible_cpu (i) { + if (i >= cpu) + break; + __release_perfctr_nmi(i, msr); + } + return 0; + } + } + return 1; +} + +void release_perfctr_nmi(unsigned int msr) +{ + int cpu; + for_each_possible_cpu (cpu) { + __release_perfctr_nmi(cpu, msr); + } +} + +int __reserve_evntsel_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_evntsel_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0])) + return 1; + return 0; +} + +static void __release_evntsel_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_evntsel_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]); +} + +int reserve_evntsel_nmi(unsigned int msr) +{ + int cpu, i; + for_each_possible_cpu (cpu) { + if (!__reserve_evntsel_nmi(cpu, msr)) { + for_each_possible_cpu (i) { + if (i >= cpu) + break; + __release_evntsel_nmi(i, msr); + } + return 0; + } + } + return 1; +} + +void release_evntsel_nmi(unsigned int msr) +{ + int cpu; + for_each_possible_cpu (cpu) { + __release_evntsel_nmi(cpu, msr); + } +} + +static __cpuinit inline int nmi_known_cpu(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6) + || (boot_cpu_data.x86 == 16)); + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return 1; + else + return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6)); + } + return 0; +} + static int endflag __initdata = 0; #ifdef CONFIG_SMP @@ -72,6 +284,28 @@ static __init void nmi_cpu_busy(void *data) } #endif +static unsigned int adjust_for_32bit_ctr(unsigned int hz) +{ + u64 counter_val; + unsigned int retval = hz; + + /* + * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter + * are writable, with higher bits sign extending from bit 31. + * So, we can only program the counter with 31 bit values and + * 32nd bit should be 1, for 33.. to be 1. + * Find the appropriate nmi_hz + */ + counter_val = (u64)cpu_khz * 1000; + do_div(counter_val, retval); + if (counter_val > 0x7fffffffULL) { + u64 count = (u64)cpu_khz * 1000; + do_div(count, 0x7fffffffUL); + retval = count + 1; + } + return retval; +} + static int __init check_nmi_watchdog(void) { unsigned int *prev_nmi_count; @@ -104,14 +338,14 @@ static int __init check_nmi_watchdog(void) if (!cpu_isset(cpu, cpu_callin_map)) continue; #endif - if (!per_cpu(wd_enabled, cpu)) + if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled) continue; if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n", cpu, prev_nmi_count[cpu], nmi_count(cpu)); - per_cpu(wd_enabled, cpu) = 0; + per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0; atomic_dec(&nmi_active); } } @@ -125,8 +359,16 @@ static int __init check_nmi_watchdog(void) /* now that we know it works we can reduce NMI frequency to something more reasonable; makes a difference in some configs */ - if (nmi_watchdog == NMI_LOCAL_APIC) - nmi_hz = lapic_adjust_nmi_hz(1); + if (nmi_watchdog == NMI_LOCAL_APIC) { + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + nmi_hz = 1; + + if (wd->perfctr_msr == MSR_P6_PERFCTR0 || + wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + } + } kfree(prev_nmi_count); return 0; @@ -149,8 +391,85 @@ static int __init setup_nmi_watchdog(char *str) __setup("nmi_watchdog=", setup_nmi_watchdog); +static void disable_lapic_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); + + if (atomic_read(&nmi_active) <= 0) + return; + + on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1); + + BUG_ON(atomic_read(&nmi_active) != 0); +} + +static void enable_lapic_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); + + /* are we already enabled */ + if (atomic_read(&nmi_active) != 0) + return; + + /* are we lapic aware */ + if (nmi_known_cpu() <= 0) + return; -/* Suspend/resume support */ + on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1); + touch_nmi_watchdog(); +} + +void disable_timer_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_IO_APIC); + + if (atomic_read(&nmi_active) <= 0) + return; + + disable_irq(0); + on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1); + + BUG_ON(atomic_read(&nmi_active) != 0); +} + +void enable_timer_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_IO_APIC); + + if (atomic_read(&nmi_active) == 0) { + touch_nmi_watchdog(); + on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1); + enable_irq(0); + } +} + +static void __acpi_nmi_disable(void *__unused) +{ + apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); +} + +/* + * Disable timer based NMIs on all CPUs: + */ +void acpi_nmi_disable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_disable, NULL, 0, 1); +} + +static void __acpi_nmi_enable(void *__unused) +{ + apic_write_around(APIC_LVT0, APIC_DM_NMI); +} + +/* + * Enable timer based NMIs on all CPUs: + */ +void acpi_nmi_enable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_enable, NULL, 0, 1); +} #ifdef CONFIG_PM @@ -197,7 +516,7 @@ static int __init init_lapic_nmi_sysfs(void) if (nmi_watchdog != NMI_LOCAL_APIC) return 0; - if (atomic_read(&nmi_active) < 0) + if ( atomic_read(&nmi_active) < 0 ) return 0; error = sysdev_class_register(&nmi_sysclass); @@ -210,69 +529,433 @@ late_initcall(init_lapic_nmi_sysfs); #endif /* CONFIG_PM */ -static void __acpi_nmi_enable(void *__unused) +/* + * Activate the NMI watchdog via the local APIC. + * Original code written by Keith Owens. + */ + +static void write_watchdog_counter(unsigned int perfctr_msr, const char *descr) { - apic_write_around(APIC_LVT0, APIC_DM_NMI); + u64 count = (u64)cpu_khz * 1000; + + do_div(count, nmi_hz); + if(descr) + Dprintk("setting %s to -0x%08Lx\n", descr, count); + wrmsrl(perfctr_msr, 0 - count); } -/* - * Enable timer based NMIs on all CPUs: - */ -void acpi_nmi_enable(void) +static void write_watchdog_counter32(unsigned int perfctr_msr, + const char *descr) { - if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) - on_each_cpu(__acpi_nmi_enable, NULL, 0, 1); + u64 count = (u64)cpu_khz * 1000; + + do_div(count, nmi_hz); + if(descr) + Dprintk("setting %s to -0x%08Lx\n", descr, count); + wrmsr(perfctr_msr, (u32)(-count), 0); } -static void __acpi_nmi_disable(void *__unused) +/* Note that these events don't tick when the CPU idles. This means + the frequency varies with CPU load. */ + +#define K7_EVNTSEL_ENABLE (1 << 22) +#define K7_EVNTSEL_INT (1 << 20) +#define K7_EVNTSEL_OS (1 << 17) +#define K7_EVNTSEL_USR (1 << 16) +#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 +#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING + +static int setup_k7_watchdog(void) { - apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); + unsigned int perfctr_msr, evntsel_msr; + unsigned int evntsel; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + perfctr_msr = MSR_K7_PERFCTR0; + evntsel_msr = MSR_K7_EVNTSEL0; + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + wrmsrl(perfctr_msr, 0UL); + + evntsel = K7_EVNTSEL_INT + | K7_EVNTSEL_OS + | K7_EVNTSEL_USR + | K7_NMI_EVENT; + + /* setup the timer */ + wrmsr(evntsel_msr, evntsel, 0); + write_watchdog_counter(perfctr_msr, "K7_PERFCTR0"); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= K7_EVNTSEL_ENABLE; + wrmsr(evntsel_msr, evntsel, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = 0; //unused + wd->check_bit = 1ULL<<63; + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; } -/* - * Disable timer based NMIs on all CPUs: - */ -void acpi_nmi_disable(void) +static void stop_k7_watchdog(void) { - if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) - on_each_cpu(__acpi_nmi_disable, NULL, 0, 1); + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + +#define P6_EVNTSEL0_ENABLE (1 << 22) +#define P6_EVNTSEL_INT (1 << 20) +#define P6_EVNTSEL_OS (1 << 17) +#define P6_EVNTSEL_USR (1 << 16) +#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 +#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED + +static int setup_p6_watchdog(void) +{ + unsigned int perfctr_msr, evntsel_msr; + unsigned int evntsel; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + perfctr_msr = MSR_P6_PERFCTR0; + evntsel_msr = MSR_P6_EVNTSEL0; + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + wrmsrl(perfctr_msr, 0UL); + + evntsel = P6_EVNTSEL_INT + | P6_EVNTSEL_OS + | P6_EVNTSEL_USR + | P6_NMI_EVENT; + + /* setup the timer */ + wrmsr(evntsel_msr, evntsel, 0); + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0"); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= P6_EVNTSEL0_ENABLE; + wrmsr(evntsel_msr, evntsel, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = 0; //unused + wd->check_bit = 1ULL<<39; + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_p6_watchdog(void) +{ + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + +/* Note that these events don't tick when the CPU idles. This means + the frequency varies with CPU load. */ + +#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) +#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) +#define P4_ESCR_OS (1<<3) +#define P4_ESCR_USR (1<<2) +#define P4_CCCR_OVF_PMI0 (1<<26) +#define P4_CCCR_OVF_PMI1 (1<<27) +#define P4_CCCR_THRESHOLD(N) ((N)<<20) +#define P4_CCCR_COMPLEMENT (1<<19) +#define P4_CCCR_COMPARE (1<<18) +#define P4_CCCR_REQUIRED (3<<16) +#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) +#define P4_CCCR_ENABLE (1<<12) +#define P4_CCCR_OVF (1<<31) +/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter + CRU_ESCR0 (with any non-null event selector) through a complemented + max threshold. [IA32-Vol3, Section 14.9.9] */ + +static int setup_p4_watchdog(void) +{ + unsigned int perfctr_msr, evntsel_msr, cccr_msr; + unsigned int evntsel, cccr_val; + unsigned int misc_enable, dummy; + unsigned int ht_num; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy); + if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) + return 0; + +#ifdef CONFIG_SMP + /* detect which hyperthread we are on */ + if (smp_num_siblings == 2) { + unsigned int ebx, apicid; + + ebx = cpuid_ebx(1); + apicid = (ebx >> 24) & 0xff; + ht_num = apicid & 1; + } else +#endif + ht_num = 0; + + /* performance counters are shared resources + * assign each hyperthread its own set + * (re-use the ESCR0 register, seems safe + * and keeps the cccr_val the same) + */ + if (!ht_num) { + /* logical cpu 0 */ + perfctr_msr = MSR_P4_IQ_PERFCTR0; + evntsel_msr = MSR_P4_CRU_ESCR0; + cccr_msr = MSR_P4_IQ_CCCR0; + cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4); + } else { + /* logical cpu 1 */ + perfctr_msr = MSR_P4_IQ_PERFCTR1; + evntsel_msr = MSR_P4_CRU_ESCR0; + cccr_msr = MSR_P4_IQ_CCCR1; + cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4); + } + + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + evntsel = P4_ESCR_EVENT_SELECT(0x3F) + | P4_ESCR_OS + | P4_ESCR_USR; + + cccr_val |= P4_CCCR_THRESHOLD(15) + | P4_CCCR_COMPLEMENT + | P4_CCCR_COMPARE + | P4_CCCR_REQUIRED; + + wrmsr(evntsel_msr, evntsel, 0); + wrmsr(cccr_msr, cccr_val, 0); + write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0"); + apic_write(APIC_LVTPC, APIC_DM_NMI); + cccr_val |= P4_CCCR_ENABLE; + wrmsr(cccr_msr, cccr_val, 0); + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = cccr_msr; + wd->check_bit = 1ULL<<39; + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_p4_watchdog(void) +{ + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + wrmsr(wd->cccr_msr, 0, 0); + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + +#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL +#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK + +static int setup_intel_arch_watchdog(void) +{ + unsigned int ebx; + union cpuid10_eax eax; + unsigned int unused; + unsigned int perfctr_msr, evntsel_msr; + unsigned int evntsel; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* + * Check whether the Architectural PerfMon supports + * Unhalted Core Cycles Event or not. + * NOTE: Corresponding bit = 0 in ebx indicates event present. + */ + cpuid(10, &(eax.full), &ebx, &unused, &unused); + if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || + (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) + goto fail; + + perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0; + evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0; + + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + wrmsrl(perfctr_msr, 0UL); + + evntsel = ARCH_PERFMON_EVENTSEL_INT + | ARCH_PERFMON_EVENTSEL_OS + | ARCH_PERFMON_EVENTSEL_USR + | ARCH_PERFMON_NMI_EVENT_SEL + | ARCH_PERFMON_NMI_EVENT_UMASK; + + /* setup the timer */ + wrmsr(evntsel_msr, evntsel, 0); + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0"); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsr(evntsel_msr, evntsel, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = 0; //unused + wd->check_bit = 1ULL << (eax.split.bit_width - 1); + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_intel_arch_watchdog(void) +{ + unsigned int ebx; + union cpuid10_eax eax; + unsigned int unused; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* + * Check whether the Architectural PerfMon supports + * Unhalted Core Cycles Event or not. + * NOTE: Corresponding bit = 0 in ebx indicates event present. + */ + cpuid(10, &(eax.full), &ebx, &unused, &unused); + if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || + (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) + return; + + wrmsr(wd->evntsel_msr, 0, 0); + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); } void setup_apic_nmi_watchdog (void *unused) { - if (__get_cpu_var(wd_enabled)) - return; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* only support LOCAL and IO APICs for now */ + if ((nmi_watchdog != NMI_LOCAL_APIC) && + (nmi_watchdog != NMI_IO_APIC)) + return; + + if (wd->enabled == 1) + return; /* cheap hack to support suspend/resume */ /* if cpu0 is not active neither should the other cpus */ if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0)) return; - switch (nmi_watchdog) { - case NMI_LOCAL_APIC: - __get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */ - if (lapic_watchdog_init(nmi_hz) < 0) { - __get_cpu_var(wd_enabled) = 0; + if (nmi_watchdog == NMI_LOCAL_APIC) { + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && + boot_cpu_data.x86 != 16) + return; + if (!setup_k7_watchdog()) + return; + break; + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { + if (!setup_intel_arch_watchdog()) + return; + break; + } + switch (boot_cpu_data.x86) { + case 6: + if (boot_cpu_data.x86_model > 0xd) + return; + + if (!setup_p6_watchdog()) + return; + break; + case 15: + if (boot_cpu_data.x86_model > 0x4) + return; + + if (!setup_p4_watchdog()) + return; + break; + default: + return; + } + break; + default: return; } - /* FALL THROUGH */ - case NMI_IO_APIC: - __get_cpu_var(wd_enabled) = 1; - atomic_inc(&nmi_active); } + wd->enabled = 1; + atomic_inc(&nmi_active); } void stop_apic_nmi_watchdog(void *unused) { + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + /* only support LOCAL and IO APICs for now */ if ((nmi_watchdog != NMI_LOCAL_APIC) && (nmi_watchdog != NMI_IO_APIC)) return; - if (__get_cpu_var(wd_enabled) == 0) + + if (wd->enabled == 0) return; - if (nmi_watchdog == NMI_LOCAL_APIC) - lapic_watchdog_stop(); - __get_cpu_var(wd_enabled) = 0; + + if (nmi_watchdog == NMI_LOCAL_APIC) { + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + stop_k7_watchdog(); + break; + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { + stop_intel_arch_watchdog(); + break; + } + switch (boot_cpu_data.x86) { + case 6: + if (boot_cpu_data.x86_model > 0xd) + break; + stop_p6_watchdog(); + break; + case 15: + if (boot_cpu_data.x86_model > 0x4) + break; + stop_p4_watchdog(); + break; + } + break; + default: + return; + } + } + wd->enabled = 0; atomic_dec(&nmi_active); } @@ -328,6 +1011,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) unsigned int sum; int touched = 0; int cpu = smp_processor_id(); + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + u64 dummy; int rc=0; /* check for other users first */ @@ -370,20 +1055,53 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) alert_counter[cpu] = 0; } /* see if the nmi watchdog went off */ - if (!__get_cpu_var(wd_enabled)) - return rc; - switch (nmi_watchdog) { - case NMI_LOCAL_APIC: - rc |= lapic_wd_event(nmi_hz); - break; - case NMI_IO_APIC: - /* don't know how to accurately check for this. - * just assume it was a watchdog timer interrupt - * This matches the old behaviour. - */ - rc = 1; - break; + if (wd->enabled) { + if (nmi_watchdog == NMI_LOCAL_APIC) { + rdmsrl(wd->perfctr_msr, dummy); + if (dummy & wd->check_bit){ + /* this wasn't a watchdog timer interrupt */ + goto done; + } + + /* only Intel P4 uses the cccr msr */ + if (wd->cccr_msr != 0) { + /* + * P4 quirks: + * - An overflown perfctr will assert its interrupt + * until the OVF flag in its CCCR is cleared. + * - LVTPC is masked on interrupt and must be + * unmasked by the LVTPC handler. + */ + rdmsrl(wd->cccr_msr, dummy); + dummy &= ~P4_CCCR_OVF; + wrmsrl(wd->cccr_msr, dummy); + apic_write(APIC_LVTPC, APIC_DM_NMI); + /* start the cycle over again */ + write_watchdog_counter(wd->perfctr_msr, NULL); + } + else if (wd->perfctr_msr == MSR_P6_PERFCTR0 || + wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { + /* P6 based Pentium M need to re-unmask + * the apic vector but it doesn't hurt + * other P6 variant. + * ArchPerfom/Core Duo also needs this */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + /* P6/ARCH_PERFMON has 32 bit counter write */ + write_watchdog_counter32(wd->perfctr_msr, NULL); + } else { + /* start the cycle over again */ + write_watchdog_counter(wd->perfctr_msr, NULL); + } + rc = 1; + } else if (nmi_watchdog == NMI_IO_APIC) { + /* don't know how to accurately check for this. + * just assume it was a watchdog timer interrupt + * This matches the old behaviour. + */ + rc = 1; + } } +done: return rc; } @@ -428,7 +1146,7 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, } if (nmi_watchdog == NMI_DEFAULT) { - if (lapic_watchdog_ok()) + if (nmi_known_cpu() > 0) nmi_watchdog = NMI_LOCAL_APIC; else nmi_watchdog = NMI_IO_APIC; @@ -464,3 +1182,11 @@ void __trigger_all_cpu_backtrace(void) EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); +EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi); +EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit); +EXPORT_SYMBOL(reserve_perfctr_nmi); +EXPORT_SYMBOL(release_perfctr_nmi); +EXPORT_SYMBOL(reserve_evntsel_nmi); +EXPORT_SYMBOL(release_evntsel_nmi); +EXPORT_SYMBOL(disable_timer_nmi_watchdog); +EXPORT_SYMBOL(enable_timer_nmi_watchdog); diff --git a/trunk/arch/i386/kernel/paravirt.c b/trunk/arch/i386/kernel/paravirt.c index 5c10f376bce1..2ec331e03fa9 100644 --- a/trunk/arch/i386/kernel/paravirt.c +++ b/trunk/arch/i386/kernel/paravirt.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -36,7 +35,7 @@ #include /* nop stub */ -void _paravirt_nop(void) +static void native_nop(void) { } @@ -55,148 +54,331 @@ char *memory_setup(void) #define DEF_NATIVE(name, code) \ extern const char start_##name[], end_##name[]; \ asm("start_" #name ": " code "; end_" #name ":") - -DEF_NATIVE(irq_disable, "cli"); -DEF_NATIVE(irq_enable, "sti"); -DEF_NATIVE(restore_fl, "push %eax; popf"); -DEF_NATIVE(save_fl, "pushf; pop %eax"); +DEF_NATIVE(cli, "cli"); +DEF_NATIVE(sti, "sti"); +DEF_NATIVE(popf, "push %eax; popf"); +DEF_NATIVE(pushf, "pushf; pop %eax"); +DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli"); DEF_NATIVE(iret, "iret"); -DEF_NATIVE(irq_enable_sysexit, "sti; sysexit"); -DEF_NATIVE(read_cr2, "mov %cr2, %eax"); -DEF_NATIVE(write_cr3, "mov %eax, %cr3"); -DEF_NATIVE(read_cr3, "mov %cr3, %eax"); -DEF_NATIVE(clts, "clts"); -DEF_NATIVE(read_tsc, "rdtsc"); +DEF_NATIVE(sti_sysexit, "sti; sysexit"); -DEF_NATIVE(ud2a, "ud2a"); +static const struct native_insns +{ + const char *start, *end; +} native_insns[] = { + [PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli }, + [PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti }, + [PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf }, + [PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf }, + [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli }, + [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret }, + [PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit }, +}; static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) { - const unsigned char *start, *end; - unsigned ret; - - switch(type) { -#define SITE(x) case PARAVIRT_PATCH(x): start = start_##x; end = end_##x; goto patch_site - SITE(irq_disable); - SITE(irq_enable); - SITE(restore_fl); - SITE(save_fl); - SITE(iret); - SITE(irq_enable_sysexit); - SITE(read_cr2); - SITE(read_cr3); - SITE(write_cr3); - SITE(clts); - SITE(read_tsc); -#undef SITE - - patch_site: - ret = paravirt_patch_insns(insns, len, start, end); - break; + unsigned int insn_len; - case PARAVIRT_PATCH(make_pgd): - case PARAVIRT_PATCH(make_pte): - case PARAVIRT_PATCH(pgd_val): - case PARAVIRT_PATCH(pte_val): -#ifdef CONFIG_X86_PAE - case PARAVIRT_PATCH(make_pmd): - case PARAVIRT_PATCH(pmd_val): -#endif - /* These functions end up returning exactly what - they're passed, in the same registers. */ - ret = paravirt_patch_nop(); - break; + /* Don't touch it if we don't have a replacement */ + if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start) + return len; + + insn_len = native_insns[type].end - native_insns[type].start; + /* Similarly if we can't fit replacement. */ + if (len < insn_len) + return len; + + memcpy(insns, native_insns[type].start, insn_len); + return insn_len; +} + +static unsigned long native_get_debugreg(int regno) +{ + unsigned long val = 0; /* Damn you, gcc! */ + + switch (regno) { + case 0: + asm("movl %%db0, %0" :"=r" (val)); break; + case 1: + asm("movl %%db1, %0" :"=r" (val)); break; + case 2: + asm("movl %%db2, %0" :"=r" (val)); break; + case 3: + asm("movl %%db3, %0" :"=r" (val)); break; + case 6: + asm("movl %%db6, %0" :"=r" (val)); break; + case 7: + asm("movl %%db7, %0" :"=r" (val)); break; default: - ret = paravirt_patch_default(type, clobbers, insns, len); + BUG(); + } + return val; +} + +static void native_set_debugreg(int regno, unsigned long value) +{ + switch (regno) { + case 0: + asm("movl %0,%%db0" : /* no output */ :"r" (value)); + break; + case 1: + asm("movl %0,%%db1" : /* no output */ :"r" (value)); + break; + case 2: + asm("movl %0,%%db2" : /* no output */ :"r" (value)); break; + case 3: + asm("movl %0,%%db3" : /* no output */ :"r" (value)); + break; + case 6: + asm("movl %0,%%db6" : /* no output */ :"r" (value)); + break; + case 7: + asm("movl %0,%%db7" : /* no output */ :"r" (value)); + break; + default: + BUG(); } +} - return ret; +void init_IRQ(void) +{ + paravirt_ops.init_IRQ(); } -unsigned paravirt_patch_nop(void) +static void native_clts(void) { - return 0; + asm volatile ("clts"); +} + +static unsigned long native_read_cr0(void) +{ + unsigned long val; + asm volatile("movl %%cr0,%0\n\t" :"=r" (val)); + return val; +} + +static void native_write_cr0(unsigned long val) +{ + asm volatile("movl %0,%%cr0": :"r" (val)); +} + +static unsigned long native_read_cr2(void) +{ + unsigned long val; + asm volatile("movl %%cr2,%0\n\t" :"=r" (val)); + return val; } -unsigned paravirt_patch_ignore(unsigned len) +static void native_write_cr2(unsigned long val) { - return len; + asm volatile("movl %0,%%cr2": :"r" (val)); } -unsigned paravirt_patch_call(void *target, u16 tgt_clobbers, - void *site, u16 site_clobbers, - unsigned len) +static unsigned long native_read_cr3(void) { - unsigned char *call = site; - unsigned long delta = (unsigned long)target - (unsigned long)(call+5); + unsigned long val; + asm volatile("movl %%cr3,%0\n\t" :"=r" (val)); + return val; +} - if (tgt_clobbers & ~site_clobbers) - return len; /* target would clobber too much for this site */ - if (len < 5) - return len; /* call too long for patch site */ +static void native_write_cr3(unsigned long val) +{ + asm volatile("movl %0,%%cr3": :"r" (val)); +} - *call++ = 0xe8; /* call */ - *(unsigned long *)call = delta; +static unsigned long native_read_cr4(void) +{ + unsigned long val; + asm volatile("movl %%cr4,%0\n\t" :"=r" (val)); + return val; +} - return 5; +static unsigned long native_read_cr4_safe(void) +{ + unsigned long val; + /* This could fault if %cr4 does not exist */ + asm("1: movl %%cr4, %0 \n" + "2: \n" + ".section __ex_table,\"a\" \n" + ".long 1b,2b \n" + ".previous \n" + : "=r" (val): "0" (0)); + return val; } -unsigned paravirt_patch_jmp(void *target, void *site, unsigned len) +static void native_write_cr4(unsigned long val) { - unsigned char *jmp = site; - unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5); + asm volatile("movl %0,%%cr4": :"r" (val)); +} - if (len < 5) - return len; /* call too long for patch site */ +static unsigned long native_save_fl(void) +{ + unsigned long f; + asm volatile("pushfl ; popl %0":"=g" (f): /* no input */); + return f; +} - *jmp++ = 0xe9; /* jmp */ - *(unsigned long *)jmp = delta; +static void native_restore_fl(unsigned long f) +{ + asm volatile("pushl %0 ; popfl": /* no output */ + :"g" (f) + :"memory", "cc"); +} - return 5; +static void native_irq_disable(void) +{ + asm volatile("cli": : :"memory"); } -unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len) +static void native_irq_enable(void) { - void *opfunc = *((void **)¶virt_ops + type); - unsigned ret; + asm volatile("sti": : :"memory"); +} - if (opfunc == NULL) - /* If there's no function, patch it with a ud2a (BUG) */ - ret = paravirt_patch_insns(site, len, start_ud2a, end_ud2a); - else if (opfunc == paravirt_nop) - /* If the operation is a nop, then nop the callsite */ - ret = paravirt_patch_nop(); - else if (type == PARAVIRT_PATCH(iret) || - type == PARAVIRT_PATCH(irq_enable_sysexit)) - /* If operation requires a jmp, then jmp */ - ret = paravirt_patch_jmp(opfunc, site, len); - else - /* Otherwise call the function; assume target could - clobber any caller-save reg */ - ret = paravirt_patch_call(opfunc, CLBR_ANY, - site, clobbers, len); +static void native_safe_halt(void) +{ + asm volatile("sti; hlt": : :"memory"); +} - return ret; +static void native_halt(void) +{ + asm volatile("hlt": : :"memory"); } -unsigned paravirt_patch_insns(void *site, unsigned len, - const char *start, const char *end) +static void native_wbinvd(void) { - unsigned insn_len = end - start; + asm volatile("wbinvd": : :"memory"); +} - if (insn_len > len || start == NULL) - insn_len = len; - else - memcpy(site, start, insn_len); +static unsigned long long native_read_msr(unsigned int msr, int *err) +{ + unsigned long long val; + + asm volatile("2: rdmsr ; xorl %0,%0\n" + "1:\n\t" + ".section .fixup,\"ax\"\n\t" + "3: movl %3,%0 ; jmp 1b\n\t" + ".previous\n\t" + ".section __ex_table,\"a\"\n" + " .align 4\n\t" + " .long 2b,3b\n\t" + ".previous" + : "=r" (*err), "=A" (val) + : "c" (msr), "i" (-EFAULT)); + + return val; +} - return insn_len; +static int native_write_msr(unsigned int msr, unsigned long long val) +{ + int err; + asm volatile("2: wrmsr ; xorl %0,%0\n" + "1:\n\t" + ".section .fixup,\"ax\"\n\t" + "3: movl %4,%0 ; jmp 1b\n\t" + ".previous\n\t" + ".section __ex_table,\"a\"\n" + " .align 4\n\t" + " .long 2b,3b\n\t" + ".previous" + : "=a" (err) + : "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)), + "i" (-EFAULT)); + return err; } -void init_IRQ(void) +static unsigned long long native_read_tsc(void) { - paravirt_ops.init_IRQ(); + unsigned long long val; + asm volatile("rdtsc" : "=A" (val)); + return val; +} + +static unsigned long long native_read_pmc(void) +{ + unsigned long long val; + asm volatile("rdpmc" : "=A" (val)); + return val; +} + +static void native_load_tr_desc(void) +{ + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); +} + +static void native_load_gdt(const struct Xgt_desc_struct *dtr) +{ + asm volatile("lgdt %0"::"m" (*dtr)); +} + +static void native_load_idt(const struct Xgt_desc_struct *dtr) +{ + asm volatile("lidt %0"::"m" (*dtr)); +} + +static void native_store_gdt(struct Xgt_desc_struct *dtr) +{ + asm ("sgdt %0":"=m" (*dtr)); +} + +static void native_store_idt(struct Xgt_desc_struct *dtr) +{ + asm ("sidt %0":"=m" (*dtr)); +} + +static unsigned long native_store_tr(void) +{ + unsigned long tr; + asm ("str %0":"=r" (tr)); + return tr; +} + +static void native_load_tls(struct thread_struct *t, unsigned int cpu) +{ +#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] + C(0); C(1); C(2); +#undef C +} + +static inline void native_write_dt_entry(void *dt, int entry, u32 entry_low, u32 entry_high) +{ + u32 *lp = (u32 *)((char *)dt + entry*8); + lp[0] = entry_low; + lp[1] = entry_high; +} + +static void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high) +{ + native_write_dt_entry(dt, entrynum, low, high); +} + +static void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high) +{ + native_write_dt_entry(dt, entrynum, low, high); +} + +static void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high) +{ + native_write_dt_entry(dt, entrynum, low, high); +} + +static void native_load_esp0(struct tss_struct *tss, + struct thread_struct *thread) +{ + tss->esp0 = thread->esp0; + + /* This can only happen when SEP is enabled, no need to test "SEP"arately */ + if (unlikely(tss->ss1 != thread->sysenter_cs)) { + tss->ss1 = thread->sysenter_cs; + wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); + } +} + +static void native_io_delay(void) +{ + asm volatile("outb %al,$0x80"); } static void native_flush_tlb(void) @@ -213,11 +395,83 @@ static void native_flush_tlb_global(void) __native_flush_tlb_global(); } -static void native_flush_tlb_single(unsigned long addr) +static void native_flush_tlb_single(u32 addr) { __native_flush_tlb_single(addr); } +#ifndef CONFIG_X86_PAE +static void native_set_pte(pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; +} + +static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; +} + +static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ + *pmdp = pmdval; +} + +#else /* CONFIG_X86_PAE */ + +static void native_set_pte(pte_t *ptep, pte_t pte) +{ + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; +} + +static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) +{ + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; +} + +static void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) +{ + ptep->pte_low = 0; + smp_wmb(); + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; +} + +static void native_set_pte_atomic(pte_t *ptep, pte_t pteval) +{ + set_64bit((unsigned long long *)ptep,pte_val(pteval)); +} + +static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ + set_64bit((unsigned long long *)pmdp,pmd_val(pmdval)); +} + +static void native_set_pud(pud_t *pudp, pud_t pudval) +{ + *pudp = pudval; +} + +static void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + ptep->pte_low = 0; + smp_wmb(); + ptep->pte_high = 0; +} + +static void native_pmd_clear(pmd_t *pmd) +{ + u32 *tmp = (u32 *)pmd; + *tmp = 0; + smp_wmb(); + *(tmp + 1) = 0; +} +#endif /* CONFIG_X86_PAE */ + /* These are in entry.S */ extern void native_iret(void); extern void native_irq_enable_sysexit(void); @@ -233,11 +487,10 @@ struct paravirt_ops paravirt_ops = { .name = "bare hardware", .paravirt_enabled = 0, .kernel_rpl = 0, - .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */ .patch = native_patch, .banner = default_banner, - .arch_setup = paravirt_nop, + .arch_setup = native_nop, .memory_setup = machine_specific_memory_setup, .get_wallclock = native_get_wallclock, .set_wallclock = native_set_wallclock, @@ -264,8 +517,8 @@ struct paravirt_ops paravirt_ops = { .safe_halt = native_safe_halt, .halt = native_halt, .wbinvd = native_wbinvd, - .read_msr = native_read_msr_safe, - .write_msr = native_write_msr_safe, + .read_msr = native_read_msr, + .write_msr = native_write_msr, .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, .get_scheduled_cycles = native_read_tsc, @@ -278,9 +531,9 @@ struct paravirt_ops paravirt_ops = { .store_idt = native_store_idt, .store_tr = native_store_tr, .load_tls = native_load_tls, - .write_ldt_entry = write_dt_entry, - .write_gdt_entry = write_dt_entry, - .write_idt_entry = write_dt_entry, + .write_ldt_entry = native_write_ldt_entry, + .write_gdt_entry = native_write_gdt_entry, + .write_idt_entry = native_write_idt_entry, .load_esp0 = native_load_esp0, .set_iopl_mask = native_set_iopl_mask, @@ -292,57 +545,44 @@ struct paravirt_ops paravirt_ops = { .apic_read = native_apic_read, .setup_boot_clock = setup_boot_APIC_clock, .setup_secondary_clock = setup_secondary_APIC_clock, - .startup_ipi_hook = paravirt_nop, #endif - .set_lazy_mode = paravirt_nop, - - .pagetable_setup_start = native_pagetable_setup_start, - .pagetable_setup_done = native_pagetable_setup_done, + .set_lazy_mode = (void *)native_nop, .flush_tlb_user = native_flush_tlb, .flush_tlb_kernel = native_flush_tlb_global, .flush_tlb_single = native_flush_tlb_single, - .flush_tlb_others = native_flush_tlb_others, - .alloc_pt = paravirt_nop, - .alloc_pd = paravirt_nop, - .alloc_pd_clone = paravirt_nop, - .release_pt = paravirt_nop, - .release_pd = paravirt_nop, + .map_pt_hook = (void *)native_nop, + + .alloc_pt = (void *)native_nop, + .alloc_pd = (void *)native_nop, + .alloc_pd_clone = (void *)native_nop, + .release_pt = (void *)native_nop, + .release_pd = (void *)native_nop, .set_pte = native_set_pte, .set_pte_at = native_set_pte_at, .set_pmd = native_set_pmd, - .pte_update = paravirt_nop, - .pte_update_defer = paravirt_nop, - -#ifdef CONFIG_HIGHPTE - .kmap_atomic_pte = kmap_atomic, -#endif - + .pte_update = (void *)native_nop, + .pte_update_defer = (void *)native_nop, #ifdef CONFIG_X86_PAE .set_pte_atomic = native_set_pte_atomic, .set_pte_present = native_set_pte_present, .set_pud = native_set_pud, .pte_clear = native_pte_clear, .pmd_clear = native_pmd_clear, - - .pmd_val = native_pmd_val, - .make_pmd = native_make_pmd, #endif - .pte_val = native_pte_val, - .pgd_val = native_pgd_val, - - .make_pte = native_make_pte, - .make_pgd = native_make_pgd, - .irq_enable_sysexit = native_irq_enable_sysexit, .iret = native_iret, - .dup_mmap = paravirt_nop, - .exit_mmap = paravirt_nop, - .activate_mm = paravirt_nop, + .startup_ipi_hook = (void *)native_nop, }; -EXPORT_SYMBOL(paravirt_ops); +/* + * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops + * semantics are subject to change. Hence we only do this + * internal-only export of this, until it gets sorted out and + * all lowlevel CPU ops used by modules are separately exported. + */ +EXPORT_SYMBOL_GPL(paravirt_ops); diff --git a/trunk/arch/i386/kernel/process.c b/trunk/arch/i386/kernel/process.c index 61999479b7a4..393a67d5d943 100644 --- a/trunk/arch/i386/kernel/process.c +++ b/trunk/arch/i386/kernel/process.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -58,6 +57,7 @@ #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -66,12 +66,6 @@ static int hlt_counter; unsigned long boot_option_idle_override = 0; EXPORT_SYMBOL(boot_option_idle_override); -DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; -EXPORT_PER_CPU_SYMBOL(current_task); - -DEFINE_PER_CPU(int, cpu_number); -EXPORT_PER_CPU_SYMBOL(cpu_number); - /* * Return saved PC of a blocked thread. */ @@ -278,24 +272,25 @@ void __devinit select_idle_routine(const struct cpuinfo_x86 *c) } } -static int __init idle_setup(char *str) +static int __init idle_setup (char *str) { - if (!strcmp(str, "poll")) { + if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); pm_idle = poll_idle; #ifdef CONFIG_X86_SMP if (smp_num_siblings > 1) printk("WARNING: polling idle and HT enabled, performance may degrade.\n"); #endif - } else if (!strcmp(str, "mwait")) - force_mwait = 1; - else - return -1; + } else if (!strncmp(str, "halt", 4)) { + printk("using halt in idle threads.\n"); + pm_idle = default_idle; + } boot_option_idle_override = 1; - return 0; + return 1; } -early_param("idle", idle_setup); + +__setup("idle=", idle_setup); void show_regs(struct pt_regs * regs) { @@ -348,7 +343,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.xds = __USER_DS; regs.xes = __USER_DS; - regs.xfs = __KERNEL_PERCPU; + regs.xfs = __KERNEL_PDA; regs.orig_eax = -1; regs.eip = (unsigned long) kernel_thread_helper; regs.xcs = __KERNEL_CS | get_kernel_rpl(); @@ -381,7 +376,7 @@ void exit_thread(void) t->io_bitmap_max = 0; tss->io_bitmap_owner = NULL; tss->io_bitmap_max = 0; - tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } } @@ -560,7 +555,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p, * Disable the bitmap via an invalid offset. We still cache * the previous bitmap owner and the IO bitmap contents: */ - tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; return; } @@ -570,7 +565,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p, * matches the next task, we dont have to do anything but * to set a valid offset in the TSS: */ - tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; + tss->io_bitmap_base = IO_BITMAP_OFFSET; return; } /* @@ -582,7 +577,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p, * redundant copies when the currently switched task does not * perform any I/O during its timeslice. */ - tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; + tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; } /* @@ -717,7 +712,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas if (prev->gs | next->gs) loadsegment(gs, next->gs); - x86_write_percpu(current_task, next_p); + write_pda(pcurrent, next_p); return prev_p; } diff --git a/trunk/arch/i386/kernel/quirks.c b/trunk/arch/i386/kernel/quirks.c index 9f6ab1789bb0..34874c398b44 100644 --- a/trunk/arch/i386/kernel/quirks.c +++ b/trunk/arch/i386/kernel/quirks.c @@ -3,10 +3,12 @@ */ #include #include +#include +#include +#include #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) - -static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) +static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev) { u8 config, rev; u32 word; @@ -14,14 +16,12 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) /* BIOS may enable hardware IRQ balancing for * E7520/E7320/E7525(revision ID 0x9 and below) * based platforms. - * Disable SW irqbalance/affinity on those platforms. + * For those platforms, make sure that the genapic is set to 'flat' */ pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); if (rev > 0x9) return; - printk(KERN_INFO "Intel E7520/7320/7525 detected."); - /* enable access to config space*/ pci_read_config_byte(dev, 0xf4, &config); pci_write_config_byte(dev, 0xf4, config|0x2); @@ -29,6 +29,44 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) /* read xTPR register */ raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); + if (!(word & (1 << 13))) { +#ifdef CONFIG_X86_64 + if (genapic != &apic_flat) + panic("APIC mode must be flat on this system\n"); +#elif defined(CONFIG_X86_GENERICARCH) + if (genapic != &apic_default) + panic("APIC mode must be default(flat) on this system. Use apic=default\n"); +#endif + } + + /* put back the original value for config space*/ + if (!(config & 0x2)) + pci_write_config_byte(dev, 0xf4, config); +} + +void __init quirk_intel_irqbalance(void) +{ + u8 config, rev; + u32 word; + + /* BIOS may enable hardware IRQ balancing for + * E7520/E7320/E7525(revision ID 0x9 and below) + * based platforms. + * Disable SW irqbalance/affinity on those platforms. + */ + rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION); + if (rev > 0x9) + return; + + printk(KERN_INFO "Intel E7520/7320/7525 detected."); + + /* enable access to config space */ + config = read_pci_config_byte(0, 0, 0, 0xf4); + write_pci_config_byte(0, 0, 0, 0xf4, config|0x2); + + /* read xTPR register */ + word = read_pci_config_16(0, 0, 0x40, 0x4c); + if (!(word & (1 << 13))) { printk(KERN_INFO "Disabling irq balancing and affinity\n"); #ifdef CONFIG_IRQBALANCE @@ -37,14 +75,25 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) noirqdebug_setup(""); #ifdef CONFIG_PROC_FS no_irq_affinity = 1; +#endif +#ifdef CONFIG_HOTPLUG_CPU + printk(KERN_INFO "Disabling cpu hotplug control\n"); + enable_cpu_hotplug = 0; +#endif +#ifdef CONFIG_X86_64 + /* force the genapic selection to flat mode so that + * interrupts can be redirected to more than one CPU. + */ + genapic_force = &apic_flat; #endif } - /* put back the original value for config space*/ + /* put back the original value for config space */ if (!(config & 0x2)) - pci_write_config_byte(dev, 0xf4, config); + write_pci_config_byte(0, 0, 0, 0xf4, config); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, verify_quirk_intel_irqbalance); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, verify_quirk_intel_irqbalance); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, verify_quirk_intel_irqbalance); + #endif diff --git a/trunk/arch/i386/kernel/reboot.c b/trunk/arch/i386/kernel/reboot.c index 50dfc65319cd..3514b4153f7f 100644 --- a/trunk/arch/i386/kernel/reboot.c +++ b/trunk/arch/i386/kernel/reboot.c @@ -17,8 +17,7 @@ #include #include #include "mach_reboot.h" -#include -#include +#include /* * Power off function, if any @@ -198,6 +197,8 @@ static unsigned char jump_to_bios [] = */ void machine_real_restart(unsigned char *code, int length) { + unsigned long flags; + local_irq_disable(); /* Write zero to CMOS register number 0x0f, which the BIOS POST @@ -210,9 +211,9 @@ void machine_real_restart(unsigned char *code, int length) safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) */ - spin_lock(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0x00, 0x8f); - spin_unlock(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); /* Remap the kernel at virtual address zero, as well as offset zero from the kernel segment. This assumes the kernel segment starts at @@ -279,7 +280,7 @@ void machine_real_restart(unsigned char *code, int length) EXPORT_SYMBOL(machine_real_restart); #endif -static void native_machine_shutdown(void) +void machine_shutdown(void) { #ifdef CONFIG_SMP int reboot_cpu_id; @@ -315,11 +316,7 @@ static void native_machine_shutdown(void) #endif } -void __attribute__((weak)) mach_reboot_fixups(void) -{ -} - -static void native_machine_emergency_restart(void) +void machine_emergency_restart(void) { if (!reboot_thru_bios) { if (efi_enabled) { @@ -343,17 +340,17 @@ static void native_machine_emergency_restart(void) machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); } -static void native_machine_restart(char * __unused) +void machine_restart(char * __unused) { machine_shutdown(); machine_emergency_restart(); } -static void native_machine_halt(void) +void machine_halt(void) { } -static void native_machine_power_off(void) +void machine_power_off(void) { if (pm_power_off) { machine_shutdown(); @@ -362,35 +359,3 @@ static void native_machine_power_off(void) } -struct machine_ops machine_ops = { - .power_off = native_machine_power_off, - .shutdown = native_machine_shutdown, - .emergency_restart = native_machine_emergency_restart, - .restart = native_machine_restart, - .halt = native_machine_halt, -}; - -void machine_power_off(void) -{ - machine_ops.power_off(); -} - -void machine_shutdown(void) -{ - machine_ops.shutdown(); -} - -void machine_emergency_restart(void) -{ - machine_ops.emergency_restart(); -} - -void machine_restart(char *cmd) -{ - machine_ops.restart(cmd); -} - -void machine_halt(void) -{ - machine_ops.halt(); -} diff --git a/trunk/arch/i386/kernel/reboot_fixups.c b/trunk/arch/i386/kernel/reboot_fixups.c index 2d78d918340f..99aab41a05b0 100644 --- a/trunk/arch/i386/kernel/reboot_fixups.c +++ b/trunk/arch/i386/kernel/reboot_fixups.c @@ -10,7 +10,7 @@ #include #include -#include +#include static void cs5530a_warm_reset(struct pci_dev *dev) { diff --git a/trunk/arch/i386/kernel/smp.c b/trunk/arch/i386/kernel/smp.c index 89a45a9ddcd4..0e8977871b1f 100644 --- a/trunk/arch/i386/kernel/smp.c +++ b/trunk/arch/i386/kernel/smp.c @@ -165,20 +165,20 @@ void fastcall send_IPI_self(int vector) } /* - * This is used to send an IPI with no shorthand notation (the destination is - * specified in bits 56 to 63 of the ICR). + * This is only used on smaller machines. */ -static inline void __send_IPI_dest_field(unsigned long mask, int vector) +void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) { + unsigned long mask = cpus_addr(cpumask)[0]; unsigned long cfg; + unsigned long flags; + local_irq_save(flags); + WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); /* * Wait for idle. */ - if (unlikely(vector == NMI_VECTOR)) - safe_apic_wait_icr_idle(); - else - apic_wait_icr_idle(); + apic_wait_icr_idle(); /* * prepare target chip field @@ -195,25 +195,13 @@ static inline void __send_IPI_dest_field(unsigned long mask, int vector) * Send the IPI. The write to APIC_ICR fires this off. */ apic_write_around(APIC_ICR, cfg); -} - -/* - * This is only used on smaller machines. - */ -void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) -{ - unsigned long mask = cpus_addr(cpumask)[0]; - unsigned long flags; - local_irq_save(flags); - WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); - __send_IPI_dest_field(mask, vector); local_irq_restore(flags); } void send_IPI_mask_sequence(cpumask_t mask, int vector) { - unsigned long flags; + unsigned long cfg, flags; unsigned int query_cpu; /* @@ -223,10 +211,30 @@ void send_IPI_mask_sequence(cpumask_t mask, int vector) */ local_irq_save(flags); + for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { if (cpu_isset(query_cpu, mask)) { - __send_IPI_dest_field(cpu_to_logical_apicid(query_cpu), - vector); + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + + /* + * prepare target chip field + */ + cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu)); + apic_write_around(APIC_ICR2, cfg); + + /* + * program the ICR + */ + cfg = __prepare_ICR(0, vector); + + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write_around(APIC_ICR, cfg); } } local_irq_restore(flags); @@ -248,6 +256,7 @@ static cpumask_t flush_cpumask; static struct mm_struct * flush_mm; static unsigned long flush_va; static DEFINE_SPINLOCK(tlbstate_lock); +#define FLUSH_ALL 0xffffffff /* * We cannot call mmdrop() because we are in interrupt context, @@ -329,7 +338,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs) if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { - if (flush_va == TLB_FLUSH_ALL) + if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); @@ -344,11 +353,9 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs) put_cpu_no_resched(); } -void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, - unsigned long va) +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, + unsigned long va) { - cpumask_t cpumask = *cpumaskp; - /* * A couple of (to be removed) sanity checks: * @@ -359,12 +366,10 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, BUG_ON(cpu_isset(smp_processor_id(), cpumask)); BUG_ON(!mm); -#ifdef CONFIG_HOTPLUG_CPU /* If a CPU which we ran on has gone down, OK. */ cpus_and(cpumask, cpumask, cpu_online_map); - if (unlikely(cpus_empty(cpumask))) + if (cpus_empty(cpumask)) return; -#endif /* * i'm not happy about this global shared spinlock in the @@ -375,7 +380,17 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, flush_mm = mm; flush_va = va; - cpus_or(flush_cpumask, cpumask, flush_cpumask); +#if NR_CPUS <= BITS_PER_LONG + atomic_set_mask(cpumask, &flush_cpumask); +#else + { + int k; + unsigned long *flush_mask = (unsigned long *)&flush_cpumask; + unsigned long *cpu_mask = (unsigned long *)&cpumask; + for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k) + atomic_set_mask(cpu_mask[k], &flush_mask[k]); + } +#endif /* * We have to send the IPI only to * CPUs affected. @@ -402,7 +417,7 @@ void flush_tlb_current_task(void) local_flush_tlb(); if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); preempt_enable(); } @@ -421,7 +436,7 @@ void flush_tlb_mm (struct mm_struct * mm) leave_mm(smp_processor_id()); } if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); preempt_enable(); } @@ -468,7 +483,7 @@ void flush_tlb_all(void) * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ -void native_smp_send_reschedule(int cpu) +void smp_send_reschedule(int cpu) { WARN_ON(cpu_is_offline(cpu)); send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); @@ -500,78 +515,36 @@ void unlock_ipi_call_lock(void) static struct call_data_struct *call_data; -static void __smp_call_function(void (*func) (void *info), void *info, - int nonatomic, int wait) -{ - struct call_data_struct data; - int cpus = num_online_cpus() - 1; - - if (!cpus) - return; - - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; - if (wait) - atomic_set(&data.finished, 0); - - call_data = &data; - mb(); - - /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_allbutself(CALL_FUNCTION_VECTOR); - - /* Wait for response */ - while (atomic_read(&data.started) != cpus) - cpu_relax(); - - if (wait) - while (atomic_read(&data.finished) != cpus) - cpu_relax(); -} - - /** - * smp_call_function_mask(): Run a function on a set of other CPUs. - * @mask: The set of cpus to run on. Must not include the current cpu. + * smp_call_function(): Run a function on all other CPUs. * @func: The function to run. This must be fast and non-blocking. * @info: An arbitrary pointer to pass to the function. + * @nonatomic: currently unused. * @wait: If true, wait (atomically) until function has completed on other CPUs. * - * Returns 0 on success, else a negative status code. - * - * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. + * Returns 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <> or are or have executed. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int native_smp_call_function_mask(cpumask_t mask, - void (*func)(void *), void *info, - int wait) +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) { struct call_data_struct data; - cpumask_t allbutself; int cpus; - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); - /* Holding any lock stops cpus from going down. */ spin_lock(&call_lock); - - allbutself = cpu_online_map; - cpu_clear(smp_processor_id(), allbutself); - - cpus_and(mask, mask, allbutself); - cpus = cpus_weight(mask); - + cpus = num_online_cpus() - 1; if (!cpus) { spin_unlock(&call_lock); return 0; } + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); @@ -581,12 +554,9 @@ int native_smp_call_function_mask(cpumask_t mask, call_data = &data; mb(); - - /* Send a message to other CPUs */ - if (cpus_equal(mask, allbutself)) - send_IPI_allbutself(CALL_FUNCTION_VECTOR); - else - send_IPI_mask(mask, CALL_FUNCTION_VECTOR); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(CALL_FUNCTION_VECTOR); /* Wait for response */ while (atomic_read(&data.started) != cpus) @@ -599,68 +569,15 @@ int native_smp_call_function_mask(cpumask_t mask, return 0; } - -/** - * smp_call_function(): Run a function on all other CPUs. - * @func: The function to run. This must be fast and non-blocking. - * @info: An arbitrary pointer to pass to the function. - * @nonatomic: Unused. - * @wait: If true, wait (atomically) until function has completed on other CPUs. - * - * Returns 0 on success, else a negative status code. - * - * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ -int smp_call_function(void (*func) (void *info), void *info, int nonatomic, - int wait) -{ - return smp_call_function_mask(cpu_online_map, func, info, wait); -} EXPORT_SYMBOL(smp_call_function); -/** - * smp_call_function_single - Run a function on another CPU - * @cpu: The target CPU. Cannot be the calling CPU. - * @func: The function to run. This must be fast and non-blocking. - * @info: An arbitrary pointer to pass to the function. - * @nonatomic: Unused. - * @wait: If true, wait until function has completed on other CPUs. - * - * Returns 0 on success, else a negative status code. - * - * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. - */ -int smp_call_function_single(int cpu, void (*func) (void *info), void *info, - int nonatomic, int wait) -{ - /* prevent preemption and reschedule on another processor */ - int ret; - int me = get_cpu(); - if (cpu == me) { - WARN_ON(1); - put_cpu(); - return -EBUSY; - } - - ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait); - - put_cpu(); - return ret; -} -EXPORT_SYMBOL(smp_call_function_single); - static void stop_this_cpu (void * dummy) { - local_irq_disable(); /* * Remove this CPU: */ cpu_clear(smp_processor_id(), cpu_online_map); + local_irq_disable(); disable_local_APIC(); if (cpu_data[smp_processor_id()].hlt_works_ok) for(;;) halt(); @@ -671,18 +588,13 @@ static void stop_this_cpu (void * dummy) * this function calls the 'stop' function on all other CPUs in the system. */ -void native_smp_send_stop(void) +void smp_send_stop(void) { - /* Don't deadlock on the call lock in panic */ - int nolock = !spin_trylock(&call_lock); - unsigned long flags; + smp_call_function(stop_this_cpu, NULL, 1, 0); - local_irq_save(flags); - __smp_call_function(stop_this_cpu, NULL, 0, 0); - if (!nolock) - spin_unlock(&call_lock); + local_irq_disable(); disable_local_APIC(); - local_irq_restore(flags); + local_irq_enable(); } /* @@ -721,6 +633,77 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs) } } +/* + * this function sends a 'generic call function' IPI to one other CPU + * in the system. + * + * cpu is a standard Linux logical CPU number. + */ +static void +__smp_call_function_single(int cpu, void (*func) (void *info), void *info, + int nonatomic, int wait) +{ + struct call_data_struct data; + int cpus = 1; + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + call_data = &data; + wmb(); + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + cpu_relax(); + + if (!wait) + return; + + while (atomic_read(&data.finished) != cpus) + cpu_relax(); +} + +/* + * smp_call_function_single - Run a function on another CPU + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @nonatomic: Currently unused. + * @wait: If true, wait until function has completed on other CPUs. + * + * Retrurns 0 on success, else a negative status code. + * + * Does not return until the remote CPU is nearly ready to execute + * or is or has executed. + */ + +int smp_call_function_single(int cpu, void (*func) (void *info), void *info, + int nonatomic, int wait) +{ + /* prevent preemption and reschedule on another processor */ + int me = get_cpu(); + if (cpu == me) { + WARN_ON(1); + put_cpu(); + return -EBUSY; + } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + + spin_lock_bh(&call_lock); + __smp_call_function_single(cpu, func, info, nonatomic, wait); + spin_unlock_bh(&call_lock); + put_cpu(); + return 0; +} +EXPORT_SYMBOL(smp_call_function_single); + static int convert_apicid_to_cpu(int apic_id) { int i; @@ -747,14 +730,3 @@ int safe_smp_processor_id(void) return cpuid >= 0 ? cpuid : 0; } - -struct smp_ops smp_ops = { - .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, - .smp_prepare_cpus = native_smp_prepare_cpus, - .cpu_up = native_cpu_up, - .smp_cpus_done = native_smp_cpus_done, - - .smp_send_stop = native_smp_send_stop, - .smp_send_reschedule = native_smp_send_reschedule, - .smp_call_function_mask = native_smp_call_function_mask, -}; diff --git a/trunk/arch/i386/kernel/smpboot.c b/trunk/arch/i386/kernel/smpboot.c index a4b7ad283f49..4ff55e675576 100644 --- a/trunk/arch/i386/kernel/smpboot.c +++ b/trunk/arch/i386/kernel/smpboot.c @@ -53,12 +53,13 @@ #include #include #include +#include +#include #include #include #include #include -#include /* Set if we find a B stepping CPU */ static int __devinitdata smp_b_stepping; @@ -99,9 +100,6 @@ EXPORT_SYMBOL(x86_cpu_to_apicid); u8 apicid_2_node[MAX_APICID]; -DEFINE_PER_CPU(unsigned long, this_cpu_off); -EXPORT_PER_CPU_SYMBOL(this_cpu_off); - /* * Trampoline 80x86 program as an array. */ @@ -158,7 +156,7 @@ static void __cpuinit smp_store_cpu_info(int id) *c = boot_cpu_data; if (id!=0) - identify_secondary_cpu(c); + identify_cpu(c); /* * Mask B, Pentium, but not Pentium MMX */ @@ -381,14 +379,14 @@ set_cpu_sibling_map(int cpu) static void __cpuinit start_secondary(void *unused) { /* - * Don't put *anything* before cpu_init(), SMP booting is too - * fragile that we want to limit the things done here to the - * most necessary things. + * Don't put *anything* before secondary_cpu_init(), SMP + * booting is too fragile that we want to limit the + * things done here to the most necessary things. */ #ifdef CONFIG_VMI vmi_bringup(); #endif - cpu_init(); + secondary_cpu_init(); preempt_disable(); smp_callin(); while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) @@ -442,6 +440,12 @@ static void __cpuinit start_secondary(void *unused) */ void __devinit initialize_secondary(void) { + /* + * switch to the per CPU GDT we already set up + * in do_boot_cpu() + */ + cpu_set_gdt(current_thread_info()->cpu); + /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. @@ -459,6 +463,7 @@ extern struct { void * esp; unsigned short ss; } stack_start; +extern struct i386_pda *start_pda; #ifdef CONFIG_NUMA @@ -516,12 +521,12 @@ static void unmap_cpu_to_logical_apicid(int cpu) unmap_cpu_to_node(cpu); } +#if APIC_DEBUG static inline void __inquire_remote_apic(int apicid) { int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; - int timeout; - unsigned long status; + int timeout, status; printk("Inquiring remote APIC #%d...\n", apicid); @@ -531,9 +536,7 @@ static inline void __inquire_remote_apic(int apicid) /* * Wait for idle. */ - status = safe_apic_wait_icr_idle(); - if (status) - printk("a previous APIC delivery may have failed\n"); + apic_wait_icr_idle(); apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); @@ -547,13 +550,14 @@ static inline void __inquire_remote_apic(int apicid) switch (status) { case APIC_ICR_RR_VALID: status = apic_read(APIC_RRR); - printk("%lx\n", status); + printk("%08x\n", status); break; default: printk("failed\n"); } } } +#endif #ifdef WAKE_SECONDARY_VIA_NMI /* @@ -564,8 +568,8 @@ static inline void __inquire_remote_apic(int apicid) static int __devinit wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) { - unsigned long send_status, accept_status = 0; - int maxlvt; + unsigned long send_status = 0, accept_status = 0; + int timeout, maxlvt; /* Target chip */ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid)); @@ -575,7 +579,12 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. @@ -605,8 +614,8 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) static int __devinit wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) { - unsigned long send_status, accept_status = 0; - int maxlvt, num_starts, j; + unsigned long send_status = 0, accept_status = 0; + int maxlvt, timeout, num_starts, j; /* * Be paranoid about clearing APIC errors. @@ -631,7 +640,12 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); mdelay(10); @@ -644,7 +658,12 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); atomic_set(&init_deasserted, 1); @@ -700,7 +719,12 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) Dprintk("Startup point 1.\n"); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. @@ -764,25 +788,6 @@ static inline struct task_struct * alloc_idle_task(int cpu) #define alloc_idle_task(cpu) fork_idle(cpu) #endif -/* Initialize the CPU's GDT. This is either the boot CPU doing itself - (still using the master per-cpu area), or a CPU doing it for a - secondary which will soon come up. */ -static __cpuinit void init_gdt(int cpu) -{ - struct desc_struct *gdt = get_cpu_gdt_table(cpu); - - pack_descriptor((u32 *)&gdt[GDT_ENTRY_PERCPU].a, - (u32 *)&gdt[GDT_ENTRY_PERCPU].b, - __per_cpu_offset[cpu], 0xFFFFF, - 0x80 | DESCTYPE_S | 0x2, 0x8); - - per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu]; - per_cpu(cpu_number, cpu) = cpu; -} - -/* Defined in head.S */ -extern struct Xgt_desc_struct early_gdt_descr; - static int __cpuinit do_boot_cpu(int apicid, int cpu) /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad @@ -796,12 +801,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu) unsigned long start_eip; unsigned short nmi_high = 0, nmi_low = 0; - /* - * Save current MTRR state in case it was changed since early boot - * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync: - */ - mtrr_save_state(); - /* * We can't use kernel_thread since we must avoid to * reschedule the child. @@ -810,9 +809,13 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu) if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); - init_gdt(cpu); - per_cpu(current_task, cpu) = idle; - early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); + /* Pre-allocate and initialize the CPU's GDT and PDA so it + doesn't have to do any memory allocation during the + delicate CPU-bringup phase. */ + if (!init_gdt(cpu, idle)) { + printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu); + return -1; /* ? */ + } idle->thread.eip = (unsigned long) start_secondary; /* start_eip had better be page-aligned! */ @@ -938,6 +941,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu) DECLARE_COMPLETION_ONSTACK(done); struct warm_boot_cpu_info info; int apicid, ret; + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); apicid = x86_cpu_to_apicid[cpu]; if (apicid == BAD_APICID) { @@ -945,6 +949,18 @@ static int __cpuinit __smp_prepare_cpu(int cpu) goto exit; } + /* + * the CPU isn't initialized at boot time, allocate gdt table here. + * cpu_init will initialize it + */ + if (!cpu_gdt_descr->address) { + cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL); + if (!cpu_gdt_descr->address) + printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); + ret = -ENOMEM; + goto exit; + } + info.complete = &done; info.apicid = apicid; info.cpu = cpu; @@ -1157,7 +1173,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) /* These are wrappers to interface to the new boot process. Someone who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ -void __init native_smp_prepare_cpus(unsigned int max_cpus) +void __init smp_prepare_cpus(unsigned int max_cpus) { smp_commenced_mask = cpumask_of_cpu(0); cpu_callin_map = cpumask_of_cpu(0); @@ -1165,18 +1181,13 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) smp_boot_cpus(max_cpus); } -void __init native_smp_prepare_boot_cpu(void) +void __devinit smp_prepare_boot_cpu(void) { - unsigned int cpu = smp_processor_id(); - - init_gdt(cpu); - switch_to_new_gdt(); - - cpu_set(cpu, cpu_online_map); - cpu_set(cpu, cpu_callout_map); - cpu_set(cpu, cpu_present_map); - cpu_set(cpu, cpu_possible_map); - __get_cpu_var(cpu_state) = CPU_ONLINE; + cpu_set(smp_processor_id(), cpu_online_map); + cpu_set(smp_processor_id(), cpu_callout_map); + cpu_set(smp_processor_id(), cpu_present_map); + cpu_set(smp_processor_id(), cpu_possible_map); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; } #ifdef CONFIG_HOTPLUG_CPU @@ -1266,7 +1277,7 @@ void __cpu_die(unsigned int cpu) } #endif /* CONFIG_HOTPLUG_CPU */ -int __cpuinit native_cpu_up(unsigned int cpu) +int __cpuinit __cpu_up(unsigned int cpu) { unsigned long flags; #ifdef CONFIG_HOTPLUG_CPU @@ -1308,10 +1319,15 @@ int __cpuinit native_cpu_up(unsigned int cpu) touch_nmi_watchdog(); } +#ifdef CONFIG_X86_GENERICARCH + if (num_online_cpus() > 8 && genapic == &apic_default) + panic("Default flat APIC routing can't be used with > 8 cpus\n"); +#endif + return 0; } -void __init native_smp_cpus_done(unsigned int max_cpus) +void __init smp_cpus_done(unsigned int max_cpus) { #ifdef CONFIG_X86_IO_APIC setup_ioapic_dest(); diff --git a/trunk/arch/i386/kernel/sysenter.c b/trunk/arch/i386/kernel/sysenter.c index ff4ee6f3326b..13ca54a85a1c 100644 --- a/trunk/arch/i386/kernel/sysenter.c +++ b/trunk/arch/i386/kernel/sysenter.c @@ -22,26 +22,16 @@ #include #include #include -#include -#include - -enum { - VDSO_DISABLED = 0, - VDSO_ENABLED = 1, - VDSO_COMPAT = 2, -}; - -#ifdef CONFIG_COMPAT_VDSO -#define VDSO_DEFAULT VDSO_COMPAT -#else -#define VDSO_DEFAULT VDSO_ENABLED -#endif /* * Should the kernel map a VDSO page into processes and pass its * address down to glibc upon exec()? */ -unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT; +#ifdef CONFIG_PARAVIRT +unsigned int __read_mostly vdso_enabled = 0; +#else +unsigned int __read_mostly vdso_enabled = 1; +#endif EXPORT_SYMBOL_GPL(vdso_enabled); @@ -56,123 +46,6 @@ __setup("vdso=", vdso_setup); extern asmlinkage void sysenter_entry(void); -static __init void reloc_symtab(Elf32_Ehdr *ehdr, - unsigned offset, unsigned size) -{ - Elf32_Sym *sym = (void *)ehdr + offset; - unsigned nsym = size / sizeof(*sym); - unsigned i; - - for(i = 0; i < nsym; i++, sym++) { - if (sym->st_shndx == SHN_UNDEF || - sym->st_shndx == SHN_ABS) - continue; /* skip */ - - if (sym->st_shndx > SHN_LORESERVE) { - printk(KERN_INFO "VDSO: unexpected st_shndx %x\n", - sym->st_shndx); - continue; - } - - switch(ELF_ST_TYPE(sym->st_info)) { - case STT_OBJECT: - case STT_FUNC: - case STT_SECTION: - case STT_FILE: - sym->st_value += VDSO_HIGH_BASE; - } - } -} - -static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset) -{ - Elf32_Dyn *dyn = (void *)ehdr + offset; - - for(; dyn->d_tag != DT_NULL; dyn++) - switch(dyn->d_tag) { - case DT_PLTGOT: - case DT_HASH: - case DT_STRTAB: - case DT_SYMTAB: - case DT_RELA: - case DT_INIT: - case DT_FINI: - case DT_REL: - case DT_DEBUG: - case DT_JMPREL: - case DT_VERSYM: - case DT_VERDEF: - case DT_VERNEED: - case DT_ADDRRNGLO ... DT_ADDRRNGHI: - /* definitely pointers needing relocation */ - dyn->d_un.d_ptr += VDSO_HIGH_BASE; - break; - - case DT_ENCODING ... OLD_DT_LOOS-1: - case DT_LOOS ... DT_HIOS-1: - /* Tags above DT_ENCODING are pointers if - they're even */ - if (dyn->d_tag >= DT_ENCODING && - (dyn->d_tag & 1) == 0) - dyn->d_un.d_ptr += VDSO_HIGH_BASE; - break; - - case DT_VERDEFNUM: - case DT_VERNEEDNUM: - case DT_FLAGS_1: - case DT_RELACOUNT: - case DT_RELCOUNT: - case DT_VALRNGLO ... DT_VALRNGHI: - /* definitely not pointers */ - break; - - case OLD_DT_LOOS ... DT_LOOS-1: - case DT_HIOS ... DT_VALRNGLO-1: - default: - if (dyn->d_tag > DT_ENCODING) - printk(KERN_INFO "VDSO: unexpected DT_tag %x\n", - dyn->d_tag); - break; - } -} - -static __init void relocate_vdso(Elf32_Ehdr *ehdr) -{ - Elf32_Phdr *phdr; - Elf32_Shdr *shdr; - int i; - - BUG_ON(memcmp(ehdr->e_ident, ELFMAG, 4) != 0 || - !elf_check_arch(ehdr) || - ehdr->e_type != ET_DYN); - - ehdr->e_entry += VDSO_HIGH_BASE; - - /* rebase phdrs */ - phdr = (void *)ehdr + ehdr->e_phoff; - for (i = 0; i < ehdr->e_phnum; i++) { - phdr[i].p_vaddr += VDSO_HIGH_BASE; - - /* relocate dynamic stuff */ - if (phdr[i].p_type == PT_DYNAMIC) - reloc_dyn(ehdr, phdr[i].p_offset); - } - - /* rebase sections */ - shdr = (void *)ehdr + ehdr->e_shoff; - for(i = 0; i < ehdr->e_shnum; i++) { - if (!(shdr[i].sh_flags & SHF_ALLOC)) - continue; - - shdr[i].sh_addr += VDSO_HIGH_BASE; - - if (shdr[i].sh_type == SHT_SYMTAB || - shdr[i].sh_type == SHT_DYNSYM) - reloc_symtab(ehdr, shdr[i].sh_offset, - shdr[i].sh_size); - } -} - void enable_sep_cpu(void) { int cpu = get_cpu(); @@ -183,33 +56,14 @@ void enable_sep_cpu(void) return; } - tss->x86_tss.ss1 = __KERNEL_CS; - tss->x86_tss.esp1 = sizeof(struct tss_struct) + (unsigned long) tss; + tss->ss1 = __KERNEL_CS; + tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); - wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.esp1, 0); + wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0); wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0); put_cpu(); } -static struct vm_area_struct gate_vma; - -static int __init gate_vma_init(void) -{ - gate_vma.vm_mm = NULL; - gate_vma.vm_start = FIXADDR_USER_START; - gate_vma.vm_end = FIXADDR_USER_END; - gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; - gate_vma.vm_page_prot = __P101; - /* - * Make sure the vDSO gets into every core dump. - * Dumping its contents makes post-mortem fully interpretable later - * without matching up the same kernel and hardware config to see - * what PC values meant. - */ - gate_vma.vm_flags |= VM_ALWAYSDUMP; - return 0; -} - /* * These symbols are defined by vsyscall.o to mark the bounds * of the ELF DSO images included therein. @@ -218,48 +72,31 @@ extern const char vsyscall_int80_start, vsyscall_int80_end; extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; static struct page *syscall_pages[1]; -static void map_compat_vdso(int map) -{ - static int vdso_mapped; - - if (map == vdso_mapped) - return; - - vdso_mapped = map; - - __set_fixmap(FIX_VDSO, page_to_pfn(syscall_pages[0]) << PAGE_SHIFT, - map ? PAGE_READONLY_EXEC : PAGE_NONE); - - /* flush stray tlbs */ - flush_tlb_all(); -} - int __init sysenter_setup(void) { void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); - const void *vsyscall; - size_t vsyscall_len; - syscall_pages[0] = virt_to_page(syscall_page); - gate_vma_init(); - +#ifdef CONFIG_COMPAT_VDSO + __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC); printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO)); +#endif if (!boot_cpu_has(X86_FEATURE_SEP)) { - vsyscall = &vsyscall_int80_start; - vsyscall_len = &vsyscall_int80_end - &vsyscall_int80_start; - } else { - vsyscall = &vsyscall_sysenter_start; - vsyscall_len = &vsyscall_sysenter_end - &vsyscall_sysenter_start; + memcpy(syscall_page, + &vsyscall_int80_start, + &vsyscall_int80_end - &vsyscall_int80_start); + return 0; } - memcpy(syscall_page, vsyscall, vsyscall_len); - relocate_vdso(syscall_page); + memcpy(syscall_page, + &vsyscall_sysenter_start, + &vsyscall_sysenter_end - &vsyscall_sysenter_start); return 0; } +#ifndef CONFIG_COMPAT_VDSO /* Defined in vsyscall-sysenter.S */ extern void SYSENTER_RETURN; @@ -268,52 +105,36 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) { struct mm_struct *mm = current->mm; unsigned long addr; - int ret = 0; - bool compat; + int ret; down_write(&mm->mmap_sem); - - /* Test compat mode once here, in case someone - changes it via sysctl */ - compat = (vdso_enabled == VDSO_COMPAT); - - map_compat_vdso(compat); - - if (compat) - addr = VDSO_HIGH_BASE; - else { - addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); - if (IS_ERR_VALUE(addr)) { - ret = addr; - goto up_fail; - } - - /* - * MAYWRITE to allow gdb to COW and set breakpoints - * - * Make sure the vDSO gets into every core dump. - * Dumping its contents makes post-mortem fully - * interpretable later without matching up the same - * kernel and hardware config to see what PC values - * meant. - */ - ret = install_special_mapping(mm, addr, PAGE_SIZE, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| - VM_ALWAYSDUMP, - syscall_pages); - - if (ret) - goto up_fail; + addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; + goto up_fail; } + /* + * MAYWRITE to allow gdb to COW and set breakpoints + * + * Make sure the vDSO gets into every core dump. + * Dumping its contents makes post-mortem fully interpretable later + * without matching up the same kernel and hardware config to see + * what PC values meant. + */ + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall_pages); + if (ret) + goto up_fail; + current->mm->context.vdso = (void *)addr; current_thread_info()->sysenter_return = - (void *)VDSO_SYM(&SYSENTER_RETURN); - - up_fail: + (void *)VDSO_SYM(&SYSENTER_RETURN); +up_fail: up_write(&mm->mmap_sem); - return ret; } @@ -326,11 +147,6 @@ const char *arch_vma_name(struct vm_area_struct *vma) struct vm_area_struct *get_gate_vma(struct task_struct *tsk) { - struct mm_struct *mm = tsk->mm; - - /* Check to see if this task was created in compat vdso mode */ - if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE) - return &gate_vma; return NULL; } @@ -343,3 +159,4 @@ int in_gate_area_no_task(unsigned long addr) { return 0; } +#endif diff --git a/trunk/arch/i386/kernel/time.c b/trunk/arch/i386/kernel/time.c index a665df61f08c..94e5cb091104 100644 --- a/trunk/arch/i386/kernel/time.c +++ b/trunk/arch/i386/kernel/time.c @@ -70,6 +70,8 @@ #include +int pit_latch_buggy; /* extern */ + #include "do_timer.h" unsigned int cpu_khz; /* Detected as we calibrate the TSC */ diff --git a/trunk/arch/i386/kernel/trampoline.S b/trunk/arch/i386/kernel/trampoline.S index f62815f8d06a..2f1814c5cfd7 100644 --- a/trunk/arch/i386/kernel/trampoline.S +++ b/trunk/arch/i386/kernel/trampoline.S @@ -29,7 +29,7 @@ * * TYPE VALUE * R_386_32 startup_32_smp - * R_386_32 boot_gdt + * R_386_32 boot_gdt_table */ #include @@ -62,8 +62,8 @@ r_base = . * to 32 bit. */ - lidtl boot_idt_descr - r_base # load idt with 0, 0 - lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate + lidtl boot_idt - r_base # load idt with 0, 0 + lgdtl boot_gdt - r_base # load gdt with whatever is appropriate xor %ax, %ax inc %ax # protected mode (PE) bit @@ -73,11 +73,11 @@ r_base = . # These need to be in the same 64K segment as the above; # hence we don't use the boot_gdt_descr defined in head.S -boot_gdt_descr: +boot_gdt: .word __BOOT_DS + 7 # gdt limit - .long boot_gdt - __PAGE_OFFSET # gdt base + .long boot_gdt_table-__PAGE_OFFSET # gdt base -boot_idt_descr: +boot_idt: .word 0 # idt limit = 0 .long 0 # idt base = 0L diff --git a/trunk/arch/i386/kernel/traps.c b/trunk/arch/i386/kernel/traps.c index f21b41e7770c..af0d3f70a817 100644 --- a/trunk/arch/i386/kernel/traps.c +++ b/trunk/arch/i386/kernel/traps.c @@ -476,6 +476,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, siginfo_t *info) { struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; if (regs->eflags & VM_MASK) { if (vm86) @@ -487,18 +489,6 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, goto kernel_trap; trap_signal: { - /* - * We want error_code and trap_no set for userspace faults and - * kernelspace faults which result in die(), but not - * kernelspace faults which are fixed up. die() gives the - * process no chance to handle the signal and notice the - * kernel fault information, so that won't result in polluting - * the information about previously queued, but not yet - * delivered, faults. See also do_general_protection below. - */ - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr; - if (info) force_sig_info(signr, info, tsk); else @@ -507,11 +497,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, } kernel_trap: { - if (!fixup_exception(regs)) { - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr; + if (!fixup_exception(regs)) die(str, regs, error_code); - } return; } @@ -596,7 +583,7 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs, * and we set the offset field correctly. Then we let the CPU to * restart the faulting instruction. */ - if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && thread->io_bitmap_ptr) { memcpy(tss->io_bitmap, thread->io_bitmap_ptr, thread->io_bitmap_max); @@ -609,13 +596,16 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs, thread->io_bitmap_max, 0xff, tss->io_bitmap_max - thread->io_bitmap_max); tss->io_bitmap_max = thread->io_bitmap_max; - tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; + tss->io_bitmap_base = IO_BITMAP_OFFSET; tss->io_bitmap_owner = thread; put_cpu(); return; } put_cpu(); + current->thread.error_code = error_code; + current->thread.trap_no = 13; + if (regs->eflags & VM_MASK) goto gp_in_vm86; @@ -634,8 +624,6 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs, gp_in_kernel: if (!fixup_exception(regs)) { - current->thread.error_code = error_code; - current->thread.trap_no = 13; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; @@ -1030,7 +1018,9 @@ fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, fastcall unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) { - struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; + int cpu = smp_processor_id(); + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); + struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address; unsigned long base = (kesp - uesp) & -THREAD_SIZE; unsigned long new_kesp = kesp - base; unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; diff --git a/trunk/arch/i386/kernel/tsc.c b/trunk/arch/i386/kernel/tsc.c index f64b81f3033b..6cb8f5336732 100644 --- a/trunk/arch/i386/kernel/tsc.c +++ b/trunk/arch/i386/kernel/tsc.c @@ -200,10 +200,13 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; + if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE) + write_seqlock_irq(&xtime_lock); + if (!ref_freq) { if (!freq->old){ ref_freq = freq->new; - return 0; + goto end; } ref_freq = freq->old; loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; @@ -230,10 +233,13 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) * TSC based sched_clock turns * to junk w/ cpufreq */ - mark_tsc_unstable("cpufreq changes"); + mark_tsc_unstable(); } } } +end: + if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE) + write_sequnlock_irq(&xtime_lock); return 0; } @@ -275,12 +281,11 @@ static struct clocksource clocksource_tsc = { CLOCK_SOURCE_MUST_VERIFY, }; -void mark_tsc_unstable(char *reason) +void mark_tsc_unstable(void) { if (!tsc_unstable) { tsc_unstable = 1; tsc_enabled = 0; - printk("Marking TSC unstable due to: %s.\n", reason); /* Can be called before registration */ if (clocksource_tsc.mult) clocksource_change_rating(&clocksource_tsc, 0); diff --git a/trunk/arch/i386/kernel/verify_cpu.S b/trunk/arch/i386/kernel/verify_cpu.S deleted file mode 100644 index e51a8695d54e..000000000000 --- a/trunk/arch/i386/kernel/verify_cpu.S +++ /dev/null @@ -1,65 +0,0 @@ -/* Check if CPU has some minimum CPUID bits - This runs in 16bit mode so that the caller can still use the BIOS - to output errors on the screen */ -#include - -verify_cpu: - pushfl # Save caller passed flags - pushl $0 # Kill any dangerous flags - popfl - -#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4 - pushfl - orl $(1<<18),(%esp) # try setting AC - popfl - pushfl - popl %eax - testl $(1<<18),%eax - jz bad -#endif -#if REQUIRED_MASK1 != 0 - pushfl # standard way to check for cpuid - popl %eax - movl %eax,%ebx - xorl $0x200000,%eax - pushl %eax - popfl - pushfl - popl %eax - cmpl %eax,%ebx - pushfl # standard way to check for cpuid - popl %eax - movl %eax,%ebx - xorl $0x200000,%eax - pushl %eax - popfl - pushfl - popl %eax - cmpl %eax,%ebx - jz bad # REQUIRED_MASK1 != 0 requires CPUID - - movl $0x0,%eax # See if cpuid 1 is implemented - cpuid - cmpl $0x1,%eax - jb bad # no cpuid 1 - - movl $0x1,%eax # Does the cpu have what it takes - cpuid - -#if CONFIG_X86_MINIMUM_CPU_MODEL > 4 -#error add proper model checking here -#endif - - andl $REQUIRED_MASK1,%edx - xorl $REQUIRED_MASK1,%edx - jnz bad -#endif /* REQUIRED_MASK1 */ - - popfl - xor %eax,%eax - ret - -bad: - popfl - movl $1,%eax - ret diff --git a/trunk/arch/i386/kernel/vmi.c b/trunk/arch/i386/kernel/vmi.c index c8726c424b35..697a70e8c0c9 100644 --- a/trunk/arch/i386/kernel/vmi.c +++ b/trunk/arch/i386/kernel/vmi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -57,7 +56,7 @@ static int disable_noidle; static int disable_vmi_timer; /* Cached VMI operations */ -static struct { +struct { void (*cpuid)(void /* non-c */); void (*_set_ldt)(u32 selector); void (*set_tr)(u32 selector); @@ -66,15 +65,16 @@ static struct { void (*release_page)(u32, u32); void (*set_pte)(pte_t, pte_t *, unsigned); void (*update_pte)(pte_t *, unsigned); - void (*set_linear_mapping)(int, void *, u32, u32); - void (*_flush_tlb)(int); + void (*set_linear_mapping)(int, u32, u32, u32); + void (*flush_tlb)(int); void (*set_initial_ap_state)(int, int); void (*halt)(void); void (*set_lazy_mode)(int mode); } vmi_ops; -/* Cached VMI operations */ -struct vmi_timer_ops vmi_timer_ops; +/* XXX move this to alternative.h */ +extern struct paravirt_patch __start_parainstructions[], + __stop_parainstructions[]; /* * VMI patching routines. @@ -83,6 +83,11 @@ struct vmi_timer_ops vmi_timer_ops; #define MNEM_JMP 0xe9 #define MNEM_RET 0xc3 +static char irq_save_disable_callout[] = { + MNEM_CALL, 0, 0, 0, 0, + MNEM_CALL, 0, 0, 0, 0, + MNEM_RET +}; #define IRQ_PATCH_INT_MASK 0 #define IRQ_PATCH_DISABLE 5 @@ -130,17 +135,33 @@ static unsigned patch_internal(int call, unsigned len, void *insns) static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len) { switch (type) { - case PARAVIRT_PATCH(irq_disable): + case PARAVIRT_IRQ_DISABLE: return patch_internal(VMI_CALL_DisableInterrupts, len, insns); - case PARAVIRT_PATCH(irq_enable): + case PARAVIRT_IRQ_ENABLE: return patch_internal(VMI_CALL_EnableInterrupts, len, insns); - case PARAVIRT_PATCH(restore_fl): + case PARAVIRT_RESTORE_FLAGS: return patch_internal(VMI_CALL_SetInterruptMask, len, insns); - case PARAVIRT_PATCH(save_fl): + case PARAVIRT_SAVE_FLAGS: return patch_internal(VMI_CALL_GetInterruptMask, len, insns); - case PARAVIRT_PATCH(iret): + case PARAVIRT_SAVE_FLAGS_IRQ_DISABLE: + if (len >= 10) { + patch_internal(VMI_CALL_GetInterruptMask, len, insns); + patch_internal(VMI_CALL_DisableInterrupts, len-5, insns+5); + return 10; + } else { + /* + * You bastards didn't leave enough room to + * patch save_flags_irq_disable inline. Patch + * to a helper + */ + BUG_ON(len < 5); + *(char *)insns = MNEM_CALL; + patch_offset(insns, irq_save_disable_callout); + return 5; + } + case PARAVIRT_INTERRUPT_RETURN: return patch_internal(VMI_CALL_IRET, len, insns); - case PARAVIRT_PATCH(irq_enable_sysexit): + case PARAVIRT_STI_SYSEXIT: return patch_internal(VMI_CALL_SYSEXIT, len, insns); default: break; @@ -209,24 +230,24 @@ static void vmi_set_tr(void) static void vmi_load_esp0(struct tss_struct *tss, struct thread_struct *thread) { - tss->x86_tss.esp0 = thread->esp0; + tss->esp0 = thread->esp0; /* This can only happen when SEP is enabled, no need to test "SEP"arately */ - if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) { - tss->x86_tss.ss1 = thread->sysenter_cs; + if (unlikely(tss->ss1 != thread->sysenter_cs)) { + tss->ss1 = thread->sysenter_cs; wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); } - vmi_ops.set_kernel_stack(__KERNEL_DS, tss->x86_tss.esp0); + vmi_ops.set_kernel_stack(__KERNEL_DS, tss->esp0); } static void vmi_flush_tlb_user(void) { - vmi_ops._flush_tlb(VMI_FLUSH_TLB); + vmi_ops.flush_tlb(VMI_FLUSH_TLB); } static void vmi_flush_tlb_kernel(void) { - vmi_ops._flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL); + vmi_ops.flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL); } /* Stub to do nothing at all; used for delays and unimplemented calls */ @@ -234,6 +255,18 @@ static void vmi_nop(void) { } +/* For NO_IDLE_HZ, we stop the clock when halting the kernel */ +static fastcall void vmi_safe_halt(void) +{ + int idle = vmi_stop_hz_timer(); + vmi_ops.halt(); + if (idle) { + local_irq_disable(); + vmi_account_time_restart_hz_timer(); + local_irq_enable(); + } +} + #ifdef CONFIG_DEBUG_PAGE_TYPE #ifdef CONFIG_X86_PAE @@ -337,11 +370,8 @@ static void vmi_check_page_type(u32 pfn, int type) #define vmi_check_page_type(p,t) do { } while (0) #endif -#ifdef CONFIG_HIGHPTE -static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) +static void vmi_map_pt_hook(int type, pte_t *va, u32 pfn) { - void *va = kmap_atomic(page, type); - /* * Internally, the VMI ROM must map virtual addresses to physical * addresses for processing MMU updates. By the time MMU updates @@ -355,11 +385,8 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) * args: SLOT VA COUNT PFN */ BUG_ON(type != KM_PTE0 && type != KM_PTE1); - vmi_ops.set_linear_mapping((type - KM_PTE0)+1, va, 1, page_to_pfn(page)); - - return va; + vmi_ops.set_linear_mapping((type - KM_PTE0)+1, (u32)va, 1, pfn); } -#endif static void vmi_allocate_pt(u32 pfn) { @@ -416,13 +443,13 @@ static void vmi_release_pd(u32 pfn) ((level) | (is_current_as(mm, user) ? \ (VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0)) -static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +static void vmi_update_pte(struct mm_struct *mm, u32 addr, pte_t *ptep) { vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } -static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +static void vmi_update_pte_defer(struct mm_struct *mm, u32 addr, pte_t *ptep) { vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0)); @@ -435,7 +462,7 @@ static void vmi_set_pte(pte_t *ptep, pte_t pte) vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT); } -static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) +static void vmi_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) { vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); @@ -489,7 +516,7 @@ static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } -static void vmi_pmd_clear(pmd_t *pmd) +void vmi_pmd_clear(pmd_t *pmd) { const pte_t pte = { 0 }; vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD); @@ -498,6 +525,8 @@ static void vmi_pmd_clear(pmd_t *pmd) #endif #ifdef CONFIG_SMP +extern void setup_pda(void); + static void __devinit vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, unsigned long start_esp) @@ -522,11 +551,13 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, ap.ds = __USER_DS; ap.es = __USER_DS; - ap.fs = __KERNEL_PERCPU; + ap.fs = __KERNEL_PDA; ap.gs = 0; ap.eflags = 0; + setup_pda(); + #ifdef CONFIG_X86_PAE /* efer should match BSP efer. */ if (cpu_has_nx) { @@ -544,9 +575,9 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, } #endif -static void vmi_set_lazy_mode(enum paravirt_lazy_mode mode) +static void vmi_set_lazy_mode(int mode) { - static DEFINE_PER_CPU(enum paravirt_lazy_mode, lazy_mode); + static DEFINE_PER_CPU(int, lazy_mode); if (!vmi_ops.set_lazy_mode) return; @@ -654,7 +685,7 @@ void vmi_bringup(void) { /* We must establish the lowmem mapping for MMU ops to work */ if (vmi_ops.set_linear_mapping) - vmi_ops.set_linear_mapping(0, (void *)__PAGE_OFFSET, max_low_pfn, 0); + vmi_ops.set_linear_mapping(0, __PAGE_OFFSET, max_low_pfn, 0); } /* @@ -709,6 +740,7 @@ do { \ } \ } while (0) + /* * Activate the VMI interface and switch into paravirtualized mode */ @@ -764,6 +796,12 @@ static inline int __init activate_vmi(void) para_fill(irq_disable, DisableInterrupts); para_fill(irq_enable, EnableInterrupts); + /* irq_save_disable !!! sheer pain */ + patch_offset(&irq_save_disable_callout[IRQ_PATCH_INT_MASK], + (char *)paravirt_ops.save_fl); + patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE], + (char *)paravirt_ops.irq_disable); + para_fill(wbinvd, WBINVD); para_fill(read_tsc, RDTSC); @@ -793,8 +831,8 @@ static inline int __init activate_vmi(void) para_wrap(set_lazy_mode, vmi_set_lazy_mode, set_lazy_mode, SetLazyMode); /* user and kernel flush are just handled with different flags to FlushTLB */ - para_wrap(flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB); - para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB); + para_wrap(flush_tlb_user, vmi_flush_tlb_user, flush_tlb, FlushTLB); + para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, flush_tlb, FlushTLB); para_fill(flush_tlb_single, InvalPage); /* @@ -840,13 +878,8 @@ static inline int __init activate_vmi(void) paravirt_ops.release_pt = vmi_release_pt; paravirt_ops.release_pd = vmi_release_pd; } - - /* Set linear is needed in all cases */ - vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping); -#ifdef CONFIG_HIGHPTE - if (vmi_ops.set_linear_mapping) - paravirt_ops.kmap_atomic_pte = vmi_kmap_atomic_pte; -#endif + para_wrap(map_pt_hook, vmi_map_pt_hook, set_linear_mapping, + SetLinearMapping); /* * These MUST always be patched. Don't support indirect jumps @@ -887,8 +920,8 @@ static inline int __init activate_vmi(void) paravirt_ops.get_wallclock = vmi_get_wallclock; paravirt_ops.set_wallclock = vmi_set_wallclock; #ifdef CONFIG_X86_LOCAL_APIC - paravirt_ops.setup_boot_clock = vmi_time_bsp_init; - paravirt_ops.setup_secondary_clock = vmi_time_ap_init; + paravirt_ops.setup_boot_clock = vmi_timer_setup_boot_alarm; + paravirt_ops.setup_secondary_clock = vmi_timer_setup_secondary_alarm; #endif paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles; paravirt_ops.get_cpu_khz = vmi_cpu_khz; @@ -900,7 +933,11 @@ static inline int __init activate_vmi(void) disable_vmi_timer = 1; } - para_fill(safe_halt, Halt); + /* No idle HZ mode only works if VMI timer and no idle is enabled */ + if (disable_noidle || disable_vmi_timer) + para_fill(safe_halt, Halt); + else + para_wrap(safe_halt, vmi_safe_halt, halt, Halt); /* * Alternative instruction rewriting doesn't happen soon enough @@ -908,7 +945,7 @@ static inline int __init activate_vmi(void) * to do this before IRQs get reenabled. Fortunately, it is * idempotent. */ - apply_paravirt(__parainstructions, __parainstructions_end); + apply_paravirt(__start_parainstructions, __stop_parainstructions); vmi_bringup(); diff --git a/trunk/arch/i386/kernel/vmiclock.c b/trunk/arch/i386/kernel/vmiclock.c deleted file mode 100644 index 26a37f8a8762..000000000000 --- a/trunk/arch/i386/kernel/vmiclock.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * VMI paravirtual timer support routines. - * - * Copyright (C) 2007, VMware, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "io_ports.h" - -#define VMI_ONESHOT (VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL | vmi_get_alarm_wiring()) -#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring()) - -static DEFINE_PER_CPU(struct clock_event_device, local_events); - -static inline u32 vmi_counter(u32 flags) -{ - /* Given VMI_ONESHOT or VMI_PERIODIC, return the corresponding - * cycle counter. */ - return flags & VMI_ALARM_COUNTER_MASK; -} - -/* paravirt_ops.get_wallclock = vmi_get_wallclock */ -unsigned long vmi_get_wallclock(void) -{ - unsigned long long wallclock; - wallclock = vmi_timer_ops.get_wallclock(); // nsec - (void)do_div(wallclock, 1000000000); // sec - - return wallclock; -} - -/* paravirt_ops.set_wallclock = vmi_set_wallclock */ -int vmi_set_wallclock(unsigned long now) -{ - return 0; -} - -/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */ -unsigned long long vmi_get_sched_cycles(void) -{ - return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE); -} - -/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */ -unsigned long vmi_cpu_khz(void) -{ - unsigned long long khz; - khz = vmi_timer_ops.get_cycle_frequency(); - (void)do_div(khz, 1000); - return khz; -} - -static inline unsigned int vmi_get_timer_vector(void) -{ -#ifdef CONFIG_X86_IO_APIC - return FIRST_DEVICE_VECTOR; -#else - return FIRST_EXTERNAL_VECTOR; -#endif -} - -/** vmi clockchip */ -#ifdef CONFIG_X86_LOCAL_APIC -static unsigned int startup_timer_irq(unsigned int irq) -{ - unsigned long val = apic_read(APIC_LVTT); - apic_write(APIC_LVTT, vmi_get_timer_vector()); - - return (val & APIC_SEND_PENDING); -} - -static void mask_timer_irq(unsigned int irq) -{ - unsigned long val = apic_read(APIC_LVTT); - apic_write(APIC_LVTT, val | APIC_LVT_MASKED); -} - -static void unmask_timer_irq(unsigned int irq) -{ - unsigned long val = apic_read(APIC_LVTT); - apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED); -} - -static void ack_timer_irq(unsigned int irq) -{ - ack_APIC_irq(); -} - -static struct irq_chip vmi_chip __read_mostly = { - .name = "VMI-LOCAL", - .startup = startup_timer_irq, - .mask = mask_timer_irq, - .unmask = unmask_timer_irq, - .ack = ack_timer_irq -}; -#endif - -/** vmi clockevent */ -#define VMI_ALARM_WIRED_IRQ0 0x00000000 -#define VMI_ALARM_WIRED_LVTT 0x00010000 -static int vmi_wiring = VMI_ALARM_WIRED_IRQ0; - -static inline int vmi_get_alarm_wiring(void) -{ - return vmi_wiring; -} - -static void vmi_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - cycle_t now, cycles_per_hz; - BUG_ON(!irqs_disabled()); - - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - break; - case CLOCK_EVT_MODE_PERIODIC: - cycles_per_hz = vmi_timer_ops.get_cycle_frequency(); - (void)do_div(cycles_per_hz, HZ); - now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC)); - vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - switch (evt->mode) { - case CLOCK_EVT_MODE_ONESHOT: - vmi_timer_ops.cancel_alarm(VMI_ONESHOT); - break; - case CLOCK_EVT_MODE_PERIODIC: - vmi_timer_ops.cancel_alarm(VMI_PERIODIC); - break; - default: - break; - } - break; - default: - break; - } -} - -static int vmi_timer_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - /* Unfortunately, set_next_event interface only passes relative - * expiry, but we want absolute expiry. It'd be better if were - * were passed an aboslute expiry, since a bunch of time may - * have been stolen between the time the delta is computed and - * when we set the alarm below. */ - cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT)); - - BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT); - vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0); - return 0; -} - -static struct clock_event_device vmi_clockevent = { - .name = "vmi-timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .shift = 22, - .set_mode = vmi_timer_set_mode, - .set_next_event = vmi_timer_next_event, - .rating = 1000, - .irq = 0, -}; - -static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &__get_cpu_var(local_events); - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static struct irqaction vmi_clock_action = { - .name = "vmi-timer", - .handler = vmi_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING, - .mask = CPU_MASK_ALL, -}; - -static void __devinit vmi_time_init_clockevent(void) -{ - cycle_t cycles_per_msec; - struct clock_event_device *evt; - - int cpu = smp_processor_id(); - evt = &__get_cpu_var(local_events); - - /* Use cycles_per_msec since div_sc params are 32-bits. */ - cycles_per_msec = vmi_timer_ops.get_cycle_frequency(); - (void)do_div(cycles_per_msec, 1000); - - memcpy(evt, &vmi_clockevent, sizeof(*evt)); - /* Must pick .shift such that .mult fits in 32-bits. Choosing - * .shift to be 22 allows 2^(32-22) cycles per nano-seconds - * before overflow. */ - evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift); - /* Upper bound is clockevent's use of ulong for cycle deltas. */ - evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt); - evt->min_delta_ns = clockevent_delta2ns(1, evt); - evt->cpumask = cpumask_of_cpu(cpu); - - printk(KERN_WARNING "vmi: registering clock event %s. mult=%lu shift=%u\n", - evt->name, evt->mult, evt->shift); - clockevents_register_device(evt); -} - -void __init vmi_time_init(void) -{ - /* Disable PIT: BIOSes start PIT CH0 with 18.2hz peridic. */ - outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */ - - vmi_time_init_clockevent(); - setup_irq(0, &vmi_clock_action); -} - -#ifdef CONFIG_X86_LOCAL_APIC -void __devinit vmi_time_bsp_init(void) -{ - /* - * On APIC systems, we want local timers to fire on each cpu. We do - * this by programming LVTT to deliver timer events to the IRQ handler - * for IRQ-0, since we can't re-use the APIC local timer handler - * without interfering with that code. - */ - clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); - local_irq_disable(); -#ifdef CONFIG_X86_SMP - /* - * XXX handle_percpu_irq only defined for SMP; we need to switch over - * to using it, since this is a local interrupt, which each CPU must - * handle individually without locking out or dropping simultaneous - * local timers on other CPUs. We also don't want to trigger the - * quirk workaround code for interrupts which gets invoked from - * handle_percpu_irq via eoi, so we use our own IRQ chip. - */ - set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt"); -#else - set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt"); -#endif - vmi_wiring = VMI_ALARM_WIRED_LVTT; - apic_write(APIC_LVTT, vmi_get_timer_vector()); - local_irq_enable(); - clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); -} - -void __devinit vmi_time_ap_init(void) -{ - vmi_time_init_clockevent(); - apic_write(APIC_LVTT, vmi_get_timer_vector()); -} -#endif - -/** vmi clocksource */ - -static cycle_t read_real_cycles(void) -{ - return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL); -} - -static struct clocksource clocksource_vmi = { - .name = "vmi-timer", - .rating = 450, - .read = read_real_cycles, - .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /* to be set */ - .shift = 22, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init init_vmi_clocksource(void) -{ - cycle_t cycles_per_msec; - - if (!vmi_timer_ops.get_cycle_frequency) - return 0; - /* Use khz2mult rather than hz2mult since hz arg is only 32-bits. */ - cycles_per_msec = vmi_timer_ops.get_cycle_frequency(); - (void)do_div(cycles_per_msec, 1000); - - /* Note that clocksource.{mult, shift} converts in the opposite direction - * as clockevents. */ - clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec, - clocksource_vmi.shift); - - printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec); - return clocksource_register(&clocksource_vmi); - -} -module_init(init_vmi_clocksource); diff --git a/trunk/arch/i386/kernel/vmitime.c b/trunk/arch/i386/kernel/vmitime.c new file mode 100644 index 000000000000..9dfb17739b67 --- /dev/null +++ b/trunk/arch/i386/kernel/vmitime.c @@ -0,0 +1,482 @@ +/* + * VMI paravirtual timer support routines. + * + * Copyright (C) 2005, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to dhecht@vmware.com + * + */ + +/* + * Portions of this code from arch/i386/kernel/timers/timer_tsc.c. + * Portions of the CONFIG_NO_IDLE_HZ code from arch/s390/kernel/time.c. + * See comments there for proper credits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef CONFIG_X86_LOCAL_APIC +#define VMI_ALARM_WIRING VMI_ALARM_WIRED_LVTT +#else +#define VMI_ALARM_WIRING VMI_ALARM_WIRED_IRQ0 +#endif + +/* Cached VMI operations */ +struct vmi_timer_ops vmi_timer_ops; + +#ifdef CONFIG_NO_IDLE_HZ + +/* /proc/sys/kernel/hz_timer state. */ +int sysctl_hz_timer; + +/* Some stats */ +static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_irqs); +static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_jiffies); +static DEFINE_PER_CPU(unsigned long, idle_start_jiffies); + +#endif /* CONFIG_NO_IDLE_HZ */ + +/* Number of alarms per second. By default this is CONFIG_VMI_ALARM_HZ. */ +static int alarm_hz = CONFIG_VMI_ALARM_HZ; + +/* Cache of the value get_cycle_frequency / HZ. */ +static signed long long cycles_per_jiffy; + +/* Cache of the value get_cycle_frequency / alarm_hz. */ +static signed long long cycles_per_alarm; + +/* The number of cycles accounted for by the 'jiffies'/'xtime' count. + * Protected by xtime_lock. */ +static unsigned long long real_cycles_accounted_system; + +/* The number of cycles accounted for by update_process_times(), per cpu. */ +static DEFINE_PER_CPU(unsigned long long, process_times_cycles_accounted_cpu); + +/* The number of stolen cycles accounted, per cpu. */ +static DEFINE_PER_CPU(unsigned long long, stolen_cycles_accounted_cpu); + +/* Clock source. */ +static cycle_t read_real_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL); +} + +static cycle_t read_available_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE); +} + +#if 0 +static cycle_t read_stolen_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_STOLEN); +} +#endif /* 0 */ + +static struct clocksource clocksource_vmi = { + .name = "vmi-timer", + .rating = 450, + .read = read_real_cycles, + .mask = CLOCKSOURCE_MASK(64), + .mult = 0, /* to be set */ + .shift = 22, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + + +/* Timer interrupt handler. */ +static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id); + +static struct irqaction vmi_timer_irq = { + .handler = vmi_timer_interrupt, + .flags = IRQF_DISABLED, + .mask = CPU_MASK_NONE, + .name = "VMI-alarm", +}; + +/* Alarm rate */ +static int __init vmi_timer_alarm_rate_setup(char* str) +{ + int alarm_rate; + if (get_option(&str, &alarm_rate) == 1 && alarm_rate > 0) { + alarm_hz = alarm_rate; + printk(KERN_WARNING "VMI timer alarm HZ set to %d\n", alarm_hz); + } + return 1; +} +__setup("vmi_timer_alarm_hz=", vmi_timer_alarm_rate_setup); + + +/* Initialization */ +static void vmi_get_wallclock_ts(struct timespec *ts) +{ + unsigned long long wallclock; + wallclock = vmi_timer_ops.get_wallclock(); // nsec units + ts->tv_nsec = do_div(wallclock, 1000000000); + ts->tv_sec = wallclock; +} + +unsigned long vmi_get_wallclock(void) +{ + struct timespec ts; + vmi_get_wallclock_ts(&ts); + return ts.tv_sec; +} + +int vmi_set_wallclock(unsigned long now) +{ + return -1; +} + +unsigned long long vmi_get_sched_cycles(void) +{ + return read_available_cycles(); +} + +unsigned long vmi_cpu_khz(void) +{ + unsigned long long khz; + + khz = vmi_timer_ops.get_cycle_frequency(); + (void)do_div(khz, 1000); + return khz; +} + +void __init vmi_time_init(void) +{ + unsigned long long cycles_per_sec, cycles_per_msec; + unsigned long flags; + + local_irq_save(flags); + setup_irq(0, &vmi_timer_irq); +#ifdef CONFIG_X86_LOCAL_APIC + set_intr_gate(LOCAL_TIMER_VECTOR, apic_vmi_timer_interrupt); +#endif + + real_cycles_accounted_system = read_real_cycles(); + per_cpu(process_times_cycles_accounted_cpu, 0) = read_available_cycles(); + + cycles_per_sec = vmi_timer_ops.get_cycle_frequency(); + cycles_per_jiffy = cycles_per_sec; + (void)do_div(cycles_per_jiffy, HZ); + cycles_per_alarm = cycles_per_sec; + (void)do_div(cycles_per_alarm, alarm_hz); + cycles_per_msec = cycles_per_sec; + (void)do_div(cycles_per_msec, 1000); + + printk(KERN_WARNING "VMI timer cycles/sec = %llu ; cycles/jiffy = %llu ;" + "cycles/alarm = %llu\n", cycles_per_sec, cycles_per_jiffy, + cycles_per_alarm); + + clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec, + clocksource_vmi.shift); + if (clocksource_register(&clocksource_vmi)) + printk(KERN_WARNING "Error registering VMITIME clocksource."); + + /* Disable PIT. */ + outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */ + + /* schedule the alarm. do this in phase with process_times_cycles_accounted_cpu + * reduce the latency calling update_process_times. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_IRQ0 | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm, + cycles_per_alarm); + + local_irq_restore(flags); +} + +#ifdef CONFIG_X86_LOCAL_APIC + +void __init vmi_timer_setup_boot_alarm(void) +{ + local_irq_disable(); + + /* Route the interrupt to the correct vector. */ + apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR); + + /* Cancel the IRQ0 wired alarm, and setup the LVTT alarm. */ + vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE); + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm, + cycles_per_alarm); + local_irq_enable(); +} + +/* Initialize the time accounting variables for an AP on an SMP system. + * Also, set the local alarm for the AP. */ +void __devinit vmi_timer_setup_secondary_alarm(void) +{ + int cpu = smp_processor_id(); + + /* Route the interrupt to the correct vector. */ + apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR); + + per_cpu(process_times_cycles_accounted_cpu, cpu) = read_available_cycles(); + + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm, + cycles_per_alarm); +} + +#endif + +/* Update system wide (real) time accounting (e.g. jiffies, xtime). */ +static void vmi_account_real_cycles(unsigned long long cur_real_cycles) +{ + long long cycles_not_accounted; + + write_seqlock(&xtime_lock); + + cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system; + while (cycles_not_accounted >= cycles_per_jiffy) { + /* systems wide jiffies. */ + do_timer(1); + + cycles_not_accounted -= cycles_per_jiffy; + real_cycles_accounted_system += cycles_per_jiffy; + } + + write_sequnlock(&xtime_lock); +} + +/* Update per-cpu process times. */ +static void vmi_account_process_times_cycles(struct pt_regs *regs, int cpu, + unsigned long long cur_process_times_cycles) +{ + long long cycles_not_accounted; + cycles_not_accounted = cur_process_times_cycles - + per_cpu(process_times_cycles_accounted_cpu, cpu); + + while (cycles_not_accounted >= cycles_per_jiffy) { + /* Account time to the current process. This includes + * calling into the scheduler to decrement the timeslice + * and possibly reschedule.*/ + update_process_times(user_mode(regs)); + /* XXX handle /proc/profile multiplier. */ + profile_tick(CPU_PROFILING); + + cycles_not_accounted -= cycles_per_jiffy; + per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } +} + +#ifdef CONFIG_NO_IDLE_HZ +/* Update per-cpu idle times. Used when a no-hz halt is ended. */ +static void vmi_account_no_hz_idle_cycles(int cpu, + unsigned long long cur_process_times_cycles) +{ + long long cycles_not_accounted; + unsigned long no_idle_hz_jiffies = 0; + + cycles_not_accounted = cur_process_times_cycles - + per_cpu(process_times_cycles_accounted_cpu, cpu); + + while (cycles_not_accounted >= cycles_per_jiffy) { + no_idle_hz_jiffies++; + cycles_not_accounted -= cycles_per_jiffy; + per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } + /* Account time to the idle process. */ + account_steal_time(idle_task(cpu), jiffies_to_cputime(no_idle_hz_jiffies)); +} +#endif + +/* Update per-cpu stolen time. */ +static void vmi_account_stolen_cycles(int cpu, + unsigned long long cur_real_cycles, + unsigned long long cur_avail_cycles) +{ + long long stolen_cycles_not_accounted; + unsigned long stolen_jiffies = 0; + + if (cur_real_cycles < cur_avail_cycles) + return; + + stolen_cycles_not_accounted = cur_real_cycles - cur_avail_cycles - + per_cpu(stolen_cycles_accounted_cpu, cpu); + + while (stolen_cycles_not_accounted >= cycles_per_jiffy) { + stolen_jiffies++; + stolen_cycles_not_accounted -= cycles_per_jiffy; + per_cpu(stolen_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } + /* HACK: pass NULL to force time onto cpustat->steal. */ + account_steal_time(NULL, jiffies_to_cputime(stolen_jiffies)); +} + +/* Body of either IRQ0 interrupt handler (UP no local-APIC) or + * local-APIC LVTT interrupt handler (UP & local-APIC or SMP). */ +static void vmi_local_timer_interrupt(int cpu) +{ + unsigned long long cur_real_cycles, cur_process_times_cycles; + + cur_real_cycles = read_real_cycles(); + cur_process_times_cycles = read_available_cycles(); + /* Update system wide (real) time state (xtime, jiffies). */ + vmi_account_real_cycles(cur_real_cycles); + /* Update per-cpu process times. */ + vmi_account_process_times_cycles(get_irq_regs(), cpu, cur_process_times_cycles); + /* Update time stolen from this cpu by the hypervisor. */ + vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles); +} + +#ifdef CONFIG_NO_IDLE_HZ + +/* Must be called only from idle loop, with interrupts disabled. */ +int vmi_stop_hz_timer(void) +{ + /* Note that cpu_set, cpu_clear are (SMP safe) atomic on x86. */ + + unsigned long seq, next; + unsigned long long real_cycles_expiry; + int cpu = smp_processor_id(); + + BUG_ON(!irqs_disabled()); + if (sysctl_hz_timer != 0) + return 0; + + cpu_set(cpu, nohz_cpu_mask); + smp_mb(); + + if (rcu_needs_cpu(cpu) || local_softirq_pending() || + (next = next_timer_interrupt(), + time_before_eq(next, jiffies + HZ/CONFIG_VMI_ALARM_HZ))) { + cpu_clear(cpu, nohz_cpu_mask); + return 0; + } + + /* Convert jiffies to the real cycle counter. */ + do { + seq = read_seqbegin(&xtime_lock); + real_cycles_expiry = real_cycles_accounted_system + + (long)(next - jiffies) * cycles_per_jiffy; + } while (read_seqretry(&xtime_lock, seq)); + + /* This cpu is going idle. Disable the periodic alarm. */ + vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE); + per_cpu(idle_start_jiffies, cpu) = jiffies; + /* Set the real time alarm to expire at the next event. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL, + real_cycles_expiry, 0); + return 1; +} + +static void vmi_reenable_hz_timer(int cpu) +{ + /* For /proc/vmi/info idle_hz stat. */ + per_cpu(vmi_idle_no_hz_jiffies, cpu) += jiffies - per_cpu(idle_start_jiffies, cpu); + per_cpu(vmi_idle_no_hz_irqs, cpu)++; + + /* Don't bother explicitly cancelling the one-shot alarm -- at + * worse we will receive a spurious timer interrupt. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRING | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm, + cycles_per_alarm); + /* Indicate this cpu is no longer nohz idle. */ + cpu_clear(cpu, nohz_cpu_mask); +} + +/* Called from interrupt handlers when (local) HZ timer is disabled. */ +void vmi_account_time_restart_hz_timer(void) +{ + unsigned long long cur_real_cycles, cur_process_times_cycles; + int cpu = smp_processor_id(); + + BUG_ON(!irqs_disabled()); + /* Account the time during which the HZ timer was disabled. */ + cur_real_cycles = read_real_cycles(); + cur_process_times_cycles = read_available_cycles(); + /* Update system wide (real) time state (xtime, jiffies). */ + vmi_account_real_cycles(cur_real_cycles); + /* Update per-cpu idle times. */ + vmi_account_no_hz_idle_cycles(cpu, cur_process_times_cycles); + /* Update time stolen from this cpu by the hypervisor. */ + vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles); + /* Reenable the hz timer. */ + vmi_reenable_hz_timer(cpu); +} + +#endif /* CONFIG_NO_IDLE_HZ */ + +/* UP (and no local-APIC) VMI-timer alarm interrupt handler. + * Handler for IRQ0. Not used when SMP or X86_LOCAL_APIC after + * APIC setup and setup_boot_vmi_alarm() is called. */ +static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id) +{ + vmi_local_timer_interrupt(smp_processor_id()); + return IRQ_HANDLED; +} + +#ifdef CONFIG_X86_LOCAL_APIC + +/* SMP VMI-timer alarm interrupt handler. Handler for LVTT vector. + * Also used in UP when CONFIG_X86_LOCAL_APIC. + * The wrapper code is from arch/i386/kernel/apic.c#smp_apic_timer_interrupt. */ +void smp_apic_vmi_timer_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + int cpu = smp_processor_id(); + + /* + * the NMI deadlock-detector uses this. + */ + per_cpu(irq_stat,cpu).apic_timer_irqs++; + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + + /* + * update_process_times() expects us to have done irq_enter(). + * Besides, if we don't timer interrupts ignore the global + * interrupt lock, which is the WrongThing (tm) to do. + */ + irq_enter(); + vmi_local_timer_interrupt(cpu); + irq_exit(); + set_irq_regs(old_regs); +} + +#endif /* CONFIG_X86_LOCAL_APIC */ diff --git a/trunk/arch/i386/kernel/vmlinux.lds.S b/trunk/arch/i386/kernel/vmlinux.lds.S index 23e8614edeee..6f38f818380b 100644 --- a/trunk/arch/i386/kernel/vmlinux.lds.S +++ b/trunk/arch/i386/kernel/vmlinux.lds.S @@ -26,11 +26,12 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(phys_startup_32) jiffies = jiffies_64; +_proxy_pda = 1; PHDRS { text PT_LOAD FLAGS(5); /* R_E */ data PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(0); /* ___ */ + note PT_NOTE FLAGS(4); /* R__ */ } SECTIONS { @@ -60,6 +61,8 @@ SECTIONS __stop___ex_table = .; } + RODATA + BUG_TABLE . = ALIGN(4); @@ -69,8 +72,6 @@ SECTIONS __tracedata_end = .; } - RODATA - /* writeable */ . = ALIGN(4096); .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ @@ -116,11 +117,22 @@ SECTIONS /* might get freed after init */ . = ALIGN(4096); + .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) { + __smp_alt_begin = .; + __smp_alt_instructions = .; + *(.smp_altinstructions) + __smp_alt_instructions_end = .; + } + . = ALIGN(4); .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { __smp_locks = .; *(.smp_locks) __smp_locks_end = .; } + .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) { + *(.smp_altinstr_replacement) + __smp_alt_end = .; + } /* will be freed after init * Following ALIGN() is required to make sure no other data falls on the * same page where __smp_alt_end is pointing as that page might be freed @@ -166,9 +178,9 @@ SECTIONS } . = ALIGN(4); .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __parainstructions = .; + __start_parainstructions = .; *(.parainstructions) - __parainstructions_end = .; + __stop_parainstructions = .; } /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ @@ -182,7 +194,7 @@ SECTIONS __initramfs_end = .; } #endif - . = ALIGN(4096); + . = ALIGN(L1_CACHE_BYTES); .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { __per_cpu_start = .; *(.data.percpu) diff --git a/trunk/arch/i386/kernel/vsyscall.lds.S b/trunk/arch/i386/kernel/vsyscall.lds.S index 4a8b0ed9b8fb..f66cd11adb72 100644 --- a/trunk/arch/i386/kernel/vsyscall.lds.S +++ b/trunk/arch/i386/kernel/vsyscall.lds.S @@ -7,7 +7,7 @@ SECTIONS { - . = VDSO_PRELINK_asm + SIZEOF_HEADERS; + . = VDSO_PRELINK + SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } @@ -21,7 +21,7 @@ SECTIONS For the layouts to match, we need to skip more than enough space for the dynamic symbol table et al. If this amount is insufficient, ld -shared will barf. Just increase it here. */ - . = VDSO_PRELINK_asm + 0x400; + . = VDSO_PRELINK + 0x400; .text : { *(.text) } :text =0x90909090 .note : { *(.note.*) } :text :note diff --git a/trunk/arch/i386/lib/bitops.c b/trunk/arch/i386/lib/bitops.c index afd0045595d4..97db3853dc82 100644 --- a/trunk/arch/i386/lib/bitops.c +++ b/trunk/arch/i386/lib/bitops.c @@ -43,7 +43,7 @@ EXPORT_SYMBOL(find_next_bit); */ int find_next_zero_bit(const unsigned long *addr, int size, int offset) { - const unsigned long *p = addr + (offset >> 5); + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); int set = 0, bit = offset & 31, res; if (bit) { @@ -64,7 +64,7 @@ int find_next_zero_bit(const unsigned long *addr, int size, int offset) /* * No zero yet, search remaining full bytes for a zero */ - res = find_first_zero_bit(p, size - 32 * (p - addr)); + res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); return (offset + set + res); } EXPORT_SYMBOL(find_next_zero_bit); diff --git a/trunk/arch/i386/lib/checksum.S b/trunk/arch/i386/lib/checksum.S index adbccd0bbb78..75ffd02654fc 100644 --- a/trunk/arch/i386/lib/checksum.S +++ b/trunk/arch/i386/lib/checksum.S @@ -25,8 +25,6 @@ * 2 of the License, or (at your option) any later version. */ -#include -#include #include /* @@ -38,6 +36,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) */ .text +.align 4 +.globl csum_partial #ifndef CONFIG_X86_USE_PPRO_CHECKSUM @@ -48,14 +48,9 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) * Fortunately, it is easy to convert 2-byte alignment to 4-byte * alignment for the unrolled loop. */ -ENTRY(csum_partial) - CFI_STARTPROC +csum_partial: pushl %esi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET esi, 0 pushl %ebx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebx, 0 movl 20(%esp),%eax # Function arg: unsigned int sum movl 16(%esp),%ecx # Function arg: int len movl 12(%esp),%esi # Function arg: unsigned char *buff @@ -133,27 +128,16 @@ ENTRY(csum_partial) roll $8, %eax 8: popl %ebx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ebx popl %esi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE esi ret - CFI_ENDPROC -ENDPROC(csum_partial) #else /* Version for PentiumII/PPro */ -ENTRY(csum_partial) - CFI_STARTPROC +csum_partial: pushl %esi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET esi, 0 pushl %ebx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebx, 0 movl 20(%esp),%eax # Function arg: unsigned int sum movl 16(%esp),%ecx # Function arg: int len movl 12(%esp),%esi # Function arg: const unsigned char *buf @@ -261,14 +245,8 @@ ENTRY(csum_partial) roll $8, %eax 90: popl %ebx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ebx popl %esi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE esi ret - CFI_ENDPROC -ENDPROC(csum_partial) #endif @@ -300,24 +278,19 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, .long 9999b, 6002f ; \ .previous +.align 4 +.globl csum_partial_copy_generic + #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -ENTRY(csum_partial_copy_generic) - CFI_STARTPROC +csum_partial_copy_generic: subl $4,%esp - CFI_ADJUST_CFA_OFFSET 4 pushl %edi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edi, 0 pushl %esi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET esi, 0 pushl %ebx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebx, 0 movl ARGBASE+16(%esp),%eax # sum movl ARGBASE+12(%esp),%ecx # len movl ARGBASE+4(%esp),%esi # src @@ -427,19 +400,10 @@ DST( movb %cl, (%edi) ) .previous popl %ebx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ebx popl %esi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE esi popl %edi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edi popl %ecx # equivalent to addl $4,%esp - CFI_ADJUST_CFA_OFFSET -4 ret - CFI_ENDPROC -ENDPROC(csum_partial_copy_generic) #else @@ -457,17 +421,10 @@ ENDPROC(csum_partial_copy_generic) #define ARGBASE 12 -ENTRY(csum_partial_copy_generic) - CFI_STARTPROC +csum_partial_copy_generic: pushl %ebx - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET ebx, 0 pushl %edi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET edi, 0 pushl %esi - CFI_ADJUST_CFA_OFFSET 4 - CFI_REL_OFFSET esi, 0 movl ARGBASE+4(%esp),%esi #src movl ARGBASE+8(%esp),%edi #dst movl ARGBASE+12(%esp),%ecx #len @@ -528,17 +485,9 @@ DST( movb %dl, (%edi) ) .previous popl %esi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE esi popl %edi - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE edi popl %ebx - CFI_ADJUST_CFA_OFFSET -4 - CFI_RESTORE ebx ret - CFI_ENDPROC -ENDPROC(csum_partial_copy_generic) #undef ROUND #undef ROUND1 diff --git a/trunk/arch/i386/lib/getuser.S b/trunk/arch/i386/lib/getuser.S index 6d84b53f12a2..62d7f178a326 100644 --- a/trunk/arch/i386/lib/getuser.S +++ b/trunk/arch/i386/lib/getuser.S @@ -8,8 +8,6 @@ * return an error value in addition to the "real" * return value. */ -#include -#include #include @@ -26,19 +24,19 @@ */ .text -ENTRY(__get_user_1) - CFI_STARTPROC +.align 4 +.globl __get_user_1 +__get_user_1: GET_THREAD_INFO(%edx) cmpl TI_addr_limit(%edx),%eax jae bad_get_user 1: movzbl (%eax),%edx xorl %eax,%eax ret - CFI_ENDPROC -ENDPROC(__get_user_1) -ENTRY(__get_user_2) - CFI_STARTPROC +.align 4 +.globl __get_user_2 +__get_user_2: addl $1,%eax jc bad_get_user GET_THREAD_INFO(%edx) @@ -47,11 +45,10 @@ ENTRY(__get_user_2) 2: movzwl -1(%eax),%edx xorl %eax,%eax ret - CFI_ENDPROC -ENDPROC(__get_user_2) -ENTRY(__get_user_4) - CFI_STARTPROC +.align 4 +.globl __get_user_4 +__get_user_4: addl $3,%eax jc bad_get_user GET_THREAD_INFO(%edx) @@ -60,16 +57,11 @@ ENTRY(__get_user_4) 3: movl -3(%eax),%edx xorl %eax,%eax ret - CFI_ENDPROC -ENDPROC(__get_user_4) bad_get_user: - CFI_STARTPROC xorl %edx,%edx movl $-14,%eax ret - CFI_ENDPROC -END(bad_get_user) .section __ex_table,"a" .long 1b,bad_get_user diff --git a/trunk/arch/i386/lib/putuser.S b/trunk/arch/i386/lib/putuser.S index f58fba109d18..a32d9f570f48 100644 --- a/trunk/arch/i386/lib/putuser.S +++ b/trunk/arch/i386/lib/putuser.S @@ -8,8 +8,6 @@ * return an error value in addition to the "real" * return value. */ -#include -#include #include @@ -25,28 +23,23 @@ * as they get called from within inline assembly. */ -#define ENTER CFI_STARTPROC ; \ - pushl %ebx ; \ - CFI_ADJUST_CFA_OFFSET 4 ; \ - CFI_REL_OFFSET ebx, 0 ; \ - GET_THREAD_INFO(%ebx) -#define EXIT popl %ebx ; \ - CFI_ADJUST_CFA_OFFSET -4 ; \ - CFI_RESTORE ebx ; \ - ret ; \ - CFI_ENDPROC +#define ENTER pushl %ebx ; GET_THREAD_INFO(%ebx) +#define EXIT popl %ebx ; ret .text -ENTRY(__put_user_1) +.align 4 +.globl __put_user_1 +__put_user_1: ENTER cmpl TI_addr_limit(%ebx),%ecx jae bad_put_user 1: movb %al,(%ecx) xorl %eax,%eax EXIT -ENDPROC(__put_user_1) -ENTRY(__put_user_2) +.align 4 +.globl __put_user_2 +__put_user_2: ENTER movl TI_addr_limit(%ebx),%ebx subl $1,%ebx @@ -55,9 +48,10 @@ ENTRY(__put_user_2) 2: movw %ax,(%ecx) xorl %eax,%eax EXIT -ENDPROC(__put_user_2) -ENTRY(__put_user_4) +.align 4 +.globl __put_user_4 +__put_user_4: ENTER movl TI_addr_limit(%ebx),%ebx subl $3,%ebx @@ -66,9 +60,10 @@ ENTRY(__put_user_4) 3: movl %eax,(%ecx) xorl %eax,%eax EXIT -ENDPROC(__put_user_4) -ENTRY(__put_user_8) +.align 4 +.globl __put_user_8 +__put_user_8: ENTER movl TI_addr_limit(%ebx),%ebx subl $7,%ebx @@ -78,16 +73,10 @@ ENTRY(__put_user_8) 5: movl %edx,4(%ecx) xorl %eax,%eax EXIT -ENDPROC(__put_user_8) bad_put_user: - CFI_STARTPROC simple - CFI_DEF_CFA esp, 2*4 - CFI_OFFSET eip, -1*4 - CFI_OFFSET ebx, -2*4 movl $-14,%eax EXIT -END(bad_put_user) .section __ex_table,"a" .long 1b,bad_put_user diff --git a/trunk/arch/i386/lib/usercopy.c b/trunk/arch/i386/lib/usercopy.c index 9f38b12b4af1..086b3726862a 100644 --- a/trunk/arch/i386/lib/usercopy.c +++ b/trunk/arch/i386/lib/usercopy.c @@ -716,6 +716,7 @@ do { \ unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n) { + BUG_ON((long) n < 0); #ifndef CONFIG_X86_WP_WORKS_OK if (unlikely(boot_cpu_data.wp_works_ok == 0) && ((unsigned long )to) < TASK_SIZE) { @@ -784,6 +785,7 @@ EXPORT_SYMBOL(__copy_to_user_ll); unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n) { + BUG_ON((long)n < 0); if (movsl_is_ok(to, from, n)) __copy_user_zeroing(to, from, n); else @@ -795,6 +797,7 @@ EXPORT_SYMBOL(__copy_from_user_ll); unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from, unsigned long n) { + BUG_ON((long)n < 0); if (movsl_is_ok(to, from, n)) __copy_user(to, from, n); else @@ -807,6 +810,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero); unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from, unsigned long n) { + BUG_ON((long)n < 0); #ifdef CONFIG_X86_INTEL_USERCOPY if ( n > 64 && cpu_has_xmm2) n = __copy_user_zeroing_intel_nocache(to, from, n); @@ -821,6 +825,7 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from, unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, unsigned long n) { + BUG_ON((long)n < 0); #ifdef CONFIG_X86_INTEL_USERCOPY if ( n > 64 && cpu_has_xmm2) n = __copy_user_intel_nocache(to, from, n); @@ -848,6 +853,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) { + BUG_ON((long) n < 0); if (access_ok(VERIFY_WRITE, to, n)) n = __copy_to_user(to, from, n); return n; @@ -873,6 +879,7 @@ EXPORT_SYMBOL(copy_to_user); unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) { + BUG_ON((long) n < 0); if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); else diff --git a/trunk/arch/i386/mach-generic/bigsmp.c b/trunk/arch/i386/mach-generic/bigsmp.c index e932d3485ae2..8a210fa915b5 100644 --- a/trunk/arch/i386/mach-generic/bigsmp.c +++ b/trunk/arch/i386/mach-generic/bigsmp.c @@ -45,7 +45,7 @@ static struct dmi_system_id __initdata bigsmp_dmi_table[] = { }; -static int __init probe_bigsmp(void) +static int probe_bigsmp(void) { if (def_to_bigsmp) dmi_bigsmp = 1; diff --git a/trunk/arch/i386/mach-generic/es7000.c b/trunk/arch/i386/mach-generic/es7000.c index b47f951c0ec2..b8963a5a3b25 100644 --- a/trunk/arch/i386/mach-generic/es7000.c +++ b/trunk/arch/i386/mach-generic/es7000.c @@ -25,45 +25,4 @@ static int probe_es7000(void) return 0; } -extern void es7000_sw_apic(void); -static void __init enable_apic_mode(void) -{ - es7000_sw_apic(); - return; -} - -static __init int mps_oem_check(struct mp_config_table *mpc, char *oem, - char *productid) -{ - if (mpc->mpc_oemptr) { - struct mp_config_oemtable *oem_table = - (struct mp_config_oemtable *)mpc->mpc_oemptr; - if (!strncmp(oem, "UNISYS", 6)) - return parse_unisys_oem((char *)oem_table); - } - return 0; -} - -#ifdef CONFIG_ACPI -/* Hook from generic ACPI tables.c */ -static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - unsigned long oem_addr; - if (!find_unisys_acpi_oem_table(&oem_addr)) { - if (es7000_check_dsdt()) - return parse_unisys_oem((char *)oem_addr); - else { - setup_unisys(); - return 1; - } - } - return 0; -} -#else -static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) -{ - return 0; -} -#endif - struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000); diff --git a/trunk/arch/i386/mach-voyager/setup.c b/trunk/arch/i386/mach-voyager/setup.c index 447bb105cf58..cfa16c151c8f 100644 --- a/trunk/arch/i386/mach-voyager/setup.c +++ b/trunk/arch/i386/mach-voyager/setup.c @@ -40,16 +40,10 @@ void __init trap_init_hook(void) { } -static struct irqaction irq0 = { - .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING, - .mask = CPU_MASK_NONE, - .name = "timer" -}; +static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL}; void __init time_init_hook(void) { - irq0.mask = cpumask_of_cpu(safe_smp_processor_id()); setup_irq(0, &irq0); } diff --git a/trunk/arch/i386/mach-voyager/voyager_cat.c b/trunk/arch/i386/mach-voyager/voyager_cat.c index 26a2d4c54b68..943a9473b138 100644 --- a/trunk/arch/i386/mach-voyager/voyager_cat.c +++ b/trunk/arch/i386/mach-voyager/voyager_cat.c @@ -1111,7 +1111,7 @@ voyager_cat_do_common_interrupt(void) printk(KERN_ERR "Voyager front panel switch turned off\n"); voyager_status.switch_off = 1; voyager_status.request_from_kernel = 1; - wake_up_process(voyager_thread); + up(&kvoyagerd_sem); } /* Tell the hardware we're taking care of the * shutdown, otherwise it will power the box off @@ -1157,7 +1157,7 @@ voyager_cat_do_common_interrupt(void) outb(VOYAGER_CAT_END, CAT_CMD); voyager_status.power_fail = 1; voyager_status.request_from_kernel = 1; - wake_up_process(voyager_thread); + up(&kvoyagerd_sem); } diff --git a/trunk/arch/i386/mach-voyager/voyager_smp.c b/trunk/arch/i386/mach-voyager/voyager_smp.c index 1a5e448a29c7..74aeedf277f4 100644 --- a/trunk/arch/i386/mach-voyager/voyager_smp.c +++ b/trunk/arch/i386/mach-voyager/voyager_smp.c @@ -536,6 +536,15 @@ do_boot_cpu(__u8 cpu) & ~( voyager_extended_vic_processors & voyager_allowed_boot_processors); + /* For the 486, we can't use the 4Mb page table trick, so + * must map a region of memory */ +#ifdef CONFIG_M486 + int i; + unsigned long *page_table_copies = (unsigned long *) + __get_free_page(GFP_KERNEL); +#endif + pgd_t orig_swapper_pg_dir0; + /* This is an area in head.S which was used to set up the * initial kernel stack. We need to alter this to give the * booting CPU a new stack (taken from its idle process) */ @@ -564,8 +573,6 @@ do_boot_cpu(__u8 cpu) hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF; cpucount++; - alternatives_smp_switch(1); - idle = fork_idle(cpu); if(IS_ERR(idle)) panic("failed fork for CPU%d", cpu); @@ -573,18 +580,39 @@ do_boot_cpu(__u8 cpu) /* init_tasks (in sched.c) is indexed logically */ stack_start.esp = (void *) idle->thread.esp; - init_gdt(cpu, idle); + /* Pre-allocate and initialize the CPU's GDT and PDA so it + doesn't have to do any memory allocation during the + delicate CPU-bringup phase. */ + if (!init_gdt(cpu, idle)) { + printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu); + cpucount--; + return; + } + irq_ctx_init(cpu); /* Note: Don't modify initial ss override */ VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, (unsigned long)hijack_source.val, hijack_source.idt.Segment, hijack_source.idt.Offset, stack_start.esp)); - - /* init lowmem identity mapping */ - clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); - flush_tlb_all(); + /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently + * (so that the booting CPU can find start_32 */ + orig_swapper_pg_dir0 = swapper_pg_dir[0]; +#ifdef CONFIG_M486 + if(page_table_copies == NULL) + panic("No free memory for 486 page tables\n"); + for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++) + page_table_copies[i] = (i * PAGE_SIZE) + | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; + + ((unsigned long *)swapper_pg_dir)[0] = + ((virt_to_phys(page_table_copies)) & PAGE_MASK) + | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; +#else + ((unsigned long *)swapper_pg_dir)[0] = + (virt_to_phys(pg0) & PAGE_MASK) + | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; +#endif if(quad_boot) { printk("CPU %d: non extended Quad boot\n", cpu); @@ -627,7 +655,11 @@ do_boot_cpu(__u8 cpu) udelay(100); } /* reset the page table */ - zap_low_mappings(); + swapper_pg_dir[0] = orig_swapper_pg_dir0; + local_flush_tlb(); +#ifdef CONFIG_M486 + free_page((unsigned long)page_table_copies); +#endif if (cpu_booted_map) { VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n", @@ -740,6 +772,12 @@ initialize_secondary(void) set_current(hard_get_current()); #endif + /* + * switch to the per CPU GDT we already set up + * in do_boot_cpu() + */ + cpu_set_gdt(current_thread_info()->cpu); + /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. @@ -1044,11 +1082,20 @@ smp_call_function_interrupt(void) } } -static int -__smp_call_function_mask (void (*func) (void *info), void *info, int retry, - int wait, __u32 mask) +/* Call this function on all CPUs using the function_interrupt above + The function to run. This must be fast and non-blocking. + An arbitrary pointer to pass to the function. + If true, keep retrying until ready. + If true, wait until function has completed on other CPUs. + [RETURNS] 0 on success, else a negative status code. Does not return until + remote CPUs are nearly ready to execute <> or are or have executed. +*/ +int +smp_call_function (void (*func) (void *info), void *info, int retry, + int wait) { struct call_data_struct data; + __u32 mask = cpus_addr(cpu_online_map)[0]; mask &= ~(1< The function to run. This must be fast and non-blocking. - An arbitrary pointer to pass to the function. - If true, keep retrying until ready. - If true, wait until function has completed on other CPUs. - [RETURNS] 0 on success, else a negative status code. Does not return until - remote CPUs are nearly ready to execute <> or are or have executed. -*/ -int -smp_call_function(void (*func) (void *info), void *info, int retry, - int wait) -{ - __u32 mask = cpus_addr(cpu_online_map)[0]; - - return __smp_call_function_mask(func, info, retry, wait, mask); -} EXPORT_SYMBOL(smp_call_function); -/* - * smp_call_function_single - Run a function on another CPU - * @func: The function to run. This must be fast and non-blocking. - * @info: An arbitrary pointer to pass to the function. - * @nonatomic: Currently unused. - * @wait: If true, wait until function has completed on other CPUs. - * - * Retrurns 0 on success, else a negative status code. - * - * Does not return until the remote CPU is nearly ready to execute - * or is or has executed. - */ - -int -smp_call_function_single(int cpu, void (*func) (void *info), void *info, - int nonatomic, int wait) -{ - __u32 mask = 1 << cpu; - - return __smp_call_function_mask(func, info, nonatomic, wait, mask); -} -EXPORT_SYMBOL(smp_call_function_single); - /* Sorry about the name. In an APIC based system, the APICs * themselves are programmed to send a timer interrupt. This is used * by linux to reschedule the processor. Voyager doesn't have this, diff --git a/trunk/arch/i386/mach-voyager/voyager_thread.c b/trunk/arch/i386/mach-voyager/voyager_thread.c index fdc1d926fb2a..f39887359e8e 100644 --- a/trunk/arch/i386/mach-voyager/voyager_thread.c +++ b/trunk/arch/i386/mach-voyager/voyager_thread.c @@ -24,16 +24,33 @@ #include #include #include -#include #include #include #include #include #include +#define THREAD_NAME "kvoyagerd" -struct task_struct *voyager_thread; -static __u8 set_timeout; +/* external variables */ +int kvoyagerd_running = 0; +DECLARE_MUTEX_LOCKED(kvoyagerd_sem); + +static int thread(void *); + +static __u8 set_timeout = 0; + +/* Start the machine monitor thread. Return 1 if OK, 0 if fail */ +static int __init +voyager_thread_start(void) +{ + if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) { + /* This is serious, but not fatal */ + printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n"); + return 1; + } + return 0; +} static int execute(const char *string) @@ -93,15 +110,31 @@ check_continuing_condition(void) } } +static void +wakeup(unsigned long unused) +{ + up(&kvoyagerd_sem); +} + static int thread(void *unused) { - printk(KERN_NOTICE "Voyager starting monitor thread\n"); + struct timer_list wakeup_timer; + + kvoyagerd_running = 1; - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT); + daemonize(THREAD_NAME); + set_timeout = 0; + + init_timer(&wakeup_timer); + + sigfillset(¤t->blocked); + + printk(KERN_NOTICE "Voyager starting monitor thread\n"); + + for(;;) { + down_interruptible(&kvoyagerd_sem); VDEBUG(("Voyager Daemon awoken\n")); if(voyager_status.request_from_kernel == 0) { /* probably awoken from timeout */ @@ -110,26 +143,20 @@ thread(void *unused) check_from_kernel(); voyager_status.request_from_kernel = 0; } + if(set_timeout) { + del_timer(&wakeup_timer); + wakeup_timer.expires = HZ + jiffies; + wakeup_timer.function = wakeup; + add_timer(&wakeup_timer); + } } } -static int __init -voyager_thread_start(void) -{ - voyager_thread = kthread_run(thread, NULL, "kvoyagerd"); - if (IS_ERR(voyager_thread)) { - printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n"); - return PTR_ERR(voyager_thread); - } - return 0; -} - - static void __exit voyager_thread_stop(void) { - kthread_stop(voyager_thread); + /* FIXME: do nothing at the moment */ } module_init(voyager_thread_start); -module_exit(voyager_thread_stop); +//module_exit(voyager_thread_stop); diff --git a/trunk/arch/i386/mm/fault.c b/trunk/arch/i386/mm/fault.c index f534c29e80b2..b8c4e259fc8b 100644 --- a/trunk/arch/i386/mm/fault.c +++ b/trunk/arch/i386/mm/fault.c @@ -20,7 +20,6 @@ #include #include /* For unblank_screen() */ #include -#include /* for max_low_pfn */ #include #include #include @@ -302,6 +301,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, struct mm_struct *mm; struct vm_area_struct * vma; unsigned long address; + unsigned long page; int write, si_code; /* get the address */ @@ -510,9 +510,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, bust_spinlocks(1); if (oops_may_print()) { - __typeof__(pte_val(__pte(0))) page; - -#ifdef CONFIG_X86_PAE + #ifdef CONFIG_X86_PAE if (error_code & 16) { pte_t *pte = lookup_address(address); @@ -521,7 +519,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, "NX-protected page - exploit attempt? " "(uid: %d)\n", current->uid); } -#endif + #endif if (address < PAGE_SIZE) printk(KERN_ALERT "BUG: unable to handle kernel NULL " "pointer dereference"); @@ -531,38 +529,25 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, printk(" at virtual address %08lx\n",address); printk(KERN_ALERT " printing eip:\n"); printk("%08lx\n", regs->eip); - - page = read_cr3(); - page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT]; -#ifdef CONFIG_X86_PAE - printk(KERN_ALERT "*pdpt = %016Lx\n", page); - if ((page >> PAGE_SHIFT) < max_low_pfn - && page & _PAGE_PRESENT) { - page &= PAGE_MASK; - page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT) - & (PTRS_PER_PMD - 1)]; - printk(KERN_ALERT "*pde = %016Lx\n", page); - page &= ~_PAGE_NX; - } -#else + } + page = read_cr3(); + page = ((unsigned long *) __va(page))[address >> 22]; + if (oops_may_print()) printk(KERN_ALERT "*pde = %08lx\n", page); -#endif - - /* - * We must not directly access the pte in the highpte - * case if the page table is located in highmem. - * And let's rather not kmap-atomic the pte, just in case - * it's allocated already. - */ - if ((page >> PAGE_SHIFT) < max_low_pfn - && (page & _PAGE_PRESENT)) { - page &= PAGE_MASK; - page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT) - & (PTRS_PER_PTE - 1)]; - printk(KERN_ALERT "*pte = %0*Lx\n", sizeof(page)*2, (u64)page); - } + /* + * We must not directly access the pte in the highpte + * case, the page table might be allocated in highmem. + * And lets rather not kmap-atomic the pte, just in case + * it's allocated already. + */ +#ifndef CONFIG_HIGHPTE + if ((page & 1) && oops_may_print()) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); } - +#endif tsk->thread.cr2 = address; tsk->thread.trap_no = 14; tsk->thread.error_code = error_code; @@ -603,6 +588,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); } +#ifndef CONFIG_X86_PAE void vmalloc_sync_all(void) { /* @@ -615,9 +601,6 @@ void vmalloc_sync_all(void) static unsigned long start = TASK_SIZE; unsigned long address; - if (SHARED_KERNEL_PMD) - return; - BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK); for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) { if (!test_bit(pgd_index(address), insync)) { @@ -640,3 +623,4 @@ void vmalloc_sync_all(void) start = address + PGDIR_SIZE; } } +#endif diff --git a/trunk/arch/i386/mm/highmem.c b/trunk/arch/i386/mm/highmem.c index ad8d86cc683e..ac70d09df7ee 100644 --- a/trunk/arch/i386/mm/highmem.c +++ b/trunk/arch/i386/mm/highmem.c @@ -26,7 +26,7 @@ void kunmap(struct page *page) * However when holding an atomic kmap is is not legal to sleep, so atomic * kmaps are appropriate for short, tight code paths only. */ -void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) +void *kmap_atomic(struct page *page, enum km_type type) { enum fixed_addresses idx; unsigned long vaddr; @@ -41,17 +41,12 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) return page_address(page); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); - set_pte(kmap_pte-idx, mk_pte(page, prot)); + set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); arch_flush_lazy_mmu_mode(); return (void*) vaddr; } -void *kmap_atomic(struct page *page, enum km_type type) -{ - return kmap_atomic_prot(page, type, kmap_prot); -} - void kunmap_atomic(void *kvaddr, enum km_type type) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; @@ -72,7 +67,6 @@ void kunmap_atomic(void *kvaddr, enum km_type type) #endif } - arch_flush_lazy_mmu_mode(); pagefault_enable(); } diff --git a/trunk/arch/i386/mm/init.c b/trunk/arch/i386/mm/init.c index dbe16f63a566..ae436882af7a 100644 --- a/trunk/arch/i386/mm/init.c +++ b/trunk/arch/i386/mm/init.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -43,7 +42,6 @@ #include #include #include -#include unsigned int __VMALLOC_RESERVE = 128 << 20; @@ -63,18 +61,17 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) pmd_t *pmd_table; #ifdef CONFIG_X86_PAE - if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - - paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - pud = pud_offset(pgd, 0); - if (pmd_table != pmd_offset(pud, 0)) - BUG(); - } -#endif + pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); + set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); + pud = pud_offset(pgd, 0); + if (pmd_table != pmd_offset(pud, 0)) + BUG(); +#else pud = pud_offset(pgd, 0); pmd_table = pmd_offset(pud, 0); +#endif + return pmd_table; } @@ -84,12 +81,14 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) */ static pte_t * __init one_page_table_init(pmd_t *pmd) { - if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { + if (pmd_none(*pmd)) { pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - BUG_ON(page_table != pte_offset_kernel(pmd, 0)); + if (page_table != pte_offset_kernel(pmd, 0)) + BUG(); + + return page_table; } return pte_offset_kernel(pmd, 0); @@ -109,6 +108,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; int pgd_idx, pmd_idx; unsigned long vaddr; @@ -119,10 +119,13 @@ static void __init page_table_range_init (unsigned long start, unsigned long end pgd = pgd_base + pgd_idx; for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - pmd = pmd + pmd_index(vaddr); + if (pgd_none(*pgd)) + one_md_table_init(pgd); + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - one_page_table_init(pmd); + if (pmd_none(*pmd)) + one_page_table_init(pmd); vaddr += PMD_SIZE; } @@ -164,22 +167,20 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) /* Map with big pages if possible, otherwise create normal page tables. */ if (cpu_has_pse) { unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; + if (is_kernel_text(address) || is_kernel_text(address2)) set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); else set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; } else { pte = one_page_table_init(pmd); - for (pte_ofs = 0; - pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; - pte++, pfn++, pte_ofs++, address += PAGE_SIZE) { - if (is_kernel_text(address)) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); - else - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); + for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { + if (is_kernel_text(address)) + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + else + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); } } } @@ -336,78 +337,24 @@ extern void __init remap_numa_kva(void); #define remap_numa_kva() do {} while (0) #endif -void __init native_pagetable_setup_start(pgd_t *base) +static void __init pagetable_init (void) { + unsigned long vaddr; + pgd_t *pgd_base = swapper_pg_dir; + #ifdef CONFIG_X86_PAE int i; - - /* - * Init entries of the first-level page table to the - * zero page, if they haven't already been set up. - * - * In a normal native boot, we'll be running on a - * pagetable rooted in swapper_pg_dir, but not in PAE - * mode, so this will end up clobbering the mappings - * for the lower 24Mbytes of the address space, - * without affecting the kernel address space. - */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) - set_pgd(&base[i], - __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); - - /* Make sure kernel address space is empty so that a pagetable - will be allocated for it. */ - memset(&base[USER_PTRS_PER_PGD], 0, - KERNEL_PGD_PTRS * sizeof(pgd_t)); + /* Init entries of the first-level page table to the zero page */ + for (i = 0; i < PTRS_PER_PGD; i++) + set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #else paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT); #endif -} - -void __init native_pagetable_setup_done(pgd_t *base) -{ -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - set_pgd(&base[0], base[USER_PTRS_PER_PGD]); -#endif -} - -/* - * Build a proper pagetable for the kernel mappings. Up until this - * point, we've been running on some set of pagetables constructed by - * the boot process. - * - * If we're booting on native hardware, this will be a pagetable - * constructed in arch/i386/kernel/head.S, and not running in PAE mode - * (even if we'll end up running in PAE). The root of the pagetable - * will be swapper_pg_dir. - * - * If we're booting paravirtualized under a hypervisor, then there are - * more options: we may already be running PAE, and the pagetable may - * or may not be based in swapper_pg_dir. In any case, - * paravirt_pagetable_setup_start() will set up swapper_pg_dir - * appropriately for the rest of the initialization to work. - * - * In general, pagetable_init() assumes that the pagetable may already - * be partially populated, and so it avoids stomping on any existing - * mappings. - */ -static void __init pagetable_init (void) -{ - unsigned long vaddr, end; - pgd_t *pgd_base = swapper_pg_dir; - - paravirt_pagetable_setup_start(pgd_base); /* Enable PSE if available */ - if (cpu_has_pse) + if (cpu_has_pse) { set_in_cr4(X86_CR4_PSE); + } /* Enable PGE if available */ if (cpu_has_pge) { @@ -424,12 +371,20 @@ static void __init pagetable_init (void) * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; - page_table_range_init(vaddr, end, pgd_base); + page_table_range_init(vaddr, 0, pgd_base); permanent_kmaps_init(pgd_base); - paravirt_pagetable_setup_done(pgd_base); +#ifdef CONFIG_X86_PAE + /* + * Add low memory identity-mappings - SMP needs it when + * starting up on an AP from real-mode. In the non-PAE + * case we already have these mappings through head.S. + * All user-space mappings are explicitly cleared after + * SMP startup. + */ + set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]); +#endif } #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) @@ -745,8 +700,6 @@ struct kmem_cache *pmd_cache; void __init pgtable_cache_init(void) { - size_t pgd_size = PTRS_PER_PGD*sizeof(pgd_t); - if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -756,23 +709,13 @@ void __init pgtable_cache_init(void) NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); - - if (!SHARED_KERNEL_PMD) { - /* If we're in PAE mode and have a non-shared - kernel pmd, then the pgd size must be a - page size. This is because the pgd_list - links through the page structure, so there - can only be one pgd per page for this to - work. */ - pgd_size = PAGE_SIZE; - } } pgd_cache = kmem_cache_create("pgd", - pgd_size, - pgd_size, + PTRS_PER_PGD*sizeof(pgd_t), + PTRS_PER_PGD*sizeof(pgd_t), 0, pgd_ctor, - (!SHARED_KERNEL_PMD) ? pgd_dtor : NULL); + PTRS_PER_PMD == 1 ? pgd_dtor : NULL); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } @@ -808,25 +751,13 @@ static int noinline do_test_wp_bit(void) void mark_rodata_ro(void) { - unsigned long start = PFN_ALIGN(_text); - unsigned long size = PFN_ALIGN(_etext) - start; + unsigned long addr = (unsigned long)__start_rodata; -#ifdef CONFIG_HOTPLUG_CPU - /* It must still be possible to apply SMP alternatives. */ - if (num_possible_cpus() <= 1) -#endif - { - change_page_attr(virt_to_page(start), - size >> PAGE_SHIFT, PAGE_KERNEL_RX); - printk("Write protecting the kernel text: %luk\n", size >> 10); - } + for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) + change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO); - start += size; - size = (unsigned long)__end_rodata - start; - change_page_attr(virt_to_page(start), - size >> PAGE_SHIFT, PAGE_KERNEL_RO); - printk("Write protecting the kernel read-only data: %luk\n", - size >> 10); + printk("Write protecting the kernel read-only data: %uk\n", + (__end_rodata - __start_rodata) >> 10); /* * change_page_attr() requires a global_flush_tlb() call after it. @@ -843,27 +774,26 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) unsigned long addr; for (addr = begin; addr < end; addr += PAGE_SIZE) { - struct page *page = pfn_to_page(addr >> PAGE_SHIFT); - ClearPageReserved(page); - init_page_count(page); - memset(page_address(page), POISON_FREE_INITMEM, PAGE_SIZE); - __free_page(page); + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); + free_page(addr); totalram_pages++; } - printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); + printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); } void free_initmem(void) { free_init_pages("unused kernel memory", - __pa_symbol(&__init_begin), - __pa_symbol(&__init_end)); + (unsigned long)(&__init_begin), + (unsigned long)(&__init_end)); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", __pa(start), __pa(end)); + free_init_pages("initrd memory", start, end); } #endif diff --git a/trunk/arch/i386/mm/pageattr.c b/trunk/arch/i386/mm/pageattr.c index 47bd477c8ecc..412ebbd8adb0 100644 --- a/trunk/arch/i386/mm/pageattr.c +++ b/trunk/arch/i386/mm/pageattr.c @@ -91,7 +91,7 @@ static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) unsigned long flags; set_pte_atomic(kpte, pte); /* change init_mm */ - if (SHARED_KERNEL_PMD) + if (PTRS_PER_PMD > 1) return; spin_lock_irqsave(&pgd_lock, flags); @@ -142,7 +142,7 @@ __change_page_attr(struct page *page, pgprot_t prot) return -EINVAL; kpte_page = virt_to_page(kpte); if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { - if (!pte_huge(*kpte)) { + if ((pte_val(*kpte) & _PAGE_PSE) == 0) { set_pte_atomic(kpte, mk_pte(page, prot)); } else { pgprot_t ref_prot; @@ -158,7 +158,7 @@ __change_page_attr(struct page *page, pgprot_t prot) kpte_page = split; } page_private(kpte_page)++; - } else if (!pte_huge(*kpte)) { + } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL)); BUG_ON(page_private(kpte_page) == 0); page_private(kpte_page)--; diff --git a/trunk/arch/i386/mm/pgtable.c b/trunk/arch/i386/mm/pgtable.c index 9a96c1647428..fa0cfbd551e1 100644 --- a/trunk/arch/i386/mm/pgtable.c +++ b/trunk/arch/i386/mm/pgtable.c @@ -144,8 +144,10 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) } static int fixmaps; +#ifndef CONFIG_COMPAT_VDSO unsigned long __FIXADDR_TOP = 0xfffff000; EXPORT_SYMBOL(__FIXADDR_TOP); +#endif void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) { @@ -171,8 +173,12 @@ void reserve_top_address(unsigned long reserve) BUG_ON(fixmaps > 0); printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", (int)-reserve); +#ifdef CONFIG_COMPAT_VDSO + BUG_ON(reserve != 0); +#else __FIXADDR_TOP = -reserve - PAGE_SIZE; __VMALLOC_RESERVE += reserve; +#endif } pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) @@ -232,92 +238,42 @@ static inline void pgd_list_del(pgd_t *pgd) set_page_private(next, (unsigned long)pprev); } -#if (PTRS_PER_PMD == 1) -/* Non-PAE pgd constructor */ void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; - /* !PAE, no pagetable sharing */ - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); - - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + spin_lock_irqsave(&pgd_lock, flags); + } - /* must happen under lock */ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, KERNEL_PGD_PTRS); + + if (PTRS_PER_PMD > 1) + return; + + /* must happen under lock */ paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, - __pa(swapper_pg_dir) >> PAGE_SHIFT, - USER_PTRS_PER_PGD, - KERNEL_PGD_PTRS); + __pa(swapper_pg_dir) >> PAGE_SHIFT, + USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD); + pgd_list_add(pgd); spin_unlock_irqrestore(&pgd_lock, flags); } -#else /* PTRS_PER_PMD > 1 */ -/* PAE pgd constructor */ -void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) -{ - /* PAE, kernel PMD may be shared */ - - if (SHARED_KERNEL_PMD) { - clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - KERNEL_PGD_PTRS); - } else { - unsigned long flags; - - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); - spin_lock_irqsave(&pgd_lock, flags); - pgd_list_add(pgd); - spin_unlock_irqrestore(&pgd_lock, flags); - } -} -#endif /* PTRS_PER_PMD */ +/* never called when PTRS_PER_PMD > 1 */ void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ - BUG_ON(SHARED_KERNEL_PMD); - paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT); spin_lock_irqsave(&pgd_lock, flags); pgd_list_del(pgd); spin_unlock_irqrestore(&pgd_lock, flags); } -#define UNSHARED_PTRS_PER_PGD \ - (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD) - -/* If we allocate a pmd for part of the kernel address space, then - make sure its initialized with the appropriate kernel mappings. - Otherwise use a cached zeroed pmd. */ -static pmd_t *pmd_cache_alloc(int idx) -{ - pmd_t *pmd; - - if (idx >= USER_PTRS_PER_PGD) { - pmd = (pmd_t *)__get_free_page(GFP_KERNEL); - - if (pmd) - memcpy(pmd, - (void *)pgd_page_vaddr(swapper_pg_dir[idx]), - sizeof(pmd_t) * PTRS_PER_PMD); - } else - pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); - - return pmd; -} - -static void pmd_cache_free(pmd_t *pmd, int idx) -{ - if (idx >= USER_PTRS_PER_PGD) - free_page((unsigned long)pmd); - else - kmem_cache_free(pmd_cache, pmd); -} - pgd_t *pgd_alloc(struct mm_struct *mm) { int i; @@ -326,12 +282,10 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (PTRS_PER_PMD == 1 || !pgd) return pgd; - for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) { - pmd_t *pmd = pmd_cache_alloc(i); - + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); if (!pmd) goto out_oom; - paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); } @@ -342,7 +296,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) pgd_t pgdent = pgd[i]; void* pmd = (void *)__va(pgd_val(pgdent)-1); paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); - pmd_cache_free(pmd, i); + kmem_cache_free(pmd_cache, pmd); } kmem_cache_free(pgd_cache, pgd); return NULL; @@ -354,11 +308,11 @@ void pgd_free(pgd_t *pgd) /* in the PAE case user pgd entries are overwritten before usage */ if (PTRS_PER_PMD > 1) - for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) { + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { pgd_t pgdent = pgd[i]; void* pmd = (void *)__va(pgd_val(pgdent)-1); paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); - pmd_cache_free(pmd, i); + kmem_cache_free(pmd_cache, pmd); } /* in the non-PAE case, free_pgtables() clears user pgd entries */ kmem_cache_free(pgd_cache, pgd); diff --git a/trunk/arch/i386/oprofile/nmi_int.c b/trunk/arch/i386/oprofile/nmi_int.c index 695f737516ae..8fda7be9dd4d 100644 --- a/trunk/arch/i386/oprofile/nmi_int.c +++ b/trunk/arch/i386/oprofile/nmi_int.c @@ -414,10 +414,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) user space an consistent name. */ cpu_type = "x86-64/hammer"; break; - case 0x10: - model = &op_athlon_spec; - cpu_type = "x86-64/family10"; - break; } break; diff --git a/trunk/arch/i386/pci/fixup.c b/trunk/arch/i386/pci/fixup.c index b62eafb997bc..8053b17ab647 100644 --- a/trunk/arch/i386/pci/fixup.c +++ b/trunk/arch/i386/pci/fixup.c @@ -354,7 +354,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); } } -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); /* * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. diff --git a/trunk/arch/i386/pci/i386.c b/trunk/arch/i386/pci/i386.c index bcd2f94b732c..43005f044424 100644 --- a/trunk/arch/i386/pci/i386.c +++ b/trunk/arch/i386/pci/i386.c @@ -246,8 +246,8 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask) continue; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available " - "because of resource %d collisions\n", - pci_name(dev), idx); + "because of resource collisions\n", + pci_name(dev)); return -EINVAL; } if (r->flags & IORESOURCE_IO) diff --git a/trunk/arch/i386/pci/init.c b/trunk/arch/i386/pci/init.c index 1cf11af96de2..b21b6da8ab1d 100644 --- a/trunk/arch/i386/pci/init.c +++ b/trunk/arch/i386/pci/init.c @@ -6,7 +6,7 @@ in the right sequence from here. */ static __init int pci_access_init(void) { - int type __attribute__((unused)) = 0; + int type = 0; #ifdef CONFIG_PCI_DIRECT type = pci_direct_probe(); diff --git a/trunk/arch/i386/pci/mmconfig-shared.c b/trunk/arch/i386/pci/mmconfig-shared.c index c7cabeed4d7b..747d8c63b0c4 100644 --- a/trunk/arch/i386/pci/mmconfig-shared.c +++ b/trunk/arch/i386/pci/mmconfig-shared.c @@ -60,19 +60,14 @@ static const char __init *pci_mmcfg_e7520(void) u32 win; pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); - win = win & 0xf000; - if(win == 0x0000 || win == 0xf000) - pci_mmcfg_config_num = 0; - else { - pci_mmcfg_config_num = 1; - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = win << 16; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = 255; - } + pci_mmcfg_config_num = 1; + pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = (win & 0xf000) << 16; + pci_mmcfg_config[0].pci_segment = 0; + pci_mmcfg_config[0].start_bus_number = 0; + pci_mmcfg_config[0].end_bus_number = 255; return "Intel Corporation E7520 Memory Controller Hub"; } @@ -113,10 +108,6 @@ static const char __init *pci_mmcfg_intel_945(void) if ((pciexbar & mask) & 0x0fffffffU) pci_mmcfg_config_num = 0; - /* Don't hit the APIC registers and their friends */ - if ((pciexbar & mask) >= 0xf0000000U) - pci_mmcfg_config_num = 0; - if (pci_mmcfg_config_num) { pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); if (!pci_mmcfg_config) diff --git a/trunk/arch/i386/power/cpu.c b/trunk/arch/i386/power/cpu.c index 998fd3ec0d68..2c15500f8713 100644 --- a/trunk/arch/i386/power/cpu.c +++ b/trunk/arch/i386/power/cpu.c @@ -21,7 +21,6 @@ unsigned long saved_context_eflags; void __save_processor_state(struct saved_context *ctxt) { - mtrr_save_fixed_ranges(NULL); kernel_fpu_begin(); /* diff --git a/trunk/arch/i386/power/suspend.c b/trunk/arch/i386/power/suspend.c index a0020b913f31..db5e98d2eb73 100644 --- a/trunk/arch/i386/power/suspend.c +++ b/trunk/arch/i386/power/suspend.c @@ -16,9 +16,6 @@ /* Defined in arch/i386/power/swsusp.S */ extern int restore_image(void); -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - /* Pointer to the temporary resume page tables */ pgd_t *resume_pg_dir; @@ -159,14 +156,3 @@ int swsusp_arch_resume(void) restore_image(); return 0; } - -/* - * pfn_is_nosave - check if given pfn is in the 'nosave' section - */ - -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT; - unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; - return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); -} diff --git a/trunk/arch/ia64/Kconfig b/trunk/arch/ia64/Kconfig index 3b71f97d0b60..e19185d26554 100644 --- a/trunk/arch/ia64/Kconfig +++ b/trunk/arch/ia64/Kconfig @@ -14,7 +14,6 @@ config IA64 select PCI if (!IA64_HP_SIM) select ACPI if (!IA64_HP_SIM) select PM if (!IA64_HP_SIM) - select ARCH_SUPPORTS_MSI default y help The Itanium Processor Family is Intel's 64-bit successor to diff --git a/trunk/arch/ia64/hp/sim/simeth.c b/trunk/arch/ia64/hp/sim/simeth.c index f26077a773d5..424e9257c9a0 100644 --- a/trunk/arch/ia64/hp/sim/simeth.c +++ b/trunk/arch/ia64/hp/sim/simeth.c @@ -427,6 +427,7 @@ make_new_skb(struct net_device *dev) printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); return NULL; } + nskb->dev = dev; skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */ @@ -473,7 +474,7 @@ simeth_rx(struct net_device *dev) * XXX Fix me * Should really do a csum+copy here */ - skb_copy_to_linear_data(skb, frame, len); + memcpy(skb->data, frame, len); #endif skb->protocol = eth_type_trans(skb, dev); diff --git a/trunk/arch/ia64/lib/csum_partial_copy.c b/trunk/arch/ia64/lib/csum_partial_copy.c index 118daf5a0632..503dfe6d1450 100644 --- a/trunk/arch/ia64/lib/csum_partial_copy.c +++ b/trunk/arch/ia64/lib/csum_partial_copy.c @@ -128,8 +128,6 @@ csum_partial_copy_from_user(const void __user *src, void *dst, return (__force __wsum)result; } -EXPORT_SYMBOL(csum_partial_copy_from_user); - __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) { diff --git a/trunk/arch/ia64/sn/kernel/huberror.c b/trunk/arch/ia64/sn/kernel/huberror.c index 2c3f9dfca78b..fcf7f93c4b61 100644 --- a/trunk/arch/ia64/sn/kernel/huberror.c +++ b/trunk/arch/ia64/sn/kernel/huberror.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include "ioerror.h" diff --git a/trunk/arch/ia64/sn/kernel/msi_sn.c b/trunk/arch/ia64/sn/kernel/msi_sn.c index 83f190ffe350..49873aa4a37d 100644 --- a/trunk/arch/ia64/sn/kernel/msi_sn.c +++ b/trunk/arch/ia64/sn/kernel/msi_sn.c @@ -87,6 +87,7 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry) if (irq < 0) return irq; + set_irq_msi(irq, entry); /* * Set up the vector plumbing. Let the prom (via sn_intr_alloc) * decide which cpu to direct this msi at by default. @@ -143,11 +144,10 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry) */ msg.data = 0x100 + irq; - set_irq_msi(irq, entry); write_msi_msg(irq, &msg); set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); - return 0; + return irq; } #ifdef CONFIG_SMP diff --git a/trunk/arch/ia64/sn/kernel/xpnet.c b/trunk/arch/ia64/sn/kernel/xpnet.c index 88fad85ceeff..c8173db0d84f 100644 --- a/trunk/arch/ia64/sn/kernel/xpnet.c +++ b/trunk/arch/ia64/sn/kernel/xpnet.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -232,7 +233,7 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) "%lu)\n", skb->data, &msg->data, (size_t) msg->embedded_bytes); - skb_copy_to_linear_data(skb, &msg->data, (size_t)msg->embedded_bytes); + memcpy(skb->data, &msg->data, (size_t) msg->embedded_bytes); } else { dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, @@ -263,16 +264,17 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg) dev_dbg(xpnet, "head=0x%p skb->data=0x%p skb->tail=0x%p " "skb->end=0x%p skb->len=%d\n", (void *) skb->head, - (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), + (void *) skb->data, (void *) skb->tail, (void *) skb->end, skb->len); + skb->dev = xpnet_device; skb->protocol = eth_type_trans(skb, xpnet_device); skb->ip_summed = CHECKSUM_UNNECESSARY; dev_dbg(xpnet, "passing skb to network layer; \n\tskb->head=0x%p " "skb->data=0x%p skb->tail=0x%p skb->end=0x%p skb->len=%d\n", - (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->len); + (void *) skb->head, (void *) skb->data, (void *) skb->tail, + (void *) skb->end, skb->len); xpnet_device->last_rx = jiffies; @@ -474,7 +476,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " "skb->end=0x%p skb->len=%d\n", (void *) skb->head, - (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), + (void *) skb->data, (void *) skb->tail, (void *) skb->end, skb->len); @@ -496,7 +498,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* get the beginning of the first cacheline and end of last */ start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1)); - end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); + end_addr = L1_CACHE_ALIGN((u64) skb->tail); /* calculate how many bytes to embed in the XPC message */ embedded_bytes = 0; @@ -565,15 +567,14 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) msg->version = XPNET_VERSION_EMBED; dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", &msg->data, skb->data, (size_t) embedded_bytes); - skb_copy_from_linear_data(skb, &msg->data, - (size_t)embedded_bytes); + memcpy(&msg->data, skb->data, (size_t) embedded_bytes); } else { msg->version = XPNET_VERSION; } msg->magic = XPNET_MAGIC; msg->size = end_addr - start_addr; msg->leadin_ignore = (u64) skb->data - start_addr; - msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); + msg->tailout_ignore = end_addr - (u64) skb->tail; msg->buf_pa = __pa(start_addr); dev_dbg(xpnet, "sending XPC message to %d:%d\nmsg->buf_pa=" diff --git a/trunk/arch/m32r/kernel/vmlinux.lds.S b/trunk/arch/m32r/kernel/vmlinux.lds.S index 6c73bca3f478..439cc257cd1d 100644 --- a/trunk/arch/m32r/kernel/vmlinux.lds.S +++ b/trunk/arch/m32r/kernel/vmlinux.lds.S @@ -110,7 +110,7 @@ SECTIONS __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/m68k/Kconfig b/trunk/arch/m68k/Kconfig index b8536c7c0877..a8e1e604dfa8 100644 --- a/trunk/arch/m68k/Kconfig +++ b/trunk/arch/m68k/Kconfig @@ -409,9 +409,6 @@ config STRAM_PROC help Say Y here to report ST-RAM usage statistics in /proc/stram. -config ATARI_KBD_CORE - bool - config HEARTBEAT bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 diff --git a/trunk/arch/m68k/Makefile b/trunk/arch/m68k/Makefile index c20831a7e1a9..34d826d10f1b 100644 --- a/trunk/arch/m68k/Makefile +++ b/trunk/arch/m68k/Makefile @@ -21,7 +21,7 @@ AS += -m68020 LDFLAGS := -m m68kelf ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linux-gnu- + CROSS_COMPILE = m68k-linux- endif ifdef CONFIG_SUN3 diff --git a/trunk/arch/m68k/amiga/config.c b/trunk/arch/m68k/amiga/config.c index 35748531327d..3204f412cad8 100644 --- a/trunk/arch/m68k/amiga/config.c +++ b/trunk/arch/m68k/amiga/config.c @@ -22,7 +22,9 @@ #include #include #include +#ifdef CONFIG_ZORRO #include +#endif #include #include @@ -60,51 +62,55 @@ static char s_cdtv[] __initdata = "CDTV"; static char s_cd32[] __initdata = "CD32"; static char s_draco[] __initdata = "Draco"; static char *amiga_models[] __initdata = { - [AMI_500-AMI_500] = s_a500, - [AMI_500PLUS-AMI_500] = s_a500p, - [AMI_600-AMI_500] = s_a600, - [AMI_1000-AMI_500] = s_a1000, - [AMI_1200-AMI_500] = s_a1200, - [AMI_2000-AMI_500] = s_a2000, - [AMI_2500-AMI_500] = s_a2500, - [AMI_3000-AMI_500] = s_a3000, - [AMI_3000T-AMI_500] = s_a3000t, - [AMI_3000PLUS-AMI_500] = s_a3000p, - [AMI_4000-AMI_500] = s_a4000, - [AMI_4000T-AMI_500] = s_a4000t, - [AMI_CDTV-AMI_500] = s_cdtv, - [AMI_CD32-AMI_500] = s_cd32, - [AMI_DRACO-AMI_500] = s_draco, + [AMI_500-AMI_500] = s_a500, + [AMI_500PLUS-AMI_500] = s_a500p, + [AMI_600-AMI_500] = s_a600, + [AMI_1000-AMI_500] = s_a1000, + [AMI_1200-AMI_500] = s_a1200, + [AMI_2000-AMI_500] = s_a2000, + [AMI_2500-AMI_500] = s_a2500, + [AMI_3000-AMI_500] = s_a3000, + [AMI_3000T-AMI_500] = s_a3000t, + [AMI_3000PLUS-AMI_500] = s_a3000p, + [AMI_4000-AMI_500] = s_a4000, + [AMI_4000T-AMI_500] = s_a4000t, + [AMI_CDTV-AMI_500] = s_cdtv, + [AMI_CD32-AMI_500] = s_cd32, + [AMI_DRACO-AMI_500] = s_draco, }; static char amiga_model_name[13] = "Amiga "; +extern char m68k_debug_device[]; + static void amiga_sched_init(irq_handler_t handler); /* amiga specific irq functions */ -extern void amiga_init_IRQ(void); +extern void amiga_init_IRQ (void); static void amiga_get_model(char *model); static int amiga_get_hardware_list(char *buffer); /* amiga specific timer functions */ -static unsigned long amiga_gettimeoffset(void); -static int a3000_hwclk(int, struct rtc_time *); -static int a2000_hwclk(int, struct rtc_time *); -static int amiga_set_clock_mmss(unsigned long); -static unsigned int amiga_get_ss(void); -extern void amiga_mksound(unsigned int count, unsigned int ticks); -static void amiga_reset(void); +static unsigned long amiga_gettimeoffset (void); +static int a3000_hwclk (int, struct rtc_time *); +static int a2000_hwclk (int, struct rtc_time *); +static int amiga_set_clock_mmss (unsigned long); +static unsigned int amiga_get_ss (void); +extern void amiga_mksound( unsigned int count, unsigned int ticks ); +static void amiga_reset (void); extern void amiga_init_sound(void); +static void amiga_savekmsg_init(void); static void amiga_mem_console_write(struct console *co, const char *b, unsigned int count); void amiga_serial_console_write(struct console *co, const char *s, unsigned int count); +static void amiga_debug_init(void); #ifdef CONFIG_HEARTBEAT static void amiga_heartbeat(int on); #endif static struct console amiga_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; @@ -113,24 +119,24 @@ static struct console amiga_console_driver = { */ static struct { - struct resource _ciab, _ciaa, _custom, _kickstart; + struct resource _ciab, _ciaa, _custom, _kickstart; } mb_resources = { - ._ciab = { - .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff - }, - ._ciaa = { - .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff - }, - ._custom = { - .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff - }, - ._kickstart = { - .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff - } + ._ciab = { + .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff + }, + ._ciaa = { + .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff + }, + ._custom = { + .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff + }, + ._kickstart = { + .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff + } }; static struct resource rtc_resource = { - .start = 0x00dc0000, .end = 0x00dcffff + .start = 0x00dc0000, .end = 0x00dcffff }; static struct resource ram_resource[NUM_MEMINFO]; @@ -142,57 +148,57 @@ static struct resource ram_resource[NUM_MEMINFO]; int amiga_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const unsigned long *data = record->data; + int unknown = 0; + const unsigned long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_AMIGA_MODEL: - amiga_model = *data; - break; + amiga_model = *data; + break; case BI_AMIGA_ECLOCK: - amiga_eclock = *data; - break; + amiga_eclock = *data; + break; case BI_AMIGA_CHIPSET: - amiga_chipset = *data; - break; + amiga_chipset = *data; + break; case BI_AMIGA_CHIP_SIZE: - amiga_chip_size = *(const int *)data; - break; + amiga_chip_size = *(const int *)data; + break; case BI_AMIGA_VBLANK: - amiga_vblank = *(const unsigned char *)data; - break; + amiga_vblank = *(const unsigned char *)data; + break; case BI_AMIGA_PSFREQ: - amiga_psfreq = *(const unsigned char *)data; - break; + amiga_psfreq = *(const unsigned char *)data; + break; case BI_AMIGA_AUTOCON: #ifdef CONFIG_ZORRO - if (zorro_num_autocon < ZORRO_NUM_AUTO) { - const struct ConfigDev *cd = (struct ConfigDev *)data; - struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; - dev->rom = cd->cd_Rom; - dev->slotaddr = cd->cd_SlotAddr; - dev->slotsize = cd->cd_SlotSize; - dev->resource.start = (unsigned long)cd->cd_BoardAddr; - dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1; - } else - printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); + if (zorro_num_autocon < ZORRO_NUM_AUTO) { + const struct ConfigDev *cd = (struct ConfigDev *)data; + struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; + dev->rom = cd->cd_Rom; + dev->slotaddr = cd->cd_SlotAddr; + dev->slotsize = cd->cd_SlotSize; + dev->resource.start = (unsigned long)cd->cd_BoardAddr; + dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; + } else + printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); #endif /* CONFIG_ZORRO */ - break; + break; case BI_AMIGA_SERPER: - /* serial port period: ignored here */ - break; + /* serial port period: ignored here */ + break; default: - unknown = 1; - } - return unknown; + unknown = 1; + } + return(unknown); } /* @@ -201,159 +207,159 @@ int amiga_parse_bootinfo(const struct bi_record *record) static void __init amiga_identify(void) { - /* Fill in some default values, if necessary */ - if (amiga_eclock == 0) - amiga_eclock = 709379; - - memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); + /* Fill in some default values, if necessary */ + if (amiga_eclock == 0) + amiga_eclock = 709379; + + memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); + + printk("Amiga hardware found: "); + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { + printk("[%s] ", amiga_models[amiga_model-AMI_500]); + strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); + } + + switch(amiga_model) { + case AMI_UNKNOWN: + goto Generic; + + case AMI_600: + case AMI_1200: + AMIGAHW_SET(A1200_IDE); + AMIGAHW_SET(PCMCIA); + case AMI_500: + case AMI_500PLUS: + case AMI_1000: + case AMI_2000: + case AMI_2500: + AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ + goto Generic; + + case AMI_3000: + case AMI_3000T: + AMIGAHW_SET(AMBER_FF); + AMIGAHW_SET(MAGIC_REKICK); + /* fall through */ + case AMI_3000PLUS: + AMIGAHW_SET(A3000_SCSI); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_4000T: + AMIGAHW_SET(A4000_SCSI); + /* fall through */ + case AMI_4000: + AMIGAHW_SET(A4000_IDE); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_CDTV: + case AMI_CD32: + AMIGAHW_SET(CD_ROM); + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + goto Generic; + + Generic: + AMIGAHW_SET(AMI_VIDEO); + AMIGAHW_SET(AMI_BLITTER); + AMIGAHW_SET(AMI_AUDIO); + AMIGAHW_SET(AMI_FLOPPY); + AMIGAHW_SET(AMI_KEYBOARD); + AMIGAHW_SET(AMI_MOUSE); + AMIGAHW_SET(AMI_SERIAL); + AMIGAHW_SET(AMI_PARALLEL); + AMIGAHW_SET(CHIP_RAM); + AMIGAHW_SET(PAULA); + + switch(amiga_chipset) { + case CS_OCS: + case CS_ECS: + case CS_AGA: + switch (amiga_custom.deniseid & 0xf) { + case 0x0c: + AMIGAHW_SET(DENISE_HR); + break; + case 0x08: + AMIGAHW_SET(LISA); + break; + } + break; + default: + AMIGAHW_SET(DENISE); + break; + } + switch ((amiga_custom.vposr>>8) & 0x7f) { + case 0x00: + AMIGAHW_SET(AGNUS_PAL); + break; + case 0x10: + AMIGAHW_SET(AGNUS_NTSC); + break; + case 0x20: + case 0x21: + AMIGAHW_SET(AGNUS_HR_PAL); + break; + case 0x30: + case 0x31: + AMIGAHW_SET(AGNUS_HR_NTSC); + break; + case 0x22: + case 0x23: + AMIGAHW_SET(ALICE_PAL); + break; + case 0x32: + case 0x33: + AMIGAHW_SET(ALICE_NTSC); + break; + } + AMIGAHW_SET(ZORRO); + break; + + case AMI_DRACO: + panic("No support for Draco yet"); + + default: + panic("Unknown Amiga Model"); + } - printk("Amiga hardware found: "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { - printk("[%s] ", amiga_models[amiga_model-AMI_500]); - strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); - } - - switch (amiga_model) { - case AMI_UNKNOWN: - goto Generic; - - case AMI_600: - case AMI_1200: - AMIGAHW_SET(A1200_IDE); - AMIGAHW_SET(PCMCIA); - case AMI_500: - case AMI_500PLUS: - case AMI_1000: - case AMI_2000: - case AMI_2500: - AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ - goto Generic; - - case AMI_3000: - case AMI_3000T: - AMIGAHW_SET(AMBER_FF); - AMIGAHW_SET(MAGIC_REKICK); - /* fall through */ - case AMI_3000PLUS: - AMIGAHW_SET(A3000_SCSI); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_4000T: - AMIGAHW_SET(A4000_SCSI); - /* fall through */ - case AMI_4000: - AMIGAHW_SET(A4000_IDE); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_CDTV: - case AMI_CD32: - AMIGAHW_SET(CD_ROM); - AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - goto Generic; - - Generic: - AMIGAHW_SET(AMI_VIDEO); - AMIGAHW_SET(AMI_BLITTER); - AMIGAHW_SET(AMI_AUDIO); - AMIGAHW_SET(AMI_FLOPPY); - AMIGAHW_SET(AMI_KEYBOARD); - AMIGAHW_SET(AMI_MOUSE); - AMIGAHW_SET(AMI_SERIAL); - AMIGAHW_SET(AMI_PARALLEL); - AMIGAHW_SET(CHIP_RAM); - AMIGAHW_SET(PAULA); - - switch (amiga_chipset) { - case CS_OCS: - case CS_ECS: - case CS_AGA: - switch (amiga_custom.deniseid & 0xf) { - case 0x0c: - AMIGAHW_SET(DENISE_HR); - break; - case 0x08: - AMIGAHW_SET(LISA); - break; - } - break; - default: - AMIGAHW_SET(DENISE); - break; - } - switch ((amiga_custom.vposr>>8) & 0x7f) { - case 0x00: - AMIGAHW_SET(AGNUS_PAL); - break; - case 0x10: - AMIGAHW_SET(AGNUS_NTSC); - break; - case 0x20: - case 0x21: - AMIGAHW_SET(AGNUS_HR_PAL); - break; - case 0x30: - case 0x31: - AMIGAHW_SET(AGNUS_HR_NTSC); - break; - case 0x22: - case 0x23: - AMIGAHW_SET(ALICE_PAL); - break; - case 0x32: - case 0x33: - AMIGAHW_SET(ALICE_NTSC); - break; - } - AMIGAHW_SET(ZORRO); - break; - - case AMI_DRACO: - panic("No support for Draco yet"); - - default: - panic("Unknown Amiga Model"); - } - -#define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - printk(str) - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); - AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); - AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); - AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); - AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); - AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); - AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); - AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); - AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); - AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); - AMIGAHW_ANNOUNCE(PAULA, "PAULA "); - AMIGAHW_ANNOUNCE(DENISE, "DENISE "); - AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); - AMIGAHW_ANNOUNCE(LISA, "LISA "); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); - AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); - if (AMIGAHW_PRESENT(ZORRO)) - printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); - printk("\n"); +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + printk(str) + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); + AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); + AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); + AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); + AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); + AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); + AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); + AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); + AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); + AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); + AMIGAHW_ANNOUNCE(PAULA, "PAULA "); + AMIGAHW_ANNOUNCE(DENISE, "DENISE "); + AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); + AMIGAHW_ANNOUNCE(LISA, "LISA "); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); + AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); + if (AMIGAHW_PRESENT(ZORRO)) + printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); + printk("\n"); #undef AMIGAHW_ANNOUNCE } @@ -364,105 +370,119 @@ static void __init amiga_identify(void) void __init config_amiga(void) { - int i; - - amiga_identify(); - - /* Yuk, we don't have PCI memory */ - iomem_resource.name = "Memory"; - for (i = 0; i < 4; i++) - request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); - - mach_sched_init = amiga_sched_init; - mach_init_IRQ = amiga_init_IRQ; - mach_get_model = amiga_get_model; - mach_get_hardware_list = amiga_get_hardware_list; - mach_gettimeoffset = amiga_gettimeoffset; - if (AMIGAHW_PRESENT(A3000_CLK)) { - mach_hwclk = a3000_hwclk; - rtc_resource.name = "A3000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { - mach_hwclk = a2000_hwclk; - rtc_resource.name = "A2000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } - - /* - * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI - * code will not be able to allocate any mem for transfers, unless we are - * dealing with a Z2 mem only system. /Jes - */ - mach_max_dma_address = 0xffffffff; - - mach_set_clock_mmss = amiga_set_clock_mmss; - mach_get_ss = amiga_get_ss; - mach_reset = amiga_reset; + int i; + + amiga_debug_init(); + amiga_identify(); + + /* Yuk, we don't have PCI memory */ + iomem_resource.name = "Memory"; + for (i = 0; i < 4; i++) + request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); + + mach_sched_init = amiga_sched_init; + mach_init_IRQ = amiga_init_IRQ; + mach_get_model = amiga_get_model; + mach_get_hardware_list = amiga_get_hardware_list; + mach_gettimeoffset = amiga_gettimeoffset; + if (AMIGAHW_PRESENT(A3000_CLK)){ + mach_hwclk = a3000_hwclk; + rtc_resource.name = "A3000 RTC"; + request_resource(&iomem_resource, &rtc_resource); + } + else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ + mach_hwclk = a2000_hwclk; + rtc_resource.name = "A2000 RTC"; + request_resource(&iomem_resource, &rtc_resource); + } + + mach_max_dma_address = 0xffffffff; /* + * default MAX_DMA=0xffffffff + * on all machines. If we don't + * do so, the SCSI code will not + * be able to allocate any mem + * for transfers, unless we are + * dealing with a Z2 mem only + * system. /Jes + */ + + mach_set_clock_mmss = amiga_set_clock_mmss; + mach_get_ss = amiga_get_ss; + mach_reset = amiga_reset; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = amiga_mksound; + mach_beep = amiga_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = amiga_heartbeat; + mach_heartbeat = amiga_heartbeat; #endif - /* Fill in the clock values (based on the 700 kHz E-Clock) */ - amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ - amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ - - /* clear all DMA bits */ - amiga_custom.dmacon = DMAF_ALL; - /* ensure that the DMA master bit is set */ - amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; - - /* don't use Z2 RAM as system memory on Z3 capable machines */ - if (AMIGAHW_PRESENT(ZORRO3)) { - int i, j; - u32 disabled_z2mem = 0; - - for (i = 0; i < m68k_num_memory; i++) { - if (m68k_memory[i].addr < 16*1024*1024) { - if (i == 0) { - /* don't cut off the branch we're sitting on */ - printk("Warning: kernel runs in Zorro II memory\n"); - continue; - } - disabled_z2mem += m68k_memory[i].size; - m68k_num_memory--; - for (j = i; j < m68k_num_memory; j++) - m68k_memory[j] = m68k_memory[j+1]; - i--; - } - } - if (disabled_z2mem) - printk("%dK of Zorro II memory will not be used as system memory\n", - disabled_z2mem>>10); + /* Fill in the clock values (based on the 700 kHz E-Clock) */ + amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ + amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ + + /* clear all DMA bits */ + amiga_custom.dmacon = DMAF_ALL; + /* ensure that the DMA master bit is set */ + amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + + /* don't use Z2 RAM as system memory on Z3 capable machines */ + if (AMIGAHW_PRESENT(ZORRO3)) { + int i, j; + u32 disabled_z2mem = 0; + for (i = 0; i < m68k_num_memory; i++) + if (m68k_memory[i].addr < 16*1024*1024) { + if (i == 0) { + /* don't cut off the branch we're sitting on */ + printk("Warning: kernel runs in Zorro II memory\n"); + continue; } - - /* request all RAM */ - for (i = 0; i < m68k_num_memory; i++) { - ram_resource[i].name = - (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : - (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : - "16-bit Slow RAM"; - ram_resource[i].start = m68k_memory[i].addr; - ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; - request_resource(&iomem_resource, &ram_resource[i]); - } - - /* initialize chipram allocator */ - amiga_chip_init(); - - /* our beloved beeper */ - if (AMIGAHW_PRESENT(AMI_AUDIO)) - amiga_init_sound(); - - /* - * if it is an A3000, set the magic bit that forces - * a hard rekick - */ - if (AMIGAHW_PRESENT(MAGIC_REKICK)) - *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; + disabled_z2mem += m68k_memory[i].size; + m68k_num_memory--; + for (j = i; j < m68k_num_memory; j++) + m68k_memory[j] = m68k_memory[j+1]; + i--; + } + if (disabled_z2mem) + printk("%dK of Zorro II memory will not be used as system memory\n", + disabled_z2mem>>10); + } + + /* request all RAM */ + for (i = 0; i < m68k_num_memory; i++) { + ram_resource[i].name = + (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : + (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : + "16-bit Slow RAM"; + ram_resource[i].start = m68k_memory[i].addr; + ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; + request_resource(&iomem_resource, &ram_resource[i]); + } + + /* initialize chipram allocator */ + amiga_chip_init (); + + /* debugging using chipram */ + if (!strcmp( m68k_debug_device, "mem" )){ + if (!AMIGAHW_PRESENT(CHIP_RAM)) + printk("Warning: no chipram present for debugging\n"); + else { + amiga_savekmsg_init(); + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); + } + } + + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); + + /* + * if it is an A3000, set the magic bit that forces + * a hard rekick + */ + if (AMIGAHW_PRESENT(MAGIC_REKICK)) + *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; } static unsigned short jiffy_ticks; @@ -470,12 +490,12 @@ static unsigned short jiffy_ticks; static void __init amiga_sched_init(irq_handler_t timer_routine) { static struct resource sched_res = { - .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, + .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, }; jiffy_ticks = (amiga_eclock+HZ/2)/HZ; if (request_resource(&mb_resources._ciab, &sched_res)) - printk("Cannot allocate ciab.ta{lo,hi}\n"); + printk("Cannot allocate ciab.ta{lo,hi}\n"); ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -493,7 +513,7 @@ static void __init amiga_sched_init(irq_handler_t timer_routine) #define TICK_SIZE 10000 /* This is always executed with interrupts disabled. */ -static unsigned long amiga_gettimeoffset(void) +static unsigned long amiga_gettimeoffset (void) { unsigned short hi, lo, hi2; unsigned long ticks, offset = 0; @@ -565,15 +585,15 @@ static int a2000_hwclk(int op, struct rtc_time *t) tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD; - while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { - tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; - udelay(70); - tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; + while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) + { + tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; + udelay(70); + tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; } if (!cnt) - printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", - tod_2000.cntrl1); + printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1); if (!op) { /* read */ t->tm_sec = tod_2000.second1 * 10 + tod_2000.second2; @@ -586,7 +606,7 @@ static int a2000_hwclk(int op, struct rtc_time *t) if (t->tm_year <= 69) t->tm_year += 100; - if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) { + if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12) t->tm_hour = 0; else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12) @@ -622,7 +642,7 @@ static int a2000_hwclk(int op, struct rtc_time *t) return 0; } -static int amiga_set_clock_mmss(unsigned long nowtime) +static int amiga_set_clock_mmss (unsigned long nowtime) { short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; @@ -640,7 +660,8 @@ static int amiga_set_clock_mmss(unsigned long nowtime) tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; - while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { + while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) + { tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; udelay(70); tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; @@ -660,7 +681,7 @@ static int amiga_set_clock_mmss(unsigned long nowtime) return 0; } -static unsigned int amiga_get_ss(void) +static unsigned int amiga_get_ss( void ) { unsigned int s; @@ -674,72 +695,71 @@ static unsigned int amiga_get_ss(void) return s; } -static NORET_TYPE void amiga_reset(void) +static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; -static void amiga_reset(void) +static void amiga_reset (void) { - unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); - unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); - - local_irq_disable(); - if (CPU_IS_040_OR_060) - /* Setup transparent translation registers for mapping - * of 16 MB kernel segment before disabling translation - */ - asm volatile ("\n" - " move.l %0,%%d0\n" - " and.l #0xff000000,%%d0\n" - " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ - " .chip 68040\n" - " movec %%d0,%%itt0\n" - " movec %%d0,%%dtt0\n" - " .chip 68k\n" - " jmp %0@\n" - : /* no outputs */ - : "a" (jmp_addr040) - : "d0"); - else - /* for 680[23]0, just disable translation and jump to the physical - * address of the label - */ - asm volatile ("\n" - " pmove %%tc,%@\n" - " bclr #7,%@\n" - " pmove %@,%%tc\n" - " jmp %0@\n" - : /* no outputs */ - : "a" (jmp_addr)); -jmp_addr_label040: - /* disable translation on '040 now */ - asm volatile ("\n" - " moveq #0,%%d0\n" - " .chip 68040\n" - " movec %%d0,%%tc\n" /* disable MMU */ - " .chip 68k\n" - : /* no outputs */ - : /* no inputs */ - : "d0"); - - jmp_addr_label: - /* pickup reset address from AmigaOS ROM, reset devices and jump - * to reset address - */ - asm volatile ("\n" - " move.w #0x2700,%sr\n" - " lea 0x01000000,%a0\n" - " sub.l %a0@(-0x14),%a0\n" - " move.l %a0@(4),%a0\n" - " subq.l #2,%a0\n" - " jra 1f\n" - /* align on a longword boundary */ - " " __ALIGN_STR "\n" - "1:\n" - " reset\n" - " jmp %a0@"); - - for (;;) - ; + unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); + unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); + + local_irq_disable(); + if (CPU_IS_040_OR_060) + /* Setup transparent translation registers for mapping + * of 16 MB kernel segment before disabling translation + */ + __asm__ __volatile__ + ("movel %0,%/d0\n\t" + "andl #0xff000000,%/d0\n\t" + "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr040)); + else + /* for 680[23]0, just disable translation and jump to the physical + * address of the label + */ + __asm__ __volatile__ + ("pmove %/tc,%@\n\t" + "bclr #7,%@\n\t" + "pmove %@,%/tc\n\t" + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr)); + jmp_addr_label040: + /* disable translation on '040 now */ + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%tc\n\t" /* disable MMU */ + ".chip 68k\n\t" + : /* no outputs */ + : /* no inputs */ + : "d0"); + + jmp_addr_label: + /* pickup reset address from AmigaOS ROM, reset devices and jump + * to reset address + */ + __asm__ __volatile__ + ("movew #0x2700,%/sr\n\t" + "leal 0x01000000,%/a0\n\t" + "subl %/a0@(-0x14),%/a0\n\t" + "movel %/a0@(4),%/a0\n\t" + "subql #2,%/a0\n\t" + "bra 1f\n\t" + /* align on a longword boundary */ + __ALIGN_STR "\n" + "1:\n\t" + "reset\n\t" + "jmp %/a0@" : /* Just that gcc scans it for % escapes */ ); + + for (;;); + } @@ -753,11 +773,11 @@ static void amiga_reset(void) #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ struct savekmsg { - unsigned long magic1; /* SAVEKMSG_MAGIC1 */ - unsigned long magic2; /* SAVEKMSG_MAGIC2 */ - unsigned long magicptr; /* address of magic1 */ - unsigned long size; - char data[0]; + unsigned long magic1; /* SAVEKMSG_MAGIC1 */ + unsigned long magic2; /* SAVEKMSG_MAGIC2 */ + unsigned long magicptr; /* address of magic1 */ + unsigned long size; + char data[0]; }; static struct savekmsg *savekmsg; @@ -765,132 +785,113 @@ static struct savekmsg *savekmsg; static void amiga_mem_console_write(struct console *co, const char *s, unsigned int count) { - if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { - memcpy(savekmsg->data + savekmsg->size, s, count); - savekmsg->size += count; - } + if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { + memcpy(savekmsg->data+savekmsg->size, s, count); + savekmsg->size += count; + } } -static int __init amiga_savekmsg_setup(char *arg) +static void amiga_savekmsg_init(void) { - static struct resource debug_res = { .name = "Debug" }; - - if (!MACH_IS_AMIGA || strcmp(arg, "mem")) - goto done; - - if (!AMIGAHW_PRESENT(CHIP_RAM)) { - printk("Warning: no chipram present for debugging\n"); - goto done; - } + static struct resource debug_res = { .name = "Debug" }; - savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); - savekmsg->magic1 = SAVEKMSG_MAGIC1; - savekmsg->magic2 = SAVEKMSG_MAGIC2; - savekmsg->magicptr = ZTWO_PADDR(savekmsg); - savekmsg->size = 0; - - amiga_console_driver.write = amiga_mem_console_write; - register_console(&amiga_console_driver); - -done: - return 0; + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; + savekmsg->magicptr = ZTWO_PADDR(savekmsg); + savekmsg->size = 0; } -early_param("debug", amiga_savekmsg_setup); - static void amiga_serial_putc(char c) { - amiga_custom.serdat = (unsigned char)c | 0x100; - while (!(amiga_custom.serdatr & 0x2000)) - ; + amiga_custom.serdat = (unsigned char)c | 0x100; + while (!(amiga_custom.serdatr & 0x2000)) + ; } void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count) + unsigned int count) { - while (count--) { - if (*s == '\n') - amiga_serial_putc('\r'); - amiga_serial_putc(*s++); - } + while (count--) { + if (*s == '\n') + amiga_serial_putc('\r'); + amiga_serial_putc(*s++); + } } #ifdef CONFIG_SERIAL_CONSOLE void amiga_serial_puts(const char *s) { - amiga_serial_console_write(NULL, s, strlen(s)); + amiga_serial_console_write(NULL, s, strlen(s)); } int amiga_serial_console_wait_key(struct console *co) { - int ch; - - while (!(amiga_custom.intreqr & IF_RBF)) - barrier(); - ch = amiga_custom.serdatr & 0xff; - /* clear the interrupt, so that another character can be read */ - amiga_custom.intreq = IF_RBF; - return ch; + int ch; + + while (!(amiga_custom.intreqr & IF_RBF)) + barrier(); + ch = amiga_custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + amiga_custom.intreq = IF_RBF; + return ch; } void amiga_serial_gets(struct console *co, char *s, int len) { - int ch, cnt = 0; - - while (1) { - ch = amiga_serial_console_wait_key(co); - - /* Check for backspace. */ - if (ch == 8 || ch == 127) { - if (cnt == 0) { - amiga_serial_putc('\007'); - continue; - } - cnt--; - amiga_serial_puts("\010 \010"); - continue; - } - - /* Check for enter. */ - if (ch == 10 || ch == 13) - break; + int ch, cnt = 0; + + while (1) { + ch = amiga_serial_console_wait_key(co); + + /* Check for backspace. */ + if (ch == 8 || ch == 127) { + if (cnt == 0) { + amiga_serial_putc('\007'); + continue; + } + cnt--; + amiga_serial_puts("\010 \010"); + continue; + } - /* See if line is too long. */ - if (cnt >= len + 1) { - amiga_serial_putc(7); - cnt--; - continue; - } + /* Check for enter. */ + if (ch == 10 || ch == 13) + break; - /* Store and echo character. */ - s[cnt++] = ch; - amiga_serial_putc(ch); + /* See if line is too long. */ + if (cnt >= len + 1) { + amiga_serial_putc(7); + cnt--; + continue; } - /* Print enter. */ - amiga_serial_puts("\r\n"); - s[cnt] = 0; + + /* Store and echo character. */ + s[cnt++] = ch; + amiga_serial_putc(ch); + } + /* Print enter. */ + amiga_serial_puts("\r\n"); + s[cnt] = 0; } #endif -static int __init amiga_debug_setup(char *arg) +static void __init amiga_debug_init(void) { - if (MACH_IS_AMIGA && !strcmp(arg, "ser")) { + if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ amiga_console_driver.write = amiga_serial_console_write; register_console(&amiga_console_driver); } - return 0; } -early_param("debug", amiga_debug_setup); - #ifdef CONFIG_HEARTBEAT static void amiga_heartbeat(int on) { - if (on) - ciaa.pra &= ~2; - else - ciaa.pra |= 2; + if (on) + ciaa.pra &= ~2; + else + ciaa.pra |= 2; } #endif @@ -900,81 +901,81 @@ static void amiga_heartbeat(int on) static void amiga_get_model(char *model) { - strcpy(model, amiga_model_name); + strcpy(model, amiga_model_name); } static int amiga_get_hardware_list(char *buffer) { - int len = 0; - - if (AMIGAHW_PRESENT(CHIP_RAM)) - len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); - len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", - amiga_psfreq, amiga_eclock); - if (AMIGAHW_PRESENT(AMI_VIDEO)) { - char *type; - switch (amiga_chipset) { - case CS_OCS: - type = "OCS"; - break; - case CS_ECS: - type = "ECS"; - break; - case CS_AGA: - type = "AGA"; - break; - default: - type = "Old or Unknown"; - break; - } - len += sprintf(buffer+len, "Graphics:\t%s\n", type); + int len = 0; + + if (AMIGAHW_PRESENT(CHIP_RAM)) + len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); + len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", + amiga_psfreq, amiga_eclock); + if (AMIGAHW_PRESENT(AMI_VIDEO)) { + char *type; + switch(amiga_chipset) { + case CS_OCS: + type = "OCS"; + break; + case CS_ECS: + type = "ECS"; + break; + case CS_AGA: + type = "AGA"; + break; + default: + type = "Old or Unknown"; + break; } + len += sprintf(buffer+len, "Graphics:\t%s\n", type); + } #define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - len += sprintf (buffer+len, "\t%s\n", str) - - len += sprintf (buffer + len, "Detected hardware:\n"); - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); - AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); - AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); - AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); - AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); - AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); - AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); - AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); - AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); - AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); - AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); - AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); - AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); - AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); - AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); + if (AMIGAHW_PRESENT(name)) \ + len += sprintf (buffer+len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); + AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); + AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); + AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); + AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); + AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); + AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); + AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); + AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); + AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); + AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); + AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); + AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); + AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); + AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); #ifdef CONFIG_ZORRO - if (AMIGAHW_PRESENT(ZORRO)) - len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " - "Device%s\n", - AMIGAHW_PRESENT(ZORRO3) ? "I" : "", - zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + if (AMIGAHW_PRESENT(ZORRO)) + len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " + "Device%s\n", + AMIGAHW_PRESENT(ZORRO3) ? "I" : "", + zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); #endif /* CONFIG_ZORRO */ #undef AMIGAHW_ANNOUNCE - return len; + return(len); } diff --git a/trunk/arch/m68k/atari/Makefile b/trunk/arch/m68k/atari/Makefile index 2cb86191f0aa..8cb6236b39db 100644 --- a/trunk/arch/m68k/atari/Makefile +++ b/trunk/arch/m68k/atari/Makefile @@ -8,4 +8,3 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_HADES) += hades-pci.o endif -obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o diff --git a/trunk/arch/m68k/atari/atakeyb.c b/trunk/arch/m68k/atari/atakeyb.c deleted file mode 100644 index 1c29603b16b3..000000000000 --- a/trunk/arch/m68k/atari/atakeyb.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * linux/atari/atakeyb.c - * - * Atari Keyboard driver for 680x0 Linux - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -/* - * Atari support by Robert de Vries - * enhanced by Bjoern Brauel and Roman Hodek - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static void atakeyb_rep(unsigned long ignore); -extern unsigned int keymap_count; - -/* Hook for MIDI serial driver */ -void (*atari_MIDI_interrupt_hook) (void); -/* Hook for mouse driver */ -void (*atari_mouse_interrupt_hook) (char *); -/* Hook for keyboard inputdev driver */ -void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); -/* Hook for mouse inputdev driver */ -void (*atari_input_mouse_interrupt_hook) (char *); - -/* variables for IKBD self test: */ - -/* state: 0: off; >0: in progress; >1: 0xf1 received */ -static volatile int ikbd_self_test; -/* timestamp when last received a char */ -static volatile unsigned long self_test_last_rcv; -/* bitmap of keys reported as broken */ -static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; - -#define BREAK_MASK (0x80) - -/* - * ++roman: The following changes were applied manually: - * - * - The Alt (= Meta) key works in combination with Shift and - * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends - * Meta-Ctrl-A (0x81) ... - * - * - The parentheses on the keypad send '(' and ')' with all - * modifiers (as would do e.g. keypad '+'), but they cannot be used as - * application keys (i.e. sending Esc O c). - * - * - HELP and UNDO are mapped to be F21 and F24, resp, that send the - * codes "\E[M" and "\E[P". (This is better than the old mapping to - * F11 and F12, because these codes are on Shift+F1/2 anyway.) This - * way, applications that allow their own keyboard mappings - * (e.g. tcsh, X Windows) can be configured to use them in the way - * the label suggests (providing help or undoing). - * - * - Console switching is done with Alt+Fx (consoles 1..10) and - * Shift+Alt+Fx (consoles 11..20). - * - * - The misc. special function implemented in the kernel are mapped - * to the following key combinations: - * - * ClrHome -> Home/Find - * Shift + ClrHome -> End/Select - * Shift + Up -> Page Up - * Shift + Down -> Page Down - * Alt + Help -> show system status - * Shift + Help -> show memory info - * Ctrl + Help -> show registers - * Ctrl + Alt + Del -> Reboot - * Alt + Undo -> switch to last console - * Shift + Undo -> send interrupt - * Alt + Insert -> stop/start output (same as ^S/^Q) - * Alt + Up -> Scroll back console (if implemented) - * Alt + Down -> Scroll forward console (if implemented) - * Alt + CapsLock -> NumLock - * - * ++Andreas: - * - * - Help mapped to K_HELP - * - Undo mapped to K_UNDO (= K_F246) - * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] - */ - -static u_short ataplain_map[NR_KEYS] __initdata = { - 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, - 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, - 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, - 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, - 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, - 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, - 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, - 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, - 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, - 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, - 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, - 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, - 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 -}; - -typedef enum kb_state_t { - KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC -} KB_STATE_T; - -#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb) - -typedef struct keyboard_state { - unsigned char buf[6]; - int len; - KB_STATE_T state; -} KEYBOARD_STATE; - -KEYBOARD_STATE kb_state; - -#define DEFAULT_KEYB_REP_DELAY (HZ/4) -#define DEFAULT_KEYB_REP_RATE (HZ/25) - -/* These could be settable by some ioctl() in future... */ -static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; -static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; - -static unsigned char rep_scancode; -static struct timer_list atakeyb_rep_timer = { - .function = atakeyb_rep, -}; - -static void atakeyb_rep(unsigned long ignore) -{ - /* Disable keyboard for the time we call handle_scancode(), else a race - * in the keyboard tty queue may happen */ - atari_disable_irq(IRQ_MFP_ACIA); - del_timer(&atakeyb_rep_timer); - - /* A keyboard int may have come in before we disabled the irq, so - * double-check whether rep_scancode is still != 0 */ - if (rep_scancode) { - init_timer(&atakeyb_rep_timer); - atakeyb_rep_timer.expires = jiffies + key_repeat_rate; - add_timer(&atakeyb_rep_timer); - - //handle_scancode(rep_scancode, 1); - if (atari_input_keyboard_interrupt_hook) - atari_input_keyboard_interrupt_hook(rep_scancode, 1); - } - - atari_enable_irq(IRQ_MFP_ACIA); -} - - -/* ++roman: If a keyboard overrun happened, we can't tell in general how much - * bytes have been lost and in which state of the packet structure we are now. - * This usually causes keyboards bytes to be interpreted as mouse movements - * and vice versa, which is very annoying. It seems better to throw away some - * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I - * introduced the RESYNC state for IKBD data. In this state, the bytes up to - * one that really looks like a key event (0x04..0xf2) or the start of a mouse - * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least - * speeds up the resynchronization of the event structure, even if maybe a - * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03, - * it's really hard to decide whether they're mouse or keyboard bytes. Since - * overruns usually occur when moving the Atari mouse rapidly, they're seen as - * mouse bytes here. If this is wrong, only a make code of the keyboard gets - * lost, which isn't too bad. Loosing a break code would be disastrous, - * because then the keyboard repeat strikes... - */ - -static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy) -{ - u_char acia_stat; - int scancode; - int break_flag; - -repeat: - if (acia.mid_ctrl & ACIA_IRQ) - if (atari_MIDI_interrupt_hook) - atari_MIDI_interrupt_hook(); - acia_stat = acia.key_ctrl; - /* check out if the interrupt came from this ACIA */ - if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) - return IRQ_HANDLED; - - if (acia_stat & ACIA_OVRN) { - /* a very fast typist or a slow system, give a warning */ - /* ...happens often if interrupts were disabled for too long */ - printk(KERN_DEBUG "Keyboard overrun\n"); - scancode = acia.key_data; - /* Turn off autorepeating in case a break code has been lost */ - del_timer(&atakeyb_rep_timer); - rep_scancode = 0; - if (ikbd_self_test) - /* During self test, don't do resyncing, just process the code */ - goto interpret_scancode; - else if (IS_SYNC_CODE(scancode)) { - /* This code seem already to be the start of a new packet or a - * single scancode */ - kb_state.state = KEYBOARD; - goto interpret_scancode; - } else { - /* Go to RESYNC state and skip this byte */ - kb_state.state = RESYNC; - kb_state.len = 1; /* skip max. 1 another byte */ - goto repeat; - } - } - - if (acia_stat & ACIA_RDRF) { - /* received a character */ - scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ - tasklet_schedule(&keyboard_tasklet); - interpret_scancode: - switch (kb_state.state) { - case KEYBOARD: - switch (scancode) { - case 0xF7: - kb_state.state = AMOUSE; - kb_state.len = 0; - break; - - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - kb_state.state = RMOUSE; - kb_state.len = 1; - kb_state.buf[0] = scancode; - break; - - case 0xFC: - kb_state.state = CLOCK; - kb_state.len = 0; - break; - - case 0xFE: - case 0xFF: - kb_state.state = JOYSTICK; - kb_state.len = 1; - kb_state.buf[0] = scancode; - break; - - case 0xF1: - /* during self-test, note that 0xf1 received */ - if (ikbd_self_test) { - ++ikbd_self_test; - self_test_last_rcv = jiffies; - break; - } - /* FALL THROUGH */ - - default: - break_flag = scancode & BREAK_MASK; - scancode &= ~BREAK_MASK; - if (ikbd_self_test) { - /* Scancodes sent during the self-test stand for broken - * keys (keys being down). The code *should* be a break - * code, but nevertheless some AT keyboard interfaces send - * make codes instead. Therefore, simply ignore - * break_flag... - */ - int keyval = plain_map[scancode], keytyp; - - set_bit(scancode, broken_keys); - self_test_last_rcv = jiffies; - keyval = plain_map[scancode]; - keytyp = KTYP(keyval) - 0xf0; - keyval = KVAL(keyval); - - printk(KERN_WARNING "Key with scancode %d ", scancode); - if (keytyp == KT_LATIN || keytyp == KT_LETTER) { - if (keyval < ' ') - printk("('^%c') ", keyval + '@'); - else - printk("('%c') ", keyval); - } - printk("is broken -- will be ignored.\n"); - break; - } else if (test_bit(scancode, broken_keys)) - break; - -#if 0 // FIXME; hangs at boot - if (break_flag) { - del_timer(&atakeyb_rep_timer); - rep_scancode = 0; - } else { - del_timer(&atakeyb_rep_timer); - rep_scancode = scancode; - atakeyb_rep_timer.expires = jiffies + key_repeat_delay; - add_timer(&atakeyb_rep_timer); - } -#endif - - // handle_scancode(scancode, !break_flag); - if (atari_input_keyboard_interrupt_hook) - atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag); - break; - } - break; - - case AMOUSE: - kb_state.buf[kb_state.len++] = scancode; - if (kb_state.len == 5) { - kb_state.state = KEYBOARD; - /* not yet used */ - /* wake up someone waiting for this */ - } - break; - - case RMOUSE: - kb_state.buf[kb_state.len++] = scancode; - if (kb_state.len == 3) { - kb_state.state = KEYBOARD; - if (atari_mouse_interrupt_hook) - atari_mouse_interrupt_hook(kb_state.buf); - } - break; - - case JOYSTICK: - kb_state.buf[1] = scancode; - kb_state.state = KEYBOARD; -#ifdef FIXED_ATARI_JOYSTICK - atari_joystick_interrupt(kb_state.buf); -#endif - break; - - case CLOCK: - kb_state.buf[kb_state.len++] = scancode; - if (kb_state.len == 6) { - kb_state.state = KEYBOARD; - /* wake up someone waiting for this. - But will this ever be used, as Linux keeps its own time. - Perhaps for synchronization purposes? */ - /* wake_up_interruptible(&clock_wait); */ - } - break; - - case RESYNC: - if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { - kb_state.state = KEYBOARD; - goto interpret_scancode; - } - kb_state.len--; - break; - } - } - -#if 0 - if (acia_stat & ACIA_CTS) - /* cannot happen */; -#endif - - if (acia_stat & (ACIA_FE | ACIA_PE)) { - printk("Error in keyboard communication\n"); - } - - /* handle_scancode() can take a lot of time, so check again if - * some character arrived - */ - goto repeat; -} - -/* - * I write to the keyboard without using interrupts, I poll instead. - * This takes for the maximum length string allowed (7) at 7812.5 baud - * 8 data 1 start 1 stop bit: 9.0 ms - * If this takes too long for normal operation, interrupt driven writing - * is the solution. (I made a feeble attempt in that direction but I - * kept it simple for now.) - */ -void ikbd_write(const char *str, int len) -{ - u_char acia_stat; - - if ((len < 1) || (len > 7)) - panic("ikbd: maximum string length exceeded"); - while (len) { - acia_stat = acia.key_ctrl; - if (acia_stat & ACIA_TDRE) { - acia.key_data = *str++; - len--; - } - } -} - -/* Reset (without touching the clock) */ -void ikbd_reset(void) -{ - static const char cmd[2] = { 0x80, 0x01 }; - - ikbd_write(cmd, 2); - - /* - * if all's well code 0xF1 is returned, else the break codes of - * all keys making contact - */ -} - -/* Set mouse button action */ -void ikbd_mouse_button_action(int mode) -{ - char cmd[2] = { 0x07, mode }; - - ikbd_write(cmd, 2); -} - -/* Set relative mouse position reporting */ -void ikbd_mouse_rel_pos(void) -{ - static const char cmd[1] = { 0x08 }; - - ikbd_write(cmd, 1); -} - -/* Set absolute mouse position reporting */ -void ikbd_mouse_abs_pos(int xmax, int ymax) -{ - char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF }; - - ikbd_write(cmd, 5); -} - -/* Set mouse keycode mode */ -void ikbd_mouse_kbd_mode(int dx, int dy) -{ - char cmd[3] = { 0x0A, dx, dy }; - - ikbd_write(cmd, 3); -} - -/* Set mouse threshold */ -void ikbd_mouse_thresh(int x, int y) -{ - char cmd[3] = { 0x0B, x, y }; - - ikbd_write(cmd, 3); -} - -/* Set mouse scale */ -void ikbd_mouse_scale(int x, int y) -{ - char cmd[3] = { 0x0C, x, y }; - - ikbd_write(cmd, 3); -} - -/* Interrogate mouse position */ -void ikbd_mouse_pos_get(int *x, int *y) -{ - static const char cmd[1] = { 0x0D }; - - ikbd_write(cmd, 1); - - /* wait for returning bytes */ -} - -/* Load mouse position */ -void ikbd_mouse_pos_set(int x, int y) -{ - char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF }; - - ikbd_write(cmd, 6); -} - -/* Set Y=0 at bottom */ -void ikbd_mouse_y0_bot(void) -{ - static const char cmd[1] = { 0x0F }; - - ikbd_write(cmd, 1); -} - -/* Set Y=0 at top */ -void ikbd_mouse_y0_top(void) -{ - static const char cmd[1] = { 0x10 }; - - ikbd_write(cmd, 1); -} - -/* Resume */ -void ikbd_resume(void) -{ - static const char cmd[1] = { 0x11 }; - - ikbd_write(cmd, 1); -} - -/* Disable mouse */ -void ikbd_mouse_disable(void) -{ - static const char cmd[1] = { 0x12 }; - - ikbd_write(cmd, 1); -} - -/* Pause output */ -void ikbd_pause(void) -{ - static const char cmd[1] = { 0x13 }; - - ikbd_write(cmd, 1); -} - -/* Set joystick event reporting */ -void ikbd_joystick_event_on(void) -{ - static const char cmd[1] = { 0x14 }; - - ikbd_write(cmd, 1); -} - -/* Set joystick interrogation mode */ -void ikbd_joystick_event_off(void) -{ - static const char cmd[1] = { 0x15 }; - - ikbd_write(cmd, 1); -} - -/* Joystick interrogation */ -void ikbd_joystick_get_state(void) -{ - static const char cmd[1] = { 0x16 }; - - ikbd_write(cmd, 1); -} - -#if 0 -/* This disables all other ikbd activities !!!! */ -/* Set joystick monitoring */ -void ikbd_joystick_monitor(int rate) -{ - static const char cmd[2] = { 0x17, rate }; - - ikbd_write(cmd, 2); - - kb_state.state = JOYSTICK_MONITOR; -} -#endif - -/* some joystick routines not in yet (0x18-0x19) */ - -/* Disable joysticks */ -void ikbd_joystick_disable(void) -{ - static const char cmd[1] = { 0x1A }; - - ikbd_write(cmd, 1); -} - -/* Time-of-day clock set */ -void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) -{ - char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; - - ikbd_write(cmd, 7); -} - -/* Interrogate time-of-day clock */ -void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) -{ - static const char cmd[1] = { 0x1C }; - - ikbd_write(cmd, 1); -} - -/* Memory load */ -void ikbd_mem_write(int address, int size, char *data) -{ - panic("Attempt to write data into keyboard memory"); -} - -/* Memory read */ -void ikbd_mem_read(int address, char data[6]) -{ - char cmd[3] = { 0x21, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); - - /* receive data and put it in data */ -} - -/* Controller execute */ -void ikbd_exec(int address) -{ - char cmd[3] = { 0x22, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); -} - -/* Status inquiries (0x87-0x9A) not yet implemented */ - -/* Set the state of the caps lock led. */ -void atari_kbd_leds(unsigned int leds) -{ - char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; - - ikbd_write(cmd, 6); -} - -/* - * The original code sometimes left the interrupt line of - * the ACIAs low forever. I hope, it is fixed now. - * - * Martin Rogge, 20 Aug 1995 - */ - -static int atari_keyb_done = 0; - -int __init atari_keyb_init(void) -{ - if (atari_keyb_done) - return 0; - - /* setup key map */ - memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); - - kb_state.state = KEYBOARD; - kb_state.len = 0; - - request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW, - "keyboard/mouse/MIDI", atari_keyboard_interrupt); - - atari_turnoff_irq(IRQ_MFP_ACIA); - do { - /* reset IKBD ACIA */ - acia.key_ctrl = ACIA_RESET | - (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; - (void)acia.key_ctrl; - (void)acia.key_data; - - /* reset MIDI ACIA */ - acia.mid_ctrl = ACIA_RESET | - (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; - (void)acia.mid_ctrl; - (void)acia.mid_data; - - /* divide 500kHz by 64 gives 7812.5 baud */ - /* 8 data no parity 1 start 1 stop bit */ - /* receive interrupt enabled */ - /* RTS low (except if switch selected), transmit interrupt disabled */ - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | - ((atari_switches & ATARI_SWITCH_IKBD) ? - ACIA_RHTID : ACIA_RLTID); - - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | - (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; - - /* make sure the interrupt line is up */ - } while ((mfp.par_dt_reg & 0x10) == 0); - - /* enable ACIA Interrupts */ - mfp.active_edge &= ~0x10; - atari_turnon_irq(IRQ_MFP_ACIA); - - ikbd_self_test = 1; - ikbd_reset(); - /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's - * self-test is finished */ - self_test_last_rcv = jiffies; - while (time_before(jiffies, self_test_last_rcv + HZ/4)) - barrier(); - /* if not incremented: no 0xf1 received */ - if (ikbd_self_test == 1) - printk(KERN_ERR "WARNING: keyboard self test failed!\n"); - ikbd_self_test = 0; - - ikbd_mouse_disable(); - ikbd_joystick_disable(); - -#ifdef FIXED_ATARI_JOYSTICK - atari_joystick_init(); -#endif - - // flag init done - atari_keyb_done = 1; - return 0; -} - - -int atari_kbdrate(struct kbd_repeat *k) -{ - if (k->delay > 0) { - /* convert from msec to jiffies */ - key_repeat_delay = (k->delay * HZ + 500) / 1000; - if (key_repeat_delay < 1) - key_repeat_delay = 1; - } - if (k->period > 0) { - key_repeat_rate = (k->period * HZ + 500) / 1000; - if (key_repeat_rate < 1) - key_repeat_rate = 1; - } - - k->delay = key_repeat_delay * 1000 / HZ; - k->period = key_repeat_rate * 1000 / HZ; - - return 0; -} - -int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) -{ -#ifdef CONFIG_MAGIC_SYSRQ - /* ALT+HELP pressed? */ - if ((keycode == 98) && ((shift_state & 0xff) == 8)) - *keycodep = 0xff; - else -#endif - *keycodep = keycode; - return 1; -} diff --git a/trunk/arch/m68k/atari/config.c b/trunk/arch/m68k/atari/config.c index e40e5dcaa347..ca5cd4344e3d 100644 --- a/trunk/arch/m68k/atari/config.c +++ b/trunk/arch/m68k/atari/config.c @@ -50,25 +50,70 @@ int atari_dont_touch_floppy_select; int atari_rtc_year_offset; /* local function prototypes */ -static void atari_reset(void); +static void atari_reset( void ); static void atari_get_model(char *model); static int atari_get_hardware_list(char *buffer); /* atari specific irq functions */ extern void atari_init_IRQ (void); -extern void atari_mksound(unsigned int count, unsigned int ticks); +extern void atari_mksound( unsigned int count, unsigned int ticks ); #ifdef CONFIG_HEARTBEAT -static void atari_heartbeat(int on); +static void atari_heartbeat( int on ); #endif /* atari specific timer functions (in time.c) */ -extern void atari_sched_init(irq_handler_t); +extern void atari_sched_init(irq_handler_t ); extern unsigned long atari_gettimeoffset (void); extern int atari_mste_hwclk (int, struct rtc_time *); extern int atari_tt_hwclk (int, struct rtc_time *); extern int atari_mste_set_clock_mmss (unsigned long); extern int atari_tt_set_clock_mmss (unsigned long); +/* atari specific debug functions (in debug.c) */ +extern void atari_debug_init(void); + + +/* I've moved hwreg_present() and hwreg_present_bywrite() out into + * mm/hwtest.c, to avoid having multiple copies of the same routine + * in the kernel [I wanted them in hp300 and they were already used + * in the nubus code. NB: I don't have an Atari so this might (just + * conceivably) break something. + * I've preserved the #if 0 version of hwreg_present_bywrite() here + * for posterity. + * -- Peter Maydell , 05/1998 + */ + +#if 0 +static int __init +hwreg_present_bywrite(volatile void *regp, unsigned char val) +{ + int ret; + long save_sp, save_vbr; + static long tmp_vectors[3] = { [2] = (long)&&after_test }; + + __asm__ __volatile__ + ( "movec %/vbr,%2\n\t" /* save vbr value */ + "movec %4,%/vbr\n\t" /* set up temporary vectors */ + "movel %/sp,%1\n\t" /* save sp */ + "moveq #0,%0\n\t" /* assume not present */ + "moveb %5,%3@\n\t" /* write the hardware reg */ + "cmpb %3@,%5\n\t" /* compare it */ + "seq %0" /* comes here only if reg */ + /* is present */ + : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr) + : "a" (regp), "r" (tmp_vectors), "d" (val) + ); + after_test: + __asm__ __volatile__ + ( "movel %0,%/sp\n\t" /* restore sp */ + "movec %1,%/vbr" /* restore vbr */ + : : "r" (save_sp), "r" (save_vbr) : "sp" + ); + + return( ret ); +} +#endif + /* ++roman: This is a more elaborate test for an SCC chip, since the plain * Medusa board generates DTACK at the SCC's standard addresses, but a SCC @@ -78,34 +123,26 @@ extern int atari_tt_set_clock_mmss (unsigned long); * should be readable without trouble (from channel A!). */ -static int __init scc_test(volatile char *ctla) +static int __init scc_test( volatile char *ctla ) { - if (!hwreg_present(ctla)) - return 0; + if (!hwreg_present( ctla )) + return( 0 ); MFPDELAY(); - *ctla = 2; - MFPDELAY(); - *ctla = 0x40; - MFPDELAY(); + *ctla = 2; MFPDELAY(); + *ctla = 0x40; MFPDELAY(); - *ctla = 2; - MFPDELAY(); - if (*ctla != 0x40) - return 0; + *ctla = 2; MFPDELAY(); + if (*ctla != 0x40) return( 0 ); MFPDELAY(); - *ctla = 2; - MFPDELAY(); - *ctla = 0x60; - MFPDELAY(); + *ctla = 2; MFPDELAY(); + *ctla = 0x60; MFPDELAY(); - *ctla = 2; - MFPDELAY(); - if (*ctla != 0x60) - return 0; + *ctla = 2; MFPDELAY(); + if (*ctla != 0x60) return( 0 ); - return 1; + return( 1 ); } @@ -115,65 +152,60 @@ static int __init scc_test(volatile char *ctla) int __init atari_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const u_long *data = record->data; + int unknown = 0; + const u_long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_ATARI_MCH_COOKIE: - atari_mch_cookie = *data; - break; + atari_mch_cookie = *data; + break; case BI_ATARI_MCH_TYPE: - atari_mch_type = *data; - break; + atari_mch_type = *data; + break; default: - unknown = 1; - break; - } - return unknown; + unknown = 1; + } + return(unknown); } /* Parse the Atari-specific switches= option. */ -static int __init atari_switches_setup(char *str) +void __init atari_switches_setup( const char *str, unsigned len ) { - char switches[strlen(str) + 1]; - char *p; - int ovsc_shift; - char *args = switches; - - if (!MACH_IS_ATARI) - return 0; - - /* copy string to local array, strsep works destructively... */ - strcpy(switches, str); - atari_switches = 0; - - /* parse the options */ - while ((p = strsep(&args, ",")) != NULL) { - if (!*p) - continue; - ovsc_shift = 0; - if (strncmp(p, "ov_", 3) == 0) { - p += 3; - ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; - } - - if (strcmp(p, "ikbd") == 0) { - /* RTS line of IKBD ACIA */ - atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; - } else if (strcmp(p, "midi") == 0) { - /* RTS line of MIDI ACIA */ - atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; - } else if (strcmp(p, "snd6") == 0) { - atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; - } else if (strcmp(p, "snd7") == 0) { - atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; - } + char switches[len+1]; + char *p; + int ovsc_shift; + char *args = switches; + + /* copy string to local array, strsep works destructively... */ + strlcpy( switches, str, sizeof(switches) ); + atari_switches = 0; + + /* parse the options */ + while ((p = strsep(&args, ",")) != NULL) { + if (!*p) continue; + ovsc_shift = 0; + if (strncmp( p, "ov_", 3 ) == 0) { + p += 3; + ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; } - return 0; -} -early_param("switches", atari_switches_setup); + if (strcmp( p, "ikbd" ) == 0) { + /* RTS line of IKBD ACIA */ + atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; + } + else if (strcmp( p, "midi" ) == 0) { + /* RTS line of MIDI ACIA */ + atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + } + else if (strcmp( p, "snd6" ) == 0) { + atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; + } + else if (strcmp( p, "snd7" ) == 0) { + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } + } +} /* @@ -182,281 +214,284 @@ early_param("switches", atari_switches_setup); void __init config_atari(void) { - unsigned short tos_version; + unsigned short tos_version; - memset(&atari_hw_present, 0, sizeof(atari_hw_present)); + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); - /* Change size of I/O space from 64KB to 4GB. */ - ioport_resource.end = 0xFFFFFFFF; + atari_debug_init(); - mach_sched_init = atari_sched_init; - mach_init_IRQ = atari_init_IRQ; - mach_get_model = atari_get_model; - mach_get_hardware_list = atari_get_hardware_list; - mach_gettimeoffset = atari_gettimeoffset; - mach_reset = atari_reset; - mach_max_dma_address = 0xffffff; + ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB + to 4GB. */ + + mach_sched_init = atari_sched_init; + mach_init_IRQ = atari_init_IRQ; + mach_get_model = atari_get_model; + mach_get_hardware_list = atari_get_hardware_list; + mach_gettimeoffset = atari_gettimeoffset; + mach_reset = atari_reset; + mach_max_dma_address = 0xffffff; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = atari_mksound; + mach_beep = atari_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = atari_heartbeat; + mach_heartbeat = atari_heartbeat; #endif - /* Set switches as requested by the user */ - if (atari_switches & ATARI_SWITCH_IKBD) - acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; - if (atari_switches & ATARI_SWITCH_MIDI) - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; - if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { - sound_ym.rd_data_reg_sel = 14; - sound_ym.wd_data = sound_ym.rd_data_reg_sel | - ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | - ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); - } + /* Set switches as requested by the user */ + if (atari_switches & ATARI_SWITCH_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & ATARI_SWITCH_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | + ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); + } + + /* ++bjoern: + * Determine hardware present + */ - /* ++bjoern: - * Determine hardware present - */ - - printk("Atari hardware found: "); - if (MACH_IS_MEDUSA || MACH_IS_HADES) { - /* There's no Atari video hardware on the Medusa, but all the - * addresses below generate a DTACK so no bus error occurs! */ - } else if (hwreg_present(f030_xreg)) { - ATARIHW_SET(VIDEL_SHIFTER); - printk("VIDEL "); - /* This is a temporary hack: If there is Falcon video - * hardware, we assume that the ST-DMA serves SCSI instead of - * ACSI. In the future, there should be a better method for - * this... - */ - ATARIHW_SET(ST_SCSI); - printk("STDMA-SCSI "); - } else if (hwreg_present(tt_palette)) { - ATARIHW_SET(TT_SHIFTER); - printk("TT_SHIFTER "); - } else if (hwreg_present(&shifter.bas_hi)) { - if (hwreg_present(&shifter.bas_lo) && - (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { - ATARIHW_SET(EXTD_SHIFTER); - printk("EXTD_SHIFTER "); - } else { - ATARIHW_SET(STND_SHIFTER); - printk("STND_SHIFTER "); - } - } - if (hwreg_present(&mfp.par_dt_reg)) { - ATARIHW_SET(ST_MFP); - printk("ST_MFP "); - } - if (hwreg_present(&tt_mfp.par_dt_reg)) { - ATARIHW_SET(TT_MFP); - printk("TT_MFP "); - } - if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) { - ATARIHW_SET(SCSI_DMA); - printk("TT_SCSI_DMA "); - } - if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) { - ATARIHW_SET(STND_DMA); - printk("STND_DMA "); - } - /* - * The ST-DMA address registers aren't readable - * on all Medusas, so the test below may fail - */ - if (MACH_IS_MEDUSA || - (hwreg_present(&st_dma.dma_vhi) && - (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && - st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && - (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && - st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { - ATARIHW_SET(EXTD_DMA); - printk("EXTD_DMA "); - } - if (hwreg_present(&tt_scsi.scsi_data)) { - ATARIHW_SET(TT_SCSI); - printk("TT_SCSI "); - } - if (hwreg_present(&sound_ym.rd_data_reg_sel)) { - ATARIHW_SET(YM_2149); - printk("YM2149 "); - } - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present(&tt_dmasnd.ctrl)) { - ATARIHW_SET(PCM_8BIT); - printk("PCM "); - } - if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) { - ATARIHW_SET(CODEC); - printk("CODEC "); - } - if (hwreg_present(&dsp56k_host_interface.icr)) { - ATARIHW_SET(DSP56K); - printk("DSP56K "); - } - if (hwreg_present(&tt_scc_dma.dma_ctrl) && + printk( "Atari hardware found: " ); + if (MACH_IS_MEDUSA || MACH_IS_HADES) { + /* There's no Atari video hardware on the Medusa, but all the + * addresses below generate a DTACK so no bus error occurs! */ + } + else if (hwreg_present( f030_xreg )) { + ATARIHW_SET(VIDEL_SHIFTER); + printk( "VIDEL " ); + /* This is a temporary hack: If there is Falcon video + * hardware, we assume that the ST-DMA serves SCSI instead of + * ACSI. In the future, there should be a better method for + * this... + */ + ATARIHW_SET(ST_SCSI); + printk( "STDMA-SCSI " ); + } + else if (hwreg_present( tt_palette )) { + ATARIHW_SET(TT_SHIFTER); + printk( "TT_SHIFTER " ); + } + else if (hwreg_present( &shifter.bas_hi )) { + if (hwreg_present( &shifter.bas_lo ) && + (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { + ATARIHW_SET(EXTD_SHIFTER); + printk( "EXTD_SHIFTER " ); + } + else { + ATARIHW_SET(STND_SHIFTER); + printk( "STND_SHIFTER " ); + } + } + if (hwreg_present( &mfp.par_dt_reg )) { + ATARIHW_SET(ST_MFP); + printk( "ST_MFP " ); + } + if (hwreg_present( &tt_mfp.par_dt_reg )) { + ATARIHW_SET(TT_MFP); + printk( "TT_MFP " ); + } + if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) { + ATARIHW_SET(SCSI_DMA); + printk( "TT_SCSI_DMA " ); + } + if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { + ATARIHW_SET(STND_DMA); + printk( "STND_DMA " ); + } + if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail */ + (hwreg_present( &st_dma.dma_vhi ) && + (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && + st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && + (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && + st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { + ATARIHW_SET(EXTD_DMA); + printk( "EXTD_DMA " ); + } + if (hwreg_present( &tt_scsi.scsi_data )) { + ATARIHW_SET(TT_SCSI); + printk( "TT_SCSI " ); + } + if (hwreg_present( &sound_ym.rd_data_reg_sel )) { + ATARIHW_SET(YM_2149); + printk( "YM2149 " ); + } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &tt_dmasnd.ctrl )) { + ATARIHW_SET(PCM_8BIT); + printk( "PCM " ); + } + if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) { + ATARIHW_SET(CODEC); + printk( "CODEC " ); + } + if (hwreg_present( &dsp56k_host_interface.icr )) { + ATARIHW_SET(DSP56K); + printk( "DSP56K " ); + } + if (hwreg_present( &tt_scc_dma.dma_ctrl ) && #if 0 - /* This test sucks! Who knows some better? */ - (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && - (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) + /* This test sucks! Who knows some better? */ + (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && + (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) #else - !MACH_IS_MEDUSA && !MACH_IS_HADES + !MACH_IS_MEDUSA && !MACH_IS_HADES #endif - ) { - ATARIHW_SET(SCC_DMA); - printk("SCC_DMA "); - } - if (scc_test(&scc.cha_a_ctrl)) { - ATARIHW_SET(SCC); - printk("SCC "); - } - if (scc_test(&st_escc.cha_b_ctrl)) { - ATARIHW_SET(ST_ESCC); - printk("ST_ESCC "); - } - if (MACH_IS_HADES) { - ATARIHW_SET(VME); - printk("VME "); - } else if (hwreg_present(&tt_scu.sys_mask)) { - ATARIHW_SET(SCU); - /* Assume a VME bus if there's a SCU */ - ATARIHW_SET(VME); - printk("VME SCU "); - } - if (hwreg_present((void *)(0xffff9210))) { - ATARIHW_SET(ANALOG_JOY); - printk("ANALOG_JOY "); - } - if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) { - ATARIHW_SET(BLITTER); - printk("BLITTER "); - } - if (hwreg_present((void *)0xfff00039)) { - ATARIHW_SET(IDE); - printk("IDE "); - } + ) { + ATARIHW_SET(SCC_DMA); + printk( "SCC_DMA " ); + } + if (scc_test( &scc.cha_a_ctrl )) { + ATARIHW_SET(SCC); + printk( "SCC " ); + } + if (scc_test( &st_escc.cha_b_ctrl )) { + ATARIHW_SET( ST_ESCC ); + printk( "ST_ESCC " ); + } + if (MACH_IS_HADES) + { + ATARIHW_SET( VME ); + printk( "VME " ); + } + else if (hwreg_present( &tt_scu.sys_mask )) { + ATARIHW_SET(SCU); + /* Assume a VME bus if there's a SCU */ + ATARIHW_SET( VME ); + printk( "VME SCU " ); + } + if (hwreg_present( (void *)(0xffff9210) )) { + ATARIHW_SET(ANALOG_JOY); + printk( "ANALOG_JOY " ); + } + if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { + ATARIHW_SET(BLITTER); + printk( "BLITTER " ); + } + if (hwreg_present((void *)0xfff00039)) { + ATARIHW_SET(IDE); + printk( "IDE " ); + } #if 1 /* This maybe wrong */ - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present(&tt_microwire.data) && - hwreg_present(&tt_microwire.mask) && - (tt_microwire.mask = 0x7ff, - udelay(1), - tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, - udelay(1), - tt_microwire.data != 0)) { - ATARIHW_SET(MICROWIRE); - while (tt_microwire.mask != 0x7ff) - ; - printk("MICROWIRE "); - } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &tt_microwire.data ) && + hwreg_present( &tt_microwire.mask ) && + (tt_microwire.mask = 0x7ff, + udelay(1), + tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + udelay(1), + tt_microwire.data != 0)) { + ATARIHW_SET(MICROWIRE); + while (tt_microwire.mask != 0x7ff) ; + printk( "MICROWIRE " ); + } #endif - if (hwreg_present(&tt_rtc.regsel)) { - ATARIHW_SET(TT_CLK); - printk("TT_CLK "); - mach_hwclk = atari_tt_hwclk; - mach_set_clock_mmss = atari_tt_set_clock_mmss; - } - if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) { - ATARIHW_SET(MSTE_CLK); - printk("MSTE_CLK "); - mach_hwclk = atari_mste_hwclk; - mach_set_clock_mmss = atari_mste_set_clock_mmss; - } - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present(&dma_wd.fdc_speed) && - hwreg_write(&dma_wd.fdc_speed, 0)) { - ATARIHW_SET(FDCSPEED); - printk("FDC_SPEED "); - } - if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { - ATARIHW_SET(ACSI); - printk("ACSI "); - } - printk("\n"); - - if (CPU_IS_040_OR_060) - /* Now it seems to be safe to turn of the tt0 transparent - * translation (the one that must not be turned off in - * head.S...) - */ - asm volatile ("\n" - " moveq #0,%%d0\n" - " .chip 68040\n" - " movec %%d0,%%itt0\n" - " movec %%d0,%%dtt0\n" - " .chip 68k" - : /* no outputs */ - : /* no inputs */ - : "d0"); - - /* allocator for memory that must reside in st-ram */ - atari_stram_init(); - - /* Set up a mapping for the VMEbus address region: - * - * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff - * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at - * 0xfe000000 virt., because this can be done with a single - * transparent translation. On the 68040, lots of often unused - * page tables would be needed otherwise. On a MegaSTE or similar, - * the highest byte is stripped off by hardware due to the 24 bit - * design of the bus. - */ - - if (CPU_IS_020_OR_030) { - unsigned long tt1_val; - tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache - * inhibit, read and write, FDC mask = 3, - * FDC val = 4 -> Supervisor only */ - asm volatile ("\n" - " .chip 68030\n" - " pmove %0@,%/tt1\n" - " .chip 68k" - : : "a" (&tt1_val)); - } else { - asm volatile ("\n" - " .chip 68040\n" - " movec %0,%%itt1\n" - " movec %0,%%dtt1\n" - " .chip 68k" - : - : "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable, - * supervisor only, non-cacheable/ - * serialized, writable */ - - } + if (hwreg_present( &tt_rtc.regsel )) { + ATARIHW_SET(TT_CLK); + printk( "TT_CLK " ); + mach_hwclk = atari_tt_hwclk; + mach_set_clock_mmss = atari_tt_set_clock_mmss; + } + if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { + ATARIHW_SET(MSTE_CLK); + printk( "MSTE_CLK "); + mach_hwclk = atari_mste_hwclk; + mach_set_clock_mmss = atari_mste_set_clock_mmss; + } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &dma_wd.fdc_speed ) && + hwreg_write( &dma_wd.fdc_speed, 0 )) { + ATARIHW_SET(FDCSPEED); + printk( "FDC_SPEED "); + } + if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { + ATARIHW_SET(ACSI); + printk( "ACSI " ); + } + printk("\n"); + + if (CPU_IS_040_OR_060) + /* Now it seems to be safe to turn of the tt0 transparent + * translation (the one that must not be turned off in + * head.S...) + */ + __asm__ volatile ("moveq #0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k" + : /* no outputs */ + : /* no inputs */ + : "d0"); + + /* allocator for memory that must reside in st-ram */ + atari_stram_init (); + + /* Set up a mapping for the VMEbus address region: + * + * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff + * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at + * 0xfe000000 virt., because this can be done with a single + * transparent translation. On the 68040, lots of often unused + * page tables would be needed otherwise. On a MegaSTE or similar, + * the highest byte is stripped off by hardware due to the 24 bit + * design of the bus. + */ - /* Fetch tos version at Physical 2 */ - /* - * We my not be able to access this address if the kernel is - * loaded to st ram, since the first page is unmapped. On the - * Medusa this is always the case and there is nothing we can do - * about this, so we just assume the smaller offset. For the TT - * we use the fact that in head.S we have set up a mapping - * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible - * in the last 16MB of the address space. - */ - tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? - 0xfff : *(unsigned short *)0xff000002; - atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; + if (CPU_IS_020_OR_030) { + unsigned long tt1_val; + tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache + * inhibit, read and write, FDC mask = 3, + * FDC val = 4 -> Supervisor only */ + __asm__ __volatile__ ( ".chip 68030\n\t" + "pmove %0@,%/tt1\n\t" + ".chip 68k" + : : "a" (&tt1_val) ); + } + else { + __asm__ __volatile__ + ( "movel %0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt1\n\t" + "movec %%d0,%%dtt1\n\t" + ".chip 68k" + : + : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, + * supervisor only, non-cacheable/ + * serialized, writable */ + : "d0" ); + + } + + /* Fetch tos version at Physical 2 */ + /* We my not be able to access this address if the kernel is + loaded to st ram, since the first page is unmapped. On the + Medusa this is always the case and there is nothing we can do + about this, so we just assume the smaller offset. For the TT + we use the fact that in head.S we have set up a mapping + 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible + in the last 16MB of the address space. */ + tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? + 0xfff : *(unsigned short *)0xff000002; + atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; } #ifdef CONFIG_HEARTBEAT -static void atari_heartbeat(int on) +static void atari_heartbeat( int on ) { - unsigned char tmp; - unsigned long flags; + unsigned char tmp; + unsigned long flags; - if (atari_dont_touch_floppy_select) - return; + if (atari_dont_touch_floppy_select) + return; - local_irq_save(flags); - sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ - tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); - local_irq_restore(flags); + local_irq_save(flags); + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); + local_irq_restore(flags); } #endif @@ -491,171 +526,180 @@ static void atari_heartbeat(int on) /* ++andreas: no need for complicated code, just depend on prefetch */ -static void atari_reset(void) +static void atari_reset (void) { - long tc_val = 0; - long reset_addr; - - /* - * On the Medusa, phys. 0x4 may contain garbage because it's no - * ROM. See above for explanation why we cannot use PTOV(4). - */ - reset_addr = MACH_IS_HADES ? 0x7fe00030 : - MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : - *(unsigned long *) 0xff000004; - - /* reset ACIA for switch off OverScan, if it's active */ - if (atari_switches & ATARI_SWITCH_OVSC_IKBD) - acia.key_ctrl = ACIA_RESET; - if (atari_switches & ATARI_SWITCH_OVSC_MIDI) - acia.mid_ctrl = ACIA_RESET; - - /* processor independent: turn off interrupts and reset the VBR; - * the caches must be left enabled, else prefetching the final jump - * instruction doesn't work. - */ - local_irq_disable(); - asm volatile ("movec %0,%%vbr" - : : "d" (0)); - - if (CPU_IS_040_OR_060) { - unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); - if (CPU_IS_060) { - /* 68060: clear PCR to turn off superscalar operation */ - asm volatile ("\n" - " .chip 68060\n" - " movec %0,%%pcr\n" - " .chip 68k" - : : "d" (0)); - } - - asm volatile ("\n" - " move.l %0,%%d0\n" - " and.l #0xff000000,%%d0\n" - " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ - " .chip 68040\n" - " movec %%d0,%%itt0\n" - " movec %%d0,%%dtt0\n" - " .chip 68k\n" - " jmp %0@" - : : "a" (jmp_addr040) - : "d0"); - jmp_addr_label040: - asm volatile ("\n" - " moveq #0,%%d0\n" - " nop\n" - " .chip 68040\n" - " cinva %%bc\n" - " nop\n" - " pflusha\n" - " nop\n" - " movec %%d0,%%tc\n" - " nop\n" - /* the following setup of transparent translations is needed on the - * Afterburner040 to successfully reboot. Other machines shouldn't - * care about a different tt regs setup, they also didn't care in - * the past that the regs weren't turned off. */ - " move.l #0xffc000,%%d0\n" /* whole insn space cacheable */ - " movec %%d0,%%itt0\n" - " movec %%d0,%%itt1\n" - " or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */ - " movec %%d0,%%dtt0\n" - " movec %%d0,%%dtt1\n" - " .chip 68k\n" - " jmp %0@" - : /* no outputs */ - : "a" (reset_addr) - : "d0"); - } else - asm volatile ("\n" - " pmove %0@,%%tc\n" - " jmp %1@" - : /* no outputs */ - : "a" (&tc_val), "a" (reset_addr)); + long tc_val = 0; + long reset_addr; + + /* On the Medusa, phys. 0x4 may contain garbage because it's no + ROM. See above for explanation why we cannot use PTOV(4). */ + reset_addr = MACH_IS_HADES ? 0x7fe00030 : + MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : + *(unsigned long *) 0xff000004; + + /* reset ACIA for switch off OverScan, if it's active */ + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_RESET; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_RESET; + + /* processor independent: turn off interrupts and reset the VBR; + * the caches must be left enabled, else prefetching the final jump + * instruction doesn't work. */ + local_irq_disable(); + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + "movec %/d0,%/vbr" + : : : "d0" ); + + if (CPU_IS_040_OR_060) { + unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); + if (CPU_IS_060) { + /* 68060: clear PCR to turn off superscalar operation */ + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + ".chip 68060\n\t" + "movec %%d0,%%pcr\n\t" + ".chip 68k" + : : : "d0" ); + } + + __asm__ __volatile__ + ("movel %0,%/d0\n\t" + "andl #0xff000000,%/d0\n\t" + "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" + "jmp %0@\n\t" + : /* no outputs */ + : "a" (jmp_addr040) + : "d0" ); + jmp_addr_label040: + __asm__ __volatile__ + ("moveq #0,%/d0\n\t" + "nop\n\t" + ".chip 68040\n\t" + "cinva %%bc\n\t" + "nop\n\t" + "pflusha\n\t" + "nop\n\t" + "movec %%d0,%%tc\n\t" + "nop\n\t" + /* the following setup of transparent translations is needed on the + * Afterburner040 to successfully reboot. Other machines shouldn't + * care about a different tt regs setup, they also didn't care in + * the past that the regs weren't turned off. */ + "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%itt1\n\t" + "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ + "movec %%d0,%%dtt0\n\t" + "movec %%d0,%%dtt1\n\t" + ".chip 68k\n\t" + "jmp %0@" + : /* no outputs */ + : "a" (reset_addr) + : "d0"); + } + else + __asm__ __volatile__ + ("pmove %0@,%/tc\n\t" + "jmp %1@" + : /* no outputs */ + : "a" (&tc_val), "a" (reset_addr)); } static void atari_get_model(char *model) { - strcpy(model, "Atari "); - switch (atari_mch_cookie >> 16) { + strcpy(model, "Atari "); + switch (atari_mch_cookie >> 16) { case ATARI_MCH_ST: - if (ATARIHW_PRESENT(MSTE_CLK)) - strcat(model, "Mega ST"); - else - strcat(model, "ST"); - break; + if (ATARIHW_PRESENT(MSTE_CLK)) + strcat (model, "Mega ST"); + else + strcat (model, "ST"); + break; case ATARI_MCH_STE: - if (MACH_IS_MSTE) - strcat(model, "Mega STE"); - else - strcat(model, "STE"); - break; + if (MACH_IS_MSTE) + strcat (model, "Mega STE"); + else + strcat (model, "STE"); + break; case ATARI_MCH_TT: - if (MACH_IS_MEDUSA) - /* Medusa has TT _MCH cookie */ - strcat(model, "Medusa"); - else if (MACH_IS_HADES) - strcat(model, "Hades"); - else - strcat(model, "TT"); - break; + if (MACH_IS_MEDUSA) + /* Medusa has TT _MCH cookie */ + strcat (model, "Medusa"); + else if (MACH_IS_HADES) + strcat(model, "Hades"); + else + strcat (model, "TT"); + break; case ATARI_MCH_FALCON: - strcat(model, "Falcon"); - if (MACH_IS_AB40) - strcat(model, " (with Afterburner040)"); - break; + strcat (model, "Falcon"); + if (MACH_IS_AB40) + strcat (model, " (with Afterburner040)"); + break; default: - sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)", - atari_mch_cookie); - break; - } + sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", + atari_mch_cookie); + break; + } } static int atari_get_hardware_list(char *buffer) { - int len = 0, i; - - for (i = 0; i < m68k_num_memory; i++) - len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", - m68k_memory[i].size >> 20, m68k_memory[i].addr, - (m68k_memory[i].addr & 0xff000000 ? - "alternate RAM" : "ST-RAM")); - -#define ATARIHW_ANNOUNCE(name, str) \ - if (ATARIHW_PRESENT(name)) \ - len += sprintf(buffer + len, "\t%s\n", str) - - len += sprintf(buffer + len, "Detected hardware:\n"); - ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); - ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); - ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); - ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); - ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); - ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); - ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); - ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); - ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); - ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); - ATARIHW_ANNOUNCE(IDE, "IDE Interface"); - ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); - ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); - ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); - ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); - ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); - ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); - ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); - ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); - ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); - ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); - ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); - ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); - ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); - ATARIHW_ANNOUNCE(SCU, "System Control Unit"); - ATARIHW_ANNOUNCE(BLITTER, "Blitter"); - ATARIHW_ANNOUNCE(VME, "VME Bus"); - ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); - - return len; + int len = 0, i; + + for (i = 0; i < m68k_num_memory; i++) + len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", + m68k_memory[i].size >> 20, m68k_memory[i].addr, + (m68k_memory[i].addr & 0xff000000 ? + "alternate RAM" : "ST-RAM")); + +#define ATARIHW_ANNOUNCE(name,str) \ + if (ATARIHW_PRESENT(name)) \ + len += sprintf (buffer + len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); + ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); + ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); + ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); + ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); + ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); + ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); + ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); + ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); + ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); + ATARIHW_ANNOUNCE(IDE, "IDE Interface"); + ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); + ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); + ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); + ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); + ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); + ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); + ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); + ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); + ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); + ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); + ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); + ATARIHW_ANNOUNCE(SCU, "System Control Unit"); + ATARIHW_ANNOUNCE(BLITTER, "Blitter"); + ATARIHW_ANNOUNCE(VME, "VME Bus"); + ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); + + return(len); } + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff --git a/trunk/arch/m68k/atari/debug.c b/trunk/arch/m68k/atari/debug.c index fbeed8c8ecbc..4ae01004d8dd 100644 --- a/trunk/arch/m68k/atari/debug.c +++ b/trunk/arch/m68k/atari/debug.c @@ -19,6 +19,8 @@ #include #include +extern char m68k_debug_device[]; + /* Flag that Modem1 port is already initialized and used */ int atari_MFP_init_done; /* Flag that Modem1 port is already initialized and used */ @@ -28,317 +30,317 @@ int atari_SCC_init_done; int atari_SCC_reset_done; static struct console atari_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; -static inline void ata_mfp_out(char c) +static inline void ata_mfp_out (char c) { - while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ - barrier(); - mfp.usart_dta = c; + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier (); + mfp.usart_dta = c; } -void atari_mfp_console_write(struct console *co, const char *str, - unsigned int count) +void atari_mfp_console_write (struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_mfp_out('\r'); - ata_mfp_out(*str++); - } + while (count--) { + if (*str == '\n') + ata_mfp_out( '\r' ); + ata_mfp_out( *str++ ); + } } -static inline void ata_scc_out(char c) +static inline void ata_scc_out (char c) { - do { - MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + do { MFPDELAY(); - scc.cha_b_data = c; + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); + scc.cha_b_data = c; } -void atari_scc_console_write(struct console *co, const char *str, - unsigned int count) +void atari_scc_console_write (struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_scc_out('\r'); - ata_scc_out(*str++); - } + while (count--) { + if (*str == '\n') + ata_scc_out( '\r' ); + ata_scc_out( *str++ ); + } } -static inline void ata_midi_out(char c) +static inline void ata_midi_out (char c) { - while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ - barrier(); - acia.mid_data = c; + while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ + barrier (); + acia.mid_data = c; } -void atari_midi_console_write(struct console *co, const char *str, - unsigned int count) +void atari_midi_console_write (struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_midi_out('\r'); - ata_midi_out(*str++); - } + while (count--) { + if (*str == '\n') + ata_midi_out( '\r' ); + ata_midi_out( *str++ ); + } } -static int ata_par_out(char c) +static int ata_par_out (char c) { - unsigned char tmp; - /* This a some-seconds timeout in case no printer is connected */ - unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; - - while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */ - ; - if (!i) - return 0; - - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = c; /* put char onto port */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ - MFPDELAY(); /* wait a bit */ - sound_ym.wd_data = tmp | 0x20; /* set strobe H */ - return 1; + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; + + while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ + ; + if (!i) return( 0 ); + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return( 1 ); } -static void atari_par_console_write(struct console *co, const char *str, - unsigned int count) +static void atari_par_console_write (struct console *co, const char *str, + unsigned int count) { - static int printer_present = 1; + static int printer_present = 1; - if (!printer_present) - return; + if (!printer_present) + return; - while (count--) { - if (*str == '\n') { - if (!ata_par_out('\r')) { - printer_present = 0; - return; - } - } - if (!ata_par_out(*str++)) { - printer_present = 0; - return; - } + while (count--) { + if (*str == '\n') + if (!ata_par_out( '\r' )) { + printer_present = 0; + return; + } + if (!ata_par_out( *str++ )) { + printer_present = 0; + return; } + } } #ifdef CONFIG_SERIAL_CONSOLE int atari_mfp_console_wait_key(struct console *co) { - while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */ - barrier(); - return mfp.usart_dta; + while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ + barrier(); + return( mfp.usart_dta ); } int atari_scc_console_wait_key(struct console *co) { - do { - MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */ + do { MFPDELAY(); - return scc.cha_b_data; + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + MFPDELAY(); + return( scc.cha_b_data ); } int atari_midi_console_wait_key(struct console *co) { - while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */ - barrier(); - return acia.mid_data; + while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ + barrier(); + return( acia.mid_data ); } #endif -/* - * The following two functions do a quick'n'dirty initialization of the MFP or +/* The following two functions do a quick'n'dirty initialization of the MFP or * SCC serial ports. They're used by the debugging interface, kgdb, and the - * serial console code. - */ + * serial console code. */ #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_mfp_port(int cflag) +static void __init atari_init_mfp_port( int cflag ) #else -void atari_init_mfp_port(int cflag) +void atari_init_mfp_port( int cflag ) #endif { - /* - * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 - * bps, resp., and work only correct if there's a RSVE or RSSPEED - */ - static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; - int baud = cflag & CBAUD; - int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; - int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* baud_table[] starts at 1200bps */ - - mfp.trn_stat &= ~0x01; /* disable TX */ - mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ - mfp.tim_ct_cd &= 0x70; /* stop timer D */ - mfp.tim_dt_d = baud_table[baud]; - mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ - mfp.trn_stat |= 0x01; /* enable TX */ - - atari_MFP_init_done = 1; + /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 + * bps, resp., and work only correct if there's a RSVE or RSSPEED */ + static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; + int baud = cflag & CBAUD; + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; + int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* baud_table[] starts at 1200bps */ + + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = baud_table[baud]; + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + + atari_MFP_init_done = 1; } -#define SCC_WRITE(reg, val) \ - do { \ - scc.cha_b_ctrl = (reg); \ - MFPDELAY(); \ - scc.cha_b_ctrl = (val); \ - MFPDELAY(); \ - } while (0) +#define SCC_WRITE(reg,val) \ + do { \ + scc.cha_b_ctrl = (reg); \ + MFPDELAY(); \ + scc.cha_b_ctrl = (val); \ + MFPDELAY(); \ + } while(0) /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a * delay of ~ 60us. */ -#define LONG_DELAY() \ - do { \ - int i; \ - for (i = 100; i > 0; --i) \ - MFPDELAY(); \ - } while (0) +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 100; i > 0; --i ) \ + MFPDELAY(); \ + } while(0) #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_scc_port(int cflag) +static void __init atari_init_scc_port( int cflag ) #else -void atari_init_scc_port(int cflag) +void atari_init_scc_port( int cflag ) #endif { - extern int atari_SCC_reset_done; - static int clksrc_table[9] = - /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ - { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; - static int brgsrc_table[9] = - /* reg 14: 0 = RTxC, 2 = PCLK */ - { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; - static int clkmode_table[9] = - /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ - { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; - static int div_table[9] = - /* reg12 (BRG low) */ - { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; - - int baud = cflag & CBAUD; - int clksrc, clkmode, div, reg3, reg5; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* tables starts at 1200bps */ - - clksrc = clksrc_table[baud]; - clkmode = clkmode_table[baud]; - div = div_table[baud]; - if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { - /* special treatment for TT, where rates >= 38400 are done via TRxC */ - clksrc = 0x28; /* TRxC */ - clkmode = baud == 6 ? 0xc0 : - baud == 7 ? 0x80 : /* really 76800bps */ - 0x40; /* really 153600bps */ - div = 0; - } - - reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; - reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; - - (void)scc.cha_b_ctrl; /* reset reg pointer */ - SCC_WRITE(9, 0xc0); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) - : 0 | 0x04 /* 1 stopbit */ | clkmode); - SCC_WRITE(3, reg3); - SCC_WRITE(5, reg5); - SCC_WRITE(9, 0); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCC_WRITE(10, 0); /* NRZ mode */ - SCC_WRITE(11, clksrc); /* main clock source */ - SCC_WRITE(12, div); /* BRG value */ - SCC_WRITE(13, 0); /* BRG high byte */ - SCC_WRITE(14, brgsrc_table[baud]); - SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0)); - SCC_WRITE(3, reg3 | 1); - SCC_WRITE(5, reg5 | 8); - - atari_SCC_reset_done = 1; - atari_SCC_init_done = 1; + extern int atari_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { + /* special treatment for TT, where rates >= 38400 are done via TRxC */ + clksrc = 0x28; /* TRxC */ + clkmode = baud == 6 ? 0xc0 : + baud == 7 ? 0x80 : /* really 76800bps */ + 0x40; /* really 153600bps */ + div = 0; + } + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + atari_SCC_reset_done = 1; + atari_SCC_init_done = 1; } #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_midi_port(int cflag) +static void __init atari_init_midi_port( int cflag ) #else -void atari_init_midi_port(int cflag) +void atari_init_midi_port( int cflag ) #endif { - int baud = cflag & CBAUD; - int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; - /* warning 7N1 isn't possible! (instead 7O2 is used...) */ - int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; - int div; - - /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as - * default) the standard MIDI speed 31250. */ - if (cflag & CBAUDEX) - baud += B38400; - if (baud == B4800) - div = ACIA_DIV64; /* really 7812.5 bps */ - else if (baud == B38400+2 /* 115200 */) - div = ACIA_DIV1; /* really 500 kbps (does that work??) */ - else - div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ - - /* RTS low, ints disabled */ - acia.mid_ctrl = div | csize | parity | + int baud = cflag & CBAUD; + int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; + /* warning 7N1 isn't possible! (instead 7O2 is used...) */ + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; + int div; + + /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as + * default) the standard MIDI speed 31250. */ + if (cflag & CBAUDEX) + baud += B38400; + if (baud == B4800) + div = ACIA_DIV64; /* really 7812.5 bps */ + else if (baud == B38400+2 /* 115200 */) + div = ACIA_DIV1; /* really 500 kbps (does that work??) */ + else + div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + + /* RTS low, ints disabled */ + acia.mid_ctrl = div | csize | parity | ((atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : ACIA_RLTID); } -static int __init atari_debug_setup(char *arg) +void __init atari_debug_init(void) { - if (!MACH_IS_ATARI) - return 0; - - if (!strcmp(arg, "ser")) - /* defaults to ser2 for a Falcon and ser1 otherwise */ - arg = MACH_IS_FALCON ? "ser2" : "ser1"; - - if (!strcmp(arg, "ser1")) { - /* ST-MFP Modem1 serial port */ - atari_init_mfp_port(B9600|CS8); - atari_console_driver.write = atari_mfp_console_write; - } else if (!strcmp(arg, "ser2")) { - /* SCC Modem2 serial port */ - atari_init_scc_port(B9600|CS8); - atari_console_driver.write = atari_scc_console_write; - } else if (!strcmp(arg, "midi")) { - /* MIDI port */ - atari_init_midi_port(B9600|CS8); - atari_console_driver.write = atari_midi_console_write; - } else if (!strcmp(arg, "par")) { - /* parallel printer */ - atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */ - sound_ym.rd_data_reg_sel = 7; /* select mixer control */ - sound_ym.wd_data = 0xff; /* sound off, ports are output */ - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = 0; /* no char */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ - atari_console_driver.write = atari_par_console_write; - } - if (atari_console_driver.write) - register_console(&atari_console_driver); - - return 0; + if (!strcmp( m68k_debug_device, "ser" )) { + /* defaults to ser2 for a Falcon and ser1 otherwise */ + strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); + + } + + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port( B9600|CS8 ); + atari_console_driver.write = atari_mfp_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + atari_init_scc_port( B9600|CS8 ); + atari_console_driver.write = atari_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "midi" )) { + /* MIDI port */ + atari_init_midi_port( B9600|CS8 ); + atari_console_driver.write = atari_midi_console_write; + } + else if (!strcmp( m68k_debug_device, "par" )) { + /* parallel printer */ + atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + atari_console_driver.write = atari_par_console_write; + } + if (atari_console_driver.write) + register_console(&atari_console_driver); } -early_param("debug", atari_debug_setup); +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff --git a/trunk/arch/m68k/kernel/entry.S b/trunk/arch/m68k/kernel/entry.S index e162ee685d20..222ce4244564 100644 --- a/trunk/arch/m68k/kernel/entry.S +++ b/trunk/arch/m68k/kernel/entry.S @@ -692,7 +692,7 @@ sys_call_table: .long sys_tgkill /* 265 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_mbind + .long sys_mbind .long sys_get_mempolicy .long sys_set_mempolicy /* 270 */ .long sys_mq_open diff --git a/trunk/arch/m68k/kernel/head.S b/trunk/arch/m68k/kernel/head.S index 05741f233567..6739e87fe825 100644 --- a/trunk/arch/m68k/kernel/head.S +++ b/trunk/arch/m68k/kernel/head.S @@ -3195,7 +3195,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1 jbra L(serial_putc_done) 3: #endif - + L(serial_putc_done): func_return serial_putc diff --git a/trunk/arch/m68k/kernel/setup.c b/trunk/arch/m68k/kernel/setup.c index 610319356691..42b8fd09ea8f 100644 --- a/trunk/arch/m68k/kernel/setup.c +++ b/trunk/arch/m68k/kernel/setup.c @@ -71,6 +71,9 @@ static struct mem_info m68k_ramdisk; static char m68k_command_line[CL_SIZE]; +char m68k_debug_device[6] = ""; +EXPORT_SYMBOL(m68k_debug_device); + void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; @@ -130,78 +133,78 @@ extern void config_hp300(void); extern void config_q40(void); extern void config_sun3x(void); +extern void mac_debugging_short (int, short); +extern void mac_debugging_long (int, long); + #define MASK_256K 0xfffc0000 extern void paging_init(void); static void __init m68k_parse_bootinfo(const struct bi_record *record) { - while (record->tag != BI_LAST) { - int unknown = 0; - const unsigned long *data = record->data; - - switch (record->tag) { - case BI_MACHTYPE: - case BI_CPUTYPE: - case BI_FPUTYPE: - case BI_MMUTYPE: - /* Already set up by head.S */ - break; - - case BI_MEMCHUNK: - if (m68k_num_memory < NUM_MEMINFO) { - m68k_memory[m68k_num_memory].addr = data[0]; - m68k_memory[m68k_num_memory].size = data[1]; - m68k_num_memory++; - } else - printk("m68k_parse_bootinfo: too many memory chunks\n"); - break; - - case BI_RAMDISK: - m68k_ramdisk.addr = data[0]; - m68k_ramdisk.size = data[1]; - break; - - case BI_COMMAND_LINE: - strlcpy(m68k_command_line, (const char *)data, - sizeof(m68k_command_line)); - break; - - default: - if (MACH_IS_AMIGA) - unknown = amiga_parse_bootinfo(record); - else if (MACH_IS_ATARI) - unknown = atari_parse_bootinfo(record); - else if (MACH_IS_MAC) - unknown = mac_parse_bootinfo(record); - else if (MACH_IS_Q40) - unknown = q40_parse_bootinfo(record); - else if (MACH_IS_BVME6000) - unknown = bvme6000_parse_bootinfo(record); - else if (MACH_IS_MVME16x) - unknown = mvme16x_parse_bootinfo(record); - else if (MACH_IS_MVME147) - unknown = mvme147_parse_bootinfo(record); - else if (MACH_IS_HP300) - unknown = hp300_parse_bootinfo(record); - else - unknown = 1; - } - if (unknown) - printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", - record->tag); - record = (struct bi_record *)((unsigned long)record + - record->size); + while (record->tag != BI_LAST) { + int unknown = 0; + const unsigned long *data = record->data; + switch (record->tag) { + case BI_MACHTYPE: + case BI_CPUTYPE: + case BI_FPUTYPE: + case BI_MMUTYPE: + /* Already set up by head.S */ + break; + + case BI_MEMCHUNK: + if (m68k_num_memory < NUM_MEMINFO) { + m68k_memory[m68k_num_memory].addr = data[0]; + m68k_memory[m68k_num_memory].size = data[1]; + m68k_num_memory++; + } else + printk("m68k_parse_bootinfo: too many memory chunks\n"); + break; + + case BI_RAMDISK: + m68k_ramdisk.addr = data[0]; + m68k_ramdisk.size = data[1]; + break; + + case BI_COMMAND_LINE: + strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line)); + break; + + default: + if (MACH_IS_AMIGA) + unknown = amiga_parse_bootinfo(record); + else if (MACH_IS_ATARI) + unknown = atari_parse_bootinfo(record); + else if (MACH_IS_MAC) + unknown = mac_parse_bootinfo(record); + else if (MACH_IS_Q40) + unknown = q40_parse_bootinfo(record); + else if (MACH_IS_BVME6000) + unknown = bvme6000_parse_bootinfo(record); + else if (MACH_IS_MVME16x) + unknown = mvme16x_parse_bootinfo(record); + else if (MACH_IS_MVME147) + unknown = mvme147_parse_bootinfo(record); + else if (MACH_IS_HP300) + unknown = hp300_parse_bootinfo(record); + else + unknown = 1; } + if (unknown) + printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", + record->tag); + record = (struct bi_record *)((unsigned long)record+record->size); + } - m68k_realnum_memory = m68k_num_memory; + m68k_realnum_memory = m68k_num_memory; #ifdef CONFIG_SINGLE_MEMORY_CHUNK - if (m68k_num_memory > 1) { - printk("Ignoring last %i chunks of physical memory\n", - (m68k_num_memory - 1)); - m68k_num_memory = 1; - } - m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; + if (m68k_num_memory > 1) { + printk("Ignoring last %i chunks of physical memory\n", + (m68k_num_memory - 1)); + m68k_num_memory = 1; + } + m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; #endif } @@ -212,6 +215,7 @@ void __init setup_arch(char **cmdline_p) unsigned long endmem, startmem; #endif int i; + char *p, *q; /* The bootinfo is located right after the kernel bss */ m68k_parse_bootinfo((const struct bi_record *)&_end); @@ -230,7 +234,7 @@ void __init setup_arch(char **cmdline_p) /* clear the fpu if we have one */ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; - asm volatile ("frestore %0" : : "m" (zero)); + asm __volatile__ ("frestore %0" : : "m" (zero)); } #endif @@ -254,7 +258,37 @@ void __init setup_arch(char **cmdline_p) *cmdline_p = m68k_command_line; memcpy(boot_command_line, *cmdline_p, CL_SIZE); - parse_early_param(); + /* Parse the command line for arch-specific options. + * For the m68k, this is currently only "debug=xxx" to enable printing + * certain kernel messages to some machine-specific device. + */ + for( p = *cmdline_p; p && *p; ) { + i = 0; + if (!strncmp( p, "debug=", 6 )) { + strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) ); + if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; + i = 1; + } +#ifdef CONFIG_ATARI + /* This option must be parsed very early */ + if (!strncmp( p, "switches=", 9 )) { + extern void atari_switches_setup( const char *, int ); + atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? + (q - (p+9)) : strlen(p+9) ); + i = 1; + } +#endif + + if (i) { + /* option processed, delete it */ + if ((q = strchr( p, ' ' ))) + strcpy( p, q+1 ); + else + *p = 0; + } else { + if ((p = strchr( p, ' ' ))) ++p; + } + } #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -262,62 +296,62 @@ void __init setup_arch(char **cmdline_p) switch (m68k_machtype) { #ifdef CONFIG_AMIGA - case MACH_AMIGA: + case MACH_AMIGA: config_amiga(); break; #endif #ifdef CONFIG_ATARI - case MACH_ATARI: + case MACH_ATARI: config_atari(); break; #endif #ifdef CONFIG_MAC - case MACH_MAC: + case MACH_MAC: config_mac(); break; #endif #ifdef CONFIG_SUN3 - case MACH_SUN3: + case MACH_SUN3: config_sun3(); break; #endif #ifdef CONFIG_APOLLO - case MACH_APOLLO: + case MACH_APOLLO: config_apollo(); break; #endif #ifdef CONFIG_MVME147 - case MACH_MVME147: + case MACH_MVME147: config_mvme147(); break; #endif #ifdef CONFIG_MVME16x - case MACH_MVME16x: + case MACH_MVME16x: config_mvme16x(); break; #endif #ifdef CONFIG_BVME6000 - case MACH_BVME6000: + case MACH_BVME6000: config_bvme6000(); break; #endif #ifdef CONFIG_HP300 - case MACH_HP300: + case MACH_HP300: config_hp300(); break; #endif #ifdef CONFIG_Q40 - case MACH_Q40: - config_q40(); + case MACH_Q40: + config_q40(); break; #endif #ifdef CONFIG_SUN3X - case MACH_SUN3X: + case MACH_SUN3X: config_sun3x(); break; #endif - default: - panic("No configuration setup"); + default: + panic ("No configuration setup"); } #ifndef CONFIG_SUN3 @@ -346,7 +380,7 @@ void __init setup_arch(char **cmdline_p) reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); initrd_end = initrd_start + m68k_ramdisk.size; - printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); + printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end); } #endif @@ -368,18 +402,18 @@ void __init setup_arch(char **cmdline_p) #if defined(CONFIG_ISA) && defined(MULTI_ISA) #if defined(CONFIG_Q40) if (MACH_IS_Q40) { - isa_type = Q40_ISA; - isa_sex = 0; + isa_type = Q40_ISA; + isa_sex = 0; } #elif defined(CONFIG_GG2) - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { - isa_type = GG2_ISA; - isa_sex = 0; + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){ + isa_type = GG2_ISA; + isa_sex = 0; } #elif defined(CONFIG_AMIGA_PCMCIA) - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { - isa_type = AG_ISA; - isa_sex = 1; + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){ + isa_type = AG_ISA; + isa_sex = 1; } #endif #endif @@ -387,66 +421,66 @@ void __init setup_arch(char **cmdline_p) static int show_cpuinfo(struct seq_file *m, void *v) { - const char *cpu, *mmu, *fpu; - unsigned long clockfreq, clockfactor; + const char *cpu, *mmu, *fpu; + unsigned long clockfreq, clockfactor; #define LOOP_CYCLES_68020 (8) #define LOOP_CYCLES_68030 (8) #define LOOP_CYCLES_68040 (3) #define LOOP_CYCLES_68060 (1) - if (CPU_IS_020) { - cpu = "68020"; - clockfactor = LOOP_CYCLES_68020; - } else if (CPU_IS_030) { - cpu = "68030"; - clockfactor = LOOP_CYCLES_68030; - } else if (CPU_IS_040) { - cpu = "68040"; - clockfactor = LOOP_CYCLES_68040; - } else if (CPU_IS_060) { - cpu = "68060"; - clockfactor = LOOP_CYCLES_68060; - } else { - cpu = "680x0"; - clockfactor = 0; - } + if (CPU_IS_020) { + cpu = "68020"; + clockfactor = LOOP_CYCLES_68020; + } else if (CPU_IS_030) { + cpu = "68030"; + clockfactor = LOOP_CYCLES_68030; + } else if (CPU_IS_040) { + cpu = "68040"; + clockfactor = LOOP_CYCLES_68040; + } else if (CPU_IS_060) { + cpu = "68060"; + clockfactor = LOOP_CYCLES_68060; + } else { + cpu = "680x0"; + clockfactor = 0; + } #ifdef CONFIG_M68KFPU_EMU_ONLY - fpu = "none(soft float)"; + fpu="none(soft float)"; #else - if (m68k_fputype & FPU_68881) - fpu = "68881"; - else if (m68k_fputype & FPU_68882) - fpu = "68882"; - else if (m68k_fputype & FPU_68040) - fpu = "68040"; - else if (m68k_fputype & FPU_68060) - fpu = "68060"; - else if (m68k_fputype & FPU_SUNFPA) - fpu = "Sun FPA"; - else - fpu = "none"; + if (m68k_fputype & FPU_68881) + fpu = "68881"; + else if (m68k_fputype & FPU_68882) + fpu = "68882"; + else if (m68k_fputype & FPU_68040) + fpu = "68040"; + else if (m68k_fputype & FPU_68060) + fpu = "68060"; + else if (m68k_fputype & FPU_SUNFPA) + fpu = "Sun FPA"; + else + fpu = "none"; #endif - if (m68k_mmutype & MMU_68851) - mmu = "68851"; - else if (m68k_mmutype & MMU_68030) - mmu = "68030"; - else if (m68k_mmutype & MMU_68040) - mmu = "68040"; - else if (m68k_mmutype & MMU_68060) - mmu = "68060"; - else if (m68k_mmutype & MMU_SUN3) - mmu = "Sun-3"; - else if (m68k_mmutype & MMU_APOLLO) - mmu = "Apollo"; - else - mmu = "unknown"; - - clockfreq = loops_per_jiffy * HZ * clockfactor; - - seq_printf(m, "CPU:\t\t%s\n" + if (m68k_mmutype & MMU_68851) + mmu = "68851"; + else if (m68k_mmutype & MMU_68030) + mmu = "68030"; + else if (m68k_mmutype & MMU_68040) + mmu = "68040"; + else if (m68k_mmutype & MMU_68060) + mmu = "68060"; + else if (m68k_mmutype & MMU_SUN3) + mmu = "Sun-3"; + else if (m68k_mmutype & MMU_APOLLO) + mmu = "Apollo"; + else + mmu = "unknown"; + + clockfreq = loops_per_jiffy*HZ*clockfactor; + + seq_printf(m, "CPU:\t\t%s\n" "MMU:\t\t%s\n" "FPU:\t\t%s\n" "Clocking:\t%lu.%1luMHz\n" @@ -456,7 +490,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) clockfreq/1000000,(clockfreq/100000)%10, loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, loops_per_jiffy); - return 0; + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -472,54 +506,44 @@ static void c_stop(struct seq_file *m, void *v) { } 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, }; int get_hardware_list(char *buffer) { - int len = 0; - char model[80]; - unsigned long mem; - int i; + int len = 0; + char model[80]; + unsigned long mem; + int i; - if (mach_get_model) - mach_get_model(model); - else - strcpy(model, "Unknown m68k"); + if (mach_get_model) + mach_get_model(model); + else + strcpy(model, "Unknown m68k"); - len += sprintf(buffer + len, "Model:\t\t%s\n", model); - for (mem = 0, i = 0; i < m68k_num_memory; i++) - mem += m68k_memory[i].size; - len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10); + len += sprintf(buffer+len, "Model:\t\t%s\n", model); + for (mem = 0, i = 0; i < m68k_num_memory; i++) + mem += m68k_memory[i].size; + len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); - if (mach_get_hardware_list) - len += mach_get_hardware_list(buffer + len); + if (mach_get_hardware_list) + len += mach_get_hardware_list(buffer+len); - return len; + return(len); } void check_bugs(void) { #ifndef CONFIG_M68KFPU_EMU if (m68k_fputype == 0) { - printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " - "WHICH IS REQUIRED BY LINUX/M68K ***\n"); - printk(KERN_EMERG "Upgrade your hardware or join the FPU " - "emulation project\n"); - panic("no FPU"); + printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " + "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); + printk( KERN_EMERG "Upgrade your hardware or join the FPU " + "emulation project\n" ); + panic( "no FPU" ); } #endif /* !CONFIG_M68KFPU_EMU */ } - -#ifdef CONFIG_ADB -static int __init adb_probe_sync_enable (char *str) { - extern int __adb_probe_sync; - __adb_probe_sync = 1; - return 1; -} - -__setup("adb_sync", adb_probe_sync_enable); -#endif /* CONFIG_ADB */ diff --git a/trunk/arch/m68k/lib/checksum.c b/trunk/arch/m68k/lib/checksum.c index cf6bb51945a2..aed3be29e06b 100644 --- a/trunk/arch/m68k/lib/checksum.c +++ b/trunk/arch/m68k/lib/checksum.c @@ -320,9 +320,6 @@ csum_partial_copy_from_user(const void __user *src, void *dst, return(sum); } -EXPORT_SYMBOL(csum_partial_copy_from_user); - - /* * copy from kernel space while checksumming, otherwise like csum_partial */ diff --git a/trunk/arch/m68k/mac/baboon.c b/trunk/arch/m68k/mac/baboon.c index 673a1085984d..a1c7ec706741 100644 --- a/trunk/arch/m68k/mac/baboon.c +++ b/trunk/arch/m68k/mac/baboon.c @@ -22,7 +22,7 @@ /* #define DEBUG_BABOON */ /* #define DEBUG_IRQS */ -int baboon_present; +int baboon_present,baboon_active; volatile struct baboon *baboon; irqreturn_t baboon_irq(int, void *); @@ -45,6 +45,7 @@ void __init baboon_init(void) baboon = (struct baboon *) BABOON_BASE; baboon_present = 1; + baboon_active = 0; printk("Baboon detected at %p\n", baboon); } @@ -65,28 +66,26 @@ void __init baboon_register_interrupts(void) irqreturn_t baboon_irq(int irq, void *dev_id) { - int irq_bit, irq_num; + int irq_bit,i; unsigned char events; #ifdef DEBUG_IRQS - printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n", + printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n", (uint) baboon->mb_control, (uint) baboon->mb_ifr, - (uint) baboon->mb_status); + (uint) baboon->mb_status, baboon_active); #endif if (!(events = baboon->mb_ifr & 0x07)) return IRQ_NONE; - irq_num = IRQ_BABOON_0; - irq_bit = 1; - do { - if (events & irq_bit) { + for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { + if (events & irq_bit/* & baboon_active*/) { + baboon_active &= ~irq_bit; + m68k_handle_int(IRQ_BABOON_0 + i); + baboon_active |= irq_bit; baboon->mb_ifr &= ~irq_bit; - m68k_handle_int(irq_num); } - irq_bit <<= 1; - irq_num++; - } while(events >= irq_bit); + } #if 0 if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL); /* for now we need to smash all interrupts */ @@ -96,18 +95,21 @@ irqreturn_t baboon_irq(int irq, void *dev_id) } void baboon_irq_enable(int irq) { + int irq_idx = IRQ_IDX(irq); + #ifdef DEBUG_IRQUSE printk("baboon_irq_enable(%d)\n", irq); #endif - /* FIXME: figure out how to mask and unmask baboon interrupt sources */ - enable_irq(IRQ_NUBUS_C); + baboon_active |= (1 << irq_idx); } void baboon_irq_disable(int irq) { + int irq_idx = IRQ_IDX(irq); + #ifdef DEBUG_IRQUSE printk("baboon_irq_disable(%d)\n", irq); #endif - disable_irq(IRQ_NUBUS_C); + baboon_active &= ~(1 << irq_idx); } void baboon_irq_clear(int irq) { diff --git a/trunk/arch/m68k/mac/config.c b/trunk/arch/m68k/mac/config.c index 5fd413246f89..562b38d00180 100644 --- a/trunk/arch/m68k/mac/config.c +++ b/trunk/arch/m68k/mac/config.c @@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk; extern char m68k_command_line[CL_SIZE]; -void *mac_env; /* Loaded by the boot asm */ +void *mac_env; /* Loaded by the boot asm */ /* The phys. video addr. - might be bogus on some machines */ unsigned long mac_orig_videoaddr; /* Mac specific timer functions */ -extern unsigned long mac_gettimeoffset(void); -extern int mac_hwclk(int, struct rtc_time *); -extern int mac_set_clock_mmss(unsigned long); +extern unsigned long mac_gettimeoffset (void); +extern int mac_hwclk (int, struct rtc_time *); +extern int mac_set_clock_mmss (unsigned long); extern int show_mac_interrupts(struct seq_file *, void *); extern void iop_preinit(void); extern void iop_init(void); @@ -82,6 +82,10 @@ extern void mac_mksound(unsigned int, unsigned int); extern void nubus_sweep_video(void); +/* Mac specific debug functions (in debug.c) */ +extern void mac_debug_init(void); +extern void mac_debugging_long(int, long); + static void mac_get_model(char *str); static void mac_sched_init(irq_handler_t vector) @@ -95,52 +99,51 @@ static void mac_sched_init(irq_handler_t vector) int __init mac_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const u_long *data = record->data; + int unknown = 0; + const u_long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_MAC_MODEL: - mac_bi_data.id = *data; - break; + mac_bi_data.id = *data; + break; case BI_MAC_VADDR: - mac_bi_data.videoaddr = *data; - break; + mac_bi_data.videoaddr = *data; + break; case BI_MAC_VDEPTH: - mac_bi_data.videodepth = *data; - break; + mac_bi_data.videodepth = *data; + break; case BI_MAC_VROW: - mac_bi_data.videorow = *data; - break; + mac_bi_data.videorow = *data; + break; case BI_MAC_VDIM: - mac_bi_data.dimensions = *data; - break; + mac_bi_data.dimensions = *data; + break; case BI_MAC_VLOGICAL: - mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); - mac_orig_videoaddr = *data; - break; + mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_orig_videoaddr = *data; + break; case BI_MAC_SCCBASE: - mac_bi_data.sccbase = *data; - break; + mac_bi_data.sccbase = *data; + break; case BI_MAC_BTIME: - mac_bi_data.boottime = *data; - break; + mac_bi_data.boottime = *data; + break; case BI_MAC_GMTBIAS: - mac_bi_data.gmtbias = *data; - break; + mac_bi_data.gmtbias = *data; + break; case BI_MAC_MEMSIZE: - mac_bi_data.memsize = *data; - break; + mac_bi_data.memsize = *data; + break; case BI_MAC_CPUID: - mac_bi_data.cpuid = *data; - break; - case BI_MAC_ROMBASE: - mac_bi_data.rombase = *data; - break; + mac_bi_data.cpuid = *data; + break; + case BI_MAC_ROMBASE: + mac_bi_data.rombase = *data; + break; default: - unknown = 1; - break; - } - return unknown; + unknown = 1; + } + return(unknown); } /* @@ -152,7 +155,6 @@ int __init mac_parse_bootinfo(const struct bi_record *record) static void mac_cache_card_flush(int writeback) { unsigned long flags; - local_irq_save(flags); via_flush_cache(); local_irq_restore(flags); @@ -160,24 +162,28 @@ static void mac_cache_card_flush(int writeback) void __init config_mac(void) { - if (!MACH_IS_MAC) - printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); + if (!MACH_IS_MAC) { + printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); + } - mach_sched_init = mac_sched_init; - mach_init_IRQ = mac_init_IRQ; - mach_get_model = mac_get_model; - mach_gettimeoffset = mac_gettimeoffset; + mach_sched_init = mac_sched_init; + mach_init_IRQ = mac_init_IRQ; + mach_get_model = mac_get_model; + mach_gettimeoffset = mac_gettimeoffset; #warning move to adb/via init #if 0 - mach_hwclk = mac_hwclk; + mach_hwclk = mac_hwclk; #endif - mach_set_clock_mmss = mac_set_clock_mmss; - mach_reset = mac_reset; - mach_halt = mac_poweroff; - mach_power_off = mac_poweroff; + mach_set_clock_mmss = mac_set_clock_mmss; + mach_reset = mac_reset; + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; mach_max_dma_address = 0xffffffff; +#if 0 + mach_debug_init = mac_debug_init; +#endif #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = mac_mksound; + mach_beep = mac_mksound; #endif #ifdef CONFIG_HEARTBEAT #if 0 @@ -193,22 +199,21 @@ void __init config_mac(void) mac_identify(); mac_report_hardware(); - /* - * AFAIK only the IIci takes a cache card. The IIfx has onboard - * cache ... someone needs to figure out how to tell if it's on or - * not. - */ + /* AFAIK only the IIci takes a cache card. The IIfx has onboard + cache ... someone needs to figure out how to tell if it's on or + not. */ if (macintosh_config->ident == MAC_MODEL_IICI - || macintosh_config->ident == MAC_MODEL_IIFX) + || macintosh_config->ident == MAC_MODEL_IIFX) { mach_l2_flush = mac_cache_card_flush; + } /* * Check for machine specific fixups. */ #ifdef OLD_NUBUS_CODE - nubus_sweep_video(); + nubus_sweep_video(); #endif } @@ -228,7 +233,8 @@ void __init config_mac(void) struct mac_model *macintosh_config; EXPORT_SYMBOL(macintosh_config); -static struct mac_model mac_data_table[] = { +static struct mac_model mac_data_table[]= +{ /* * We'll pretend to be a Macintosh II, that's pretty safe. */ @@ -778,12 +784,12 @@ void mac_identify(void) if (!model) { /* no bootinfo model id -> NetBSD booter was used! */ /* XXX FIXME: breaks for model > 31 */ - model = (mac_bi_data.cpuid >> 2) & 63; - printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); + model=(mac_bi_data.cpuid>>2)&63; + printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); } macintosh_config = mac_data_table; - for (m = macintosh_config; m->ident != -1; m++) { + for (m = macintosh_config ; m->ident != -1 ; m++) { if (m->ident == model) { macintosh_config = m; break; @@ -795,26 +801,27 @@ void mac_identify(void) /* the serial ports set to "Faster" mode in MacOS. */ iop_preinit(); + mac_debug_init(); - printk(KERN_INFO "Detected Macintosh model: %d \n", model); + printk (KERN_INFO "Detected Macintosh model: %d \n", model); /* * Report booter data: */ - printk(KERN_DEBUG " Penguin bootinfo data:\n"); - printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", + printk (KERN_DEBUG " Penguin bootinfo data:\n"); + printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", mac_bi_data.videoaddr, mac_bi_data.videorow, mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, mac_bi_data.dimensions >> 16); - printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", + printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", mac_bi_data.videological, mac_orig_videoaddr, mac_bi_data.sccbase); - printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", + printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", mac_bi_data.boottime, mac_bi_data.gmtbias); - printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); #if 0 - printk("Ramdisk: addr 0x%lx size 0x%lx\n", + printk ("Ramdisk: addr 0x%lx size 0x%lx\n", m68k_ramdisk.addr, m68k_ramdisk.size); #endif @@ -823,22 +830,22 @@ void mac_identify(void) */ switch (macintosh_config->scsi_type) { case MAC_SCSI_OLD: - MACHW_SET(MAC_SCSI_80); - break; + MACHW_SET(MAC_SCSI_80); + break; case MAC_SCSI_QUADRA: case MAC_SCSI_QUADRA2: case MAC_SCSI_QUADRA3: - MACHW_SET(MAC_SCSI_96); - if ((macintosh_config->ident == MAC_MODEL_Q900) || - (macintosh_config->ident == MAC_MODEL_Q950)) - MACHW_SET(MAC_SCSI_96_2); - break; + MACHW_SET(MAC_SCSI_96); + if ((macintosh_config->ident == MAC_MODEL_Q900) || + (macintosh_config->ident == MAC_MODEL_Q950)) + MACHW_SET(MAC_SCSI_96_2); + break; default: - printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); - MACHW_SET(MAC_SCSI_80); - break; - } + printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); + MACHW_SET(MAC_SCSI_80); + break; + } iop_init(); via_init(); oss_init(); @@ -853,6 +860,6 @@ void mac_report_hardware(void) static void mac_get_model(char *str) { - strcpy(str, "Macintosh "); + strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); } diff --git a/trunk/arch/m68k/mac/debug.c b/trunk/arch/m68k/mac/debug.c index 7a5bed5bdc57..4eeb09dc0e8f 100644 --- a/trunk/arch/m68k/mac/debug.c +++ b/trunk/arch/m68k/mac/debug.c @@ -27,6 +27,10 @@ #include #include +extern char m68k_debug_device[]; + +extern struct compat_bootinfo compat_boot_info; + extern unsigned long mac_videobase; extern unsigned long mac_videodepth; extern unsigned long mac_rowbytes; @@ -48,7 +52,7 @@ extern void mac_serial_print(const char *); */ #ifdef DEBUG_SCREEN -static int peng, line; +static int peng=0, line=0; #endif void mac_debugging_short(int pos, short num) @@ -70,14 +74,15 @@ void mac_debugging_short(int pos, short num) } /* calculate current offset */ - pengoffset = (unsigned char *)mac_videobase + - (150+line*2) * mac_rowbytes) + 80 * peng; + pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) + +80*peng; - pptr = pengoffset; + pptr=pengoffset; - for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */ + for(i=0;i<8*sizeof(short);i++) /* # of bits */ + { /* value mask for bit i, reverse order */ - *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00); + *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00); } peng++; @@ -110,10 +115,11 @@ void mac_debugging_long(int pos, long addr) pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) +80*peng; - pptr = pengoffset; + pptr=pengoffset; - for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */ - *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00); + for(i=0;i<8*sizeof(long);i++) /* # of bits */ + { + *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00); } peng++; @@ -130,15 +136,16 @@ void mac_debugging_long(int pos, long addr) * TODO: serial debug code */ -struct mac_SCC { - u_char cha_b_ctrl; - u_char char_dummy1; - u_char cha_a_ctrl; - u_char char_dummy2; - u_char cha_b_data; - u_char char_dummy3; - u_char cha_a_data; -}; +struct mac_SCC + { + u_char cha_b_ctrl; + u_char char_dummy1; + u_char cha_a_ctrl; + u_char char_dummy2; + u_char cha_b_data; + u_char char_dummy3; + u_char cha_a_data; + }; # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase)) @@ -151,9 +158,9 @@ int mac_SCC_reset_done; static int scc_port = -1; static struct console mac_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; /* @@ -171,8 +178,8 @@ static struct console mac_console_driver = { * this driver if Mac. */ -void mac_debug_console_write(struct console *co, const char *str, - unsigned int count) +void mac_debug_console_write (struct console *co, const char *str, + unsigned int count) { mac_serial_print(str); } @@ -183,50 +190,48 @@ void mac_debug_console_write(struct console *co, const char *str, #define uSEC 1 -static inline void mac_sccb_out(char c) +static inline void mac_sccb_out (char c) { - int i; - - do { - for (i = uSEC; i > 0; --i) - barrier(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - for (i = uSEC; i > 0; --i) + int i; + do { + for( i = uSEC; i > 0; --i ) barrier(); - scc.cha_b_data = c; + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_b_data = c; } -static inline void mac_scca_out(char c) +static inline void mac_scca_out (char c) { - int i; - - do { - for (i = uSEC; i > 0; --i) - barrier(); - } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ - for (i = uSEC; i > 0; --i) + int i; + do { + for( i = uSEC; i > 0; --i ) barrier(); - scc.cha_a_data = c; + } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_a_data = c; } -void mac_sccb_console_write(struct console *co, const char *str, - unsigned int count) +void mac_sccb_console_write (struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - mac_sccb_out('\r'); - mac_sccb_out(*str++); - } + while (count--) { + if (*str == '\n') + mac_sccb_out( '\r' ); + mac_sccb_out( *str++ ); + } } -void mac_scca_console_write(struct console *co, const char *str, - unsigned int count) +void mac_scca_console_write (struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - mac_scca_out('\r'); - mac_scca_out(*str++); - } + while (count--) { + if (*str == '\n') + mac_scca_out( '\r' ); + mac_scca_out( *str++ ); + } } @@ -234,41 +239,41 @@ void mac_scca_console_write(struct console *co, const char *str, * SCC serial ports. They're used by the debugging interface, kgdb, and the * serial console code. */ #define SCCB_WRITE(reg,val) \ - do { \ - int i; \ - scc.cha_b_ctrl = (reg); \ - for (i = uSEC; i > 0; --i) \ - barrier(); \ - scc.cha_b_ctrl = (val); \ - for (i = uSEC; i > 0; --i) \ - barrier(); \ - } while(0) + do { \ + int i; \ + scc.cha_b_ctrl = (reg); \ + for( i = uSEC; i > 0; --i ) \ + barrier(); \ + scc.cha_b_ctrl = (val); \ + for( i = uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) #define SCCA_WRITE(reg,val) \ - do { \ - int i; \ - scc.cha_a_ctrl = (reg); \ - for (i = uSEC; i > 0; --i) \ - barrier(); \ - scc.cha_a_ctrl = (val); \ - for (i = uSEC; i > 0; --i) \ - barrier(); \ - } while(0) + do { \ + int i; \ + scc.cha_a_ctrl = (reg); \ + for( i = uSEC; i > 0; --i ) \ + barrier(); \ + scc.cha_a_ctrl = (val); \ + for( i = uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a * delay of ~ 60us. */ /* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/ -#define LONG_DELAY() \ - do { \ - int i; \ - for (i = 60*uSEC; i > 0; --i) \ - barrier(); \ - } while(0) +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 60*uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) #ifndef CONFIG_SERIAL_CONSOLE -static void __init mac_init_scc_port(int cflag, int port) +static void __init mac_init_scc_port( int cflag, int port ) #else -void mac_init_scc_port(int cflag, int port) +void mac_init_scc_port( int cflag, int port ) #endif { extern int mac_SCC_reset_done; @@ -287,102 +292,106 @@ void mac_init_scc_port(int cflag, int port) /* reg12 (BRG low) */ { 94, 62, 46, 22, 10, 4, 1, 0, 0 }; - int baud = cflag & CBAUD; - int clksrc, clkmode, div, reg3, reg5; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* tables starts at 1200bps */ - - clksrc = clksrc_table[baud]; - clkmode = clkmode_table[baud]; - div = div_table[baud]; - - reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); - reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; - - if (port == 1) { - (void)scc.cha_b_ctrl; /* reset reg pointer */ - SCCB_WRITE(9, 0xc0); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | - 0x04 /* 1 stopbit */ | - clkmode); - SCCB_WRITE(3, reg3); - SCCB_WRITE(5, reg5); - SCCB_WRITE(9, 0); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCB_WRITE(10, 0); /* NRZ mode */ - SCCB_WRITE(11, clksrc); /* main clock source */ - SCCB_WRITE(12, div); /* BRG value */ - SCCB_WRITE(13, 0); /* BRG high byte */ - SCCB_WRITE(14, 1); - SCCB_WRITE(3, reg3 | 1); - SCCB_WRITE(5, reg5 | 8); - } else if (port == 0) { - (void)scc.cha_a_ctrl; /* reset reg pointer */ - SCCA_WRITE(9, 0xc0); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | - 0x04 /* 1 stopbit */ | - clkmode); - SCCA_WRITE(3, reg3); - SCCA_WRITE(5, reg5); - SCCA_WRITE(9, 0); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCA_WRITE(10, 0); /* NRZ mode */ - SCCA_WRITE(11, clksrc); /* main clock source */ - SCCA_WRITE(12, div); /* BRG value */ - SCCA_WRITE(13, 0); /* BRG high byte */ - SCCA_WRITE(14, 1); - SCCA_WRITE(3, reg3 | 1); - SCCA_WRITE(5, reg5 | 8); - } + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; - mac_SCC_reset_done = 1; - mac_SCC_init_done = 1; + reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); + reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; + + if (port == 1) { + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCCB_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCCB_WRITE( 3, reg3 ); + SCCB_WRITE( 5, reg5 ); + SCCB_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCB_WRITE( 10, 0 ); /* NRZ mode */ + SCCB_WRITE( 11, clksrc ); /* main clock source */ + SCCB_WRITE( 12, div ); /* BRG value */ + SCCB_WRITE( 13, 0 ); /* BRG high byte */ + SCCB_WRITE( 14, 1 ); + SCCB_WRITE( 3, reg3 | 1 ); + SCCB_WRITE( 5, reg5 | 8 ); + } else if (port == 0) { + (void)scc.cha_a_ctrl; /* reset reg pointer */ + SCCA_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCCA_WRITE( 3, reg3 ); + SCCA_WRITE( 5, reg5 ); + SCCA_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCA_WRITE( 10, 0 ); /* NRZ mode */ + SCCA_WRITE( 11, clksrc ); /* main clock source */ + SCCA_WRITE( 12, div ); /* BRG value */ + SCCA_WRITE( 13, 0 ); /* BRG high byte */ + SCCA_WRITE( 14, 1 ); + SCCA_WRITE( 3, reg3 | 1 ); + SCCA_WRITE( 5, reg5 | 8 ); + } + + mac_SCC_reset_done = 1; + mac_SCC_init_done = 1; } #endif /* DEBUG_SERIAL */ -void mac_init_scca_port(int cflag) +void mac_init_scca_port( int cflag ) { mac_init_scc_port(cflag, 0); } -void mac_init_sccb_port(int cflag) +void mac_init_sccb_port( int cflag ) { mac_init_scc_port(cflag, 1); } -static int __init mac_debug_setup(char *arg) +void __init mac_debug_init(void) { - if (!MACH_IS_MAC) - return 0; - #ifdef DEBUG_SERIAL - if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) { - /* Mac modem port */ - mac_init_scc_port(B9600|CS8, 0); - mac_console_driver.write = mac_scca_console_write; - scc_port = 0; - } else if (!strcmp(arg, "ser2")) { - /* Mac printer port */ - mac_init_scc_port(B9600|CS8, 1); - mac_console_driver.write = mac_sccb_console_write; - scc_port = 1; - } + if ( !strcmp( m68k_debug_device, "ser" ) + || !strcmp( m68k_debug_device, "ser1" )) { + /* Mac modem port */ + mac_init_scc_port( B9600|CS8, 0 ); + mac_console_driver.write = mac_scca_console_write; + scc_port = 0; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* Mac printer port */ + mac_init_scc_port( B9600|CS8, 1 ); + mac_console_driver.write = mac_sccb_console_write; + scc_port = 1; + } #endif #ifdef DEBUG_HEADS - if (!strcmp(arg, "scn") || !strcmp(arg, "con")) { - /* display, using head.S console routines */ - mac_console_driver.write = mac_debug_console_write; - } + if ( !strcmp( m68k_debug_device, "scn" ) + || !strcmp( m68k_debug_device, "con" )) { + /* display, using head.S console routines */ + mac_console_driver.write = mac_debug_console_write; + } #endif - if (mac_console_driver.write) - register_console(&mac_console_driver); - return 0; + if (mac_console_driver.write) + register_console(&mac_console_driver); } -early_param("debug", mac_debug_setup); +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff --git a/trunk/arch/m68k/mac/oss.c b/trunk/arch/m68k/mac/oss.c index d7be16917efd..63690819565a 100644 --- a/trunk/arch/m68k/mac/oss.c +++ b/trunk/arch/m68k/mac/oss.c @@ -109,11 +109,13 @@ irqreturn_t oss_irq(int irq, void *dev_id) /* FIXME: how do you clear a pending IRQ? */ if (events & OSS_IP_SOUND) { - oss->irq_pending &= ~OSS_IP_SOUND; /* FIXME: call sound handler */ + oss->irq_pending &= ~OSS_IP_SOUND; } else if (events & OSS_IP_SCSI) { - oss->irq_pending &= ~OSS_IP_SCSI; + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; m68k_handle_int(IRQ_MAC_SCSI); + oss->irq_pending &= ~OSS_IP_SCSI; + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; } else { /* FIXME: error check here? */ } @@ -141,16 +143,14 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id) #endif /* There are only six slots on the OSS, not seven */ - i = 6; - irq_bit = 0x40; - do { - --i; - irq_bit >>= 1; + for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { if (events & irq_bit) { - oss->irq_pending &= ~irq_bit; + oss->irq_level[i] = OSS_IRQLEV_DISABLED; m68k_handle_int(NUBUS_SOURCE_BASE + i); + oss->irq_pending &= ~irq_bit; + oss->irq_level[i] = OSS_IRQLEV_NUBUS; } - } while(events & (irq_bit - 1)); + } return IRQ_HANDLED; } diff --git a/trunk/arch/m68k/mac/psc.c b/trunk/arch/m68k/mac/psc.c index d66f723b17c3..15378a5878c9 100644 --- a/trunk/arch/m68k/mac/psc.c +++ b/trunk/arch/m68k/mac/psc.c @@ -131,8 +131,11 @@ irqreturn_t psc_irq(int irq, void *dev_id) { int pIFR = pIFRbase + ((int) dev_id); int pIER = pIERbase + ((int) dev_id); - int irq_num; - unsigned char irq_bit, events; + int base_irq; + int irq_bit,i; + unsigned char events; + + base_irq = irq << 3; #ifdef DEBUG_IRQS printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n", @@ -143,16 +146,14 @@ irqreturn_t psc_irq(int irq, void *dev_id) if (!events) return IRQ_NONE; - irq_num = irq << 3; - irq_bit = 1; - do { - if (events & irq_bit) { + for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + psc_write_byte(pIER, irq_bit); + m68k_handle_int(base_irq + i); psc_write_byte(pIFR, irq_bit); - m68k_handle_int(irq_num); + psc_write_byte(pIER, irq_bit | 0x80); } - irq_num++; - irq_bit <<= 1; - } while (events >= irq_bit); + } return IRQ_HANDLED; } diff --git a/trunk/arch/m68k/mac/via.c b/trunk/arch/m68k/mac/via.c index d5cac72eb3db..e27735be2924 100644 --- a/trunk/arch/m68k/mac/via.c +++ b/trunk/arch/m68k/mac/via.c @@ -13,10 +13,6 @@ * for info. A full-text web search on 6522 AND VIA will probably also * net some usefulness. 20apr1999 * - * Additional data is here (the SY6522 was used in the Mac II etc): - * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf - * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf - * * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) * @@ -41,7 +37,7 @@ volatile __u8 *via1, *via2; /* See note in mac_via.h about how this is possibly not useful */ volatile long *via_memory_bogon=(long *)&via_memory_bogon; #endif -int rbv_present, via_alt_mapping; +int rbv_present,via_alt_mapping; __u8 rbv_clear; /* @@ -64,19 +60,7 @@ static int gIER,gIFR,gBufA,gBufB; #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set - * high. On RBV we just use the slot interrupt enable register. On Macs with - * genuine VIA chips we must use nubus_disabled to keep track of disabled slot - * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 - * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. - * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble, - * because closing one of those drivers can mask all of the NuBus interrupts. - * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's - * possible to get interrupts from cards that MacOS or the ROM has configured - * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and - * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. - */ -static u8 nubus_disabled; +static int nubus_active; void via_debug_dump(void); irqreturn_t via1_irq(int, void *); @@ -154,11 +138,11 @@ void __init via_init(void) printk(KERN_INFO "VIA2 at %p is ", via2); if (rbv_present) { - printk("an RBV\n"); + printk(KERN_INFO "an RBV\n"); } else if (oss_present) { - printk("an OSS\n"); + printk(KERN_INFO "an OSS\n"); } else { - printk("a 6522 or clone\n"); + printk(KERN_INFO "a 6522 or clone\n"); } #ifdef DEBUG_VIA @@ -179,7 +163,6 @@ void __init via_init(void) via1[vT2CL] = 0; via1[vT2CH] = 0; via1[vACR] &= 0x3F; - via1[vACR] &= ~0x03; /* disable port A & B latches */ /* * SE/30: disable video IRQ @@ -210,14 +193,8 @@ void __init via_init(void) /* that the IIfx emulates this alternate mapping using the OSS. */ switch(macintosh_config->ident) { - case MAC_MODEL_P475: - case MAC_MODEL_P475F: - case MAC_MODEL_P575: - case MAC_MODEL_Q605: - case MAC_MODEL_Q605_ACC: case MAC_MODEL_C610: case MAC_MODEL_Q610: - case MAC_MODEL_Q630: case MAC_MODEL_C650: case MAC_MODEL_Q650: case MAC_MODEL_Q700: @@ -251,22 +228,6 @@ void __init via_init(void) via2[vT2CL] = 0; via2[vT2CH] = 0; via2[vACR] &= 0x3F; - via2[vACR] &= ~0x03; /* disable port A & B latches */ - } - - /* - * Set vPCR for SCSI interrupts (but not on RBV) - */ - if (!rbv_present) { - if (macintosh_config->scsi_type == MAC_SCSI_OLD) { - /* CB2 (IRQ) indep. input, positive edge */ - /* CA2 (DRQ) indep. input, positive edge */ - via2[vPCR] = 0x66; - } else { - /* CB2 (IRQ) indep. input, negative edge */ - /* CA2 (DRQ) indep. input, negative edge */ - via2[vPCR] = 0x22; - } } } @@ -395,75 +356,78 @@ int via_get_cache_disable(void) void __init via_nubus_init(void) { + /* don't set nubus_active = 0 here, it kills the Baboon */ + /* interrupt that we've already registered. */ + /* unlock nubus transactions */ - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { + if (!rbv_present) { /* set the line to be an output on non-RBV machines */ - if (!rbv_present) + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { via2[vDirB] |= 0x02; + } + } - /* this seems to be an ADB bit on PMU machines */ - /* according to MkLinux. -- jmt */ + /* this seems to be an ADB bit on PMU machines */ + /* according to MkLinux. -- jmt */ + + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { via2[gBufB] |= 0x02; } - /* Disable all the slot interrupts (where possible). */ - - switch (macintosh_config->via_type) { - case MAC_VIA_II: - /* Just make the port A lines inputs. */ - switch(macintosh_config->ident) { - case MAC_MODEL_II: - case MAC_MODEL_IIX: - case MAC_MODEL_IICX: - case MAC_MODEL_SE30: - /* The top two bits are RAM size outputs. */ - via2[vDirA] &= 0xC0; - break; - default: - via2[vDirA] &= 0x80; - } - break; - case MAC_VIA_IIci: - /* RBV. Disable all the slot interrupts. SIER works like IER. */ + /* disable nubus slot interrupts. */ + if (rbv_present) { via2[rSIER] = 0x7F; - break; - case MAC_VIA_QUADRA: - /* Disable the inactive slot interrupts by making those lines outputs. */ + via2[rSIER] = nubus_active | 0x80; + } else { + /* These are ADB bits on PMU */ if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { - via2[vBufA] |= 0x7F; - via2[vDirA] |= 0x7F; + (macintosh_config->adb_type != MAC_ADB_PB2)) { + switch(macintosh_config->ident) + { + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + via2[vBufA] |= 0x3F; + via2[vDirA] = ~nubus_active | 0xc0; + break; + default: + via2[vBufA] = 0xFF; + via2[vDirA] = ~nubus_active; + } } - break; } } /* * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's * via6522.c :-), disable/pending masks added. + * + * The new interrupt architecture in macints.c takes care of a lot of the + * gruntwork for us, including tallying the interrupts and calling the + * handlers on the linked list. All we need to do here is basically generate + * the machspec interrupt number after clearing the interrupt. */ irqreturn_t via1_irq(int irq, void *dev_id) { - int irq_num; - unsigned char irq_bit, events; + int irq_bit, i; + unsigned char events, mask; - events = via1[vIFR] & via1[vIER] & 0x7F; - if (!events) + mask = via1[vIER] & 0x7F; + if (!(events = via1[vIFR] & mask)) return IRQ_NONE; - irq_num = VIA1_SOURCE_BASE; - irq_bit = 1; - do { + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) if (events & irq_bit) { + via1[vIER] = irq_bit; + m68k_handle_int(VIA1_SOURCE_BASE + i); via1[vIFR] = irq_bit; - m68k_handle_int(irq_num); + via1[vIER] = irq_bit | 0x80; } - ++irq_num; - irq_bit <<= 1; - } while (events >= irq_bit); #if 0 /* freakin' pmu is doing weird stuff */ if (!oss_present) { @@ -484,23 +448,20 @@ irqreturn_t via1_irq(int irq, void *dev_id) irqreturn_t via2_irq(int irq, void *dev_id) { - int irq_num; - unsigned char irq_bit, events; + int irq_bit, i; + unsigned char events, mask; - events = via2[gIFR] & via2[gIER] & 0x7F; - if (!events) + mask = via2[gIER] & 0x7F; + if (!(events = via2[gIFR] & mask)) return IRQ_NONE; - irq_num = VIA2_SOURCE_BASE; - irq_bit = 1; - do { + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) if (events & irq_bit) { + via2[gIER] = irq_bit; via2[gIFR] = irq_bit | rbv_clear; - m68k_handle_int(irq_num); + m68k_handle_int(VIA2_SOURCE_BASE + i); + via2[gIER] = irq_bit | 0x80; } - ++irq_num; - irq_bit <<= 1; - } while (events >= irq_bit); return IRQ_HANDLED; } @@ -511,75 +472,71 @@ irqreturn_t via2_irq(int irq, void *dev_id) irqreturn_t via_nubus_irq(int irq, void *dev_id) { - int slot_irq; - unsigned char slot_bit, events; - - events = ~via2[gBufA] & 0x7F; - if (rbv_present) - events &= via2[rSIER]; - else - events &= ~via2[vDirA]; - if (!events) + int irq_bit, i; + unsigned char events; + + if (!(events = ~via2[gBufA] & nubus_active)) return IRQ_NONE; - do { - slot_irq = IRQ_NUBUS_F; - slot_bit = 0x40; - do { - if (events & slot_bit) { - events &= ~slot_bit; - m68k_handle_int(slot_irq); - } - --slot_irq; - slot_bit >>= 1; - } while (events); - - /* clear the CA1 interrupt and make certain there's no more. */ - via2[gIFR] = 0x02 | rbv_clear; - events = ~via2[gBufA] & 0x7F; - if (rbv_present) - events &= via2[rSIER]; - else - events &= ~via2[vDirA]; - } while (events); + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + via_irq_disable(NUBUS_SOURCE_BASE + i); + m68k_handle_int(NUBUS_SOURCE_BASE + i); + via_irq_enable(NUBUS_SOURCE_BASE + i); + } + } return IRQ_HANDLED; } void via_irq_enable(int irq) { int irq_src = IRQ_SRC(irq); int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); #endif if (irq_src == 1) { - via1[vIER] = IER_SET_BIT(irq_idx); + via1[vIER] = irq_bit | 0x80; } else if (irq_src == 2) { - if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0) - via2[gIER] = IER_SET_BIT(irq_idx); + /* + * Set vPCR for SCSI interrupts (but not on RBV) + */ + if ((irq_idx == 0) && !rbv_present) { + if (macintosh_config->scsi_type == MAC_SCSI_OLD) { + /* CB2 (IRQ) indep. input, positive edge */ + /* CA2 (DRQ) indep. input, positive edge */ + via2[vPCR] = 0x66; + } else { + /* CB2 (IRQ) indep. input, negative edge */ + /* CA2 (DRQ) indep. input, negative edge */ + via2[vPCR] = 0x22; + } + } + via2[gIER] = irq_bit | 0x80; } else if (irq_src == 7) { - switch (macintosh_config->via_type) { - case MAC_VIA_II: - nubus_disabled &= ~(1 << irq_idx); - /* Enable the CA1 interrupt when no slot is disabled. */ - if (!nubus_disabled) - via2[gIER] = IER_SET_BIT(1); - break; - case MAC_VIA_IIci: - /* On RBV, enable the slot interrupt. - * SIER works like IER. - */ + nubus_active |= irq_bit; + if (rbv_present) { + /* enable the slot interrupt. SIER works like IER. */ via2[rSIER] = IER_SET_BIT(irq_idx); - break; - case MAC_VIA_QUADRA: - /* Make the port A line an input to enable the slot irq. - * But not on PowerBooks, that's ADB. - */ + } else { + /* Make sure the bit is an input, to enable the irq */ + /* But not on PowerBooks, that's ADB... */ if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) - via2[vDirA] &= ~(1 << irq_idx); - break; + (macintosh_config->adb_type != MAC_ADB_PB2)) { + switch(macintosh_config->ident) + { + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + via2[vDirA] &= (~irq_bit | 0xc0); + break; + default: + via2[vDirA] &= ~irq_bit; + } + } } } } @@ -587,31 +544,29 @@ void via_irq_enable(int irq) { void via_irq_disable(int irq) { int irq_src = IRQ_SRC(irq); int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); #endif if (irq_src == 1) { - via1[vIER] = IER_CLR_BIT(irq_idx); + via1[vIER] = irq_bit; } else if (irq_src == 2) { - via2[gIER] = IER_CLR_BIT(irq_idx); + via2[gIER] = irq_bit; } else if (irq_src == 7) { - switch (macintosh_config->via_type) { - case MAC_VIA_II: - nubus_disabled |= 1 << irq_idx; - if (nubus_disabled) - via2[gIER] = IER_CLR_BIT(1); - break; - case MAC_VIA_IIci: + if (rbv_present) { + /* disable the slot interrupt. SIER works like IER. */ via2[rSIER] = IER_CLR_BIT(irq_idx); - break; - case MAC_VIA_QUADRA: + } else { + /* disable the nubus irq by changing dir to output */ + /* except on PMU */ if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) - via2[vDirA] |= 1 << irq_idx; - break; + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[vDirA] |= irq_bit; + } } + nubus_active &= ~irq_bit; } } @@ -625,9 +580,7 @@ void via_irq_clear(int irq) { } else if (irq_src == 2) { via2[gIFR] = irq_bit | rbv_clear; } else if (irq_src == 7) { - /* FIXME: There is no way to clear an individual nubus slot - * IRQ flag, other than getting the device to do it. - */ + /* FIXME: hmm.. */ } } @@ -647,7 +600,6 @@ int via_irq_pending(int irq) } else if (irq_src == 2) { return via2[gIFR] & irq_bit; } else if (irq_src == 7) { - /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */ return ~via2[gBufA] & irq_bit; } return 0; diff --git a/trunk/arch/m68k/q40/config.c b/trunk/arch/m68k/q40/config.c index 476e18eca758..92f873cc7060 100644 --- a/trunk/arch/m68k/q40/config.c +++ b/trunk/arch/m68k/q40/config.c @@ -35,35 +35,35 @@ #include #include -extern irqreturn_t q40_process_int(int level, struct pt_regs *regs); -extern void q40_init_IRQ(void); +extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); +extern void q40_init_IRQ (void); static void q40_get_model(char *model); static int q40_get_hardware_list(char *buffer); extern void q40_sched_init(irq_handler_t handler); -extern unsigned long q40_gettimeoffset(void); -extern int q40_hwclk(int, struct rtc_time *); -extern unsigned int q40_get_ss(void); -extern int q40_set_clock_mmss(unsigned long); +extern unsigned long q40_gettimeoffset (void); +extern int q40_hwclk (int, struct rtc_time *); +extern unsigned int q40_get_ss (void); +extern int q40_set_clock_mmss (unsigned long); static int q40_get_rtc_pll(struct rtc_pll_info *pll); static int q40_set_rtc_pll(struct rtc_pll_info *pll); -extern void q40_reset(void); +extern void q40_reset (void); void q40_halt(void); extern void q40_waitbut(void); -void q40_set_vectors(void); +void q40_set_vectors (void); -extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/); +extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ ); +extern char m68k_debug_device[]; static void q40_mem_console_write(struct console *co, const char *b, - unsigned int count); + unsigned int count); extern int ql_ticks; static struct console q40_console_driver = { - .name = "debug", - .write = q40_mem_console_write, - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; @@ -74,162 +74,150 @@ static int _cpleft; static void q40_mem_console_write(struct console *co, const char *s, unsigned int count) { - const char *p = s; - - if (count < _cpleft) { - while (count-- > 0) { - *q40_mem_cptr = *p++; - q40_mem_cptr += 4; - _cpleft--; - } - } -} - -static int __init q40_debug_setup(char *arg) -{ - /* useful for early debugging stages - writes kernel messages into SRAM */ - if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) { - /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ - _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4; - register_console(&q40_console_driver); - } - return 0; + char *p=(char *)s; + + if (count<_cpleft) + while (count-- >0){ + *q40_mem_cptr=*p++; + q40_mem_cptr+=4; + _cpleft--; + } } - -early_param("debug", q40_debug_setup); - #if 0 void printq40(char *str) { - int l = strlen(str); - char *p = q40_mem_cptr; - - while (l-- > 0 && _cpleft-- > 0) { - *p = *str++; - p += 4; - } - q40_mem_cptr = p; + int l=strlen(str); + char *p=q40_mem_cptr; + + while (l-- >0 && _cpleft-- >0) + { + *p=*str++; + p+=4; + } + q40_mem_cptr=p; } #endif -static int halted; +static int halted=0; #ifdef CONFIG_HEARTBEAT static void q40_heartbeat(int on) { - if (halted) - return; + if (halted) return; - if (on) - Q40_LED_ON(); - else - Q40_LED_OFF(); + if (on) + Q40_LED_ON(); + else + Q40_LED_OFF(); } #endif void q40_reset(void) { - halted = 1; - printk("\n\n*******************************************\n" + halted=1; + printk ("\n\n*******************************************\n" "Called q40_reset : press the RESET button!! \n" "*******************************************\n"); Q40_LED_ON(); - while (1) - ; + while(1) ; } void q40_halt(void) { - halted = 1; - printk("\n\n*******************\n" - " Called q40_halt\n" - "*******************\n"); + halted=1; + printk ("\n\n*******************\n" + " Called q40_halt\n" + "*******************\n"); Q40_LED_ON(); - while (1) - ; + while(1) ; } static void q40_get_model(char *model) { - sprintf(model, "Q40"); + sprintf(model, "Q40"); } /* No hardware options on Q40? */ static int q40_get_hardware_list(char *buffer) { - *buffer = '\0'; - return 0; + *buffer = '\0'; + return 0; } -static unsigned int serports[] = -{ - 0x3f8,0x2f8,0x3e8,0x2e8,0 -}; +static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0}; void q40_disable_irqs(void) { - unsigned i, j; + unsigned i,j; - j = 0; - while ((i = serports[j++])) - outb(0, i + UART_IER); - master_outb(0, EXT_ENABLE_REG); - master_outb(0, KEY_IRQ_ENABLE_REG); + j=0; + while((i=serports[j++])) outb(0,i+UART_IER); + master_outb(0,EXT_ENABLE_REG); + master_outb(0,KEY_IRQ_ENABLE_REG); } void __init config_q40(void) { - mach_sched_init = q40_sched_init; + mach_sched_init = q40_sched_init; - mach_init_IRQ = q40_init_IRQ; - mach_gettimeoffset = q40_gettimeoffset; - mach_hwclk = q40_hwclk; - mach_get_ss = q40_get_ss; - mach_get_rtc_pll = q40_get_rtc_pll; - mach_set_rtc_pll = q40_set_rtc_pll; - mach_set_clock_mmss = q40_set_clock_mmss; + mach_init_IRQ = q40_init_IRQ; + mach_gettimeoffset = q40_gettimeoffset; + mach_hwclk = q40_hwclk; + mach_get_ss = q40_get_ss; + mach_get_rtc_pll = q40_get_rtc_pll; + mach_set_rtc_pll = q40_set_rtc_pll; + mach_set_clock_mmss = q40_set_clock_mmss; - mach_reset = q40_reset; - mach_get_model = q40_get_model; - mach_get_hardware_list = q40_get_hardware_list; + mach_reset = q40_reset; + mach_get_model = q40_get_model; + mach_get_hardware_list = q40_get_hardware_list; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = q40_mksound; + mach_beep = q40_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = q40_heartbeat; + mach_heartbeat = q40_heartbeat; #endif - mach_halt = q40_halt; - - /* disable a few things that SMSQ might have left enabled */ - q40_disable_irqs(); - - /* no DMA at all, but ide-scsi requires it.. make sure - * all physical RAM fits into the boundary - otherwise - * allocator may play costly and useless tricks */ - mach_max_dma_address = 1024*1024*1024; + mach_halt = q40_halt; + + /* disable a few things that SMSQ might have left enabled */ + q40_disable_irqs(); + + /* no DMA at all, but ide-scsi requires it.. make sure + * all physical RAM fits into the boundary - otherwise + * allocator may play costly and useless tricks */ + mach_max_dma_address = 1024*1024*1024; + + /* useful for early debugging stages - writes kernel messages into SRAM */ + if (!strncmp( m68k_debug_device,"mem",3 )) + { + /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ + _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4; + q40_console_driver.write = q40_mem_console_write; + register_console(&q40_console_driver); + } } int q40_parse_bootinfo(const struct bi_record *rec) { - return 1; + return 1; } -static inline unsigned char bcd2bin(unsigned char b) +static inline unsigned char bcd2bin (unsigned char b) { - return (b >> 4) * 10 + (b & 15); + return ((b>>4)*10 + (b&15)); } -static inline unsigned char bin2bcd(unsigned char b) +static inline unsigned char bin2bcd (unsigned char b) { - return (b / 10) * 16 + (b % 10); + return (((b/10)*16) + (b%10)); } -unsigned long q40_gettimeoffset(void) +unsigned long q40_gettimeoffset (void) { - return 5000 * (ql_ticks != 0); + return 5000*(ql_ticks!=0); } @@ -250,9 +238,9 @@ unsigned long q40_gettimeoffset(void) int q40_hwclk(int op, struct rtc_time *t) { - if (op) { - /* Write.... */ - Q40_RTC_CTRL |= Q40_RTC_WRITE; + if (op) + { /* Write.... */ + Q40_RTC_CTRL |= Q40_RTC_WRITE; Q40_RTC_SECS = bin2bcd(t->tm_sec); Q40_RTC_MINS = bin2bcd(t->tm_min); @@ -263,23 +251,25 @@ int q40_hwclk(int op, struct rtc_time *t) if (t->tm_wday >= 0) Q40_RTC_DOW = bin2bcd(t->tm_wday+1); - Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); - } else { - /* Read.... */ - Q40_RTC_CTRL |= Q40_RTC_READ; - - t->tm_year = bcd2bin (Q40_RTC_YEAR); - t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; - t->tm_mday = bcd2bin (Q40_RTC_DATE); - t->tm_hour = bcd2bin (Q40_RTC_HOUR); - t->tm_min = bcd2bin (Q40_RTC_MINS); - t->tm_sec = bcd2bin (Q40_RTC_SECS); - - Q40_RTC_CTRL &= ~(Q40_RTC_READ); - - if (t->tm_year < 70) - t->tm_year += 100; - t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; + Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); + } + else + { /* Read.... */ + Q40_RTC_CTRL |= Q40_RTC_READ; + + t->tm_year = bcd2bin (Q40_RTC_YEAR); + t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; + t->tm_mday = bcd2bin (Q40_RTC_DATE); + t->tm_hour = bcd2bin (Q40_RTC_HOUR); + t->tm_min = bcd2bin (Q40_RTC_MINS); + t->tm_sec = bcd2bin (Q40_RTC_SECS); + + Q40_RTC_CTRL &= ~(Q40_RTC_READ); + + if (t->tm_year < 70) + t->tm_year += 100; + t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; + } return 0; @@ -295,25 +285,29 @@ unsigned int q40_get_ss(void) * clock is out by > 30 minutes. Logic lifted from atari code. */ -int q40_set_clock_mmss(unsigned long nowtime) +int q40_set_clock_mmss (unsigned long nowtime) { int retval = 0; short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; int rtc_minutes; - rtc_minutes = bcd2bin(Q40_RTC_MINS); - if ((rtc_minutes < real_minutes ? - real_minutes - rtc_minutes : - rtc_minutes - real_minutes) < 30) { - Q40_RTC_CTRL |= Q40_RTC_WRITE; + rtc_minutes = bcd2bin (Q40_RTC_MINS); + + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + Q40_RTC_CTRL |= Q40_RTC_WRITE; Q40_RTC_MINS = bin2bcd(real_minutes); Q40_RTC_SECS = bin2bcd(real_seconds); Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); - } else + } + else retval = -1; + return retval; } @@ -324,23 +318,21 @@ int q40_set_clock_mmss(unsigned long nowtime) static int q40_get_rtc_pll(struct rtc_pll_info *pll) { - int tmp = Q40_RTC_CTRL; - + int tmp=Q40_RTC_CTRL; pll->pll_value = tmp & Q40_RTC_PLL_MASK; if (tmp & Q40_RTC_PLL_SIGN) pll->pll_value = -pll->pll_value; - pll->pll_max = 31; - pll->pll_min = -31; - pll->pll_posmult = 512; - pll->pll_negmult = 256; - pll->pll_clock = 125829120; - + pll->pll_max=31; + pll->pll_min=-31; + pll->pll_posmult=512; + pll->pll_negmult=256; + pll->pll_clock=125829120; return 0; } static int q40_set_rtc_pll(struct rtc_pll_info *pll) { - if (!pll->pll_ctrl) { + if (!pll->pll_ctrl){ /* the docs are a bit unclear so I am doublesetting */ /* RTC_WRITE here ... */ int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | diff --git a/trunk/arch/m68k/sun3/sun3ints.c b/trunk/arch/m68k/sun3/sun3ints.c index 4232a2c2fae9..baf74e8de8b5 100644 --- a/trunk/arch/m68k/sun3/sun3ints.c +++ b/trunk/arch/m68k/sun3/sun3ints.c @@ -103,7 +103,7 @@ void sun3_init_IRQ(void) m68k_setup_auto_interrupt(sun3_inthandle); m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7); - m68k_setup_user_interrupt(VEC_USER, 128, NULL); + m68k_setup_user_interrupt(VEC_USER, 192, NULL); request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL); request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL); diff --git a/trunk/arch/m68k/sun3x/prom.c b/trunk/arch/m68k/sun3x/prom.c index 48f8eb7b1565..574cf06df9e4 100644 --- a/trunk/arch/m68k/sun3x/prom.c +++ b/trunk/arch/m68k/sun3x/prom.c @@ -34,100 +34,99 @@ e_vector *sun3x_prom_vbr; /* Handle returning to the prom */ void sun3x_halt(void) { - unsigned long flags; + unsigned long flags; - /* Disable interrupts while we mess with things */ - local_irq_save(flags); + /* Disable interrupts while we mess with things */ + local_irq_save(flags); - /* Restore prom vbr */ - asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + /* Restore prom vbr */ + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); - /* Restore prom NMI clock */ -// sun3x_disable_intreg(5); - sun3_enable_irq(7); + /* Restore prom NMI clock */ +// sun3x_disable_intreg(5); + sun3_enable_irq(7); - /* Let 'er rip */ - asm volatile ("trap #14"); + /* Let 'er rip */ + __asm__ volatile ("trap #14" : : ); - /* Restore everything */ - sun3_disable_irq(7); - sun3_enable_irq(5); + /* Restore everything */ + sun3_disable_irq(7); + sun3_enable_irq(5); - asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); - local_irq_restore(flags); + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); + local_irq_restore(flags); } void sun3x_reboot(void) { - /* This never returns, don't bother saving things */ - local_irq_disable(); + /* This never returns, don't bother saving things */ + local_irq_disable(); - /* Restore prom vbr */ - asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + /* Restore prom vbr */ + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); - /* Restore prom NMI clock */ - sun3_disable_irq(5); - sun3_enable_irq(7); + /* Restore prom NMI clock */ + sun3_disable_irq(5); + sun3_enable_irq(7); - /* Let 'er rip */ - (*romvec->pv_reboot)("vmlinux"); + /* Let 'er rip */ + (*romvec->pv_reboot)("vmlinux"); } +extern char m68k_debug_device[]; + static void sun3x_prom_write(struct console *co, const char *s, unsigned int count) { - while (count--) { - if (*s == '\n') - sun3x_putchar('\r'); - sun3x_putchar(*s++); - } + while (count--) { + if (*s == '\n') + sun3x_putchar('\r'); + sun3x_putchar(*s++); + } } /* debug console - write-only */ static struct console sun3x_debug = { - .name = "debug", - .write = sun3x_prom_write, - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .write = sun3x_prom_write, + .flags = CON_PRINTBUFFER, + .index = -1, }; void sun3x_prom_init(void) { - /* Read the vector table */ - - sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); - sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); - sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); - sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); - sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); - sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); - romvec = (struct linux_romvec *)SUN3X_PROM_BASE; - - idprom_init(); - - if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { - printk("Warning: machine reports strange type %02x\n", - idprom->id_machtype); - printk("Pretending it's a 3/80, but very afraid...\n"); - idprom->id_machtype = SM_SUN3X | SM_3_80; - } - - /* point trap #14 at abort. - * XXX this is futile since we restore the vbr first - oops - */ - vectors[VEC_TRAP14] = sun3x_prom_abort; -} + /* Read the vector table */ -static int __init sun3x_debug_setup(char *arg) -{ - /* If debug=prom was specified, start the debug console */ - if (MACH_IS_SUN3X && !strcmp(arg, "prom")) - register_console(&sun3x_debug); - return 0; -} + sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); + sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); + sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); + sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); + sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); + sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); + romvec = (struct linux_romvec *)SUN3X_PROM_BASE; + + idprom_init(); + + if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { + printk("Warning: machine reports strange type %02x\n", + idprom->id_machtype); + printk("Pretending it's a 3/80, but very afraid...\n"); + idprom->id_machtype = SM_SUN3X | SM_3_80; + } -early_param("debug", sun3x_debug_setup); + /* point trap #14 at abort. + * XXX this is futile since we restore the vbr first - oops + */ + vectors[VEC_TRAP14] = sun3x_prom_abort; + + /* If debug=prom was specified, start the debug console */ + + if (!strcmp(m68k_debug_device, "prom")) + register_console(&sun3x_debug); + + +} /* some prom functions to export */ int prom_getintdefault(int node, char *property, int deflt) @@ -142,6 +141,7 @@ int prom_getbool (int node, char *prop) void prom_printf(char *fmt, ...) { + } void prom_halt (void) @@ -159,7 +159,7 @@ prom_get_idprom(char *idbuf, int num_bytes) int i; /* make a copy of the idprom structure */ - for (i = 0; i < num_bytes; i++) + for(i = 0; i < num_bytes; i++) idbuf[i] = ((char *)SUN3X_IDPROM)[i]; return idbuf[0]; diff --git a/trunk/arch/m68knommu/kernel/dma.c b/trunk/arch/m68knommu/kernel/dma.c index 0a25874a2aae..14b19c4161f4 100644 --- a/trunk/arch/m68knommu/kernel/dma.c +++ b/trunk/arch/m68knommu/kernel/dma.c @@ -8,6 +8,7 @@ #include #include #include +#include #include void *dma_alloc_coherent(struct device *dev, size_t size, diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 130d825e5438..c78b14380b3e 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -10,6 +10,7 @@ menu "Machine selection" config ZONE_DMA bool + default y choice prompt "System type" @@ -164,7 +165,7 @@ config MIPS_COBALT select HW_HAS_PCI select I8259 select IRQ_CPU - select PCI_GT64XXX_PCI0 + select MIPS_GT64111 select SYS_HAS_CPU_NEVADA select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL @@ -206,7 +207,7 @@ config MIPS_EV64120 depends on EXPERIMENTAL select DMA_NONCOHERENT select HW_HAS_PCI - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select SYS_HAS_CPU_R5000 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL @@ -244,7 +245,7 @@ config LASAT select DMA_NONCOHERENT select SYS_HAS_EARLY_PRINTK select HW_HAS_PCI - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select MIPS_NILE4 select R5000_CPU_SCACHE select SYS_HAS_CPU_R5000 @@ -262,7 +263,7 @@ config MIPS_ATLAS select HW_HAS_PCI select MIPS_BOARDS_GEN select MIPS_BONITO64 - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select MIPS_MSC select RM7000_CPU_SCACHE select SWAP_IO_SPACE @@ -295,7 +296,7 @@ config MIPS_MALTA select MIPS_BOARDS_GEN select MIPS_BONITO64 select MIPS_CPU_SCACHE - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select MIPS_MSC select SWAP_IO_SPACE select SYS_HAS_CPU_MIPS32_R1 @@ -339,7 +340,7 @@ config WR_PPMC select BOOT_ELF32 select DMA_NONCOHERENT select HW_HAS_PCI - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select SWAP_IO_SPACE select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 @@ -397,7 +398,7 @@ config MOMENCO_OCELOT select HW_HAS_PCI select IRQ_CPU select IRQ_CPU_RM7K - select PCI_GT64XXX_PCI0 + select MIPS_GT64120 select RM7000_CPU_SCACHE select SWAP_IO_SPACE select SYS_HAS_CPU_RM7000 @@ -500,8 +501,10 @@ config DDB5477 ether port USB, AC97, PCI, etc. config MACH_VR41XX - bool "NEC VR4100 series based machines" + bool "NEC VR41XX-based machines" select SYS_HAS_CPU_VR41XX + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL select GENERIC_HARDIRQS_NO__DO_IRQ config PMC_YOSEMITE @@ -776,7 +779,6 @@ config TOSHIBA_JMR3927 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select TOSHIBA_BOARDS - select GENERIC_HARDIRQS_NO__DO_IRQ config TOSHIBA_RBTX4927 bool "Toshiba TBTX49[23]7 board" @@ -920,7 +922,6 @@ config SYS_HAS_EARLY_PRINTK config GENERIC_ISA_DMA bool - select ZONE_DMA config I8259 bool @@ -944,7 +945,6 @@ config MIPS_DISABLE_OBSOLETE_IDE config GENERIC_ISA_DMA_SUPPORT_BROKEN bool - select ZONE_DMA # # Endianess selection. Sufficiently obscure so many users don't know what to @@ -999,7 +999,10 @@ config DDB5XXX_COMMON config MIPS_BOARDS_GEN bool -config PCI_GT64XXX_PCI0 +config MIPS_GT64111 + bool + +config MIPS_GT64120 bool config MIPS_TX3927 diff --git a/trunk/arch/mips/Makefile b/trunk/arch/mips/Makefile index f2f742df32c7..92bca6ad6ab1 100644 --- a/trunk/arch/mips/Makefile +++ b/trunk/arch/mips/Makefile @@ -530,29 +530,25 @@ cflags-$(CONFIG_SGI_IP32) += -Iinclude/asm-mips/mach-ip32 load-$(CONFIG_SGI_IP32) += 0xffffffff80004000 # -# Sibyte SB1250/BCM1480 SOC +# Sibyte SB1250 SOC # # This is a LIB so that it links at the end, and initcalls are later # the sequence; but it is built as an object so that modules don't get # removed (as happens, even if they have __initcall/module_init) # core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/sb1250/ -core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/common/ cflags-$(CONFIG_SIBYTE_BCM112X) += -Iinclude/asm-mips/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/ -core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/common/ cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/bcm1480/ -core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/common/ cflags-$(CONFIG_SIBYTE_BCM1x55) += -Iinclude/asm-mips/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/bcm1480/ -core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/common/ cflags-$(CONFIG_SIBYTE_BCM1x80) += -Iinclude/asm-mips/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL diff --git a/trunk/arch/mips/basler/excite/excite_setup.c b/trunk/arch/mips/basler/excite/excite_setup.c index 2f0e4c08eb04..42f0eda1d51f 100644 --- a/trunk/arch/mips/basler/excite/excite_setup.c +++ b/trunk/arch/mips/basler/excite/excite_setup.c @@ -63,7 +63,7 @@ volatile void __iomem * const ocd_base = (void *) (EXCITE_ADDR_OCD); volatile void __iomem * const titan_base = (void *) (EXCITE_ADDR_TITAN); /* Protect access to shared GPI registers */ -DEFINE_SPINLOCK(titan_lock); +spinlock_t titan_lock = SPIN_LOCK_UNLOCKED; int titan_irqflags; diff --git a/trunk/arch/mips/cobalt/Makefile b/trunk/arch/mips/cobalt/Makefile index 9565b2104dcd..b36dd8f538f9 100644 --- a/trunk/arch/mips/cobalt/Makefile +++ b/trunk/arch/mips/cobalt/Makefile @@ -2,8 +2,7 @@ # Makefile for the Cobalt micro systems family specific parts of the kernel # -obj-y := irq.o reset.o setup.o buttons.o +obj-y := irq.o reset.o setup.o -obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_EARLY_PRINTK) += console.o obj-$(CONFIG_MTD_PHYSMAP) += mtd.o diff --git a/trunk/arch/mips/cobalt/buttons.c b/trunk/arch/mips/cobalt/buttons.c deleted file mode 100644 index 9e143989c7b8..000000000000 --- a/trunk/arch/mips/cobalt/buttons.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Cobalt buttons platform device. - * - * Copyright (C) 2007 Yoichi Yuasa - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -static struct resource cobalt_buttons_resource __initdata = { - .start = 0x1d000000, - .end = 0x1d000003, - .flags = IORESOURCE_MEM, -}; - -static __init int cobalt_add_buttons(void) -{ - struct platform_device *pd; - int error; - - pd = platform_device_alloc("Cobalt buttons", -1); - if (!pd) - return -ENOMEM; - - error = platform_device_add_resources(pd, &cobalt_buttons_resource, 1); - if (error) - goto err_free_device; - - error = platform_device_add(pd); - if (error) - goto err_free_device; - - return 0; - - err_free_device: - platform_device_put(pd); - return error; -} -device_initcall(cobalt_add_buttons); diff --git a/trunk/arch/mips/cobalt/console.c b/trunk/arch/mips/cobalt/console.c index 0485d51f7216..ca56b415b8ac 100644 --- a/trunk/arch/mips/cobalt/console.c +++ b/trunk/arch/mips/cobalt/console.c @@ -1,11 +1,13 @@ /* * (C) P. Horton 2006 */ -#include +#include +#include +#include +#include #include - -#include +#include void prom_putchar(char c) { diff --git a/trunk/arch/mips/cobalt/irq.c b/trunk/arch/mips/cobalt/irq.c index 950ad1e8be44..fe93b846923b 100644 --- a/trunk/arch/mips/cobalt/irq.c +++ b/trunk/arch/mips/cobalt/irq.c @@ -17,7 +17,7 @@ #include #include -#include +#include /* * We have two types of interrupts that we handle, ones that come in through diff --git a/trunk/arch/mips/cobalt/pci.c b/trunk/arch/mips/cobalt/pci.c deleted file mode 100644 index d91027f43de6..000000000000 --- a/trunk/arch/mips/cobalt/pci.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Register PCI controller. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996, 1997, 2004, 05 by Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) - * - */ -#include -#include - -#include - -extern struct pci_ops gt64xxx_pci0_ops; - -static struct resource cobalt_mem_resource = { - .start = GT_DEF_PCI0_MEM0_BASE, - .end = GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1, - .name = "PCI memory", - .flags = IORESOURCE_MEM, -}; - -static struct resource cobalt_io_resource = { - .start = 0x1000, - .end = GT_DEF_PCI0_IO_SIZE - 1, - .name = "PCI I/O", - .flags = IORESOURCE_IO, -}; - -static struct pci_controller cobalt_pci_controller = { - .pci_ops = >64xxx_pci0_ops, - .mem_resource = &cobalt_mem_resource, - .io_resource = &cobalt_io_resource, - .io_offset = 0 - GT_DEF_PCI0_IO_BASE, -}; - -static int __init cobalt_pci_init(void) -{ - register_pci_controller(&cobalt_pci_controller); - - return 0; -} - -arch_initcall(cobalt_pci_init); diff --git a/trunk/arch/mips/cobalt/reset.c b/trunk/arch/mips/cobalt/reset.c index 43cca21fdbc0..753dfccae6fa 100644 --- a/trunk/arch/mips/cobalt/reset.c +++ b/trunk/arch/mips/cobalt/reset.c @@ -8,12 +8,15 @@ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv) */ -#include - +#include +#include +#include #include +#include #include - -#include +#include +#include +#include void cobalt_machine_halt(void) { diff --git a/trunk/arch/mips/cobalt/setup.c b/trunk/arch/mips/cobalt/setup.c index d0dd81790f74..88d34f11385a 100644 --- a/trunk/arch/mips/cobalt/setup.c +++ b/trunk/arch/mips/cobalt/setup.c @@ -19,10 +19,12 @@ #include #include #include +#include +#include #include #include -#include +#include extern void cobalt_machine_restart(char *command); extern void cobalt_machine_halt(void); @@ -61,6 +63,22 @@ void __init plat_timer_setup(struct irqaction *irq) GT_WRITE(GT_INTRMASK_OFS, GT_INTR_T0EXP_MSK | GT_READ(GT_INTRMASK_OFS)); } +extern struct pci_ops gt64111_pci_ops; + +static struct resource cobalt_mem_resource = { + .start = GT_DEF_PCI0_MEM0_BASE, + .end = GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1, + .name = "PCI memory", + .flags = IORESOURCE_MEM +}; + +static struct resource cobalt_io_resource = { + .start = 0x1000, + .end = 0xffff, + .name = "PCI I/O", + .flags = IORESOURCE_IO +}; + /* * Cobalt doesn't have PS/2 keyboard/mouse interfaces, * keyboard conntroller is never used. @@ -93,6 +111,14 @@ static struct resource cobalt_reserved_resources[] = { }, }; +static struct pci_controller cobalt_pci_controller = { + .pci_ops = >64111_pci_ops, + .mem_resource = &cobalt_mem_resource, + .mem_offset = 0, + .io_resource = &cobalt_io_resource, + .io_offset = 0 - GT_DEF_PCI0_IO_BASE, +}; + void __init plat_mem_setup(void) { static struct uart_port uart; @@ -120,6 +146,10 @@ void __init plat_mem_setup(void) printk("Cobalt board ID: %d\n", cobalt_board_id); +#ifdef CONFIG_PCI + register_pci_controller(&cobalt_pci_controller); +#endif + if (cobalt_board_id > COBALT_BRD_ID_RAQ1) { #ifdef CONFIG_SERIAL_8250 uart.line = 0; diff --git a/trunk/arch/mips/configs/jmr3927_defconfig b/trunk/arch/mips/configs/jmr3927_defconfig index 068e48ec7093..21a094752dab 100644 --- a/trunk/arch/mips/configs/jmr3927_defconfig +++ b/trunk/arch/mips/configs/jmr3927_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc3 -# Thu Mar 15 00:40:40 2007 +# Linux kernel version: 2.6.20 +# Tue Feb 20 21:47:34 2007 # CONFIG_MIPS=y @@ -70,7 +70,7 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set CONFIG_DMA_NONCOHERENT=y CONFIG_DMA_NEED_PCI_MAP_STATE=y CONFIG_CPU_BIG_ENDIAN=y @@ -138,12 +138,12 @@ CONFIG_ZONE_DMA_FLAG=1 # CONFIG_HZ_48 is not set # CONFIG_HZ_100 is not set # CONFIG_HZ_128 is not set -CONFIG_HZ_250=y +# CONFIG_HZ_250 is not set # CONFIG_HZ_256 is not set -# CONFIG_HZ_1000 is not set +CONFIG_HZ_1000=y # CONFIG_HZ_1024 is not set CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -CONFIG_HZ=250 +CONFIG_HZ=1000 CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -175,15 +175,14 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_SYSFS_DEPRECATED=y -# CONFIG_RELAY is not set -# CONFIG_BLK_DEV_INITRD is not set +CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_EMBEDDED=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y @@ -218,11 +217,11 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y -# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_DEADLINE is not set -CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DEFAULT_IOSCHED="anticipatory" # # Bus options (PCI, PCMCIA, EISA, ISA, TC) @@ -234,10 +233,12 @@ CONFIG_MMU=y # # PCCARD (PCMCIA/CardBus) support # +# CONFIG_PCCARD is not set # # PCI Hotplug Support # +# CONFIG_HOTPLUG_PCI is not set # # Executable file formats @@ -249,7 +250,10 @@ CONFIG_TRAD_SIGNALS=y # # Power management options # -# CONFIG_PM is not set +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_SYSFS_DEPRECATED is not set # # Networking @@ -263,7 +267,12 @@ CONFIG_NET=y CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y -# CONFIG_NET_KEY is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set @@ -281,18 +290,19 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set -# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETWORK_SECMARK=y # CONFIG_NETFILTER is not set # @@ -333,7 +343,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_IEEE80211 is not set +CONFIG_IEEE80211=y +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=y +CONFIG_IEEE80211_CRYPT_CCMP=y +CONFIG_IEEE80211_SOFTMAC=y +# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set +CONFIG_WIRELESS_EXT=y # # Device Drivers @@ -344,12 +360,14 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y # CONFIG_SYS_HYPERVISOR is not set # # Connector - unified userspace <-> kernelspace linker # -# CONFIG_CONNECTOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y # # Memory Technology Devices (MTD) @@ -378,13 +396,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CDROM_PKTCDVD=y +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=y # # Misc devices # -# CONFIG_SGI_IOC4 is not set +CONFIG_SGI_IOC4=y # CONFIG_TIFM_CORE is not set # @@ -395,7 +416,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # SCSI device support # -# CONFIG_RAID_ATTRS is not set +CONFIG_RAID_ATTRS=y # CONFIG_SCSI is not set # CONFIG_SCSI_NETLINK is not set @@ -441,13 +462,26 @@ CONFIG_NETDEVICES=y # # PHY device support # -# CONFIG_PHYLIB is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=y +CONFIG_DAVICOM_PHY=y +CONFIG_QSEMI_PHY=y +CONFIG_LXT_PHY=y +CONFIG_CICADA_PHY=y +CONFIG_VITESSE_PHY=y +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -CONFIG_MII=y +# CONFIG_MII is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set @@ -459,27 +493,7 @@ CONFIG_MII=y # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -CONFIG_TC35815=y -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_SC92031 is not set +# CONFIG_NET_PCI is not set # # Ethernet (1000 Mbit) @@ -495,21 +509,20 @@ CONFIG_TC35815=y # CONFIG_SKGE is not set # CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set -# CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set -# CONFIG_QLA3XXX is not set +CONFIG_QLA3XXX=y # CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set -# CONFIG_CHELSIO_T3 is not set +CONFIG_CHELSIO_T3=y # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set -# CONFIG_NETXEN_NIC is not set +CONFIG_NETXEN_NIC=y # # Token Ring devices @@ -553,7 +566,10 @@ CONFIG_INPUT=y # # Userland interfaces # -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_TSDEV is not set # CONFIG_INPUT_EVDEV is not set @@ -571,13 +587,21 @@ CONFIG_INPUT=y # # Hardware I/O ports # -# CONFIG_SERIO is not set +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +CONFIG_SERIO_RAW=y # CONFIG_GAMEPORT is not set # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_SERIAL_NONSTANDARD=y # CONFIG_COMPUTONE is not set # CONFIG_ROCKETPORT is not set @@ -585,7 +609,7 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_DIGIEPCA is not set # CONFIG_MOXA_INTELLIO is not set # CONFIG_MOXA_SMARTIO is not set -# CONFIG_MOXA_SMARTIO_NEW is not set +CONFIG_MOXA_SMARTIO_NEW=y # CONFIG_ISI is not set # CONFIG_SYNCLINKMP is not set # CONFIG_SYNCLINK_GT is not set @@ -605,12 +629,11 @@ CONFIG_SERIAL_NONSTANDARD=y # Non-8250 serial port support # CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_TXX9=y CONFIG_HAS_TXX9_SERIAL=y CONFIG_SERIAL_TXX9_NR_UARTS=6 -CONFIG_SERIAL_TXX9_CONSOLE=y -CONFIG_SERIAL_TXX9_STDSERIAL=y +# CONFIG_SERIAL_TXX9_CONSOLE is not set +# CONFIG_SERIAL_TXX9_STDSERIAL is not set # CONFIG_SERIAL_JSM is not set # CONFIG_UNIX98_PTYS is not set CONFIG_LEGACY_PTYS=y @@ -661,11 +684,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_HWMON is not set # CONFIG_HWMON_VID is not set -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - # # Multimedia devices # @@ -679,8 +697,51 @@ CONFIG_LEGACY_PTY_COUNT=256 # # Graphics support # +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB=y +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_SMIVGX is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set -# CONFIG_FB is not set # # Sound @@ -803,7 +864,7 @@ CONFIG_INOTIFY_USER=y CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set +CONFIG_FUSE_FS=y # # CD-ROM/DVD Filesystems @@ -828,13 +889,14 @@ CONFIG_SYSFS=y # CONFIG_TMPFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=y # # Miscellaneous filesystems # # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set @@ -882,7 +944,10 @@ CONFIG_MSDOS_PARTITION=y # # Distributed Lock Manager # -# CONFIG_DLM is not set +CONFIG_DLM=y +CONFIG_DLM_TCP=y +# CONFIG_DLM_SCTP is not set +# CONFIG_DLM_DEBUG is not set # # Profiling support @@ -907,22 +972,65 @@ CONFIG_CMDLINE="" # # Security options # -# CONFIG_KEYS is not set +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y # CONFIG_SECURITY is not set # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_WP512=y +CONFIG_CRYPTO_TGR192=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=y +CONFIG_CRYPTO_BLOWFISH=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y +CONFIG_CRYPTO_SERPENT=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_CAST5=y +CONFIG_CRYPTO_CAST6=y +CONFIG_CRYPTO_TEA=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_KHAZAD=y +CONFIG_CRYPTO_ANUBIS=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CAMELLIA=y + +# +# Hardware crypto devices +# # # Library routines # CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set +CONFIG_CRC16=y CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig b/trunk/arch/mips/configs/pnx8550-v2pci_defconfig similarity index 59% rename from trunk/arch/powerpc/configs/mpc832x_rdb_defconfig rename to trunk/arch/mips/configs/pnx8550-v2pci_defconfig index 56fc0a824458..3d6c2d743502 100644 --- a/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig +++ b/trunk/arch/mips/configs/pnx8550-v2pci_defconfig @@ -1,51 +1,159 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc3 -# Mon Mar 12 17:32:19 2007 +# Linux kernel version: 2.6.20 +# Tue Feb 20 21:47:39 2007 # -# CONFIG_PPC64 is not set -CONFIG_PPC32=y -CONFIG_PPC_MERGE=y -CONFIG_MMU=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_IRQ_PER_CPU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_MIPS=y + +# +# Machine selection +# +CONFIG_ZONE_DMA=y +# CONFIG_MIPS_MTX1 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_BASLER_EXCITE is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_WR_PPMC is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MIPS_XXS1500 is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_DDB5477 is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_QEMU is not set +# CONFIG_MARKEINS is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SNI_RM is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_PPC=y -CONFIG_EARLY_PRINTK=y -CONFIG_GENERIC_NVRAM=y +CONFIG_GENERIC_TIME=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_PPC_OF=y -CONFIG_PPC_UDBG_16550=y -# CONFIG_GENERIC_TBSYNC is not set -CONFIG_AUDIT_ARCH=y -CONFIG_GENERIC_BUG=y -CONFIG_DEFAULT_UIMAGE=y - -# -# Processor support -# -# CONFIG_CLASSIC32 is not set -# CONFIG_PPC_82xx is not set -CONFIG_PPC_83xx=y -# CONFIG_PPC_85xx is not set -# CONFIG_PPC_86xx is not set -# CONFIG_PPC_8xx is not set -# CONFIG_40x is not set -# CONFIG_44x is not set -# CONFIG_E200 is not set -CONFIG_6xx=y -CONFIG_83xx=y -CONFIG_PPC_FPU=y -# CONFIG_PPC_DCR_NATIVE is not set -# CONFIG_PPC_DCR_MMIO is not set -CONFIG_PPC_STD_MMU=y -CONFIG_PPC_STD_MMU_32=y -# CONFIG_SMP is not set +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_PNX8550=y +CONFIG_SOC_PNX8550=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +CONFIG_CPU_MIPS32_R1=y +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +# CONFIG_MIPS_VPE_LOADER is not set +# CONFIG_64BIT_PHYS_ADDR is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +# CONFIG_HZ_48 is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_256 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_KEXEC is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -69,23 +177,24 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set -CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_EMBEDDED=y -CONFIG_SYSCTL_SYSCALL=y -# CONFIG_KALLSYMS is not set +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y -# CONFIG_EPOLL is not set +CONFIG_EPOLL=y CONFIG_SHMEM=y CONFIG_SLAB=y CONFIG_VM_EVENT_COUNTERS=y @@ -98,11 +207,10 @@ CONFIG_BASE_SMALL=0 # Loadable module support # CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y # # Block layer @@ -124,68 +232,13 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" -CONFIG_QUICC_ENGINE=y -CONFIG_PPC_GEN550=y -# CONFIG_WANT_EARLY_SERIAL is not set # -# Platform support -# -# CONFIG_MPC8313_RDB is not set -# CONFIG_MPC832x_MDS is not set -CONFIG_MPC832x_RDB=y -# CONFIG_MPC834x_MDS is not set -# CONFIG_MPC834x_ITX is not set -# CONFIG_MPC836x_MDS is not set -CONFIG_PPC_MPC832x=y -# CONFIG_MPIC is not set - +# Bus options (PCI, PCMCIA, EISA, ISA, TC) # -# Kernel options -# -# CONFIG_HIGHMEM is not set -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_MATH_EMULATION=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 -CONFIG_PROC_DEVICETREE=y -# CONFIG_CMDLINE_BOOL is not set -# CONFIG_PM is not set -CONFIG_SECCOMP=y -CONFIG_ISA_DMA_API=y - -# -# Bus options -# -CONFIG_ZONE_DMA=y -CONFIG_GENERIC_ISA_DMA=y -# CONFIG_MPIC_WEIRD is not set -# CONFIG_PPC_I8259 is not set -CONFIG_PPC_INDIRECT_PCI=y -CONFIG_FSL_SOC=y +CONFIG_HW_HAS_PCI=y CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -# CONFIG_PCIEPORTBUS is not set +CONFIG_MMU=y # # PCCARD (PCMCIA/CardBus) support @@ -198,18 +251,19 @@ CONFIG_PCI_DOMAINS=y # CONFIG_HOTPLUG_PCI is not set # -# Advanced setup +# Executable file formats # -# CONFIG_ADVANCED_OPTIONS is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y # -# Default settings for advanced configuration options are used +# Power management options # -CONFIG_HIGHMEM_START=0xfe000000 -CONFIG_LOWMEM_SIZE=0x30000000 -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE=0x80000000 -CONFIG_BOOT_LOAD=0x00800000 +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_SYSFS_DEPRECATED is not set # # Networking @@ -226,26 +280,25 @@ CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set +CONFIG_XFRM_MIGRATE=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_MULTICAST=y +# CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y +# CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set +CONFIG_INET_TUNNEL=m CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y @@ -254,12 +307,100 @@ CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set -# CONFIG_IPV6 is not set +CONFIG_TCP_MD5SIG=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set -# CONFIG_NETFILTER is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK_SUPPORT=y +# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set # # DCCP Configuration (EXPERIMENTAL) @@ -291,6 +432,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -310,7 +452,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y # CONFIG_SYS_HYPERVISOR is not set # @@ -336,7 +478,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -349,29 +490,87 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set # # Misc devices # -# CONFIG_SGI_IOC4 is not set +CONFIG_SGI_IOC4=m # CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # -# CONFIG_IDE is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_IT8213=m +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_TC86C001=m +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y -# CONFIG_SCSI_TGT is not set -# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_TGT=m +CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y # @@ -390,26 +589,31 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_MULTI_LUN is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set -# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_SCAN_ASYNC=y # # SCSI Transports # -# CONFIG_SCSI_SPI_ATTRS is not set -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_ISCSI_ATTRS=m # CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_ISCSI_TCP is not set +CONFIG_ISCSI_TCP=m # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set @@ -419,11 +623,8 @@ CONFIG_BLK_DEV_SD=y # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set # CONFIG_SCSI_HPTIOP is not set -# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set @@ -467,12 +668,6 @@ CONFIG_BLK_DEV_SD=y # # CONFIG_I2O is not set -# -# Macintosh device drivers -# -# CONFIG_MAC_EMUMOUSEBTN is not set -# CONFIG_WINDFARM is not set - # # Network device support # @@ -480,7 +675,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=m # # ARCnet devices @@ -501,22 +696,44 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set +# CONFIG_DM9000 is not set # # Tulip family network device support # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set -# CONFIG_NET_PCI is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +CONFIG_NATSEMI=y +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set -CONFIG_E1000=y -# CONFIG_E1000_NAPI is not set -# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +# CONFIG_E1000 is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -525,14 +742,9 @@ CONFIG_E1000=y # CONFIG_SKGE is not set # CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set -# CONFIG_GIANFAR is not set -CONFIG_UCC_GETH=y -CONFIG_UGETH_NAPI=y -# CONFIG_UGETH_MAGIC_PACKET is not set -# CONFIG_UGETH_FILTERING is not set -# CONFIG_UGETH_TX_ON_DEMOND is not set # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set @@ -540,11 +752,11 @@ CONFIG_UGETH_NAPI=y # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set -# CONFIG_CHELSIO_T3 is not set +CONFIG_CHELSIO_T3=m # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set -# CONFIG_NETXEN_NIC is not set +CONFIG_NETXEN_NIC=m # # Token Ring devices @@ -562,8 +774,17 @@ CONFIG_UGETH_NAPI=y # CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PPP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set +CONFIG_SLHC=m # CONFIG_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set @@ -589,17 +810,29 @@ CONFIG_INPUT=y # # Userland interfaces # -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_EVBUG is not set # # Input Device Drivers # -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set @@ -607,33 +840,52 @@ CONFIG_INPUT=y # # Hardware I/O ports # -# CONFIG_SERIO is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set # # Character devices # -# CONFIG_VT is not set -# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +CONFIG_MOXA_SMARTIO_NEW=m +# CONFIG_ISI is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set # # Serial drivers # -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250 is not set # # Non-8250 serial port support # -# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_PNX8XXX=y +CONFIG_SERIAL_PNX8XXX_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set -# CONFIG_SERIAL_OF_PLATFORM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -646,33 +898,13 @@ CONFIG_LEGACY_PTY_COUNT=256 # # Watchdog Cards # -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set - -# -# Watchdog Device Drivers -# -# CONFIG_SOFT_WATCHDOG is not set -CONFIG_83xx_WDT=y - -# -# PCI-based Watchdog Cards -# -# CONFIG_PCIPCWATCHDOG is not set -# CONFIG_WDTPCI is not set - -# -# USB-based Watchdog Cards -# -# CONFIG_USBPCWATCHDOG is not set +# CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y -# CONFIG_NVRAM is not set -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set @@ -684,13 +916,13 @@ CONFIG_GEN_RTC=y # # I2C support # -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m # # I2C Algorithms # -# CONFIG_I2C_ALGOBIT is not set +CONFIG_I2C_ALGOBIT=m # CONFIG_I2C_ALGOPCF is not set # CONFIG_I2C_ALGOPCA is not set @@ -705,7 +937,6 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set -CONFIG_I2C_MPC=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set @@ -730,7 +961,6 @@ CONFIG_I2C_MPC=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_M41T00 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set @@ -798,11 +1028,6 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - # # Multimedia devices # @@ -817,9 +1042,52 @@ CONFIG_HWMON=y # # Graphics support # +CONFIG_FIRMWARE_EDID=y +CONFIG_FB=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_SMIVGX is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set -# CONFIG_FB is not set -# CONFIG_FB_IBM_GXT4500 is not set # # Sound @@ -846,25 +1114,15 @@ CONFIG_USB=y # CONFIG_USB_DEVICEFS=y # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set # # USB Host Controller Drivers # -CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_SPLIT_ISO is not set -# CONFIG_USB_EHCI_ROOT_HUB_TT is not set -# CONFIG_USB_EHCI_TT_NEWSCHED is not set -# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set +# CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_ISP116X_HCD is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PPC_OF=y -CONFIG_USB_OHCI_HCD_PPC_OF_BE=y -# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set -CONFIG_USB_OHCI_HCD_PCI=y -CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y -CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y -CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OHCI_HCD is not set # CONFIG_USB_UHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set @@ -885,6 +1143,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set @@ -897,13 +1156,10 @@ CONFIG_USB_STORAGE=y # # USB Input Devices # -# CONFIG_USB_HID is not set - -# -# USB HID Boot Protocol drivers -# -# CONFIG_USB_KBD is not set -# CONFIG_USB_MOUSE is not set +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set # CONFIG_USB_ACECAD is not set @@ -962,10 +1218,8 @@ CONFIG_USB_MON=y # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set -# CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set # CONFIG_USB_TRANCEVIBRATOR is not set -# CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set # @@ -1047,7 +1301,11 @@ CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set +CONFIG_XFS_FS=m +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set @@ -1056,8 +1314,8 @@ CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set # @@ -1080,14 +1338,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # Pseudo filesystems # CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y +# CONFIG_PROC_KCORE is not set CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=m # # Miscellaneous filesystems @@ -1099,7 +1357,7 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set +CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -1112,18 +1370,21 @@ CONFIG_RAMFS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set -CONFIG_NFS_V4=y +# CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set +CONFIG_NFSD=m +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y -CONFIG_SUNRPC_GSS=y -CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -1133,31 +1394,15 @@ CONFIG_RPCSEC_GSS_KRB5=y # # Partition Types # -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_LDM_PARTITION=y -# CONFIG_LDM_DEBUG is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_KARMA_PARTITION is not set -# CONFIG_EFI_PARTITION is not set # # Native Language Support # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -1174,14 +1419,14 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_936 is not set # CONFIG_NLS_CODEPAGE_950 is not set -CONFIG_NLS_CODEPAGE_932=y +# CONFIG_NLS_CODEPAGE_932 is not set # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set -CONFIG_NLS_ISO8859_8=y +# CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -1199,35 +1444,20 @@ CONFIG_NLS_ISO8859_1=y # # Distributed Lock Manager # -# CONFIG_DLM is not set +CONFIG_DLM=m +CONFIG_DLM_TCP=y +# CONFIG_DLM_SCTP is not set +# CONFIG_DLM_DEBUG is not set # -# QE Options -# -CONFIG_UCC_SLOW=y -CONFIG_UCC_FAST=y -CONFIG_UCC=y - -# -# Library routines -# -CONFIG_BITREVERSE=y -# CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y - -# -# Instrumentation Support +# Profiling support # # CONFIG_PROFILING is not set # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set @@ -1236,10 +1466,9 @@ CONFIG_ENABLE_MUST_CHECK=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_BOOTX_TEXT is not set -# CONFIG_SERIAL_TEXT_DEBUG is not set -# CONFIG_PPC_EARLY_DEBUG is not set +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="" +CONFIG_SYS_SUPPORTS_KGDB=y # # Security options @@ -1252,25 +1481,26 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_BLKCIPHER=y -CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=m +CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_HMAC is not set -# CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_XCBC=m # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=y -# CONFIG_CRYPTO_SHA1 is not set +CONFIG_CRYPTO_SHA1=m # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_GF128MUL=m CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_PCBC=m -# CONFIG_CRYPTO_LRW is not set -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_FCRYPT is not set +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_DES is not set +CONFIG_CRYPTO_FCRYPT=m # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set @@ -1278,15 +1508,33 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_ARC4 is not set +CONFIG_CRYPTO_ARC4=m # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m # CONFIG_CRYPTO_TEST is not set # # Hardware crypto devices # + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/mips/gt64120/wrppmc/pci.c b/trunk/arch/mips/gt64120/wrppmc/pci.c index 0d5289bc1804..2fbe93467f78 100644 --- a/trunk/arch/mips/gt64120/wrppmc/pci.c +++ b/trunk/arch/mips/gt64120/wrppmc/pci.c @@ -13,7 +13,7 @@ #include #include -extern struct pci_ops gt64xxx_pci0_ops; +extern struct pci_ops gt64120_pci_ops; static struct resource pci0_io_resource = { .name = "pci_0 io", @@ -30,7 +30,7 @@ static struct resource pci0_mem_resource = { }; static struct pci_controller hose_0 = { - .pci_ops = >64xxx_pci0_ops, + .pci_ops = >64120_pci_ops, .io_resource = &pci0_io_resource, .mem_resource = &pci0_mem_resource, }; diff --git a/trunk/arch/mips/jmr3927/common/prom.c b/trunk/arch/mips/jmr3927/common/prom.c index 5398813e50e6..aa481b774c42 100644 --- a/trunk/arch/mips/jmr3927/common/prom.c +++ b/trunk/arch/mips/jmr3927/common/prom.c @@ -41,6 +41,16 @@ #include +extern int prom_argc; +extern char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + char * __init prom_getcmdline(void) { return &(arcs_cmdline[0]); @@ -50,8 +60,6 @@ void __init prom_init_cmdline(void) { char *cp; int actr; - int prom_argc = fw_arg0; - char **prom_argv = (char **) fw_arg1; actr = 1; /* Always ignore argv[0] */ diff --git a/trunk/arch/mips/jmr3927/common/puts.c b/trunk/arch/mips/jmr3927/common/puts.c index c611ab497888..1c1cad9cd078 100644 --- a/trunk/arch/mips/jmr3927/common/puts.c +++ b/trunk/arch/mips/jmr3927/common/puts.c @@ -32,29 +32,137 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include #include +#include #define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif void -prom_putchar(char c) +putch(const unsigned char c) { int i = 0; do { + slow_down(); i++; - if (i>TIMEOUT) + if (i>TIMEOUT) { break; + } } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); tx3927_sioptr(1)->tfifo = c; return; } +unsigned char getch(void) +{ + int i = 0; + int dicr; + char c; + + /* diable RX int. */ + dicr = tx3927_sioptr(1)->dicr; + tx3927_sioptr(1)->dicr = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (tx3927_sioptr(1)->disr & TXx927_SIDISR_UVALID) + ; + c = tx3927_sioptr(1)->rfifo; + + /* clear RX int. status */ + tx3927_sioptr(1)->disr &= ~TXx927_SIDISR_RDIS; + /* enable RX int. */ + tx3927_sioptr(1)->dicr = dicr; + + return c; +} +void +do_jmr3927_led_set(char n) +{ + /* and with current leds */ + jmr3927_led_and_set(n); +} + void -puts(const char *cp) +puts(unsigned char *cp) { - while (*cp) - prom_putchar(*cp++); - prom_putchar('\r'); - prom_putchar('\n'); + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); } diff --git a/trunk/arch/mips/jmr3927/rbhma3100/Makefile b/trunk/arch/mips/jmr3927/rbhma3100/Makefile index 8d00ba460cef..18fe9a898cb7 100644 --- a/trunk/arch/mips/jmr3927/rbhma3100/Makefile +++ b/trunk/arch/mips/jmr3927/rbhma3100/Makefile @@ -3,4 +3,5 @@ # obj-y += init.o irq.o setup.o +obj-$(CONFIG_RUNTIME_DEBUG) += debug.o obj-$(CONFIG_KGDB) += kgdb_io.o diff --git a/trunk/arch/mips/jmr3927/rbhma3100/init.c b/trunk/arch/mips/jmr3927/rbhma3100/init.c index 9169fab1773a..a55cb4572ded 100644 --- a/trunk/arch/mips/jmr3927/rbhma3100/init.c +++ b/trunk/arch/mips/jmr3927/rbhma3100/init.c @@ -28,10 +28,20 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include +#include +#include + +#include #include +#include #include +int prom_argc; +char **prom_argv, **prom_envp; extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); +unsigned long mips_nofpu = 0; const char *get_system_type(void) { @@ -42,7 +52,7 @@ const char *get_system_type(void) ; } -extern void puts(const char *cp); +extern void puts(unsigned char *cp); void __init prom_init(void) { @@ -51,6 +61,10 @@ void __init prom_init(void) if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) puts("Warning: TX3927 TLB off\n"); #endif + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + mips_machgroup = MACH_GROUP_TOSHIBA; #ifdef CONFIG_TOSHIBA_JMR3927 diff --git a/trunk/arch/mips/jmr3927/rbhma3100/irq.c b/trunk/arch/mips/jmr3927/rbhma3100/irq.c index 1187b44a3dd4..7d2c203cb406 100644 --- a/trunk/arch/mips/jmr3927/rbhma3100/irq.c +++ b/trunk/arch/mips/jmr3927/rbhma3100/irq.c @@ -30,21 +30,53 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include + +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include +#include #include #if JMR3927_IRQ_END > NR_IRQS #error JMR3927_IRQ_END > NR_IRQS #endif +struct tb_irq_space* tb_irq_spaces; + +static int jmr3927_irq_base = -1; + +#ifdef CONFIG_PCI +static int jmr3927_gen_iack(void) +{ + /* generate ACK cycle */ +#ifdef __BIG_ENDIAN + return (tx3927_pcicptr->iiadp >> 24) & 0xff; +#else + return tx3927_pcicptr->iiadp & 0xff; +#endif +} +#endif + #define irc_dlevel 0 #define irc_elevel 1 @@ -55,24 +87,89 @@ static unsigned char irc_level[TX3927_NUM_IR] = { 6, 6, 6 /* TMR */ }; +static void jmr3927_irq_disable(unsigned int irq_nr); +static void jmr3927_irq_enable(unsigned int irq_nr); + +static void jmr3927_irq_ack(unsigned int irq) +{ + if (irq == JMR3927_IRQ_IRC_TMR0) + jmr3927_tmrptr->tisr = 0; /* ack interrupt */ + + jmr3927_irq_disable(irq); +} + +static void jmr3927_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + jmr3927_irq_enable(irq); +} + +static void jmr3927_irq_disable(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->mask_func) + sp->mask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } +} + +static void jmr3927_irq_enable(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->unmask_func) + sp->unmask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } +} + /* * CP0_STATUS is a thread's resource (saved/restored on context switch). - * So disable_irq/enable_irq MUST handle IOC/IRC registers. + * So disable_irq/enable_irq MUST handle IOC/ISAC/IRC registers. */ -static void mask_irq_ioc(unsigned int irq) +static void mask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask & ~bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} +static void unmask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask | bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} + +static void mask_irq_ioc(int irq_nr, int space_id) { /* 0: mask */ - unsigned int irq_nr = irq - JMR3927_IRQ_IOC; unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); unsigned int bit = 1 << irq_nr; jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR); /* flush write buffer */ (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); } -static void unmask_irq_ioc(unsigned int irq) +static void unmask_irq_ioc(int irq_nr, int space_id) { /* 0: mask */ - unsigned int irq_nr = irq - JMR3927_IRQ_IOC; unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); unsigned int bit = 1 << irq_nr; jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR); @@ -80,9 +177,8 @@ static void unmask_irq_ioc(unsigned int irq) (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); } -static void mask_irq_irc(unsigned int irq) +static void mask_irq_irc(int irq_nr, int space_id) { - unsigned int irq_nr = irq - JMR3927_IRQ_IRC; volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; if (irq_nr & 1) *ilrp = (*ilrp & 0x00ff) | (irc_dlevel << 8); @@ -95,9 +191,8 @@ static void mask_irq_irc(unsigned int irq) (void)tx3927_ircptr->ssr; } -static void unmask_irq_irc(unsigned int irq) +static void unmask_irq_irc(int irq_nr, int space_id) { - unsigned int irq_nr = irq - JMR3927_IRQ_IRC; volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; if (irq_nr & 1) *ilrp = (*ilrp & 0x00ff) | (irc_level[irq_nr] << 8); @@ -108,14 +203,98 @@ static void unmask_irq_irc(unsigned int irq) tx3927_ircptr->imr = irc_elevel; } +struct tb_irq_space jmr3927_isac_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_ISAC, + nr_irqs : JMR3927_NR_IRQ_ISAC, + .mask_func = mask_irq_isac, + .unmask_func = unmask_irq_isac, + .name = "ISAC", + .space_id = 0, + can_share : 0 +}; +struct tb_irq_space jmr3927_ioc_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_IOC, + nr_irqs : JMR3927_NR_IRQ_IOC, + .mask_func = mask_irq_ioc, + .unmask_func = unmask_irq_ioc, + .name = "IOC", + .space_id = 0, + can_share : 1 +}; + +struct tb_irq_space jmr3927_irc_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_IRC, + .nr_irqs = JMR3927_NR_IRQ_IRC, + .mask_func = mask_irq_irc, + .unmask_func = unmask_irq_irc, + .name = "on-chip", + .space_id = 0, + .can_share = 0 +}; + + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND +static int tx_branch_likely_bug_count = 0; +static int have_tx_branch_likely_bug = 0; + +static void tx_branch_likely_bug_fixup(void) +{ + struct pt_regs *regs = get_irq_regs(); + + /* TX39/49-BUG: Under this condition, the insn in delay slot + of the branch likely insn is executed (not nullified) even + the branch condition is false. */ + if (!have_tx_branch_likely_bug) + return; + if ((regs->cp0_epc & 0xfff) == 0xffc && + KSEGX(regs->cp0_epc) != KSEG0 && + KSEGX(regs->cp0_epc) != KSEG1) { + unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); + /* beql,bnel,blezl,bgtzl */ + /* bltzl,bgezl,blezall,bgezall */ + /* bczfl, bcztl */ + if ((insn & 0xf0000000) == 0x50000000 || + (insn & 0xfc0e0000) == 0x04020000 || + (insn & 0xf3fe0000) == 0x41020000) { + regs->cp0_epc -= 4; + tx_branch_likely_bug_count++; + printk(KERN_INFO + "fix branch-likery bug in %s (insn %08x)\n", + current->comm, insn); + } + } +} +#endif + +static void jmr3927_spurious(void) +{ + struct pt_regs * regs = get_irq_regs(); + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(); +#endif + printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", + regs->cp0_cause, regs->cp0_epc, regs->regs[31]); +} + asmlinkage void plat_irq_dispatch(void) { - unsigned long cp0_cause = read_c0_cause(); + struct pt_regs * regs = get_irq_regs(); int irq; - if ((cp0_cause & CAUSEF_IP7) == 0) +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(); +#endif + if ((regs->cp0_cause & CAUSEF_IP7) == 0) { +#if 0 + jmr3927_spurious(); +#endif return; - irq = (cp0_cause >> CAUSEB_IP2) & 0x0f; + } + irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; do_IRQ(irq + JMR3927_IRQ_IRC); } @@ -138,6 +317,35 @@ static struct irqaction ioc_action = { jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, }; +static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id) +{ + unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); + int i; + + for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { + if (istat & (1 << i)) { + irq = JMR3927_IRQ_ISAC + i; + do_IRQ(irq); + } + } + return IRQ_HANDLED; +} + +static struct irqaction isac_action = { + jmr3927_isac_interrupt, 0, CPU_MASK_NONE, "ISAC", NULL, NULL, +}; + + +static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id) +{ + printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); + + return IRQ_HANDLED; +} +static struct irqaction isaerr_action = { + jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, +}; + static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) { printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); @@ -150,19 +358,54 @@ static struct irqaction pcierr_action = { jmr3927_pcierr_interrupt, 0, CPU_MASK_NONE, "PCI error", NULL, NULL, }; -static void __init jmr3927_irq_init(void); +int jmr3927_ether1_irq = 0; + +void jmr3927_irq_init(u32 irq_base); void __init arch_init_irq(void) { + /* look for io board's presence */ + int have_isac = jmr3927_have_isac(); + /* Now, interrupt control disabled, */ /* all IRC interrupts are masked, */ /* all IRC interrupt mode are Low Active. */ + if (have_isac) { + + /* ETHER1 (NE2000 compatible 10M-Ether) parameter setup */ + /* temporary enable interrupt control */ + tx3927_ircptr->cer = 1; + /* ETHER1 Int. Is High-Active. */ + if (tx3927_ircptr->ssr & (1 << 0)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT0; +#if 0 /* INT3 may be asserted by ether0 (even after reboot...) */ + else if (tx3927_ircptr->ssr & (1 << 3)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT3; +#endif + /* disable interrupt control */ + tx3927_ircptr->cer = 0; + + /* Ether1: High Active */ + if (jmr3927_ether1_irq) { + int ether1_irc = jmr3927_ether1_irq - JMR3927_IRQ_IRC; + tx3927_ircptr->cr[ether1_irc / 8] |= + TX3927_IRCR_HIGH << ((ether1_irc % 8) * 2); + } + } + /* mask all IOC interrupts */ jmr3927_ioc_reg_out(0, JMR3927_IOC_INTM_ADDR); /* setup IOC interrupt mode (SOFT:High Active, Others:Low Active) */ jmr3927_ioc_reg_out(JMR3927_IOC_INTF_SOFT, JMR3927_IOC_INTP_ADDR); + if (have_isac) { + /* mask all ISAC interrupts */ + jmr3927_isac_reg_out(0, JMR3927_ISAC_INTM_ADDR); + /* setup ISAC interrupt mode (ISAIRQ3,ISAIRQ5:Low Active ???) */ + jmr3927_isac_reg_out(JMR3927_ISAC_INTF_IRQ3|JMR3927_ISAC_INTF_IRQ5, JMR3927_ISAC_INTP_ADDR); + } + /* clear PCI Soft interrupts */ jmr3927_ioc_reg_out(0, JMR3927_IOC_INTS1_ADDR); /* clear PCI Reset interrupts */ @@ -172,11 +415,21 @@ void __init arch_init_irq(void) tx3927_ircptr->cer = TX3927_IRCER_ICE; tx3927_ircptr->imr = irc_elevel; - jmr3927_irq_init(); + jmr3927_irq_init(NR_ISA_IRQS); + + /* setup irq space */ + add_tb_irq_space(&jmr3927_isac_irqspace); + add_tb_irq_space(&jmr3927_ioc_irqspace); + add_tb_irq_space(&jmr3927_irc_irqspace); /* setup IOC interrupt 1 (PCI, MODEM) */ setup_irq(JMR3927_IRQ_IOCINT, &ioc_action); + if (have_isac) { + setup_irq(JMR3927_IRQ_ISACINT, &isac_action); + setup_irq(JMR3927_IRQ_ISAC_ISAER, &isaerr_action); + } + #ifdef CONFIG_PCI setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action); #endif @@ -185,28 +438,21 @@ void __init arch_init_irq(void) set_c0_status(ST0_IM); /* IE bit is still 0. */ } -static struct irq_chip jmr3927_irq_ioc = { - .name = "jmr3927_ioc", - .ack = mask_irq_ioc, - .mask = mask_irq_ioc, - .mask_ack = mask_irq_ioc, - .unmask = unmask_irq_ioc, +static struct irq_chip jmr3927_irq_controller = { + .name = "jmr3927_irq", + .ack = jmr3927_irq_ack, + .mask = jmr3927_irq_disable, + .mask_ack = jmr3927_irq_ack, + .unmask = jmr3927_irq_enable, + .end = jmr3927_irq_end, }; -static struct irq_chip jmr3927_irq_irc = { - .name = "jmr3927_irc", - .ack = mask_irq_irc, - .mask = mask_irq_irc, - .mask_ack = mask_irq_irc, - .unmask = unmask_irq_irc, -}; - -static void __init jmr3927_irq_init(void) +void jmr3927_irq_init(u32 irq_base) { u32 i; - for (i = JMR3927_IRQ_IRC; i < JMR3927_IRQ_IRC + JMR3927_NR_IRQ_IRC; i++) - set_irq_chip_and_handler(i, &jmr3927_irq_irc, handle_level_irq); - for (i = JMR3927_IRQ_IOC; i < JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC; i++) - set_irq_chip_and_handler(i, &jmr3927_irq_ioc, handle_level_irq); + for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++) + set_irq_chip(i, &jmr3927_irq_controller); + + jmr3927_irq_base = irq_base; } diff --git a/trunk/arch/mips/jmr3927/rbhma3100/kgdb_io.c b/trunk/arch/mips/jmr3927/rbhma3100/kgdb_io.c index 2604f2c9a96e..269a42deae06 100644 --- a/trunk/arch/mips/jmr3927/rbhma3100/kgdb_io.c +++ b/trunk/arch/mips/jmr3927/rbhma3100/kgdb_io.c @@ -31,12 +31,23 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include #include #define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif static int remoteDebugInitialized = 0; -static void debugInit(int baud) int putDebugChar(unsigned char c) { @@ -92,8 +103,20 @@ unsigned char getDebugChar(void) return c; } -static void debugInit(int baud) +void debugInit(int baud) { + /* + volatile unsigned long lcr; + volatile unsigned long dicr; + volatile unsigned long disr; + volatile unsigned long cisr; + volatile unsigned long fcr; + volatile unsigned long flcr; + volatile unsigned long bgr; + volatile unsigned long tfifo; + volatile unsigned long rfifo; + */ + tx3927_sioptr(0)->lcr = 0x020; tx3927_sioptr(0)->dicr = 0; tx3927_sioptr(0)->disr = 0x4100; @@ -102,4 +125,31 @@ static void debugInit(int baud) tx3927_sioptr(0)->flcr = 0x02; tx3927_sioptr(0)->bgr = ((JMR3927_BASE_BAUD + baud / 2) / baud) | TXx927_SIBGR_BCLK_T0; +#if 0 + /* + * Reset the UART. + */ + tx3927_sioptr(0)->fcr = TXx927_SIFCR_SWRST; + while (tx3927_sioptr(0)->fcr & TXx927_SIFCR_SWRST) + ; + + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + tx3927_sioptr(0)->lcr = TXx927_SILCR_UMODE_8BIT | + TXx927_SILCR_USBL_1BIT | + TXx927_SILCR_SCS_IMCLK_BG; + tx3927_sioptr(0)->bgr = + ((JMR3927_BASE_BAUD + baud / 2) / baud) | + TXx927_SIBGR_BCLK_T0; + + /* HW RTS/CTS control */ + if (ser->flags & ASYNC_HAVE_CTS_LINE) + tx3927_sioptr(0)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + tx3927_sioptr(0)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); +#endif } diff --git a/trunk/arch/mips/jmr3927/rbhma3100/setup.c b/trunk/arch/mips/jmr3927/rbhma3100/setup.c index d1ef2895d564..fc523bda068f 100644 --- a/trunk/arch/mips/jmr3927/rbhma3100/setup.c +++ b/trunk/arch/mips/jmr3927/rbhma3100/setup.c @@ -54,18 +54,87 @@ #include #include +#include +#include #include +#include #include #include +#include -extern void puts(const char *cp); +extern void puts(unsigned char *cp); /* Tick Timer divider */ #define JMR3927_TIMER_CCD 0 /* 1/2 */ #define JMR3927_TIMER_CLK (JMR3927_IMCLK / (2 << JMR3927_TIMER_CCD)) +unsigned char led_state = 0xf; + +struct { + struct resource ram0; + struct resource ram1; + struct resource pcimem; + struct resource iob; + struct resource ioc; + struct resource pciio; + struct resource jmy1394; + struct resource rom1; + struct resource rom0; + struct resource sio0; + struct resource sio1; +} jmr3927_resources = { + { + .start = 0, + .end = 0x01FFFFFF, + .name = "RAM0", + .flags = IORESOURCE_MEM + }, { + .start = 0x02000000, + .end = 0x03FFFFFF, + .name = "RAM1", + .flags = IORESOURCE_MEM + }, { + .start = 0x08000000, + .end = 0x07FFFFFF, + .name = "PCIMEM", + .flags = IORESOURCE_MEM + }, { + .start = 0x10000000, + .end = 0x13FFFFFF, + .name = "IOB" + }, { + .start = 0x14000000, + .end = 0x14FFFFFF, + .name = "IOC" + }, { + .start = 0x15000000, + .end = 0x15FFFFFF, + .name = "PCIIO" + }, { + .start = 0x1D000000, + .end = 0x1D3FFFFF, + .name = "JMY1394" + }, { + .start = 0x1E000000, + .end = 0x1E3FFFFF, + .name = "ROM1" + }, { + .start = 0x1FC00000, + .end = 0x1FFFFFFF, + .name = "ROM0" + }, { + .start = 0xFFFEF300, + .end = 0xFFFEF3FF, + .name = "SIO0" + }, { + .start = 0xFFFEF400, + .end = 0xFFFEF4FF, + .name = "SIO1" + }, +}; + /* don't enable - see errata */ -static int jmr3927_ccfg_toeon; +int jmr3927_ccfg_toeon = 0; static inline void do_reset(void) { @@ -104,15 +173,9 @@ static cycle_t jmr3927_hpt_read(void) return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr; } -static void jmr3927_timer_ack(void) -{ - jmr3927_tmrptr->tisr = 0; /* ack interrupt */ -} - static void __init jmr3927_time_init(void) { clocksource_mips.read = jmr3927_hpt_read; - mips_timer_ack = jmr3927_timer_ack; mips_hpt_frequency = JMR3927_TIMER_CLK; } @@ -127,6 +190,9 @@ void __init plat_timer_setup(struct irqaction *irq) setup_irq(JMR3927_IRQ_TICK, irq); } +#define USECS_PER_JIFFY (1000000/HZ) + +//#undef DO_WRITE_THROUGH #define DO_WRITE_THROUGH #define DO_ENABLE_CACHE @@ -158,6 +224,12 @@ void __init plat_mem_setup(void) /* Reboot on panic */ panic_timeout = 180; + { + unsigned int conf; + conf = read_c0_conf(); + } + +#if 1 /* cache setup */ { unsigned int conf; @@ -184,14 +256,16 @@ void __init plat_mem_setup(void) write_c0_conf(conf); write_c0_cache(0); } +#endif /* initialize board */ jmr3927_board_init(); argptr = prom_getcmdline(); - if ((argptr = strstr(argptr, "toeon")) != NULL) - jmr3927_ccfg_toeon = 1; + if ((argptr = strstr(argptr, "toeon")) != NULL) { + jmr3927_ccfg_toeon = 1; + } argptr = prom_getcmdline(); if ((argptr = strstr(argptr, "ip=")) == NULL) { argptr = prom_getcmdline(); @@ -207,7 +281,7 @@ void __init plat_mem_setup(void) memset(&req, 0, sizeof(req)); req.line = i; req.iotype = UPIO_MEM; - req.membase = (unsigned char __iomem *)TX3927_SIO_REG(i); + req.membase = (char *)TX3927_SIO_REG(i); req.mapbase = TX3927_SIO_REG(i); req.irq = i == 0 ? JMR3927_IRQ_IRC_SIO0 : JMR3927_IRQ_IRC_SIO1; @@ -229,33 +303,65 @@ void __init plat_mem_setup(void) static void tx3927_setup(void); +#ifdef CONFIG_PCI +unsigned long mips_pci_io_base; +unsigned long mips_pci_io_size; +unsigned long mips_pci_mem_base; +unsigned long mips_pci_mem_size; +/* for legacy I/O, PCI I/O PCI Bus address must be 0 */ +unsigned long mips_pci_io_pciaddr = 0; +#endif + static void __init jmr3927_board_init(void) { + char *argptr; + +#ifdef CONFIG_PCI + mips_pci_io_base = JMR3927_PCIIO; + mips_pci_io_size = JMR3927_PCIIO_SIZE; + mips_pci_mem_base = JMR3927_PCIMEM; + mips_pci_mem_size = JMR3927_PCIMEM_SIZE; +#endif + tx3927_setup(); + if (jmr3927_have_isac()) { + +#ifdef CONFIG_FB_E1355 + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=e1355fb:crt16h"); + } +#endif + +#ifdef CONFIG_BLK_DEV_IDE + /* overrides PCI-IDE */ +#endif + } + /* SIO0 DTR on */ jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); jmr3927_led_set(0); + + if (jmr3927_have_isac()) + jmr3927_io_led_set(0); printk("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, jmr3927_dipsw1(), jmr3927_dipsw2(), jmr3927_dipsw3(), jmr3927_dipsw4()); + if (jmr3927_have_isac()) + printk("JMI-3927IO2 --- ISAC(Rev %d) DIPSW:%01x\n", + jmr3927_isac_reg_in(JMR3927_ISAC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_io_dipsw()); } -static void __init tx3927_setup(void) +void __init tx3927_setup(void) { int i; -#ifdef CONFIG_PCI - unsigned long mips_pci_io_base = JMR3927_PCIIO; - unsigned long mips_pci_io_size = JMR3927_PCIIO_SIZE; - unsigned long mips_pci_mem_base = JMR3927_PCIMEM; - unsigned long mips_pci_mem_size = JMR3927_PCIMEM_SIZE; - /* for legacy I/O, PCI I/O PCI Bus address must be 0 */ - unsigned long mips_pci_io_pciaddr = 0; -#endif /* SDRAMC are configured by PROM */ @@ -369,8 +475,10 @@ static void __init tx3927_setup(void) tx3927_pcicptr->mbas = ~(mips_pci_mem_size - 1); tx3927_pcicptr->mba = 0; tx3927_pcicptr->tlbmma = 0; +#ifndef JMR3927_INIT_INDIRECT_PCI /* Enable Direct mapping Address Space Decoder */ tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE; +#endif /* Clear All Local Bus Status */ tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; @@ -383,15 +491,22 @@ static void __init tx3927_setup(void) /* PCIC Int => IRC IRQ10 */ tx3927_pcicptr->il = TX3927_IR_PCI; +#if 1 /* Target Control (per errata) */ tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E; +#endif /* Enable Bus Arbiter */ +#if 0 + tx3927_pcicptr->req_trace = 0x73737373; +#endif tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN; tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | +#if 1 PCI_COMMAND_IO | +#endif PCI_COMMAND_PARITY | PCI_COMMAND_SERR; } #endif /* CONFIG_PCI */ @@ -440,6 +555,8 @@ static int __init jmr3927_rtc_init(void) .flags = IORESOURCE_MEM, }; struct platform_device *dev; + if (!jmr3927_have_nvram()) + return -ENODEV; dev = platform_device_register_simple("ds1742", -1, &res, 1); return IS_ERR(dev) ? PTR_ERR(dev) : 0; } diff --git a/trunk/arch/mips/kernel/asm-offsets.c b/trunk/arch/mips/kernel/asm-offsets.c index 761a779d5c4f..222de465db73 100644 --- a/trunk/arch/mips/kernel/asm-offsets.c +++ b/trunk/arch/mips/kernel/asm-offsets.c @@ -102,6 +102,7 @@ void output_thread_info_defines(void) offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); offset("#define TI_REGS ", struct thread_info, regs); + constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER); constant("#define _THREAD_SIZE ", THREAD_SIZE); constant("#define _THREAD_MASK ", THREAD_MASK); linefeed; diff --git a/trunk/arch/mips/kernel/i8259.c b/trunk/arch/mips/kernel/i8259.c index 2345160e63fc..9c79703979b2 100644 --- a/trunk/arch/mips/kernel/i8259.c +++ b/trunk/arch/mips/kernel/i8259.c @@ -328,8 +328,8 @@ void __init init_i8259_irqs (void) { int i; - insert_resource(&ioport_resource, &pic1_io_resource); - insert_resource(&ioport_resource, &pic2_io_resource); + request_resource(&ioport_resource, &pic1_io_resource); + request_resource(&ioport_resource, &pic2_io_resource); init_8259A(0); diff --git a/trunk/arch/mips/kernel/kspd.c b/trunk/arch/mips/kernel/kspd.c index c6580018c94b..29eadd404fa5 100644 --- a/trunk/arch/mips/kernel/kspd.c +++ b/trunk/arch/mips/kernel/kspd.c @@ -17,7 +17,6 @@ */ #include #include -#include #include #include #include @@ -199,6 +198,7 @@ void sp_work_handle_request(void) int cmd; char *vcwd; + mm_segment_t old_fs; int size; ret.retval = -1; @@ -241,6 +241,8 @@ void sp_work_handle_request(void) if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv, (int)&tz, 0,0)) == 0) ret.retval = tv.tv_sec; + + ret.errno = errno; break; case MTSP_SYSCALL_EXIT: @@ -277,6 +279,7 @@ void sp_work_handle_request(void) if (cmd >= 0) { ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1, generic.arg2, generic.arg3); + ret.errno = errno; } else printk(KERN_WARNING "KSPD: Unknown SP syscall number %d\n", sc.cmd); diff --git a/trunk/arch/mips/kernel/r2300_switch.S b/trunk/arch/mips/kernel/r2300_switch.S index 656bde2e11b1..28c2e2e6af73 100644 --- a/trunk/arch/mips/kernel/r2300_switch.S +++ b/trunk/arch/mips/kernel/r2300_switch.S @@ -49,8 +49,7 @@ LEAF(resume) #ifndef CONFIG_CPU_HAS_LLSC sw zero, ll_bit #endif - mfc0 t1, CP0_STATUS - sw t1, THREAD_STATUS(a0) + mfc0 t2, CP0_STATUS cpu_save_nonscratch a0 sw ra, THREAD_REG31(a0) @@ -60,8 +59,8 @@ LEAF(resume) lw t3, TASK_THREAD_INFO(a0) lw t0, TI_FLAGS(t3) li t1, _TIF_USEDFPU - and t2, t0, t1 - beqz t2, 1f + and t1, t0 + beqz t1, 1f nor t1, zero, t1 and t0, t0, t1 @@ -74,10 +73,13 @@ LEAF(resume) li t1, ~ST0_CU1 and t0, t0, t1 sw t0, ST_OFF(t3) + /* clear thread_struct CU1 bit */ + and t2, t1 fpu_save_single a0, t0 # clobbers t0 1: + sw t2, THREAD_STATUS(a0) /* * The order of restoring the registers takes care of the race * updating $28, $29 and kernelsp without disabling ints. diff --git a/trunk/arch/mips/kernel/r4k_switch.S b/trunk/arch/mips/kernel/r4k_switch.S index cc566cf12246..c7698fd9955c 100644 --- a/trunk/arch/mips/kernel/r4k_switch.S +++ b/trunk/arch/mips/kernel/r4k_switch.S @@ -48,8 +48,7 @@ #ifndef CONFIG_CPU_HAS_LLSC sw zero, ll_bit #endif - mfc0 t1, CP0_STATUS - LONG_S t1, THREAD_STATUS(a0) + mfc0 t2, CP0_STATUS cpu_save_nonscratch a0 LONG_S ra, THREAD_REG31(a0) @@ -59,8 +58,8 @@ PTR_L t3, TASK_THREAD_INFO(a0) LONG_L t0, TI_FLAGS(t3) li t1, _TIF_USEDFPU - and t2, t0, t1 - beqz t2, 1f + and t1, t0 + beqz t1, 1f nor t1, zero, t1 and t0, t0, t1 @@ -73,10 +72,13 @@ li t1, ~ST0_CU1 and t0, t0, t1 LONG_S t0, ST_OFF(t3) + /* clear thread_struct CU1 bit */ + and t2, t1 fpu_save_double a0 t0 t1 # c0_status passed in t0 # clobbers t1 1: + LONG_S t2, THREAD_STATUS(a0) /* * The order of restoring the registers takes care of the race diff --git a/trunk/arch/mips/kernel/rtlx.c b/trunk/arch/mips/kernel/rtlx.c index bfc8ca168f83..e6e3047151a6 100644 --- a/trunk/arch/mips/kernel/rtlx.c +++ b/trunk/arch/mips/kernel/rtlx.c @@ -289,7 +289,7 @@ unsigned int rtlx_write_poll(int index) return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); } -ssize_t rtlx_read(int index, void __user *buff, size_t count) +ssize_t rtlx_read(int index, void __user *buff, size_t count, int user) { size_t lx_write, fl = 0L; struct rtlx_channel *lx; @@ -331,10 +331,9 @@ ssize_t rtlx_read(int index, void __user *buff, size_t count) return count; } -ssize_t rtlx_write(int index, const void __user *buffer, size_t count) +ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user) { struct rtlx_channel *rt; - unsigned long failed; size_t rt_read; size_t fl; @@ -364,7 +363,7 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count) } out: - count -= failed; + count -= cailed; smp_wmb(); rt->rt_write = (rt->rt_write + count) % rt->buffer_size; diff --git a/trunk/arch/mips/kernel/signal-common.h b/trunk/arch/mips/kernel/signal-common.h index c0faabd52010..297dfcb97524 100644 --- a/trunk/arch/mips/kernel/signal-common.h +++ b/trunk/arch/mips/kernel/signal-common.h @@ -34,13 +34,4 @@ extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); /* Check and clear pending FPU exceptions in saved CSR */ extern int fpcsr_pending(unsigned int __user *fpcsr); -/* Make sure we will not lose FPU ownership */ -#ifdef CONFIG_PREEMPT -#define lock_fpu_owner() preempt_disable() -#define unlock_fpu_owner() preempt_enable() -#else -#define lock_fpu_owner() pagefault_disable() -#define unlock_fpu_owner() pagefault_enable() -#endif - #endif /* __SIGNAL_COMMON_H */ diff --git a/trunk/arch/mips/kernel/signal.c b/trunk/arch/mips/kernel/signal.c index 07d67309451a..8c3c5a5789b0 100644 --- a/trunk/arch/mips/kernel/signal.c +++ b/trunk/arch/mips/kernel/signal.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -78,46 +78,6 @@ struct rt_sigframe { /* * Helper routines */ -static int protected_save_fp_context(struct sigcontext __user *sc) -{ - int err; - while (1) { - lock_fpu_owner(); - own_fpu_inatomic(1); - err = save_fp_context(sc); /* this might fail */ - unlock_fpu_owner(); - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - -static int protected_restore_fp_context(struct sigcontext __user *sc) -{ - int err, tmp; - while (1) { - lock_fpu_owner(); - own_fpu_inatomic(0); - err = restore_fp_context(sc); /* this might fail */ - unlock_fpu_owner(); - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; @@ -153,7 +113,10 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) * Save FPU state to signal context. Signal handler * will "inherit" current FPU state. */ - err |= protected_save_fp_context(sc); + own_fpu(1); + enable_fp_in_kernel(); + err |= save_fp_context(sc); + disable_fp_in_kernel(); } return err; } @@ -185,7 +148,7 @@ check_and_restore_fp_context(struct sigcontext __user *sc) err = sig = fpcsr_pending(&sc->sc_fpc_csr); if (err > 0) err = 0; - err |= protected_restore_fp_context(sc); + err |= restore_fp_context(sc); return err ?: sig; } @@ -224,8 +187,11 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) if (used_math) { /* restore fpu context if we have used it before */ + own_fpu(0); + enable_fp_in_kernel(); if (!err) err = check_and_restore_fp_context(sc); + disable_fp_in_kernel(); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(0); diff --git a/trunk/arch/mips/kernel/signal32.c b/trunk/arch/mips/kernel/signal32.c index b9a014411f83..151fd2f0893a 100644 --- a/trunk/arch/mips/kernel/signal32.c +++ b/trunk/arch/mips/kernel/signal32.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -176,46 +176,6 @@ struct rt_sigframe32 { /* * sigcontext handlers */ -static int protected_save_fp_context32(struct sigcontext32 __user *sc) -{ - int err; - while (1) { - lock_fpu_owner(); - own_fpu_inatomic(1); - err = save_fp_context32(sc); /* this might fail */ - unlock_fpu_owner(); - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - -static int protected_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, tmp; - while (1) { - lock_fpu_owner(); - own_fpu_inatomic(0); - err = restore_fp_context32(sc); /* this might fail */ - unlock_fpu_owner(); - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - static int setup_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { @@ -249,7 +209,10 @@ static int setup_sigcontext32(struct pt_regs *regs, * Save FPU state to signal context. Signal handler * will "inherit" current FPU state. */ - err |= protected_save_fp_context32(sc); + own_fpu(1); + enable_fp_in_kernel(); + err |= save_fp_context32(sc); + disable_fp_in_kernel(); } return err; } @@ -262,7 +225,7 @@ check_and_restore_fp_context32(struct sigcontext32 __user *sc) err = sig = fpcsr_pending(&sc->sc_fpc_csr); if (err > 0) err = 0; - err |= protected_restore_fp_context32(sc); + err |= restore_fp_context32(sc); return err ?: sig; } @@ -298,8 +261,11 @@ static int restore_sigcontext32(struct pt_regs *regs, if (used_math) { /* restore fpu context if we have used it before */ + own_fpu(0); + enable_fp_in_kernel(); if (!err) err = check_and_restore_fp_context32(sc); + disable_fp_in_kernel(); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(0); diff --git a/trunk/arch/mips/kernel/traps.c b/trunk/arch/mips/kernel/traps.c index 493cb29b8a42..7d76a85422b2 100644 --- a/trunk/arch/mips/kernel/traps.c +++ b/trunk/arch/mips/kernel/traps.c @@ -650,7 +650,7 @@ asmlinkage void do_bp(struct pt_regs *regs) unsigned int opcode, bcode; siginfo_t info; - if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) + if (get_user(opcode, (unsigned int __user *) exception_epc(regs))) goto out_sigsegv; /* @@ -700,7 +700,7 @@ asmlinkage void do_tr(struct pt_regs *regs) unsigned int opcode, tcode = 0; siginfo_t info; - if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) + if (get_user(opcode, (unsigned int __user *) exception_epc(regs))) goto out_sigsegv; /* Immediate versions don't provide a code. */ @@ -757,12 +757,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; - die_if_kernel("do_cpu invoked from kernel context!", regs); - cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; switch (cpid) { case 0: + die_if_kernel("do_cpu invoked from kernel context!", regs); if (!cpu_has_llsc) if (!simulate_llsc(regs)) return; @@ -773,6 +772,9 @@ asmlinkage void do_cpu(struct pt_regs *regs) break; case 1: + if (!test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) + die_if_kernel("do_cpu invoked from kernel context!", + regs); if (used_math()) /* Using the FPU again. */ own_fpu(1); else { /* First time FPU user. */ @@ -780,7 +782,19 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } - if (!raw_cpu_has_fpu) { + if (raw_cpu_has_fpu) { + if (test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) { + local_irq_disable(); + if (cpu_has_fpu) + regs->cp0_status |= ST0_CU1; + /* + * We must return without enabling + * interrupts to ensure keep FPU + * ownership until resume. + */ + return; + } + } else { int sig; sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 0); @@ -822,6 +836,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) case 2: case 3: + die_if_kernel("do_cpu invoked from kernel context!", regs); break; } diff --git a/trunk/arch/mips/kernel/vmlinux.lds.S b/trunk/arch/mips/kernel/vmlinux.lds.S index 043f637e3d10..c76b793310c2 100644 --- a/trunk/arch/mips/kernel/vmlinux.lds.S +++ b/trunk/arch/mips/kernel/vmlinux.lds.S @@ -119,7 +119,7 @@ SECTIONS .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; #endif - . = ALIGN(_PAGE_SIZE); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/mips/lib/iomap.c b/trunk/arch/mips/lib/iomap.c index e3acb2dad33a..d51d5cb0a4a9 100644 --- a/trunk/arch/mips/lib/iomap.c +++ b/trunk/arch/mips/lib/iomap.c @@ -6,6 +6,7 @@ * (C) Copyright 2007 MIPS Technologies, Inc. * written by Ralf Baechle */ +#include #include #include diff --git a/trunk/arch/mips/mips-boards/generic/display.c b/trunk/arch/mips/mips-boards/generic/display.c index 548dbe5ce7c8..f653946afc23 100644 --- a/trunk/arch/mips/mips-boards/generic/display.c +++ b/trunk/arch/mips/mips-boards/generic/display.c @@ -24,16 +24,16 @@ void mips_display_message(const char *str) { - static unsigned int __iomem *display = NULL; + static volatile unsigned int *display = NULL; int i; if (unlikely(display == NULL)) - display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int)); + display = (volatile unsigned int *)ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int)); for (i = 0; i <= 14; i=i+2) { if (*str) - writel(*str++, display + i); + display[i] = *str++; else - writel(' ', display + i); + display[i] = ' '; } } diff --git a/trunk/arch/mips/mips-boards/generic/pci.c b/trunk/arch/mips/mips-boards/generic/pci.c index f98d60f78658..3192a14698c8 100644 --- a/trunk/arch/mips/mips-boards/generic/pci.c +++ b/trunk/arch/mips/mips-boards/generic/pci.c @@ -65,7 +65,7 @@ static struct resource msc_io_resource = { }; extern struct pci_ops bonito64_pci_ops; -extern struct pci_ops gt64xxx_pci0_ops; +extern struct pci_ops gt64120_pci_ops; extern struct pci_ops msc_pci_ops; static struct pci_controller bonito64_controller = { @@ -76,7 +76,7 @@ static struct pci_controller bonito64_controller = { }; static struct pci_controller gt64120_controller = { - .pci_ops = >64xxx_pci0_ops, + .pci_ops = >64120_pci_ops, .io_resource = >64120_io_resource, .mem_resource = >64120_mem_resource, }; diff --git a/trunk/arch/mips/mips-boards/generic/reset.c b/trunk/arch/mips/mips-boards/generic/reset.c index 7a1bb51f81ee..0996ba368b2a 100644 --- a/trunk/arch/mips/mips-boards/generic/reset.c +++ b/trunk/arch/mips/mips-boards/generic/reset.c @@ -39,24 +39,24 @@ static void atlas_machine_power_off(void); static void mips_machine_restart(char *command) { - unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int)); + volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int)); - writew(GORESET, softres_reg); + *softres_reg = GORESET; } static void mips_machine_halt(void) { - unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int)); + volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int)); - writew(GORESET, softres_reg); + *softres_reg = GORESET; } #if defined(CONFIG_MIPS_ATLAS) static void atlas_machine_power_off(void) { - unsigned int __iomem *psustby_reg = ioremap(ATLAS_PSUSTBY_REG, sizeof(unsigned int)); + volatile unsigned int *psustby_reg = (unsigned int *)ioremap(ATLAS_PSUSTBY_REG, sizeof(unsigned int)); - writew(ATLAS_GOSTBY, psustby_reg); + *psustby_reg = ATLAS_GOSTBY; } #endif diff --git a/trunk/arch/mips/mips-boards/malta/malta_int.c b/trunk/arch/mips/mips-boards/malta/malta_int.c index 83d76025d61d..3c206bb17160 100644 --- a/trunk/arch/mips/mips-boards/malta/malta_int.c +++ b/trunk/arch/mips/mips-boards/malta/malta_int.c @@ -42,6 +42,8 @@ #include #include +extern void mips_timer_interrupt(void); + static DEFINE_SPINLOCK(mips_irq_lock); static inline int mips_pcibios_iack(void) @@ -83,7 +85,7 @@ static inline int mips_pcibios_iack(void) dummy = BONITO_PCIMAP_CFG; iob(); /* sync */ - irq = readl((u32 *)_pcictrl_bonito_pcicfg); + irq = *(volatile u32 *)(_pcictrl_bonito_pcicfg); iob(); /* sync */ irq &= 0xff; BONITO_PCIMAP_CFG = 0; diff --git a/trunk/arch/mips/mips-boards/malta/malta_setup.c b/trunk/arch/mips/mips-boards/malta/malta_setup.c index 7873932532a1..56ea76679cd4 100644 --- a/trunk/arch/mips/mips-boards/malta/malta_setup.c +++ b/trunk/arch/mips/mips-boards/malta/malta_setup.c @@ -145,8 +145,7 @@ void __init plat_mem_setup(void) #ifdef CONFIG_BLK_DEV_IDE /* Check PCI clock */ { - unsigned int __iomem *jmpr_p = (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int)); - int jmpr = (readw(jmpr_p) >> 2) & 0x07; + int jmpr = (*((volatile unsigned int *)ioremap(MALTA_JMPRS_REG, sizeof(unsigned int))) >> 2) & 0x07; static const int pciclocks[] __initdata = { 33, 20, 25, 30, 12, 16, 37, 10 }; @@ -180,6 +179,7 @@ void __init plat_mem_setup(void) }; #endif #endif + mips_reboot_setup(); board_time_init = mips_time_init; diff --git a/trunk/arch/mips/mips-boards/sim/Makefile b/trunk/arch/mips/mips-boards/sim/Makefile index dc0bfda11427..6aeebc9122f2 100644 --- a/trunk/arch/mips/mips-boards/sim/Makefile +++ b/trunk/arch/mips/mips-boards/sim/Makefile @@ -17,8 +17,7 @@ # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # -obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \ - sim_cmdline.o +obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o obj-$(CONFIG_EARLY_PRINTK) += sim_console.o obj-$(CONFIG_SMP) += sim_smp.o diff --git a/trunk/arch/mips/mips-boards/sim/sim_platform.c b/trunk/arch/mips/mips-boards/sim/sim_platform.c deleted file mode 100644 index 53210a8c5dec..000000000000 --- a/trunk/arch/mips/mips-boards/sim/sim_platform.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 by Ralf Baechle (ralf@linux-mips.org) - */ -#include -#include -#include -#include - -static char mipsnet_string[] = "mipsnet"; - -static struct platform_device eth1_device = { - .name = mipsnet_string, - .id = 0, -}; - -/* - * Create a platform device for the GPI port that receives the - * image data from the embedded camera. - */ -static int __init mipsnet_devinit(void) -{ - int err; - - err = platform_device_register(ð1_device); - if (err) - printk(KERN_ERR "%s: registration failed\n", mipsnet_string); - - return err; -} - -device_initcall(mipsnet_devinit); diff --git a/trunk/arch/mips/mm/cache.c b/trunk/arch/mips/mm/cache.c index abf99b1eba13..4e8f1b683376 100644 --- a/trunk/arch/mips/mm/cache.c +++ b/trunk/arch/mips/mm/cache.c @@ -96,7 +96,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) kaddr = kmap_coherent(page, vmaddr); flush_data_cache_page((unsigned long)kaddr); - kunmap_coherent(); + kunmap_coherent(kaddr); } } diff --git a/trunk/arch/mips/mm/init.c b/trunk/arch/mips/mm/init.c index 2d1c2c024822..e9951c0e689f 100644 --- a/trunk/arch/mips/mm/init.c +++ b/trunk/arch/mips/mm/init.c @@ -177,7 +177,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) #define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) -void kunmap_coherent(void) +void kunmap_coherent(struct page *page) { #ifndef CONFIG_MIPS_MT_SMTC unsigned int wired; @@ -210,7 +210,7 @@ void copy_user_highpage(struct page *to, struct page *from, if (cpu_has_dc_aliases) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); - kunmap_coherent(); + kunmap_coherent(from); } else { vfrom = kmap_atomic(from, KM_USER0); copy_page(vto, vfrom); @@ -233,7 +233,7 @@ void copy_to_user_page(struct vm_area_struct *vma, if (cpu_has_dc_aliases) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); - kunmap_coherent(); + kunmap_coherent(page); } else memcpy(dst, src, len); if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) @@ -250,7 +250,7 @@ void copy_from_user_page(struct vm_area_struct *vma, void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(dst, vfrom, len); - kunmap_coherent(); + kunmap_coherent(page); } else memcpy(dst, src, len); } @@ -351,15 +351,18 @@ void __init paging_init(void) #endif kmap_coherent_init(); -#ifdef CONFIG_ZONE_DMA - if (min_low_pfn < MAX_DMA_PFN && MAX_DMA_PFN <= max_low_pfn) { - zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn; - zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN; - } else if (max_low_pfn < MAX_DMA_PFN) - zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn; +#ifdef CONFIG_ISA + if (max_low_pfn >= MAX_DMA_PFN) + if (min_low_pfn >= MAX_DMA_PFN) { + zones_size[ZONE_DMA] = 0; + zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; + } else { + zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn; + zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN; + } else #endif - zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; + zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn; #ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn; diff --git a/trunk/arch/mips/oprofile/op_model_mipsxx.c b/trunk/arch/mips/oprofile/op_model_mipsxx.c index 4f94fa261aae..69a8bcfe72b2 100644 --- a/trunk/arch/mips/oprofile/op_model_mipsxx.c +++ b/trunk/arch/mips/oprofile/op_model_mipsxx.c @@ -35,7 +35,7 @@ #define vpe_id() smp_processor_id() #else #define WHAT 0 -#define vpe_id() 0 +#define vpe_id() smp_processor_id() #endif #define __define_perf_accessors(r, n, np) \ diff --git a/trunk/arch/mips/pci/Makefile b/trunk/arch/mips/pci/Makefile index df487c063b1d..bf85995ca042 100644 --- a/trunk/arch/mips/pci/Makefile +++ b/trunk/arch/mips/pci/Makefile @@ -8,7 +8,8 @@ obj-y += pci.o pci-dac.o # PCI bus host bridge specific code # obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o -obj-$(CONFIG_PCI_GT64XXX_PCI0) += ops-gt64xxx_pci0.o +obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o +obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o obj-$(CONFIG_PCI_MARVELL) += ops-marvell.o obj-$(CONFIG_MIPS_MSC) += ops-msc.o obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o diff --git a/trunk/arch/mips/pci/fixup-jmr3927.c b/trunk/arch/mips/pci/fixup-jmr3927.c index 73d18503517c..6e72d213f4cd 100644 --- a/trunk/arch/mips/pci/fixup-jmr3927.c +++ b/trunk/arch/mips/pci/fixup-jmr3927.c @@ -29,6 +29,7 @@ */ #include #include +#include #include #include @@ -80,8 +81,14 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) /* Check OnBoard Ethernet (IDSEL=A24, DevNu=13) */ if (dev->bus->parent == NULL && - slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(24)) - irq = JMR3927_IRQ_ETHER0; + slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(24)) { + extern int jmr3927_ether1_irq; + /* check this irq line was reserved for ether1 */ + if (jmr3927_ether1_irq != JMR3927_IRQ_ETHER0) + irq = JMR3927_IRQ_ETHER0; + else + irq = 0; /* disable */ + } return irq; } diff --git a/trunk/arch/mips/pci/ops-gt64111.c b/trunk/arch/mips/pci/ops-gt64111.c new file mode 100644 index 000000000000..ecd3991bd0e4 --- /dev/null +++ b/trunk/arch/mips/pci/ops-gt64111.c @@ -0,0 +1,100 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997, 2002 by Ralf Baechle + * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) + */ +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* + * Device 31 on the GT64111 is used to generate PCI special + * cycles, so we shouldn't expected to find a device there ... + */ +static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn) +{ + if (bus->number == 0 && PCI_SLOT(devfn) < 31) + return 0; + + return -1; +} + +static int gt64111_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 * val) +{ + if (pci_range_ck(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (size) { + case 4: + PCI_CFG_SET(devfn, where); + *val = GT_READ(GT_PCI0_CFGDATA_OFS); + return PCIBIOS_SUCCESSFUL; + + case 2: + PCI_CFG_SET(devfn, (where & ~0x3)); + *val = GT_READ(GT_PCI0_CFGDATA_OFS) + >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; + + case 1: + PCI_CFG_SET(devfn, (where & ~0x3)); + *val = GT_READ(GT_PCI0_CFGDATA_OFS) + >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; + } + + return PCIBIOS_BAD_REGISTER_NUMBER; +} + +static int gt64111_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 tmp; + + if (pci_range_ck(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (size) { + case 4: + PCI_CFG_SET(devfn, where); + GT_WRITE(GT_PCI0_CFGDATA_OFS, val); + + return PCIBIOS_SUCCESSFUL; + + case 2: + PCI_CFG_SET(devfn, (where & ~0x3)); + tmp = GT_READ(GT_PCI0_CFGDATA_OFS); + tmp &= ~(0xffff << ((where & 0x3) * 8)); + tmp |= (val << ((where & 0x3) * 8)); + GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp); + + return PCIBIOS_SUCCESSFUL; + + case 1: + PCI_CFG_SET(devfn, (where & ~0x3)); + tmp = GT_READ(GT_PCI0_CFGDATA_OFS); + tmp &= ~(0xff << ((where & 0x3) * 8)); + tmp |= (val << ((where & 0x3) * 8)); + GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp); + + return PCIBIOS_SUCCESSFUL; + } + + return PCIBIOS_BAD_REGISTER_NUMBER; +} + +struct pci_ops gt64111_pci_ops = { + .read = gt64111_pci_read_config, + .write = gt64111_pci_write_config, +}; diff --git a/trunk/arch/mips/pci/ops-gt64xxx_pci0.c b/trunk/arch/mips/pci/ops-gt64120.c similarity index 80% rename from trunk/arch/mips/pci/ops-gt64xxx_pci0.c rename to trunk/arch/mips/pci/ops-gt64120.c index 3d896c5f413f..6335844d607a 100644 --- a/trunk/arch/mips/pci/ops-gt64xxx_pci0.c +++ b/trunk/arch/mips/pci/ops-gt64120.c @@ -39,8 +39,8 @@ #define PCI_CFG_TYPE1_DEV_SHF 11 #define PCI_CFG_TYPE1_BUS_SHF 16 -static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type, - struct pci_bus *bus, unsigned int devfn, int where, u32 * data) +static int gt64120_pcibios_config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, int where, u32 * data) { unsigned char busnum = bus->number; u32 intr; @@ -100,13 +100,13 @@ static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type, * We can't address 8 and 16 bit words directly. Instead we have to * read/write a 32bit word and mask/modify the data we actually want. */ -static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 * val) +static int gt64120_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 * val) { u32 data = 0; - if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, - where, &data)) + if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, + &data)) return PCIBIOS_DEVICE_NOT_FOUND; if (size == 1) @@ -119,16 +119,16 @@ static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } -static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) +static int gt64120_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) { u32 data = 0; if (size == 4) data = val; else { - if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, - devfn, where, &data)) + if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, + where, &data)) return PCIBIOS_DEVICE_NOT_FOUND; if (size == 1) @@ -139,14 +139,14 @@ static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn, (val << ((where & 3) << 3)); } - if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, - where, &data)) + if (gt64120_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where, + &data)) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; } -struct pci_ops gt64xxx_pci0_ops = { - .read = gt64xxx_pci0_pcibios_read, - .write = gt64xxx_pci0_pcibios_write +struct pci_ops gt64120_pci_ops = { + .read = gt64120_pcibios_read, + .write = gt64120_pcibios_write }; diff --git a/trunk/arch/mips/pci/ops-tx3927.c b/trunk/arch/mips/pci/ops-tx3927.c index aa698bd0d5e3..42530a0b84b3 100644 --- a/trunk/arch/mips/pci/ops-tx3927.c +++ b/trunk/arch/mips/pci/ops-tx3927.c @@ -40,6 +40,7 @@ #include #include +#include static inline int mkaddr(unsigned char bus, unsigned char dev_fn, unsigned char where) @@ -129,3 +130,234 @@ struct pci_ops jmr3927_pci_ops = { jmr3927_pci_read_config, jmr3927_pci_write_config, }; + + +#ifndef JMR3927_INIT_INDIRECT_PCI + +inline unsigned long tc_readl(volatile __u32 * addr) +{ + return readl(addr); +} + +inline void tc_writel(unsigned long data, volatile __u32 * addr) +{ + writel(data, addr); +} +#else + +unsigned long tc_readl(volatile __u32 * addr) +{ + unsigned long val; + + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) CPHYSADDR(addr); + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_MEMREAD << PCI_IPCIBE_ICMD_SHIFT) | + PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + val = + le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr-> + ipcidata); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} + +void tc_writel(unsigned long data, volatile __u32 * addr) +{ + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = + cpu_to_le32(data); + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) CPHYSADDR(addr); + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_MEMWRITE << PCI_IPCIBE_ICMD_SHIFT) | + PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} + +unsigned char tx_ioinb(unsigned char *addr) +{ + unsigned long val; + __u32 ioaddr; + int offset; + int byte; + + ioaddr = (unsigned long) addr; + offset = ioaddr & 0x3; + byte = 0xf & ~(8 >> offset); + + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + val = + le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr-> + ipcidata); + val = val & 0xff; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} + +void tx_iooutb(unsigned long data, unsigned char *addr) +{ + __u32 ioaddr; + int offset; + int byte; + + data = data | (data << 8) | (data << 16) | (data << 24); + ioaddr = (unsigned long) addr; + offset = ioaddr & 0x3; + byte = 0xf & ~(8 >> offset); + + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = data; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} + +unsigned short tx_ioinw(unsigned short *addr) +{ + unsigned long val; + __u32 ioaddr; + int offset; + int byte; + + ioaddr = (unsigned long) addr; + offset = ioaddr & 0x2; + byte = 3 << offset; + + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + val = + le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr-> + ipcidata); + val = val & 0xffff; + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; + +} + +void tx_iooutw(unsigned long data, unsigned short *addr) +{ + __u32 ioaddr; + int offset; + int byte; + + data = data | (data << 16); + ioaddr = (unsigned long) addr; + offset = ioaddr & 0x2; + byte = 3 << offset; + + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = data; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} + +unsigned long tx_ioinl(unsigned int *addr) +{ + unsigned long val; + __u32 ioaddr; + + ioaddr = (unsigned long) addr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | + PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + val = + le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr-> + ipcidata); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; + return val; +} + +void tx_iooutl(unsigned long data, unsigned int *addr) +{ + __u32 ioaddr; + + ioaddr = (unsigned long) addr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = + cpu_to_le32(data); + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr = + (unsigned long) ioaddr; + *(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe = + (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | + PCI_IPCIBE_IBE_LONG; + while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC)); + /* clear by setting */ + tx3927_pcicptr->istat |= PCI_ISTAT_IDICC; +} + +void tx_insbyte(unsigned char *addr, void *buffer, unsigned int count) +{ + unsigned char *ptr = (unsigned char *) buffer; + + while (count--) { + *ptr++ = tx_ioinb(addr); + } +} + +void tx_insword(unsigned short *addr, void *buffer, unsigned int count) +{ + unsigned short *ptr = (unsigned short *) buffer; + + while (count--) { + *ptr++ = tx_ioinw(addr); + } +} + +void tx_inslong(unsigned int *addr, void *buffer, unsigned int count) +{ + unsigned long *ptr = (unsigned long *) buffer; + + while (count--) { + *ptr++ = tx_ioinl(addr); + } +} + +void tx_outsbyte(unsigned char *addr, void *buffer, unsigned int count) +{ + unsigned char *ptr = (unsigned char *) buffer; + + while (count--) { + tx_iooutb(*ptr++, addr); + } +} + +void tx_outsword(unsigned short *addr, void *buffer, unsigned int count) +{ + unsigned short *ptr = (unsigned short *) buffer; + + while (count--) { + tx_iooutw(*ptr++, addr); + } +} + +void tx_outslong(unsigned int *addr, void *buffer, unsigned int count) +{ + unsigned long *ptr = (unsigned long *) buffer; + + while (count--) { + tx_iooutl(*ptr++, addr); + } +} +#endif diff --git a/trunk/arch/mips/pci/pci-lasat.c b/trunk/arch/mips/pci/pci-lasat.c index 985784a3e6f8..88fb191ad2eb 100644 --- a/trunk/arch/mips/pci/pci-lasat.c +++ b/trunk/arch/mips/pci/pci-lasat.c @@ -12,7 +12,7 @@ #include extern struct pci_ops nile4_pci_ops; -extern struct pci_ops gt64xxx_pci0_ops; +extern struct pci_ops gt64120_pci_ops; static struct resource lasat_pci_mem_resource = { .name = "LASAT PCI MEM", .start = 0x18000000, @@ -38,7 +38,7 @@ static int __init lasat_pci_setup(void) switch (mips_machtype) { case MACH_LASAT_100: - lasat_pci_controller.pci_ops = >64xxx_pci0_ops; + lasat_pci_controller.pci_ops = >64120_pci_ops; break; case MACH_LASAT_200: lasat_pci_controller.pci_ops = &nile4_pci_ops; diff --git a/trunk/arch/mips/pci/pci-ocelot.c b/trunk/arch/mips/pci/pci-ocelot.c index 7f94f26d35ae..2b9495dce6ba 100644 --- a/trunk/arch/mips/pci/pci-ocelot.c +++ b/trunk/arch/mips/pci/pci-ocelot.c @@ -81,7 +81,7 @@ static struct resource ocelot_io_resource = { }; static struct pci_controller ocelot_pci_controller = { - .pci_ops = gt64xxx_pci0_ops; + .pci_ops = gt64120_pci_ops; .mem_resource = &ocelot_mem_resource; .io_resource = &ocelot_io_resource; }; diff --git a/trunk/arch/mips/pci/pci.c b/trunk/arch/mips/pci/pci.c index 8108231f2e20..de7cfc559ddb 100644 --- a/trunk/arch/mips/pci/pci.c +++ b/trunk/arch/mips/pci/pci.c @@ -77,13 +77,6 @@ pcibios_align_resource(void *data, struct resource *res, void __init register_pci_controller(struct pci_controller *hose) { - if (request_resource(&iomem_resource, hose->mem_resource) < 0) - goto out; - if (request_resource(&ioport_resource, hose->io_resource) < 0) { - release_resource(hose->mem_resource); - goto out; - } - *hose_tail = hose; hose_tail = &hose->next; @@ -94,11 +87,6 @@ void __init register_pci_controller(struct pci_controller *hose) printk(KERN_WARNING "registering PCI controller with io_map_base unset\n"); } - return; - -out: - printk(KERN_WARNING - "Skipping PCI bus scan due to resource conflict\n"); } /* Most MIPS systems have straight-forward swizzling needs. */ @@ -133,6 +121,11 @@ static int __init pcibios_init(void) /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { + if (request_resource(&iomem_resource, hose->mem_resource) < 0) + goto out; + if (request_resource(&ioport_resource, hose->io_resource) < 0) + goto out_free_mem_resource; + if (!hose->iommu) PCI_DMA_BUS_IS_PHYS = 1; @@ -151,6 +144,14 @@ static int __init pcibios_init(void) need_domain_info = 1; } } + continue; + +out_free_mem_resource: + release_resource(hose->mem_resource); + +out: + printk(KERN_WARNING + "Skipping PCI bus scan due to resource conflict\n"); } if (!pci_probe_only) diff --git a/trunk/arch/mips/sgi-ip22/ip22-nvram.c b/trunk/arch/mips/sgi-ip22/ip22-nvram.c index e19d60d5fcc1..fd29fd407ae8 100644 --- a/trunk/arch/mips/sgi-ip22/ip22-nvram.c +++ b/trunk/arch/mips/sgi-ip22/ip22-nvram.c @@ -52,7 +52,8 @@ * national semiconductor nv ram chip the op code is 3 bits and * the address is 6/8 bits. */ -static inline void eeprom_cmd(unsigned int *ctrl, unsigned cmd, unsigned reg) +static inline void eeprom_cmd(volatile unsigned int *ctrl, unsigned cmd, + unsigned reg) { unsigned short ser_cmd; int i; @@ -60,34 +61,33 @@ static inline void eeprom_cmd(unsigned int *ctrl, unsigned cmd, unsigned reg) ser_cmd = cmd | (reg << (16 - BITS_IN_COMMAND)); for (i = 0; i < BITS_IN_COMMAND; i++) { if (ser_cmd & (1<<15)) /* if high order bit set */ - writel(readl(ctrl) | EEPROM_DATO, ctrl); + *ctrl |= EEPROM_DATO; else - writel(readl(ctrl) & ~EEPROM_DATO, ctrl); - writel(readl(ctrl) & ~EEPROM_ECLK, ctrl); - writel(readl(ctrl) | EEPROM_ECLK, ctrl); + *ctrl &= ~EEPROM_DATO; + *ctrl &= ~EEPROM_ECLK; + *ctrl |= EEPROM_ECLK; ser_cmd <<= 1; } - /* see data sheet timing diagram */ - writel(readl(ctrl) & ~EEPROM_DATO, ctrl); + *ctrl &= ~EEPROM_DATO; /* see data sheet timing diagram */ } -unsigned short ip22_eeprom_read(unsigned int *ctrl, int reg) +unsigned short ip22_eeprom_read(volatile unsigned int *ctrl, int reg) { unsigned short res = 0; int i; - writel(readl(ctrl) & ~EEPROM_EPROT, ctrl); + *ctrl &= ~EEPROM_EPROT; eeprom_cs_on(ctrl); eeprom_cmd(ctrl, EEPROM_READ, reg); /* clock the data ouf of serial mem */ for (i = 0; i < 16; i++) { - writel(readl(ctrl) & ~EEPROM_ECLK, ctrl); + *ctrl &= ~EEPROM_ECLK; delay(); - writel(readl(ctrl) | EEPROM_ECLK, ctrl); + *ctrl |= EEPROM_ECLK; delay(); res <<= 1; - if (readl(ctrl) & EEPROM_DATI) + if (*ctrl & EEPROM_DATI) res |= 1; } diff --git a/trunk/arch/mips/sgi-ip22/ip22-time.c b/trunk/arch/mips/sgi-ip22/ip22-time.c index 8e88a442b22a..205554734099 100644 --- a/trunk/arch/mips/sgi-ip22/ip22-time.c +++ b/trunk/arch/mips/sgi-ip22/ip22-time.c @@ -94,7 +94,7 @@ static int indy_rtc_set_time(unsigned long tim) static unsigned long dosample(void) { u32 ct0, ct1; - u8 msb, lsb; + volatile u8 msb, lsb; /* Start the counter. */ sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | @@ -107,21 +107,21 @@ static unsigned long dosample(void) /* Latch and spin until top byte of counter2 is zero */ do { - writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword); - lsb = readb(&sgint->tcnt2); - msb = readb(&sgint->tcnt2); + sgint->tcword = SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT; + lsb = sgint->tcnt2; + msb = sgint->tcnt2; ct1 = read_c0_count(); } while (msb); /* Stop the counter. */ - writeb(sgint->tcword, (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | - SGINT_TCWORD_MSWST)); + sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | + SGINT_TCWORD_MSWST); /* * Return the difference, this is how far the r4k counter increments * for every 1/HZ seconds. We round off the nearest 1 MHz of master * clock (= 1000000 / HZ / 2). */ - + /*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/ return (ct1 - ct0) / (500000/HZ) * (500000/HZ); } diff --git a/trunk/arch/mips/sibyte/Kconfig b/trunk/arch/mips/sibyte/Kconfig index e6b003ec6716..bdf24a7b5494 100644 --- a/trunk/arch/mips/sibyte/Kconfig +++ b/trunk/arch/mips/sibyte/Kconfig @@ -2,7 +2,6 @@ config SIBYTE_SB1250 bool select HW_HAS_PCI select SIBYTE_ENABLE_LDT_IF_PCI - select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP @@ -35,7 +34,6 @@ config SIBYTE_BCM112X config SIBYTE_BCM1x80 bool select HW_HAS_PCI - select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP diff --git a/trunk/arch/mips/sibyte/common/Makefile b/trunk/arch/mips/sibyte/common/Makefile deleted file mode 100644 index 8a06a4fb5212..000000000000 --- a/trunk/arch/mips/sibyte/common/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-y := - -obj-$(CONFIG_SIBYTE_TBPROF) += sb_tbprof.o - -EXTRA_AFLAGS := $(CFLAGS) diff --git a/trunk/arch/mips/sibyte/sb1250/Makefile b/trunk/arch/mips/sibyte/sb1250/Makefile index df662c61473a..04c0f1a7f616 100644 --- a/trunk/arch/mips/sibyte/sb1250/Makefile +++ b/trunk/arch/mips/sibyte/sb1250/Makefile @@ -1,5 +1,6 @@ obj-y := setup.o irq.o time.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o obj-$(CONFIG_SIBYTE_STANDALONE) += prom.o obj-$(CONFIG_SIBYTE_BUS_WATCHER) += bus_watcher.o diff --git a/trunk/arch/mips/sibyte/common/sb_tbprof.c b/trunk/arch/mips/sibyte/sb1250/bcm1250_tbprof.c similarity index 80% rename from trunk/arch/mips/sibyte/common/sb_tbprof.c rename to trunk/arch/mips/sibyte/sb1250/bcm1250_tbprof.c index 4fcdaa8ba514..ea0ca131a3cf 100644 --- a/trunk/arch/mips/sibyte/common/sb_tbprof.c +++ b/trunk/arch/mips/sibyte/sb1250/bcm1250_tbprof.c @@ -31,29 +31,14 @@ #include #include #include +#include #include + #include #include - -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) -#include -#include -#include -#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include #include #include -#else -#error invalid SiByte UART configuation -#endif - -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) -#undef K_INT_TRACE_FREEZE -#define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE -#undef K_INT_PERF_CNT -#define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT -#endif - #include #include @@ -133,7 +118,7 @@ static struct sbprof_tb sbp; : /* inputs */ \ : /* modifies */ "$8" ) -#define DEVNAME "sb_tbprof" +#define DEVNAME "bcm1250_tbprof" #define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES) @@ -147,7 +132,6 @@ static struct sbprof_tb sbp; * overflow. * * We map the interrupt for trace_buffer_freeze to handle it on CPU 0. - * */ static u64 tb_period; @@ -159,36 +143,25 @@ static void arm_tb(void) u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL; /* - * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to - * trigger start of trace. XXX vary sampling period + * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to trigger + *start of trace. XXX vary sampling period */ __raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1)); scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG)); /* - * Unfortunately, in Pass 2 we must clear all counters to knock down - * a previous interrupt request. This means that bus profiling - * requires ALL of the SCD perf counters. + * Unfortunately, in Pass 2 we must clear all counters to knock down a + * previous interrupt request. This means that bus profiling requires + * ALL of the SCD perf counters. */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) - __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) | - /* keep counters 0,2,3,4,5,6,7 as is */ - V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */ - IOADDR(A_BCM1480_SCD_PERF_CNT_CFG0)); - __raw_writeq( - M_SPC_CFG_ENABLE | /* enable counting */ - M_SPC_CFG_CLEAR | /* clear all counters */ - V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */ - IOADDR(A_BCM1480_SCD_PERF_CNT_CFG1)); -#else __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) | /* keep counters 0,2,3 as is */ M_SPC_CFG_ENABLE | /* enable counting */ M_SPC_CFG_CLEAR | /* clear all counters */ V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */ IOADDR(A_SCD_PERF_CNT_CFG)); -#endif __raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1)); + /* Reset the trace buffer */ __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG)); #if 0 && defined(M_SCD_TRACE_CFG_FORCECNT) @@ -217,37 +190,38 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id) /* Subscripts decrease to put bundle in the order */ /* t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */ p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t2 hi */ + /* read t2 hi */ p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t2 lo */ + /* read t2 lo */ p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t1 hi */ + /* read t1 hi */ p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t1 lo */ + /* read t1 lo */ p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t0 hi */ + /* read t0 hi */ p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ)); - /* read t0 lo */ + /* read t0 lo */ } if (!sbp.tb_enable) { pr_debug(DEVNAME ": tb_intr shutdown\n"); __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG)); sbp.tb_armed = 0; - wake_up_interruptible(&sbp.tb_sync); + wake_up(&sbp.tb_sync); } else { - /* knock down current interrupt and get another one later */ - arm_tb(); + arm_tb(); /* knock down current interrupt and get another one later */ } } else { /* No more trace buffer samples */ pr_debug(DEVNAME ": tb_intr full\n"); __raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG)); sbp.tb_armed = 0; - if (!sbp.tb_enable) - wake_up_interruptible(&sbp.tb_sync); - wake_up_interruptible(&sbp.tb_read); + if (!sbp.tb_enable) { + wake_up(&sbp.tb_sync); + } + wake_up(&sbp.tb_read); } + return IRQ_HANDLED; } @@ -276,8 +250,8 @@ static int sbprof_zbprof_start(struct file *filp) sbp.next_tb_sample = 0; filp->f_pos = 0; - err = request_irq (K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, - DEVNAME " trace freeze", &sbp); + err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0, + DEVNAME " trace freeze", &sbp); if (err) return -EBUSY; @@ -289,29 +263,23 @@ static int sbprof_zbprof_start(struct file *filp) IOADDR(A_SCD_PERF_CNT_CFG)); /* - * We grab this interrupt to prevent others from trying to use - * it, even though we don't want to service the interrupts - * (they only feed into the trace-on-interrupt mechanism) + * We grab this interrupt to prevent others from trying to use it, even + * though we don't want to service the interrupts (they only feed into + * the trace-on-interrupt mechanism) */ - if (request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0, DEVNAME " scd perfcnt", &sbp)) { - free_irq(K_INT_TRACE_FREEZE, &sbp); - return -EBUSY; - } + err = request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0, + DEVNAME " scd perfcnt", &sbp); + if (err) + goto out_free_irq; /* - * I need the core to mask these, but the interrupt mapper to - * pass them through. I am exploiting my knowledge that - * cp0_status masks out IP[5]. krw + * I need the core to mask these, but the interrupt mapper to pass them + * through. I am exploiting my knowledge that cp0_status masks out + * IP[5]. krw */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) - __raw_writeq(K_BCM1480_INT_MAP_I3, - IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + - ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3))); -#else __raw_writeq(K_INT_MAP_I3, IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_PERF_CNT << 3))); -#endif /* Initialize address traps */ __raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0)); @@ -330,7 +298,7 @@ static int sbprof_zbprof_start(struct file *filp) __raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3)); /* Initialize Trace Event 0-7 */ - /* when interrupt */ + /* when interrupt */ __raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0)); __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1)); __raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2)); @@ -356,23 +324,24 @@ static int sbprof_zbprof_start(struct file *filp) __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7)); /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) - __raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f), - IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L))); -#else __raw_writeq(1ULL << K_INT_PERF_CNT, IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE))); -#endif + arm_tb(); pr_debug(DEVNAME ": done starting\n"); return 0; + +out_free_irq: + free_irq(K_INT_TRACE_FREEZE, &sbp); + + return err; } static int sbprof_zbprof_stop(void) { - int err = 0; + int err; pr_debug(DEVNAME ": stopping\n"); @@ -396,7 +365,7 @@ static int sbprof_zbprof_stop(void) pr_debug(DEVNAME ": done stopping\n"); - return err; + return 0; } static int sbprof_tb_open(struct inode *inode, struct file *filp) @@ -411,9 +380,11 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp) return -EBUSY; memset(&sbp, 0, sizeof(struct sbprof_tb)); + sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES); if (!sbp.sbprof_tbbuf) return -ENOMEM; + memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES); init_waitqueue_head(&sbp.tb_sync); init_waitqueue_head(&sbp.tb_read); @@ -426,9 +397,8 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp) static int sbprof_tb_release(struct inode *inode, struct file *filp) { - int minor; + int minor = iminor(inode); - minor = iminor(inode); if (minor != 0 || !sbp.open) return -ENODEV; @@ -449,10 +419,10 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf, size_t size, loff_t *offp) { int cur_sample, sample_off, cur_count, sample_left; - char *src; - int count = 0; - char *dest = buf; long cur_off = *offp; + char *dest = buf; + int count = 0; + char *src; if (!access_ok(VERIFY_WRITE, buf, size)) return -EFAULT; @@ -475,6 +445,7 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf, mutex_unlock(&sbp.lock); return err; } + pr_debug(DEVNAME ": read from sample %d, %d bytes\n", cur_sample, cur_count); size -= cur_count; @@ -490,46 +461,45 @@ static ssize_t sbprof_tb_read(struct file *filp, char *buf, dest += cur_count; count += cur_count; } + *offp = cur_off; mutex_unlock(&sbp.lock); return count; } -static long sbprof_tb_ioctl(struct file *filp, - unsigned int command, - unsigned long arg) +static long sbprof_tb_ioctl(struct file *filp, unsigned int command, + unsigned long arg) { - int err = 0; + int error = 0; switch (command) { case SBPROF_ZBSTART: mutex_lock(&sbp.lock); - err = sbprof_zbprof_start(filp); + error = sbprof_zbprof_start(filp); mutex_unlock(&sbp.lock); break; case SBPROF_ZBSTOP: mutex_lock(&sbp.lock); - err = sbprof_zbprof_stop(); + error = sbprof_zbprof_stop(); mutex_unlock(&sbp.lock); break; - case SBPROF_ZBWAITFULL: { - err = wait_event_interruptible(sbp.tb_read, TB_FULL); - if (err) + case SBPROF_ZBWAITFULL: + error = wait_event_interruptible(sbp.tb_read, TB_FULL); + if (error) break; - err = put_user(TB_FULL, (int *) arg); + error = put_user(TB_FULL, (int *) arg); break; - } default: - err = -EINVAL; + error = -EINVAL; break; } - return err; + return error; } static const struct file_operations sbprof_tb_fops = { @@ -574,8 +544,8 @@ static int __init sbprof_tb_init(void) sbp.open = 0; tb_period = zbbus_mhz * 10000LL; - pr_info(DEVNAME ": initialized - tb_period = %lld\n", - (long long) tb_period); + pr_info(DEVNAME ": initialized - tb_period = %lld\n", tb_period); + return 0; out_class: diff --git a/trunk/arch/mips/sibyte/sb1250/setup.c b/trunk/arch/mips/sibyte/sb1250/setup.c index f4a6169aa0a4..87188f0f6fbe 100644 --- a/trunk/arch/mips/sibyte/sb1250/setup.c +++ b/trunk/arch/mips/sibyte/sb1250/setup.c @@ -141,18 +141,6 @@ static int __init setup_bcm112x(void) periph_rev = 3; pass_str = "A2"; break; - case K_SYS_REVISION_BCM112x_A3: - periph_rev = 3; - pass_str = "A3"; - break; - case K_SYS_REVISION_BCM112x_A4: - periph_rev = 3; - pass_str = "A4"; - break; - case K_SYS_REVISION_BCM112x_B0: - periph_rev = 3; - pass_str = "B0"; - break; default: printk("Unknown %s rev %x\n", soc_str, soc_pass); ret = 1; diff --git a/trunk/arch/mips/sni/pcimt.c b/trunk/arch/mips/sni/pcimt.c index 9ee208daa8b1..8e8593b64f6a 100644 --- a/trunk/arch/mips/sni/pcimt.c +++ b/trunk/arch/mips/sni/pcimt.c @@ -91,7 +91,7 @@ static struct platform_device pcimt_serial8250_device = { }; static struct resource sni_io_resource = { - .start = 0x00000000UL, + .start = 0x00001000UL, .end = 0x03bfffffUL, .name = "PCIMT IO MEM", .flags = IORESOURCE_IO, @@ -132,19 +132,107 @@ static struct resource pcimt_io_resources[] = { }; static struct resource sni_mem_resource = { - .start = 0x18000000UL, - .end = 0x1fbfffffUL, + .start = 0x10000000UL, + .end = 0xffffffffUL, .name = "PCIMT PCI MEM", .flags = IORESOURCE_MEM }; +/* + * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used + * for other purposes. Be paranoid and allocate all of the before the PCI + * code gets a chance to to map anything else there ... + * + * This leaves the following areas available: + * + * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory + * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory + * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory + * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory + * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory + */ +static struct resource pcimt_mem_resources[] = { + { + .start = 0x100a0000, + .end = 0x100bffff, + .name = "Video RAM area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x100c0000, + .end = 0x100fffff, + .name = "ISA Reserved", + .flags = IORESOURCE_BUSY + }, { + .start = 0x14000000, + .end = 0x17bfffff, + .name = "PCI IO", + .flags = IORESOURCE_BUSY + }, { + .start = 0x17c00000, + .end = 0x17ffffff, + .name = "Cache Replacement Area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1a000000, + .end = 0x1a000003, + .name = "PCI INT Acknowledge", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc00000, + .end = 0x1fc7ffff, + .name = "Boot PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc80000, + .end = 0x1fcfffff, + .name = "Diag PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fd00000, + .end = 0x1fdfffff, + .name = "X-Bus", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fe00000, + .end = 0x1fefffff, + .name = "BIOS map", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ff00000, + .end = 0x1ff7ffff, + .name = "NVRAM / EEPROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fff0000, + .end = 0x1fffefff, + .name = "ASIC PCI", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ffff000, + .end = 0x1fffffff, + .name = "MP Agent", + .flags = IORESOURCE_BUSY + }, { + .start = 0x20000000, + .end = 0x9fffffff, + .name = "Main Memory", + .flags = IORESOURCE_BUSY + } +}; + static void __init sni_pcimt_resource_init(void) { int i; /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) - request_resource(&sni_io_resource, pcimt_io_resources + i); + request_resource(&ioport_resource, pcimt_io_resources + i); + + /* request mem space for pcimt-specific devices */ + for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) + request_resource(&sni_mem_resource, pcimt_mem_resources + i); + + ioport_resource.end = sni_io_resource.end; } extern struct pci_ops sni_pcimt_ops; @@ -152,10 +240,9 @@ extern struct pci_ops sni_pcimt_ops; static struct pci_controller sni_controller = { .pci_ops = &sni_pcimt_ops, .mem_resource = &sni_mem_resource, - .mem_offset = 0x00000000UL, + .mem_offset = 0x10000000UL, .io_resource = &sni_io_resource, - .io_offset = 0x00000000UL, - .io_map_base = SNI_PORT_BASE + .io_offset = 0x00000000UL }; static void enable_pcimt_irq(unsigned int irq) @@ -276,17 +363,15 @@ void __init sni_pcimt_irq_init(void) void sni_pcimt_init(void) { + sni_pcimt_resource_init(); sni_pcimt_detect(); sni_pcimt_sc_init(); rtc_mips_get_time = mc146818_get_cmos_time; rtc_mips_set_time = mc146818_set_rtc_mmss; board_time_init = sni_cpu_time_init; - ioport_resource.end = sni_io_resource.end; #ifdef CONFIG_PCI - PCIBIOS_MIN_IO = 0x9000; register_pci_controller(&sni_controller); #endif - sni_pcimt_resource_init(); } static int __init snirm_pcimt_setup_devinit(void) diff --git a/trunk/arch/mips/sni/pcit.c b/trunk/arch/mips/sni/pcit.c index 00d151f4d121..1dfc3f00bbd3 100644 --- a/trunk/arch/mips/sni/pcit.c +++ b/trunk/arch/mips/sni/pcit.c @@ -43,7 +43,7 @@ static struct platform_device pcit_serial8250_device = { }; static struct plat_serial8250_port pcit_cplus_data[] = { - PORT(0x3f8, 0), + PORT(0x3f8, 4), PORT(0x2f8, 3), PORT(0x3e8, 4), PORT(0x2e8, 3), @@ -59,9 +59,9 @@ static struct platform_device pcit_cplus_serial8250_device = { }; static struct resource sni_io_resource = { - .start = 0x00000000UL, + .start = 0x00001000UL, .end = 0x03bfffffUL, - .name = "PCIT IO", + .name = "PCIT IO MEM", .flags = IORESOURCE_IO, }; @@ -91,11 +91,6 @@ static struct resource pcit_io_resources[] = { .end = 0xdf, .name = "dma2", .flags = IORESOURCE_BUSY - }, { - .start = 0xcf8, - .end = 0xcfb, - .name = "PCI config addr", - .flags = IORESOURCE_BUSY }, { .start = 0xcfc, .end = 0xcff, @@ -105,19 +100,107 @@ static struct resource pcit_io_resources[] = { }; static struct resource sni_mem_resource = { - .start = 0x18000000UL, - .end = 0x1fbfffffUL, + .start = 0x10000000UL, + .end = 0xffffffffUL, .name = "PCIT PCI MEM", .flags = IORESOURCE_MEM }; +/* + * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used + * for other purposes. Be paranoid and allocate all of the before the PCI + * code gets a chance to to map anything else there ... + * + * This leaves the following areas available: + * + * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory + * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory + * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory + * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory + * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory + */ +static struct resource pcit_mem_resources[] = { + { + .start = 0x14000000, + .end = 0x17bfffff, + .name = "PCI IO", + .flags = IORESOURCE_BUSY + }, { + .start = 0x17c00000, + .end = 0x17ffffff, + .name = "Cache Replacement Area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x180a0000, + .end = 0x180bffff, + .name = "Video RAM area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x180c0000, + .end = 0x180fffff, + .name = "ISA Reserved", + .flags = IORESOURCE_BUSY + }, { + .start = 0x19000000, + .end = 0x1fbfffff, + .name = "PCI MEM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc00000, + .end = 0x1fc7ffff, + .name = "Boot PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc80000, + .end = 0x1fcfffff, + .name = "Diag PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fd00000, + .end = 0x1fdfffff, + .name = "X-Bus", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fe00000, + .end = 0x1fefffff, + .name = "BIOS map", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ff00000, + .end = 0x1ff7ffff, + .name = "NVRAM / EEPROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fff0000, + .end = 0x1fffefff, + .name = "MAUI ASIC", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ffff000, + .end = 0x1fffffff, + .name = "MP Agent", + .flags = IORESOURCE_BUSY + }, { + .start = 0x20000000, + .end = 0x9fffffff, + .name = "Main Memory", + .flags = IORESOURCE_BUSY + } +}; + static void __init sni_pcit_resource_init(void) { int i; /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++) - request_resource(&sni_io_resource, pcit_io_resources + i); + request_resource(&ioport_resource, pcit_io_resources + i); + + /* request mem space for pcimt-specific devices */ + for (i = 0; i < ARRAY_SIZE(pcit_mem_resources); i++) + request_resource(&sni_mem_resource, pcit_mem_resources + i); + + ioport_resource.end = sni_io_resource.end; } @@ -126,10 +209,9 @@ extern struct pci_ops sni_pcit_ops; static struct pci_controller sni_pcit_controller = { .pci_ops = &sni_pcit_ops, .mem_resource = &sni_mem_resource, - .mem_offset = 0x00000000UL, + .mem_offset = 0x10000000UL, .io_resource = &sni_io_resource, - .io_offset = 0x00000000UL, - .io_map_base = SNI_PORT_BASE + .io_offset = 0x00000000UL }; static void enable_pcit_irq(unsigned int irq) @@ -180,7 +262,7 @@ static void pcit_hwint0(void) int irq; clear_c0_status(IE_IRQ0); - irq = ffs((pending >> 16) & 0x3f); + irq = ffs((pending >> 16) & 0x7f); if (likely(irq > 0)) do_IRQ (irq + SNI_PCIT_INT_START - 1); @@ -207,8 +289,6 @@ static void sni_pcit_hwint_cplus(void) if (pending & C_IRQ0) pcit_hwint0(); - else if (pending & C_IRQ1) - do_IRQ (MIPS_CPU_IRQ_BASE + 3); else if (pending & C_IRQ2) do_IRQ (MIPS_CPU_IRQ_BASE + 4); else if (pending & C_IRQ3) @@ -237,23 +317,21 @@ void __init sni_pcit_cplus_irq_init(void) mips_cpu_irq_init(); for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++) set_irq_chip(i, &pcit_irq_type); - *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000; + *(volatile u32 *)SNI_PCIT_INT_REG = 0; sni_hwint = sni_pcit_hwint_cplus; change_c0_status(ST0_IM, IE_IRQ0); - setup_irq (MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq); + setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq); } void sni_pcit_init(void) { + sni_pcit_resource_init(); rtc_mips_get_time = mc146818_get_cmos_time; rtc_mips_set_time = mc146818_set_rtc_mmss; board_time_init = sni_cpu_time_init; - ioport_resource.end = sni_io_resource.end; #ifdef CONFIG_PCI - PCIBIOS_MIN_IO = 0x9000; register_pci_controller(&sni_pcit_controller); #endif - sni_pcit_resource_init(); } static int __init snirm_pcit_setup_devinit(void) diff --git a/trunk/arch/mips/vr41xx/Kconfig b/trunk/arch/mips/vr41xx/Kconfig index 8f4d3e74c230..92f41f6f934a 100644 --- a/trunk/arch/mips/vr41xx/Kconfig +++ b/trunk/arch/mips/vr41xx/Kconfig @@ -1,10 +1,6 @@ -choice - prompt "Machine type" - depends on MACH_VR41XX - default TANBAC_TB022X - config CASIO_E55 - bool "CASIO CASSIOPEIA E-10/15/55/65" + bool "Support for CASIO CASSIOPEIA E-10/15/55/65" + depends on MACH_VR41XX select DMA_NONCOHERENT select IRQ_CPU select ISA @@ -12,7 +8,8 @@ config CASIO_E55 select SYS_SUPPORTS_LITTLE_ENDIAN config IBM_WORKPAD - bool "IBM WorkPad z50" + bool "Support for IBM WorkPad z50" + depends on MACH_VR41XX select DMA_NONCOHERENT select IRQ_CPU select ISA @@ -20,18 +17,26 @@ config IBM_WORKPAD select SYS_SUPPORTS_LITTLE_ENDIAN config NEC_CMBVR4133 - bool "NEC CMB-VR4133" + bool "Support for NEC CMB-VR4133" + depends on MACH_VR41XX select DMA_NONCOHERENT select IRQ_CPU select HW_HAS_PCI select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN +config ROCKHOPPER + bool "Support for Rockhopper baseboard" + depends on NEC_CMBVR4133 + select I8259 + select HAVE_STD_PC_SERIAL_PORT + config TANBAC_TB022X - bool "TANBAC VR4131 multichip module and TANBAC VR4131DIMM" + bool "Support for TANBAC VR4131 multichip module and TANBAC VR4131DIMM" + depends on MACH_VR41XX select DMA_NONCOHERENT - select IRQ_CPU select HW_HAS_PCI + select IRQ_CPU select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN help @@ -41,65 +46,40 @@ config TANBAC_TB022X Please refer to about VR4131 multichip module and VR4131DIMM. -config VICTOR_MPC30X - bool "Victor MP-C303/304" - select DMA_NONCOHERENT - select IRQ_CPU - select HW_HAS_PCI - select PCI_VR41XX - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_LITTLE_ENDIAN - -config ZAO_CAPCELLA - bool "ZAO Networks Capcella" - select DMA_NONCOHERENT - select IRQ_CPU - select HW_HAS_PCI - select PCI_VR41XX - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_LITTLE_ENDIAN - -endchoice - -config ROCKHOPPER - bool "Support for Rockhopper base board" - depends on NEC_CMBVR4133 - select PCI_VR41XX - select I8259 - select HAVE_STD_PC_SERIAL_PORT - -choice - prompt "Base board type" - depends on TANBAC_TB022X - default TANBAC_TB0287 - -config TANBAC_TB0219 - bool "TANBAC DIMM Evaluation Kit(TB0219)" - select GPIO_VR41XX - select PCI_VR41XX - help - The TANBAC DIMM Evaluation Kit(TB0219) is a MIPS-based platform - manufactured by TANBAC. - Please refer to about DIMM Evaluation Kit. - config TANBAC_TB0226 - bool "TANBAC Mbase(TB0226)" + bool "Support for TANBAC Mbase(TB0226)" + depends on TANBAC_TB022X select GPIO_VR41XX - select PCI_VR41XX help The TANBAC Mbase(TB0226) is a MIPS-based platform manufactured by TANBAC. Please refer to about Mbase. config TANBAC_TB0287 - bool "TANBAC Mini-ITX DIMM base(TB0287)" - select PCI_VR41XX + bool "Support for TANBAC Mini-ITX DIMM base(TB0287)" + depends on TANBAC_TB022X help The TANBAC Mini-ITX DIMM base(TB0287) is a MIPS-based platform manufactured by TANBAC. Please refer to about Mini-ITX DIMM base. -endchoice +config VICTOR_MPC30X + bool "Support for Victor MP-C303/304" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + +config ZAO_CAPCELLA + bool "Support for ZAO Networks Capcella" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN config PCI_VR41XX bool "Add PCI control unit support of NEC VR4100 series" diff --git a/trunk/arch/parisc/configs/c3000_defconfig b/trunk/arch/parisc/configs/c3000_defconfig index eb2f9a3d515c..782906b644dd 100644 --- a/trunk/arch/parisc/configs/c3000_defconfig +++ b/trunk/arch/parisc/configs/c3000_defconfig @@ -435,6 +435,7 @@ CONFIG_SCSI_SATA_SIL=m # CONFIG_SCSI_SATA_ULI is not set CONFIG_SCSI_SATA_VIA=m # CONFIG_SCSI_SATA_VITESSE is not set +CONFIG_SCSI_SATA_INTEL_COMBINED=y # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_IPS is not set diff --git a/trunk/arch/parisc/kernel/vmlinux.lds.S b/trunk/arch/parisc/kernel/vmlinux.lds.S index c74585990598..2a8253358c6c 100644 --- a/trunk/arch/parisc/kernel/vmlinux.lds.S +++ b/trunk/arch/parisc/kernel/vmlinux.lds.S @@ -181,7 +181,7 @@ SECTIONS .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; #endif - . = ALIGN(ASM_PAGE_SIZE); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index a54a9a2e36f3..6dfbd52694ab 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -11,11 +11,6 @@ config PPC64 This option selects whether a 32-bit or a 64-bit kernel will be built. -config PPC_PM_NEEDS_RTC_LIB - bool - select RTC_LIB - default y if PM - config PPC32 bool default y if !PPC64 @@ -94,7 +89,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER config ARCH_MAY_HAVE_PC_FDC bool - default !PPC_PSERIES || PCI + default y config PPC_OF def_bool y @@ -162,20 +157,17 @@ config PPC_83xx select FSL_SOC select 83xx select PPC_FPU - select WANT_DEVICE_TREE config PPC_85xx bool "Freescale 85xx" select E500 select FSL_SOC select 85xx - select WANT_DEVICE_TREE config PPC_86xx bool "Freescale 86xx" select 6xx select FSL_SOC - select FSL_PCIE select PPC_FPU select ALTIVEC help @@ -194,6 +186,7 @@ config 44x bool "AMCC 44x" select PPC_DCR_NATIVE + config E200 bool "Freescale e200" @@ -374,7 +367,394 @@ endmenu source "init/Kconfig" -source "arch/powerpc/platforms/Kconfig" +menu "Platform support" + depends on PPC64 || CLASSIC32 + +choice + prompt "Machine type" + default PPC_MULTIPLATFORM + +config PPC_MULTIPLATFORM + bool "Generic desktop/server/laptop" + help + Select this option if configuring for an IBM pSeries or + RS/6000 machine, an Apple machine, or a PReP, CHRP, + Maple or Cell-based machine. + +config EMBEDDED6xx + bool "Embedded 6xx/7xx/7xxx-based board" + depends on PPC32 && (BROKEN||BROKEN_ON_SMP) + +config APUS + bool "Amiga-APUS" + depends on PPC32 && BROKEN + help + Select APUS if configuring for a PowerUP Amiga. + More information is available at: + . +endchoice + +config QUICC_ENGINE + bool + depends on PPC_MPC836x || PPC_MPC832x + default y + help + The QUICC Engine (QE) is a new generation of communications + coprocessors on Freescale embedded CPUs (akin to CPM in older chips). + Selecting this option means that you wish to build a kernel + for a machine with a QE coprocessor. + +config PPC_PSERIES + depends on PPC_MULTIPLATFORM && PPC64 + bool "IBM pSeries & new (POWER5-based) iSeries" + select MPIC + select PPC_I8259 + select PPC_RTAS + select RTAS_ERROR_LOGGING + select PPC_UDBG_16550 + select PPC_NATIVE + default y + +config PPC_ISERIES + bool "IBM Legacy iSeries" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_INDIRECT_IO + +config PPC_CHRP + bool "Common Hardware Reference Platform (CHRP) based machines" + depends on PPC_MULTIPLATFORM && PPC32 + select MPIC + select PPC_I8259 + select PPC_INDIRECT_PCI + select PPC_RTAS + select PPC_MPC106 + select PPC_UDBG_16550 + select PPC_NATIVE + default y + +config PPC_MPC52xx + bool + default n + +config PPC_MPC5200 + bool + select PPC_MPC52xx + default n + +config PPC_MPC5200_BUGFIX + bool "MPC5200 (L25R) bugfix support" + depends on PPC_MPC5200 + default n + help + Enable workarounds for original MPC5200 errata. This is not required + for MPC5200B based boards. + + It is safe to say 'Y' here + +config PPC_EFIKA + bool "bPlan Efika 5k2. MPC5200B based computer" + depends on PPC_MULTIPLATFORM && PPC32 + select PPC_RTAS + select RTAS_PROC + select PPC_MPC52xx + select PPC_NATIVE + default n + +config PPC_LITE5200 + bool "Freescale Lite5200 Eval Board" + depends on PPC_MULTIPLATFORM && PPC32 + select PPC_MPC5200 + default n + +config PPC_PMAC + bool "Apple PowerMac based machines" + depends on PPC_MULTIPLATFORM + select MPIC + select PPC_INDIRECT_PCI if PPC32 + select PPC_MPC106 if PPC32 + select PPC_NATIVE + default y + +config PPC_PMAC64 + bool + depends on PPC_PMAC && POWER4 + select MPIC + select U3_DART + select MPIC_BROKEN_U3 + select GENERIC_TBSYNC + select PPC_970_NAP + default y + +config PPC_PREP + bool "PowerPC Reference Platform (PReP) based machines" + depends on PPC_MULTIPLATFORM && PPC32 && BROKEN + select MPIC + select PPC_I8259 + select PPC_INDIRECT_PCI + select PPC_UDBG_16550 + select PPC_NATIVE + default n + +config PPC_MAPLE + depends on PPC_MULTIPLATFORM && PPC64 + bool "Maple 970FX Evaluation Board" + select MPIC + select U3_DART + select MPIC_BROKEN_U3 + select GENERIC_TBSYNC + select PPC_UDBG_16550 + select PPC_970_NAP + select PPC_NATIVE + select PPC_RTAS + select MMIO_NVRAM + select ATA_NONSTANDARD if ATA + default n + help + This option enables support for the Maple 970FX Evaluation Board. + For more information, refer to + +config PPC_PASEMI + depends on PPC_MULTIPLATFORM && PPC64 + bool "PA Semi SoC-based platforms" + default n + select MPIC + select PPC_UDBG_16550 + select GENERIC_TBSYNC + select PPC_NATIVE + help + This option enables support for PA Semi's PWRficient line + of SoC processors, including PA6T-1682M + +config PPC_CELL + bool + default n + +config PPC_CELL_NATIVE + bool + select PPC_CELL + select PPC_DCR_MMIO + select PPC_OF_PLATFORM_PCI + select PPC_INDIRECT_IO + select PPC_NATIVE + select MPIC + default n + +config PPC_IBM_CELL_BLADE + bool "IBM Cell Blade" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL_NATIVE + select PPC_RTAS + select MMIO_NVRAM + select PPC_UDBG_16550 + select UDBG_RTAS_CONSOLE + +config PPC_PS3 + bool "Sony PS3 (incomplete)" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL + select USB_ARCH_HAS_OHCI + select USB_OHCI_LITTLE_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_ARCH_HAS_EHCI + select USB_EHCI_BIG_ENDIAN_MMIO + help + This option enables support for the Sony PS3 game console + and other platforms using the PS3 hypervisor. + Support for this platform is not yet complete, so + enabling this will not result in a bootable kernel on a + PS3 system. + +config PPC_CELLEB + bool "Toshiba's Cell Reference Set 'Celleb' Architecture" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL + select PPC_OF_PLATFORM_PCI + select HAS_TXX9_SERIAL + select PPC_UDBG_BEAT + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_EHCI_BIG_ENDIAN_MMIO + +config PPC_NATIVE + bool + depends on PPC_MULTIPLATFORM + help + Support for running natively on the hardware, i.e. without + a hypervisor. This option is not user-selectable but should + be selected by all platforms that need it. + +config UDBG_RTAS_CONSOLE + bool "RTAS based debug console" + depends on PPC_RTAS + default n + +config PPC_UDBG_BEAT + bool "BEAT based debug console" + depends on PPC_CELLEB + default n + +config XICS + depends on PPC_PSERIES + bool + default y + +config U3_DART + bool + depends on PPC_MULTIPLATFORM && PPC64 + default n + +config PPC_RTAS + bool + default n + +config RTAS_ERROR_LOGGING + bool + depends on PPC_RTAS + default n + +config RTAS_PROC + bool "Proc interface to RTAS" + depends on PPC_RTAS + default y + +config RTAS_FLASH + tristate "Firmware flash interface" + depends on PPC64 && RTAS_PROC + +config PPC_PMI + tristate "Support for PMI" + depends PPC_IBM_CELL_BLADE + help + PMI (Platform Management Interrupt) is a way to + communicate with the BMC (Baseboard Mangement Controller). + It is used in some IBM Cell blades. + default m + +config MMIO_NVRAM + bool + default n + +config MPIC_BROKEN_U3 + bool + depends on PPC_MAPLE + default y + +config IBMVIO + depends on PPC_PSERIES || PPC_ISERIES + bool + default y + +config IBMEBUS + depends on PPC_PSERIES + bool "Support for GX bus based adapters" + help + Bus device driver for GX bus based adapters. + +config PPC_MPC106 + bool + default n + +config PPC_970_NAP + bool + default n + +config PPC_INDIRECT_IO + bool + select GENERIC_IOMAP + default n + +config GENERIC_IOMAP + bool + default n + +source "drivers/cpufreq/Kconfig" + +config CPU_FREQ_PMAC + bool "Support for Apple PowerBooks" + depends on CPU_FREQ && ADB_PMU && PPC32 + select CPU_FREQ_TABLE + help + This adds support for frequency switching on Apple PowerBooks, + this currently includes some models of iBook & Titanium + PowerBook. + +config CPU_FREQ_PMAC64 + bool "Support for some Apple G5s" + depends on CPU_FREQ && PPC64 + select CPU_FREQ_TABLE + help + This adds support for frequency switching on Apple iMac G5, + and some of the more recent desktop G5 machines as well. + +config PPC601_SYNC_FIX + bool "Workarounds for PPC601 bugs" + depends on 6xx && (PPC_PREP || PPC_PMAC) + help + Some versions of the PPC601 (the first PowerPC chip) have bugs which + mean that extra synchronization instructions are required near + certain instructions, typically those that make major changes to the + CPU state. These extra instructions reduce performance slightly. + If you say N here, these extra instructions will not be included, + resulting in a kernel which will run faster but may not run at all + on some systems with the PPC601 chip. + + If in doubt, say Y here. + +config TAU + bool "On-chip CPU temperature sensor support" + depends on 6xx + help + G3 and G4 processors have an on-chip temperature sensor called the + 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die + temperature within 2-4 degrees Celsius. This option shows the current + on-die temperature in /proc/cpuinfo if the cpu supports it. + + Unfortunately, on some chip revisions, this sensor is very inaccurate + and in many cases, does not work at all, so don't assume the cpu + temp is actually what /proc/cpuinfo says it is. + +config TAU_INT + bool "Interrupt driven TAU driver (DANGEROUS)" + depends on TAU + ---help--- + The TAU supports an interrupt driven mode which causes an interrupt + whenever the temperature goes out of range. This is the fastest way + to get notified the temp has exceeded a range. With this option off, + a timer is used to re-check the temperature periodically. + + However, on some cpus it appears that the TAU interrupt hardware + is buggy and can cause a situation which would lead unexplained hard + lockups. + + Unless you are extending the TAU driver, or enjoy kernel/hardware + debugging, leave this option off. + +config TAU_AVERAGE + bool "Average high and low temp" + depends on TAU + ---help--- + The TAU hardware can compare the temperature to an upper and lower + bound. The default behavior is to show both the upper and lower + bound in /proc/cpuinfo. If the range is large, the temperature is + either changing a lot, or the TAU hardware is broken (likely on some + G4's). If the range is small (around 4 degrees), the temperature is + relatively stable. If you say Y here, a single temperature value, + halfway between the upper and lower bounds, will be reported in + /proc/cpuinfo. + + If in doubt, say N here. + +endmenu + +source arch/powerpc/platforms/embedded6xx/Kconfig +source arch/powerpc/platforms/4xx/Kconfig +source arch/powerpc/platforms/82xx/Kconfig +source arch/powerpc/platforms/83xx/Kconfig +source arch/powerpc/platforms/85xx/Kconfig +source arch/powerpc/platforms/86xx/Kconfig +source arch/powerpc/platforms/8xx/Kconfig +source arch/powerpc/platforms/cell/Kconfig +source arch/powerpc/platforms/ps3/Kconfig +source arch/powerpc/platforms/pasemi/Kconfig menu "Kernel options" @@ -457,6 +837,15 @@ config CRASH_DUMP Don't change this unless you know what you are doing. +config EMBEDDEDBOOT + bool + depends on 8xx || 8260 + default y + +config PC_KEYBOARD + bool "PC PS/2 style Keyboard" + depends on 4xx || CPM2 + config PPCBUG_NVRAM bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC default y if PPC_PREP @@ -470,6 +859,8 @@ config IRQ_ALL_CPUS CPU. Generally saying Y is safe, although some problems have been reported with SMP Power Macintoshes with this option enabled. +source "arch/powerpc/platforms/pseries/Kconfig" + config NUMA bool "NUMA support" depends on PPC64 @@ -519,10 +910,10 @@ config PPC_64K_PAGES depends on PPC64 help This option changes the kernel logical page size to 64k. On machines - without processor support for 64k pages, the kernel will simulate - them by loading each individual 4k page on demand transparently, - while on hardware with such support, it will be used to map - normal application pages. + without processor support for 64k pages, the kernel will simulate + them by loading each individual 4k page on demand transparently, + while on hardware with such support, it will be used to map + normal application pages. config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" @@ -540,6 +931,8 @@ config PROC_DEVICETREE an image of the device tree that the kernel copies from Open Firmware or other boot firmware. If unsure, say Y here. +source "arch/powerpc/platforms/prep/Kconfig" + config CMDLINE_BOOL bool "Default bootloader kernel arguments" @@ -574,29 +967,6 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. -config WANT_DEVICE_TREE - bool - default n - -config DEVICE_TREE - string "Static device tree source file" - depends on WANT_DEVICE_TREE - help - This specifies the device tree source (.dts) file to be - compiled and included when building the bootwrapper. If a - relative filename is given, then it will be relative to - arch/powerpc/boot/dts. If you are not using the bootwrapper, - or do not need to build a dts into the bootwrapper, this - field is ignored. - - For example, this is required when building a cuImage target - for an older U-Boot, which cannot pass a device tree itself. - Such a kernel will not work with a newer U-Boot that tries to - pass a device tree (unless you tell it not to). If your U-Boot - does not mention a device tree in "help bootm", then use the - cuImage target and specify a device tree here. Otherwise, use - the uImage target and leave this field blank. - endmenu config ISA_DMA_API @@ -625,15 +995,22 @@ config GENERIC_ISA_DMA depends on PPC64 || POWER4 || 6xx && !CPM2 default y -config PPC_INDIRECT_PCI +config MPIC + bool + default n + +config MPIC_WEIRD bool - depends on PCI - default y if 40x || 44x default n -config PPC_INDIRECT_PCI_BE +config PPC_I8259 bool - depends PPC_INDIRECT_PCI + default n + +config PPC_INDIRECT_PCI + bool + depends on PCI + default y if 40x || 44x default n config EISA @@ -645,18 +1022,13 @@ config SBUS config FSL_SOC bool -config FSL_PCIE - bool - depends on PPC_86xx - # Yes MCA RS/6000s exist but Linux-PPC does not currently support any config MCA bool config PCI bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \ - || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \ - || MPC7448HPC2 || PPC_PS3 + || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2 || PPC_PS3 default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \ && !PPC_85xx && !PPC_86xx default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS @@ -856,10 +1228,12 @@ source "fs/Kconfig" source "arch/powerpc/sysdev/qe_lib/Kconfig" +source "arch/powerpc/platforms/iseries/Kconfig" + source "lib/Kconfig" menu "Instrumentation Support" - depends on EXPERIMENTAL + depends on EXPERIMENTAL source "arch/powerpc/oprofile/Kconfig" diff --git a/trunk/arch/powerpc/Kconfig.debug b/trunk/arch/powerpc/Kconfig.debug index 86aa3745af7f..d39d13327e6d 100644 --- a/trunk/arch/powerpc/Kconfig.debug +++ b/trunk/arch/powerpc/Kconfig.debug @@ -18,15 +18,6 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config DEBUG_PAGEALLOC - bool "Debug page memory allocations" - depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND - help - Unmap pages from the kernel linear mapping after free_pages(). - This results in a large slowdown, but helps to find certain types - of memory corruptions. - - config HCALL_STATS bool "Hypervisor call instrumentation" depends on PPC_PSERIES && DEBUG_FS @@ -141,7 +132,8 @@ config BOOTX_TEXT config SERIAL_TEXT_DEBUG bool "Support for early boot texts over serial port" - depends on 4xx + depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \ + PPC_GEN550 || PPC_MPC52xx config PPC_EARLY_DEBUG bool "Early debugging (dangerous)" diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile index 794992025d8d..a00fe7236555 100644 --- a/trunk/arch/powerpc/Makefile +++ b/trunk/arch/powerpc/Makefile @@ -102,9 +102,9 @@ CFLAGS += $(call cc-option,-mno-altivec) # kernel considerably. CFLAGS += $(call cc-option,-funit-at-a-time) -# Never use string load/store instructions as they are -# often slow when they are implemented at all -CFLAGS += -mno-string +ifndef CONFIG_FSL_BOOKE +CFLAGS += -mstring +endif ifeq ($(CONFIG_6xx),y) CFLAGS += -mcpu=powerpc @@ -148,7 +148,7 @@ all: $(KBUILD_IMAGE) CPPFLAGS_vmlinux.lds := -Upowerpc -BOOT_TARGETS = zImage zImage.initrd uImage cuImage +BOOT_TARGETS = zImage zImage.initrd uImage PHONY += $(BOOT_TARGETS) @@ -166,9 +166,6 @@ define archhelp @echo ' *_defconfig - Select default config from arch/$(ARCH)/configs' endef -install: - $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install - archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/trunk/arch/powerpc/boot/.gitignore b/trunk/arch/powerpc/boot/.gitignore index eec7af7e5993..0734b2fc1d95 100644 --- a/trunk/arch/powerpc/boot/.gitignore +++ b/trunk/arch/powerpc/boot/.gitignore @@ -18,9 +18,6 @@ kernel-vmlinux.strip.c kernel-vmlinux.strip.gz mktree uImage -cuImage -cuImage.bin.gz -cuImage.elf zImage zImage.chrp zImage.coff diff --git a/trunk/arch/powerpc/boot/Makefile b/trunk/arch/powerpc/boot/Makefile index 3716594ea33e..dc779407de14 100644 --- a/trunk/arch/powerpc/boot/Makefile +++ b/trunk/arch/powerpc/boot/Makefile @@ -40,11 +40,10 @@ zliblinuxheader := zlib.h zconf.h zutil.h $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \ $(addprefix $(obj)/,$(zlibheader)) -src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ - ns16550.c serial.c simple_alloc.c div64.S util.S \ - gunzip_util.c elf_util.c $(zlib) devtree.c -src-plat := of.c cuboot-83xx.c cuboot-85xx.c -src-boot := $(src-wlib) $(src-plat) empty.c +src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ + ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib) +src-plat := of.c +src-boot := crt0.S $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) @@ -76,7 +75,7 @@ $(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S @cp $< $@ clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \ - empty.c zImage.coff.lds zImage.lds + empty.c zImage zImage.coff.lds zImage.lds zImage.sandpoint quiet_cmd_bootcc = BOOTCC $@ cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< @@ -85,25 +84,23 @@ quiet_cmd_bootas = BOOTAS $@ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< quiet_cmd_bootar = BOOTAR $@ - cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@ + cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@ -$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE +$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c $(call if_changed_dep,bootcc) -$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE +$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S $(call if_changed_dep,bootas) -$(obj)/wrapper.a: $(obj-wlib) FORCE - $(call if_changed,bootar) +$(obj)/wrapper.a: $(obj-wlib) + $(call cmd,bootar) hostprogs-y := addnote addRamDisk hack-coff mktree -targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a) -extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ +extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ $(obj)/zImage.lds $(obj)/zImage.coff.lds wrapper :=$(srctree)/$(src)/wrapper -wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \ - $(wrapper) FORCE +wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) ############# # Bits for building various flavours of zImage @@ -116,42 +113,41 @@ CROSSWRAP := -C "$(CROSS_COMPILE)" endif endif -# args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd quiet_cmd_wrap = WRAP $@ - cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \ - $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux + cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux +quiet_cmd_wrap_initrd = WRAP $@ + cmd_wrap_initrd =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \ + -i $(obj)/ramdisk.image.gz vmlinux -image-$(CONFIG_PPC_PSERIES) += zImage.pseries -image-$(CONFIG_PPC_MAPLE) += zImage.pseries -image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries -image-$(CONFIG_PPC_PS3) += zImage.ps3 -image-$(CONFIG_PPC_CELLEB) += zImage.pseries -image-$(CONFIG_PPC_CHRP) += zImage.chrp -image-$(CONFIG_PPC_EFIKA) += zImage.chrp -image-$(CONFIG_PPC_PMAC) += zImage.pmac -image-$(CONFIG_DEFAULT_UIMAGE) += uImage cuImage +$(obj)/zImage.chrp: vmlinux $(wrapperbits) + $(call cmd,wrap,chrp) -# For 32-bit powermacs, build the COFF and miboot images -# as well as the ELF images. -ifeq ($(CONFIG_PPC32),y) -image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot -endif +$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits) + $(call cmd,wrap_initrd,chrp) -initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-)) -initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y)) -initrd-y := $(filter-out $(image-y), $(initrd-y)) -targets += $(image-y) $(initrd-y) +$(obj)/zImage.pseries: vmlinux $(wrapperbits) + $(call cmd,wrap,pseries) + +$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits) + $(call cmd,wrap_initrd,pseries) + +$(obj)/zImage.pmac: vmlinux $(wrapperbits) + $(call cmd,wrap,pmac) + +$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits) + $(call cmd,wrap_initrd,pmac) -$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz +$(obj)/zImage.coff: vmlinux $(wrapperbits) + $(call cmd,wrap,pmaccoff) -# Don't put the ramdisk on the pattern rule; when its missing make will try -# the pattern rule with less dependencies that also matches (even with the -# hard dependency listed). -$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) - $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz) +$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits) + $(call cmd,wrap_initrd,pmaccoff) -$(obj)/zImage.%: vmlinux $(wrapperbits) - $(call if_changed,wrap,$*) +$(obj)/zImage.miboot: vmlinux $(wrapperbits) + $(call cmd,wrap,miboot) + +$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits) + $(call cmd,wrap_initrd,miboot) $(obj)/zImage.ps3: vmlinux $(STRIP) -s -R .comment $< -o $@ @@ -160,32 +156,34 @@ $(obj)/zImage.initrd.ps3: vmlinux @echo " WARNING zImage.initrd.ps3 not supported (yet)" $(obj)/uImage: vmlinux $(wrapperbits) - $(call if_changed,wrap,uboot) + $(call cmd,wrap,uboot) -cuboot-plat-$(CONFIG_83xx) += 83xx -cuboot-plat-$(CONFIG_85xx) += 85xx -cuboot-plat-y += unknown-platform +image-$(CONFIG_PPC_PSERIES) += zImage.pseries +image-$(CONFIG_PPC_MAPLE) += zImage.pseries +image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries +image-$(CONFIG_PPC_PS3) += zImage.ps3 +image-$(CONFIG_PPC_CELLEB) += zImage.pseries +image-$(CONFIG_PPC_CHRP) += zImage.chrp +image-$(CONFIG_PPC_EFIKA) += zImage.chrp +image-$(CONFIG_PPC_PMAC) += zImage.pmac +image-$(CONFIG_DEFAULT_UIMAGE) += uImage -dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\ - ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE) +# For 32-bit powermacs, build the COFF and miboot images +# as well as the ELF images. +ifeq ($(CONFIG_PPC32),y) +image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot +endif -$(obj)/cuImage: vmlinux $(wrapperbits) - $(call if_changed,wrap,cuboot-$(word 1,$(cuboot-plat-y)),$(dts)) +initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y)) $(obj)/zImage: $(addprefix $(obj)/, $(image-y)) @rm -f $@; ln $< $@ $(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y)) @rm -f $@; ln $< $@ -install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) +install: $(CONFIGURE) $(image-y) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $< -# anything not in $(targets) -clean-files += $(image-) $(initrd-) zImage zImage.initrd \ - cuImage.elf cuImage.bin.gz - -# clean up files cached by wrapper -clean-kernel := vmlinux.strip vmlinux.bin -clean-kernel += $(addsuffix .gz,$(clean-kernel)) -# If not absolute clean-files are relative to $(obj). -clean-files += $(addprefix $(objtree)/, $(clean-kernel)) +clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz) +clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz) +clean-files += $(image-) diff --git a/trunk/arch/powerpc/boot/crt0.S b/trunk/arch/powerpc/boot/crt0.S index 5a4215c4b014..70e65b13e033 100644 --- a/trunk/arch/powerpc/boot/crt0.S +++ b/trunk/arch/powerpc/boot/crt0.S @@ -16,11 +16,8 @@ _zimage_start_opd: .long _zimage_start, 0, 0, 0 - .weak _zimage_start .globl _zimage_start _zimage_start: - .globl _zimage_start_lib -_zimage_start_lib: /* Work out the offset between the address we were linked at and the address where we're running. */ bl 1f @@ -47,7 +44,7 @@ _zimage_start_lib: addi r9,r9,4 bdnz 2b - /* Do a cache flush for our text, in case the loader didn't */ + /* Do a cache flush for our text, in case OF didn't */ 3: lis r9,_start@ha addi r9,r9,_start@l add r9,r0,r9 @@ -62,34 +59,6 @@ _zimage_start_lib: sync isync - /* Clear the BSS */ - lis r9,__bss_start@ha - addi r9,r9,__bss_start@l - add r9,r0,r9 - lis r8,_end@ha - addi r8,r8,_end@l - add r8,r0,r8 - li r10,0 -5: stw r10,0(r9) - addi r9,r9,4 - cmplw cr0,r9,r8 - blt 5b - - /* Possibly set up a custom stack */ -.weak _platform_stack_top - lis r8,_platform_stack_top@ha - addi r8,r8,_platform_stack_top@l - cmpwi r8,0 - beq 6f - add r8,r0,r8 - lwz r1,0(r8) - add r1,r0,r1 - li r0,0 - stwu r0,-16(r1) /* establish a stack frame */ -6: - - /* Call platform_init() */ - bl platform_init - - /* Call start */ + mr r6,r1 b start + diff --git a/trunk/arch/powerpc/boot/cuboot-83xx.c b/trunk/arch/powerpc/boot/cuboot-83xx.c deleted file mode 100644 index 6cbc20afb4d8..000000000000 --- a/trunk/arch/powerpc/boot/cuboot-83xx.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Old U-boot compatibility for 83xx - * - * Author: Scott Wood - * - * Copyright (c) 2007 Freescale Semiconductor, Inc. - * - * 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 "ops.h" -#include "stdio.h" - -#define TARGET_83xx -#include "ppcboot.h" - -static bd_t bd; -extern char _end[]; -extern char _dtb_start[], _dtb_end[]; - -static void platform_fixups(void) -{ - void *soc; - - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); - dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); - - /* Unfortunately, the specific model number is encoded in the - * soc node name in existing dts files -- once that is fixed, - * this can do a simple path lookup. - */ - soc = find_node_by_devtype(NULL, "soc"); - if (soc) { - void *serial = NULL; - - setprop(soc, "bus-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); - - while ((serial = find_node_by_devtype(serial, "serial"))) { - if (get_parent(serial) != soc) - continue; - - setprop(serial, "clock-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); - } - } -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize; - unsigned long avail_ram = end_of_ram - (unsigned long)_end; - - memcpy(&bd, (bd_t *)r3, sizeof(bd)); - loader_info.initrd_addr = r4; - loader_info.initrd_size = r4 ? r5 : 0; - loader_info.cmdline = (char *)r6; - loader_info.cmdline_len = r7 - r6; - - simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64); - ft_init(_dtb_start, _dtb_end - _dtb_start, 32); - serial_console_init(); - platform_ops.fixups = platform_fixups; -} diff --git a/trunk/arch/powerpc/boot/cuboot-85xx.c b/trunk/arch/powerpc/boot/cuboot-85xx.c deleted file mode 100644 index f88ba00ac122..000000000000 --- a/trunk/arch/powerpc/boot/cuboot-85xx.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Old U-boot compatibility for 85xx - * - * Author: Scott Wood - * - * Copyright (c) 2007 Freescale Semiconductor, Inc. - * - * 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 "ops.h" -#include "stdio.h" - -#define TARGET_85xx -#include "ppcboot.h" - -static bd_t bd; -extern char _end[]; -extern char _dtb_start[], _dtb_end[]; - -static void platform_fixups(void) -{ - void *soc; - - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr, - bd.bi_enet2addr); - dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 8, bd.bi_busfreq); - - /* Unfortunately, the specific model number is encoded in the - * soc node name in existing dts files -- once that is fixed, - * this can do a simple path lookup. - */ - soc = find_node_by_devtype(NULL, "soc"); - if (soc) { - void *serial = NULL; - - setprop(soc, "bus-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); - - while ((serial = find_node_by_devtype(serial, "serial"))) { - if (get_parent(serial) != soc) - continue; - - setprop(serial, "clock-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); - } - } -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize; - unsigned long avail_ram = end_of_ram - (unsigned long)_end; - - memcpy(&bd, (bd_t *)r3, sizeof(bd)); - loader_info.initrd_addr = r4; - loader_info.initrd_size = r4 ? r5 : 0; - loader_info.cmdline = (char *)r6; - loader_info.cmdline_len = r7 - r6; - - simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64); - ft_init(_dtb_start, _dtb_end - _dtb_start, 32); - serial_console_init(); - platform_ops.fixups = platform_fixups; -} diff --git a/trunk/arch/powerpc/boot/devtree.c b/trunk/arch/powerpc/boot/devtree.c deleted file mode 100644 index c9951550ed2c..000000000000 --- a/trunk/arch/powerpc/boot/devtree.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * devtree.c - convenience functions for device tree manipulation - * Copyright 2007 David Gibson, IBM Corporation. - * Copyright (c) 2007 Freescale Semiconductor, Inc. - * - * Authors: David Gibson - * Scott Wood - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include "types.h" -#include "string.h" -#include "stdio.h" -#include "ops.h" - -void dt_fixup_memory(u64 start, u64 size) -{ - void *root, *memory; - int naddr, nsize, i; - u32 memreg[4]; - - root = finddevice("/"); - if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0) - naddr = 2; - if (naddr < 1 || naddr > 2) - fatal("Can't cope with #address-cells == %d in /\n\r", naddr); - - if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0) - nsize = 1; - if (nsize < 1 || nsize > 2) - fatal("Can't cope with #size-cells == %d in /\n\r", nsize); - - i = 0; - if (naddr == 2) - memreg[i++] = start >> 32; - memreg[i++] = start & 0xffffffff; - if (nsize == 2) - memreg[i++] = size >> 32; - memreg[i++] = size & 0xffffffff; - - memory = finddevice("/memory"); - if (! memory) { - memory = create_node(NULL, "memory"); - setprop_str(memory, "device_type", "memory"); - } - - printf("Memory <- <0x%x", memreg[0]); - for (i = 1; i < (naddr + nsize); i++) - printf(" 0x%x", memreg[i]); - printf("> (%ldMB)\n\r", (unsigned long)(size >> 20)); - - setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32)); -} - -#define MHZ(x) ((x + 500000) / 1000000) - -void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus) -{ - void *devp = NULL; - - printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu)); - printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb)); - if (bus > 0) - printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus)); - - while ((devp = find_node_by_devtype(devp, "cpu"))) { - setprop_val(devp, "clock-frequency", cpu); - setprop_val(devp, "timebase-frequency", tb); - if (bus > 0) - setprop_val(devp, "bus-frequency", bus); - } -} - -void dt_fixup_clock(const char *path, u32 freq) -{ - void *devp = finddevice(path); - - if (devp) { - printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq)); - setprop_val(devp, "clock-frequency", freq); - } -} - -void __dt_fixup_mac_addresses(u32 startindex, ...) -{ - va_list ap; - u32 index = startindex; - void *devp; - const u8 *addr; - - va_start(ap, startindex); - while ((addr = va_arg(ap, const u8 *))) { - devp = find_node_by_prop_value(NULL, "linux,network-index", - (void*)&index, sizeof(index)); - - printf("ENET%d: local-mac-address <-" - " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index, - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - - if (devp) - setprop(devp, "local-mac-address", addr, 6); - - index++; - } - va_end(ap); -} - -#define MAX_ADDR_CELLS 4 -#define MAX_RANGES 8 - -static void get_reg_format(void *node, u32 *naddr, u32 *nsize) -{ - if (getprop(node, "#address-cells", naddr, 4) != 4) - *naddr = 2; - if (getprop(node, "#size-cells", nsize, 4) != 4) - *nsize = 1; -} - -static void copy_val(u32 *dest, u32 *src, int naddr) -{ - int pad = MAX_ADDR_CELLS - naddr; - - memset(dest, 0, pad * 4); - memcpy(dest + pad, src, naddr * 4); -} - -static int sub_reg(u32 *reg, u32 *sub) -{ - int i, borrow = 0; - - for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) { - int prev_borrow = borrow; - borrow = reg[i] < sub[i] + prev_borrow; - reg[i] -= sub[i] + prev_borrow; - } - - return !borrow; -} - -static int add_reg(u32 *reg, u32 *add, int naddr) -{ - int i, carry = 0; - - for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) { - u64 tmp = (u64)reg[i] + add[i] + carry; - carry = tmp >> 32; - reg[i] = (u32)tmp; - } - - return !carry; -} - -/* It is assumed that if the first byte of reg fits in a - * range, then the whole reg block fits. - */ -static int compare_reg(u32 *reg, u32 *range, u32 *rangesize) -{ - int i; - u32 end; - - for (i = 0; i < MAX_ADDR_CELLS; i++) { - if (reg[i] < range[i]) - return 0; - if (reg[i] > range[i]) - break; - } - - for (i = 0; i < MAX_ADDR_CELLS; i++) { - end = range[i] + rangesize[i]; - - if (reg[i] < end) - break; - if (reg[i] > end) - return 0; - } - - return reg[i] != end; -} - -/* reg must be MAX_ADDR_CELLS */ -static int find_range(u32 *reg, u32 *ranges, int nregaddr, - int naddr, int nsize, int buflen) -{ - int nrange = nregaddr + naddr + nsize; - int i; - - for (i = 0; i + nrange <= buflen; i += nrange) { - u32 range_addr[MAX_ADDR_CELLS]; - u32 range_size[MAX_ADDR_CELLS]; - - copy_val(range_addr, ranges + i, naddr); - copy_val(range_size, ranges + i + nregaddr + naddr, nsize); - - if (compare_reg(reg, range_addr, range_size)) - return i; - } - - return -1; -} - -/* Currently only generic buses without special encodings are supported. - * In particular, PCI is not supported. Also, only the beginning of the - * reg block is tracked; size is ignored except in ranges. - */ -static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3]; - -static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, - unsigned long *size) -{ - u32 last_addr[MAX_ADDR_CELLS]; - u32 this_addr[MAX_ADDR_CELLS]; - void *parent; - u64 ret_addr, ret_size; - u32 naddr, nsize, prev_naddr; - int buflen, offset; - - parent = get_parent(node); - if (!parent) - return 0; - - get_reg_format(parent, &naddr, &nsize); - - if (nsize > 2) - return 0; - - offset = (naddr + nsize) * res; - - if (reglen < offset + naddr + nsize || - sizeof(dt_xlate_buf) < offset + naddr + nsize) - return 0; - - copy_val(last_addr, dt_xlate_buf + offset, naddr); - - ret_size = dt_xlate_buf[offset + naddr]; - if (nsize == 2) { - ret_size <<= 32; - ret_size |= dt_xlate_buf[offset + naddr + 1]; - } - - while ((node = get_parent(node))) { - prev_naddr = naddr; - - get_reg_format(node, &naddr, &nsize); - - buflen = getprop(node, "ranges", dt_xlate_buf, - sizeof(dt_xlate_buf)); - if (buflen < 0) - continue; - if (buflen > sizeof(dt_xlate_buf)) - return 0; - - offset = find_range(last_addr, dt_xlate_buf, prev_naddr, - naddr, nsize, buflen / 4); - - if (offset < 0) - return 0; - - copy_val(this_addr, dt_xlate_buf + offset, prev_naddr); - - if (!sub_reg(last_addr, this_addr)) - return 0; - - copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr); - - if (!add_reg(last_addr, this_addr, naddr)) - return 0; - } - - if (naddr > 2) - return 0; - - ret_addr = ((u64)last_addr[2] << 32) | last_addr[3]; - - if (sizeof(void *) == 4 && - (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL || - ret_addr + ret_size > 0x100000000ULL)) - return 0; - - *addr = ret_addr; - if (size) - *size = ret_size; - - return 1; -} - -int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size) -{ - int reglen; - - reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4; - return dt_xlate(node, res, reglen, addr, size); -} - -int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr) -{ - - if (buflen > sizeof(dt_xlate_buf)) - return 0; - - memcpy(dt_xlate_buf, buf, buflen); - return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL); -} diff --git a/trunk/arch/powerpc/boot/dts/kuroboxHD.dts b/trunk/arch/powerpc/boot/dts/kuroboxHD.dts index 157dc98d3988..b89791802e86 100644 --- a/trunk/arch/powerpc/boot/dts/kuroboxHD.dts +++ b/trunk/arch/powerpc/boot/dts/kuroboxHD.dts @@ -29,6 +29,7 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts" cpus { linux,phandle = <2000>; + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; @@ -125,17 +126,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts" interrupt-parent = <4400>; interrupt-map-mask = ; interrupt-map = < - /* IDSEL 11 - IRQ0 ETH */ + /* IDSEL 0x11 - IRQ0 ETH */ 5800 0 0 1 4400 0 1 5800 0 0 2 4400 1 1 5800 0 0 3 4400 2 1 5800 0 0 4 4400 3 1 - /* IDSEL 12 - IRQ1 IDE0 */ + /* IDSEL 0x12 - IRQ1 IDE0 */ 6000 0 0 1 4400 1 1 6000 0 0 2 4400 2 1 6000 0 0 3 4400 3 1 6000 0 0 4 4400 0 1 - /* IDSEL 14 - IRQ3 USB2.0 */ + /* IDSEL 0x14 - IRQ3 USB2.0 */ 7000 0 0 1 4400 3 1 7000 0 0 2 4400 3 1 7000 0 0 3 4400 3 1 diff --git a/trunk/arch/powerpc/boot/dts/kuroboxHG.dts b/trunk/arch/powerpc/boot/dts/kuroboxHG.dts index 919eb29097db..753102752d8b 100644 --- a/trunk/arch/powerpc/boot/dts/kuroboxHG.dts +++ b/trunk/arch/powerpc/boot/dts/kuroboxHG.dts @@ -29,6 +29,7 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts" cpus { linux,phandle = <2000>; + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; @@ -125,17 +126,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts" interrupt-parent = <4400>; interrupt-map-mask = ; interrupt-map = < - /* IDSEL 11 - IRQ0 ETH */ + /* IDSEL 0x11 - IRQ0 ETH */ 5800 0 0 1 4400 0 1 5800 0 0 2 4400 1 1 5800 0 0 3 4400 2 1 5800 0 0 4 4400 3 1 - /* IDSEL 12 - IRQ1 IDE0 */ + /* IDSEL 0x12 - IRQ1 IDE0 */ 6000 0 0 1 4400 1 1 6000 0 0 2 4400 2 1 6000 0 0 3 4400 3 1 6000 0 0 4 4400 0 1 - /* IDSEL 14 - IRQ3 USB2.0 */ + /* IDSEL 0x14 - IRQ3 USB2.0 */ 7000 0 0 1 4400 3 1 7000 0 0 2 4400 3 1 7000 0 0 3 4400 3 1 diff --git a/trunk/arch/powerpc/boot/dts/lite5200.dts b/trunk/arch/powerpc/boot/dts/lite5200.dts index ba54c6b40a09..c03103c63285 100644 --- a/trunk/arch/powerpc/boot/dts/lite5200.dts +++ b/trunk/arch/powerpc/boot/dts/lite5200.dts @@ -24,6 +24,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/lite5200b.dts b/trunk/arch/powerpc/boot/dts/lite5200b.dts index 2e003081b0d3..3875ca9a9a62 100644 --- a/trunk/arch/powerpc/boot/dts/lite5200b.dts +++ b/trunk/arch/powerpc/boot/dts/lite5200b.dts @@ -24,6 +24,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc7448hpc2.dts b/trunk/arch/powerpc/boot/dts/mpc7448hpc2.dts index 6fa3754f293a..41d0720c5900 100644 --- a/trunk/arch/powerpc/boot/dts/mpc7448hpc2.dts +++ b/trunk/arch/powerpc/boot/dts/mpc7448hpc2.dts @@ -19,6 +19,7 @@ linux,phandle = <100>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells =<0>; linux,phandle = <200>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8272ads.dts b/trunk/arch/powerpc/boot/dts/mpc8272ads.dts index 423eedcf634f..260b2e447779 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8272ads.dts @@ -17,6 +17,7 @@ linux,phandle = <100>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; linux,phandle = <200>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts b/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts index a1533cc07d09..6d721900d00e 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -16,6 +16,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts index c798491f4cd0..06b310698a02 100644 --- a/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts @@ -16,6 +16,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts b/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts deleted file mode 100644 index b55bced1593d..000000000000 --- a/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ /dev/null @@ -1,291 +0,0 @@ -/* - * MPC832x RDB Device Tree Source - * - * Copyright 2007 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/ { - model = "MPC8323ERDB"; - compatible = "MPC8323ERDB", "MPC832xRDB", "MPC83xxRDB"; - #address-cells = <1>; - #size-cells = <1>; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8323@0 { - device_type = "cpu"; - reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <4000>; // L1, 16K - i-cache-size = <4000>; // L1, 16K - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - 32-bit; - }; - }; - - memory { - device_type = "memory"; - reg = <00000000 04000000>; - }; - - soc8323@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "soc"; - ranges = <0 e0000000 00100000>; - reg = ; - bus-frequency = <0>; - - wdt@200 { - device_type = "watchdog"; - compatible = "mpc83xx_wdt"; - reg = <200 100>; - }; - - i2c@3000 { - device_type = "i2c"; - compatible = "fsl-i2c"; - reg = <3000 100>; - interrupts = ; - interrupt-parent = <&pic>; - dfsrr; - }; - - serial@4500 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4500 100>; - clock-frequency = <0>; - interrupts = <9 8>; - interrupt-parent = <&pic>; - }; - - serial@4600 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4600 100>; - clock-frequency = <0>; - interrupts = ; - interrupt-parent = <&pic>; - }; - - crypto@30000 { - device_type = "crypto"; - model = "SEC2"; - compatible = "talitos"; - reg = <30000 7000>; - interrupts = ; - interrupt-parent = <&pic>; - /* Rev. 2.2 */ - num-channels = <1>; - channel-fifo-len = <18>; - exec-units-mask = <0000004c>; - descriptor-types-mask = <0122003f>; - }; - - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x10 AD16 (USB) */ - 8000 0 0 1 &pic 11 8 - - /* IDSEL 0x11 AD17 (Mini1)*/ - 8800 0 0 1 &pic 12 8 - 8800 0 0 2 &pic 13 8 - 8800 0 0 3 &pic 14 8 - 8800 0 0 4 &pic 30 8 - - /* IDSEL 0x12 AD18 (PCI/Mini2) */ - 9000 0 0 1 &pic 13 8 - 9000 0 0 2 &pic 14 8 - 9000 0 0 3 &pic 30 8 - 9000 0 0 4 &pic 11 8>; - - interrupt-parent = <&pic>; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <42000000 0 80000000 80000000 0 10000000 - 02000000 0 90000000 90000000 0 10000000 - 01000000 0 d0000000 d0000000 0 04000000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "83xx"; - device_type = "pci"; - }; - - pic:pic@700 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <700 100>; - built-in; - device_type = "ipic"; - }; - - par_io@1400 { - reg = <1400 100>; - device_type = "par_io"; - num-ports = <7>; - - ucc2pio:ucc_pin@02 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 3 4 3 0 2 0 /* MDIO */ - 3 5 1 0 2 0 /* MDC */ - 3 15 2 0 1 0 /* RX_CLK (CLK16) */ - 3 17 2 0 1 0 /* TX_CLK (CLK3) */ - 0 12 1 0 1 0 /* TxD0 */ - 0 13 1 0 1 0 /* TxD1 */ - 0 14 1 0 1 0 /* TxD2 */ - 0 15 1 0 1 0 /* TxD3 */ - 0 16 2 0 1 0 /* RxD0 */ - 0 17 2 0 1 0 /* RxD1 */ - 0 18 2 0 1 0 /* RxD2 */ - 0 19 2 0 1 0 /* RxD3 */ - 0 1a 2 0 1 0 /* RX_ER */ - 0 1b 1 0 1 0 /* TX_ER */ - 0 1c 2 0 1 0 /* RX_DV */ - 0 1d 2 0 1 0 /* COL */ - 0 1e 1 0 1 0 /* TX_EN */ - 0 1f 2 0 1 0>; /* CRS */ - }; - ucc3pio:ucc_pin@03 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 0 d 2 0 1 0 /* RX_CLK (CLK9) */ - 3 18 2 0 1 0 /* TX_CLK (CLK10) */ - 1 0 1 0 1 0 /* TxD0 */ - 1 1 1 0 1 0 /* TxD1 */ - 1 2 1 0 1 0 /* TxD2 */ - 1 3 1 0 1 0 /* TxD3 */ - 1 4 2 0 1 0 /* RxD0 */ - 1 5 2 0 1 0 /* RxD1 */ - 1 6 2 0 1 0 /* RxD2 */ - 1 7 2 0 1 0 /* RxD3 */ - 1 8 2 0 1 0 /* RX_ER */ - 1 9 1 0 1 0 /* TX_ER */ - 1 a 2 0 1 0 /* RX_DV */ - 1 b 2 0 1 0 /* COL */ - 1 c 1 0 1 0 /* TX_EN */ - 1 d 2 0 1 0>; /* CRS */ - }; - }; - }; - - qe@e0100000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "qe"; - model = "QE"; - ranges = <0 e0100000 00100000>; - reg = ; - brg-frequency = <0>; - bus-frequency = ; - - muram@10000 { - device_type = "muram"; - ranges = <0 00010000 00004000>; - - data-only@0 { - reg = <0 4000>; - }; - }; - - spi@4c0 { - device_type = "spi"; - compatible = "fsl_spi"; - reg = <4c0 40>; - interrupts = <2>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - spi@500 { - device_type = "spi"; - compatible = "fsl_spi"; - reg = <500 40>; - interrupts = <1>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - ucc@3000 { - device_type = "network"; - compatible = "ucc_geth"; - model = "UCC"; - device-id = <2>; - reg = <3000 200>; - interrupts = <21>; - interrupt-parent = <&qeic>; - mac-address = [ 00 04 9f ef 03 02 ]; - rx-clock = <20>; - tx-clock = <13>; - phy-handle = <&phy00>; - pio-handle = <&ucc2pio>; - }; - - ucc@2200 { - device_type = "network"; - compatible = "ucc_geth"; - model = "UCC"; - device-id = <3>; - reg = <2200 200>; - interrupts = <22>; - interrupt-parent = <&qeic>; - mac-address = [ 00 04 9f ef 03 01 ]; - rx-clock = <19>; - tx-clock = <1a>; - phy-handle = <&phy04>; - pio-handle = <&ucc3pio>; - }; - - mdio@3120 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3120 18>; - device_type = "mdio"; - compatible = "ucc_geth_phy"; - - phy00:ethernet-phy@00 { - interrupt-parent = <&pic>; - interrupts = <0>; - reg = <0>; - device_type = "ethernet-phy"; - interface = <3>; //ENET_100_MII - }; - phy04:ethernet-phy@04 { - interrupt-parent = <&pic>; - interrupts = <0>; - reg = <4>; - device_type = "ethernet-phy"; - interface = <3>; - }; - }; - - qeic:qeic@80 { - interrupt-controller; - device_type = "qeic"; - #address-cells = <0>; - #interrupt-cells = <1>; - reg = <80 80>; - built-in; - big-endian; - interrupts = <20 8 21 8>; //high:32 low:33 - interrupt-parent = <&pic>; - }; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/mpc8349emitx.dts b/trunk/arch/powerpc/boot/dts/mpc8349emitx.dts index db0d00303275..61b550bf1645 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -15,6 +15,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/trunk/arch/powerpc/boot/dts/mpc8349emitxgp.dts index f636528a3c72..b2e1a5ec3779 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -15,6 +15,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts index 07bcc5194d2b..e4b43c24bc0b 100644 --- a/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -16,6 +16,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts index 7f578eb57082..4fe45c021848 100644 --- a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -21,6 +21,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8540ads.dts b/trunk/arch/powerpc/boot/dts/mpc8540ads.dts index f261d647ac85..3c0917fa791c 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8540ads.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8541cds.dts b/trunk/arch/powerpc/boot/dts/mpc8541cds.dts index 5fdcb69554f2..2a1ae760ab3a 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8541cds.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8544ds.dts b/trunk/arch/powerpc/boot/dts/mpc8544ds.dts deleted file mode 100644 index 6b084605bb4b..000000000000 --- a/trunk/arch/powerpc/boot/dts/mpc8544ds.dts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * MPC8544 DS Device Tree Source - * - * Copyright 2007 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/ { - model = "MPC8544DS"; - compatible = "MPC8544DS", "MPC85xxDS"; - #address-cells = <1>; - #size-cells = <1>; - - cpus { - #cpus = <1>; - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8544@0 { - device_type = "cpu"; - reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <8000>; // L1, 32K - i-cache-size = <8000>; // L1, 32K - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - 32-bit; - }; - }; - - memory { - device_type = "memory"; - reg = <00000000 00000000>; // Filled by U-Boot - }; - - soc8544@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "soc"; - ranges = <0 e0000000 00100000>; - reg = ; // CCSRBAR 1M - bus-frequency = <0>; // Filled out by uboot. - - i2c@3000 { - device_type = "i2c"; - compatible = "fsl-i2c"; - reg = <3000 100>; - interrupts = <1b 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - mdio@24520 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "mdio"; - compatible = "gianfar"; - reg = <24520 20>; - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3a 1>; - reg = <0>; - device_type = "ethernet-phy"; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <3a 1>; - reg = <1>; - device_type = "ethernet-phy"; - }; - }; - - ethernet@24000 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <24000 1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = ; - interrupt-parent = <&mpic>; - phy-handle = <&phy0>; - }; - - ethernet@26000 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <26000 1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = ; - interrupt-parent = <&mpic>; - phy-handle = <&phy1>; - }; - - serial@4500 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4500 100>; - clock-frequency = <0>; - interrupts = <1a 2>; - interrupt-parent = <&mpic>; - }; - - serial@4600 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4600 100>; - clock-frequency = <0>; - interrupts = <1a 2>; - interrupt-parent = <&mpic>; - }; - - mpic: pic@40000 { - clock-frequency = <0>; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <40000 40000>; - built-in; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - big-endian; - }; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/mpc8548cds.dts b/trunk/arch/powerpc/boot/dts/mpc8548cds.dts index b2b2200d0425..7eb5d81d5eec 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8548cds.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8555cds.dts b/trunk/arch/powerpc/boot/dts/mpc8555cds.dts index 68a4795720dc..5f9c102a0ab4 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8555cds.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8560ads.dts b/trunk/arch/powerpc/boot/dts/mpc8560ads.dts index 1f2afe9291d2..10502638b0e9 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8560ads.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8568mds.dts b/trunk/arch/powerpc/boot/dts/mpc8568mds.dts index 7361b36749cb..bf49d8c997b9 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8568mds.dts @@ -21,6 +21,7 @@ #size-cells = <1>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/trunk/arch/powerpc/boot/dts/mpc8641_hpcn.dts index 260b264c869e..8a4995a85ba0 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -17,6 +17,7 @@ #size-cells = <1>; cpus { + #cpus = <2>; #address-cells = <1>; #size-cells = <0>; @@ -299,30 +300,6 @@ }; }; - - pci@9000 { - compatible = "86xx"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <9000 1000>; - bus-range = <0 ff>; - ranges = <02000000 0 a0000000 a0000000 0 20000000 - 01000000 0 00000000 e3000000 0 00100000>; - clock-frequency = <1fca055>; - interrupt-parent = <&mpic>; - interrupts = <19 2>; - interrupt-map-mask = ; - interrupt-map = < - /* IDSEL 0x0 */ - 0000 0 0 1 &mpic 44 1 - 0000 0 0 2 &mpic 45 1 - 0000 0 0 3 &mpic 46 1 - 0000 0 0 4 &mpic 47 1 - >; - }; - mpic: pic@40000 { clock-frequency = <0>; interrupt-controller; diff --git a/trunk/arch/powerpc/boot/dts/mpc866ads.dts b/trunk/arch/powerpc/boot/dts/mpc866ads.dts index c0d06fd12927..2b56b5df451a 100644 --- a/trunk/arch/powerpc/boot/dts/mpc866ads.dts +++ b/trunk/arch/powerpc/boot/dts/mpc866ads.dts @@ -18,6 +18,7 @@ linux,phandle = <100>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; linux,phandle = <200>; diff --git a/trunk/arch/powerpc/boot/dts/mpc885ads.dts b/trunk/arch/powerpc/boot/dts/mpc885ads.dts index 110bf6170603..faecd08c54da 100644 --- a/trunk/arch/powerpc/boot/dts/mpc885ads.dts +++ b/trunk/arch/powerpc/boot/dts/mpc885ads.dts @@ -18,6 +18,7 @@ linux,phandle = <100>; cpus { + #cpus = <1>; #address-cells = <1>; #size-cells = <0>; linux,phandle = <200>; diff --git a/trunk/arch/powerpc/boot/elf.h b/trunk/arch/powerpc/boot/elf.h index 1941bc50d4c5..d4828fcf1cb9 100644 --- a/trunk/arch/powerpc/boot/elf.h +++ b/trunk/arch/powerpc/boot/elf.h @@ -146,12 +146,4 @@ typedef struct elf64_phdr { #define ELFOSABI_NONE 0 #define ELFOSABI_LINUX 3 -struct elf_info { - unsigned long loadsize; - unsigned long memsize; - unsigned long elfoffset; -}; -int parse_elf64(void *hdr, struct elf_info *info); -int parse_elf32(void *hdr, struct elf_info *info); - #endif /* _PPC_BOOT_ELF_H_ */ diff --git a/trunk/arch/powerpc/boot/elf_util.c b/trunk/arch/powerpc/boot/elf_util.c deleted file mode 100644 index 7454aa4cc20c..000000000000 --- a/trunk/arch/powerpc/boot/elf_util.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include "elf.h" -#include "page.h" -#include "string.h" -#include "stdio.h" - -int parse_elf64(void *hdr, struct elf_info *info) -{ - Elf64_Ehdr *elf64 = hdr; - Elf64_Phdr *elf64ph; - unsigned int i; - - if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 && - elf64->e_ident[EI_MAG1] == ELFMAG1 && - elf64->e_ident[EI_MAG2] == ELFMAG2 && - elf64->e_ident[EI_MAG3] == ELFMAG3 && - elf64->e_ident[EI_CLASS] == ELFCLASS64 && - elf64->e_ident[EI_DATA] == ELFDATA2MSB && - elf64->e_type == ET_EXEC && - elf64->e_machine == EM_PPC64)) - return 0; - - elf64ph = (Elf64_Phdr *)((unsigned long)elf64 + - (unsigned long)elf64->e_phoff); - for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++) - if (elf64ph->p_type == PT_LOAD) - break; - if (i >= (unsigned int)elf64->e_phnum) - return 0; - - info->loadsize = (unsigned long)elf64ph->p_filesz; - info->memsize = (unsigned long)elf64ph->p_memsz; - info->elfoffset = (unsigned long)elf64ph->p_offset; - - return 1; -} - -int parse_elf32(void *hdr, struct elf_info *info) -{ - Elf32_Ehdr *elf32 = hdr; - Elf32_Phdr *elf32ph; - unsigned int i; - - if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 && - elf32->e_ident[EI_MAG1] == ELFMAG1 && - elf32->e_ident[EI_MAG2] == ELFMAG2 && - elf32->e_ident[EI_MAG3] == ELFMAG3 && - elf32->e_ident[EI_CLASS] == ELFCLASS32 && - elf32->e_ident[EI_DATA] == ELFDATA2MSB && - elf32->e_type == ET_EXEC && - elf32->e_machine == EM_PPC)) - return 0; - - elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff); - for (i = 0; i < elf32->e_phnum; i++, elf32ph++) - if (elf32ph->p_type == PT_LOAD) - break; - if (i >= elf32->e_phnum) - return 0; - - info->loadsize = elf32ph->p_filesz; - info->memsize = elf32ph->p_memsz; - info->elfoffset = elf32ph->p_offset; - return 1; -} diff --git a/trunk/arch/powerpc/boot/flatdevtree.c b/trunk/arch/powerpc/boot/flatdevtree.c index d00fbd92a458..c76c194715b2 100644 --- a/trunk/arch/powerpc/boot/flatdevtree.c +++ b/trunk/arch/powerpc/boot/flatdevtree.c @@ -29,20 +29,12 @@ #define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1)) -static char *ft_root_node(struct ft_cxt *cxt) -{ - return cxt->rgn[FT_STRUCT].start; -} - /* Routines for keeping node ptrs returned by ft_find_device current */ /* First entry not used b/c it would return 0 and be taken as NULL/error */ -static void *ft_get_phandle(struct ft_cxt *cxt, char *node) +static void *ft_node_add(struct ft_cxt *cxt, char *node) { unsigned int i; - if (!node) - return NULL; - for (i = 1; i < cxt->nodes_used; i++) /* already there? */ if (cxt->node_tbl[i] == node) return (void *)i; @@ -246,7 +238,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, if (rgn == FT_STRUCT) ft_node_update_before(cxt, p, -nextra); } - *pp -= nextra; + *p -= nextra; cxt->rgn[rgn].start -= nextra; cxt->rgn[rgn].size += nextra; return 1; @@ -261,14 +253,8 @@ static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, char *str, *next; enum ft_rgn_id r; - if (!cxt->isordered) { - unsigned long rgn_off = *pp - cxt->rgn[rgn].start; - - if (!ft_reorder(cxt, nextra)) - return 0; - - *pp = cxt->rgn[rgn].start + rgn_off; - } + if (!cxt->isordered && !ft_reorder(cxt, nextra)) + return 0; if (ft_shuffle(cxt, pp, rgn, nextra)) return 1; @@ -429,7 +415,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data, { int off, len; - off = map_string(cxt, name); + off = lookup_string(cxt, name); if (off == NO_STRING) return -1; @@ -604,7 +590,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) void ft_begin_tree(struct ft_cxt *cxt) { - cxt->p = ft_root_node(cxt); + cxt->p = cxt->rgn[FT_STRUCT].start; } void ft_end_tree(struct ft_cxt *cxt) @@ -650,21 +636,8 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path) /* require absolute path */ if (srch_path[0] != '/') return NULL; - node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path); - return ft_get_phandle(cxt, node); -} - -void *ft_find_device_rel(struct ft_cxt *cxt, const void *top, - const char *srch_path) -{ - char *node; - - node = ft_node_ph2node(cxt, top); - if (node == NULL) - return NULL; - - node = ft_find_descendent(cxt, node, srch_path); - return ft_get_phandle(cxt, node); + node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path); + return ft_node_add(cxt, node); } void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) @@ -728,18 +701,23 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) return NULL; } -void *__ft_get_parent(struct ft_cxt *cxt, void *node) +void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) { + void *node; int d; struct ft_atom atom; char *p; + node = ft_node_ph2node(cxt, phandle); + if (node == NULL) + return NULL; + for (d = 0; cxt->genealogy[d] != NULL; ++d) if (cxt->genealogy[d] == node) - return d > 0 ? cxt->genealogy[d - 1] : NULL; + return cxt->genealogy[d > 0 ? d - 1 : 0]; /* have to do it the hard way... */ - p = ft_root_node(cxt); + p = cxt->rgn[FT_STRUCT].start; d = 0; while ((p = ft_next(cxt, p, &atom)) != NULL) { switch (atom.tag) { @@ -748,7 +726,7 @@ void *__ft_get_parent(struct ft_cxt *cxt, void *node) if (node == atom.data) { /* found it */ cxt->genealogy[d + 1] = NULL; - return d > 0 ? cxt->genealogy[d - 1] : NULL; + return d > 0 ? cxt->genealogy[d - 1] : node; } ++d; break; @@ -760,131 +738,41 @@ void *__ft_get_parent(struct ft_cxt *cxt, void *node) return NULL; } -void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) +int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, + void *buf, const unsigned int buflen) { - void *node = ft_node_ph2node(cxt, phandle); - if (node == NULL) - return NULL; + struct ft_atom atom; + void *node; + char *p; + int depth; + unsigned int size; - node = __ft_get_parent(cxt, node); - return ft_get_phandle(cxt, node); -} + node = ft_node_ph2node(cxt, phandle); + if (node == NULL) + return -1; -static const void *__ft_get_prop(struct ft_cxt *cxt, void *node, - const char *propname, unsigned int *len) -{ - struct ft_atom atom; - int depth = 0; + depth = 0; + p = (char *)node; - while ((node = ft_next(cxt, node, &atom)) != NULL) { + while ((p = ft_next(cxt, p, &atom)) != NULL) { switch (atom.tag) { case OF_DT_BEGIN_NODE: ++depth; break; - case OF_DT_PROP: - if (depth != 1 || strcmp(atom.name, propname)) + if ((depth != 1) || strcmp(atom.name, propname)) break; - - if (len) - *len = atom.size; - - return atom.data; - + size = min(atom.size, buflen); + memcpy(buf, atom.data, size); + return atom.size; case OF_DT_END_NODE: if (--depth <= 0) - return NULL; + return -1; } } - - return NULL; -} - -int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, - void *buf, const unsigned int buflen) -{ - const void *data; - unsigned int size; - - void *node = ft_node_ph2node(cxt, phandle); - if (!node) - return -1; - - data = __ft_get_prop(cxt, node, propname, &size); - if (data) { - unsigned int clipped_size = min(size, buflen); - memcpy(buf, data, clipped_size); - return size; - } - return -1; } -void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev, - const char *propname, const char *propval, - unsigned int proplen) -{ - struct ft_atom atom; - char *p = ft_root_node(cxt); - char *next; - int past_prev = prev ? 0 : 1; - int depth = -1; - - while ((next = ft_next(cxt, p, &atom)) != NULL) { - const void *data; - unsigned int size; - - switch (atom.tag) { - case OF_DT_BEGIN_NODE: - depth++; - - if (prev == p) { - past_prev = 1; - break; - } - - if (!past_prev || depth < 1) - break; - - data = __ft_get_prop(cxt, p, propname, &size); - if (!data || size != proplen) - break; - if (memcmp(data, propval, size)) - break; - - return p; - - case OF_DT_END_NODE: - if (depth-- == 0) - return NULL; - - break; - } - - p = next; - } - - return NULL; -} - -void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev, - const char *propname, const char *propval, - int proplen) -{ - void *node = NULL; - - if (prev) { - node = ft_node_ph2node(cxt, prev); - - if (!node) - return NULL; - } - - node = __ft_find_node_by_prop_value(cxt, node, propname, - propval, proplen); - return ft_get_phandle(cxt, node); -} - int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, const void *buf, const unsigned int buflen) { @@ -961,26 +849,19 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname) return -1; } -void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) +void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path) { struct ft_atom atom; char *p, *next; int depth = 0; - if (parent) { - p = ft_node_ph2node(cxt, parent); - if (!p) - return NULL; - } else { - p = ft_root_node(cxt); - } - + p = cxt->rgn[FT_STRUCT].start; while ((next = ft_next(cxt, p, &atom)) != NULL) { switch (atom.tag) { case OF_DT_BEGIN_NODE: ++depth; - if (depth == 1 && strcmp(atom.name, name) == 0) - /* duplicate node name, return error */ + if (depth == 1 && strcmp(atom.name, path) == 0) + /* duplicate node path, return error */ return NULL; break; case OF_DT_END_NODE: @@ -989,7 +870,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) break; /* end of node, insert here */ cxt->p = p; - ft_begin_node(cxt, name); + ft_begin_node(cxt, path); ft_end_node(cxt); return p; } diff --git a/trunk/arch/powerpc/boot/flatdevtree.h b/trunk/arch/powerpc/boot/flatdevtree.h index cb26325d72db..b9cd9f61f351 100644 --- a/trunk/arch/powerpc/boot/flatdevtree.h +++ b/trunk/arch/powerpc/boot/flatdevtree.h @@ -97,17 +97,10 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); void ft_dump_blob(const void *bphp); void ft_merge_blob(struct ft_cxt *cxt, void *blob); void *ft_find_device(struct ft_cxt *cxt, const char *srch_path); -void *ft_find_device_rel(struct ft_cxt *cxt, const void *top, - const char *srch_path); void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path); int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, void *buf, const unsigned int buflen); int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, const void *buf, const unsigned int buflen); -void *ft_get_parent(struct ft_cxt *cxt, const void *phandle); -void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev, - const char *propname, const char *propval, - int proplen); -void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name); #endif /* FLATDEVTREE_H */ diff --git a/trunk/arch/powerpc/boot/flatdevtree_misc.c b/trunk/arch/powerpc/boot/flatdevtree_misc.c index 4341e6558c1a..04da38fa477f 100644 --- a/trunk/arch/powerpc/boot/flatdevtree_misc.c +++ b/trunk/arch/powerpc/boot/flatdevtree_misc.c @@ -16,43 +16,24 @@ static struct ft_cxt cxt; -static void *fdtm_finddevice(const char *name) +static void *ft_finddevice(const char *name) { return ft_find_device(&cxt, name); } -static int fdtm_getprop(const void *phandle, const char *propname, - void *buf, const int buflen) +static int ft_getprop(const void *phandle, const char *propname, void *buf, + const int buflen) { return ft_get_prop(&cxt, phandle, propname, buf, buflen); } -static int fdtm_setprop(const void *phandle, const char *propname, - const void *buf, const int buflen) +static int ft_setprop(const void *phandle, const char *propname, + const void *buf, const int buflen) { return ft_set_prop(&cxt, phandle, propname, buf, buflen); } -static void *fdtm_get_parent(const void *phandle) -{ - return ft_get_parent(&cxt, phandle); -} - -static void *fdtm_create_node(const void *phandle, const char *name) -{ - return ft_create_node(&cxt, phandle, name); -} - -static void *fdtm_find_node_by_prop_value(const void *prev, - const char *propname, - const char *propval, - int proplen) -{ - return ft_find_node_by_prop_value(&cxt, prev, propname, - propval, proplen); -} - -static unsigned long fdtm_finalize(void) +static unsigned long ft_finalize(void) { ft_end_tree(&cxt); return (unsigned long)cxt.bph; @@ -60,13 +41,10 @@ static unsigned long fdtm_finalize(void) int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device) { - dt_ops.finddevice = fdtm_finddevice; - dt_ops.getprop = fdtm_getprop; - dt_ops.setprop = fdtm_setprop; - dt_ops.get_parent = fdtm_get_parent; - dt_ops.create_node = fdtm_create_node; - dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value; - dt_ops.finalize = fdtm_finalize; + dt_ops.finddevice = ft_finddevice; + dt_ops.getprop = ft_getprop; + dt_ops.setprop = ft_setprop; + dt_ops.finalize = ft_finalize; return ft_open(&cxt, dt_blob, max_size, max_find_device, platform_ops.realloc); diff --git a/trunk/arch/powerpc/boot/gunzip_util.c b/trunk/arch/powerpc/boot/gunzip_util.c deleted file mode 100644 index df8ab07e9ff4..000000000000 --- a/trunk/arch/powerpc/boot/gunzip_util.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2007 David Gibson, IBM Corporation. - * Based on earlier work, Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include "string.h" -#include "stdio.h" -#include "ops.h" -#include "gunzip_util.h" - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -/** - * gunzip_start - prepare to decompress gzip data - * @state: decompressor state structure to be initialized - * @src: buffer containing gzip compressed or uncompressed data - * @srclen: size in bytes of the buffer at src - * - * If the buffer at @src contains a gzip header, this function - * initializes zlib to decompress the data, storing the decompression - * state in @state. The other functions in this file can then be used - * to decompress data from the gzipped stream. - * - * If the buffer at @src does not contain a gzip header, it is assumed - * to contain uncompressed data. The buffer information is recorded - * in @state and the other functions in this file will simply copy - * data from the uncompressed data stream at @src. - * - * Any errors, such as bad compressed data, cause an error to be - * printed an the platform's exit() function to be called. - */ -void gunzip_start(struct gunzip_state *state, void *src, int srclen) -{ - char *hdr = src; - int hdrlen = 0; - - memset(state, 0, sizeof(*state)); - - /* Check for gzip magic number */ - if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) { - /* gzip data, initialize zlib parameters */ - int r, flags; - - state->s.workspace = state->scratch; - if (zlib_inflate_workspacesize() > sizeof(state->scratch)) - fatal("insufficient scratch space for gunzip\n\r"); - - /* skip header */ - hdrlen = 10; - flags = hdr[3]; - if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0) - fatal("bad gzipped data\n\r"); - if ((flags & EXTRA_FIELD) != 0) - hdrlen = 12 + hdr[10] + (hdr[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (hdr[hdrlen++] != 0) - ; - if ((flags & COMMENT) != 0) - while (hdr[hdrlen++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - hdrlen += 2; - if (hdrlen >= srclen) - fatal("gunzip_start: ran out of data in header\n\r"); - - r = zlib_inflateInit2(&state->s, -MAX_WBITS); - if (r != Z_OK) - fatal("inflateInit2 returned %d\n\r", r); - } - - state->s.next_in = src + hdrlen; - state->s.avail_in = srclen - hdrlen; -} - -/** - * gunzip_partial - extract bytes from a gzip data stream - * @state: gzip state structure previously initialized by gunzip_start() - * @dst: buffer to store extracted data - * @dstlen: maximum number of bytes to extract - * - * This function extracts at most @dstlen bytes from the data stream - * previously associated with @state by gunzip_start(), decompressing - * if necessary. Exactly @dstlen bytes are extracted unless the data - * stream doesn't contain enough bytes, in which case the entire - * remainder of the stream is decompressed. - * - * Returns the actual number of bytes extracted. If any errors occur, - * such as a corrupted compressed stream, an error is printed an the - * platform's exit() function is called. - */ -int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen) -{ - int len; - - if (state->s.workspace) { - /* gunzipping */ - int r; - - state->s.next_out = dst; - state->s.avail_out = dstlen; - r = zlib_inflate(&state->s, Z_FULL_FLUSH); - if (r != Z_OK && r != Z_STREAM_END) - fatal("inflate returned %d msg: %s\n\r", r, state->s.msg); - len = state->s.next_out - (unsigned char *)dst; - } else { - /* uncompressed image */ - len = min(state->s.avail_in, (unsigned)dstlen); - memcpy(dst, state->s.next_in, len); - state->s.next_in += len; - state->s.avail_in -= len; - } - return len; -} - -/** - * gunzip_exactly - extract a fixed number of bytes from a gzip data stream - * @state: gzip state structure previously initialized by gunzip_start() - * @dst: buffer to store extracted data - * @dstlen: number of bytes to extract - * - * This function extracts exactly @dstlen bytes from the data stream - * previously associated with @state by gunzip_start(), decompressing - * if necessary. - * - * If there are less @dstlen bytes available in the data stream, or if - * any other errors occur, such as a corrupted compressed stream, an - * error is printed an the platform's exit() function is called. - */ -void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen) -{ - int len; - - len = gunzip_partial(state, dst, dstlen); - if (len < dstlen) - fatal("\n\rgunzip_exactly: ran out of data!" - " Wanted %d, got %d.\n\r", dstlen, len); -} - -/** - * gunzip_discard - discard bytes from a gzip data stream - * @state: gzip state structure previously initialized by gunzip_start() - * @len: number of bytes to discard - * - * This function extracts, then discards exactly @len bytes from the - * data stream previously associated with @state by gunzip_start(). - * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish() - * calls will extract the data following the discarded bytes in the - * data stream. - * - * If there are less @len bytes available in the data stream, or if - * any other errors occur, such as a corrupted compressed stream, an - * error is printed an the platform's exit() function is called. - */ -void gunzip_discard(struct gunzip_state *state, int len) -{ - static char discard_buf[128]; - - while (len > sizeof(discard_buf)) { - gunzip_exactly(state, discard_buf, sizeof(discard_buf)); - len -= sizeof(discard_buf); - } - - if (len > 0) - gunzip_exactly(state, discard_buf, len); -} - -/** - * gunzip_finish - extract all remaining bytes from a gzip data stream - * @state: gzip state structure previously initialized by gunzip_start() - * @dst: buffer to store extracted data - * @dstlen: maximum number of bytes to extract - * - * This function extracts all remaining data, or at most @dstlen - * bytes, from the stream previously associated with @state by - * gunzip_start(). zlib is then shut down, so it is an error to use - * any of the functions in this file on @state until it is - * re-initialized with another call to gunzip_start(). - * - * If any errors occur, such as a corrupted compressed stream, an - * error is printed an the platform's exit() function is called. - */ -int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen) -{ - int len; - - if (state->s.workspace) { - len = gunzip_partial(state, dst, dstlen); - zlib_inflateEnd(&state->s); - } else { - /* uncompressed image */ - len = min(state->s.avail_in, (unsigned)dstlen); - memcpy(dst, state->s.next_in, len); - } - - return len; -} diff --git a/trunk/arch/powerpc/boot/gunzip_util.h b/trunk/arch/powerpc/boot/gunzip_util.h deleted file mode 100644 index b3dfa6e87b3a..000000000000 --- a/trunk/arch/powerpc/boot/gunzip_util.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Decompression convenience functions - * - * Copyright 2007 David Gibson, IBM Corporation. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#ifndef _PPC_BOOT_GUNZIP_UTIL_H_ -#define _PPC_BOOT_GUNZIP_UTIL_H_ - -#include "zlib.h" - -/* - * These functions are designed to make life easy for decompressing - * kernel images, initrd images or any other gzip compressed image, - * particularly if its useful to decompress part of the image (e.g. to - * examine headers) before decompressing the remainder. - * - * To use: - * - declare a gunzip_state structure - * - use gunzip_start() to initialize the state, associating it - * with a stream of compressed data - * - use gunzip_partial(), gunzip_exactly() and gunzip_discard() - * in any combination to extract pieces of data from the stream - * - Finally use gunzip_finish() to extract the tail of the - * compressed stream and wind up zlib - */ - -/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */ -#define GUNZIP_SCRATCH_SIZE 46912 - -struct gunzip_state { - z_stream s; - char scratch[46912]; -}; - -void gunzip_start(struct gunzip_state *state, void *src, int srclen); -int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen); -void gunzip_exactly(struct gunzip_state *state, void *dst, int len); -void gunzip_discard(struct gunzip_state *state, int len); -int gunzip_finish(struct gunzip_state *state, void *dst, int len); - -#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */ diff --git a/trunk/arch/powerpc/boot/main.c b/trunk/arch/powerpc/boot/main.c index 56b56a8d4b23..6f6b50d238b6 100644 --- a/trunk/arch/powerpc/boot/main.c +++ b/trunk/arch/powerpc/boot/main.c @@ -14,10 +14,11 @@ #include "page.h" #include "string.h" #include "stdio.h" +#include "zlib.h" #include "ops.h" -#include "gunzip_util.h" #include "flatdevtree.h" -#include "reg.h" + +extern void flush_cache(void *, unsigned long); extern char _start[]; extern char __bss_start[]; @@ -29,173 +30,304 @@ extern char _initrd_end[]; extern char _dtb_start[]; extern char _dtb_end[]; -static struct gunzip_state gzstate; - struct addr_range { - void *addr; + unsigned long addr; unsigned long size; + unsigned long memsize; }; +static struct addr_range vmlinux; +static struct addr_range vmlinuz; +static struct addr_range initrd; -typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *); +static unsigned long elfoffset; +static int is_64bit; -#undef DEBUG - -static struct addr_range prep_kernel(void) -{ - char elfheader[256]; - void *vmlinuz_addr = _vmlinux_start; - unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start; - void *addr = 0; - struct elf_info ei; - int len; +/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */ +static char scratch[46912]; +static char elfheader[256]; - /* gunzip the ELF header of the kernel */ - gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size); - gunzip_exactly(&gzstate, elfheader, sizeof(elfheader)); +typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *); - if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei)) - fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r"); +#undef DEBUG - if (platform_ops.image_hdr) - platform_ops.image_hdr(elfheader); +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 - /* We need to alloc the memsize: gzip will expand the kernel - * text/data, then possible rubbish we don't care about. But - * the kernel bss must be claimed (it will be zero'd by the - * kernel itself) - */ - printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize); - - if (platform_ops.vmlinux_alloc) { - addr = platform_ops.vmlinux_alloc(ei.memsize); - } else { - if ((unsigned long)_start < ei.memsize) - fatal("Insufficient memory for kernel at address 0!" - " (_start=%p)\n\r", _start); +static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n\r"); + exit(); } - /* Finally, gunzip the kernel */ - printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr, - vmlinuz_addr, vmlinuz_addr+vmlinuz_size); - /* discard up to the actual load data */ - gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader)); - len = gunzip_finish(&gzstate, addr, ei.loadsize); - if (len != ei.loadsize) - fatal("ran out of data! only got 0x%x of 0x%lx bytes.\n\r", - len, ei.loadsize); - printf("done 0x%x bytes\n\r", len); + if (zlib_inflate_workspacesize() > sizeof(scratch)) { + printf("gunzip needs more mem\n"); + exit(); + } + memset(&s, 0, sizeof(s)); + s.workspace = scratch; + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FULL_FLUSH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); +} - flush_cache(addr, ei.loadsize); +static int is_elf64(void *hdr) +{ + Elf64_Ehdr *elf64 = hdr; + Elf64_Phdr *elf64ph; + unsigned int i; + + if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 && + elf64->e_ident[EI_MAG1] == ELFMAG1 && + elf64->e_ident[EI_MAG2] == ELFMAG2 && + elf64->e_ident[EI_MAG3] == ELFMAG3 && + elf64->e_ident[EI_CLASS] == ELFCLASS64 && + elf64->e_ident[EI_DATA] == ELFDATA2MSB && + elf64->e_type == ET_EXEC && + elf64->e_machine == EM_PPC64)) + return 0; + + elf64ph = (Elf64_Phdr *)((unsigned long)elf64 + + (unsigned long)elf64->e_phoff); + for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++) + if (elf64ph->p_type == PT_LOAD) + break; + if (i >= (unsigned int)elf64->e_phnum) + return 0; + + elfoffset = (unsigned long)elf64ph->p_offset; + vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset; + vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset; + + is_64bit = 1; + return 1; +} - return (struct addr_range){addr, ei.memsize}; +static int is_elf32(void *hdr) +{ + Elf32_Ehdr *elf32 = hdr; + Elf32_Phdr *elf32ph; + unsigned int i; + + if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 && + elf32->e_ident[EI_MAG1] == ELFMAG1 && + elf32->e_ident[EI_MAG2] == ELFMAG2 && + elf32->e_ident[EI_MAG3] == ELFMAG3 && + elf32->e_ident[EI_CLASS] == ELFCLASS32 && + elf32->e_ident[EI_DATA] == ELFDATA2MSB && + elf32->e_type == ET_EXEC && + elf32->e_machine == EM_PPC)) + return 0; + + elf32 = (Elf32_Ehdr *)elfheader; + elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff); + for (i = 0; i < elf32->e_phnum; i++, elf32ph++) + if (elf32ph->p_type == PT_LOAD) + break; + if (i >= elf32->e_phnum) + return 0; + + elfoffset = elf32ph->p_offset; + vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset; + vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset; + return 1; } -static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen, - unsigned long initrd_addr, - unsigned long initrd_size) +static void prep_kernel(unsigned long a1, unsigned long a2) { - /* If we have an image attached to us, it overrides anything - * supplied by the loader. */ - if (_initrd_end > _initrd_start) { - printf("Attached initrd image at 0x%p-0x%p\n\r", - _initrd_start, _initrd_end); - initrd_addr = (unsigned long)_initrd_start; - initrd_size = _initrd_end - _initrd_start; - } else if (initrd_size > 0) { - printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r", - initrd_addr, initrd_addr + initrd_size); + int len; + + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + + /* gunzip the ELF header of the kernel */ + if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + len = vmlinuz.size; + gunzip(elfheader, sizeof(elfheader), + (unsigned char *)vmlinuz.addr, &len); + } else + memcpy(elfheader, (const void *)vmlinuz.addr, + sizeof(elfheader)); + + if (!is_elf64(elfheader) && !is_elf32(elfheader)) { + printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r"); + exit(); } + if (platform_ops.image_hdr) + platform_ops.image_hdr(elfheader); - /* If there's no initrd at all, we're done */ - if (! initrd_size) - return (struct addr_range){0, 0}; + /* We need to alloc the memsize plus the file offset since gzip + * will expand the header (file offset), then the kernel, then + * possible rubbish we don't care about. But the kernel bss must + * be claimed (it will be zero'd by the kernel itself) + */ + printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize); + vmlinux.addr = (unsigned long)malloc(vmlinux.memsize); + if (vmlinux.addr == 0) { + printf("Can't allocate memory for kernel image !\n\r"); + exit(); + } /* - * If the initrd is too low it will be clobbered when the - * kernel relocates to its final location. In this case, - * allocate a safer place and move it. + * Now find the initrd + * + * First see if we have an image attached to us. If so + * allocate memory for it and copy it there. */ - if (initrd_addr < vmlinux.size) { - void *old_addr = (void *)initrd_addr; - + initrd.size = (unsigned long)(_initrd_end - _initrd_start); + initrd.memsize = initrd.size; + if (initrd.size > 0) { printf("Allocating 0x%lx bytes for initrd ...\n\r", - initrd_size); - initrd_addr = (unsigned long)malloc(initrd_size); - if (! initrd_addr) - fatal("Can't allocate memory for initial " - "ramdisk !\n\r"); - printf("Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r", - initrd_addr, old_addr, initrd_size); - memmove((void *)initrd_addr, old_addr, initrd_size); + initrd.size); + initrd.addr = (unsigned long)malloc((u32)initrd.size); + if (initrd.addr == 0) { + printf("Can't allocate memory for initial " + "ramdisk !\n\r"); + exit(); + } + printf("initial ramdisk moving 0x%lx <- 0x%lx " + "(0x%lx bytes)\n\r", initrd.addr, + (unsigned long)_initrd_start, initrd.size); + memmove((void *)initrd.addr, (void *)_initrd_start, + initrd.size); + printf("initrd head: 0x%lx\n\r", + *((unsigned long *)initrd.addr)); + } else if (a2 != 0) { + /* Otherwise, see if yaboot or another loader gave us an initrd */ + initrd.addr = a1; + initrd.memsize = initrd.size = a2; + printf("Using loader supplied initrd at 0x%lx (0x%lx bytes)\n\r", + initrd.addr, initrd.size); } - printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd_addr)); + /* Eventually gunzip the kernel */ + if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", + vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); + len = vmlinuz.size; + gunzip((void *)vmlinux.addr, vmlinux.memsize, + (unsigned char *)vmlinuz.addr, &len); + printf("done 0x%lx bytes\n\r", len); + } else { + memmove((void *)vmlinux.addr,(void *)vmlinuz.addr, + vmlinuz.size); + } - /* Tell the kernel initrd address via device tree */ - setprop_val(chosen, "linux,initrd-start", (u32)(initrd_addr)); - setprop_val(chosen, "linux,initrd-end", (u32)(initrd_addr+initrd_size)); + /* Skip over the ELF header */ +#ifdef DEBUG + printf("... skipping 0x%lx bytes of ELF header\n\r", + elfoffset); +#endif + vmlinux.addr += elfoffset; - return (struct addr_range){(void *)initrd_addr, initrd_size}; + flush_cache((void *)vmlinux.addr, vmlinux.size); } /* A buffer that may be edited by tools operating on a zImage binary so as to * edit the command line passed to vmlinux (by setting /chosen/bootargs). * The buffer is put in it's own section so that tools may locate it easier. */ -static char cmdline[COMMAND_LINE_SIZE] +static char builtin_cmdline[COMMAND_LINE_SIZE] __attribute__((__section__("__builtin_cmdline"))); -static void prep_cmdline(void *chosen) +static void get_cmdline(char *buf, int size) { - if (cmdline[0] == '\0') - getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1); + void *devp; + int len = strlen(builtin_cmdline); + + buf[0] = '\0'; + + if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */ + len = min(len, size-1); + strncpy(buf, builtin_cmdline, len); + buf[len] = '\0'; + } + else if ((devp = finddevice("/chosen"))) + getprop(devp, "bootargs", buf, size); +} - printf("\n\rLinux/PowerPC load: %s", cmdline); - /* If possible, edit the command line */ - if (console_ops.edit_cmdline) - console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE); - printf("\n\r"); +static void set_cmdline(char *buf) +{ + void *devp; - /* Put the command line back into the devtree for the kernel */ - setprop_str(chosen, "bootargs", cmdline); + if ((devp = finddevice("/chosen"))) + setprop(devp, "bootargs", buf, strlen(buf) + 1); } struct platform_ops platform_ops; struct dt_ops dt_ops; struct console_ops console_ops; -struct loader_info loader_info; -void start(void) +void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) { - struct addr_range vmlinux, initrd; kernel_entry_t kentry; + char cmdline[COMMAND_LINE_SIZE]; unsigned long ft_addr = 0; - void *chosen; - /* Do this first, because malloc() could clobber the loader's - * command line. Only use the loader command line if a - * built-in command line wasn't set by an external tool */ - if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0')) - memmove(cmdline, loader_info.cmdline, - min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1)); + memset(__bss_start, 0, _end - __bss_start); + memset(&platform_ops, 0, sizeof(platform_ops)); + memset(&dt_ops, 0, sizeof(dt_ops)); + memset(&console_ops, 0, sizeof(console_ops)); + if (platform_init(promptr, _dtb_start, _dtb_end)) + exit(); if (console_ops.open && (console_ops.open() < 0)) exit(); if (platform_ops.fixups) platform_ops.fixups(); printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", - _start, get_sp()); + _start, sp); - /* Ensure that the device tree has a /chosen node */ - chosen = finddevice("/chosen"); - if (!chosen) - chosen = create_node(NULL, "chosen"); + prep_kernel(a1, a2); - vmlinux = prep_kernel(); - initrd = prep_initrd(vmlinux, chosen, - loader_info.initrd_addr, loader_info.initrd_size); - prep_cmdline(chosen); + /* If cmdline came from zimage wrapper or if we can edit the one + * in the dt, print it out and edit it, if possible. + */ + if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) { + get_cmdline(cmdline, COMMAND_LINE_SIZE); + printf("\n\rLinux/PowerPC load: %s", cmdline); + if (console_ops.edit_cmdline) + console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE); + printf("\n\r"); + set_cmdline(cmdline); + } printf("Finalizing device tree..."); if (dt_ops.finalize) @@ -203,7 +335,7 @@ void start(void) if (ft_addr) printf(" flat tree at 0x%lx\n\r", ft_addr); else - printf(" using OF tree (promptr=%p)\n\r", loader_info.promptr); + printf(" using OF tree (promptr=%p)\n\r", promptr); if (console_ops.close) console_ops.close(); @@ -212,9 +344,10 @@ void start(void) if (ft_addr) kentry(ft_addr, 0, NULL); else - kentry((unsigned long)initrd.addr, initrd.size, - loader_info.promptr); + /* XXX initrd addr/size should be passed in properties */ + kentry(initrd.addr, initrd.size, promptr); - /* console closed so printf in fatal below may not work */ - fatal("Error: Linux kernel returned to zImage boot wrapper!\n\r"); + /* console closed so printf below may not work */ + printf("Error: Linux kernel returned to zImage boot wrapper!\n\r"); + exit(); } diff --git a/trunk/arch/powerpc/boot/ns16550.c b/trunk/arch/powerpc/boot/ns16550.c index f8f1b2f31412..1ffe72e35cdc 100644 --- a/trunk/arch/powerpc/boot/ns16550.c +++ b/trunk/arch/powerpc/boot/ns16550.c @@ -55,15 +55,10 @@ static u8 ns16550_tstc(void) int ns16550_console_init(void *devp, struct serial_console_data *scdp) { int n; - unsigned long reg_phys; n = getprop(devp, "virtual-reg", ®_base, sizeof(reg_base)); - if (n != sizeof(reg_base)) { - if (!dt_xlate_reg(devp, 0, ®_phys, NULL)) - return -1; - - reg_base = (void *)reg_phys; - } + if (n != sizeof(reg_base)) + return -1; n = getprop(devp, "reg-shift", ®_shift, sizeof(reg_shift)); if (n != sizeof(reg_shift)) diff --git a/trunk/arch/powerpc/boot/of.c b/trunk/arch/powerpc/boot/of.c index d16ee3e3f868..0182f384f3e6 100644 --- a/trunk/arch/powerpc/boot/of.c +++ b/trunk/arch/powerpc/boot/of.c @@ -173,7 +173,7 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align) return (void *) virt; } -static void *of_try_claim(unsigned long size) +static void *of_try_claim(u32 size) { unsigned long addr = 0; @@ -208,16 +208,6 @@ static void of_image_hdr(const void *hdr) } } -static void *of_vmlinux_alloc(unsigned long size) -{ - void *p = malloc(size); - - if (!p) - fatal("Can't allocate memory for kernel image!\n\r"); - - return p; -} - static void of_exit(void) { call_prom("exit", 0, 0); @@ -266,12 +256,11 @@ static void of_console_write(char *buf, int len) call_prom("write", 3, 1, of_stdout_handle, buf, len); } -void platform_init(unsigned long a1, unsigned long a2, void *promptr) +int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end) { platform_ops.image_hdr = of_image_hdr; platform_ops.malloc = of_try_claim; platform_ops.exit = of_exit; - platform_ops.vmlinux_alloc = of_vmlinux_alloc; dt_ops.finddevice = of_finddevice; dt_ops.getprop = of_getprop; @@ -281,9 +270,5 @@ void platform_init(unsigned long a1, unsigned long a2, void *promptr) console_ops.write = of_console_write; prom = (int (*)(void *))promptr; - loader_info.promptr = promptr; - if (a1 && a2 && a2 != 0xdeadbeef) { - loader_info.initrd_addr = a1; - loader_info.initrd_size = a2; - } + return 0; } diff --git a/trunk/arch/powerpc/boot/ops.h b/trunk/arch/powerpc/boot/ops.h index 73bd47a3a079..8abb6516bb7c 100644 --- a/trunk/arch/powerpc/boot/ops.h +++ b/trunk/arch/powerpc/boot/ops.h @@ -11,9 +11,7 @@ #ifndef _PPC_BOOT_OPS_H_ #define _PPC_BOOT_OPS_H_ -#include #include "types.h" -#include "string.h" #define COMMAND_LINE_SIZE 512 #define MAX_PATH_LEN 256 @@ -23,11 +21,10 @@ struct platform_ops { void (*fixups)(void); void (*image_hdr)(const void *); - void * (*malloc)(unsigned long size); + void * (*malloc)(u32 size); void (*free)(void *ptr); void * (*realloc)(void *ptr, unsigned long size); void (*exit)(void); - void * (*vmlinux_alloc)(unsigned long size); }; extern struct platform_ops platform_ops; @@ -38,12 +35,6 @@ struct dt_ops { const int buflen); int (*setprop)(const void *phandle, const char *name, const void *buf, const int buflen); - void *(*get_parent)(const void *phandle); - /* The node must not already exist. */ - void *(*create_node)(const void *parent, const char *name); - void *(*find_node_by_prop_value)(const void *prev, - const char *propname, - const char *propval, int proplen); unsigned long (*finalize)(void); }; extern struct dt_ops dt_ops; @@ -67,23 +58,13 @@ struct serial_console_data { void (*close)(void); }; -struct loader_info { - void *promptr; - unsigned long initrd_addr, initrd_size; - char *cmdline; - int cmdline_len; -}; -extern struct loader_info loader_info; - -void start(void); +int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end); int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device); int serial_console_init(void); int ns16550_console_init(void *devp, struct serial_console_data *scdp); -void *simple_alloc_init(char *base, unsigned long heap_size, - unsigned long granularity, unsigned long max_allocs); -extern void flush_cache(void *, unsigned long); -int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size); -int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr); +void *simple_alloc_init(char *base, u32 heap_size, u32 granularity, + u32 max_allocs); + static inline void *finddevice(const char *name) { @@ -95,76 +76,12 @@ static inline int getprop(void *devp, const char *name, void *buf, int buflen) return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1; } -static inline int setprop(void *devp, const char *name, - const void *buf, int buflen) +static inline int setprop(void *devp, const char *name, void *buf, int buflen) { return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1; } -#define setprop_val(devp, name, val) \ - do { \ - typeof(val) x = (val); \ - setprop((devp), (name), &x, sizeof(x)); \ - } while (0) - -static inline int setprop_str(void *devp, const char *name, const char *buf) -{ - if (dt_ops.setprop) - return dt_ops.setprop(devp, name, buf, strlen(buf) + 1); - - return -1; -} - -static inline void *get_parent(const char *devp) -{ - return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL; -} - -static inline void *create_node(const void *parent, const char *name) -{ - return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL; -} - -static inline void *find_node_by_prop_value(const void *prev, - const char *propname, - const char *propval, int proplen) -{ - if (dt_ops.find_node_by_prop_value) - return dt_ops.find_node_by_prop_value(prev, propname, - propval, proplen); - - return NULL; -} - -static inline void *find_node_by_prop_value_str(const void *prev, - const char *propname, - const char *propval) -{ - return find_node_by_prop_value(prev, propname, propval, - strlen(propval) + 1); -} - -static inline void *find_node_by_devtype(const void *prev, - const char *type) -{ - return find_node_by_prop_value_str(prev, "device_type", type); -} - -void dt_fixup_memory(u64 start, u64 size); -void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq); -void dt_fixup_clock(const char *path, u32 freq); -void __dt_fixup_mac_addresses(u32 startindex, ...); -#define dt_fixup_mac_addresses(...) \ - __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL) - - -static inline void *find_node_by_linuxphandle(const u32 linuxphandle) -{ - return find_node_by_prop_value(NULL, "linux,phandle", - (char *)&linuxphandle, sizeof(u32)); -} - -static inline void *malloc(unsigned long size) +static inline void *malloc(u32 size) { return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL; } @@ -181,11 +98,5 @@ static inline void exit(void) platform_ops.exit(); for(;;); } -#define fatal(args...) { printf(args); exit(); } - - -#define BSS_STACK(size) \ - static char _bss_stack[size]; \ - void *_platform_stack_top = _bss_stack + sizeof(_bss_stack); #endif /* _PPC_BOOT_OPS_H_ */ diff --git a/trunk/arch/powerpc/boot/ppcboot.h b/trunk/arch/powerpc/boot/ppcboot.h deleted file mode 100644 index 5290ff2c2b2b..000000000000 --- a/trunk/arch/powerpc/boot/ppcboot.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This interface is used for compatibility with old U-boots *ONLY*. - * Please do not imitate or extend this. - */ - -/* - * (C) Copyright 2000, 2001 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __PPCBOOT_H__ -#define __PPCBOOT_H__ - -/* - * Board information passed to kernel from PPCBoot - * - * include/asm-ppc/ppcboot.h - */ - -#include "types.h" - -typedef struct bd_info { - unsigned long bi_memstart; /* start of DRAM memory */ - unsigned long bi_memsize; /* size of DRAM memory in bytes */ - unsigned long bi_flashstart; /* start of FLASH memory */ - unsigned long bi_flashsize; /* size of FLASH memory */ - unsigned long bi_flashoffset; /* reserved area for startup monitor */ - unsigned long bi_sramstart; /* start of SRAM memory */ - unsigned long bi_sramsize; /* size of SRAM memory */ -#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\ - defined(TARGET_83xx) - unsigned long bi_immr_base; /* base of IMMR register */ -#endif -#if defined(TARGET_PPC_MPC52xx) - unsigned long bi_mbar_base; /* base of internal registers */ -#endif - unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ - unsigned long bi_ip_addr; /* IP Address */ - unsigned char bi_enetaddr[6]; /* Ethernet address */ - unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ - unsigned long bi_intfreq; /* Internal Freq, in MHz */ - unsigned long bi_busfreq; /* Bus Freq, in MHz */ -#if defined(TARGET_CPM2) - unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */ - unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */ - unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */ - unsigned long bi_vco; /* VCO Out from PLL, in MHz */ -#endif -#if defined(TARGET_PPC_MPC52xx) - unsigned long bi_ipbfreq; /* IPB Bus Freq, in MHz */ - unsigned long bi_pcifreq; /* PCI Bus Freq, in MHz */ -#endif - unsigned long bi_baudrate; /* Console Baudrate */ -#if defined(TARGET_4xx) - unsigned char bi_s_version[4]; /* Version of this structure */ - unsigned char bi_r_version[32]; /* Version of the ROM (IBM) */ - unsigned int bi_procfreq; /* CPU (Internal) Freq, in Hz */ - unsigned int bi_plb_busfreq; /* PLB Bus speed, in Hz */ - unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ - unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ -#endif -#if defined(TARGET_HYMOD) - hymod_conf_t bi_hymod_conf; /* hymod configuration information */ -#endif -#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \ - defined(TARGET_85xx) || defined(TARGET_83xx) - /* second onboard ethernet port */ - unsigned char bi_enet1addr[6]; -#define HAVE_ENET1ADDR -#endif -#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx) - /* third onboard ethernet ports */ - unsigned char bi_enet2addr[6]; -#define HAVE_ENET2ADDR -#endif -#if defined(TARGET_440GX) - /* fourth onboard ethernet ports */ - unsigned char bi_enet3addr[6]; -#define HAVE_ENET3ADDR -#endif -#if defined(TARGET_4xx) - unsigned int bi_opbfreq; /* OB clock in Hz */ - int bi_iic_fast[2]; /* Use fast i2c mode */ -#endif -#if defined(TARGET_440GX) - int bi_phynum[4]; /* phy mapping */ - int bi_phymode[4]; /* phy mode */ -#endif -} bd_t; - -#define bi_tbfreq bi_intfreq - -#endif /* __PPCBOOT_H__ */ diff --git a/trunk/arch/powerpc/boot/reg.h b/trunk/arch/powerpc/boot/reg.h deleted file mode 100644 index d3cd9ee98afb..000000000000 --- a/trunk/arch/powerpc/boot/reg.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _PPC_BOOT_REG_H -#define _PPC_BOOT_REG_H -/* - * Copyright 2007 Davud Gibson, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -static inline u32 mfpvr(void) -{ - u32 pvr; - asm volatile ("mfpvr %0" : "=r"(pvr)); - return pvr; -} - -register void *__stack_pointer asm("r1"); -#define get_sp() (__stack_pointer) - -#endif /* _PPC_BOOT_REG_H */ diff --git a/trunk/arch/powerpc/boot/simple_alloc.c b/trunk/arch/powerpc/boot/simple_alloc.c index 65ec135d0157..cfe3a7505ba0 100644 --- a/trunk/arch/powerpc/boot/simple_alloc.c +++ b/trunk/arch/powerpc/boot/simple_alloc.c @@ -19,24 +19,24 @@ #define ENTRY_IN_USE 0x02 static struct alloc_info { - unsigned long flags; - unsigned long base; - unsigned long size; + u32 flags; + u32 base; + u32 size; } *alloc_tbl; -static unsigned long tbl_entries; -static unsigned long alloc_min; -static unsigned long next_base; -static unsigned long space_left; +static u32 tbl_entries; +static u32 alloc_min; +static u32 next_base; +static u32 space_left; /* * First time an entry is used, its base and size are set. * An entry can be freed and re-malloc'd but its base & size don't change. * Should be smart enough for needs of bootwrapper. */ -static void *simple_malloc(unsigned long size) +static void *simple_malloc(u32 size) { - unsigned long i; + u32 i; struct alloc_info *p = alloc_tbl; if (size == 0) @@ -67,14 +67,13 @@ static void *simple_malloc(unsigned long size) static struct alloc_info *simple_find_entry(void *ptr) { - unsigned long i; + u32 i; struct alloc_info *p = alloc_tbl; for (i=0; iflags & ENTRY_BEEN_USED)) break; - if ((p->flags & ENTRY_IN_USE) && - (p->base == (unsigned long)ptr)) + if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr)) return p; } return NULL; @@ -123,10 +122,10 @@ static void *simple_realloc(void *ptr, unsigned long size) * Returns addr of first byte after heap so caller can see if it took * too much space. If so, change args & try again. */ -void *simple_alloc_init(char *base, unsigned long heap_size, - unsigned long granularity, unsigned long max_allocs) +void *simple_alloc_init(char *base, u32 heap_size, u32 granularity, + u32 max_allocs) { - unsigned long heap_base, tbl_size; + u32 heap_base, tbl_size; heap_size = _ALIGN_UP(heap_size, granularity); alloc_min = granularity; @@ -137,7 +136,7 @@ void *simple_alloc_init(char *base, unsigned long heap_size, alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8); memset(alloc_tbl, 0, tbl_size); - heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min); + heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min); next_base = heap_base; space_left = heap_size; diff --git a/trunk/arch/powerpc/boot/stdio.h b/trunk/arch/powerpc/boot/stdio.h index adffc58412d4..73b8a91bfb34 100644 --- a/trunk/arch/powerpc/boot/stdio.h +++ b/trunk/arch/powerpc/boot/stdio.h @@ -7,12 +7,11 @@ #define EINVAL 22 /* Invalid argument */ #define ENOSPC 28 /* No space left on device */ -extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +extern int printf(const char *fmt, ...); #define fprintf(fmt, args...) printf(args) -extern int sprintf(char *buf, const char *fmt, ...) - __attribute__((format(printf, 2, 3))); +extern int sprintf(char *buf, const char *fmt, ...); extern int vsprintf(char *buf, const char *fmt, va_list args); diff --git a/trunk/arch/powerpc/boot/wrapper b/trunk/arch/powerpc/boot/wrapper index 5cedd901201f..024e4d425c59 100755 --- a/trunk/arch/powerpc/boot/wrapper +++ b/trunk/arch/powerpc/boot/wrapper @@ -29,7 +29,6 @@ initrd= dtb= dts= cacheit= -gzip=.gz # cross-compilation prefix CROSS= @@ -43,7 +42,7 @@ tmpdir=. usage() { echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2 echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2 - echo ' [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2 + echo ' [-D datadir] [-W workingdir] [vmlinux]' >&2 exit 1 } @@ -92,9 +91,6 @@ while [ "$#" -gt 0 ]; do [ "$#" -gt 0 ] || usage tmpdir="$1" ;; - --no-gzip) - gzip= - ;; -?) usage ;; @@ -141,44 +137,31 @@ miboot|uboot) ksection=image isection=initrd ;; -cuboot*) - gzip= - ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" -if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then +if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then ${CROSS}objcopy $objflags "$kernel" "$vmz.$$" - - if [ -n "$gzip" ]; then - gzip -f -9 "$vmz.$$" - fi - + gzip -f -9 "$vmz.$$" if [ -n "$cacheit" ]; then - mv -f "$vmz.$$$gzip" "$vmz$gzip" + mv -f "$vmz.$$.gz" "$vmz.gz" else vmz="$vmz.$$" fi fi -vmz="$vmz$gzip" - case "$platform" in -uboot|cuboot*) +uboot) + rm -f "$ofile" version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \ cut -d' ' -f3` if [ -n "$version" ]; then version="-n Linux-$version" fi -esac - -case "$platform" in -uboot) - rm -f "$ofile" mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \ - $version -d "$vmz" "$ofile" + $version -d "$vmz.gz" "$ofile" if [ -z "$cacheit" ]; then - rm -f "$vmz" + rm -f $vmz.gz fi exit 0 ;; @@ -190,9 +173,9 @@ addsec() { --set-section-flags=$3=contents,alloc,load,readonly,data } -addsec $tmp "$vmz" $ksection $object/empty.o +addsec $tmp "$vmz.gz" $ksection $object/empty.o if [ -z "$cacheit" ]; then - rm -f "$vmz" + rm -f "$vmz.gz" fi if [ -n "$initrd" ]; then @@ -208,7 +191,7 @@ fi if [ "$platform" != "miboot" ]; then ${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \ - $platformo $tmp $object/wrapper.a + $object/crt0.o $platformo $tmp $object/wrapper.a rm $tmp fi @@ -218,19 +201,7 @@ pseries|chrp) $object/addnote "$ofile" ;; pmaccoff) - entry=`objdump -f "$ofile" | grep '^start address ' | \ - cut -d' ' -f3` - ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" + ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile" $object/hack-coff "$ofile" ;; -cuboot*) - base=`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1` - entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | \ - cut -d' ' -f3` - mv "$ofile" "$ofile".elf - ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin - gzip -f -9 "$ofile".bin - mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \ - $version -d "$ofile".bin.gz "$ofile" - ;; esac diff --git a/trunk/arch/powerpc/boot/zImage.coff.lds.S b/trunk/arch/powerpc/boot/zImage.coff.lds.S index fe87a90ce7f1..a360905e5428 100644 --- a/trunk/arch/powerpc/boot/zImage.coff.lds.S +++ b/trunk/arch/powerpc/boot/zImage.coff.lds.S @@ -1,6 +1,5 @@ OUTPUT_ARCH(powerpc:common) -ENTRY(_zimage_start_opd) -EXTERN(_zimage_start_opd) +ENTRY(_start) SECTIONS { . = (5*1024*1024); diff --git a/trunk/arch/powerpc/boot/zImage.lds.S b/trunk/arch/powerpc/boot/zImage.lds.S index f6e380fdb388..4be3c6414b04 100644 --- a/trunk/arch/powerpc/boot/zImage.lds.S +++ b/trunk/arch/powerpc/boot/zImage.lds.S @@ -1,6 +1,5 @@ OUTPUT_ARCH(powerpc:common) ENTRY(_zimage_start) -EXTERN(_zimage_start) SECTIONS { . = (4*1024*1024); diff --git a/trunk/arch/powerpc/configs/cell_defconfig b/trunk/arch/powerpc/configs/cell_defconfig index 6061e5f7696e..cf7e316ad4f6 100644 --- a/trunk/arch/powerpc/configs/cell_defconfig +++ b/trunk/arch/powerpc/configs/cell_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc6 -# Mon Apr 23 20:46:48 2007 +# Linux kernel version: 2.6.21-rc3 +# Fri Mar 9 23:34:53 2007 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -139,31 +139,11 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_PPC_PMAC is not set # CONFIG_PPC_MAPLE is not set # CONFIG_PPC_PASEMI is not set -CONFIG_PPC_CELLEB=y -CONFIG_PPC_PS3=y - -# -# PS3 Platform Options -# -# CONFIG_PS3_ADVANCED is not set -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_USE_LPAR_ADDR=y -CONFIG_PS3_VUART=y -CONFIG_PS3_PS3AV=y -CONFIG_PS3_SYS_MANAGER=y CONFIG_PPC_CELL=y CONFIG_PPC_CELL_NATIVE=y CONFIG_PPC_IBM_CELL_BLADE=y - -# -# Cell Broadband Engine options -# -CONFIG_SPU_FS=m -CONFIG_SPU_BASE=y -CONFIG_CBE_RAS=y -CONFIG_CBE_THERM=m -CONFIG_CBE_CPUFREQ=m +CONFIG_PPC_PS3=y +CONFIG_PPC_CELLEB=y CONFIG_PPC_NATIVE=y CONFIG_UDBG_RTAS_CONSOLE=y CONFIG_PPC_UDBG_BEAT=y @@ -194,6 +174,26 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_WANT_EARLY_SERIAL is not set CONFIG_MPIC=y +# +# Cell Broadband Engine options +# +CONFIG_SPU_FS=m +CONFIG_SPU_BASE=y +CONFIG_CBE_RAS=y +CONFIG_CBE_THERM=m +CONFIG_CBE_CPUFREQ=m + +# +# PS3 Platform Options +# +# CONFIG_PS3_ADVANCED is not set +CONFIG_PS3_HTAB_SIZE=20 +# CONFIG_PS3_DYNAMIC_DMA is not set +CONFIG_PS3_USE_LPAR_ADDR=y +CONFIG_PS3_VUART=y +CONFIG_PS3_PS3AV=y +CONFIG_PS3_SYS_MANAGER=y + # # Kernel options # @@ -534,6 +534,7 @@ CONFIG_BLK_DEV_GENERIC=y # CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_AEC62XX=y # CONFIG_BLK_DEV_ALI15X3 is not set @@ -560,10 +561,11 @@ CONFIG_BLK_DEV_SIIMAGE=y # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_TC86C001 is not set -CONFIG_BLK_DEV_CELLEB=y +CONFIG_BLK_DEV_IDE_CELLEB=y # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y # CONFIG_BLK_DEV_HD is not set # @@ -935,7 +937,7 @@ CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set CONFIG_HVC_DRIVER=y CONFIG_HVC_RTAS=y -CONFIG_HVC_BEAT=y +# CONFIG_HVC_BEAT is not set # # IPMI @@ -1480,8 +1482,6 @@ CONFIG_NLS_ISO8859_15=m # Distributed Lock Manager # # CONFIG_DLM is not set -# CONFIG_UCC_SLOW is not set -# CONFIG_UCC_FAST is not set # # Library routines @@ -1540,7 +1540,6 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_FAULT_INJECTION is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_PAGEALLOC is not set CONFIG_DEBUGGER=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y diff --git a/trunk/arch/powerpc/configs/g5_defconfig b/trunk/arch/powerpc/configs/g5_defconfig index 3ccf19d8da38..7724847f702a 100644 --- a/trunk/arch/powerpc/configs/g5_defconfig +++ b/trunk/arch/powerpc/configs/g5_defconfig @@ -143,7 +143,7 @@ CONFIG_PPC_NATIVE=y CONFIG_U3_DART=y # CONFIG_PPC_RTAS is not set # CONFIG_MMIO_NVRAM is not set -CONFIG_MPIC_U3_HT_IRQS=y +CONFIG_MPIC_BROKEN_U3=y # CONFIG_PPC_MPC106 is not set CONFIG_PPC_970_NAP=y # CONFIG_PPC_INDIRECT_IO is not set diff --git a/trunk/arch/powerpc/configs/maple_defconfig b/trunk/arch/powerpc/configs/maple_defconfig index 15366f0e489f..de97f2f0ae96 100644 --- a/trunk/arch/powerpc/configs/maple_defconfig +++ b/trunk/arch/powerpc/configs/maple_defconfig @@ -146,7 +146,7 @@ CONFIG_PPC_RTAS=y CONFIG_RTAS_PROC=y # CONFIG_RTAS_FLASH is not set # CONFIG_MMIO_NVRAM is not set -CONFIG_MPIC_U3_HT_IRQS=y +CONFIG_MPIC_BROKEN_U3=y # CONFIG_PPC_MPC106 is not set CONFIG_PPC_970_NAP=y # CONFIG_PPC_INDIRECT_IO is not set diff --git a/trunk/arch/powerpc/configs/mpc8544_ds_defconfig b/trunk/arch/powerpc/configs/mpc8544_ds_defconfig deleted file mode 100644 index b563513cc96c..000000000000 --- a/trunk/arch/powerpc/configs/mpc8544_ds_defconfig +++ /dev/null @@ -1,1077 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc3 -# Mon Mar 19 17:18:49 2007 -# -# CONFIG_PPC64 is not set -CONFIG_PPC32=y -CONFIG_PPC_MERGE=y -CONFIG_MMU=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_IRQ_PER_CPU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_ARCH_HAS_ILOG2_U32=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_FIND_NEXT_BIT=y -CONFIG_PPC=y -CONFIG_EARLY_PRINTK=y -CONFIG_GENERIC_NVRAM=y -CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_PPC_OF=y -CONFIG_PPC_UDBG_16550=y -# CONFIG_GENERIC_TBSYNC is not set -CONFIG_AUDIT_ARCH=y -CONFIG_GENERIC_BUG=y -CONFIG_DEFAULT_UIMAGE=y - -# -# Processor support -# -# CONFIG_CLASSIC32 is not set -# CONFIG_PPC_82xx is not set -# CONFIG_PPC_83xx is not set -CONFIG_PPC_85xx=y -# CONFIG_PPC_86xx is not set -# CONFIG_PPC_8xx is not set -# CONFIG_40x is not set -# CONFIG_44x is not set -# CONFIG_E200 is not set -CONFIG_85xx=y -CONFIG_E500=y -# CONFIG_PPC_DCR_NATIVE is not set -# CONFIG_PPC_DCR_MMIO is not set -CONFIG_BOOKE=y -CONFIG_FSL_BOOKE=y -# CONFIG_PHYS_64BIT is not set -# CONFIG_SPE is not set -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_IPC_NS=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -# CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set -CONFIG_AUDIT=y -# CONFIG_AUDITSYSCALL is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_SYSFS_DEPRECATED=y -# CONFIG_RELAY is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_SYSCTL=y -CONFIG_EMBEDDED=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_KALLSYMS=y -CONFIG_KALLSYMS_ALL=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_HOTPLUG is not set -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_SLAB=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y - -# -# Block layer -# -CONFIG_BLOCK=y -CONFIG_LBD=y -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_DEFAULT_AS is not set -# CONFIG_DEFAULT_DEADLINE is not set -CONFIG_DEFAULT_CFQ=y -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="cfq" -# CONFIG_WANT_EARLY_SERIAL is not set - -# -# Platform support -# -# CONFIG_MPC8540_ADS is not set -# CONFIG_MPC8560_ADS is not set -# CONFIG_MPC85xx_CDS is not set -# CONFIG_MPC85xx_MDS is not set -CONFIG_MPC8544_DS=y -CONFIG_MPC85xx=y -CONFIG_PPC_INDIRECT_PCI_BE=y -CONFIG_MPIC=y - -# -# Kernel options -# -CONFIG_HIGHMEM=y -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=m -CONFIG_MATH_EMULATION=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 -CONFIG_PROC_DEVICETREE=y -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="root=/dev/sda3 rw console=ttyS0,115200" -# CONFIG_PM is not set -CONFIG_SECCOMP=y -CONFIG_ISA_DMA_API=y - -# -# Bus options -# -CONFIG_ZONE_DMA=y -# CONFIG_MPIC_WEIRD is not set -# CONFIG_PPC_I8259 is not set -CONFIG_PPC_INDIRECT_PCI=y -CONFIG_FSL_SOC=y -# CONFIG_PCI is not set -# CONFIG_PCI_DOMAINS is not set - -# -# PCCARD (PCMCIA/CardBus) support -# - -# -# PCI Hotplug Support -# - -# -# Advanced setup -# -# CONFIG_ADVANCED_OPTIONS is not set - -# -# Default settings for advanced configuration options are used -# -CONFIG_HIGHMEM_START=0xfe000000 -CONFIG_LOWMEM_SIZE=0x30000000 -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE=0x80000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_NETDEBUG is not set -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set -CONFIG_NET_KEY=m -# CONFIG_NET_KEY_MIGRATE is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_ASK_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NET_IPIP=y -CONFIG_NET_IPGRE=y -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -CONFIG_INET_TUNNEL=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -# CONFIG_NETWORK_SECMARK is not set -# CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_MSG is not set -# CONFIG_SCTP_DBG_OBJCNT is not set -# CONFIG_SCTP_HMAC_NONE is not set -# CONFIG_SCTP_HMAC_SHA1 is not set -CONFIG_SCTP_HMAC_MD5=y - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_IEEE80211 is not set -CONFIG_FIB_RULES=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# -# CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=2 -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -CONFIG_SCSI=y -# CONFIG_SCSI_TGT is not set -# CONFIG_SCSI_NETLINK is not set -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -CONFIG_CHR_DEV_SG=y -# CONFIG_CHR_DEV_SCH is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -CONFIG_SCSI_MULTI_LUN=y -# CONFIG_SCSI_CONSTANTS is not set -CONFIG_SCSI_LOGGING=y -# CONFIG_SCSI_SCAN_ASYNC is not set - -# -# SCSI Transports -# -# CONFIG_SCSI_SPI_ATTRS is not set -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set -# CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# -# CONFIG_ISCSI_TCP is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# -CONFIG_ATA=y -# CONFIG_ATA_NONSTANDARD is not set -# CONFIG_PATA_PLATFORM is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Macintosh device drivers -# -# CONFIG_MAC_EMUMOUSEBTN is not set -# CONFIG_WINDFARM is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# PHY device support -# -CONFIG_PHYLIB=y - -# -# MII PHY device drivers -# -# CONFIG_MARVELL_PHY is not set -# CONFIG_DAVICOM_PHY is not set -# CONFIG_QSEMI_PHY is not set -# CONFIG_LXT_PHY is not set -# CONFIG_CICADA_PHY is not set -CONFIG_VITESSE_PHY=y -# CONFIG_SMSC_PHY is not set -# CONFIG_BROADCOM_PHY is not set -# CONFIG_FIXED_PHY is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MII=y - -# -# Ethernet (1000 Mbit) -# -CONFIG_GIANFAR=y -CONFIG_GFAR_NAPI=y - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set - -# -# Userland interfaces -# -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_VT_HW_CONSOLE_BINDING is not set -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -# CONFIG_SERIAL_UARTLITE is not set -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_OF_PLATFORM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_HW_RANDOM is not set -CONFIG_NVRAM=y -CONFIG_GEN_RTC=y -CONFIG_GEN_RTC_X=y -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -CONFIG_DVB=y -CONFIG_DVB_CORE=m -# CONFIG_DVB_CORE_ATTACH is not set - -# -# Supported DVB Frontends -# - -# -# Customise DVB Frontends -# -# CONFIG_DVB_FE_CUSTOMISE is not set - -# -# DVB-S (satellite) frontends -# - -# -# DVB-T (terrestrial) frontends -# - -# -# DVB-C (cable) frontends -# - -# -# ATSC (North American/Korean Terrestrial/Cable DTV) frontends -# - -# -# Tuners/PLL support -# - -# -# Miscellaneous devices -# - -# -# Graphics support -# -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -# CONFIG_FB is not set -# CONFIG_FB_IBM_GXT4500 is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# HID Devices -# -CONFIG_HID=y -# CONFIG_HID_DEBUG is not set - -# -# USB support -# -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# LED devices -# -# CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - -# -# Real Time Clock -# -CONFIG_RTC_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set - -# -# RTC interfaces -# -CONFIG_RTC_INTF_SYSFS=y -CONFIG_RTC_INTF_PROC=y -CONFIG_RTC_INTF_DEV=y -# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set - -# -# RTC drivers -# -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_TEST is not set -# CONFIG_RTC_DRV_V3020 is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# - -# -# Auxiliary Display support -# - -# -# Virtualization -# - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set -# CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -# CONFIG_XFS_FS is not set -# CONFIG_GFS2_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_UDF_NLS=y - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=y -CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -CONFIG_NTFS_FS=y -# CONFIG_NTFS_DEBUG is not set -# CONFIG_NTFS_RW is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_SYSCTL=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -# CONFIG_TMPFS_POSIX_ACL is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# -CONFIG_ADFS_FS=m -# CONFIG_ADFS_FS_RW is not set -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -# CONFIG_BEFS_DEBUG is not set -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_CRAMFS=y -CONFIG_VXFS_FS=m -CONFIG_HPFS_FS=m -CONFIG_QNX4FS_FS=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_UFS_DEBUG is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -CONFIG_NFS_V4=y -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -CONFIG_SUNRPC_GSS=y -CONFIG_RPCSEC_GSS_KRB5=y -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_KARMA_PARTITION is not set -# CONFIG_EFI_PARTITION is not set - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=m - -# -# Distributed Lock Manager -# -# CONFIG_DLM is not set - -# -# Library routines -# -CONFIG_BITREVERSE=y -# CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set -CONFIG_CRC32=y -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=y -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y - -# -# Instrumentation Support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set -# CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_HIGHMEM is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_LIST is not set -CONFIG_FORCED_INLINING=y -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_FAULT_INJECTION is not set -# CONFIG_DEBUG_STACKOVERFLOW is not set -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUGGER is not set -# CONFIG_BDI_SWITCH is not set -# CONFIG_BOOTX_TEXT is not set -# CONFIG_PPC_EARLY_DEBUG is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_BLKCIPHER=y -CONFIG_CRYPTO_HASH=y -CONFIG_CRYPTO_MANAGER=y -CONFIG_CRYPTO_HMAC=y -# CONFIG_CRYPTO_XCBC is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_MD4 is not set -CONFIG_CRYPTO_MD5=y -# CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -# CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_GF128MUL is not set -# CONFIG_CRYPTO_ECB is not set -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_PCBC=m -# CONFIG_CRYPTO_LRW is not set -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_FCRYPT is not set -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -# CONFIG_CRYPTO_DEFLATE is not set -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# diff --git a/trunk/arch/powerpc/configs/ppc64_defconfig b/trunk/arch/powerpc/configs/ppc64_defconfig index 126b9f87df25..a8da0aea3b87 100644 --- a/trunk/arch/powerpc/configs/ppc64_defconfig +++ b/trunk/arch/powerpc/configs/ppc64_defconfig @@ -152,7 +152,7 @@ CONFIG_RTAS_ERROR_LOGGING=y CONFIG_RTAS_PROC=y CONFIG_RTAS_FLASH=m CONFIG_MMIO_NVRAM=y -CONFIG_MPIC_U3_HT_IRQS=y +CONFIG_MPIC_BROKEN_U3=y CONFIG_IBMVIO=y # CONFIG_IBMEBUS is not set # CONFIG_PPC_MPC106 is not set diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile index aa693d0f151a..8120d428ebfd 100644 --- a/trunk/arch/powerpc/kernel/Makefile +++ b/trunk/arch/powerpc/kernel/Makefile @@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o procfs-$(CONFIG_PPC64) := proc_ppc64.o obj-$(CONFIG_PROC_FS) += $(procfs-y) -rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o -obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y) +rtaspci-$(CONFIG_PPC64) := rtas_pci.o +obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y) obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_LPARCFG) += lparcfg.o @@ -37,7 +37,6 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o obj32-$(CONFIG_MODULES) += module_32.o ifeq ($(CONFIG_PPC_MERGE),y) diff --git a/trunk/arch/powerpc/kernel/align.c b/trunk/arch/powerpc/kernel/align.c index 5c9ff7f5c44e..4734b5de599d 100644 --- a/trunk/arch/powerpc/kernel/align.c +++ b/trunk/arch/powerpc/kernel/align.c @@ -241,7 +241,7 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr) if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size)) return -EFAULT; for (i = 0; i < size / sizeof(long); ++i) - if (__put_user_inatomic(0, p+i)) + if (__put_user(0, p+i)) return -EFAULT; return 1; } @@ -288,8 +288,7 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, } else { unsigned long pc = regs->nip ^ (swiz & 4); - if (__get_user_inatomic(instr, - (unsigned int __user *)pc)) + if (__get_user(instr, (unsigned int __user *)pc)) return -EFAULT; if (swiz == 0 && (flags & SW)) instr = cpu_to_le32(instr); @@ -325,31 +324,27 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, ((nb0 + 3) / 4) * sizeof(unsigned long)); for (i = 0; i < nb; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user(REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } else { for (i = 0; i < nb; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user(REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } @@ -403,8 +398,7 @@ int fix_alignment(struct pt_regs *regs) if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE)) pc ^= 4; - if (unlikely(__get_user_inatomic(instr, - (unsigned int __user *)pc))) + if (unlikely(__get_user(instr, (unsigned int __user *)pc))) return -EFAULT; if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE)) instr = cpu_to_le32(instr); @@ -480,16 +474,16 @@ int fix_alignment(struct pt_regs *regs) p = (unsigned long) addr; switch (nb) { case 8: - ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++)); - ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++)); - ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++)); - ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++)); + ret |= __get_user(data.v[0], SWIZ_PTR(p++)); + ret |= __get_user(data.v[1], SWIZ_PTR(p++)); + ret |= __get_user(data.v[2], SWIZ_PTR(p++)); + ret |= __get_user(data.v[3], SWIZ_PTR(p++)); case 4: - ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++)); - ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++)); + ret |= __get_user(data.v[4], SWIZ_PTR(p++)); + ret |= __get_user(data.v[5], SWIZ_PTR(p++)); case 2: - ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++)); - ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++)); + ret |= __get_user(data.v[6], SWIZ_PTR(p++)); + ret |= __get_user(data.v[7], SWIZ_PTR(p++)); if (unlikely(ret)) return -EFAULT; } @@ -557,16 +551,16 @@ int fix_alignment(struct pt_regs *regs) p = (unsigned long) addr; switch (nb) { case 8: - ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++)); - ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++)); - ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++)); - ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++)); + ret |= __put_user(data.v[0], SWIZ_PTR(p++)); + ret |= __put_user(data.v[1], SWIZ_PTR(p++)); + ret |= __put_user(data.v[2], SWIZ_PTR(p++)); + ret |= __put_user(data.v[3], SWIZ_PTR(p++)); case 4: - ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++)); - ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++)); + ret |= __put_user(data.v[4], SWIZ_PTR(p++)); + ret |= __put_user(data.v[5], SWIZ_PTR(p++)); case 2: - ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++)); - ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++)); + ret |= __put_user(data.v[6], SWIZ_PTR(p++)); + ret |= __put_user(data.v[7], SWIZ_PTR(p++)); } if (unlikely(ret)) return -EFAULT; diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index 0c5150c69175..030d300cd71c 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -77,6 +77,7 @@ int main(void) DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); #else /* CONFIG_PPC64 */ DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); + DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); DEFINE(PT_PTRACED, PT_PTRACED); @@ -139,7 +140,6 @@ int main(void) DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr)); DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); - DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); DEFINE(SLBSHADOW_STACKVSID, offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid)); diff --git a/trunk/arch/powerpc/kernel/btext.c b/trunk/arch/powerpc/kernel/btext.c index e7b684689e04..3678997339d6 100644 --- a/trunk/arch/powerpc/kernel/btext.c +++ b/trunk/arch/powerpc/kernel/btext.c @@ -161,33 +161,33 @@ int btext_initialize(struct device_node *np) unsigned long address = 0; const u32 *prop; - prop = of_get_property(np, "linux,bootx-width", NULL); + prop = get_property(np, "linux,bootx-width", NULL); if (prop == NULL) - prop = of_get_property(np, "width", NULL); + prop = get_property(np, "width", NULL); if (prop == NULL) return -EINVAL; width = *prop; - prop = of_get_property(np, "linux,bootx-height", NULL); + prop = get_property(np, "linux,bootx-height", NULL); if (prop == NULL) - prop = of_get_property(np, "height", NULL); + prop = get_property(np, "height", NULL); if (prop == NULL) return -EINVAL; height = *prop; - prop = of_get_property(np, "linux,bootx-depth", NULL); + prop = get_property(np, "linux,bootx-depth", NULL); if (prop == NULL) - prop = of_get_property(np, "depth", NULL); + prop = get_property(np, "depth", NULL); if (prop == NULL) return -EINVAL; depth = *prop; pitch = width * ((depth + 7) / 8); - prop = of_get_property(np, "linux,bootx-linebytes", NULL); + prop = get_property(np, "linux,bootx-linebytes", NULL); if (prop == NULL) - prop = of_get_property(np, "linebytes", NULL); + prop = get_property(np, "linebytes", NULL); if (prop && *prop != 0xffffffffu) pitch = *prop; if (pitch == 1) pitch = 0x1000; - prop = of_get_property(np, "address", NULL); + prop = get_property(np, "address", NULL); if (prop) address = *prop; @@ -219,7 +219,7 @@ int __init btext_find_display(int allow_nonstdout) struct device_node *np = NULL; int rc = -ENODEV; - name = of_get_property(of_chosen, "linux,stdout-path", NULL); + name = get_property(of_chosen, "linux,stdout-path", NULL); if (name != NULL) { np = of_find_node_by_path(name); if (np != NULL) { @@ -236,7 +236,7 @@ int __init btext_find_display(int allow_nonstdout) return rc; for (np = NULL; (np = of_find_node_by_type(np, "display"));) { - if (of_get_property(np, "linux,opened", NULL)) { + if (get_property(np, "linux,opened", NULL)) { printk("trying %s ...\n", np->full_name); rc = btext_initialize(np); printk("result: %d\n", rc); diff --git a/trunk/arch/powerpc/kernel/cpu_setup_pa6t.S b/trunk/arch/powerpc/kernel/cpu_setup_pa6t.S index d62cb9cae4e9..4047be25c4d2 100644 --- a/trunk/arch/powerpc/kernel/cpu_setup_pa6t.S +++ b/trunk/arch/powerpc/kernel/cpu_setup_pa6t.S @@ -34,7 +34,7 @@ _GLOBAL(__setup_cpu_pa6t) beqlr mfspr r0,SPRN_HID5 - ori r0,r0,0x38 + ori r0,r0,0x30 mtspr SPRN_HID5,r0 mfspr r0,SPRN_LPCR diff --git a/trunk/arch/powerpc/kernel/cputable.c b/trunk/arch/powerpc/kernel/cputable.c index 9cb24d20f0f9..e4006dc087ca 100644 --- a/trunk/arch/powerpc/kernel/cputable.c +++ b/trunk/arch/powerpc/kernel/cputable.c @@ -389,8 +389,6 @@ static struct cpu_spec cpu_specs[] = { .pmc_type = PPC_PMC_PA6T, .cpu_setup = __setup_cpu_pa6t, .cpu_restore = __restore_cpu_pa6t, - .oprofile_cpu_type = "ppc64/pa6t", - .oprofile_type = PPC_OPROFILE_PA6T, .platform = "pa6t", }, { /* default match */ @@ -560,18 +558,6 @@ static struct cpu_spec cpu_specs[] = { .cpu_setup = __setup_cpu_750cx, .platform = "ppc750", }, - { /* 750CL */ - .pvr_mask = 0xfffff0f0, - .pvr_value = 0x00087010, - .cpu_name = "750CL", - .cpu_features = CPU_FTRS_750CL, - .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, - .icache_bsize = 32, - .dcache_bsize = 32, - .num_pmcs = 4, - .cpu_setup = __setup_cpu_750, - .platform = "ppc750", - }, { /* 745/755 */ .pvr_mask = 0xfffff000, .pvr_value = 0x00083000, diff --git a/trunk/arch/powerpc/kernel/entry_32.S b/trunk/arch/powerpc/kernel/entry_32.S index c29d1652a421..c03e829fee3c 100644 --- a/trunk/arch/powerpc/kernel/entry_32.S +++ b/trunk/arch/powerpc/kernel/entry_32.S @@ -191,6 +191,7 @@ stack_ovf: 0: _GLOBAL(DoSyscall) + stw r0,THREAD+LAST_SYSCALL(r2) stw r3,ORIG_GPR3(r1) li r12,0 stw r12,RESULT(r1) diff --git a/trunk/arch/powerpc/kernel/head_64.S b/trunk/arch/powerpc/kernel/head_64.S index 1111fcec7673..97cedcd6c9b4 100644 --- a/trunk/arch/powerpc/kernel/head_64.S +++ b/trunk/arch/powerpc/kernel/head_64.S @@ -278,12 +278,8 @@ exception_marker: beq- 1f; \ ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ 1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ - bge- cr1,2f; /* abort if it is */ \ - b 3f; \ -2: li r1,(n); /* will be reloaded later */ \ - sth r1,PACA_TRAP_SAVE(r13); \ - b bad_stack; \ -3: std r9,_CCR(r1); /* save CR in stackframe */ \ + bge- cr1,bad_stack; /* abort if it is */ \ + std r9,_CCR(r1); /* save CR in stackframe */ \ std r11,_NIP(r1); /* save SRR0 in stackframe */ \ std r12,_MSR(r1); /* save SRR1 in stackframe */ \ std r10,0(r1); /* make stack chain pointer */ \ @@ -944,8 +940,6 @@ bad_stack: SAVE_2GPRS(7,r1) SAVE_10GPRS(12,r1) SAVE_10GPRS(22,r1) - lhz r12,PACA_TRAP_SAVE(r13) - std r12,_TRAP(r1) addi r11,r1,INT_FRAME_SIZE std r11,0(r1) li r12,0 @@ -1561,6 +1555,7 @@ _GLOBAL(generic_secondary_smp_init) /* turn on 64-bit mode */ bl .enable_64b_mode + isync /* Set up a paca value for this processor. Since we have the * physical cpu id in r24, we need to search the pacas to find @@ -1740,6 +1735,10 @@ _STATIC(__boot_from_prom) /* We never return */ trap +/* + * At this point, r3 contains the physical address we are running at, + * returned by prom_init() + */ _STATIC(__after_prom_start) /* @@ -1852,6 +1851,7 @@ __secondary_start_pmac_0: _GLOBAL(pmac_secondary_start) /* turn on 64-bit mode */ bl .enable_64b_mode + isync /* Copy some CPU settings from CPU 0 */ bl .__restore_cpu_ppc970 diff --git a/trunk/arch/powerpc/kernel/ibmebus.c b/trunk/arch/powerpc/kernel/ibmebus.c index 9a8c9af43b22..82bd2f10770f 100644 --- a/trunk/arch/powerpc/kernel/ibmebus.c +++ b/trunk/arch/powerpc/kernel/ibmebus.c @@ -2,37 +2,36 @@ * IBM PowerPC IBM eBus Infrastructure Support. * * Copyright (c) 2005 IBM Corporation - * Joachim Fenkes * Heiko J Schick - * + * * All rights reserved. * - * This source code is distributed under a dual license of GPL v2.0 and OpenIB - * BSD. + * This source code is distributed under a dual license of GPL v2.0 and OpenIB + * BSD. * * OpenIB BSD License * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation * and/or other materials - * provided with the distribution. + * provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ @@ -44,19 +43,19 @@ #include #include -static struct device ibmebus_bus_device = { /* fake "parent" device */ - .bus_id = "ibmebus", +static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */ + .name = ibmebus_bus_device.ofdev.dev.bus_id, + .ofdev.dev.bus_id = "ibmebus", + .ofdev.dev.bus = &ibmebus_bus_type, }; -struct bus_type ibmebus_bus_type; - static void *ibmebus_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *mem; - + mem = kmalloc(size, flag); *dma_handle = (dma_addr_t)mem; @@ -64,7 +63,7 @@ static void *ibmebus_alloc_coherent(struct device *dev, } static void ibmebus_free_coherent(struct device *dev, - size_t size, void *vaddr, + size_t size, void *vaddr, dma_addr_t dma_handle) { kfree(vaddr); @@ -80,7 +79,7 @@ static dma_addr_t ibmebus_map_single(struct device *dev, static void ibmebus_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, + size_t size, enum dma_data_direction direction) { return; @@ -91,13 +90,13 @@ static int ibmebus_map_sg(struct device *dev, int nents, enum dma_data_direction direction) { int i; - + for (i = 0; i < nents; i++) { - sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) + sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) + sg[i].offset; sg[i].dma_length = sg[i].length; } - + return nents; } @@ -129,15 +128,15 @@ static int ibmebus_bus_probe(struct device *dev) struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); const struct of_device_id *id; int error = -ENODEV; - + if (!ibmebusdrv->probe) return error; - + id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev); if (id) { error = ibmebusdrv->probe(ibmebusdev, id); } - + return error; } @@ -145,11 +144,11 @@ static int ibmebus_bus_remove(struct device *dev) { struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); - + if (ibmebusdrv->remove) { return ibmebusdrv->remove(ibmebusdev); } - + return 0; } @@ -159,12 +158,21 @@ static void __devinit ibmebus_dev_release(struct device *dev) kfree(to_ibmebus_dev(dev)); } -static int __devinit ibmebus_register_device_common( +static ssize_t ibmebusdev_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name); +} +static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, + NULL); + +static struct ibmebus_dev* __devinit ibmebus_register_device_common( struct ibmebus_dev *dev, const char *name) { int err = 0; - dev->ofdev.dev.parent = &ibmebus_bus_device; + dev->name = name; + dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev; dev->ofdev.dev.bus = &ibmebus_bus_type; dev->ofdev.dev.release = ibmebus_dev_release; @@ -173,15 +181,17 @@ static int __devinit ibmebus_register_device_common( dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node); /* An ibmebusdev is based on a of_device. We have to change the - * bus type to use our own DMA mapping operations. - */ + * bus type to use our own DMA mapping operations. + */ if ((err = of_device_register(&dev->ofdev)) != 0) { printk(KERN_ERR "%s: failed to register device (%d).\n", __FUNCTION__, err); - return -ENODEV; + return NULL; } - - return 0; + + device_create_file(&dev->ofdev.dev, &dev_attr_name); + + return dev; } static struct ibmebus_dev* __devinit ibmebus_register_device_node( @@ -191,35 +201,35 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node( const char *loc_code; int length; - loc_code = of_get_property(dn, "ibm,loc-code", NULL); + loc_code = get_property(dn, "ibm,loc-code", NULL); if (!loc_code) { printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", __FUNCTION__, dn->name ? dn->name : ""); - return ERR_PTR(-EINVAL); + return NULL; } - + if (strlen(loc_code) == 0) { printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", __FUNCTION__); - return ERR_PTR(-EINVAL); + return NULL; } dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); if (!dev) { - return ERR_PTR(-ENOMEM); + return NULL; } dev->ofdev.node = of_node_get(dn); - + length = strlen(loc_code); - memcpy(dev->ofdev.dev.bus_id, loc_code - + (length - min(length, BUS_ID_SIZE - 1)), + memcpy(dev->ofdev.dev.bus_id, loc_code + + (length - min(length, BUS_ID_SIZE - 1)), min(length, BUS_ID_SIZE - 1)); /* Register with generic device framework. */ - if (ibmebus_register_device_common(dev, dn->name) != 0) { + if (ibmebus_register_device_common(dev, dn->name) == NULL) { kfree(dev); - return ERR_PTR(-ENODEV); + return NULL; } return dev; @@ -228,16 +238,17 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node( static void ibmebus_probe_of_nodes(char* name) { struct device_node *dn = NULL; - + while ((dn = of_find_node_by_name(dn, name))) { - if (IS_ERR(ibmebus_register_device_node(dn))) { + if (ibmebus_register_device_node(dn) == NULL) { of_node_put(dn); + return; } } - + of_node_put(dn); - + return; } @@ -251,21 +262,17 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt) return; } -static int ibmebus_match_name(struct device *dev, void *data) +static int ibmebus_match_helper(struct device *dev, void *data) { - const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); - const char *name; - - name = of_get_property(ebus_dev->ofdev.node, "name", NULL); - - if (name && (strcmp(data, name) == 0)) + if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0) return 1; - + return 0; } static int ibmebus_unregister_device(struct device *dev) { + device_remove_file(dev, &dev_attr_name); of_device_unregister(to_of_device(dev)); return 0; @@ -274,16 +281,17 @@ static int ibmebus_unregister_device(struct device *dev) static void ibmebus_remove_devices_by_id(struct of_device_id *idt) { struct device *dev; - + while (strlen(idt->name) > 0) { - while ((dev = bus_find_device(&ibmebus_bus_type, NULL, + while ((dev = bus_find_device(&ibmebus_bus_type, NULL, (void*)idt->name, - ibmebus_match_name))) { + ibmebus_match_helper))) { ibmebus_unregister_device(dev); } idt++; + } - + return; } @@ -299,33 +307,30 @@ int ibmebus_register_driver(struct ibmebus_driver *drv) if ((err = driver_register(&drv->driver) != 0)) return err; - /* remove all supported devices first, in case someone - * probed them manually before registering the driver */ - ibmebus_remove_devices_by_id(drv->id_table); ibmebus_add_devices_by_id(drv->id_table); - + return 0; } EXPORT_SYMBOL(ibmebus_register_driver); void ibmebus_unregister_driver(struct ibmebus_driver *drv) -{ +{ driver_unregister(&drv->driver); ibmebus_remove_devices_by_id(drv->id_table); } EXPORT_SYMBOL(ibmebus_unregister_driver); int ibmebus_request_irq(struct ibmebus_dev *dev, - u32 ist, + u32 ist, irq_handler_t handler, unsigned long irq_flags, const char * devname, void *dev_id) { unsigned int irq = irq_create_mapping(NULL, ist); - + if (irq == NO_IRQ) return -EINVAL; - + return request_irq(irq, handler, irq_flags, devname, dev_id); } @@ -334,163 +339,56 @@ EXPORT_SYMBOL(ibmebus_request_irq); void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) { unsigned int irq = irq_find_mapping(NULL, ist); - + free_irq(irq, dev_id); } EXPORT_SYMBOL(ibmebus_free_irq); static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) -{ +{ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv); const struct of_device_id *ids = ebus_drv->id_table; const struct of_device_id *found_id; - + if (!ids) return 0; - + found_id = of_match_device(ids, &ebus_dev->ofdev); if (found_id) return 1; - + return 0; } -static ssize_t name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); - const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL); - return sprintf(buf, "%s\n", name); -} - -static struct device_attribute ibmebus_dev_attrs[] = { - __ATTR_RO(name), - __ATTR_NULL -}; - -static int ibmebus_match_path(struct device *dev, void *data) -{ - int rc; - struct device_node *dn = - of_node_get(to_ibmebus_dev(dev)->ofdev.node); - - rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0)); - - of_node_put(dn); - return rc; -} - -static char *ibmebus_chomp(const char *in, size_t count) -{ - char *out = (char*)kmalloc(count + 1, GFP_KERNEL); - if (!out) - return NULL; - - memcpy(out, in, count); - out[count] = '\0'; - if (out[count - 1] == '\n') - out[count - 1] = '\0'; - - return out; -} - -static ssize_t ibmebus_store_probe(struct bus_type *bus, - const char *buf, size_t count) -{ - struct device_node *dn = NULL; - struct ibmebus_dev *dev; - char *path; - ssize_t rc; - - path = ibmebus_chomp(buf, count); - if (!path) - return -ENOMEM; - - if (bus_find_device(&ibmebus_bus_type, NULL, path, - ibmebus_match_path)) { - printk(KERN_WARNING "%s: %s has already been probed\n", - __FUNCTION__, path); - rc = -EINVAL; - goto out; - } - - if ((dn = of_find_node_by_path(path))) { - dev = ibmebus_register_device_node(dn); - of_node_put(dn); - rc = IS_ERR(dev) ? PTR_ERR(dev) : count; - } else { - printk(KERN_WARNING "%s: no such device node: %s\n", - __FUNCTION__, path); - rc = -ENODEV; - } - -out: - kfree(path); - return rc; -} - -static ssize_t ibmebus_store_remove(struct bus_type *bus, - const char *buf, size_t count) -{ - struct device *dev; - char *path; - - path = ibmebus_chomp(buf, count); - if (!path) - return -ENOMEM; - - if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, - ibmebus_match_path))) { - ibmebus_unregister_device(dev); - - kfree(path); - return count; - } else { - printk(KERN_WARNING "%s: %s not on the bus\n", - __FUNCTION__, path); - - kfree(path); - return -ENODEV; - } -} - -static struct bus_attribute ibmebus_bus_attrs[] = { - __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), - __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), - __ATTR_NULL -}; - struct bus_type ibmebus_bus_type = { - .name = "ibmebus", - .match = ibmebus_bus_match, - .dev_attrs = ibmebus_dev_attrs, - .bus_attrs = ibmebus_bus_attrs + .name = "ibmebus", + .match = ibmebus_bus_match, }; EXPORT_SYMBOL(ibmebus_bus_type); static int __init ibmebus_bus_init(void) { int err; - + printk(KERN_INFO "IBM eBus Device Driver\n"); - + err = bus_register(&ibmebus_bus_type); if (err) { printk(KERN_ERR ":%s: failed to register IBM eBus.\n", __FUNCTION__); return err; } - - err = device_register(&ibmebus_bus_device); + + err = device_register(&ibmebus_bus_device.ofdev.dev); if (err) { - printk(KERN_WARNING "%s: device_register returned %i\n", + printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__, err); bus_unregister(&ibmebus_bus_type); return err; } - + return 0; } __initcall(ibmebus_bus_init); diff --git a/trunk/arch/powerpc/kernel/iommu.c b/trunk/arch/powerpc/kernel/iommu.c index c08ceca6277d..95edad4faf26 100644 --- a/trunk/arch/powerpc/kernel/iommu.c +++ b/trunk/arch/powerpc/kernel/iommu.c @@ -47,8 +47,6 @@ static int novmerge = 0; static int novmerge = 1; #endif -static int protect4gb = 1; - static inline unsigned long iommu_num_pages(unsigned long vaddr, unsigned long slen) { @@ -60,16 +58,6 @@ static inline unsigned long iommu_num_pages(unsigned long vaddr, return npages; } -static int __init setup_protect4gb(char *str) -{ - if (strcmp(str, "on") == 0) - protect4gb = 1; - else if (strcmp(str, "off") == 0) - protect4gb = 0; - - return 1; -} - static int __init setup_iommu(char *str) { if (!strcmp(str, "novmerge")) @@ -79,7 +67,6 @@ static int __init setup_iommu(char *str) return 1; } -__setup("protect4gb=", setup_protect4gb); __setup("iommu=", setup_iommu); static unsigned long iommu_range_alloc(struct iommu_table *tbl, @@ -442,9 +429,6 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) { unsigned long sz; - unsigned long start_index, end_index; - unsigned long entries_per_4g; - unsigned long index; static int welcomed = 0; struct page *page; @@ -466,7 +450,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) #ifdef CONFIG_CRASH_DUMP if (ppc_md.tce_get) { - unsigned long tceval; + unsigned long index, tceval; unsigned long tcecount = 0; /* @@ -496,23 +480,6 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); #endif - /* - * DMA cannot cross 4 GB boundary. Mark last entry of each 4 - * GB chunk as reserved. - */ - if (protect4gb) { - entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT; - - /* Mark the last bit before a 4GB boundary as used */ - start_index = tbl->it_offset | (entries_per_4g - 1); - start_index -= tbl->it_offset; - - end_index = tbl->it_size; - - for (index = start_index; index < end_index - 1; index += entries_per_4g) - __set_bit(index, tbl->it_map); - } - if (!welcomed) { printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", novmerge ? "disabled" : "enabled"); diff --git a/trunk/arch/powerpc/kernel/irq.c b/trunk/arch/powerpc/kernel/irq.c index 6c83fe229e60..100930826850 100644 --- a/trunk/arch/powerpc/kernel/irq.c +++ b/trunk/arch/powerpc/kernel/irq.c @@ -394,7 +394,7 @@ EXPORT_SYMBOL(do_softirq); #ifdef CONFIG_PPC_MERGE static LIST_HEAD(irq_hosts); -static DEFINE_SPINLOCK(irq_big_lock); +static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED; static DEFINE_PER_CPU(unsigned int, irq_radix_reader); static unsigned int irq_radix_writer; struct irq_map_entry irq_map[NR_IRQS]; diff --git a/trunk/arch/powerpc/kernel/kprobes.c b/trunk/arch/powerpc/kernel/kprobes.c index ef647e7a9dc3..dd2886f97e98 100644 --- a/trunk/arch/powerpc/kernel/kprobes.c +++ b/trunk/arch/powerpc/kernel/kprobes.c @@ -59,14 +59,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) } if (!ret) { - memcpy(p->ainsn.insn, p->addr, - MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); p->opcode = *p->addr; flush_icache_range((unsigned long)p->ainsn.insn, (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); } - p->ainsn.boostable = 0; return ret; } @@ -234,38 +232,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) return 1; ss_probe: - if (p->ainsn.boostable >= 0) { - unsigned int insn = *p->ainsn.insn; - - /* regs->nip is also adjusted if emulate_step returns 1 */ - ret = emulate_step(regs, insn); - if (ret > 0) { - /* - * Once this instruction has been boosted - * successfully, set the boostable flag - */ - if (unlikely(p->ainsn.boostable == 0)) - p->ainsn.boostable = 1; - - if (p->post_handler) - p->post_handler(p, regs, 0); - - kcb->kprobe_status = KPROBE_HIT_SSDONE; - reset_current_kprobe(); - preempt_enable_no_resched(); - return 1; - } else if (ret < 0) { - /* - * We don't allow kprobes on mtmsr(d)/rfi(d), etc. - * So, we should never get here... but, its still - * good to catch them, just in case... - */ - printk("Can't step on instruction %x\n", insn); - BUG(); - } else if (ret == 0) - /* This instruction can't be boosted */ - p->ainsn.boostable = -1; - } prepare_singlestep(p, regs); kcb->kprobe_status = KPROBE_HIT_SS; return 1; diff --git a/trunk/arch/powerpc/kernel/legacy_serial.c b/trunk/arch/powerpc/kernel/legacy_serial.c index 63dd2c3ad95e..325f490a10cc 100644 --- a/trunk/arch/powerpc/kernel/legacy_serial.c +++ b/trunk/arch/powerpc/kernel/legacy_serial.c @@ -44,12 +44,12 @@ static int __init add_legacy_port(struct device_node *np, int want_index, int index; /* get clock freq. if present */ - clk = of_get_property(np, "clock-frequency", NULL); + clk = get_property(np, "clock-frequency", NULL); if (clk && *clk) clock = *clk; /* get default speed if present */ - spd = of_get_property(np, "current-speed", NULL); + spd = get_property(np, "current-speed", NULL); /* If we have a location index, then try to use it */ if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS) @@ -121,11 +121,11 @@ static int __init add_legacy_soc_port(struct device_node *np, /* We only support ports that have a clock frequency properly * encoded in the device-tree. */ - if (of_get_property(np, "clock-frequency", NULL) == NULL) + if (get_property(np, "clock-frequency", NULL) == NULL) return -1; /* if rtas uses this device, don't try to use it as well */ - if (of_get_property(np, "used-by-rtas", NULL) != NULL) + if (get_property(np, "used-by-rtas", NULL) != NULL) return -1; /* Get the address */ @@ -157,7 +157,7 @@ static int __init add_legacy_isa_port(struct device_node *np, DBG(" -> add_legacy_isa_port(%s)\n", np->full_name); /* Get the ISA port number */ - reg = of_get_property(np, "reg", NULL); + reg = get_property(np, "reg", NULL); if (reg == NULL) return -1; @@ -168,7 +168,7 @@ static int __init add_legacy_isa_port(struct device_node *np, /* Now look for an "ibm,aix-loc" property that gives us ordering * if any... */ - typep = of_get_property(np, "ibm,aix-loc", NULL); + typep = get_property(np, "ibm,aix-loc", NULL); /* If we have a location index, then use it */ if (typep && *typep == 'S') @@ -206,7 +206,7 @@ static int __init add_legacy_pci_port(struct device_node *np, * compatible UARTs on PCI need all sort of quirks (port offsets * etc...) that this code doesn't know about */ - if (of_get_property(np, "clock-frequency", NULL) == NULL) + if (get_property(np, "clock-frequency", NULL) == NULL) return -1; /* Get the PCI address. Assume BAR 0 */ @@ -232,7 +232,7 @@ static int __init add_legacy_pci_port(struct device_node *np, * we get to their "reg" property */ if (np != pci_dev) { - const u32 *reg = of_get_property(np, "reg", NULL); + const u32 *reg = get_property(np, "reg", NULL); if (reg && (*reg < 4)) index = lindex = *reg; } @@ -296,7 +296,7 @@ void __init find_legacy_serial_ports(void) DBG(" -> find_legacy_serial_port()\n"); /* Now find out if one of these is out firmware console */ - path = of_get_property(of_chosen, "linux,stdout-path", NULL); + path = get_property(of_chosen, "linux,stdout-path", NULL); if (path != NULL) { stdout = of_find_node_by_path(path); if (stdout) @@ -529,7 +529,7 @@ static int __init check_legacy_serial_console(void) } /* We are getting a weird phandle from OF ... */ /* ... So use the full path instead */ - name = of_get_property(of_chosen, "linux,stdout-path", NULL); + name = get_property(of_chosen, "linux,stdout-path", NULL); if (name == NULL) { DBG(" no linux,stdout-path !\n"); return -ENODEV; @@ -541,12 +541,12 @@ static int __init check_legacy_serial_console(void) } DBG("stdout is %s\n", prom_stdout->full_name); - name = of_get_property(prom_stdout, "name", NULL); + name = get_property(prom_stdout, "name", NULL); if (!name) { DBG(" stdout package has no name !\n"); goto not_found; } - spd = of_get_property(prom_stdout, "current-speed", NULL); + spd = get_property(prom_stdout, "current-speed", NULL); if (spd) speed = *spd; diff --git a/trunk/arch/powerpc/kernel/lparcfg.c b/trunk/arch/powerpc/kernel/lparcfg.c index c492cee90e0f..89486b631284 100644 --- a/trunk/arch/powerpc/kernel/lparcfg.c +++ b/trunk/arch/powerpc/kernel/lparcfg.c @@ -130,31 +130,30 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v) /* * Methods used to fetch LPAR data when running on a pSeries platform. */ +/* find a better place for this function... */ static void log_plpar_hcall_return(unsigned long rc, char *tag) { - switch(rc) { - case 0: + if (rc == 0) /* success, return */ return; - case H_HARDWARE: - printk(KERN_INFO "plpar-hcall (%s) " - "Hardware fault\n", tag); - return; - case H_FUNCTION: - printk(KERN_INFO "plpar-hcall (%s) " - "Function not allowed\n", tag); - return; - case H_AUTHORITY: - printk(KERN_INFO "plpar-hcall (%s) " - "Not authorized to this function\n", tag); - return; - case H_PARAMETER: - printk(KERN_INFO "plpar-hcall (%s) " - "Bad parameter(s)\n",tag); - return; - default: - printk(KERN_INFO "plpar-hcall (%s) " - "Unexpected rc(0x%lx)\n", tag, rc); - } +/* check for null tag ? */ + if (rc == H_HARDWARE) + printk(KERN_INFO + "plpar-hcall (%s) failed with hardware fault\n", tag); + else if (rc == H_FUNCTION) + printk(KERN_INFO + "plpar-hcall (%s) failed; function not allowed\n", tag); + else if (rc == H_AUTHORITY) + printk(KERN_INFO + "plpar-hcall (%s) failed; not authorized to this" + " function\n", tag); + else if (rc == H_PARAMETER) + printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", + tag); + else + printk(KERN_INFO + "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n", + tag, rc); + } /* @@ -322,16 +321,15 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) struct device_node *rtas_node; const int *lrdrp = NULL; - rtas_node = of_find_node_by_path("/rtas"); + rtas_node = find_path_device("/rtas"); if (rtas_node) - lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL); + lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL); if (lrdrp == NULL) { partition_potential_processors = vdso_data->processorCount; } else { partition_potential_processors = *(lrdrp + 4); } - of_node_put(rtas_node); partition_active_processors = lparcfg_count_active_processors(); @@ -539,27 +537,25 @@ static int lparcfg_data(struct seq_file *m, void *v) seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); - rootdn = of_find_node_by_path("/"); + rootdn = find_path_device("/"); if (rootdn) { - tmp = of_get_property(rootdn, "model", NULL); + tmp = get_property(rootdn, "model", NULL); if (tmp) { model = tmp; /* Skip "IBM," - see platforms/iseries/dt.c */ if (firmware_has_feature(FW_FEATURE_ISERIES)) model += 4; } - tmp = of_get_property(rootdn, "system-id", NULL); + tmp = get_property(rootdn, "system-id", NULL); if (tmp) { system_id = tmp; /* Skip "IBM," - see platforms/iseries/dt.c */ if (firmware_has_feature(FW_FEATURE_ISERIES)) system_id += 4; } - lp_index_ptr = of_get_property(rootdn, "ibm,partition-no", - NULL); + lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL); if (lp_index_ptr) lp_index = *lp_index_ptr; - of_node_put(rootdn); } seq_printf(m, "serial_number=%s\n", system_id); seq_printf(m, "system_type=%s\n", model); diff --git a/trunk/arch/powerpc/kernel/machine_kexec_64.c b/trunk/arch/powerpc/kernel/machine_kexec_64.c index 704375bda73a..a24b09c27718 100644 --- a/trunk/arch/powerpc/kernel/machine_kexec_64.c +++ b/trunk/arch/powerpc/kernel/machine_kexec_64.c @@ -72,8 +72,8 @@ int default_machine_kexec_prepare(struct kimage *image) /* We also should not overwrite the tce tables */ for (node = of_find_node_by_type(NULL, "pci"); node != NULL; node = of_find_node_by_type(node, "pci")) { - basep = of_get_property(node, "linux,tce-base", NULL); - sizep = of_get_property(node, "linux,tce-size", NULL); + basep = get_property(node, "linux,tce-base", NULL); + sizep = get_property(node, "linux,tce-size", NULL); if (basep == NULL || sizep == NULL) continue; @@ -294,19 +294,19 @@ static unsigned long htab_base, kernel_end; static struct property htab_base_prop = { .name = "linux,htab-base", .length = sizeof(unsigned long), - .value = &htab_base, + .value = (unsigned char *)&htab_base, }; static struct property htab_size_prop = { .name = "linux,htab-size", .length = sizeof(unsigned long), - .value = &htab_size_bytes, + .value = (unsigned char *)&htab_size_bytes, }; static struct property kernel_end_prop = { .name = "linux,kernel-end", .length = sizeof(unsigned long), - .value = &kernel_end, + .value = (unsigned char *)&kernel_end, }; static void __init export_htab_values(void) @@ -335,7 +335,7 @@ static void __init export_htab_values(void) static struct property crashk_base_prop = { .name = "linux,crashkernel-base", .length = sizeof(unsigned long), - .value = &crashk_res.start, + .value = (unsigned char *)&crashk_res.start, }; static unsigned long crashk_size; @@ -343,7 +343,7 @@ static unsigned long crashk_size; static struct property crashk_size_prop = { .name = "linux,crashkernel-size", .length = sizeof(unsigned long), - .value = &crashk_size, + .value = (unsigned char *)&crashk_size, }; static void __init export_crashk_values(void) diff --git a/trunk/arch/powerpc/kernel/misc_32.S b/trunk/arch/powerpc/kernel/misc_32.S index 98decf8ebff4..412bea3cf813 100644 --- a/trunk/arch/powerpc/kernel/misc_32.S +++ b/trunk/arch/powerpc/kernel/misc_32.S @@ -734,6 +734,10 @@ _GLOBAL(abs) sub r3,r3,r4 blr +_GLOBAL(_get_SP) + mr r3,r1 /* Close enough */ + blr + /* * Create a kernel thread * kernel_thread(fn, arg, flags) diff --git a/trunk/arch/powerpc/kernel/of_device.c b/trunk/arch/powerpc/kernel/of_device.c index 0c8ea7659d92..e921514e655b 100644 --- a/trunk/arch/powerpc/kernel/of_device.c +++ b/trunk/arch/powerpc/kernel/of_device.c @@ -120,117 +120,6 @@ void of_device_unregister(struct of_device *ofdev) } -static ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) -{ - const char *compat; - int cplen, i; - ssize_t tsize, csize, repend; - - /* Name & Type */ - csize = snprintf(str, len, "of:N%sT%s", - ofdev->node->name, ofdev->node->type); - - /* Get compatible property if any */ - compat = of_get_property(ofdev->node, "compatible", &cplen); - if (!compat) - return csize; - - /* Find true end (we tolerate multiple \0 at the end */ - for (i=(cplen-1); i>=0 && !compat[i]; i--) - cplen--; - if (!cplen) - return csize; - cplen++; - - /* Check space (need cplen+1 chars including final \0) */ - tsize = csize + cplen; - repend = tsize; - - if (csize>=len) /* @ the limit, all is already filled */ - return tsize; - - if (tsize>=len) { /* limit compat list */ - cplen = len-csize-1; - repend = len; - } - - /* Copy and do char replacement */ - memcpy(&str[csize+1], compat, cplen); - for (i=csize; inode->name)) - return -ENOMEM; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", ofdev->node->type)) - return -ENOMEM; - - /* Since the compatible field can contain pretty much anything - * it's not really legal to split it out with commas. We split it - * up using a number of environment variables instead. */ - - compat = of_get_property(ofdev->node, "compatible", &cplen); - while (compat && *compat && cplen > 0) { - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat)) - return -ENOMEM; - - sl = strlen (compat) + 1; - compat += sl; - cplen -= sl; - seen++; - } - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen)) - return -ENOMEM; - - /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=")) - return -ENOMEM; - - sl = of_device_get_modalias(ofdev, &buffer[length-1], - buffer_size-length); - if (sl >= (buffer_size-length)) - return -ENOMEM; - - length += sl; - - envp[i] = NULL; - - return 0; -} - - EXPORT_SYMBOL(of_match_node); EXPORT_SYMBOL(of_match_device); EXPORT_SYMBOL(of_device_register); @@ -238,4 +127,3 @@ EXPORT_SYMBOL(of_device_unregister); EXPORT_SYMBOL(of_dev_get); EXPORT_SYMBOL(of_dev_put); EXPORT_SYMBOL(of_release_dev); -EXPORT_SYMBOL(of_device_uevent); diff --git a/trunk/arch/powerpc/kernel/of_platform.c b/trunk/arch/powerpc/kernel/of_platform.c index 908ed7926db4..b7345176b399 100644 --- a/trunk/arch/powerpc/kernel/of_platform.c +++ b/trunk/arch/powerpc/kernel/of_platform.c @@ -133,7 +133,6 @@ static int of_platform_device_resume(struct device * dev) struct bus_type of_platform_bus_type = { .name = "of_platform", .match = of_platform_bus_match, - .uevent = of_device_uevent, .probe = of_platform_device_probe, .remove = of_platform_device_remove, .suspend = of_platform_device_suspend, @@ -178,7 +177,7 @@ static void of_platform_make_bus_id(struct of_device *dev) * and 'D' for MMIO DCRs. */ #ifdef CONFIG_PPC_DCR - reg = of_get_property(node, "dcr-reg", NULL); + reg = get_property(node, "dcr-reg", NULL); if (reg) { #ifdef CONFIG_PPC_DCR_NATIVE snprintf(name, BUS_ID_SIZE, "d%x.%s", @@ -198,7 +197,7 @@ static void of_platform_make_bus_id(struct of_device *dev) /* * For MMIO, get the physical address */ - reg = of_get_property(node, "reg", NULL); + reg = get_property(node, "reg", NULL); if (reg) { addr = of_translate_address(node, reg); if (addr != OF_BAD_ADDR) { @@ -476,6 +475,9 @@ static struct of_platform_driver of_pci_phb_driver = { .name = "of-pci", .match_table = of_pci_phb_ids, .probe = of_pci_phb_probe, + .driver = { + .multithread_probe = 1, + }, }; static __init int of_pci_phb_init(void) diff --git a/trunk/arch/powerpc/kernel/pci_32.c b/trunk/arch/powerpc/kernel/pci_32.c index f022862de344..d8ef2e100505 100644 --- a/trunk/arch/powerpc/kernel/pci_32.c +++ b/trunk/arch/powerpc/kernel/pci_32.c @@ -637,7 +637,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus) if (pci_bus >= pci_bus_count) return; - bus_range = of_get_property(node, "bus-range", &len); + bus_range = get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, " "assuming it starts at 0\n", node->full_name); @@ -649,20 +649,17 @@ make_one_node_map(struct device_node* node, u8 pci_bus) struct pci_dev* dev; const unsigned int *class_code, *reg; - class_code = of_get_property(node, "class-code", NULL); + class_code = get_property(node, "class-code", NULL); if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) continue; - reg = of_get_property(node, "reg", NULL); + reg = get_property(node, "reg", NULL); if (!reg) continue; - dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff)); - if (!dev || !dev->subordinate) { - pci_dev_put(dev); + dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff)); + if (!dev || !dev->subordinate) continue; - } make_one_node_map(node, dev->subordinate->number); - pci_dev_put(dev); } } @@ -672,7 +669,6 @@ pcibios_make_OF_bus_map(void) int i; struct pci_controller* hose; struct property *map_prop; - struct device_node *dn; pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL); if (!pci_to_OF_bus_map) { @@ -694,13 +690,12 @@ pcibios_make_OF_bus_map(void) continue; make_one_node_map(node, hose->first_busno); } - dn = of_find_node_by_path("/"); - map_prop = of_find_property(dn, "pci-OF-bus-map", NULL); + map_prop = of_find_property(find_path_device("/"), + "pci-OF-bus-map", NULL); if (map_prop) { BUG_ON(pci_bus_count > map_prop->length); memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count); } - of_node_put(dn); #ifdef DEBUG printk("PCI->OF bus map:\n"); for (i=0; i> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && strcmp(node->name, "multifunc-device")) @@ -749,7 +744,7 @@ static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, unsigned int psize; while ((np = of_get_next_child(parent, np)) != NULL) { - reg = of_get_property(np, "reg", &psize); + reg = get_property(np, "reg", &psize); if (reg == NULL || psize < 4) continue; if (((reg[0] >> 8) & 0xff) == devfn) @@ -864,7 +859,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, find_OF_pci_device_filter, (void *)node)) return -ENODEV; - reg = of_get_property(node, "reg", NULL); + reg = get_property(node, "reg", NULL); if (!reg) return -ENODEV; *bus = (reg[0] >> 16) & 0xff; @@ -900,14 +895,14 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, int rlen = 0, orig_rlen; int memno = 0; struct resource *res; - int np, na = of_n_addr_cells(dev); + int np, na = prom_n_addr_cells(dev); np = na + 5; /* First we try to merge ranges to fix a problem with some pmacs * that can have more than 3 ranges, fortunately using contiguous * addresses -- BenH */ - dt_ranges = of_get_property(dev, "ranges", &rlen); + dt_ranges = get_property(dev, "ranges", &rlen); if (!dt_ranges) return; /* Sanity check, though hopefully that never happens */ @@ -1011,19 +1006,14 @@ void __init pci_create_OF_bus_map(void) { struct property* of_prop; - struct device_node *dn; - + of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256); - if (!of_prop) - return; - dn = of_find_node_by_path("/"); - if (dn) { + if (of_prop && find_path_device("/")) { memset(of_prop, -1, sizeof(struct property) + 256); of_prop->name = "pci-OF-bus-map"; of_prop->length = 256; - of_prop->value = &of_prop[1]; - prom_add_property(dn, of_prop); - of_node_put(dn); + of_prop->value = (unsigned char *)&of_prop[1]; + prom_add_property(find_path_device("/"), of_prop); } } diff --git a/trunk/arch/powerpc/kernel/pci_64.c b/trunk/arch/powerpc/kernel/pci_64.c index 7138092826aa..7e97d71a5f8f 100644 --- a/trunk/arch/powerpc/kernel/pci_64.c +++ b/trunk/arch/powerpc/kernel/pci_64.c @@ -61,7 +61,8 @@ void iSeries_pcibios_init(void); LIST_HEAD(hose_list); -static struct dma_mapping_ops *pci_dma_ops; +struct dma_mapping_ops *pci_dma_ops; +EXPORT_SYMBOL(pci_dma_ops); int global_phb_number; /* Global phb counter */ @@ -69,17 +70,6 @@ int global_phb_number; /* Global phb counter */ struct pci_dev *ppc64_isabridge_dev = NULL; EXPORT_SYMBOL_GPL(ppc64_isabridge_dev); -void set_pci_dma_ops(struct dma_mapping_ops *dma_ops) -{ - pci_dma_ops = dma_ops; -} - -struct dma_mapping_ops *get_pci_dma_ops(void) -{ - return pci_dma_ops; -} -EXPORT_SYMBOL(get_pci_dma_ops); - static void fixup_broken_pcnet32(struct pci_dev* dev) { if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { @@ -268,7 +258,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def) const u32 *prop; int len; - prop = of_get_property(np, name, &len); + prop = get_property(np, name, &len); if (prop && len >= 4) return *prop; return def; @@ -301,7 +291,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) u32 i; int proplen; - addrs = of_get_property(node, "assigned-addresses", &proplen); + addrs = get_property(node, "assigned-addresses", &proplen); if (!addrs) return; DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs); @@ -340,10 +330,10 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, struct pci_dev *dev; const char *type; - dev = alloc_pci_dev(); + dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) return NULL; - type = of_get_property(node, "device_type", NULL); + type = get_property(node, "device_type", NULL); if (type == NULL) type = ""; @@ -407,7 +397,7 @@ void __devinit of_scan_bus(struct device_node *node, while ((child = of_get_next_child(node, child)) != NULL) { DBG(" * %s\n", child->full_name); - reg = of_get_property(child, "reg", ®len); + reg = get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; devfn = (reg[0] >> 8) & 0xff; @@ -440,13 +430,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node, DBG("of_scan_pci_bridge(%s)\n", node->full_name); /* parse bus-range property */ - busrange = of_get_property(node, "bus-range", &len); + busrange = get_property(node, "bus-range", &len); if (busrange == NULL || len != 8) { printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", node->full_name); return; } - ranges = of_get_property(node, "ranges", &len); + ranges = get_property(node, "ranges", &len); if (ranges == NULL) { printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", node->full_name); @@ -910,7 +900,7 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, unsigned int size; int rlen = 0; - range = of_get_property(isa_node, "ranges", &rlen); + range = get_property(isa_node, "ranges", &rlen); if (range == NULL || (rlen < sizeof(struct isa_range))) { printk(KERN_ERR "no ISA ranges or unexpected isa range size," "mapping 64k\n"); @@ -957,7 +947,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, int rlen = 0; int memno = 0; struct resource *res; - int np, na = of_n_addr_cells(dev); + int np, na = prom_n_addr_cells(dev); unsigned long pci_addr, cpu_phys_addr; np = na + 5; @@ -970,7 +960,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, * (size depending on dev->n_addr_cells) * cells 4+5 or 5+6: the size of the range */ - ranges = of_get_property(dev, "ranges", &rlen); + ranges = get_property(dev, "ranges", &rlen); if (ranges == NULL) return; hose->io_base_phys = 0; diff --git a/trunk/arch/powerpc/kernel/pci_dn.c b/trunk/arch/powerpc/kernel/pci_dn.c index d7d36df9c053..68df018dae0e 100644 --- a/trunk/arch/powerpc/kernel/pci_dn.c +++ b/trunk/arch/powerpc/kernel/pci_dn.c @@ -40,8 +40,7 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data) { struct pci_controller *phb = data; - const int *type = - of_get_property(dn, "ibm,pci-config-space-type", NULL); + const int *type = get_property(dn, "ibm,pci-config-space-type", NULL); const u32 *regs; struct pci_dn *pdn; @@ -55,14 +54,14 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data) dn->data = pdn; pdn->node = dn; pdn->phb = phb; - regs = of_get_property(dn, "reg", NULL); + regs = get_property(dn, "reg", NULL); if (regs) { /* First register entry is addr (00BBSS00) */ pdn->busno = (regs[0] >> 16) & 0xff; pdn->devfn = (regs[0] >> 8) & 0xff; } if (firmware_has_feature(FW_FEATURE_ISERIES)) { - const u32 *busp = of_get_property(dn, "linux,subbus", NULL); + const u32 *busp = get_property(dn, "linux,subbus", NULL); if (busp) pdn->bussubno = *busp; } @@ -101,7 +100,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, u32 class; nextdn = NULL; - classp = of_get_property(dn, "class-code", NULL); + classp = get_property(dn, "class-code", NULL); class = classp ? *classp : 0; if (pre && ((ret = pre(dn, data)) != NULL)) diff --git a/trunk/arch/powerpc/kernel/ppc_ksyms.c b/trunk/arch/powerpc/kernel/ppc_ksyms.c index ff252aaead12..ecee596d28f6 100644 --- a/trunk/arch/powerpc/kernel/ppc_ksyms.c +++ b/trunk/arch/powerpc/kernel/ppc_ksyms.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,8 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcasecmp); +EXPORT_SYMBOL(strncasecmp); EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); diff --git a/trunk/arch/powerpc/kernel/process.c b/trunk/arch/powerpc/kernel/process.c index e509aae2feb3..e53b2988d1bf 100644 --- a/trunk/arch/powerpc/kernel/process.c +++ b/trunk/arch/powerpc/kernel/process.c @@ -305,7 +305,9 @@ struct task_struct *__switch_to(struct task_struct *prev, set_dabr(new->thread.dabr); __get_cpu_var(current_dabr) = new->thread.dabr; } -#endif /* CONFIG_PPC64 */ + + flush_tlb_pending(); +#endif new_thread = &new->thread; old_thread = ¤t->thread; @@ -400,11 +402,11 @@ static void printbits(unsigned long val, struct regbit *bits) } #ifdef CONFIG_PPC64 -#define REG "%016lx" +#define REG "%016lX" #define REGS_PER_LINE 4 #define LAST_VOLATILE 13 #else -#define REG "%08lx" +#define REG "%08lX" #define REGS_PER_LINE 8 #define LAST_VOLATILE 12 #endif @@ -419,7 +421,7 @@ void show_regs(struct pt_regs * regs) regs, regs->trap, print_tainted(), init_utsname()->release); printk("MSR: "REG" ", regs->msr); printbits(regs->msr, msr_bits); - printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); + printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer); trap = TRAP(regs); if (trap == 0x300 || trap == 0x600) printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); @@ -570,6 +572,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, kregs->nip = *((unsigned long *)ret_from_fork); #else kregs->nip = (unsigned long)ret_from_fork; + p->thread.last_syscall = -1; #endif return 0; @@ -820,35 +823,6 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, return error; } -#ifdef CONFIG_IRQSTACKS -static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, - unsigned long nbytes) -{ - unsigned long stack_page; - unsigned long cpu = task_cpu(p); - - /* - * Avoid crashing if the stack has overflowed and corrupted - * task_cpu(p), which is in the thread_info struct. - */ - if (cpu < NR_CPUS && cpu_possible(cpu)) { - stack_page = (unsigned long) hardirq_ctx[cpu]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - - stack_page = (unsigned long) softirq_ctx[cpu]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - } - return 0; -} - -#else -#define valid_irq_stack(sp, p, nb) 0 -#endif /* CONFIG_IRQSTACKS */ - int validate_sp(unsigned long sp, struct task_struct *p, unsigned long nbytes) { @@ -858,7 +832,19 @@ int validate_sp(unsigned long sp, struct task_struct *p, && sp <= stack_page + THREAD_SIZE - nbytes) return 1; - return valid_irq_stack(sp, p, nbytes); +#ifdef CONFIG_IRQSTACKS + stack_page = (unsigned long) hardirq_ctx[task_cpu(p)]; + if (sp >= stack_page + sizeof(struct thread_struct) + && sp <= stack_page + THREAD_SIZE - nbytes) + return 1; + + stack_page = (unsigned long) softirq_ctx[task_cpu(p)]; + if (sp >= stack_page + sizeof(struct thread_struct) + && sp <= stack_page + THREAD_SIZE - nbytes) + return 1; +#endif + + return 0; } #ifdef CONFIG_PPC64 diff --git a/trunk/arch/powerpc/kernel/prom.c b/trunk/arch/powerpc/kernel/prom.c index caef555f2dc0..8d52b23348bd 100644 --- a/trunk/arch/powerpc/kernel/prom.c +++ b/trunk/arch/powerpc/kernel/prom.c @@ -390,19 +390,18 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, if (allnextpp) { pp->name = "name"; pp->length = sz; - pp->value = pp + 1; + pp->value = (unsigned char *)(pp + 1); *prev_pp = pp; prev_pp = &pp->next; memcpy(pp->value, ps, sz - 1); ((char *)pp->value)[sz - 1] = 0; - DBG("fixed up name for %s -> %s\n", pathp, - (char *)pp->value); + DBG("fixed up name for %s -> %s\n", pathp, pp->value); } } if (allnextpp) { *prev_pp = NULL; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); + np->name = get_property(np, "name", NULL); + np->type = get_property(np, "device_type", NULL); if (!np->name) np->name = ""; @@ -720,7 +719,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { unsigned long *lprop; - u32 *prop; unsigned long l; char *p; @@ -762,22 +760,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, crashk_res.end = crashk_res.start + *lprop - 1; #endif -#ifdef CONFIG_BLK_DEV_INITRD - DBG("Looking for initrd properties... "); - prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); - if (prop) { - initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); - if (prop) { - initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } - DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end); -#endif /* CONFIG_BLK_DEV_INITRD */ - /* Retreive command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) @@ -944,12 +926,6 @@ static void __init early_reserve_mem(void) self_size = initial_boot_params->totalsize; lmb_reserve(self_base, self_size); -#ifdef CONFIG_BLK_DEV_INITRD - /* then reserve the initrd, if any */ - if (initrd_start && (initrd_end > initrd_start)) - lmb_reserve(__pa(initrd_start), initrd_end - initrd_start); -#endif /* CONFIG_BLK_DEV_INITRD */ - #ifdef CONFIG_PPC32 /* * Handle the case where we might be booting from an old kexec @@ -978,6 +954,9 @@ static void __init early_reserve_mem(void) size = *(reserve_map++); if (size == 0) break; + /* skip if the reservation is for the blob */ + if (base == self_base && size == self_size) + continue; DBG("reserving: %llx -> %llx\n", base, size); lmb_reserve(base, size); } @@ -1042,46 +1021,102 @@ void __init early_init_devtree(void *params) #undef printk -int of_n_addr_cells(struct device_node* np) +int +prom_n_addr_cells(struct device_node* np) { const int *ip; do { if (np->parent) np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); + ip = get_property(np, "#address-cells", NULL); if (ip != NULL) return *ip; } while (np->parent); /* No #address-cells property for the root node, default to 1 */ return 1; } -EXPORT_SYMBOL(of_n_addr_cells); +EXPORT_SYMBOL(prom_n_addr_cells); -int of_n_size_cells(struct device_node* np) +int +prom_n_size_cells(struct device_node* np) { const int* ip; do { if (np->parent) np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); + ip = get_property(np, "#size-cells", NULL); if (ip != NULL) return *ip; } while (np->parent); /* No #size-cells property for the root node, default to 1 */ return 1; } -EXPORT_SYMBOL(of_n_size_cells); +EXPORT_SYMBOL(prom_n_size_cells); + +/** + * Construct and return a list of the device_nodes with a given name. + */ +struct device_node *find_devices(const char *name) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->name != 0 && strcasecmp(np->name, name) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_devices); + +/** + * Construct and return a list of the device_nodes with a given type. + */ +struct device_node *find_type_devices(const char *type) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (np->type != 0 && strcasecmp(np->type, type) == 0) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_type_devices); + +/** + * Returns all nodes linked together + */ +struct device_node *find_all_nodes(void) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + *prevp = np; + prevp = &np->next; + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_all_nodes); /** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ -int of_device_is_compatible(const struct device_node *device, - const char *compat) +int device_is_compatible(const struct device_node *device, const char *compat) { const char* cp; int cplen, l; - cp = of_get_property(device, "compatible", &cplen); + cp = get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -1094,7 +1129,7 @@ int of_device_is_compatible(const struct device_node *device, return 0; } -EXPORT_SYMBOL(of_device_is_compatible); +EXPORT_SYMBOL(device_is_compatible); /** @@ -1108,13 +1143,51 @@ int machine_is_compatible(const char *compat) root = of_find_node_by_path("/"); if (root) { - rc = of_device_is_compatible(root, compat); + rc = device_is_compatible(root, compat); of_node_put(root); } return rc; } EXPORT_SYMBOL(machine_is_compatible); +/** + * Construct and return a list of the device_nodes with a given type + * and compatible property. + */ +struct device_node *find_compatible_devices(const char *type, + const char *compat) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + if (type != NULL + && !(np->type != 0 && strcasecmp(np->type, type) == 0)) + continue; + if (device_is_compatible(np, compat)) { + *prevp = np; + prevp = &np->next; + } + } + *prevp = NULL; + return head; +} +EXPORT_SYMBOL(find_compatible_devices); + +/** + * Find the device_node with a given full_name. + */ +struct device_node *find_path_device(const char *path) +{ + struct device_node *np; + + for (np = allnodes; np != 0; np = np->allnext) + if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) + return np; + return NULL; +} +EXPORT_SYMBOL(find_path_device); + /******* * * New implementation of the OF "find" APIs, return a refcounted @@ -1207,7 +1280,7 @@ struct device_node *of_find_compatible_node(struct device_node *from, if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; - if (of_device_is_compatible(np, compatible) && of_node_get(np)) + if (device_is_compatible(np, compatible) && of_node_get(np)) break; } of_node_put(from); @@ -1454,8 +1527,8 @@ static int of_finish_dynamic_node(struct device_node *node) int err = 0; const phandle *ibm_phandle; - node->name = of_get_property(node, "name", NULL); - node->type = of_get_property(node, "device_type", NULL); + node->name = get_property(node, "name", NULL); + node->type = get_property(node, "device_type", NULL); if (!parent) { err = -ENODEV; @@ -1469,7 +1542,7 @@ static int of_finish_dynamic_node(struct device_node *node) return -ENODEV; /* fix up new node's linux_phandle field */ - if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL))) + if ((ibm_phandle = get_property(node, "ibm,phandle", NULL))) node->linux_phandle = *ibm_phandle; out: @@ -1532,13 +1605,13 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -const void *of_get_property(const struct device_node *np, const char *name, +const void *get_property(const struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; } -EXPORT_SYMBOL(of_get_property); +EXPORT_SYMBOL(get_property); /* * Add a property to a node @@ -1669,10 +1742,10 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist * fallback to "reg" property and assume no threads */ - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", + intserv = get_property(np, "ibm,ppc-interrupt-server#s", &plen); if (intserv == NULL) { - const u32 *reg = of_get_property(np, "reg", NULL); + const u32 *reg = get_property(np, "reg", NULL); if (reg == NULL) continue; if (*reg == hardid) { diff --git a/trunk/arch/powerpc/kernel/prom_init.c b/trunk/arch/powerpc/kernel/prom_init.c index e27d9d1b6e67..4fb5938ce6d3 100644 --- a/trunk/arch/powerpc/kernel/prom_init.c +++ b/trunk/arch/powerpc/kernel/prom_init.c @@ -2035,50 +2035,39 @@ static void __init fixup_device_tree_maple(void) #endif #ifdef CONFIG_PPC_CHRP -/* - * Pegasos and BriQ lacks the "ranges" property in the isa node - * Pegasos needs decimal IRQ 14/15, not hexadecimal - */ +/* Pegasos and BriQ lacks the "ranges" property in the isa node */ static void __init fixup_device_tree_chrp(void) { - phandle ph; - u32 prop[6]; + phandle isa; + u32 isa_ranges[6]; u32 rloc = 0x01006000; /* IO space; PCI device = 12 */ char *name; int rc; name = "/pci@80000000/isa@c"; - ph = call_prom("finddevice", 1, 1, ADDR(name)); - if (!PHANDLE_VALID(ph)) { + isa = call_prom("finddevice", 1, 1, ADDR(name)); + if (!PHANDLE_VALID(isa)) { name = "/pci@ff500000/isa@6"; - ph = call_prom("finddevice", 1, 1, ADDR(name)); + isa = call_prom("finddevice", 1, 1, ADDR(name)); rloc = 0x01003000; /* IO space; PCI device = 6 */ } - if (PHANDLE_VALID(ph)) { - rc = prom_getproplen(ph, "ranges"); - if (rc == 0 || rc == PROM_ERROR) { - prom_printf("Fixing up missing ISA range on Pegasos...\n"); - - prop[0] = 0x1; - prop[1] = 0x0; - prop[2] = rloc; - prop[3] = 0x0; - prop[4] = 0x0; - prop[5] = 0x00010000; - prom_setprop(ph, name, "ranges", prop, sizeof(prop)); - } - } + if (!PHANDLE_VALID(isa)) + return; - name = "/pci@80000000/ide@C,1"; - ph = call_prom("finddevice", 1, 1, ADDR(name)); - if (PHANDLE_VALID(ph)) { - prom_printf("Fixing up IDE interrupt on Pegasos...\n"); - prop[0] = 14; - prop[1] = 0x0; - prop[2] = 15; - prop[3] = 0x0; - prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32)); - } + rc = prom_getproplen(isa, "ranges"); + if (rc != 0 && rc != PROM_ERROR) + return; + + prom_printf("Fixing up missing ISA range on Pegasos...\n"); + + isa_ranges[0] = 0x1; + isa_ranges[1] = 0x0; + isa_ranges[2] = rloc; + isa_ranges[3] = 0x0; + isa_ranges[4] = 0x0; + isa_ranges[5] = 0x00010000; + prom_setprop(isa, name, "ranges", + isa_ranges, sizeof(isa_ranges)); } #else #define fixup_device_tree_chrp() diff --git a/trunk/arch/powerpc/kernel/prom_parse.c b/trunk/arch/powerpc/kernel/prom_parse.c index aa40a5307294..91b443c9a488 100644 --- a/trunk/arch/powerpc/kernel/prom_parse.c +++ b/trunk/arch/powerpc/kernel/prom_parse.c @@ -68,9 +68,9 @@ static void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec) { if (addrc) - *addrc = of_n_addr_cells(dev); + *addrc = prom_n_addr_cells(dev); if (sizec) - *sizec = of_n_size_cells(dev); + *sizec = prom_n_size_cells(dev); } static u64 of_bus_default_map(u32 *addr, const u32 *range, @@ -196,7 +196,7 @@ const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, return NULL; /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, &psize); + prop = get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL; psize /= 4; @@ -438,7 +438,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * to translate addresses that aren't supposed to be translated in * the first place. --BenH. */ - ranges = of_get_property(parent, "ranges", &rlen); + ranges = get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { offset = of_read_number(addr, na); memset(addr, 0, pna * 4); @@ -578,7 +578,7 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, return NULL; /* Get "reg" or "assigned-addresses" property */ - prop = of_get_property(dev, bus->addresses, &psize); + prop = get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL; psize /= 4; @@ -650,17 +650,17 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, /* busno is always one cell */ *busno = *(dma_window++); - prop = of_get_property(dn, "ibm,#dma-address-cells", NULL); + prop = get_property(dn, "ibm,#dma-address-cells", NULL); if (!prop) - prop = of_get_property(dn, "#address-cells", NULL); + prop = get_property(dn, "#address-cells", NULL); - cells = prop ? *(u32 *)prop : of_n_addr_cells(dn); + cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn); *phys = of_read_number(dma_window, cells); dma_window += cells; - prop = of_get_property(dn, "ibm,#dma-size-cells", NULL); - cells = prop ? *(u32 *)prop : of_n_size_cells(dn); + prop = get_property(dn, "ibm,#dma-size-cells", NULL); + cells = prop ? *(u32 *)prop : prom_n_size_cells(dn); *size = of_read_number(dma_window, cells); } @@ -680,7 +680,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child) return NULL; do { - parp = of_get_property(child, "interrupt-parent", NULL); + parp = get_property(child, "interrupt-parent", NULL); if (parp == NULL) p = of_get_parent(child); else { @@ -691,7 +691,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child) } of_node_put(child); child = p; - } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); + } while (p && get_property(p, "#interrupt-cells", NULL) == NULL); return p; } @@ -716,7 +716,7 @@ void of_irq_map_init(unsigned int flags) struct device_node *np; for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) { - if (of_get_property(np, "interrupt-controller", NULL) + if (get_property(np, "interrupt-controller", NULL) == NULL) continue; /* Skip /chosen/interrupt-controller */ @@ -755,7 +755,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, * is none, we are nice and just walk up the tree */ do { - tmp = of_get_property(ipar, "#interrupt-cells", NULL); + tmp = get_property(ipar, "#interrupt-cells", NULL); if (tmp != NULL) { intsize = *tmp; break; @@ -779,7 +779,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, */ old = of_node_get(ipar); do { - tmp = of_get_property(old, "#address-cells", NULL); + tmp = get_property(old, "#address-cells", NULL); tnode = of_get_parent(old); of_node_put(old); old = tnode; @@ -795,8 +795,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, /* Now check if cursor is an interrupt-controller and if it is * then we are done */ - if (of_get_property(ipar, "interrupt-controller", NULL) != - NULL) { + if (get_property(ipar, "interrupt-controller", NULL) != NULL) { DBG(" -> got it !\n"); memcpy(out_irq->specifier, intspec, intsize * sizeof(u32)); @@ -807,7 +806,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, } /* Now look for an interrupt-map */ - imap = of_get_property(ipar, "interrupt-map", &imaplen); + imap = get_property(ipar, "interrupt-map", &imaplen); /* No interrupt map, check for an interrupt parent */ if (imap == NULL) { DBG(" -> no map, getting parent\n"); @@ -817,7 +816,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, imaplen /= sizeof(u32); /* Look for a mask */ - imask = of_get_property(ipar, "interrupt-map-mask", NULL); + imask = get_property(ipar, "interrupt-map-mask", NULL); /* If we were passed no "reg" property and we attempt to parse * an interrupt-map, then #address-cells must be 0. @@ -864,13 +863,15 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, /* Get #interrupt-cells and #address-cells of new * parent */ - tmp = of_get_property(newpar, "#interrupt-cells", NULL); + tmp = get_property(newpar, "#interrupt-cells", + NULL); if (tmp == NULL) { DBG(" -> parent lacks #interrupt-cells !\n"); goto fail; } newintsize = *tmp; - tmp = of_get_property(newpar, "#address-cells", NULL); + tmp = get_property(newpar, "#address-cells", + NULL); newaddrsize = (tmp == NULL) ? 0 : *tmp; DBG(" -> newintsize=%d, newaddrsize=%d\n", @@ -927,7 +928,7 @@ static int of_irq_map_oldworld(struct device_node *device, int index, * everything together on these) */ while (device) { - ints = of_get_property(device, "AAPL,interrupts", &intlen); + ints = get_property(device, "AAPL,interrupts", &intlen); if (ints != NULL) break; device = device->parent; @@ -969,13 +970,13 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq return of_irq_map_oldworld(device, index, out_irq); /* Get the interrupts property */ - intspec = of_get_property(device, "interrupts", &intlen); + intspec = get_property(device, "interrupts", &intlen); if (intspec == NULL) return -EINVAL; intlen /= sizeof(u32); /* Get the reg property (if any) */ - addr = of_get_property(device, "reg", NULL); + addr = get_property(device, "reg", NULL); /* Look for the interrupt parent. */ p = of_irq_find_parent(device); @@ -983,7 +984,7 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq return -EINVAL; /* Get size of interrupt specifier */ - tmp = of_get_property(p, "#interrupt-cells", NULL); + tmp = get_property(p, "#interrupt-cells", NULL); if (tmp == NULL) { of_node_put(p); return -EINVAL; diff --git a/trunk/arch/powerpc/kernel/rtas-proc.c b/trunk/arch/powerpc/kernel/rtas-proc.c index 190b7ed1dbfb..6cbf2ae5d7aa 100644 --- a/trunk/arch/powerpc/kernel/rtas-proc.c +++ b/trunk/arch/powerpc/kernel/rtas-proc.c @@ -450,7 +450,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v) int llen, offs; sprintf (rstr, SENSOR_PREFIX"%04d", p->token); - loc = of_get_property(rtas_node, rstr, &llen); + loc = get_property(rtas_node, rstr, &llen); /* A sensor may have multiple instances */ for (j = 0, offs = 0; j <= p->quant; j++) { @@ -477,7 +477,7 @@ static int ppc_rtas_find_all_sensors(void) const unsigned int *utmp; int len, i; - utmp = of_get_property(rtas_node, "rtas-sensors", &len); + utmp = get_property(rtas_node, "rtas-sensors", &len); if (utmp == NULL) { printk (KERN_ERR "error: could not get rtas-sensors\n"); return 1; diff --git a/trunk/arch/powerpc/kernel/rtas.c b/trunk/arch/powerpc/kernel/rtas.c index 214780798289..9d0735a54564 100644 --- a/trunk/arch/powerpc/kernel/rtas.c +++ b/trunk/arch/powerpc/kernel/rtas.c @@ -192,19 +192,18 @@ void rtas_progress(char *s, unsigned short hex) if (display_width == 0) { display_width = 0x10; - if ((root = of_find_node_by_path("/rtas"))) { - if ((p = of_get_property(root, + if ((root = find_path_device("/rtas"))) { + if ((p = get_property(root, "ibm,display-line-length", NULL))) display_width = *p; - if ((p = of_get_property(root, + if ((p = get_property(root, "ibm,form-feed", NULL))) form_feed = *p; - if ((p = of_get_property(root, + if ((p = get_property(root, "ibm,display-number-of-lines", NULL))) display_lines = *p; - row_width = of_get_property(root, + row_width = get_property(root, "ibm,display-truncation-length", NULL); - of_node_put(root); } display_character = rtas_token("display-character"); set_indicator = rtas_token("set-indicator"); @@ -299,7 +298,7 @@ int rtas_token(const char *service) const int *tokp; if (rtas.dev == NULL) return RTAS_UNKNOWN_SERVICE; - tokp = of_get_property(rtas.dev, service, NULL); + tokp = get_property(rtas.dev, service, NULL); return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; } EXPORT_SYMBOL(rtas_token); @@ -833,12 +832,12 @@ void __init rtas_initialize(void) if (rtas.dev) { const u32 *basep, *entryp, *sizep; - basep = of_get_property(rtas.dev, "linux,rtas-base", NULL); - sizep = of_get_property(rtas.dev, "rtas-size", NULL); + basep = get_property(rtas.dev, "linux,rtas-base", NULL); + sizep = get_property(rtas.dev, "rtas-size", NULL); if (basep != NULL && sizep != NULL) { rtas.base = *basep; rtas.size = *sizep; - entryp = of_get_property(rtas.dev, + entryp = get_property(rtas.dev, "linux,rtas-entry", NULL); if (entryp == NULL) /* Ugh */ rtas.entry = rtas.base; diff --git a/trunk/arch/powerpc/kernel/rtas_pci.c b/trunk/arch/powerpc/kernel/rtas_pci.c index f2286822be09..ace9f4c86e67 100644 --- a/trunk/arch/powerpc/kernel/rtas_pci.c +++ b/trunk/arch/powerpc/kernel/rtas_pci.c @@ -60,7 +60,7 @@ static int of_device_available(struct device_node * dn) { const char *status; - status = of_get_property(dn, "status", NULL); + status = get_property(dn, "status", NULL); if (!status) return 1; @@ -177,7 +177,7 @@ struct pci_ops rtas_pci_ops = { int is_python(struct device_node *dev) { - const char *model = of_get_property(dev, "model", NULL); + const char *model = get_property(dev, "model", NULL); if (model && strstr(model, "Python")) return 1; @@ -247,7 +247,7 @@ static int phb_set_bus_ranges(struct device_node *dev, const int *bus_range; unsigned int len; - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { return 1; } @@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_controller *phb) return 0; } -void __init find_and_init_phbs(void) +unsigned long __init find_and_init_phbs(void) { struct device_node *node; struct pci_controller *phb; @@ -309,16 +309,18 @@ void __init find_and_init_phbs(void) if (of_chosen) { const int *prop; - prop = of_get_property(of_chosen, + prop = get_property(of_chosen, "linux,pci-probe-only", NULL); if (prop) pci_probe_only = *prop; - prop = of_get_property(of_chosen, + prop = get_property(of_chosen, "linux,pci-assign-all-buses", NULL); if (prop) pci_assign_all_buses = *prop; } + + return 0; } /* RPA-specific bits for removing PHBs */ diff --git a/trunk/arch/powerpc/kernel/setup-common.c b/trunk/arch/powerpc/kernel/setup-common.c index 370803722e47..89cfaf49d3de 100644 --- a/trunk/arch/powerpc/kernel/setup-common.c +++ b/trunk/arch/powerpc/kernel/setup-common.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -303,8 +304,26 @@ struct seq_operations cpuinfo_op = { void __init check_for_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD - DBG(" -> check_for_initrd() initrd_start=0x%lx initrd_end=0x%lx\n", - initrd_start, initrd_end); + const unsigned int *prop; + int len; + + DBG(" -> check_for_initrd()\n"); + + if (of_chosen) { + prop = get_property(of_chosen, "linux,initrd-start", &len); + if (prop != NULL) { + initrd_start = (unsigned long) + __va(of_read_ulong(prop, len / 4)); + prop = get_property(of_chosen, + "linux,initrd-end", &len); + if (prop != NULL) { + initrd_end = (unsigned long) + __va(of_read_ulong(prop, len / 4)); + initrd_below_start_ok = 1; + } else + initrd_start = 0; + } + } /* If we were passed an initrd, set the ROOT_DEV properly if the values * look sensible. If not, clear initrd reference. @@ -352,12 +371,11 @@ void __init smp_setup_cpu_maps(void) const int *intserv; int j, len = sizeof(u32), nthreads = 1; - intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", - &len); + intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len); if (intserv) nthreads = len / sizeof(int); else { - intserv = of_get_property(dn, "reg", NULL); + intserv = get_property(dn, "reg", NULL); if (!intserv) intserv = &cpu; /* assume logical == phys */ } @@ -380,10 +398,10 @@ void __init smp_setup_cpu_maps(void) int num_addr_cell, num_size_cell, maxcpus; const unsigned int *ireg; - num_addr_cell = of_n_addr_cells(dn); - num_size_cell = of_n_size_cells(dn); + num_addr_cell = prom_n_addr_cells(dn); + num_size_cell = prom_n_size_cells(dn); - ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL); + ireg = get_property(dn, "ibm,lrdr-capacity", NULL); if (!ireg) goto out; @@ -478,39 +496,11 @@ void probe_machine(void) printk(KERN_INFO "Using %s machine description\n", ppc_md.name); } -/* Match a class of boards, not a specific device configuration. */ int check_legacy_ioport(unsigned long base_port) { - struct device_node *parent, *np = NULL; - int ret = -ENODEV; - - switch(base_port) { - case I8042_DATA_REG: - np = of_find_node_by_type(NULL, "8042"); - break; - case FDC_BASE: /* FDC1 */ - np = of_find_node_by_type(NULL, "fdc"); - break; -#ifdef CONFIG_PPC_PREP - case _PIDXR: - case _PNPWRP: - case PNPBIOS_BASE: - /* implement me */ -#endif - default: - /* ipmi is supposed to fail here */ - break; - } - if (!np) - return ret; - parent = of_get_parent(np); - if (parent) { - if (strcmp(parent->type, "isa") == 0) - ret = 0; - of_node_put(parent); - } - of_node_put(np); - return ret; + if (ppc_md.check_legacy_ioport == NULL) + return 0; + return ppc_md.check_legacy_ioport(base_port); } EXPORT_SYMBOL(check_legacy_ioport); diff --git a/trunk/arch/powerpc/kernel/setup_32.c b/trunk/arch/powerpc/kernel/setup_32.c index 35f8f443c14f..44a6a3c47feb 100644 --- a/trunk/arch/powerpc/kernel/setup_32.c +++ b/trunk/arch/powerpc/kernel/setup_32.c @@ -92,8 +92,7 @@ unsigned long __init early_init(unsigned long dt_ptr) /* First zero the BSS -- use memset_io, some platforms don't have * caches on yet */ - memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, - __bss_stop - __bss_start); + memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start); /* * Identify the CPU type and fix up code sections @@ -196,22 +195,18 @@ EXPORT_SYMBOL(nvram_sync); #endif /* CONFIG_NVRAM */ -static DEFINE_PER_CPU(struct cpu, cpu_devices); +static struct cpu cpu_devices[NR_CPUS]; int __init ppc_init(void) { - int cpu; + int i; /* clear the progress line */ - if (ppc_md.progress) - ppc_md.progress(" ", 0xffff); + if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); /* register CPU devices */ - for_each_possible_cpu(cpu) { - struct cpu *c = &per_cpu(cpu_devices, cpu); - c->hotpluggable = 1; - register_cpu(c, cpu); - } + for_each_possible_cpu(i) + register_cpu(&cpu_devices[i], i); /* call platform init */ if (ppc_md.init != NULL) { diff --git a/trunk/arch/powerpc/kernel/setup_64.c b/trunk/arch/powerpc/kernel/setup_64.c index 6018178708a5..3733de30e84d 100644 --- a/trunk/arch/powerpc/kernel/setup_64.c +++ b/trunk/arch/powerpc/kernel/setup_64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -109,7 +110,7 @@ static void check_smt_enabled(void) dn = of_find_node_by_path("/options"); if (dn) { - smt_option = of_get_property(dn, "ibm,smt-enabled", NULL); + smt_option = get_property(dn, "ibm,smt-enabled", NULL); if (smt_option) { if (!strcmp(smt_option, "on")) @@ -304,10 +305,10 @@ static void __init initialize_cache_info(void) size = 0; lsize = cur_cpu_spec->dcache_bsize; - sizep = of_get_property(np, "d-cache-size", NULL); + sizep = get_property(np, "d-cache-size", NULL); if (sizep != NULL) size = *sizep; - lsizep = of_get_property(np, dc, NULL); + lsizep = get_property(np, dc, NULL); if (lsizep != NULL) lsize = *lsizep; if (sizep == 0 || lsizep == 0) @@ -321,10 +322,10 @@ static void __init initialize_cache_info(void) size = 0; lsize = cur_cpu_spec->icache_bsize; - sizep = of_get_property(np, "i-cache-size", NULL); + sizep = get_property(np, "i-cache-size", NULL); if (sizep != NULL) size = *sizep; - lsizep = of_get_property(np, ic, NULL); + lsizep = get_property(np, ic, NULL); if (lsizep != NULL) lsize = *lsizep; if (sizep == 0 || lsizep == 0) @@ -582,14 +583,14 @@ void __init setup_per_cpu_areas(void) char *ptr; /* Copy section for each CPU (we discard the original) */ - size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE); + size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); #ifdef CONFIG_MODULES if (size < PERCPU_ENOUGH_ROOM) size = PERCPU_ENOUGH_ROOM; #endif for_each_possible_cpu(i) { - ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); + ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size); if (!ptr) panic("Cannot allocate cpu data for CPU %d\n", i); diff --git a/trunk/arch/powerpc/kernel/smp.c b/trunk/arch/powerpc/kernel/smp.c index d8e503b2e1af..924d692bc8f9 100644 --- a/trunk/arch/powerpc/kernel/smp.c +++ b/trunk/arch/powerpc/kernel/smp.c @@ -428,6 +428,10 @@ void generic_mach_cpu_die(void) smp_wmb(); while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) cpu_relax(); + +#ifdef CONFIG_PPC64 + flush_tlb_pending(); +#endif cpu_set(cpu, cpu_online_map); local_irq_enable(); } diff --git a/trunk/arch/powerpc/kernel/suspend.c b/trunk/arch/powerpc/kernel/suspend.c deleted file mode 100644 index 8cee57107541..000000000000 --- a/trunk/arch/powerpc/kernel/suspend.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Suspend support specific for power. - * - * Distribute under GPLv2 - * - * Copyright (c) 2002 Pavel Machek - * Copyright (c) 2001 Patrick Mochel - */ - -#include - -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - -/* - * pfn_is_nosave - check if given pfn is in the 'nosave' section - */ - -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; - unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; - return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); -} diff --git a/trunk/arch/powerpc/kernel/sys_ppc32.c b/trunk/arch/powerpc/kernel/sys_ppc32.c index 047246ad4f65..673e8d9df7f5 100644 --- a/trunk/arch/powerpc/kernel/sys_ppc32.c +++ b/trunk/arch/powerpc/kernel/sys_ppc32.c @@ -53,6 +53,10 @@ #include #include +/* readdir & getdents */ +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) +#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) + struct old_linux_dirent32 { u32 d_ino; u32 d_offset; diff --git a/trunk/arch/powerpc/kernel/sysfs.c b/trunk/arch/powerpc/kernel/sysfs.c index 933e214c33e8..d57818aea081 100644 --- a/trunk/arch/powerpc/kernel/sysfs.c +++ b/trunk/arch/powerpc/kernel/sysfs.c @@ -66,17 +66,16 @@ static int __init smt_setup(void) if (!cpu_has_feature(CPU_FTR_SMT)) return -ENODEV; - options = of_find_node_by_path("/options"); + options = find_path_device("/options"); if (!options) return -ENODEV; - val = of_get_property(options, "ibm,smt-snooze-delay", NULL); + val = get_property(options, "ibm,smt-snooze-delay", NULL); if (!smt_snooze_cmdline && val) { for_each_possible_cpu(cpu) per_cpu(smt_snooze_delay, cpu) = *val; } - of_node_put(options); return 0; } __initcall(smt_setup); @@ -190,12 +189,12 @@ SYSFS_PMCSETUP(purr, SPRN_PURR); SYSFS_PMCSETUP(spurr, SPRN_SPURR); SYSFS_PMCSETUP(dscr, SPRN_DSCR); -SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0); -SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1); -SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2); -SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); -SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); -SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); +SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0); +SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1); +SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2); +SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3); +SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4); +SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5); static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); diff --git a/trunk/arch/powerpc/kernel/time.c b/trunk/arch/powerpc/kernel/time.c index 7cedef8f5f70..f6f0c6b07c4c 100644 --- a/trunk/arch/powerpc/kernel/time.c +++ b/trunk/arch/powerpc/kernel/time.c @@ -834,7 +834,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val) cpu = of_find_node_by_type(NULL, "cpu"); if (cpu) { - fp = of_get_property(cpu, name, NULL); + fp = get_property(cpu, name, NULL); if (fp) { found = 1; *val = of_read_ulong(fp, cells); diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index f7862224fe85..17724fb2067f 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -90,11 +90,21 @@ EXPORT_SYMBOL(unregister_die_notifier); * Trap & Exception support */ -#ifdef CONFIG_PMAC_BACKLIGHT -static void pmac_backlight_unblank(void) +static DEFINE_SPINLOCK(die_lock); + +int die(const char *str, struct pt_regs *regs, long err) { + static int die_counter; + + if (debugger(regs)) + return 1; + + console_verbose(); + spin_lock_irq(&die_lock); + bust_spinlocks(1); +#ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); - if (pmac_backlight) { + if (machine_is(powermac) && pmac_backlight) { struct backlight_properties *props; props = &pmac_backlight->props; @@ -103,67 +113,26 @@ static void pmac_backlight_unblank(void) backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); -} -#else -static inline void pmac_backlight_unblank(void) { } #endif - -int die(const char *str, struct pt_regs *regs, long err) -{ - static struct { - spinlock_t lock; - u32 lock_owner; - int lock_owner_depth; - } die = { - .lock = __SPIN_LOCK_UNLOCKED(die.lock), - .lock_owner = -1, - .lock_owner_depth = 0 - }; - static int die_counter; - unsigned long flags; - - if (debugger(regs)) - return 1; - - oops_enter(); - - if (die.lock_owner != raw_smp_processor_id()) { - console_verbose(); - spin_lock_irqsave(&die.lock, flags); - die.lock_owner = smp_processor_id(); - die.lock_owner_depth = 0; - bust_spinlocks(1); - if (machine_is(powermac)) - pmac_backlight_unblank(); - } else { - local_save_flags(flags); - } - - if (++die.lock_owner_depth < 3) { - printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); + printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT - printk("PREEMPT "); + printk("PREEMPT "); #endif #ifdef CONFIG_SMP - printk("SMP NR_CPUS=%d ", NR_CPUS); + printk("SMP NR_CPUS=%d ", NR_CPUS); #endif #ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC "); + printk("DEBUG_PAGEALLOC "); #endif #ifdef CONFIG_NUMA - printk("NUMA "); + printk("NUMA "); #endif - printk("%s\n", ppc_md.name ? ppc_md.name : ""); - - print_modules(); - show_regs(regs); - } else { - printk("Recursive die() failure, output suppressed\n"); - } + printk("%s\n", ppc_md.name ? "" : ppc_md.name); + print_modules(); + show_regs(regs); bust_spinlocks(0); - die.lock_owner = -1; - spin_unlock_irqrestore(&die.lock, flags); + spin_unlock_irq(&die_lock); if (kexec_should_crash(current) || kexec_sr_activated(smp_processor_id())) @@ -176,7 +145,6 @@ int die(const char *str, struct pt_regs *regs, long err) if (panic_on_oops) panic("Fatal exception"); - oops_exit(); do_exit(err); return 0; diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c index b2c1b67a10a7..2968ffeafdb6 100644 --- a/trunk/arch/powerpc/kernel/vio.c +++ b/trunk/arch/powerpc/kernel/vio.c @@ -37,7 +37,7 @@ #include #include -extern struct kset devices_subsys; /* needed for vio_find_name() */ +extern struct subsystem devices_subsys; /* needed for vio_find_name() */ static struct vio_dev vio_bus_device = { /* fake "parent" device */ .name = vio_bus_device.dev.bus_id, @@ -81,7 +81,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) struct iommu_table *tbl; unsigned long offset, size; - dma_window = of_get_property(dev->dev.archdata.of_node, + dma_window = get_property(dev->dev.archdata.of_node, "ibm,my-dma-window", NULL); if (!dma_window) return NULL; @@ -226,7 +226,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) return NULL; } - unit_address = of_get_property(of_node, "reg", NULL); + unit_address = get_property(of_node, "reg", NULL); if (unit_address == NULL) { printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, @@ -246,7 +246,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) viodev->type = of_node->type; viodev->unit_address = *unit_address; if (firmware_has_feature(FW_FEATURE_ISERIES)) { - unit_address = of_get_property(of_node, + unit_address = get_property(of_node, "linux,unit_address", NULL); if (unit_address != NULL) viodev->unit_address = *unit_address; @@ -308,7 +308,7 @@ static int __init vio_bus_init(void) return err; } - node_vroot = of_find_node_by_name(NULL, "vdevice"); + node_vroot = find_devices("vdevice"); if (node_vroot) { struct device_node *of_node; @@ -322,7 +322,6 @@ static int __init vio_bus_init(void) __FUNCTION__, of_node); vio_register_device_node(of_node); } - of_node_put(node_vroot); } return 0; @@ -378,7 +377,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, dn = dev->archdata.of_node; if (!dn) return -ENODEV; - cp = of_get_property(dn, "compatible", &length); + cp = get_property(dn, "compatible", &length); if (!cp) return -ENODEV; @@ -407,12 +406,12 @@ struct bus_type vio_bus_type = { * @which: The property/attribute to be extracted. * @length: Pointer to length of returned data size (unused if NULL). * - * Calls prom.c's of_get_property() to return the value of the + * Calls prom.c's get_property() to return the value of the * attribute specified by @which */ const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) { - return of_get_property(vdev->dev.archdata.of_node, which, length); + return get_property(vdev->dev.archdata.of_node, which, length); } EXPORT_SYMBOL(vio_get_attribute); @@ -427,7 +426,7 @@ static struct vio_dev *vio_find_name(const char *kobj_name) { struct kobject *found; - found = kset_find_obj(&devices_subsys, kobj_name); + found = kset_find_obj(&devices_subsys.kset, kobj_name); if (!found) return NULL; @@ -444,7 +443,7 @@ struct vio_dev *vio_find_node(struct device_node *vnode) char kobj_name[BUS_ID_SIZE]; /* construct the kobject name from the device node */ - unit_address = of_get_property(vnode, "reg", NULL); + unit_address = get_property(vnode, "reg", NULL); if (!unit_address) return NULL; snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); diff --git a/trunk/arch/powerpc/kernel/vmlinux.lds.S b/trunk/arch/powerpc/kernel/vmlinux.lds.S index 132067313147..7eefeb4a30e7 100644 --- a/trunk/arch/powerpc/kernel/vmlinux.lds.S +++ b/trunk/arch/powerpc/kernel/vmlinux.lds.S @@ -139,7 +139,11 @@ SECTIONS __initramfs_end = .; } #endif - . = ALIGN(PAGE_SIZE); +#ifdef CONFIG_PPC32 + . = ALIGN(32); +#else + . = ALIGN(128); +#endif .data.percpu : { __per_cpu_start = .; *(.data.percpu) diff --git a/trunk/arch/powerpc/lib/Makefile b/trunk/arch/powerpc/lib/Makefile index 450258de7ca1..4b1ba49fbd9e 100644 --- a/trunk/arch/powerpc/lib/Makefile +++ b/trunk/arch/powerpc/lib/Makefile @@ -7,12 +7,13 @@ EXTRA_CFLAGS += -mno-minimal-toc endif ifeq ($(CONFIG_PPC_MERGE),y) -obj-y := string.o +obj-y := string.o strcase.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o endif obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ - memcpy_64.o usercopy_64.o mem_64.o string.o + memcpy_64.o usercopy_64.o mem_64.o string.o \ + strcase.o obj-$(CONFIG_QUICC_ENGINE) += rheap.o obj-$(CONFIG_XMON) += sstep.o obj-$(CONFIG_KPROBES) += sstep.o diff --git a/trunk/arch/powerpc/lib/copyuser_64.S b/trunk/arch/powerpc/lib/copyuser_64.S index 25ec5378afa4..a6b54cb97c49 100644 --- a/trunk/arch/powerpc/lib/copyuser_64.S +++ b/trunk/arch/powerpc/lib/copyuser_64.S @@ -24,7 +24,7 @@ _GLOBAL(__copy_tofrom_user) dcbt 0,r4 beq .Lcopy_page_4K andi. r6,r6,7 - PPC_MTOCRF 0x01,r5 + mtcrf 0x01,r5 blt cr1,.Lshort_copy bne .Ldst_unaligned .Ldst_aligned: @@ -135,7 +135,7 @@ _GLOBAL(__copy_tofrom_user) b .Ldo_tail .Ldst_unaligned: - PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */ + mtcrf 0x01,r6 /* put #bytes to 8B bdry into cr7 */ subf r5,r6,r5 li r7,0 cmpldi r1,r5,16 @@ -150,7 +150,7 @@ _GLOBAL(__copy_tofrom_user) 2: bf cr7*4+1,3f 37: lwzx r0,r7,r4 83: stwx r0,r7,r3 -3: PPC_MTOCRF 0x01,r5 +3: mtcrf 0x01,r5 add r4,r6,r4 add r3,r6,r3 b .Ldst_aligned diff --git a/trunk/arch/powerpc/lib/locks.c b/trunk/arch/powerpc/lib/locks.c index 79d0fa3a470d..80b482ca30df 100644 --- a/trunk/arch/powerpc/lib/locks.c +++ b/trunk/arch/powerpc/lib/locks.c @@ -43,11 +43,9 @@ void __spin_yield(raw_spinlock_t *lock) if (firmware_has_feature(FW_FEATURE_ISERIES)) HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); -#ifdef CONFIG_PPC_SPLPAR else plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), yield_count); -#endif } /* @@ -74,11 +72,9 @@ void __rw_yield(raw_rwlock_t *rw) if (firmware_has_feature(FW_FEATURE_ISERIES)) HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, ((u64)holder_cpu << 32) | yield_count); -#ifdef CONFIG_PPC_SPLPAR else plpar_hcall_norets(H_CONFER, get_hard_smp_processor_id(holder_cpu), yield_count); -#endif } #endif diff --git a/trunk/arch/powerpc/lib/mem_64.S b/trunk/arch/powerpc/lib/mem_64.S index 11ce045e21fd..68df20283ff5 100644 --- a/trunk/arch/powerpc/lib/mem_64.S +++ b/trunk/arch/powerpc/lib/mem_64.S @@ -19,7 +19,7 @@ _GLOBAL(memset) rlwimi r4,r4,16,0,15 cmplw cr1,r5,r0 /* do we get that far? */ rldimi r4,r4,32,0 - PPC_MTOCRF 1,r0 + mtcrf 1,r0 mr r6,r3 blt cr1,8f beq+ 3f /* if already 8-byte aligned */ @@ -49,7 +49,7 @@ _GLOBAL(memset) bdnz 4b 5: srwi. r0,r5,3 clrlwi r5,r5,29 - PPC_MTOCRF 1,r0 + mtcrf 1,r0 beq 8f bf 29,6f std r4,0(r6) @@ -65,7 +65,7 @@ _GLOBAL(memset) std r4,0(r6) addi r6,r6,8 8: cmpwi r5,0 - PPC_MTOCRF 1,r5 + mtcrf 1,r5 beqlr+ bf 29,9f stw r4,0(r6) diff --git a/trunk/arch/powerpc/lib/memcpy_64.S b/trunk/arch/powerpc/lib/memcpy_64.S index 3f131129d1c1..7173ba98f427 100644 --- a/trunk/arch/powerpc/lib/memcpy_64.S +++ b/trunk/arch/powerpc/lib/memcpy_64.S @@ -12,7 +12,7 @@ .align 7 _GLOBAL(memcpy) std r3,48(r1) /* save destination pointer for return value */ - PPC_MTOCRF 0x01,r5 + mtcrf 0x01,r5 cmpldi cr1,r5,16 neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry andi. r6,r6,7 @@ -128,7 +128,7 @@ _GLOBAL(memcpy) b .Ldo_tail .Ldst_unaligned: - PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7 + mtcrf 0x01,r6 # put #bytes to 8B bdry into cr7 subf r5,r6,r5 li r7,0 cmpldi r1,r5,16 @@ -143,7 +143,7 @@ _GLOBAL(memcpy) 2: bf cr7*4+1,3f lwzx r0,r7,r4 stwx r0,r7,r3 -3: PPC_MTOCRF 0x01,r5 +3: mtcrf 0x01,r5 add r4,r6,r4 add r3,r6,r3 b .Ldst_aligned diff --git a/trunk/arch/powerpc/lib/sstep.c b/trunk/arch/powerpc/lib/sstep.c index 4aae0c387645..7e8ded051b5b 100644 --- a/trunk/arch/powerpc/lib/sstep.c +++ b/trunk/arch/powerpc/lib/sstep.c @@ -54,7 +54,7 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs) */ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) { - unsigned int opcode, rs, rb, rd, spr; + unsigned int opcode, rd; unsigned long int imm; opcode = instr >> 26; @@ -152,49 +152,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) regs->nip &= 0xffffffffUL; return 1; #endif - case 0x26: /* mfcr */ - regs->gpr[rd] = regs->ccr; - regs->gpr[rd] &= 0xffffffffUL; - goto mtspr_out; - case 0x2a6: /* mfspr */ - spr = (instr >> 11) & 0x3ff; - switch (spr) { - case 0x20: /* mfxer */ - regs->gpr[rd] = regs->xer; - regs->gpr[rd] &= 0xffffffffUL; - goto mtspr_out; - case 0x100: /* mflr */ - regs->gpr[rd] = regs->link; - goto mtspr_out; - case 0x120: /* mfctr */ - regs->gpr[rd] = regs->ctr; - goto mtspr_out; - } - break; - case 0x378: /* orx */ - rs = (instr >> 21) & 0x1f; - rb = (instr >> 11) & 0x1f; - if (rs == rb) { /* mr */ - rd = (instr >> 16) & 0x1f; - regs->gpr[rd] = regs->gpr[rs]; - goto mtspr_out; - } - break; - case 0x3a6: /* mtspr */ - spr = (instr >> 11) & 0x3ff; - switch (spr) { - case 0x20: /* mtxer */ - regs->xer = (regs->gpr[rd] & 0xffffffffUL); - goto mtspr_out; - case 0x100: /* mtlr */ - regs->link = regs->gpr[rd]; - goto mtspr_out; - case 0x120: /* mtctr */ - regs->ctr = regs->gpr[rd]; -mtspr_out: - regs->nip += 4; - return 1; - } } } return 0; diff --git a/trunk/arch/powerpc/lib/strcase.c b/trunk/arch/powerpc/lib/strcase.c new file mode 100644 index 000000000000..f8ec1eba3fdd --- /dev/null +++ b/trunk/arch/powerpc/lib/strcase.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int strcasecmp(const char *s1, const char *s2) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 == c2 && c1 != 0); + return c1 - c2; +} + +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} diff --git a/trunk/arch/powerpc/mm/hash_low_32.S b/trunk/arch/powerpc/mm/hash_low_32.S index ddceefc06ecc..bd68df5fa78a 100644 --- a/trunk/arch/powerpc/mm/hash_low_32.S +++ b/trunk/arch/powerpc/mm/hash_low_32.S @@ -283,7 +283,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64) #define PTEG_SIZE 64 #define LG_PTEG_SIZE 6 #define LDPTEu lwzu -#define LDPTE lwz #define STPTE stw #define CMPPTE cmpw #define PTE_H 0x40 @@ -390,30 +389,13 @@ _GLOBAL(hash_page_patch_C) * and we know there is a definite (although small) speed * advantage to putting the PTE in the primary PTEG, we always * put the PTE in the primary PTEG. - * - * In addition, we skip any slot that is mapping kernel text in - * order to avoid a deadlock when not using BAT mappings if - * trying to hash in the kernel hash code itself after it has - * already taken the hash table lock. This works in conjunction - * with pre-faulting of the kernel text. - * - * If the hash table bucket is full of kernel text entries, we'll - * lockup here but that shouldn't happen */ - -1: addis r4,r7,next_slot@ha /* get next evict slot */ + addis r4,r7,next_slot@ha lwz r6,next_slot@l(r4) - addi r6,r6,PTE_SIZE /* search for candidate */ + addi r6,r6,PTE_SIZE andi. r6,r6,7*PTE_SIZE stw r6,next_slot@l(r4) add r4,r3,r6 - LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */ - clrrwi r0,r0,12 - lis r6,etext@h - ori r6,r6,etext@l /* get etext */ - tophys(r6,r6) - cmpl cr0,r0,r6 /* compare and try again */ - blt 1b #ifndef CONFIG_SMP /* Store PTE in PTEG */ diff --git a/trunk/arch/powerpc/mm/hash_low_64.S b/trunk/arch/powerpc/mm/hash_low_64.S index e64ce3eec36e..9bc0a9c2b9bc 100644 --- a/trunk/arch/powerpc/mm/hash_low_64.S +++ b/trunk/arch/powerpc/mm/hash_low_64.S @@ -445,12 +445,9 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) htab_insert_pte: /* real page number in r5, PTE RPN value + index */ - andis. r0,r31,_PAGE_4K_PFN@h - srdi r5,r31,PTE_RPN_SHIFT - bne- htab_special_pfn + rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT add r5,r5,r25 -htab_special_pfn: sldi r5,r5,HW_PAGE_SHIFT /* Calculate primary group hash */ diff --git a/trunk/arch/powerpc/mm/hash_native_64.c b/trunk/arch/powerpc/mm/hash_native_64.c index 79aedaf36f2b..6f1016acdbf6 100644 --- a/trunk/arch/powerpc/mm/hash_native_64.c +++ b/trunk/arch/powerpc/mm/hash_native_64.c @@ -505,7 +505,7 @@ static inline int tlb_batching_enabled(void) int enabled = 1; if (root) { - const char *model = of_get_property(root, "model", NULL); + const char *model = get_property(root, "model", NULL); if (model && !strcmp(model, "IBM,9076-N81")) enabled = 0; of_node_put(root); diff --git a/trunk/arch/powerpc/mm/hash_utils_64.c b/trunk/arch/powerpc/mm/hash_utils_64.c index 49618461defb..3c7fe2c65b5a 100644 --- a/trunk/arch/powerpc/mm/hash_utils_64.c +++ b/trunk/arch/powerpc/mm/hash_utils_64.c @@ -100,11 +100,6 @@ unsigned int HPAGE_SHIFT; #ifdef CONFIG_PPC_64K_PAGES int mmu_ci_restrictions; #endif -#ifdef CONFIG_DEBUG_PAGEALLOC -static u8 *linear_map_hash_slots; -static unsigned long linear_map_hash_count; -static spinlock_t linear_map_hash_lock; -#endif /* CONFIG_DEBUG_PAGEALLOC */ /* There are definitions of page sizes arrays to be used when none * is provided by the firmware. @@ -157,10 +152,11 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, for (vaddr = vstart, paddr = pstart; vaddr < vend; vaddr += step, paddr += step) { - unsigned long hash, hpteg; + unsigned long vpn, hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr); unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); + vpn = va >> shift; tmp_mode = mode; /* Make non-kernel text non-executable */ @@ -178,10 +174,6 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, if (ret < 0) break; -#ifdef CONFIG_DEBUG_PAGEALLOC - if ((paddr >> PAGE_SHIFT) < linear_map_hash_count) - linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80; -#endif /* CONFIG_DEBUG_PAGEALLOC */ } return ret < 0 ? ret : 0; } @@ -289,7 +281,6 @@ static void __init htab_init_page_sizes(void) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found: -#ifndef CONFIG_DEBUG_PAGEALLOC /* * Pick a size for the linear mapping. Currently, we only support * 16M, 1M and 4K which is the default @@ -298,7 +289,6 @@ static void __init htab_init_page_sizes(void) mmu_linear_psize = MMU_PAGE_16M; else if (mmu_psize_defs[MMU_PAGE_1M].shift) mmu_linear_psize = MMU_PAGE_1M; -#endif /* CONFIG_DEBUG_PAGEALLOC */ #ifdef CONFIG_PPC_64K_PAGES /* @@ -313,14 +303,12 @@ static void __init htab_init_page_sizes(void) if (mmu_psize_defs[MMU_PAGE_64K].shift) { mmu_virtual_psize = MMU_PAGE_64K; mmu_vmalloc_psize = MMU_PAGE_64K; - if (mmu_linear_psize == MMU_PAGE_4K) - mmu_linear_psize = MMU_PAGE_64K; if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) mmu_io_psize = MMU_PAGE_64K; else mmu_ci_restrictions = 1; } -#endif /* CONFIG_PPC_64K_PAGES */ +#endif printk(KERN_DEBUG "Page orders: linear mapping = %d, " "virtual = %d, io = %d\n", @@ -488,13 +476,6 @@ void __init htab_initialize(void) mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; -#ifdef CONFIG_DEBUG_PAGEALLOC - linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT; - linear_map_hash_slots = __va(lmb_alloc_base(linear_map_hash_count, - 1, lmb.rmo_size)); - memset(linear_map_hash_slots, 0, linear_map_hash_count); -#endif /* CONFIG_DEBUG_PAGEALLOC */ - /* On U3 based machines, we need to reserve the DART area and * _NOT_ map it to avoid cache paradoxes as it's remapped non * cacheable later on @@ -592,27 +573,6 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) return pp; } -/* - * Demote a segment to using 4k pages. - * For now this makes the whole process use 4k pages. - */ -void demote_segment_4k(struct mm_struct *mm, unsigned long addr) -{ -#ifdef CONFIG_PPC_64K_PAGES - if (mm->context.user_psize == MMU_PAGE_4K) - return; - mm->context.user_psize = MMU_PAGE_4K; - mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp; - get_paca()->context = mm->context; - slb_flush_and_rebolt(); -#ifdef CONFIG_SPE_BASE - spu_flush_all_slbs(mm); -#endif -#endif -} - -EXPORT_SYMBOL_GPL(demote_segment_4k); - /* Result code is: * 0 - handled * 1 - normal page fault @@ -705,19 +665,15 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) #ifndef CONFIG_PPC_64K_PAGES rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); #else - /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */ - if (pte_val(*ptep) & _PAGE_4K_PFN) { - demote_segment_4k(mm, ea); - psize = MMU_PAGE_4K; - } - if (mmu_ci_restrictions) { /* If this PTE is non-cacheable, switch to 4k */ if (psize == MMU_PAGE_64K && (pte_val(*ptep) & _PAGE_NO_CACHE)) { if (user_region) { - demote_segment_4k(mm, ea); psize = MMU_PAGE_4K; + mm->context.user_psize = MMU_PAGE_4K; + mm->context.sllp = SLB_VSID_USER | + mmu_psize_defs[MMU_PAGE_4K].sllp; } else if (ea < VMALLOC_END) { /* * some driver did a non-cacheable mapping @@ -800,8 +756,16 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, if (mmu_ci_restrictions) { /* If this PTE is non-cacheable, switch to 4k */ if (mm->context.user_psize == MMU_PAGE_64K && - (pte_val(*ptep) & _PAGE_NO_CACHE)) - demote_segment_4k(mm, ea); + (pte_val(*ptep) & _PAGE_NO_CACHE)) { + mm->context.user_psize = MMU_PAGE_4K; + mm->context.sllp = SLB_VSID_USER | + mmu_psize_defs[MMU_PAGE_4K].sllp; + get_paca()->context = mm->context; + slb_flush_and_rebolt(); +#ifdef CONFIG_SPE_BASE + spu_flush_all_slbs(mm); +#endif + } } if (mm->context.user_psize == MMU_PAGE_64K) __hash_page_64K(ea, access, vsid, ptep, trap, local); @@ -861,62 +825,3 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address) } bad_page_fault(regs, address, SIGBUS); } - -#ifdef CONFIG_DEBUG_PAGEALLOC -static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) -{ - unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr); - unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); - unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY | - _PAGE_COHERENT | PP_RWXX | HPTE_R_N; - int ret; - - hash = hpt_hash(va, PAGE_SHIFT); - hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); - - ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), - mode, HPTE_V_BOLTED, mmu_linear_psize); - BUG_ON (ret < 0); - spin_lock(&linear_map_hash_lock); - BUG_ON(linear_map_hash_slots[lmi] & 0x80); - linear_map_hash_slots[lmi] = ret | 0x80; - spin_unlock(&linear_map_hash_lock); -} - -static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) -{ - unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr); - unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); - - hash = hpt_hash(va, PAGE_SHIFT); - spin_lock(&linear_map_hash_lock); - BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); - hidx = linear_map_hash_slots[lmi] & 0x7f; - linear_map_hash_slots[lmi] = 0; - spin_unlock(&linear_map_hash_lock); - if (hidx & _PTEIDX_SECONDARY) - hash = ~hash; - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - slot += hidx & _PTEIDX_GROUP_IX; - ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0); -} - -void kernel_map_pages(struct page *page, int numpages, int enable) -{ - unsigned long flags, vaddr, lmi; - int i; - - local_irq_save(flags); - for (i = 0; i < numpages; i++, page++) { - vaddr = (unsigned long)page_address(page); - lmi = __pa(vaddr) >> PAGE_SHIFT; - if (lmi >= linear_map_hash_count) - continue; - if (enable) - kernel_map_linear_page(vaddr, lmi); - else - kernel_unmap_linear_page(vaddr, lmi); - } - local_irq_restore(flags); -} -#endif /* CONFIG_DEBUG_PAGEALLOC */ diff --git a/trunk/arch/powerpc/mm/hugetlbpage.c b/trunk/arch/powerpc/mm/hugetlbpage.c index 8508f973d9cc..f6ffaaa7a5bf 100644 --- a/trunk/arch/powerpc/mm/hugetlbpage.c +++ b/trunk/arch/powerpc/mm/hugetlbpage.c @@ -316,11 +316,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, { if (pte_present(*ptep)) { /* We open-code pte_clear because we need to pass the right - * argument to hpte_need_flush (huge / !huge). Might not be - * necessary anymore if we make hpte_need_flush() get the - * page size from the slices + * argument to hpte_update (huge / !huge) */ - pte_update(mm, addr & HPAGE_MASK, ptep, ~0UL, 1); + unsigned long old = pte_update(ptep, ~0UL); + if (old & _PAGE_HASHPTE) + hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1); + flush_tlb_pending(); } *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); } @@ -328,7 +329,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1); + unsigned long old = pte_update(ptep, ~0UL); + + if (old & _PAGE_HASHPTE) + hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1); + *ptep = __pte(0); + return __pte(old); } diff --git a/trunk/arch/powerpc/mm/init_32.c b/trunk/arch/powerpc/mm/init_32.c index 5fce6ccecb8d..0e53ca8f02fb 100644 --- a/trunk/arch/powerpc/mm/init_32.c +++ b/trunk/arch/powerpc/mm/init_32.c @@ -115,10 +115,6 @@ void MMU_setup(void) if (strstr(cmd_line, "noltlbs")) { __map_without_ltlbs = 1; } -#ifdef CONFIG_DEBUG_PAGEALLOC - __map_without_bats = 1; - __map_without_ltlbs = 1; -#endif } /* diff --git a/trunk/arch/powerpc/mm/lmb.c b/trunk/arch/powerpc/mm/lmb.c index e3a1e8dc536a..716a2906a24d 100644 --- a/trunk/arch/powerpc/mm/lmb.c +++ b/trunk/arch/powerpc/mm/lmb.c @@ -146,10 +146,6 @@ static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long rgnbase = rgn->region[i].base; unsigned long rgnsize = rgn->region[i].size; - if ((rgnbase == base) && (rgnsize == size)) - /* Already have this region, so we're done */ - return 0; - adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); if ( adjacent > 0 ) { rgn->region[i].base -= size; diff --git a/trunk/arch/powerpc/mm/mem.c b/trunk/arch/powerpc/mm/mem.c index c4bcd7546424..52f397c108a7 100644 --- a/trunk/arch/powerpc/mm/mem.c +++ b/trunk/arch/powerpc/mm/mem.c @@ -58,6 +58,9 @@ int init_bootmem_done; int mem_init_done; unsigned long memory_limit; +extern void hash_preload(struct mm_struct *mm, unsigned long ea, + unsigned long access, unsigned long trap); + int page_is_ram(unsigned long pfn) { unsigned long paddr = (pfn << PAGE_SHIFT); diff --git a/trunk/arch/powerpc/mm/mmu_decl.h b/trunk/arch/powerpc/mm/mmu_decl.h index 9c4538bb04b0..bea2d21ac6f7 100644 --- a/trunk/arch/powerpc/mm/mmu_decl.h +++ b/trunk/arch/powerpc/mm/mmu_decl.h @@ -19,14 +19,9 @@ * 2 of the License, or (at your option) any later version. * */ -#include #include #include -extern void hash_preload(struct mm_struct *mm, unsigned long ea, - unsigned long access, unsigned long trap); - - #ifdef CONFIG_PPC32 extern void mapin_ram(void); extern int map_page(unsigned long va, phys_addr_t pa, int flags); diff --git a/trunk/arch/powerpc/mm/numa.c b/trunk/arch/powerpc/mm/numa.c index b3a592b25ab3..e86c37c82cfd 100644 --- a/trunk/arch/powerpc/mm/numa.c +++ b/trunk/arch/powerpc/mm/numa.c @@ -74,7 +74,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) { /* Try interrupt server first */ - interrupt_server = of_get_property(cpu_node, + interrupt_server = get_property(cpu_node, "ibm,ppc-interrupt-server#s", &len); len = len / sizeof(u32); @@ -85,7 +85,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) return cpu_node; } } else { - reg = of_get_property(cpu_node, "reg", &len); + reg = get_property(cpu_node, "reg", &len); if (reg && (len > 0) && (reg[0] == hw_cpuid)) return cpu_node; } @@ -97,7 +97,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) /* must hold reference to node during call */ static const int *of_get_associativity(struct device_node *dev) { - return of_get_property(dev, "ibm,associativity", NULL); + return get_property(dev, "ibm,associativity", NULL); } /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa @@ -179,7 +179,7 @@ static int __init find_min_common_depth(void) * configuration (should be all 0's) and the second is for a normal * NUMA configuration. */ - ref_points = of_get_property(rtas_root, + ref_points = get_property(rtas_root, "ibm,associativity-reference-points", &len); if ((len >= 1) && ref_points) { @@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) if (!memory) panic("numa.c: No memory nodes found!"); - *n_addr_cells = of_n_addr_cells(memory); - *n_size_cells = of_n_size_cells(memory); + *n_addr_cells = prom_n_addr_cells(memory); + *n_size_cells = prom_n_size_cells(memory); of_node_put(memory); } @@ -308,9 +308,9 @@ static void __init parse_drconf_memory(struct device_node *memory) int nid, default_nid = 0; unsigned int start, ai, flags; - lm = of_get_property(memory, "ibm,lmb-size", &ls); - dm = of_get_property(memory, "ibm,dynamic-memory", &ld); - aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la); + lm = get_property(memory, "ibm,lmb-size", &ls); + dm = get_property(memory, "ibm,dynamic-memory", &ld); + aa = get_property(memory, "ibm,associativity-lookup-arrays", &la); if (!lm || !dm || !aa || ls < sizeof(unsigned int) || ld < sizeof(unsigned int) || la < 2 * sizeof(unsigned int)) @@ -404,10 +404,10 @@ static int __init parse_numa_properties(void) const unsigned int *memcell_buf; unsigned int len; - memcell_buf = of_get_property(memory, + memcell_buf = get_property(memory, "linux,usable-memory", &len); if (!memcell_buf || len <= 0) - memcell_buf = of_get_property(memory, "reg", &len); + memcell_buf = get_property(memory, "reg", &len); if (!memcell_buf || len <= 0) continue; @@ -725,7 +725,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr) const unsigned int *memcell_buf; unsigned int len; - memcell_buf = of_get_property(memory, "reg", &len); + memcell_buf = get_property(memory, "reg", &len); if (!memcell_buf || len <= 0) continue; diff --git a/trunk/arch/powerpc/mm/pgtable_32.c b/trunk/arch/powerpc/mm/pgtable_32.c index bca560374927..c284bdac9947 100644 --- a/trunk/arch/powerpc/mm/pgtable_32.c +++ b/trunk/arch/powerpc/mm/pgtable_32.c @@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) * mem_init() sets high_memory so only do the check after that. */ if (mem_init_done && (p < virt_to_phys(high_memory))) { - printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n", - (unsigned long long)p, __builtin_return_address(0)); + printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p, + __builtin_return_address(0)); return NULL; } @@ -266,12 +266,9 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) pg = pte_alloc_kernel(pd, va); if (pg != 0) { err = 0; - /* The PTE should never be already set nor present in the - * hash table - */ - BUG_ON(pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)); - set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); + set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); + if (mem_init_done) + flush_HPTE(0, va, pmd_val(*pd)); } return err; } @@ -282,19 +279,16 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) void __init mapin_ram(void) { unsigned long v, p, s, f; - int ktext; s = mmu_mapin_ram(); v = KERNELBASE + s; p = PPC_MEMSTART + s; for (; s < total_lowmem; s += PAGE_SIZE) { - ktext = ((char *) v >= _stext && (char *) v < etext); - f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM; + if ((char *) v >= _stext && (char *) v < etext) + f = _PAGE_RAM_TEXT; + else + f = _PAGE_RAM; map_page(v, p, f); -#ifdef CONFIG_PPC_STD_MMU_32 - if (ktext) - hash_preload(&init_mm, v, 0, 0x300); -#endif v += PAGE_SIZE; p += PAGE_SIZE; } @@ -451,55 +445,3 @@ mm_ptov (unsigned long paddr) return ret; } -#ifdef CONFIG_DEBUG_PAGEALLOC - -static int __change_page_attr(struct page *page, pgprot_t prot) -{ - pte_t *kpte; - pmd_t *kpmd; - unsigned long address; - - BUG_ON(PageHighMem(page)); - address = (unsigned long)page_address(page); - - if (v_mapped_by_bats(address) || v_mapped_by_tlbcam(address)) - return 0; - if (!get_pteptr(&init_mm, address, &kpte, &kpmd)) - return -EINVAL; - set_pte_at(&init_mm, address, kpte, mk_pte(page, prot)); - wmb(); - flush_HPTE(0, address, pmd_val(*kpmd)); - pte_unmap(kpte); - - return 0; -} - -/* - * Change the page attributes of an page in the linear mapping. - * - * THIS CONFLICTS WITH BAT MAPPINGS, DEBUG USE ONLY - */ -static int change_page_attr(struct page *page, int numpages, pgprot_t prot) -{ - int i, err = 0; - unsigned long flags; - - local_irq_save(flags); - for (i = 0; i < numpages; i++, page++) { - err = __change_page_attr(page, prot); - if (err) - break; - } - local_irq_restore(flags); - return err; -} - - -void kernel_map_pages(struct page *page, int numpages, int enable) -{ - if (PageHighMem(page)) - return; - - change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0)); -} -#endif /* CONFIG_DEBUG_PAGEALLOC */ diff --git a/trunk/arch/powerpc/mm/ppc_mmu_32.c b/trunk/arch/powerpc/mm/ppc_mmu_32.c index 05066674a7a0..7cceb2c44cb9 100644 --- a/trunk/arch/powerpc/mm/ppc_mmu_32.c +++ b/trunk/arch/powerpc/mm/ppc_mmu_32.c @@ -85,10 +85,8 @@ unsigned long __init mmu_mapin_ram(void) unsigned long max_size = (256<<20); unsigned long align; - if (__map_without_bats) { - printk(KERN_DEBUG "RAM mapped without BATs\n"); + if (__map_without_bats) return 0; - } /* Set up BAT2 and if necessary BAT3 to cover RAM. */ diff --git a/trunk/arch/powerpc/mm/tlb_64.c b/trunk/arch/powerpc/mm/tlb_64.c index fd8d08c325eb..b58baa65c4a7 100644 --- a/trunk/arch/powerpc/mm/tlb_64.c +++ b/trunk/arch/powerpc/mm/tlb_64.c @@ -120,20 +120,17 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) } /* - * A linux PTE was changed and the corresponding hash table entry - * neesd to be flushed. This function will either perform the flush - * immediately or will batch it up if the current CPU has an active - * batch on it. - * - * Must be called from within some kind of spinlock/non-preempt region... + * Update the MMU hash table to correspond with a change to + * a Linux PTE. If wrprot is true, it is permissible to + * change the existing HPTE to read-only rather than removing it + * (if we remove it we should clear the _PTE_HPTEFLAGS bits). */ -void hpte_need_flush(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, unsigned long pte, int huge) +void hpte_update(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, unsigned long pte, int huge) { struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - unsigned long vsid, vaddr; + unsigned long vsid; unsigned int psize; - real_pte_t rpte; int i; i = batch->index; @@ -154,26 +151,6 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, } else psize = pte_pagesize_index(pte); - /* Build full vaddr */ - if (!is_kernel_addr(addr)) { - vsid = get_vsid(mm->context.id, addr); - WARN_ON(vsid == 0); - } else - vsid = get_kernel_vsid(addr); - vaddr = (vsid << 28 ) | (addr & 0x0fffffff); - rpte = __real_pte(__pte(pte), ptep); - - /* - * Check if we have an active batch on this CPU. If not, just - * flush now and return. For now, we don global invalidates - * in that case, might be worth testing the mm cpu mask though - * and decide to use local invalidates instead... - */ - if (!batch->active) { - flush_hash_page(vaddr, rpte, psize, 0); - return; - } - /* * This can happen when we are in the middle of a TLB batch and * we encounter memory pressure (eg copy_page_range when it tries @@ -185,42 +162,47 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, * batch */ if (i != 0 && (mm != batch->mm || batch->psize != psize)) { - __flush_tlb_pending(batch); + flush_tlb_pending(); i = 0; } if (i == 0) { batch->mm = mm; batch->psize = psize; } - batch->pte[i] = rpte; - batch->vaddr[i] = vaddr; + if (!is_kernel_addr(addr)) { + vsid = get_vsid(mm->context.id, addr); + WARN_ON(vsid == 0); + } else + vsid = get_kernel_vsid(addr); + batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff); + batch->pte[i] = __real_pte(__pte(pte), ptep); batch->index = ++i; if (i >= PPC64_TLB_BATCH_NR) - __flush_tlb_pending(batch); + flush_tlb_pending(); } -/* - * This function is called when terminating an mmu batch or when a batch - * is full. It will perform the flush of all the entries currently stored - * in a batch. - * - * Must be called from within some kind of spinlock/non-preempt region... - */ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) { + int i; + int cpu; cpumask_t tmp; - int i, local = 0; + int local = 0; + BUG_ON(in_interrupt()); + + cpu = get_cpu(); i = batch->index; - tmp = cpumask_of_cpu(smp_processor_id()); + tmp = cpumask_of_cpu(cpu); if (cpus_equal(batch->mm->cpu_vm_mask, tmp)) local = 1; + if (i == 1) flush_hash_page(batch->vaddr[0], batch->pte[0], batch->psize, local); else flush_hash_range(i, local); batch->index = 0; + put_cpu(); } void pte_free_finish(void) diff --git a/trunk/arch/powerpc/oprofile/Makefile b/trunk/arch/powerpc/oprofile/Makefile index 4b5f9528218c..4ccef2d5530c 100644 --- a/trunk/arch/powerpc/oprofile/Makefile +++ b/trunk/arch/powerpc/oprofile/Makefile @@ -12,6 +12,6 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ oprofile-y := $(DRIVER_OBJS) common.o backtrace.o oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o -oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o +oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o oprofile-$(CONFIG_6xx) += op_model_7450.o diff --git a/trunk/arch/powerpc/oprofile/common.c b/trunk/arch/powerpc/oprofile/common.c index 1a7ef7e246d2..fbd62eacfdf4 100644 --- a/trunk/arch/powerpc/oprofile/common.c +++ b/trunk/arch/powerpc/oprofile/common.c @@ -160,9 +160,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case PPC_OPROFILE_POWER4: model = &op_model_power4; break; - case PPC_OPROFILE_PA6T: - model = &op_model_pa6t; - break; #endif #ifdef CONFIG_6xx case PPC_OPROFILE_G4: diff --git a/trunk/arch/powerpc/oprofile/op_model_cell.c b/trunk/arch/powerpc/oprofile/op_model_cell.c index 626b29f38304..e08e1d7b3dc5 100644 --- a/trunk/arch/powerpc/oprofile/op_model_cell.c +++ b/trunk/arch/powerpc/oprofile/op_model_cell.c @@ -37,7 +37,6 @@ #include #include "../platforms/cell/interrupt.h" -#include "../platforms/cell/cbe_regs.h" #define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ #define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying @@ -131,7 +130,7 @@ static int pm_rtas_token; static u32 reset_value[NR_PHYS_CTRS]; static int num_counters; static int oprofile_running; -static DEFINE_SPINLOCK(virt_cntr_lock); +static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED; static u32 ctr_enabled; diff --git a/trunk/arch/powerpc/oprofile/op_model_pa6t.c b/trunk/arch/powerpc/oprofile/op_model_pa6t.c deleted file mode 100644 index e8a56b0adadc..000000000000 --- a/trunk/arch/powerpc/oprofile/op_model_pa6t.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2006-2007 PA Semi, Inc - * - * Author: Shashi Rao, PA Semi - * - * Maintained by: Olof Johansson - * - * Based on arch/powerpc/oprofile/op_model_power4.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This 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 - -static unsigned char oprofile_running; - -/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */ -static u64 mmcr0_val; -static u64 mmcr1_val; - -/* inited in pa6t_reg_setup */ -static u64 reset_value[OP_MAX_COUNTER]; - -static inline u64 ctr_read(unsigned int i) -{ - switch (i) { - case 0: - return mfspr(SPRN_PA6T_PMC0); - case 1: - return mfspr(SPRN_PA6T_PMC1); - case 2: - return mfspr(SPRN_PA6T_PMC2); - case 3: - return mfspr(SPRN_PA6T_PMC3); - case 4: - return mfspr(SPRN_PA6T_PMC4); - case 5: - return mfspr(SPRN_PA6T_PMC5); - default: - printk(KERN_ERR "ctr_read called with bad arg %u\n", i); - return 0; - } -} - -static inline void ctr_write(unsigned int i, u64 val) -{ - switch (i) { - case 0: - mtspr(SPRN_PA6T_PMC0, val); - break; - case 1: - mtspr(SPRN_PA6T_PMC1, val); - break; - case 2: - mtspr(SPRN_PA6T_PMC2, val); - break; - case 3: - mtspr(SPRN_PA6T_PMC3, val); - break; - case 4: - mtspr(SPRN_PA6T_PMC4, val); - break; - case 5: - mtspr(SPRN_PA6T_PMC5, val); - break; - default: - printk(KERN_ERR "ctr_write called with bad arg %u\n", i); - break; - } -} - - -/* precompute the values to stuff in the hardware registers */ -static void pa6t_reg_setup(struct op_counter_config *ctr, - struct op_system_config *sys, - int num_ctrs) -{ - int pmc; - - /* - * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the - * event_mappings file by turning off the counters that the user doesn't - * care about - * - * setup user and kernel profiling - */ - for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) - if (!ctr[pmc].enabled) { - sys->mmcr0 &= ~(0x1UL << pmc); - sys->mmcr0 &= ~(0x1UL << (pmc+12)); - pr_debug("turned off counter %u\n", pmc); - } - - if (sys->enable_kernel) - sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN; - else - sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN); - - if (sys->enable_user) - sys->mmcr0 |= PA6T_MMCR0_PREN; - else - sys->mmcr0 &= ~PA6T_MMCR0_PREN; - - /* - * The performance counter event settings are given in the mmcr0 and - * mmcr1 values passed from the user in the op_system_config - * structure (sys variable). - */ - mmcr0_val = sys->mmcr0; - mmcr1_val = sys->mmcr1; - pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0); - pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1); - - for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) { - /* counters are 40 bit. Move to cputable at some point? */ - reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count; - pr_debug("reset_value for pmc%u inited to 0x%lx\n", - pmc, reset_value[pmc]); - } -} - -/* configure registers on this cpu */ -static void pa6t_cpu_setup(struct op_counter_config *ctr) -{ - u64 mmcr0 = mmcr0_val; - u64 mmcr1 = mmcr1_val; - - /* Default is all PMCs off */ - mmcr0 &= ~(0x3FUL); - mtspr(SPRN_PA6T_MMCR0, mmcr0); - - /* program selected programmable events in */ - mtspr(SPRN_PA6T_MMCR1, mmcr1); - - pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(), - mfspr(SPRN_PA6T_MMCR0)); - pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(), - mfspr(SPRN_PA6T_MMCR1)); -} - -static void pa6t_start(struct op_counter_config *ctr) -{ - int i; - - /* Hold off event counting until rfid */ - u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS; - - for (i = 0; i < cur_cpu_spec->num_pmcs; i++) - if (ctr[i].enabled) - ctr_write(i, reset_value[i]); - else - ctr_write(i, 0UL); - - mtspr(SPRN_PA6T_MMCR0, mmcr0); - - oprofile_running = 1; - - pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0); -} - -static void pa6t_stop(void) -{ - u64 mmcr0; - - /* freeze counters */ - mmcr0 = mfspr(SPRN_PA6T_MMCR0); - mmcr0 |= PA6T_MMCR0_FCM0; - mtspr(SPRN_PA6T_MMCR0, mmcr0); - - oprofile_running = 0; - - pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0); -} - -/* handle the perfmon overflow vector */ -static void pa6t_handle_interrupt(struct pt_regs *regs, - struct op_counter_config *ctr) -{ - unsigned long pc = mfspr(SPRN_PA6T_SIAR); - int is_kernel = is_kernel_addr(pc); - u64 val; - int i; - u64 mmcr0; - - /* disable perfmon counting until rfid */ - mmcr0 = mfspr(SPRN_PA6T_MMCR0); - mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS); - - /* Record samples. We've got one global bit for whether a sample - * was taken, so add it for any counter that triggered overflow. - */ - for (i = 0; i < cur_cpu_spec->num_pmcs; i++) { - val = ctr_read(i); - if (val & (0x1UL << 39)) { /* Overflow bit set */ - if (oprofile_running && ctr[i].enabled) { - if (mmcr0 & PA6T_MMCR0_SIARLOG) - oprofile_add_ext_sample(pc, regs, i, is_kernel); - ctr_write(i, reset_value[i]); - } else { - ctr_write(i, 0UL); - } - } - } - - /* Restore mmcr0 to a good known value since the PMI changes it */ - mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS; - mtspr(SPRN_PA6T_MMCR0, mmcr0); -} - -struct op_powerpc_model op_model_pa6t = { - .reg_setup = pa6t_reg_setup, - .cpu_setup = pa6t_cpu_setup, - .start = pa6t_start, - .stop = pa6t_stop, - .handle_interrupt = pa6t_handle_interrupt, -}; diff --git a/trunk/arch/powerpc/platforms/4xx/Kconfig b/trunk/arch/powerpc/platforms/4xx/Kconfig index ded357c17414..2f2a13ed7667 100644 --- a/trunk/arch/powerpc/platforms/4xx/Kconfig +++ b/trunk/arch/powerpc/platforms/4xx/Kconfig @@ -3,206 +3,278 @@ config 4xx depends on 40x || 44x default y -config BOOKE +config WANT_EARLY_SERIAL bool - depends on 44x - default y + select SERIAL_8250 + default n -menu "AMCC 40x options" +menu "AMCC 4xx options" + depends on 4xx + +choice + prompt "Machine Type" depends on 40x + default WALNUT -#config BUBINGA -# bool "Bubinga" -# depends on 40x -# default n -# select 405EP -# help -# This option enables support for the IBM 405EP evaluation board. - -#config CPCI405 -# bool "CPCI405" -# depends on 40x -# default n -# select 405GP -# help -# This option enables support for the CPCI405 board. - -#config EP405 -# bool "EP405/EP405PC" -# depends on 40x -# default n -# select 405GP -# help -# This option enables support for the EP405/EP405PC boards. - -#config EP405PC -# bool "EP405PC Support" -# depends on EP405 -# default y -# help -# This option enables support for the extra features of the EP405PC board. - -#config REDWOOD_5 -# bool "Redwood-5" -# depends on 40x -# default n -# select STB03xxx -# help -# This option enables support for the IBM STB04 evaluation board. - -#config REDWOOD_6 -# bool "Redwood-6" -# depends on 40x -# default n -# select STB03xxx -# help -# This option enables support for the IBM STBx25xx evaluation board. - -#config SYCAMORE -# bool "Sycamore" -# depends on 40x -# default n -# select 405GPR -# help -# This option enables support for the IBM PPC405GPr evaluation board. - -#config WALNUT -# bool "Walnut" -# depends on 40x -# default y -# select 405GP -# help -# This option enables support for the IBM PPC405GP evaluation board. - -#config XILINX_ML300 -# bool "Xilinx-ML300" -# depends on 40x -# default y -# select VIRTEX_II_PRO -# help -# This option enables support for the Xilinx ML300 evaluation board. +config BUBINGA + bool "Bubinga" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM 405EP evaluation board. -endmenu +config CPCI405 + bool "CPCI405" + help + This option enables support for the CPCI405 board. + +config EP405 + bool "EP405/EP405PC" + help + This option enables support for the EP405/EP405PC boards. + +config REDWOOD_5 + bool "Redwood-5" + help + This option enables support for the IBM STB04 evaluation board. + +config REDWOOD_6 + bool "Redwood-6" + help + This option enables support for the IBM STBx25xx evaluation board. + +config SYCAMORE + bool "Sycamore" + help + This option enables support for the IBM PPC405GPr evaluation board. + +config WALNUT + bool "Walnut" + help + This option enables support for the IBM PPC405GP evaluation board. + +config XILINX_ML300 + bool "Xilinx-ML300" + help + This option enables support for the Xilinx ML300 evaluation board. + +endchoice + +choice + prompt "Machine Type" + depends on 44x + default EBONY + +config BAMBOO + bool "Bamboo" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440EP evaluation board. + +config EBONY + bool "Ebony" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440GP evaluation board. + +config LUAN + bool "Luan" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440SP evaluation board. + +config OCOTEA + bool "Ocotea" + select WANT_EARLY_SERIAL + help + This option enables support for the IBM PPC440GX evaluation board. -# 40x specific CPU modules, selected based on the board above. +endchoice + +config EP405PC + bool "EP405PC Support" + depends on EP405 + + +# It's often necessary to know the specific 4xx processor type. +# Fortunately, it is impled (so far) from the board type, so we +# don't need to ask more redundant questions. config NP405H bool - #depends on ASH + depends on ASH + default y -# OAK doesn't exist but wanted to keep this around for any future 403GCX boards -config 403GCX +config 440EP bool - #depends on OAK - select IBM405_ERR51 + depends on BAMBOO + select PPC_FPU + default y -config 405GP +config 440GP bool - select IBM405_ERR77 - select IBM405_ERR51 + depends on EBONY + default y -config 405EP +config 440GX bool + depends on OCOTEA + default y -config 405GPR +config 440SP bool + depends on LUAN + default y -config VIRTEX_II_PRO +config 440 bool - select IBM405_ERR77 - select IBM405_ERR51 + depends on 440GP || 440SP || 440EP + default y -config STB03xxx +config 440A bool - select IBM405_ERR77 - select IBM405_ERR51 + depends on 440GX + default y -# 40x errata/workaround config symbols, selected by the CPU models above +config IBM440EP_ERR42 + bool + depends on 440EP + default y # All 405-based cores up until the 405GPR and 405EP have this errata. config IBM405_ERR77 bool + depends on 40x && !403GCX && !405GPR && !405EP + default y # All 40x-based cores, up until the 405GPR and 405EP have this errata. config IBM405_ERR51 bool + depends on 40x && !405GPR && !405EP + default y -menu "AMCC 44x options" +config BOOKE + bool depends on 44x + default y + +config IBM_OCP + bool + depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y -#config BAMBOO -# bool "Bamboo" -# depends on 44x -# default n -# select 440EP -# help -# This option enables support for the IBM PPC440EP evaluation board. +config XILINX_OCP + bool + depends on XILINX_ML300 + default y -config EBONY - bool "Ebony" - depends on 44x +config IBM_EMAC4 + bool + depends on 440GX || 440SP default y - select 440GP - help - This option enables support for the IBM PPC440GP evaluation board. -#config LUAN -# bool "Luan" -# depends on 44x -# default n -# select 440SP -# help -# This option enables support for the IBM PPC440SP evaluation board. - -#config OCOTEA -# bool "Ocotea" -# depends on 44x -# default n -# select 440GX -# help -# This option enables support for the IBM PPC440GX evaluation board. +config BIOS_FIXUP + bool + depends on BUBINGA || EP405 || SYCAMORE || WALNUT + default y -endmenu +# OAK doesn't exist but wanted to keep this around for any future 403GCX boards +config 403GCX + bool + depends on OAK + default y -# 44x specific CPU modules, selected based on the board above. -config 440EP +config 405EP bool - select PPC_FPU - select IBM440EP_ERR42 + depends on BUBINGA + default y -config 440GP +config 405GP bool - select IBM_NEW_EMAC_ZMII + depends on CPCI405 || EP405 || WALNUT + default y -config 440GX +config 405GPR bool + depends on SYCAMORE + default y -config 440SP +config VIRTEX_II_PRO bool + depends on XILINX_ML300 + default y -config 440A +config STB03xxx bool - depends on 440GX + depends on REDWOOD_5 || REDWOOD_6 default y -# 44x errata/workaround config symbols, selected by the CPU models above -config IBM440EP_ERR42 +config EMBEDDEDBOOT bool + depends on EP405 || XILINX_ML300 + default y -#config XILINX_OCP -# bool -# depends on XILINX_ML300 -# default y +config IBM_OPENBIOS + bool + depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + default y -#config BIOS_FIXUP -# bool -# depends on BUBINGA || EP405 || SYCAMORE || WALNUT -# default y +config PPC4xx_DMA + bool "PPC4xx DMA controller support" + depends on 4xx -#config PPC4xx_DMA -# bool "PPC4xx DMA controller support" -# depends on 4xx +config PPC4xx_EDMA + bool + depends on !STB03xxx && PPC4xx_DMA + default y + +config PPC_GEN550 + bool + depends on 4xx + default y -#config PPC4xx_EDMA -# bool -# depends on !STB03xxx && PPC4xx_DMA -# default y +choice + prompt "TTYS0 device and default console" + depends on 40x + default UART0_TTYS0 + +config UART0_TTYS0 + bool "UART0" + +config UART0_TTYS1 + bool "UART1" + +endchoice + +config SERIAL_SICC + bool "SICC Serial port support" + depends on STB03xxx + +config UART1_DFLT_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +config SERIAL_SICC_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y +endmenu + + +menu "IBM 40x options" + depends on 40x + +config SERIAL_SICC + bool "SICC Serial port" + depends on STB03xxx + +config UART1_DFLT_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +config SERIAL_SICC_CONSOLE + bool + depends on SERIAL_SICC && UART0_TTYS1 + default y + +endmenu diff --git a/trunk/arch/powerpc/platforms/52xx/Kconfig b/trunk/arch/powerpc/platforms/52xx/Kconfig deleted file mode 100644 index bc4aa4a80a12..000000000000 --- a/trunk/arch/powerpc/platforms/52xx/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config PPC_MPC52xx - bool - default n - -config PPC_MPC5200 - bool - select PPC_MPC52xx - default n - -config PPC_MPC5200_BUGFIX - bool "MPC5200 (L25R) bugfix support" - depends on PPC_MPC5200 - default n - help - Enable workarounds for original MPC5200 errata. This is not required - for MPC5200B based boards. - - It is safe to say 'Y' here - -config PPC_EFIKA - bool "bPlan Efika 5k2. MPC5200B based computer" - depends on PPC_MULTIPLATFORM && PPC32 - select PPC_RTAS - select RTAS_PROC - select PPC_MPC52xx - select PPC_NATIVE - default n - -config PPC_LITE5200 - bool "Freescale Lite5200 Eval Board" - depends on PPC_MULTIPLATFORM && PPC32 - select PPC_MPC5200 - default n - - diff --git a/trunk/arch/powerpc/platforms/52xx/efika.c b/trunk/arch/powerpc/platforms/52xx/efika.c index a6bba97314eb..8de034116681 100644 --- a/trunk/arch/powerpc/platforms/52xx/efika.c +++ b/trunk/arch/powerpc/platforms/52xx/efika.c @@ -112,7 +112,7 @@ void __init efika_pcisetup(void) return; } - bus_range = of_get_property(pcictrl, "bus-range", &len); + bus_range = get_property(pcictrl, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't get bus-range for %s\n", pcictrl->full_name); @@ -158,17 +158,18 @@ void __init efika_pcisetup(void) static void efika_show_cpuinfo(struct seq_file *m) { struct device_node *root; - const char *revision; - const char *codegendescription; - const char *codegenvendor; + const char *revision = NULL; + const char *codegendescription = NULL; + const char *codegenvendor = NULL; root = of_find_node_by_path("/"); if (!root) return; - revision = of_get_property(root, "revision", NULL); - codegendescription = of_get_property(root, "CODEGEN,description", NULL); - codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL); + revision = get_property(root, "revision", NULL); + codegendescription = + get_property(root, "CODEGEN,description", NULL); + codegenvendor = get_property(root, "CODEGEN,vendor", NULL); if (codegendescription) seq_printf(m, "machine\t\t: %s\n", codegendescription); diff --git a/trunk/arch/powerpc/platforms/52xx/lite5200.c b/trunk/arch/powerpc/platforms/52xx/lite5200.c index 8e2646ac417b..cc3b40de21dd 100644 --- a/trunk/arch/powerpc/platforms/52xx/lite5200.c +++ b/trunk/arch/powerpc/platforms/52xx/lite5200.c @@ -94,8 +94,8 @@ static void __init lite5200_setup_arch(void) np = of_find_node_by_type(NULL, "cpu"); if (np) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); + unsigned int *fp = + (int *)get_property(np, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else @@ -108,11 +108,9 @@ static void __init lite5200_setup_arch(void) lite5200_setup_cpu(); /* Platorm specific */ #ifdef CONFIG_PCI - np = of_find_node_by_type(NULL, "pci"); - if (np) { + np = of_find_node_by_type(np, "pci"); + if (np) mpc52xx_add_bridge(np); - of_node_put(np); - } #endif #ifdef CONFIG_BLK_DEV_INITRD @@ -134,7 +132,7 @@ void lite5200_show_cpuinfo(struct seq_file *m) const char *model = NULL; if (np) - model = of_get_property(np, "model", NULL); + model = get_property(np, "model", NULL); seq_printf(m, "vendor\t\t: Freescale Semiconductor\n"); seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown"); diff --git a/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c b/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c index 2dd415ff55a9..ed0cb694aea8 100644 --- a/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -60,7 +60,7 @@ mpc52xx_find_ipb_freq(struct device_node *node) of_node_get(node); while (node) { - p_ipb_freq = of_get_property(node, "bus-frequency", NULL); + p_ipb_freq = get_property(node, "bus-frequency", NULL); if (p_ipb_freq) break; diff --git a/trunk/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/trunk/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 34d34a26d305..faf161bdbc1c 100644 --- a/trunk/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/trunk/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -370,7 +370,7 @@ mpc52xx_add_bridge(struct device_node *node) return -EINVAL; } - bus_range = of_get_property(node, "bus-range", &len); + bus_range = get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", node->full_name); diff --git a/trunk/arch/powerpc/platforms/82xx/Kconfig b/trunk/arch/powerpc/platforms/82xx/Kconfig index de7fce9cb6eb..47d841ecf2e2 100644 --- a/trunk/arch/powerpc/platforms/82xx/Kconfig +++ b/trunk/arch/powerpc/platforms/82xx/Kconfig @@ -1,36 +1,21 @@ +menu "Platform support" + depends on PPC_82xx + choice - prompt "Machine Type" - depends on PPC_82xx - default MPC82xx_ADS + prompt "Machine Type" + default MPC82xx_ADS config MPC82xx_ADS - bool "Freescale MPC82xx ADS" - select DEFAULT_UIMAGE - select PQ2ADS - select 8272 - select 8260 - select FSL_SOC - help - This option enables support for the MPC8272 ADS board + bool "Freescale MPC82xx ADS" + select DEFAULT_UIMAGE + select PQ2ADS + select 8272 + select 8260 + select CPM2 + select FSL_SOC + help + This option enables support for the MPC8272 ADS board endchoice -config PQ2ADS - bool - default n - -config 8260 - bool - depends on 6xx - select CPM2 - help - The MPC8260 is a typical embedded CPU made by Freescale. Selecting - this option means that you wish to build a kernel for a machine with - an 8260 class CPU. - -config 8272 - bool - select 8260 - help - The MPC8272 CPM has a different internal dpram setup than other CPM2 - devices +endmenu diff --git a/trunk/arch/powerpc/platforms/82xx/mpc82xx.c b/trunk/arch/powerpc/platforms/82xx/mpc82xx.c index cc9900d2e5ee..74e7892cdfcf 100644 --- a/trunk/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/trunk/arch/powerpc/platforms/82xx/mpc82xx.c @@ -55,17 +55,17 @@ static int __init get_freq(char *name, unsigned long *val) { struct device_node *cpu; - const unsigned int *fp; + unsigned int *fp; int found = 0; /* The cpu node should have timebase and clock frequency properties */ cpu = of_find_node_by_type(NULL, "cpu"); if (cpu) { - fp = of_get_property(cpu, name, NULL); + fp = (unsigned int *)get_property(cpu, name, NULL); if (fp) { found = 1; - *val = *fp; + *val = *fp++; } of_node_put(cpu); diff --git a/trunk/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/trunk/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 47cb09f08052..7334c1a15b90 100644 --- a/trunk/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/trunk/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -456,7 +456,7 @@ void m82xx_pci_init_irq(void) iounmap(immap); return; } - irq_map = of_get_property(np, "interrupt-map", &size); + irq_map = get_property(np, "interrupt-map", &size); if ((!irq_map) || (size <= 7)) { printk(KERN_INFO "No interrupt-map property of pci node\n"); iounmap(immap); @@ -481,7 +481,7 @@ void m82xx_pci_init_irq(void) } pci_pic_node = of_node_get(np); /* PCI interrupt controller registers: status and mask */ - regs = of_get_property(np, "reg", &size); + regs = get_property(np, "reg", &size); if ((!regs) || (size <= 2)) { printk(KERN_INFO "No reg property in pci pic node\n"); iounmap(immap); @@ -521,20 +521,20 @@ void __init add_bridge(struct device_node *np) struct pci_controller *hose; struct resource r; const int *bus_range; - const uint *ptr; + const void *ptr; memset(&r, 0, sizeof(r)); if (of_address_to_resource(np, 0, &r)) { printk(KERN_INFO "No PCI reg property in device tree\n"); return; } - if (!(ptr = of_get_property(np, "clock-frequency", NULL))) { + if (!(ptr = get_property(np, "clock-frequency", NULL))) { printk(KERN_INFO "No clock-frequency property in PCI node"); return; } - pci_clk_frq = *ptr; + pci_clk_frq = *(uint *) ptr; of_node_put(np); - bus_range = of_get_property(np, "bus-range", &len); + bus_range = get_property(np, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", np->full_name); diff --git a/trunk/arch/powerpc/platforms/83xx/Kconfig b/trunk/arch/powerpc/platforms/83xx/Kconfig index 19cafdf6df93..713b31a16ce9 100644 --- a/trunk/arch/powerpc/platforms/83xx/Kconfig +++ b/trunk/arch/powerpc/platforms/83xx/Kconfig @@ -1,6 +1,8 @@ +menu "Platform support" + depends on PPC_83xx + choice prompt "Machine Type" - depends on PPC_83xx default MPC834x_MDS config MPC8313_RDB @@ -16,13 +18,6 @@ config MPC832x_MDS help This option enables support for the MPC832x MDS evaluation board. -config MPC832x_RDB - bool "Freescale MPC832x RDB" - select DEFAULT_UIMAGE - select QUICC_ENGINE - help - This option enables support for the MPC8323 RDB board. - config MPC834x_MDS bool "Freescale MPC834x MDS" select DEFAULT_UIMAGE @@ -62,7 +57,7 @@ config PPC_MPC832x bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - default y if MPC832x_MDS || MPC832x_RDB + default y if MPC832x_MDS config MPC834x bool @@ -75,3 +70,5 @@ config PPC_MPC836x select PPC_UDBG_16550 select PPC_INDIRECT_PCI default y if MPC836x_MDS + +endmenu diff --git a/trunk/arch/powerpc/platforms/83xx/Makefile b/trunk/arch/powerpc/platforms/83xx/Makefile index 31a91b53f528..dfc970d0df10 100644 --- a/trunk/arch/powerpc/platforms/83xx/Makefile +++ b/trunk/arch/powerpc/platforms/83xx/Makefile @@ -4,7 +4,6 @@ obj-y := misc.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o -obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c index fff09f5d6edf..17e3a3c6d8b4 100644 --- a/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -41,6 +41,7 @@ #include #include "mpc83xx.h" +#include "mpc832x_mds.h" #undef DEBUG #ifdef DEBUG diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.h b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.h new file mode 100644 index 000000000000..a49588904f8a --- /dev/null +++ b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Description: + * MPC832x MDS board specific header. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC832x_MDS_H__ +#define __MACH_MPC832x_MDS_H__ + +extern u8 *get_bcsr(void); + +#endif /* __MACH_MPC832x_MDS_H__ */ diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c deleted file mode 100644 index 6b71e9ffb11a..000000000000 --- a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * arch/powerpc/platforms/83xx/mpc832x_rdb.c - * - * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved. - * - * Description: - * MPC832x RDB board specific routines. - * This file is based on mpc832x_mds.c and mpc8313_rdb.c - * Author: Michael Barkowski - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "mpc83xx.h" - -#undef DEBUG -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc832x_rdb_setup_arch(void) -{ - struct device_node *np; - - if (ppc_md.progress) - ppc_md.progress("mpc832x_rdb_setup_arch()", 0); - -#ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; -#endif - -#ifdef CONFIG_QUICC_ENGINE - qe_reset(); - - if ((np = of_find_node_by_name(np, "par_io")) != NULL) { - par_io_init(np); - of_node_put(np); - - for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) - par_io_of_config(np); - } -#endif /* CONFIG_QUICC_ENGINE */ -} - -static struct of_device_id mpc832x_ids[] = { - { .type = "soc", }, - { .compatible = "soc", }, - { .type = "qe", }, - {}, -}; - -static int __init mpc832x_declare_of_platform_devices(void) -{ - if (!machine_is(mpc832x_rdb)) - return 0; - - /* Publish the QE devices */ - of_platform_bus_probe(NULL, mpc832x_ids, NULL); - - return 0; -} -device_initcall(mpc832x_declare_of_platform_devices); - -void __init mpc832x_rdb_init_IRQ(void) -{ - - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); - of_node_put(np); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return; - - qe_ic_init(np, 0); - of_node_put(np); -#endif /* CONFIG_QUICC_ENGINE */ -} - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc832x_rdb_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC832xRDB"); -} - -define_machine(mpc832x_rdb) { - .name = "MPC832x RDB", - .probe = mpc832x_rdb_probe, - .setup_arch = mpc832x_rdb_setup_arch, - .init_IRQ = mpc832x_rdb_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/trunk/arch/powerpc/platforms/83xx/mpc834x_itx.h b/trunk/arch/powerpc/platforms/83xx/mpc834x_itx.h new file mode 100644 index 000000000000..174ca4ef55f3 --- /dev/null +++ b/trunk/arch/powerpc/platforms/83xx/mpc834x_itx.h @@ -0,0 +1,23 @@ +/* + * arch/powerpc/platforms/83xx/mpc834x_itx.h + * + * MPC834X ITX common board definitions + * + * Maintainer: Kumar Gala + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_MPC83XX_ITX_H__ +#define __MACH_MPC83XX_ITX_H__ + +#define PIRQA MPC83xx_IRQ_EXT4 +#define PIRQB MPC83xx_IRQ_EXT5 +#define PIRQC MPC83xx_IRQ_EXT6 +#define PIRQD MPC83xx_IRQ_EXT7 + +#endif /* __MACH_MPC83XX_ITX_H__ */ diff --git a/trunk/arch/powerpc/platforms/83xx/pci.c b/trunk/arch/powerpc/platforms/83xx/pci.c index 774457d09e94..9c3650555144 100644 --- a/trunk/arch/powerpc/platforms/83xx/pci.c +++ b/trunk/arch/powerpc/platforms/83xx/pci.c @@ -60,7 +60,7 @@ int __init add_bridge(struct device_node *dev) has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); /* Get bus range if any */ - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); diff --git a/trunk/arch/powerpc/platforms/85xx/Kconfig b/trunk/arch/powerpc/platforms/85xx/Kconfig index 629926e01e90..e764c0aced88 100644 --- a/trunk/arch/powerpc/platforms/85xx/Kconfig +++ b/trunk/arch/powerpc/platforms/85xx/Kconfig @@ -1,6 +1,8 @@ +menu "Platform support" + depends on PPC_85xx + choice prompt "Machine Type" - depends on PPC_85xx default MPC8540_ADS config MPC8540_ADS @@ -28,12 +30,6 @@ config MPC85xx_MDS help This option enables support for the MPC85xx MDS board -config MPC8544_DS - bool "Freescale MPC8544 DS" - select DEFAULT_UIMAGE - help - This option enables support for the MPC8544 DS board - endchoice config MPC8540 @@ -44,15 +40,33 @@ config MPC8540 config MPC8560 bool - select CPM2 + select PPC_INDIRECT_PCI default y if MPC8560_ADS config MPC85xx bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - select PPC_INDIRECT_PCI_BE - select MPIC select SERIAL_8250_SHARE_IRQ if SERIAL_8250 - default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \ - || MPC85xx_MDS || MPC8544_DS + default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS + +config PPC_INDIRECT_PCI_BE + bool + depends on PPC_85xx + default y + +config MPIC + bool + default y + +config CPM2 + bool + depends on MPC8560 + default y + help + The CPM2 (Communications Processor Module) is a coprocessor on + embedded CPUs made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with a CPM2 coprocessor + on it. + +endmenu diff --git a/trunk/arch/powerpc/platforms/85xx/Makefile b/trunk/arch/powerpc/platforms/85xx/Makefile index 4e02cbb14cf7..4e63917ada9d 100644 --- a/trunk/arch/powerpc/platforms/85xx/Makefile +++ b/trunk/arch/powerpc/platforms/85xx/Makefile @@ -5,5 +5,4 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o -obj-$(CONFIG_MPC8544_DS) += mpc8544_ds.o obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o diff --git a/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c b/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c deleted file mode 100644 index 2867f85e6325..000000000000 --- a/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * MPC8544 DS Board Setup - * - * Author Xianghua Xiao (x.xiao@freescale.com) - * Copyright 2007 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "mpc85xx.h" - -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -#else -#define DBG(fmt, args...) -#endif - - -void __init mpc8544_ds_pic_init(void) -{ - struct mpic *mpic; - struct resource r; - struct device_node *np = NULL; -#ifdef CONFIG_PPC_I8259 - struct device_node *cascade_node = NULL; - int cascade_irq; -#endif - - np = of_find_node_by_type(np, "open-pic"); - - if (np == NULL) { - printk(KERN_ERR "Could not find open-pic node\n"); - return; - } - - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "Failed to map mpic register space\n"); - of_node_put(np); - return; - } - - /* Alloc mpic structure and per isu has 16 INT entries. */ - mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 16, 64, " OPENPIC "); - BUG_ON(mpic == NULL); - - /* - * 48 Internal Interrupts - */ - mpic_assign_isu(mpic, 0, r.start + 0x10200); - mpic_assign_isu(mpic, 1, r.start + 0x10400); - mpic_assign_isu(mpic, 2, r.start + 0x10600); - - /* - * 16 External interrupts - */ - mpic_assign_isu(mpic, 3, r.start + 0x10000); - - mpic_init(mpic); - -#ifdef CONFIG_PPC_I8259 - /* Initialize the i8259 controller */ - for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { - cascade_node = np; - break; - } - - if (cascade_node == NULL) { - printk(KERN_DEBUG "Could not find i8259 PIC\n"); - return; - } - - cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { - printk(KERN_ERR "Failed to map cascade interrupt\n"); - return; - } - - DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq); - - i8259_init(cascade_node, 0); - of_node_put(cascade_node); - - set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade); -#endif /* CONFIG_PPC_I8259 */ -} - - -/* - * Setup the architecture - */ -static void __init mpc8544_ds_setup_arch(void) -{ - if (ppc_md.progress) - ppc_md.progress("mpc8544_ds_setup_arch()", 0); - - printk("MPC8544 DS board from Freescale Semiconductor\n"); -} - - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc8544_ds_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC8544DS"); -} - -define_machine(mpc8544_ds) { - .name = "MPC8544 DS", - .probe = mpc8544_ds_probe, - .setup_arch = mpc8544_ds_setup_arch, - .init_IRQ = mpc8544_ds_pic_init, - .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 5d27621f0927..8ed034aeca5f 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -227,7 +227,7 @@ static void __init mpc85xx_ads_setup_arch(void) if (cpu != 0) { const unsigned int *fp; - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 7e71636f9098..4232686be441 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -237,7 +237,7 @@ static void __init mpc85xx_cds_setup_arch(void) if (cpu != 0) { const unsigned int *fp; - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 54db41689954..81144d2ae455 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -80,7 +80,7 @@ static void __init mpc85xx_mds_setup_arch(void) np = of_find_node_by_type(NULL, "cpu"); if (np != NULL) { const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); + get_property(np, "clock-frequency", NULL); if (fp != NULL) loops_per_jiffy = *fp / HZ; else diff --git a/trunk/arch/powerpc/platforms/85xx/pci.c b/trunk/arch/powerpc/platforms/85xx/pci.c index 48f17e23d771..05930eeb6e7f 100644 --- a/trunk/arch/powerpc/platforms/85xx/pci.c +++ b/trunk/arch/powerpc/platforms/85xx/pci.c @@ -51,7 +51,7 @@ int __init add_bridge(struct device_node *dev) has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); /* Get bus range if any */ - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); diff --git a/trunk/arch/powerpc/platforms/86xx/Kconfig b/trunk/arch/powerpc/platforms/86xx/Kconfig index d1bcff500464..0c70944d0e37 100644 --- a/trunk/arch/powerpc/platforms/86xx/Kconfig +++ b/trunk/arch/powerpc/platforms/86xx/Kconfig @@ -1,6 +1,8 @@ +menu "Platform Support" + depends on PPC_86xx + choice prompt "Machine Type" - depends on PPC_86xx default MPC8641_HPCN config MPC8641_HPCN @@ -12,10 +14,20 @@ config MPC8641_HPCN endchoice + config MPC8641 bool select PPC_INDIRECT_PCI - select PPC_INDIRECT_PCI_BE select PPC_UDBG_16550 - select MPIC default y if MPC8641_HPCN + +config MPIC + bool + default y + +config PPC_INDIRECT_PCI_BE + bool + depends on PPC_86xx + default y + +endmenu diff --git a/trunk/arch/powerpc/platforms/86xx/Makefile b/trunk/arch/powerpc/platforms/86xx/Makefile index 418fd8f4d268..476a6eeee710 100644 --- a/trunk/arch/powerpc/platforms/86xx/Makefile +++ b/trunk/arch/powerpc/platforms/86xx/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o -obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_PCI) += pci.o mpc86xx_pcie.o diff --git a/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 3d3d98f5bd4a..f42f801cf84e 100644 --- a/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -349,7 +349,7 @@ mpc86xx_hpcn_setup_arch(void) if (np != 0) { const unsigned int *fp; - fp = of_get_property(np, "clock-frequency", NULL); + fp = get_property(np, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else @@ -384,7 +384,7 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_file *m) root = of_find_node_by_path("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); seq_printf(m, "Machine\t\t: %s\n", model); of_node_put(root); diff --git a/trunk/arch/powerpc/sysdev/fsl_pcie.c b/trunk/arch/powerpc/platforms/86xx/mpc86xx_pcie.c similarity index 99% rename from trunk/arch/powerpc/sysdev/fsl_pcie.c rename to trunk/arch/powerpc/platforms/86xx/mpc86xx_pcie.c index 041c07e8b665..a2f4f730213e 100644 --- a/trunk/arch/powerpc/sysdev/fsl_pcie.c +++ b/trunk/arch/powerpc/platforms/86xx/mpc86xx_pcie.c @@ -24,6 +24,8 @@ #include #include +#include "mpc86xx.h" + #define PCI_CFG_OUT out_be32 /* ERRATA PCI-Ex 14 PCIE Controller timeout */ diff --git a/trunk/arch/powerpc/platforms/86xx/pci.c b/trunk/arch/powerpc/platforms/86xx/pci.c index 8235c562661f..481e18ed5be9 100644 --- a/trunk/arch/powerpc/platforms/86xx/pci.c +++ b/trunk/arch/powerpc/platforms/86xx/pci.c @@ -22,9 +22,9 @@ #include #include #include +#include #include #include -#include #include "mpc86xx.h" @@ -163,7 +163,7 @@ int __init add_bridge(struct device_node *dev) has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); /* Get bus range if any */ - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); diff --git a/trunk/arch/powerpc/platforms/8xx/Kconfig b/trunk/arch/powerpc/platforms/8xx/Kconfig index 39bb8c5ebe70..beea6834bb7e 100644 --- a/trunk/arch/powerpc/platforms/8xx/Kconfig +++ b/trunk/arch/powerpc/platforms/8xx/Kconfig @@ -1,3 +1,6 @@ +menu "Platform support" + depends on PPC_8xx + config FADS bool @@ -6,7 +9,6 @@ config CPM1 choice prompt "8xx Machine Type" - depends on PPC_8xx depends on 8xx default MPC885ADS @@ -34,36 +36,38 @@ config MPC885ADS endchoice menu "Freescale Ethernet driver platform-specific options" - depends on (FS_ENET && MPC885ADS) + depends on (FS_ENET && MPC885ADS) + + config MPC8xx_SECOND_ETH + bool "Second Ethernet channel" + depends on MPC885ADS + default y + help + This enables support for second Ethernet on MPC885ADS and MPC86xADS boards. + The latter will use SCC1, for 885ADS you can select it below. + + choice + prompt "Second Ethernet channel" + depends on MPC8xx_SECOND_ETH + default MPC8xx_SECOND_ETH_FEC2 + + config MPC8xx_SECOND_ETH_FEC2 + bool "FEC2" + depends on MPC885ADS + help + Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2 + (often 2-nd UART) will not work if this is enabled. + + config MPC8xx_SECOND_ETH_SCC3 + bool "SCC3" + depends on MPC885ADS + help + Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1 + (often 1-nd UART) will not work if this is enabled. + + endchoice - config MPC8xx_SECOND_ETH - bool "Second Ethernet channel" - depends on MPC885ADS - default y - help - This enables support for second Ethernet on MPC885ADS and MPC86xADS boards. - The latter will use SCC1, for 885ADS you can select it below. - - choice - prompt "Second Ethernet channel" - depends on MPC8xx_SECOND_ETH - default MPC8xx_SECOND_ETH_FEC2 - - config MPC8xx_SECOND_ETH_FEC2 - bool "FEC2" - depends on MPC885ADS - help - Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2 - (often 2-nd UART) will not work if this is enabled. - - config MPC8xx_SECOND_ETH_SCC3 - bool "SCC3" - depends on MPC885ADS - help - Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1 - (often 1-nd UART) will not work if this is enabled. - - endchoice +endmenu endmenu @@ -94,7 +98,7 @@ config 8xx_CPU6 require workarounds for Linux (and most other OSes to work). If you get a BUG() very early in boot, this might fix the problem. For more details read the document entitled "MPC860 Family Device Errata - Reference" on Freescale's website. This option also incurs a + Reference" on Motorola's website. This option also incurs a performance hit. If in doubt, say N here. @@ -131,3 +135,4 @@ config UCODE_PATCH depends on !NO_UCODE_PATCH endmenu + diff --git a/trunk/arch/powerpc/platforms/8xx/m8xx_setup.c b/trunk/arch/powerpc/platforms/8xx/m8xx_setup.c index 0901dbada350..9ed7125f0150 100644 --- a/trunk/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/trunk/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -85,17 +85,17 @@ init_internal_rtc(void) static int __init get_freq(char *name, unsigned long *val) { struct device_node *cpu; - const unsigned int *fp; + unsigned int *fp; int found = 0; /* The cpu node should have timebase and clock frequency properties */ cpu = of_find_node_by_type(NULL, "cpu"); if (cpu) { - fp = of_get_property(cpu, name, NULL); + fp = (unsigned int *)get_property(cpu, name, NULL); if (fp) { found = 1; - *val = *fp; + *val = *fp++; } of_node_put(cpu); @@ -262,7 +262,7 @@ void mpc8xx_show_cpuinfo(struct seq_file *m) root = of_find_node_by_path("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); seq_printf(m, "Machine\t\t: %s\n", model); of_node_put(root); diff --git a/trunk/arch/powerpc/platforms/8xx/mpc86xads.h b/trunk/arch/powerpc/platforms/8xx/mpc86xads.h index 59bad2f9ae51..b5d19dd0619c 100644 --- a/trunk/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/trunk/arch/powerpc/platforms/8xx/mpc86xads.h @@ -37,7 +37,7 @@ #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver -#define PCMCIA_MEM_ADDR ((uint)0xff020000) +#define PCMCIA_MEM_ADDR (uint)0xff020000) #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) /* Bits of interest in the BCSRs. diff --git a/trunk/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/trunk/arch/powerpc/platforms/8xx/mpc86xads_setup.c index a35315af5c53..ef52ce701b0e 100644 --- a/trunk/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/trunk/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -247,7 +247,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data) } } -int platform_device_skip(const char *model, int id) +int platform_device_skip(char *model, int id) { return 0; } @@ -260,7 +260,7 @@ static void __init mpc86xads_setup_arch(void) if (cpu != 0) { const unsigned int *fp; - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else diff --git a/trunk/arch/powerpc/platforms/8xx/mpc885ads.h b/trunk/arch/powerpc/platforms/8xx/mpc885ads.h index 7c31aec284c2..30cbebfe84c5 100644 --- a/trunk/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/trunk/arch/powerpc/platforms/8xx/mpc885ads.h @@ -37,7 +37,7 @@ #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver -#define PCMCIA_MEM_ADDR ((uint)0xff020000) +#define PCMCIA_MEM_ADDR (uint)0xff020000) #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) /* Bits of interest in the BCSRs. diff --git a/trunk/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/trunk/arch/powerpc/platforms/8xx/mpc885ads_setup.c index a57b57785acd..c5fefdf66c0a 100644 --- a/trunk/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/trunk/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -322,7 +322,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data) } } -int platform_device_skip(const char *model, int id) +int platform_device_skip(char *model, int id) { #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 const char *dev = "FEC"; @@ -346,7 +346,7 @@ static void __init mpc885ads_setup_arch(void) if (cpu != 0) { const unsigned int *fp; - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig deleted file mode 100644 index 51e33347c147..000000000000 --- a/trunk/arch/powerpc/platforms/Kconfig +++ /dev/null @@ -1,259 +0,0 @@ -menu "Platform support" - -choice - prompt "Machine type" - depends on PPC64 || CLASSIC32 - default PPC_MULTIPLATFORM - -config PPC_MULTIPLATFORM - bool "Generic desktop/server/laptop" - help - Select this option if configuring for an IBM pSeries or - RS/6000 machine, an Apple machine, or a PReP, CHRP, - Maple or Cell-based machine. - -config EMBEDDED6xx - bool "Embedded 6xx/7xx/7xxx-based board" - depends on PPC32 && (BROKEN||BROKEN_ON_SMP) - -config APUS - bool "Amiga-APUS" - depends on PPC32 && BROKEN - help - Select APUS if configuring for a PowerUP Amiga. - More information is available at: - . -endchoice - -source "arch/powerpc/platforms/pseries/Kconfig" -source "arch/powerpc/platforms/iseries/Kconfig" -source "arch/powerpc/platforms/chrp/Kconfig" -source "arch/powerpc/platforms/52xx/Kconfig" -source "arch/powerpc/platforms/powermac/Kconfig" -source "arch/powerpc/platforms/prep/Kconfig" -source "arch/powerpc/platforms/maple/Kconfig" -source "arch/powerpc/platforms/pasemi/Kconfig" -source "arch/powerpc/platforms/celleb/Kconfig" -source "arch/powerpc/platforms/ps3/Kconfig" -source "arch/powerpc/platforms/cell/Kconfig" -source "arch/powerpc/platforms/8xx/Kconfig" -source "arch/powerpc/platforms/82xx/Kconfig" -source "arch/powerpc/platforms/83xx/Kconfig" -source "arch/powerpc/platforms/85xx/Kconfig" -source "arch/powerpc/platforms/86xx/Kconfig" -source "arch/powerpc/platforms/embedded6xx/Kconfig" -#source "arch/powerpc/platforms/4xx/Kconfig - -config PPC_NATIVE - bool - depends on PPC_MULTIPLATFORM - help - Support for running natively on the hardware, i.e. without - a hypervisor. This option is not user-selectable but should - be selected by all platforms that need it. - -config UDBG_RTAS_CONSOLE - bool "RTAS based debug console" - depends on PPC_RTAS - default n - -config PPC_UDBG_BEAT - bool "BEAT based debug console" - depends on PPC_CELLEB - default n - -config XICS - depends on PPC_PSERIES - bool - default y - -config MPIC - bool - default n - -config MPIC_WEIRD - bool - default n - -config PPC_I8259 - bool - default n - -config U3_DART - bool - depends on PPC_MULTIPLATFORM && PPC64 - default n - -config PPC_RTAS - bool - default n - -config RTAS_ERROR_LOGGING - bool - depends on PPC_RTAS - default n - -config RTAS_PROC - bool "Proc interface to RTAS" - depends on PPC_RTAS - default y - -config RTAS_FLASH - tristate "Firmware flash interface" - depends on PPC64 && RTAS_PROC - -config PPC_PMI - tristate "Support for PMI" - depends PPC_IBM_CELL_BLADE - help - PMI (Platform Management Interrupt) is a way to - communicate with the BMC (Baseboard Mangement Controller). - It is used in some IBM Cell blades. - default m - -config MMIO_NVRAM - bool - default n - -config MPIC_U3_HT_IRQS - bool - depends on PPC_MAPLE - default y - -config IBMVIO - depends on PPC_PSERIES || PPC_ISERIES - bool - default y - -config IBMEBUS - depends on PPC_PSERIES - bool "Support for GX bus based adapters" - help - Bus device driver for GX bus based adapters. - -config PPC_MPC106 - bool - default n - -config PPC_970_NAP - bool - default n - -config PPC_INDIRECT_IO - bool - select GENERIC_IOMAP - default n - -config GENERIC_IOMAP - bool - default n - -source "drivers/cpufreq/Kconfig" - -menu "CPU Frequency drivers" - depends on CPU_FREQ - -config CPU_FREQ_PMAC - bool "Support for Apple PowerBooks" - depends on ADB_PMU && PPC32 - select CPU_FREQ_TABLE - help - This adds support for frequency switching on Apple PowerBooks, - this currently includes some models of iBook & Titanium - PowerBook. - -config CPU_FREQ_PMAC64 - bool "Support for some Apple G5s" - depends on PPC_PMAC && PPC64 - select CPU_FREQ_TABLE - help - This adds support for frequency switching on Apple iMac G5, - and some of the more recent desktop G5 machines as well. - -config PPC_PASEMI_CPUFREQ - bool "Support for PA Semi PWRficient" - depends on PPC_PASEMI - default y - select CPU_FREQ_TABLE - help - This adds the support for frequency switching on PA Semi - PWRficient processors. - -endmenu - -config PPC601_SYNC_FIX - bool "Workarounds for PPC601 bugs" - depends on 6xx && (PPC_PREP || PPC_PMAC) - help - Some versions of the PPC601 (the first PowerPC chip) have bugs which - mean that extra synchronization instructions are required near - certain instructions, typically those that make major changes to the - CPU state. These extra instructions reduce performance slightly. - If you say N here, these extra instructions will not be included, - resulting in a kernel which will run faster but may not run at all - on some systems with the PPC601 chip. - - If in doubt, say Y here. - -config TAU - bool "On-chip CPU temperature sensor support" - depends on CLASSIC32 - help - G3 and G4 processors have an on-chip temperature sensor called the - 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die - temperature within 2-4 degrees Celsius. This option shows the current - on-die temperature in /proc/cpuinfo if the cpu supports it. - - Unfortunately, on some chip revisions, this sensor is very inaccurate - and in many cases, does not work at all, so don't assume the cpu - temp is actually what /proc/cpuinfo says it is. - -config TAU_INT - bool "Interrupt driven TAU driver (DANGEROUS)" - depends on TAU - ---help--- - The TAU supports an interrupt driven mode which causes an interrupt - whenever the temperature goes out of range. This is the fastest way - to get notified the temp has exceeded a range. With this option off, - a timer is used to re-check the temperature periodically. - - However, on some cpus it appears that the TAU interrupt hardware - is buggy and can cause a situation which would lead unexplained hard - lockups. - - Unless you are extending the TAU driver, or enjoy kernel/hardware - debugging, leave this option off. - -config TAU_AVERAGE - bool "Average high and low temp" - depends on TAU - ---help--- - The TAU hardware can compare the temperature to an upper and lower - bound. The default behavior is to show both the upper and lower - bound in /proc/cpuinfo. If the range is large, the temperature is - either changing a lot, or the TAU hardware is broken (likely on some - G4's). If the range is small (around 4 degrees), the temperature is - relatively stable. If you say Y here, a single temperature value, - halfway between the upper and lower bounds, will be reported in - /proc/cpuinfo. - - If in doubt, say N here. - -config QUICC_ENGINE - bool - help - The QUICC Engine (QE) is a new generation of communications - coprocessors on Freescale embedded CPUs (akin to CPM in older chips). - Selecting this option means that you wish to build a kernel - for a machine with a QE coprocessor. - -config CPM2 - bool - default n - help - The CPM2 (Communications Processor Module) is a coprocessor on - embedded CPUs made by Freescale. Selecting this option means that - you wish to build a kernel for a machine with a CPM2 coprocessor - on it (826x, 827x, 8560). - -endmenu diff --git a/trunk/arch/powerpc/platforms/cell/Kconfig b/trunk/arch/powerpc/platforms/cell/Kconfig index 82551770917c..06a85b704331 100644 --- a/trunk/arch/powerpc/platforms/cell/Kconfig +++ b/trunk/arch/powerpc/platforms/cell/Kconfig @@ -1,26 +1,3 @@ -config PPC_CELL - bool - default n - -config PPC_CELL_NATIVE - bool - select PPC_CELL - select PPC_DCR_MMIO - select PPC_OF_PLATFORM_PCI - select PPC_INDIRECT_IO - select PPC_NATIVE - select MPIC - default n - -config PPC_IBM_CELL_BLADE - bool "IBM Cell Blade" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_CELL_NATIVE - select PPC_RTAS - select MMIO_NVRAM - select PPC_UDBG_16550 - select UDBG_RTAS_CONSOLE - menu "Cell Broadband Engine options" depends on PPC_CELL @@ -41,7 +18,6 @@ config SPU_BASE config CBE_RAS bool "RAS features for bare metal Cell BE" - depends on PPC_CELL_NATIVE default y config CBE_THERM diff --git a/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c b/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c index f9ac3fe3be97..a3850fd1e94c 100644 --- a/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/trunk/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -25,12 +25,9 @@ #include #include -#include #include #include #include -#include -#include #include "cbe_regs.h" @@ -71,38 +68,6 @@ static u64 MIC_Slow_Next_Timer_table[] = { * hardware specific functions */ -static struct of_device *pmi_dev; - -static int set_pmode_pmi(int cpu, unsigned int pmode) -{ - int ret; - pmi_message_t pmi_msg; -#ifdef DEBUG - u64 time; -#endif - - pmi_msg.type = PMI_TYPE_FREQ_CHANGE; - pmi_msg.data1 = cbe_cpu_to_node(cpu); - pmi_msg.data2 = pmode; - -#ifdef DEBUG - time = (u64) get_cycles(); -#endif - - pmi_send_message(pmi_dev, pmi_msg); - ret = pmi_msg.data2; - - pr_debug("PMI returned slow mode %d\n", ret); - -#ifdef DEBUG - time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */ - time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */ - pr_debug("had to wait %lu ns for a transition\n", time); -#endif - return ret; -} - - static int get_pmode(int cpu) { int ret; @@ -114,7 +79,7 @@ static int get_pmode(int cpu) return ret; } -static int set_pmode_reg(int cpu, unsigned int pmode) +static int set_pmode(int cpu, unsigned int pmode) { struct cbe_pmd_regs __iomem *pmd_regs; struct cbe_mic_tm_regs __iomem *mic_tm_regs; @@ -155,71 +120,37 @@ static int set_pmode_reg(int cpu, unsigned int pmode) return 0; } -static int set_pmode(int cpu, unsigned int slow_mode) { - if (pmi_dev) - return set_pmode_pmi(cpu, slow_mode); - else - return set_pmode_reg(cpu, slow_mode); -} - -static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) -{ - struct cpufreq_policy policy; - u8 cpu; - u8 cbe_pmode_new; - - BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); - - cpu = cbe_node_to_cpu(pmi_msg.data1); - cbe_pmode_new = pmi_msg.data2; - - cpufreq_get_policy(&policy, cpu); - - policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency); - policy.min = min(policy.min, policy.max); - - pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max); - cpufreq_set_policy(&policy); -} - -static struct pmi_handler cbe_pmi_handler = { - .type = PMI_TYPE_FREQ_CHANGE, - .handle_pmi_message = cbe_cpufreq_handle_pmi, -}; - - /* * cpufreq functions */ -static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) +static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy) { - const u32 *max_freqp; - u32 max_freq; + u32 *max_freq; int i, cur_pmode; struct device_node *cpu; cpu = of_get_cpu_node(policy->cpu, NULL); - if (!cpu) + if(!cpu) return -ENODEV; pr_debug("init cpufreq on CPU %d\n", policy->cpu); - max_freqp = of_get_property(cpu, "clock-frequency", NULL); + max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); - if (!max_freqp) + if(!max_freq) return -EINVAL; - /* we need the freq in kHz */ - max_freq = *max_freqp / 1000; + // we need the freq in kHz + *max_freq /= 1000; - pr_debug("max clock-frequency is at %u kHz\n", max_freq); + pr_debug("max clock-frequency is at %u kHz\n", *max_freq); pr_debug("initializing frequency table\n"); - /* initialize frequency table */ + // initialize frequency table for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { - cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index; + cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index; pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); } @@ -236,10 +167,10 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpus = cpu_sibling_map[policy->cpu]; #endif - cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); + cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu); /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ - return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); + return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) @@ -271,7 +202,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target freqs.new = cbe_freqs[cbe_pmode_new].frequency; freqs.cpu = policy->cpu; - mutex_lock(&cbe_switch_mutex); + mutex_lock (&cbe_switch_mutex); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", @@ -302,26 +233,11 @@ static struct cpufreq_driver cbe_cpufreq_driver = { static int __init cbe_cpufreq_init(void) { - struct device_node *np; - - if (!machine_is(cell)) - return -ENODEV; - - np = of_find_node_by_type(NULL, "ibm,pmi"); - - pmi_dev = of_find_device_by_node(np); - - if (pmi_dev) - pmi_register_handler(pmi_dev, &cbe_pmi_handler); - return cpufreq_register_driver(&cbe_cpufreq_driver); } static void __exit cbe_cpufreq_exit(void) { - if (pmi_dev) - pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); - cpufreq_unregister_driver(&cbe_cpufreq_driver); } diff --git a/trunk/arch/powerpc/platforms/cell/cbe_regs.c b/trunk/arch/powerpc/platforms/cell/cbe_regs.c index 12c9674b4b1f..9a0ee62691d5 100644 --- a/trunk/arch/powerpc/platforms/cell/cbe_regs.c +++ b/trunk/arch/powerpc/platforms/cell/cbe_regs.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include "cbe_regs.h" @@ -29,7 +27,6 @@ static struct cbe_regs_map { struct device_node *cpu_node; - struct device_node *be_node; struct cbe_pmd_regs __iomem *pmd_regs; struct cbe_iic_regs __iomem *iic_regs; struct cbe_mic_tm_regs __iomem *mic_tm_regs; @@ -40,43 +37,30 @@ static int cbe_regs_map_count; static struct cbe_thread_map { struct device_node *cpu_node; - struct device_node *be_node; struct cbe_regs_map *regs; - unsigned int thread_id; - unsigned int cbe_id; } cbe_thread_map[NR_CPUS]; -static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE }; -static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE; - static struct cbe_regs_map *cbe_find_map(struct device_node *np) { int i; struct device_node *tmp_np; - if (strcasecmp(np->type, "spe")) { - for (i = 0; i < cbe_regs_map_count; i++) - if (cbe_regs_maps[i].cpu_node == np || - cbe_regs_maps[i].be_node == np) - return &cbe_regs_maps[i]; - return NULL; - } + if (strcasecmp(np->type, "spe") == 0) { + if (np->data == NULL) { + /* walk up path until cpu node was found */ + tmp_np = np->parent; + while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0) + tmp_np = tmp_np->parent; - if (np->data) + np->data = cbe_find_map(tmp_np); + } return np->data; + } - /* walk up path until cpu or be node was found */ - tmp_np = np; - do { - tmp_np = tmp_np->parent; - /* on a correct devicetree we wont get up to root */ - BUG_ON(!tmp_np); - } while (strcasecmp(tmp_np->type, "cpu") && - strcasecmp(tmp_np->type, "be")); - - np->data = cbe_find_map(tmp_np); - - return np->data; + for (i = 0; i < cbe_regs_map_count; i++) + if (cbe_regs_maps[i].cpu_node == np) + return &cbe_regs_maps[i]; + return NULL; } struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np) @@ -146,105 +130,38 @@ struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu) } EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs); +/* FIXME + * This is little more than a stub at the moment. It should be + * fleshed out so that it works for both SMT and non-SMT, no + * matter if the passed cpu is odd or even. + * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1. + * For SMT disabled, returns 0 for all cpus. + */ u32 cbe_get_hw_thread_id(int cpu) { - return cbe_thread_map[cpu].thread_id; + return (cpu & 1); } EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id); -u32 cbe_cpu_to_node(int cpu) -{ - return cbe_thread_map[cpu].cbe_id; -} -EXPORT_SYMBOL_GPL(cbe_cpu_to_node); - -u32 cbe_node_to_cpu(int node) -{ - return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t)); -} -EXPORT_SYMBOL_GPL(cbe_node_to_cpu); - -static struct device_node *cbe_get_be_node(int cpu_id) -{ - struct device_node *np; - - for_each_node_by_type (np, "be") { - int len,i; - const phandle *cpu_handle; - - cpu_handle = of_get_property(np, "cpus", &len); - - for (i=0; ibe_node) { - struct device_node *be, *np; - - be = map->be_node; - - for_each_node_by_type(np, "pervasive") - if (of_get_parent(np) == be) - map->pmd_regs = of_iomap(np, 0); - - for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller") - if (of_get_parent(np) == be) - map->iic_regs = of_iomap(np, 2); - - for_each_node_by_type(np, "mic-tm") - if (of_get_parent(np) == be) - map->mic_tm_regs = of_iomap(np, 0); - } else { - struct device_node *cpu; - /* That hack must die die die ! */ - const struct address_prop { - unsigned long address; - unsigned int len; - } __attribute__((packed)) *prop; - - cpu = map->cpu_node; - - prop = of_get_property(cpu, "pervasive", NULL); - if (prop != NULL) - map->pmd_regs = ioremap(prop->address, prop->len); - - prop = of_get_property(cpu, "iic", NULL); - if (prop != NULL) - map->iic_regs = ioremap(prop->address, prop->len); - - prop = of_get_property(cpu, "mic-tm", NULL); - if (prop != NULL) - map->mic_tm_regs = ioremap(prop->address, prop->len); - } -} - - void __init cbe_regs_init(void) { int i; - unsigned int thread_id; struct device_node *cpu; /* Build local fast map of CPUs */ - for_each_possible_cpu(i) { - cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id); - cbe_thread_map[i].be_node = cbe_get_be_node(i); - cbe_thread_map[i].thread_id = thread_id; - } + for_each_possible_cpu(i) + cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL); /* Find maps for each device tree CPU */ for_each_node_by_type(cpu, "cpu") { - struct cbe_regs_map *map; - unsigned int cbe_id; + struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++]; + + /* That hack must die die die ! */ + const struct address_prop { + unsigned long address; + unsigned int len; + } __attribute__((packed)) *prop; - cbe_id = cbe_regs_map_count++; - map = &cbe_regs_maps[cbe_id]; if (cbe_regs_map_count > MAX_CBE) { printk(KERN_ERR "cbe_regs: More BE chips than supported" @@ -253,21 +170,22 @@ void __init cbe_regs_init(void) return; } map->cpu_node = cpu; + for_each_possible_cpu(i) + if (cbe_thread_map[i].cpu_node == cpu) + cbe_thread_map[i].regs = map; - for_each_possible_cpu(i) { - struct cbe_thread_map *thread = &cbe_thread_map[i]; + prop = get_property(cpu, "pervasive", NULL); + if (prop != NULL) + map->pmd_regs = ioremap(prop->address, prop->len); - if (thread->cpu_node == cpu) { - thread->regs = map; - thread->cbe_id = cbe_id; - map->be_node = thread->be_node; - cpu_set(i, cbe_local_mask[cbe_id]); - if(thread->thread_id == 0) - cpu_set(i, cbe_first_online_cpu); - } - } + prop = get_property(cpu, "iic", NULL); + if (prop != NULL) + map->iic_regs = ioremap(prop->address, prop->len); - cbe_fill_regs_map(map); + prop = (struct address_prop *)get_property(cpu, "mic-tm", + NULL); + if (prop != NULL) + map->mic_tm_regs = ioremap(prop->address, prop->len); } } diff --git a/trunk/arch/powerpc/platforms/cell/cbe_regs.h b/trunk/arch/powerpc/platforms/cell/cbe_regs.h index 17d597144877..440a7ecc66ea 100644 --- a/trunk/arch/powerpc/platforms/cell/cbe_regs.h +++ b/trunk/arch/powerpc/platforms/cell/cbe_regs.h @@ -255,11 +255,6 @@ struct cbe_mic_tm_regs { extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu); -/* some utility functions to deal with SMT */ -extern u32 cbe_get_hw_thread_id(int cpu); -extern u32 cbe_cpu_to_node(int cpu); -extern u32 cbe_node_to_cpu(int node); - /* Init this module early */ extern void cbe_regs_init(void); diff --git a/trunk/arch/powerpc/platforms/cell/cbe_thermal.c b/trunk/arch/powerpc/platforms/cell/cbe_thermal.c index f370f0fa6f4c..70e0d968d30f 100644 --- a/trunk/arch/powerpc/platforms/cell/cbe_thermal.c +++ b/trunk/arch/powerpc/platforms/cell/cbe_thermal.c @@ -1,31 +1,6 @@ /* * thermal support for the cell processor * - * This module adds some sysfs attributes to cpu and spu nodes. - * Base for measurements are the digital thermal sensors (DTS) - * located on the chip. - * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius - * The attributes can be found under - * /sys/devices/system/cpu/cpuX/thermal - * /sys/devices/system/spu/spuX/thermal - * - * The following attributes are added for each node: - * temperature: - * contains the current temperature measured by the DTS - * throttle_begin: - * throttling begins when temperature is greater or equal to - * throttle_begin. Setting this value to 125 prevents throttling. - * throttle_end: - * throttling is being ceased, if the temperature is lower than - * throttle_end. Due to a delay between applying throttling and - * a reduced temperature this value should be less than throttle_begin. - * A value equal to throttle_begin provides only a very little hysteresis. - * throttle_full_stop: - * If the temperatrue is greater or equal to throttle_full_stop, - * full throttling is applied to the cpu or spu. This value should be - * greater than throttle_begin and throttle_end. Setting this value to - * 65 prevents the unit from running code at all. - * * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 * * Author: Christian Krafft @@ -56,26 +31,6 @@ #include "cbe_regs.h" #include "spu_priv1_mmio.h" -#define TEMP_MIN 65 -#define TEMP_MAX 125 - -#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode) \ -struct sysdev_attribute attr_ ## _prefix ## _ ## _name = { \ - .attr = { .name = __stringify(_name), .mode = _mode }, \ - .show = _prefix ## _show_ ## _name, \ - .store = _prefix ## _store_ ## _name, \ -}; - -static inline u8 reg_to_temp(u8 reg_value) -{ - return ((reg_value & 0x3f) << 1) + TEMP_MIN; -} - -static inline u8 temp_to_reg(u8 temp) -{ - return ((temp - TEMP_MIN) >> 1) & 0x3f; -} - static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) { struct spu *spu; @@ -88,14 +43,14 @@ static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) /* returns the value for a given spu in a given register */ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg) { - const unsigned int *id; + unsigned int *id; union spe_reg value; struct spu *spu; /* getting the id from the reg attribute will not work on future device-tree layouts * in future we should store the id to the spu struct and use it here */ spu = container_of(sysdev, struct spu, sysdev); - id = of_get_property(spu_devnode(spu), "reg", NULL); + id = (unsigned int *)get_property(spu_devnode(spu), "reg", NULL); value.val = in_be64(®->val); return value.spe[*id]; @@ -103,81 +58,20 @@ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iom static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf) { - u8 value; + int value; struct cbe_pmd_regs __iomem *pmd_regs; pmd_regs = get_pmd_regs(sysdev); value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1); - - return sprintf(buf, "%d\n", reg_to_temp(value)); -} - -static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos) -{ - u64 value; - - value = in_be64(&pmd_regs->tm_tpr.val); - /* access the corresponding byte */ - value >>= pos; + /* clear all other bits */ value &= 0x3F; + /* temp is stored in steps of 2 degrees */ + value *= 2; + /* base temp is 65 degrees */ + value += 65; - return sprintf(buf, "%d\n", reg_to_temp(value)); -} - -static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos) -{ - u64 reg_value; - int temp; - u64 new_value; - int ret; - - ret = sscanf(buf, "%u", &temp); - - if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX) - return -EINVAL; - - new_value = temp_to_reg(temp); - - reg_value = in_be64(&pmd_regs->tm_tpr.val); - - /* zero out bits for new value */ - reg_value &= ~(0xffull << pos); - /* set bits to new value */ - reg_value |= new_value << pos; - - out_be64(&pmd_regs->tm_tpr.val, reg_value); - return size; -} - -static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf) -{ - return show_throttle(get_pmd_regs(sysdev), buf, 0); -} - -static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf) -{ - return show_throttle(get_pmd_regs(sysdev), buf, 8); -} - -static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf) -{ - return show_throttle(get_pmd_regs(sysdev), buf, 16); -} - -static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(get_pmd_regs(sysdev), buf, size, 0); -} - -static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(get_pmd_regs(sysdev), buf, size, 8); -} - -static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(get_pmd_regs(sysdev), buf, size, 16); + return sprintf(buf, "%d\n", (int) value); } static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) @@ -188,9 +82,16 @@ static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); value = in_be64(&pmd_regs->ts_ctsr2); - value = (value >> pos) & 0x3f; + /* access the corresponding byte */ + value >>= pos; + /* clear all other bits */ + value &= 0x3F; + /* temp is stored in steps of 2 degrees */ + value *= 2; + /* base temp is 65 degrees */ + value += 65; - return sprintf(buf, "%d\n", reg_to_temp(value)); + return sprintf(buf, "%d\n", (int) value); } @@ -207,52 +108,13 @@ static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf) return ppe_show_temp(sysdev, buf, 0); } -static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf) -{ - return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32); -} - -static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf) -{ - return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40); -} - -static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf) -{ - return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48); -} - -static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32); -} - -static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40); -} - -static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size) -{ - return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48); -} - - static struct sysdev_attribute attr_spu_temperature = { .attr = {.name = "temperature", .mode = 0400 }, .show = spu_show_temp, }; -static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600); -static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600); -static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600); - - static struct attribute *spu_attributes[] = { &attr_spu_temperature.attr, - &attr_spu_throttle_end.attr, - &attr_spu_throttle_begin.attr, - &attr_spu_throttle_full_stop.attr, NULL, }; @@ -271,16 +133,9 @@ static struct sysdev_attribute attr_ppe_temperature1 = { .show = ppe_show_temp1, }; -static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600); -static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600); -static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600); - static struct attribute *ppe_attributes[] = { &attr_ppe_temperature0.attr, &attr_ppe_temperature1.attr, - &attr_ppe_throttle_end.attr, - &attr_ppe_throttle_begin.attr, - &attr_ppe_throttle_full_stop.attr, NULL, }; diff --git a/trunk/arch/powerpc/platforms/cell/interrupt.c b/trunk/arch/powerpc/platforms/cell/interrupt.c index 4fc4e92775d0..6666d037eb44 100644 --- a/trunk/arch/powerpc/platforms/cell/interrupt.c +++ b/trunk/arch/powerpc/platforms/cell/interrupt.c @@ -261,7 +261,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, return -ENODEV; if (intsize != 1) return -ENODEV; - val = of_get_property(ct, "#interrupt-cells", NULL); + val = get_property(ct, "#interrupt-cells", NULL); if (val == NULL || *val != 1) return -ENODEV; @@ -327,7 +327,7 @@ static int __init setup_iic(void) if (!device_is_compatible(dn, "IBM,CBEA-Internal-Interrupt-Controller")) continue; - np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL); + np = get_property(dn, "ibm,interrupt-server-ranges", NULL); if (np == NULL) { printk(KERN_WARNING "IIC: CPU association not found\n"); of_node_put(dn); diff --git a/trunk/arch/powerpc/platforms/cell/io-workarounds.c b/trunk/arch/powerpc/platforms/cell/io-workarounds.c index d68d920eb2c4..7c73128305ec 100644 --- a/trunk/arch/powerpc/platforms/cell/io-workarounds.c +++ b/trunk/arch/powerpc/platforms/cell/io-workarounds.c @@ -318,7 +318,7 @@ static int __init spider_pci_workaround_init(void) */ list_for_each_entry(phb, &hose_list, list_node) { struct device_node *np = phb->arch_data; - const char *model = of_get_property(np, "model", NULL); + const char *model = get_property(np, "model", NULL); /* If no model property or name isn't exactly "pci", skip */ if (model == NULL || strcmp(np->name, "pci")) diff --git a/trunk/arch/powerpc/platforms/cell/iommu.c b/trunk/arch/powerpc/platforms/cell/iommu.c index 760caa76841a..67d617b60a23 100644 --- a/trunk/arch/powerpc/platforms/cell/iommu.c +++ b/trunk/arch/powerpc/platforms/cell/iommu.c @@ -291,9 +291,9 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base) const unsigned int *nidp; const unsigned long *tmp; - nidp = of_get_property(np, "node-id", NULL); + nidp = get_property(np, "node-id", NULL); if (nidp && *nidp == nid) { - tmp = of_get_property(np, "ioc-translation", NULL); + tmp = get_property(np, "ioc-translation", NULL); if (tmp) { *base = *tmp; of_node_put(np); @@ -430,7 +430,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, struct iommu_window *window; const unsigned int *ioid; - ioid = of_get_property(np, "ioid", NULL); + ioid = get_property(np, "ioid", NULL); if (ioid == NULL) printk(KERN_WARNING "iommu: missing ioid for %s using 0\n", np->full_name); @@ -496,7 +496,7 @@ static void cell_dma_dev_setup(struct device *dev) struct dev_archdata *archdata = &dev->archdata; /* If we run without iommu, no need to do anything */ - if (get_pci_dma_ops() == &dma_direct_ops) + if (pci_dma_ops == &dma_direct_ops) return; /* Current implementation uses the first window available in that @@ -530,7 +530,7 @@ static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action, return 0; /* We use the PCI DMA ops */ - dev->archdata.dma_ops = get_pci_dma_ops(); + dev->archdata.dma_ops = pci_dma_ops; cell_dma_dev_setup(dev); @@ -549,7 +549,7 @@ static int __init cell_iommu_get_window(struct device_node *np, unsigned long index; /* Use ibm,dma-window if available, else, hard code ! */ - dma_window = of_get_property(np, "ibm,dma-window", NULL); + dma_window = get_property(np, "ibm,dma-window", NULL); if (dma_window == NULL) { *base = 0; *size = 0x80000000u; @@ -646,7 +646,7 @@ static int __init cell_iommu_init_disabled(void) unsigned long base = 0, size; /* When no iommu is present, we use direct DMA ops */ - set_pci_dma_ops(&dma_direct_ops); + pci_dma_ops = &dma_direct_ops; /* First make sure all IOC translation is turned off */ cell_disable_iommus(); @@ -734,7 +734,7 @@ static int __init cell_iommu_init(void) } /* Setup default PCI iommu ops */ - set_pci_dma_ops(&dma_iommu_ops); + pci_dma_ops = &dma_iommu_ops; bail: /* Register callbacks on OF platform device addition/removal diff --git a/trunk/arch/powerpc/platforms/cell/ras.c b/trunk/arch/powerpc/platforms/cell/ras.c index 3961a085b432..0984c7071695 100644 --- a/trunk/arch/powerpc/platforms/cell/ras.c +++ b/trunk/arch/powerpc/platforms/cell/ras.c @@ -3,13 +3,11 @@ #include #include #include -#include #include #include #include #include -#include #include "ras.h" #include "cbe_regs.h" @@ -84,164 +82,6 @@ static int cbe_machine_check_handler(struct pt_regs *regs) return 0; } -struct ptcal_area { - struct list_head list; - int nid; - int order; - struct page *pages; -}; - -static LIST_HEAD(ptcal_list); - -static int ptcal_start_tok, ptcal_stop_tok; - -static int __init cbe_ptcal_enable_on_node(int nid, int order) -{ - struct ptcal_area *area; - int ret = -ENOMEM; - unsigned long addr; - -#ifdef CONFIG_CRASH_DUMP - rtas_call(ptcal_stop_tok, 1, 1, NULL, nid); -#endif - - area = kmalloc(sizeof(*area), GFP_KERNEL); - if (!area) - goto out_err; - - area->nid = nid; - area->order = order; - area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order); - - if (!area->pages) - goto out_free_area; - - addr = __pa(page_address(area->pages)); - - ret = -EIO; - if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid, - (unsigned int)(addr >> 32), - (unsigned int)(addr & 0xffffffff))) { - printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n", - __FUNCTION__, nid); - goto out_free_pages; - } - - list_add(&area->list, &ptcal_list); - - return 0; - -out_free_pages: - __free_pages(area->pages, area->order); -out_free_area: - kfree(area); -out_err: - return ret; -} - -static int __init cbe_ptcal_enable(void) -{ - const u32 *size; - struct device_node *np; - int order, found_mic = 0; - - np = of_find_node_by_path("/rtas"); - if (!np) - return -ENODEV; - - size = of_get_property(np, "ibm,cbe-ptcal-size", NULL); - if (!size) - return -ENODEV; - - pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size); - order = get_order(*size); - of_node_put(np); - - /* support for malta device trees, with be@/mic@ nodes */ - for_each_node_by_type(np, "mic-tm") { - cbe_ptcal_enable_on_node(of_node_to_nid(np), order); - found_mic = 1; - } - - if (found_mic) - return 0; - - /* support for older device tree - use cpu nodes */ - for_each_node_by_type(np, "cpu") { - const u32 *nid = of_get_property(np, "node-id", NULL); - if (!nid) { - printk(KERN_ERR "%s: node %s is missing node-id?\n", - __FUNCTION__, np->full_name); - continue; - } - cbe_ptcal_enable_on_node(*nid, order); - found_mic = 1; - } - - return found_mic ? 0 : -ENODEV; -} - -static int cbe_ptcal_disable(void) -{ - struct ptcal_area *area, *tmp; - int ret = 0; - - pr_debug("%s: disabling PTCAL\n", __FUNCTION__); - - list_for_each_entry_safe(area, tmp, &ptcal_list, list) { - /* disable ptcal on this node */ - if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) { - printk(KERN_ERR "%s: error disabling PTCAL " - "on node %d!\n", __FUNCTION__, - area->nid); - ret = -EIO; - continue; - } - - /* ensure we can access the PTCAL area */ - memset(page_address(area->pages), 0, - 1 << (area->order + PAGE_SHIFT)); - - /* clean up */ - list_del(&area->list); - __free_pages(area->pages, area->order); - kfree(area); - } - - return ret; -} - -static int cbe_ptcal_notify_reboot(struct notifier_block *nb, - unsigned long code, void *data) -{ - return cbe_ptcal_disable(); -} - -static struct notifier_block cbe_ptcal_reboot_notifier = { - .notifier_call = cbe_ptcal_notify_reboot -}; - -int __init cbe_ptcal_init(void) -{ - int ret; - ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal"); - ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal"); - - if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE - || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE) - return -ENODEV; - - ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier); - if (ret) { - printk(KERN_ERR "Can't disable PTCAL, so not enabling\n"); - return ret; - } - - return cbe_ptcal_enable(); -} - -arch_initcall(cbe_ptcal_init); - void __init cbe_ras_init(void) { unsigned long hid0; diff --git a/trunk/arch/powerpc/platforms/cell/setup.c b/trunk/arch/powerpc/platforms/cell/setup.c index 54b96183cb64..36989c2eee66 100644 --- a/trunk/arch/powerpc/platforms/cell/setup.c +++ b/trunk/arch/powerpc/platforms/cell/setup.c @@ -71,7 +71,7 @@ static void cell_show_cpuinfo(struct seq_file *m) root = of_find_node_by_path("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); seq_printf(m, "machine\t\t: CHRP %s\n", model); of_node_put(root); } @@ -190,6 +190,15 @@ static int __init cell_probe(void) return 1; } +/* + * Cell has no legacy IO; anything calling this function has to + * fail or bad things will happen + */ +static int cell_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + define_machine(cell) { .name = "Cell", .probe = cell_probe, @@ -202,6 +211,7 @@ define_machine(cell) { .get_rtc_time = rtas_get_rtc_time, .set_rtc_time = rtas_set_rtc_time, .calibrate_decr = generic_calibrate_decr, + .check_legacy_ioport = cell_check_legacy_ioport, .progress = cell_progress, .init_IRQ = cell_init_irq, .pci_setup_phb = rtas_setup_phb, diff --git a/trunk/arch/powerpc/platforms/cell/spider-pic.c b/trunk/arch/powerpc/platforms/cell/spider-pic.c index fb1f15797bbb..21a9ebd4978e 100644 --- a/trunk/arch/powerpc/platforms/cell/spider-pic.c +++ b/trunk/arch/powerpc/platforms/cell/spider-pic.c @@ -254,25 +254,25 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) } /* Now do the horrible hacks */ - tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL); + tmp = get_property(pic->of_node, "#interrupt-cells", NULL); if (tmp == NULL) return NO_IRQ; intsize = *tmp; - imap = of_get_property(pic->of_node, "interrupt-map", &imaplen); + imap = get_property(pic->of_node, "interrupt-map", &imaplen); if (imap == NULL || imaplen < (intsize + 1)) return NO_IRQ; iic = of_find_node_by_phandle(imap[intsize]); if (iic == NULL) return NO_IRQ; imap += intsize + 1; - tmp = of_get_property(iic, "#interrupt-cells", NULL); + tmp = get_property(iic, "#interrupt-cells", NULL); if (tmp == NULL) return NO_IRQ; intsize = *tmp; /* Assume unit is last entry of interrupt specifier */ unit = imap[intsize - 1]; /* Ok, we have a unit, now let's try to get the node */ - tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL); + tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL); if (tmp == NULL) { of_node_put(iic); return NO_IRQ; diff --git a/trunk/arch/powerpc/platforms/cell/spu_base.c b/trunk/arch/powerpc/platforms/cell/spu_base.c index fec51525252e..eba7a2641dce 100644 --- a/trunk/arch/powerpc/platforms/cell/spu_base.c +++ b/trunk/arch/powerpc/platforms/cell/spu_base.c @@ -36,14 +36,12 @@ #include const struct spu_management_ops *spu_management_ops; -EXPORT_SYMBOL_GPL(spu_management_ops); - const struct spu_priv1_ops *spu_priv1_ops; static struct list_head spu_list[MAX_NUMNODES]; static LIST_HEAD(spu_full_list); static DEFINE_MUTEX(spu_mutex); -static DEFINE_SPINLOCK(spu_list_lock); +static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL_GPL(spu_priv1_ops); @@ -292,6 +290,7 @@ spu_irq_class_1(int irq, void *data) return stat ? IRQ_HANDLED : IRQ_NONE; } +EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom); static irqreturn_t spu_irq_class_2(int irq, void *data) @@ -432,11 +431,10 @@ struct spu *spu_alloc_node(int node) spu = list_entry(spu_list[node].next, struct spu, list); list_del_init(&spu->list); pr_debug("Got SPU %d %d\n", spu->number, spu->node); + spu_init_channels(spu); } mutex_unlock(&spu_mutex); - if (spu) - spu_init_channels(spu); return spu; } EXPORT_SYMBOL_GPL(spu_alloc_node); @@ -463,6 +461,108 @@ void spu_free(struct spu *spu) } EXPORT_SYMBOL_GPL(spu_free); +static int spu_handle_mm_fault(struct spu *spu) +{ + struct mm_struct *mm = spu->mm; + struct vm_area_struct *vma; + u64 ea, dsisr, is_write; + int ret; + + ea = spu->dar; + dsisr = spu->dsisr; +#if 0 + if (!IS_VALID_EA(ea)) { + return -EFAULT; + } +#endif /* XXX */ + if (mm == NULL) { + return -EFAULT; + } + if (mm->pgd == NULL) { + return -EFAULT; + } + + down_read(&mm->mmap_sem); + vma = find_vma(mm, ea); + if (!vma) + goto bad_area; + if (vma->vm_start <= ea) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +#if 0 + if (expand_stack(vma, ea)) + goto bad_area; +#endif /* XXX */ +good_area: + is_write = dsisr & MFC_DSISR_ACCESS_PUT; + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + if (dsisr & MFC_DSISR_ACCESS_DENIED) + goto bad_area; + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + ret = 0; + switch (handle_mm_fault(mm, vma, ea, is_write)) { + case VM_FAULT_MINOR: + current->min_flt++; + break; + case VM_FAULT_MAJOR: + current->maj_flt++; + break; + case VM_FAULT_SIGBUS: + ret = -EFAULT; + goto bad_area; + case VM_FAULT_OOM: + ret = -ENOMEM; + goto bad_area; + default: + BUG(); + } + up_read(&mm->mmap_sem); + return ret; + +bad_area: + up_read(&mm->mmap_sem); + return -EFAULT; +} + +int spu_irq_class_1_bottom(struct spu *spu) +{ + u64 ea, dsisr, access, error = 0UL; + int ret = 0; + + ea = spu->dar; + dsisr = spu->dsisr; + if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) { + u64 flags; + + access = (_PAGE_PRESENT | _PAGE_USER); + access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; + local_irq_save(flags); + if (hash_page(ea, access, 0x300) != 0) + error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; + local_irq_restore(flags); + } + if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) { + if ((ret = spu_handle_mm_fault(spu)) != 0) + error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; + else + error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR; + } + spu->dar = 0UL; + spu->dsisr = 0UL; + if (!error) { + spu_restart_dma(spu); + } else { + spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE); + } + return ret; +} + struct sysdev_class spu_sysdev_class = { set_kset_name("spu") }; @@ -536,6 +636,12 @@ static int spu_create_sysdev(struct spu *spu) return 0; } +static void spu_destroy_sysdev(struct spu *spu) +{ + sysfs_remove_device_from_node(&spu->sysdev, spu->node); + sysdev_unregister(&spu->sysdev); +} + static int __init create_spu(void *data) { struct spu *spu; @@ -587,37 +693,58 @@ static int __init create_spu(void *data) return ret; } -static int __init init_spu_base(void) +static void destroy_spu(struct spu *spu) { - int i, ret = 0; + list_del_init(&spu->list); + list_del_init(&spu->full_list); - for (i = 0; i < MAX_NUMNODES; i++) - INIT_LIST_HEAD(&spu_list[i]); + spu_destroy_sysdev(spu); + spu_free_irqs(spu); + spu_destroy_spu(spu); + kfree(spu); +} + +static void cleanup_spu_base(void) +{ + struct spu *spu, *tmp; + int node; + + mutex_lock(&spu_mutex); + for (node = 0; node < MAX_NUMNODES; node++) { + list_for_each_entry_safe(spu, tmp, &spu_list[node], list) + destroy_spu(spu); + } + mutex_unlock(&spu_mutex); + sysdev_class_unregister(&spu_sysdev_class); +} +module_exit(cleanup_spu_base); + +static int __init init_spu_base(void) +{ + int i, ret; if (!spu_management_ops) - goto out; + return 0; /* create sysdev class for spus */ ret = sysdev_class_register(&spu_sysdev_class); if (ret) - goto out; + return ret; + + for (i = 0; i < MAX_NUMNODES; i++) + INIT_LIST_HEAD(&spu_list[i]); ret = spu_enumerate_spus(create_spu); if (ret) { printk(KERN_WARNING "%s: Error initializing spus\n", __FUNCTION__); - goto out_unregister_sysdev_class; + cleanup_spu_base(); + return ret; } xmon_register_spus(&spu_full_list); - return 0; - - out_unregister_sysdev_class: - sysdev_class_unregister(&spu_sysdev_class); - out: - return ret; } module_init(init_spu_base); diff --git a/trunk/arch/powerpc/platforms/cell/spu_coredump.c b/trunk/arch/powerpc/platforms/cell/spu_coredump.c index 4fd37ff1e210..6915b418ee73 100644 --- a/trunk/arch/powerpc/platforms/cell/spu_coredump.c +++ b/trunk/arch/powerpc/platforms/cell/spu_coredump.c @@ -26,18 +26,19 @@ #include -static struct spu_coredump_calls *spu_coredump_calls; +static struct spu_coredump_calls spu_coredump_calls; static DEFINE_MUTEX(spu_coredump_mutex); int arch_notes_size(void) { long ret; + struct module *owner = spu_coredump_calls.owner; ret = -ENOSYS; mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - ret = spu_coredump_calls->arch_notes_size(); - module_put(spu_coredump_calls->owner); + if (owner && try_module_get(owner)) { + ret = spu_coredump_calls.arch_notes_size(); + module_put(owner); } mutex_unlock(&spu_coredump_mutex); return ret; @@ -45,35 +46,36 @@ int arch_notes_size(void) void arch_write_notes(struct file *file) { + struct module *owner = spu_coredump_calls.owner; + mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - spu_coredump_calls->arch_write_notes(file); - module_put(spu_coredump_calls->owner); + if (owner && try_module_get(owner)) { + spu_coredump_calls.arch_write_notes(file); + module_put(owner); } mutex_unlock(&spu_coredump_mutex); } int register_arch_coredump_calls(struct spu_coredump_calls *calls) { - int ret = 0; - + if (spu_coredump_calls.owner) + return -EBUSY; mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls) - ret = -EBUSY; - else - spu_coredump_calls = calls; + spu_coredump_calls.arch_notes_size = calls->arch_notes_size; + spu_coredump_calls.arch_write_notes = calls->arch_write_notes; + spu_coredump_calls.owner = calls->owner; mutex_unlock(&spu_coredump_mutex); - return ret; + return 0; } EXPORT_SYMBOL_GPL(register_arch_coredump_calls); void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) { - BUG_ON(spu_coredump_calls != calls); + BUG_ON(spu_coredump_calls.owner != calls->owner); mutex_lock(&spu_coredump_mutex); - spu_coredump_calls = NULL; + spu_coredump_calls.owner = NULL; mutex_unlock(&spu_coredump_mutex); } EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); diff --git a/trunk/arch/powerpc/platforms/cell/spu_manage.c b/trunk/arch/powerpc/platforms/cell/spu_manage.c index 1d4562ae463d..e34599f53d28 100644 --- a/trunk/arch/powerpc/platforms/cell/spu_manage.c +++ b/trunk/arch/powerpc/platforms/cell/spu_manage.c @@ -48,11 +48,11 @@ static u64 __init find_spu_unit_number(struct device_node *spe) { const unsigned int *prop; int proplen; - prop = of_get_property(spe, "unit-id", &proplen); + prop = get_property(spe, "unit-id", &proplen); if (proplen == 4) return (u64)*prop; - prop = of_get_property(spe, "reg", &proplen); + prop = get_property(spe, "reg", &proplen); if (proplen == 4) return (u64)*prop; @@ -76,12 +76,12 @@ static int __init spu_map_interrupts_old(struct spu *spu, int nid; /* Get the interrupt source unit from the device-tree */ - tmp = of_get_property(np, "isrc", NULL); + tmp = get_property(np, "isrc", NULL); if (!tmp) return -ENODEV; isrc = tmp[0]; - tmp = of_get_property(np->parent->parent, "node-id", NULL); + tmp = get_property(np->parent->parent, "node-id", NULL); if (!tmp) { printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); nid = spu->node; @@ -110,7 +110,7 @@ static void __iomem * __init spu_map_prop_old(struct spu *spu, } __attribute__((packed)) *prop; int proplen; - prop = of_get_property(n, name, &proplen); + prop = get_property(n, name, &proplen); if (prop == NULL || proplen != sizeof (struct address_prop)) return NULL; @@ -124,11 +124,11 @@ static int __init spu_map_device_old(struct spu *spu) int ret; ret = -ENODEV; - spu->name = of_get_property(node, "name", NULL); + spu->name = get_property(node, "name", NULL); if (!spu->name) goto out; - prop = of_get_property(node, "local-store", NULL); + prop = get_property(node, "local-store", NULL); if (!prop) goto out; spu->local_store_phys = *(unsigned long *)prop; @@ -139,7 +139,7 @@ static int __init spu_map_device_old(struct spu *spu) if (!spu->local_store) goto out; - prop = of_get_property(node, "problem", NULL); + prop = get_property(node, "problem", NULL); if (!prop) goto out_unmap; spu->problem_phys = *(unsigned long *)prop; @@ -226,7 +226,7 @@ static int __init spu_map_device(struct spu *spu) struct device_node *np = spu->devnode; int ret = -ENODEV; - spu->name = of_get_property(np, "name", NULL); + spu->name = get_property(np, "name", NULL); if (!spu->name) goto out; diff --git a/trunk/arch/powerpc/platforms/cell/spufs/Makefile b/trunk/arch/powerpc/platforms/cell/spufs/Makefile index 2cd89c11af5a..472217d19faf 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/Makefile +++ b/trunk/arch/powerpc/platforms/cell/spufs/Makefile @@ -1,4 +1,4 @@ -obj-y += switch.o fault.o +obj-y += switch.o obj-$(CONFIG_SPU_FS) += spufs.o spufs-y += inode.o file.o context.o syscalls.o coredump.o diff --git a/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c b/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c index 3322528fa6eb..1898f0d3a8b8 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -350,11 +350,6 @@ static int spu_backing_send_mfc_command(struct spu_context *ctx, return ret; } -static void spu_backing_restart_dma(struct spu_context *ctx) -{ - /* nothing to do here */ -} - struct spu_context_ops spu_backing_ops = { .mbox_read = spu_backing_mbox_read, .mbox_stat_read = spu_backing_mbox_stat_read, @@ -381,5 +376,4 @@ struct spu_context_ops spu_backing_ops = { .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus, .get_mfc_free_elements = spu_backing_get_mfc_free_elements, .send_mfc_command = spu_backing_send_mfc_command, - .restart_dma = spu_backing_restart_dma, }; diff --git a/trunk/arch/powerpc/platforms/cell/spufs/context.c b/trunk/arch/powerpc/platforms/cell/spufs/context.c index a87d9ca3dba2..04ad2e364e97 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/context.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/context.c @@ -41,10 +41,9 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) goto out_free; } spin_lock_init(&ctx->mmio_lock); - spin_lock_init(&ctx->mapping_lock); kref_init(&ctx->kref); mutex_init(&ctx->state_mutex); - mutex_init(&ctx->run_mutex); + init_MUTEX(&ctx->run_sema); init_waitqueue_head(&ctx->ibox_wq); init_waitqueue_head(&ctx->wbox_wq); init_waitqueue_head(&ctx->stop_wq); @@ -52,7 +51,6 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) ctx->state = SPU_STATE_SAVED; ctx->ops = &spu_backing_ops; ctx->owner = get_task_mm(current); - INIT_LIST_HEAD(&ctx->rq); if (gang) spu_gang_add_ctx(gang, ctx); ctx->rt_priority = current->rt_priority; @@ -77,7 +75,6 @@ void destroy_spu_context(struct kref *kref) spu_fini_csa(&ctx->csa); if (ctx->gang) spu_gang_remove_ctx(ctx->gang, ctx); - BUG_ON(!list_empty(&ctx->rq)); kfree(ctx); } @@ -121,6 +118,46 @@ void spu_unmap_mappings(struct spu_context *ctx) unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); } +/** + * spu_acquire_exclusive - lock spu contex and protect against userspace access + * @ctx: spu contex to lock + * + * Note: + * Returns 0 and with the context locked on success + * Returns negative error and with the context _unlocked_ on failure. + */ +int spu_acquire_exclusive(struct spu_context *ctx) +{ + int ret = -EINVAL; + + spu_acquire(ctx); + /* + * Context is about to be freed, so we can't acquire it anymore. + */ + if (!ctx->owner) + goto out_unlock; + + if (ctx->state == SPU_STATE_SAVED) { + ret = spu_activate(ctx, 0); + if (ret) + goto out_unlock; + } else { + /* + * We need to exclude userspace access to the context. + * + * To protect against memory access we invalidate all ptes + * and make sure the pagefault handlers block on the mutex. + */ + spu_unmap_mappings(ctx); + } + + return 0; + + out_unlock: + spu_release(ctx); + return ret; +} + /** * spu_acquire_runnable - lock spu contex and make sure it is in runnable state * @ctx: spu contex to lock diff --git a/trunk/arch/powerpc/platforms/cell/spufs/coredump.c b/trunk/arch/powerpc/platforms/cell/spufs/coredump.c index 5d9ad5a0307b..725e19561159 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/coredump.c @@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, struct spu_context *ctx; loff_t pos = 0; int sz, dfd, rc, total = 0; - const int bufsz = PAGE_SIZE; + const int bufsz = 4096; char *name; char fullname[80], *buf; struct elf_note en; - buf = (void *)get_zeroed_page(GFP_KERNEL); + buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return; @@ -187,8 +187,9 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, sz = spufs_coredump_read[i].size; ctx = ctx_info->ctx; - if (!ctx) - goto out; + if (!ctx) { + return; + } sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; @@ -196,25 +197,23 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, en.n_type = NT_SPU; if (!spufs_dump_write(file, &en, sizeof(en))) - goto out; + return; if (!spufs_dump_write(file, fullname, en.n_namesz)) - goto out; + return; if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) - goto out; + return; do { rc = do_coredump_read(i, ctx, buf, bufsz, &pos); if (rc > 0) { if (!spufs_dump_write(file, buf, rc)) - goto out; + return; total += rc; } } while (rc == bufsz && total < sz); spufs_dump_seek(file, roundup((unsigned long)file->f_pos - total + sz, 4)); -out: - free_page((unsigned long)buf); } static void spufs_arch_write_notes(struct file *file) diff --git a/trunk/arch/powerpc/platforms/cell/spufs/fault.c b/trunk/arch/powerpc/platforms/cell/spufs/fault.c deleted file mode 100644 index 0f75c07e29d8..000000000000 --- a/trunk/arch/powerpc/platforms/cell/spufs/fault.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Low-level SPU handling - * - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 - * - * Author: Arnd Bergmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include - -#include -#include - -#include "spufs.h" - -/* - * This ought to be kept in sync with the powerpc specific do_page_fault - * function. Currently, there are a few corner cases that we haven't had - * to handle fortunately. - */ -static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) -{ - struct vm_area_struct *vma; - unsigned long is_write; - int ret; - -#if 0 - if (!IS_VALID_EA(ea)) { - return -EFAULT; - } -#endif /* XXX */ - if (mm == NULL) { - return -EFAULT; - } - if (mm->pgd == NULL) { - return -EFAULT; - } - - down_read(&mm->mmap_sem); - vma = find_vma(mm, ea); - if (!vma) - goto bad_area; - if (vma->vm_start <= ea) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (expand_stack(vma, ea)) - goto bad_area; -good_area: - is_write = dsisr & MFC_DSISR_ACCESS_PUT; - if (is_write) { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } else { - if (dsisr & MFC_DSISR_ACCESS_DENIED) - goto bad_area; - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; - } - ret = 0; - switch (handle_mm_fault(mm, vma, ea, is_write)) { - case VM_FAULT_MINOR: - current->min_flt++; - break; - case VM_FAULT_MAJOR: - current->maj_flt++; - break; - case VM_FAULT_SIGBUS: - ret = -EFAULT; - goto bad_area; - case VM_FAULT_OOM: - ret = -ENOMEM; - goto bad_area; - default: - BUG(); - } - up_read(&mm->mmap_sem); - return ret; - -bad_area: - up_read(&mm->mmap_sem); - return -EFAULT; -} - -static void spufs_handle_dma_error(struct spu_context *ctx, - unsigned long ea, int type) -{ - if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { - ctx->event_return |= type; - wake_up_all(&ctx->stop_wq); - } else { - siginfo_t info; - memset(&info, 0, sizeof(info)); - - switch (type) { - case SPE_EVENT_INVALID_DMA: - info.si_signo = SIGBUS; - info.si_code = BUS_OBJERR; - break; - case SPE_EVENT_SPE_DATA_STORAGE: - info.si_signo = SIGBUS; - info.si_addr = (void __user *)ea; - info.si_code = BUS_ADRERR; - break; - case SPE_EVENT_DMA_ALIGNMENT: - info.si_signo = SIGBUS; - /* DAR isn't set for an alignment fault :( */ - info.si_code = BUS_ADRALN; - break; - case SPE_EVENT_SPE_ERROR: - info.si_signo = SIGILL; - info.si_addr = (void __user *)(unsigned long) - ctx->ops->npc_read(ctx) - 4; - info.si_code = ILL_ILLOPC; - break; - } - if (info.si_signo) - force_sig_info(info.si_signo, &info, current); - } -} - -void spufs_dma_callback(struct spu *spu, int type) -{ - spufs_handle_dma_error(spu->ctx, spu->dar, type); -} -EXPORT_SYMBOL_GPL(spufs_dma_callback); - -/* - * bottom half handler for page faults, we can't do this from - * interrupt context, since we might need to sleep. - * we also need to give up the mutex so we can get scheduled - * out while waiting for the backing store. - * - * TODO: try calling hash_page from the interrupt handler first - * in order to speed up the easy case. - */ -int spufs_handle_class1(struct spu_context *ctx) -{ - u64 ea, dsisr, access; - unsigned long flags; - int ret; - - /* - * dar and dsisr get passed from the registers - * to the spu_context, to this function, but not - * back to the spu if it gets scheduled again. - * - * if we don't handle the fault for a saved context - * in time, we can still expect to get the same fault - * the immediately after the context restore. - */ - if (ctx->state == SPU_STATE_RUNNABLE) { - ea = ctx->spu->dar; - dsisr = ctx->spu->dsisr; - ctx->spu->dar= ctx->spu->dsisr = 0; - } else { - ea = ctx->csa.priv1.mfc_dar_RW; - dsisr = ctx->csa.priv1.mfc_dsisr_RW; - ctx->csa.priv1.mfc_dar_RW = 0; - ctx->csa.priv1.mfc_dsisr_RW = 0; - } - - if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) - return 0; - - pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, - dsisr, ctx->state); - - /* we must not hold the lock when entering spu_handle_mm_fault */ - spu_release(ctx); - - access = (_PAGE_PRESENT | _PAGE_USER); - access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; - local_irq_save(flags); - ret = hash_page(ea, access, 0x300); - local_irq_restore(flags); - - /* hashing failed, so try the actual fault handler */ - if (ret) - ret = spu_handle_mm_fault(current->mm, ea, dsisr); - - spu_acquire(ctx); - /* - * If we handled the fault successfully and are in runnable - * state, restart the DMA. - * In case of unhandled error report the problem to user space. - */ - if (!ret) { - if (ctx->spu) - ctx->ops->restart_dma(ctx); - } else - spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); - - return ret; -} -EXPORT_SYMBOL_GPL(spufs_handle_class1); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/file.c b/trunk/arch/powerpc/platforms/cell/spufs/file.c index d010b2464a98..505266a568d4 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/file.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/file.c @@ -44,25 +44,9 @@ spufs_mem_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); file->private_data = ctx; - if (!i->i_openers++) - ctx->local_store = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); - return 0; -} - -static int -spufs_mem_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->local_store = NULL; - spin_unlock(&ctx->mapping_lock); + ctx->local_store = inode->i_mapping; + smp_wmb(); return 0; } @@ -165,7 +149,6 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, - .release = spufs_mem_release, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, @@ -255,33 +238,16 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); file->private_data = ctx; - if (!i->i_openers++) - ctx->cntl = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->cntl = inode->i_mapping; + smp_wmb(); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx"); } -static int -spufs_cntl_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - simple_attr_close(inode, file); - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->cntl = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - static const struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, - .release = spufs_cntl_release, + .release = simple_attr_close, .read = simple_attr_read, .write = simple_attr_write, .mmap = spufs_cntl_mmap, @@ -757,28 +723,12 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); file->private_data = ctx; - if (!i->i_openers++) - ctx->signal1 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->signal1 = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static int -spufs_signal1_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->signal1 = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, size_t len, loff_t *pos) { @@ -871,7 +821,6 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations spufs_signal1_fops = { .open = spufs_signal1_open, - .release = spufs_signal1_release, .read = spufs_signal1_read, .write = spufs_signal1_write, .mmap = spufs_signal1_mmap, @@ -881,28 +830,12 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); file->private_data = ctx; - if (!i->i_openers++) - ctx->signal2 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->signal2 = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static int -spufs_signal2_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->signal2 = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, size_t len, loff_t *pos) { @@ -999,7 +932,6 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations spufs_signal2_fops = { .open = spufs_signal2_open, - .release = spufs_signal2_release, .read = spufs_signal2_read, .write = spufs_signal2_write, .mmap = spufs_signal2_mmap, @@ -1099,30 +1031,13 @@ static int spufs_mss_open(struct inode *inode, struct file *file) struct spu_context *ctx = i->i_ctx; file->private_data = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!i->i_openers++) - ctx->mss = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->mss = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static int -spufs_mss_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->mss = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - static const struct file_operations spufs_mss_fops = { .open = spufs_mss_open, - .release = spufs_mss_release, .mmap = spufs_mss_mmap, }; @@ -1157,30 +1072,14 @@ static int spufs_psmap_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); file->private_data = i->i_ctx; - if (!i->i_openers++) - ctx->psmap = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->psmap = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static int -spufs_psmap_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->psmap = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - static const struct file_operations spufs_psmap_fops = { .open = spufs_psmap_open, - .release = spufs_psmap_release, .mmap = spufs_psmap_mmap, }; @@ -1227,27 +1126,12 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) if (atomic_read(&inode->i_count) != 1) return -EBUSY; - spin_lock(&ctx->mapping_lock); file->private_data = ctx; - if (!i->i_openers++) - ctx->mfc = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + ctx->mfc = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static int -spufs_mfc_release(struct inode *inode, struct file *file) -{ - struct spufs_inode_info *i = SPUFS_I(inode); - struct spu_context *ctx = i->i_ctx; - - spin_lock(&ctx->mapping_lock); - if (!--i->i_openers) - ctx->mfc = NULL; - spin_unlock(&ctx->mapping_lock); - return 0; -} - /* interrupt-level mfc callback function. */ void spufs_mfc_callback(struct spu *spu) { @@ -1429,10 +1313,7 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, if (ret) goto out; - ret = spu_acquire_runnable(ctx, 0); - if (ret) - goto out; - + spu_acquire_runnable(ctx, 0); if (file->f_flags & O_NONBLOCK) { ret = ctx->ops->send_mfc_command(ctx, &cmd); } else { @@ -1518,7 +1399,6 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on) static const struct file_operations spufs_mfc_fops = { .open = spufs_mfc_open, - .release = spufs_mfc_release, .read = spufs_mfc_read, .write = spufs_mfc_write, .poll = spufs_mfc_poll, diff --git a/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c b/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c index 428875c5e4ec..ae42e03b8c86 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -296,14 +296,6 @@ static int spu_hw_send_mfc_command(struct spu_context *ctx, } } -static void spu_hw_restart_dma(struct spu_context *ctx) -{ - struct spu_priv2 __iomem *priv2 = ctx->spu->priv2; - - if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags)) - out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); -} - struct spu_context_ops spu_hw_ops = { .mbox_read = spu_hw_mbox_read, .mbox_stat_read = spu_hw_mbox_stat_read, @@ -328,5 +320,4 @@ struct spu_context_ops spu_hw_ops = { .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus, .get_mfc_free_elements = spu_hw_get_mfc_free_elements, .send_mfc_command = spu_hw_send_mfc_command, - .restart_dma = spu_hw_restart_dma, }; diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index 13e4f70ec8c0..8079983ef94f 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "spufs.h" @@ -55,7 +54,6 @@ spufs_alloc_inode(struct super_block *sb) ei->i_gang = NULL; ei->i_ctx = NULL; - ei->i_openers = 0; return &ei->vfs_inode; } @@ -522,14 +520,13 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) /* File system initialization */ enum { - Opt_uid, Opt_gid, Opt_mode, Opt_err, + Opt_uid, Opt_gid, Opt_err, }; static match_table_t spufs_tokens = { - { Opt_uid, "uid=%d" }, - { Opt_gid, "gid=%d" }, - { Opt_mode, "mode=%o" }, - { Opt_err, NULL }, + { Opt_uid, "uid=%d" }, + { Opt_gid, "gid=%d" }, + { Opt_err, NULL }, }; static int @@ -556,11 +553,6 @@ spufs_parse_options(char *options, struct inode *root) return 0; root->i_gid = option; break; - case Opt_mode: - if (match_octal(&args[0], &option)) - return 0; - root->i_mode = option | S_IFDIR; - break; default: return 0; } @@ -568,11 +560,6 @@ spufs_parse_options(char *options, struct inode *root) return 1; } -static void spufs_exit_isolated_loader(void) -{ - kfree(isolated_loader); -} - static void spufs_init_isolated_loader(void) { @@ -584,7 +571,7 @@ spufs_init_isolated_loader(void) if (!dn) return; - loader = of_get_property(dn, "loader", &size); + loader = get_property(dn, "loader", &size); if (!loader) return; @@ -666,10 +653,6 @@ static int __init spufs_init(void) { int ret; - ret = -ENODEV; - if (!spu_management_ops) - goto out; - ret = -ENOMEM; spufs_inode_cache = kmem_cache_create("spufs_inode_cache", sizeof(struct spufs_inode_info), 0, @@ -677,29 +660,25 @@ static int __init spufs_init(void) if (!spufs_inode_cache) goto out; - ret = spu_sched_init(); - if (ret) - goto out_cache; + if (spu_sched_init() != 0) { + kmem_cache_destroy(spufs_inode_cache); + goto out; + } ret = register_filesystem(&spufs_type); if (ret) - goto out_sched; + goto out_cache; ret = register_spu_syscalls(&spufs_calls); if (ret) goto out_fs; ret = register_arch_coredump_calls(&spufs_coredump_calls); if (ret) - goto out_syscalls; + goto out_fs; spufs_init_isolated_loader(); return 0; - -out_syscalls: - unregister_spu_syscalls(&spufs_calls); out_fs: unregister_filesystem(&spufs_type); -out_sched: - spu_sched_exit(); out_cache: kmem_cache_destroy(spufs_inode_cache); out: @@ -710,7 +689,6 @@ module_init(spufs_init); static void __exit spufs_exit(void) { spu_sched_exit(); - spufs_exit_isolated_loader(); unregister_arch_coredump_calls(&spufs_coredump_calls); unregister_spu_syscalls(&spufs_calls); unregister_filesystem(&spufs_type); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/run.c b/trunk/arch/powerpc/platforms/cell/spufs/run.c index 57626600b1a4..f95a611ca362 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/run.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/run.c @@ -18,6 +18,27 @@ void spufs_stop_callback(struct spu *spu) wake_up_all(&ctx->stop_wq); } +void spufs_dma_callback(struct spu *spu, int type) +{ + struct spu_context *ctx = spu->ctx; + + if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { + ctx->event_return |= type; + wake_up_all(&ctx->stop_wq); + } else { + switch (type) { + case SPE_EVENT_DMA_ALIGNMENT: + case SPE_EVENT_SPE_DATA_STORAGE: + case SPE_EVENT_INVALID_DMA: + force_sig(SIGBUS, /* info, */ current); + break; + case SPE_EVENT_SPE_ERROR: + force_sig(SIGILL, /* info */ current); + break; + } + } +} + static inline int spu_stopped(struct spu_context *ctx, u32 * stat) { struct spu *spu; @@ -42,17 +63,12 @@ static int spu_setup_isolated(struct spu_context *ctx) const u32 status_loading = SPU_STATUS_RUNNING | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; - ret = -ENODEV; if (!isolated_loader) - goto out; + return -ENODEV; - /* - * We need to exclude userspace access to the context. - * - * To protect against memory access we invalidate all ptes - * and make sure the pagefault handlers block on the mutex. - */ - spu_unmap_mappings(ctx); + ret = spu_acquire_exclusive(ctx); + if (ret) + goto out; mfc_cntl = &ctx->spu->priv2->mfc_control_RW; @@ -66,7 +82,7 @@ static int spu_setup_isolated(struct spu_context *ctx) printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", __FUNCTION__); ret = -EIO; - goto out; + goto out_unlock; } cond_resched(); } @@ -103,15 +119,12 @@ static int spu_setup_isolated(struct spu_context *ctx) pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); ret = -EACCES; - goto out_drop_priv; - } - if (!(status & SPU_STATUS_ISOLATED_STATE)) { + } else if (!(status & SPU_STATUS_ISOLATED_STATE)) { /* This isn't allowed by the CBEA, but check anyway */ pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); ret = -EINVAL; - goto out_drop_priv; } out_drop_priv: @@ -119,19 +132,30 @@ static int spu_setup_isolated(struct spu_context *ctx) sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; spu_mfc_sr1_set(ctx->spu, sr1); +out_unlock: + spu_release(ctx); out: return ret; } -static int spu_run_init(struct spu_context *ctx, u32 * npc) +static inline int spu_run_init(struct spu_context *ctx, u32 * npc) { - if (ctx->flags & SPU_CREATE_ISOLATE) { - unsigned long runcntl; + int ret; + unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; + + ret = spu_acquire_runnable(ctx, 0); + if (ret) + return ret; + if (ctx->flags & SPU_CREATE_ISOLATE) { if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { - int ret = spu_setup_isolated(ctx); - if (ret) - return ret; + /* Need to release ctx, because spu_setup_isolated will + * acquire it exclusively. + */ + spu_release(ctx); + ret = spu_setup_isolated(ctx); + if (!ret) + ret = spu_acquire_runnable(ctx, 0); } /* if userspace has set the runcntrl register (eg, to issue an @@ -140,17 +164,16 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc) (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); if (runcntl == 0) runcntl = SPU_RUNCNTL_RUNNABLE; - ctx->ops->runcntl_write(ctx, runcntl); } else { spu_start_tick(ctx); ctx->ops->npc_write(ctx, *npc); - ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); } - return 0; + ctx->ops->runcntl_write(ctx, runcntl); + return ret; } -static int spu_run_fini(struct spu_context *ctx, u32 * npc, +static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, u32 * status) { int ret = 0; @@ -166,27 +189,19 @@ static int spu_run_fini(struct spu_context *ctx, u32 * npc, return ret; } -static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, +static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, u32 *status) { int ret; - ret = spu_run_fini(ctx, npc, status); - if (ret) + if ((ret = spu_run_fini(ctx, npc, status)) != 0) return ret; - - if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT)) + if (*status & (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT)) { return *status; - - ret = spu_acquire_runnable(ctx, 0); - if (ret) - return ret; - - ret = spu_run_init(ctx, npc); - if (ret) { - spu_release(ctx); - return ret; } + if ((ret = spu_run_init(ctx, npc)) != 0) + return ret; return 0; } @@ -238,17 +253,17 @@ int spu_process_callback(struct spu_context *ctx) { struct spu_syscall_block s; u32 ls_pointer, npc; - void __iomem *ls; + char *ls; long spu_ret; int ret; /* get syscall block from local store */ - npc = ctx->ops->npc_read(ctx) & ~3; - ls = (void __iomem *)ctx->ops->get_ls(ctx); - ls_pointer = in_be32(ls + npc); + npc = ctx->ops->npc_read(ctx); + ls = ctx->ops->get_ls(ctx); + ls_pointer = *(u32*)(ls + npc); if (ls_pointer > (LS_SIZE - sizeof(s))) return -EFAULT; - memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); + memcpy(&s, ls + ls_pointer, sizeof (s)); /* do actual syscall without pinning the spu */ ret = 0; @@ -268,7 +283,7 @@ int spu_process_callback(struct spu_context *ctx) } /* write result, jump over indirect pointer */ - memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); + memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret)); ctx->ops->npc_write(ctx, npc); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); return ret; @@ -277,8 +292,11 @@ int spu_process_callback(struct spu_context *ctx) static inline int spu_process_events(struct spu_context *ctx) { struct spu *spu = ctx->spu; + u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; int ret = 0; + if (spu->dsisr & pte_fault) + ret = spu_irq_class_1_bottom(spu); if (spu->class_0_pending) ret = spu_irq_class_0_bottom(spu); if (!ret && signal_pending(current)) @@ -292,21 +310,14 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, int ret; u32 status; - if (mutex_lock_interruptible(&ctx->run_mutex)) + if (down_interruptible(&ctx->run_sema)) return -ERESTARTSYS; ctx->ops->master_start(ctx); ctx->event_return = 0; - - ret = spu_acquire_runnable(ctx, 0); - if (ret) - return ret; - ret = spu_run_init(ctx, npc); - if (ret) { - spu_release(ctx); + if (ret) goto out; - } do { ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); @@ -319,10 +330,6 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, break; status &= ~SPU_STATUS_STOPPED_BY_STOP; } - ret = spufs_handle_class1(ctx); - if (ret) - break; - if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, &status); if (ret) { @@ -356,6 +363,6 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, out: *event = ctx->event_return; - mutex_unlock(&ctx->run_mutex); + up(&ctx->run_sema); return ret; } diff --git a/trunk/arch/powerpc/platforms/cell/spufs/sched.c b/trunk/arch/powerpc/platforms/cell/spufs/sched.c index 91030b8abdca..39823cec0844 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/sched.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/sched.c @@ -71,27 +71,14 @@ static inline int node_allowed(int node) void spu_start_tick(struct spu_context *ctx) { - if (ctx->policy == SCHED_RR) { - /* - * Make sure the exiting bit is cleared. - */ - clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags); - mb(); + if (ctx->policy == SCHED_RR) queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); - } } void spu_stop_tick(struct spu_context *ctx) { - if (ctx->policy == SCHED_RR) { - /* - * While the work can be rearming normally setting this flag - * makes sure it does not rearm itself anymore. - */ - set_bit(SPU_SCHED_EXITING, &ctx->sched_flags); - mb(); + if (ctx->policy == SCHED_RR) cancel_delayed_work(&ctx->sched_work); - } } void spu_sched_tick(struct work_struct *work) @@ -99,15 +86,7 @@ void spu_sched_tick(struct work_struct *work) struct spu_context *ctx = container_of(work, struct spu_context, sched_work.work); struct spu *spu; - int preempted = 0; - - /* - * If this context is being stopped avoid rescheduling from the - * scheduler tick because we would block on the state_mutex. - * The caller will yield the spu later on anyway. - */ - if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) - return; + int rearm = 1; mutex_lock(&ctx->state_mutex); spu = ctx->spu; @@ -115,19 +94,12 @@ void spu_sched_tick(struct work_struct *work) int best = sched_find_first_bit(spu_prio->bitmap); if (best <= ctx->prio) { spu_deactivate(ctx); - preempted = 1; + rearm = 0; } } mutex_unlock(&ctx->state_mutex); - if (preempted) { - /* - * We need to break out of the wait loop in spu_run manually - * to ensure this context gets put on the runqueue again - * ASAP. - */ - wake_up(&ctx->stop_wq); - } else + if (rearm) spu_start_tick(ctx); } @@ -236,40 +208,58 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) * spu_add_to_rq - add a context to the runqueue * @ctx: context to add */ -static void __spu_add_to_rq(struct spu_context *ctx) +static void spu_add_to_rq(struct spu_context *ctx) { - int prio = ctx->prio; + spin_lock(&spu_prio->runq_lock); + list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); + set_bit(ctx->prio, spu_prio->bitmap); + spin_unlock(&spu_prio->runq_lock); +} - list_add_tail(&ctx->rq, &spu_prio->runq[prio]); - set_bit(prio, spu_prio->bitmap); +/** + * spu_del_from_rq - remove a context from the runqueue + * @ctx: context to remove + */ +static void spu_del_from_rq(struct spu_context *ctx) +{ + spin_lock(&spu_prio->runq_lock); + list_del_init(&ctx->rq); + if (list_empty(&spu_prio->runq[ctx->prio])) + clear_bit(ctx->prio, spu_prio->bitmap); + spin_unlock(&spu_prio->runq_lock); } -static void __spu_del_from_rq(struct spu_context *ctx) +/** + * spu_grab_context - remove one context from the runqueue + * @prio: priority of the context to be removed + * + * This function removes one context from the runqueue for priority @prio. + * If there is more than one context with the given priority the first + * task on the runqueue will be taken. + * + * Returns the spu_context it just removed. + * + * Must be called with spu_prio->runq_lock held. + */ +static struct spu_context *spu_grab_context(int prio) { - int prio = ctx->prio; + struct list_head *rq = &spu_prio->runq[prio]; - if (!list_empty(&ctx->rq)) - list_del_init(&ctx->rq); - if (list_empty(&spu_prio->runq[prio])) - clear_bit(prio, spu_prio->bitmap); + if (list_empty(rq)) + return NULL; + return list_entry(rq->next, struct spu_context, rq); } static void spu_prio_wait(struct spu_context *ctx) { DEFINE_WAIT(wait); - spin_lock(&spu_prio->runq_lock); prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); if (!signal_pending(current)) { - __spu_add_to_rq(ctx); - spin_unlock(&spu_prio->runq_lock); mutex_unlock(&ctx->state_mutex); schedule(); mutex_lock(&ctx->state_mutex); - spin_lock(&spu_prio->runq_lock); - __spu_del_from_rq(ctx); } - spin_unlock(&spu_prio->runq_lock); __set_current_state(TASK_RUNNING); remove_wait_queue(&ctx->stop_wq, &wait); } @@ -290,14 +280,9 @@ static void spu_reschedule(struct spu *spu) spin_lock(&spu_prio->runq_lock); best = sched_find_first_bit(spu_prio->bitmap); if (best < MAX_PRIO) { - struct list_head *rq = &spu_prio->runq[best]; - struct spu_context *ctx; - - BUG_ON(list_empty(rq)); - - ctx = list_entry(rq->next, struct spu_context, rq); - __spu_del_from_rq(ctx); - wake_up(&ctx->stop_wq); + struct spu_context *ctx = spu_grab_context(best); + if (ctx) + wake_up(&ctx->stop_wq); } spin_unlock(&spu_prio->runq_lock); } @@ -380,12 +365,6 @@ static struct spu *find_victim(struct spu_context *ctx) } spu_unbind_context(spu, victim); mutex_unlock(&victim->state_mutex); - /* - * We need to break out of the wait loop in spu_run - * manually to ensure this context gets put on the - * runqueue again ASAP. - */ - wake_up(&victim->stop_wq); return spu; } } @@ -398,7 +377,7 @@ static struct spu *find_victim(struct spu_context *ctx) * @ctx: spu context to schedule * @flags: flags (currently ignored) * - * Tries to find a free spu to run @ctx. If no free spu is available + * Tries to find a free spu to run @ctx. If no free spu is availble * add the context to the runqueue so it gets woken up once an spu * is available. */ @@ -423,7 +402,9 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) return 0; } + spu_add_to_rq(ctx); spu_prio_wait(ctx); + spu_del_from_rq(ctx); } while (!signal_pending(current)); return -ERESTARTSYS; @@ -457,6 +438,7 @@ void spu_deactivate(struct spu_context *ctx) void spu_yield(struct spu_context *ctx) { struct spu *spu; + int need_yield = 0; if (mutex_trylock(&ctx->state_mutex)) { if ((spu = ctx->spu) != NULL) { @@ -465,10 +447,13 @@ void spu_yield(struct spu_context *ctx) pr_debug("%s: yielding SPU %d NODE %d\n", __FUNCTION__, spu->number, spu->node); spu_deactivate(ctx); + need_yield = 1; } } mutex_unlock(&ctx->state_mutex); } + if (unlikely(need_yield)) + yield(); } int __init spu_sched_init(void) diff --git a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h index 0a947fd7de57..5c4e47d69d79 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/trunk/arch/powerpc/platforms/cell/spufs/spufs.h @@ -41,7 +41,7 @@ struct spu_gang; /* ctx->sched_flags */ enum { - SPU_SCHED_EXITING = 0, + SPU_SCHED_WAKE = 0, /* currently unused */ }; struct spu_context { @@ -50,17 +50,16 @@ struct spu_context { spinlock_t mmio_lock; /* protects mmio access */ struct address_space *local_store; /* local store mapping. */ struct address_space *mfc; /* 'mfc' area mappings. */ - struct address_space *cntl; /* 'control' area mappings. */ - struct address_space *signal1; /* 'signal1' area mappings. */ - struct address_space *signal2; /* 'signal2' area mappings. */ - struct address_space *mss; /* 'mss' area mappings. */ - struct address_space *psmap; /* 'psmap' area mappings. */ - spinlock_t mapping_lock; + struct address_space *cntl; /* 'control' area mappings. */ + struct address_space *signal1; /* 'signal1' area mappings. */ + struct address_space *signal2; /* 'signal2' area mappings. */ + struct address_space *mss; /* 'mss' area mappings. */ + struct address_space *psmap; /* 'psmap' area mappings. */ u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; struct mutex state_mutex; - struct mutex run_mutex; + struct semaphore run_sema; struct mm_struct *owner; @@ -141,7 +140,6 @@ struct spu_context_ops { struct spu_dma_info * info); void (*proxydma_info_read) (struct spu_context * ctx, struct spu_proxydma_info * info); - void (*restart_dma)(struct spu_context *ctx); }; extern struct spu_context_ops spu_hw_ops; @@ -151,7 +149,6 @@ struct spufs_inode_info { struct spu_context *i_ctx; struct spu_gang *i_gang; struct inode vfs_inode; - int i_openers; }; #define SPUFS_I(inode) \ container_of(inode, struct spufs_inode_info, vfs_inode) @@ -173,9 +170,6 @@ int put_spu_gang(struct spu_gang *gang); void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); -/* fault handling */ -int spufs_handle_class1(struct spu_context *ctx); - /* context management */ static inline void spu_acquire(struct spu_context *ctx) { @@ -196,6 +190,7 @@ void spu_unmap_mappings(struct spu_context *ctx); void spu_forget(struct spu_context *ctx); int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); void spu_acquire_saved(struct spu_context *ctx); +int spu_acquire_exclusive(struct spu_context *ctx); int spu_activate(struct spu_context *ctx, unsigned long flags); void spu_deactivate(struct spu_context *ctx); @@ -223,13 +218,14 @@ extern char *isolated_loader; prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ if (condition) \ break; \ - if (signal_pending(current)) { \ - __ret = -ERESTARTSYS; \ - break; \ + if (!signal_pending(current)) { \ + spu_release(ctx); \ + schedule(); \ + spu_acquire(ctx); \ + continue; \ } \ - spu_release(ctx); \ - schedule(); \ - spu_acquire(ctx); \ + __ret = -ERESTARTSYS; \ + break; \ } \ finish_wait(&(wq), &__wait); \ __ret; \ diff --git a/trunk/arch/powerpc/platforms/cell/spufs/switch.c b/trunk/arch/powerpc/platforms/cell/spufs/switch.c index 8347c4a3f894..fd91c73de34e 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/switch.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/switch.c @@ -2084,10 +2084,6 @@ int spu_save(struct spu_state *prev, struct spu *spu) int rc; acquire_spu_lock(spu); /* Step 1. */ - prev->dar = spu->dar; - prev->dsisr = spu->dsisr; - spu->dar = 0; - spu->dsisr = 0; rc = __do_spu_save(prev, spu); /* Steps 2-53. */ release_spu_lock(spu); if (rc != 0 && rc != 2 && rc != 6) { @@ -2113,9 +2109,9 @@ int spu_restore(struct spu_state *new, struct spu *spu) acquire_spu_lock(spu); harvest(NULL, spu); + spu->dar = 0; + spu->dsisr = 0; spu->slb_replace = 0; - new->dar = 0; - new->dsisr = 0; spu->class_0_pending = 0; rc = __do_spu_restore(new, spu); release_spu_lock(spu); diff --git a/trunk/arch/powerpc/platforms/celleb/Kconfig b/trunk/arch/powerpc/platforms/celleb/Kconfig deleted file mode 100644 index 2db1e293433e..000000000000 --- a/trunk/arch/powerpc/platforms/celleb/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config PPC_CELLEB - bool "Toshiba's Cell Reference Set 'Celleb' Architecture" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_CELL - select PPC_OF_PLATFORM_PCI - select HAS_TXX9_SERIAL - select PPC_UDBG_BEAT - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_EHCI_BIG_ENDIAN_MMIO diff --git a/trunk/arch/powerpc/platforms/celleb/iommu.c b/trunk/arch/powerpc/platforms/celleb/iommu.c index 755d869d8553..f63b94c65353 100644 --- a/trunk/arch/powerpc/platforms/celleb/iommu.c +++ b/trunk/arch/powerpc/platforms/celleb/iommu.c @@ -37,7 +37,7 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid, const unsigned long *dma_window; for_each_node_by_type(dn, "ioif") { - dma_window = of_get_property(dn, "toshiba,dma-window", NULL); + dma_window = get_property(dn, "toshiba,dma-window", NULL); if (dma_window) { *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL; *ioid = dma_window[0] & 0x7ffUL; @@ -80,7 +80,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb, if (action != BUS_NOTIFY_ADD_DEVICE) return 0; - dev->archdata.dma_ops = get_pci_dma_ops(); + dev->archdata.dma_ops = pci_dma_ops; return 0; } @@ -95,7 +95,7 @@ static int __init celleb_init_iommu(void) return -ENODEV; celleb_init_direct_mapping(); - set_pci_dma_ops(&dma_direct_ops); + pci_dma_ops = &dma_direct_ops; bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); return 0; diff --git a/trunk/arch/powerpc/platforms/celleb/pci.c b/trunk/arch/powerpc/platforms/celleb/pci.c index d1adf34cd5e8..98de836dfed3 100644 --- a/trunk/arch/powerpc/platforms/celleb/pci.c +++ b/trunk/arch/powerpc/platforms/celleb/pci.c @@ -309,13 +309,13 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, goto error; } - name = of_get_property(node, "model", &rlen); + name = get_property(node, "model", &rlen); if (!name) { printk(KERN_ERR "PCI: model property not found.\n"); goto error; } - wi4 = of_get_property(node, "reg", &rlen); + wi4 = get_property(node, "reg", &rlen); if (wi4 == NULL) goto error; @@ -352,10 +352,10 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, } pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res); - wi0 = of_get_property(node, "device-id", NULL); - wi1 = of_get_property(node, "vendor-id", NULL); - wi2 = of_get_property(node, "class-code", NULL); - wi3 = of_get_property(node, "revision-id", NULL); + wi0 = get_property(node, "device-id", NULL); + wi1 = get_property(node, "vendor-id", NULL); + wi2 = get_property(node, "class-code", NULL); + wi3 = get_property(node, "revision-id", NULL); celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff); celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff); @@ -376,7 +376,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr); - li = of_get_property(node, "interrupts", &rlen); + li = get_property(node, "interrupts", &rlen); val = li[0]; celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1); celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val); @@ -424,7 +424,7 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev, const int *bus_range; unsigned int len; - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) return 1; @@ -451,7 +451,7 @@ int __devinit celleb_setup_phb(struct pci_controller *phb) struct device_node *node; unsigned int rlen; - name = of_get_property(dev, "name", &rlen); + name = get_property(dev, "name", &rlen); if (!name) return 1; diff --git a/trunk/arch/powerpc/platforms/celleb/setup.c b/trunk/arch/powerpc/platforms/celleb/setup.c index 596ab2a788d4..5f4d0d933238 100644 --- a/trunk/arch/powerpc/platforms/celleb/setup.c +++ b/trunk/arch/powerpc/platforms/celleb/setup.c @@ -67,7 +67,7 @@ static void celleb_show_cpuinfo(struct seq_file *m) root = of_find_node_by_path("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); /* using "CHRP" is to trick anaconda into installing FCx into Celleb */ seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model); of_node_put(root); @@ -128,6 +128,15 @@ static int __init celleb_probe(void) return 1; } +/* + * Cell has no legacy IO; anything calling this function has to + * fail or bad things will happen + */ +static int celleb_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + #ifdef CONFIG_KEXEC static void celleb_kexec_cpu_down(int crash, int secondary) { @@ -164,6 +173,7 @@ define_machine(celleb) { .get_rtc_time = beat_get_rtc_time, .set_rtc_time = beat_set_rtc_time, .calibrate_decr = generic_calibrate_decr, + .check_legacy_ioport = celleb_check_legacy_ioport, .progress = celleb_progress, .power_save = beat_power_save, .nvram_size = beat_nvram_get_size, diff --git a/trunk/arch/powerpc/platforms/chrp/Kconfig b/trunk/arch/powerpc/platforms/chrp/Kconfig deleted file mode 100644 index d2c690531963..000000000000 --- a/trunk/arch/powerpc/platforms/chrp/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config PPC_CHRP - bool "Common Hardware Reference Platform (CHRP) based machines" - depends on PPC_MULTIPLATFORM && PPC32 - select MPIC - select PPC_I8259 - select PPC_INDIRECT_PCI - select PPC_RTAS - select PPC_MPC106 - select PPC_UDBG_16550 - select PPC_NATIVE - default y diff --git a/trunk/arch/powerpc/platforms/chrp/nvram.c b/trunk/arch/powerpc/platforms/chrp/nvram.c index 8efd4244701c..0dd4a64757d9 100644 --- a/trunk/arch/powerpc/platforms/chrp/nvram.c +++ b/trunk/arch/powerpc/platforms/chrp/nvram.c @@ -74,7 +74,7 @@ void __init chrp_nvram_init(void) if (nvram == NULL) return; - nbytes_p = of_get_property(nvram, "#bytes", &proplen); + nbytes_p = get_property(nvram, "#bytes", &proplen); if (nbytes_p == NULL || proplen != sizeof(unsigned int)) return; diff --git a/trunk/arch/powerpc/platforms/chrp/pci.c b/trunk/arch/powerpc/platforms/chrp/pci.c index 1469d6478f67..ddb4a116ea89 100644 --- a/trunk/arch/powerpc/platforms/chrp/pci.c +++ b/trunk/arch/powerpc/platforms/chrp/pci.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -136,11 +137,9 @@ hydra_init(void) struct device_node *np; struct resource r; - np = of_find_node_by_name(NULL, "mac-io"); - if (np == NULL || of_address_to_resource(np, 0, &r)) { - of_node_put(np); + np = find_devices("mac-io"); + if (np == NULL || of_address_to_resource(np, 0, &r)) return 0; - } Hydra = ioremap(r.start, r.end-r.start); printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start); printk("Hydra Feature_Control was %x", @@ -187,9 +186,10 @@ setup_python(struct pci_controller *hose, struct device_node *dev) /* Marvell Discovery II based Pegasos 2 */ static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev) { - struct device_node *root = of_find_node_by_path("/"); + struct device_node *root = find_path_device("/"); struct device_node *rtas; + of_node_get(root); rtas = of_find_node_by_name (root, "rtas"); if (rtas) { hose->ops = &rtas_pci_ops; @@ -199,7 +199,6 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d " your firmware\n"); } pci_assign_all_buses = 1; - /* keep the reference to the root node */ } void __init @@ -212,14 +211,14 @@ chrp_find_bridges(void) const unsigned int *dma; const char *model, *machine; int is_longtrail = 0, is_mot = 0, is_pegasos = 0; - struct device_node *root = of_find_node_by_path("/"); + struct device_node *root = find_path_device("/"); struct resource r; /* * The PCI host bridge nodes on some machines don't have * properties to adequately identify them, so we have to * look at what sort of machine this is as well. */ - machine = of_get_property(root, "model", NULL); + machine = get_property(root, "model", NULL); if (machine != NULL) { is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; is_mot = strncmp(machine, "MOT", 3) == 0; @@ -238,7 +237,7 @@ chrp_find_bridges(void) dev->full_name); continue; } - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", dev->full_name); @@ -264,7 +263,7 @@ chrp_find_bridges(void) hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; - model = of_get_property(dev, "model", NULL); + model = get_property(dev, "model", NULL); if (model == NULL) model = ""; if (device_is_compatible(dev, "IBM,python")) { @@ -286,8 +285,7 @@ chrp_find_bridges(void) r.start + 0x000f8000, r.start + 0x000f8010); if (index == 0) { - dma = of_get_property(dev, "system-dma-base", - &len); + dma = get_property(dev, "system-dma-base",&len); if (dma && len >= sizeof(*dma)) { dma = (unsigned int *) (((unsigned long)dma) + @@ -305,13 +303,12 @@ chrp_find_bridges(void) /* check the first bridge for a property that we can use to set pci_dram_offset */ - dma = of_get_property(dev, "ibm,dma-ranges", &len); + dma = get_property(dev, "ibm,dma-ranges", &len); if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { pci_dram_offset = dma[2] - dma[3]; printk("pci_dram_offset = %lx\n", pci_dram_offset); } } - of_node_put(root); } /* SL82C105 IDE Control/Status Register */ diff --git a/trunk/arch/powerpc/platforms/chrp/setup.c b/trunk/arch/powerpc/platforms/chrp/setup.c index 1870038a8e0a..117c9a0055bd 100644 --- a/trunk/arch/powerpc/platforms/chrp/setup.c +++ b/trunk/arch/powerpc/platforms/chrp/setup.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -110,9 +111,9 @@ void chrp_show_cpuinfo(struct seq_file *m) struct device_node *root; const char *model = ""; - root = of_find_node_by_path("/"); + root = find_path_device("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); seq_printf(m, "machine\t\t: CHRP %s\n", model); /* longtrail (goldengate) stuff */ @@ -160,7 +161,6 @@ void chrp_show_cpuinfo(struct seq_file *m) gg2_cachetypes[(t>>2) & 3], gg2_cachemodes[t & 3]); } - of_node_put(root); } /* @@ -205,15 +205,13 @@ static void __init sio_init(void) { struct device_node *root; - if ((root = of_find_node_by_path("/")) && - !strncmp(of_get_property(root, "model", NULL), - "IBM,LongTrail", 13)) { + if ((root = find_path_device("/")) && + !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { /* logical device 0 (KBC/Keyboard) */ sio_fixup_irq("keyboard", 0, 1, 2); /* select logical device 1 (KBC/Mouse) */ sio_fixup_irq("mouse", 1, 12, 2); } - of_node_put(root); } @@ -226,12 +224,12 @@ static void __init pegasos_set_l2cr(void) return; /* Enable L2 cache if needed */ - np = of_find_node_by_type(NULL, "cpu"); + np = find_type_devices("cpu"); if (np != NULL) { - const unsigned int *l2cr = of_get_property(np, "l2cr", NULL); + const unsigned int *l2cr = get_property(np, "l2cr", NULL); if (l2cr == NULL) { printk ("Pegasos l2cr : no cpu l2cr property found\n"); - goto out; + return; } if (!((*l2cr) & 0x80000000)) { printk ("Pegasos l2cr : L2 cache was not active, " @@ -240,8 +238,6 @@ static void __init pegasos_set_l2cr(void) _set_L2CR((*l2cr) | 0x80000000); } } -out: - of_node_put(np); } static void briq_restart(char *cmd) @@ -254,14 +250,14 @@ static void briq_restart(char *cmd) void __init chrp_setup_arch(void) { - struct device_node *root = of_find_node_by_path("/"); + struct device_node *root = find_path_device ("/"); const char *machine = NULL; /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000/HZ; if (root) - machine = of_get_property(root, "model", NULL); + machine = get_property(root, "model", NULL); if (machine && strncmp(machine, "Pegasos", 7) == 0) { _chrp_type = _CHRP_Pegasos; } else if (machine && strncmp(machine, "IBM", 3) == 0) { @@ -277,7 +273,6 @@ void __init chrp_setup_arch(void) /* Let's assume it is an IBM chrp if all else fails */ _chrp_type = _CHRP_IBM; } - of_node_put(root); printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]); rtas_initialize(); @@ -366,8 +361,8 @@ static void __init chrp_find_openpic(void) return; root = of_find_node_by_path("/"); if (root) { - opprop = of_get_property(root, "platform-open-pic", &oplen); - na = of_n_addr_cells(root); + opprop = get_property(root, "platform-open-pic", &oplen); + na = prom_n_addr_cells(root); } if (opprop && oplen >= na * sizeof(unsigned int)) { opaddr = opprop[na-1]; /* assume 32-bit */ @@ -383,7 +378,7 @@ static void __init chrp_find_openpic(void) printk(KERN_INFO "OpenPIC at %lx\n", opaddr); - iranges = of_get_property(np, "interrupt-ranges", &len); + iranges = get_property(np, "interrupt-ranges", &len); if (iranges == NULL) len = 0; /* non-distributed mpic */ else @@ -432,7 +427,7 @@ static void __init chrp_find_openpic(void) of_node_put(np); } -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) static struct irqaction xmon_irqaction = { .handler = xmon_irq, .mask = CPU_MASK_NONE, @@ -468,16 +463,15 @@ static void __init chrp_find_8259(void) * Also, Pegasos-type platforms don't have a proper node to start * from anyway */ - for_each_node_by_name(np, "pci") { - const unsigned int *addrp = of_get_property(np, + for (np = find_devices("pci"); np != NULL; np = np->next) { + const unsigned int *addrp = get_property(np, "8259-interrupt-acknowledge", NULL); if (addrp == NULL) continue; - chrp_int_ack = addrp[of_n_addr_cells(np)-1]; + chrp_int_ack = addrp[prom_n_addr_cells(np)-1]; break; } - of_node_put(np); if (np == NULL) printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" " address, polling\n"); @@ -499,7 +493,7 @@ static void __init chrp_find_8259(void) void __init chrp_init_IRQ(void) { -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) struct device_node *kbd; #endif chrp_find_openpic(); @@ -516,14 +510,13 @@ void __init chrp_init_IRQ(void) if (_chrp_type == _CHRP_Pegasos) ppc_md.get_irq = i8259_irq; -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) +#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) /* see if there is a keyboard in the device tree with a parent of type "adb" */ - for_each_node_by_name(kbd, "keyboard") + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) if (kbd->parent && kbd->parent->type && strcmp(kbd->parent->type, "adb") == 0) break; - of_node_put(kbd); if (kbd) setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction); #endif @@ -549,9 +542,9 @@ chrp_init2(void) /* Get the event scan rate for the rtas so we know how * often it expects a heartbeat. -- Cort */ - device = of_find_node_by_name(NULL, "rtas"); + device = find_devices("rtas"); if (device) - p = of_get_property(device, "rtas-event-scan-rate", NULL); + p = get_property(device, "rtas-event-scan-rate", NULL); if (p && *p) { /* * Arrange to call chrp_event_scan at least *p times @@ -578,7 +571,6 @@ chrp_init2(void) printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", *p, interval); } - of_node_put(device); if (ppc_md.progress) ppc_md.progress(" Have fun! ", 0x7777); diff --git a/trunk/arch/powerpc/platforms/chrp/time.c b/trunk/arch/powerpc/platforms/chrp/time.c index 96d1e4b3c493..7d7889026936 100644 --- a/trunk/arch/powerpc/platforms/chrp/time.c +++ b/trunk/arch/powerpc/platforms/chrp/time.c @@ -39,17 +39,12 @@ long __init chrp_time_init(void) struct resource r; int base; - rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00"); + rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL) - rtcs = of_find_compatible_node(NULL, "rtc", "ds1385-rtc"); - if (rtcs == NULL) - return 0; - if (of_address_to_resource(rtcs, 0, &r)) { - of_node_put(rtcs); + rtcs = find_compatible_devices("rtc", "ds1385-rtc"); + if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r)) return 0; - } - of_node_put(rtcs); - + base = r.start; nvram_as1 = 0; nvram_as0 = base; diff --git a/trunk/arch/powerpc/platforms/embedded6xx/Kconfig b/trunk/arch/powerpc/platforms/embedded6xx/Kconfig index 9557908ef545..3410bcbc9dbe 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/trunk/arch/powerpc/platforms/embedded6xx/Kconfig @@ -2,6 +2,78 @@ choice prompt "Machine Type" depends on EMBEDDED6xx +config KATANA + bool "Artesyn-Katana" + help + Select KATANA if configuring an Artesyn KATANA 750i or 3750 + cPCI board. + +config WILLOW + bool "Cogent-Willow" + +config CPCI690 + bool "Force-CPCI690" + help + Select CPCI690 if configuring a Force CPCI690 cPCI board. + +config POWERPMC250 + bool "Force-PowerPMC250" + +config CHESTNUT + bool "IBM 750FX Eval board or 750GX Eval board" + help + Select CHESTNUT if configuring an IBM 750FX Eval Board or a + IBM 750GX Eval board. + +config SPRUCE + bool "IBM-Spruce" + select PPC_INDIRECT_PCI + +config HDPU + bool "Sky-HDPU" + help + Select HDPU if configuring a Sky Computers Compute Blade. + +config HDPU_FEATURES + depends on HDPU + tristate "HDPU-Features" + help + Select to enable HDPU enhanced features. + +config EV64260 + bool "Marvell-EV64260BP" + help + Select EV64260 if configuring a Marvell (formerly Galileo) + EV64260BP Evaluation platform. + +config LOPEC + bool "Motorola-LoPEC" + select PPC_I8259 + +config MVME5100 + bool "Motorola-MVME5100" + select PPC_INDIRECT_PCI + +config PPLUS + bool "Motorola-PowerPlus" + select PPC_I8259 + select PPC_INDIRECT_PCI + +config PRPMC750 + bool "Motorola-PrPMC750" + select PPC_INDIRECT_PCI + +config PRPMC800 + bool "Motorola-PrPMC800" + select PPC_INDIRECT_PCI + +config SANDPOINT + bool "Motorola-Sandpoint" + select PPC_I8259 + help + Select SANDPOINT if configuring for a Motorola Sandpoint X3 + (any flavor). + config LINKSTATION bool "Linkstation / Kurobox(HG) from Buffalo" select MPIC @@ -25,24 +97,212 @@ config MPC7448HPC2 help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) platform + +config RADSTONE_PPC7D + bool "Radstone Technology PPC7D board" + select PPC_I8259 + +config PAL4 + bool "SBS-Palomar4" + +config EST8260 + bool "EST8260" + ---help--- + The EST8260 is a single-board computer manufactured by Wind River + Systems, Inc. (formerly Embedded Support Tools Corp.) and based on + the MPC8260. Wind River Systems has a website at + , but the EST8260 cannot be found on it + and has probably been discontinued or rebadged. + +config SBC82xx + bool "SBC82xx" + ---help--- + SBC PowerQUICC II, single-board computer with MPC82xx CPU + Manufacturer: Wind River Systems, Inc. + Date of Release: May 2003 + End of Life: - + URL: + +config SBS8260 + bool "SBS8260" + +config RPX8260 + bool "RPXSUPER" + +config TQM8260 + bool "TQM8260" + ---help--- + MPC8260 based module, little larger than credit card, + up to 128 MB global + 64 MB local RAM, 32 MB Flash, + 32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet, + 2 x serial ports, ... + Manufacturer: TQ Components, www.tq-group.de + Date of Release: June 2001 + End of Life: not yet :-) + URL: + +config ADS8272 + bool "ADS8272" + +config PQ2FADS + bool "Freescale-PQ2FADS" + help + Select PQ2FADS if you wish to configure for a Freescale + PQ2FADS board (-VR or -ZU). + +config EV64360 + bool "Marvell-EV64360BP" + help + Select EV64360 if configuring a Marvell EV64360BP Evaluation + platform. endchoice +config PQ2ADS + bool + depends on ADS8272 + default y + +config TQM8xxL + bool + depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L) + default y + +config 8260 + bool "CPM2 Support" if WILLOW + depends on 6xx + default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS + help + The MPC8260 is a typical embedded CPU made by Motorola. Selecting + this option means that you wish to build a kernel for a machine with + an 8260 class CPU. + +config 8272 + bool + depends on 6xx + default y if ADS8272 + select 8260 + help + The MPC8272 CPM has a different internal dpram setup than other CPM2 + devices + +config CPM2 + bool + depends on 8260 || MPC8560 || MPC8555 + default y + help + The CPM2 (Communications Processor Module) is a coprocessor on + embedded CPUs made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with a CPM2 coprocessor + on it (826x, 827x, 8560). + +config PPC_GEN550 + bool + depends on SANDPOINT || SPRUCE || PPLUS || \ + PRPMC750 || PRPMC800 || LOPEC || \ + (EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \ + 83xx || LINKSTATION + default y + +config FORCE + bool + depends on 6xx && POWERPMC250 + default y + +config GT64260 + bool + depends on EV64260 || CPCI690 + default y + +config MV64360 # Really MV64360 & MV64460 + bool + depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360 + default y + +config MV64X60 + bool + depends on (GT64260 || MV64360) + select PPC_INDIRECT_PCI + default y + config TSI108_BRIDGE bool depends on MPC7448HPC2 default y +menu "Set bridge options" + depends on MV64X60 + +config NOT_COHERENT_CACHE + bool "Turn off Cache Coherency" + default n + help + Some 64x60 bridges lock up when trying to enforce cache coherency. + When this option is selected, cache coherency will be turned off. + Note that this can cause other problems (e.g., stale data being + speculatively loaded via a cached mapping). Use at your own risk. + +config MV64X60_BASE + hex "Set bridge base used by firmware" + default "0xf1000000" + help + A firmware can leave the base address of the bridge's registers at + a non-standard location. If so, set this value to reflect the + address of that non-standard location. + +config MV64X60_NEW_BASE + hex "Set bridge base used by kernel" + default "0xf1000000" + help + If the current base address of the bridge's registers is not where + you want it, set this value to the address that you want it moved to. + +endmenu + +config NONMONARCH_SUPPORT + bool "Enable Non-Monarch Support" + depends on PRPMC800 + +config HARRIER + bool + depends on PRPMC800 + default y + +config EPIC_SERIAL_MODE + bool + depends on 6xx && (LOPEC || SANDPOINT) + default y + config MPC10X_BRIDGE bool - depends on LINKSTATION + depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION select PPC_INDIRECT_PCI default y config MPC10X_OPENPIC bool - depends on LINKSTATION + depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION default y config MPC10X_STORE_GATHERING bool "Enable MPC10x store gathering" depends on MPC10X_BRIDGE + +config SANDPOINT_ENABLE_UART1 + bool "Enable DUART mode on Sandpoint" + depends on SANDPOINT + help + If this option is enabled then the MPC824x processor will run + in DUART mode instead of UART mode. + +config HARRIER_STORE_GATHERING + bool "Enable Harrier store gathering" + depends on HARRIER + +config MVME5100_IPMC761_PRESENT + bool "MVME5100 configured with an IPMC761" + depends on MVME5100 + select PPC_I8259 + +config SPRUCE_BAUD_33M + bool "Spruce baud clock support" + depends on SPRUCE diff --git a/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c b/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c index b412f006a9c5..3f6c4114f908 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -58,11 +58,11 @@ static int __init add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; - const int *bus_range; + int *bus_range; printk("Adding PCI host bridge %s\n", dev->full_name); - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); @@ -106,7 +106,7 @@ static void __init linkstation_init_IRQ(void) { struct mpic *mpic; struct device_node *dnp; - const u32 *prop; + void *prop; int size; phys_addr_t paddr; @@ -114,7 +114,7 @@ static void __init linkstation_init_IRQ(void) if (dnp == NULL) return; - prop = of_get_property(dnp, "reg", &size); + prop = (struct device_node *)get_property(dnp, "reg", &size); paddr = (phys_addr_t)of_translate_address(dnp, prop); mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC "); diff --git a/trunk/arch/powerpc/platforms/embedded6xx/ls_uart.c b/trunk/arch/powerpc/platforms/embedded6xx/ls_uart.c index d0bee9f19e4e..0e837762cc5b 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -110,8 +110,8 @@ static int __init ls_uarts_init(void) if (!avr) return -EINVAL; - avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len); - phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0]; + avr_clock = *(u32*)get_property(avr, "clock-frequency", &len); + phys_addr = ((u32*)get_property(avr, "reg", &len))[0]; if (!avr_clock || !phys_addr) return -EINVAL; diff --git a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index c3f64ddb0be6..3fcc85f60fbf 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ static void __init mpc7448_hpc2_setup_arch(void) if (cpu != 0) { const unsigned int *fp; - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != 0) loops_per_jiffy = *fp / HZ; else @@ -90,6 +91,16 @@ static void __init mpc7448_hpc2_setup_arch(void) } tsi108_csr_vir_base = get_vir_csrbase(); +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + ROOT_DEV = Root_RAM0; +#endif + /* setup PCI host bridge */ #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) @@ -132,7 +143,7 @@ static void __init mpc7448_hpc2_init_IRQ(void) tsi_pic = of_find_node_by_type(NULL, "open-pic"); if (tsi_pic) { unsigned int size; - const void *prop = of_get_property(tsi_pic, "reg", &size); + const void *prop = get_property(tsi_pic, "reg", &size); mpic_paddr = of_translate_address(tsi_pic, prop); } diff --git a/trunk/arch/powerpc/platforms/iseries/Kconfig b/trunk/arch/powerpc/platforms/iseries/Kconfig index 46c3a8e7c3a8..54e6b3b6f261 100644 --- a/trunk/arch/powerpc/platforms/iseries/Kconfig +++ b/trunk/arch/powerpc/platforms/iseries/Kconfig @@ -1,7 +1,3 @@ -config PPC_ISERIES - bool "IBM Legacy iSeries" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_INDIRECT_IO menu "iSeries device drivers" depends on PPC_ISERIES diff --git a/trunk/arch/powerpc/platforms/iseries/iommu.c b/trunk/arch/powerpc/platforms/iseries/iommu.c index 3b6a9666c2c0..d7a756d5135c 100644 --- a/trunk/arch/powerpc/platforms/iseries/iommu.c +++ b/trunk/arch/powerpc/platforms/iseries/iommu.c @@ -171,7 +171,7 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn) { struct iommu_table *tbl; struct pci_dn *pdn = PCI_DN(dn); - const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL); + const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL); BUG_ON(lsn == NULL); @@ -194,5 +194,5 @@ void iommu_init_early_iSeries(void) ppc_md.tce_build = tce_build_iSeries; ppc_md.tce_free = tce_free_iSeries; - set_pci_dma_ops(&dma_iommu_ops); + pci_dma_ops = &dma_iommu_ops; } diff --git a/trunk/arch/powerpc/platforms/iseries/irq.c b/trunk/arch/powerpc/platforms/iseries/irq.c index 63b33675848b..5225abfafd9b 100644 --- a/trunk/arch/powerpc/platforms/iseries/irq.c +++ b/trunk/arch/powerpc/platforms/iseries/irq.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -336,8 +337,6 @@ unsigned int iSeries_get_irq(void) return irq; } -#ifdef CONFIG_PCI - static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -385,4 +384,3 @@ void __init iSeries_init_IRQ(void) "failed with rc 0x%x\n", ret); } -#endif /* CONFIG_PCI */ diff --git a/trunk/arch/powerpc/platforms/iseries/pci.c b/trunk/arch/powerpc/platforms/iseries/pci.c index 9c974227155e..4a06d9c34986 100644 --- a/trunk/arch/powerpc/platforms/iseries/pci.c +++ b/trunk/arch/powerpc/platforms/iseries/pci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -176,7 +177,7 @@ void __init iSeries_pci_final_fixup(void) struct pci_dn *pdn = PCI_DN(node); const u32 *agent; - agent = of_get_property(node, "linux,agent-id", NULL); + agent = get_property(node, "linux,agent-id", NULL); if ((pdn != NULL) && (agent != NULL)) { u8 irq = iSeries_allocate_IRQ(pdn->busno, 0, pdn->bussubno); @@ -754,7 +755,7 @@ void __init iSeries_pcibios_init(void) if ((node->type == NULL) || (strcmp(node->type, "pci") != 0)) continue; - busp = of_get_property(node, "bus-range", NULL); + busp = get_property(node, "bus-range", NULL); if (busp == NULL) continue; bus = *busp; diff --git a/trunk/arch/powerpc/platforms/iseries/setup.c b/trunk/arch/powerpc/platforms/iseries/setup.c index 7f5dcee814d4..cce7e309340c 100644 --- a/trunk/arch/powerpc/platforms/iseries/setup.c +++ b/trunk/arch/powerpc/platforms/iseries/setup.c @@ -628,6 +628,15 @@ static void iseries_iounmap(volatile void __iomem *token) { } +/* + * iSeries has no legacy IO, anything calling this function has to + * fail or bad things will happen + */ +static int iseries_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + static int __init iseries_probe(void) { unsigned long root = of_get_flat_dt_root(); @@ -658,6 +667,7 @@ define_machine(iseries) { .calibrate_decr = generic_calibrate_decr, .progress = iSeries_progress, .probe = iseries_probe, + .check_legacy_ioport = iseries_check_legacy_ioport, .ioremap = iseries_ioremap, .iounmap = iseries_iounmap, /* XXX Implement enable_pmcs for iSeries */ diff --git a/trunk/arch/powerpc/platforms/iseries/viopath.c b/trunk/arch/powerpc/platforms/iseries/viopath.c index 2ca2d8a9de97..e2100ece9c65 100644 --- a/trunk/arch/powerpc/platforms/iseries/viopath.c +++ b/trunk/arch/powerpc/platforms/iseries/viopath.c @@ -155,7 +155,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) node = of_find_node_by_path("/"); sysid = NULL; if (node != NULL) - sysid = of_get_property(node, "system-id", NULL); + sysid = get_property(node, "system-id", NULL); if (sysid == NULL) seq_printf(m, "SRLNBR=\n"); diff --git a/trunk/arch/powerpc/platforms/maple/Kconfig b/trunk/arch/powerpc/platforms/maple/Kconfig deleted file mode 100644 index f7c95eb5d8ba..000000000000 --- a/trunk/arch/powerpc/platforms/maple/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config PPC_MAPLE - depends on PPC_MULTIPLATFORM && PPC64 - bool "Maple 970FX Evaluation Board" - select MPIC - select U3_DART - select MPIC_U3_HT_IRQS - select GENERIC_TBSYNC - select PPC_UDBG_16550 - select PPC_970_NAP - select PPC_NATIVE - select PPC_RTAS - select MMIO_NVRAM - select ATA_NONSTANDARD if ATA - default n - help - This option enables support for the Maple 970FX Evaluation Board. - For more information, refer to diff --git a/trunk/arch/powerpc/platforms/maple/pci.c b/trunk/arch/powerpc/platforms/maple/pci.c index b1d3b99c3f9d..73c59904697f 100644 --- a/trunk/arch/powerpc/platforms/maple/pci.c +++ b/trunk/arch/powerpc/platforms/maple/pci.c @@ -44,11 +44,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher int len; /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = of_get_property(node, "class-code", NULL); + class_code = get_property(node, "class-code", NULL); if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) continue; - bus_range = of_get_property(node, "bus-range", &len); + bus_range = get_property(node, "bus-range", &len); if (bus_range != NULL && len > 2 * sizeof(int)) { if (bus_range[1] > higher) higher = bus_range[1]; @@ -77,7 +77,7 @@ static void __init fixup_bus_range(struct device_node *bridge) bridge->full_name); return; } - bus_range = prop->value; + bus_range = (int *)prop->value; bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); } @@ -454,7 +454,7 @@ static int __init add_bridge(struct device_node *dev) DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", dev->full_name); diff --git a/trunk/arch/powerpc/platforms/maple/setup.c b/trunk/arch/powerpc/platforms/maple/setup.c index 2a30c5b2532e..82d3f9e28d7c 100644 --- a/trunk/arch/powerpc/platforms/maple/setup.c +++ b/trunk/arch/powerpc/platforms/maple/setup.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -113,8 +114,8 @@ static void maple_restart(char *cmd) printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); goto fail; } - maple_nvram_offset = of_get_property(sp, "restart-addr", NULL); - maple_nvram_command = of_get_property(sp, "restart-value", NULL); + maple_nvram_offset = get_property(sp, "restart-addr", NULL); + maple_nvram_command = get_property(sp, "restart-value", NULL); of_node_put(sp); /* send command */ @@ -140,8 +141,8 @@ static void maple_power_off(void) printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); goto fail; } - maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL); - maple_nvram_command = of_get_property(sp, "power-off-value", NULL); + maple_nvram_offset = get_property(sp, "power-off-addr", NULL); + maple_nvram_command = get_property(sp, "power-off-value", NULL); of_node_put(sp); /* send command */ @@ -248,8 +249,8 @@ static void __init maple_init_IRQ(void) /* Find address list in /platform-open-pic */ root = of_find_node_by_path("/"); - naddr = of_n_addr_cells(root); - opprop = of_get_property(root, "platform-open-pic", &opplen); + naddr = prom_n_addr_cells(root); + opprop = get_property(root, "platform-open-pic", &opplen); if (opprop != 0) { openpic_addr = of_read_number(opprop, naddr); has_isus = (opplen > naddr); @@ -260,11 +261,11 @@ static void __init maple_init_IRQ(void) BUG_ON(openpic_addr == 0); /* Check for a big endian MPIC */ - if (of_get_property(np, "big-endian", NULL) != NULL) + if (get_property(np, "big-endian", NULL) != NULL) flags |= MPIC_BIG_ENDIAN; /* XXX Maple specific bits */ - flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET; + flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET; /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ flags |= MPIC_BIG_ENDIAN; diff --git a/trunk/arch/powerpc/platforms/pasemi/Kconfig b/trunk/arch/powerpc/platforms/pasemi/Kconfig index eb4dbc705b06..68dc529dfd2f 100644 --- a/trunk/arch/powerpc/platforms/pasemi/Kconfig +++ b/trunk/arch/powerpc/platforms/pasemi/Kconfig @@ -1,15 +1,3 @@ -config PPC_PASEMI - depends on PPC_MULTIPLATFORM && PPC64 - bool "PA Semi SoC-based platforms" - default n - select MPIC - select PPC_UDBG_16550 - select GENERIC_TBSYNC - select PPC_NATIVE - help - This option enables support for PA Semi's PWRficient line - of SoC processors, including PA6T-1682M - menu "PA Semi PWRficient options" depends on PPC_PASEMI @@ -19,11 +7,4 @@ config PPC_PASEMI_IOMMU help IOMMU support for PA6T-1682M -config PPC_PASEMI_MDIO - depends on PHYLIB - tristate "MDIO support via GPIO" - default y - help - Driver for MDIO via GPIO on PWRficient platforms - endmenu diff --git a/trunk/arch/powerpc/platforms/pasemi/Makefile b/trunk/arch/powerpc/platforms/pasemi/Makefile index 2cd2a4f26a48..e657ccae90a9 100644 --- a/trunk/arch/powerpc/platforms/pasemi/Makefile +++ b/trunk/arch/powerpc/platforms/pasemi/Makefile @@ -1,3 +1,2 @@ obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o -obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o -obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o + diff --git a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c b/trunk/arch/powerpc/platforms/pasemi/cpufreq.c deleted file mode 100644 index 2a57d6023685..000000000000 --- a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2007 PA Semi, Inc - * - * Authors: Egor Martovetsky - * Olof Johansson - * - * Maintained by: Olof Johansson - * - * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c: - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include - -#include -#include -#include - -#define SDCASR_REG 0x0100 -#define SDCASR_REG_STRIDE 0x1000 -#define SDCPWR_CFGA0_REG 0x0100 -#define SDCPWR_PWST0_REG 0x0000 -#define SDCPWR_GIZTIME_REG 0x0440 - -/* SDCPWR_GIZTIME_REG fields */ -#define SDCPWR_GIZTIME_GR 0x80000000 -#define SDCPWR_GIZTIME_LONGLOCK 0x000000ff - -/* Offset of ASR registers from SDC base */ -#define SDCASR_OFFSET 0x120000 - -static void __iomem *sdcpwr_mapbase; -static void __iomem *sdcasr_mapbase; - -static DEFINE_MUTEX(pas_switch_mutex); - -/* Current astate, is used when waking up from power savings on - * one core, in case the other core has switched states during - * the idle time. - */ -static int current_astate; - -/* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */ -static struct cpufreq_frequency_table pas_freqs[] = { - {0, 0}, - {1, 0}, - {2, 0}, - {3, 0}, - {4, 0}, - {0, CPUFREQ_TABLE_END}, -}; - -static struct freq_attr *pas_cpu_freqs_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -/* - * hardware specific functions - */ - -static int get_astate_freq(int astate) -{ - u32 ret; - ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10)); - - return ret & 0x3f; -} - -static int get_cur_astate(int cpu) -{ - u32 ret; - - ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG); - ret = (ret >> (cpu * 4)) & 0x7; - - return ret; -} - -static int get_gizmo_latency(void) -{ - u32 giztime, ret; - - giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG); - - /* just provide the upper bound */ - if (giztime & SDCPWR_GIZTIME_GR) - ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000; - else - ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000; - - return ret; -} - -static void set_astate(int cpu, unsigned int astate) -{ - u64 flags; - - /* Return if called before init has run */ - if (unlikely(!sdcasr_mapbase)) - return; - - local_irq_save(flags); - - out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate); - - local_irq_restore(flags); -} - -void restore_astate(int cpu) -{ - set_astate(cpu, current_astate); -} - -/* - * cpufreq functions - */ - -static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - const u32 *max_freqp; - u32 max_freq; - int i, cur_astate; - struct resource res; - struct device_node *cpu, *dn; - int err = -ENODEV; - - cpu = of_get_cpu_node(policy->cpu, NULL); - - if (!cpu) - goto out; - - dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); - if (!dn) - goto out; - err = of_address_to_resource(dn, 0, &res); - of_node_put(dn); - if (err) - goto out; - sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000); - if (!sdcasr_mapbase) { - err = -EINVAL; - goto out; - } - - dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); - if (!dn) { - err = -ENODEV; - goto out_unmap_sdcasr; - } - err = of_address_to_resource(dn, 0, &res); - of_node_put(dn); - if (err) - goto out_unmap_sdcasr; - sdcpwr_mapbase = ioremap(res.start, 0x1000); - if (!sdcpwr_mapbase) { - err = -EINVAL; - goto out_unmap_sdcasr; - } - - pr_debug("init cpufreq on CPU %d\n", policy->cpu); - - max_freqp = of_get_property(cpu, "clock-frequency", NULL); - if (!max_freqp) { - err = -EINVAL; - goto out_unmap_sdcpwr; - } - - /* we need the freq in kHz */ - max_freq = *max_freqp / 1000; - - pr_debug("max clock-frequency is at %u kHz\n", max_freq); - pr_debug("initializing frequency table\n"); - - /* initialize frequency table */ - for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { - pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000; - pr_debug("%d: %d\n", i, pas_freqs[i].frequency); - } - - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - - policy->cpuinfo.transition_latency = get_gizmo_latency(); - - cur_astate = get_cur_astate(policy->cpu); - pr_debug("current astate is at %d\n",cur_astate); - - policy->cur = pas_freqs[cur_astate].frequency; - policy->cpus = cpu_online_map; - - cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu); - - /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max - * are set correctly - */ - return cpufreq_frequency_table_cpuinfo(policy, pas_freqs); - -out_unmap_sdcpwr: - iounmap(sdcpwr_mapbase); - -out_unmap_sdcasr: - iounmap(sdcasr_mapbase); -out: - return err; -} - -static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - if (sdcasr_mapbase) - iounmap(sdcasr_mapbase); - if (sdcpwr_mapbase) - iounmap(sdcpwr_mapbase); - - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static int pas_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, pas_freqs); -} - -static int pas_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_freqs freqs; - int pas_astate_new; - int i; - - cpufreq_frequency_table_target(policy, - pas_freqs, - target_freq, - relation, - &pas_astate_new); - - freqs.old = policy->cur; - freqs.new = pas_freqs[pas_astate_new].frequency; - freqs.cpu = policy->cpu; - - mutex_lock(&pas_switch_mutex); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", - policy->cpu, - pas_freqs[pas_astate_new].frequency, - pas_freqs[pas_astate_new].index); - - current_astate = pas_astate_new; - - for_each_online_cpu(i) - set_astate(i, pas_astate_new); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - mutex_unlock(&pas_switch_mutex); - - return 0; -} - -static struct cpufreq_driver pas_cpufreq_driver = { - .name = "pas-cpufreq", - .owner = THIS_MODULE, - .flags = CPUFREQ_CONST_LOOPS, - .init = pas_cpufreq_cpu_init, - .exit = pas_cpufreq_cpu_exit, - .verify = pas_cpufreq_verify, - .target = pas_cpufreq_target, - .attr = pas_cpu_freqs_attr, -}; - -/* - * module init and destoy - */ - -static int __init pas_cpufreq_init(void) -{ - if (!machine_is_compatible("PA6T-1682M")) - return -ENODEV; - - return cpufreq_register_driver(&pas_cpufreq_driver); -} - -static void __exit pas_cpufreq_exit(void) -{ - cpufreq_unregister_driver(&pas_cpufreq_driver); -} - -module_init(pas_cpufreq_init); -module_exit(pas_cpufreq_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Egor Martovetsky , Olof Johansson "); diff --git a/trunk/arch/powerpc/platforms/pasemi/gpio_mdio.c b/trunk/arch/powerpc/platforms/pasemi/gpio_mdio.c deleted file mode 100644 index c91a33593bb8..000000000000 --- a/trunk/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2006-2007 PA Semi, Inc - * - * Author: Olof Johansson, PA Semi - * - * Maintained by: Olof Johansson - * - * Based on drivers/net/fs_enet/mii-bitbang.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This 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 - -#define DELAY 1 - -static void __iomem *gpio_regs; - -struct gpio_priv { - int mdc_pin; - int mdio_pin; -}; - -#define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin) -#define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin) - -static inline void mdio_lo(struct mii_bus *bus) -{ - out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus)); -} - -static inline void mdio_hi(struct mii_bus *bus) -{ - out_le32(gpio_regs, 1 << MDIO_PIN(bus)); -} - -static inline void mdc_lo(struct mii_bus *bus) -{ - out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus)); -} - -static inline void mdc_hi(struct mii_bus *bus) -{ - out_le32(gpio_regs, 1 << MDC_PIN(bus)); -} - -static inline void mdio_active(struct mii_bus *bus) -{ - out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus))); -} - -static inline void mdio_tristate(struct mii_bus *bus) -{ - out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus))); -} - -static inline int mdio_read(struct mii_bus *bus) -{ - return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus))); -} - -static void clock_out(struct mii_bus *bus, int bit) -{ - if (bit) - mdio_hi(bus); - else - mdio_lo(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - mdc_lo(bus); -} - -/* Utility to send the preamble, address, and register (common to read and write). */ -static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg) -{ - int i; - - /* CFE uses a really long preamble (40 bits). We'll do the same. */ - mdio_active(bus); - for (i = 0; i < 40; i++) { - clock_out(bus, 1); - } - - /* send the start bit (01) and the read opcode (10) or write (10) */ - clock_out(bus, 0); - clock_out(bus, 1); - - clock_out(bus, read); - clock_out(bus, !read); - - /* send the PHY address */ - for (i = 0; i < 5; i++) { - clock_out(bus, (addr & 0x10) != 0); - addr <<= 1; - } - - /* send the register address */ - for (i = 0; i < 5; i++) { - clock_out(bus, (reg & 0x10) != 0); - reg <<= 1; - } -} - -static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location) -{ - u16 rdreg; - int ret, i; - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - - bitbang_pre(bus, 1, addr, reg); - - /* tri-state our MDIO I/O pin so we can read */ - mdio_tristate(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - mdc_lo(bus); - - /* read 16 bits of register data, MSB first */ - rdreg = 0; - for (i = 0; i < 16; i++) { - mdc_lo(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - mdc_lo(bus); - udelay(DELAY); - rdreg <<= 1; - rdreg |= mdio_read(bus); - } - - mdc_hi(bus); - udelay(DELAY); - mdc_lo(bus); - udelay(DELAY); - - ret = rdreg; - - return ret; -} - -static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val) -{ - int i; - - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - u16 value = val & 0xffff; - - bitbang_pre(bus, 0, addr, reg); - - /* send the turnaround (10) */ - mdc_lo(bus); - mdio_hi(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - mdc_lo(bus); - mdio_lo(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - - /* write 16 bits of register data, MSB first */ - for (i = 0; i < 16; i++) { - mdc_lo(bus); - if (value & 0x8000) - mdio_hi(bus); - else - mdio_lo(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - value <<= 1; - } - - /* - * Tri-state the MDIO line. - */ - mdio_tristate(bus); - mdc_lo(bus); - udelay(DELAY); - mdc_hi(bus); - udelay(DELAY); - return 0; -} - -static int gpio_mdio_reset(struct mii_bus *bus) -{ - /*nothing here - dunno how to reset it*/ - return 0; -} - - -static int __devinit gpio_mdio_probe(struct of_device *ofdev, - const struct of_device_id *match) -{ - struct device *dev = &ofdev->dev; - struct device_node *np = ofdev->node; - struct device_node *gpio_np; - struct mii_bus *new_bus; - struct resource res; - struct gpio_priv *priv; - const unsigned int *prop; - int err = 0; - int i; - - gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); - - if (!gpio_np) - return -ENODEV; - - err = of_address_to_resource(gpio_np, 0, &res); - of_node_put(gpio_np); - - if (err) - return -EINVAL; - - if (!gpio_regs) - gpio_regs = ioremap(res.start, 0x100); - - if (!gpio_regs) - return -EPERM; - - priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - - if (new_bus == NULL) - return -ENOMEM; - - new_bus->name = "pasemi gpio mdio bus", - new_bus->read = &gpio_mdio_read, - new_bus->write = &gpio_mdio_write, - new_bus->reset = &gpio_mdio_reset, - - prop = of_get_property(np, "reg", NULL); - new_bus->id = *prop; - new_bus->priv = priv; - - new_bus->phy_mask = 0; - - new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - for(i = 0; i < PHY_MAX_ADDR; ++i) - new_bus->irq[i] = irq_create_mapping(NULL, 10); - - - prop = of_get_property(np, "mdc-pin", NULL); - priv->mdc_pin = *prop; - - prop = of_get_property(np, "mdio-pin", NULL); - priv->mdio_pin = *prop; - - new_bus->dev = dev; - dev_set_drvdata(dev, new_bus); - - err = mdiobus_register(new_bus); - - if (0 != err) { - printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", - new_bus->name, err); - goto bus_register_fail; - } - - return 0; - -bus_register_fail: - kfree(new_bus); - - return err; -} - - -static int gpio_mdio_remove(struct of_device *dev) -{ - struct mii_bus *bus = dev_get_drvdata(&dev->dev); - - mdiobus_unregister(bus); - - dev_set_drvdata(&dev->dev, NULL); - - kfree(bus->priv); - bus->priv = NULL; - kfree(bus); - - return 0; -} - -static struct of_device_id gpio_mdio_match[] = -{ - { - .compatible = "gpio-mdio", - }, - {}, -}; - -static struct of_platform_driver gpio_mdio_driver = -{ - .name = "gpio-mdio-bitbang", - .match_table = gpio_mdio_match, - .probe = gpio_mdio_probe, - .remove = gpio_mdio_remove, -}; - -int gpio_mdio_init(void) -{ - return of_register_platform_driver(&gpio_mdio_driver); -} - -void gpio_mdio_exit(void) -{ - of_unregister_platform_driver(&gpio_mdio_driver); -} -device_initcall(gpio_mdio_init); - diff --git a/trunk/arch/powerpc/platforms/pasemi/idle.c b/trunk/arch/powerpc/platforms/pasemi/idle.c index 5985ce0c5c48..1ca3ff381591 100644 --- a/trunk/arch/powerpc/platforms/pasemi/idle.c +++ b/trunk/arch/powerpc/platforms/pasemi/idle.c @@ -61,10 +61,6 @@ static int pasemi_system_reset_exception(struct pt_regs *regs) /* do system reset */ return 0; } - - /* Set higher astate since we come out of power savings at 0 */ - restore_astate(hard_smp_processor_id()); - /* everything handled */ regs->msr |= MSR_RI; return 1; @@ -72,11 +68,6 @@ static int pasemi_system_reset_exception(struct pt_regs *regs) void __init pasemi_idle_init(void) { -#ifndef CONFIG_PPC_PASEMI_CPUFREQ - printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); - current_mode = 0; -#endif - ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); diff --git a/trunk/arch/powerpc/platforms/pasemi/iommu.c b/trunk/arch/powerpc/platforms/pasemi/iommu.c index 95fa6a7d15ee..71dbf1a56e13 100644 --- a/trunk/arch/powerpc/platforms/pasemi/iommu.c +++ b/trunk/arch/powerpc/platforms/pasemi/iommu.c @@ -249,13 +249,13 @@ void iommu_init_early_pasemi(void) iommu_off = 1; #else iommu_off = of_chosen && - of_get_property(of_chosen, "linux,iommu-off", NULL); + get_property(of_chosen, "linux,iommu-off", NULL); #endif if (iommu_off) { /* Direct I/O, IOMMU off */ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null; ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null; - set_pci_dma_ops(&dma_direct_ops); + pci_dma_ops = &dma_direct_ops; return; } @@ -266,7 +266,7 @@ void iommu_init_early_pasemi(void) ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi; ppc_md.tce_build = iobmap_build; ppc_md.tce_free = iobmap_free; - set_pci_dma_ops(&dma_iommu_ops); + pci_dma_ops = &dma_iommu_ops; } void __init alloc_iobmap_l2(void) diff --git a/trunk/arch/powerpc/platforms/pasemi/pasemi.h b/trunk/arch/powerpc/platforms/pasemi/pasemi.h index be8495497611..2d3927e6edb0 100644 --- a/trunk/arch/powerpc/platforms/pasemi/pasemi.h +++ b/trunk/arch/powerpc/platforms/pasemi/pasemi.h @@ -14,14 +14,6 @@ extern void __init pasemi_idle_init(void); extern void idle_spin(void); extern void idle_doze(void); -/* Restore astate to last set */ -#ifdef CONFIG_PPC_PASEMI_CPUFREQ -extern void restore_astate(int cpu); -#else -static inline void restore_astate(int cpu) -{ -} -#endif #endif /* _PASEMI_PASEMI_H */ diff --git a/trunk/arch/powerpc/platforms/pasemi/pci.c b/trunk/arch/powerpc/platforms/pasemi/pci.c index 056243da360b..7ecb2ba24db9 100644 --- a/trunk/arch/powerpc/platforms/pasemi/pci.c +++ b/trunk/arch/powerpc/platforms/pasemi/pci.c @@ -33,17 +33,7 @@ #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) -static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset) -{ - /* Device 0 Function 0 is special: It's config space spans function 1 as - * well, so allow larger offset. It's really a two-function device but the - * second function does not probe. - */ - if (bus == 0 && devfn == 0) - return offset < 8192; - else - return offset < 4096; -} +#define CONFIG_OFFSET_VALID(off) ((off) < 4096) static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, u8 bus, u8 devfn, int offset) @@ -61,7 +51,7 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, if (!hose) return PCIBIOS_DEVICE_NOT_FOUND; - if (!pa_pxp_offset_valid(bus->number, devfn, offset)) + if (!CONFIG_OFFSET_VALID(offset)) return PCIBIOS_BAD_REGISTER_NUMBER; addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); @@ -95,7 +85,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, if (!hose) return PCIBIOS_DEVICE_NOT_FOUND; - if (!pa_pxp_offset_valid(bus->number, devfn, offset)) + if (!CONFIG_OFFSET_VALID(offset)) return PCIBIOS_BAD_REGISTER_NUMBER; addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); diff --git a/trunk/arch/powerpc/platforms/pasemi/setup.c b/trunk/arch/powerpc/platforms/pasemi/setup.c index f88f0ec4c8cb..449cf1a08291 100644 --- a/trunk/arch/powerpc/platforms/pasemi/setup.c +++ b/trunk/arch/powerpc/platforms/pasemi/setup.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "pasemi.h" @@ -102,6 +101,12 @@ void __init pas_setup_arch(void) pasemi_idle_init(); } +/* No legacy IO on our parts */ +static int pas_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + static __init void pas_init_IRQ(void) { struct device_node *np; @@ -131,8 +136,8 @@ static __init void pas_init_IRQ(void) /* Find address list in /platform-open-pic */ root = of_find_node_by_path("/"); - naddr = of_n_addr_cells(root); - opprop = of_get_property(root, "platform-open-pic", &opplen); + naddr = prom_n_addr_cells(root); + opprop = get_property(root, "platform-open-pic", &opplen); if (!opprop) { printk(KERN_ERR "No platform-open-pic property.\n"); of_node_put(root); @@ -142,7 +147,7 @@ static __init void pas_init_IRQ(void) printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); mpic = mpic_alloc(mpic_node, openpic_addr, - MPIC_PRIMARY|MPIC_LARGE_VECTORS|MPIC_WANTS_RESET, + MPIC_PRIMARY|MPIC_LARGE_VECTORS, 0, 0, " PAS-OPIC "); BUG_ON(!mpic); @@ -204,20 +209,6 @@ static void __init pas_init_early(void) iommu_init_early_pasemi(); } -static struct of_device_id pasemi_bus_ids[] = { - { .type = "sdc", }, - {}, -}; - -static int __init pasemi_publish_devices(void) -{ - /* Publish OF platform devices for southbridge IOs */ - of_platform_bus_probe(NULL, pasemi_bus_ids, NULL); - - return 0; -} -device_initcall(pasemi_publish_devices); - /* * Called very early, MMU is off, device-tree isn't unflattened @@ -246,6 +237,7 @@ define_machine(pas) { .restart = pas_restart, .get_boot_time = pas_get_boot_time, .calibrate_decr = generic_calibrate_decr, + .check_legacy_ioport = pas_check_legacy_ioport, .progress = pas_progress, .machine_check_exception = pas_machine_check_handler, .pci_irq_fixup = pas_pci_irq_fixup, diff --git a/trunk/arch/powerpc/platforms/powermac/Kconfig b/trunk/arch/powerpc/platforms/powermac/Kconfig deleted file mode 100644 index 5b7afe50039a..000000000000 --- a/trunk/arch/powerpc/platforms/powermac/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config PPC_PMAC - bool "Apple PowerMac based machines" - depends on PPC_MULTIPLATFORM - select MPIC - select PPC_INDIRECT_PCI if PPC32 - select PPC_MPC106 if PPC32 - select PPC_NATIVE - default y - -config PPC_PMAC64 - bool - depends on PPC_PMAC && POWER4 - select MPIC - select U3_DART - select MPIC_U3_HT_IRQS - select GENERIC_TBSYNC - select PPC_970_NAP - default y - - diff --git a/trunk/arch/powerpc/platforms/powermac/backlight.c b/trunk/arch/powerpc/platforms/powermac/backlight.c index d679964ae2ab..de7440e62cc4 100644 --- a/trunk/arch/powerpc/platforms/powermac/backlight.c +++ b/trunk/arch/powerpc/platforms/powermac/backlight.c @@ -56,16 +56,13 @@ struct backlight_device *pmac_backlight; int pmac_has_backlight_type(const char *type) { - struct device_node* bk_node = of_find_node_by_name(NULL, "backlight"); + struct device_node* bk_node = find_devices("backlight"); if (bk_node) { - const char *prop = of_get_property(bk_node, + const char *prop = get_property(bk_node, "backlight-control", NULL); - if (prop && strncmp(prop, type, strlen(type)) == 0) { - of_node_put(bk_node); + if (prop && strncmp(prop, type, strlen(type)) == 0) return 1; - } - of_node_put(bk_node); } return 0; diff --git a/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c b/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c index 1fe35dab0e9e..c2b6b4134f68 100644 --- a/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/trunk/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -420,7 +421,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) static u32 read_gpio(struct device_node *np) { - const u32 *reg = of_get_property(np, "reg", NULL); + const u32 *reg = get_property(np, "reg", NULL); u32 offset; if (reg == NULL) @@ -520,14 +521,13 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) int lenp, rc; const u32 *freqs, *ratio; - freqs = of_get_property(cpunode, "bus-frequencies", &lenp); + freqs = get_property(cpunode, "bus-frequencies", &lenp); lenp /= sizeof(u32); if (freqs == NULL || lenp != 2) { printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); return 1; } - ratio = of_get_property(cpunode, "processor-to-bus-ratio*2", - NULL); + ratio = get_property(cpunode, "processor-to-bus-ratio*2", NULL); if (ratio == NULL) { printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); return 1; @@ -562,7 +562,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) /* If we use the PMU, look for the min & max frequencies in the * device-tree */ - value = of_get_property(cpunode, "min-clock-frequency", NULL); + value = get_property(cpunode, "min-clock-frequency", NULL); if (!value) return 1; low_freq = (*value) / 1000; @@ -571,7 +571,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) if (low_freq < 100000) low_freq *= 10; - value = of_get_property(cpunode, "max-clock-frequency", NULL); + value = get_property(cpunode, "max-clock-frequency", NULL); if (!value) return 1; hi_freq = (*value) / 1000; @@ -585,7 +585,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode) { struct device_node *volt_gpio_np; - if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL) + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) return 1; volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); @@ -614,11 +614,11 @@ static int pmac_cpufreq_init_750FX(struct device_node *cpunode) u32 pvr; const u32 *value; - if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL) + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) return 1; hi_freq = cur_freq; - value = of_get_property(cpunode, "reduced-clock-frequency", NULL); + value = get_property(cpunode, "reduced-clock-frequency", NULL); if (!value) return 1; low_freq = (*value) / 1000; @@ -657,19 +657,19 @@ static int __init pmac_cpufreq_setup(void) return 0; /* Assume only one CPU */ - cpunode = of_find_node_by_type(NULL, "cpu"); + cpunode = find_type_devices("cpu"); if (!cpunode) goto out; /* Get current cpu clock freq */ - value = of_get_property(cpunode, "clock-frequency", NULL); + value = get_property(cpunode, "clock-frequency", NULL); if (!value) goto out; cur_freq = (*value) / 1000; /* Check for 7447A based MacRISC3 */ if (machine_is_compatible("MacRISC3") && - of_get_property(cpunode, "dynamic-power-step", NULL) && + get_property(cpunode, "dynamic-power-step", NULL) && PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { pmac_cpufreq_init_7447A(cpunode); /* Check for other MacRISC3 machines */ @@ -707,7 +707,6 @@ static int __init pmac_cpufreq_setup(void) else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000) pmac_cpufreq_init_750FX(cpunode); out: - of_node_put(cpunode); if (set_speed_proc == NULL) return -ENODEV; diff --git a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c index 567d5523b690..9d22361a26d6 100644 --- a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -410,7 +410,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) /* Get first CPU node */ for (cpunode = NULL; (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { - const u32 *reg = of_get_property(cpunode, "reg", NULL); + const u32 *reg = get_property(cpunode, "reg", NULL); if (reg == NULL || (*reg) != 0) continue; if (!strcmp(cpunode->type, "cpu")) @@ -422,7 +422,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) } /* Check 970FX for now */ - valp = of_get_property(cpunode, "cpu-version", NULL); + valp = get_property(cpunode, "cpu-version", NULL); if (!valp) { DBG("No cpu-version property !\n"); goto bail_noprops; @@ -434,7 +434,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) } /* Look for the powertune data in the device-tree */ - g5_pmode_data = of_get_property(cpunode, "power-mode-data",&psize); + g5_pmode_data = get_property(cpunode, "power-mode-data",&psize); if (!g5_pmode_data) { DBG("No power-mode-data !\n"); goto bail_noprops; @@ -493,7 +493,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus) * half freq in this version. So far, I haven't yet seen a machine * supporting anything else. */ - valp = of_get_property(cpunode, "clock-frequency", NULL); + valp = get_property(cpunode, "clock-frequency", NULL); if (!valp) return -ENODEV; max_freq = (*valp)/1000; @@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus) /* Lookup the cpuid eeprom node */ cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0"); if (cpuid != NULL) - eeprom = of_get_property(cpuid, "cpuid", NULL); + eeprom = get_property(cpuid, "cpuid", NULL); if (eeprom == NULL) { printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n"); rc = -ENODEV; @@ -573,13 +573,13 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus) /* Lookup the i2c hwclock */ for (hwclock = NULL; (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){ - const char *loc = of_get_property(hwclock, + const char *loc = get_property(hwclock, "hwctrl-location", NULL); if (loc == NULL) continue; if (strcmp(loc, "CPU CLOCK")) continue; - if (!of_get_property(hwclock, "platform-get-frequency", NULL)) + if (!get_property(hwclock, "platform-get-frequency", NULL)) continue; break; } @@ -638,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus) */ /* Get max frequency from device-tree */ - valp = of_get_property(cpunode, "clock-frequency", NULL); + valp = get_property(cpunode, "clock-frequency", NULL); if (!valp) { printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n"); rc = -ENODEV; diff --git a/trunk/arch/powerpc/platforms/powermac/feature.c b/trunk/arch/powerpc/platforms/powermac/feature.c index 52cfdd86c928..24cc50c1774a 100644 --- a/trunk/arch/powerpc/platforms/powermac/feature.c +++ b/trunk/arch/powerpc/platforms/powermac/feature.c @@ -1044,7 +1044,6 @@ core99_reset_cpu(struct device_node *node, long param, long value) unsigned long flags; struct macio_chip *macio; struct device_node *np; - struct device_node *cpus; const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, KL_GPIO_RESET_CPU1, KL_GPIO_RESET_CPU2, @@ -1054,12 +1053,12 @@ core99_reset_cpu(struct device_node *node, long param, long value) if (macio->type != macio_keylargo) return -ENODEV; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) + np = find_path_device("/cpus"); + if (np == NULL) return -ENODEV; - for (np = cpus->child; np != NULL; np = np->sibling) { - const u32 *num = of_get_property(np, "reg", NULL); - const u32 *rst = of_get_property(np, "soft-reset", NULL); + for (np = np->child; np != NULL; np = np->sibling) { + const u32 *num = get_property(np, "reg", NULL); + const u32 *rst = get_property(np, "soft-reset", NULL); if (num == NULL || rst == NULL) continue; if (param == *num) { @@ -1067,7 +1066,6 @@ core99_reset_cpu(struct device_node *node, long param, long value) break; } } - of_node_put(cpus); if (np == NULL || reset_io == 0) reset_io = dflt_reset_lines[param]; @@ -1097,7 +1095,7 @@ core99_usb_enable(struct device_node *node, long param, long value) macio->type != macio_intrepid) return -ENODEV; - prop = of_get_property(node, "AAPL,clock-id", NULL); + prop = get_property(node, "AAPL,clock-id", NULL); if (!prop) return -ENODEV; if (strncmp(prop, "usb0u048", 8) == 0) @@ -1499,18 +1497,17 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) unsigned long flags; struct macio_chip *macio; struct device_node *np; - struct device_node *cpus; macio = &macio_chips[0]; if (macio->type != macio_keylargo2 && macio->type != macio_shasta) return -ENODEV; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) + np = find_path_device("/cpus"); + if (np == NULL) return -ENODEV; - for (np = cpus->child; np != NULL; np = np->sibling) { - const u32 *num = of_get_property(np, "reg", NULL); - const u32 *rst = of_get_property(np, "soft-reset", NULL); + for (np = np->child; np != NULL; np = np->sibling) { + const u32 *num = get_property(np, "reg", NULL); + const u32 *rst = get_property(np, "soft-reset", NULL); if (num == NULL || rst == NULL) continue; if (param == *num) { @@ -1518,7 +1515,6 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) break; } } - of_node_put(cpus); if (np == NULL || reset_io == 0) return -ENODEV; @@ -2408,15 +2404,14 @@ static int __init probe_motherboard(void) struct macio_chip *macio = &macio_chips[0]; const char *model = NULL; struct device_node *dt; - int ret = 0; /* Lookup known motherboard type in device-tree. First try an * exact match on the "model" property, then try a "compatible" * match is none is found. */ - dt = of_find_node_by_name(NULL, "device-tree"); + dt = find_devices("device-tree"); if (dt != NULL) - model = of_get_property(dt, "model", NULL); + model = get_property(dt, "model", NULL); for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { pmac_mb = pmac_mb_defs[i]; @@ -2479,18 +2474,15 @@ static int __init probe_motherboard(void) break; #endif /* CONFIG_POWER4 */ default: - ret = -ENODEV; - goto done; + return -ENODEV; } found: #ifndef CONFIG_POWER4 /* Fixup Hooper vs. Comet */ if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4); - if (!mach_id_ptr) { - ret = -ENODEV; - goto done; - } + if (!mach_id_ptr) + return -ENODEV; /* Here, I used to disable the media-bay on comet. It * appears this is wrong, the floppy connector is actually * a kind of media-bay and works with the current driver. @@ -2507,26 +2499,18 @@ static int __init probe_motherboard(void) * that all Apple OF revs did it properly, I do it the paranoid way. */ while (uninorth_base && uninorth_rev > 3) { - struct device_node *cpus = of_find_node_by_path("/cpus"); - struct device_node *np; - - if (!cpus || !cpus->child) { + struct device_node *np = find_path_device("/cpus"); + if (!np || !np->child) { printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); - of_node_put(cpus); break; } - np = cpus->child; + np = np->child; /* Nap mode not supported on SMP */ - if (np->sibling) { - of_node_put(cpus); + if (np->sibling) break; - } /* Nap mode not supported if flush-on-lock property is present */ - if (of_get_property(np, "flush-on-lock", NULL)) { - of_node_put(cpus); + if (get_property(np, "flush-on-lock", NULL)) break; - } - of_node_put(cpus); powersave_nap = 1; printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n"); break; @@ -2548,9 +2532,7 @@ static int __init probe_motherboard(void) printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); -done: - of_node_put(dt); - return ret; + return 0; } /* Initialize the Core99 UniNorth host bridge and memory controller @@ -2576,7 +2558,7 @@ static void __init probe_uninorth(void) if (uninorth_node == NULL) return; - addrp = of_get_property(uninorth_node, "reg", NULL); + addrp = get_property(uninorth_node, "reg", NULL); if (addrp == NULL) return; address = of_translate_address(uninorth_node, addrp); @@ -2660,7 +2642,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ return; } if (type == macio_keylargo || type == macio_keylargo2) { - const u32 *did = of_get_property(node, "device-id", NULL); + const u32 *did = get_property(node, "device-id", NULL); if (*did == 0x00000025) type = macio_pangea; if (*did == 0x0000003e) @@ -2673,7 +2655,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ macio_chips[i].base = base; macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; macio_chips[i].name = macio_names[type]; - revp = of_get_property(node, "revision-id", NULL); + revp = get_property(node, "revision-id", NULL); if (revp) macio_chips[i].rev = *revp; printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", @@ -2724,8 +2706,8 @@ initial_serial_shutdown(struct device_node *np) int port_type = PMAC_SCC_ASYNC; int modem = 0; - slots = of_get_property(np, "slot-names", &len); - conn = of_get_property(np, "AAPL,connector", &len); + slots = get_property(np, "slot-names", &len); + conn = get_property(np, "AAPL,connector", &len); if (conn && (strcmp(conn, "infrared") == 0)) port_type = PMAC_SCC_IRDA; else if (device_is_compatible(np, "cobalt")) @@ -2753,14 +2735,12 @@ set_initial_features(void) * differenciate them all and since that hack was there for a long * time, I'll keep it around */ - if (macio_chips[0].type == macio_ohare) { + if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) { struct macio_chip *macio = &macio_chips[0]; - np = of_find_node_by_name(NULL, "via-pmu"); - if (np) - MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); - else - MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); - of_node_put(np); + MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); + } else if (macio_chips[0].type == macio_ohare) { + struct macio_chip *macio = &macio_chips[0]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); } else if (macio_chips[1].type == macio_ohare) { struct macio_chip *macio = &macio_chips[1]; MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); @@ -2853,13 +2833,14 @@ set_initial_features(void) } /* Switch airport off */ - for_each_node_by_name(np, "radio") { + np = find_devices("radio"); + while(np) { if (np && np->parent == macio_chips[0].of_node) { macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; core99_airport_enable(np, 0, 0); } + np = np->next; } - of_node_put(np); } /* On all machines that support sound PM, switch sound off */ @@ -2879,12 +2860,16 @@ set_initial_features(void) #endif /* CONFIG_POWER4 */ /* On all machines, switch modem & serial ports off */ - for_each_node_by_name(np, "ch-a") + np = find_devices("ch-a"); + while(np) { initial_serial_shutdown(np); - of_node_put(np); - for_each_node_by_name(np, "ch-b") + np = np->next; + } + np = find_devices("ch-b"); + while(np) { initial_serial_shutdown(np); - of_node_put(np); + np = np->next; + } } void __init diff --git a/trunk/arch/powerpc/platforms/powermac/low_i2c.c b/trunk/arch/powerpc/platforms/powermac/low_i2c.c index 5430e146b3e9..bfc4829162f1 100644 --- a/trunk/arch/powerpc/platforms/powermac/low_i2c.c +++ b/trunk/arch/powerpc/platforms/powermac/low_i2c.c @@ -491,7 +491,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) * on all i2c keywest nodes so far ... we would have to fallback * to macio parsing if that wasn't the case */ - addrp = of_get_property(np, "AAPL,address", NULL); + addrp = get_property(np, "AAPL,address", NULL); if (addrp == NULL) { printk(KERN_ERR "low_i2c: Can't find address for %s\n", np->full_name); @@ -505,13 +505,13 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) host->timeout_timer.function = kw_i2c_timeout; host->timeout_timer.data = (unsigned long)host; - psteps = of_get_property(np, "AAPL,address-step", NULL); + psteps = get_property(np, "AAPL,address-step", NULL); steps = psteps ? (*psteps) : 0x10; for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) steps >>= 1; /* Select interface rate */ host->speed = KW_I2C_MODE_25KHZ; - prate = of_get_property(np, "AAPL,i2c-rate", NULL); + prate = get_property(np, "AAPL,i2c-rate", NULL); if (prate) switch(*prate) { case 100: host->speed = KW_I2C_MODE_100KHZ; @@ -619,7 +619,7 @@ static void __init kw_i2c_probe(void) } else { for (child = NULL; (child = of_get_next_child(np, child)) != NULL;) { - const u32 *reg = of_get_property(child, + const u32 *reg = get_property(child, "reg", NULL); if (reg == NULL) continue; @@ -905,7 +905,7 @@ static void __init smu_i2c_probe(void) if (strcmp(busnode->type, "i2c") && strcmp(busnode->type, "i2c-bus")) continue; - reg = of_get_property(busnode, "reg", NULL); + reg = get_property(busnode, "reg", NULL); if (reg == NULL) continue; @@ -950,8 +950,7 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node) if (p == bus->busnode) { if (prev && bus->flags & pmac_i2c_multibus) { const u32 *reg; - reg = of_get_property(prev, "reg", - NULL); + reg = get_property(prev, "reg", NULL); if (!reg) continue; if (((*reg) >> 8) != bus->channel) @@ -972,7 +971,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus); u8 pmac_i2c_get_dev_addr(struct device_node *device) { - const u32 *reg = of_get_property(device, "reg", NULL); + const u32 *reg = get_property(device, "reg", NULL); if (reg == NULL) return 0; diff --git a/trunk/arch/powerpc/platforms/powermac/pci.c b/trunk/arch/powerpc/platforms/powermac/pci.c index 22c4ae4c6934..6fbac308ded6 100644 --- a/trunk/arch/powerpc/platforms/powermac/pci.c +++ b/trunk/arch/powerpc/platforms/powermac/pci.c @@ -70,11 +70,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher int len; /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = of_get_property(node, "class-code", NULL); + class_code = get_property(node, "class-code", NULL); if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) continue; - bus_range = of_get_property(node, "bus-range", &len); + bus_range = get_property(node, "bus-range", &len); if (bus_range != NULL && len > 2 * sizeof(int)) { if (bus_range[1] > higher) higher = bus_range[1]; @@ -100,7 +100,7 @@ static void __init fixup_bus_range(struct device_node *bridge) if (prop == NULL || prop->length < 2 * sizeof(int)) return; - bus_range = prop->value; + bus_range = (int *)prop->value; bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); } @@ -246,8 +246,8 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) if (np == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - vendor = of_get_property(np, "vendor-id", NULL); - device = of_get_property(np, "device-id", NULL); + vendor = get_property(np, "vendor-id", NULL); + device = get_property(np, "device-id", NULL); if (vendor == NULL || device == NULL) return PCIBIOS_DEVICE_NOT_FOUND; @@ -622,14 +622,13 @@ static void __init init_p2pbridge(void) /* XXX it would be better here to identify the specific PCI-PCI bridge chip we have. */ - p2pbridge = of_find_node_by_name(NULL, "pci-bridge"); - if (p2pbridge == NULL + if ((p2pbridge = find_devices("pci-bridge")) == 0 || p2pbridge->parent == NULL || strcmp(p2pbridge->parent->name, "pci") != 0) - goto done; + return; if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { DBG("Can't find PCI infos for PCI<->PCI bridge\n"); - goto done; + return; } /* Warning: At this point, we have not yet renumbered all busses. * So we must use OF walking to find out hose @@ -637,18 +636,16 @@ static void __init init_p2pbridge(void) hose = pci_find_hose_for_OF_device(p2pbridge); if (!hose) { DBG("Can't find hose for PCI<->PCI bridge\n"); - goto done; + return; } if (early_read_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) { printk(KERN_ERR "init_p2pbridge: couldn't read bridge" " control\n"); - goto done; + return; } val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); -done: - of_node_put(p2pbridge); } static void __init init_second_ohare(void) @@ -694,17 +691,17 @@ static void __init fixup_nec_usb2(void) const u32 *prop; u8 bus, devfn; - prop = of_get_property(nec, "vendor-id", NULL); + prop = get_property(nec, "vendor-id", NULL); if (prop == NULL) continue; if (0x1033 != *prop) continue; - prop = of_get_property(nec, "device-id", NULL); + prop = get_property(nec, "device-id", NULL); if (prop == NULL) continue; if (0x0035 != *prop) continue; - prop = of_get_property(nec, "reg", NULL); + prop = get_property(nec, "reg", NULL); if (prop == NULL) continue; devfn = (prop[0] >> 8) & 0xff; @@ -912,7 +909,7 @@ static int __init add_bridge(struct device_node *dev) has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); /* Get bus range if any */ - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); @@ -1202,7 +1199,8 @@ void __init pmac_pcibios_after_init(void) } #endif /* CONFIG_BLK_DEV_IDE */ - for_each_node_by_name(nd, "firewire") { + nd = find_devices("firewire"); + while (nd) { if (nd->parent && (device_is_compatible(nd, "pci106b,18") || device_is_compatible(nd, "pci106b,30") || device_is_compatible(nd, "pci11c1,5811")) @@ -1210,14 +1208,15 @@ void __init pmac_pcibios_after_init(void) pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0); pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } + nd = nd->next; } - of_node_put(nd); - for_each_node_by_name(nd, "ethernet") { + nd = find_devices("ethernet"); + while (nd) { if (nd->parent && device_is_compatible(nd, "gmac") && device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); + nd = nd->next; } - of_node_put(nd); } #ifdef CONFIG_PPC32 diff --git a/trunk/arch/powerpc/platforms/powermac/pfunc_base.c b/trunk/arch/powerpc/platforms/powermac/pfunc_base.c index 45d54b9ad9e0..5c6c15c5f9a3 100644 --- a/trunk/arch/powerpc/platforms/powermac/pfunc_base.c +++ b/trunk/arch/powerpc/platforms/powermac/pfunc_base.c @@ -114,7 +114,7 @@ static void macio_gpio_init_one(struct macio_chip *macio) * we just create them all */ for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) { - const u32 *reg = of_get_property(gp, "reg", NULL); + const u32 *reg = get_property(gp, "reg", NULL); unsigned long offset; if (reg == NULL) continue; diff --git a/trunk/arch/powerpc/platforms/powermac/pfunc_core.c b/trunk/arch/powerpc/platforms/powermac/pfunc_core.c index 85434231ae14..7651f278615a 100644 --- a/trunk/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/trunk/arch/powerpc/platforms/powermac/pfunc_core.c @@ -692,7 +692,8 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata) name = pp->name + plen; if (strlen(name) && pp->length >= 12) count += pmf_add_function_prop(dev, driverdata, name, - pp->value, pp->length); + (u32 *)pp->value, + pp->length); } return count; } @@ -820,7 +821,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target, * one, then we fallback to a direct call attempt */ snprintf(fname, 63, "platform-%s", name); - prop = of_get_property(target, fname, NULL); + prop = get_property(target, fname, NULL); if (prop == NULL) goto find_it; ph = *prop; diff --git a/trunk/arch/powerpc/platforms/powermac/pic.c b/trunk/arch/powerpc/platforms/powermac/pic.c index ae5097ac0378..5e5c0e4add91 100644 --- a/trunk/arch/powerpc/platforms/powermac/pic.c +++ b/trunk/arch/powerpc/platforms/powermac/pic.c @@ -482,14 +482,14 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); flags |= MPIC_WANTS_RESET; - if (of_get_property(np, "big-endian", NULL)) + if (get_property(np, "big-endian", NULL)) flags |= MPIC_BIG_ENDIAN; /* Primary Big Endian means HT interrupts. This is quite dodgy * but works until I find a better way */ if (master && (flags & MPIC_BIG_ENDIAN)) - flags |= MPIC_U3_HT_IRQS; + flags |= MPIC_BROKEN_U3; mpic = mpic_alloc(np, r.start, flags, 0, 0, name); if (mpic == NULL) @@ -510,7 +510,7 @@ static int __init pmac_pic_probe_mpic(void) for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) != NULL;) { if (master == NULL && - of_get_property(np, "interrupts", NULL) == NULL) + get_property(np, "interrupts", NULL) == NULL) master = of_node_get(np); else if (slave == NULL) slave = of_node_get(np); @@ -575,7 +575,7 @@ void __init pmac_pic_init(void) #ifdef CONFIG_PPC32 if (!pmac_newworld) flags |= OF_IMAP_OLDWORLD_MAC; - if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL) + if (get_property(of_chosen, "linux,bootx", NULL) != NULL) flags |= OF_IMAP_NO_PHANDLE; #endif /* CONFIG_PPC_32 */ diff --git a/trunk/arch/powerpc/platforms/powermac/setup.c b/trunk/arch/powerpc/platforms/powermac/setup.c index b820cabac697..651fa424ea06 100644 --- a/trunk/arch/powerpc/platforms/powermac/setup.c +++ b/trunk/arch/powerpc/platforms/powermac/setup.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -134,12 +135,12 @@ static void pmac_show_cpuinfo(struct seq_file *m) seq_printf(m, "machine\t\t: "); np = of_find_node_by_path("/"); if (np != NULL) { - pp = of_get_property(np, "model", NULL); + pp = get_property(np, "model", NULL); if (pp != NULL) seq_printf(m, "%s\n", pp); else seq_printf(m, "PowerMac\n"); - pp = of_get_property(np, "compatible", &plen); + pp = get_property(np, "compatible", &plen); if (pp != NULL) { seq_printf(m, "motherboard\t:"); while (plen > 0) { @@ -163,13 +164,11 @@ static void pmac_show_cpuinfo(struct seq_file *m) if (np == NULL) np = of_find_node_by_type(NULL, "cache"); if (np != NULL) { - const unsigned int *ic = - of_get_property(np, "i-cache-size", NULL); - const unsigned int *dc = - of_get_property(np, "d-cache-size", NULL); + const unsigned int *ic = get_property(np, "i-cache-size", NULL); + const unsigned int *dc = get_property(np, "d-cache-size", NULL); seq_printf(m, "L2 cache\t:"); has_l2cache = 1; - if (of_get_property(np, "cache-unified", NULL) != 0 && dc) { + if (get_property(np, "cache-unified", NULL) != 0 && dc) { seq_printf(m, " %dK unified", *dc / 1024); } else { if (ic) @@ -178,7 +177,7 @@ static void pmac_show_cpuinfo(struct seq_file *m) seq_printf(m, "%s %dK data", (ic? " +": ""), *dc / 1024); } - pp = of_get_property(np, "ram-type", NULL); + pp = get_property(np, "ram-type", NULL); if (pp) seq_printf(m, " %s", pp); seq_printf(m, "\n"); @@ -193,11 +192,8 @@ static void pmac_show_cpuinfo(struct seq_file *m) #ifndef CONFIG_ADB_CUDA int find_via_cuda(void) { - struct device_node *dn = of_find_node_by_name(NULL, "via-cuda"); - - if (!dn) + if (!find_devices("via-cuda")) return 0; - of_node_put(dn); printk("WARNING ! Your machine is CUDA-based but your kernel\n"); printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); return 0; @@ -207,11 +203,8 @@ int find_via_cuda(void) #ifndef CONFIG_ADB_PMU int find_via_pmu(void) { - struct device_node *dn = of_find_node_by_name(NULL, "via-pmu"); - - if (!dn) + if (!find_devices("via-pmu")) return 0; - of_node_put(dn); printk("WARNING ! Your machine is PMU-based but your kernel\n"); printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); return 0; @@ -231,8 +224,6 @@ static volatile u32 *sysctrl_regs; static void __init ohare_init(void) { - struct device_node *dn; - /* this area has the CPU identification register and some registers used by smp boards */ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); @@ -242,9 +233,7 @@ static void __init ohare_init(void) * We assume that we have a PSX memory controller iff * we have an ohare I/O controller. */ - dn = of_find_node_by_name(NULL, "ohare"); - if (dn) { - of_node_put(dn); + if (find_devices("ohare") != NULL) { if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { if (sysctrl_regs[4] & 0x10) sysctrl_regs[4] |= 0x04000020; @@ -260,19 +249,18 @@ static void __init l2cr_init(void) { /* Checks "l2cr-value" property in the registry */ if (cpu_has_feature(CPU_FTR_L2CR)) { - struct device_node *np = of_find_node_by_name(NULL, "cpus"); + struct device_node *np = find_devices("cpus"); if (np == 0) - np = of_find_node_by_type(NULL, "cpu"); + np = find_type_devices("cpu"); if (np != 0) { const unsigned int *l2cr = - of_get_property(np, "l2cr-value", NULL); + get_property(np, "l2cr-value", NULL); if (l2cr != 0) { ppc_override_l2cr = 1; ppc_override_l2cr_value = *l2cr; _set_L2CR(0); _set_L2CR(ppc_override_l2cr_value); } - of_node_put(np); } } @@ -298,7 +286,7 @@ static void __init pmac_setup_arch(void) loops_per_jiffy = 50000000 / HZ; cpu = of_find_node_by_type(NULL, "cpu"); if (cpu != NULL) { - fp = of_get_property(cpu, "clock-frequency", NULL); + fp = get_property(cpu, "clock-frequency", NULL); if (fp != NULL) { if (pvr >= 0x30 && pvr < 0x80) /* PPC970 etc. */ @@ -315,7 +303,7 @@ static void __init pmac_setup_arch(void) /* See if newworld or oldworld */ for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; ) - if (of_get_property(ic, "interrupt-controller", NULL)) + if (get_property(ic, "interrupt-controller", NULL)) break; if (ic) { pmac_newworld = 1; @@ -353,15 +341,8 @@ static void __init pmac_setup_arch(void) #ifdef CONFIG_SMP /* Check for Core99 */ - ic = of_find_node_by_name(NULL, "uni-n"); - if (!ic) - ic = of_find_node_by_name(NULL, "u3"); - if (!ic) - ic = of_find_node_by_name(NULL, "u4"); - if (ic) { - of_node_put(ic); + if (find_devices("uni-n") || find_devices("u3") || find_devices("u4")) smp_ops = &core99_smp_ops; - } #ifdef CONFIG_PPC32 else smp_ops = &psurge_smp_ops; @@ -635,6 +616,15 @@ static void __init pmac_init_early(void) #endif } +/* + * pmac has no legacy IO, anything calling this function has to + * fail or bad things will happen + */ +static int pmac_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + static int __init pmac_declare_of_platform_devices(void) { struct device_node *np; @@ -746,6 +736,7 @@ define_machine(powermac) { .get_rtc_time = pmac_get_rtc_time, .calibrate_decr = pmac_calibrate_decr, .feature_call = pmac_do_feature_call, + .check_legacy_ioport = pmac_check_legacy_ioport, .progress = udbg_progress, #ifdef CONFIG_PPC64 .pci_probe_mode = pmac_pci_probe_mode, diff --git a/trunk/arch/powerpc/platforms/powermac/smp.c b/trunk/arch/powerpc/platforms/powermac/smp.c index 6f32c4eca6e5..d73fb73802bb 100644 --- a/trunk/arch/powerpc/platforms/powermac/smp.c +++ b/trunk/arch/powerpc/platforms/powermac/smp.c @@ -264,7 +264,6 @@ static void __init psurge_quad_init(void) static int __init smp_psurge_probe(void) { int i, ncpus; - struct device_node *dn; /* We don't do SMP on the PPC601 -- paulus */ if (PVR_VER(mfspr(SPRN_PVR)) == 1) @@ -280,10 +279,8 @@ static int __init smp_psurge_probe(void) * in the hammerhead memory controller in the case of the * dual-cpu powersurge board. -- paulus. */ - dn = of_find_node_by_name(NULL, "hammerhead"); - if (dn == NULL) + if (find_devices("hammerhead") == NULL) return 1; - of_node_put(dn); hhead_base = ioremap(HAMMERHEAD_BASE, 0x800); quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024); @@ -570,7 +567,7 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc); if (pmac_tb_clock_chip_host == NULL) continue; - reg = of_get_property(cc, "reg", NULL); + reg = get_property(cc, "reg", NULL); if (reg == NULL) continue; switch (*reg) { @@ -698,7 +695,7 @@ static void __init smp_core99_setup(int ncpus) struct device_node *cpus = of_find_node_by_path("/cpus"); if (cpus && - of_get_property(cpus, "platform-cpu-timebase", NULL)) { + get_property(cpus, "platform-cpu-timebase", NULL)) { pmac_tb_freeze = smp_core99_pfunc_tb_freeze; printk(KERN_INFO "Processor timebase sync using" " platform function\n"); @@ -715,7 +712,7 @@ static void __init smp_core99_setup(int ncpus) core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ cpu = of_find_node_by_type(NULL, "cpu"); if (cpu != NULL) { - tbprop = of_get_property(cpu, "timebase-enable", NULL); + tbprop = get_property(cpu, "timebase-enable", NULL); if (tbprop) core99_tb_gpio = *tbprop; of_node_put(cpu); diff --git a/trunk/arch/powerpc/platforms/powermac/time.c b/trunk/arch/powerpc/platforms/powermac/time.c index bf9da56942e8..a4173906e945 100644 --- a/trunk/arch/powerpc/platforms/powermac/time.c +++ b/trunk/arch/powerpc/platforms/powermac/time.c @@ -297,11 +297,49 @@ int __init via_calibrate_decr(void) } #endif +#ifdef CONFIG_PM +/* + * Reset the time after a sleep. + */ +static int +time_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + static unsigned long time_diff; + unsigned long flags; + unsigned long seq; + struct timespec tv; + + switch (when) { + case PBOOK_SLEEP_NOW: + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + time_diff = xtime.tv_sec - pmac_get_boot_time(); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + break; + case PBOOK_WAKE: + tv.tv_sec = pmac_get_boot_time() + time_diff; + tv.tv_nsec = 0; + do_settimeofday(&tv); + break; + } + return PBOOK_SLEEP_OK; +} + +static struct pmu_sleep_notifier time_sleep_notifier = { + time_sleep_notify, SLEEP_LEVEL_MISC, +}; +#endif /* CONFIG_PM */ + /* * Query the OF and get the decr frequency. */ void __init pmac_calibrate_decr(void) { +#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU) + /* XXX why here? */ + pmu_register_sleep_notifier(&time_sleep_notifier); +#endif + generic_calibrate_decr(); #ifdef CONFIG_PPC32 diff --git a/trunk/arch/powerpc/platforms/powermac/udbg_scc.c b/trunk/arch/powerpc/platforms/powermac/udbg_scc.c index 47de4d3fc167..379db05b0082 100644 --- a/trunk/arch/powerpc/platforms/powermac/udbg_scc.c +++ b/trunk/arch/powerpc/platforms/powermac/udbg_scc.c @@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc) macio = of_get_parent(escc); if (macio == NULL) goto bail; - path = of_get_property(of_chosen, "linux,stdout-path", NULL); + path = get_property(of_chosen, "linux,stdout-path", NULL); if (path != NULL) stdout = of_find_node_by_path(path); for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) { @@ -96,13 +96,13 @@ void udbg_scc_init(int force_scc) ch = ch_def ? ch_def : ch_a; /* Get address within mac-io ASIC */ - reg = of_get_property(escc, "reg", NULL); + reg = get_property(escc, "reg", NULL); if (reg == NULL) goto bail; addr = reg[0]; /* Get address of mac-io PCI itself */ - reg = of_get_property(macio, "assigned-addresses", NULL); + reg = get_property(macio, "assigned-addresses", NULL); if (reg == NULL) goto bail; addr += reg[2]; diff --git a/trunk/arch/powerpc/platforms/prep/Kconfig b/trunk/arch/powerpc/platforms/prep/Kconfig index 29d411279b0c..673ac47a1626 100644 --- a/trunk/arch/powerpc/platforms/prep/Kconfig +++ b/trunk/arch/powerpc/platforms/prep/Kconfig @@ -1,12 +1,3 @@ -config PPC_PREP - bool "PowerPC Reference Platform (PReP) based machines" - depends on PPC_MULTIPLATFORM && PPC32 && BROKEN - select MPIC - select PPC_I8259 - select PPC_INDIRECT_PCI - select PPC_UDBG_16550 - select PPC_NATIVE - default n config PREP_RESIDUAL bool "Support for PReP Residual Data" diff --git a/trunk/arch/powerpc/platforms/ps3/Kconfig b/trunk/arch/powerpc/platforms/ps3/Kconfig index 40f0008af4d1..1a481a60a883 100644 --- a/trunk/arch/powerpc/platforms/ps3/Kconfig +++ b/trunk/arch/powerpc/platforms/ps3/Kconfig @@ -1,19 +1,3 @@ -config PPC_PS3 - bool "Sony PS3 (incomplete)" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_CELL - select USB_ARCH_HAS_OHCI - select USB_OHCI_LITTLE_ENDIAN - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_ARCH_HAS_EHCI - select USB_EHCI_BIG_ENDIAN_MMIO - help - This option enables support for the Sony PS3 game console - and other platforms using the PS3 hypervisor. - Support for this platform is not yet complete, so - enabling this will not result in a bootable kernel on a - PS3 system. - menu "PS3 Platform Options" depends on PPC_PS3 diff --git a/trunk/arch/powerpc/platforms/ps3/htab.c b/trunk/arch/powerpc/platforms/ps3/htab.c index ea60c451cf87..e12e59fea13a 100644 --- a/trunk/arch/powerpc/platforms/ps3/htab.c +++ b/trunk/arch/powerpc/platforms/ps3/htab.c @@ -39,7 +39,7 @@ static unsigned long htab_addr; static unsigned char *bolttab; static unsigned char *inusetab; -static DEFINE_SPINLOCK(ps3_bolttab_lock); +static spinlock_t ps3_bolttab_lock = SPIN_LOCK_UNLOCKED; #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \ _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) diff --git a/trunk/arch/powerpc/platforms/pseries/Kconfig b/trunk/arch/powerpc/platforms/pseries/Kconfig index 16e4e401b820..a57032cf6f1b 100644 --- a/trunk/arch/powerpc/platforms/pseries/Kconfig +++ b/trunk/arch/powerpc/platforms/pseries/Kconfig @@ -1,13 +1,3 @@ -config PPC_PSERIES - depends on PPC_MULTIPLATFORM && PPC64 - bool "IBM pSeries & new (POWER5-based) iSeries" - select MPIC - select PPC_I8259 - select PPC_RTAS - select RTAS_ERROR_LOGGING - select PPC_UDBG_16550 - select PPC_NATIVE - default y config PPC_SPLPAR depends on PPC_PSERIES diff --git a/trunk/arch/powerpc/platforms/pseries/Makefile b/trunk/arch/powerpc/platforms/pseries/Makefile index 90235d598751..2dfd05095a25 100644 --- a/trunk/arch/powerpc/platforms/pseries/Makefile +++ b/trunk/arch/powerpc/platforms/pseries/Makefile @@ -2,15 +2,14 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y := lpar.o hvCall.o nvram.o reconfig.o \ - setup.o iommu.o ras.o rtasd.o \ +obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ + setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ firmware.o power.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o obj-$(CONFIG_KEXEC) += kexec.o -obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o diff --git a/trunk/arch/powerpc/platforms/pseries/eeh.c b/trunk/arch/powerpc/platforms/pseries/eeh.c index 48fbd442e9df..6cedbc002e0f 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh.c @@ -74,10 +74,7 @@ * is broken and panic. This sets the threshold for how many read * attempts we allow before panicking. */ -#define EEH_MAX_FAILS 2100000 - -/* Time to wait for a PCI slot to retport status, in milliseconds */ -#define PCI_BUS_RESET_WAIT_MSEC (60*1000) +#define EEH_MAX_FAILS 100000 /* RTAS tokens */ static int ibm_set_eeh_option; @@ -86,7 +83,6 @@ static int ibm_read_slot_reset_state; static int ibm_read_slot_reset_state2; static int ibm_slot_error_detail; static int ibm_get_config_addr_info; -static int ibm_get_config_addr_info2; static int ibm_configure_bridge; int eeh_subsystem_enabled; @@ -171,55 +167,6 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); } -/** - * eeh_wait_for_slot_status - returns error status of slot - * @pdn pci device node - * @max_wait_msecs maximum number to millisecs to wait - * - * Return negative value if a permanent error, else return - * Partition Endpoint (PE) status value. - * - * If @max_wait_msecs is positive, then this routine will - * sleep until a valid status can be obtained, or until - * the max allowed wait time is exceeded, in which case - * a -2 is returned. - */ -int -eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) -{ - int rc; - int rets[3]; - int mwait; - - while (1) { - rc = read_slot_reset_state(pdn, rets); - if (rc) return rc; - if (rets[1] == 0) return -1; /* EEH is not supported */ - - if (rets[0] != 5) return rets[0]; /* return actual status */ - - if (rets[2] == 0) return -1; /* permanently unavailable */ - - if (max_wait_msecs <= 0) return -1; - - mwait = rets[2]; - if (mwait <= 0) { - printk (KERN_WARNING - "EEH: Firmware returned bad wait value=%d\n", mwait); - mwait = 1000; - } else if (mwait > 300*1000) { - printk (KERN_WARNING - "EEH: Firmware is taking too long, time=%d\n", mwait); - mwait = 300*1000; - } - max_wait_msecs -= mwait; - msleep (mwait); - } - - printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); - return -2; -} - /** * eeh_token_to_phys - convert EEH address token to phys address * @token i/o token, should be address in the form 0xA.... @@ -282,7 +229,7 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag) dn = find_device_pe (dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr) dn = dn->parent; PCI_DN(dn)->eeh_mode |= mode_flag; @@ -316,7 +263,7 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) dn = find_device_pe (dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr) dn = dn->parent; PCI_DN(dn)->eeh_mode &= ~mode_flag; @@ -346,6 +293,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) int rets[3]; unsigned long flags; struct pci_dn *pdn; + enum pci_channel_state state; int rc = 0; total_mmio_ffs++; @@ -419,14 +367,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) goto dn_unlock; } - /* Note that config-io to empty slots may fail; - * they are empty when they don't have children. */ - if ((rets[0] == 5) && (dn->child == NULL)) { - false_positives++; - rc = 0; - goto dn_unlock; - } - /* If EEH is not supported on this device, punt. */ if (rets[1] != 1) { printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", @@ -437,7 +377,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) } /* If not the kind of error we know about, punt. */ - if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { + if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { + false_positives++; + rc = 0; + goto dn_unlock; + } + + /* Note that config-io to empty slots may fail; + * we recognize empty because they don't have children. */ + if ((rets[0] == 5) && (dn->child == NULL)) { false_positives++; rc = 0; goto dn_unlock; @@ -451,12 +399,17 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) eeh_mark_slot (dn, EEH_MODE_ISOLATED); spin_unlock_irqrestore(&confirm_error_lock, flags); - eeh_send_failure_event (dn, dev); + state = pci_channel_io_normal; + if ((rets[0] == 2) || (rets[0] == 4)) + state = pci_channel_io_frozen; + if (rets[0] == 5) + state = pci_channel_io_perm_failure; + eeh_send_failure_event (dn, dev, state, rets[2]); /* Most EEH events are due to device driver bugs. Having * a stack trace will help the device-driver authors figure * out what happened. So print that out. */ - dump_stack(); + if (rets[0] != 5) dump_stack(); return 1; dn_unlock: @@ -504,6 +457,38 @@ EXPORT_SYMBOL(eeh_check_failure); /* ------------------------------------------------------------- */ /* The code below deals with error recovery */ +/** + * eeh_slot_availability - returns error status of slot + * @pdn pci device node + * + * Return negative value if a permanent error, else return + * a number of milliseconds to wait until the PCI slot is + * ready to be used. + */ +static int +eeh_slot_availability(struct pci_dn *pdn) +{ + int rc; + int rets[3]; + + rc = read_slot_reset_state(pdn, rets); + + if (rc) return rc; + + if (rets[1] == 0) return -1; /* EEH is not supported */ + if (rets[0] == 0) return 0; /* Oll Korrect */ + if (rets[0] == 5) { + if (rets[2] == 0) return -1; /* permanently unavailable */ + return rets[2]; /* number of millisecs to wait */ + } + if (rets[0] == 1) + return 250; + + printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n", + rc, rets[0], rets[1], rets[2]); + return -2; +} + /** * rtas_pci_enable - enable MMIO or DMA transfers for this slot * @pdn pci device node @@ -527,13 +512,9 @@ rtas_pci_enable(struct pci_dn *pdn, int function) function); if (rc) - printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", + printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n", function, rc, pdn->node->full_name); - rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); - if ((rc == 4) && (function == EEH_THAW_MMIO)) - return 0; - return rc; } @@ -614,24 +595,36 @@ int rtas_set_slot_reset(struct pci_dn *pdn) { int i, rc; - /* Take three shots at resetting the bus */ - for (i=0; i<3; i++) { - __rtas_set_slot_reset(pdn); + __rtas_set_slot_reset(pdn); - rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); + /* Now double check with the firmware to make sure the device is + * ready to be used; if not, wait for recovery. */ + for (i=0; i<10; i++) { + rc = eeh_slot_availability (pdn); if (rc == 0) return 0; + if (rc == -2) { + printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n", + i, pdn->node->full_name); + __rtas_set_slot_reset(pdn); + continue; + } + if (rc < 0) { printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", pdn->node->full_name); return -1; } - printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n", - i+1, pdn->node->full_name); + + msleep (rc+100); } - return -1; + rc = eeh_slot_availability (pdn); + if (rc) + printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name); + + return rc; } /* ------------------------------------------------------- */ @@ -751,48 +744,16 @@ struct eeh_early_enable_info { unsigned int buid_lo; }; -static int get_pe_addr (int config_addr, - struct eeh_early_enable_info *info) -{ - unsigned int rets[3]; - int ret; - - /* Use latest config-addr token on power6 */ - if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { - /* Make sure we have a PE in hand */ - ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 1); - if (ret || (rets[0]==0)) - return 0; - - ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 0); - if (ret) - return 0; - return rets[0]; - } - - /* Use older config-addr token on power5 */ - if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 0); - if (ret) - return 0; - return rets[0]; - } - return 0; -} - /* Enable eeh for the given device node. */ static void *early_enable_eeh(struct device_node *dn, void *data) { unsigned int rets[3]; struct eeh_early_enable_info *info = data; int ret; - const char *status = of_get_property(dn, "status", NULL); - const u32 *class_code = of_get_property(dn, "class-code", NULL); - const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); - const u32 *device_id = of_get_property(dn, "device-id", NULL); + const char *status = get_property(dn, "status", NULL); + const u32 *class_code = get_property(dn, "class-code", NULL); + const u32 *vendor_id = get_property(dn, "vendor-id", NULL); + const u32 *device_id = get_property(dn, "device-id", NULL); const u32 *regs; int enable; struct pci_dn *pdn = PCI_DN(dn); @@ -835,7 +796,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ - regs = of_get_property(dn, "reg", NULL); + regs = get_property(dn, "reg", NULL); if (regs) { /* First register entry is addr (00BBSS00) */ /* Try to enable eeh */ @@ -849,7 +810,15 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* If the newer, better, ibm,get-config-addr-info is supported, * then use that instead. */ - pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); + pdn->eeh_pe_config_addr = 0; + if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, + pdn->eeh_config_addr, + info->buid_hi, info->buid_lo, + 0); + if (ret == 0) + pdn->eeh_pe_config_addr = rets[0]; + } /* Some older systems (Power4) allow the * ibm,set-eeh-option call to succeed even on nodes @@ -920,7 +889,6 @@ void __init eeh_init(void) ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); - ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_driver.c b/trunk/arch/powerpc/platforms/pseries/eeh_driver.c index 3170e003f76a..a4c0bf84ef2e 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_driver.c @@ -158,8 +158,7 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata) return; rc = driver->err_handler->slot_reset(dev); - if ((*res == PCI_ERS_RESULT_NONE) || - (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc; + if (*res == PCI_ERS_RESULT_NONE) *res = rc; if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; } @@ -249,7 +248,6 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata) static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) { - struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ @@ -265,20 +263,23 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) if (rc) return rc; - /* Walk over all functions on this device. */ - dn = pe_dn->node; - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) - dn = dn->parent->child; - - while (dn) { - struct pci_dn *ppe = PCI_DN(dn); - /* On Power4, always true because eeh_pe_config_addr=0 */ - if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { - rtas_configure_bridge(ppe); - eeh_restore_bars(ppe); + /* New-style config addrs might be shared across multiple devices, + * Walk over all functions on this device */ + if (pe_dn->eeh_pe_config_addr) { + struct device_node *pe = pe_dn->node; + pe = pe->parent->child; + while (pe) { + struct pci_dn *ppe = PCI_DN(pe); + if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { + rtas_configure_bridge(ppe); + eeh_restore_bars(ppe); + } + pe = pe->sibling; } - dn = dn->sibling; - } + } else { + rtas_configure_bridge(pe_dn); + eeh_restore_bars(pe_dn); + } /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, @@ -298,7 +299,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) /* The longest amount of time to wait for a pci device * to come back on line, in seconds. */ -#define MAX_WAIT_FOR_RECOVERY 150 +#define MAX_WAIT_FOR_RECOVERY 15 struct pci_dn * handle_eeh_events (struct eeh_event *event) { @@ -314,14 +315,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) if (!frozen_dn) { - location = of_get_property(event->dn, "ibm,loc-code", NULL); + location = get_property(event->dn, "ibm,loc-code", NULL); location = location ? location : "unknown"; printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " "for location=%s pci addr=%s\n", location, pci_name(event->dev)); return NULL; } - location = of_get_property(frozen_dn, "ibm,loc-code", NULL); + location = get_property(frozen_dn, "ibm,loc-code", NULL); location = location ? location : "unknown"; /* There are two different styles for coming up with the PE. @@ -340,6 +341,13 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) return NULL; } +#if 0 + /* We may get "permanent failure" messages on empty slots. + * These are false alarms. Empty slots have no child dn. */ + if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL)) + return; +#endif + frozen_pdn = PCI_DN(frozen_dn); frozen_pdn->eeh_freeze_count++; @@ -354,12 +362,13 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; - /* Get the current PCI slot state. */ - rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); - if (rc < 0) { - printk(KERN_WARNING "EEH: Permanent failure\n"); + /* If the reset state is a '5' and the time to reset is 0 (infinity) + * or is more then 15 seconds, then mark this as a permanent failure. + */ + if ((event->state == pci_channel_io_perm_failure) && + ((event->time_unavail <= 0) || + (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000))) goto hard_fail; - } eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */); printk(KERN_WARNING @@ -381,18 +390,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) */ if (result == PCI_ERS_RESULT_NONE) { rc = eeh_reset_device(frozen_pdn, frozen_bus); - if (rc) { - printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); + if (rc) goto hard_fail; - } } /* If all devices reported they can proceed, then re-enable MMIO */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); - if (rc < 0) - goto hard_fail; if (rc) { result = PCI_ERS_RESULT_NEED_RESET; } else { @@ -405,8 +410,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) if (result == PCI_ERS_RESULT_CAN_RECOVER) { rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); - if (rc < 0) - goto hard_fail; if (rc) result = PCI_ERS_RESULT_NEED_RESET; else @@ -414,28 +417,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) } /* If any device has a hard failure, then shut off everything. */ - if (result == PCI_ERS_RESULT_DISCONNECT) { - printk(KERN_WARNING "EEH: Device driver gave up\n"); + if (result == PCI_ERS_RESULT_DISCONNECT) goto hard_fail; - } /* If any device called out for a reset, then reset the slot */ if (result == PCI_ERS_RESULT_NEED_RESET) { rc = eeh_reset_device(frozen_pdn, NULL); - if (rc) { - printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); + if (rc) goto hard_fail; - } result = PCI_ERS_RESULT_NONE; pci_walk_bus(frozen_bus, eeh_report_reset, &result); } /* All devices should claim they have recovered by now. */ - if ((result != PCI_ERS_RESULT_RECOVERED) && - (result != PCI_ERS_RESULT_NONE)) { - printk(KERN_WARNING "EEH: Not recovered\n"); + if (result != PCI_ERS_RESULT_RECOVERED) goto hard_fail; - } /* Tell all device drivers that they can resume operations */ pci_walk_bus(frozen_bus, eeh_report_resume, NULL); diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_event.c b/trunk/arch/powerpc/platforms/pseries/eeh_event.c index ddb80f5d850b..49037edf7d39 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_event.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_event.c @@ -118,7 +118,9 @@ static void eeh_thread_launcher(struct work_struct *dummy) * (from a workqueue). */ int eeh_send_failure_event (struct device_node *dn, - struct pci_dev *dev) + struct pci_dev *dev, + enum pci_channel_state state, + int time_unavail) { unsigned long flags; struct eeh_event *event; @@ -126,7 +128,7 @@ int eeh_send_failure_event (struct device_node *dn, if (!mem_init_done) { printk(KERN_ERR "EEH: event during early boot not handled\n"); - location = of_get_property(dn, "ibm,loc-code", NULL); + location = get_property(dn, "ibm,loc-code", NULL); printk(KERN_ERR "EEH: device node = %s\n", dn->full_name); printk(KERN_ERR "EEH: PCI location = %s\n", location); return 1; @@ -142,6 +144,8 @@ int eeh_send_failure_event (struct device_node *dn, event->dn = dn; event->dev = dev; + event->state = state; + event->time_unavail = time_unavail; /* We may or may not be called in an interrupt context */ spin_lock_irqsave(&eeh_eventlist_lock, flags); diff --git a/trunk/arch/powerpc/platforms/pseries/firmware.c b/trunk/arch/powerpc/platforms/pseries/firmware.c index 29bf83bfb1f0..90522e3c9d46 100644 --- a/trunk/arch/powerpc/platforms/pseries/firmware.c +++ b/trunk/arch/powerpc/platforms/pseries/firmware.c @@ -80,7 +80,7 @@ void __init fw_feature_init(void) goto out; } - hypertas = of_get_property(dn, "ibm,hypertas-functions", &len); + hypertas = get_property(dn, "ibm,hypertas-functions", &len); if (hypertas == NULL) goto out; diff --git a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c index 9711eb0d5496..f460b9cbfd46 100644 --- a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -143,7 +143,7 @@ static int pseries_add_processor(struct device_node *np) int err = -ENOSPC, len, nthreads, i; const u32 *intserv; - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len); + intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len); if (!intserv) return 0; @@ -203,7 +203,7 @@ static void pseries_remove_processor(struct device_node *np) int len, nthreads, i; const u32 *intserv; - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len); + intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len); if (!intserv) return; diff --git a/trunk/arch/powerpc/platforms/pseries/iommu.c b/trunk/arch/powerpc/platforms/pseries/iommu.c index 66665c82415c..e6653a868b91 100644 --- a/trunk/arch/powerpc/platforms/pseries/iommu.c +++ b/trunk/arch/powerpc/platforms/pseries/iommu.c @@ -242,7 +242,6 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum) return tce_ret; } -#ifdef CONFIG_PCI static void iommu_table_setparms(struct pci_controller *phb, struct device_node *dn, struct iommu_table *tbl) @@ -253,8 +252,8 @@ static void iommu_table_setparms(struct pci_controller *phb, node = (struct device_node *)phb->arch_data; - basep = of_get_property(node, "linux,tce-base", NULL); - sizep = of_get_property(node, "linux,tce-size", NULL); + basep = get_property(node, "linux,tce-base", NULL); + sizep = get_property(node, "linux,tce-size", NULL); if (basep == NULL || sizep == NULL) { printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has " "missing tce entries !\n", dn->full_name); @@ -404,7 +403,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) /* Find nearest ibm,dma-window, walking up the device tree */ for (pdn = dn; pdn != NULL; pdn = pdn->parent) { - dma_window = of_get_property(pdn, "ibm,dma-window", NULL); + dma_window = get_property(pdn, "ibm,dma-window", NULL); if (dma_window != NULL) break; } @@ -479,6 +478,29 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) pci_name(dev)); } +static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) +{ + int err = NOTIFY_OK; + struct device_node *np = node; + struct pci_dn *pci = PCI_DN(np); + + switch (action) { + case PSERIES_RECONFIG_REMOVE: + if (pci && pci->iommu_table && + get_property(np, "ibm,dma-window", NULL)) + iommu_free_table(np); + break; + default: + err = NOTIFY_DONE; + break; + } + return err; +} + +static struct notifier_block iommu_reconfig_nb = { + .notifier_call = iommu_reconfig_notifier, +}; + static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) { struct device_node *pdn, *dn; @@ -499,7 +521,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; pdn = pdn->parent) { - dma_window = of_get_property(pdn, "ibm,dma-window", NULL); + dma_window = get_property(pdn, "ibm,dma-window", NULL); if (dma_window) break; } @@ -532,44 +554,15 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) dev->dev.archdata.dma_data = pci->iommu_table; } -#else /* CONFIG_PCI */ -#define pci_dma_bus_setup_pSeries NULL -#define pci_dma_dev_setup_pSeries NULL -#define pci_dma_bus_setup_pSeriesLP NULL -#define pci_dma_dev_setup_pSeriesLP NULL -#endif /* !CONFIG_PCI */ - -static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) -{ - int err = NOTIFY_OK; - struct device_node *np = node; - struct pci_dn *pci = PCI_DN(np); - - switch (action) { - case PSERIES_RECONFIG_REMOVE: - if (pci && pci->iommu_table && - of_get_property(np, "ibm,dma-window", NULL)) - iommu_free_table(np); - break; - default: - err = NOTIFY_DONE; - break; - } - return err; -} - -static struct notifier_block iommu_reconfig_nb = { - .notifier_call = iommu_reconfig_notifier, -}; /* These are called very early. */ void iommu_init_early_pSeries(void) { - if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) { + if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) { /* Direct I/O, IOMMU off */ ppc_md.pci_dma_dev_setup = NULL; ppc_md.pci_dma_bus_setup = NULL; - set_pci_dma_ops(&dma_direct_ops); + pci_dma_ops = &dma_direct_ops; return; } @@ -595,6 +588,6 @@ void iommu_init_early_pSeries(void) pSeries_reconfig_notifier_register(&iommu_reconfig_nb); - set_pci_dma_ops(&dma_iommu_ops); + pci_dma_ops = &dma_iommu_ops; } diff --git a/trunk/arch/powerpc/platforms/pseries/lpar.c b/trunk/arch/powerpc/platforms/pseries/lpar.c index 3a70e8ad7bc8..843ee9643211 100644 --- a/trunk/arch/powerpc/platforms/pseries/lpar.c +++ b/trunk/arch/powerpc/platforms/pseries/lpar.c @@ -209,13 +209,13 @@ void __init find_udbg_vterm(void) /* find the boot console from /chosen/stdout */ if (!of_chosen) return; - name = of_get_property(of_chosen, "linux,stdout-path", NULL); + name = get_property(of_chosen, "linux,stdout-path", NULL); if (name == NULL) return; stdout_node = of_find_node_by_path(name); if (!stdout_node) return; - name = of_get_property(stdout_node, "name", NULL); + name = get_property(stdout_node, "name", NULL); if (!name) { printk(KERN_WARNING "stdout node missing 'name' property!\n"); goto out; @@ -226,7 +226,7 @@ void __init find_udbg_vterm(void) /* Check if it's a virtual terminal */ if (strncmp(name, "vty", 3) != 0) goto out; - termno = of_get_property(stdout_node, "reg", NULL); + termno = get_property(stdout_node, "reg", NULL); if (termno == NULL) goto out; vtermno = termno[0]; diff --git a/trunk/arch/powerpc/platforms/pseries/nvram.c b/trunk/arch/powerpc/platforms/pseries/nvram.c index f68903e15bd5..64163cecdf93 100644 --- a/trunk/arch/powerpc/platforms/pseries/nvram.c +++ b/trunk/arch/powerpc/platforms/pseries/nvram.c @@ -130,7 +130,7 @@ int __init pSeries_nvram_init(void) if (nvram == NULL) return -ENODEV; - nbytes_p = of_get_property(nvram, "#bytes", &proplen); + nbytes_p = get_property(nvram, "#bytes", &proplen); if (nbytes_p == NULL || proplen != sizeof(unsigned int)) return -EIO; diff --git a/trunk/arch/powerpc/platforms/pseries/pci.c b/trunk/arch/powerpc/platforms/pseries/pci.c index 2c6ded29f73d..fa59124ce3fe 100644 --- a/trunk/arch/powerpc/platforms/pseries/pci.c +++ b/trunk/arch/powerpc/platforms/pseries/pci.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -40,7 +39,7 @@ void pcibios_name_device(struct pci_dev *dev) */ dn = pci_device_to_OF_node(dev); if (dn) { - const char *loc_code = of_get_property(dn, "ibm,loc-code", 0); + char *loc_code = get_property(dn, "ibm,loc-code", 0); if (loc_code) { int loc_len = strlen(loc_code); if (loc_len < sizeof(dev->dev.name)) { diff --git a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c index fdc1a369f767..ac56b868913a 100644 --- a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -29,7 +29,6 @@ #include #include #include -#include static struct pci_bus * find_bus_among_children(struct pci_bus *bus, diff --git a/trunk/arch/powerpc/platforms/pseries/power.c b/trunk/arch/powerpc/platforms/pseries/power.c index 73e69023d90a..2624b71df73d 100644 --- a/trunk/arch/powerpc/platforms/pseries/power.c +++ b/trunk/arch/powerpc/platforms/pseries/power.c @@ -28,13 +28,13 @@ unsigned long rtas_poweron_auto; /* default and normal state is 0 */ -static ssize_t auto_poweron_show(struct kset *kset, char *buf) +static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf) { return sprintf(buf, "%lu\n", rtas_poweron_auto); } static ssize_t -auto_poweron_store(struct kset *kset, const char *buf, size_t n) +auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n) { int ret; unsigned long ups_restart; @@ -72,12 +72,12 @@ static int __init pm_init(void) { int error = subsystem_register(&power_subsys); if (!error) - error = sysfs_create_group(&power_subsys.kobj, &attr_group); + error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group); return error; } core_initcall(pm_init); #else -extern struct kset power_subsys; +extern struct subsystem power_subsys; static int __init apo_pm_init(void) { diff --git a/trunk/arch/powerpc/platforms/pseries/ras.c b/trunk/arch/powerpc/platforms/pseries/ras.c index 3a393c7f390e..edc038873113 100644 --- a/trunk/arch/powerpc/platforms/pseries/ras.c +++ b/trunk/arch/powerpc/platforms/pseries/ras.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ static void request_ras_irqs(struct device_node *np, * map those interrupts using the default interrupt host and default * trigger */ - opicprop = of_get_property(np, "open-pic-interrupt", &opicplen); + opicprop = get_property(np, "open-pic-interrupt", &opicplen); if (opicprop) { opicplen /= sizeof(u32); for (i = 0; i < opicplen; i++) { diff --git a/trunk/arch/powerpc/platforms/pseries/rtasd.c b/trunk/arch/powerpc/platforms/pseries/rtasd.c index 9797b10b2935..77d0937d5c07 100644 --- a/trunk/arch/powerpc/platforms/pseries/rtasd.c +++ b/trunk/arch/powerpc/platforms/pseries/rtasd.c @@ -363,7 +363,7 @@ static int get_eventscan_parms(void) node = of_find_node_by_path("/rtas"); - ip = of_get_property(node, "rtas-event-scan-rate", NULL); + ip = get_property(node, "rtas-event-scan-rate", NULL); if (ip == NULL) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); of_node_put(node); diff --git a/trunk/arch/powerpc/platforms/pseries/setup.c b/trunk/arch/powerpc/platforms/pseries/setup.c index 33eec2822c66..34aff47b1f55 100644 --- a/trunk/arch/powerpc/platforms/pseries/setup.c +++ b/trunk/arch/powerpc/platforms/pseries/setup.c @@ -65,7 +65,6 @@ #include #include #include -#include #include "plpar_wrappers.h" #include "pseries.h" @@ -93,7 +92,7 @@ static void pSeries_show_cpuinfo(struct seq_file *m) root = of_find_node_by_path("/"); if (root) - model = of_get_property(root, "model", NULL); + model = get_property(root, "model", NULL); seq_printf(m, "machine\t\t: CHRP %s\n", model); of_node_put(root); } @@ -139,8 +138,8 @@ static void __init pseries_mpic_init_IRQ(void) struct mpic *mpic; np = of_find_node_by_path("/"); - naddr = of_n_addr_cells(np); - opprop = of_get_property(np, "platform-open-pic", &opplen); + naddr = prom_n_addr_cells(np); + opprop = get_property(np, "platform-open-pic", &opplen); if (opprop != 0) { openpic_addr = of_read_number(opprop, naddr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); @@ -189,11 +188,11 @@ static void __init pseries_mpic_init_IRQ(void) break; if (strcmp(np->name, "pci") != 0) continue; - addrp = of_get_property(np, "8259-interrupt-acknowledge", + addrp = get_property(np, "8259-interrupt-acknowledge", NULL); if (addrp == NULL) continue; - naddr = of_n_addr_cells(np); + naddr = prom_n_addr_cells(np); intack = addrp[naddr-1]; if (naddr > 1) intack |= ((unsigned long)addrp[naddr-2]) << 32; @@ -226,7 +225,7 @@ static void __init pseries_discover_pic(void) for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { - typep = of_get_property(np, "compatible", NULL); + typep = get_property(np, "compatible", NULL); if (strstr(typep, "open-pic")) { pSeries_mpic_node = of_node_get(np); ppc_md.init_IRQ = pseries_mpic_init_IRQ; @@ -335,6 +334,32 @@ static void __init pSeries_init_early(void) DBG(" <- pSeries_init_early()\n"); } + +static int pSeries_check_legacy_ioport(unsigned int baseport) +{ + struct device_node *np; + +#define I8042_DATA_REG 0x60 +#define FDC_BASE 0x3f0 + + + switch(baseport) { + case I8042_DATA_REG: + np = of_find_node_by_type(NULL, "8042"); + if (np == NULL) + return -ENODEV; + of_node_put(np); + break; + case FDC_BASE: + np = of_find_node_by_type(NULL, "fdc"); + if (np == NULL) + return -ENODEV; + of_node_put(np); + break; + } + return 0; +} + /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -489,10 +514,6 @@ void pSeries_power_off(void) for (;;); } -#ifndef CONFIG_PCI -void pSeries_final_fixup(void) { } -#endif - define_machine(pseries) { .name = "pSeries", .probe = pSeries_probe, @@ -511,6 +532,7 @@ define_machine(pseries) { .set_rtc_time = rtas_set_rtc_time, .calibrate_decr = generic_calibrate_decr, .progress = rtas_progress, + .check_legacy_ioport = pSeries_check_legacy_ioport, .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, }; diff --git a/trunk/arch/powerpc/platforms/pseries/xics.c b/trunk/arch/powerpc/platforms/pseries/xics.c index 896cbf340c42..81d172d65038 100644 --- a/trunk/arch/powerpc/platforms/pseries/xics.c +++ b/trunk/arch/powerpc/platforms/pseries/xics.c @@ -576,7 +576,7 @@ static void __init xics_init_one_node(struct device_node *np, * This happens to be the case so far but we are playing with fire... * should be fixed one of these days. -BenH. */ - ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL); + ireg = get_property(np, "ibm,interrupt-server-ranges", NULL); /* Do that ever happen ? we'll know soon enough... but even good'old * f80 does have that property .. @@ -588,7 +588,7 @@ static void __init xics_init_one_node(struct device_node *np, */ *indx = *ireg; } - ireg = of_get_property(np, "reg", &ilen); + ireg = get_property(np, "reg", &ilen); if (!ireg) panic("xics_init_IRQ: can't find interrupt reg property"); @@ -640,10 +640,10 @@ static void __init xics_setup_8259_cascade(void) break; if (strcmp(np->name, "pci") != 0) continue; - addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL); + addrp = get_property(np, "8259-interrupt-acknowledge", NULL); if (addrp == NULL) continue; - naddr = of_n_addr_cells(np); + naddr = prom_n_addr_cells(np); intack = addrp[naddr-1]; if (naddr > 1) intack |= ((unsigned long)addrp[naddr-2]) << 32; @@ -664,11 +664,10 @@ static struct device_node *cpuid_to_of_node(int cpu) int i, len; const u32 *intserv; - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", - &len); + intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len); if (!intserv) - intserv = of_get_property(np, "reg", &len); + intserv = get_property(np, "reg", &len); i = len / sizeof(u32); @@ -710,7 +709,7 @@ void __init xics_init_IRQ(void) /* Find the server numbers for the boot cpu. */ np = cpuid_to_of_node(boot_cpuid); BUG_ON(!np); - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); if (!ireg) goto skip_gserver_check; i = ilen / sizeof(int); @@ -726,7 +725,7 @@ void __init xics_init_IRQ(void) default_server = hcpuid; default_distrib_server = ireg[j+1]; - isize = of_get_property(np, + isize = get_property(np, "ibm,interrupt-server#-size", NULL); if (isize) interrupt_server_size = *isize; diff --git a/trunk/arch/powerpc/sysdev/Makefile b/trunk/arch/powerpc/sysdev/Makefile index e96ca9618dbb..26ca3ffbc1de 100644 --- a/trunk/arch/powerpc/sysdev/Makefile +++ b/trunk/arch/powerpc/sysdev/Makefile @@ -11,17 +11,12 @@ obj-$(CONFIG_PPC_PMI) += pmi.o obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_FSL_SOC) += fsl_soc.o -obj-$(CONFIG_FSL_PCIE) += fsl_pcie.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ -# contains only the suspend handler for time -obj-$(CONFIG_PM) += timer.o - ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_83xx) += ipic.o -obj-$(CONFIG_4xx) += uic.o endif # Temporary hack until we have migrated to asm-powerpc diff --git a/trunk/arch/powerpc/sysdev/dart_iommu.c b/trunk/arch/powerpc/sysdev/dart_iommu.c index 336186dd7f10..1488535b0e13 100644 --- a/trunk/arch/powerpc/sysdev/dart_iommu.c +++ b/trunk/arch/powerpc/sysdev/dart_iommu.c @@ -333,7 +333,7 @@ void iommu_init_early_dart(void) ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart; /* Setup pci_dma ops */ - set_pci_dma_ops(&dma_iommu_ops); + pci_dma_ops = &dma_iommu_ops; return; } @@ -343,7 +343,7 @@ void iommu_init_early_dart(void) ppc_md.pci_dma_bus_setup = NULL; /* Setup pci_dma ops */ - set_pci_dma_ops(&dma_direct_ops); + pci_dma_ops = &dma_direct_ops; } diff --git a/trunk/arch/powerpc/sysdev/dcr.c b/trunk/arch/powerpc/sysdev/dcr.c index 574b6ef44e0b..1fc5819e7d18 100644 --- a/trunk/arch/powerpc/sysdev/dcr.c +++ b/trunk/arch/powerpc/sysdev/dcr.c @@ -26,7 +26,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) { unsigned int ds; - const u32 *dr = of_get_property(np, "dcr-reg", &ds); + const u32 *dr = get_property(np, "dcr-reg", &ds); if (dr == NULL || ds & 1 || index >= (ds / 8)) return 0; @@ -37,7 +37,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) unsigned int dcr_resource_len(struct device_node *np, unsigned int index) { unsigned int ds; - const u32 *dr = of_get_property(np, "dcr-reg", &ds); + const u32 *dr = get_property(np, "dcr-reg", &ds); if (dr == NULL || ds & 1 || index >= (ds / 8)) return 0; @@ -53,9 +53,9 @@ static struct device_node * find_dcr_parent(struct device_node * node) const u32 *p; for (par = of_node_get(node); par;) { - if (of_get_property(par, "dcr-controller", NULL)) + if (get_property(par, "dcr-controller", NULL)) break; - p = of_get_property(par, "dcr-parent", NULL); + p = get_property(par, "dcr-parent", NULL); tmp = par; if (p == NULL) par = of_get_parent(par); @@ -80,13 +80,13 @@ u64 of_translate_dcr_address(struct device_node *dev, return OF_BAD_ADDR; /* Stride is not properly defined yet, default to 0x10 for Axon */ - p = of_get_property(dp, "dcr-mmio-stride", NULL); + p = get_property(dp, "dcr-mmio-stride", NULL); stride = (p == NULL) ? 0x10 : *p; /* XXX FIXME: Which property name is to use of the 2 following ? */ - p = of_get_property(dp, "dcr-mmio-range", NULL); + p = get_property(dp, "dcr-mmio-range", NULL); if (p == NULL) - p = of_get_property(dp, "dcr-mmio-space", NULL); + p = get_property(dp, "dcr-mmio-space", NULL); if (p == NULL) return OF_BAD_ADDR; diff --git a/trunk/arch/powerpc/sysdev/fsl_pcie.h b/trunk/arch/powerpc/sysdev/fsl_pcie.h deleted file mode 100644 index 8d9779c84bea..000000000000 --- a/trunk/arch/powerpc/sysdev/fsl_pcie.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * MPC85xx/86xx PCI Express structure define - * - * Copyright 2007 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifdef __KERNEL__ -#ifndef __POWERPC_FSL_PCIE_H -#define __POWERPC_FSL_PCIE_H - -/* PCIE Express IO block registers in 85xx/86xx */ - -struct ccsr_pex { - __be32 __iomem pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */ - __be32 __iomem pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */ - u8 __iomem res1[4]; - __be32 __iomem pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */ - __be32 __iomem pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */ - u8 __iomem res2[12]; - __be32 __iomem pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */ - __be32 __iomem pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */ - __be32 __iomem pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */ - __be32 __iomem pex_pmcr; /* 0x.02c - PCI Express power management command register */ - u8 __iomem res3[3024]; - __be32 __iomem pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */ - __be32 __iomem pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/ - u8 __iomem res4[8]; - __be32 __iomem pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/ - u8 __iomem res5[12]; - __be32 __iomem pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */ - __be32 __iomem pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/ - __be32 __iomem pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/ - u8 __iomem res6[4]; - __be32 __iomem pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/ - u8 __iomem res7[12]; - __be32 __iomem pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */ - __be32 __iomem pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/ - __be32 __iomem pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/ - u8 __iomem res8[4]; - __be32 __iomem pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/ - u8 __iomem res9[12]; - __be32 __iomem pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */ - __be32 __iomem pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/ - __be32 __iomem pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/ - u8 __iomem res10[4]; - __be32 __iomem pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/ - u8 __iomem res11[12]; - __be32 __iomem pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */ - __be32 __iomem pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/ - __be32 __iomem pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/ - u8 __iomem res12[4]; - __be32 __iomem pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/ - u8 __iomem res13[12]; - u8 __iomem res14[256]; - __be32 __iomem pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */ - u8 __iomem res15[4]; - __be32 __iomem pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */ - __be32 __iomem pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */ - __be32 __iomem pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */ - u8 __iomem res16[12]; - __be32 __iomem pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */ - u8 __iomem res17[4]; - __be32 __iomem pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */ - __be32 __iomem pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */ - __be32 __iomem pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */ - u8 __iomem res18[12]; - __be32 __iomem pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */ - u8 __iomem res19[4]; - __be32 __iomem pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */ - __be32 __iomem pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */ - __be32 __iomem pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */ - u8 __iomem res20[12]; - __be32 __iomem pex_err_dr; /* 0x.e00 - PCI Express error detect register */ - u8 __iomem res21[4]; - __be32 __iomem pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */ - u8 __iomem res22[4]; - __be32 __iomem pex_err_disr; /* 0x.e10 - PCI Express error disable register */ - u8 __iomem res23[12]; - __be32 __iomem pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */ - u8 __iomem res24[4]; - __be32 __iomem pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */ - __be32 __iomem pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */ - __be32 __iomem pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */ - __be32 __iomem pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */ -}; - -#endif /* __POWERPC_FSL_PCIE_H */ -#endif /* __KERNEL__ */ diff --git a/trunk/arch/powerpc/sysdev/fsl_soc.c b/trunk/arch/powerpc/sysdev/fsl_soc.c index 8a123c71449f..d20f02927f72 100644 --- a/trunk/arch/powerpc/sysdev/fsl_soc.c +++ b/trunk/arch/powerpc/sysdev/fsl_soc.c @@ -52,7 +52,7 @@ phys_addr_t get_immrbase(void) soc = of_find_node_by_type(NULL, "soc"); if (soc) { unsigned int size; - const void *prop = of_get_property(soc, "reg", &size); + const void *prop = get_property(soc, "reg", &size); if (prop) immrbase = of_translate_address(soc, prop); @@ -78,8 +78,8 @@ u32 get_brgfreq(void) node = of_find_node_by_type(NULL, "cpm"); if (node) { unsigned int size; - const unsigned int *prop = of_get_property(node, - "brg-frequency", &size); + const unsigned int *prop = get_property(node, "brg-frequency", + &size); if (prop) brgfreq = *prop; @@ -103,8 +103,8 @@ u32 get_baudrate(void) node = of_find_node_by_type(NULL, "serial"); if (node) { unsigned int size; - const unsigned int *prop = of_get_property(node, - "current-speed", &size); + const unsigned int *prop = get_property(node, "current-speed", + &size); if (prop) fs_baudrate = *prop; @@ -153,8 +153,7 @@ static int __init gfar_mdio_of_init(void) while ((child = of_get_next_child(np, child)) != NULL) { int irq = irq_of_parse_and_map(child, 0); if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, - "reg", NULL); + const u32 *id = get_property(child, "reg", NULL); mdio_data.irq[*id] = irq; } } @@ -210,7 +209,7 @@ static int __init gfar_of_init(void) of_irq_to_resource(np, 0, &r[1]); - model = of_get_property(np, "model", NULL); + model = get_property(np, "model", NULL); /* If we aren't the FEC we have multiple interrupts */ if (model && strcasecmp(model, "FEC")) { @@ -254,7 +253,7 @@ static int __init gfar_of_init(void) FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; - ph = of_get_property(np, "phy-handle", NULL); + ph = get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); if (phy == NULL) { @@ -264,7 +263,7 @@ static int __init gfar_of_init(void) mdio = of_get_parent(phy); - id = of_get_property(phy, "reg", NULL); + id = get_property(phy, "reg", NULL); ret = of_address_to_resource(mdio, 0, &res); if (ret) { of_node_put(phy); @@ -326,11 +325,11 @@ static int __init fsl_i2c_of_init(void) } i2c_data.device_flags = 0; - flags = of_get_property(np, "dfsrr", NULL); + flags = get_property(np, "dfsrr", NULL); if (flags) i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR; - flags = of_get_property(np, "fsl5200-clocking", NULL); + flags = get_property(np, "fsl5200-clocking", NULL); if (flags) i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200; @@ -375,7 +374,7 @@ static int __init mpc83xx_wdt_init(void) goto nosoc; } - freq = of_get_property(soc, "bus-frequency", NULL); + freq = get_property(soc, "bus-frequency", NULL); if (!freq) { ret = -ENODEV; goto err; @@ -467,15 +466,15 @@ static int __init fsl_usb_of_init(void) usb_data.operating_mode = FSL_USB2_MPH_HOST; - prop = of_get_property(np, "port0", NULL); + prop = get_property(np, "port0", NULL); if (prop) usb_data.port_enables |= FSL_USB2_PORT0_ENABLED; - prop = of_get_property(np, "port1", NULL); + prop = get_property(np, "port1", NULL); if (prop) usb_data.port_enables |= FSL_USB2_PORT1_ENABLED; - prop = of_get_property(np, "phy_type", NULL); + prop = get_property(np, "phy_type", NULL); usb_data.phy_mode = determine_usb_phy(prop); ret = @@ -502,7 +501,7 @@ static int __init fsl_usb_of_init(void) of_irq_to_resource(np, 0, &r[1]); - prop = of_get_property(np, "dr_mode", NULL); + prop = get_property(np, "dr_mode", NULL); if (!prop || !strcmp(prop, "host")) { usb_data.operating_mode = FSL_USB2_DR_HOST; @@ -539,7 +538,7 @@ static int __init fsl_usb_of_init(void) goto err; } - prop = of_get_property(np, "phy_type", NULL); + prop = get_property(np, "phy_type", NULL); usb_data.phy_mode = determine_usb_phy(prop); if (usb_dev_dr_host) { @@ -634,7 +633,7 @@ static int __init fs_enet_of_init(void) goto err; } - model = of_get_property(np, "model", NULL); + model = get_property(np, "model", NULL); if (model == NULL) { ret = -ENODEV; goto unreg; @@ -644,7 +643,7 @@ static int __init fs_enet_of_init(void) if (mac_addr) memcpy(fs_enet_data.macaddr, mac_addr, 6); - ph = of_get_property(np, "phy-handle", NULL); + ph = get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); if (phy == NULL) { @@ -652,12 +651,12 @@ static int __init fs_enet_of_init(void) goto unreg; } - phy_addr = of_get_property(phy, "reg", NULL); + phy_addr = get_property(phy, "reg", NULL); fs_enet_data.phy_addr = *phy_addr; - phy_irq = of_get_property(phy, "interrupts", NULL); + phy_irq = get_property(phy, "interrupts", NULL); - id = of_get_property(np, "device-id", NULL); + id = get_property(np, "device-id", NULL); fs_enet_data.fs_no = *id; strcpy(fs_enet_data.fs_type, model); @@ -669,10 +668,8 @@ static int __init fs_enet_of_init(void) goto unreg; } - fs_enet_data.clk_rx = *((u32 *)of_get_property(np, - "rx-clock", NULL)); - fs_enet_data.clk_tx = *((u32 *)of_get_property(np, - "tx-clock", NULL)); + fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); + fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); if (strstr(model, "FCC")) { int fcc_index = *id - 1; @@ -693,7 +690,7 @@ static int __init fs_enet_of_init(void) fs_enet_data.bus_id = (char*)&bus_id[(*id)]; fs_enet_data.init_ioports = init_fcc_ioports; - mdio_bb_prop = of_get_property(phy, "bitbang", NULL); + mdio_bb_prop = get_property(phy, "bitbang", NULL); if (mdio_bb_prop) { struct platform_device *fs_enet_mdio_bb_dev; struct fs_mii_bb_platform_info fs_enet_mdio_bb_data; @@ -799,10 +796,10 @@ static int __init cpm_uart_of_init(void) goto err; } - id = of_get_property(np, "device-id", NULL); + id = get_property(np, "device-id", NULL); cpm_uart_data.fs_no = *id; - model = of_get_property(np, "model", NULL); + model = (char*)get_property(np, "model", NULL); strcpy(cpm_uart_data.fs_type, model); cpm_uart_data.uart_clk = ppc_proc_freq; @@ -811,10 +808,8 @@ static int __init cpm_uart_of_init(void) cpm_uart_data.tx_buf_size = 32; cpm_uart_data.rx_num_fifo = 4; cpm_uart_data.rx_buf_size = 32; - cpm_uart_data.clk_rx = *((u32 *)of_get_property(np, - "rx-clock", NULL)); - cpm_uart_data.clk_tx = *((u32 *)of_get_property(np, - "tx-clock", NULL)); + cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); + cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); ret = platform_device_add_data(cpm_uart_dev, &cpm_uart_data, @@ -838,7 +833,7 @@ arch_initcall(cpm_uart_of_init); #ifdef CONFIG_8xx extern void init_scc_ioports(struct fs_platform_info*); -extern int platform_device_skip(const char *model, int id); +extern int platform_device_skip(char *model, int id); static int __init fs_enet_mdio_of_init(void) { @@ -905,22 +900,21 @@ static int __init fs_enet_of_init(void) struct resource r[4]; struct device_node *phy = NULL, *mdio = NULL; struct fs_platform_info fs_enet_data; - const unsigned int *id; - const unsigned int *phy_addr; + unsigned int *id, *phy_addr; void *mac_addr; - const phandle *ph; - const char *model; + phandle *ph; + char *model; memset(r, 0, sizeof(r)); memset(&fs_enet_data, 0, sizeof(fs_enet_data)); - model = of_get_property(np, "model", NULL); + model = (char *)get_property(np, "model", NULL); if (model == NULL) { ret = -ENODEV; goto unreg; } - id = of_get_property(np, "device-id", NULL); + id = (u32 *) get_property(np, "device-id", NULL); fs_enet_data.fs_no = *id; if (platform_device_skip(model, *id)) @@ -935,12 +929,12 @@ static int __init fs_enet_of_init(void) if (mac_addr) memcpy(fs_enet_data.macaddr, mac_addr, 6); - ph = of_get_property(np, "phy-handle", NULL); + ph = (phandle *) get_property(np, "phy-handle", NULL); if (ph != NULL) phy = of_find_node_by_phandle(*ph); if (phy != NULL) { - phy_addr = of_get_property(phy, "reg", NULL); + phy_addr = (u32 *) get_property(phy, "reg", NULL); fs_enet_data.phy_addr = *phy_addr; fs_enet_data.has_phy = 1; @@ -953,7 +947,7 @@ static int __init fs_enet_of_init(void) } } - model = of_get_property(np, "model", NULL); + model = (char*)get_property(np, "model", NULL); strcpy(fs_enet_data.fs_type, model); if (strstr(model, "FEC")) { @@ -1044,8 +1038,8 @@ static int __init cpm_smc_uart_of_init(void) i++) { struct resource r[3]; struct fs_uart_platform_info cpm_uart_data; - const int *id; - const char *model; + int *id; + char *model; memset(r, 0, sizeof(r)); memset(&cpm_uart_data, 0, sizeof(cpm_uart_data)); @@ -1072,10 +1066,10 @@ static int __init cpm_smc_uart_of_init(void) goto err; } - model = of_get_property(np, "model", NULL); + model = (char*)get_property(np, "model", NULL); strcpy(cpm_uart_data.fs_type, model); - id = of_get_property(np, "device-id", NULL); + id = (int*)get_property(np, "device-id", NULL); cpm_uart_data.fs_no = *id; cpm_uart_data.uart_clk = ppc_proc_freq; diff --git a/trunk/arch/powerpc/sysdev/mpic.c b/trunk/arch/powerpc/sysdev/mpic.c index 0b84b7c775d8..bcfb900481f8 100644 --- a/trunk/arch/powerpc/sysdev/mpic.c +++ b/trunk/arch/powerpc/sysdev/mpic.c @@ -304,7 +304,7 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic) } } -#ifdef CONFIG_MPIC_U3_HT_IRQS +#ifdef CONFIG_MPIC_BROKEN_U3 /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) * to force the edge setting on the MPIC and do the ack workaround. @@ -476,7 +476,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) } } -#else /* CONFIG_MPIC_U3_HT_IRQS */ +#else /* CONFIG_MPIC_BROKEN_U3 */ static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) { @@ -487,7 +487,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) { } -#endif /* CONFIG_MPIC_U3_HT_IRQS */ +#endif /* CONFIG_MPIC_BROKEN_U3 */ #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) @@ -615,7 +615,7 @@ static void mpic_end_irq(unsigned int irq) mpic_eoi(mpic); } -#ifdef CONFIG_MPIC_U3_HT_IRQS +#ifdef CONFIG_MPIC_BROKEN_U3 static void mpic_unmask_ht_irq(unsigned int irq) { @@ -665,7 +665,7 @@ static void mpic_end_ht_irq(unsigned int irq) mpic_ht_end_irq(mpic, src); mpic_eoi(mpic); } -#endif /* !CONFIG_MPIC_U3_HT_IRQS */ +#endif /* !CONFIG_MPIC_BROKEN_U3 */ #ifdef CONFIG_SMP @@ -788,7 +788,7 @@ static struct irq_chip mpic_ipi_chip = { }; #endif /* CONFIG_SMP */ -#ifdef CONFIG_MPIC_U3_HT_IRQS +#ifdef CONFIG_MPIC_BROKEN_U3 static struct irq_chip mpic_irq_ht_chip = { .startup = mpic_startup_ht_irq, .shutdown = mpic_shutdown_ht_irq, @@ -797,7 +797,7 @@ static struct irq_chip mpic_irq_ht_chip = { .eoi = mpic_end_ht_irq, .set_type = mpic_set_irq_type, }; -#endif /* CONFIG_MPIC_U3_HT_IRQS */ +#endif /* CONFIG_MPIC_BROKEN_U3 */ static int mpic_host_match(struct irq_host *h, struct device_node *node) @@ -837,11 +837,11 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, /* Default chip */ chip = &mpic->hc_irq; -#ifdef CONFIG_MPIC_U3_HT_IRQS +#ifdef CONFIG_MPIC_BROKEN_U3 /* Check for HT interrupts, override vecpri */ if (mpic_is_ht_interrupt(mpic, hw)) chip = &mpic->hc_ht_irq; -#endif /* CONFIG_MPIC_U3_HT_IRQS */ +#endif /* CONFIG_MPIC_BROKEN_U3 */ DBG("mpic: mapping to irq chip @%p\n", chip); @@ -937,12 +937,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_irq.typename = name; if (flags & MPIC_PRIMARY) mpic->hc_irq.set_affinity = mpic_set_affinity; -#ifdef CONFIG_MPIC_U3_HT_IRQS +#ifdef CONFIG_MPIC_BROKEN_U3 mpic->hc_ht_irq = mpic_irq_ht_chip; mpic->hc_ht_irq.typename = name; if (flags & MPIC_PRIMARY) mpic->hc_ht_irq.set_affinity = mpic_set_affinity; -#endif /* CONFIG_MPIC_U3_HT_IRQS */ +#endif /* CONFIG_MPIC_BROKEN_U3 */ #ifdef CONFIG_SMP mpic->hc_ipi = mpic_ipi_chip; @@ -970,7 +970,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->spurious_vec = intvec_top; /* Check for "big-endian" in device-tree */ - if (node && of_get_property(node, "big-endian", NULL) != NULL) + if (node && get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; @@ -986,13 +986,13 @@ struct mpic * __init mpic_alloc(struct device_node *node, BUG_ON(paddr == 0 && node == NULL); /* If no physical address passed in, check if it's dcr based */ - if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) + if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL) mpic->flags |= MPIC_USES_DCR; #ifdef CONFIG_PPC_DCR if (mpic->flags & MPIC_USES_DCR) { const u32 *dbasep; - dbasep = of_get_property(node, "dcr-reg", NULL); + dbasep = get_property(node, "dcr-reg", NULL); BUG_ON(dbasep == NULL); mpic->dcr_base = *dbasep; mpic->reg_type = mpic_access_dcr; @@ -1006,7 +1006,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, */ if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { const u32 *reg; - reg = of_get_property(node, "reg", NULL); + reg = get_property(node, "reg", NULL); BUG_ON(reg == NULL); paddr = of_translate_address(node, reg); BUG_ON(paddr == OF_BAD_ADDR); @@ -1142,7 +1142,7 @@ void __init mpic_init(struct mpic *mpic) /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); - if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) + if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) mpic_scan_ht_pics(mpic); for (i = 0; i < mpic->num_sources; i++) { diff --git a/trunk/arch/powerpc/sysdev/pmi.c b/trunk/arch/powerpc/sysdev/pmi.c index 85a7c99c1003..a5282011d39e 100644 --- a/trunk/arch/powerpc/sysdev/pmi.c +++ b/trunk/arch/powerpc/sysdev/pmi.c @@ -33,7 +33,7 @@ #include #include #include -#include + struct pmi_data { struct list_head handler; @@ -49,6 +49,21 @@ struct pmi_data { }; + +static void __iomem *of_iomap(struct device_node *np) +{ + struct resource res; + + if (of_address_to_resource(np, 0, &res)) + return NULL; + + pr_debug("Resource start: 0x%lx\n", res.start); + pr_debug("Resource end: 0x%lx\n", res.end); + + return ioremap(res.start, 1 + res.end - res.start); +} + + static int pmi_irq_handler(int irq, void *dev_id) { struct pmi_data *data; @@ -103,7 +118,6 @@ static int pmi_irq_handler(int irq, void *dev_id) static struct of_device_id pmi_match[] = { { .type = "ibm,pmi", .name = "ibm,pmi" }, - { .type = "ibm,pmi" }, {}, }; @@ -139,7 +153,7 @@ static int pmi_of_probe(struct of_device *dev, goto out; } - data->pmi_reg = of_iomap(np, 0); + data->pmi_reg = of_iomap(np); if (!data->pmi_reg) { printk(KERN_ERR "pmi: invalid register address.\n"); rc = -EFAULT; @@ -265,9 +279,6 @@ void pmi_register_handler(struct of_device *device, struct pmi_data *data; data = device->dev.driver_data; - if (!data) - return; - spin_lock(&data->handler_spinlock); list_add_tail(&handler->node, &data->handler); spin_unlock(&data->handler_spinlock); @@ -278,13 +289,11 @@ void pmi_unregister_handler(struct of_device *device, struct pmi_handler *handler) { struct pmi_data *data; - data = device->dev.driver_data; - - if (!data) - return; pr_debug("pmi: unregistering handler %p\n", handler); + data = device->dev.driver_data; + spin_lock(&data->handler_spinlock); list_del(&handler->node); spin_unlock(&data->handler_spinlock); diff --git a/trunk/arch/powerpc/sysdev/qe_lib/Kconfig b/trunk/arch/powerpc/sysdev/qe_lib/Kconfig index 887739f3badc..a725e80befa8 100644 --- a/trunk/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/trunk/arch/powerpc/sysdev/qe_lib/Kconfig @@ -2,8 +2,11 @@ # QE Communication options # +menu "QE Options" + depends on QUICC_ENGINE + config UCC_SLOW - bool + bool "UCC Slow Protocols Support" default n select UCC help @@ -11,9 +14,10 @@ config UCC_SLOW protocols: UART, BISYNC, QMC config UCC_FAST - bool + bool "UCC Fast Protocols Support" default n select UCC + select UCC_SLOW help This option provides qe_lib support to UCC fast protocols: HDLC, Ethernet, ATM, transparent @@ -22,3 +26,5 @@ config UCC bool default y if UCC_FAST || UCC_SLOW +endmenu + diff --git a/trunk/arch/powerpc/sysdev/qe_lib/qe.c b/trunk/arch/powerpc/sysdev/qe_lib/qe.c index 7f4c07543961..43f6cc9d7ea0 100644 --- a/trunk/arch/powerpc/sysdev/qe_lib/qe.c +++ b/trunk/arch/powerpc/sysdev/qe_lib/qe.c @@ -71,7 +71,7 @@ phys_addr_t get_qe_base(void) qe = of_find_node_by_type(NULL, "qe"); if (qe) { unsigned int size; - const void *prop = of_get_property(qe, "reg", &size); + const void *prop = get_property(qe, "reg", &size); qebase = of_translate_address(qe, prop); of_node_put(qe); }; @@ -158,7 +158,7 @@ unsigned int get_brg_clk(void) qe = of_find_node_by_type(NULL, "qe"); if (qe) { unsigned int size; - const u32 *prop = of_get_property(qe, "brg-frequency", &size); + const u32 *prop = get_property(qe, "brg-frequency", &size); brg_clk = *prop; of_node_put(qe); }; diff --git a/trunk/arch/powerpc/sysdev/qe_lib/qe_io.c b/trunk/arch/powerpc/sysdev/qe_lib/qe_io.c index e32b45bf9ff5..0afe6bfe3714 100644 --- a/trunk/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/trunk/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -53,7 +53,7 @@ int par_io_init(struct device_node *np) return ret; par_io = ioremap(res.start, res.end - res.start + 1); - num_ports = of_get_property(np, "num-ports", NULL); + num_ports = get_property(np, "num-ports", NULL); if (num_ports) num_par_io_ports = *num_ports; @@ -161,7 +161,7 @@ int par_io_of_config(struct device_node *np) return -1; } - ph = of_get_property(np, "pio-handle", NULL); + ph = get_property(np, "pio-handle", NULL); if (ph == 0) { printk(KERN_ERR "pio-handle not available \n"); return -1; @@ -169,7 +169,7 @@ int par_io_of_config(struct device_node *np) pio = of_find_node_by_phandle(*ph); - pio_map = of_get_property(pio, "pio-map", &pio_map_len); + pio_map = get_property(pio, "pio-map", &pio_map_len); if (pio_map == NULL) { printk(KERN_ERR "pio-map is not set! \n"); return -1; diff --git a/trunk/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/trunk/arch/powerpc/sysdev/qe_lib/ucc_fast.c index 66137bf2dfb0..a457ac1c6639 100644 --- a/trunk/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/trunk/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -210,9 +210,6 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uf_regs = uccf->uf_regs; uccf->p_ucce = (u32 *) & (uf_regs->ucce); uccf->p_uccm = (u32 *) & (uf_regs->uccm); -#ifdef CONFIG_UGETH_TX_ON_DEMAND - uccf->p_utodr = (u16 *) & (uf_regs->utodr); -#endif #ifdef STATISTICS uccf->tx_frames = 0; uccf->rx_frames = 0; diff --git a/trunk/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/trunk/arch/powerpc/sysdev/qe_lib/ucc_slow.c index b930d686a4d1..817df73ecf56 100644 --- a/trunk/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/trunk/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -187,7 +187,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) { + if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) { printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); ucc_slow_free(uccs); return ret; @@ -195,7 +195,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Set UCC to slow type */ if ((ret = ucc_set_type(us_info->ucc_num, - (struct ucc_common *) us_regs, + (struct ucc_common *) (us_info->regs), UCC_SPEED_TYPE_SLOW))) { printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); ucc_slow_free(uccs); diff --git a/trunk/arch/powerpc/sysdev/timer.c b/trunk/arch/powerpc/sysdev/timer.c deleted file mode 100644 index 4a01748b4217..000000000000 --- a/trunk/arch/powerpc/sysdev/timer.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Common code to keep time when machine suspends. - * - * Copyright 2007 Johannes Berg - * - * GPLv2 - */ - -#include -#include -#include - -static unsigned long suspend_rtc_time; - -/* - * Reset the time after a sleep. - */ -static int timer_resume(struct sys_device *dev) -{ - struct timeval tv; - struct timespec ts; - struct rtc_time cur_rtc_tm; - unsigned long cur_rtc_time, diff; - - /* get current RTC time and convert to seconds */ - get_rtc_time(&cur_rtc_tm); - rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time); - - diff = cur_rtc_time - suspend_rtc_time; - - /* adjust time of day by seconds that elapsed while - * we were suspended */ - do_gettimeofday(&tv); - ts.tv_sec = tv.tv_sec + diff; - ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC; - do_settimeofday(&ts); - - return 0; -} - -static int timer_suspend(struct sys_device *dev, pm_message_t state) -{ - struct rtc_time suspend_rtc_tm; - WARN_ON(!ppc_md.get_rtc_time); - - get_rtc_time(&suspend_rtc_tm); - rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time); - - return 0; -} - -static struct sysdev_class timer_sysclass = { - .resume = timer_resume, - .suspend = timer_suspend, - set_kset_name("timer"), -}; - -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int time_init_device(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; -} - -device_initcall(time_init_device); diff --git a/trunk/arch/powerpc/sysdev/tsi108_dev.c b/trunk/arch/powerpc/sysdev/tsi108_dev.c index 337039ee51e6..97f37ef4bbbf 100644 --- a/trunk/arch/powerpc/sysdev/tsi108_dev.c +++ b/trunk/arch/powerpc/sysdev/tsi108_dev.c @@ -48,7 +48,7 @@ phys_addr_t get_csrbase(void) tsi = of_find_node_by_type(NULL, "tsi-bridge"); if (tsi) { unsigned int size; - const void *prop = of_get_property(tsi, "reg", &size); + const void *prop = get_property(tsi, "reg", &size); tsi108_csr_base = of_translate_address(tsi, prop); of_node_put(tsi); }; @@ -77,10 +77,10 @@ static int __init tsi108_eth_of_init(void) struct resource r[2]; struct device_node *phy; hw_info tsi_eth_data; - const unsigned int *id; - const unsigned int *phy_id; + unsigned int *id; + unsigned int *phy_id; const void *mac_addr; - const phandle *ph; + phandle *ph; memset(r, 0, sizeof(r)); memset(&tsi_eth_data, 0, sizeof(tsi_eth_data)); @@ -107,10 +107,10 @@ static int __init tsi108_eth_of_init(void) goto err; } - mac_addr = of_get_property(np, "address", NULL); + mac_addr = get_property(np, "address", NULL); memcpy(tsi_eth_data.mac_addr, mac_addr, 6); - ph = of_get_property(np, "phy-handle", NULL); + ph = (phandle *) get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); if (phy == NULL) { @@ -118,8 +118,8 @@ static int __init tsi108_eth_of_init(void) goto unreg; } - id = of_get_property(phy, "reg", NULL); - phy_id = of_get_property(phy, "phy-id", NULL); + id = (u32 *) get_property(phy, "reg", NULL); + phy_id = (u32 *) get_property(phy, "phy-id", NULL); ret = of_address_to_resource(phy, 0, &res); if (ret) { of_node_put(phy); diff --git a/trunk/arch/powerpc/sysdev/tsi108_pci.c b/trunk/arch/powerpc/sysdev/tsi108_pci.c index 58b9e7f8abf2..ae249c6bbbcf 100644 --- a/trunk/arch/powerpc/sysdev/tsi108_pci.c +++ b/trunk/arch/powerpc/sysdev/tsi108_pci.c @@ -211,7 +211,7 @@ int __init tsi108_setup_pci(struct device_node *dev) has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); /* Get bus range if any */ - bus_range = of_get_property(dev, "bus-range", &len); + bus_range = get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); diff --git a/trunk/arch/powerpc/sysdev/uic.c b/trunk/arch/powerpc/sysdev/uic.c deleted file mode 100644 index 968fb40af9dc..000000000000 --- a/trunk/arch/powerpc/sysdev/uic.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * arch/powerpc/sysdev/uic.c - * - * IBM PowerPC 4xx Universal Interrupt Controller - * - * Copyright 2007 David Gibson , IBM Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NR_UIC_INTS 32 - -#define UIC_SR 0x0 -#define UIC_ER 0x2 -#define UIC_CR 0x3 -#define UIC_PR 0x4 -#define UIC_TR 0x5 -#define UIC_MSR 0x6 -#define UIC_VR 0x7 -#define UIC_VCR 0x8 - -#define uic_irq_to_hw(virq) (irq_map[virq].hwirq) - -struct uic *primary_uic; - -struct uic { - int index; - int dcrbase; - - spinlock_t lock; - - /* The remapper for this UIC */ - struct irq_host *irqhost; - - /* For secondary UICs, the cascade interrupt's irqaction */ - struct irqaction cascade; - - /* The device node of the interrupt controller */ - struct device_node *of_node; -}; - -static void uic_unmask_irq(unsigned int virq) -{ - struct uic *uic = get_irq_chip_data(virq); - unsigned int src = uic_irq_to_hw(virq); - unsigned long flags; - u32 er; - - spin_lock_irqsave(&uic->lock, flags); - er = mfdcr(uic->dcrbase + UIC_ER); - er |= 1 << (31 - src); - mtdcr(uic->dcrbase + UIC_ER, er); - spin_unlock_irqrestore(&uic->lock, flags); -} - -static void uic_mask_irq(unsigned int virq) -{ - struct uic *uic = get_irq_chip_data(virq); - unsigned int src = uic_irq_to_hw(virq); - unsigned long flags; - u32 er; - - spin_lock_irqsave(&uic->lock, flags); - er = mfdcr(uic->dcrbase + UIC_ER); - er &= ~(1 << (31 - src)); - mtdcr(uic->dcrbase + UIC_ER, er); - spin_unlock_irqrestore(&uic->lock, flags); -} - -static void uic_ack_irq(unsigned int virq) -{ - struct uic *uic = get_irq_chip_data(virq); - unsigned int src = uic_irq_to_hw(virq); - unsigned long flags; - - spin_lock_irqsave(&uic->lock, flags); - mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src)); - spin_unlock_irqrestore(&uic->lock, flags); -} - -static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) -{ - struct uic *uic = get_irq_chip_data(virq); - unsigned int src = uic_irq_to_hw(virq); - struct irq_desc *desc = get_irq_desc(virq); - unsigned long flags; - int trigger, polarity; - u32 tr, pr, mask; - - switch (flow_type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_NONE: - uic_mask_irq(virq); - return 0; - - case IRQ_TYPE_EDGE_RISING: - trigger = 1; polarity = 1; - break; - case IRQ_TYPE_EDGE_FALLING: - trigger = 1; polarity = 0; - break; - case IRQ_TYPE_LEVEL_HIGH: - trigger = 0; polarity = 1; - break; - case IRQ_TYPE_LEVEL_LOW: - trigger = 0; polarity = 0; - break; - default: - return -EINVAL; - } - - mask = ~(1 << (31 - src)); - - spin_lock_irqsave(&uic->lock, flags); - tr = mfdcr(uic->dcrbase + UIC_TR); - pr = mfdcr(uic->dcrbase + UIC_PR); - tr = (tr & mask) | (trigger << (31-src)); - pr = (pr & mask) | (polarity << (31-src)); - - mtdcr(uic->dcrbase + UIC_PR, pr); - mtdcr(uic->dcrbase + UIC_TR, tr); - - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); - desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; - if (trigger) - desc->status |= IRQ_LEVEL; - - spin_unlock_irqrestore(&uic->lock, flags); - - return 0; -} - -static struct irq_chip uic_irq_chip = { - .typename = " UIC ", - .unmask = uic_unmask_irq, - .mask = uic_mask_irq, -/* .mask_ack = uic_mask_irq_and_ack, */ - .ack = uic_ack_irq, - .set_type = uic_set_irq_type, -}; - -static int uic_host_match(struct irq_host *h, struct device_node *node) -{ - struct uic *uic = h->host_data; - return uic->of_node == node; -} - -static int uic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct uic *uic = h->host_data; - - set_irq_chip_data(virq, uic); - /* Despite the name, handle_level_irq() works for both level - * and edge irqs on UIC. FIXME: check this is correct */ - set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq); - - /* Set default irq type */ - set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static int uic_host_xlate(struct irq_host *h, struct device_node *ct, - u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ - /* UIC intspecs must have 2 cells */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - -static struct irq_host_ops uic_host_ops = { - .match = uic_host_match, - .map = uic_host_map, - .xlate = uic_host_xlate, -}; - -irqreturn_t uic_cascade(int virq, void *data) -{ - struct uic *uic = data; - u32 msr; - int src; - int subvirq; - - msr = mfdcr(uic->dcrbase + UIC_MSR); - src = 32 - ffs(msr); - - subvirq = irq_linear_revmap(uic->irqhost, src); - generic_handle_irq(subvirq); - - return IRQ_HANDLED; -} - -static struct uic * __init uic_init_one(struct device_node *node) -{ - struct uic *uic; - const u32 *indexp, *dcrreg; - int len; - - BUG_ON(! device_is_compatible(node, "ibm,uic")); - - uic = alloc_bootmem(sizeof(*uic)); - if (! uic) - return NULL; /* FIXME: panic? */ - - memset(uic, 0, sizeof(*uic)); - spin_lock_init(&uic->lock); - uic->of_node = of_node_get(node); - indexp = of_get_property(node, "cell-index", &len); - if (!indexp || (len != sizeof(u32))) { - printk(KERN_ERR "uic: Device node %s has missing or invalid " - "cell-index property\n", node->full_name); - return NULL; - } - uic->index = *indexp; - - dcrreg = of_get_property(node, "dcr-reg", &len); - if (!dcrreg || (len != 2*sizeof(u32))) { - printk(KERN_ERR "uic: Device node %s has missing or invalid " - "dcr-reg property\n", node->full_name); - return NULL; - } - uic->dcrbase = *dcrreg; - - uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS, - &uic_host_ops, -1); - if (! uic->irqhost) { - of_node_put(node); - return NULL; /* FIXME: panic? */ - } - - uic->irqhost->host_data = uic; - - /* Start with all interrupts disabled, level and non-critical */ - mtdcr(uic->dcrbase + UIC_ER, 0); - mtdcr(uic->dcrbase + UIC_CR, 0); - mtdcr(uic->dcrbase + UIC_TR, 0); - /* Clear any pending interrupts, in case the firmware left some */ - mtdcr(uic->dcrbase + UIC_SR, 0xffffffff); - - printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index, - NR_UIC_INTS, uic->dcrbase); - - return uic; -} - -void __init uic_init_tree(void) -{ - struct device_node *np; - struct uic *uic; - const u32 *interrupts; - - /* First locate and initialize the top-level UIC */ - - np = of_find_compatible_node(NULL, NULL, "ibm,uic"); - while (np) { - interrupts = of_get_property(np, "interrupts", NULL); - if (! interrupts) - break; - - np = of_find_compatible_node(np, NULL, "ibm,uic"); - } - - BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the - * top-level interrupt controller */ - primary_uic = uic_init_one(np); - if (! primary_uic) - panic("Unable to initialize primary UIC %s\n", np->full_name); - - irq_set_default_host(primary_uic->irqhost); - of_node_put(np); - - /* The scan again for cascaded UICs */ - np = of_find_compatible_node(NULL, NULL, "ibm,uic"); - while (np) { - interrupts = of_get_property(np, "interrupts", NULL); - if (interrupts) { - /* Secondary UIC */ - int cascade_virq; - int ret; - - uic = uic_init_one(np); - if (! uic) - panic("Unable to initialize a secondary UIC %s\n", - np->full_name); - - cascade_virq = irq_of_parse_and_map(np, 0); - - uic->cascade.handler = uic_cascade; - uic->cascade.name = "UIC cascade"; - uic->cascade.dev_id = uic; - - ret = setup_irq(cascade_virq, &uic->cascade); - if (ret) - printk(KERN_ERR "Failed to setup_irq(%d) for " - "UIC%d cascade\n", cascade_virq, - uic->index); - - /* FIXME: setup critical cascade?? */ - } - - np = of_find_compatible_node(np, NULL, "ibm,uic"); - } -} - -/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ -unsigned int uic_get_irq(void) -{ - u32 msr; - int src; - - BUG_ON(! primary_uic); - - msr = mfdcr(primary_uic->dcrbase + UIC_MSR); - src = 32 - ffs(msr); - - return irq_linear_revmap(primary_uic->irqhost, src); -} diff --git a/trunk/arch/powerpc/xmon/xmon.c b/trunk/arch/powerpc/xmon/xmon.c index b481db1dacb4..bf299b66f3fc 100644 --- a/trunk/arch/powerpc/xmon/xmon.c +++ b/trunk/arch/powerpc/xmon/xmon.c @@ -330,17 +330,18 @@ static void release_output_lock(void) static int xmon_core(struct pt_regs *regs, int fromipi) { int cmd = 0; + unsigned long msr; struct bpt *bp; long recurse_jmp[JMP_BUF_LEN]; unsigned long offset; - unsigned long flags; #ifdef CONFIG_SMP int cpu; int secondary; unsigned long timeout; #endif - local_irq_save(flags); + msr = mfmsr(); + mtmsr(msr & ~MSR_EE); /* disable interrupts */ bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { @@ -515,7 +516,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) insert_cpu_bpts(); - local_irq_restore(flags); + mtmsr(msr); /* restore interrupt enable */ return cmd != 'X' && cmd != EOF; } @@ -1359,12 +1360,8 @@ static void print_bug_trap(struct pt_regs *regs) if (is_warning_bug(bug)) return; -#ifdef CONFIG_DEBUG_BUGVERBOSE printf("kernel BUG at %s:%u!\n", bug->file, bug->line); -#else - printf("kernel BUG at %p!\n", (void *)bug->bug_addr); -#endif } void excprint(struct pt_regs *fp) diff --git a/trunk/arch/ppc/8260_io/enet.c b/trunk/arch/ppc/8260_io/enet.c index 4c0a7d732f69..a6056c29cf00 100644 --- a/trunk/arch/ppc/8260_io/enet.c +++ b/trunk/arch/ppc/8260_io/enet.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -476,6 +477,7 @@ for (;;) { cep->stats.rx_dropped++; } else { + skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), diff --git a/trunk/arch/ppc/8260_io/fcc_enet.c b/trunk/arch/ppc/8260_io/fcc_enet.c index cab395da25da..06b84c372e58 100644 --- a/trunk/arch/ppc/8260_io/fcc_enet.c +++ b/trunk/arch/ppc/8260_io/fcc_enet.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -733,6 +734,7 @@ for (;;) { cep->stats.rx_dropped++; } else { + skb->dev = dev; skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), diff --git a/trunk/arch/ppc/8xx_io/Kconfig b/trunk/arch/ppc/8xx_io/Kconfig index c623e44f01ad..57dacf978532 100644 --- a/trunk/arch/ppc/8xx_io/Kconfig +++ b/trunk/arch/ppc/8xx_io/Kconfig @@ -74,6 +74,10 @@ config ENET_BIG_BUFFERS Allocate large buffers for MPC8xx Ethernet. Increases throughput and decreases the likelihood of dropped packets, but costs memory. +config HTDMSOUND + bool "Embedded Planet HIOX Audio" + depends on SOUND=y + # This doesn't really belong here, but it is convenient to ask # 8xx specific questions. comment "Generic MPC8xx Options" diff --git a/trunk/arch/ppc/8xx_io/Makefile b/trunk/arch/ppc/8xx_io/Makefile index 1051a06df7e0..d8760181fe99 100644 --- a/trunk/arch/ppc/8xx_io/Makefile +++ b/trunk/arch/ppc/8xx_io/Makefile @@ -7,3 +7,4 @@ obj-y := commproc.o obj-$(CONFIG_FEC_ENET) += fec.o obj-$(CONFIG_SCC_ENET) += enet.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o +obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o diff --git a/trunk/arch/ppc/8xx_io/cs4218.h b/trunk/arch/ppc/8xx_io/cs4218.h new file mode 100644 index 000000000000..e5f943045afa --- /dev/null +++ b/trunk/arch/ppc/8xx_io/cs4218.h @@ -0,0 +1,166 @@ +#ifndef _cs4218_h_ +/* + * Hacked version of linux/drivers/sound/dmasound/dmasound.h + * + * + * Minor numbers for the sound driver. + * + * Unfortunately Creative called the codec chip of SB as a DSP. For this + * reason the /dev/dsp is reserved for digitized audio use. There is a + * device for true DSP processors but it will be called something else. + * In v3.0 it's /dev/sndproc but this could be a temporary solution. + */ +#define _cs4218_h_ + +#include + +#define SND_NDEVS 256 /* Number of supported devices */ +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +#define SND_DEV_STATUS 6 /* /dev/sndstat */ +/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ +#define SND_DEV_PSS SND_DEV_SNDPROC + +/* switch on various prinks */ +#define DEBUG_DMASOUND 1 + +#define MAX_AUDIO_DEV 5 +#define MAX_MIXER_DEV 4 +#define MAX_SYNTH_DEV 3 +#define MAX_MIDI_DEV 6 +#define MAX_TIMER_DEV 3 + +#define MAX_CATCH_RADIUS 10 + +#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) +#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) + +#define IOCTL_IN(arg, ret) \ + do { int error = get_user(ret, (int *)(arg)); \ + if (error) return error; \ + } while (0) +#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) + +static inline int ioctl_return(int *addr, int value) +{ + return value < 0 ? value : put_user(value, addr); +} + +#define HAS_RECORD + + /* + * Initialization + */ + +/* description of the set-up applies to either hard or soft settings */ + +typedef struct { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ +} SETTINGS; + + /* + * Machine definitions + */ + +typedef struct { + const char *name; + const char *name2; + void (*open)(void); + void (*release)(void); + void *(*dma_alloc)(unsigned int, gfp_t); + void (*dma_free)(void *, unsigned int); + int (*irqinit)(void); +#ifdef MODULE + void (*irqcleanup)(void); +#endif + void (*init)(void); + void (*silence)(void); + int (*setFormat)(int); + int (*setVolume)(int); + int (*setBass)(int); + int (*setTreble)(int); + int (*setGain)(int); + void (*play)(void); + void (*record)(void); /* optional */ + void (*mixer_init)(void); /* optional */ + int (*mixer_ioctl)(u_int, u_long); /* optional */ + int (*write_sq_setup)(void); /* optional */ + int (*read_sq_setup)(void); /* optional */ + int (*sq_open)(mode_t); /* optional */ + int (*state_info)(char *, size_t); /* optional */ + void (*abort_read)(void); /* optional */ + int min_dsp_speed; + int max_dsp_speed; + int version ; + int hardware_afmts ; /* OSS says we only return h'ware info */ + /* when queried via SNDCTL_DSP_GETFMTS */ + int capabilities ; /* low-level reply to SNDCTL_DSP_GETCAPS */ + SETTINGS default_hard ; /* open() or init() should set something valid */ + SETTINGS default_soft ; /* you can make it look like old OSS, if you want to */ +} MACHINE; + + /* + * Low level stuff + */ + +typedef struct { + ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); + ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +} TRANS; + + + /* + * Sound queue stuff, the heart of the driver + */ + +struct sound_queue { + /* buffers allocated for this queue */ + int numBufs; /* real limits on what the user can have */ + int bufSize; /* in bytes */ + char **buffers; + + /* current parameters */ + int locked ; /* params cannot be modified when != 0 */ + int user_frags ; /* user requests this many */ + int user_frag_size ; /* of this size */ + int max_count; /* actual # fragments <= numBufs */ + int block_size; /* internal block size in bytes */ + int max_active; /* in-use fragments <= max_count */ + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari, PMac: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int active; + wait_queue_head_t action_queue, open_queue, sync_queue; + int open_mode; + int busy, syncing, xruns, died; +}; + +#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ) +#define WAKE_UP(queue) (wake_up_interruptible(&queue)) + +#endif /* _cs4218_h_ */ diff --git a/trunk/arch/ppc/8xx_io/cs4218_tdm.c b/trunk/arch/ppc/8xx_io/cs4218_tdm.c new file mode 100644 index 000000000000..a956f28ab162 --- /dev/null +++ b/trunk/arch/ppc/8xx_io/cs4218_tdm.c @@ -0,0 +1,2833 @@ + +/* This is a modified version of linux/drivers/sound/dmasound.c to + * support the CS4218 codec on the 8xx TDM port. Thanks to everyone + * that contributed to the dmasound software (which includes me :-). + * + * The CS4218 is configured in Mode 4, sub-mode 0. This provides + * left/right data only on the TDM port, as a 32-bit word, per frame + * pulse. The control of the CS4218 is provided by some other means, + * like the SPI port. + * Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Should probably do something different with this path name..... + * Actually, I should just stop using it... + */ +#include "cs4218.h" +#include + +#include +#include +#include + +#define DMASND_CS4218 5 + +#define MAX_CATCH_RADIUS 10 +#define MIN_BUFFERS 4 +#define MIN_BUFSIZE 4 +#define MAX_BUFSIZE 128 + +#define HAS_8BIT_TABLES + +static int sq_unit = -1; +static int mixer_unit = -1; +static int state_unit = -1; +static int irq_installed = 0; +static char **sound_buffers = NULL; +static char **sound_read_buffers = NULL; + +static DEFINE_SPINLOCK(cs4218_lock); + +/* Local copies of things we put in the control register. Output + * volume, like most codecs is really attenuation. + */ +static int cs4218_rate_index; + +/* + * Stuff for outputting a beep. The values range from -327 to +327 + * so we can multiply by an amplitude in the range 0..100 to get a + * signed short value to put in the output buffer. + */ +static short beep_wform[256] = { + 0, 40, 79, 117, 153, 187, 218, 245, + 269, 288, 304, 316, 323, 327, 327, 324, + 318, 310, 299, 288, 275, 262, 249, 236, + 224, 213, 204, 196, 190, 186, 183, 182, + 182, 183, 186, 189, 192, 196, 200, 203, + 206, 208, 209, 209, 209, 207, 204, 201, + 197, 193, 188, 183, 179, 174, 170, 166, + 163, 161, 160, 159, 159, 160, 161, 162, + 164, 166, 168, 169, 171, 171, 171, 170, + 169, 167, 163, 159, 155, 150, 144, 139, + 133, 128, 122, 117, 113, 110, 107, 105, + 103, 103, 103, 103, 104, 104, 105, 105, + 105, 103, 101, 97, 92, 86, 78, 68, + 58, 45, 32, 18, 3, -11, -26, -41, + -55, -68, -79, -88, -95, -100, -102, -102, + -99, -93, -85, -75, -62, -48, -33, -16, + 0, 16, 33, 48, 62, 75, 85, 93, + 99, 102, 102, 100, 95, 88, 79, 68, + 55, 41, 26, 11, -3, -18, -32, -45, + -58, -68, -78, -86, -92, -97, -101, -103, + -105, -105, -105, -104, -104, -103, -103, -103, + -103, -105, -107, -110, -113, -117, -122, -128, + -133, -139, -144, -150, -155, -159, -163, -167, + -169, -170, -171, -171, -171, -169, -168, -166, + -164, -162, -161, -160, -159, -159, -160, -161, + -163, -166, -170, -174, -179, -183, -188, -193, + -197, -201, -204, -207, -209, -209, -209, -208, + -206, -203, -200, -196, -192, -189, -186, -183, + -182, -182, -183, -186, -190, -196, -204, -213, + -224, -236, -249, -262, -275, -288, -299, -310, + -318, -324, -327, -327, -323, -316, -304, -288, + -269, -245, -218, -187, -153, -117, -79, -40, +}; + +#define BEEP_SPEED 5 /* 22050 Hz sample rate */ +#define BEEP_BUFLEN 512 +#define BEEP_VOLUME 15 /* 0 - 100 */ + +static int beep_volume = BEEP_VOLUME; +static int beep_playing = 0; +static int beep_state = 0; +static short *beep_buf; +static void (*orig_mksound)(unsigned int, unsigned int); + +/* This is found someplace else......I guess in the keyboard driver + * we don't include. + */ +static void (*kd_mksound)(unsigned int, unsigned int); + +static int catchRadius = 0; +static int numBufs = 4, bufSize = 32; +static int numReadBufs = 4, readbufSize = 32; + + +/* TDM/Serial transmit and receive buffer descriptors. +*/ +static volatile cbd_t *rx_base, *rx_cur, *tx_base, *tx_cur; + +module_param(catchRadius, int, 0); +module_param(numBufs, int, 0); +module_param(bufSize, int, 0); +module_param(numreadBufs, int, 0); +module_param(readbufSize, int, 0); + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) +#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) + +#define IOCTL_IN(arg, ret) \ + do { int error = get_user(ret, (int *)(arg)); \ + if (error) return error; \ + } while (0) +#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) + +/* CS4218 serial port control in mode 4. +*/ +#define CS_INTMASK ((uint)0x40000000) +#define CS_DO1 ((uint)0x20000000) +#define CS_LATTEN ((uint)0x1f000000) +#define CS_RATTEN ((uint)0x00f80000) +#define CS_MUTE ((uint)0x00040000) +#define CS_ISL ((uint)0x00020000) +#define CS_ISR ((uint)0x00010000) +#define CS_LGAIN ((uint)0x0000f000) +#define CS_RGAIN ((uint)0x00000f00) + +#define CS_LATTEN_SET(X) (((X) & 0x1f) << 24) +#define CS_RATTEN_SET(X) (((X) & 0x1f) << 19) +#define CS_LGAIN_SET(X) (((X) & 0x0f) << 12) +#define CS_RGAIN_SET(X) (((X) & 0x0f) << 8) + +#define CS_LATTEN_GET(X) (((X) >> 24) & 0x1f) +#define CS_RATTEN_GET(X) (((X) >> 19) & 0x1f) +#define CS_LGAIN_GET(X) (((X) >> 12) & 0x0f) +#define CS_RGAIN_GET(X) (((X) >> 8) & 0x0f) + +/* The control register is effectively write only. We have to keep a copy + * of what we write. + */ +static uint cs4218_control; + +/* A place to store expanding information. +*/ +static int expand_bal; +static int expand_data; + +/* Since I can't make the microcode patch work for the SPI, I just + * clock the bits using software. + */ +static void sw_spi_init(void); +static void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt); +static uint cs4218_ctl_write(uint ctlreg); + +/*** Some low level helpers **************************************************/ + +/* 16 bit mu-law */ + +static short ulaw2dma16[] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, +}; + +/* 16 bit A-law */ + +static short alaw2dma16[] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, +}; + + +/*** Translations ************************************************************/ + + +static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); + + +/*** Low level stuff *********************************************************/ + +struct cs_sound_settings { + MACHINE mach; /* machine dependent things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans_write; /* supported translations for playback */ + TRANS *trans_read; /* supported translations for record */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int gain; + int minDev; /* minor device number currently open */ +}; + +static struct cs_sound_settings sound; + +static void *CS_Alloc(unsigned int size, gfp_t flags); +static void CS_Free(void *ptr, unsigned int size); +static int CS_IrqInit(void); +#ifdef MODULE +static void CS_IrqCleanup(void); +#endif /* MODULE */ +static void CS_Silence(void); +static void CS_Init(void); +static void CS_Play(void); +static void CS_Record(void); +static int CS_SetFormat(int format); +static int CS_SetVolume(int volume); +static void cs4218_tdm_tx_intr(void *devid); +static void cs4218_tdm_rx_intr(void *devid); +static void cs4218_intr(void *devid); +static int cs_get_volume(uint reg); +static int cs_volume_setter(int volume, int mute); +static int cs_get_gain(uint reg); +static int cs_set_gain(int gain); +static void cs_mksound(unsigned int hz, unsigned int ticks); +static void cs_nosound(unsigned long xx); + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); + +static ssize_t sound_copy_translate(const u_char *userPtr, + size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t sound_copy_translate_read(const u_char *userPtr, + size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); + + +/* + * /dev/mixer abstraction + */ + +struct sound_mixer { + int busy; + int modify_counter; +}; + +static struct sound_mixer mixer; + +static struct sound_queue sq; +static struct sound_queue read_sq; + +#define sq_block_address(i) (sq.buffers[i]) +#define SIGNAL_RECEIVED (signal_pending(current)) +#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK) +#define ONE_SECOND HZ /* in jiffies (100ths of a second) */ +#define NO_TIME_LIMIT 0xffffffff + +/* + * /dev/sndstat + */ + +struct sound_state { + int busy; + char buf[512]; + int len, ptr; +}; + +static struct sound_state state; + +/*** Common stuff ********************************************************/ + +static long long sound_lseek(struct file *file, long long offset, int orig); + +/*** Config & Setup **********************************************************/ + +void dmasound_setup(char *str, int *ints); + +/*** Translations ************************************************************/ + + +/* ++TeSche: radically changed for new expanding purposes... + * + * These two routines now deal with copying/expanding/translating the samples + * from user space into our buffer at the right frequency. They take care about + * how much data there's actually to read, how much buffer space there is and + * to convert samples into the right frequency/encoding. They will only work on + * complete samples so it may happen they leave some bytes in the input stream + * if the user didn't write a multiple of the current sample size. They both + * return the number of bytes they've used from both streams so you may detect + * such a situation. Luckily all programs should be able to cope with that. + * + * I think I've optimized anything as far as one can do in plain C, all + * variables should fit in registers and the loops are really short. There's + * one loop for every possible situation. Writing a more generalized and thus + * parameterized loop would only produce slower code. Feel free to optimize + * this in assembler if you like. :) + * + * I think these routines belong here because they're not yet really hardware + * independent, especially the fact that the Falcon can play 16bit samples + * only in stereo is hardcoded in both of them! + * + * ++geert: split in even more functions (one per format) + */ + +static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16; + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min(userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = table[data]; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = table[data]; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min(userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = data << 8; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = data << 8; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min(userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = (data ^ 0x80) << 8; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = (data ^ 0x80) << 8; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +/* This is the default format of the codec. Signed, 16-bit stereo + * generated by an application shouldn't have to be copied at all. + * We should just get the phsical address of the buffers and update + * the TDM BDs directly. + */ +static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int stereo = sound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min(userCount, frameLeft); + if (!stereo) { + short *up = (short *) userPtr; + while (count > 0) { + short data; + if (get_user(data, up++)) + return -EFAULT; + *fp++ = data; + *fp++ = data; + count--; + } + } else { + if (copy_from_user(fp, userPtr, count * 4)) + return -EFAULT; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + int stereo = sound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + short *up = (short *) userPtr; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min(userCount, frameLeft); + while (count > 0) { + int data; + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + *fp++ = data; + if (stereo) { + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + } + *fp++ = data; + count--; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + + +static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned short *table = (unsigned short *) + (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16); + unsigned int data = expand_data; + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + int bal = expand_bal; + int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + int utotal, ftotal; + int stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = table[c]; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + table[c]; + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + + +static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + int stereo = sound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = c << 8; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + (c << 8); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + + +static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + int stereo = sound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = (c ^ 0x80) << 8; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + ((c ^ 0x80) << 8); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + + +static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + unsigned short *up = (unsigned short *) userPtr; + int bal = expand_bal; + int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + int stereo = sound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + unsigned short c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(data, up++)) + return -EFAULT; + if (stereo) { + if (get_user(c, up++)) + return -EFAULT; + data = (data << 16) + c; + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 4: utotal * 2; +} + + +static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + unsigned short *up = (unsigned short *) userPtr; + int bal = expand_bal; + int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + int stereo = sound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + unsigned short c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + if (stereo) { + if (get_user(c, up++)) + return -EFAULT; + data = (data << 16) + (c ^ mask); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 4: utotal * 2; +} + +static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min(userCount, frameLeft); + while (count > 0) { + u_char data; + + val = *p++; + data = val >> 8; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + if (stereo) { + val = *p; + data = val >> 8; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + } + p++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = sound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min(userCount, frameLeft); + while (count > 0) { + u_char data; + + val = *p++; + data = (val >> 8) ^ 0x80; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + if (stereo) { + val = *p; + data = (val >> 8) ^ 0x80; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + } + p++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int stereo = sound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min(userCount, frameLeft); + if (!stereo) { + short *up = (short *) userPtr; + while (count > 0) { + short data; + data = *fp; + if (put_user(data, up++)) + return -EFAULT; + fp+=2; + count--; + } + } else { + if (copy_to_user((u_char *)userPtr, fp, count * 4)) + return -EFAULT; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + int stereo = sound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + short *up = (short *) userPtr; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min(userCount, frameLeft); + while (count > 0) { + int data; + + data = *fp++; + data ^= mask; + if (put_user(data, up++)) + return -EFAULT; + if (stereo) { + data = *fp; + data ^= mask; + if (put_user(data, up++)) + return -EFAULT; + } + fp++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +static TRANS transCSNormal = { + cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8, + cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16 +}; + +static TRANS transCSExpand = { + cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8, + cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16 +}; + +static TRANS transCSNormalRead = { + NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read, + cs4218_ct_s16_read, cs4218_ct_u16_read, + cs4218_ct_s16_read, cs4218_ct_u16_read +}; + +/*** Low level stuff *********************************************************/ + +static void *CS_Alloc(unsigned int size, gfp_t flags) +{ + int order; + + size >>= 13; + for (order=0; order < 5; order++) { + if (size == 0) + break; + size >>= 1; + } + return (void *)__get_free_pages(flags, order); +} + +static void CS_Free(void *ptr, unsigned int size) +{ + int order; + + size >>= 13; + for (order=0; order < 5; order++) { + if (size == 0) + break; + size >>= 1; + } + free_pages((ulong)ptr, order); +} + +static int __init CS_IrqInit(void) +{ + cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL); + return 1; +} + +#ifdef MODULE +static void CS_IrqCleanup(void) +{ + volatile smc_t *sp; + volatile cpm8xx_t *cp; + + /* First disable transmitter and receiver. + */ + sp = &cpmp->cp_smc[1]; + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* And now shut down the SMC. + */ + cp = cpmp; /* Get pointer to Communication Processor */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Release the interrupt handler. + */ + cpm_free_handler(CPMVEC_SMC2); + + kfree(beep_buf); + kd_mksound = orig_mksound; +} +#endif /* MODULE */ + +static void CS_Silence(void) +{ + volatile smc_t *sp; + + /* Disable transmitter. + */ + sp = &cpmp->cp_smc[1]; + sp->smc_smcmr &= ~SMCMR_TEN; +} + +/* Frequencies depend upon external oscillator. There are two + * choices, 12.288 and 11.2896 MHz. The RPCG audio supports both through + * and external control register selection bit. + */ +static int cs4218_freqs[] = { + /* 12.288 11.2896 */ + 48000, 44100, + 32000, 29400, + 24000, 22050, + 19200, 17640, + 16000, 14700, + 12000, 11025, + 9600, 8820, + 8000, 7350 +}; + +static void CS_Init(void) +{ + int i, tolerance; + + switch (sound.soft.format) { + case AFMT_S16_LE: + case AFMT_U16_LE: + sound.hard.format = AFMT_S16_LE; + break; + default: + sound.hard.format = AFMT_S16_BE; + break; + } + sound.hard.stereo = 1; + sound.hard.size = 16; + + /* + * If we have a sample rate which is within catchRadius percent + * of the requested value, we don't have to expand the samples. + * Otherwise choose the next higher rate. + */ + i = (sizeof(cs4218_freqs) / sizeof(int)); + do { + tolerance = catchRadius * cs4218_freqs[--i] / 100; + } while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0); + if (sound.soft.speed >= cs4218_freqs[i] - tolerance) + sound.trans_write = &transCSNormal; + else + sound.trans_write = &transCSExpand; + sound.trans_read = &transCSNormalRead; + sound.hard.speed = cs4218_freqs[i]; + cs4218_rate_index = i; + + /* The CS4218 has seven selectable clock dividers for the sample + * clock. The HIOX then provides one of two external rates. + * An even numbered frequency table index uses the high external + * clock rate. + */ + *(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL); + if ((i & 1) == 0) + *(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI; + i >>= 1; + *(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL); + + expand_bal = -sound.soft.speed; +} + +static int CS_SetFormat(int format) +{ + int size; + + switch (format) { + case AFMT_QUERY: + return sound.soft.format; + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", + format); + size = 8; + format = AFMT_U8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = size; + } + + CS_Init(); + + return format; +} + +/* Volume is the amount of attenuation we tell the codec to impose + * on the outputs. There are 32 levels, with 0 the "loudest". + */ +#define CS_VOLUME_TO_MASK(x) (31 - ((((x) - 1) * 31) / 99)) +#define CS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 31)) + +static int cs_get_volume(uint reg) +{ + int volume; + + volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg)); + volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8; + return volume; +} + +static int cs_volume_setter(int volume, int mute) +{ + uint tempctl; + + if (mute && volume == 0) { + tempctl = cs4218_control | CS_MUTE; + } else { + tempctl = cs4218_control & ~CS_MUTE; + tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN); + tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff)); + tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff)); + volume = cs_get_volume(tempctl); + } + if (tempctl != cs4218_control) { + cs4218_ctl_write(tempctl); + } + return volume; +} + + +/* Gain has 16 steps from 0 to 15. These are in 1.5dB increments from + * 0 (no gain) to 22.5 dB. + */ +#define CS_RECLEVEL_TO_GAIN(v) \ + ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) +#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3) + +static int cs_get_gain(uint reg) +{ + int gain; + + gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg)); + gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8; + return gain; +} + +static int cs_set_gain(int gain) +{ + uint tempctl; + + tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN); + tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff)); + tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff)); + gain = cs_get_gain(tempctl); + + if (tempctl != cs4218_control) { + cs4218_ctl_write(tempctl); + } + return gain; +} + +static int CS_SetVolume(int volume) +{ + return cs_volume_setter(volume, CS_MUTE); +} + +static void CS_Play(void) +{ + int i, count; + unsigned long flags; + volatile cbd_t *bdp; + volatile cpm8xx_t *cp; + + /* Protect buffer */ + spin_lock_irqsave(&cs4218_lock, flags); +#if 0 + if (awacs_beep_state) { + /* sound takes precedence over beeps */ + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + out_le32(&awacs->control, + (in_le32(&awacs->control) & ~0x1f00) + | (awacs_rate_index << 8)); + out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); + out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count]))); + + beep_playing = 0; + awacs_beep_state = 0; + } +#endif + i = sq.front + sq.active; + if (i >= sq.max_count) + i -= sq.max_count; + while (sq.active < 2 && sq.active < sq.count) { + count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size; + if (count < sq.block_size && !sq.syncing) + /* last block not yet filled, and we're not syncing. */ + break; + + bdp = &tx_base[i]; + bdp->cbd_datlen = count; + + flush_dcache_range((ulong)sound_buffers[i], + (ulong)(sound_buffers[i] + count)); + + if (++i >= sq.max_count) + i = 0; + + if (sq.active == 0) { + /* The SMC does not load its fifo until the first + * TDM frame pulse, so the transmit data gets shifted + * by one word. To compensate for this, we incorrectly + * transmit the first buffer and shorten it by one + * word. Subsequent buffers are then aligned properly. + */ + bdp->cbd_datlen -= 2; + + /* Start up the SMC Transmitter. + */ + cp = cpmp; + cp->cp_smc[1].smc_smcmr |= SMCMR_TEN; + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, + CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + + /* Buffer is ready now. + */ + bdp->cbd_sc |= BD_SC_READY; + + ++sq.active; + } + spin_unlock_irqrestore(&cs4218_lock, flags); +} + + +static void CS_Record(void) +{ + unsigned long flags; + volatile smc_t *sp; + + if (read_sq.active) + return; + + /* Protect buffer */ + spin_lock_irqsave(&cs4218_lock, flags); + + /* This is all we have to do......Just start it up. + */ + sp = &cpmp->cp_smc[1]; + sp->smc_smcmr |= SMCMR_REN; + + read_sq.active = 1; + + spin_unlock_irqrestore(&cs4218_lock, flags); +} + + +static void +cs4218_tdm_tx_intr(void *devid) +{ + int i = sq.front; + volatile cbd_t *bdp; + + while (sq.active > 0) { + bdp = &tx_base[i]; + if (bdp->cbd_sc & BD_SC_READY) + break; /* this frame is still going */ + --sq.count; + --sq.active; + if (++i >= sq.max_count) + i = 0; + } + if (i != sq.front) + WAKE_UP(sq.action_queue); + sq.front = i; + + CS_Play(); + + if (!sq.active) + WAKE_UP(sq.sync_queue); +} + + +static void +cs4218_tdm_rx_intr(void *devid) +{ + + /* We want to blow 'em off when shutting down. + */ + if (read_sq.active == 0) + return; + + /* Check multiple buffers in case we were held off from + * interrupt processing for a long time. Geeze, I really hope + * this doesn't happen. + */ + while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) { + + /* Invalidate the data cache range for this buffer. + */ + invalidate_dcache_range( + (uint)(sound_read_buffers[read_sq.rear]), + (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size)); + + /* Make buffer available again and move on. + */ + rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY; + read_sq.rear++; + + /* Wrap the buffer ring. + */ + if (read_sq.rear >= read_sq.max_active) + read_sq.rear = 0; + + /* If we have caught up to the front buffer, bump it. + * This will cause weird (but not fatal) results if the + * read loop is currently using this buffer. The user is + * behind in this case anyway, so weird things are going + * to happen. + */ + if (read_sq.rear == read_sq.front) { + read_sq.front++; + if (read_sq.front >= read_sq.max_active) + read_sq.front = 0; + } + } + + WAKE_UP(read_sq.action_queue); +} + +static void cs_nosound(unsigned long xx) +{ + unsigned long flags; + + /* not sure if this is needed, since hardware command is #if 0'd */ + spin_lock_irqsave(&cs4218_lock, flags); + if (beep_playing) { +#if 0 + st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); +#endif + beep_playing = 0; + } + spin_unlock_irqrestore(&cs4218_lock, flags); +} + +static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0); + +static void cs_mksound(unsigned int hz, unsigned int ticks) +{ + unsigned long flags; + int beep_speed = BEEP_SPEED; + int srate = cs4218_freqs[beep_speed]; + int period, ncycles, nsamples; + int i, j, f; + short *p; + static int beep_hz_cache; + static int beep_nsamples_cache; + static int beep_volume_cache; + + if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { +#if 1 + /* this is a hack for broken X server code */ + hz = 750; + ticks = 12; +#else + /* cancel beep currently playing */ + awacs_nosound(0); + return; +#endif + } + /* lock while modifying beep_timer */ + spin_lock_irqsave(&cs4218_lock, flags); + del_timer(&beep_timer); + if (ticks) { + beep_timer.expires = jiffies + ticks; + add_timer(&beep_timer); + } + if (beep_playing || sq.active || beep_buf == NULL) { + spin_unlock_irqrestore(&cs4218_lock, flags); + return; /* too hard, sorry :-( */ + } + beep_playing = 1; +#if 0 + st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); +#endif + spin_unlock_irqrestore(&cs4218_lock, flags); + + if (hz == beep_hz_cache && beep_volume == beep_volume_cache) { + nsamples = beep_nsamples_cache; + } else { + period = srate * 256 / hz; /* fixed point */ + ncycles = BEEP_BUFLEN * 256 / period; + nsamples = (period * ncycles) >> 8; + f = ncycles * 65536 / nsamples; + j = 0; + p = beep_buf; + for (i = 0; i < nsamples; ++i, p += 2) { + p[0] = p[1] = beep_wform[j >> 8] * beep_volume; + j = (j + f) & 0xffff; + } + beep_hz_cache = hz; + beep_volume_cache = beep_volume; + beep_nsamples_cache = nsamples; + } + +#if 0 + st_le16(&beep_dbdma_cmd->req_count, nsamples*4); + st_le16(&beep_dbdma_cmd->xfer_status, 0); + st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd)); + st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf)); + awacs_beep_state = 1; + + spin_lock_irqsave(&cs4218_lock, flags); + if (beep_playing) { /* i.e. haven't been terminated already */ + out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); + out_le32(&awacs->control, + (in_le32(&awacs->control) & ~0x1f00) + | (beep_speed << 8)); + out_le32(&awacs->byteswap, 0); + out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + out_le32(&awacs_txdma->control, RUN | (RUN << 16)); + } + spin_unlock_irqrestore(&cs4218_lock, flags); +#endif +} + +static MACHINE mach_cs4218 = { + .owner = THIS_MODULE, + .name = "HIOX CS4218", + .name2 = "Built-in Sound", + .dma_alloc = CS_Alloc, + .dma_free = CS_Free, + .irqinit = CS_IrqInit, +#ifdef MODULE + .irqcleanup = CS_IrqCleanup, +#endif /* MODULE */ + .init = CS_Init, + .silence = CS_Silence, + .setFormat = CS_SetFormat, + .setVolume = CS_SetVolume, + .play = CS_Play +}; + + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void) +{ + /* update hardware settings one more */ + (*sound.mach.init)(); + + (*sound.mach.silence)(); +} + + +static void sound_init(void) +{ + (*sound.mach.init)(); +} + + +static int sound_set_format(int format) +{ + return(*sound.mach.setFormat)(format); +} + + +static int sound_set_speed(int speed) +{ + if (speed < 0) + return(sound.soft.speed); + + sound.soft.speed = speed; + (*sound.mach.init)(); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; + + return(sound.soft.speed); +} + + +static int sound_set_stereo(int stereo) +{ + if (stereo < 0) + return(sound.soft.stereo); + + stereo = !!stereo; /* should be 0 or 1 now */ + + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init)(); + + return(stereo); +} + + +static int sound_set_volume(int volume) +{ + return(*sound.mach.setVolume)(volume); +} + +static ssize_t sound_copy_translate(const u_char *userPtr, + size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL; + + switch (sound.soft.format) { + case AFMT_MU_LAW: + ct_func = sound.trans_write->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans_write->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans_write->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans_write->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans_write->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans_write->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans_write->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans_write->ct_u16le; + break; + } + if (ct_func) + return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + else + return 0; +} + +static ssize_t sound_copy_translate_read(const u_char *userPtr, + size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL; + + switch (sound.soft.format) { + case AFMT_MU_LAW: + ct_func = sound.trans_read->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans_read->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans_read->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans_read->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans_read->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans_read->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans_read->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans_read->ct_u16le; + break; + } + if (ct_func) + return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + else + return 0; +} + + +/* + * /dev/mixer abstraction + */ + +static int mixer_open(struct inode *inode, struct file *file) +{ + mixer.busy = 1; + return nonseekable_open(inode, file); +} + + +static int mixer_release(struct inode *inode, struct file *file) +{ + mixer.busy = 0; + return 0; +} + + +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + int data; + uint tmpcs; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + mixer.modify_counter++; + if (cmd == OSS_GETVERSION) + return IOCTL_OUT(arg, SOUND_VERSION); + switch (cmd) { + case SOUND_MIXER_INFO: { + mixer_info info; + strlcpy(info.id, "CS4218_TDM", sizeof(info.id)); + strlcpy(info.name, "CS4218_TDM", sizeof(info.name)); + info.name[sizeof(info.name)-1] = 0; + info.modify_counter = mixer.modify_counter; + if (copy_to_user((int *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_LINE + | SOUND_MASK_MIC | SOUND_MASK_RECLEV + | SOUND_MASK_ALTPCM; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECMASK: + data = SOUND_MASK_LINE | SOUND_MASK_MIC; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECSRC: + if (cs4218_control & CS_DO1) + data = SOUND_MASK_LINE; + else + data = SOUND_MASK_MIC; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data &= (SOUND_MASK_LINE | SOUND_MASK_MIC); + if (data & SOUND_MASK_LINE) + tmpcs = cs4218_control | + (CS_ISL | CS_ISR | CS_DO1); + if (data & SOUND_MASK_MIC) + tmpcs = cs4218_control & + ~(CS_ISL | CS_ISR | CS_DO1); + if (tmpcs != cs4218_control) + cs4218_ctl_write(tmpcs); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_CAPS: + return IOCTL_OUT(arg, 0); + case SOUND_MIXER_READ_VOLUME: + data = (cs4218_control & CS_MUTE)? 0: + cs_get_volume(cs4218_control); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_volume(data)); + case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ + IOCTL_IN(arg, data); + beep_volume = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_ALTPCM: + return IOCTL_OUT(arg, beep_volume); + case SOUND_MIXER_WRITE_RECLEV: + IOCTL_IN(arg, data); + data = cs_set_gain(data); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECLEV: + data = cs_get_gain(cs4218_control); + return IOCTL_OUT(arg, data); + } + + return -EINVAL; +} + + +static const struct file_operations mixer_fops = +{ + .owner = THIS_MODULE, + .llseek = sound_lseek, + .ioctl = mixer_ioctl, + .open = mixer_open, + .release = mixer_release, +}; + + +static void __init mixer_init(void) +{ + mixer_unit = register_sound_mixer(&mixer_fops, -1); + if (mixer_unit < 0) + return; + + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + + /* Set Line input, no gain, no attenuation. + */ + cs4218_control = CS_ISL | CS_ISR | CS_DO1; + cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0); + cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0); + cs4218_ctl_write(cs4218_control); +} + + +/* + * Sound queue stuff, the heart of the driver + */ + + +static int sq_allocate_buffers(void) +{ + int i; + + if (sound_buffers) + return 0; + sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); + if (!sound_buffers) + return -ENOMEM; + for (i = 0; i < numBufs; i++) { + sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); + if (!sound_buffers[i]) { + while (i--) + sound.mach.dma_free (sound_buffers[i], bufSize << 10); + kfree (sound_buffers); + sound_buffers = 0; + return -ENOMEM; + } + } + return 0; +} + + +static void sq_release_buffers(void) +{ + int i; + + if (sound_buffers) { + for (i = 0; i < numBufs; i++) + sound.mach.dma_free (sound_buffers[i], bufSize << 10); + kfree (sound_buffers); + sound_buffers = 0; + } +} + + +static int sq_allocate_read_buffers(void) +{ + int i; + + if (sound_read_buffers) + return 0; + sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL); + if (!sound_read_buffers) + return -ENOMEM; + for (i = 0; i < numBufs; i++) { + sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10, + GFP_KERNEL); + if (!sound_read_buffers[i]) { + while (i--) + sound.mach.dma_free (sound_read_buffers[i], + readbufSize << 10); + kfree (sound_read_buffers); + sound_read_buffers = 0; + return -ENOMEM; + } + } + return 0; +} + +static void sq_release_read_buffers(void) +{ + int i; + + if (sound_read_buffers) { + cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN; + for (i = 0; i < numReadBufs; i++) + sound.mach.dma_free (sound_read_buffers[i], + bufSize << 10); + kfree (sound_read_buffers); + sound_read_buffers = 0; + } +} + + +static void sq_setup(int numBufs, int bufSize, char **write_buffers) +{ + int i; + volatile cbd_t *bdp; + volatile cpm8xx_t *cp; + volatile smc_t *sp; + + /* Make sure the SMC transmit is shut down. + */ + cp = cpmp; + sp = &cpmp->cp_smc[1]; + sp->smc_smcmr &= ~SMCMR_TEN; + + sq.max_count = numBufs; + sq.max_active = numBufs; + sq.block_size = bufSize; + sq.buffers = write_buffers; + + sq.front = sq.count = 0; + sq.rear = -1; + sq.syncing = 0; + sq.active = 0; + + bdp = tx_base; + for (i=0; icbd_bufaddr = virt_to_bus(write_buffers[i]); + bdp++; + } + + /* This causes the SMC to sync up with the first buffer again. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); +} + +static void read_sq_setup(int numBufs, int bufSize, char **read_buffers) +{ + int i; + volatile cbd_t *bdp; + volatile cpm8xx_t *cp; + volatile smc_t *sp; + + /* Make sure the SMC receive is shut down. + */ + cp = cpmp; + sp = &cpmp->cp_smc[1]; + sp->smc_smcmr &= ~SMCMR_REN; + + read_sq.max_count = numBufs; + read_sq.max_active = numBufs; + read_sq.block_size = bufSize; + read_sq.buffers = read_buffers; + + read_sq.front = read_sq.count = 0; + read_sq.rear = 0; + read_sq.rear_size = 0; + read_sq.syncing = 0; + read_sq.active = 0; + + bdp = rx_base; + for (i=0; icbd_bufaddr = virt_to_bus(read_buffers[i]); + bdp->cbd_datlen = read_sq.block_size; + bdp++; + } + + /* This causes the SMC to sync up with the first buffer again. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); +} + + +static void sq_play(void) +{ + (*sound.mach.play)(); +} + + +/* ++TeSche: radically changed this one too */ + +static ssize_t sq_write(struct file *file, const char *src, size_t uLeft, + loff_t *ppos) +{ + ssize_t uWritten = 0; + u_char *dest; + ssize_t uUsed, bUsed, bLeft; + + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. + */ + if (uLeft == 0) + return 0; + + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) + */ + + if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + if (uUsed <= 0) + return uUsed; + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + + do { + while (sq.count == sq.max_active) { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return uWritten > 0 ? uWritten : -EAGAIN; + SLEEP(sq.action_queue); + if (SIGNAL_RECEIVED) + return uWritten > 0 ? uWritten : -EINTR; + } + + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. + */ + + dest = sq_block_address((sq.rear+1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + if (uUsed <= 0) + break; + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) { + sq.rear = (sq.rear+1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } while (bUsed); /* uUsed may have been 0 */ + + sq_play(); + + return uUsed < 0? uUsed: uWritten; +} + + +/***********/ + +/* Here is how the values are used for reading. + * The value 'active' simply indicates the DMA is running. This is + * done so the driver semantics are DMA starts when the first read is + * posted. The value 'front' indicates the buffer we should next + * send to the user. The value 'rear' indicates the buffer the DMA is + * currently filling. When 'front' == 'rear' the buffer "ring" is + * empty (we always have an empty available). The 'rear_size' is used + * to track partial offsets into the current buffer. Right now, I just keep + * The DMA running. If the reader can't keep up, the interrupt tosses + * the oldest buffer. We could also shut down the DMA in this case. + */ +static ssize_t sq_read(struct file *file, char *dst, size_t uLeft, + loff_t *ppos) +{ + + ssize_t uRead, bLeft, bUsed, uUsed; + + if (uLeft == 0) + return 0; + + if (!read_sq.active) + CS_Record(); /* Kick off the record process. */ + + uRead = 0; + + /* Move what the user requests, depending upon other options. + */ + while (uLeft > 0) { + + /* When front == rear, the DMA is not done yet. + */ + while (read_sq.front == read_sq.rear) { + if (NON_BLOCKING(read_sq.open_mode)) { + return uRead > 0 ? uRead : -EAGAIN; + } + SLEEP(read_sq.action_queue); + if (SIGNAL_RECEIVED) + return uRead > 0 ? uRead : -EINTR; + } + + /* The amount we move is either what is left in the + * current buffer or what the user wants. + */ + bLeft = read_sq.block_size - read_sq.rear_size; + bUsed = read_sq.rear_size; + uUsed = sound_copy_translate_read(dst, uLeft, + read_sq.buffers[read_sq.front], &bUsed, bLeft); + if (uUsed <= 0) + return uUsed; + dst += uUsed; + uRead += uUsed; + uLeft -= uUsed; + read_sq.rear_size += bUsed; + if (read_sq.rear_size >= read_sq.block_size) { + read_sq.rear_size = 0; + read_sq.front++; + if (read_sq.front >= read_sq.max_active) + read_sq.front = 0; + } + } + return uRead; +} + +static int sq_open(struct inode *inode, struct file *file) +{ + int rc = 0; + + if (file->f_mode & FMODE_WRITE) { + if (sq.busy) { + rc = -EBUSY; + if (NON_BLOCKING(file->f_flags)) + goto err_out; + rc = -EINTR; + while (sq.busy) { + SLEEP(sq.open_queue); + if (SIGNAL_RECEIVED) + goto err_out; + } + } + sq.busy = 1; /* Let's play spot-the-race-condition */ + + if (sq_allocate_buffers()) goto err_out_nobusy; + + sq_setup(numBufs, bufSize<<10,sound_buffers); + sq.open_mode = file->f_mode; + } + + + if (file->f_mode & FMODE_READ) { + if (read_sq.busy) { + rc = -EBUSY; + if (NON_BLOCKING(file->f_flags)) + goto err_out; + rc = -EINTR; + while (read_sq.busy) { + SLEEP(read_sq.open_queue); + if (SIGNAL_RECEIVED) + goto err_out; + } + rc = 0; + } + read_sq.busy = 1; + if (sq_allocate_read_buffers()) goto err_out_nobusy; + + read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers); + read_sq.open_mode = file->f_mode; + } + + /* Start up the 4218 by: + * Reset. + * Enable, unreset. + */ + *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO; + eieio(); + *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO; + mdelay(50); + *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO; + + /* We need to send the current control word in case someone + * opened /dev/mixer and changed things while we were shut + * down. Chances are good the initialization that follows + * would have done this, but it is still possible it wouldn't. + */ + cs4218_ctl_write(cs4218_control); + + sound.minDev = iminor(inode) & 0x0f; + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_init(); + if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + + return nonseekable_open(inode, file); + +err_out_nobusy: + if (file->f_mode & FMODE_WRITE) { + sq.busy = 0; + WAKE_UP(sq.open_queue); + } + if (file->f_mode & FMODE_READ) { + read_sq.busy = 0; + WAKE_UP(read_sq.open_queue); + } +err_out: + return rc; +} + + +static void sq_reset(void) +{ + sound_silence(); + sq.active = 0; + sq.count = 0; + sq.front = (sq.rear+1) % sq.max_count; +#if 0 + init_tdm_buffers(); +#endif +} + + +static int sq_fsync(struct file *filp, struct dentry *dentry) +{ + int rc = 0; + + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ + + while (sq.active) { + SLEEP(sq.sync_queue); + if (SIGNAL_RECEIVED) { + /* While waiting for audio output to drain, an + * interrupt occurred. Stop audio output immediately + * and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } + + sq.syncing = 0; + return rc; +} + +static int sq_release(struct inode *inode, struct file *file) +{ + int rc = 0; + + if (sq.busy) + rc = sq_fsync(file, file->f_path.dentry); + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_silence(); + + sq_release_read_buffers(); + sq_release_buffers(); + + if (file->f_mode & FMODE_READ) { + read_sq.busy = 0; + WAKE_UP(read_sq.open_queue); + } + + if (file->f_mode & FMODE_WRITE) { + sq.busy = 0; + WAKE_UP(sq.open_queue); + } + + /* Shut down the SMC. + */ + cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN); + + /* Shut down the codec. + */ + *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO; + eieio(); + *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO; + + /* Wake up a process waiting for the queue being released. + * Note: There may be several processes waiting for a call + * to open() returning. */ + + return rc; +} + + +static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + u_long fmt; + int data; +#if 0 + int size, nbufs; +#else + int size; +#endif + + switch (cmd) { + case SNDCTL_DSP_RESET: + sq_reset(); + return 0; + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return sq_fsync(file, file->f_path.dentry); + + /* ++TeSche: before changing any of these it's + * probably wise to wait until sound playing has + * settled down. */ + case SNDCTL_DSP_SPEED: + sq_fsync(file, file->f_path.dentry); + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_speed(data)); + case SNDCTL_DSP_STEREO: + sq_fsync(file, file->f_path.dentry); + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_stereo(data)); + case SOUND_PCM_WRITE_CHANNELS: + sq_fsync(file, file->f_path.dentry); + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); + case SNDCTL_DSP_SETFMT: + sq_fsync(file, file->f_path.dentry); + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_format(data)); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans_write) { + if (sound.trans_write->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans_write->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans_write->ct_s8) + fmt |= AFMT_S8; + if (sound.trans_write->ct_u8) + fmt |= AFMT_U8; + if (sound.trans_write->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans_write->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans_write->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans_write->ct_u16le) + fmt |= AFMT_U16_LE; + } + return IOCTL_OUT(arg, fmt); + case SNDCTL_DSP_GETBLKSIZE: + size = sq.block_size + * sound.soft.size * (sound.soft.stereo + 1) + / (sound.hard.size * (sound.hard.stereo + 1)); + return IOCTL_OUT(arg, size); + case SNDCTL_DSP_SUBDIVIDE: + break; +#if 0 /* Sorry can't do this at the moment. The CPM allocated buffers + * long ago that can't be changed. + */ + case SNDCTL_DSP_SETFRAGMENT: + if (sq.count || sq.active || sq.syncing) + return -EINVAL; + IOCTL_IN(arg, size); + nbufs = size >> 16; + if (nbufs < 2 || nbufs > numBufs) + nbufs = numBufs; + size &= 0xffff; + if (size >= 8 && size <= 30) { + size = 1 << size; + size *= sound.hard.size * (sound.hard.stereo + 1); + size /= sound.soft.size * (sound.soft.stereo + 1); + if (size > (bufSize << 10)) + size = bufSize << 10; + } else + size = bufSize << 10; + sq_setup(numBufs, size, sound_buffers); + sq.max_active = nbufs; + return 0; +#endif + + default: + return mixer_ioctl(inode, file, cmd, arg); + } + return -EINVAL; +} + + + +static const struct file_operations sq_fops = +{ + .owner = THIS_MODULE, + .llseek = sound_lseek, + .read = sq_read, /* sq_read */ + .write = sq_write, + .ioctl = sq_ioctl, + .open = sq_open, + .release = sq_release, +}; + + +static void __init sq_init(void) +{ + sq_unit = register_sound_dsp(&sq_fops, -1); + if (sq_unit < 0) + return; + + init_waitqueue_head(&sq.action_queue); + init_waitqueue_head(&sq.open_queue); + init_waitqueue_head(&sq.sync_queue); + init_waitqueue_head(&read_sq.action_queue); + init_waitqueue_head(&read_sq.open_queue); + init_waitqueue_head(&read_sq.sync_queue); + + sq.busy = 0; + read_sq.busy = 0; + + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S16_BE; + sound.dsp.stereo = 1; + sound.dsp.size = 16; + + /* set minimum rate possible without expanding */ + sound.dsp.speed = 8000; + + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; + sound.hard = sound.dsp; + + sound_silence(); +} + +/* + * /dev/sndstat + */ + + +/* state.buf should not overflow! */ + +static int state_open(struct inode *inode, struct file *file) +{ + char *buffer = state.buf, *mach = "", cs4218_buf[50]; + int len = 0; + + if (state.busy) + return -EBUSY; + + state.ptr = 0; + state.busy = 1; + + sprintf(cs4218_buf, "Crystal CS4218 on TDM, "); + mach = cs4218_buf; + + len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) { + case AFMT_MU_LAW: + len += sprintf(buffer+len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer+len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer+len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer+len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer+len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer+len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer+len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer+len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d" + " sq.max_active = %d\n", + sq.block_size, sq.max_count, sq.max_active); + len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n", + sq.active, sq.syncing); + state.len = len; + return nonseekable_open(inode, file); +} + + +static int state_release(struct inode *inode, struct file *file) +{ + state.busy = 0; + return 0; +} + + +static ssize_t state_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int n = state.len - state.ptr; + if (n > count) + n = count; + if (n <= 0) + return 0; + if (copy_to_user(buf, &state.buf[state.ptr], n)) + return -EFAULT; + state.ptr += n; + return n; +} + + +static const struct file_operations state_fops = +{ + .owner = THIS_MODULE, + .llseek = sound_lseek, + .read = state_read, + .open = state_open, + .release = state_release, +}; + + +static void __init state_init(void) +{ + state_unit = register_sound_special(&state_fops, SND_DEV_STATUS); + if (state_unit < 0) + return; + state.busy = 0; +} + + +/*** Common stuff ********************************************************/ + +static long long sound_lseek(struct file *file, long long offset, int orig) +{ + return -ESPIPE; +} + + +/*** Config & Setup **********************************************************/ + + +int __init tdm8xx_sound_init(void) +{ + int i, has_sound; + uint dp_offset; + volatile uint *sirp; + volatile cbd_t *bdp; + volatile cpm8xx_t *cp; + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile immap_t *immap; + + has_sound = 0; + + /* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes. + */ + cp = cpmp; /* Get pointer to Communication Processor */ + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + + /* Set all TDMa control bits to zero. This enables most features + * we want. + */ + cp->cp_simode &= ~0x00000fff; + + /* Enable common receive/transmit clock pins, use IDL format. + * Sync on falling edge, transmit rising clock, receive falling + * clock, delay 1 bit on both Tx and Rx. Common Tx/Rx clocks and + * sync. + * Connect SMC2 to TSA. + */ + cp->cp_simode |= 0x80000141; + + /* Configure port A pins for TDMa operation. + * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used. + */ + immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */ + immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */ + immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */ + + immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */ + immap->im_ioport.iop_pcdir &= ~0x0800; + + /* Initialize the SI TDM routing table. We use TDMa only. + * The receive table and transmit table each have only one + * entry, to capture/send four bytes after each frame pulse. + * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2) + */ + cp->cp_sigmr = 0; + sirp = (uint *)cp->cp_siram; + + *sirp = 0x018f0000; /* Receive entry */ + sirp += 64; + *sirp = 0x018f0000; /* Tramsmit entry */ + + /* Enable single TDMa routing. + */ + cp->cp_sigmr = 0x04; + + /* Initialize the SMC for transparent operation. + */ + sp = &cpmp->cp_smc[1]; + up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2]; + + /* We need to allocate a transmit and receive buffer + * descriptors from dual port ram. + */ + dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; + up->smc_rbase = dp_offset; + rx_cur = rx_base = (cbd_t *)bdp; + + for (i=0; i<(numReadBufs-1); i++) { + bdp->cbd_bufaddr = 0; + bdp->cbd_datlen = 0; + bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; + bdp++; + } + bdp->cbd_bufaddr = 0; + bdp->cbd_datlen = 0; + bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + + /* Now, do the same for the transmit buffers. + */ + dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8); + + bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; + up->smc_tbase = dp_offset; + tx_cur = tx_base = (cbd_t *)bdp; + + for (i=0; i<(numBufs-1); i++) { + bdp->cbd_bufaddr = 0; + bdp->cbd_datlen = 0; + bdp->cbd_sc = BD_SC_INTRPT; + bdp++; + } + bdp->cbd_bufaddr = 0; + bdp->cbd_datlen = 0; + bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); + + /* Set transparent SMC mode. + * A few things are specific to our application. The codec interface + * is MSB first, hence the REVD selection. The CD/CTS pulse are + * used by the TSA to indicate the frame start to the SMC. + */ + up->smc_rfcr = SCC_EB; + up->smc_tfcr = SCC_EB; + up->smc_mrblr = readbufSize * 1024; + + /* Set 16-bit reversed data, transparent mode. + */ + sp->smc_smcmr = smcr_mk_clen(15) | + SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS; + + /* Enable and clear events. + * Because of FIFO delays, all we need is the receive interrupt + * and we can process both the current receive and current + * transmit interrupt within a few microseconds of the transmit. + */ + sp->smc_smce = 0xff; + sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX; + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + sound.mach = mach_cs4218; + has_sound = 1; + + /* Initialize beep stuff */ + orig_mksound = kd_mksound; + kd_mksound = cs_mksound; + beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); + if (beep_buf == NULL) + printk(KERN_WARNING "dmasound: no memory for " + "beep buffer\n"); + + if (!has_sound) + return -ENODEV; + + /* Initialize the software SPI. + */ + sw_spi_init(); + + /* Set up sound queue, /dev/audio and /dev/dsp. */ + + /* Set default settings. */ + sq_init(); + + /* Set up /dev/sndstat. */ + state_init(); + + /* Set up /dev/mixer. */ + mixer_init(); + + if (!sound.mach.irqinit()) { + printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); + return -ENODEV; + } +#ifdef MODULE + irq_installed = 1; +#endif + + printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", + numBufs, bufSize); + + return 0; +} + +/* Due to FIFOs and bit delays, the transmit interrupt occurs a few + * microseconds ahead of the receive interrupt. + * When we get an interrupt, we service the transmit first, then + * check for a receive to prevent the overhead of returning through + * the interrupt handler only to get back here right away during + * full duplex operation. + */ +static void +cs4218_intr(void *dev_id) +{ + volatile smc_t *sp; + volatile cpm8xx_t *cp; + + sp = &cpmp->cp_smc[1]; + + if (sp->smc_smce & SCCM_TX) { + sp->smc_smce = SCCM_TX; + cs4218_tdm_tx_intr((void *)sp); + } + + if (sp->smc_smce & SCCM_RX) { + sp->smc_smce = SCCM_RX; + cs4218_tdm_rx_intr((void *)sp); + } + + if (sp->smc_smce & SCCM_TXE) { + /* Transmit underrun. This happens with the application + * didn't keep up sending buffers. We tell the SMC to + * restart, which will cause it to poll the current (next) + * BD. If the user supplied data since this occurred, + * we just start running again. If they didn't, the SMC + * will poll the descriptor until data is placed there. + */ + sp->smc_smce = SCCM_TXE; + cp = cpmp; /* Get pointer to Communication Processor */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, + CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } +} + + +#define MAXARGS 8 /* Should be sufficient for now */ + +void __init dmasound_setup(char *str, int *ints) +{ + /* check the bootstrap parameter for "dmasound=" */ + + switch (ints[0]) { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk("dmasound_setup: invalid number of arguments\n"); + } +} + +/* Software SPI functions. + * These are on Port B. + */ +#define PB_SPICLK ((uint)0x00000002) +#define PB_SPIMOSI ((uint)0x00000004) +#define PB_SPIMISO ((uint)0x00000008) + +static +void sw_spi_init(void) +{ + volatile cpm8xx_t *cp; + volatile uint *hcsr4; + + hcsr4 = (volatile uint *)HIOX_CSR4_ADDR; + cp = cpmp; /* Get pointer to Communication Processor */ + + *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */ + + /* Make these Port B signals general purpose I/O. + * First, make sure the clock is low. + */ + cp->cp_pbdat &= ~PB_SPICLK; + cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO); + + /* Clock and Master Output are outputs. + */ + cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI); + + /* Master Input. + */ + cp->cp_pbdir &= ~PB_SPIMISO; + +} + +/* Write the CS4218 control word out the SPI port. While the + * the control word is going out, the status word is arriving. + */ +static +uint cs4218_ctl_write(uint ctlreg) +{ + uint status; + + sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4); + + /* Shadow the control register.....I guess we could do + * the same for the status, but for now we just return it + * and let the caller decide. + */ + cs4218_control = ctlreg; + return status; +} + +static +void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt) +{ + int bits, i; + u_char outbyte, inbyte; + volatile cpm8xx_t *cp; + volatile uint *hcsr4; + + hcsr4 = (volatile uint *)HIOX_CSR4_ADDR; + cp = cpmp; /* Get pointer to Communication Processor */ + + /* The timing on the bus is pretty slow. Code inefficiency + * and eieio() is our friend here :-). + */ + cp->cp_pbdat &= ~PB_SPICLK; + *hcsr4 |= HIOX_CSR4_AUDSPISEL; /* Enable SPI select */ + eieio(); + + /* Clock in/out the bytes. Data is valid on the falling edge + * of the clock. Data is MSB first. + */ + for (i=0; icp_pbdat |= PB_SPICLK; + eieio(); + if (outbyte & 0x80) + cp->cp_pbdat |= PB_SPIMOSI; + else + cp->cp_pbdat &= ~PB_SPIMOSI; + eieio(); + cp->cp_pbdat &= ~PB_SPICLK; + eieio(); + outbyte <<= 1; + inbyte <<= 1; + if (cp->cp_pbdat & PB_SPIMISO) + inbyte |= 1; + } + *ibuf++ = inbyte; + } + + *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */ + eieio(); +} + +void cleanup_module(void) +{ + if (irq_installed) { + sound_silence(); +#ifdef MODULE + sound.mach.irqcleanup(); +#endif + } + + sq_release_read_buffers(); + sq_release_buffers(); + + if (mixer_unit >= 0) + unregister_sound_mixer(mixer_unit); + if (state_unit >= 0) + unregister_sound_special(state_unit); + if (sq_unit >= 0) + unregister_sound_dsp(sq_unit); +} + +module_init(tdm8xx_sound_init); +module_exit(cleanup_module); + diff --git a/trunk/arch/ppc/8xx_io/enet.c b/trunk/arch/ppc/8xx_io/enet.c index e58288e14369..b23c45bc151a 100644 --- a/trunk/arch/ppc/8xx_io/enet.c +++ b/trunk/arch/ppc/8xx_io/enet.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -505,6 +506,7 @@ for (;;) { cep->stats.rx_dropped++; } else { + skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, cep->rx_vaddr[bdp - cep->rx_bd_base], diff --git a/trunk/arch/ppc/8xx_io/fec.c b/trunk/arch/ppc/8xx_io/fec.c index 57a9a61e54b5..e6c28fb423b2 100644 --- a/trunk/arch/ppc/8xx_io/fec.c +++ b/trunk/arch/ppc/8xx_io/fec.c @@ -724,6 +724,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; } else { + skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, data, pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); diff --git a/trunk/arch/ppc/boot/common/misc-common.c b/trunk/arch/ppc/boot/common/misc-common.c index 9589969cec72..8e1fccd96fc0 100644 --- a/trunk/arch/ppc/boot/common/misc-common.c +++ b/trunk/arch/ppc/boot/common/misc-common.c @@ -57,8 +57,7 @@ unsigned char *ISA_io = NULL; #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE) \ - || defined(CONFIG_SERIAL_UARTLITE_CONSOLE) + || defined(CONFIG_SERIAL_MPSC_CONSOLE) extern unsigned long com_port; extern int serial_tstc(unsigned long com_port); @@ -81,8 +80,7 @@ int tstc(void) { #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE) \ - || defined(CONFIG_SERIAL_UARTLITE_CONSOLE) + || defined(CONFIG_SERIAL_MPSC_CONSOLE) if(keyb_present) return (CRT_tstc() || serial_tstc(com_port)); else @@ -97,8 +95,7 @@ int getc(void) while (1) { #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE) \ - || defined(CONFIG_SERIAL_UARTLITE_CONSOLE) + || defined(CONFIG_SERIAL_MPSC_CONSOLE) if (serial_tstc(com_port)) return (serial_getc(com_port)); #endif /* serial console */ @@ -115,8 +112,7 @@ putc(const char c) #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE) \ - || defined(CONFIG_SERIAL_UARTLITE_CONSOLE) + || defined(CONFIG_SERIAL_MPSC_CONSOLE) serial_putc(com_port, c); if ( c == '\n' ) serial_putc(com_port, '\r'); @@ -165,8 +161,7 @@ void puts(const char *s) while ( ( c = *s++ ) != '\0' ) { #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE) \ - || defined(CONFIG_SERIAL_UARTLITE_CONSOLE) + || defined(CONFIG_SERIAL_MPSC_CONSOLE) serial_putc(com_port, c); if ( c == '\n' ) serial_putc(com_port, '\r'); #endif /* serial console */ diff --git a/trunk/arch/ppc/boot/simple/Makefile b/trunk/arch/ppc/boot/simple/Makefile index 5b877792d14f..bcfb6cde70c4 100644 --- a/trunk/arch/ppc/boot/simple/Makefile +++ b/trunk/arch/ppc/boot/simple/Makefile @@ -201,7 +201,6 @@ boot-$(CONFIG_8260) += m8260_tty.o endif boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o -boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o LIBS := $(common)/lib.a $(bootlib)/lib.a ifeq ($(CONFIG_PPC_PREP),y) diff --git a/trunk/arch/ppc/boot/simple/uartlite_tty.c b/trunk/arch/ppc/boot/simple/uartlite_tty.c deleted file mode 100644 index 0eae1eab38d4..000000000000 --- a/trunk/arch/ppc/boot/simple/uartlite_tty.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xilinx UARTLITE bootloader driver - * - * Copyright (c) 2007 Secret Lab Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include - -#define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR)) - -void -serial_putc(unsigned long com_port, unsigned char c) -{ - while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x08) != 0); /* spin */ - out_be32(UARTLITE_BASEADDR + 0x4, c); -} - -unsigned char -serial_getc(unsigned long com_port) -{ - while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) == 0); /* spin */ - return in_be32(UARTLITE_BASEADDR); -} - -int -serial_tstc(unsigned long com_port) -{ - return ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) != 0); -} diff --git a/trunk/arch/ppc/kernel/asm-offsets.c b/trunk/arch/ppc/kernel/asm-offsets.c index c5850a272650..1f91eca2f3d7 100644 --- a/trunk/arch/ppc/kernel/asm-offsets.c +++ b/trunk/arch/ppc/kernel/asm-offsets.c @@ -40,6 +40,7 @@ main(void) DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(KSP, offsetof(struct thread_struct, ksp)); DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); + DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); diff --git a/trunk/arch/ppc/kernel/entry.S b/trunk/arch/ppc/kernel/entry.S index ab64256110bd..a9d455369dc6 100644 --- a/trunk/arch/ppc/kernel/entry.S +++ b/trunk/arch/ppc/kernel/entry.S @@ -191,6 +191,7 @@ stack_ovf: 0: _GLOBAL(DoSyscall) + stw r0,THREAD+LAST_SYSCALL(r2) stw r3,ORIG_GPR3(r1) li r12,0 stw r12,RESULT(r1) diff --git a/trunk/arch/ppc/kernel/ppc_ksyms.c b/trunk/arch/ppc/kernel/ppc_ksyms.c index 4ad499605d05..1318b6f4c3df 100644 --- a/trunk/arch/ppc/kernel/ppc_ksyms.c +++ b/trunk/arch/ppc/kernel/ppc_ksyms.c @@ -93,6 +93,8 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcasecmp); +EXPORT_SYMBOL(strncasecmp); EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(csum_partial); diff --git a/trunk/arch/ppc/kernel/vmlinux.lds.S b/trunk/arch/ppc/kernel/vmlinux.lds.S index 44cd128fb719..a0625562a44b 100644 --- a/trunk/arch/ppc/kernel/vmlinux.lds.S +++ b/trunk/arch/ppc/kernel/vmlinux.lds.S @@ -130,7 +130,7 @@ SECTIONS __ftr_fixup : { *(__ftr_fixup) } __stop___ftr_fixup = .; - . = ALIGN(4096); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/ppc/lib/Makefile b/trunk/arch/ppc/lib/Makefile index 422bef9bae7b..50358e4ea159 100644 --- a/trunk/arch/ppc/lib/Makefile +++ b/trunk/arch/ppc/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc-specific library files.. # -obj-y := checksum.o string.o div64.o +obj-y := checksum.o string.o strcase.o div64.o obj-$(CONFIG_8xx) += rheap.o obj-$(CONFIG_CPM2) += rheap.o diff --git a/trunk/arch/ppc/lib/strcase.c b/trunk/arch/ppc/lib/strcase.c new file mode 100644 index 000000000000..3b0094cc2b52 --- /dev/null +++ b/trunk/arch/ppc/lib/strcase.c @@ -0,0 +1,24 @@ +#include +#include + +int strcasecmp(const char *s1, const char *s2) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 == c2 && c1 != 0); + return c1 - c2; +} + +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} diff --git a/trunk/arch/ppc/platforms/4xx/Kconfig b/trunk/arch/ppc/platforms/4xx/Kconfig index 76551b679030..705ae56016f0 100644 --- a/trunk/arch/ppc/platforms/4xx/Kconfig +++ b/trunk/arch/ppc/platforms/4xx/Kconfig @@ -29,7 +29,6 @@ config CPCI405 config EP405 bool "EP405/EP405PC" - select EMBEDDEDBOOT help This option enables support for the EP405/EP405PC boards. @@ -55,15 +54,11 @@ config WALNUT config XILINX_ML300 bool "Xilinx-ML300" - select XILINX_VIRTEX_II_PRO - select EMBEDDEDBOOT help This option enables support for the Xilinx ML300 evaluation board. config XILINX_ML403 bool "Xilinx-ML403" - select XILINX_VIRTEX_4_FX - select EMBEDDEDBOOT help This option enables support for the Xilinx ML403 evaluation board. endchoice @@ -220,14 +215,18 @@ config 405GPR config XILINX_VIRTEX_II_PRO bool - select XILINX_VIRTEX + depends on XILINX_ML300 + default y config XILINX_VIRTEX_4_FX bool - select XILINX_VIRTEX + depends on XILINX_ML403 + default y config XILINX_VIRTEX bool + depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX + default y config STB03xxx bool @@ -236,6 +235,8 @@ config STB03xxx config EMBEDDEDBOOT bool + depends on EP405 || XILINX_ML300 || XILINX_ML403 + default y config IBM_OPENBIOS bool diff --git a/trunk/arch/ppc/platforms/4xx/Makefile b/trunk/arch/ppc/platforms/4xx/Makefile index 723ad7985cc6..fa6610bccaf9 100644 --- a/trunk/arch/ppc/platforms/4xx/Makefile +++ b/trunk/arch/ppc/platforms/4xx/Makefile @@ -28,4 +28,5 @@ obj-$(CONFIG_440SP) += ibm440sp.o obj-$(CONFIG_440SPE) += ppc440spe.o obj-$(CONFIG_405EP) += ibm405ep.o obj-$(CONFIG_405GPR) += ibm405gpr.o +obj-$(CONFIG_XILINX_VIRTEX) += virtex.o diff --git a/trunk/arch/ppc/platforms/4xx/ocotea.c b/trunk/arch/ppc/platforms/4xx/ocotea.c index 5e994e146ba8..84e999d9a7bb 100644 --- a/trunk/arch/ppc/platforms/4xx/ocotea.c +++ b/trunk/arch/ppc/platforms/4xx/ocotea.c @@ -178,7 +178,7 @@ ocotea_setup_pcix(void) /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); - PCIX_WRITEL(0x80000007, PCIX0_PIM0SA); + PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); eieio(); } @@ -289,7 +289,7 @@ ocotea_setup_arch(void) * from FPGA, because it can be changed by on-board switches * --ebs */ - ibm440gx_get_clocks(&clocks, 33300000, 6 * 1843200); + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); ocp_sys_info.opb_bus_freq = clocks.opb; /* Setup TODC access */ diff --git a/trunk/arch/ppc/platforms/4xx/taishan.c b/trunk/arch/ppc/platforms/4xx/taishan.c index 5d9af8ddb155..bb0253eef45a 100644 --- a/trunk/arch/ppc/platforms/4xx/taishan.c +++ b/trunk/arch/ppc/platforms/4xx/taishan.c @@ -235,7 +235,7 @@ taishan_setup_pcix(void) /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); - PCIX_WRITEL(0x80000007, PCIX0_PIM0SA); + PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH); iounmap(pcix_reg_base); diff --git a/trunk/arch/ppc/platforms/4xx/virtex.c b/trunk/arch/ppc/platforms/4xx/virtex.c new file mode 100644 index 000000000000..133a83147199 --- /dev/null +++ b/trunk/arch/ppc/platforms/4xx/virtex.c @@ -0,0 +1,56 @@ +/* + * Virtex-II Pro & Virtex-4 FX common infrastructure + * + * Maintainer: Grant Likely + * + * Copyright 2005 Secret Lab Technologies Ltd. + * Copyright 2005 General Dynamics Canada Ltd. + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XPAR_UART(num) { \ + .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \ + .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \ + .iotype = UPIO_MEM, \ + .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \ + .flags = UPF_BOOT_AUTOCONF, \ + .regshift = 2, \ + } + +struct plat_serial8250_port serial_platform_data[] = { +#ifdef XPAR_UARTNS550_0_BASEADDR + XPAR_UART(0), +#endif +#ifdef XPAR_UARTNS550_1_BASEADDR + XPAR_UART(1), +#endif +#ifdef XPAR_UARTNS550_2_BASEADDR + XPAR_UART(2), +#endif +#ifdef XPAR_UARTNS550_3_BASEADDR + XPAR_UART(3), +#endif + { }, /* terminated by empty record */ +}; + +struct platform_device ppc_sys_platform_devices[] = { + [VIRTEX_UART] = { + .name = "serial8250", + .id = 0, + .dev.platform_data = serial_platform_data, + }, +}; + diff --git a/trunk/arch/ppc/platforms/4xx/virtex.h b/trunk/arch/ppc/platforms/4xx/virtex.h index 738280420be5..c14325dfd7b1 100644 --- a/trunk/arch/ppc/platforms/4xx/virtex.h +++ b/trunk/arch/ppc/platforms/4xx/virtex.h @@ -1,35 +1,35 @@ /* - * Basic Virtex platform defines, included by + * arch/ppc/platforms/4xx/virtex.h * - * 2005-2007 (c) Secret Lab Technologies Ltd. - * 2002-2004 (c) MontaVista Software, Inc. + * Include file that defines the Xilinx Virtex-II Pro processor * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. */ #ifdef __KERNEL__ #ifndef __ASM_VIRTEX_H__ #define __ASM_VIRTEX_H__ +/* serial defines */ + #include -#include /* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */ #if !defined(BASE_BAUD) #define BASE_BAUD (0) /* dummy value; not used */ #endif - + +/* Device type enumeration for platform bus definitions */ #ifndef __ASSEMBLY__ -extern const char* virtex_machine_name; -#define PPC4xx_MACHINE_NAME (virtex_machine_name) -#endif /* !__ASSEMBLY__ */ - -/* We don't need anything mapped. Size of zero will accomplish that. */ -#define PPC4xx_ONB_IO_PADDR 0u -#define PPC4xx_ONB_IO_VADDR 0u -#define PPC4xx_ONB_IO_SIZE 0u - +enum ppc_sys_devices { + VIRTEX_UART, NUM_PPC_SYS_DEVS, +}; +#endif + #endif /* __ASM_VIRTEX_H__ */ #endif /* __KERNEL__ */ diff --git a/trunk/arch/ppc/platforms/4xx/xilinx_ml300.c b/trunk/arch/ppc/platforms/4xx/xilinx_ml300.c index 6e522fefc26f..fb5f0b5e13d1 100644 --- a/trunk/arch/ppc/platforms/4xx/xilinx_ml300.c +++ b/trunk/arch/ppc/platforms/4xx/xilinx_ml300.c @@ -18,9 +18,9 @@ #include #include #include +#include #include -#include #include /* @@ -53,9 +53,24 @@ * ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c */ -const char* virtex_machine_name = "ML300 Reference Design"; +/* Board specifications structures */ +struct ppc_sys_spec *cur_ppc_sys_spec; +struct ppc_sys_spec ppc_sys_specs[] = { + { + /* Only one entry, always assume the same design */ + .ppc_sys_name = "Xilinx ML300 Reference Design", + .mask = 0x00000000, + .value = 0x00000000, + .num_devices = 1, + .device_list = (enum ppc_sys_devices[]) + { + VIRTEX_UART, + }, + }, +}; #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) + static volatile unsigned *powerdown_base = (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR; @@ -80,14 +95,52 @@ ml300_map_io(void) #endif } +/* Early serial support functions */ +static void __init +ml300_early_serial_init(int num, struct plat_serial8250_port *pdata) +{ +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + struct uart_port serial_req; + + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.mapbase = pdata->mapbase; + serial_req.membase = pdata->membase; + serial_req.irq = pdata->irq; + serial_req.uartclk = pdata->uartclk; + serial_req.regshift = pdata->regshift; + serial_req.iotype = pdata->iotype; + serial_req.flags = pdata->flags; + gen550_init(num, &serial_req); +#endif +} + +void __init +ml300_early_serial_map(void) +{ +#ifdef CONFIG_SERIAL_8250 + struct plat_serial8250_port *pdata; + int i = 0; + + pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART); + while(pdata && pdata->flags) + { + pdata->membase = ioremap(pdata->mapbase, 0x100); + ml300_early_serial_init(i, pdata); + pdata++; + i++; + } +#endif /* CONFIG_SERIAL_8250 */ +} + void __init ml300_setup_arch(void) { - virtex_early_serial_map(); + ml300_early_serial_map(); ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */ /* Identify the system */ - printk(KERN_INFO "Xilinx ML300 Reference System (Virtex-II Pro)\n"); + printk(KERN_INFO "Xilinx Virtex-II Pro port\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); } /* Called after board_setup_irq from ppc4xx_init_IRQ(). */ @@ -103,6 +156,8 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, { ppc4xx_init(r3, r4, r5, r6, r7); + identify_ppc_sys_by_id(mfspr(SPRN_PVR)); + ppc_md.setup_arch = ml300_setup_arch; ppc_md.setup_io_mappings = ml300_map_io; ppc_md.init_IRQ = ml300_init_irq; @@ -112,7 +167,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_KGDB - ppc_md.early_serial_map = virtex_early_serial_map; + ppc_md.early_serial_map = ml300_early_serial_map; #endif } diff --git a/trunk/arch/ppc/platforms/4xx/xilinx_ml300.h b/trunk/arch/ppc/platforms/4xx/xilinx_ml300.h new file mode 100644 index 000000000000..3d57332ba820 --- /dev/null +++ b/trunk/arch/ppc/platforms/4xx/xilinx_ml300.h @@ -0,0 +1,45 @@ +/* + * Include file that defines the Xilinx ML300 evaluation board + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_XILINX_ML300_H__ +#define __ASM_XILINX_ML300_H__ + +/* ML300 has a Xilinx Virtex-II Pro processor */ +#include + +#ifndef __ASSEMBLY__ + +#include + +typedef struct board_info { + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +#endif /* !__ASSEMBLY__ */ + +/* We don't need anything mapped. Size of zero will accomplish that. */ +#define PPC4xx_ONB_IO_PADDR 0u +#define PPC4xx_ONB_IO_VADDR 0u +#define PPC4xx_ONB_IO_SIZE 0u + +#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System" + +#endif /* __ASM_XILINX_ML300_H__ */ +#endif /* __KERNEL__ */ diff --git a/trunk/arch/ppc/platforms/4xx/xilinx_ml403.c b/trunk/arch/ppc/platforms/4xx/xilinx_ml403.c index bc3ace3762e7..cb3bf7a2bcbe 100644 --- a/trunk/arch/ppc/platforms/4xx/xilinx_ml403.c +++ b/trunk/arch/ppc/platforms/4xx/xilinx_ml403.c @@ -1,9 +1,11 @@ /* + * arch/ppc/platforms/4xx/xilinx_ml403.c + * * Xilinx ML403 evaluation board initialization * * Author: Grant Likely * - * 2005-2007 (c) Secret Lab Technologies Ltd. + * 2005 (c) Secret Lab Technologies Ltd. * 2002-2004 (c) MontaVista Software, Inc. * * This file is licensed under the terms of the GNU General Public License @@ -20,9 +22,9 @@ #include #include #include +#include #include -#include #include /* @@ -55,9 +57,24 @@ * ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c */ -const char* virtex_machine_name = "ML403 Reference Design"; +/* Board specifications structures */ +struct ppc_sys_spec *cur_ppc_sys_spec; +struct ppc_sys_spec ppc_sys_specs[] = { + { + /* Only one entry, always assume the same design */ + .ppc_sys_name = "Xilinx ML403 Reference Design", + .mask = 0x00000000, + .value = 0x00000000, + .num_devices = 1, + .device_list = (enum ppc_sys_devices[]) + { + VIRTEX_UART, + }, + }, +}; #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) + static volatile unsigned *powerdown_base = (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR; @@ -82,10 +99,47 @@ ml403_map_io(void) #endif } +/* Early serial support functions */ +static void __init +ml403_early_serial_init(int num, struct plat_serial8250_port *pdata) +{ +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + struct uart_port serial_req; + + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.mapbase = pdata->mapbase; + serial_req.membase = pdata->membase; + serial_req.irq = pdata->irq; + serial_req.uartclk = pdata->uartclk; + serial_req.regshift = pdata->regshift; + serial_req.iotype = pdata->iotype; + serial_req.flags = pdata->flags; + gen550_init(num, &serial_req); +#endif +} + +void __init +ml403_early_serial_map(void) +{ +#ifdef CONFIG_SERIAL_8250 + struct plat_serial8250_port *pdata; + int i = 0; + + pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART); + while(pdata && pdata->flags) + { + pdata->membase = ioremap(pdata->mapbase, 0x100); + ml403_early_serial_init(i, pdata); + pdata++; + i++; + } +#endif /* CONFIG_SERIAL_8250 */ +} + void __init ml403_setup_arch(void) { - virtex_early_serial_map(); + ml403_early_serial_map(); ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */ /* Identify the system */ @@ -105,6 +159,8 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, { ppc4xx_init(r3, r4, r5, r6, r7); + identify_ppc_sys_by_id(mfspr(SPRN_PVR)); + ppc_md.setup_arch = ml403_setup_arch; ppc_md.setup_io_mappings = ml403_map_io; ppc_md.init_IRQ = ml403_init_irq; @@ -114,7 +170,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif #ifdef CONFIG_KGDB - ppc_md.early_serial_map = virtex_early_serial_map; + ppc_md.early_serial_map = ml403_early_serial_map; #endif } diff --git a/trunk/arch/ppc/platforms/4xx/xilinx_ml403.h b/trunk/arch/ppc/platforms/4xx/xilinx_ml403.h new file mode 100644 index 000000000000..473596959902 --- /dev/null +++ b/trunk/arch/ppc/platforms/4xx/xilinx_ml403.h @@ -0,0 +1,49 @@ +/* + * arch/ppc/platforms/4xx/xilinx_ml403.h + * + * Include file that defines the Xilinx ML403 reference design + * + * Author: Grant Likely + * + * 2005 (c) Secret Lab Technologies Ltd. + * 2002-2004 (c) MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_XILINX_ML403_H__ +#define __ASM_XILINX_ML403_H__ + +/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */ +#include + +#ifndef __ASSEMBLY__ + +#include + +typedef struct board_info { + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +#endif /* !__ASSEMBLY__ */ + +/* We don't need anything mapped. Size of zero will accomplish that. */ +#define PPC4xx_ONB_IO_PADDR 0u +#define PPC4xx_ONB_IO_VADDR 0u +#define PPC4xx_ONB_IO_SIZE 0u + +#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design" + +#endif /* __ASM_XILINX_ML403_H__ */ +#endif /* __KERNEL__ */ diff --git a/trunk/arch/ppc/platforms/4xx/xparameters/xparameters.h b/trunk/arch/ppc/platforms/4xx/xparameters/xparameters.h index 01aa043ff381..66ec5f35f306 100644 --- a/trunk/arch/ppc/platforms/4xx/xparameters/xparameters.h +++ b/trunk/arch/ppc/platforms/4xx/xparameters/xparameters.h @@ -34,63 +34,3 @@ .io_type = SERIAL_IO_MEM, \ }, #endif - -/* - * A few reasonable defaults for the #defines which could be missing depending - * on the IP version or variant (e.g. OPB vs PLB) - */ - -#ifndef XPAR_EMAC_0_CAM_EXIST -#define XPAR_EMAC_0_CAM_EXIST 0 -#endif -#ifndef XPAR_EMAC_0_JUMBO_EXIST -#define XPAR_EMAC_0_JUMBO_EXIST 0 -#endif -#ifndef XPAR_EMAC_0_TX_DRE_TYPE -#define XPAR_EMAC_0_TX_DRE_TYPE 0 -#endif -#ifndef XPAR_EMAC_0_RX_DRE_TYPE -#define XPAR_EMAC_0_RX_DRE_TYPE 0 -#endif -#ifndef XPAR_EMAC_0_TX_INCLUDE_CSUM -#define XPAR_EMAC_0_TX_INCLUDE_CSUM 0 -#endif -#ifndef XPAR_EMAC_0_RX_INCLUDE_CSUM -#define XPAR_EMAC_0_RX_INCLUDE_CSUM 0 -#endif - -#ifndef XPAR_EMAC_1_CAM_EXIST -#define XPAR_EMAC_1_CAM_EXIST 0 -#endif -#ifndef XPAR_EMAC_1_JUMBO_EXIST -#define XPAR_EMAC_1_JUMBO_EXIST 0 -#endif -#ifndef XPAR_EMAC_1_TX_DRE_TYPE -#define XPAR_EMAC_1_TX_DRE_TYPE 0 -#endif -#ifndef XPAR_EMAC_1_RX_DRE_TYPE -#define XPAR_EMAC_1_RX_DRE_TYPE 0 -#endif -#ifndef XPAR_EMAC_1_TX_INCLUDE_CSUM -#define XPAR_EMAC_1_TX_INCLUDE_CSUM 0 -#endif -#ifndef XPAR_EMAC_1_RX_INCLUDE_CSUM -#define XPAR_EMAC_1_RX_INCLUDE_CSUM 0 -#endif - -#ifndef XPAR_GPIO_0_IS_DUAL -#define XPAR_GPIO_0_IS_DUAL 0 -#endif -#ifndef XPAR_GPIO_1_IS_DUAL -#define XPAR_GPIO_1_IS_DUAL 0 -#endif -#ifndef XPAR_GPIO_2_IS_DUAL -#define XPAR_GPIO_2_IS_DUAL 0 -#endif -#ifndef XPAR_GPIO_3_IS_DUAL -#define XPAR_GPIO_3_IS_DUAL 0 -#endif -#ifndef XPAR_GPIO_4_IS_DUAL -#define XPAR_GPIO_4_IS_DUAL 0 -#endif - diff --git a/trunk/arch/ppc/platforms/rpxclassic.h b/trunk/arch/ppc/platforms/rpxclassic.h index a3c1118e5b09..57a2a55dab8c 100644 --- a/trunk/arch/ppc/platforms/rpxclassic.h +++ b/trunk/arch/ppc/platforms/rpxclassic.h @@ -69,6 +69,10 @@ extern bd_t m8xx_board_info; #define BCSR2_QSPACESEL ((uint)0x00004000) #define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */ +#if defined(CONFIG_HTDMSOUND) +#include +#endif + /* define IO_BASE for pcmcia, CLLF only */ #if !defined(CONFIG_PCI) #define _IO_BASE 0x80000000 diff --git a/trunk/arch/ppc/platforms/rpxhiox.h b/trunk/arch/ppc/platforms/rpxhiox.h new file mode 100644 index 000000000000..c3fa5a653762 --- /dev/null +++ b/trunk/arch/ppc/platforms/rpxhiox.h @@ -0,0 +1,41 @@ +/* + * The Embedded Planet HIOX expansion card definitions. + * There were a few different versions of these cards, but only + * the one that escaped real production is defined here. + * + * Copyright (c) 2000 Dan Malek (dmalek@jlc.net) + */ +#ifndef __MACH_RPX_HIOX_DEFS +#define __MACH_RPX_HIOX_DEFS + +#define HIOX_CSR_ADDR ((uint)0xfac00000) +#define HIOX_CSR_SIZE ((uint)(4 * 1024)) +#define HIOX_CSR0_ADDR HIOX_CSR_ADDR +#define HIOX_CSR4_ADDR ((uint)0xfac00004) + +#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00) +#define HIOX_CSR0_ENSCC2 ((uint)0x80000000) +#define HIOX_CSR0_ENSMC2 ((uint)0x04000000) +#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000) +#define HIOX_CSR0_VDORST_HL ((uint)0x01000000) +#define HIOX_CSR0_RS232SEL ((uint)0x0000c000) +#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000) +#define HIOX_CSR0_SMC1SEL ((uint)0x00008000) +#define HIOX_CSR0_SCC1SEL ((uint)0x00004000) +#define HIOX_CSR0_ENTOUCH ((uint)0x00000080) +#define HIOX_CSR0_PDOWN100 ((uint)0x00000060) +#define HIOX_CSR0_PDOWN10 ((uint)0x00000040) +#define HIOX_CSR0_PDOWN1 ((uint)0x00000020) +#define HIOX_CSR0_TSELSPI ((uint)0x00000010) +#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008) +#define HIOX_CSR4_DEFAULT ((uint)0x00000000) +#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000) +#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000) +#define HIOX_CSR4_ENAUDIO ((uint)0x00000080) +#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */ +#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020) +#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010) +#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008) +#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007) + +#endif diff --git a/trunk/arch/ppc/platforms/rpxlite.h b/trunk/arch/ppc/platforms/rpxlite.h index b615501d55fc..719780646270 100644 --- a/trunk/arch/ppc/platforms/rpxlite.h +++ b/trunk/arch/ppc/platforms/rpxlite.h @@ -57,6 +57,10 @@ extern bd_t m8xx_board_info; #define BCSR1_PCVCTL6 ((uint)0x00020000) #define BCSR1_PCVCTL7 ((uint)0x00010000) +#if defined(CONFIG_HTDMSOUND) +#include +#endif + /* define IO_BASE for pcmcia */ #define _IO_BASE 0x80000000 #define _IO_BASE_SIZE 0x1000 diff --git a/trunk/arch/ppc/syslib/Makefile b/trunk/arch/ppc/syslib/Makefile index 95694159b226..09911118c675 100644 --- a/trunk/arch/ppc/syslib/Makefile +++ b/trunk/arch/ppc/syslib/Makefile @@ -18,8 +18,7 @@ obj-$(CONFIG_440SP) += ibm440gx_common.o ibm440sp_common.o obj-$(CONFIG_440SPE) += ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o ifeq ($(CONFIG_4xx),y) ifeq ($(CONFIG_XILINX_VIRTEX),y) -obj-$(CONFIG_40x) += xilinx_pic.o -obj-y += virtex_devices.o +obj-$(CONFIG_40x) += xilinx_pic.o ppc_sys.o else ifeq ($(CONFIG_403),y) obj-$(CONFIG_40x) += ppc403_pic.o diff --git a/trunk/arch/ppc/syslib/cpc710.h b/trunk/arch/ppc/syslib/cpc710.h new file mode 100644 index 000000000000..5299bf8b5d01 --- /dev/null +++ b/trunk/arch/ppc/syslib/cpc710.h @@ -0,0 +1,81 @@ +/* + * Definitions for the IBM CPC710 PCI Host Bridge + * + * Author: Matt Porter + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __PPC_PLATFORMS_CPC710_H +#define __PPC_PLATFORMS_CPC710_H + +/* General bridge and memory controller registers */ +#define PIDR 0xff000008 +#define CNFR 0xff00000c +#define RSTR 0xff000010 +#define UCTL 0xff001000 +#define MPSR 0xff001010 +#define SIOC 0xff001020 +#define ABCNTL 0xff001030 +#define SRST 0xff001040 +#define ERRC 0xff001050 +#define SESR 0xff001060 +#define SEAR 0xff001070 +#define SIOC1 0xff001090 +#define PGCHP 0xff001100 +#define GPDIR 0xff001130 +#define GPOUT 0xff001150 +#define ATAS 0xff001160 +#define AVDG 0xff001170 +#define MCCR 0xff001200 +#define MESR 0xff001220 +#define MEAR 0xff001230 +#define MCER0 0xff001300 +#define MCER1 0xff001310 +#define MCER2 0xff001320 +#define MCER3 0xff001330 +#define MCER4 0xff001340 +#define MCER5 0xff001350 +#define MCER6 0xff001360 +#define MCER7 0xff001370 + +/* + * PCI32/64 configuration registers + * Given as offsets from their + * respective physical segment BAR + */ +#define PIBAR 0x000f7800 +#define PMBAR 0x000f7810 +#define MSIZE 0x000f7f40 +#define IOSIZE 0x000f7f60 +#define SMBAR 0x000f7f80 +#define SIBAR 0x000f7fc0 +#define PSSIZE 0x000f8100 +#define PPSIZE 0x000f8110 +#define BARPS 0x000f8120 +#define BARPP 0x000f8130 +#define PSBAR 0x000f8140 +#define PPBAR 0x000f8150 +#define BPMDLK 0x000f8200 /* Bottom of Peripheral Memory Space */ +#define TPMDLK 0x000f8210 /* Top of Peripheral Memory Space */ +#define BIODLK 0x000f8220 /* Bottom of Peripheral I/O Space */ +#define TIODLK 0x000f8230 /* Top of Perioheral I/O Space */ +#define DLKCTRL 0x000f8240 /* Deadlock control */ +#define DLKDEV 0x000f8250 /* Deadlock device */ + +/* System standard configuration registers space */ +#define DCR 0xff200000 +#define DID 0xff200004 +#define BAR 0xff200018 + +/* Device specific configuration space */ +#define PCIENB 0xff201000 + +/* Configuration space registers */ +#define CPC710_BUS_NUMBER 0x40 +#define CPC710_SUB_BUS_NUMBER 0x41 + +#endif /* __PPC_PLATFORMS_CPC710_H */ diff --git a/trunk/arch/ppc/syslib/m8xx_setup.c b/trunk/arch/ppc/syslib/m8xx_setup.c index 9caf850c9b38..01e48d88f22d 100644 --- a/trunk/arch/ppc/syslib/m8xx_setup.c +++ b/trunk/arch/ppc/syslib/m8xx_setup.c @@ -413,7 +413,7 @@ m8xx_map_io(void) io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO); #endif #endif -#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX) +#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX) io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO); #endif #ifdef CONFIG_FADS diff --git a/trunk/arch/ppc/syslib/ppc4xx_sgdma.c b/trunk/arch/ppc/syslib/ppc4xx_sgdma.c index 5dadca3e0d61..2f83e162971f 100644 --- a/trunk/arch/ppc/syslib/ppc4xx_sgdma.c +++ b/trunk/arch/ppc/syslib/ppc4xx_sgdma.c @@ -23,10 +23,10 @@ #include #include #include +#include #include #include -#include #include void diff --git a/trunk/arch/ppc/syslib/virtex_devices.c b/trunk/arch/ppc/syslib/virtex_devices.c deleted file mode 100644 index 16546788e23b..000000000000 --- a/trunk/arch/ppc/syslib/virtex_devices.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Virtex hard ppc405 core common device listing - * - * Copyright 2005-2007 Secret Lab Technologies Ltd. - * Copyright 2005 Freescale Semiconductor Inc. - * Copyright 2002-2004 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * UARTLITE: shortcut macro for single instance - */ -#define XPAR_UARTLITE(num) { \ - .name = "uartlite", \ - .id = num, \ - .num_resources = 2, \ - .resource = (struct resource[]) { \ - { \ - .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \ - .end = XPAR_UARTLITE_##num##_HIGHADDR, \ - .flags = IORESOURCE_MEM, \ - }, \ - { \ - .start = XPAR_INTC_0_UARTLITE_##num##_VEC_ID, \ - .flags = IORESOURCE_IRQ, \ - }, \ - }, \ -} - -/* - * Full UART: shortcut macro for single instance + platform data structure - */ -#define XPAR_UART(num) { \ - .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \ - .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \ - .iotype = UPIO_MEM, \ - .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \ - .flags = UPF_BOOT_AUTOCONF, \ - .regshift = 2, \ -} - -/* - * SystemACE: shortcut macro for single instance - */ -#define XPAR_SYSACE(num) { \ - .name = "xsysace", \ - .id = XPAR_SYSACE_##num##_DEVICE_ID, \ - .num_resources = 2, \ - .resource = (struct resource[]) { \ - { \ - .start = XPAR_SYSACE_##num##_BASEADDR, \ - .end = XPAR_SYSACE_##num##_HIGHADDR, \ - .flags = IORESOURCE_MEM, \ - }, \ - { \ - .start = XPAR_INTC_0_SYSACE_##num##_VEC_ID, \ - .flags = IORESOURCE_IRQ, \ - }, \ - }, \ -} - - -/* UART 8250 driver platform data table */ -struct plat_serial8250_port virtex_serial_platform_data[] = { -#if defined(XPAR_UARTNS550_0_BASEADDR) - XPAR_UART(0), -#endif -#if defined(XPAR_UARTNS550_1_BASEADDR) - XPAR_UART(1), -#endif -#if defined(XPAR_UARTNS550_2_BASEADDR) - XPAR_UART(2), -#endif -#if defined(XPAR_UARTNS550_3_BASEADDR) - XPAR_UART(3), -#endif -#if defined(XPAR_UARTNS550_4_BASEADDR) - XPAR_UART(4), -#endif -#if defined(XPAR_UARTNS550_5_BASEADDR) - XPAR_UART(5), -#endif -#if defined(XPAR_UARTNS550_6_BASEADDR) - XPAR_UART(6), -#endif -#if defined(XPAR_UARTNS550_7_BASEADDR) - XPAR_UART(7), -#endif - { }, /* terminated by empty record */ -}; - - -struct platform_device virtex_platform_devices[] = { - /* UARTLITE instances */ -#if defined(XPAR_UARTLITE_0_BASEADDR) - XPAR_UARTLITE(0), -#endif -#if defined(XPAR_UARTLITE_1_BASEADDR) - XPAR_UARTLITE(1), -#endif -#if defined(XPAR_UARTLITE_2_BASEADDR) - XPAR_UARTLITE(2), -#endif -#if defined(XPAR_UARTLITE_3_BASEADDR) - XPAR_UARTLITE(3), -#endif -#if defined(XPAR_UARTLITE_4_BASEADDR) - XPAR_UARTLITE(4), -#endif -#if defined(XPAR_UARTLITE_5_BASEADDR) - XPAR_UARTLITE(5), -#endif -#if defined(XPAR_UARTLITE_6_BASEADDR) - XPAR_UARTLITE(6), -#endif -#if defined(XPAR_UARTLITE_7_BASEADDR) - XPAR_UARTLITE(7), -#endif - - /* Full UART instances */ -#if defined(XPAR_UARTNS550_0_BASEADDR) - { - .name = "serial8250", - .id = 0, - .dev.platform_data = virtex_serial_platform_data, - }, -#endif - - /* SystemACE instances */ -#if defined(XPAR_SYSACE_0_BASEADDR) - XPAR_SYSACE(0), -#endif -#if defined(XPAR_SYSACE_1_BASEADDR) - XPAR_SYSACE(1), -#endif - - /* ML300/403 reference design framebuffer */ -#if defined(XPAR_TFT_0_BASEADDR) - { - .name = "xilinxfb", - .id = 0, - .num_resources = 1, - .resource = (struct resource[]) { - { - .start = XPAR_TFT_0_BASEADDR, - .end = XPAR_TFT_0_BASEADDR+7, - .flags = IORESOURCE_IO, - }, - }, - }, -#endif -}; - -/* Early serial support functions */ -static void __init -virtex_early_serial_init(int num, struct plat_serial8250_port *pdata) -{ -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) - struct uart_port serial_req; - - memset(&serial_req, 0, sizeof(serial_req)); - serial_req.mapbase = pdata->mapbase; - serial_req.membase = pdata->membase; - serial_req.irq = pdata->irq; - serial_req.uartclk = pdata->uartclk; - serial_req.regshift = pdata->regshift; - serial_req.iotype = pdata->iotype; - serial_req.flags = pdata->flags; - gen550_init(num, &serial_req); -#endif -} - -void __init -virtex_early_serial_map(void) -{ -#ifdef CONFIG_SERIAL_8250 - struct plat_serial8250_port *pdata; - int i = 0; - - pdata = virtex_serial_platform_data; - while(pdata && pdata->flags) { - pdata->membase = ioremap(pdata->mapbase, 0x100); - virtex_early_serial_init(i, pdata); - pdata++; - i++; - } -#endif /* CONFIG_SERIAL_8250 */ -} - -/* - * default fixup routine; do nothing and return success. - * - * Reimplement this routine in your custom board support file to - * override the default behaviour - */ -int __attribute__ ((weak)) -virtex_device_fixup(struct platform_device *dev) -{ - return 0; -} - -static int __init virtex_init(void) -{ - struct platform_device *index = virtex_platform_devices; - unsigned int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(virtex_platform_devices); i++, index++) { - if (virtex_device_fixup(index) != 0) - continue; - - if (platform_device_register(index)) { - ret = 1; - printk(KERN_ERR "cannot register dev %s:%d\n", - index->name, index->id); - } - } - return ret; -} - -subsys_initcall(virtex_init); diff --git a/trunk/arch/ppc/syslib/virtex_devices.h b/trunk/arch/ppc/syslib/virtex_devices.h deleted file mode 100644 index 4a17dd3927c1..000000000000 --- a/trunk/arch/ppc/syslib/virtex_devices.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Common support header for virtex ppc405 platforms - * - * Copyright 2007 Secret Lab Technologies Ltd. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#ifndef __ASM_VIRTEX_DEVICES_H__ -#define __ASM_VIRTEX_DEVICES_H__ - -#include - -void __init virtex_early_serial_map(void); - -/* Prototype for device fixup routine. Implement this routine in the - * board specific fixup code and the generic setup code will call it for - * each device is the platform device list. - * - * If the hook returns a non-zero value, then the device will not get - * registered with the platform bus - */ -int virtex_device_fixup(struct platform_device *dev); - -#endif /* __ASM_VIRTEX_DEVICES_H__ */ diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index e6ec418093e5..0f293aa7b0fa 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -41,11 +41,6 @@ config GENERIC_HWEIGHT config GENERIC_TIME def_bool y -config GENERIC_BUG - bool - depends on BUG - default y - config NO_IOMEM def_bool y @@ -519,14 +514,6 @@ config KEXEC current kernel, and to start another kernel. It is like a reboot but is independent of hardware/microcode support. -config ZFCPDUMP - tristate "zfcpdump support" - select SMP - default n - help - Select this option if you want to build an zfcpdump enabled kernel. - Refer to "Documentation/s390/zfcpdump.txt" for more details on this. - endmenu source "net/Kconfig" diff --git a/trunk/arch/s390/Makefile b/trunk/arch/s390/Makefile index 68441e0e74b6..b1e558496469 100644 --- a/trunk/arch/s390/Makefile +++ b/trunk/arch/s390/Makefile @@ -67,10 +67,8 @@ endif ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y) cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE) -ifneq ($(call cc-option-yn,-mstack-size=8192),y) cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD) endif -endif ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack @@ -105,9 +103,6 @@ install: vmlinux image: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ -zfcpdump: - $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ - archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/trunk/arch/s390/appldata/appldata_base.c b/trunk/arch/s390/appldata/appldata_base.c index ee89b33145d5..0c3cf4b16ae4 100644 --- a/trunk/arch/s390/appldata/appldata_base.c +++ b/trunk/arch/s390/appldata/appldata_base.c @@ -668,7 +668,45 @@ EXPORT_SYMBOL_GPL(appldata_register_ops); EXPORT_SYMBOL_GPL(appldata_unregister_ops); EXPORT_SYMBOL_GPL(appldata_diag); +#ifdef MODULE +/* + * Kernel symbols needed by appldata_mem and appldata_os modules. + * However, if this file is compiled as a module (for testing only), these + * symbols are not exported. In this case, we define them locally and export + * those. + */ +void si_swapinfo(struct sysinfo *val) +{ + val->freeswap = -1ul; + val->totalswap = -1ul; +} + +unsigned long avenrun[3] = {-1 - FIXED_1/200, -1 - FIXED_1/200, + -1 - FIXED_1/200}; +int nr_threads = -1; + +void get_full_page_state(struct page_state *ps) +{ + memset(ps, -1, sizeof(struct page_state)); +} + +unsigned long nr_running(void) +{ + return -1; +} + +unsigned long nr_iowait(void) +{ + return -1; +} + +/*unsigned long nr_context_switches(void) +{ + return -1; +}*/ +#endif /* MODULE */ EXPORT_SYMBOL_GPL(si_swapinfo); EXPORT_SYMBOL_GPL(nr_threads); EXPORT_SYMBOL_GPL(nr_running); EXPORT_SYMBOL_GPL(nr_iowait); +//EXPORT_SYMBOL_GPL(nr_context_switches); diff --git a/trunk/arch/s390/appldata/appldata_net_sum.c b/trunk/arch/s390/appldata/appldata_net_sum.c index 2180ac105b05..f64b8c867ae2 100644 --- a/trunk/arch/s390/appldata/appldata_net_sum.c +++ b/trunk/arch/s390/appldata/appldata_net_sum.c @@ -107,7 +107,10 @@ static void appldata_get_net_sum_data(void *data) tx_dropped = 0; collisions = 0; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->get_stats == NULL) { + continue; + } stats = dev->get_stats(dev); rx_packets += stats->rx_packets; tx_packets += stats->tx_packets; diff --git a/trunk/arch/s390/crypto/aes_s390.c b/trunk/arch/s390/crypto/aes_s390.c index 3660ca6a3306..91636353f6f0 100644 --- a/trunk/arch/s390/crypto/aes_s390.c +++ b/trunk/arch/s390/crypto/aes_s390.c @@ -119,8 +119,7 @@ static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-s390", .cra_priority = CRYPT_S390_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER | - CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, @@ -207,8 +206,7 @@ static struct crypto_alg ecb_aes_alg = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -302,8 +300,7 @@ static struct crypto_alg cbc_aes_alg = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -336,14 +333,10 @@ static int __init aes_init(void) return -EOPNOTSUPP; /* z9 109 and z9 BC/EC only support 128 bit key length */ - if (keylen_flag == AES_KEYLEN_128) { - aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE; - ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; - cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; + if (keylen_flag == AES_KEYLEN_128) printk(KERN_INFO "aes_s390: hardware acceleration only available for" "128 bit keys\n"); - } ret = crypto_register_alg(&aes_alg); if (ret) diff --git a/trunk/arch/s390/crypto/sha1_s390.c b/trunk/arch/s390/crypto/sha1_s390.c index af4460ec381f..969639f31977 100644 --- a/trunk/arch/s390/crypto/sha1_s390.c +++ b/trunk/arch/s390/crypto/sha1_s390.c @@ -25,100 +25,99 @@ */ #include #include +#include #include - +#include +#include #include "crypt_s390.h" #define SHA1_DIGEST_SIZE 20 #define SHA1_BLOCK_SIZE 64 -struct s390_sha1_ctx { - u64 count; /* message length */ +struct crypt_s390_sha1_ctx { + u64 count; u32 state[5]; - u8 buf[2 * SHA1_BLOCK_SIZE]; + u32 buf_len; + u8 buffer[2 * SHA1_BLOCK_SIZE]; }; static void sha1_init(struct crypto_tfm *tfm) { - struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - - sctx->state[0] = 0x67452301; - sctx->state[1] = 0xEFCDAB89; - sctx->state[2] = 0x98BADCFE; - sctx->state[3] = 0x10325476; - sctx->state[4] = 0xC3D2E1F0; - sctx->count = 0; + struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + ctx->count = 0; + ctx->buf_len = 0; } static void sha1_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) { - struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - unsigned int index; - int ret; - - /* how much is already in the buffer? */ - index = sctx->count & 0x3f; - - sctx->count += len; - - if (index + len < SHA1_BLOCK_SIZE) - goto store; - - /* process one stored block */ - if (index) { - memcpy(sctx->buf + index, data, SHA1_BLOCK_SIZE - index); - ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf, - SHA1_BLOCK_SIZE); - BUG_ON(ret != SHA1_BLOCK_SIZE); - data += SHA1_BLOCK_SIZE - index; - len -= SHA1_BLOCK_SIZE - index; + struct crypt_s390_sha1_ctx *sctx; + long imd_len; + + sctx = crypto_tfm_ctx(tfm); + sctx->count += len * 8; /* message bit length */ + + /* anything in buffer yet? -> must be completed */ + if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { + /* complete full block and hash */ + memcpy(sctx->buffer + sctx->buf_len, data, + SHA1_BLOCK_SIZE - sctx->buf_len); + crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, + SHA1_BLOCK_SIZE); + data += SHA1_BLOCK_SIZE - sctx->buf_len; + len -= SHA1_BLOCK_SIZE - sctx->buf_len; + sctx->buf_len = 0; } - /* process as many blocks as possible */ - if (len >= SHA1_BLOCK_SIZE) { - ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, - len & ~(SHA1_BLOCK_SIZE - 1)); - BUG_ON(ret != (len & ~(SHA1_BLOCK_SIZE - 1))); - data += ret; - len -= ret; + /* rest of data contains full blocks? */ + imd_len = len & ~0x3ful; + if (imd_len) { + crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len); + data += imd_len; + len -= imd_len; + } + /* anything left? store in buffer */ + if (len) { + memcpy(sctx->buffer + sctx->buf_len , data, len); + sctx->buf_len += len; } - -store: - /* anything left? */ - if (len) - memcpy(sctx->buf + index , data, len); } -/* Add padding and return the message digest. */ -static void sha1_final(struct crypto_tfm *tfm, u8 *out) -{ - struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - u64 bits; - unsigned int index, end; - int ret; - /* must perform manual padding */ - index = sctx->count & 0x3f; - end = (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE); +static void pad_message(struct crypt_s390_sha1_ctx* sctx) +{ + int index; + index = sctx->buf_len; + sctx->buf_len = (sctx->buf_len < 56) ? + SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; /* start pad with 1 */ - sctx->buf[index] = 0x80; - + sctx->buffer[index] = 0x80; /* pad with zeros */ index++; - memset(sctx->buf + index, 0x00, end - index - 8); - - /* append message length */ - bits = sctx->count * 8; - memcpy(sctx->buf + end - 8, &bits, sizeof(bits)); + memset(sctx->buffer + index, 0x00, sctx->buf_len - index); + /* append length */ + memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, + sizeof sctx->count); +} - ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf, end); - BUG_ON(ret != end); +/* Add padding and return the message digest. */ +static void sha1_final(struct crypto_tfm *tfm, u8 *out) +{ + struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); + /* must perform manual padding */ + pad_message(sctx); + crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); /* copy digest to out */ memcpy(out, sctx->state, SHA1_DIGEST_SIZE); - /* wipe context */ memset(sctx, 0, sizeof *sctx); } @@ -129,7 +128,7 @@ static struct crypto_alg alg = { .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct s390_sha1_ctx), + .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .digest = { diff --git a/trunk/arch/s390/crypto/sha256_s390.c b/trunk/arch/s390/crypto/sha256_s390.c index 2ced3330bce0..78436c696d37 100644 --- a/trunk/arch/s390/crypto/sha256_s390.c +++ b/trunk/arch/s390/crypto/sha256_s390.c @@ -26,7 +26,7 @@ #define SHA256_BLOCK_SIZE 64 struct s390_sha256_ctx { - u64 count; /* message length */ + u64 count; u32 state[8]; u8 buf[2 * SHA256_BLOCK_SIZE]; }; @@ -54,9 +54,10 @@ static void sha256_update(struct crypto_tfm *tfm, const u8 *data, int ret; /* how much is already in the buffer? */ - index = sctx->count & 0x3f; + index = sctx->count / 8 & 0x3f; - sctx->count += len; + /* update message bit length */ + sctx->count += len * 8; if ((index + len) < SHA256_BLOCK_SIZE) goto store; @@ -86,17 +87,12 @@ static void sha256_update(struct crypto_tfm *tfm, const u8 *data, memcpy(sctx->buf + index , data, len); } -/* Add padding and return the message digest */ -static void sha256_final(struct crypto_tfm *tfm, u8 *out) +static void pad_message(struct s390_sha256_ctx* sctx) { - struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm); - u64 bits; - unsigned int index, end; - int ret; + int index, end; - /* must perform manual padding */ - index = sctx->count & 0x3f; - end = (index < 56) ? SHA256_BLOCK_SIZE : (2 * SHA256_BLOCK_SIZE); + index = sctx->count / 8 & 0x3f; + end = index < 56 ? SHA256_BLOCK_SIZE : 2 * SHA256_BLOCK_SIZE; /* start pad with 1 */ sctx->buf[index] = 0x80; @@ -106,11 +102,21 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out) memset(sctx->buf + index, 0x00, end - index - 8); /* append message length */ - bits = sctx->count * 8; - memcpy(sctx->buf + end - 8, &bits, sizeof(bits)); + memcpy(sctx->buf + end - 8, &sctx->count, sizeof sctx->count); + + sctx->count = end * 8; +} + +/* Add padding and return the message digest */ +static void sha256_final(struct crypto_tfm *tfm, u8 *out) +{ + struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm); + + /* must perform manual padding */ + pad_message(sctx); - ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf, end); - BUG_ON(ret != end); + crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf, + sctx->count / 8); /* copy digest to out */ memcpy(out, sctx->state, SHA256_DIGEST_SIZE); diff --git a/trunk/arch/s390/defconfig b/trunk/arch/s390/defconfig index 0e4da8a7d826..741d2bbb2b37 100644 --- a/trunk/arch/s390/defconfig +++ b/trunk/arch/s390/defconfig @@ -12,7 +12,6 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_TIME=y -CONFIG_GENERIC_BUG=y CONFIG_NO_IOMEM=y CONFIG_S390=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -167,7 +166,6 @@ CONFIG_NO_IDLE_HZ=y CONFIG_NO_IDLE_HZ_INIT=y CONFIG_S390_HYPFS_FS=y CONFIG_KEXEC=y -# CONFIG_ZFCPDUMP is not set # # Networking @@ -707,7 +705,6 @@ CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set -CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set diff --git a/trunk/arch/s390/kernel/Makefile b/trunk/arch/s390/kernel/Makefile index 3195d375bd51..5492d25d7d69 100644 --- a/trunk/arch/s390/kernel/Makefile +++ b/trunk/arch/s390/kernel/Makefile @@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o + semaphore.o s390_ext.o debug.o irq.o ipl.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/trunk/arch/s390/kernel/compat_linux.c b/trunk/arch/s390/kernel/compat_linux.c index 5236fdb17fcb..664c669b1856 100644 --- a/trunk/arch/s390/kernel/compat_linux.c +++ b/trunk/arch/s390/kernel/compat_linux.c @@ -495,34 +495,29 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) * sys32_execve() executes a new program after the asm stub has set * things up for us. This should basically do what I want it to. */ -asmlinkage long sys32_execve(void) +asmlinkage long +sys32_execve(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); - char *filename; - unsigned long result; - int rc; + int error; + char * filename; - filename = getname(compat_ptr(regs->orig_gpr2)); - if (IS_ERR(filename)) { - result = PTR_ERR(filename); + filename = getname(compat_ptr(regs.orig_gpr2)); + error = PTR_ERR(filename); + if (IS_ERR(filename)) goto out; + error = compat_do_execve(filename, compat_ptr(regs.gprs[3]), + compat_ptr(regs.gprs[4]), ®s); + if (error == 0) + { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + current->thread.fp_regs.fpc=0; + asm volatile("sfpc %0,0" : : "d" (0)); } - rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]), - compat_ptr(regs->gprs[4]), regs); - if (rc) { - result = rc; - goto out_putname; - } - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - current->thread.fp_regs.fpc=0; - asm volatile("sfpc %0,0" : : "d" (0)); - result = regs->gprs[2]; -out_putname: putname(filename); out: - return result; + return error; } @@ -923,20 +918,19 @@ asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count) return sys_write(fd, buf, count); } -asmlinkage long sys32_clone(void) +asmlinkage long sys32_clone(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); - unsigned long clone_flags; - unsigned long newsp; + unsigned long clone_flags; + unsigned long newsp; int __user *parent_tidptr, *child_tidptr; - clone_flags = regs->gprs[3] & 0xffffffffUL; - newsp = regs->orig_gpr2 & 0x7fffffffUL; - parent_tidptr = compat_ptr(regs->gprs[4]); - child_tidptr = compat_ptr(regs->gprs[5]); - if (!newsp) - newsp = regs->gprs[15]; - return do_fork(clone_flags, newsp, regs, 0, + clone_flags = regs.gprs[3] & 0xffffffffUL; + newsp = regs.orig_gpr2 & 0x7fffffffUL; + parent_tidptr = compat_ptr(regs.gprs[4]); + child_tidptr = compat_ptr(regs.gprs[5]); + if (!newsp) + newsp = regs.gprs[15]; + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } diff --git a/trunk/arch/s390/kernel/compat_signal.c b/trunk/arch/s390/kernel/compat_signal.c index 80a54a0149ab..887a9881d0d0 100644 --- a/trunk/arch/s390/kernel/compat_signal.c +++ b/trunk/arch/s390/kernel/compat_signal.c @@ -255,9 +255,9 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, } asmlinkage long -sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss) +sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, + struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); stack_t kss, koss; unsigned long ss_sp; int ret, err = 0; @@ -344,9 +344,8 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) return 0; } -asmlinkage long sys32_sigreturn(void) +asmlinkage long sys32_sigreturn(struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; sigset_t set; @@ -371,9 +370,8 @@ asmlinkage long sys32_sigreturn(void) return 0; } -asmlinkage long sys32_rt_sigreturn(void) +asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; sigset_t set; stack_t st; @@ -409,8 +407,8 @@ asmlinkage long sys32_rt_sigreturn(void) return regs->gprs[2]; badframe: - force_sig(SIGSEGV, current); - return 0; + force_sig(SIGSEGV, current); + return 0; } /* diff --git a/trunk/arch/s390/kernel/dis.c b/trunk/arch/s390/kernel/dis.c deleted file mode 100644 index dabaf98943d0..000000000000 --- a/trunk/arch/s390/kernel/dis.c +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * arch/s390/kernel/dis.c - * - * Disassemble s390 instructions. - * - * Copyright IBM Corp. 2007 - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_64BIT -#define ONELONG "%08lx: " -#else /* CONFIG_64BIT */ -#define ONELONG "%016lx: " -#endif /* CONFIG_64BIT */ - -#define OPERAND_GPR 0x1 /* Operand printed as %rx */ -#define OPERAND_FPR 0x2 /* Operand printed as %fx */ -#define OPERAND_AR 0x4 /* Operand printed as %ax */ -#define OPERAND_CR 0x8 /* Operand printed as %cx */ -#define OPERAND_DISP 0x10 /* Operand printed as displacement */ -#define OPERAND_BASE 0x20 /* Operand printed as base register */ -#define OPERAND_INDEX 0x40 /* Operand printed as index register */ -#define OPERAND_PCREL 0x80 /* Operand printed as pc-relative symbol */ -#define OPERAND_SIGNED 0x100 /* Operand printed as signed value */ -#define OPERAND_LENGTH 0x200 /* Operand printed as length (+1) */ - -enum { - UNUSED, /* Indicates the end of the operand list */ - R_8, /* GPR starting at position 8 */ - R_12, /* GPR starting at position 12 */ - R_16, /* GPR starting at position 16 */ - R_20, /* GPR starting at position 20 */ - R_24, /* GPR starting at position 24 */ - R_28, /* GPR starting at position 28 */ - R_32, /* GPR starting at position 32 */ - F_8, /* FPR starting at position 8 */ - F_12, /* FPR starting at position 12 */ - F_16, /* FPR starting at position 16 */ - F_20, /* FPR starting at position 16 */ - F_24, /* FPR starting at position 24 */ - F_28, /* FPR starting at position 28 */ - F_32, /* FPR starting at position 32 */ - A_8, /* Access reg. starting at position 8 */ - A_12, /* Access reg. starting at position 12 */ - A_24, /* Access reg. starting at position 24 */ - A_28, /* Access reg. starting at position 28 */ - C_8, /* Control reg. starting at position 8 */ - C_12, /* Control reg. starting at position 12 */ - B_16, /* Base register starting at position 16 */ - B_32, /* Base register starting at position 32 */ - X_12, /* Index register starting at position 12 */ - D_20, /* Displacement starting at position 20 */ - D_36, /* Displacement starting at position 36 */ - D20_20, /* 20 bit displacement starting at 20 */ - L4_8, /* 4 bit length starting at position 8 */ - L4_12, /* 4 bit length starting at position 12 */ - L8_8, /* 8 bit length starting at position 8 */ - U4_8, /* 4 bit unsigned value starting at 8 */ - U4_12, /* 4 bit unsigned value starting at 12 */ - U4_16, /* 4 bit unsigned value starting at 16 */ - U4_20, /* 4 bit unsigned value starting at 20 */ - U8_8, /* 8 bit unsigned value starting at 8 */ - U8_16, /* 8 bit unsigned value starting at 16 */ - I16_16, /* 16 bit signed value starting at 16 */ - U16_16, /* 16 bit unsigned value starting at 16 */ - J16_16, /* PC relative jump offset at 16 */ - J32_16, /* PC relative long offset at 16 */ - I32_16, /* 32 bit signed value starting at 16 */ - U32_16, /* 32 bit unsigned value starting at 16 */ - M_16, /* 4 bit optional mask starting at 16 */ - RO_28, /* optional GPR starting at position 28 */ -}; - -/* - * Enumeration of the different instruction formats. - * For details consult the principles of operation. - */ -enum { - INSTR_INVALID, - INSTR_E, INSTR_RIE_RRP, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, - INSTR_RIL_UP, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP, - INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0, - INSTR_RRE_FF, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, INSTR_RRE_RR, - INSTR_RRE_RR_OPT, INSTR_RRF_F0FF, INSTR_RRF_FUFF, INSTR_RRF_M0RR, - INSTR_RRF_R0RR, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, - INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR, - INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, INSTR_RSI_RRP, - INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, - INSTR_RSY_RURD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, - INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD, - INSTR_RXF_FRRDF, INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RX_FRRD, - INSTR_RX_RRRD, INSTR_RX_URRD, INSTR_SIY_URD, INSTR_SI_URD, - INSTR_SSE_RDRD, INSTR_SSF_RRDRD, INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, - INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3, - INSTR_S_00, INSTR_S_RD, -}; - -struct operand { - int bits; /* The number of bits in the operand. */ - int shift; /* The number of bits to shift. */ - int flags; /* One bit syntax flags. */ -}; - -struct insn { - const char name[5]; - unsigned char opfrag; - unsigned char format; -}; - -static const struct operand operands[] = -{ - [UNUSED] = { 0, 0, 0 }, - [R_8] = { 4, 8, OPERAND_GPR }, - [R_12] = { 4, 12, OPERAND_GPR }, - [R_16] = { 4, 16, OPERAND_GPR }, - [R_20] = { 4, 20, OPERAND_GPR }, - [R_24] = { 4, 24, OPERAND_GPR }, - [R_28] = { 4, 28, OPERAND_GPR }, - [R_32] = { 4, 32, OPERAND_GPR }, - [F_8] = { 4, 8, OPERAND_FPR }, - [F_12] = { 4, 12, OPERAND_FPR }, - [F_16] = { 4, 16, OPERAND_FPR }, - [F_20] = { 4, 16, OPERAND_FPR }, - [F_24] = { 4, 24, OPERAND_FPR }, - [F_28] = { 4, 28, OPERAND_FPR }, - [F_32] = { 4, 32, OPERAND_FPR }, - [A_8] = { 4, 8, OPERAND_AR }, - [A_12] = { 4, 12, OPERAND_AR }, - [A_24] = { 4, 24, OPERAND_AR }, - [A_28] = { 4, 28, OPERAND_AR }, - [C_8] = { 4, 8, OPERAND_CR }, - [C_12] = { 4, 12, OPERAND_CR }, - [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR }, - [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR }, - [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR }, - [D_20] = { 12, 20, OPERAND_DISP }, - [D_36] = { 12, 36, OPERAND_DISP }, - [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED }, - [L4_8] = { 4, 8, OPERAND_LENGTH }, - [L4_12] = { 4, 12, OPERAND_LENGTH }, - [L8_8] = { 8, 8, OPERAND_LENGTH }, - [U4_8] = { 4, 8, 0 }, - [U4_12] = { 4, 12, 0 }, - [U4_16] = { 4, 16, 0 }, - [U4_20] = { 4, 20, 0 }, - [U8_8] = { 8, 8, 0 }, - [U8_16] = { 8, 16, 0 }, - [I16_16] = { 16, 16, OPERAND_SIGNED }, - [U16_16] = { 16, 16, 0 }, - [J16_16] = { 16, 16, OPERAND_PCREL }, - [J32_16] = { 32, 16, OPERAND_PCREL }, - [I32_16] = { 32, 16, OPERAND_SIGNED }, - [U32_16] = { 32, 16, 0 }, - [M_16] = { 4, 16, 0 }, - [RO_28] = { 4, 28, OPERAND_GPR } -}; - -static const unsigned char formats[][7] = { - [INSTR_E] = { 0xff, 0,0,0,0,0,0 }, /* e.g. pr */ - [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxhg */ - [INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 }, /* e.g. brasl */ - [INSTR_RIL_UP] = { 0x0f, U4_8,J32_16,0,0,0,0 }, /* e.g. brcl */ - [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, /* e.g. afi */ - [INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 }, /* e.g. alfi */ - [INSTR_RI_RI] = { 0x0f, R_8,I16_16,0,0,0,0 }, /* e.g. ahi */ - [INSTR_RI_RP] = { 0x0f, R_8,J16_16,0,0,0,0 }, /* e.g. brct */ - [INSTR_RI_RU] = { 0x0f, R_8,U16_16,0,0,0,0 }, /* e.g. tml */ - [INSTR_RI_UP] = { 0x0f, U4_8,J16_16,0,0,0,0 }, /* e.g. brc */ - [INSTR_RRE_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. palb */ - [INSTR_RRE_0R] = { 0xff, R_28,0,0,0,0,0 }, /* e.g. tb */ - [INSTR_RRE_AA] = { 0xff, A_24,A_28,0,0,0,0 }, /* e.g. cpya */ - [INSTR_RRE_AR] = { 0xff, A_24,R_28,0,0,0,0 }, /* e.g. sar */ - [INSTR_RRE_F0] = { 0xff, F_24,0,0,0,0,0 }, /* e.g. sqer */ - [INSTR_RRE_FF] = { 0xff, F_24,F_28,0,0,0,0 }, /* e.g. debr */ - [INSTR_RRE_R0] = { 0xff, R_24,0,0,0,0,0 }, /* e.g. ipm */ - [INSTR_RRE_RA] = { 0xff, R_24,A_28,0,0,0,0 }, /* e.g. ear */ - [INSTR_RRE_RF] = { 0xff, R_24,F_28,0,0,0,0 }, /* e.g. cefbr */ - [INSTR_RRE_RR] = { 0xff, R_24,R_28,0,0,0,0 }, /* e.g. lura */ - [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 }, /* efpc, sfpc */ - [INSTR_RRF_F0FF] = { 0xff, F_16,F_24,F_28,0,0,0 }, /* e.g. madbr */ - [INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 },/* e.g. didbr */ - [INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 },/* e.g. .insn */ - [INSTR_RRF_R0RR] = { 0xff, R_24,R_28,R_16,0,0,0 }, /* e.g. idte */ - [INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 }, /* e.g. fixr */ - [INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 }, /* e.g. cfebr */ - [INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 }, /* e.g. sske */ - [INSTR_RR_FF] = { 0xff, F_8,F_12,0,0,0,0 }, /* e.g. adr */ - [INSTR_RR_R0] = { 0xff, R_8, 0,0,0,0,0 }, /* e.g. spm */ - [INSTR_RR_RR] = { 0xff, R_8,R_12,0,0,0,0 }, /* e.g. lr */ - [INSTR_RR_U0] = { 0xff, U8_8, 0,0,0,0,0 }, /* e.g. svc */ - [INSTR_RR_UR] = { 0xff, U4_8,R_12,0,0,0,0 }, /* e.g. bcr */ - [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. lmh */ - [INSTR_RSE_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lmh */ - [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icmh */ - [INSTR_RSL_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. tp */ - [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxh */ - [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },/* e.g. stmy */ - [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, - /* e.g. icmh */ - [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 },/* e.g. lamy */ - [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },/* e.g. lamy */ - [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, /* e.g. lam */ - [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lctl */ - [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. sll */ - [INSTR_RS_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. cs */ - [INSTR_RS_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icm */ - [INSTR_RXE_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. axbr */ - [INSTR_RXE_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. lg */ - [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 }, - /* e.g. madb */ - [INSTR_RXY_RRRD] = { 0xff, R_8,D20_20,X_12,B_16,0,0 },/* e.g. ly */ - [INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley */ - [INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. ae */ - [INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. l */ - [INSTR_RX_URRD] = { 0x00, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */ - [INSTR_SI_URD] = { 0x00, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */ - [INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, /* e.g. tmy */ - [INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */ - [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 }, - /* e.g. mvc */ - [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 }, - /* e.g. srp */ - [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 }, - /* e.g. pack */ - [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 }, - /* e.g. mvck */ - [INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 }, - /* e.g. plo */ - [INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 }, - /* e.g. lmd */ - [INSTR_S_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. hsch */ - [INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 }, /* e.g. lpsw */ - [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 }, - /* e.g. mvcos */ -}; - -static struct insn opcode[] = { -#ifdef CONFIG_64BIT - { "lmd", 0xef, INSTR_SS_RRRDRD3 }, -#endif - { "spm", 0x04, INSTR_RR_R0 }, - { "balr", 0x05, INSTR_RR_RR }, - { "bctr", 0x06, INSTR_RR_RR }, - { "bcr", 0x07, INSTR_RR_UR }, - { "svc", 0x0a, INSTR_RR_U0 }, - { "bsm", 0x0b, INSTR_RR_RR }, - { "bassm", 0x0c, INSTR_RR_RR }, - { "basr", 0x0d, INSTR_RR_RR }, - { "mvcl", 0x0e, INSTR_RR_RR }, - { "clcl", 0x0f, INSTR_RR_RR }, - { "lpr", 0x10, INSTR_RR_RR }, - { "lnr", 0x11, INSTR_RR_RR }, - { "ltr", 0x12, INSTR_RR_RR }, - { "lcr", 0x13, INSTR_RR_RR }, - { "nr", 0x14, INSTR_RR_RR }, - { "clr", 0x15, INSTR_RR_RR }, - { "or", 0x16, INSTR_RR_RR }, - { "xr", 0x17, INSTR_RR_RR }, - { "lr", 0x18, INSTR_RR_RR }, - { "cr", 0x19, INSTR_RR_RR }, - { "ar", 0x1a, INSTR_RR_RR }, - { "sr", 0x1b, INSTR_RR_RR }, - { "mr", 0x1c, INSTR_RR_RR }, - { "dr", 0x1d, INSTR_RR_RR }, - { "alr", 0x1e, INSTR_RR_RR }, - { "slr", 0x1f, INSTR_RR_RR }, - { "lpdr", 0x20, INSTR_RR_FF }, - { "lndr", 0x21, INSTR_RR_FF }, - { "ltdr", 0x22, INSTR_RR_FF }, - { "lcdr", 0x23, INSTR_RR_FF }, - { "hdr", 0x24, INSTR_RR_FF }, - { "ldxr", 0x25, INSTR_RR_FF }, - { "lrdr", 0x25, INSTR_RR_FF }, - { "mxr", 0x26, INSTR_RR_FF }, - { "mxdr", 0x27, INSTR_RR_FF }, - { "ldr", 0x28, INSTR_RR_FF }, - { "cdr", 0x29, INSTR_RR_FF }, - { "adr", 0x2a, INSTR_RR_FF }, - { "sdr", 0x2b, INSTR_RR_FF }, - { "mdr", 0x2c, INSTR_RR_FF }, - { "ddr", 0x2d, INSTR_RR_FF }, - { "awr", 0x2e, INSTR_RR_FF }, - { "swr", 0x2f, INSTR_RR_FF }, - { "lper", 0x30, INSTR_RR_FF }, - { "lner", 0x31, INSTR_RR_FF }, - { "lter", 0x32, INSTR_RR_FF }, - { "lcer", 0x33, INSTR_RR_FF }, - { "her", 0x34, INSTR_RR_FF }, - { "ledr", 0x35, INSTR_RR_FF }, - { "lrer", 0x35, INSTR_RR_FF }, - { "axr", 0x36, INSTR_RR_FF }, - { "sxr", 0x37, INSTR_RR_FF }, - { "ler", 0x38, INSTR_RR_FF }, - { "cer", 0x39, INSTR_RR_FF }, - { "aer", 0x3a, INSTR_RR_FF }, - { "ser", 0x3b, INSTR_RR_FF }, - { "mder", 0x3c, INSTR_RR_FF }, - { "mer", 0x3c, INSTR_RR_FF }, - { "der", 0x3d, INSTR_RR_FF }, - { "aur", 0x3e, INSTR_RR_FF }, - { "sur", 0x3f, INSTR_RR_FF }, - { "sth", 0x40, INSTR_RX_RRRD }, - { "la", 0x41, INSTR_RX_RRRD }, - { "stc", 0x42, INSTR_RX_RRRD }, - { "ic", 0x43, INSTR_RX_RRRD }, - { "ex", 0x44, INSTR_RX_RRRD }, - { "bal", 0x45, INSTR_RX_RRRD }, - { "bct", 0x46, INSTR_RX_RRRD }, - { "bc", 0x47, INSTR_RX_URRD }, - { "lh", 0x48, INSTR_RX_RRRD }, - { "ch", 0x49, INSTR_RX_RRRD }, - { "ah", 0x4a, INSTR_RX_RRRD }, - { "sh", 0x4b, INSTR_RX_RRRD }, - { "mh", 0x4c, INSTR_RX_RRRD }, - { "bas", 0x4d, INSTR_RX_RRRD }, - { "cvd", 0x4e, INSTR_RX_RRRD }, - { "cvb", 0x4f, INSTR_RX_RRRD }, - { "st", 0x50, INSTR_RX_RRRD }, - { "lae", 0x51, INSTR_RX_RRRD }, - { "n", 0x54, INSTR_RX_RRRD }, - { "cl", 0x55, INSTR_RX_RRRD }, - { "o", 0x56, INSTR_RX_RRRD }, - { "x", 0x57, INSTR_RX_RRRD }, - { "l", 0x58, INSTR_RX_RRRD }, - { "c", 0x59, INSTR_RX_RRRD }, - { "a", 0x5a, INSTR_RX_RRRD }, - { "s", 0x5b, INSTR_RX_RRRD }, - { "m", 0x5c, INSTR_RX_RRRD }, - { "d", 0x5d, INSTR_RX_RRRD }, - { "al", 0x5e, INSTR_RX_RRRD }, - { "sl", 0x5f, INSTR_RX_RRRD }, - { "std", 0x60, INSTR_RX_FRRD }, - { "mxd", 0x67, INSTR_RX_FRRD }, - { "ld", 0x68, INSTR_RX_FRRD }, - { "cd", 0x69, INSTR_RX_FRRD }, - { "ad", 0x6a, INSTR_RX_FRRD }, - { "sd", 0x6b, INSTR_RX_FRRD }, - { "md", 0x6c, INSTR_RX_FRRD }, - { "dd", 0x6d, INSTR_RX_FRRD }, - { "aw", 0x6e, INSTR_RX_FRRD }, - { "sw", 0x6f, INSTR_RX_FRRD }, - { "ste", 0x70, INSTR_RX_FRRD }, - { "ms", 0x71, INSTR_RX_RRRD }, - { "le", 0x78, INSTR_RX_FRRD }, - { "ce", 0x79, INSTR_RX_FRRD }, - { "ae", 0x7a, INSTR_RX_FRRD }, - { "se", 0x7b, INSTR_RX_FRRD }, - { "mde", 0x7c, INSTR_RX_FRRD }, - { "me", 0x7c, INSTR_RX_FRRD }, - { "de", 0x7d, INSTR_RX_FRRD }, - { "au", 0x7e, INSTR_RX_FRRD }, - { "su", 0x7f, INSTR_RX_FRRD }, - { "ssm", 0x80, INSTR_S_RD }, - { "lpsw", 0x82, INSTR_S_RD }, - { "diag", 0x83, INSTR_RS_RRRD }, - { "brxh", 0x84, INSTR_RSI_RRP }, - { "brxle", 0x85, INSTR_RSI_RRP }, - { "bxh", 0x86, INSTR_RS_RRRD }, - { "bxle", 0x87, INSTR_RS_RRRD }, - { "srl", 0x88, INSTR_RS_R0RD }, - { "sll", 0x89, INSTR_RS_R0RD }, - { "sra", 0x8a, INSTR_RS_R0RD }, - { "sla", 0x8b, INSTR_RS_R0RD }, - { "srdl", 0x8c, INSTR_RS_R0RD }, - { "sldl", 0x8d, INSTR_RS_R0RD }, - { "srda", 0x8e, INSTR_RS_R0RD }, - { "slda", 0x8f, INSTR_RS_R0RD }, - { "stm", 0x90, INSTR_RS_RRRD }, - { "tm", 0x91, INSTR_SI_URD }, - { "mvi", 0x92, INSTR_SI_URD }, - { "ts", 0x93, INSTR_S_RD }, - { "ni", 0x94, INSTR_SI_URD }, - { "cli", 0x95, INSTR_SI_URD }, - { "oi", 0x96, INSTR_SI_URD }, - { "xi", 0x97, INSTR_SI_URD }, - { "lm", 0x98, INSTR_RS_RRRD }, - { "trace", 0x99, INSTR_RS_RRRD }, - { "lam", 0x9a, INSTR_RS_AARD }, - { "stam", 0x9b, INSTR_RS_AARD }, - { "mvcle", 0xa8, INSTR_RS_RRRD }, - { "clcle", 0xa9, INSTR_RS_RRRD }, - { "stnsm", 0xac, INSTR_SI_URD }, - { "stosm", 0xad, INSTR_SI_URD }, - { "sigp", 0xae, INSTR_RS_RRRD }, - { "mc", 0xaf, INSTR_SI_URD }, - { "lra", 0xb1, INSTR_RX_RRRD }, - { "stctl", 0xb6, INSTR_RS_CCRD }, - { "lctl", 0xb7, INSTR_RS_CCRD }, - { "cs", 0xba, INSTR_RS_RRRD }, - { "cds", 0xbb, INSTR_RS_RRRD }, - { "clm", 0xbd, INSTR_RS_RURD }, - { "stcm", 0xbe, INSTR_RS_RURD }, - { "icm", 0xbf, INSTR_RS_RURD }, - { "mvn", 0xd1, INSTR_SS_L0RDRD }, - { "mvc", 0xd2, INSTR_SS_L0RDRD }, - { "mvz", 0xd3, INSTR_SS_L0RDRD }, - { "nc", 0xd4, INSTR_SS_L0RDRD }, - { "clc", 0xd5, INSTR_SS_L0RDRD }, - { "oc", 0xd6, INSTR_SS_L0RDRD }, - { "xc", 0xd7, INSTR_SS_L0RDRD }, - { "mvck", 0xd9, INSTR_SS_RRRDRD }, - { "mvcp", 0xda, INSTR_SS_RRRDRD }, - { "mvcs", 0xdb, INSTR_SS_RRRDRD }, - { "tr", 0xdc, INSTR_SS_L0RDRD }, - { "trt", 0xdd, INSTR_SS_L0RDRD }, - { "ed", 0xde, INSTR_SS_L0RDRD }, - { "edmk", 0xdf, INSTR_SS_L0RDRD }, - { "pku", 0xe1, INSTR_SS_L0RDRD }, - { "unpku", 0xe2, INSTR_SS_L0RDRD }, - { "mvcin", 0xe8, INSTR_SS_L0RDRD }, - { "pka", 0xe9, INSTR_SS_L0RDRD }, - { "unpka", 0xea, INSTR_SS_L0RDRD }, - { "plo", 0xee, INSTR_SS_RRRDRD2 }, - { "srp", 0xf0, INSTR_SS_LIRDRD }, - { "mvo", 0xf1, INSTR_SS_LLRDRD }, - { "pack", 0xf2, INSTR_SS_LLRDRD }, - { "unpk", 0xf3, INSTR_SS_LLRDRD }, - { "zap", 0xf8, INSTR_SS_LLRDRD }, - { "cp", 0xf9, INSTR_SS_LLRDRD }, - { "ap", 0xfa, INSTR_SS_LLRDRD }, - { "sp", 0xfb, INSTR_SS_LLRDRD }, - { "mp", 0xfc, INSTR_SS_LLRDRD }, - { "dp", 0xfd, INSTR_SS_LLRDRD }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_01[] = { -#ifdef CONFIG_64BIT - { "sam64", 0x0e, INSTR_E }, -#endif - { "pr", 0x01, INSTR_E }, - { "upt", 0x02, INSTR_E }, - { "sckpf", 0x07, INSTR_E }, - { "tam", 0x0b, INSTR_E }, - { "sam24", 0x0c, INSTR_E }, - { "sam31", 0x0d, INSTR_E }, - { "trap2", 0xff, INSTR_E }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_a5[] = { -#ifdef CONFIG_64BIT - { "iihh", 0x00, INSTR_RI_RU }, - { "iihl", 0x01, INSTR_RI_RU }, - { "iilh", 0x02, INSTR_RI_RU }, - { "iill", 0x03, INSTR_RI_RU }, - { "nihh", 0x04, INSTR_RI_RU }, - { "nihl", 0x05, INSTR_RI_RU }, - { "nilh", 0x06, INSTR_RI_RU }, - { "nill", 0x07, INSTR_RI_RU }, - { "oihh", 0x08, INSTR_RI_RU }, - { "oihl", 0x09, INSTR_RI_RU }, - { "oilh", 0x0a, INSTR_RI_RU }, - { "oill", 0x0b, INSTR_RI_RU }, - { "llihh", 0x0c, INSTR_RI_RU }, - { "llihl", 0x0d, INSTR_RI_RU }, - { "llilh", 0x0e, INSTR_RI_RU }, - { "llill", 0x0f, INSTR_RI_RU }, -#endif - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_a7[] = { -#ifdef CONFIG_64BIT - { "tmhh", 0x02, INSTR_RI_RU }, - { "tmhl", 0x03, INSTR_RI_RU }, - { "brctg", 0x07, INSTR_RI_RP }, - { "lghi", 0x09, INSTR_RI_RI }, - { "aghi", 0x0b, INSTR_RI_RI }, - { "mghi", 0x0d, INSTR_RI_RI }, - { "cghi", 0x0f, INSTR_RI_RI }, -#endif - { "tmlh", 0x00, INSTR_RI_RU }, - { "tmll", 0x01, INSTR_RI_RU }, - { "brc", 0x04, INSTR_RI_UP }, - { "bras", 0x05, INSTR_RI_RP }, - { "brct", 0x06, INSTR_RI_RP }, - { "lhi", 0x08, INSTR_RI_RI }, - { "ahi", 0x0a, INSTR_RI_RI }, - { "mhi", 0x0c, INSTR_RI_RI }, - { "chi", 0x0e, INSTR_RI_RI }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_b2[] = { -#ifdef CONFIG_64BIT - { "sske", 0x2b, INSTR_RRF_M0RR }, - { "stckf", 0x7c, INSTR_S_RD }, - { "cu21", 0xa6, INSTR_RRF_M0RR }, - { "cuutf", 0xa6, INSTR_RRF_M0RR }, - { "cu12", 0xa7, INSTR_RRF_M0RR }, - { "cutfu", 0xa7, INSTR_RRF_M0RR }, - { "stfle", 0xb0, INSTR_S_RD }, - { "lpswe", 0xb2, INSTR_S_RD }, -#endif - { "stidp", 0x02, INSTR_S_RD }, - { "sck", 0x04, INSTR_S_RD }, - { "stck", 0x05, INSTR_S_RD }, - { "sckc", 0x06, INSTR_S_RD }, - { "stckc", 0x07, INSTR_S_RD }, - { "spt", 0x08, INSTR_S_RD }, - { "stpt", 0x09, INSTR_S_RD }, - { "spka", 0x0a, INSTR_S_RD }, - { "ipk", 0x0b, INSTR_S_00 }, - { "ptlb", 0x0d, INSTR_S_00 }, - { "spx", 0x10, INSTR_S_RD }, - { "stpx", 0x11, INSTR_S_RD }, - { "stap", 0x12, INSTR_S_RD }, - { "sie", 0x14, INSTR_S_RD }, - { "pc", 0x18, INSTR_S_RD }, - { "sac", 0x19, INSTR_S_RD }, - { "cfc", 0x1a, INSTR_S_RD }, - { "ipte", 0x21, INSTR_RRE_RR }, - { "ipm", 0x22, INSTR_RRE_R0 }, - { "ivsk", 0x23, INSTR_RRE_RR }, - { "iac", 0x24, INSTR_RRE_R0 }, - { "ssar", 0x25, INSTR_RRE_R0 }, - { "epar", 0x26, INSTR_RRE_R0 }, - { "esar", 0x27, INSTR_RRE_R0 }, - { "pt", 0x28, INSTR_RRE_RR }, - { "iske", 0x29, INSTR_RRE_RR }, - { "rrbe", 0x2a, INSTR_RRE_RR }, - { "sske", 0x2b, INSTR_RRE_RR }, - { "tb", 0x2c, INSTR_RRE_0R }, - { "dxr", 0x2d, INSTR_RRE_F0 }, - { "pgin", 0x2e, INSTR_RRE_RR }, - { "pgout", 0x2f, INSTR_RRE_RR }, - { "csch", 0x30, INSTR_S_00 }, - { "hsch", 0x31, INSTR_S_00 }, - { "msch", 0x32, INSTR_S_RD }, - { "ssch", 0x33, INSTR_S_RD }, - { "stsch", 0x34, INSTR_S_RD }, - { "tsch", 0x35, INSTR_S_RD }, - { "tpi", 0x36, INSTR_S_RD }, - { "sal", 0x37, INSTR_S_00 }, - { "rsch", 0x38, INSTR_S_00 }, - { "stcrw", 0x39, INSTR_S_RD }, - { "stcps", 0x3a, INSTR_S_RD }, - { "rchp", 0x3b, INSTR_S_00 }, - { "schm", 0x3c, INSTR_S_00 }, - { "bakr", 0x40, INSTR_RRE_RR }, - { "cksm", 0x41, INSTR_RRE_RR }, - { "sqdr", 0x44, INSTR_RRE_F0 }, - { "sqer", 0x45, INSTR_RRE_F0 }, - { "stura", 0x46, INSTR_RRE_RR }, - { "msta", 0x47, INSTR_RRE_R0 }, - { "palb", 0x48, INSTR_RRE_00 }, - { "ereg", 0x49, INSTR_RRE_RR }, - { "esta", 0x4a, INSTR_RRE_RR }, - { "lura", 0x4b, INSTR_RRE_RR }, - { "tar", 0x4c, INSTR_RRE_AR }, - { "cpya", INSTR_RRE_AA }, - { "sar", 0x4e, INSTR_RRE_AR }, - { "ear", 0x4f, INSTR_RRE_RA }, - { "csp", 0x50, INSTR_RRE_RR }, - { "msr", 0x52, INSTR_RRE_RR }, - { "mvpg", 0x54, INSTR_RRE_RR }, - { "mvst", 0x55, INSTR_RRE_RR }, - { "cuse", 0x57, INSTR_RRE_RR }, - { "bsg", 0x58, INSTR_RRE_RR }, - { "bsa", 0x5a, INSTR_RRE_RR }, - { "clst", 0x5d, INSTR_RRE_RR }, - { "srst", 0x5e, INSTR_RRE_RR }, - { "cmpsc", 0x63, INSTR_RRE_RR }, - { "cmpsc", 0x63, INSTR_RRE_RR }, - { "siga", 0x74, INSTR_S_RD }, - { "xsch", 0x76, INSTR_S_00 }, - { "rp", 0x77, INSTR_S_RD }, - { "stcke", 0x78, INSTR_S_RD }, - { "sacf", 0x79, INSTR_S_RD }, - { "stsi", 0x7d, INSTR_S_RD }, - { "srnm", 0x99, INSTR_S_RD }, - { "stfpc", 0x9c, INSTR_S_RD }, - { "lfpc", 0x9d, INSTR_S_RD }, - { "tre", 0xa5, INSTR_RRE_RR }, - { "cuutf", 0xa6, INSTR_RRE_RR }, - { "cutfu", 0xa7, INSTR_RRE_RR }, - { "stfl", 0xb1, INSTR_S_RD }, - { "trap4", 0xff, INSTR_S_RD }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_b3[] = { -#ifdef CONFIG_64BIT - { "maylr", 0x38, INSTR_RRF_F0FF }, - { "mylr", 0x39, INSTR_RRF_F0FF }, - { "mayr", 0x3a, INSTR_RRF_F0FF }, - { "myr", 0x3b, INSTR_RRF_F0FF }, - { "mayhr", 0x3c, INSTR_RRF_F0FF }, - { "myhr", 0x3d, INSTR_RRF_F0FF }, - { "cegbr", 0xa4, INSTR_RRE_RR }, - { "cdgbr", 0xa5, INSTR_RRE_RR }, - { "cxgbr", 0xa6, INSTR_RRE_RR }, - { "cgebr", 0xa8, INSTR_RRF_U0RF }, - { "cgdbr", 0xa9, INSTR_RRF_U0RF }, - { "cgxbr", 0xaa, INSTR_RRF_U0RF }, - { "cfer", 0xb8, INSTR_RRF_U0RF }, - { "cfdr", 0xb9, INSTR_RRF_U0RF }, - { "cfxr", 0xba, INSTR_RRF_U0RF }, - { "cegr", 0xc4, INSTR_RRE_RR }, - { "cdgr", 0xc5, INSTR_RRE_RR }, - { "cxgr", 0xc6, INSTR_RRE_RR }, - { "cger", 0xc8, INSTR_RRF_U0RF }, - { "cgdr", 0xc9, INSTR_RRF_U0RF }, - { "cgxr", 0xca, INSTR_RRF_U0RF }, -#endif - { "lpebr", 0x00, INSTR_RRE_FF }, - { "lnebr", 0x01, INSTR_RRE_FF }, - { "ltebr", 0x02, INSTR_RRE_FF }, - { "lcebr", 0x03, INSTR_RRE_FF }, - { "ldebr", 0x04, INSTR_RRE_FF }, - { "lxdbr", 0x05, INSTR_RRE_FF }, - { "lxebr", 0x06, INSTR_RRE_FF }, - { "mxdbr", 0x07, INSTR_RRE_FF }, - { "kebr", 0x08, INSTR_RRE_FF }, - { "cebr", 0x09, INSTR_RRE_FF }, - { "aebr", 0x0a, INSTR_RRE_FF }, - { "sebr", 0x0b, INSTR_RRE_FF }, - { "mdebr", 0x0c, INSTR_RRE_FF }, - { "debr", 0x0d, INSTR_RRE_FF }, - { "maebr", 0x0e, INSTR_RRF_F0FF }, - { "msebr", 0x0f, INSTR_RRF_F0FF }, - { "lpdbr", 0x10, INSTR_RRE_FF }, - { "lndbr", 0x11, INSTR_RRE_FF }, - { "ltdbr", 0x12, INSTR_RRE_FF }, - { "lcdbr", 0x13, INSTR_RRE_FF }, - { "sqebr", 0x14, INSTR_RRE_FF }, - { "sqdbr", 0x15, INSTR_RRE_FF }, - { "sqxbr", 0x16, INSTR_RRE_FF }, - { "meebr", 0x17, INSTR_RRE_FF }, - { "kdbr", 0x18, INSTR_RRE_FF }, - { "cdbr", 0x19, INSTR_RRE_FF }, - { "adbr", 0x1a, INSTR_RRE_FF }, - { "sdbr", 0x1b, INSTR_RRE_FF }, - { "mdbr", 0x1c, INSTR_RRE_FF }, - { "ddbr", 0x1d, INSTR_RRE_FF }, - { "madbr", 0x1e, INSTR_RRF_F0FF }, - { "msdbr", 0x1f, INSTR_RRF_F0FF }, - { "lder", 0x24, INSTR_RRE_FF }, - { "lxdr", 0x25, INSTR_RRE_FF }, - { "lxer", 0x26, INSTR_RRE_FF }, - { "maer", 0x2e, INSTR_RRF_F0FF }, - { "mser", 0x2f, INSTR_RRF_F0FF }, - { "sqxr", 0x36, INSTR_RRE_FF }, - { "meer", 0x37, INSTR_RRE_FF }, - { "madr", 0x3e, INSTR_RRF_F0FF }, - { "msdr", 0x3f, INSTR_RRF_F0FF }, - { "lpxbr", 0x40, INSTR_RRE_FF }, - { "lnxbr", 0x41, INSTR_RRE_FF }, - { "ltxbr", 0x42, INSTR_RRE_FF }, - { "lcxbr", 0x43, INSTR_RRE_FF }, - { "ledbr", 0x44, INSTR_RRE_FF }, - { "ldxbr", 0x45, INSTR_RRE_FF }, - { "lexbr", 0x46, INSTR_RRE_FF }, - { "fixbr", 0x47, INSTR_RRF_U0FF }, - { "kxbr", 0x48, INSTR_RRE_FF }, - { "cxbr", 0x49, INSTR_RRE_FF }, - { "axbr", 0x4a, INSTR_RRE_FF }, - { "sxbr", 0x4b, INSTR_RRE_FF }, - { "mxbr", 0x4c, INSTR_RRE_FF }, - { "dxbr", 0x4d, INSTR_RRE_FF }, - { "tbedr", 0x50, INSTR_RRF_U0FF }, - { "tbdr", 0x51, INSTR_RRF_U0FF }, - { "diebr", 0x53, INSTR_RRF_FUFF }, - { "fiebr", 0x57, INSTR_RRF_U0FF }, - { "thder", 0x58, INSTR_RRE_RR }, - { "thdr", 0x59, INSTR_RRE_RR }, - { "didbr", 0x5b, INSTR_RRF_FUFF }, - { "fidbr", 0x5f, INSTR_RRF_U0FF }, - { "lpxr", 0x60, INSTR_RRE_FF }, - { "lnxr", 0x61, INSTR_RRE_FF }, - { "ltxr", 0x62, INSTR_RRE_FF }, - { "lcxr", 0x63, INSTR_RRE_FF }, - { "lxr", 0x65, INSTR_RRE_RR }, - { "lexr", 0x66, INSTR_RRE_FF }, - { "fixr", 0x67, INSTR_RRF_U0FF }, - { "cxr", 0x69, INSTR_RRE_FF }, - { "lzer", 0x74, INSTR_RRE_R0 }, - { "lzdr", 0x75, INSTR_RRE_R0 }, - { "lzxr", 0x76, INSTR_RRE_R0 }, - { "fier", 0x77, INSTR_RRF_U0FF }, - { "fidr", 0x7f, INSTR_RRF_U0FF }, - { "sfpc", 0x84, INSTR_RRE_RR_OPT }, - { "efpc", 0x8c, INSTR_RRE_RR_OPT }, - { "cefbr", 0x94, INSTR_RRE_RF }, - { "cdfbr", 0x95, INSTR_RRE_RF }, - { "cxfbr", 0x96, INSTR_RRE_RF }, - { "cfebr", 0x98, INSTR_RRF_U0RF }, - { "cfdbr", 0x99, INSTR_RRF_U0RF }, - { "cfxbr", 0x9a, INSTR_RRF_U0RF }, - { "cefr", 0xb4, INSTR_RRE_RF }, - { "cdfr", 0xb5, INSTR_RRE_RF }, - { "cxfr", 0xb6, INSTR_RRE_RF }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_b9[] = { -#ifdef CONFIG_64BIT - { "lpgr", 0x00, INSTR_RRE_RR }, - { "lngr", 0x01, INSTR_RRE_RR }, - { "ltgr", 0x02, INSTR_RRE_RR }, - { "lcgr", 0x03, INSTR_RRE_RR }, - { "lgr", 0x04, INSTR_RRE_RR }, - { "lurag", 0x05, INSTR_RRE_RR }, - { "lgbr", 0x06, INSTR_RRE_RR }, - { "lghr", 0x07, INSTR_RRE_RR }, - { "agr", 0x08, INSTR_RRE_RR }, - { "sgr", 0x09, INSTR_RRE_RR }, - { "algr", 0x0a, INSTR_RRE_RR }, - { "slgr", 0x0b, INSTR_RRE_RR }, - { "msgr", 0x0c, INSTR_RRE_RR }, - { "dsgr", 0x0d, INSTR_RRE_RR }, - { "eregg", 0x0e, INSTR_RRE_RR }, - { "lrvgr", 0x0f, INSTR_RRE_RR }, - { "lpgfr", 0x10, INSTR_RRE_RR }, - { "lngfr", 0x11, INSTR_RRE_RR }, - { "ltgfr", 0x12, INSTR_RRE_RR }, - { "lcgfr", 0x13, INSTR_RRE_RR }, - { "lgfr", 0x14, INSTR_RRE_RR }, - { "llgfr", 0x16, INSTR_RRE_RR }, - { "llgtr", 0x17, INSTR_RRE_RR }, - { "agfr", 0x18, INSTR_RRE_RR }, - { "sgfr", 0x19, INSTR_RRE_RR }, - { "algfr", 0x1a, INSTR_RRE_RR }, - { "slgfr", 0x1b, INSTR_RRE_RR }, - { "msgfr", 0x1c, INSTR_RRE_RR }, - { "dsgfr", 0x1d, INSTR_RRE_RR }, - { "cgr", 0x20, INSTR_RRE_RR }, - { "clgr", 0x21, INSTR_RRE_RR }, - { "sturg", 0x25, INSTR_RRE_RR }, - { "lbr", 0x26, INSTR_RRE_RR }, - { "lhr", 0x27, INSTR_RRE_RR }, - { "cgfr", 0x30, INSTR_RRE_RR }, - { "clgfr", 0x31, INSTR_RRE_RR }, - { "bctgr", 0x46, INSTR_RRE_RR }, - { "ngr", 0x80, INSTR_RRE_RR }, - { "ogr", 0x81, INSTR_RRE_RR }, - { "xgr", 0x82, INSTR_RRE_RR }, - { "flogr", 0x83, INSTR_RRE_RR }, - { "llgcr", 0x84, INSTR_RRE_RR }, - { "llghr", 0x85, INSTR_RRE_RR }, - { "mlgr", 0x86, INSTR_RRE_RR }, - { "dlgr", 0x87, INSTR_RRE_RR }, - { "alcgr", 0x88, INSTR_RRE_RR }, - { "slbgr", 0x89, INSTR_RRE_RR }, - { "cspg", 0x8a, INSTR_RRE_RR }, - { "idte", 0x8e, INSTR_RRF_R0RR }, - { "llcr", 0x94, INSTR_RRE_RR }, - { "llhr", 0x95, INSTR_RRE_RR }, - { "esea", 0x9d, INSTR_RRE_R0 }, - { "lptea", 0xaa, INSTR_RRF_RURR }, - { "cu14", 0xb0, INSTR_RRF_M0RR }, - { "cu24", 0xb1, INSTR_RRF_M0RR }, - { "cu41", 0xb2, INSTR_RRF_M0RR }, - { "cu42", 0xb3, INSTR_RRF_M0RR }, -#endif - { "kmac", 0x1e, INSTR_RRE_RR }, - { "lrvr", 0x1f, INSTR_RRE_RR }, - { "km", 0x2e, INSTR_RRE_RR }, - { "kmc", 0x2f, INSTR_RRE_RR }, - { "kimd", 0x3e, INSTR_RRE_RR }, - { "klmd", 0x3f, INSTR_RRE_RR }, - { "epsw", 0x8d, INSTR_RRE_RR }, - { "trtt", 0x90, INSTR_RRE_RR }, - { "trtt", 0x90, INSTR_RRF_M0RR }, - { "trto", 0x91, INSTR_RRE_RR }, - { "trto", 0x91, INSTR_RRF_M0RR }, - { "trot", 0x92, INSTR_RRE_RR }, - { "trot", 0x92, INSTR_RRF_M0RR }, - { "troo", 0x93, INSTR_RRE_RR }, - { "troo", 0x93, INSTR_RRF_M0RR }, - { "mlr", 0x96, INSTR_RRE_RR }, - { "dlr", 0x97, INSTR_RRE_RR }, - { "alcr", 0x98, INSTR_RRE_RR }, - { "slbr", 0x99, INSTR_RRE_RR }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_c0[] = { -#ifdef CONFIG_64BIT - { "lgfi", 0x01, INSTR_RIL_RI }, - { "xihf", 0x06, INSTR_RIL_RU }, - { "xilf", 0x07, INSTR_RIL_RU }, - { "iihf", 0x08, INSTR_RIL_RU }, - { "iilf", 0x09, INSTR_RIL_RU }, - { "nihf", 0x0a, INSTR_RIL_RU }, - { "nilf", 0x0b, INSTR_RIL_RU }, - { "oihf", 0x0c, INSTR_RIL_RU }, - { "oilf", 0x0d, INSTR_RIL_RU }, - { "llihf", 0x0e, INSTR_RIL_RU }, - { "llilf", 0x0f, INSTR_RIL_RU }, -#endif - { "larl", 0x00, INSTR_RIL_RP }, - { "brcl", 0x04, INSTR_RIL_UP }, - { "brasl", 0x05, INSTR_RIL_RP }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_c2[] = { -#ifdef CONFIG_64BIT - { "slgfi", 0x04, INSTR_RIL_RU }, - { "slfi", 0x05, INSTR_RIL_RU }, - { "agfi", 0x08, INSTR_RIL_RI }, - { "afi", 0x09, INSTR_RIL_RI }, - { "algfi", 0x0a, INSTR_RIL_RU }, - { "alfi", 0x0b, INSTR_RIL_RU }, - { "cgfi", 0x0c, INSTR_RIL_RI }, - { "cfi", 0x0d, INSTR_RIL_RI }, - { "clgfi", 0x0e, INSTR_RIL_RU }, - { "clfi", 0x0f, INSTR_RIL_RU }, -#endif - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_c8[] = { -#ifdef CONFIG_64BIT - { "mvcos", 0x00, INSTR_SSF_RRDRD }, -#endif - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_e3[] = { -#ifdef CONFIG_64BIT - { "ltg", 0x02, INSTR_RXY_RRRD }, - { "lrag", 0x03, INSTR_RXY_RRRD }, - { "lg", 0x04, INSTR_RXY_RRRD }, - { "cvby", 0x06, INSTR_RXY_RRRD }, - { "ag", 0x08, INSTR_RXY_RRRD }, - { "sg", 0x09, INSTR_RXY_RRRD }, - { "alg", 0x0a, INSTR_RXY_RRRD }, - { "slg", 0x0b, INSTR_RXY_RRRD }, - { "msg", 0x0c, INSTR_RXY_RRRD }, - { "dsg", 0x0d, INSTR_RXY_RRRD }, - { "cvbg", 0x0e, INSTR_RXY_RRRD }, - { "lrvg", 0x0f, INSTR_RXY_RRRD }, - { "lt", 0x12, INSTR_RXY_RRRD }, - { "lray", 0x13, INSTR_RXY_RRRD }, - { "lgf", 0x14, INSTR_RXY_RRRD }, - { "lgh", 0x15, INSTR_RXY_RRRD }, - { "llgf", 0x16, INSTR_RXY_RRRD }, - { "llgt", 0x17, INSTR_RXY_RRRD }, - { "agf", 0x18, INSTR_RXY_RRRD }, - { "sgf", 0x19, INSTR_RXY_RRRD }, - { "algf", 0x1a, INSTR_RXY_RRRD }, - { "slgf", 0x1b, INSTR_RXY_RRRD }, - { "msgf", 0x1c, INSTR_RXY_RRRD }, - { "dsgf", 0x1d, INSTR_RXY_RRRD }, - { "cg", 0x20, INSTR_RXY_RRRD }, - { "clg", 0x21, INSTR_RXY_RRRD }, - { "stg", 0x24, INSTR_RXY_RRRD }, - { "cvdy", 0x26, INSTR_RXY_RRRD }, - { "cvdg", 0x2e, INSTR_RXY_RRRD }, - { "strvg", 0x2f, INSTR_RXY_RRRD }, - { "cgf", 0x30, INSTR_RXY_RRRD }, - { "clgf", 0x31, INSTR_RXY_RRRD }, - { "strvh", 0x3f, INSTR_RXY_RRRD }, - { "bctg", 0x46, INSTR_RXY_RRRD }, - { "sty", 0x50, INSTR_RXY_RRRD }, - { "msy", 0x51, INSTR_RXY_RRRD }, - { "ny", 0x54, INSTR_RXY_RRRD }, - { "cly", 0x55, INSTR_RXY_RRRD }, - { "oy", 0x56, INSTR_RXY_RRRD }, - { "xy", 0x57, INSTR_RXY_RRRD }, - { "ly", 0x58, INSTR_RXY_RRRD }, - { "cy", 0x59, INSTR_RXY_RRRD }, - { "ay", 0x5a, INSTR_RXY_RRRD }, - { "sy", 0x5b, INSTR_RXY_RRRD }, - { "aly", 0x5e, INSTR_RXY_RRRD }, - { "sly", 0x5f, INSTR_RXY_RRRD }, - { "sthy", 0x70, INSTR_RXY_RRRD }, - { "lay", 0x71, INSTR_RXY_RRRD }, - { "stcy", 0x72, INSTR_RXY_RRRD }, - { "icy", 0x73, INSTR_RXY_RRRD }, - { "lb", 0x76, INSTR_RXY_RRRD }, - { "lgb", 0x77, INSTR_RXY_RRRD }, - { "lhy", 0x78, INSTR_RXY_RRRD }, - { "chy", 0x79, INSTR_RXY_RRRD }, - { "ahy", 0x7a, INSTR_RXY_RRRD }, - { "shy", 0x7b, INSTR_RXY_RRRD }, - { "ng", 0x80, INSTR_RXY_RRRD }, - { "og", 0x81, INSTR_RXY_RRRD }, - { "xg", 0x82, INSTR_RXY_RRRD }, - { "mlg", 0x86, INSTR_RXY_RRRD }, - { "dlg", 0x87, INSTR_RXY_RRRD }, - { "alcg", 0x88, INSTR_RXY_RRRD }, - { "slbg", 0x89, INSTR_RXY_RRRD }, - { "stpq", 0x8e, INSTR_RXY_RRRD }, - { "lpq", 0x8f, INSTR_RXY_RRRD }, - { "llgc", 0x90, INSTR_RXY_RRRD }, - { "llgh", 0x91, INSTR_RXY_RRRD }, - { "llc", 0x94, INSTR_RXY_RRRD }, - { "llh", 0x95, INSTR_RXY_RRRD }, -#endif - { "lrv", 0x1e, INSTR_RXY_RRRD }, - { "lrvh", 0x1f, INSTR_RXY_RRRD }, - { "strv", 0x3e, INSTR_RXY_RRRD }, - { "ml", 0x96, INSTR_RXY_RRRD }, - { "dl", 0x97, INSTR_RXY_RRRD }, - { "alc", 0x98, INSTR_RXY_RRRD }, - { "slb", 0x99, INSTR_RXY_RRRD }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_e5[] = { -#ifdef CONFIG_64BIT - { "strag", 0x02, INSTR_SSE_RDRD }, -#endif - { "lasp", 0x00, INSTR_SSE_RDRD }, - { "tprot", 0x01, INSTR_SSE_RDRD }, - { "mvcsk", 0x0e, INSTR_SSE_RDRD }, - { "mvcdk", 0x0f, INSTR_SSE_RDRD }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_eb[] = { -#ifdef CONFIG_64BIT - { "lmg", 0x04, INSTR_RSY_RRRD }, - { "srag", 0x0a, INSTR_RSY_RRRD }, - { "slag", 0x0b, INSTR_RSY_RRRD }, - { "srlg", 0x0c, INSTR_RSY_RRRD }, - { "sllg", 0x0d, INSTR_RSY_RRRD }, - { "tracg", 0x0f, INSTR_RSY_RRRD }, - { "csy", 0x14, INSTR_RSY_RRRD }, - { "rllg", 0x1c, INSTR_RSY_RRRD }, - { "clmh", 0x20, INSTR_RSY_RURD }, - { "clmy", 0x21, INSTR_RSY_RURD }, - { "stmg", 0x24, INSTR_RSY_RRRD }, - { "stctg", 0x25, INSTR_RSY_CCRD }, - { "stmh", 0x26, INSTR_RSY_RRRD }, - { "stcmh", 0x2c, INSTR_RSY_RURD }, - { "stcmy", 0x2d, INSTR_RSY_RURD }, - { "lctlg", 0x2f, INSTR_RSY_CCRD }, - { "csg", 0x30, INSTR_RSY_RRRD }, - { "cdsy", 0x31, INSTR_RSY_RRRD }, - { "cdsg", 0x3e, INSTR_RSY_RRRD }, - { "bxhg", 0x44, INSTR_RSY_RRRD }, - { "bxleg", 0x45, INSTR_RSY_RRRD }, - { "tmy", 0x51, INSTR_SIY_URD }, - { "mviy", 0x52, INSTR_SIY_URD }, - { "niy", 0x54, INSTR_SIY_URD }, - { "cliy", 0x55, INSTR_SIY_URD }, - { "oiy", 0x56, INSTR_SIY_URD }, - { "xiy", 0x57, INSTR_SIY_URD }, - { "icmh", 0x80, INSTR_RSE_RURD }, - { "icmh", 0x80, INSTR_RSY_RURD }, - { "icmy", 0x81, INSTR_RSY_RURD }, - { "clclu", 0x8f, INSTR_RSY_RRRD }, - { "stmy", 0x90, INSTR_RSY_RRRD }, - { "lmh", 0x96, INSTR_RSY_RRRD }, - { "lmy", 0x98, INSTR_RSY_RRRD }, - { "lamy", 0x9a, INSTR_RSY_AARD }, - { "stamy", 0x9b, INSTR_RSY_AARD }, -#endif - { "rll", 0x1d, INSTR_RSY_RRRD }, - { "mvclu", 0x8e, INSTR_RSY_RRRD }, - { "tp", 0xc0, INSTR_RSL_R0RD }, - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_ec[] = { -#ifdef CONFIG_64BIT - { "brxhg", 0x44, INSTR_RIE_RRP }, - { "brxlg", 0x45, INSTR_RIE_RRP }, -#endif - { "", 0, INSTR_INVALID } -}; - -static struct insn opcode_ed[] = { -#ifdef CONFIG_64BIT - { "mayl", 0x38, INSTR_RXF_FRRDF }, - { "myl", 0x39, INSTR_RXF_FRRDF }, - { "may", 0x3a, INSTR_RXF_FRRDF }, - { "my", 0x3b, INSTR_RXF_FRRDF }, - { "mayh", 0x3c, INSTR_RXF_FRRDF }, - { "myh", 0x3d, INSTR_RXF_FRRDF }, - { "ley", 0x64, INSTR_RXY_FRRD }, - { "ldy", 0x65, INSTR_RXY_FRRD }, - { "stey", 0x66, INSTR_RXY_FRRD }, - { "stdy", 0x67, INSTR_RXY_FRRD }, -#endif - { "ldeb", 0x04, INSTR_RXE_FRRD }, - { "lxdb", 0x05, INSTR_RXE_FRRD }, - { "lxeb", 0x06, INSTR_RXE_FRRD }, - { "mxdb", 0x07, INSTR_RXE_FRRD }, - { "keb", 0x08, INSTR_RXE_FRRD }, - { "ceb", 0x09, INSTR_RXE_FRRD }, - { "aeb", 0x0a, INSTR_RXE_FRRD }, - { "seb", 0x0b, INSTR_RXE_FRRD }, - { "mdeb", 0x0c, INSTR_RXE_FRRD }, - { "deb", 0x0d, INSTR_RXE_FRRD }, - { "maeb", 0x0e, INSTR_RXF_FRRDF }, - { "mseb", 0x0f, INSTR_RXF_FRRDF }, - { "tceb", 0x10, INSTR_RXE_FRRD }, - { "tcdb", 0x11, INSTR_RXE_FRRD }, - { "tcxb", 0x12, INSTR_RXE_FRRD }, - { "sqeb", 0x14, INSTR_RXE_FRRD }, - { "sqdb", 0x15, INSTR_RXE_FRRD }, - { "meeb", 0x17, INSTR_RXE_FRRD }, - { "kdb", 0x18, INSTR_RXE_FRRD }, - { "cdb", 0x19, INSTR_RXE_FRRD }, - { "adb", 0x1a, INSTR_RXE_FRRD }, - { "sdb", 0x1b, INSTR_RXE_FRRD }, - { "mdb", 0x1c, INSTR_RXE_FRRD }, - { "ddb", 0x1d, INSTR_RXE_FRRD }, - { "madb", 0x1e, INSTR_RXF_FRRDF }, - { "msdb", 0x1f, INSTR_RXF_FRRDF }, - { "lde", 0x24, INSTR_RXE_FRRD }, - { "lxd", 0x25, INSTR_RXE_FRRD }, - { "lxe", 0x26, INSTR_RXE_FRRD }, - { "mae", 0x2e, INSTR_RXF_FRRDF }, - { "mse", 0x2f, INSTR_RXF_FRRDF }, - { "sqe", 0x34, INSTR_RXE_FRRD }, - { "mee", 0x37, INSTR_RXE_FRRD }, - { "mad", 0x3e, INSTR_RXF_FRRDF }, - { "msd", 0x3f, INSTR_RXF_FRRDF }, - { "", 0, INSTR_INVALID } -}; - -/* Extracts an operand value from an instruction. */ -static unsigned int extract_operand(unsigned char *code, - const struct operand *operand) -{ - unsigned int val; - int bits; - - /* Extract fragments of the operand byte for byte. */ - code += operand->shift / 8; - bits = (operand->shift & 7) + operand->bits; - val = 0; - do { - val <<= 8; - val |= (unsigned int) *code++; - bits -= 8; - } while (bits > 0); - val >>= -bits; - val &= ((1U << (operand->bits - 1)) << 1) - 1; - - /* Check for special long displacement case. */ - if (operand->bits == 20 && operand->shift == 20) - val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; - - /* Sign extend value if the operand is signed or pc relative. */ - if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) && - (val & (1U << (operand->bits - 1)))) - val |= (-1U << (operand->bits - 1)) << 1; - - /* Double value if the operand is pc relative. */ - if (operand->flags & OPERAND_PCREL) - val <<= 1; - - /* Length x in an instructions has real length x + 1. */ - if (operand->flags & OPERAND_LENGTH) - val++; - return val; -} - -static inline int insn_length(unsigned char code) -{ - return ((((int) code + 64) >> 7) + 1) << 1; -} - -static struct insn *find_insn(unsigned char *code) -{ - unsigned char opfrag = code[1]; - unsigned char opmask; - struct insn *table; - - switch (code[0]) { - case 0x01: - table = opcode_01; - break; - case 0xa5: - table = opcode_a5; - break; - case 0xa7: - table = opcode_a7; - break; - case 0xb2: - table = opcode_b2; - break; - case 0xb3: - table = opcode_b3; - break; - case 0xb9: - table = opcode_b9; - break; - case 0xc0: - table = opcode_c0; - break; - case 0xc2: - table = opcode_c2; - break; - case 0xc8: - table = opcode_c8; - break; - case 0xe3: - table = opcode_e3; - opfrag = code[5]; - break; - case 0xe5: - table = opcode_e5; - break; - case 0xeb: - table = opcode_eb; - opfrag = code[5]; - break; - case 0xec: - table = opcode_ec; - opfrag = code[5]; - break; - case 0xed: - table = opcode_ed; - opfrag = code[5]; - break; - default: - table = opcode; - opfrag = code[0]; - break; - } - while (table->format != INSTR_INVALID) { - opmask = formats[table->format][0]; - if (table->opfrag == (opfrag & opmask)) - return table; - table++; - } - return NULL; -} - -static int print_insn(char *buffer, unsigned char *code, unsigned long addr) -{ - struct insn *insn; - const unsigned char *ops; - const struct operand *operand; - unsigned int value; - char separator; - char *ptr; - - ptr = buffer; - insn = find_insn(code); - if (insn) { - ptr += sprintf(ptr, "%.5s\t", insn->name); - /* Extract the operands. */ - separator = 0; - for (ops = formats[insn->format] + 1; *ops != 0; ops++) { - operand = operands + *ops; - value = extract_operand(code, operand); - if ((operand->flags & OPERAND_INDEX) && value == 0) - continue; - if ((operand->flags & OPERAND_BASE) && - value == 0 && separator == '(') { - separator = ','; - continue; - } - if (separator) - ptr += sprintf(ptr, "%c", separator); - if (operand->flags & OPERAND_GPR) - ptr += sprintf(ptr, "%%r%i", value); - else if (operand->flags & OPERAND_FPR) - ptr += sprintf(ptr, "%%f%i", value); - else if (operand->flags & OPERAND_AR) - ptr += sprintf(ptr, "%%a%i", value); - else if (operand->flags & OPERAND_CR) - ptr += sprintf(ptr, "%%c%i", value); - else if (operand->flags & OPERAND_PCREL) - ptr += sprintf(ptr, "%lx", value + addr); - else if (operand->flags & OPERAND_SIGNED) - ptr += sprintf(ptr, "%i", value); - else - ptr += sprintf(ptr, "%u", value); - if (operand->flags & OPERAND_DISP) - separator = '('; - else if (operand->flags & OPERAND_BASE) { - ptr += sprintf(ptr, ")"); - separator = ','; - } else - separator = ','; - } - } else - ptr += sprintf(ptr, "unknown"); - return (int) (ptr - buffer); -} - -void show_code(struct pt_regs *regs) -{ - char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; - unsigned char code[64]; - char buffer[64], *ptr; - mm_segment_t old_fs; - unsigned long addr; - int start, end, opsize, hops, i; - - /* Get a snapshot of the 64 bytes surrounding the fault address. */ - old_fs = get_fs(); - set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS); - for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) { - addr = regs->psw.addr - 34 + start; - if (__copy_from_user(code + start - 2, - (char __user *) addr, 2)) - break; - } - for (end = 32; end < 64; end += 2) { - addr = regs->psw.addr + end - 32; - if (__copy_from_user(code + end, - (char __user *) addr, 2)) - break; - } - set_fs(old_fs); - /* Code snapshot useable ? */ - if ((regs->psw.addr & 1) || start >= end) { - printk("%s Code: Bad PSW.\n", mode); - return; - } - /* Find a starting point for the disassembly. */ - while (start < 32) { - hops = 0; - for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) { - if (!find_insn(code + start + i)) - break; - i += insn_length(code[start + i]); - } - if (start + i == 32) - /* Looks good, sequence ends at PSW. */ - break; - start += 2; - } - /* Decode the instructions. */ - ptr = buffer; - ptr += sprintf(ptr, "%s Code:", mode); - hops = 0; - while (start < end && hops < 8) { - *ptr++ = (start == 32) ? '>' : ' '; - addr = regs->psw.addr + start - 32; - ptr += sprintf(ptr, ONELONG, addr); - opsize = insn_length(code[start]); - if (start + opsize >= end) - break; - for (i = 0; i < opsize; i++) - ptr += sprintf(ptr, "%02x", code[start + i]); - *ptr++ = '\t'; - if (i < 6) - *ptr++ = '\t'; - ptr += print_insn(ptr, code + start, addr); - start += opsize; - printk(buffer); - ptr = buffer; - ptr += sprintf(ptr, "\n "); - hops++; - } - printk("\n"); -} diff --git a/trunk/arch/s390/kernel/early.c b/trunk/arch/s390/kernel/early.c index 50538e545618..5e47936573f2 100644 --- a/trunk/arch/s390/kernel/early.c +++ b/trunk/arch/s390/kernel/early.c @@ -253,10 +253,11 @@ static noinline __init void find_memory_chunks(unsigned long memsize) break; #endif /* - * Finish memory detection at the first hole - * if storage size is unknown. + * Finish memory detection at the first hole, unless + * - we reached the hsa -> skip it. + * - we know there must be more. */ - if (cc == -1UL && !memsize) + if (cc == -1UL && !memsize && old_addr != ADDR2G) break; if (memsize && addr >= memsize) break; diff --git a/trunk/arch/s390/kernel/entry.S b/trunk/arch/s390/kernel/entry.S index c8a2212014e0..dddc3de30401 100644 --- a/trunk/arch/s390/kernel/entry.S +++ b/trunk/arch/s390/kernel/entry.S @@ -249,6 +249,8 @@ sysc_do_restart: bnz BASED(sysc_tracesys) basr %r14,%r8 # call sys_xxxx st %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! sysc_return: tm SP_PSW+1(%r15),0x01 # returning to user ? @@ -379,37 +381,50 @@ ret_from_fork: b BASED(sysc_return) # -# kernel_execve function needs to deal with pt_regs that is not -# at the usual place +# clone, fork, vfork, exec and sigreturn need glue, +# because they all expect pt_regs as parameter, +# but are called with different parameter. +# return-address is set up above # - .globl kernel_execve -kernel_execve: - stm %r12,%r15,48(%r15) - lr %r14,%r15 - l %r13,__LC_SVC_NEW_PSW+4 - s %r15,BASED(.Lc_spsize) - st %r14,__SF_BACKCHAIN(%r15) - la %r12,SP_PTREGS(%r15) - xc 0(__PT_SIZE,%r12),0(%r12) - l %r1,BASED(.Ldo_execve) - lr %r5,%r12 - basr %r14,%r1 - ltr %r2,%r2 - be BASED(0f) - a %r15,BASED(.Lc_spsize) - lm %r12,%r15,48(%r15) - br %r14 - # execve succeeded. -0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts - l %r15,__LC_KERNEL_STACK # load ksp - s %r15,BASED(.Lc_spsize) # make room for registers & psw - l %r9,__LC_THREAD_INFO - mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - l %r1,BASED(.Lexecve_tail) - basr %r14,%r1 - b BASED(sysc_return) +sys_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lclone) + br %r1 # branch to sys_clone + +sys_fork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lfork) + br %r1 # branch to sys_fork + +sys_vfork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lvfork) + br %r1 # branch to sys_vfork + +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lexecve) + lr %r12,%r14 # save return address + basr %r14,%r1 # call sys_execve + ltr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8 + # in system_call/sysc_tracesys + +sys_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigreturn) + br %r1 # branch to sys_sigreturn + +sys_rt_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lrt_sigreturn) + br %r1 # branch to sys_sigreturn + +sys_sigaltstack_glue: + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigaltstack) + br %r1 # branch to sys_sigreturn /* * Program check handler routine @@ -1016,11 +1031,19 @@ cleanup_io_leave_insn: .Ldo_extint: .long do_extint .Ldo_signal: .long do_signal .Lhandle_per: .long do_single_step -.Ldo_execve: .long do_execve -.Lexecve_tail: .long execve_tail .Ljump_table: .long pgm_check_table .Lschedule: .long schedule +.Lclone: .long sys_clone +.Lexecve: .long sys_execve +.Lfork: .long sys_fork +.Lrt_sigreturn: .long sys_rt_sigreturn +.Lrt_sigsuspend: + .long sys_rt_sigsuspend +.Lsigreturn: .long sys_sigreturn +.Lsigsuspend: .long sys_sigsuspend +.Lsigaltstack: .long sys_sigaltstack .Ltrace: .long syscall_trace +.Lvfork: .long sys_vfork .Lschedtail: .long schedule_tail .Lsysc_table: .long sys_call_table #ifdef CONFIG_TRACE_IRQFLAGS diff --git a/trunk/arch/s390/kernel/entry64.S b/trunk/arch/s390/kernel/entry64.S index 93745fd8f555..0f758c329a5d 100644 --- a/trunk/arch/s390/kernel/entry64.S +++ b/trunk/arch/s390/kernel/entry64.S @@ -244,6 +244,8 @@ sysc_noemu: jnz sysc_tracesys basr %r14,%r8 # call sys_xxxx stg %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! sysc_return: tm SP_PSW+1(%r15),0x01 # returning to user ? @@ -369,35 +371,77 @@ ret_from_fork: j sysc_return # -# kernel_execve function needs to deal with pt_regs that is not -# at the usual place +# clone, fork, vfork, exec and sigreturn need glue, +# because they all expect pt_regs as parameter, +# but are called with different parameter. +# return-address is set up above # - .globl kernel_execve -kernel_execve: - stmg %r12,%r15,96(%r15) - lgr %r14,%r15 - aghi %r15,-SP_SIZE - stg %r14,__SF_BACKCHAIN(%r15) - la %r12,SP_PTREGS(%r15) - xc 0(__PT_SIZE,%r12),0(%r12) - lgr %r5,%r12 - brasl %r14,do_execve - ltgfr %r2,%r2 - je 0f - aghi %r15,SP_SIZE - lmg %r12,%r15,96(%r15) - br %r14 - # execve succeeded. -0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts - lg %r15,__LC_KERNEL_STACK # load ksp - aghi %r15,-SP_SIZE # make room for registers & psw - lg %r13,__LC_SVC_NEW_PSW+8 - lg %r9,__LC_THREAD_INFO - mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs - xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - brasl %r14,execve_tail - j sysc_return +sys_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_clone # branch to sys_clone + +#ifdef CONFIG_COMPAT +sys32_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys32_clone # branch to sys32_clone +#endif + +sys_fork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_fork # branch to sys_fork + +sys_vfork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_vfork # branch to sys_vfork + +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + lgr %r12,%r14 # save return address + brasl %r14,sys_execve # call sys_execve + ltgr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 6(%r12) # SKIP STG 2,SP_R2(15) in + # system_call/sysc_tracesys +#ifdef CONFIG_COMPAT +sys32_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + lgr %r12,%r14 # save return address + brasl %r14,sys32_execve # call sys32_execve + ltgr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 6(%r12) # SKIP STG 2,SP_R2(15) in + # system_call/sysc_tracesys +#endif + +sys_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_sigreturn # branch to sys_sigreturn + +#ifdef CONFIG_COMPAT +sys32_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_sigreturn # branch to sys32_sigreturn +#endif + +sys_rt_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_rt_sigreturn # branch to sys_sigreturn + +#ifdef CONFIG_COMPAT +sys32_rt_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_rt_sigreturn # branch to sys32_sigreturn +#endif + +sys_sigaltstack_glue: + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_sigaltstack # branch to sys_sigreturn + +#ifdef CONFIG_COMPAT +sys32_sigaltstack_glue: + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_sigaltstack_wrapper # branch to sys_sigreturn +#endif /* * Program check handler routine diff --git a/trunk/arch/s390/kernel/head64.S b/trunk/arch/s390/kernel/head64.S index a87b1976d409..37010709fe68 100644 --- a/trunk/arch/s390/kernel/head64.S +++ b/trunk/arch/s390/kernel/head64.S @@ -39,69 +39,7 @@ startup_continue: basr %r13,0 # get base .LPG1: sll %r13,1 # remove high order bit srl %r13,1 - -#ifdef CONFIG_ZFCPDUMP - - # check if we have been ipled using zfcp dump: - - tm 0xb9,0x01 # test if subchannel is enabled - jno .nodump # subchannel disabled - l %r1,0xb8 - la %r5,.Lipl_schib-.LPG1(%r13) - stsch 0(%r5) # get schib of subchannel - jne .nodump # schib not available - tm 5(%r5),0x01 # devno valid? - jno .nodump - tm 4(%r5),0x80 # qdio capable device? - jno .nodump - l %r2,20(%r0) # address of ipl parameter block - lhi %r3,0 - ic %r3,0x148(%r2) # get opt field - chi %r3,0x20 # load with dump? - jne .nodump - - # store all prefix registers in case of load with dump: - - la %r7,0 # base register for 0 page - la %r8,0 # first cpu - l %r11,.Lpref_arr_ptr-.LPG1(%r13) # address of prefix array - ahi %r11,4 # skip boot cpu - lr %r12,%r11 - ahi %r12,(CONFIG_NR_CPUS*4) # end of prefix array - stap .Lcurrent_cpu+2-.LPG1(%r13) # store current cpu addr -1: - cl %r8,.Lcurrent_cpu-.LPG1(%r13) # is ipl cpu ? - je 4f # if yes get next cpu -2: - lr %r9,%r7 - sigp %r9,%r8,0x9 # stop & store status of cpu - brc 8,3f # accepted - brc 4,4f # status stored: next cpu - brc 2,2b # busy: try again - brc 1,4f # not op: next cpu -3: - mvc 0(4,%r11),264(%r7) # copy prefix register to prefix array - ahi %r11,4 # next element in prefix array - clr %r11,%r12 - je 5f # no more space in prefix array -4: - ahi %r8,1 # next cpu (r8 += 1) - cl %r8,.Llast_cpu-.LPG1(%r13) # is last possible cpu ? - jl 1b # jump if not last cpu -5: - lhi %r1,2 # mode 2 = esame (dump) - j 6f - .align 4 -.Lipl_schib: - .rept 13 - .long 0 - .endr -.nodump: - lhi %r1,1 # mode 1 = esame (normal ipl) -6: -#else - lhi %r1,1 # mode 1 = esame (normal ipl) -#endif /* CONFIG_ZFCPDUMP */ + lhi %r1,1 # mode 1 = esame mvi __LC_AR_MODE_ID,1 # set esame flag slr %r0,%r0 # set cpuid to zero sigp %r1,%r0,0x12 # switch to esame mode @@ -211,14 +149,6 @@ startup_continue: .L4malign:.quad 0xffffffffffc00000 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 .Lnop: .long 0x07000700 -#ifdef CONFIG_ZFCPDUMP -.Lcurrent_cpu: - .long 0x0 -.Llast_cpu: - .long 0x0000ffff -.Lpref_arr_ptr: - .long zfcpdump_prefix_array -#endif /* CONFIG_ZFCPDUMP */ .Lparmaddr: .quad PARMAREA .align 64 diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c index 0ea048d350d8..f731185bf2bd 100644 --- a/trunk/arch/s390/kernel/ipl.c +++ b/trunk/arch/s390/kernel/ipl.c @@ -29,21 +29,36 @@ #define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm) #define SCCB_FLAG (s390_readinfo_sccb.flags) -#define IPL_UNKNOWN_STR "unknown" -#define IPL_CCW_STR "ccw" -#define IPL_FCP_STR "fcp" -#define IPL_FCP_DUMP_STR "fcp_dump" -#define IPL_NSS_STR "nss" +enum ipl_type { + IPL_TYPE_NONE = 1, + IPL_TYPE_UNKNOWN = 2, + IPL_TYPE_CCW = 4, + IPL_TYPE_FCP = 8, + IPL_TYPE_NSS = 16, +}; + +#define IPL_NONE_STR "none" +#define IPL_UNKNOWN_STR "unknown" +#define IPL_CCW_STR "ccw" +#define IPL_FCP_STR "fcp" +#define IPL_NSS_STR "nss" + +/* + * Must be in data section since the bss section + * is not cleared when these are accessed. + */ +u16 ipl_devno __attribute__((__section__(".data"))) = 0; +u32 ipl_flags __attribute__((__section__(".data"))) = 0; static char *ipl_type_str(enum ipl_type type) { switch (type) { + case IPL_TYPE_NONE: + return IPL_NONE_STR; case IPL_TYPE_CCW: return IPL_CCW_STR; case IPL_TYPE_FCP: return IPL_FCP_STR; - case IPL_TYPE_FCP_DUMP: - return IPL_FCP_DUMP_STR; case IPL_TYPE_NSS: return IPL_NSS_STR; case IPL_TYPE_UNKNOWN: @@ -52,55 +67,15 @@ static char *ipl_type_str(enum ipl_type type) } } -enum dump_type { - DUMP_TYPE_NONE = 1, - DUMP_TYPE_CCW = 2, - DUMP_TYPE_FCP = 4, -}; - -#define DUMP_NONE_STR "none" -#define DUMP_CCW_STR "ccw" -#define DUMP_FCP_STR "fcp" - -static char *dump_type_str(enum dump_type type) -{ - switch (type) { - case DUMP_TYPE_NONE: - return DUMP_NONE_STR; - case DUMP_TYPE_CCW: - return DUMP_CCW_STR; - case DUMP_TYPE_FCP: - return DUMP_FCP_STR; - default: - return NULL; - } -} - -/* - * Must be in data section since the bss section - * is not cleared when these are accessed. - */ -static u16 ipl_devno __attribute__((__section__(".data"))) = 0; -u32 ipl_flags __attribute__((__section__(".data"))) = 0; - enum ipl_method { - REIPL_METHOD_CCW_CIO, - REIPL_METHOD_CCW_DIAG, - REIPL_METHOD_CCW_VM, - REIPL_METHOD_FCP_RO_DIAG, - REIPL_METHOD_FCP_RW_DIAG, - REIPL_METHOD_FCP_RO_VM, - REIPL_METHOD_FCP_DUMP, - REIPL_METHOD_NSS, - REIPL_METHOD_DEFAULT, -}; - -enum dump_method { - DUMP_METHOD_NONE, - DUMP_METHOD_CCW_CIO, - DUMP_METHOD_CCW_DIAG, - DUMP_METHOD_CCW_VM, - DUMP_METHOD_FCP_DIAG, + IPL_METHOD_NONE, + IPL_METHOD_CCW_CIO, + IPL_METHOD_CCW_DIAG, + IPL_METHOD_CCW_VM, + IPL_METHOD_FCP_RO_DIAG, + IPL_METHOD_FCP_RW_DIAG, + IPL_METHOD_FCP_RO_VM, + IPL_METHOD_NSS, }; enum shutdown_action { @@ -132,15 +107,15 @@ static int diag308_set_works = 0; static int reipl_capabilities = IPL_TYPE_UNKNOWN; static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; -static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; +static enum ipl_method reipl_method = IPL_METHOD_NONE; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; static char reipl_nss_name[NSS_NAME_SIZE + 1]; -static int dump_capabilities = DUMP_TYPE_NONE; -static enum dump_type dump_type = DUMP_TYPE_NONE; -static enum dump_method dump_method = DUMP_METHOD_NONE; +static int dump_capabilities = IPL_TYPE_NONE; +static enum ipl_type dump_type = IPL_TYPE_NONE; +static enum ipl_method dump_method = IPL_METHOD_NONE; static struct ipl_parameter_block *dump_block_fcp; static struct ipl_parameter_block *dump_block_ccw; @@ -159,12 +134,11 @@ int diag308(unsigned long subcode, void *addr) : "d" (subcode) : "cc", "memory"); return _rc; } -EXPORT_SYMBOL_GPL(diag308); /* SYSFS */ #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ char *page) \ { \ return sprintf(page, _format, _value); \ @@ -173,13 +147,13 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL); #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ char *page) \ { \ return sprintf(page, _fmt_out, \ (unsigned long long) _value); \ } \ -static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ const char *buf, size_t len) \ { \ unsigned long long value; \ @@ -194,12 +168,12 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ sys_##_prefix##_##_name##_store); #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ -static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ char *page) \ { \ return sprintf(page, _fmt_out, _value); \ } \ -static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ +static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ const char *buf, size_t len) \ { \ if (sscanf(buf, _fmt_in, _value) != 1) \ @@ -223,7 +197,7 @@ static void make_attrs_ro(struct attribute **attrs) * ipl section */ -static __init enum ipl_type get_ipl_type(void) +static enum ipl_type ipl_get_type(void) { struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; @@ -237,57 +211,24 @@ static __init enum ipl_type get_ipl_type(void) return IPL_TYPE_UNKNOWN; if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP) return IPL_TYPE_UNKNOWN; - if (ipl->ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP) - return IPL_TYPE_FCP_DUMP; return IPL_TYPE_FCP; } -void __init setup_ipl_info(void) -{ - ipl_info.type = get_ipl_type(); - switch (ipl_info.type) { - case IPL_TYPE_CCW: - ipl_info.data.ccw.dev_id.devno = ipl_devno; - ipl_info.data.ccw.dev_id.ssid = 0; - break; - case IPL_TYPE_FCP: - case IPL_TYPE_FCP_DUMP: - ipl_info.data.fcp.dev_id.devno = - IPL_PARMBLOCK_START->ipl_info.fcp.devno; - ipl_info.data.fcp.dev_id.ssid = 0; - ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn; - ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun; - break; - case IPL_TYPE_NSS: - strncpy(ipl_info.data.nss.name, kernel_nss_name, - sizeof(ipl_info.data.nss.name)); - break; - case IPL_TYPE_UNKNOWN: - default: - /* We have no info to copy */ - break; - } -} - -struct ipl_info ipl_info; -EXPORT_SYMBOL_GPL(ipl_info); - -static ssize_t ipl_type_show(struct kset *kset, char *page) +static ssize_t ipl_type_show(struct subsystem *subsys, char *page) { - return sprintf(page, "%s\n", ipl_type_str(ipl_info.type)); + return sprintf(page, "%s\n", ipl_type_str(ipl_get_type())); } static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); -static ssize_t sys_ipl_device_show(struct kset *kset, char *page) +static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page) { struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; - switch (ipl_info.type) { + switch (ipl_get_type()) { case IPL_TYPE_CCW: return sprintf(page, "0.0.%04x\n", ipl_devno); case IPL_TYPE_FCP: - case IPL_TYPE_FCP_DUMP: return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno); default: return 0; @@ -371,7 +312,7 @@ static struct attribute_group ipl_fcp_attr_group = { /* CCW ipl device attributes */ -static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) +static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page) { char loadparm[LOADPARM_LEN + 1] = {}; @@ -469,7 +410,7 @@ static void reipl_get_ascii_loadparm(char *loadparm) strstrip(loadparm); } -static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) +static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page) { char buf[LOADPARM_LEN + 1]; @@ -477,7 +418,7 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) return sprintf(page, "%s\n", buf); } -static ssize_t reipl_ccw_loadparm_store(struct kset *kset, +static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys, const char *buf, size_t len) { int i, lp_len; @@ -544,40 +485,34 @@ static int reipl_set_type(enum ipl_type type) switch(type) { case IPL_TYPE_CCW: if (MACHINE_IS_VM) - reipl_method = REIPL_METHOD_CCW_VM; + reipl_method = IPL_METHOD_CCW_VM; else - reipl_method = REIPL_METHOD_CCW_CIO; + reipl_method = IPL_METHOD_CCW_CIO; break; case IPL_TYPE_FCP: if (diag308_set_works) - reipl_method = REIPL_METHOD_FCP_RW_DIAG; + reipl_method = IPL_METHOD_FCP_RW_DIAG; else if (MACHINE_IS_VM) - reipl_method = REIPL_METHOD_FCP_RO_VM; + reipl_method = IPL_METHOD_FCP_RO_VM; else - reipl_method = REIPL_METHOD_FCP_RO_DIAG; - break; - case IPL_TYPE_FCP_DUMP: - reipl_method = REIPL_METHOD_FCP_DUMP; + reipl_method = IPL_METHOD_FCP_RO_DIAG; break; case IPL_TYPE_NSS: - reipl_method = REIPL_METHOD_NSS; - break; - case IPL_TYPE_UNKNOWN: - reipl_method = REIPL_METHOD_DEFAULT; + reipl_method = IPL_METHOD_NSS; break; default: - BUG(); + reipl_method = IPL_METHOD_NONE; } reipl_type = type; return 0; } -static ssize_t reipl_type_show(struct kset *kset, char *page) +static ssize_t reipl_type_show(struct subsystem *subsys, char *page) { return sprintf(page, "%s\n", ipl_type_str(reipl_type)); } -static ssize_t reipl_type_store(struct kset *kset, const char *buf, +static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf, size_t len) { int rc = -EINVAL; @@ -644,43 +579,43 @@ static struct attribute_group dump_ccw_attr_group = { /* dump type */ -static int dump_set_type(enum dump_type type) +static int dump_set_type(enum ipl_type type) { if (!(dump_capabilities & type)) return -EINVAL; switch(type) { - case DUMP_TYPE_CCW: + case IPL_TYPE_CCW: if (MACHINE_IS_VM) - dump_method = DUMP_METHOD_CCW_VM; + dump_method = IPL_METHOD_CCW_VM; else - dump_method = DUMP_METHOD_CCW_CIO; + dump_method = IPL_METHOD_CCW_CIO; break; - case DUMP_TYPE_FCP: - dump_method = DUMP_METHOD_FCP_DIAG; + case IPL_TYPE_FCP: + dump_method = IPL_METHOD_FCP_RW_DIAG; break; default: - dump_method = DUMP_METHOD_NONE; + dump_method = IPL_METHOD_NONE; } dump_type = type; return 0; } -static ssize_t dump_type_show(struct kset *kset, char *page) +static ssize_t dump_type_show(struct subsystem *subsys, char *page) { - return sprintf(page, "%s\n", dump_type_str(dump_type)); + return sprintf(page, "%s\n", ipl_type_str(dump_type)); } -static ssize_t dump_type_store(struct kset *kset, const char *buf, +static ssize_t dump_type_store(struct subsystem *subsys, const char *buf, size_t len) { int rc = -EINVAL; - if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0) - rc = dump_set_type(DUMP_TYPE_NONE); - else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0) - rc = dump_set_type(DUMP_TYPE_CCW); - else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0) - rc = dump_set_type(DUMP_TYPE_FCP); + if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0) + rc = dump_set_type(IPL_TYPE_NONE); + else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0) + rc = dump_set_type(IPL_TYPE_CCW); + else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) + rc = dump_set_type(IPL_TYPE_FCP); return (rc != 0) ? rc : len; } @@ -697,12 +632,12 @@ static decl_subsys(shutdown_actions, NULL, NULL); /* on panic */ -static ssize_t on_panic_show(struct kset *kset, char *page) +static ssize_t on_panic_show(struct subsystem *subsys, char *page) { return sprintf(page, "%s\n", shutdown_action_str(on_panic_action)); } -static ssize_t on_panic_store(struct kset *kset, const char *buf, +static ssize_t on_panic_store(struct subsystem *subsys, const char *buf, size_t len) { if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0) @@ -729,14 +664,14 @@ void do_reipl(void) char loadparm[LOADPARM_LEN + 1]; switch (reipl_method) { - case REIPL_METHOD_CCW_CIO: + case IPL_METHOD_CCW_CIO: devid.devno = reipl_block_ccw->ipl_info.ccw.devno; - if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno) + if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno) diag308(DIAG308_IPL, NULL); devid.ssid = 0; reipl_ccw_dev(&devid); break; - case REIPL_METHOD_CCW_VM: + case IPL_METHOD_CCW_VM: reipl_get_ascii_loadparm(loadparm); if (strlen(loadparm) == 0) sprintf(buf, "IPL %X", @@ -746,32 +681,30 @@ void do_reipl(void) reipl_block_ccw->ipl_info.ccw.devno, loadparm); __cpcmd(buf, NULL, 0, NULL); break; - case REIPL_METHOD_CCW_DIAG: + case IPL_METHOD_CCW_DIAG: diag308(DIAG308_SET, reipl_block_ccw); diag308(DIAG308_IPL, NULL); break; - case REIPL_METHOD_FCP_RW_DIAG: + case IPL_METHOD_FCP_RW_DIAG: diag308(DIAG308_SET, reipl_block_fcp); diag308(DIAG308_IPL, NULL); break; - case REIPL_METHOD_FCP_RO_DIAG: + case IPL_METHOD_FCP_RO_DIAG: diag308(DIAG308_IPL, NULL); break; - case REIPL_METHOD_FCP_RO_VM: + case IPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; - case REIPL_METHOD_NSS: + case IPL_METHOD_NSS: sprintf(buf, "IPL %s", reipl_nss_name); __cpcmd(buf, NULL, 0, NULL); break; - case REIPL_METHOD_DEFAULT: + case IPL_METHOD_NONE: + default: if (MACHINE_IS_VM) __cpcmd("IPL", NULL, 0, NULL); diag308(DIAG308_IPL, NULL); break; - case REIPL_METHOD_FCP_DUMP: - default: - break; } signal_processor(smp_processor_id(), sigp_stop_and_store_status); } @@ -782,28 +715,28 @@ static void do_dump(void) static char buf[100]; switch (dump_method) { - case DUMP_METHOD_CCW_CIO: + case IPL_METHOD_CCW_CIO: smp_send_stop(); devid.devno = dump_block_ccw->ipl_info.ccw.devno; devid.ssid = 0; reipl_ccw_dev(&devid); break; - case DUMP_METHOD_CCW_VM: + case IPL_METHOD_CCW_VM: smp_send_stop(); sprintf(buf, "STORE STATUS"); __cpcmd(buf, NULL, 0, NULL); sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); __cpcmd(buf, NULL, 0, NULL); break; - case DUMP_METHOD_CCW_DIAG: + case IPL_METHOD_CCW_DIAG: diag308(DIAG308_SET, dump_block_ccw); diag308(DIAG308_DUMP, NULL); break; - case DUMP_METHOD_FCP_DIAG: + case IPL_METHOD_FCP_RW_DIAG: diag308(DIAG308_SET, dump_block_fcp); diag308(DIAG308_DUMP, NULL); break; - case DUMP_METHOD_NONE: + case IPL_METHOD_NONE: default: return; } @@ -844,13 +777,12 @@ static int __init ipl_init(void) rc = firmware_register(&ipl_subsys); if (rc) return rc; - switch (ipl_info.type) { + switch (ipl_get_type()) { case IPL_TYPE_CCW: rc = sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_ccw_attr_group); break; case IPL_TYPE_FCP: - case IPL_TYPE_FCP_DUMP: rc = ipl_register_fcp_files(); break; case IPL_TYPE_NSS: @@ -920,7 +852,7 @@ static int __init reipl_ccw_init(void) /* FIXME: check for diag308_set_works when enabling diag ccw reipl */ if (!MACHINE_IS_VM) sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; - if (ipl_info.type == IPL_TYPE_CCW) + if (ipl_get_type() == IPL_TYPE_CCW) reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; reipl_capabilities |= IPL_TYPE_CCW; return 0; @@ -930,9 +862,9 @@ static int __init reipl_fcp_init(void) { int rc; - if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP)) + if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP)) return 0; - if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP)) + if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP)) make_attrs_ro(reipl_fcp_attrs); reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); @@ -943,7 +875,7 @@ static int __init reipl_fcp_init(void) free_page((unsigned long)reipl_block_fcp); return rc; } - if (ipl_info.type == IPL_TYPE_FCP) { + if (ipl_get_type() == IPL_TYPE_FCP) { memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE); } else { reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; @@ -977,7 +909,7 @@ static int __init reipl_init(void) rc = reipl_nss_init(); if (rc) return rc; - rc = reipl_set_type(ipl_info.type); + rc = reipl_set_type(ipl_get_type()); if (rc) return rc; return 0; @@ -999,7 +931,7 @@ static int __init dump_ccw_init(void) dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; dump_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; - dump_capabilities |= DUMP_TYPE_CCW; + dump_capabilities |= IPL_TYPE_CCW; return 0; } @@ -1024,7 +956,7 @@ static int __init dump_fcp_init(void) dump_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN; dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP; dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP; - dump_capabilities |= DUMP_TYPE_FCP; + dump_capabilities |= IPL_TYPE_FCP; return 0; } @@ -1063,7 +995,7 @@ static int __init dump_init(void) rc = dump_fcp_init(); if (rc) return rc; - dump_set_type(DUMP_TYPE_NONE); + dump_set_type(IPL_TYPE_NONE); return 0; } @@ -1106,27 +1038,6 @@ static int __init s390_ipl_init(void) __initcall(s390_ipl_init); -void __init ipl_save_parameters(void) -{ - struct cio_iplinfo iplinfo; - unsigned int *ipl_ptr; - void *src, *dst; - - if (cio_get_iplinfo(&iplinfo)) - return; - - ipl_devno = iplinfo.devno; - ipl_flags |= IPL_DEVNO_VALID; - if (!iplinfo.is_qdio) - return; - ipl_flags |= IPL_PARMBLOCK_VALID; - ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR; - src = (void *)(unsigned long)*ipl_ptr; - dst = (void *)IPL_PARMBLOCK_ORIGIN; - memmove(dst, src, PAGE_SIZE); - *ipl_ptr = IPL_PARMBLOCK_ORIGIN; -} - static LIST_HEAD(rcall); static DEFINE_MUTEX(rcall_mutex); diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c index 23c61f6d965b..993f35381496 100644 --- a/trunk/arch/s390/kernel/kprobes.c +++ b/trunk/arch/s390/kernel/kprobes.c @@ -516,7 +516,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) return 1; } -int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -603,6 +603,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ret = NOTIFY_STOP; break; case DIE_TRAP: + case DIE_PAGE_FAULT: /* kprobe_running() needs smp_processor_id() */ preempt_disable(); if (kprobe_running() && diff --git a/trunk/arch/s390/kernel/module.c b/trunk/arch/s390/kernel/module.c index 59b4e796680a..39d1dd752529 100644 --- a/trunk/arch/s390/kernel/module.c +++ b/trunk/arch/s390/kernel/module.c @@ -31,7 +31,6 @@ #include #include #include -#include #if 0 #define DEBUGP printk @@ -399,10 +398,9 @@ int module_finalize(const Elf_Ehdr *hdr, struct module *me) { vfree(me->arch.syminfo); - return module_bug_finalize(hdr, sechdrs, me); + return 0; } void module_arch_cleanup(struct module *mod) { - module_bug_cleanup(mod); } diff --git a/trunk/arch/s390/kernel/process.c b/trunk/arch/s390/kernel/process.c index 11d9b0197626..5acfac654f9d 100644 --- a/trunk/arch/s390/kernel/process.c +++ b/trunk/arch/s390/kernel/process.c @@ -280,26 +280,24 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, return 0; } -asmlinkage long sys_fork(void) +asmlinkage long sys_fork(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); - return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); + return do_fork(SIGCHLD, regs.gprs[15], ®s, 0, NULL, NULL); } -asmlinkage long sys_clone(void) +asmlinkage long sys_clone(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); - unsigned long clone_flags; - unsigned long newsp; + unsigned long clone_flags; + unsigned long newsp; int __user *parent_tidptr, *child_tidptr; - clone_flags = regs->gprs[3]; - newsp = regs->orig_gpr2; - parent_tidptr = (int __user *) regs->gprs[4]; - child_tidptr = (int __user *) regs->gprs[5]; - if (!newsp) - newsp = regs->gprs[15]; - return do_fork(clone_flags, newsp, regs, 0, + clone_flags = regs.gprs[3]; + newsp = regs.orig_gpr2; + parent_tidptr = (int __user *) regs.gprs[4]; + child_tidptr = (int __user *) regs.gprs[5]; + if (!newsp) + newsp = regs.gprs[15]; + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } @@ -313,52 +311,40 @@ asmlinkage long sys_clone(void) * do not have enough call-clobbered registers to hold all * the information you need. */ -asmlinkage long sys_vfork(void) +asmlinkage long sys_vfork(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - regs->gprs[15], regs, 0, NULL, NULL); -} - -asmlinkage void execve_tail(void) -{ - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - current->thread.fp_regs.fpc = 0; - if (MACHINE_HAS_IEEE) - asm volatile("sfpc %0,%0" : : "d" (0)); + regs.gprs[15], ®s, 0, NULL, NULL); } /* * sys_execve() executes a new program. */ -asmlinkage long sys_execve(void) +asmlinkage long sys_execve(struct pt_regs regs) { - struct pt_regs *regs = task_pt_regs(current); - char *filename; - unsigned long result; - int rc; - - filename = getname((char __user *) regs->orig_gpr2); - if (IS_ERR(filename)) { - result = PTR_ERR(filename); - goto out; + int error; + char * filename; + + filename = getname((char __user *) regs.orig_gpr2); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, (char __user * __user *) regs.gprs[3], + (char __user * __user *) regs.gprs[4], ®s); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + current->thread.fp_regs.fpc = 0; + if (MACHINE_HAS_IEEE) + asm volatile("sfpc %0,%0" : : "d" (0)); } - rc = do_execve(filename, (char __user * __user *) regs->gprs[3], - (char __user * __user *) regs->gprs[4], regs); - if (rc) { - result = rc; - goto out_putname; - } - execve_tail(); - result = regs->gprs[2]; -out_putname: - putname(filename); + putname(filename); out: - return result; + return error; } + /* * fill in the FPU structure for a core dump. */ diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index 6bfb0889eb10..863c8d08c026 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -65,7 +65,7 @@ long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | * User copy operations. */ struct uaccess_ops uaccess; -EXPORT_SYMBOL(uaccess); +EXPORT_SYMBOL_GPL(uaccess); /* * Machine setup.. @@ -74,8 +74,6 @@ unsigned int console_mode = 0; unsigned int console_devno = -1; unsigned int console_irq = -1; unsigned long machine_flags = 0; -unsigned long elf_hwcap = 0; -char elf_platform[ELF_PLATFORM_SIZE]; struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ @@ -287,26 +285,6 @@ static void __init conmode_default(void) } } -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) -static void __init setup_zfcpdump(unsigned int console_devno) -{ - static char str[64]; - - if (ipl_info.type != IPL_TYPE_FCP_DUMP) - return; - if (console_devno != -1) - sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x", - ipl_info.data.fcp.dev_id.devno, console_devno); - else - sprintf(str, "cio_ignore=all,!0.0.%04x", - ipl_info.data.fcp.dev_id.devno); - strcat(COMMAND_LINE, str); - console_loglevel = 2; -} -#else -static inline void setup_zfcpdump(unsigned int console_devno) {} -#endif /* CONFIG_ZFCPDUMP */ - #ifdef CONFIG_SMP void (*_machine_restart)(char *command) = machine_restart_smp; void (*_machine_halt)(void) = machine_halt_smp; @@ -608,20 +586,13 @@ setup_resources(void) } } -unsigned long real_memory_size; -EXPORT_SYMBOL_GPL(real_memory_size); - static void __init setup_memory_end(void) { - unsigned long memory_size; + unsigned long real_size, memory_size; unsigned long max_mem, max_phys; int i; -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) - if (ipl_info.type == IPL_TYPE_FCP_DUMP) - memory_end = ZFCPDUMP_HSA_SIZE; -#endif - memory_size = 0; + memory_size = real_size = 0; max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE; memory_end &= PAGE_MASK; @@ -630,8 +601,7 @@ static void __init setup_memory_end(void) for (i = 0; i < MEMORY_CHUNKS; i++) { struct mem_chunk *chunk = &memory_chunk[i]; - real_memory_size = max(real_memory_size, - chunk->addr + chunk->size); + real_size = max(real_size, chunk->addr + chunk->size); if (chunk->addr >= max_mem) { memset(chunk, 0, sizeof(*chunk)); continue; @@ -751,98 +721,6 @@ setup_memory(void) #endif } -static __init unsigned int stfl(void) -{ - asm volatile( - " .insn s,0xb2b10000,0(0)\n" /* stfl */ - "0:\n" - EX_TABLE(0b,0b)); - return S390_lowcore.stfl_fac_list; -} - -static __init int stfle(unsigned long long *list, int doublewords) -{ - typedef struct { unsigned long long _[doublewords]; } addrtype; - register unsigned long __nr asm("0") = doublewords - 1; - - asm volatile(".insn s,0xb2b00000,%0" /* stfle */ - : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); - return __nr + 1; -} - -/* - * Setup hardware capabilities. - */ -static void __init setup_hwcaps(void) -{ - static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; - struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; - unsigned long long facility_list_extended; - unsigned int facility_list; - int i; - - facility_list = stfl(); - /* - * The store facility list bits numbers as found in the principles - * of operation are numbered with bit 1UL<<31 as number 0 to - * bit 1UL<<0 as number 31. - * Bit 0: instructions named N3, "backported" to esa-mode - * Bit 2: z/Architecture mode is active - * Bit 7: the store-facility-list-extended facility is installed - * Bit 17: the message-security assist is installed - * Bit 19: the long-displacement facility is installed - * Bit 21: the extended-immediate facility is installed - * These get translated to: - * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1, - * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, - * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. - */ - for (i = 0; i < 6; i++) - if (facility_list & (1UL << (31 - stfl_bits[i]))) - elf_hwcap |= 1UL << i; - - /* - * Check for additional facilities with store-facility-list-extended. - * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 - * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information - * as stored by stfl, bits 32-xxx contain additional facilities. - * How many facility words are stored depends on the number of - * doublewords passed to the instruction. The additional facilites - * are: - * Bit 43: decimal floating point facility is installed - * translated to: - * HWCAP_S390_DFP bit 6. - */ - if ((elf_hwcap & (1UL << 2)) && - stfle(&facility_list_extended, 1) > 0) { - if (facility_list_extended & (1ULL << (64 - 43))) - elf_hwcap |= 1UL << 6; - } - - switch (cpuinfo->cpu_id.machine) { - case 0x9672: -#if !defined(CONFIG_64BIT) - default: /* Use "g5" as default for 31 bit kernels. */ -#endif - strcpy(elf_platform, "g5"); - break; - case 0x2064: - case 0x2066: -#if defined(CONFIG_64BIT) - default: /* Use "z900" as default for 64 bit kernels. */ -#endif - strcpy(elf_platform, "z900"); - break; - case 0x2084: - case 0x2086: - strcpy(elf_platform, "z990"); - break; - case 0x2094: - strcpy(elf_platform, "z9-109"); - break; - } -} - /* * Setup function called from init/main.c just after the banner * was printed. @@ -887,7 +765,6 @@ setup_arch(char **cmdline_p) parse_early_param(); - setup_ipl_info(); setup_memory_end(); setup_addressing_mode(); setup_memory(); @@ -898,11 +775,6 @@ setup_arch(char **cmdline_p) __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; smp_setup_cpu_possible_map(); - /* - * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). - */ - setup_hwcaps(); - /* * Create kernel page tables and switch to virtual addressing. */ @@ -910,9 +782,6 @@ setup_arch(char **cmdline_p) /* Setup default console */ conmode_default(); - - /* Setup zfcpdump support */ - setup_zfcpdump(console_devno); } void print_cpu_info(struct cpuinfo_S390 *cpuinfo) @@ -938,12 +807,8 @@ void print_cpu_info(struct cpuinfo_S390 *cpuinfo) static int show_cpuinfo(struct seq_file *m, void *v) { - static const char *hwcap_str[7] = { - "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp" - }; struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; - int i; s390_adjust_jiffies(); preempt_disable(); @@ -953,13 +818,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) "bogomips per cpu: %lu.%02lu\n", num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); - seq_puts(m, "features\t: "); - for (i = 0; i < 7; i++) - if (hwcap_str[i] && (elf_hwcap & (1UL << i))) - seq_printf(m, "%s ", hwcap_str[i]); - seq_puts(m, "\n"); } - if (cpu_online(n)) { #ifdef CONFIG_SMP if (smp_processor_id() == n) diff --git a/trunk/arch/s390/kernel/signal.c b/trunk/arch/s390/kernel/signal.c index 3c41907799a1..554f9cf7499c 100644 --- a/trunk/arch/s390/kernel/signal.c +++ b/trunk/arch/s390/kernel/signal.c @@ -102,9 +102,9 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, } asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, + struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); return do_sigaltstack(uss, uoss, regs->gprs[15]); } @@ -163,9 +163,8 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) return 0; } -asmlinkage long sys_sigreturn(void) +asmlinkage long sys_sigreturn(struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); sigframe __user *frame = (sigframe __user *)regs->gprs[15]; sigset_t set; @@ -190,9 +189,8 @@ asmlinkage long sys_sigreturn(void) return 0; } -asmlinkage long sys_rt_sigreturn(void) +asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) { - struct pt_regs *regs = task_pt_regs(current); rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15]; sigset_t set; diff --git a/trunk/arch/s390/kernel/smp.c b/trunk/arch/s390/kernel/smp.c index 3754e2031b39..97764f710bb7 100644 --- a/trunk/arch/s390/kernel/smp.c +++ b/trunk/arch/s390/kernel/smp.c @@ -1,12 +1,12 @@ /* * arch/s390/kernel/smp.c * - * Copyright IBM Corp. 1999,2007 + * Copyright (C) IBM Corp. 1999,2006 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Heiko Carstens (heiko.carstens@de.ibm.com) + * Martin Schwidefsky (schwidefsky@de.ibm.com) + * Heiko Carstens (heiko.carstens@de.ibm.com) * - * based on other smp stuff by + * based on other smp stuff by * (c) 1995 Alan Cox, CymruNET Ltd * (c) 1998 Ingo Molnar * @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -41,19 +40,17 @@ #include #include #include -#include + +extern volatile int __cpu_logical_map[]; /* * An array with a pointer the lowcore of every CPU. */ + struct _lowcore *lowcore_ptr[NR_CPUS]; -EXPORT_SYMBOL(lowcore_ptr); cpumask_t cpu_online_map = CPU_MASK_NONE; -EXPORT_SYMBOL(cpu_online_map); - cpumask_t cpu_possible_map = CPU_MASK_NONE; -EXPORT_SYMBOL(cpu_possible_map); static struct task_struct *current_set[NR_CPUS]; @@ -73,7 +70,7 @@ struct call_data_struct { int wait; }; -static struct call_data_struct *call_data; +static struct call_data_struct * call_data; /* * 'Call function' interrupt callback @@ -153,8 +150,8 @@ static void __smp_call_function_map(void (*func) (void *info), void *info, * * Run a function on all other CPUs. * - * You must not call this function with disabled interrupts, from a - * hardware interrupt handler or from a bottom half. + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler. You may call it from a bottom half. */ int smp_call_function(void (*func) (void *info), void *info, int nonatomic, int wait) @@ -180,11 +177,11 @@ EXPORT_SYMBOL(smp_call_function); * * Run a function on one processor. * - * You must not call this function with disabled interrupts, from a - * hardware interrupt handler or from a bottom half. + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler. You may call it from a bottom half. */ int smp_call_function_on(void (*func) (void *info), void *info, int nonatomic, - int wait, int cpu) + int wait, int cpu) { cpumask_t map = CPU_MASK_NONE; @@ -198,9 +195,9 @@ EXPORT_SYMBOL(smp_call_function_on); static void do_send_stop(void) { - int cpu, rc; + int cpu, rc; - /* stop all processors */ + /* stop all processors */ for_each_online_cpu(cpu) { if (cpu == smp_processor_id()) continue; @@ -212,9 +209,9 @@ static void do_send_stop(void) static void do_store_status(void) { - int cpu, rc; + int cpu, rc; - /* store status of all processors in their lowcores (real 0) */ + /* store status of all processors in their lowcores (real 0) */ for_each_online_cpu(cpu) { if (cpu == smp_processor_id()) continue; @@ -222,8 +219,8 @@ static void do_store_status(void) rc = signal_processor_p( (__u32)(unsigned long) lowcore_ptr[cpu], cpu, sigp_store_status_at_address); - } while (rc == sigp_busy); - } + } while(rc == sigp_busy); + } } static void do_wait_for_stop(void) @@ -234,7 +231,7 @@ static void do_wait_for_stop(void) for_each_online_cpu(cpu) { if (cpu == smp_processor_id()) continue; - while (!smp_cpu_not_running(cpu)) + while(!smp_cpu_not_running(cpu)) cpu_relax(); } } @@ -248,7 +245,7 @@ void smp_send_stop(void) /* Disable all interrupts/machine checks */ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); - /* write magic number to zero page (absolute 0) */ + /* write magic number to zero page (absolute 0) */ lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; /* stop other processors. */ @@ -264,7 +261,8 @@ void smp_send_stop(void) /* * Reboot, halt and power_off routines for SMP. */ -void machine_restart_smp(char *__unused) + +void machine_restart_smp(char * __unused) { smp_send_stop(); do_reipl(); @@ -295,17 +293,17 @@ void machine_power_off_smp(void) static void do_ext_call_interrupt(__u16 code) { - unsigned long bits; + unsigned long bits; - /* - * handle bit signal external calls - * - * For the ec_schedule signal we have to do nothing. All the work - * is done automatically when we return from the interrupt. - */ + /* + * handle bit signal external calls + * + * For the ec_schedule signal we have to do nothing. All the work + * is done automatically when we return from the interrupt. + */ bits = xchg(&S390_lowcore.ext_call_fast, 0); - if (test_bit(ec_call_function, &bits)) + if (test_bit(ec_call_function, &bits)) do_call_function(); } @@ -315,11 +313,11 @@ static void do_ext_call_interrupt(__u16 code) */ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) { - /* - * Set signaling bit in lowcore of target cpu and kick it - */ + /* + * Set signaling bit in lowcore of target cpu and kick it + */ set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); - while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy) + while(signal_processor(cpu, sigp_emergency_signal) == sigp_busy) udelay(10); } @@ -334,7 +332,7 @@ void smp_ptlb_callback(void *info) void smp_ptlb_all(void) { - on_each_cpu(smp_ptlb_callback, NULL, 0, 1); + on_each_cpu(smp_ptlb_callback, NULL, 0, 1); } EXPORT_SYMBOL(smp_ptlb_all); #endif /* ! CONFIG_64BIT */ @@ -346,7 +344,7 @@ EXPORT_SYMBOL(smp_ptlb_all); */ void smp_send_reschedule(int cpu) { - smp_ext_bitcall(cpu, ec_schedule); + smp_ext_bitcall(cpu, ec_schedule); } /* @@ -360,12 +358,11 @@ struct ec_creg_mask_parms { /* * callback for setting/clearing control bits */ -static void smp_ctl_bit_callback(void *info) -{ +static void smp_ctl_bit_callback(void *info) { struct ec_creg_mask_parms *pp = info; unsigned long cregs[16]; int i; - + __ctl_store(cregs, 0, 15); for (i = 0; i <= 15; i++) cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i]; @@ -384,7 +381,6 @@ void smp_ctl_set_bit(int cr, int bit) parms.orvals[cr] = 1 << bit; on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); } -EXPORT_SYMBOL(smp_ctl_set_bit); /* * Clear a bit in a control register of all cpus @@ -398,72 +394,13 @@ void smp_ctl_clear_bit(int cr, int bit) parms.andvals[cr] = ~(1L << bit); on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); } -EXPORT_SYMBOL(smp_ctl_clear_bit); - -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) - -/* - * zfcpdump_prefix_array holds prefix registers for the following scenario: - * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to - * save its prefix registers, since they get lost, when switching from 31 bit - * to 64 bit. - */ -unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \ - __attribute__((__section__(".data"))); - -static void __init smp_get_save_areas(void) -{ - unsigned int cpu, cpu_num, rc; - __u16 boot_cpu_addr; - - if (ipl_info.type != IPL_TYPE_FCP_DUMP) - return; - boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; - cpu_num = 1; - for (cpu = 0; cpu <= 65535; cpu++) { - if ((u16) cpu == boot_cpu_addr) - continue; - __cpu_logical_map[1] = (__u16) cpu; - if (signal_processor(1, sigp_sense) == sigp_not_operational) - continue; - if (cpu_num >= NR_CPUS) { - printk("WARNING: Registers for cpu %i are not " - "saved, since dump kernel was compiled with" - "NR_CPUS=%i!\n", cpu_num, NR_CPUS); - continue; - } - zfcpdump_save_areas[cpu_num] = - alloc_bootmem(sizeof(union save_area)); - while (1) { - rc = signal_processor(1, sigp_stop_and_store_status); - if (rc != sigp_busy) - break; - cpu_relax(); - } - memcpy(zfcpdump_save_areas[cpu_num], - (void *)(unsigned long) store_prefix() + - SAVE_AREA_BASE, SAVE_AREA_SIZE); -#ifdef __s390x__ - /* copy original prefix register */ - zfcpdump_save_areas[cpu_num]->s390x.pref_reg = - zfcpdump_prefix_array[cpu_num]; -#endif - cpu_num++; - } -} - -union save_area *zfcpdump_save_areas[NR_CPUS + 1]; -EXPORT_SYMBOL_GPL(zfcpdump_save_areas); - -#else -#define smp_get_save_areas() do { } while (0) -#endif /* * Lets check how many CPUs we have. */ -static unsigned int __init smp_count_cpus(void) +static unsigned int +__init smp_count_cpus(void) { unsigned int cpu, num_cpus; __u16 boot_cpu_addr; @@ -479,30 +416,31 @@ static unsigned int __init smp_count_cpus(void) if ((__u16) cpu == boot_cpu_addr) continue; __cpu_logical_map[1] = (__u16) cpu; - if (signal_processor(1, sigp_sense) == sigp_not_operational) + if (signal_processor(1, sigp_sense) == + sigp_not_operational) continue; num_cpus++; } - printk("Detected %d CPU's\n", (int) num_cpus); + printk("Detected %d CPU's\n",(int) num_cpus); printk("Boot cpu address %2X\n", boot_cpu_addr); return num_cpus; } /* - * Activate a secondary processor. + * Activate a secondary processor. */ int __devinit start_secondary(void *cpuvoid) { - /* Setup the cpu */ - cpu_init(); + /* Setup the cpu */ + cpu_init(); preempt_disable(); /* Enable TOD clock interrupts on the secondary cpu. */ - init_cpu_timer(); + init_cpu_timer(); #ifdef CONFIG_VIRT_TIMER /* Enable cpu timer interrupts on the secondary cpu. */ - init_cpu_vtimer(); + init_cpu_vtimer(); #endif /* Enable pfault pseudo page faults on this cpu. */ pfault_init(); @@ -511,11 +449,11 @@ int __devinit start_secondary(void *cpuvoid) cpu_set(smp_processor_id(), cpu_online_map); /* Switch on interrupts */ local_irq_enable(); - /* Print info about this processor */ - print_cpu_info(&S390_lowcore.cpu_data); - /* cpu_idle will call schedule for us */ - cpu_idle(); - return 0; + /* Print info about this processor */ + print_cpu_info(&S390_lowcore.cpu_data); + /* cpu_idle will call schedule for us */ + cpu_idle(); + return 0; } static void __init smp_create_idle(unsigned int cpu) @@ -532,13 +470,56 @@ static void __init smp_create_idle(unsigned int cpu) current_set[cpu] = p; } -static int cpu_stopped(int cpu) +/* Reserving and releasing of CPUs */ + +static DEFINE_SPINLOCK(smp_reserve_lock); +static int smp_cpu_reserved[NR_CPUS]; + +int +smp_get_cpu(cpumask_t cpu_mask) +{ + unsigned long flags; + int cpu; + + spin_lock_irqsave(&smp_reserve_lock, flags); + /* Try to find an already reserved cpu. */ + for_each_cpu_mask(cpu, cpu_mask) { + if (smp_cpu_reserved[cpu] != 0) { + smp_cpu_reserved[cpu]++; + /* Found one. */ + goto out; + } + } + /* Reserve a new cpu from cpu_mask. */ + for_each_cpu_mask(cpu, cpu_mask) { + if (cpu_online(cpu)) { + smp_cpu_reserved[cpu]++; + goto out; + } + } + cpu = -ENODEV; +out: + spin_unlock_irqrestore(&smp_reserve_lock, flags); + return cpu; +} + +void +smp_put_cpu(int cpu) +{ + unsigned long flags; + + spin_lock_irqsave(&smp_reserve_lock, flags); + smp_cpu_reserved[cpu]--; + spin_unlock_irqrestore(&smp_reserve_lock, flags); +} + +static int +cpu_stopped(int cpu) { __u32 status; /* Check for stopped state */ - if (signal_processor_ps(&status, 0, cpu, sigp_sense) == - sigp_status_stored) { + if (signal_processor_ps(&status, 0, cpu, sigp_sense) == sigp_status_stored) { if (status & 0x40) return 1; } @@ -547,13 +528,14 @@ static int cpu_stopped(int cpu) /* Upping and downing of CPUs */ -int __cpu_up(unsigned int cpu) +int +__cpu_up(unsigned int cpu) { struct task_struct *idle; - struct _lowcore *cpu_lowcore; + struct _lowcore *cpu_lowcore; struct stack_frame *sf; - sigp_ccode ccode; - int curr_cpu; + sigp_ccode ccode; + int curr_cpu; for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) { __cpu_logical_map[cpu] = (__u16) curr_cpu; @@ -566,7 +548,7 @@ int __cpu_up(unsigned int cpu) ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), cpu, sigp_set_prefix); - if (ccode) { + if (ccode){ printk("sigp_set_prefix failed for cpu %d " "with condition code %d\n", (int) cpu, (int) ccode); @@ -574,9 +556,9 @@ int __cpu_up(unsigned int cpu) } idle = current_set[cpu]; - cpu_lowcore = lowcore_ptr[cpu]; + cpu_lowcore = lowcore_ptr[cpu]; cpu_lowcore->kernel_stack = (unsigned long) - task_stack_page(idle) + THREAD_SIZE; + task_stack_page(idle) + (THREAD_SIZE); sf = (struct stack_frame *) (cpu_lowcore->kernel_stack - sizeof(struct pt_regs) - sizeof(struct stack_frame)); @@ -588,11 +570,11 @@ int __cpu_up(unsigned int cpu) " stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; - cpu_lowcore->current_task = (unsigned long) idle; - cpu_lowcore->cpu_data.cpu_nr = cpu; + cpu_lowcore->current_task = (unsigned long) idle; + cpu_lowcore->cpu_data.cpu_nr = cpu; eieio(); - while (signal_processor(cpu, sigp_restart) == sigp_busy) + while (signal_processor(cpu,sigp_restart) == sigp_busy) udelay(10); while (!cpu_online(cpu)) @@ -607,7 +589,6 @@ void __init smp_setup_cpu_possible_map(void) { unsigned int phy_cpus, pos_cpus, cpu; - smp_get_save_areas(); phy_cpus = smp_count_cpus(); pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS); @@ -639,11 +620,18 @@ static int __init setup_possible_cpus(char *s) } early_param("possible_cpus", setup_possible_cpus); -int __cpu_disable(void) +int +__cpu_disable(void) { + unsigned long flags; struct ec_creg_mask_parms cr_parms; int cpu = smp_processor_id(); + spin_lock_irqsave(&smp_reserve_lock, flags); + if (smp_cpu_reserved[cpu] != 0) { + spin_unlock_irqrestore(&smp_reserve_lock, flags); + return -EBUSY; + } cpu_clear(cpu, cpu_online_map); /* Disable pfault pseudo page faults on this cpu. */ @@ -654,23 +642,24 @@ int __cpu_disable(void) /* disable all external interrupts */ cr_parms.orvals[0] = 0; - cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | - 1 << 11 | 1 << 10 | 1 << 6 | 1 << 4); + cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 | + 1<<11 | 1<<10 | 1<< 6 | 1<< 4); /* disable all I/O interrupts */ cr_parms.orvals[6] = 0; - cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | - 1 << 27 | 1 << 26 | 1 << 25 | 1 << 24); + cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 | + 1<<27 | 1<<26 | 1<<25 | 1<<24); /* disable most machine checks */ cr_parms.orvals[14] = 0; - cr_parms.andvals[14] = ~(1 << 28 | 1 << 27 | 1 << 26 | - 1 << 25 | 1 << 24); + cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24); smp_ctl_bit_callback(&cr_parms); + spin_unlock_irqrestore(&smp_reserve_lock, flags); return 0; } -void __cpu_die(unsigned int cpu) +void +__cpu_die(unsigned int cpu) { /* Wait until target cpu is down */ while (!smp_cpu_not_running(cpu)) @@ -678,12 +667,13 @@ void __cpu_die(unsigned int cpu) printk("Processor %d spun down\n", cpu); } -void cpu_die(void) +void +cpu_die(void) { idle_task_exit(); signal_processor(smp_processor_id(), sigp_stop); BUG(); - for (;;); + for(;;); } #endif /* CONFIG_HOTPLUG_CPU */ @@ -696,36 +686,36 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { unsigned long stack; unsigned int cpu; - int i; - - /* request the 0x1201 emergency signal external interrupt */ - if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) - panic("Couldn't request external interrupt 0x1201"); - memset(lowcore_ptr, 0, sizeof(lowcore_ptr)); - /* - * Initialize prefix pages and stacks for all possible cpus - */ + int i; + + /* request the 0x1201 emergency signal external interrupt */ + if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) + panic("Couldn't request external interrupt 0x1201"); + memset(lowcore_ptr,0,sizeof(lowcore_ptr)); + /* + * Initialize prefix pages and stacks for all possible cpus + */ print_cpu_info(&S390_lowcore.cpu_data); - for_each_possible_cpu(i) { + for_each_possible_cpu(i) { lowcore_ptr[i] = (struct _lowcore *) - __get_free_pages(GFP_KERNEL | GFP_DMA, - sizeof(void*) == 8 ? 1 : 0); - stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); - if (!lowcore_ptr[i] || !stack) + __get_free_pages(GFP_KERNEL|GFP_DMA, + sizeof(void*) == 8 ? 1 : 0); + stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER); + if (lowcore_ptr[i] == NULL || stack == 0ULL) panic("smp_boot_cpus failed to allocate memory\n"); *(lowcore_ptr[i]) = S390_lowcore; - lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE; - stack = __get_free_pages(GFP_KERNEL, 0); - if (!stack) + lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); + stack = __get_free_pages(GFP_KERNEL,0); + if (stack == 0ULL) panic("smp_boot_cpus failed to allocate memory\n"); - lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE; + lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) { lowcore_ptr[i]->extended_save_area_addr = - (__u32) __get_free_pages(GFP_KERNEL, 0); - if (!lowcore_ptr[i]->extended_save_area_addr) + (__u32) __get_free_pages(GFP_KERNEL,0); + if (lowcore_ptr[i]->extended_save_area_addr == 0) panic("smp_boot_cpus failed to " "allocate memory\n"); } @@ -764,63 +754,34 @@ void smp_cpus_done(unsigned int max_cpus) */ int setup_profiling_timer(unsigned int multiplier) { - return 0; + return 0; } static DEFINE_PER_CPU(struct cpu, cpu_devices); -static ssize_t show_capability(struct sys_device *dev, char *buf) -{ - unsigned int capability; - int rc; - - rc = get_cpu_capability(&capability); - if (rc) - return rc; - return sprintf(buf, "%u\n", capability); -} -static SYSDEV_ATTR(capability, 0444, show_capability, NULL); - -static int __cpuinit smp_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned int)(long)hcpu; - struct cpu *c = &per_cpu(cpu_devices, cpu); - struct sys_device *s = &c->sysdev; - - switch (action) { - case CPU_ONLINE: - if (sysdev_create_file(s, &attr_capability)) - return NOTIFY_BAD; - break; - case CPU_DEAD: - sysdev_remove_file(s, &attr_capability); - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata smp_cpu_nb = { - .notifier_call = smp_cpu_notify, -}; - static int __init topology_init(void) { int cpu; - - register_cpu_notifier(&smp_cpu_nb); + int ret; for_each_possible_cpu(cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); - struct sys_device *s = &c->sysdev; c->hotpluggable = 1; - register_cpu(c, cpu); - if (!cpu_online(cpu)) - continue; - s = &c->sysdev; - sysdev_create_file(s, &attr_capability); + ret = register_cpu(c, cpu); + if (ret) + printk(KERN_WARNING "topology_init: register_cpu %d " + "failed (%d)\n", cpu, ret); } return 0; } + subsys_initcall(topology_init); + +EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(cpu_possible_map); +EXPORT_SYMBOL(lowcore_ptr); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_get_cpu); +EXPORT_SYMBOL(smp_put_cpu); diff --git a/trunk/arch/s390/kernel/sys_s390.c b/trunk/arch/s390/kernel/sys_s390.c index 3a77c22cda78..584ed95f3380 100644 --- a/trunk/arch/s390/kernel/sys_s390.c +++ b/trunk/arch/s390/kernel/sys_s390.c @@ -266,3 +266,23 @@ s390_fadvise64_64(struct fadvise64_64_args __user *args) return -EFAULT; return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice); } + +/* + * Do a system call from kernel instead of calling sys_execve so we + * end up with proper pt_regs. + */ +int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +{ + register const char *__arg1 asm("2") = filename; + register char *const*__arg2 asm("3") = argv; + register char *const*__arg3 asm("4") = envp; + register long __svcres asm("2"); + asm volatile( + "svc %b1" + : "=d" (__svcres) + : "i" (__NR_execve), + "0" (__arg1), + "d" (__arg2), + "d" (__arg3) : "memory"); + return __svcres; +} diff --git a/trunk/arch/s390/kernel/syscalls.S b/trunk/arch/s390/kernel/syscalls.S index cd8d321cd0c2..c774f1069e10 100644 --- a/trunk/arch/s390/kernel/syscalls.S +++ b/trunk/arch/s390/kernel/syscalls.S @@ -10,7 +10,7 @@ NI_SYSCALL /* 0 */ SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper) -SYSCALL(sys_fork,sys_fork,sys_fork) +SYSCALL(sys_fork_glue,sys_fork_glue,sys_fork_glue) SYSCALL(sys_read,sys_read,sys32_read_wrapper) SYSCALL(sys_write,sys_write,sys32_write_wrapper) SYSCALL(sys_open,sys_open,sys32_open_wrapper) /* 5 */ @@ -19,7 +19,7 @@ SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall) SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper) SYSCALL(sys_link,sys_link,sys32_link_wrapper) SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */ -SYSCALL(sys_execve,sys_execve,sys32_execve) +SYSCALL(sys_execve_glue,sys_execve_glue,sys32_execve_glue) SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper) SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */ SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper) @@ -127,8 +127,8 @@ SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */ SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) -SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) -SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */ +SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue) +SYSCALL(sys_clone_glue,sys_clone_glue,sys32_clone_glue) /* 120 */ SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper) NI_SYSCALL /* modify_ldt for i386 */ @@ -181,7 +181,7 @@ SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper) SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */ SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */ SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper) -SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn) +SYSCALL(sys_rt_sigreturn_glue,sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue) SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper) SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */ SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper) @@ -194,11 +194,11 @@ SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper) SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper) SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */ -SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack) +SYSCALL(sys_sigaltstack_glue,sys_sigaltstack_glue,sys32_sigaltstack_glue) SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper) NI_SYSCALL /* streams1 */ NI_SYSCALL /* streams2 */ -SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */ +SYSCALL(sys_vfork_glue,sys_vfork_glue,sys_vfork_glue) /* 190 */ SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper) SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper) SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper) diff --git a/trunk/arch/s390/kernel/time.c b/trunk/arch/s390/kernel/time.c index 711dae8da7ad..e1ad464b6f20 100644 --- a/trunk/arch/s390/kernel/time.c +++ b/trunk/arch/s390/kernel/time.c @@ -280,6 +280,7 @@ static void clock_comparator_interrupt(__u16 code) } static void etr_reset(void); +static void etr_init(void); static void etr_ext_handler(__u16); /* @@ -354,6 +355,7 @@ void __init time_init(void) #ifdef CONFIG_VIRT_TIMER vtime_init(); #endif + etr_init(); } /* @@ -424,11 +426,11 @@ static struct etr_aib etr_port1; static int etr_port1_uptodate; static unsigned long etr_events; static struct timer_list etr_timer; +static struct tasklet_struct etr_tasklet; static DEFINE_PER_CPU(atomic_t, etr_sync_word); static void etr_timeout(unsigned long dummy); -static void etr_work_fn(struct work_struct *work); -static DECLARE_WORK(etr_work, etr_work_fn); +static void etr_tasklet_fn(unsigned long dummy); /* * The etr get_clock function. It will write the current clock value @@ -505,31 +507,29 @@ static void etr_reset(void) } } -static int __init etr_init(void) +static void etr_init(void) { struct etr_aib aib; if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) - return 0; + return; /* Check if this machine has the steai instruction. */ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) set_bit(ETR_FLAG_STEAI, &etr_flags); setup_timer(&etr_timer, etr_timeout, 0UL); + tasklet_init(&etr_tasklet, etr_tasklet_fn, 0); if (!etr_port0_online && !etr_port1_online) set_bit(ETR_FLAG_EACCES, &etr_flags); if (etr_port0_online) { set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } if (etr_port1_online) { set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } - return 0; } -arch_initcall(etr_init); - /* * Two sorts of ETR machine checks. The architecture reads: * "When a machine-check niterruption occurs and if a switch-to-local or @@ -549,7 +549,7 @@ void etr_switch_to_local(void) return; etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } /* @@ -564,7 +564,7 @@ void etr_sync_check(void) return; etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } /* @@ -591,13 +591,13 @@ static void etr_ext_handler(__u16 code) * Both ports are not up-to-date now. */ set_bit(ETR_EVENT_PORT_ALERT, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } static void etr_timeout(unsigned long dummy) { set_bit(ETR_EVENT_UPDATE, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } /* @@ -927,7 +927,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, if (!eacr.e0 && !eacr.e1) return eacr; - /* Update port0 or port1 with aib stored in etr_work_fn. */ + /* Update port0 or port1 with aib stored in etr_tasklet_fn. */ if (aib->esw.q == 0) { /* Information for port 0 stored. */ if (eacr.p0 && !etr_port0_uptodate) { @@ -1007,7 +1007,7 @@ static void etr_update_eacr(struct etr_eacr eacr) * particular this is the only function that calls etr_update_eacr(), * it "controls" the etr control register. */ -static void etr_work_fn(struct work_struct *work) +static void etr_tasklet_fn(unsigned long dummy) { unsigned long long now; struct etr_eacr eacr; @@ -1220,13 +1220,13 @@ static ssize_t etr_online_store(struct sys_device *dev, return count; /* Nothing to do. */ etr_port0_online = value; set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } else { if (etr_port1_online == value) return count; /* Nothing to do. */ etr_port1_online = value; set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); - schedule_work(&etr_work); + tasklet_hi_schedule(&etr_tasklet); } return count; } diff --git a/trunk/arch/s390/kernel/traps.c b/trunk/arch/s390/kernel/traps.c index 49dec830373a..f0e5a320e2ec 100644 --- a/trunk/arch/s390/kernel/traps.c +++ b/trunk/arch/s390/kernel/traps.c @@ -30,7 +30,7 @@ #include #include #include -#include + #include #include #include @@ -188,31 +188,18 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); -static inline int mask_bits(struct pt_regs *regs, unsigned long bits) -{ - return (regs->psw.mask & bits) / ((~bits + 1) & bits); -} - void show_registers(struct pt_regs *regs) { + mm_segment_t old_fs; char *mode; + int i; mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; printk("%s PSW : %p %p", mode, (void *) regs->psw.mask, (void *) regs->psw.addr); print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN); - printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " - "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER), - mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO), - mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY), - mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT), - mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC), - mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM)); -#ifdef CONFIG_64BIT - printk(" EA:%x", mask_bits(regs, PSW_BASE_BITS)); -#endif - printk("\n%s GPRS: " FOURLONG, mode, + printk("%s GPRS: " FOURLONG, mode, regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); printk(" " FOURLONG, regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); @@ -221,7 +208,41 @@ void show_registers(struct pt_regs *regs) printk(" " FOURLONG, regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); - show_code(regs); +#if 0 + /* FIXME: this isn't needed any more but it changes the ksymoops + * input. To remove or not to remove ... */ + save_access_regs(regs->acrs); + printk("%s ACRS: %08x %08x %08x %08x\n", mode, + regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]); +#endif + + /* + * Print the first 20 byte of the instruction stream at the + * time of the fault. + */ + old_fs = get_fs(); + if (regs->psw.mask & PSW_MASK_PSTATE) + set_fs(USER_DS); + else + set_fs(KERNEL_DS); + printk("%s Code: ", mode); + for (i = 0; i < 20; i++) { + unsigned char c; + if (__get_user(c, (char __user *)(regs->psw.addr + i))) { + printk(" Bad PSW."); + break; + } + printk("%02x ", c); + } + set_fs(old_fs); + + printk("\n"); } /* This is called from fs/proc/array.c */ @@ -297,11 +318,6 @@ report_user_fault(long interruption_code, struct pt_regs *regs) #endif } -int is_valid_bugaddr(unsigned long addr) -{ - return 1; -} - static void __kprobes inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) @@ -328,14 +344,8 @@ static void __kprobes inline do_trap(long interruption_code, int signr, fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); if (fixup) regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; - else { - enum bug_trap_type btt; - - btt = report_bug(regs->psw.addr & PSW_ADDR_INSN); - if (btt == BUG_TRAP_TYPE_WARN) - return; - die(str, regs, interruption_code); - } + else + die(str, regs, interruption_code); } } diff --git a/trunk/arch/s390/kernel/vmlinux.lds.S b/trunk/arch/s390/kernel/vmlinux.lds.S index e9d3432aba60..c30716ae130c 100644 --- a/trunk/arch/s390/kernel/vmlinux.lds.S +++ b/trunk/arch/s390/kernel/vmlinux.lds.S @@ -45,8 +45,6 @@ SECTIONS __ex_table : { *(__ex_table) } __stop___ex_table = .; - BUG_TABLE - .data : { /* Data */ *(.data) CONSTRUCTORS @@ -79,12 +77,6 @@ SECTIONS *(.init.text) _einittext = .; } - /* - * .exit.text is discarded at runtime, not link time, - * to deal with references from __bug_table - */ - .exit.text : { *(.exit.text) } - .init.data : { *(.init.data) } . = ALIGN(256); __setup_start = .; @@ -107,7 +99,7 @@ SECTIONS . = ALIGN(2); __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(256); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; @@ -124,7 +116,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { - *(.exit.data) *(.exitcall.exit) + *(.exit.text) *(.exit.data) *(.exitcall.exit) } /* Stabs debugging sections. */ diff --git a/trunk/arch/s390/kernel/vtime.c b/trunk/arch/s390/kernel/vtime.c index 1e1a6ee2cac1..9d5b02801b46 100644 --- a/trunk/arch/s390/kernel/vtime.c +++ b/trunk/arch/s390/kernel/vtime.c @@ -128,7 +128,7 @@ static inline void set_vtimer(__u64 expires) S390_lowcore.last_update_timer = expires; /* store expire time for this CPU timer */ - __get_cpu_var(virt_cpu_timer).to_expire = expires; + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; } #else static inline void set_vtimer(__u64 expires) @@ -137,7 +137,7 @@ static inline void set_vtimer(__u64 expires) asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); /* store expire time for this CPU timer */ - __get_cpu_var(virt_cpu_timer).to_expire = expires; + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; } #endif @@ -145,7 +145,7 @@ static void start_cpu_timer(void) { struct vtimer_queue *vt_list; - vt_list = &__get_cpu_var(virt_cpu_timer); + vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); /* CPU timer interrupt is pending, don't reprogramm it */ if (vt_list->idle & 1LL<<63) @@ -159,7 +159,7 @@ static void stop_cpu_timer(void) { struct vtimer_queue *vt_list; - vt_list = &__get_cpu_var(virt_cpu_timer); + vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); /* nothing to do */ if (list_empty(&vt_list->list)) { @@ -219,7 +219,7 @@ static void do_callbacks(struct list_head *cb_list) if (list_empty(cb_list)) return; - vt_list = &__get_cpu_var(virt_cpu_timer); + vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); list_for_each_entry_safe(event, tmp, cb_list, entry) { fn = event->function; @@ -244,6 +244,7 @@ static void do_callbacks(struct list_head *cb_list) */ static void do_cpu_timer_interrupt(__u16 error_code) { + int cpu; __u64 next, delta; struct vtimer_queue *vt_list; struct vtimer_list *event, *tmp; @@ -252,7 +253,8 @@ static void do_cpu_timer_interrupt(__u16 error_code) struct list_head cb_list; INIT_LIST_HEAD(&cb_list); - vt_list = &__get_cpu_var(virt_cpu_timer); + cpu = smp_processor_id(); + vt_list = &per_cpu(virt_cpu_timer, cpu); /* walk timer list, fire all expired events */ spin_lock(&vt_list->lock); @@ -532,7 +534,7 @@ void init_cpu_vtimer(void) /* enable cpu timer interrupts */ __ctl_set_bit(0,10); - vt_list = &__get_cpu_var(virt_cpu_timer); + vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); INIT_LIST_HEAD(&vt_list->list); spin_lock_init(&vt_list->lock); vt_list->to_expire = 0; diff --git a/trunk/arch/s390/lib/Makefile b/trunk/arch/s390/lib/Makefile index 59aea65ce99f..7a44fed21b35 100644 --- a/trunk/arch/s390/lib/Makefile +++ b/trunk/arch/s390/lib/Makefile @@ -5,6 +5,6 @@ EXTRA_AFLAGS := -traditional lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o -obj-$(CONFIG_32BIT) += div64.o +lib-$(CONFIG_32BIT) += div64.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/trunk/arch/s390/lib/div64.c b/trunk/arch/s390/lib/div64.c index a5f8300bf3ee..0481f3424a13 100644 --- a/trunk/arch/s390/lib/div64.c +++ b/trunk/arch/s390/lib/div64.c @@ -147,3 +147,5 @@ uint32_t __div64_32(uint64_t *n, uint32_t base) } #endif /* MARCH_G5 */ + +EXPORT_SYMBOL(__div64_32); diff --git a/trunk/arch/s390/mm/fault.c b/trunk/arch/s390/mm/fault.c index 91f705adc3f9..7462aebd3eb6 100644 --- a/trunk/arch/s390/mm/fault.c +++ b/trunk/arch/s390/mm/fault.c @@ -26,9 +26,9 @@ #include #include #include -#include #include +#include #include #include #include @@ -52,24 +52,34 @@ extern int sysctl_userprocess_debug; extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES -static inline int notify_page_fault(struct pt_regs *regs, long err) +static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +int register_page_fault_notifier(struct notifier_block *nb) { - int ret = 0; - - /* kprobe_running() needs smp_processor_id() */ - if (!user_mode(regs)) { - preempt_disable(); - if (kprobe_running() && kprobe_fault_handler(regs, 14)) - ret = 1; - preempt_enable(); - } + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +} - return ret; +int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +} + +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); } #else -static inline int notify_page_fault(struct pt_regs *regs, long err) +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) { - return 0; + return NOTIFY_DONE; } #endif @@ -160,127 +170,74 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, force_sig_info(SIGSEGV, &si, current); } -static void do_no_context(struct pt_regs *regs, unsigned long error_code, - unsigned long address) -{ - const struct exception_table_entry *fixup; - - /* Are we prepared to handle this kernel fault? */ - fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK); - if (fixup) { - regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; - return; - } - - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - if (check_space(current) == 0) - printk(KERN_ALERT "Unable to handle kernel pointer dereference" - " at virtual kernel address %p\n", (void *)address); - else - printk(KERN_ALERT "Unable to handle kernel paging request" - " at virtual user address %p\n", (void *)address); - - die("Oops", regs, error_code); - do_exit(SIGKILL); -} - -static void do_low_address(struct pt_regs *regs, unsigned long error_code) -{ - /* Low-address protection hit in kernel mode means - NULL pointer write access in kernel mode. */ - if (regs->psw.mask & PSW_MASK_PSTATE) { - /* Low-address protection hit in user mode 'cannot happen'. */ - die ("Low-address protection", regs, error_code); - do_exit(SIGKILL); - } - - do_no_context(regs, error_code, 0); -} - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code, - unsigned long address) -{ - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; - - up_read(&mm->mmap_sem); - if (is_init(tsk)) { - yield(); - down_read(&mm->mmap_sem); - return 1; - } - printk("VM: killing process %s\n", tsk->comm); - if (regs->psw.mask & PSW_MASK_PSTATE) - do_exit(SIGKILL); - do_no_context(regs, error_code, address); - return 0; -} - -static void do_sigbus(struct pt_regs *regs, unsigned long error_code, - unsigned long address) -{ - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; - - up_read(&mm->mmap_sem); - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - tsk->thread.prot_addr = address; - tsk->thread.trap_no = error_code; - force_sig(SIGBUS, tsk); - - /* Kernel mode? Handle exceptions or die */ - if (!(regs->psw.mask & PSW_MASK_PSTATE)) - do_no_context(regs, error_code, address); -} - #ifdef CONFIG_S390_EXEC_PROTECT extern long sys_sigreturn(struct pt_regs *regs); extern long sys_rt_sigreturn(struct pt_regs *regs); extern long sys32_sigreturn(struct pt_regs *regs); extern long sys32_rt_sigreturn(struct pt_regs *regs); -static int signal_return(struct mm_struct *mm, struct pt_regs *regs, - unsigned long address, unsigned long error_code) +static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs, + int rt) { - u16 instruction; - int rc, compat; - - pagefault_disable(); - rc = __get_user(instruction, (u16 __user *) regs->psw.addr); - pagefault_enable(); - if (rc) - return -EFAULT; - up_read(&mm->mmap_sem); clear_tsk_thread_flag(current, TIF_SINGLE_STEP); #ifdef CONFIG_COMPAT - compat = test_tsk_thread_flag(current, TIF_31BIT); - if (compat && instruction == 0x0a77) - sys32_sigreturn(regs); - else if (compat && instruction == 0x0aad) - sys32_rt_sigreturn(regs); + if (test_tsk_thread_flag(current, TIF_31BIT)) { + if (rt) + sys32_rt_sigreturn(regs); + else + sys32_sigreturn(regs); + return; + } +#endif /* CONFIG_COMPAT */ + if (rt) + sys_rt_sigreturn(regs); else -#endif - if (instruction == 0x0a77) sys_sigreturn(regs); - else if (instruction == 0x0aad) - sys_rt_sigreturn(regs); + return; +} + +static int signal_return(struct mm_struct *mm, struct pt_regs *regs, + unsigned long address, unsigned long error_code) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + u16 *instruction; + unsigned long pfn, uaddr = regs->psw.addr; + + spin_lock(&mm->page_table_lock); + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto out_fault; + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto out_fault; + pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr); + if (!pte || !pte_present(*pte)) + goto out_fault; + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out_fault; + spin_unlock(&mm->page_table_lock); + + instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1))); + if (*instruction == 0x0a77) + do_sigreturn(mm, regs, 0); + else if (*instruction == 0x0aad) + do_sigreturn(mm, regs, 1); else { + printk("- XXX - do_exception: task = %s, primary, NO EXEC " + "-> SIGSEGV\n", current->comm); + up_read(&mm->mmap_sem); current->thread.prot_addr = address; current->thread.trap_no = error_code; do_sigsegv(regs, error_code, SEGV_MAPERR, address); } return 0; +out_fault: + spin_unlock(&mm->page_table_lock); + return -EFAULT; } #endif /* CONFIG_S390_EXEC_PROTECT */ @@ -296,23 +253,49 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs, * 3b Region third trans. -> Not present (nullification) */ static inline void -do_exception(struct pt_regs *regs, unsigned long error_code, int write) +do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) { - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long address; - int space; + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + unsigned long address; + const struct exception_table_entry *fixup; int si_code; + int space; - if (notify_page_fault(regs, error_code)) + tsk = current; + mm = tsk->mm; + + if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, + SIGSEGV) == NOTIFY_STOP) return; - tsk = current; - mm = tsk->mm; + /* + * Check for low-address protection. This needs to be treated + * as a special case because the translation exception code + * field is not guaranteed to contain valid data in this case. + */ + if (is_protection && !(S390_lowcore.trans_exc_code & 4)) { + + /* Low-address protection hit in kernel mode means + NULL pointer write access in kernel mode. */ + if (!(regs->psw.mask & PSW_MASK_PSTATE)) { + address = 0; + space = 0; + goto no_context; + } + + /* Low-address protection hit in user mode 'cannot happen'. */ + die ("Low-address protection", regs, error_code); + do_exit(SIGKILL); + } - /* get the failing address and the affected space */ - address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; + /* + * get the failing address + * more specific the segment and page table portion of + * the address + */ + address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; space = check_space(tsk); /* @@ -330,7 +313,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) */ local_irq_enable(); - down_read(&mm->mmap_sem); + down_read(&mm->mmap_sem); si_code = SEGV_MAPERR; vma = find_vma(mm, address); @@ -347,19 +330,19 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) return; #endif - if (vma->vm_start <= address) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (expand_stack(vma, address)) - goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: si_code = SEGV_ACCERR; - if (!write) { + if (!is_protection) { /* page not present, check vm flags */ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) goto bad_area; @@ -374,7 +357,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) * make sure we exit gracefully rather than endlessly redo * the fault. */ - switch (handle_mm_fault(mm, vma, address, write)) { + switch (handle_mm_fault(mm, vma, address, is_protection)) { case VM_FAULT_MINOR: tsk->min_flt++; break; @@ -382,12 +365,9 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) tsk->maj_flt++; break; case VM_FAULT_SIGBUS: - do_sigbus(regs, error_code, address); - return; + goto do_sigbus; case VM_FAULT_OOM: - if (do_out_of_memory(regs, error_code, address)) - goto survive; - return; + goto out_of_memory; default: BUG(); } @@ -405,34 +385,75 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) * Fix it, but check if it's kernel or user first.. */ bad_area: - up_read(&mm->mmap_sem); + up_read(&mm->mmap_sem); - /* User mode accesses just cause a SIGSEGV */ - if (regs->psw.mask & PSW_MASK_PSTATE) { - tsk->thread.prot_addr = address; - tsk->thread.trap_no = error_code; + /* User mode accesses just cause a SIGSEGV */ + if (regs->psw.mask & PSW_MASK_PSTATE) { + tsk->thread.prot_addr = address; + tsk->thread.trap_no = error_code; do_sigsegv(regs, error_code, si_code, address); - return; + return; } no_context: - do_no_context(regs, error_code, address); + /* Are we prepared to handle this kernel fault? */ + fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK); + if (fixup) { + regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; + return; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if (space == 0) + printk(KERN_ALERT "Unable to handle kernel pointer dereference" + " at virtual kernel address %p\n", (void *)address); + else + printk(KERN_ALERT "Unable to handle kernel paging request" + " at virtual user address %p\n", (void *)address); + + die("Oops", regs, error_code); + do_exit(SIGKILL); + + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. +*/ +out_of_memory: + up_read(&mm->mmap_sem); + if (is_init(tsk)) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", tsk->comm); + if (regs->psw.mask & PSW_MASK_PSTATE) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.prot_addr = address; + tsk->thread.trap_no = error_code; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(regs->psw.mask & PSW_MASK_PSTATE)) + goto no_context; } void __kprobes do_protection_exception(struct pt_regs *regs, unsigned long error_code) { - /* Protection exception is supressing, decrement psw address. */ regs->psw.addr -= (error_code >> 16); - /* - * Check for low-address protection. This needs to be treated - * as a special case because the translation exception code - * field is not guaranteed to contain valid data in this case. - */ - if (unlikely(!(S390_lowcore.trans_exc_code & 4))) { - do_low_address(regs, error_code); - return; - } do_exception(regs, 4, 1); } diff --git a/trunk/arch/sh/boards/hp6xx/pm.c b/trunk/arch/sh/boards/hp6xx/pm.c index 8143d1b948e7..d1947732fb3e 100644 --- a/trunk/arch/sh/boards/hp6xx/pm.c +++ b/trunk/arch/sh/boards/hp6xx/pm.c @@ -27,6 +27,9 @@ static int hp6x0_pm_enter(suspend_state_t state) u16 hd64461_stbcr; #endif + if (state != PM_SUSPEND_MEM) + return -EINVAL; + #ifdef CONFIG_HD64461_ENABLER outb(0, HD64461_PCC1CSCIER); @@ -67,9 +70,12 @@ static int hp6x0_pm_enter(suspend_state_t state) return 0; } +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ static struct pm_ops hp6x0_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, .enter = hp6x0_pm_enter, - .valid = pm_valid_only_mem, }; static int __init hp6x0_pm_init(void) diff --git a/trunk/arch/sh/kernel/vmlinux.lds.S b/trunk/arch/sh/kernel/vmlinux.lds.S index 2f606d0ce1f6..78a6c09875b2 100644 --- a/trunk/arch/sh/kernel/vmlinux.lds.S +++ b/trunk/arch/sh/kernel/vmlinux.lds.S @@ -54,7 +54,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); .data.page_aligned : { *(.data.page_aligned) } - . = ALIGN(PAGE_SIZE); + . = ALIGN(L1_CACHE_BYTES); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/sh/lib/Makefile b/trunk/arch/sh/lib/Makefile index 0b9cca5c7cb4..b5681e3f9684 100644 --- a/trunk/arch/sh/lib/Makefile +++ b/trunk/arch/sh/lib/Makefile @@ -3,7 +3,7 @@ # lib-y = delay.o memset.o memmove.o memchr.o \ - checksum.o strlen.o div64.o udivdi3.o \ + checksum.o strcasecmp.o strlen.o div64.o udivdi3.o \ div64-generic.o memcpy-y := memcpy.o diff --git a/trunk/arch/sh/lib/strcasecmp.c b/trunk/arch/sh/lib/strcasecmp.c new file mode 100644 index 000000000000..4e57a216feaf --- /dev/null +++ b/trunk/arch/sh/lib/strcasecmp.c @@ -0,0 +1,26 @@ +/* + * linux/arch/alpha/lib/strcasecmp.c + */ + +#include + + +/* We handle nothing here except the C locale. Since this is used in + only one place, on strings known to contain only 7 bit ASCII, this + is ok. */ + +int strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } while (ca == cb && ca != '\0'); + + return ca - cb; +} diff --git a/trunk/arch/sh64/kernel/vmlinux.lds.S b/trunk/arch/sh64/kernel/vmlinux.lds.S index 4f9616f39830..a59c5e998131 100644 --- a/trunk/arch/sh64/kernel/vmlinux.lds.S +++ b/trunk/arch/sh64/kernel/vmlinux.lds.S @@ -85,7 +85,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) } - . = ALIGN(PAGE_SIZE); + . = ALIGN(L1_CACHE_BYTES); __per_cpu_start = .; .data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) } __per_cpu_end = . ; diff --git a/trunk/arch/sh64/mach-cayman/iomap.c b/trunk/arch/sh64/mach-cayman/iomap.c index a5c645f02d57..2d06e9a55137 100644 --- a/trunk/arch/sh64/mach-cayman/iomap.c +++ b/trunk/arch/sh64/mach-cayman/iomap.c @@ -9,6 +9,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ +#include #include #include diff --git a/trunk/arch/sparc/kernel/ebus.c b/trunk/arch/sparc/kernel/ebus.c index 7bb86b9cdaa3..ba58c3a061fd 100644 --- a/trunk/arch/sparc/kernel/ebus.c +++ b/trunk/arch/sparc/kernel/ebus.c @@ -25,7 +25,7 @@ struct linux_ebus *ebus_chain = NULL; /* We are together with pcic.c under CONFIG_PCI. */ -extern unsigned int pcic_pin_to_irq(unsigned int, const char *name); +extern unsigned int pcic_pin_to_irq(unsigned int, char *name); /* * IRQ Blacklist @@ -69,7 +69,7 @@ static inline unsigned long ebus_alloc(size_t size) /* */ -int __init ebus_blacklist_irq(const char *name) +int __init ebus_blacklist_irq(char *name) { struct ebus_device_irq *dp; @@ -86,8 +86,8 @@ int __init ebus_blacklist_irq(const char *name) void __init fill_ebus_child(struct device_node *dp, struct linux_ebus_child *dev) { - const int *regs; - const int *irqs; + int *regs; + int *irqs; int i, len; dev->prom_node = dp; @@ -146,9 +146,9 @@ void __init fill_ebus_child(struct device_node *dp, void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { - const struct linux_prom_registers *regs; + struct linux_prom_registers *regs; struct linux_ebus_child *child; - const int *irqs; + int *irqs; int i, n, len; unsigned long baseaddr; @@ -269,7 +269,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d void __init ebus_init(void) { - const struct linux_prom_pci_registers *regs; + struct linux_prom_pci_registers *regs; struct linux_pbm_info *pbm; struct linux_ebus_device *dev; struct linux_ebus *ebus; diff --git a/trunk/arch/sparc/kernel/of_device.c b/trunk/arch/sparc/kernel/of_device.c index fd7f8cb668a3..48c24f7518c2 100644 --- a/trunk/arch/sparc/kernel/of_device.c +++ b/trunk/arch/sparc/kernel/of_device.c @@ -210,7 +210,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned int (*get_flags)(u32 *addr); }; /* @@ -270,7 +270,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned int of_bus_default_get_flags(u32 *addr) { return IORESOURCE_MEM; } @@ -334,7 +334,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned int of_bus_pci_get_flags(u32 *addr) { unsigned int flags = 0; u32 w = addr[0]; @@ -375,7 +375,7 @@ static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) return of_bus_default_map(addr, range, na, ns, pna); } -static unsigned int of_bus_sbus_get_flags(const u32 *addr) +static unsigned int of_bus_sbus_get_flags(u32 *addr) { return IORESOURCE_MEM; } @@ -432,7 +432,7 @@ static int __init build_one_resource(struct device_node *parent, u32 *addr, int na, int ns, int pna) { - const u32 *ranges; + u32 *ranges; unsigned int rlen; int rone; @@ -470,7 +470,7 @@ static void __init build_device_resources(struct of_device *op, struct of_bus *bus; int na, ns; int index, num_reg; - const void *preg; + void *preg; if (!parent) return; @@ -492,7 +492,7 @@ static void __init build_device_resources(struct of_device *op, for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; - const u32 *reg = (preg + (index * ((na + ns) * 4))); + u32 *reg = (preg + (index * ((na + ns) * 4))); struct device_node *dp = op->node; struct device_node *pp = p_op->node; struct of_bus *pbus, *dbus; @@ -559,7 +559,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - const struct linux_prom_irqs *intr; + struct linux_prom_irqs *intr; int len, i; if (!op) @@ -579,8 +579,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, for (i = 0; i < op->num_irqs; i++) op->irqs[i] = intr[i].pri; } else { - const unsigned int *irq = - of_get_property(dp, "interrupts", &len); + unsigned int *irq = of_get_property(dp, "interrupts", &len); if (irq) { op->num_irqs = len / sizeof(unsigned int); @@ -595,7 +594,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, }; struct device_node *io_unit, *sbi = dp->parent; - const struct linux_prom_registers *regs; + struct linux_prom_registers *regs; int board, slot; while (sbi) { diff --git a/trunk/arch/sparc/kernel/pcic.c b/trunk/arch/sparc/kernel/pcic.c index 5ca7e8f42bd9..1c927c538b8b 100644 --- a/trunk/arch/sparc/kernel/pcic.c +++ b/trunk/arch/sparc/kernel/pcic.c @@ -37,6 +37,8 @@ #include +unsigned int pcic_pin_to_irq(unsigned int pin, char *name); + /* * I studied different documents and many live PROMs both from 2.30 * family and 3.xx versions. I came to the amazing conclusion: there is @@ -679,7 +681,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) * pcic_pin_to_irq() is exported to ebus.c. */ unsigned int -pcic_pin_to_irq(unsigned int pin, const char *name) +pcic_pin_to_irq(unsigned int pin, char *name) { struct linux_pcic *pcic = &pcic0; unsigned int irq; diff --git a/trunk/arch/sparc/kernel/prom.c b/trunk/arch/sparc/kernel/prom.c index eed140b3c739..2cc302b6bec0 100644 --- a/trunk/arch/sparc/kernel/prom.c +++ b/trunk/arch/sparc/kernel/prom.c @@ -32,13 +32,12 @@ static struct device_node *allnodes; */ static DEFINE_RWLOCK(devtree_lock); -int of_device_is_compatible(const struct device_node *device, - const char *compat) +int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; int cplen, l; - cp = of_get_property(device, "compatible", &cplen); + cp = (char *) of_get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -151,14 +150,13 @@ struct device_node *of_find_compatible_node(struct device_node *from, } EXPORT_SYMBOL(of_find_compatible_node); -struct property *of_find_property(const struct device_node *np, - const char *name, +struct property *of_find_property(struct device_node *np, const char *name, int *lenp) { struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { - if (strcasecmp(pp->name, name) == 0) { + if (strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; break; @@ -172,8 +170,7 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -const void *of_get_property(const struct device_node *np, const char *name, - int *lenp) +void *of_get_property(struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; @@ -195,7 +192,7 @@ EXPORT_SYMBOL(of_getintprop_default); int of_n_addr_cells(struct device_node *np) { - const int* ip; + int* ip; do { if (np->parent) np = np->parent; @@ -210,7 +207,7 @@ EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np) { - const int* ip; + int* ip; do { if (np->parent) np = np->parent; @@ -242,7 +239,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len while (*prevp) { struct property *prop = *prevp; - if (!strcasecmp(prop->name, name)) { + if (!strcmp(prop->name, name)) { void *old_val = prop->value; int ret; diff --git a/trunk/arch/sparc/kernel/time.c b/trunk/arch/sparc/kernel/time.c index f1401b57ccc7..9bb1240aaf8a 100644 --- a/trunk/arch/sparc/kernel/time.c +++ b/trunk/arch/sparc/kernel/time.c @@ -301,7 +301,7 @@ static __inline__ void sun4_clock_probe(void) static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - const char *model = of_get_property(dp, "model", NULL); + char *model = of_get_property(dp, "model", NULL); if (!model) return -ENODEV; diff --git a/trunk/arch/sparc/kernel/vmlinux.lds.S b/trunk/arch/sparc/kernel/vmlinux.lds.S index f0bb6e60e620..e5c24e0521de 100644 --- a/trunk/arch/sparc/kernel/vmlinux.lds.S +++ b/trunk/arch/sparc/kernel/vmlinux.lds.S @@ -65,7 +65,7 @@ SECTIONS __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/sparc64/Kconfig b/trunk/arch/sparc64/Kconfig index be9e10b94ef8..1a6348b565fb 100644 --- a/trunk/arch/sparc64/Kconfig +++ b/trunk/arch/sparc64/Kconfig @@ -19,14 +19,6 @@ config SPARC64 SPARC64 ports; its web page is available at . -config GENERIC_TIME - bool - default y - -config GENERIC_CLOCKEVENTS - bool - default y - config 64BIT def_bool y @@ -42,6 +34,10 @@ config LOCKDEP_SUPPORT bool default y +config TIME_INTERPOLATION + bool + default y + config ARCH_MAY_HAVE_PC_FDC bool default y @@ -117,8 +113,6 @@ config GENERIC_HARDIRQS menu "General machine setup" -source "kernel/time/Kconfig" - config SMP bool "Symmetric multi-processing support" ---help--- @@ -220,7 +214,6 @@ config ARCH_SPARSEMEM_ENABLE config ARCH_SPARSEMEM_DEFAULT def_bool y - select SPARSEMEM_STATIC config LARGE_ALLOCS def_bool y @@ -306,7 +299,6 @@ config SUN_IO config PCI bool "PCI support" - select ARCH_SUPPORTS_MSI help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/trunk/arch/sparc64/kernel/central.c b/trunk/arch/sparc64/kernel/central.c index c65b2f9c98d8..e724c54af029 100644 --- a/trunk/arch/sparc64/kernel/central.c +++ b/trunk/arch/sparc64/kernel/central.c @@ -32,7 +32,7 @@ static void central_probe_failure(int line) static void central_ranges_init(struct linux_central *central) { struct device_node *dp = central->prom_node; - const void *pval; + void *pval; int len; central->num_central_ranges = 0; @@ -47,7 +47,7 @@ static void central_ranges_init(struct linux_central *central) static void fhc_ranges_init(struct linux_fhc *fhc) { struct device_node *dp = fhc->prom_node; - const void *pval; + void *pval; int len; fhc->num_fhc_ranges = 0; @@ -119,7 +119,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) static void probe_other_fhcs(void) { struct device_node *dp; - const struct linux_prom64_registers *fpregs; + struct linux_prom64_registers *fpregs; for_each_node_by_name(dp, "fhc") { struct linux_fhc *fhc; @@ -190,8 +190,7 @@ static void probe_clock_board(struct linux_central *central, struct device_node *fp) { struct device_node *dp; - struct linux_prom_registers cregs[3]; - const struct linux_prom_registers *pr; + struct linux_prom_registers cregs[3], *pr; int nslots, tmp, nregs; dp = fp->child; @@ -300,8 +299,7 @@ static void init_all_fhc_hw(void) void central_probe(void) { - struct linux_prom_registers fpregs[6]; - const struct linux_prom_registers *pr; + struct linux_prom_registers fpregs[6], *pr; struct linux_fhc *fhc; struct device_node *dp, *fp; int err; diff --git a/trunk/arch/sparc64/kernel/chmc.c b/trunk/arch/sparc64/kernel/chmc.c index 777d34577045..9699abeb9907 100644 --- a/trunk/arch/sparc64/kernel/chmc.c +++ b/trunk/arch/sparc64/kernel/chmc.c @@ -343,8 +343,8 @@ static int init_one_mctrl(struct device_node *dp) { struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL); int portid = of_getintprop_default(dp, "portid", -1); - const struct linux_prom64_registers *regs; - const void *pval; + struct linux_prom64_registers *regs; + void *pval; int len; if (!mp) diff --git a/trunk/arch/sparc64/kernel/ebus.c b/trunk/arch/sparc64/kernel/ebus.c index 0ace17bafba4..35bf895fdeee 100644 --- a/trunk/arch/sparc64/kernel/ebus.c +++ b/trunk/arch/sparc64/kernel/ebus.c @@ -285,7 +285,7 @@ static void __init fill_ebus_child(struct device_node *dp, int non_standard_regs) { struct of_device *op; - const int *regs; + int *regs; int i, len; dev->prom_node = dp; @@ -438,9 +438,11 @@ static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p) void __init ebus_init(void) { + struct pci_pbm_info *pbm; struct linux_ebus_device *dev; struct linux_ebus *ebus; struct pci_dev *pdev; + struct pcidev_cookie *cookie; struct device_node *dp; int is_rio; int num_ebus = 0; @@ -451,7 +453,8 @@ void __init ebus_init(void) return; } - dp = pci_device_to_OF_node(pdev); + cookie = pdev->sysdata; + dp = cookie->prom_node; ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = NULL; @@ -477,7 +480,8 @@ void __init ebus_init(void) break; } ebus->is_rio = is_rio; - dp = pci_device_to_OF_node(pdev); + cookie = pdev->sysdata; + dp = cookie->prom_node; continue; } printk("ebus%d:", num_ebus); @@ -485,6 +489,7 @@ void __init ebus_init(void) ebus->index = num_ebus; ebus->prom_node = dp; ebus->self = pdev; + ebus->parent = pbm = cookie->pbm; ebus->ofdev.node = dp; ebus->ofdev.dev.parent = &pdev->dev; @@ -526,7 +531,8 @@ void __init ebus_init(void) if (!pdev) break; - dp = pci_device_to_OF_node(pdev); + cookie = pdev->sysdata; + dp = cookie->prom_node; ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; diff --git a/trunk/arch/sparc64/kernel/irq.c b/trunk/arch/sparc64/kernel/irq.c index 6241e3dbbd57..c443db184371 100644 --- a/trunk/arch/sparc64/kernel/irq.c +++ b/trunk/arch/sparc64/kernel/irq.c @@ -589,6 +589,32 @@ void ack_bad_irq(unsigned int virt_irq) ino, virt_irq); } +#ifndef CONFIG_SMP +extern irqreturn_t timer_interrupt(int, void *); + +void timer_irq(int irq, struct pt_regs *regs) +{ + unsigned long clr_mask = 1 << irq; + unsigned long tick_mask = tick_ops->softint_mask; + struct pt_regs *old_regs; + + if (get_softint() & tick_mask) { + irq = 0; + clr_mask = tick_mask; + } + clear_softint(clr_mask); + + old_regs = set_irq_regs(regs); + irq_enter(); + + kstat_this_cpu.irqs[0]++; + timer_interrupt(irq, NULL); + + irq_exit(); + set_irq_regs(old_regs); +} +#endif + void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bucket; @@ -627,7 +653,7 @@ static u64 prom_limit0, prom_limit1; static void map_prom_timers(void) { struct device_node *dp; - const unsigned int *addr; + unsigned int *addr; /* PROM timer node hangs out in the top level of device siblings... */ dp = of_find_node_by_path("/"); diff --git a/trunk/arch/sparc64/kernel/isa.c b/trunk/arch/sparc64/kernel/isa.c index 6a6882e57ff2..98721a8f8619 100644 --- a/trunk/arch/sparc64/kernel/isa.c +++ b/trunk/arch/sparc64/kernel/isa.c @@ -24,9 +24,27 @@ static void __init report_dev(struct sparc_isa_device *isa_dev, int child) static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) { - struct of_device *op = of_find_device_by_node(isa_dev->prom_node); + struct linux_prom_registers *pregs; + unsigned long base, len; + int prop_len; + + pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len); + if (!pregs) + return; - memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource)); + /* Only the first one is interesting. */ + len = pregs[0].reg_size; + base = (((unsigned long)pregs[0].which_io << 32) | + (unsigned long)pregs[0].phys_addr); + base += isa_dev->bus->parent->io_space.start; + + isa_dev->resource.start = base; + isa_dev->resource.end = (base + len - 1UL); + isa_dev->resource.flags = IORESOURCE_IO; + isa_dev->resource.name = isa_dev->prom_node->name; + + request_resource(&isa_dev->bus->parent->io_space, + &isa_dev->resource); } static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev) @@ -140,10 +158,19 @@ void __init isa_init(void) pdev = NULL; while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) { + struct pcidev_cookie *pdev_cookie; + struct pci_pbm_info *pbm; struct sparc_isa_bridge *isa_br; struct device_node *dp; - dp = pci_device_to_OF_node(pdev); + pdev_cookie = pdev->sysdata; + if (!pdev_cookie) { + printk("ISA: Warning, ISA bridge ignored due to " + "lack of OBP data.\n"); + continue; + } + pbm = pdev_cookie->pbm; + dp = pdev_cookie->prom_node; isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL); if (!isa_br) { @@ -168,9 +195,10 @@ void __init isa_init(void) isa_br->next = isa_chain; isa_chain = isa_br; + isa_br->parent = pbm; isa_br->self = pdev; isa_br->index = index++; - isa_br->prom_node = dp; + isa_br->prom_node = pdev_cookie->prom_node; printk("isa%d:", isa_br->index); diff --git a/trunk/arch/sparc64/kernel/of_device.c b/trunk/arch/sparc64/kernel/of_device.c index 9ac9a307999a..fb9bf1e4d036 100644 --- a/trunk/arch/sparc64/kernel/of_device.c +++ b/trunk/arch/sparc64/kernel/of_device.c @@ -245,7 +245,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned int (*get_flags)(u32 *addr); }; /* @@ -305,7 +305,7 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned int of_bus_default_get_flags(u32 *addr) { return IORESOURCE_MEM; } @@ -317,11 +317,6 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) static int of_bus_pci_match(struct device_node *np) { if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { - const char *model = of_get_property(np, "model", NULL); - - if (model && !strcmp(model, "SUNW,simba")) - return 0; - /* Do not do PCI specific frobbing if the * PCI bridge lacks a ranges property. We * want to pass it through up to the next @@ -337,21 +332,6 @@ static int of_bus_pci_match(struct device_node *np) return 0; } -static int of_bus_simba_match(struct device_node *np) -{ - const char *model = of_get_property(np, "model", NULL); - - if (model && !strcmp(model, "SUNW,simba")) - return 1; - return 0; -} - -static int of_bus_simba_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - return 0; -} - static void of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec) { @@ -389,7 +369,7 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned int of_bus_pci_get_flags(u32 *addr) { unsigned int flags = 0; u32 w = addr[0]; @@ -456,15 +436,6 @@ static struct of_bus of_busses[] = { .map = of_bus_pci_map, .get_flags = of_bus_pci_get_flags, }, - /* SIMBA */ - { - .name = "simba", - .addr_prop_name = "assigned-addresses", - .match = of_bus_simba_match, - .count_cells = of_bus_pci_count_cells, - .map = of_bus_simba_map, - .get_flags = of_bus_pci_get_flags, - }, /* SBUS */ { .name = "sbus", @@ -511,7 +482,7 @@ static int __init build_one_resource(struct device_node *parent, u32 *addr, int na, int ns, int pna) { - const u32 *ranges; + u32 *ranges; unsigned int rlen; int rone; @@ -542,7 +513,7 @@ static int __init build_one_resource(struct device_node *parent, static int __init use_1to1_mapping(struct device_node *pp) { - const char *model; + char *model; /* If this is on the PMU bus, don't try to translate it even * if a ranges property exists. @@ -577,7 +548,7 @@ static void __init build_device_resources(struct of_device *op, struct of_bus *bus; int na, ns; int index, num_reg; - const void *preg; + void *preg; if (!parent) return; @@ -607,7 +578,7 @@ static void __init build_device_resources(struct of_device *op, for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; - const u32 *reg = (preg + (index * ((na + ns) * 4))); + u32 *reg = (preg + (index * ((na + ns) * 4))); struct device_node *dp = op->node; struct device_node *pp = p_op->node; struct of_bus *pbus, *dbus; @@ -672,14 +643,14 @@ static void __init build_device_resources(struct of_device *op, static struct device_node * __init apply_interrupt_map(struct device_node *dp, struct device_node *pp, - const u32 *imap, int imlen, const u32 *imask, + u32 *imap, int imlen, u32 *imask, unsigned int *irq_p) { struct device_node *cp; unsigned int irq = *irq_p; struct of_bus *bus; phandle handle; - const u32 *reg; + u32 *reg; int na, num_reg, i; bus = of_match_bus(pp); @@ -734,7 +705,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, struct device_node *pp, unsigned int irq) { - const struct linux_prom_pci_registers *regs; + struct linux_prom_pci_registers *regs; unsigned int bus, devfn, slot, ret; if (irq < 1 || irq > 4) @@ -759,6 +730,12 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, * D: 2-bit slot number, derived from PCI device number as * (dev - 1) for bus A, or (dev - 2) for bus B * L: 2-bit line number + * + * Actually, more "portable" way to calculate the funky + * slot number is to subtract pbm->pci_first_slot from the + * device number, and that's exactly what the pre-OF + * sparc64 code did, but we're building this stuff generically + * using the OBP tree, not in the PCI controller layer. */ if (bus & 0x80) { /* PBM-A */ @@ -817,7 +794,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op, pp = dp->parent; ip = NULL; while (pp) { - const void *imap, *imsk; + void *imap, *imsk; int imlen; imap = of_get_property(pp, "interrupt-map", &imlen); @@ -882,7 +859,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - const unsigned int *irq; + unsigned int *irq; int len, i; if (!op) diff --git a/trunk/arch/sparc64/kernel/pci.c b/trunk/arch/sparc64/kernel/pci.c index 9a549547cb2b..12109886bb1e 100644 --- a/trunk/arch/sparc64/kernel/pci.c +++ b/trunk/arch/sparc64/kernel/pci.c @@ -1,11 +1,9 @@ -/* pci.c: UltraSparc PCI controller support. +/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $ + * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) - * - * OF tree based PCI bus probing taken from the PowerPC port - * with minor modifications, see there for credits. */ #include @@ -26,9 +24,6 @@ #include #include #include -#include - -#include "pci_impl.h" unsigned long pci_memspace_mask = 0xffffffffUL; @@ -282,10 +277,10 @@ int __init pcic_present(void) return pci_controller_scan(pci_is_controller); } -const struct pci_iommu_ops *pci_iommu_ops; +struct pci_iommu_ops *pci_iommu_ops; EXPORT_SYMBOL(pci_iommu_ops); -extern const struct pci_iommu_ops pci_sun4u_iommu_ops, +extern struct pci_iommu_ops pci_sun4u_iommu_ops, pci_sun4v_iommu_ops; /* Find each controller in the system, attach and initialize @@ -305,467 +300,6 @@ static void __init pci_controller_probe(void) pci_controller_scan(pci_controller_init); } -static unsigned long pci_parse_of_flags(u32 addr0) -{ - unsigned long flags = 0; - - if (addr0 & 0x02000000) { - flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY; - flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64; - flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M; - if (addr0 & 0x40000000) - flags |= IORESOURCE_PREFETCH - | PCI_BASE_ADDRESS_MEM_PREFETCH; - } else if (addr0 & 0x01000000) - flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; - return flags; -} - -/* The of_device layer has translated all of the assigned-address properties - * into physical address resources, we only have to figure out the register - * mapping. - */ -static void pci_parse_of_addrs(struct of_device *op, - struct device_node *node, - struct pci_dev *dev) -{ - struct resource *op_res; - const u32 *addrs; - int proplen; - - addrs = of_get_property(node, "assigned-addresses", &proplen); - if (!addrs) - return; - printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs); - op_res = &op->resource[0]; - for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) { - struct resource *res; - unsigned long flags; - int i; - - flags = pci_parse_of_flags(addrs[0]); - if (!flags) - continue; - i = addrs[0] & 0xff; - printk(" start: %lx, end: %lx, i: %x\n", - op_res->start, op_res->end, i); - - if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { - res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; - } else if (i == dev->rom_base_reg) { - res = &dev->resource[PCI_ROM_RESOURCE]; - flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; - } else { - printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); - continue; - } - res->start = op_res->start; - res->end = op_res->end; - res->flags = flags; - res->name = pci_name(dev); - } -} - -struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus, int devfn, - int host_controller) -{ - struct dev_archdata *sd; - struct pci_dev *dev; - const char *type; - u32 class; - - dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); - if (!dev) - return NULL; - - sd = &dev->dev.archdata; - sd->iommu = pbm->iommu; - sd->stc = &pbm->stc; - sd->host_controller = pbm; - sd->prom_node = node; - sd->op = of_find_device_by_node(node); - sd->msi_num = 0xffffffff; - - type = of_get_property(node, "device_type", NULL); - if (type == NULL) - type = ""; - - printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n", - devfn, type, host_controller); - - dev->bus = bus; - dev->sysdata = node; - dev->dev.parent = bus->bridge; - dev->dev.bus = &pci_bus_type; - dev->devfn = devfn; - dev->multifunction = 0; /* maybe a lie? */ - - if (host_controller) { - dev->vendor = 0x108e; - dev->device = 0x8000; - dev->subsystem_vendor = 0x0000; - dev->subsystem_device = 0x0000; - dev->cfg_size = 256; - dev->class = PCI_CLASS_BRIDGE_HOST << 8; - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - 0x00, PCI_SLOT(devfn), PCI_FUNC(devfn)); - } else { - dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); - dev->device = of_getintprop_default(node, "device-id", 0xffff); - dev->subsystem_vendor = - of_getintprop_default(node, "subsystem-vendor-id", 0); - dev->subsystem_device = - of_getintprop_default(node, "subsystem-id", 0); - - dev->cfg_size = pci_cfg_space_size(dev); - - /* We can't actually use the firmware value, we have - * to read what is in the register right now. One - * reason is that in the case of IDE interfaces the - * firmware can sample the value before the the IDE - * interface is programmed into native mode. - */ - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); - dev->class = class >> 8; - - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - } - printk(" class: 0x%x device name: %s\n", - dev->class, pci_name(dev)); - - dev->current_state = 4; /* unknown power state */ - dev->error_state = pci_channel_io_normal; - - if (host_controller) { - dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; - dev->rom_base_reg = PCI_ROM_ADDRESS1; - dev->irq = PCI_IRQ_NONE; - } else { - if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { - /* a PCI-PCI bridge */ - dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; - dev->rom_base_reg = PCI_ROM_ADDRESS1; - } else if (!strcmp(type, "cardbus")) { - dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; - } else { - dev->hdr_type = PCI_HEADER_TYPE_NORMAL; - dev->rom_base_reg = PCI_ROM_ADDRESS; - - dev->irq = sd->op->irqs[0]; - if (dev->irq == 0xffffffff) - dev->irq = PCI_IRQ_NONE; - } - } - pci_parse_of_addrs(sd->op, node, dev); - - printk(" adding to system ...\n"); - - pci_device_add(dev, bus); - - return dev; -} - -static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) -{ - u32 idx, first, last; - - first = 8; - last = 0; - for (idx = 0; idx < 8; idx++) { - if ((map & (1 << idx)) != 0) { - if (first > idx) - first = idx; - if (last < idx) - last = idx; - } - } - - *first_p = first; - *last_p = last; -} - -static void __init pci_resource_adjust(struct resource *res, - struct resource *root) -{ - res->start += root->start; - res->end += root->start; -} - -/* Cook up fake bus resources for SUNW,simba PCI bridges which lack - * a proper 'ranges' property. - */ -static void __init apb_fake_ranges(struct pci_dev *dev, - struct pci_bus *bus, - struct pci_pbm_info *pbm) -{ - struct resource *res; - u32 first, last; - u8 map; - - pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map); - apb_calc_first_last(map, &first, &last); - res = bus->resource[0]; - res->start = (first << 21); - res->end = (last << 21) + ((1 << 21) - 1); - res->flags = IORESOURCE_IO; - pci_resource_adjust(res, &pbm->io_space); - - pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); - apb_calc_first_last(map, &first, &last); - res = bus->resource[1]; - res->start = (first << 21); - res->end = (last << 21) + ((1 << 21) - 1); - res->flags = IORESOURCE_MEM; - pci_resource_adjust(res, &pbm->mem_space); -} - -static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus); - -#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) - -void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_dev *dev) -{ - struct pci_bus *bus; - const u32 *busrange, *ranges; - int len, i, simba; - struct resource *res; - unsigned int flags; - u64 size; - - printk("of_scan_pci_bridge(%s)\n", node->full_name); - - /* parse bus-range property */ - busrange = of_get_property(node, "bus-range", &len); - if (busrange == NULL || len != 8) { - printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", - node->full_name); - return; - } - ranges = of_get_property(node, "ranges", &len); - simba = 0; - if (ranges == NULL) { - const char *model = of_get_property(node, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) { - simba = 1; - } else { - printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; - } - } - - bus = pci_add_new_bus(dev->bus, dev, busrange[0]); - if (!bus) { - printk(KERN_ERR "Failed to create pci bus for %s\n", - node->full_name); - return; - } - - bus->primary = dev->bus->number; - bus->subordinate = busrange[1]; - bus->bridge_ctl = 0; - - /* parse ranges property, or cook one up by hand for Simba */ - /* PCI #address-cells == 3 and #size-cells == 2 always */ - res = &dev->resource[PCI_BRIDGE_RESOURCES]; - for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { - res->flags = 0; - bus->resource[i] = res; - ++res; - } - if (simba) { - apb_fake_ranges(dev, bus, pbm); - goto simba_cont; - } - i = 1; - for (; len >= 32; len -= 32, ranges += 8) { - struct resource *root; - - flags = pci_parse_of_flags(ranges[0]); - size = GET_64BIT(ranges, 6); - if (flags == 0 || size == 0) - continue; - if (flags & IORESOURCE_IO) { - res = bus->resource[0]; - if (res->flags) { - printk(KERN_ERR "PCI: ignoring extra I/O range" - " for bridge %s\n", node->full_name); - continue; - } - root = &pbm->io_space; - } else { - if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { - printk(KERN_ERR "PCI: too many memory ranges" - " for bridge %s\n", node->full_name); - continue; - } - res = bus->resource[i]; - ++i; - root = &pbm->mem_space; - } - - res->start = GET_64BIT(ranges, 1); - res->end = res->start + size - 1; - res->flags = flags; - - /* Another way to implement this would be to add an of_device - * layer routine that can calculate a resource for a given - * range property value in a PCI device. - */ - pci_resource_adjust(res, root); - } -simba_cont: - sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), - bus->number); - printk(" bus name: %s\n", bus->name); - - pci_of_scan_bus(pbm, node, bus); -} - -static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus) -{ - struct device_node *child; - const u32 *reg; - int reglen, devfn; - struct pci_dev *dev; - - printk("PCI: scan_bus[%s] bus no %d\n", - node->full_name, bus->number); - - child = NULL; - while ((child = of_get_next_child(node, child)) != NULL) { - printk(" * %s\n", child->full_name); - reg = of_get_property(child, "reg", ®len); - if (reg == NULL || reglen < 20) - continue; - devfn = (reg[0] >> 8) & 0xff; - - /* create a new pci_dev for this device */ - dev = of_create_pci_dev(pbm, child, bus, devfn, 0); - if (!dev) - continue; - printk("PCI: dev header type: %x\n", dev->hdr_type); - - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - of_scan_pci_bridge(pbm, child, dev); - } -} - -static ssize_t -show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) -{ - struct pci_dev *pdev; - struct device_node *dp; - - pdev = to_pci_dev(dev); - dp = pdev->dev.archdata.prom_node; - - return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name); -} - -static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); - -static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) -{ - struct pci_dev *dev; - struct pci_bus *child_bus; - int err; - - list_for_each_entry(dev, &bus->devices, bus_list) { - /* we don't really care if we can create this file or - * not, but we need to assign the result of the call - * or the world will fall under alien invasion and - * everybody will be frozen on a spaceship ready to be - * eaten on alpha centauri by some green and jelly - * humanoid. - */ - err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr); - } - list_for_each_entry(child_bus, &bus->children, node) - pci_bus_register_of_sysfs(child_bus); -} - -int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 *value) -{ - static u8 fake_pci_config[] = { - 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ - 0x00, 0x80, /* Device: 0x8000 (PBM) */ - 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ - 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ - 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ - 0x00, /* Cacheline: 0x00 */ - 0x40, /* Latency: 0x40 */ - 0x00, /* Header-Type: 0x00 normal */ - }; - - *value = 0; - if (where >= 0 && where < sizeof(fake_pci_config) && - (where + size) >= 0 && - (where + size) < sizeof(fake_pci_config) && - size <= sizeof(u32)) { - while (size--) { - *value <<= 8; - *value |= fake_pci_config[where + size]; - } - } - - return PCIBIOS_SUCCESSFUL; -} - -int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 value) -{ - return PCIBIOS_SUCCESSFUL; -} - -struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) -{ - struct pci_controller_info *p = pbm->parent; - struct device_node *node = pbm->prom_node; - struct pci_dev *host_pdev; - struct pci_bus *bus; - - printk("PCI: Scanning PBM %s\n", node->full_name); - - /* XXX parent device? XXX */ - bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm); - if (!bus) { - printk(KERN_ERR "Failed to create bus for %s\n", - node->full_name); - return NULL; - } - bus->secondary = pbm->pci_first_busno; - bus->subordinate = pbm->pci_last_busno; - - bus->resource[0] = &pbm->io_space; - bus->resource[1] = &pbm->mem_space; - - /* Create the dummy host bridge and link it in. */ - host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1); - bus->self = host_pdev; - - pci_of_scan_bus(pbm, node, bus); - pci_bus_add_devices(bus); - pci_bus_register_of_sysfs(bus); - - return bus; -} - static void __init pci_scan_each_controller_bus(void) { struct pci_controller_info *p; @@ -826,33 +360,8 @@ void pcibios_align_resource(void *data, struct resource *res, { } -int pcibios_enable_device(struct pci_dev *dev, int mask) +int pcibios_enable_device(struct pci_dev *pdev, int mask) { - u16 cmd, oldcmd; - int i; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - oldcmd = cmd; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - - /* Only set up the requested stuff */ - if (!(mask & (1<flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != oldcmd) { - printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n", - pci_name(dev), cmd); - /* Enable the appropriate bits in the PCI command register. */ - pci_write_config_word(dev, PCI_COMMAND, cmd); - } return 0; } @@ -871,7 +380,7 @@ void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region else root = &pbm->mem_space; - pci_resource_adjust(&zero_res, root); + pbm->parent->resource_adjust(pdev, &zero_res, root); region->start = res->start - zero_res.start; region->end = res->end - zero_res.start; @@ -892,7 +401,7 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, else root = &pbm->mem_space; - pci_resource_adjust(res, root); + pbm->parent->resource_adjust(pdev, res, root); } EXPORT_SYMBOL(pcibios_bus_to_resource); @@ -913,17 +422,55 @@ char * __devinit pcibios_setup(char *str) static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state) { - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm; struct pci_controller_info *p; unsigned long space_size, user_offset, user_size; + if (!pcp) + return -ENXIO; + pbm = pcp->pbm; + if (!pbm) + return -ENXIO; + p = pbm->parent; - if (mmap_state == pci_mmap_io) { - space_size = (pbm->io_space.end - - pbm->io_space.start) + 1; + if (p->pbms_same_domain) { + unsigned long lowest, highest; + + lowest = ~0UL; highest = 0UL; + if (mmap_state == pci_mmap_io) { + if (p->pbm_A.io_space.flags) { + lowest = p->pbm_A.io_space.start; + highest = p->pbm_A.io_space.end + 1; + } + if (p->pbm_B.io_space.flags) { + if (lowest > p->pbm_B.io_space.start) + lowest = p->pbm_B.io_space.start; + if (highest < p->pbm_B.io_space.end + 1) + highest = p->pbm_B.io_space.end + 1; + } + space_size = highest - lowest; + } else { + if (p->pbm_A.mem_space.flags) { + lowest = p->pbm_A.mem_space.start; + highest = p->pbm_A.mem_space.end + 1; + } + if (p->pbm_B.mem_space.flags) { + if (lowest > p->pbm_B.mem_space.start) + lowest = p->pbm_B.mem_space.start; + if (highest < p->pbm_B.mem_space.end + 1) + highest = p->pbm_B.mem_space.end + 1; + } + space_size = highest - lowest; + } } else { - space_size = (pbm->mem_space.end - - pbm->mem_space.start) + 1; + if (mmap_state == pci_mmap_io) { + space_size = (pbm->io_space.end - + pbm->io_space.start) + 1; + } else { + space_size = (pbm->mem_space.end - + pbm->mem_space.start) + 1; + } } /* Make sure the request is in range. */ @@ -934,12 +481,31 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc (user_offset + user_size) > space_size) return -EINVAL; - if (mmap_state == pci_mmap_io) { - vma->vm_pgoff = (pbm->io_space.start + - user_offset) >> PAGE_SHIFT; + if (p->pbms_same_domain) { + unsigned long lowest = ~0UL; + + if (mmap_state == pci_mmap_io) { + if (p->pbm_A.io_space.flags) + lowest = p->pbm_A.io_space.start; + if (p->pbm_B.io_space.flags && + lowest > p->pbm_B.io_space.start) + lowest = p->pbm_B.io_space.start; + } else { + if (p->pbm_A.mem_space.flags) + lowest = p->pbm_A.mem_space.start; + if (p->pbm_B.mem_space.flags && + lowest > p->pbm_B.mem_space.start) + lowest = p->pbm_B.mem_space.start; + } + vma->vm_pgoff = (lowest + user_offset) >> PAGE_SHIFT; } else { - vma->vm_pgoff = (pbm->mem_space.start + - user_offset) >> PAGE_SHIFT; + if (mmap_state == pci_mmap_io) { + vma->vm_pgoff = (pbm->io_space.start + + user_offset) >> PAGE_SHIFT; + } else { + vma->vm_pgoff = (pbm->mem_space.start + + user_offset) >> PAGE_SHIFT; + } } return 0; @@ -1073,8 +639,9 @@ int pci_domain_nr(struct pci_bus *pbus) struct pci_controller_info *p = pbm->parent; ret = p->index; - ret = ((ret << 1) + - ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); + if (p->pbms_same_domain == 0) + ret = ((ret << 1) + + ((pbm == &pbm->parent->pbm_B) ? 1 : 0)); } return ret; @@ -1084,7 +651,8 @@ EXPORT_SYMBOL(pci_domain_nr); #ifdef CONFIG_PCI_MSI int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; int virt_irq, err; @@ -1092,17 +660,18 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) return -EINVAL; err = p->setup_msi_irq(&virt_irq, pdev, desc); - if (err) + if (err < 0) return err; - return 0; + return virt_irq; } void arch_teardown_msi_irq(unsigned int virt_irq) { struct msi_desc *entry = get_irq_msi(virt_irq); struct pci_dev *pdev = entry->dev; - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; if (!pbm->msi_num || !p->setup_msi_irq) @@ -1114,7 +683,9 @@ void arch_teardown_msi_irq(unsigned int virt_irq) struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) { - return pdev->dev.archdata.prom_node; + struct pcidev_cookie *pc = pdev->sysdata; + + return pc->op->node; } EXPORT_SYMBOL(pci_device_to_OF_node); diff --git a/trunk/arch/sparc64/kernel/pci_common.c b/trunk/arch/sparc64/kernel/pci_common.c index 1e6aeedf43c4..5a92cb90ebe0 100644 --- a/trunk/arch/sparc64/kernel/pci_common.c +++ b/trunk/arch/sparc64/kernel/pci_common.c @@ -1,6 +1,7 @@ -/* pci_common.c: PCI controller common support. +/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $ + * pci_common.c: PCI controller common support. * - * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ #include @@ -15,137 +16,748 @@ #include "pci_impl.h" -static void pci_register_legacy_regions(struct resource *io_res, - struct resource *mem_res) +/* Fix self device of BUS and hook it into BUS->self. + * The pci_scan_bus does not do this for the host bridge. + */ +void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) { - struct resource *p; + struct pci_dev *pdev; - /* VGA Video RAM. */ - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return; + list_for_each_entry(pdev, &pbus->devices, bus_list) { + if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { + pbus->self = pdev; + return; + } + } - p->name = "Video RAM area"; - p->start = mem_res->start + 0xa0000UL; - p->end = p->start + 0x1ffffUL; - p->flags = IORESOURCE_BUSY; - request_resource(mem_res, p); + prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); + prom_halt(); +} - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) +/* Find the OBP PROM device tree node for a PCI device. */ +static struct device_node * __init +find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev, + struct device_node *bus_node, + struct linux_prom_pci_registers **pregs, + int *nregs) +{ + struct device_node *dp; + + *nregs = 0; + + /* + * Return the PBM's PROM node in case we are it's PCI device, + * as the PBM's reg property is different to standard PCI reg + * properties. We would delete this device entry otherwise, + * which confuses XFree86's device probing... + */ + if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) && + (pdev->vendor == PCI_VENDOR_ID_SUN) && + (pdev->device == PCI_DEVICE_ID_SUN_PBM || + pdev->device == PCI_DEVICE_ID_SUN_SCHIZO || + pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO || + pdev->device == PCI_DEVICE_ID_SUN_SABRE || + pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) + return bus_node; + + dp = bus_node->child; + while (dp) { + struct linux_prom_pci_registers *regs; + struct property *prop; + int len; + + prop = of_find_property(dp, "reg", &len); + if (!prop) + goto do_next_sibling; + + regs = prop->value; + if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { + *pregs = regs; + *nregs = len / sizeof(struct linux_prom_pci_registers); + return dp; + } + + do_next_sibling: + dp = dp->sibling; + } + + return NULL; +} + +/* Older versions of OBP on PCI systems encode 64-bit MEM + * space assignments incorrectly, this fixes them up. We also + * take the opportunity here to hide other kinds of bogus + * assignments. + */ +static void __init fixup_obp_assignments(struct pci_dev *pdev, + struct pcidev_cookie *pcp) +{ + int i; + + if (pdev->vendor == PCI_VENDOR_ID_AL && + (pdev->device == PCI_DEVICE_ID_AL_M7101 || + pdev->device == PCI_DEVICE_ID_AL_M1533)) { + int i; + + /* Zap all of the normal resources, they are + * meaningless and generate bogus resource collision + * messages. This is OpenBoot's ill-fated attempt to + * represent the implicit resources that these devices + * have. + */ + pcp->num_prom_assignments = 0; + for (i = 0; i < 6; i++) { + pdev->resource[i].start = + pdev->resource[i].end = + pdev->resource[i].flags = 0; + } + pdev->resource[PCI_ROM_RESOURCE].start = + pdev->resource[PCI_ROM_RESOURCE].end = + pdev->resource[PCI_ROM_RESOURCE].flags = 0; return; + } - p->name = "System ROM"; - p->start = mem_res->start + 0xf0000UL; - p->end = p->start + 0xffffUL; - p->flags = IORESOURCE_BUSY; - request_resource(mem_res, p); + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + int space; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) + ap = &pcp->prom_assignments[i]; + space = ap->phys_hi >> 24; + if ((space & 0x3) == 2 && + (space & 0x4) != 0) { + ap->phys_hi &= ~(0x7 << 24); + ap->phys_hi |= 0x3 << 24; + } + } +} + +static ssize_t +show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) +{ + struct pci_dev *pdev; + struct pcidev_cookie *sysdata; + + pdev = to_pci_dev(dev); + sysdata = pdev->sysdata; + + return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name); +} + +static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); + +/* Fill in the PCI device cookie sysdata for the given + * PCI device. This cookie is the means by which one + * can get to OBP and PCI controller specific information + * for a PCI device. + */ +static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + struct device_node *bus_node) +{ + struct linux_prom_pci_registers *pregs = NULL; + struct pcidev_cookie *pcp; + struct device_node *dp; + struct property *prop; + int nregs, len, err; + + dp = find_device_prom_node(pbm, pdev, bus_node, + &pregs, &nregs); + if (!dp) { + /* If it is not in the OBP device tree then + * there must be a damn good reason for it. + * + * So what we do is delete the device from the + * PCI device tree completely. This scenario + * is seen, for example, on CP1500 for the + * second EBUS/HappyMeal pair if the external + * connector for it is not present. + */ + pci_remove_bus_device(pdev); return; + } - p->name = "Video ROM"; - p->start = mem_res->start + 0xc0000UL; - p->end = p->start + 0x7fffUL; - p->flags = IORESOURCE_BUSY; - request_resource(mem_res, p); + pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC); + if (pcp == NULL) { + prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n"); + prom_halt(); + } + pcp->pbm = pbm; + pcp->prom_node = dp; + pcp->op = of_find_device_by_node(dp); + memcpy(pcp->prom_regs, pregs, + nregs * sizeof(struct linux_prom_pci_registers)); + pcp->num_prom_regs = nregs; + + /* We can't have the pcidev_cookie assignments be just + * direct pointers into the property value, since they + * are potentially modified by the probing process. + */ + prop = of_find_property(dp, "assigned-addresses", &len); + if (!prop) { + pcp->num_prom_assignments = 0; + } else { + memcpy(pcp->prom_assignments, prop->value, len); + pcp->num_prom_assignments = + (len / sizeof(pcp->prom_assignments[0])); + } + + if (strcmp(dp->name, "ebus") == 0) { + struct linux_prom_ebus_ranges *erng; + int iter; + + /* EBUS is special... */ + prop = of_find_property(dp, "ranges", &len); + if (!prop) { + prom_printf("EBUS: Fatal error, no range property\n"); + prom_halt(); + } + erng = prop->value; + len = (len / sizeof(erng[0])); + for (iter = 0; iter < len; iter++) { + struct linux_prom_ebus_ranges *ep = &erng[iter]; + struct linux_prom_pci_registers *ap; + + ap = &pcp->prom_assignments[iter]; + + ap->phys_hi = ep->parent_phys_hi; + ap->phys_mid = ep->parent_phys_mid; + ap->phys_lo = ep->parent_phys_lo; + ap->size_hi = 0; + ap->size_lo = ep->size; + } + pcp->num_prom_assignments = len; + } + + fixup_obp_assignments(pdev, pcp); + + pdev->sysdata = pcp; + + /* we don't really care if we can create this file or not, + * but we need to assign the result of the call or the world will fall + * under alien invasion and everybody will be frozen on a spaceship + * ready to be eaten on alpha centauri by some green and jelly humanoid. + */ + err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr); } -static void pci_register_iommu_region(struct pci_pbm_info *pbm) +void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + struct device_node *dp) { - const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); + struct pci_dev *pdev, *pdev_next; + struct pci_bus *this_pbus, *pbus_next; + + /* This must be _safe because the cookie fillin + routine can delete devices from the tree. */ + list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list) + pdev_cookie_fillin(pbm, pdev, dp); - if (vdma) { - struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); + list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) { + struct pcidev_cookie *pcp = this_pbus->self->sysdata; + + pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); + } +} - if (!rp) { - prom_printf("Cannot allocate IOMMU resource.\n"); +static void __init bad_assignment(struct pci_dev *pdev, + struct linux_prom_pci_registers *ap, + struct resource *res, + int do_prom_halt) +{ + prom_printf("PCI: Bogus PROM assignment. BUS[%02x] DEVFN[%x]\n", + pdev->bus->number, pdev->devfn); + if (ap) + prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n", + ap->phys_hi, ap->phys_mid, ap->phys_lo, + ap->size_hi, ap->size_lo); + if (res) + prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n", + res->start, res->end, res->flags); + if (do_prom_halt) + prom_halt(); +} + +static struct resource * +__init get_root_resource(struct linux_prom_pci_registers *ap, + struct pci_pbm_info *pbm) +{ + int space = (ap->phys_hi >> 24) & 3; + + switch (space) { + case 0: + /* Configuration space, silently ignore it. */ + return NULL; + + case 1: + /* 16-bit IO space */ + return &pbm->io_space; + + case 2: + /* 32-bit MEM space */ + return &pbm->mem_space; + + case 3: + /* 64-bit MEM space, these are allocated out of + * the 32-bit mem_space range for the PBM, ie. + * we just zero out the upper 32-bits. + */ + return &pbm->mem_space; + + default: + printk("PCI: What is resource space %x?\n", space); + return NULL; + }; +} + +static struct resource * +__init get_device_resource(struct linux_prom_pci_registers *ap, + struct pci_dev *pdev) +{ + struct resource *res; + int breg = (ap->phys_hi & 0xff); + + switch (breg) { + case PCI_ROM_ADDRESS: + /* Unfortunately I have seen several cases where + * buggy FCODE uses a space value of '1' (I/O space) + * in the register property for the ROM address + * so disable this sanity check for now. + */ +#if 0 + { + int space = (ap->phys_hi >> 24) & 3; + + /* It had better be MEM space. */ + if (space != 2) + bad_assignment(pdev, ap, NULL, 0); + } +#endif + res = &pdev->resource[PCI_ROM_RESOURCE]; + break; + + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_2: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: + res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; + break; + + default: + bad_assignment(pdev, ap, NULL, 0); + res = NULL; + break; + }; + + return res; +} + +static void __init pdev_record_assignments(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + int i; + + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + struct resource *root, *res; + + /* The format of this property is specified in + * the PCI Bus Binding to IEEE1275-1994. + */ + ap = &pcp->prom_assignments[i]; + root = get_root_resource(ap, pbm); + res = get_device_resource(ap, pdev); + if (root == NULL || res == NULL || + res->flags == 0) + continue; + + /* Ok we know which resource this PROM assignment is + * for, sanity check it. + */ + if ((res->start & 0xffffffffUL) != ap->phys_lo) + bad_assignment(pdev, ap, res, 1); + + /* If it is a 64-bit MEM space assignment, verify that + * the resource is too and that the upper 32-bits match. + */ + if (((ap->phys_hi >> 24) & 3) == 3) { + if (((res->flags & IORESOURCE_MEM) == 0) || + ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + != PCI_BASE_ADDRESS_MEM_TYPE_64)) + bad_assignment(pdev, ap, res, 1); + if ((res->start >> 32) != ap->phys_mid) + bad_assignment(pdev, ap, res, 1); + + /* PBM cannot generate cpu initiated PIOs + * to the full 64-bit space. Therefore the + * upper 32-bits better be zero. If it is + * not, just skip it and we will assign it + * properly ourselves. + */ + if ((res->start >> 32) != 0UL) { + printk(KERN_ERR "PCI: OBP assigns out of range MEM address " + "%016lx for region %ld on device %s\n", + res->start, (res - &pdev->resource[0]), pci_name(pdev)); + continue; + } + } + + /* Adjust the resource into the physical address space + * of this PBM. + */ + pbm->parent->resource_adjust(pdev, res, root); + + if (request_resource(root, res) < 0) { + int rnum; + + /* OK, there is some conflict. But this is fine + * since we'll reassign it in the fixup pass. + * + * Do not print the warning for ROM resources + * as such a conflict is quite common and + * harmless as the ROM bar is disabled. + */ + rnum = (res - &pdev->resource[0]); + if (rnum != PCI_ROM_RESOURCE) + printk(KERN_ERR "PCI: Resource collision, " + "region %d " + "[%016lx:%016lx] of device %s\n", + rnum, + res->start, res->end, + pci_name(pdev)); + } + } +} + +void __init pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *dev; + struct pci_bus *bus; + + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_record_assignments(pbm, dev); + + list_for_each_entry(bus, &pbus->children, node) + pci_record_assignments(pbm, bus); +} + +/* Return non-zero if PDEV has implicit I/O resources even + * though it may not have an I/O base address register + * active. + */ +static int __init has_implicit_io(struct pci_dev *pdev) +{ + int class = pdev->class >> 8; + + if (class == PCI_CLASS_NOT_DEFINED || + class == PCI_CLASS_NOT_DEFINED_VGA || + class == PCI_CLASS_STORAGE_IDE || + (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) + return 1; + + return 0; +} + +static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + u32 reg; + u16 cmd; + int i, io_seen, mem_seen; + + io_seen = mem_seen = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *root, *res; + unsigned long size, min, max, align; + + res = &pdev->resource[i]; + + if (res->flags & IORESOURCE_IO) + io_seen++; + else if (res->flags & IORESOURCE_MEM) + mem_seen++; + + /* If it is already assigned or the resource does + * not exist, there is nothing to do. + */ + if (res->parent != NULL || res->flags == 0UL) + continue; + + /* Determine the root we allocate from. */ + if (res->flags & IORESOURCE_IO) { + root = &pbm->io_space; + min = root->start + 0x400UL; + max = root->end; + } else { + root = &pbm->mem_space; + min = root->start; + max = min + 0x80000000UL; + } + + size = res->end - res->start; + align = size + 1; + if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) { + /* uh oh */ + prom_printf("PCI: Failed to allocate resource %d for %s\n", + i, pci_name(pdev)); prom_halt(); } - rp->name = "IOMMU"; - rp->start = pbm->mem_space.start + (unsigned long) vdma[0]; - rp->end = rp->start + (unsigned long) vdma[1] - 1UL; - rp->flags = IORESOURCE_BUSY; - request_resource(&pbm->mem_space, rp); + + /* Update PCI config space. */ + pbm->parent->base_address_update(pdev, i); + } + + /* Special case, disable the ROM. Several devices + * act funny (ie. do not respond to memory space writes) + * when it is left enabled. A good example are Qlogic,ISP + * adapters. + */ + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg); + + /* If we saw I/O or MEM resources, enable appropriate + * bits in PCI command register. + */ + if (io_seen || mem_seen) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (io_seen || has_implicit_io(pdev)) + cmd |= PCI_COMMAND_IO; + if (mem_seen) + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + + /* If this is a PCI bridge or an IDE controller, + * enable bus mastering. In the former case also + * set the cache line size correctly. + */ + if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) || + (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) && + ((pdev->class & 0x80) != 0))) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, + (64 / sizeof(u32))); } } -void pci_determine_mem_io_space(struct pci_pbm_info *pbm) +void __init pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus) { - const struct linux_prom_pci_ranges *pbm_ranges; - int i, saw_mem, saw_io; - int num_pbm_ranges; + struct pci_dev *dev; + struct pci_bus *bus; - saw_mem = saw_io = 0; - pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i); - num_pbm_ranges = i / sizeof(*pbm_ranges); + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_assign_unassigned(pbm, dev); - for (i = 0; i < num_pbm_ranges; i++) { - const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; - unsigned long a; - u32 parent_phys_hi, parent_phys_lo; - int type; + list_for_each_entry(bus, &pbus->children, node) + pci_assign_unassigned(pbm, bus); +} - parent_phys_hi = pr->parent_phys_hi; - parent_phys_lo = pr->parent_phys_lo; - if (tlb_type == hypervisor) - parent_phys_hi &= 0x0fffffff; +static void __init pdev_fixup_irq(struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct of_device *op = pcp->op; - type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)parent_phys_hi << 32UL) | - ((unsigned long)parent_phys_lo << 0UL)); + if (op->irqs[0] == 0xffffffff) { + pdev->irq = PCI_IRQ_NONE; + return; + } - switch (type) { - case 0: - /* PCI config space, 16MB */ - pbm->config_space = a; - break; + pdev->irq = op->irqs[0]; - case 1: - /* 16-bit IO space, 16MB */ - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; - saw_io = 1; - break; + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, + pdev->irq & PCI_IRQ_INO); +} - case 2: - /* 32-bit MEM space, 2GB */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); - pbm->mem_space.flags = IORESOURCE_MEM; - saw_mem = 1; - break; +void __init pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *dev; + struct pci_bus *bus; - case 3: - /* XXX 64-bit MEM handling XXX */ + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_fixup_irq(dev); - default: - break; - }; + list_for_each_entry(bus, &pbus->children, node) + pci_fixup_irq(pbm, bus); +} + +static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) +{ + u16 cmd; + u8 hdr_type, min_gnt, ltimer; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + /* Read it back, if the mastering bit did not + * get set, the device does not support bus + * mastering so we have nothing to do here. + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_MASTER) == 0) + return; + + /* Set correct cache line size, 64-byte on all + * Sparc64 PCI systems. Note that the value is + * measured in 32-bit words. + */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, + 64 / sizeof(u32)); + + pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type); + hdr_type &= ~0x80; + if (hdr_type != PCI_HEADER_TYPE_NORMAL) + return; + + /* If the latency timer is already programmed with a non-zero + * value, assume whoever set it (OBP or whoever) knows what + * they are doing. + */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, <imer); + if (ltimer != 0) + return; + + /* XXX Since I'm tipping off the min grant value to + * XXX choose a suitable latency timer value, I also + * XXX considered making use of the max latency value + * XXX as well. Unfortunately I've seen too many bogusly + * XXX low settings for it to the point where it lacks + * XXX any usefulness. In one case, an ethernet card + * XXX claimed a min grant of 10 and a max latency of 5. + * XXX Now, if I had two such cards on the same bus I + * XXX could not set the desired burst period (calculated + * XXX from min grant) without violating the max latency + * XXX bound. Duh... + * XXX + * XXX I blame dumb PC bios implementors for stuff like + * XXX this, most of them don't even try to do something + * XXX sensible with latency timer values and just set some + * XXX default value (usually 32) into every device. + */ + + pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt); + + if (min_gnt == 0) { + /* If no min_gnt setting then use a default + * value. + */ + if (is_66mhz) + ltimer = 16; + else + ltimer = 32; + } else { + int shift_factor; + + if (is_66mhz) + shift_factor = 2; + else + shift_factor = 3; + + /* Use a default value when the min_gnt value + * is erroneously high. + */ + if (((unsigned int) min_gnt << shift_factor) > 512 || + ((min_gnt << shift_factor) & 0xff) == 0) { + ltimer = 8 << shift_factor; + } else { + ltimer = min_gnt << shift_factor; + } } - if (!saw_io || !saw_mem) { - prom_printf("%s: Fatal error, missing %s PBM range.\n", - pbm->name, - (!saw_io ? "IO" : "MEM")); - prom_halt(); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer); +} + +void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + int all_are_66mhz; + u16 status; + + if (pbm->is_66mhz_capable == 0) { + all_are_66mhz = 0; + goto out; } - printk("%s: PCI IO[%lx] MEM[%lx]\n", - pbm->name, - pbm->io_space.start, - pbm->mem_space.start); + all_are_66mhz = 1; + list_for_each_entry(pdev, &pbus->devices, bus_list) { + pci_read_config_word(pdev, PCI_STATUS, &status); + if (!(status & PCI_STATUS_66MHZ)) { + all_are_66mhz = 0; + break; + } + } +out: + pbm->all_devs_66mhz = all_are_66mhz; + + printk("PCI%d(PBM%c): Bus running at %dMHz\n", + pbm->parent->index, + (pbm == &pbm->parent->pbm_A) ? 'A' : 'B', + (all_are_66mhz ? 66 : 33)); +} + +void pci_setup_busmastering(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *dev; + struct pci_bus *bus; + int is_66mhz; + + is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz; + + list_for_each_entry(dev, &pbus->devices, bus_list) + pdev_setup_busmastering(dev, is_66mhz); + + list_for_each_entry(bus, &pbus->children, node) + pci_setup_busmastering(pbm, bus); +} + +void pci_register_legacy_regions(struct resource *io_res, + struct resource *mem_res) +{ + struct resource *p; + + /* VGA Video RAM. */ + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return; - pbm->io_space.name = pbm->mem_space.name = pbm->name; + p->name = "Video RAM area"; + p->start = mem_res->start + 0xa0000UL; + p->end = p->start + 0x1ffffUL; + p->flags = IORESOURCE_BUSY; + request_resource(mem_res, p); - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return; - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); - pci_register_iommu_region(pbm); + p->name = "System ROM"; + p->start = mem_res->start + 0xf0000UL; + p->end = p->start + 0xffffUL; + p->flags = IORESOURCE_BUSY; + request_resource(mem_res, p); + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return; + + p->name = "Video ROM"; + p->start = mem_res->start + 0xc0000UL; + p->end = p->start + 0x7fffUL; + p->flags = IORESOURCE_BUSY; + request_resource(mem_res, p); } /* Generic helper routines for PCI error reporting. */ diff --git a/trunk/arch/sparc64/kernel/pci_impl.h b/trunk/arch/sparc64/kernel/pci_impl.h index 1208583fcb83..971e2bea30b4 100644 --- a/trunk/arch/sparc64/kernel/pci_impl.h +++ b/trunk/arch/sparc64/kernel/pci_impl.h @@ -1,6 +1,7 @@ -/* pci_impl.h: Helper definitions for PCI controller support. +/* $Id: pci_impl.h,v 1.9 2001/06/13 06:34:30 davem Exp $ + * pci_impl.h: Helper definitions for PCI controller support. * - * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ #ifndef PCI_IMPL_H @@ -12,22 +13,26 @@ #include extern struct pci_controller_info *pci_controller_root; -extern unsigned long pci_memspace_mask; extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ -extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); -extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); - -extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 *value); -extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 value); +extern void pci_fixup_host_bridge_self(struct pci_bus *pbus); +extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + struct device_node *prom_node); +extern void pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_setup_busmastering(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_register_legacy_regions(struct resource *io_res, + struct resource *mem_res); /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); diff --git a/trunk/arch/sparc64/kernel/pci_iommu.c b/trunk/arch/sparc64/kernel/pci_iommu.c index 66712772f494..7aca0f33f885 100644 --- a/trunk/arch/sparc64/kernel/pci_iommu.c +++ b/trunk/arch/sparc64/kernel/pci_iommu.c @@ -1,6 +1,7 @@ -/* pci_iommu.c: UltraSparc PCI controller IOM/STC support. +/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $ + * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * - * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com) */ @@ -35,7 +36,7 @@ "i" (ASI_PHYS_BYPASS_EC_E)) /* Must be invoked under the IOMMU lock. */ -static void __iommu_flushall(struct iommu *iommu) +static void __iommu_flushall(struct pci_iommu *iommu) { unsigned long tag; int entry; @@ -63,7 +64,7 @@ static void __iommu_flushall(struct iommu *iommu) #define IOPTE_IS_DUMMY(iommu, iopte) \ ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) -static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) +static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) { unsigned long val = iopte_val(*iopte); @@ -74,9 +75,9 @@ static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) } /* Based largely upon the ppc64 iommu allocator. */ -static long pci_arena_alloc(struct iommu *iommu, unsigned long npages) +static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages) { - struct iommu_arena *arena = &iommu->arena; + struct pci_iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; int pass; @@ -115,7 +116,7 @@ static long pci_arena_alloc(struct iommu *iommu, unsigned long npages) return n; } -static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; @@ -123,7 +124,7 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign __clear_bit(i, arena->map); } -void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) +void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) { unsigned long i, tsbbase, order, sz, num_tsb_entries; @@ -169,7 +170,7 @@ void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 iopte_make_dummy(iommu, &iommu->page_table[i]); } -static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) +static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages) { long entry; @@ -180,12 +181,12 @@ static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) return iommu->page_table + entry; } -static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) +static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages) { pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); } -static int iommu_alloc_ctx(struct iommu *iommu) +static int iommu_alloc_ctx(struct pci_iommu *iommu) { int lowest = iommu->ctx_lowest_free; int sz = IOMMU_NUM_CTXS - lowest; @@ -204,7 +205,7 @@ static int iommu_alloc_ctx(struct iommu *iommu) return n; } -static inline void iommu_free_ctx(struct iommu *iommu, int ctx) +static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) { if (likely(ctx)) { __clear_bit(ctx, iommu->ctx_bitmap); @@ -219,7 +220,8 @@ static inline void iommu_free_ctx(struct iommu *iommu, int ctx) */ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; iopte_t *iopte; unsigned long flags, order, first_page; void *ret; @@ -235,7 +237,8 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr return NULL; memset((char *)first_page, 0, PAGE_SIZE << order); - iommu = pdev->dev.archdata.iommu; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); @@ -265,12 +268,14 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr /* Free and unmap a consistent DMA translation. */ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; iopte_t *iopte; unsigned long flags, order, npages; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = pdev->dev.archdata.iommu; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; iopte = iommu->page_table + ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); @@ -290,16 +295,18 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, */ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; iopte_t *base; unsigned long flags, npages, oaddr; unsigned long i, base_paddr, ctx; u32 bus_addr, ret; unsigned long iopte_protection; - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; if (unlikely(direction == PCI_DMA_NONE)) goto bad_no_ctx; @@ -342,7 +349,7 @@ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, return PCI_DMA_ERROR_CODE; } -static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) +static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) { int limit; @@ -409,8 +416,9 @@ static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vad /* Unmap a single streaming mode DMA translation. */ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; iopte_t *base; unsigned long flags, npages, ctx, i; @@ -420,8 +428,9 @@ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ return; } - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -540,8 +549,9 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, */ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; unsigned long flags, ctx, npages, iopte_protection; iopte_t *base; u32 dma_base; @@ -560,8 +570,9 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n return 1; } - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; if (unlikely(direction == PCI_DMA_NONE)) goto bad_no_ctx; @@ -625,8 +636,9 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n /* Unmap a set of streaming mode DMA translations. */ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; iopte_t *base; unsigned long flags, ctx, i, npages; u32 bus_addr; @@ -636,8 +648,9 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in WARN_ON(1); } - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -683,12 +696,14 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in */ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; unsigned long flags, ctx, npages; - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; if (!strbuf->strbuf_enabled) return; @@ -721,13 +736,15 @@ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_ */ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct iommu *iommu; - struct strbuf *strbuf; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; + struct pci_strbuf *strbuf; unsigned long flags, ctx, npages, i; u32 bus_addr; - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + strbuf = &pcp->pbm->stc; if (!strbuf->strbuf_enabled) return; @@ -758,7 +775,7 @@ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist spin_unlock_irqrestore(&iommu->lock, flags); } -const struct pci_iommu_ops pci_sun4u_iommu_ops = { +struct pci_iommu_ops pci_sun4u_iommu_ops = { .alloc_consistent = pci_4u_alloc_consistent, .free_consistent = pci_4u_free_consistent, .map_single = pci_4u_map_single, @@ -792,12 +809,13 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) { + struct pcidev_cookie *pcp = pdev->sysdata; u64 dma_addr_mask; if (pdev == NULL) { dma_addr_mask = 0xffffffff; } else { - struct iommu *iommu = pdev->dev.archdata.iommu; + struct pci_iommu *iommu = pcp->pbm->iommu; dma_addr_mask = iommu->dma_addr_mask; diff --git a/trunk/arch/sparc64/kernel/pci_psycho.c b/trunk/arch/sparc64/kernel/pci_psycho.c index 253d40ec2245..fda5db223d96 100644 --- a/trunk/arch/sparc64/kernel/pci_psycho.c +++ b/trunk/arch/sparc64/kernel/pci_psycho.c @@ -1,6 +1,7 @@ -/* pci_psycho.c: PSYCHO/U2P specific PCI controller support. +/* $Id: pci_psycho.c,v 1.33 2002/02/01 00:58:33 davem Exp $ + * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * - * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ @@ -118,10 +119,6 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - switch (size) { case 1: *value = 0xff; @@ -175,9 +172,6 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; @@ -269,7 +263,7 @@ static void __psycho_check_one_stc(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a) { - struct strbuf *strbuf = &pbm->stc; + struct pci_strbuf *strbuf = &pbm->stc; unsigned long regbase = p->pbm_A.controller_regs; unsigned long err_base, tag_base, line_base; u64 control; @@ -418,7 +412,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, unsigned long afar, enum psycho_error_type type) { - struct iommu *iommu = p->pbm_A.iommu; + struct pci_iommu *iommu = p->pbm_A.iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -901,6 +895,59 @@ static void psycho_register_error_handlers(struct pci_controller_info *p) } /* PSYCHO boot time probing and initialization. */ +static void psycho_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +static void psycho_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res, *root; + u32 reg; + int where, size, is_64bit; + + res = &pdev->resource[resource]; + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + is_64bit = 0; + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else { + root = &pbm->mem_space; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } + + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= IORESOURCE_ROM_ENABLE; + } + pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); +} + static void pbm_config_busmastering(struct pci_pbm_info *pbm) { u8 *addr; @@ -921,7 +968,28 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - pbm->pci_bus = pci_scan_one_pbm(pbm); + struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("PSYCHO: Critical allocation failure.\n"); + prom_halt(); + } + + /* All we care about is the PBM. */ + cookie->pbm = pbm; + + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, + p->pci_ops, + pbm); + pci_fixup_host_bridge_self(pbm->pci_bus); + pbm->pci_bus->self->sysdata = cookie; + + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); + pci_determine_66mhz_disposition(pbm, pbm->pci_bus); + pci_setup_busmastering(pbm, pbm->pci_bus); } static void psycho_scan_bus(struct pci_controller_info *p) @@ -941,7 +1009,7 @@ static void psycho_scan_bus(struct pci_controller_info *p) static void psycho_iommu_init(struct pci_controller_info *p) { - struct iommu *iommu = p->pbm_A.iommu; + struct pci_iommu *iommu = p->pbm_A.iommu; unsigned long i; u64 control; @@ -1026,6 +1094,19 @@ static void psycho_controller_hwinit(struct pci_controller_info *p) psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp); } +static void pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + + pbm->io_space.name = pbm->mem_space.name = name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); +} + static void psycho_pbm_strbuf_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a) @@ -1091,11 +1172,19 @@ static void psycho_pbm_init(struct pci_controller_info *p, unsigned int *busrange; struct property *prop; struct pci_pbm_info *pbm; + int len; - if (is_pbm_a) + if (is_pbm_a) { pbm = &p->pbm_A; - else + pbm->pci_first_slot = 1; + pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A; + pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A; + } else { pbm = &p->pbm_B; + pbm->pci_first_slot = 2; + pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B; + pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B; + } pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; pbm->chip_version = 0; @@ -1107,15 +1196,41 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (prop) pbm->chip_revision = *(int *) prop->value; + pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; + pbm->io_space.flags = IORESOURCE_IO; + pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; + pbm->mem_space.flags = IORESOURCE_MEM; + pbm->parent = p; pbm->prom_node = dp; pbm->name = dp->full_name; + pbm_register_toplevel_resources(p, pbm); + printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", pbm->name, pbm->chip_version, pbm->chip_revision); - pci_determine_mem_io_space(pbm); + prop = of_find_property(dp, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; + pbm->num_pbm_ranges = + (len / sizeof(struct linux_prom_pci_ranges)); + } else { + pbm->num_pbm_ranges = 0; + } + + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; + } else { + pbm->num_pbm_intmap = 0; + } prop = of_find_property(dp, "bus-range", NULL); busrange = prop->value; @@ -1131,7 +1246,7 @@ void psycho_init(struct device_node *dp, char *model_name) { struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; - struct iommu *iommu; + struct pci_iommu *iommu; struct property *prop; u32 upa_portid; int is_pbm_a; @@ -1154,7 +1269,7 @@ void psycho_init(struct device_node *dp, char *model_name) prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_halt(); } - iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) { prom_printf("PSYCHO: Fatal memory allocation error.\n"); prom_halt(); @@ -1167,7 +1282,10 @@ void psycho_init(struct device_node *dp, char *model_name) p->pbm_A.portid = upa_portid; p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; + p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; + p->base_address_update = psycho_base_address_update; + p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; prop = of_find_property(dp, "reg", NULL); diff --git a/trunk/arch/sparc64/kernel/pci_sabre.c b/trunk/arch/sparc64/kernel/pci_sabre.c index 397862fbd9e1..94bb681f2323 100644 --- a/trunk/arch/sparc64/kernel/pci_sabre.c +++ b/trunk/arch/sparc64/kernel/pci_sabre.c @@ -1,6 +1,7 @@ -/* pci_sabre.c: Sabre specific PCI controller support. +/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $ + * pci_sabre.c: Sabre specific PCI controller support. * - * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ @@ -253,6 +254,9 @@ static int __sabre_out_of_range(struct pci_pbm_info *pbm, return 0; return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8) || ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8)); @@ -318,12 +322,6 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - struct pci_pbm_info *pbm = bus->sysdata; - - if (bus == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus, devfn, where, - size, value); - if (!bus->number && sabre_out_of_range(devfn)) { switch (size) { case 1: @@ -440,12 +438,6 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - struct pci_pbm_info *pbm = bus->sysdata; - - if (bus == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus, devfn, where, - size, value); - if (bus->number) return __sabre_write_pci_cfg(bus, devfn, where, size, value); @@ -498,7 +490,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p, unsigned long afsr, unsigned long afar) { - struct iommu *iommu = p->pbm_A.iommu; + struct pci_iommu *iommu = p->pbm_A.iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -718,8 +710,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p) p->index); ret = IRQ_HANDLED; } - pci_bus_read_config_word(sabre_root_bus, 0, - PCI_STATUS, &stat); + pci_read_config_word(sabre_root_bus->self, + PCI_STATUS, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | @@ -727,8 +719,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p) PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n", p->index, stat); - pci_bus_write_config_word(sabre_root_bus, 0, - PCI_STATUS, 0xffff); + pci_write_config_word(sabre_root_bus->self, + PCI_STATUS, 0xffff); ret = IRQ_HANDLED; } return ret; @@ -808,10 +800,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { sabre_check_iommu_error(p, afsr, afar); pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus); } - if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) + if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) { pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus); - + pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus); + } /* For excessive retries, SABRE/PBM will abort the device * and there is no way to specifically check for excessive * retries in the config space status registers. So what @@ -819,8 +813,10 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id) * abort events. */ - if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) + if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) { pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus); + } return IRQ_HANDLED; } @@ -873,52 +869,144 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) sabre_write(base + SABRE_PCICTRL, tmp); } +static void sabre_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + struct pci_pbm_info *pbm = pdev->bus->sysdata; + unsigned long base; + + if (res->flags & IORESOURCE_IO) + base = pbm->controller_regs + SABRE_IOSPACE; + else + base = pbm->controller_regs + SABRE_MEMSPACE; + + res->start += base; + res->end += base; +} + +static void sabre_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res; + unsigned long base; + u32 reg; + int where, size, is_64bit; + + res = &pdev->resource[resource]; + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + is_64bit = 0; + if (res->flags & IORESOURCE_IO) + base = pbm->controller_regs + SABRE_IOSPACE; + else { + base = pbm->controller_regs + SABRE_MEMSPACE; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } + + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - base)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= IORESOURCE_ROM_ENABLE; + } + pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); +} + static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { struct pci_dev *pdev; list_for_each_entry(pdev, &sabre_bus->devices, bus_list) { + if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { + u32 word32; u16 word16; - pci_read_config_word(pdev, PCI_COMMAND, &word16); + sabre_read_pci_cfg(pdev->bus, pdev->devfn, + PCI_COMMAND, 2, &word32); + word16 = (u16) word32; word16 |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, word16); + word32 = (u32) word16; + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_COMMAND, 2, word32); /* Status register bits are "write 1 to clear". */ - pci_write_config_word(pdev, PCI_STATUS, 0xffff); - pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_STATUS, 2, 0xffff); + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_SEC_STATUS, 2, 0xffff); /* Use a primary/seconday latency timer value * of 64. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_LATENCY_TIMER, 1, 64); + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_SEC_LATENCY_TIMER, 1, 64); /* Enable reporting/forwarding of master aborts, * parity, and SERR. */ - pci_write_config_byte(pdev, PCI_BRIDGE_CONTROL, - (PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_MASTER_ABORT)); + sabre_write_pci_cfg(pdev->bus, pdev->devfn, + PCI_BRIDGE_CONTROL, 1, + (PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_MASTER_ABORT)); } } } +static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) +{ + struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("SABRE: Critical allocation failure.\n"); + prom_halt(); + } + + /* All we care about is the PBM. */ + cookie->pbm = pbm; + + return cookie; +} + static void sabre_scan_bus(struct pci_controller_info *p) { static int once; - struct pci_bus *pbus; + struct pci_bus *sabre_bus, *pbus; + struct pci_pbm_info *pbm; + struct pcidev_cookie *cookie; + int sabres_scanned; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. */ p->pbm_A.is_66mhz_capable = 0; + p->pbm_B.is_66mhz_capable = 0; /* This driver has not been verified to handle * multiple SABREs yet, so trap this. @@ -932,13 +1020,56 @@ static void sabre_scan_bus(struct pci_controller_info *p) } once++; - pbus = pci_scan_one_pbm(&p->pbm_A); - if (!pbus) - return; + cookie = alloc_bridge_cookie(&p->pbm_A); + + sabre_bus = pci_scan_bus(p->pci_first_busno, + p->pci_ops, + &p->pbm_A); + pci_fixup_host_bridge_self(sabre_bus); + sabre_bus->self->sysdata = cookie; + + sabre_root_bus = sabre_bus; + + apb_init(p, sabre_bus); + + sabres_scanned = 0; + + list_for_each_entry(pbus, &sabre_bus->children, node) { + + if (pbus->number == p->pbm_A.pci_first_busno) { + pbm = &p->pbm_A; + } else if (pbus->number == p->pbm_B.pci_first_busno) { + pbm = &p->pbm_B; + } else + continue; - sabre_root_bus = pbus; + cookie = alloc_bridge_cookie(pbm); + pbus->self->sysdata = cookie; - apb_init(p, pbus); + sabres_scanned++; + + pbus->sysdata = pbm; + pbm->pci_bus = pbus; + pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbus); + pci_assign_unassigned(pbm, pbus); + pci_fixup_irq(pbm, pbus); + pci_determine_66mhz_disposition(pbm, pbus); + pci_setup_busmastering(pbm, pbus); + } + + if (!sabres_scanned) { + /* Hummingbird, no APBs. */ + pbm = &p->pbm_A; + sabre_bus->sysdata = pbm; + pbm->pci_bus = sabre_bus; + pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, sabre_bus); + pci_assign_unassigned(pbm, sabre_bus); + pci_fixup_irq(pbm, sabre_bus); + pci_determine_66mhz_disposition(pbm, sabre_bus); + pci_setup_busmastering(pbm, sabre_bus); + } sabre_register_error_handlers(p); } @@ -947,7 +1078,7 @@ static void sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset, u32 dma_mask) { - struct iommu *iommu = p->pbm_A.iommu; + struct pci_iommu *iommu = p->pbm_A.iommu; unsigned long i; u64 control; @@ -995,31 +1126,224 @@ static void sabre_iommu_init(struct pci_controller_info *p, sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); } -static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp) +static void pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE; + unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE; + unsigned int devfn; + unsigned long first, last, i; + u8 *addr, map; + + sprintf(name, "SABRE%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1); + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->io_space.start = ibase + (first << 21UL); + pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1); + pbm->io_space.flags = IORESOURCE_IO; + + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->mem_space.start = mbase + (first << 29UL); + pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1); + pbm->mem_space.flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, &pbm->io_space) < 0) { + prom_printf("Cannot register PBM-%c's IO space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } + if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { + prom_printf("Cannot register PBM-%c's MEM space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } + + /* Register legacy regions if this PBM covers that area. */ + if (pbm->io_space.start == ibase && + pbm->mem_space.start == mbase) + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); +} + +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) { struct pci_pbm_info *pbm; + struct device_node *node; + struct property *prop; + u32 *busrange; + int len, simbas_found; + + simbas_found = 0; + node = dp->child; + while (node != NULL) { + if (strcmp(node->name, "pci")) + goto next_pci; + + prop = of_find_property(node, "model", NULL); + if (!prop || strncmp(prop->value, "SUNW,simba", prop->length)) + goto next_pci; + + simbas_found++; + + prop = of_find_property(node, "bus-range", NULL); + busrange = prop->value; + if (busrange[0] == 1) + pbm = &p->pbm_B; + else + pbm = &p->pbm_A; + + pbm->name = node->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); + + pbm->chip_type = PBM_CHIP_TYPE_SABRE; + pbm->parent = p; + pbm->prom_node = node; + pbm->pci_first_slot = 1; + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + + prop = of_find_property(node, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; + pbm->num_pbm_ranges = + (len / sizeof(struct linux_prom_pci_ranges)); + } else { + pbm->num_pbm_ranges = 0; + } - pbm = &p->pbm_A; - pbm->name = dp->full_name; - printk("%s: SABRE PCI Bus Module\n", pbm->name); + prop = of_find_property(node, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(node, "interrupt-map-mask", + NULL); + pbm->pbm_intmask = prop->value; + } else { + pbm->num_pbm_intmap = 0; + } - pbm->chip_type = PBM_CHIP_TYPE_SABRE; - pbm->parent = p; - pbm->prom_node = dp; - pbm->pci_first_busno = p->pci_first_busno; - pbm->pci_last_busno = p->pci_last_busno; + pbm_register_toplevel_resources(p, pbm); + + next_pci: + node = node->sibling; + } + if (simbas_found == 0) { + struct resource *rp; - pci_determine_mem_io_space(pbm); + /* No APBs underneath, probably this is a hummingbird + * system. + */ + pbm = &p->pbm_A; + pbm->parent = p; + pbm->prom_node = dp; + pbm->pci_first_busno = p->pci_first_busno; + pbm->pci_last_busno = p->pci_last_busno; + + prop = of_find_property(dp, "ranges", &len); + if (prop) { + pbm->pbm_ranges = prop->value; + pbm->num_pbm_ranges = + (len / sizeof(struct linux_prom_pci_ranges)); + } else { + pbm->num_pbm_ranges = 0; + } + + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", + NULL); + pbm->pbm_intmask = prop->value; + } else { + pbm->num_pbm_intmap = 0; + } + + pbm->name = dp->full_name; + printk("%s: SABRE PCI Bus Module\n", pbm->name); + + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + /* Hack up top-level resources. */ + pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; + pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; + pbm->io_space.flags = IORESOURCE_IO; + + pbm->mem_space.start = + (p->pbm_A.controller_regs + SABRE_MEMSPACE); + pbm->mem_space.end = + (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); + pbm->mem_space.flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, &pbm->io_space) < 0) { + prom_printf("Cannot register Hummingbird's IO space.\n"); + prom_halt(); + } + if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { + prom_printf("Cannot register Hummingbird's MEM space.\n"); + prom_halt(); + } + + rp = kmalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) { + prom_printf("Cannot allocate IOMMU resource.\n"); + prom_halt(); + } + rp->name = "IOMMU"; + rp->start = pbm->mem_space.start + (unsigned long) dma_start; + rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; + rp->flags = IORESOURCE_BUSY; + request_resource(&pbm->mem_space, rp); + + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); + } } void sabre_init(struct device_node *dp, char *model_name) { - const struct linux_prom64_registers *pr_regs; + struct linux_prom64_registers *pr_regs; struct pci_controller_info *p; - struct iommu *iommu; + struct pci_iommu *iommu; + struct property *prop; int tsbsize; - const u32 *busrange; - const u32 *vdma; + u32 *busrange; + u32 *vdma; u32 upa_portid, dma_mask; u64 clear_irq; @@ -1027,9 +1351,13 @@ void sabre_init(struct device_node *dp, char *model_name) if (!strcmp(model_name, "pci108e,a001")) hummingbird_p = 1; else if (!strcmp(model_name, "SUNW,sabre")) { - const char *compat = of_get_property(dp, "compatible", NULL); - if (compat && !strcmp(compat, "pci108e,a001")) - hummingbird_p = 1; + prop = of_find_property(dp, "compatible", NULL); + if (prop) { + const char *compat = prop->value; + + if (!strcmp(compat, "pci108e,a001")) + hummingbird_p = 1; + } if (!hummingbird_p) { struct device_node *dp; @@ -1053,28 +1381,37 @@ void sabre_init(struct device_node *dp, char *model_name) prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); prom_halt(); } - p->pbm_A.iommu = iommu; + p->pbm_A.iommu = p->pbm_B.iommu = iommu; - upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); + upa_portid = 0xff; + prop = of_find_property(dp, "upa-portid", NULL); + if (prop) + upa_portid = *(u32 *) prop->value; p->next = pci_controller_root; pci_controller_root = p; p->pbm_A.portid = upa_portid; + p->pbm_B.portid = upa_portid; p->index = pci_num_controllers++; + p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; + p->base_address_update = sabre_base_address_update; + p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; /* * Map in SABRE register set and report the presence of this SABRE. */ - pr_regs = of_get_property(dp, "reg", NULL); + prop = of_find_property(dp, "reg", NULL); + pr_regs = prop->value; /* * First REG in property is base of entire SABRE register space. */ p->pbm_A.controller_regs = pr_regs[0].phys_addr; + p->pbm_B.controller_regs = pr_regs[0].phys_addr; /* Clear interrupts */ @@ -1092,10 +1429,11 @@ void sabre_init(struct device_node *dp, char *model_name) SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ - p->pbm_A.config_space = + p->pbm_A.config_space = p->pbm_B.config_space = (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); - vdma = of_get_property(dp, "virtual-dma", NULL); + prop = of_find_property(dp, "virtual-dma", NULL); + vdma = prop->value; dma_mask = vdma[0]; switch(vdma[1]) { @@ -1119,12 +1457,13 @@ void sabre_init(struct device_node *dp, char *model_name) sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); - busrange = of_get_property(dp, "bus-range", NULL); + prop = of_find_property(dp, "bus-range", NULL); + busrange = prop->value; p->pci_first_busno = busrange[0]; p->pci_last_busno = busrange[1]; /* * Look for APB underneath. */ - sabre_pbm_init(p, dp); + sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]); } diff --git a/trunk/arch/sparc64/kernel/pci_schizo.c b/trunk/arch/sparc64/kernel/pci_schizo.c index 91a7385e5d32..66911b126aed 100644 --- a/trunk/arch/sparc64/kernel/pci_schizo.c +++ b/trunk/arch/sparc64/kernel/pci_schizo.c @@ -1,6 +1,7 @@ -/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. +/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $ + * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * - * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com) */ #include @@ -125,9 +126,6 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); switch (size) { case 1: *value = 0xff; @@ -181,9 +179,6 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; @@ -279,7 +274,7 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct strbuf *strbuf = &pbm->stc; + struct pci_strbuf *strbuf = &pbm->stc; unsigned long regbase = pbm->pbm_regs; unsigned long err_base, tag_base, line_base; u64 control; @@ -387,7 +382,7 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type) { - struct iommu *iommu = pbm->iommu; + struct pci_iommu *iommu = pbm->iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; @@ -1234,8 +1229,42 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) pci_config_write8(addr, 64); } -static void schizo_scan_bus(struct pci_controller_info *p) +static void pbm_scan_bus(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("%s: Critical allocation failure.\n", pbm->name); + prom_halt(); + } + + /* All we care about is the PBM. */ + cookie->pbm = pbm; + + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, + p->pci_ops, + pbm); + pci_fixup_host_bridge_self(pbm->pci_bus); + pbm->pci_bus->self->sysdata = cookie; + + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); + pci_determine_66mhz_disposition(pbm, pbm->pci_bus); + pci_setup_busmastering(pbm, pbm->pci_bus); +} + +static void __schizo_scan_bus(struct pci_controller_info *p, + int chip_type) { + if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) { + printk("PCI: Only one PCI bus module of controller found.\n"); + printk("PCI: Ignoring entire controller.\n"); + return; + } + pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL) @@ -1244,19 +1273,154 @@ static void schizo_scan_bus(struct pci_controller_info *p) p->pbm_A.is_66mhz_capable = (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL) != NULL); - - p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B); - p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A); + pbm_scan_bus(p, &p->pbm_B); + pbm_scan_bus(p, &p->pbm_A); /* After the PCI bus scan is complete, we can register * the error interrupt handlers. */ - if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO) + if (chip_type == PBM_CHIP_TYPE_TOMATILLO) tomatillo_register_error_handlers(p); else schizo_register_error_handlers(p); } +static void schizo_scan_bus(struct pci_controller_info *p) +{ + __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO); +} + +static void tomatillo_scan_bus(struct pci_controller_info *p) +{ + __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO); +} + +static void schizo_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res, *root; + u32 reg; + int where, size, is_64bit; + + res = &pdev->resource[resource]; + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + is_64bit = 0; + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else { + root = &pbm->mem_space; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } + + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= IORESOURCE_ROM_ENABLE; + } + pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); +} + +static void schizo_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +/* Use ranges property to determine where PCI MEM, I/O, and Config + * space are for this PCI bus module. + */ +static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm) +{ + int i, saw_cfg, saw_mem, saw_io; + + saw_cfg = saw_mem = saw_io = 0; + for (i = 0; i < pbm->num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + unsigned long a; + int type; + + type = (pr->child_phys_hi >> 24) & 0x3; + a = (((unsigned long)pr->parent_phys_hi << 32UL) | + ((unsigned long)pr->parent_phys_lo << 0UL)); + + switch (type) { + case 0: + /* PCI config space, 16MB */ + pbm->config_space = a; + saw_cfg = 1; + break; + + case 1: + /* 16-bit IO space, 16MB */ + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; + saw_io = 1; + break; + + case 2: + /* 32-bit MEM space, 2GB */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + saw_mem = 1; + break; + + default: + break; + }; + } + + if (!saw_cfg || !saw_io || !saw_mem) { + prom_printf("%s: Fatal error, missing %s PBM range.\n", + pbm->name, + ((!saw_cfg ? + "CFG" : + (!saw_io ? + "IO" : "MEM")))); + prom_halt(); + } + + printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", + pbm->name, + pbm->config_space, + pbm->io_space.start, + pbm->mem_space.start); +} + +static void pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); +} + #define SCHIZO_STRBUF_CONTROL (0x02800UL) #define SCHIZO_STRBUF_FLUSH (0x02808UL) #define SCHIZO_STRBUF_FSYNC (0x02810UL) @@ -1308,7 +1472,7 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { - struct iommu *iommu = pbm->iommu; + struct pci_iommu *iommu = pbm->iommu; unsigned long i, tagbase, database; struct property *prop; u32 vdma[2], dma_mask; @@ -1490,12 +1654,14 @@ static void schizo_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 portid, int chip_type) { - const struct linux_prom64_registers *regs; - const unsigned int *busrange; + struct linux_prom64_registers *regs; + struct property *prop; + unsigned int *busrange; struct pci_pbm_info *pbm; const char *chipset_name; - const u32 *ino_bitmap; + u32 *ino_bitmap; int is_pbm_a; + int len; switch (chip_type) { case PBM_CHIP_TYPE_TOMATILLO: @@ -1523,9 +1689,11 @@ static void schizo_pbm_init(struct pci_controller_info *p, * 3) PBM PCI config space * 4) Ichip regs */ - regs = of_get_property(dp, "reg", NULL); + prop = of_find_property(dp, "reg", NULL); + regs = prop->value; is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); + if (is_pbm_a) pbm = &p->pbm_A; else @@ -1534,10 +1702,17 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->portid = portid; pbm->parent = p; pbm->prom_node = dp; + pbm->pci_first_slot = 1; pbm->chip_type = chip_type; - pbm->chip_version = of_getintprop_default(dp, "version#", 0); - pbm->chip_revision = of_getintprop_default(dp, "module-version#", 0); + pbm->chip_version = 0; + prop = of_find_property(dp, "version#", NULL); + if (prop) + pbm->chip_version = *(int *) prop->value; + pbm->chip_revision = 0; + prop = of_find_property(dp, "module-revision#", NULL); + if (prop) + pbm->chip_revision = *(int *) prop->value; pbm->pbm_regs = regs[0].phys_addr; pbm->controller_regs = regs[1].phys_addr - 0x10000UL; @@ -1548,18 +1723,40 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->name = dp->full_name; printk("%s: %s PCI Bus Module ver[%x:%x]\n", - pbm->name, chipset_name, + pbm->name, + (chip_type == PBM_CHIP_TYPE_TOMATILLO ? + "TOMATILLO" : "SCHIZO"), pbm->chip_version, pbm->chip_revision); schizo_pbm_hw_init(pbm); - pci_determine_mem_io_space(pbm); + prop = of_find_property(dp, "ranges", &len); + pbm->pbm_ranges = prop->value; + pbm->num_pbm_ranges = + (len / sizeof(struct linux_prom_pci_ranges)); - ino_bitmap = of_get_property(dp, "ino-bitmap", NULL); + schizo_determine_mem_io_space(pbm); + pbm_register_toplevel_resources(p, pbm); + + prop = of_find_property(dp, "interrupt-map", &len); + if (prop) { + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; + } else { + pbm->num_pbm_intmap = 0; + } + + prop = of_find_property(dp, "ino-bitmap", NULL); + ino_bitmap = prop->value; pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | ((u64)ino_bitmap[0] << 0UL)); - busrange = of_get_property(dp, "bus-range", NULL); + prop = of_find_property(dp, "bus-range", NULL); + busrange = prop->value; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; @@ -1580,10 +1777,15 @@ static inline int portid_compare(u32 x, u32 y, int chip_type) static void __schizo_init(struct device_node *dp, char *model_name, int chip_type) { struct pci_controller_info *p; - struct iommu *iommu; + struct pci_iommu *iommu; + struct property *prop; + int is_pbm_a; u32 portid; - portid = of_getintprop_default(dp, "portid", 0xff); + portid = 0xff; + prop = of_find_property(dp, "portid", NULL); + if (prop) + portid = *(u32 *) prop->value; for (p = pci_controller_root; p; p = p->next) { struct pci_pbm_info *pbm; @@ -1596,43 +1798,48 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ &p->pbm_B); if (portid_compare(pbm->portid, portid, chip_type)) { + is_pbm_a = (p->pbm_A.prom_node == NULL); schizo_pbm_init(p, dp, portid, chip_type); return; } } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); - if (!p) - goto memfail; - - iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); - if (!iommu) - goto memfail; + if (!p) { + prom_printf("SCHIZO: Fatal memory allocation error.\n"); + prom_halt(); + } + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + if (!iommu) { + prom_printf("SCHIZO: Fatal memory allocation error.\n"); + prom_halt(); + } p->pbm_A.iommu = iommu; - iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); - if (!iommu) - goto memfail; - + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + if (!iommu) { + prom_printf("SCHIZO: Fatal memory allocation error.\n"); + prom_halt(); + } p->pbm_B.iommu = iommu; p->next = pci_controller_root; pci_controller_root = p; p->index = pci_num_controllers++; - p->scan_bus = schizo_scan_bus; + p->pbms_same_domain = 0; + p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? + tomatillo_scan_bus : + schizo_scan_bus); + p->base_address_update = schizo_base_address_update; + p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; /* Like PSYCHO we have a 2GB aligned area for memory space. */ pci_memspace_mask = 0x7fffffffUL; schizo_pbm_init(p, dp, portid, chip_type); - return; - -memfail: - prom_printf("SCHIZO: Fatal memory allocation error.\n"); - prom_halt(); } void schizo_init(struct device_node *dp, char *model_name) diff --git a/trunk/arch/sparc64/kernel/pci_sun4v.c b/trunk/arch/sparc64/kernel/pci_sun4v.c index 1ccf4c9a9a43..ec22cd61ec8c 100644 --- a/trunk/arch/sparc64/kernel/pci_sun4v.c +++ b/trunk/arch/sparc64/kernel/pci_sun4v.c @@ -1,6 +1,6 @@ /* pci_sun4v.c: SUN4V specific PCI controller support. * - * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 2006 David S. Miller (davem@davemloft.net) */ #include @@ -29,7 +29,7 @@ #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) -struct iommu_batch { +struct pci_iommu_batch { struct pci_dev *pdev; /* Device mapping is for. */ unsigned long prot; /* IOMMU page protections */ unsigned long entry; /* Index into IOTSB. */ @@ -37,12 +37,12 @@ struct iommu_batch { unsigned long npages; /* Number of pages in list. */ }; -static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch); +static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch); /* Interrupts must be disabled. */ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); p->pdev = pdev; p->prot = prot; @@ -51,10 +51,10 @@ static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long pro } /* Interrupts must be disabled. */ -static long pci_iommu_batch_flush(struct iommu_batch *p) +static long pci_iommu_batch_flush(struct pci_iommu_batch *p) { - struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller; - unsigned long devhandle = pbm->devhandle; + struct pcidev_cookie *pcp = p->pdev->sysdata; + unsigned long devhandle = pcp->pbm->devhandle; unsigned long prot = p->prot; unsigned long entry = p->entry; u64 *pglist = p->pglist; @@ -89,7 +89,7 @@ static long pci_iommu_batch_flush(struct iommu_batch *p) /* Interrupts must be disabled. */ static inline long pci_iommu_batch_add(u64 phys_page) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); @@ -103,14 +103,14 @@ static inline long pci_iommu_batch_add(u64 phys_page) /* Interrupts must be disabled. */ static inline long pci_iommu_batch_end(void) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); return pci_iommu_batch_flush(p); } -static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages) +static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages) { unsigned long n, i, start, end, limit; int pass; @@ -149,7 +149,7 @@ static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages) return n; } -static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; @@ -159,7 +159,8 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, order, first_page, npages, n; void *ret; long entry; @@ -177,7 +178,8 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr memset((char *)first_page, 0, PAGE_SIZE << order); - iommu = pdev->dev.archdata.iommu; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; spin_lock_irqsave(&iommu->lock, flags); entry = pci_arena_alloc(&iommu->arena, npages); @@ -224,15 +226,15 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) { - struct pci_pbm_info *pbm; - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, order, npages, entry; u32 devhandle; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; - devhandle = pbm->devhandle; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + devhandle = pcp->pbm->devhandle; entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); @@ -257,14 +259,16 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, npages, oaddr; unsigned long i, base_paddr; u32 bus_addr, ret; unsigned long prot; long entry; - iommu = pdev->dev.archdata.iommu; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; if (unlikely(direction == PCI_DMA_NONE)) goto bad; @@ -320,8 +324,8 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct pci_pbm_info *pbm; - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, npages; long entry; u32 devhandle; @@ -332,9 +336,9 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ return; } - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; - devhandle = pbm->devhandle; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + devhandle = pcp->pbm->devhandle; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -456,7 +460,8 @@ static inline long fill_sg(long entry, struct pci_dev *pdev, static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, npages, prot; u32 dma_base; struct scatterlist *sgtmp; @@ -475,7 +480,8 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n return 1; } - iommu = pdev->dev.archdata.iommu; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; if (unlikely(direction == PCI_DMA_NONE)) goto bad; @@ -531,8 +537,8 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { - struct pci_pbm_info *pbm; - struct iommu *iommu; + struct pcidev_cookie *pcp; + struct pci_iommu *iommu; unsigned long flags, i, npages; long entry; u32 devhandle, bus_addr; @@ -542,9 +548,9 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in WARN_ON(1); } - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; - devhandle = pbm->devhandle; + pcp = pdev->sysdata; + iommu = pcp->pbm->iommu; + devhandle = pcp->pbm->devhandle; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -583,7 +589,7 @@ static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist /* Nothing to do... */ } -const struct pci_iommu_ops pci_sun4v_iommu_ops = { +struct pci_iommu_ops pci_sun4v_iommu_ops = { .alloc_consistent = pci_4v_alloc_consistent, .free_consistent = pci_4v_free_consistent, .map_single = pci_4v_map_single, @@ -594,12 +600,132 @@ const struct pci_iommu_ops pci_sun4v_iommu_ops = { .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, }; +/* SUN4V PCI configuration space accessors. */ + +struct pdev_entry { + struct pdev_entry *next; + u32 devhandle; + unsigned int bus; + unsigned int device; + unsigned int func; +}; + +#define PDEV_HTAB_SIZE 16 +#define PDEV_HTAB_MASK (PDEV_HTAB_SIZE - 1) +static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE]; + +static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) +{ + unsigned int val; + + val = (devhandle ^ (devhandle >> 4)); + val ^= bus; + val ^= device; + val ^= func; + + return val & PDEV_HTAB_MASK; +} + +static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) +{ + struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL); + struct pdev_entry **slot; + + if (!p) + return -ENOMEM; + + slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; + p->next = *slot; + *slot = p; + + p->devhandle = devhandle; + p->bus = bus; + p->device = device; + p->func = func; + + return 0; +} + +/* Recursively descend into the OBP device tree, rooted at toplevel_node, + * looking for a PCI device matching bus and devfn. + */ +static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) +{ + toplevel_node = toplevel_node->child; + + while (toplevel_node != NULL) { + struct linux_prom_pci_registers *regs; + struct property *prop; + int ret; + + ret = obp_find(toplevel_node, bus, devfn); + if (ret != 0) + return ret; + + prop = of_find_property(toplevel_node, "reg", NULL); + if (!prop) + goto next_sibling; + + regs = prop->value; + if (((regs->phys_hi >> 16) & 0xff) == bus && + ((regs->phys_hi >> 8) & 0xff) == devfn) + break; + + next_sibling: + toplevel_node = toplevel_node->sibling; + } + + return toplevel_node != NULL; +} + +static int pdev_htab_populate(struct pci_pbm_info *pbm) +{ + u32 devhandle = pbm->devhandle; + unsigned int bus; + + for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) { + unsigned int devfn; + + for (devfn = 0; devfn < 256; devfn++) { + unsigned int device = PCI_SLOT(devfn); + unsigned int func = PCI_FUNC(devfn); + + if (obp_find(pbm->prom_node, bus, devfn)) { + int err = pdev_htab_add(devhandle, bus, + device, func); + if (err) + return err; + } + } + } + + return 0; +} + +static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) +{ + struct pdev_entry *p; + + p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; + while (p) { + if (p->devhandle == devhandle && + p->bus == bus && + p->device == device && + p->func == func) + break; + + p = p->next; + } + + return p; +} + static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) { if (bus < pbm->pci_first_busno || bus > pbm->pci_last_busno) return 1; - return 0; + return pdev_find(pbm->devhandle, bus, device, func) == NULL; } static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, @@ -612,9 +738,6 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { ret = ~0UL; } else { @@ -653,9 +776,6 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { /* Do nothing. */ } else { @@ -680,7 +800,27 @@ static struct pci_ops pci_sun4v_ops = { static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - pbm->pci_bus = pci_scan_one_pbm(pbm); + struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + + if (!cookie) { + prom_printf("%s: Critical allocation failure.\n", pbm->name); + prom_halt(); + } + + /* All we care about is the PBM. */ + cookie->pbm = pbm; + + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); +#if 0 + pci_fixup_host_bridge_self(pbm->pci_bus); + pbm->pci_bus->self->sysdata = cookie; +#endif + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); + pci_determine_66mhz_disposition(pbm, pbm->pci_bus); + pci_setup_busmastering(pbm, pbm->pci_bus); } static void pci_sun4v_scan_bus(struct pci_controller_info *p) @@ -704,10 +844,130 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } +static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res, *root; + u32 reg; + int where, size, is_64bit; + + res = &pdev->resource[resource]; + if (resource < 6) { + where = PCI_BASE_ADDRESS_0 + (resource * 4); + } else if (resource == PCI_ROM_RESOURCE) { + where = pdev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + /* XXX 64-bit MEM handling is not %100 correct... XXX */ + is_64bit = 0; + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else { + root = &pbm->mem_space; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } + + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + if (resource == PCI_ROM_RESOURCE) { + reg |= PCI_ROM_ADDRESS_ENABLE; + res->flags |= IORESOURCE_ROM_ENABLE; + } + pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); +} + +static void pci_sun4v_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +/* Use ranges property to determine where PCI MEM, I/O, and Config + * space are for this PCI bus module. + */ +static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm) +{ + int i, saw_mem, saw_io; + + saw_mem = saw_io = 0; + for (i = 0; i < pbm->num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + unsigned long a; + int type; + + type = (pr->child_phys_hi >> 24) & 0x3; + a = (((unsigned long)pr->parent_phys_hi << 32UL) | + ((unsigned long)pr->parent_phys_lo << 0UL)); + + switch (type) { + case 1: + /* 16-bit IO space, 16MB */ + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; + saw_io = 1; + break; + + case 2: + /* 32-bit MEM space, 2GB */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + saw_mem = 1; + break; + + case 3: + /* XXX 64-bit MEM handling XXX */ + + default: + break; + }; + } + + if (!saw_io || !saw_mem) { + prom_printf("%s: Fatal error, missing %s PBM range.\n", + pbm->name, + (!saw_io ? "IO" : "MEM")); + prom_halt(); + } + + printk("%s: PCI IO[%lx] MEM[%lx]\n", + pbm->name, + pbm->io_space.start, + pbm->mem_space.start); +} + +static void pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); +} + static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, - struct iommu *iommu) + struct pci_iommu *iommu) { - struct iommu_arena *arena = &iommu->arena; + struct pci_iommu_arena *arena = &iommu->arena; unsigned long i, cnt = 0; u32 devhandle; @@ -734,7 +994,7 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { - struct iommu *iommu = pbm->iommu; + struct pci_iommu *iommu = pbm->iommu; struct property *prop; unsigned long num_tsb_entries, sz; u32 vdma[2], dma_mask, dma_offset; @@ -1021,7 +1281,7 @@ static int msi_queue_alloc(struct pci_pbm_info *pbm) static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) { - const u32 *val; + u32 *val; int len; val = of_get_property(pbm->prom_node, "#msi-eqs", &len); @@ -1029,16 +1289,16 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) goto no_msi; pbm->msiq_num = *val; if (pbm->msiq_num) { - const struct msiq_prop { + struct msiq_prop { u32 first_msiq; u32 num_msiq; u32 first_devino; } *mqp; - const struct msi_range_prop { + struct msi_range_prop { u32 first_msi; u32 num_msi; } *mrng; - const struct addr_range_prop { + struct addr_range_prop { u32 msi32_high; u32 msi32_low; u32 msi32_len; @@ -1150,7 +1410,8 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, struct pci_dev *pdev, struct msi_desc *entry) { - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; unsigned long devino, msiqid; struct msi_msg msg; int msi_num, err; @@ -1169,6 +1430,8 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, if (!devino) goto out_err; + set_irq_msi(*virt_irq_p, entry); + msiqid = ((devino - pbm->msiq_first_devino) + pbm->msiq_first); @@ -1192,7 +1455,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID)) goto out_err; - pdev->dev.archdata.msi_num = msi_num; + pcp->msi_num = msi_num; if (entry->msi_attrib.is_64) { msg.address_hi = pbm->msi64_start >> 32; @@ -1202,8 +1465,6 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, msg.address_lo = pbm->msi32_start; } msg.data = msi_num; - - set_irq_msi(*virt_irq_p, entry); write_msi_msg(*virt_irq_p, &msg); irq_install_pre_handler(*virt_irq_p, @@ -1223,11 +1484,12 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq, struct pci_dev *pdev) { - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; unsigned long msiqid, err; unsigned int msi_num; - msi_num = pdev->dev.archdata.msi_num; + msi_num = pcp->msi_num; err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid); if (err) { printk(KERN_ERR "%s: getmsiq gives error %lu\n", @@ -1254,6 +1516,8 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) { struct pci_pbm_info *pbm; + struct property *prop; + int len, i; if (devhandle & 0x40) pbm = &p->pbm_B; @@ -1262,6 +1526,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pbm->parent = p; pbm->prom_node = dp; + pbm->pci_first_slot = 1; pbm->devhandle = devhandle; @@ -1269,17 +1534,39 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node printk("%s: SUN4V PCI Bus Module\n", pbm->name); - pci_determine_mem_io_space(pbm); + prop = of_find_property(dp, "ranges", &len); + pbm->pbm_ranges = prop->value; + pbm->num_pbm_ranges = + (len / sizeof(struct linux_prom_pci_ranges)); + + /* Mask out the top 8 bits of the ranges, leaving the real + * physical address. + */ + for (i = 0; i < pbm->num_pbm_ranges; i++) + pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; + + pci_sun4v_determine_mem_io_space(pbm); + pbm_register_toplevel_resources(p, pbm); + + prop = of_find_property(dp, "interrupt-map", &len); + pbm->pbm_intmap = prop->value; + pbm->num_pbm_intmap = + (len / sizeof(struct linux_prom_pci_intmap)); + + prop = of_find_property(dp, "interrupt-map-mask", NULL); + pbm->pbm_intmask = prop->value; pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); pci_sun4v_msi_init(pbm); + + pdev_htab_populate(pbm); } void sun4v_pci_init(struct device_node *dp, char *model_name) { struct pci_controller_info *p; - struct iommu *iommu; + struct pci_iommu *iommu; struct property *prop; struct linux_prom64_registers *regs; u32 devhandle; @@ -1319,13 +1606,13 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) if (!p) goto fatal_memory_error; - iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; p->pbm_A.iommu = iommu; - iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; @@ -1335,8 +1622,11 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) pci_controller_root = p; p->index = pci_num_controllers++; + p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; + p->base_address_update = pci_sun4v_base_address_update; + p->resource_adjust = pci_sun4v_resource_adjust; #ifdef CONFIG_PCI_MSI p->setup_msi_irq = pci_sun4v_setup_msi_irq; p->teardown_msi_irq = pci_sun4v_teardown_msi_irq; diff --git a/trunk/arch/sparc64/kernel/process.c b/trunk/arch/sparc64/kernel/process.c index a114151f9fbe..b291060c25a6 100644 --- a/trunk/arch/sparc64/kernel/process.c +++ b/trunk/arch/sparc64/kernel/process.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -89,14 +88,12 @@ void cpu_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while(1) { - tick_nohz_stop_sched_tick(); - while (!need_resched()) - sparc64_yield(); - tick_nohz_restart_sched_tick(); - - preempt_enable_no_resched(); - schedule(); - preempt_disable(); + if (need_resched()) { + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } + sparc64_yield(); } } diff --git a/trunk/arch/sparc64/kernel/prom.c b/trunk/arch/sparc64/kernel/prom.c index 5e1fcd05160d..0917c24c4f08 100644 --- a/trunk/arch/sparc64/kernel/prom.c +++ b/trunk/arch/sparc64/kernel/prom.c @@ -36,13 +36,12 @@ static struct device_node *allnodes; */ static DEFINE_RWLOCK(devtree_lock); -int of_device_is_compatible(const struct device_node *device, - const char *compat) +int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; int cplen, l; - cp = of_get_property(device, "compatible", &cplen); + cp = (char *) of_get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { @@ -155,14 +154,13 @@ struct device_node *of_find_compatible_node(struct device_node *from, } EXPORT_SYMBOL(of_find_compatible_node); -struct property *of_find_property(const struct device_node *np, - const char *name, +struct property *of_find_property(struct device_node *np, const char *name, int *lenp) { struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { - if (strcasecmp(pp->name, name) == 0) { + if (strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; break; @@ -176,8 +174,7 @@ EXPORT_SYMBOL(of_find_property); * Find a property with a given name for a given node * and return the value. */ -const void *of_get_property(const struct device_node *np, const char *name, - int *lenp) +void *of_get_property(struct device_node *np, const char *name, int *lenp) { struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL; @@ -199,7 +196,7 @@ EXPORT_SYMBOL(of_getintprop_default); int of_n_addr_cells(struct device_node *np) { - const int* ip; + int* ip; do { if (np->parent) np = np->parent; @@ -214,7 +211,7 @@ EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np) { - const int* ip; + int* ip; do { if (np->parent) np = np->parent; @@ -246,7 +243,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len while (*prevp) { struct property *prop = *prevp; - if (!strcasecmp(prop->name, name)) { + if (!strcmp(prop->name, name)) { void *old_val = prop->value; int ret; @@ -400,7 +397,7 @@ static unsigned int psycho_irq_build(struct device_node *dp, static void psycho_irq_trans_init(struct device_node *dp) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = psycho_irq_build; @@ -550,7 +547,7 @@ static unsigned long __sabre_onboard_imap_off[] = { static int sabre_device_needs_wsync(struct device_node *dp) { struct device_node *parent = dp->parent; - const char *parent_model, *parent_compat; + char *parent_model, *parent_compat; /* This traversal up towards the root is meant to * handle two cases: @@ -592,7 +589,7 @@ static unsigned int sabre_irq_build(struct device_node *dp, { struct sabre_irq_data *irq_data = _data; unsigned long controller_regs = irq_data->controller_regs; - const struct linux_prom_pci_registers *regs; + struct linux_prom_pci_registers *regs; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; @@ -642,9 +639,9 @@ static unsigned int sabre_irq_build(struct device_node *dp, static void sabre_irq_trans_init(struct device_node *dp) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; struct sabre_irq_data *irq_data; - const u32 *busrange; + u32 *busrange; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sabre_irq_build; @@ -798,7 +795,7 @@ static unsigned int schizo_irq_build(struct device_node *dp, static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; struct schizo_irq_data *irq_data; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); @@ -839,7 +836,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp, static void pci_sun4v_irq_trans_init(struct device_node *dp) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = pci_sun4v_irq_build; @@ -943,7 +940,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, void *_data) { unsigned long reg_base = (unsigned long) _data; - const struct linux_prom_registers *regs; + struct linux_prom_registers *regs; unsigned long imap, iclr; int sbus_slot = 0; int sbus_level = 0; @@ -997,7 +994,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, static void sbus_irq_trans_init(struct device_node *dp) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sbus_of_build_irq; @@ -1083,7 +1080,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp, static void sun4v_vdev_irq_trans_init(struct device_node *dp) { - const struct linux_prom64_registers *regs; + struct linux_prom64_registers *regs; dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = sun4v_vdev_irq_build; diff --git a/trunk/arch/sparc64/kernel/sbus.c b/trunk/arch/sparc64/kernel/sbus.c index 3b05428cc909..14f78fb5e890 100644 --- a/trunk/arch/sparc64/kernel/sbus.c +++ b/trunk/arch/sparc64/kernel/sbus.c @@ -26,9 +26,23 @@ #define MAP_BASE ((u32)0xc0000000) -struct sbus_info { - struct iommu iommu; - struct strbuf strbuf; +struct sbus_iommu_arena { + unsigned long *map; + unsigned int hint; + unsigned int limit; +}; + +struct sbus_iommu { + spinlock_t lock; + + struct sbus_iommu_arena arena; + + iopte_t *page_table; + unsigned long strbuf_regs; + unsigned long iommu_regs; + unsigned long sbus_control_reg; + + volatile unsigned long strbuf_flushflag; }; /* Offsets from iommu_regs */ @@ -44,17 +58,16 @@ struct sbus_info { #define IOMMU_DRAM_VALID (1UL << 30UL) -static void __iommu_flushall(struct iommu *iommu) +static void __iommu_flushall(struct sbus_iommu *iommu) { - unsigned long tag; + unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; int entry; - tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); for (entry = 0; entry < 16; entry++) { upa_writeq(0, tag); tag += 8UL; } - upa_readq(iommu->write_complete_reg); + upa_readq(iommu->sbus_control_reg); } /* Offsets from strbuf_regs */ @@ -69,14 +82,15 @@ static void __iommu_flushall(struct iommu *iommu) #define STRBUF_TAG_VALID 0x02UL -static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction) +static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction) { unsigned long n; int limit; n = npages; while (n--) - upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush); + upa_writeq(base + (n << IO_PAGE_SHIFT), + iommu->strbuf_regs + STRBUF_PFLUSH); /* If the device could not have possibly put dirty data into * the streaming cache, no flush-flag synchronization needs @@ -85,14 +99,15 @@ static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 ba if (direction == SBUS_DMA_TODEVICE) return; - *(strbuf->strbuf_flushflag) = 0UL; + iommu->strbuf_flushflag = 0UL; /* Whoopee cushion! */ - upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync); - upa_readq(iommu->write_complete_reg); + upa_writeq(__pa(&iommu->strbuf_flushflag), + iommu->strbuf_regs + STRBUF_FSYNC); + upa_readq(iommu->sbus_control_reg); limit = 100000; - while (*(strbuf->strbuf_flushflag) == 0UL) { + while (iommu->strbuf_flushflag == 0UL) { limit--; if (!limit) break; @@ -106,9 +121,9 @@ static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 ba } /* Based largely upon the ppc64 iommu allocator. */ -static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages) +static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages) { - struct iommu_arena *arena = &iommu->arena; + struct sbus_iommu_arena *arena = &iommu->arena; unsigned long n, i, start, end, limit; int pass; @@ -147,7 +162,7 @@ static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages) return n; } -static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages) { unsigned long i; @@ -155,7 +170,7 @@ static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsig __clear_bit(i, arena->map); } -static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize) +static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize) { unsigned long tsbbase, order, sz, num_tsb_entries; @@ -163,14 +178,13 @@ static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize) /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); - iommu->page_table_map_base = MAP_BASE; /* Allocate and initialize the free area map. */ sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { - prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n"); + prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); prom_halt(); } iommu->arena.limit = num_tsb_entries; @@ -186,7 +200,7 @@ static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize) memset(iommu->page_table, 0, tsbsize); } -static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) +static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages) { long entry; @@ -197,15 +211,14 @@ static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) return iommu->page_table + entry; } -static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) +static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages) { sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); } void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr) { - struct sbus_info *info; - struct iommu *iommu; + struct sbus_iommu *iommu; iopte_t *iopte; unsigned long flags, order, first_page; void *ret; @@ -221,8 +234,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; memset((char *)first_page, 0, PAGE_SIZE << order); - info = sdev->bus->iommu; - iommu = &info->iommu; + iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); @@ -233,7 +245,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; } - *dvma_addr = (iommu->page_table_map_base + + *dvma_addr = (MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); ret = (void *) first_page; npages = size >> IO_PAGE_SHIFT; @@ -251,20 +263,18 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma) { - struct sbus_info *info; - struct iommu *iommu; + struct sbus_iommu *iommu; iopte_t *iopte; unsigned long flags, order, npages; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - info = sdev->bus->iommu; - iommu = &info->iommu; + iommu = sdev->bus->iommu; iopte = iommu->page_table + - ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + ((dvma - MAP_BASE) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - free_npages(iommu, dvma - iommu->page_table_map_base, npages); + free_npages(iommu, dvma - MAP_BASE, npages); spin_unlock_irqrestore(&iommu->lock, flags); @@ -275,16 +285,14 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction) { - struct sbus_info *info; - struct iommu *iommu; + struct sbus_iommu *iommu; iopte_t *base; unsigned long flags, npages, oaddr; unsigned long i, base_paddr; u32 bus_addr, ret; unsigned long iopte_protection; - info = sdev->bus->iommu; - iommu = &info->iommu; + iommu = sdev->bus->iommu; if (unlikely(direction == SBUS_DMA_NONE)) BUG(); @@ -300,7 +308,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire if (unlikely(!base)) BUG(); - bus_addr = (iommu->page_table_map_base + + bus_addr = (MAP_BASE + ((base - iommu->page_table) << IO_PAGE_SHIFT)); ret = bus_addr | (oaddr & ~IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK); @@ -317,9 +325,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct sbus_info *info = sdev->bus->iommu; - struct iommu *iommu = &info->iommu; - struct strbuf *strbuf = &info->strbuf; + struct sbus_iommu *iommu = sdev->bus->iommu; iopte_t *base; unsigned long flags, npages, i; @@ -329,15 +335,15 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, in npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT); bus_addr &= IO_PAGE_MASK; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, bus_addr, npages, direction); for (i = 0; i < npages; i++) iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + free_npages(iommu, bus_addr - MAP_BASE, npages); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -419,8 +425,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_info *info; - struct iommu *iommu; + struct sbus_iommu *iommu; unsigned long flags, npages, iopte_protection; iopte_t *base; u32 dma_base; @@ -437,8 +442,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i return 1; } - info = sdev->bus->iommu; - iommu = &info->iommu; + iommu = sdev->bus->iommu; if (unlikely(direction == SBUS_DMA_NONE)) BUG(); @@ -452,7 +456,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i if (unlikely(base == NULL)) BUG(); - dma_base = iommu->page_table_map_base + + dma_base = MAP_BASE + ((base - iommu->page_table) << IO_PAGE_SHIFT); /* Normalize DVMA addresses. */ @@ -481,9 +485,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; + struct sbus_iommu *iommu; iopte_t *base; unsigned long flags, i, npages; u32 bus_addr; @@ -491,9 +493,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems if (unlikely(direction == SBUS_DMA_NONE)) BUG(); - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; + iommu = sdev->bus->iommu; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -505,33 +505,29 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems bus_addr) >> IO_PAGE_SHIFT; base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, bus_addr, npages, direction); for (i = 0; i < npages; i++) iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + free_npages(iommu, bus_addr - MAP_BASE, npages); spin_unlock_irqrestore(&iommu->lock, flags); } void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) { - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; + struct sbus_iommu *iommu; unsigned long flags, npages; - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; + iommu = sdev->bus->iommu; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; bus_addr &= IO_PAGE_MASK; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, bus_addr, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -541,15 +537,11 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) { - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; + struct sbus_iommu *iommu; unsigned long flags, npages, i; u32 bus_addr; - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; + iommu = sdev->bus->iommu; bus_addr = sglist[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nelems; i++) { @@ -561,7 +553,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, - bus_addr) >> IO_PAGE_SHIFT; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); + sbus_strbuf_flush(iommu, bus_addr, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -572,13 +564,12 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, /* Enable 64-bit DVMA mode for the given device. */ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) { - struct sbus_info *info = sdev->bus->iommu; - struct iommu *iommu = &info->iommu; + struct sbus_iommu *iommu = sdev->bus->iommu; int slot = sdev->slot; unsigned long cfg_reg; u64 val; - cfg_reg = iommu->write_complete_reg; + cfg_reg = iommu->sbus_control_reg; switch (slot) { case 0: cfg_reg += 0x20UL; @@ -713,9 +704,8 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap) unsigned int sbus_build_irq(void *buscookie, unsigned int ino) { struct sbus_bus *sbus = (struct sbus_bus *)buscookie; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; - unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long imap, iclr; int sbus_level = 0; @@ -776,9 +766,8 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) static irqreturn_t sysio_ue_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; - unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int reported; @@ -849,9 +838,8 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) static irqreturn_t sysio_ce_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; - unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int reported; @@ -927,13 +915,12 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct sbus_iommu *iommu = sbus->iommu; unsigned long afsr_reg, afar_reg, reg_base; unsigned long afsr, afar, error_bits; int reported; - reg_base = iommu->write_complete_reg - 0x2000UL; + reg_base = iommu->sbus_control_reg - 0x2000UL; afsr_reg = reg_base + SYSIO_SBUS_AFSR; afar_reg = reg_base + SYSIO_SBUS_AFAR; @@ -995,9 +982,8 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) static void __init sysio_register_error_handlers(struct sbus_bus *sbus) { - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; - unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; + struct sbus_iommu *iommu = sbus->iommu; + unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned int irq; u64 control; @@ -1031,20 +1017,18 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus) SYSIO_ECNTRL_CEEN), reg_base + ECC_CONTROL); - control = upa_readq(iommu->write_complete_reg); + control = upa_readq(iommu->sbus_control_reg); control |= 0x100UL; /* SBUS Error Interrupt Enable */ - upa_writeq(control, iommu->write_complete_reg); + upa_writeq(control, iommu->sbus_control_reg); } /* Boot time initialization. */ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { - const struct linux_prom64_registers *pr; + struct linux_prom64_registers *pr; struct device_node *dp; - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long regs, reg_base; + struct sbus_iommu *iommu; + unsigned long regs; u64 control; int i; @@ -1059,42 +1043,33 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) } regs = pr->phys_addr; - info = kzalloc(sizeof(*info), GFP_ATOMIC); - if (info == NULL) { - prom_printf("sbus_iommu_init: Fatal error, " - "kmalloc(info) failed\n"); + iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC); + if (iommu == NULL) { + prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n"); prom_halt(); } - iommu = &info->iommu; - strbuf = &info->strbuf; - - reg_base = regs + SYSIO_IOMMUREG_BASE; - iommu->iommu_control = reg_base + IOMMU_CONTROL; - iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE; - iommu->iommu_flush = reg_base + IOMMU_FLUSH; + /* Align on E$ line boundary. */ + iommu = (struct sbus_iommu *) + (((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) & + ~(SMP_CACHE_BYTES - 1UL)); - reg_base = regs + SYSIO_STRBUFREG_BASE; - strbuf->strbuf_control = reg_base + STRBUF_CONTROL; - strbuf->strbuf_pflush = reg_base + STRBUF_PFLUSH; - strbuf->strbuf_fsync = reg_base + STRBUF_FSYNC; + memset(iommu, 0, sizeof(*iommu)); - strbuf->strbuf_enabled = 1; + /* Setup spinlock. */ + spin_lock_init(&iommu->lock); - strbuf->strbuf_flushflag = (volatile unsigned long *) - ((((unsigned long)&strbuf->__flushflag_buf[0]) - + 63UL) - & ~63UL); - strbuf->strbuf_flushflag_pa = (unsigned long) - __pa(strbuf->strbuf_flushflag); + /* Init register offsets. */ + iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE; + iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE; /* The SYSIO SBUS control register is used for dummy reads * in order to ensure write completion. */ - iommu->write_complete_reg = regs + 0x2000UL; + iommu->sbus_control_reg = regs + 0x2000UL; /* Link into SYSIO software state. */ - sbus->iommu = info; + sbus->iommu = iommu; printk("SYSIO: UPA portID %x, at %016lx\n", sbus->portid, regs); @@ -1102,44 +1077,40 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ sbus_iommu_table_init(iommu, IO_TSB_SIZE); - control = upa_readq(iommu->iommu_control); + control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL); control = ((7UL << 16UL) | (0UL << 2UL) | (1UL << 1UL) | (1UL << 0UL)); - upa_writeq(control, iommu->iommu_control); + upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL); /* Clean out any cruft in the IOMMU using * diagnostic accesses. */ for (i = 0; i < 16; i++) { - unsigned long dram, tag; - - dram = iommu->iommu_control + (IOMMU_DRAMDIAG - IOMMU_CONTROL); - tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); + unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG; + unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; dram += (unsigned long)i * 8UL; tag += (unsigned long)i * 8UL; upa_writeq(0, dram); upa_writeq(0, tag); } - upa_readq(iommu->write_complete_reg); + upa_readq(iommu->sbus_control_reg); /* Give the TSB to SYSIO. */ - upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase); + upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE); /* Setup streaming buffer, DE=1 SB_EN=1 */ control = (1UL << 1UL) | (1UL << 0UL); - upa_writeq(control, strbuf->strbuf_control); + upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL); /* Clear out the tags using diagnostics. */ for (i = 0; i < 16; i++) { unsigned long ptag, ltag; - ptag = strbuf->strbuf_control + - (STRBUF_PTAGDIAG - STRBUF_CONTROL); - ltag = strbuf->strbuf_control + - (STRBUF_LTAGDIAG - STRBUF_CONTROL); + ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG; + ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG; ptag += (unsigned long)i * 8UL; ltag += (unsigned long)i * 8UL; @@ -1148,9 +1119,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) } /* Enable DVMA arbitration for all devices/slots. */ - control = upa_readq(iommu->write_complete_reg); + control = upa_readq(iommu->sbus_control_reg); control |= 0x3fUL; - upa_writeq(control, iommu->write_complete_reg); + upa_writeq(control, iommu->sbus_control_reg); /* Now some Xfire specific grot... */ if (this_is_starfire) @@ -1162,7 +1133,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) void sbus_fill_device_irq(struct sbus_dev *sdev) { struct device_node *dp = of_find_node_by_phandle(sdev->prom_node); - const struct linux_prom_irqs *irqs; + struct linux_prom_irqs *irqs; irqs = of_get_property(dp, "interrupts", NULL); if (!irqs) { diff --git a/trunk/arch/sparc64/kernel/smp.c b/trunk/arch/sparc64/kernel/smp.c index 1fac215252e4..fc99f7b8012f 100644 --- a/trunk/arch/sparc64/kernel/smp.c +++ b/trunk/arch/sparc64/kernel/smp.c @@ -45,7 +45,7 @@ extern void calibrate_delay(void); /* Please don't make this stuff initdata!!! --DaveM */ -unsigned char boot_cpu_id; +static unsigned char boot_cpu_id; cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; @@ -81,6 +81,8 @@ void __init smp_store_cpu_info(int id) struct device_node *dp; int def; + /* multiplier and counter set by + smp_setup_percpu_timer() */ cpu_data(id).udelay_val = loops_per_jiffy; cpu_find_by_mid(id, &dp); @@ -123,7 +125,7 @@ void __init smp_store_cpu_info(int id) cpu_data(id).ecache_size, cpu_data(id).ecache_line_size); } -extern void setup_sparc64_timer(void); +static void smp_setup_percpu_timer(void); static volatile unsigned long callin_flag = 0; @@ -138,7 +140,7 @@ void __init smp_callin(void) __flush_tlb_all(); - setup_sparc64_timer(); + smp_setup_percpu_timer(); if (cheetah_pcache_forced_on) cheetah_enable_pcache(); @@ -175,6 +177,8 @@ void cpu_panic(void) panic("SMP bolixed\n"); } +static unsigned long current_tick_offset __read_mostly; + /* This tick register synchronization scheme is taken entirely from * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit. * @@ -257,7 +261,7 @@ void smp_synchronize_tick_client(void) } else adj = -delta; - tick_ops->add_tick(adj); + tick_ops->add_tick(adj, current_tick_offset); } #if DEBUG_TICK_SYNC t[i].rt = rt; @@ -1176,15 +1180,117 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) preempt_enable(); } +#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier +#define prof_counter(__cpu) cpu_data(__cpu).counter + +void smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + unsigned long compare, tick, pstate; + int cpu = smp_processor_id(); + int user = user_mode(regs); + struct pt_regs *old_regs; + + /* + * Check for level 14 softint. + */ + { + unsigned long tick_mask = tick_ops->softint_mask; + + if (!(get_softint() & tick_mask)) { + extern void handler_irq(int, struct pt_regs *); + + handler_irq(14, regs); + return; + } + clear_softint(tick_mask); + } + + old_regs = set_irq_regs(regs); + do { + profile_tick(CPU_PROFILING); + if (!--prof_counter(cpu)) { + irq_enter(); + + if (cpu == boot_cpu_id) { + kstat_this_cpu.irqs[0]++; + timer_tick_interrupt(regs); + } + + update_process_times(user); + + irq_exit(); + + prof_counter(cpu) = prof_multiplier(cpu); + } + + /* Guarantee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + compare = tick_ops->add_compare(current_tick_offset); + tick = tick_ops->get_tick(); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); + } while (time_after_eq(tick, compare)); + set_irq_regs(old_regs); +} + +static void __init smp_setup_percpu_timer(void) +{ + int cpu = smp_processor_id(); + unsigned long pstate; + + prof_counter(cpu) = prof_multiplier(cpu) = 1; + + /* Guarantee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + tick_ops->init_tick(current_tick_offset); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); +} + void __init smp_tick_init(void) { boot_cpu_id = hard_smp_processor_id(); + current_tick_offset = timer_tick_offset; + + prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1; } /* /proc/profile writes can call this, don't __init it please. */ +static DEFINE_SPINLOCK(prof_setup_lock); + int setup_profiling_timer(unsigned int multiplier) { - return -EINVAL; + unsigned long flags; + int i; + + if ((!multiplier) || (timer_tick_offset / multiplier) < 1000) + return -EINVAL; + + spin_lock_irqsave(&prof_setup_lock, flags); + for_each_possible_cpu(i) + prof_multiplier(i) = multiplier; + current_tick_offset = (timer_tick_offset / multiplier); + spin_unlock_irqrestore(&prof_setup_lock, flags); + + return 0; } static void __init smp_tune_scheduling(void) @@ -1343,11 +1449,11 @@ void __init setup_per_cpu_areas(void) /* Copy section for each CPU (we discard the original) */ goal = PERCPU_ENOUGH_ROOM; - __per_cpu_shift = PAGE_SHIFT; - for (size = PAGE_SIZE; size < goal; size <<= 1UL) + __per_cpu_shift = 0; + for (size = 1UL; size < goal; size <<= 1UL) __per_cpu_shift++; - ptr = alloc_bootmem_pages(size * NR_CPUS); + ptr = alloc_bootmem(size * NR_CPUS); __per_cpu_base = ptr - __per_cpu_start; diff --git a/trunk/arch/sparc64/kernel/sparc64_ksyms.c b/trunk/arch/sparc64/kernel/sparc64_ksyms.c index d00f51a5683f..beffc82a1e85 100644 --- a/trunk/arch/sparc64/kernel/sparc64_ksyms.c +++ b/trunk/arch/sparc64/kernel/sparc64_ksyms.c @@ -212,6 +212,7 @@ EXPORT_SYMBOL(insl); #ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(isa_chain); +EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); diff --git a/trunk/arch/sparc64/kernel/time.c b/trunk/arch/sparc64/kernel/time.c index 259063f41f95..f84da4f1b706 100644 --- a/trunk/arch/sparc64/kernel/time.c +++ b/trunk/arch/sparc64/kernel/time.c @@ -31,9 +31,6 @@ #include #include #include -#include -#include -#include #include #include @@ -63,7 +60,6 @@ static void __iomem *mstk48t59_regs; static int set_rtc_mmss(unsigned long); #define TICK_PRIV_BIT (1UL << 63) -#define TICKCMP_IRQ_BIT (1UL << 63) #ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) @@ -97,22 +93,21 @@ static void tick_disable_protection(void) : "g2"); } -static void tick_disable_irq(void) +static void tick_init_tick(unsigned long offset) { + tick_disable_protection(); + __asm__ __volatile__( + " rd %%tick, %%g1\n" + " andn %%g1, %1, %%g1\n" " ba,pt %%xcc, 1f\n" - " nop\n" + " add %%g1, %0, %%g1\n" " .align 64\n" - "1: wr %0, 0x0, %%tick_cmpr\n" + "1: wr %%g1, 0x0, %%tick_cmpr\n" " rd %%tick_cmpr, %%g0" : /* no outputs */ - : "r" (TICKCMP_IRQ_BIT)); -} - -static void tick_init_tick(void) -{ - tick_disable_protection(); - tick_disable_irq(); + : "r" (offset), "r" (TICK_PRIV_BIT) + : "g1"); } static unsigned long tick_get_tick(void) @@ -126,14 +121,20 @@ static unsigned long tick_get_tick(void) return ret & ~TICK_PRIV_BIT; } -static int tick_add_compare(unsigned long adj) +static unsigned long tick_get_compare(void) { - unsigned long orig_tick, new_tick, new_compare; + unsigned long ret; - __asm__ __volatile__("rd %%tick, %0" - : "=r" (orig_tick)); + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "mov %0, %0" + : "=r" (ret)); - orig_tick &= ~TICKCMP_IRQ_BIT; + return ret; +} + +static unsigned long tick_add_compare(unsigned long adj) +{ + unsigned long new_compare; /* Workaround for Spitfire Errata (#54 I think??), I discovered * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch @@ -144,41 +145,44 @@ static int tick_add_compare(unsigned long adj) * at the start of an I-cache line, and perform a dummy * read back from %tick_cmpr right after writing to it. -DaveM */ - __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" - " add %1, %2, %0\n\t" + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "ba,pt %%xcc, 1f\n\t" + " add %0, %1, %0\n\t" ".align 64\n" "1:\n\t" "wr %0, 0, %%tick_cmpr\n\t" - "rd %%tick_cmpr, %%g0\n\t" - : "=r" (new_compare) - : "r" (orig_tick), "r" (adj)); - - __asm__ __volatile__("rd %%tick, %0" - : "=r" (new_tick)); - new_tick &= ~TICKCMP_IRQ_BIT; + "rd %%tick_cmpr, %%g0" + : "=&r" (new_compare) + : "r" (adj)); - return ((long)(new_tick - (orig_tick+adj))) > 0L; + return new_compare; } -static unsigned long tick_add_tick(unsigned long adj) +static unsigned long tick_add_tick(unsigned long adj, unsigned long offset) { - unsigned long new_tick; + unsigned long new_tick, tmp; /* Also need to handle Blackbird bug here too. */ __asm__ __volatile__("rd %%tick, %0\n\t" - "add %0, %1, %0\n\t" + "add %0, %2, %0\n\t" "wrpr %0, 0, %%tick\n\t" - : "=&r" (new_tick) - : "r" (adj)); + "andn %0, %4, %1\n\t" + "ba,pt %%xcc, 1f\n\t" + " add %1, %3, %1\n\t" + ".align 64\n" + "1:\n\t" + "wr %1, 0, %%tick_cmpr\n\t" + "rd %%tick_cmpr, %%g0" + : "=&r" (new_tick), "=&r" (tmp) + : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT)); return new_tick; } static struct sparc64_tick_ops tick_operations __read_mostly = { - .name = "tick", .init_tick = tick_init_tick, - .disable_irq = tick_disable_irq, .get_tick = tick_get_tick, + .get_compare = tick_get_compare, .add_tick = tick_add_tick, .add_compare = tick_add_compare, .softint_mask = 1UL << 0, @@ -186,15 +190,7 @@ static struct sparc64_tick_ops tick_operations __read_mostly = { struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations; -static void stick_disable_irq(void) -{ - __asm__ __volatile__( - "wr %0, 0x0, %%asr25" - : /* no outputs */ - : "r" (TICKCMP_IRQ_BIT)); -} - -static void stick_init_tick(void) +static void stick_init_tick(unsigned long offset) { /* Writes to the %tick and %stick register are not * allowed on sun4v. The Hypervisor controls that @@ -202,7 +198,6 @@ static void stick_init_tick(void) */ if (tlb_type != hypervisor) { tick_disable_protection(); - tick_disable_irq(); /* Let the user get at STICK too. */ __asm__ __volatile__( @@ -214,7 +209,14 @@ static void stick_init_tick(void) : "g1", "g2"); } - stick_disable_irq(); + __asm__ __volatile__( + " rd %%asr24, %%g1\n" + " andn %%g1, %1, %%g1\n" + " add %%g1, %0, %%g1\n" + " wr %%g1, 0x0, %%asr25" + : /* no outputs */ + : "r" (offset), "r" (TICK_PRIV_BIT) + : "g1"); } static unsigned long stick_get_tick(void) @@ -227,43 +229,49 @@ static unsigned long stick_get_tick(void) return ret & ~TICK_PRIV_BIT; } -static unsigned long stick_add_tick(unsigned long adj) +static unsigned long stick_get_compare(void) { - unsigned long new_tick; + unsigned long ret; + + __asm__ __volatile__("rd %%asr25, %0" + : "=r" (ret)); + + return ret; +} + +static unsigned long stick_add_tick(unsigned long adj, unsigned long offset) +{ + unsigned long new_tick, tmp; __asm__ __volatile__("rd %%asr24, %0\n\t" - "add %0, %1, %0\n\t" + "add %0, %2, %0\n\t" "wr %0, 0, %%asr24\n\t" - : "=&r" (new_tick) - : "r" (adj)); + "andn %0, %4, %1\n\t" + "add %1, %3, %1\n\t" + "wr %1, 0, %%asr25" + : "=&r" (new_tick), "=&r" (tmp) + : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT)); return new_tick; } -static int stick_add_compare(unsigned long adj) +static unsigned long stick_add_compare(unsigned long adj) { - unsigned long orig_tick, new_tick; - - __asm__ __volatile__("rd %%asr24, %0" - : "=r" (orig_tick)); - orig_tick &= ~TICKCMP_IRQ_BIT; - - __asm__ __volatile__("wr %0, 0, %%asr25" - : /* no outputs */ - : "r" (orig_tick + adj)); + unsigned long new_compare; - __asm__ __volatile__("rd %%asr24, %0" - : "=r" (new_tick)); - new_tick &= ~TICKCMP_IRQ_BIT; + __asm__ __volatile__("rd %%asr25, %0\n\t" + "add %0, %1, %0\n\t" + "wr %0, 0, %%asr25" + : "=&r" (new_compare) + : "r" (adj)); - return ((long)(new_tick - (orig_tick+adj))) > 0L; + return new_compare; } static struct sparc64_tick_ops stick_operations __read_mostly = { - .name = "stick", .init_tick = stick_init_tick, - .disable_irq = stick_disable_irq, .get_tick = stick_get_tick, + .get_compare = stick_get_compare, .add_tick = stick_add_tick, .add_compare = stick_add_compare, .softint_mask = 1UL << 16, @@ -312,6 +320,20 @@ static unsigned long __hbird_read_stick(void) return ret; } +static unsigned long __hbird_read_compare(void) +{ + unsigned long low, high; + unsigned long addr = HBIRD_STICKCMP_ADDR; + + __asm__ __volatile__("ldxa [%2] %3, %0\n\t" + "add %2, 0x8, %2\n\t" + "ldxa [%2] %3, %1" + : "=&r" (low), "=&r" (high), "=&r" (addr) + : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr)); + + return (high << 32UL) | low; +} + static void __hbird_write_stick(unsigned long val) { unsigned long low = (val & 0xffffffffUL); @@ -342,13 +364,10 @@ static void __hbird_write_compare(unsigned long val) "i" (ASI_PHYS_BYPASS_EC_E)); } -static void hbtick_disable_irq(void) +static void hbtick_init_tick(unsigned long offset) { - __hbird_write_compare(TICKCMP_IRQ_BIT); -} + unsigned long val; -static void hbtick_init_tick(void) -{ tick_disable_protection(); /* XXX This seems to be necessary to 'jumpstart' Hummingbird @@ -358,7 +377,8 @@ static void hbtick_init_tick(void) */ __hbird_write_stick(__hbird_read_stick()); - hbtick_disable_irq(); + val = __hbird_read_stick() & ~TICK_PRIV_BIT; + __hbird_write_compare(val + offset); } static unsigned long hbtick_get_tick(void) @@ -366,95 +386,122 @@ static unsigned long hbtick_get_tick(void) return __hbird_read_stick() & ~TICK_PRIV_BIT; } -static unsigned long hbtick_add_tick(unsigned long adj) +static unsigned long hbtick_get_compare(void) +{ + return __hbird_read_compare(); +} + +static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset) { unsigned long val; val = __hbird_read_stick() + adj; __hbird_write_stick(val); + val &= ~TICK_PRIV_BIT; + __hbird_write_compare(val + offset); + return val; } -static int hbtick_add_compare(unsigned long adj) +static unsigned long hbtick_add_compare(unsigned long adj) { - unsigned long val = __hbird_read_stick(); - unsigned long val2; + unsigned long val = __hbird_read_compare() + adj; - val &= ~TICKCMP_IRQ_BIT; - val += adj; + val &= ~TICK_PRIV_BIT; __hbird_write_compare(val); - val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT; - - return ((long)(val2 - val)) > 0L; + return val; } static struct sparc64_tick_ops hbtick_operations __read_mostly = { - .name = "hbtick", .init_tick = hbtick_init_tick, - .disable_irq = hbtick_disable_irq, .get_tick = hbtick_get_tick, + .get_compare = hbtick_get_compare, .add_tick = hbtick_add_tick, .add_compare = hbtick_add_compare, .softint_mask = 1UL << 0, }; +/* timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + * + * NOTE: On SUN5 systems the ticker interrupt comes in using 2 + * interrupts, one at level14 and one with softint bit 0. + */ +unsigned long timer_tick_offset __read_mostly; + static unsigned long timer_ticks_per_nsec_quotient __read_mostly; #define TICK_SIZE (tick_nsec / 1000) -#define USEC_AFTER 500000 -#define USEC_BEFORE 500000 +static inline void timer_check_rtc(void) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update; + + /* Determine when to update the Mostek clock. */ + if (ntp_synced() && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 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 */ + } +} -static void sync_cmos_clock(unsigned long dummy); +irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + unsigned long ticks, compare, pstate; -static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); + write_seqlock(&xtime_lock); -static void sync_cmos_clock(unsigned long dummy) -{ - struct timeval now, next; - int fail = 1; + do { +#ifndef CONFIG_SMP + profile_tick(CPU_PROFILING); + update_process_times(user_mode(get_irq_regs())); +#endif + do_timer(1); - /* - * 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. - * This code is run on a timer. If the clock is set, that timer - * may not expire at the correct time. Thus, we adjust... - */ - if (!ntp_synced()) - /* - * Not synced, exit, do not restart a timer (if one is - * running, let it run out). + /* Guarantee that the following sequences execute + * uninterrupted. */ - return; + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); - do_gettimeofday(&now); - if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && - now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) - fail = set_rtc_mmss(now.tv_sec); + compare = tick_ops->add_compare(timer_tick_offset); + ticks = tick_ops->get_tick(); - next.tv_usec = USEC_AFTER - now.tv_usec; - if (next.tv_usec <= 0) - next.tv_usec += USEC_PER_SEC; + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); + } while (time_after_eq(ticks, compare)); - if (!fail) - next.tv_sec = 659; - else - next.tv_sec = 0; + timer_check_rtc(); - if (next.tv_usec >= USEC_PER_SEC) { - next.tv_sec++; - next.tv_usec -= USEC_PER_SEC; - } - mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next)); + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; } -void notify_arch_cmos_timer(void) +#ifdef CONFIG_SMP +void timer_tick_interrupt(struct pt_regs *regs) { - mod_timer(&sync_cmos_timer, jiffies + 1); + write_seqlock(&xtime_lock); + + do_timer(1); + + timer_check_rtc(); + + write_sequnlock(&xtime_lock); } +#endif /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) @@ -704,7 +751,7 @@ static int hypervisor_set_time(u32 secs) return -EOPNOTSUPP; } -static int __init clock_model_matches(const char *model) +static int __init clock_model_matches(char *model) { if (strcmp(model, "mk48t02") && strcmp(model, "mk48t08") && @@ -721,7 +768,7 @@ static int __init clock_model_matches(const char *model) static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - const char *model = of_get_property(dp, "model", NULL); + char *model = of_get_property(dp, "model", NULL); unsigned long size, flags; void __iomem *regs; @@ -853,6 +900,7 @@ static unsigned long sparc64_init_timers(void) prop = of_find_property(dp, "stick-frequency", NULL); } clock = *(unsigned int *) prop->value; + timer_tick_offset = clock / HZ; #ifdef CONFIG_SMP smp_tick_init(); @@ -861,6 +909,26 @@ static unsigned long sparc64_init_timers(void) return clock; } +static void sparc64_start_timers(void) +{ + unsigned long pstate; + + /* Guarantee that the following sequences execute + * uninterrupted. + */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + tick_ops->init_tick(timer_tick_offset); + + /* Restore PSTATE_IE. */ + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : /* no outputs */ + : "r" (pstate)); +} + struct freq_table { unsigned long clock_tick_ref; unsigned int ref_freq; @@ -907,148 +975,29 @@ static struct notifier_block sparc64_cpufreq_notifier_block = { #endif /* CONFIG_CPU_FREQ */ -static int sparc64_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - return tick_ops->add_compare(delta) ? -ETIME : 0; -} - -static void sparc64_timer_setup(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - tick_ops->disable_irq(); - break; - - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_UNUSED: - WARN_ON(1); - break; - }; -} - -static struct clock_event_device sparc64_clockevent = { - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sparc64_timer_setup, - .set_next_event = sparc64_next_event, - .rating = 100, - .shift = 30, - .irq = -1, -}; -static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); - -void timer_interrupt(int irq, struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - unsigned long tick_mask = tick_ops->softint_mask; - int cpu = smp_processor_id(); - struct clock_event_device *evt = &per_cpu(sparc64_events, cpu); - - clear_softint(tick_mask); - - irq_enter(); - - kstat_this_cpu.irqs[0]++; - - if (unlikely(!evt->event_handler)) { - printk(KERN_WARNING - "Spurious SPARC64 timer interrupt on cpu %d\n", cpu); - } else - evt->event_handler(evt); - - irq_exit(); - - set_irq_regs(old_regs); -} - -void __devinit setup_sparc64_timer(void) -{ - struct clock_event_device *sevt; - unsigned long pstate; - - /* Guarantee that the following sequences execute - * uninterrupted. - */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - - tick_ops->init_tick(); - - /* Restore PSTATE_IE. */ - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" - : /* no outputs */ - : "r" (pstate)); - - sevt = &__get_cpu_var(sparc64_events); - - memcpy(sevt, &sparc64_clockevent, sizeof(*sevt)); - sevt->cpumask = cpumask_of_cpu(smp_processor_id()); - - clockevents_register_device(sevt); -} - -#define SPARC64_NSEC_PER_CYC_SHIFT 32UL - -static struct clocksource clocksource_tick = { - .rating = 100, - .mask = CLOCKSOURCE_MASK(64), - .shift = 16, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, +static struct time_interpolator sparc64_cpu_interpolator = { + .source = TIME_SOURCE_CPU, + .shift = 16, + .mask = 0xffffffffffffffffLL }; -static void __init setup_clockevent_multiplier(unsigned long hz) -{ - unsigned long mult, shift = 32; - - while (1) { - mult = div_sc(hz, NSEC_PER_SEC, shift); - if (mult && (mult >> 32UL) == 0UL) - break; - - shift--; - } - - sparc64_clockevent.shift = shift; - sparc64_clockevent.mult = mult; -} - +/* The quotient formula is taken from the IA64 port. */ +#define SPARC64_NSEC_PER_CYC_SHIFT 10UL void __init time_init(void) { unsigned long clock = sparc64_init_timers(); - timer_ticks_per_nsec_quotient = - clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT); + sparc64_cpu_interpolator.frequency = clock; + register_time_interpolator(&sparc64_cpu_interpolator); - clocksource_tick.name = tick_ops->name; - clocksource_tick.mult = - clocksource_hz2mult(clock, - clocksource_tick.shift); - clocksource_tick.read = tick_ops->get_tick; - - printk("clocksource: mult[%x] shift[%d]\n", - clocksource_tick.mult, clocksource_tick.shift); - - clocksource_register(&clocksource_tick); - - sparc64_clockevent.name = tick_ops->name; - - setup_clockevent_multiplier(clock); - - sparc64_clockevent.max_delta_ns = - clockevent_delta2ns(0x7fffffffffffffff, &sparc64_clockevent); - sparc64_clockevent.min_delta_ns = - clockevent_delta2ns(0xF, &sparc64_clockevent); - - printk("clockevent: mult[%lx] shift[%d]\n", - sparc64_clockevent.mult, sparc64_clockevent.shift); + /* Now that the interpolator is registered, it is + * safe to start the timer ticking. + */ + sparc64_start_timers(); - setup_sparc64_timer(); + timer_ticks_per_nsec_quotient = + (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + + (clock / 2)) / clock); #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, @@ -1177,6 +1126,10 @@ static int set_rtc_mmss(unsigned long nowtime) #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ static unsigned char mini_rtc_status; /* bitmapped status byte. */ +/* months start at 0 now */ +static unsigned char days_in_mo[] = +{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + #define FEBRUARY 2 #define STARTOFTIME 1970 #define SECDAY 86400L @@ -1325,7 +1278,8 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file, case RTC_SET_TIME: /* Set the RTC */ { - int year, days; + int year; + unsigned char leap_yr; if (!capable(CAP_SYS_TIME)) return -EACCES; @@ -1334,14 +1288,14 @@ static int mini_rtc_ioctl(struct inode *inode, struct file *file, return -EFAULT; year = wtime.tm_year + 1900; - days = month_days[wtime.tm_mon] + - ((wtime.tm_mon == 1) && leapyear(year)); + leap_yr = ((!(year % 4) && (year % 100)) || + !(year % 400)); - if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || - (wtime.tm_mday < 1)) + if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1)) return -EINVAL; - if (wtime.tm_mday < 0 || wtime.tm_mday > days) + if (wtime.tm_mday < 0 || wtime.tm_mday > + (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr))) return -EINVAL; if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || diff --git a/trunk/arch/sparc64/kernel/ttable.S b/trunk/arch/sparc64/kernel/ttable.S index 7575aa371da8..d7d2a8bdc66e 100644 --- a/trunk/arch/sparc64/kernel/ttable.S +++ b/trunk/arch/sparc64/kernel/ttable.S @@ -60,7 +60,11 @@ tl0_irq4: BTRAP(0x44) tl0_irq5: TRAP_IRQ(handler_irq, 5) tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49) tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) -tl0_irq14: TRAP_IRQ(timer_interrupt, 14) +#ifndef CONFIG_SMP +tl0_irq14: TRAP_IRQ(timer_irq, 14) +#else +tl0_irq14: TICK_SMP_IRQ +#endif tl0_irq15: TRAP_IRQ(handler_irq, 15) tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) diff --git a/trunk/arch/sparc64/mm/init.c b/trunk/arch/sparc64/mm/init.c index cafadcbcdf38..f146071a4b2a 100644 --- a/trunk/arch/sparc64/mm/init.c +++ b/trunk/arch/sparc64/mm/init.c @@ -122,21 +122,26 @@ static void __init read_obp_memory(const char *property, size = 0UL; base = new_base; } - if (size == 0UL) { - /* If it is empty, simply get rid of it. - * This simplifies the logic of the other - * functions that process these arrays. - */ - memmove(®s[i], ®s[i + 1], - (ents - i - 1) * sizeof(regs[0])); - i--; - ents--; - continue; - } regs[i].phys_addr = base; regs[i].reg_size = size; } + for (i = 0; i < ents; i++) { + if (regs[i].reg_size == 0UL) { + int j; + + for (j = i; j < ents - 1; j++) { + regs[j].phys_addr = + regs[j+1].phys_addr; + regs[j].reg_size = + regs[j+1].reg_size; + } + + ents--; + i--; + } + } + *num_ents = ents; sort(regs, ents, sizeof(struct linux_prom64_registers), @@ -149,6 +154,15 @@ unsigned long *sparc64_valid_addr_bitmap __read_mostly; unsigned long kern_base __read_mostly; unsigned long kern_size __read_mostly; +/* get_new_mmu_context() uses "cache + 1". */ +DEFINE_SPINLOCK(ctx_alloc_lock); +unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6)) +unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; + +/* References to special section boundaries */ +extern char _start[], _end[]; + /* Initial ramdisk setup */ extern unsigned long sparc_ramdisk_image64; extern unsigned int sparc_ramdisk_image; @@ -392,70 +406,19 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) if (tlb_type == spitfire) { unsigned long kaddr; - /* This code only runs on Spitfire cpus so this is - * why we can assume _PAGE_PADDR_4U. - */ - for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) { - unsigned long paddr, mask = _PAGE_PADDR_4U; - - if (kaddr >= PAGE_OFFSET) - paddr = kaddr & mask; - else { - pgd_t *pgdp = pgd_offset_k(kaddr); - pud_t *pudp = pud_offset(pgdp, kaddr); - pmd_t *pmdp = pmd_offset(pudp, kaddr); - pte_t *ptep = pte_offset_kernel(pmdp, kaddr); - - paddr = pte_val(*ptep) & mask; - } - __flush_icache_page(paddr); - } + for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) + __flush_icache_page(__get_phys(kaddr)); } } void show_mem(void) { - unsigned long total = 0, reserved = 0; - unsigned long shared = 0, cached = 0; - pg_data_t *pgdat; - - printk(KERN_INFO "Mem-info:\n"); + printk("Mem-info:\n"); show_free_areas(); - printk(KERN_INFO "Free swap: %6ldkB\n", + printk("Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT-10)); - for_each_online_pgdat(pgdat) { - unsigned long i, flags; - - pgdat_resize_lock(pgdat, &flags); - for (i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page = pgdat_page_nr(pgdat, i); - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; - } - pgdat_resize_unlock(pgdat, &flags); - } - - printk(KERN_INFO "%lu pages of RAM\n", total); - printk(KERN_INFO "%lu reserved pages\n", reserved); - printk(KERN_INFO "%lu pages shared\n", shared); - printk(KERN_INFO "%lu pages swap cached\n", cached); - - printk(KERN_INFO "%lu pages dirty\n", - global_page_state(NR_FILE_DIRTY)); - printk(KERN_INFO "%lu pages writeback\n", - global_page_state(NR_WRITEBACK)); - printk(KERN_INFO "%lu pages mapped\n", - global_page_state(NR_FILE_MAPPED)); - printk(KERN_INFO "%lu pages slab\n", - global_page_state(NR_SLAB_RECLAIMABLE) + - global_page_state(NR_SLAB_UNRECLAIMABLE)); - printk(KERN_INFO "%lu pages pagetables\n", - global_page_state(NR_PAGETABLE)); + printk("%ld pages of RAM\n", num_physpages); + printk("%lu free pages\n", nr_free_pages()); } void mmu_info(struct seq_file *m) @@ -695,13 +658,6 @@ void __flush_dcache_range(unsigned long start, unsigned long end) } #endif /* DCACHE_ALIASING_POSSIBLE */ -/* get_new_mmu_context() uses "cache + 1". */ -DEFINE_SPINLOCK(ctx_alloc_lock); -unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; -#define MAX_CTX_NR (1UL << CTX_NR_BITS) -#define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR) -DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR); - /* Caller does TLB context flushing on local CPU if necessary. * The caller also ensures that CTX_VALID(mm->context) is false. * @@ -761,6 +717,95 @@ void get_new_mmu_context(struct mm_struct *mm) smp_new_mmu_context_version(); } +void sparc_ultra_dump_itlb(void) +{ + int slot; + + if (tlb_type == spitfire) { + printk ("Contents of itlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", + 0, + spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), + slot+1, + spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1), + slot+2, + spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); + } + } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { + printk ("Contents of itlb0:\n"); + for (slot = 0; slot < 16; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot), + slot+1, + cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1)); + } + printk ("Contents of itlb2:\n"); + for (slot = 0; slot < 128; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot), + slot+1, + cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1)); + } + } +} + +void sparc_ultra_dump_dtlb(void) +{ + int slot; + + if (tlb_type == spitfire) { + printk ("Contents of dtlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", 0, + spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), + slot+1, + spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), + slot+2, + spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); + } + } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { + printk ("Contents of dtlb0:\n"); + for (slot = 0; slot < 16; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot), + slot+1, + cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1)); + } + printk ("Contents of dtlb2:\n"); + for (slot = 0; slot < 512; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2), + slot+1, + cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2)); + } + if (tlb_type == cheetah_plus) { + printk ("Contents of dtlb3:\n"); + for (slot = 0; slot < 512; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3), + slot+1, + cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3)); + } + } + } +} + +extern unsigned long cmdline_memory_size; + /* Find a free area for the bootmem map, avoiding the kernel image * and the initial ramdisk. */ @@ -770,8 +815,8 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, unsigned long avoid_start, avoid_end, bootmap_size; int i; - bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn); - bootmap_size <<= PAGE_SHIFT; + bootmap_size = ((end_pfn - start_pfn) + 7) / 8; + bootmap_size = ALIGN(bootmap_size, sizeof(long)); avoid_start = avoid_end = 0; #ifdef CONFIG_BLK_DEV_INITRD @@ -938,20 +983,6 @@ static void __init trim_pavail(unsigned long *cur_size_p, } } -/* About pages_avail, this is the value we will use to calculate - * the zholes_size[] argument given to free_area_init_node(). The - * page allocator uses this to calculate nr_kernel_pages, - * nr_all_pages and zone->present_pages. On NUMA it is used - * to calculate zone->min_unmapped_pages and zone->min_slab_pages. - * - * So this number should really be set to what the page allocator - * actually ends up with. This means: - * 1) It should include bootmem map pages, we'll release those. - * 2) It should not include the kernel image, except for the - * __init sections which we will also release. - * 3) It should include the initrd image, since we'll release - * that too. - */ static unsigned long __init bootmem_init(unsigned long *pages_avail, unsigned long phys_base) { @@ -1038,6 +1069,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, initrd_start, initrd_end); #endif reserve_bootmem(initrd_start, size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; initrd_start += PAGE_OFFSET; initrd_end += PAGE_OFFSET; @@ -1050,11 +1082,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, reserve_bootmem(kern_base, kern_size); *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT; - /* Add back in the initmem pages. */ - size = ((unsigned long)(__init_end) & PAGE_MASK) - - PAGE_ALIGN((unsigned long)__init_begin); - *pages_avail += size >> PAGE_SHIFT; - /* Reserve the bootmem map. We do not account for it * in pages_avail because we will release that memory * in free_all_bootmem. @@ -1065,6 +1092,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, (bootmap_pfn << PAGE_SHIFT), size); #endif reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; for (i = 0; i < pavail_ents; i++) { unsigned long start_pfn, end_pfn; @@ -1556,10 +1584,6 @@ void __init mem_init(void) #ifdef CONFIG_DEBUG_BOOTMEM prom_printf("mem_init: Calling free_all_bootmem().\n"); #endif - - /* We subtract one to account for the mem_map_zero page - * allocated below. - */ totalram_pages = num_physpages = free_all_bootmem() - 1; /* @@ -1859,6 +1883,62 @@ static unsigned long kern_large_tte(unsigned long paddr) return val | paddr; } +/* + * Translate PROM's mapping we capture at boot time into physical address. + * The second parameter is only set from prom_callback() invocations. + */ +unsigned long prom_virt_to_phys(unsigned long promva, int *error) +{ + unsigned long mask; + int i; + + mask = _PAGE_PADDR_4U; + if (tlb_type == hypervisor) + mask = _PAGE_PADDR_4V; + + for (i = 0; i < prom_trans_ents; i++) { + struct linux_prom_translation *p = &prom_trans[i]; + + if (promva >= p->virt && + promva < (p->virt + p->size)) { + unsigned long base = p->data & mask; + + if (error) + *error = 0; + return base + (promva & (8192 - 1)); + } + } + if (error) + *error = 1; + return 0UL; +} + +/* XXX We should kill off this ugly thing at so me point. XXX */ +unsigned long sun4u_get_pte(unsigned long addr) +{ + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long mask = _PAGE_PADDR_4U; + + if (tlb_type == hypervisor) + mask = _PAGE_PADDR_4V; + + if (addr >= PAGE_OFFSET) + return addr & mask; + + if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) + return prom_virt_to_phys(addr, NULL); + + pgdp = pgd_offset_k(addr); + pudp = pud_offset(pgdp, addr); + pmdp = pmd_offset(pudp, addr); + ptep = pte_offset_kernel(pmdp, addr); + + return pte_val(*ptep) & mask; +} + /* If not locked, zap it. */ void __flush_tlb_all(void) { diff --git a/trunk/arch/sparc64/solaris/ioctl.c b/trunk/arch/sparc64/solaris/ioctl.c index 18352a498628..330743c5b3d8 100644 --- a/trunk/arch/sparc64/solaris/ioctl.c +++ b/trunk/arch/sparc64/solaris/ioctl.c @@ -686,8 +686,7 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg) int i = 0; read_lock_bh(&dev_base_lock); - for_each_netdev(d) - i++; + for (d = dev_base; d; d = d->next) i++; read_unlock_bh(&dev_base_lock); if (put_user (i, (int __user *)A(arg))) diff --git a/trunk/arch/sparc64/solaris/misc.c b/trunk/arch/sparc64/solaris/misc.c index 542c808ec2c8..9fcaad6dd11f 100644 --- a/trunk/arch/sparc64/solaris/misc.c +++ b/trunk/arch/sparc64/solaris/misc.c @@ -224,8 +224,7 @@ static char *serial(char *buffer, int sz) *buffer = 0; if (dp) { - const char *val = - of_get_property(dp, "system-board-serial#", &len); + char *val = of_get_property(dp, "system-board-serial#", &len); if (val && len > 0) { if (len > sz) diff --git a/trunk/arch/um/defconfig b/trunk/arch/um/defconfig index f938fa822146..780cc0a4a128 100644 --- a/trunk/arch/um/defconfig +++ b/trunk/arch/um/defconfig @@ -41,7 +41,6 @@ CONFIG_M686=y # CONFIG_MGEODE_LX is not set # CONFIG_MCYRIXIII is not set # CONFIG_MVIAC3_2 is not set -# CONFIG_MVIAC7 is not set # CONFIG_X86_GENERIC is not set CONFIG_X86_CMPXCHG=y CONFIG_X86_XADD=y diff --git a/trunk/arch/um/drivers/daemon_kern.c b/trunk/arch/um/drivers/daemon_kern.c index adeece11e596..9c2e7a758f21 100644 --- a/trunk/arch/um/drivers/daemon_kern.c +++ b/trunk/arch/um/drivers/daemon_kern.c @@ -46,7 +46,7 @@ static int daemon_read(int fd, struct sk_buff **skb, { *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if(*skb == NULL) return(-ENOMEM); - return(net_recvfrom(fd, skb_mac_header(*skb), + return(net_recvfrom(fd, (*skb)->mac.raw, (*skb)->dev->mtu + ETH_HEADER_OTHER)); } diff --git a/trunk/arch/um/drivers/mcast_kern.c b/trunk/arch/um/drivers/mcast_kern.c index e6b8e0dd72a8..52ccb7b53cd2 100644 --- a/trunk/arch/um/drivers/mcast_kern.c +++ b/trunk/arch/um/drivers/mcast_kern.c @@ -50,7 +50,7 @@ static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) { *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if(*skb == NULL) return(-ENOMEM); - return(net_recvfrom(fd, skb_mac_header(*skb), + return(net_recvfrom(fd, (*skb)->mac.raw, (*skb)->dev->mtu + ETH_HEADER_OTHER)); } diff --git a/trunk/arch/um/drivers/net_kern.c b/trunk/arch/um/drivers/net_kern.c index 859303730b2f..04e31f86c10a 100644 --- a/trunk/arch/um/drivers/net_kern.c +++ b/trunk/arch/um/drivers/net_kern.c @@ -55,7 +55,7 @@ static int uml_net_rx(struct net_device *dev) skb->dev = dev; skb_put(skb, dev->mtu); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; pkt_len = (*lp->read)(lp->fd, &skb, lp); if (pkt_len > 0) { diff --git a/trunk/arch/um/drivers/pcap_kern.c b/trunk/arch/um/drivers/pcap_kern.c index 948849343ca4..e67362acf0e7 100644 --- a/trunk/arch/um/drivers/pcap_kern.c +++ b/trunk/arch/um/drivers/pcap_kern.c @@ -36,7 +36,7 @@ static int pcap_read(int fd, struct sk_buff **skb, { *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if(*skb == NULL) return(-ENOMEM); - return(pcap_user_read(fd, skb_mac_header(*skb), + return(pcap_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu + ETH_HEADER_OTHER, (struct pcap_data *) &lp->user)); } diff --git a/trunk/arch/um/drivers/slip_kern.c b/trunk/arch/um/drivers/slip_kern.c index 125c44f77638..25634bd1f585 100644 --- a/trunk/arch/um/drivers/slip_kern.c +++ b/trunk/arch/um/drivers/slip_kern.c @@ -49,7 +49,7 @@ static unsigned short slip_protocol(struct sk_buff *skbuff) static int slip_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) { - return(slip_user_read(fd, skb_mac_header(*skb), (*skb)->dev->mtu, + return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, (struct slip_data *) &lp->user)); } diff --git a/trunk/arch/um/drivers/slirp_kern.c b/trunk/arch/um/drivers/slirp_kern.c index 0a0324a6d290..b3ed8fb874ab 100644 --- a/trunk/arch/um/drivers/slirp_kern.c +++ b/trunk/arch/um/drivers/slirp_kern.c @@ -53,7 +53,7 @@ static unsigned short slirp_protocol(struct sk_buff *skbuff) static int slirp_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) { - return(slirp_user_read(fd, skb_mac_header(*skb), (*skb)->dev->mtu, + return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, (struct slirp_data *) &lp->user)); } diff --git a/trunk/arch/um/os-Linux/drivers/ethertap_kern.c b/trunk/arch/um/os-Linux/drivers/ethertap_kern.c index 12689141414d..70541821775f 100644 --- a/trunk/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/trunk/arch/um/os-Linux/drivers/ethertap_kern.c @@ -43,7 +43,7 @@ static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP); if(*skb == NULL) return(-ENOMEM); - len = net_recvfrom(fd, skb_mac_header(*skb), + len = net_recvfrom(fd, (*skb)->mac.raw, (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP); if(len <= 0) return(len); skb_pull(*skb, 2); diff --git a/trunk/arch/um/os-Linux/drivers/tuntap_kern.c b/trunk/arch/um/os-Linux/drivers/tuntap_kern.c index f1714e7fb1d0..76570a2c25c3 100644 --- a/trunk/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/trunk/arch/um/os-Linux/drivers/tuntap_kern.c @@ -43,7 +43,7 @@ static int tuntap_read(int fd, struct sk_buff **skb, { *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if(*skb == NULL) return(-ENOMEM); - return(net_read(fd, skb_mac_header(*skb), + return(net_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu + ETH_HEADER_OTHER)); } diff --git a/trunk/arch/x86_64/Kconfig b/trunk/arch/x86_64/Kconfig index 145bb824b2a8..56eb14c98475 100644 --- a/trunk/arch/x86_64/Kconfig +++ b/trunk/arch/x86_64/Kconfig @@ -415,13 +415,13 @@ config OUT_OF_LINE_PFN_TO_PAGE depends on DISCONTIGMEM config NR_CPUS - int "Maximum number of CPUs (2-255)" + int "Maximum number of CPUs (2-256)" range 2 255 depends on SMP default "8" help This allows you to specify the maximum number of CPUs which this - kernel will support. Current maximum is 255 CPUs due to + kernel will support. Current maximum is 256 CPUs due to APIC addressing limits. Less depending on the hardware. This is purely to save memory - each supported CPU requires @@ -565,56 +565,23 @@ config CRASH_DUMP PHYSICAL_START. For more details see Documentation/kdump/kdump.txt -config RELOCATABLE - bool "Build a relocatable kernel(EXPERIMENTAL)" - depends on EXPERIMENTAL - help - Builds a relocatable kernel. This enables loading and running - a kernel binary from a different physical address than it has - been compiled for. - - One use is for the kexec on panic case where the recovery kernel - must live at a different physical address than the primary - kernel. - - Note: If CONFIG_RELOCATABLE=y, then kernel run from the address - it has been loaded at and compile time physical address - (CONFIG_PHYSICAL_START) is ignored. - config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) + default "0x1000000" if CRASH_DUMP default "0x200000" help - This gives the physical address where the kernel is loaded. It - should be aligned to 2MB boundary. - - If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then - bzImage will decompress itself to above physical address and - run from there. Otherwise, bzImage will run from the address where - it has been loaded by the boot loader and will ignore above physical - address. - - In normal kdump cases one does not have to set/change this option - as now bzImage can be compiled as a completely relocatable image - (CONFIG_RELOCATABLE=y) and be used to load and run from a different - address. This option is mainly useful for the folks who don't want - to use a bzImage for capturing the crash dump and want to use a - vmlinux instead. - - So if you are using bzImage for capturing the crash dump, leave - the value here unchanged to 0x200000 and set CONFIG_RELOCATABLE=y. - Otherwise if you plan to use vmlinux for capturing the crash dump - change this value to start of the reserved region (Typically 16MB - 0x1000000). In other words, it can be set based on the "X" value as + This gives the physical address where the kernel is loaded. Normally + for regular kernels this value is 0x200000 (2MB). But in the case + of kexec on panic the fail safe kernel needs to run at a different + address than the panic-ed kernel. This option is used to set the load + address for kernels used to capture crash dump on being kexec'ed + after panic. The default value for crash dump kernels is + 0x1000000 (16MB). This can also be set based on the "X" value as specified in the "crashkernel=YM@XM" command line boot parameter passed to the panic-ed kernel. Typically this parameter is set as crashkernel=64M@16M. Please take a look at Documentation/kdump/kdump.txt for more details about crash dumps. - Usage of bzImage for capturing the crash dump is advantageous as - one does not have to build two kernels. Same kernel can be used - as production kernel and capture kernel. - Don't change this unless you know what you are doing. config SECCOMP @@ -660,6 +627,14 @@ config CC_STACKPROTECTOR_ALL source kernel/Kconfig.hz +config REORDER + bool "Function reordering" + default n + help + This option enables the toolchain to reorder functions for a more + optimal TLB usage. If you have pretty much any version of binutils, + this can increase your kernel build time by roughly one minute. + config K8_NB def_bool y depends on AGP_AMD64 || IOMMU || (PCI && NUMA) @@ -701,7 +676,6 @@ menu "Bus options (PCI etc.)" config PCI bool "PCI support" - select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC) # x86-64 doesn't support PCI BIOS access from long mode so always go direct. config PCI_DIRECT diff --git a/trunk/arch/x86_64/Makefile b/trunk/arch/x86_64/Makefile index 29617ae3926d..2941a915d4ef 100644 --- a/trunk/arch/x86_64/Makefile +++ b/trunk/arch/x86_64/Makefile @@ -40,6 +40,10 @@ cflags-y += -m64 cflags-y += -mno-red-zone cflags-y += -mcmodel=kernel cflags-y += -pipe +cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections +# this makes reading assembly source easier, but produces worse code +# actually it makes the kernel smaller too. +cflags-y += -fno-reorder-blocks cflags-y += -Wno-sign-compare cflags-y += -fno-asynchronous-unwind-tables ifneq ($(CONFIG_DEBUG_INFO),y) diff --git a/trunk/arch/x86_64/boot/Makefile b/trunk/arch/x86_64/boot/Makefile index ee6f6505f95f..deb063e7762d 100644 --- a/trunk/arch/x86_64/boot/Makefile +++ b/trunk/arch/x86_64/boot/Makefile @@ -36,7 +36,7 @@ subdir- := compressed/ #Let make clean descend in compressed/ # --------------------------------------------------------------------------- $(obj)/bzImage: IMAGE_OFFSET := 0x100000 -$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ +$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ $(obj)/bzImage: BUILDFLAGS := -b quiet_cmd_image = BUILD $@ diff --git a/trunk/arch/x86_64/boot/compressed/Makefile b/trunk/arch/x86_64/boot/compressed/Makefile index 705a3e33d7e1..e70fa6e1da08 100644 --- a/trunk/arch/x86_64/boot/compressed/Makefile +++ b/trunk/arch/x86_64/boot/compressed/Makefile @@ -8,14 +8,16 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o EXTRA_AFLAGS := -traditional +AFLAGS := $(subst -m64,-m32,$(AFLAGS)) # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with # -m32 -CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin -LDFLAGS := -m elf_x86_64 +CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing +LDFLAGS := -m elf_i386 -LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386 + +$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: @@ -25,7 +27,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE $(call if_changed,gzip) -LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T +LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld) diff --git a/trunk/arch/x86_64/boot/compressed/head.S b/trunk/arch/x86_64/boot/compressed/head.S index f9d5692a0106..6f55565e4d42 100644 --- a/trunk/arch/x86_64/boot/compressed/head.S +++ b/trunk/arch/x86_64/boot/compressed/head.S @@ -26,279 +26,116 @@ #include #include -#include #include -#include -.section ".text.head" .code32 .globl startup_32 - + startup_32: cld cli - movl $(__KERNEL_DS), %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - -/* Calculate the delta between where we were compiled to run - * at and where we were actually loaded at. This can only be done - * with a short local call on x86. Nothing else will tell us what - * address we are running at. The reserved chunk of the real-mode - * data at 0x34-0x3f are used as the stack for this calculation. - * Only 4 bytes are needed. - */ - leal 0x40(%esi), %esp - call 1f -1: popl %ebp - subl $1b, %ebp - -/* setup a stack and make sure cpu supports long mode. */ - movl $user_stack_end, %eax - addl %ebp, %eax - movl %eax, %esp - - call verify_cpu - testl %eax, %eax - jnz no_longmode - -/* Compute the delta between where we were compiled to run at - * and where the code will actually run at. - */ -/* %ebp contains the address we are loaded at by the boot loader and %ebx - * contains the address where we should move the kernel image temporarily - * for safe in-place decompression. - */ - -#ifdef CONFIG_RELOCATABLE - movl %ebp, %ebx - addl $(LARGE_PAGE_SIZE -1), %ebx - andl $LARGE_PAGE_MASK, %ebx -#else - movl $CONFIG_PHYSICAL_START, %ebx -#endif - - /* Replace the compressed data size with the uncompressed size */ - subl input_len(%ebp), %ebx - movl output_len(%ebp), %eax - addl %eax, %ebx - /* Add 8 bytes for every 32K input block */ - shrl $12, %eax - addl %eax, %ebx - /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ - addl $(32768 + 18 + 4095), %ebx - andl $~4095, %ebx + movl $(__KERNEL_DS),%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs + + lss stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b /* - * Prepare for entering 64 bit mode + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. */ - - /* Load new GDT with the 64bit segments using 32bit descriptor */ - leal gdt(%ebp), %eax - movl %eax, gdt+2(%ebp) - lgdt gdt(%ebp) - - /* Enable PAE mode */ - xorl %eax, %eax - orl $(1 << 5), %eax - movl %eax, %cr4 - - /* - * Build early 4G boot pagetable - */ - /* Initialize Page tables to 0*/ - leal pgtable(%ebx), %edi - xorl %eax, %eax - movl $((4096*6)/4), %ecx - rep stosl - - /* Build Level 4 */ - leal pgtable + 0(%ebx), %edi - leal 0x1007 (%edi), %eax - movl %eax, 0(%edi) - - /* Build Level 3 */ - leal pgtable + 0x1000(%ebx), %edi - leal 0x1007(%edi), %eax - movl $4, %ecx -1: movl %eax, 0x00(%edi) - addl $0x00001000, %eax - addl $8, %edi - decl %ecx - jnz 1b - - /* Build Level 2 */ - leal pgtable + 0x2000(%ebx), %edi - movl $0x00000183, %eax - movl $2048, %ecx -1: movl %eax, 0(%edi) - addl $0x00200000, %eax - addl $8, %edi - decl %ecx - jnz 1b - - /* Enable the boot page tables */ - leal pgtable(%ebx), %eax - movl %eax, %cr3 - - /* Enable Long mode in EFER (Extended Feature Enable Register) */ - movl $MSR_EFER, %ecx - rdmsr - btsl $_EFER_LME, %eax - wrmsr - - /* Setup for the jump to 64bit mode - * - * When the jump is performend we will be in long mode but - * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 - * (and in turn EFER.LMA = 1). To jump into 64bit mode we use - * the new gdt/idt that has __KERNEL_CS with CS.L = 1. - * We place all of the values on our mini stack so lret can - * used to perform that far jump. - */ - pushl $__KERNEL_CS - leal startup_64(%ebp), %eax - pushl %eax - - /* Enter paged protected Mode, activating Long Mode */ - movl $0x80000001, %eax /* Enable Paging and Protected mode */ - movl %eax, %cr0 - - /* Jump from 32bit compatibility mode into 64bit mode. */ - lret - -no_longmode: - /* This isn't an x86-64 CPU so hang */ -1: - hlt - jmp 1b - -#include "../../kernel/verify_cpu.S" - - /* Be careful here startup_64 needs to be at a predictable - * address so I can export it in an ELF header. Bootloaders - * should look at the ELF header to find this address, as - * it may change in the future. - */ - .code64 - .org 0x200 -ENTRY(startup_64) - /* We come here either from startup_32 or directly from a - * 64bit bootloader. If we come here from a bootloader we depend on - * an identity mapped page table being provied that maps our - * entire text+data+bss and hopefully all of memory. - */ - - /* Setup data segments. */ - xorl %eax, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - /* Compute the decompressed kernel start address. It is where - * we were loaded at aligned to a 2M boundary. %rbp contains the - * decompressed kernel start address. - * - * If it is a relocatable kernel then decompress and run the kernel - * from load address aligned to 2MB addr, otherwise decompress and - * run the kernel from CONFIG_PHYSICAL_START - */ - - /* Start with the delta to where the kernel will run at. */ -#ifdef CONFIG_RELOCATABLE - leaq startup_32(%rip) /* - $startup_32 */, %rbp - addq $(LARGE_PAGE_SIZE - 1), %rbp - andq $LARGE_PAGE_MASK, %rbp - movq %rbp, %rbx -#else - movq $CONFIG_PHYSICAL_START, %rbp - movq %rbp, %rbx -#endif - - /* Replace the compressed data size with the uncompressed size */ - movl input_len(%rip), %eax - subq %rax, %rbx - movl output_len(%rip), %eax - addq %rax, %rbx - /* Add 8 bytes for every 32K input block */ - shrq $12, %rax - addq %rax, %rbx - /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ - addq $(32768 + 18 + 4095), %rbx - andq $~4095, %rbx - -/* Copy the compressed kernel to the end of our buffer - * where decompression in place becomes safe. - */ - leaq _end(%rip), %r8 - leaq _end(%rbx), %r9 - movq $_end /* - $startup_32 */, %rcx -1: subq $8, %r8 - subq $8, %r9 - movq 0(%r8), %rax - movq %rax, 0(%r9) - subq $8, %rcx - jnz 1b - -/* - * Jump to the relocated address. - */ - leaq relocated(%rbx), %rax - jmp *%rax - -.section ".text" -relocated: - + pushl $0 + popfl /* * Clear BSS */ - xorq %rax, %rax - leaq _edata(%rbx), %rdi - leaq _end(%rbx), %rcx - subq %rdi, %rcx + xorl %eax,%eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi,%ecx cld rep stosb - - /* Setup the stack */ - leaq user_stack_end(%rip), %rsp - - /* zero EFLAGS after setting rsp */ - pushq $0 - popfq - /* * Do the decompression, and jump to the new kernel.. */ - pushq %rsi # Save the real mode argument - movq %rsi, %rdi # real mode address - leaq _heap(%rip), %rsi # _heap - leaq input_data(%rip), %rdx # input_data - movl input_len(%rip), %eax - movq %rax, %rcx # input_len - movq %rbp, %r8 # output - call decompress_kernel - popq %rsi + subl $16,%esp # place for structure on the stack + movl %esp,%eax + pushl %esi # real mode pointer as second arg + pushl %eax # address of structure as first arg + call decompress_kernel + orl %eax,%eax + jnz 3f + addl $8,%esp + xorl %ebx,%ebx + ljmp $(__KERNEL_CS), $__PHYSICAL_START +/* + * We come here, if we were loaded high. + * We need to move the move-in-place routine down to 0x1000 + * and then start it with the buffer addresses in registers, + * which we got from the stack. + */ +3: + movl %esi,%ebx + movl $move_routine_start,%esi + movl $0x1000,%edi + movl $move_routine_end,%ecx + subl %esi,%ecx + addl $3,%ecx + shrl $2,%ecx + cld + rep + movsl + + popl %esi # discard the address + addl $4,%esp # real mode pointer + popl %esi # low_buffer_start + popl %ecx # lcount + popl %edx # high_buffer_start + popl %eax # hcount + movl $__PHYSICAL_START,%edi + cli # make sure we don't get interrupted + ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine /* - * Jump to the decompressed kernel. + * Routine (template) for moving the decompressed kernel in place, + * if we were high loaded. This _must_ PIC-code ! */ - jmp *%rbp +move_routine_start: + movl %ecx,%ebp + shrl $2,%ecx + rep + movsl + movl %ebp,%ecx + andl $3,%ecx + rep + movsb + movl %edx,%esi + movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 + addl $3,%ecx + shrl $2,%ecx + rep + movsl + movl %ebx,%esi # Restore setup pointer + xorl %ebx,%ebx + ljmp $(__KERNEL_CS), $__PHYSICAL_START +move_routine_end: - .data -gdt: - .word gdt_end - gdt - .long gdt - .word 0 - .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x00af9a000000ffff /* __KERNEL_CS */ - .quad 0x00cf92000000ffff /* __KERNEL_DS */ -gdt_end: - .bss -/* Stack for uncompression */ - .balign 4 -user_stack: + +/* Stack for uncompression */ + .align 32 +user_stack: .fill 4096,4,0 -user_stack_end: +stack_start: + .long user_stack+4096 + .word __KERNEL_DS + diff --git a/trunk/arch/x86_64/boot/compressed/misc.c b/trunk/arch/x86_64/boot/compressed/misc.c index f932b0e89096..3755b2e394d0 100644 --- a/trunk/arch/x86_64/boot/compressed/misc.c +++ b/trunk/arch/x86_64/boot/compressed/misc.c @@ -9,95 +9,10 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ -#define _LINUX_STRING_H_ 1 -#define __LINUX_BITMAP_H 1 - -#include #include #include #include -/* WARNING!! - * This code is compiled with -fPIC and it is relocated dynamically - * at run time, but no relocation processing is performed. - * This means that it is not safe to place pointers in static structures. - */ - -/* - * Getting to provable safe in place decompression is hard. - * Worst case behaviours need to be analized. - * Background information: - * - * The file layout is: - * magic[2] - * method[1] - * flags[1] - * timestamp[4] - * extraflags[1] - * os[1] - * compressed data blocks[N] - * crc[4] orig_len[4] - * - * resulting in 18 bytes of non compressed data overhead. - * - * Files divided into blocks - * 1 bit (last block flag) - * 2 bits (block type) - * - * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved. - * The smallest block type encoding is always used. - * - * stored: - * 32 bits length in bytes. - * - * fixed: - * magic fixed tree. - * symbols. - * - * dynamic: - * dynamic tree encoding. - * symbols. - * - * - * The buffer for decompression in place is the length of the - * uncompressed data, plus a small amount extra to keep the algorithm safe. - * The compressed data is placed at the end of the buffer. The output - * pointer is placed at the start of the buffer and the input pointer - * is placed where the compressed data starts. Problems will occur - * when the output pointer overruns the input pointer. - * - * The output pointer can only overrun the input pointer if the input - * pointer is moving faster than the output pointer. A condition only - * triggered by data whose compressed form is larger than the uncompressed - * form. - * - * The worst case at the block level is a growth of the compressed data - * of 5 bytes per 32767 bytes. - * - * The worst case internal to a compressed block is very hard to figure. - * The worst case can at least be boundined by having one bit that represents - * 32764 bytes and then all of the rest of the bytes representing the very - * very last byte. - * - * All of which is enough to compute an amount of extra data that is required - * to be safe. To avoid problems at the block level allocating 5 extra bytes - * per 32767 bytes of data is sufficient. To avoind problems internal to a block - * adding an extra 32767 bytes (the worst case uncompressed block size) is - * sufficient, to ensure that in the worst case the decompressed data for - * block will stop the byte before the compressed data for a block begins. - * To avoid problems with the compressed data's meta information an extra 18 - * bytes are needed. Leading to the formula: - * - * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. - * - * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. - * Adding 32768 instead of 32767 just makes for round numbers. - * Adding the decompressor_size is necessary as it musht live after all - * of the data as well. Last I measured the decompressor is about 14K. - * 10K of actuall data and 4K of bss. - * - */ - /* * gzip declarations */ @@ -113,20 +28,15 @@ typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; -#define WSIZE 0x80000000 /* Window size must be at least 32k, - * and a power of two - * We don't actually have a window just - * a huge output buffer so I report - * a 2G windows size, as that should - * always be larger than our output buffer. - */ +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ -static uch *inbuf; /* input buffer */ -static uch *window; /* Sliding window buffer, (and final output buffer) */ +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ -static unsigned insize; /* valid bytes in inbuf */ -static unsigned inptr; /* index of next byte to be processed in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ @@ -177,6 +87,8 @@ extern unsigned char input_data[]; extern int input_len; static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; static void *malloc(int size); static void free(void *where); @@ -186,10 +98,17 @@ static void *memcpy(void *dest, const void *src, unsigned n); static void putstr(const char *); -static long free_mem_ptr; +extern int end; +static long free_mem_ptr = (long)&end; static long free_mem_end_ptr; -#define HEAP_SIZE 0x7000 +#define INPLACE_MOVE_ROUTINE 0x1000 +#define LOW_BUFFER_START 0x2000 +#define LOW_BUFFER_MAX 0x90000 +#define HEAP_SIZE 0x3000 +static unsigned int low_buffer_end, low_buffer_size; +static int high_loaded =0; +static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; static char *vidmem = (char *)0xb8000; static int vidport; @@ -299,31 +218,58 @@ static void* memcpy(void* dest, const void* src, unsigned n) */ static int fill_inbuf(void) { - error("ran out of input data"); - return 0; + if (insize != 0) { + error("ran out of input data"); + } + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ +static void flush_window_low(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void flush_window_high(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + in = window; + for (n = 0; n < outcnt; n++) { + ch = *output_data++ = *in++; + if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + static void flush_window(void) { - /* With my window equal to my output buffer - * I only need to compute the crc here. - */ - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, ch; - - in = window; - for (n = 0; n < outcnt; n++) { - ch = *in++; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - outcnt = 0; + if (high_loaded) flush_window_high(); + else flush_window_low(); } static void error(char *x) @@ -335,8 +281,57 @@ static void error(char *x) while(1); /* Halt */ } -asmlinkage void decompress_kernel(void *rmode, unsigned long heap, - uch *input_data, unsigned long input_len, uch *output) +static void setup_normal_output_buffer(void) +{ +#ifdef STANDARD_MEMORY_BIOS_CALL + if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory"); +#else + if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); +#endif + output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */ + free_mem_end_ptr = (long)real_mode; +} + +struct moveparams { + uch *low_buffer_start; int lcount; + uch *high_buffer_start; int hcount; +}; + +static void setup_output_buffer_if_we_run_high(struct moveparams *mv) +{ + high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); +#ifdef STANDARD_MEMORY_BIOS_CALL + if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory"); +#else + if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); +#endif + mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; + low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX + ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; + low_buffer_size = low_buffer_end - LOW_BUFFER_START; + high_loaded = 1; + free_mem_end_ptr = (long)high_buffer_start; + if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); + mv->hcount = 0; /* say: we need not to move high_buffer */ + } + else mv->hcount = -1; + mv->high_buffer_start = high_buffer_start; +} + +static void close_output_buffer_if_we_run_high(struct moveparams *mv) +{ + if (bytes_out > low_buffer_size) { + mv->lcount = low_buffer_size; + if (mv->hcount) + mv->hcount = bytes_out - low_buffer_size; + } else { + mv->lcount = bytes_out; + mv->hcount = 0; + } +} + +int decompress_kernel(struct moveparams *mv, void *rmode) { real_mode = rmode; @@ -351,21 +346,13 @@ asmlinkage void decompress_kernel(void *rmode, unsigned long heap, lines = RM_SCREEN_INFO.orig_video_lines; cols = RM_SCREEN_INFO.orig_video_cols; - window = output; /* Output buffer (Normally at 1M) */ - free_mem_ptr = heap; /* Heap */ - free_mem_end_ptr = heap + HEAP_SIZE; - inbuf = input_data; /* Input buffer */ - insize = input_len; - inptr = 0; - - if ((ulg)output & (__KERNEL_ALIGN - 1)) - error("Destination address not 2M aligned"); - if ((ulg)output >= 0xffffffffffUL) - error("Destination address too large"); + if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); + else setup_output_buffer_if_we_run_high(mv); makecrc(); putstr(".\nDecompressing Linux..."); gunzip(); putstr("done.\nBooting the kernel.\n"); - return; + if (high_loaded) close_output_buffer_if_we_run_high(mv); + return high_loaded; } diff --git a/trunk/arch/x86_64/boot/compressed/vmlinux.lds b/trunk/arch/x86_64/boot/compressed/vmlinux.lds deleted file mode 100644 index 94c13e557fb4..000000000000 --- a/trunk/arch/x86_64/boot/compressed/vmlinux.lds +++ /dev/null @@ -1,44 +0,0 @@ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(startup_64) -SECTIONS -{ - /* Be careful parts of head.S assume startup_32 is at - * address 0. - */ - . = 0; - .text : { - _head = . ; - *(.text.head) - _ehead = . ; - *(.text.compressed) - _text = .; /* Text */ - *(.text) - *(.text.*) - _etext = . ; - } - .rodata : { - _rodata = . ; - *(.rodata) /* read-only data */ - *(.rodata.*) - _erodata = . ; - } - .data : { - _data = . ; - *(.data) - *(.data.*) - _edata = . ; - } - .bss : { - _bss = . ; - *(.bss) - *(.bss.*) - *(COMMON) - . = ALIGN(8); - _end = . ; - . = ALIGN(4096); - pgtable = . ; - . = . + 4096 * 6; - _heap = .; - } -} diff --git a/trunk/arch/x86_64/boot/compressed/vmlinux.scr b/trunk/arch/x86_64/boot/compressed/vmlinux.scr index bd1429ce193e..1ed9d791f863 100644 --- a/trunk/arch/x86_64/boot/compressed/vmlinux.scr +++ b/trunk/arch/x86_64/boot/compressed/vmlinux.scr @@ -1,10 +1,9 @@ SECTIONS { - .text.compressed : { + .data : { input_len = .; - LONG(input_data_end - input_data) input_data = .; - *(.data) - output_len = . - 4; - input_data_end = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; } } diff --git a/trunk/arch/x86_64/boot/setup.S b/trunk/arch/x86_64/boot/setup.S index e9e33f949697..770940cc0108 100644 --- a/trunk/arch/x86_64/boot/setup.S +++ b/trunk/arch/x86_64/boot/setup.S @@ -51,7 +51,6 @@ #include #include #include -#include /* Signature words to ensure LILO loaded us right */ #define SIG1 0xAA55 @@ -81,7 +80,7 @@ start: # This is the setup header, and it must start at %cs:2 (old 0x9020:2) .ascii "HdrS" # header signature - .word 0x0206 # header version number (>= 0x0105) + .word 0x0204 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) realmode_swtch: .word 0, 0 # default_switch, SETUPSEG start_sys_seg: .word SYSSEG @@ -156,20 +155,7 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # low memory 0x10000 or higher. ramdisk_max: .long 0xffffffff -kernel_alignment: .long 0x200000 # physical addr alignment required for - # protected mode relocatable kernel -#ifdef CONFIG_RELOCATABLE -relocatable_kernel: .byte 1 -#else -relocatable_kernel: .byte 0 -#endif -pad2: .byte 0 -pad3: .word 0 - -cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, - #added with boot protocol - #version 2.06 - + trampoline: call start_of_setup .align 16 # The offset at this point is 0x240 @@ -304,10 +290,64 @@ loader_ok: movw %cs,%ax movw %ax,%ds - call verify_cpu - testl %eax,%eax - jz sse_ok - + /* minimum CPUID flags for x86-64 */ + /* see http://www.x86-64.org/lists/discuss/msg02971.html */ +#define SSE_MASK ((1<<25)|(1<<26)) +#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\ + (1<<13)|(1<<15)|(1<<24)) +#define REQUIRED_MASK2 (1<<29) + + pushfl /* standard way to check for cpuid */ + popl %eax + movl %eax,%ebx + xorl $0x200000,%eax + pushl %eax + popfl + pushfl + popl %eax + cmpl %eax,%ebx + jz no_longmode /* cpu has no cpuid */ + movl $0x0,%eax + cpuid + cmpl $0x1,%eax + jb no_longmode /* no cpuid 1 */ + xor %di,%di + cmpl $0x68747541,%ebx /* AuthenticAMD */ + jnz noamd + cmpl $0x69746e65,%edx + jnz noamd + cmpl $0x444d4163,%ecx + jnz noamd + mov $1,%di /* cpu is from AMD */ +noamd: + movl $0x1,%eax + cpuid + andl $REQUIRED_MASK1,%edx + xorl $REQUIRED_MASK1,%edx + jnz no_longmode + movl $0x80000000,%eax + cpuid + cmpl $0x80000001,%eax + jb no_longmode /* no extended cpuid */ + movl $0x80000001,%eax + cpuid + andl $REQUIRED_MASK2,%edx + xorl $REQUIRED_MASK2,%edx + jnz no_longmode +sse_test: + movl $1,%eax + cpuid + andl $SSE_MASK,%edx + cmpl $SSE_MASK,%edx + je sse_ok + test %di,%di + jz no_longmode /* only try to force SSE on AMD */ + movl $0xc0010015,%ecx /* HWCR */ + rdmsr + btr $15,%eax /* enable SSE */ + wrmsr + xor %di,%di /* don't loop */ + jmp sse_test /* try again */ no_longmode: call beep lea long_mode_panic,%si @@ -317,8 +357,7 @@ no_longmode_loop: long_mode_panic: .string "Your CPU does not support long mode. Use a 32bit distribution." .byte 0 - -#include "../kernel/verify_cpu.S" + sse_ok: popw %ds @@ -807,7 +846,7 @@ gdt_48: # Include video setup & detection code -#include "../../i386/boot/video.S" +#include "video.S" # Setup signature -- must be last setup_sig1: .word SIG1 diff --git a/trunk/arch/x86_64/boot/video.S b/trunk/arch/x86_64/boot/video.S new file mode 100644 index 000000000000..6090516c9c7f --- /dev/null +++ b/trunk/arch/x86_64/boot/video.S @@ -0,0 +1,2043 @@ +/* video.S + * + * Display adapter & video mode setup, version 2.13 (14-May-99) + * + * Copyright (C) 1995 -- 1998 Martin Mares + * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson + * + * Rewritten to use GNU 'as' by Chris Noe May 1999 + * + * For further information, look at Documentation/svga.txt. + * + */ + +/* Enable autodetection of SVGA adapters and modes. */ +#undef CONFIG_VIDEO_SVGA + +/* Enable autodetection of VESA modes */ +#define CONFIG_VIDEO_VESA + +/* Enable compacting of mode table */ +#define CONFIG_VIDEO_COMPACT + +/* Retain screen contents when switching modes */ +#define CONFIG_VIDEO_RETAIN + +/* Enable local mode list */ +#undef CONFIG_VIDEO_LOCAL + +/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ +#undef CONFIG_VIDEO_400_HACK + +/* Hack that lets you force specific BIOS mode ID and specific dimensions */ +#undef CONFIG_VIDEO_GFX_HACK +#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */ +#define VIDEO_GFX_BIOS_BX 0x0102 +#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */ + +/* This code uses an extended set of video mode numbers. These include: + * Aliases for standard modes + * NORMAL_VGA (-1) + * EXTENDED_VGA (-2) + * ASK_VGA (-3) + * Video modes numbered by menu position -- NOT RECOMMENDED because of lack + * of compatibility when extending the table. These are between 0x00 and 0xff. + */ +#define VIDEO_FIRST_MENU 0x0000 + +/* Standard BIOS video modes (BIOS number + 0x0100) */ +#define VIDEO_FIRST_BIOS 0x0100 + +/* VESA BIOS video modes (VESA number + 0x0200) */ +#define VIDEO_FIRST_VESA 0x0200 + +/* Video7 special modes (BIOS number + 0x0900) */ +#define VIDEO_FIRST_V7 0x0900 + +/* Special video modes */ +#define VIDEO_FIRST_SPECIAL 0x0f00 +#define VIDEO_80x25 0x0f00 +#define VIDEO_8POINT 0x0f01 +#define VIDEO_80x43 0x0f02 +#define VIDEO_80x28 0x0f03 +#define VIDEO_CURRENT_MODE 0x0f04 +#define VIDEO_80x30 0x0f05 +#define VIDEO_80x34 0x0f06 +#define VIDEO_80x60 0x0f07 +#define VIDEO_GFX_HACK 0x0f08 +#define VIDEO_LAST_SPECIAL 0x0f09 + +/* Video modes given by resolution */ +#define VIDEO_FIRST_RESOLUTION 0x1000 + +/* The "recalculate timings" flag */ +#define VIDEO_RECALC 0x8000 + +/* Positions of various video parameters passed to the kernel */ +/* (see also include/linux/tty.h) */ +#define PARAM_CURSOR_POS 0x00 +#define PARAM_VIDEO_PAGE 0x04 +#define PARAM_VIDEO_MODE 0x06 +#define PARAM_VIDEO_COLS 0x07 +#define PARAM_VIDEO_EGA_BX 0x0a +#define PARAM_VIDEO_LINES 0x0e +#define PARAM_HAVE_VGA 0x0f +#define PARAM_FONT_POINTS 0x10 + +#define PARAM_LFB_WIDTH 0x12 +#define PARAM_LFB_HEIGHT 0x14 +#define PARAM_LFB_DEPTH 0x16 +#define PARAM_LFB_BASE 0x18 +#define PARAM_LFB_SIZE 0x1c +#define PARAM_LFB_LINELENGTH 0x24 +#define PARAM_LFB_COLORS 0x26 +#define PARAM_VESAPM_SEG 0x2e +#define PARAM_VESAPM_OFF 0x30 +#define PARAM_LFB_PAGES 0x32 +#define PARAM_VESA_ATTRIB 0x34 +#define PARAM_CAPABILITIES 0x36 + +/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ +#ifdef CONFIG_VIDEO_RETAIN +#define DO_STORE call store_screen +#else +#define DO_STORE +#endif /* CONFIG_VIDEO_RETAIN */ + +# This is the main entry point called by setup.S +# %ds *must* be pointing to the bootsector +video: pushw %ds # We use different segments + pushw %ds # FS contains original DS + popw %fs + pushw %cs # DS is equal to CS + popw %ds + pushw %cs # ES is equal to CS + popw %es + xorw %ax, %ax + movw %ax, %gs # GS is zero + cld + call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA) +#ifdef CONFIG_VIDEO_SELECT + movw %fs:(0x01fa), %ax # User selected video mode + cmpw $ASK_VGA, %ax # Bring up the menu + jz vid2 + + call mode_set # Set the mode + jc vid1 + + leaw badmdt, %si # Invalid mode ID + call prtstr +vid2: call mode_menu +vid1: +#ifdef CONFIG_VIDEO_RETAIN + call restore_screen # Restore screen contents +#endif /* CONFIG_VIDEO_RETAIN */ + call store_edid +#endif /* CONFIG_VIDEO_SELECT */ + call mode_params # Store mode parameters + popw %ds # Restore original DS + ret + +# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. +basic_detect: + movb $0, %fs:(PARAM_HAVE_VGA) + movb $0x12, %ah # Check EGA/VGA + movb $0x10, %bl + int $0x10 + movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel + cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card. + je basret + + incb adapter + movw $0x1a00, %ax # Check EGA or VGA? + int $0x10 + cmpb $0x1a, %al # 1a means VGA... + jne basret # anything else is EGA. + + incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA + incb adapter +basret: ret + +# Store the video mode parameters for later usage by the kernel. +# This is done by asking the BIOS except for the rows/columns +# parameters in the default 80x25 mode -- these are set directly, +# because some very obscure BIOSes supply insane values. +mode_params: +#ifdef CONFIG_VIDEO_SELECT + cmpb $0, graphic_mode + jnz mopar_gr +#endif + movb $0x03, %ah # Read cursor position + xorb %bh, %bh + int $0x10 + movw %dx, %fs:(PARAM_CURSOR_POS) + movb $0x0f, %ah # Read page/mode/width + int $0x10 + movw %bx, %fs:(PARAM_VIDEO_PAGE) + movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width + cmpb $0x7, %al # MDA/HGA => segment differs + jnz mopar0 + + movw $0xb000, video_segment +mopar0: movw %gs:(0x485), %ax # Font size + movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA) + movw force_size, %ax # Forced size? + orw %ax, %ax + jz mopar1 + + movb %ah, %fs:(PARAM_VIDEO_COLS) + movb %al, %fs:(PARAM_VIDEO_LINES) + ret + +mopar1: movb $25, %al + cmpb $0, adapter # If we are on CGA/MDA/HGA, the + jz mopar2 # screen must have 25 lines. + + movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS + incb %al # location of max lines. +mopar2: movb %al, %fs:(PARAM_VIDEO_LINES) + ret + +#ifdef CONFIG_VIDEO_SELECT +# Fetching of VESA frame buffer parameters +mopar_gr: + leaw modelist+1024, %di + movb $0x23, %fs:(PARAM_HAVE_VGA) + movw 16(%di), %ax + movw %ax, %fs:(PARAM_LFB_LINELENGTH) + movw 18(%di), %ax + movw %ax, %fs:(PARAM_LFB_WIDTH) + movw 20(%di), %ax + movw %ax, %fs:(PARAM_LFB_HEIGHT) + movb 25(%di), %al + movb $0, %ah + movw %ax, %fs:(PARAM_LFB_DEPTH) + movb 29(%di), %al + movb $0, %ah + movw %ax, %fs:(PARAM_LFB_PAGES) + movl 40(%di), %eax + movl %eax, %fs:(PARAM_LFB_BASE) + movl 31(%di), %eax + 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 + movw $0x4f00, %ax + int $0x10 + xorl %eax, %eax + movw 18(%di), %ax + movl %eax, %fs:(PARAM_LFB_SIZE) + +# store mode capabilities + movl 10(%di), %eax + movl %eax, %fs:(PARAM_CAPABILITIES) + +# switching the DAC to 8-bit is for <= 8 bpp only + movw %fs:(PARAM_LFB_DEPTH), %ax + cmpw $8, %ax + jg dac_done + +# get DAC switching capability + xorl %eax, %eax + movb 10(%di), %al + testb $1, %al + jz dac_set + +# attempt to switch DAC to 8-bit + movw $0x4f08, %ax + movw $0x0800, %bx + int $0x10 + cmpw $0x004f, %ax + jne dac_set + movb %bh, dac_size # store actual DAC size + +dac_set: +# set color size to DAC size + movb dac_size, %al + movb %al, %fs:(PARAM_LFB_COLORS+0) + movb %al, %fs:(PARAM_LFB_COLORS+2) + movb %al, %fs:(PARAM_LFB_COLORS+4) + movb %al, %fs:(PARAM_LFB_COLORS+6) + +# set color offsets to 0 + movb $0, %fs:(PARAM_LFB_COLORS+1) + movb $0, %fs:(PARAM_LFB_COLORS+3) + movb $0, %fs:(PARAM_LFB_COLORS+5) + movb $0, %fs:(PARAM_LFB_COLORS+7) + +dac_done: +# get protected mode interface informations + movw $0x4f0a, %ax + xorw %bx, %bx + xorw %di, %di + int $0x10 + cmp $0x004f, %ax + jnz no_pm + + movw %es, %fs:(PARAM_VESAPM_SEG) + movw %di, %fs:(PARAM_VESAPM_OFF) +no_pm: ret + +# The video mode menu +mode_menu: + leaw keymsg, %si # "Return/Space/Timeout" message + call prtstr + call flush +nokey: call getkt + + cmpb $0x0d, %al # ENTER ? + je listm # yes - manual mode selection + + cmpb $0x20, %al # SPACE ? + je defmd1 # no - repeat + + call beep + jmp nokey + +defmd1: ret # No mode chosen? Default 80x25 + +listm: call mode_table # List mode table +listm0: leaw name_bann, %si # Print adapter name + call prtstr + movw card_name, %si + orw %si, %si + jnz an2 + + movb adapter, %al + leaw old_name, %si + orb %al, %al + jz an1 + + leaw ega_name, %si + decb %al + jz an1 + + leaw vga_name, %si + jmp an1 + +an2: call prtstr + leaw svga_name, %si +an1: call prtstr + leaw listhdr, %si # Table header + call prtstr + movb $0x30, %dl # DL holds mode number + leaw modelist, %si +lm1: cmpw $ASK_VGA, (%si) # End? + jz lm2 + + movb %dl, %al # Menu selection number + call prtchr + call prtsp2 + lodsw + call prthw # Mode ID + call prtsp2 + movb 0x1(%si), %al + call prtdec # Rows + movb $0x78, %al # the letter 'x' + call prtchr + lodsw + call prtdec # Columns + movb $0x0d, %al # New line + call prtchr + movb $0x0a, %al + call prtchr + incb %dl # Next character + cmpb $0x3a, %dl + jnz lm1 + + movb $0x61, %dl + jmp lm1 + +lm2: leaw prompt, %si # Mode prompt + call prtstr + leaw edit_buf, %di # Editor buffer +lm3: call getkey + cmpb $0x0d, %al # Enter? + jz lment + + cmpb $0x08, %al # Backspace? + jz lmbs + + cmpb $0x20, %al # Printable? + jc lm3 + + cmpw $edit_buf+4, %di # Enough space? + jz lm3 + + stosb + call prtchr + jmp lm3 + +lmbs: cmpw $edit_buf, %di # Backspace + jz lm3 + + decw %di + movb $0x08, %al + call prtchr + call prtspc + movb $0x08, %al + call prtchr + jmp lm3 + +lment: movb $0, (%di) + leaw crlft, %si + call prtstr + leaw edit_buf, %si + cmpb $0, (%si) # Empty string = default mode + jz lmdef + + cmpb $0, 1(%si) # One character = menu selection + jz mnusel + + cmpw $0x6373, (%si) # "scan" => mode scanning + jnz lmhx + + cmpw $0x6e61, 2(%si) + jz lmscan + +lmhx: xorw %bx, %bx # Else => mode ID in hex +lmhex: lodsb + orb %al, %al + jz lmuse1 + + subb $0x30, %al + jc lmbad + + cmpb $10, %al + jc lmhx1 + + subb $7, %al + andb $0xdf, %al + cmpb $10, %al + jc lmbad + + cmpb $16, %al + jnc lmbad + +lmhx1: shlw $4, %bx + orb %al, %bl + jmp lmhex + +lmuse1: movw %bx, %ax + jmp lmuse + +mnusel: lodsb # Menu selection + xorb %ah, %ah + subb $0x30, %al + jc lmbad + + cmpb $10, %al + jc lmuse + + cmpb $0x61-0x30, %al + jc lmbad + + subb $0x61-0x30-10, %al + cmpb $36, %al + jnc lmbad + +lmuse: call mode_set + jc lmdef + +lmbad: leaw unknt, %si + call prtstr + jmp lm2 +lmscan: cmpb $0, adapter # Scanning only on EGA/VGA + jz lmbad + + movw $0, mt_end # Scanning of modes is + movb $1, scanning # done as new autodetection. + call mode_table + jmp listm0 +lmdef: ret + +# Additional parts of mode_set... (relative jumps, you know) +setv7: # Video7 extended modes + DO_STORE + subb $VIDEO_FIRST_V7>>8, %bh + movw $0x6f05, %ax + int $0x10 + stc + ret + +_setrec: jmp setrec # Ugly... +_set_80x25: jmp set_80x25 + +# Aliases for backward compatibility. +setalias: + movw $VIDEO_80x25, %ax + incw %bx + jz mode_set + + movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al + incw %bx + jnz setbad # Fall-through! + +# Setting of user mode (AX=mode ID) => CF=success +mode_set: + movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S + movw %ax, %bx + cmpb $0xff, %ah + jz setalias + + testb $VIDEO_RECALC>>8, %ah + jnz _setrec + + cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah + jnc setres + + cmpb $VIDEO_FIRST_SPECIAL>>8, %ah + jz setspc + + cmpb $VIDEO_FIRST_V7>>8, %ah + jz setv7 + + cmpb $VIDEO_FIRST_VESA>>8, %ah + jnc check_vesa + + orb %ah, %ah + jz setmenu + + decb %ah + jz setbios + +setbad: clc + movb $0, do_restore # The screen needn't be restored + ret + +setvesa: + DO_STORE + subb $VIDEO_FIRST_VESA>>8, %bh + movw $0x4f02, %ax # VESA BIOS mode set call + int $0x10 + cmpw $0x004f, %ax # AL=4f if implemented + jnz setbad # AH=0 if OK + + stc + ret + +setbios: + DO_STORE + int $0x10 # Standard BIOS mode set call + pushw %bx + movb $0x0f, %ah # Check if really set + int $0x10 + popw %bx + cmpb %bl, %al + jnz setbad + + stc + ret + +setspc: xorb %bh, %bh # Set special mode + cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl + jnc setbad + + addw %bx, %bx + jmp *spec_inits(%bx) + +setmenu: + orb %al, %al # 80x25 is an exception + jz _set_80x25 + + pushw %bx # Set mode chosen from menu + call mode_table # Build the mode table + popw %ax + shlw $2, %ax + addw %ax, %si + cmpw %di, %si + jnc setbad + + movw (%si), %ax # Fetch mode ID +_m_s: jmp mode_set + +setres: pushw %bx # Set mode chosen by resolution + call mode_table + popw %bx + xchgb %bl, %bh +setr1: lodsw + cmpw $ASK_VGA, %ax # End of the list? + jz setbad + + lodsw + cmpw %bx, %ax + jnz setr1 + + movw -4(%si), %ax # Fetch mode ID + jmp _m_s + +check_vesa: +#ifdef CONFIG_FIRMWARE_EDID + leaw modelist+1024, %di + movw $0x4f00, %ax + int $0x10 + cmpw $0x004f, %ax + jnz setbad + + movw 4(%di), %ax + movw %ax, vbe_version +#endif + leaw modelist+1024, %di + subb $VIDEO_FIRST_VESA>>8, %bh + movw %bx, %cx # Get mode information structure + movw $0x4f01, %ax + int $0x10 + addb $VIDEO_FIRST_VESA>>8, %bh + cmpw $0x004f, %ax + jnz setbad + + movb (%di), %al # Check capabilities. + andb $0x19, %al + cmpb $0x09, %al + jz setvesa # This is a text mode + + movb (%di), %al # Check capabilities. + andb $0x99, %al + cmpb $0x99, %al + jnz _setbad # Doh! No linear frame buffer. + + subb $VIDEO_FIRST_VESA>>8, %bh + orw $0x4000, %bx # Use linear frame buffer + movw $0x4f02, %ax # VESA BIOS mode set call + int $0x10 + cmpw $0x004f, %ax # AL=4f if implemented + jnz _setbad # AH=0 if OK + + movb $1, graphic_mode # flag graphic mode + movb $0, do_restore # no screen restore + stc + ret + +_setbad: jmp setbad # Ugly... + +# Recalculate vertical display end registers -- this fixes various +# inconsistencies of extended modes on many adapters. Called when +# the VIDEO_RECALC flag is set in the mode ID. + +setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode + call mode_set + jnc rct3 + + movw %gs:(0x485), %ax # Font size in pixels + movb %gs:(0x484), %bl # Number of rows + incb %bl + mulb %bl # Number of visible + decw %ax # scan lines - 1 + movw $0x3d4, %dx + movw %ax, %bx + movb $0x12, %al # Lower 8 bits + movb %bl, %ah + outw %ax, %dx + movb $0x07, %al # Bits 8 and 9 in the overflow register + call inidx + xchgb %al, %ah + andb $0xbd, %ah + shrb %bh + jnc rct1 + orb $0x02, %ah +rct1: shrb %bh + jnc rct2 + orb $0x40, %ah +rct2: movb $0x07, %al + outw %ax, %dx + stc +rct3: ret + +# Table of routines for setting of the special modes. +spec_inits: + .word set_80x25 + .word set_8pixel + .word set_80x43 + .word set_80x28 + .word set_current + .word set_80x30 + .word set_80x34 + .word set_80x60 + .word set_gfx + +# Set the 80x25 mode. If already set, do nothing. +set_80x25: + movw $0x5019, force_size # Override possibly broken BIOS +use_80x25: +#ifdef CONFIG_VIDEO_400_HACK + movw $0x1202, %ax # Force 400 scan lines + movb $0x30, %bl + int $0x10 +#else + movb $0x0f, %ah # Get current mode ID + int $0x10 + cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available + jz st80 # on CGA/MDA/HGA and is also available on EGAM + + cmpw $0x5003, %ax # Unknown mode, force 80x25 color + jnz force3 + +st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25 + jz set80 + + movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc. + orb %al, %al # Some buggy BIOS'es set 0 rows + jz set80 + + cmpb $24, %al # It's hopefully correct + jz set80 +#endif /* CONFIG_VIDEO_400_HACK */ +force3: DO_STORE + movw $0x0003, %ax # Forced set + int $0x10 +set80: stc + ret + +# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. +set_8pixel: + DO_STORE + call use_80x25 # The base is 80x25 +set_8pt: + movw $0x1112, %ax # Use 8x8 font + xorb %bl, %bl + int $0x10 + movw $0x1200, %ax # Use alternate print screen + movb $0x20, %bl + int $0x10 + movw $0x1201, %ax # Turn off cursor emulation + movb $0x34, %bl + int $0x10 + movb $0x01, %ah # Define cursor scan lines 6-7 + movw $0x0607, %cx + int $0x10 +set_current: + stc + ret + +# Set the 80x28 mode. This mode works on all VGA's, because it's a standard +# 80x25 mode with 14-point fonts instead of 16-point. +set_80x28: + DO_STORE + call use_80x25 # The base is 80x25 +set14: movw $0x1111, %ax # Use 9x14 font + xorb %bl, %bl + int $0x10 + movb $0x01, %ah # Define cursor scan lines 11-12 + movw $0x0b0c, %cx + int $0x10 + stc + ret + +# Set the 80x43 mode. This mode is works on all VGA's. +# It's a 350-scanline mode with 8-pixel font. +set_80x43: + DO_STORE + movw $0x1201, %ax # Set 350 scans + movb $0x30, %bl + int $0x10 + movw $0x0003, %ax # Reset video mode + int $0x10 + jmp set_8pt # Use 8-pixel font + +# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font. +set_80x30: + call use_80x25 # Start with real 80x25 + DO_STORE + movw $0x3cc, %dx # Get CRTC port + inb %dx, %al + movb $0xd4, %dl + rorb %al # Mono or color? + jc set48a + + movb $0xb4, %dl +set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7) + call outidx + movw $0x0b06, %ax # Vertical total + call outidx + movw $0x3e07, %ax # (Vertical) overflow + call outidx + movw $0xea10, %ax # Vertical sync start + call outidx + movw $0xdf12, %ax # Vertical display end + call outidx + movw $0xe715, %ax # Vertical blank start + call outidx + movw $0x0416, %ax # Vertical blank end + call outidx + pushw %dx + movb $0xcc, %dl # Misc output register (read) + inb %dx, %al + movb $0xc2, %dl # (write) + andb $0x0d, %al # Preserve clock select bits and color bit + orb $0xe2, %al # Set correct sync polarity + outb %al, %dx + popw %dx + movw $0x501e, force_size + stc # That's all. + ret + +# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font. +set_80x34: + call set_80x30 # Set 480 scans + call set14 # And 14-pt font + movw $0xdb12, %ax # VGA vertical display end + movw $0x5022, force_size +setvde: call outidx + stc + ret + +# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font. +set_80x60: + call set_80x30 # Set 480 scans + call set_8pt # And 8-pt font + movw $0xdf12, %ax # VGA vertical display end + movw $0x503c, force_size + jmp setvde + +# Special hack for ThinkPad graphics +set_gfx: +#ifdef CONFIG_VIDEO_GFX_HACK + movw $VIDEO_GFX_BIOS_AX, %ax + movw $VIDEO_GFX_BIOS_BX, %bx + int $0x10 + movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size + stc +#endif + ret + +#ifdef CONFIG_VIDEO_RETAIN + +# Store screen contents to temporary buffer. +store_screen: + cmpb $0, do_restore # Already stored? + jnz stsr + + testb $CAN_USE_HEAP, loadflags # Have we space for storing? + jz stsr + + pushw %ax + pushw %bx + pushw force_size # Don't force specific size + movw $0, force_size + call mode_params # Obtain params of current mode + popw force_size + movb %fs:(PARAM_VIDEO_LINES), %ah + movb %fs:(PARAM_VIDEO_COLS), %al + movw %ax, %bx # BX=dimensions + mulb %ah + movw %ax, %cx # CX=number of characters + addw %ax, %ax # Calculate image size + addw $modelist+1024+4, %ax + cmpw heap_end_ptr, %ax + jnc sts1 # Unfortunately, out of memory + + movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params + leaw modelist+1024, %di + stosw + movw %bx, %ax + stosw + pushw %ds # Store the screen + movw video_segment, %ds + xorw %si, %si + rep + movsw + popw %ds + incb do_restore # Screen will be restored later +sts1: popw %bx + popw %ax +stsr: ret + +# Restore screen contents from temporary buffer. +restore_screen: + cmpb $0, do_restore # Has the screen been stored? + jz res1 + + call mode_params # Get parameters of current mode + movb %fs:(PARAM_VIDEO_LINES), %cl + movb %fs:(PARAM_VIDEO_COLS), %ch + leaw modelist+1024, %si # Screen buffer + lodsw # Set cursor position + movw %ax, %dx + cmpb %cl, %dh + jc res2 + + movb %cl, %dh + decb %dh +res2: cmpb %ch, %dl + jc res3 + + movb %ch, %dl + decb %dl +res3: movb $0x02, %ah + movb $0x00, %bh + int $0x10 + lodsw # Display size + movb %ah, %dl # DL=number of lines + movb $0, %ah # BX=phys. length of orig. line + movw %ax, %bx + cmpb %cl, %dl # Too many? + jc res4 + + pushw %ax + movb %dl, %al + subb %cl, %al + mulb %bl + addw %ax, %si + addw %ax, %si + popw %ax + movb %cl, %dl +res4: cmpb %ch, %al # Too wide? + jc res5 + + movb %ch, %al # AX=width of src. line +res5: movb $0, %cl + xchgb %ch, %cl + movw %cx, %bp # BP=width of dest. line + pushw %es + movw video_segment, %es + xorw %di, %di # Move the data + addw %bx, %bx # Convert BX and BP to _bytes_ + addw %bp, %bp +res6: pushw %si + pushw %di + movw %ax, %cx + rep + movsw + popw %di + popw %si + addw %bp, %di + addw %bx, %si + decb %dl + jnz res6 + + popw %es # Done +res1: ret +#endif /* CONFIG_VIDEO_RETAIN */ + +# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port) +outidx: outb %al, %dx + pushw %ax + movb %ah, %al + incw %dx + outb %al, %dx + decw %dx + popw %ax + ret + +# Build the table of video modes (stored after the setup.S code at the +# `modelist' label. Each video mode record looks like: +# .word MODE-ID (our special mode ID (see above)) +# .byte rows (number of rows) +# .byte columns (number of columns) +# Returns address of the end of the table in DI, the end is marked +# with a ASK_VGA ID. +mode_table: + movw mt_end, %di # Already filled? + orw %di, %di + jnz mtab1x + + leaw modelist, %di # Store standard modes: + movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL) + stosl + movb adapter, %al # CGA/MDA/HGA -- no more modes + orb %al, %al + jz mtabe + + decb %al + jnz mtabv + + movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode + stosl + jmp mtabe + +mtab1x: jmp mtab1 + +mtabv: leaw vga_modes, %si # All modes for std VGA + movw $vga_modes_end-vga_modes, %cx + rep # I'm unable to use movsw as I don't know how to store a half + movsb # of the expression above to cx without using explicit shr. + + cmpb $0, scanning # Mode scan requested? + jz mscan1 + + call mode_scan +mscan1: + +#ifdef CONFIG_VIDEO_LOCAL + call local_modes +#endif /* CONFIG_VIDEO_LOCAL */ + +#ifdef CONFIG_VIDEO_VESA + call vesa_modes # Detect VESA VGA modes +#endif /* CONFIG_VIDEO_VESA */ + +#ifdef CONFIG_VIDEO_SVGA + cmpb $0, scanning # Bypass when scanning + jnz mscan2 + + call svga_modes # Detect SVGA cards & modes +mscan2: +#endif /* CONFIG_VIDEO_SVGA */ + +mtabe: + +#ifdef CONFIG_VIDEO_COMPACT + leaw modelist, %si + movw %di, %dx + movw %si, %di +cmt1: cmpw %dx, %si # Scan all modes + jz cmt2 + + leaw modelist, %bx # Find in previous entries + movw 2(%si), %cx +cmt3: cmpw %bx, %si + jz cmt4 + + cmpw 2(%bx), %cx # Found => don't copy this entry + jz cmt5 + + addw $4, %bx + jmp cmt3 + +cmt4: movsl # Copy entry + jmp cmt1 + +cmt5: addw $4, %si # Skip entry + jmp cmt1 + +cmt2: +#endif /* CONFIG_VIDEO_COMPACT */ + + movw $ASK_VGA, (%di) # End marker + movw %di, mt_end +mtab1: leaw modelist, %si # SI=mode list, DI=list end +ret0: ret + +# Modes usable on all standard VGAs +vga_modes: + .word VIDEO_8POINT + .word 0x5032 # 80x50 + .word VIDEO_80x43 + .word 0x502b # 80x43 + .word VIDEO_80x28 + .word 0x501c # 80x28 + .word VIDEO_80x30 + .word 0x501e # 80x30 + .word VIDEO_80x34 + .word 0x5022 # 80x34 + .word VIDEO_80x60 + .word 0x503c # 80x60 +#ifdef CONFIG_VIDEO_GFX_HACK + .word VIDEO_GFX_HACK + .word VIDEO_GFX_DUMMY_RESOLUTION +#endif + +vga_modes_end: +# Detect VESA modes. + +#ifdef CONFIG_VIDEO_VESA +vesa_modes: + cmpb $2, adapter # VGA only + jnz ret0 + + movw %di, %bp # BP=original mode table end + addw $0x200, %di # Buffer space + movw $0x4f00, %ax # VESA Get card info call + int $0x10 + movw %bp, %di + cmpw $0x004f, %ax # Successful? + jnz ret0 + + cmpw $0x4556, 0x200(%di) + jnz ret0 + + cmpw $0x4153, 0x202(%di) + jnz ret0 + + movw $vesa_name, card_name # Set name to "VESA VGA" + pushw %gs + lgsw 0x20e(%di), %si # GS:SI=mode list + movw $128, %cx # Iteration limit +vesa1: +# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst. +# XXX: lodsw %gs:(%si), %ax # Get next mode in the list + gs; lodsw + cmpw $0xffff, %ax # End of the table? + jz vesar + + cmpw $0x0080, %ax # Check validity of mode ID + jc vesa2 + + orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff + jz vesan # Certain BIOSes report 0x80-0xff! + + cmpw $0x0800, %ax + jnc vesae + +vesa2: pushw %cx + movw %ax, %cx # Get mode information structure + movw $0x4f01, %ax + int $0x10 + movw %cx, %bx # BX=mode number + addb $VIDEO_FIRST_VESA>>8, %bh + popw %cx + cmpw $0x004f, %ax + jnz vesan # Don't report errors (buggy BIOSES) + + movb (%di), %al # Check capabilities. We require + andb $0x19, %al # a color text mode. + cmpb $0x09, %al + jnz vesan + + cmpw $0xb800, 8(%di) # Standard video memory address required + jnz vesan + + testb $2, (%di) # Mode characteristics supplied? + movw %bx, (%di) # Store mode number + jz vesa3 + + xorw %dx, %dx + movw 0x12(%di), %bx # Width + orb %bh, %bh + jnz vesan + + movb %bl, 0x3(%di) + movw 0x14(%di), %ax # Height + orb %ah, %ah + jnz vesan + + movb %al, 2(%di) + mulb %bl + cmpw $8193, %ax # Small enough for Linux console driver? + jnc vesan + + jmp vesaok + +vesa3: subw $0x8108, %bx # This mode has no detailed info specified, + jc vesan # so it must be a standard VESA mode. + + cmpw $5, %bx + jnc vesan + + movw vesa_text_mode_table(%bx), %ax + movw %ax, 2(%di) +vesaok: addw $4, %di # The mode is valid. Store it. +vesan: loop vesa1 # Next mode. Limit exceeded => error +vesae: leaw vesaer, %si + call prtstr + movw %bp, %di # Discard already found modes. +vesar: popw %gs + ret + +# Dimensions of standard VESA text modes +vesa_text_mode_table: + .byte 60, 80 # 0108 + .byte 25, 132 # 0109 + .byte 43, 132 # 010A + .byte 50, 132 # 010B + .byte 60, 132 # 010C +#endif /* CONFIG_VIDEO_VESA */ + +# Scan for video modes. A bit dirty, but should work. +mode_scan: + movw $0x0100, %cx # Start with mode 0 +scm1: movb $0, %ah # Test the mode + movb %cl, %al + int $0x10 + movb $0x0f, %ah + int $0x10 + cmpb %cl, %al + jnz scm2 # Mode not set + + movw $0x3c0, %dx # Test if it's a text mode + movb $0x10, %al # Mode bits + call inidx + andb $0x03, %al + jnz scm2 + + movb $0xce, %dl # Another set of mode bits + movb $0x06, %al + call inidx + shrb %al + jc scm2 + + movb $0xd4, %dl # Cursor location + movb $0x0f, %al + call inidx + orb %al, %al + jnz scm2 + + movw %cx, %ax # Ok, store the mode + stosw + movb %gs:(0x484), %al # Number of rows + incb %al + stosb + movw %gs:(0x44a), %ax # Number of columns + stosb +scm2: incb %cl + jns scm1 + + movw $0x0003, %ax # Return back to mode 3 + int $0x10 + ret + +tstidx: outw %ax, %dx # OUT DX,AX and inidx +inidx: outb %al, %dx # Read from indexed VGA register + incw %dx # AL=index, DX=index reg port -> AL=data + inb %dx, %al + decw %dx + ret + +# Try to detect type of SVGA card and supply (usually approximate) video +# mode table for it. + +#ifdef CONFIG_VIDEO_SVGA +svga_modes: + leaw svga_table, %si # Test all known SVGA adapters +dosvga: lodsw + movw %ax, %bp # Default mode table + orw %ax, %ax + jz didsv1 + + lodsw # Pointer to test routine + pushw %si + pushw %di + pushw %es + movw $0xc000, %bx + movw %bx, %es + call *%ax # Call test routine + popw %es + popw %di + popw %si + orw %bp, %bp + jz dosvga + + movw %bp, %si # Found, copy the modes + movb svga_prefix, %ah +cpsvga: lodsb + orb %al, %al + jz didsv + + stosw + movsw + jmp cpsvga + +didsv: movw %si, card_name # Store pointer to card name +didsv1: ret + +# Table of all known SVGA cards. For each card, we store a pointer to +# a table of video modes supported by the card and a pointer to a routine +# used for testing of presence of the card. The video mode table is always +# followed by the name of the card or the chipset. +svga_table: + .word ati_md, ati_test + .word oak_md, oak_test + .word paradise_md, paradise_test + .word realtek_md, realtek_test + .word s3_md, s3_test + .word chips_md, chips_test + .word video7_md, video7_test + .word cirrus5_md, cirrus5_test + .word cirrus6_md, cirrus6_test + .word cirrus1_md, cirrus1_test + .word ahead_md, ahead_test + .word everex_md, everex_test + .word genoa_md, genoa_test + .word trident_md, trident_test + .word tseng_md, tseng_test + .word 0 + +# Test routines and mode tables: + +# S3 - The test algorithm was taken from the SuperProbe package +# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org +s3_test: + movw $0x0f35, %cx # we store some constants in cl/ch + movw $0x03d4, %dx + movb $0x38, %al + call inidx + movb %al, %bh # store current CRT-register 0x38 + movw $0x0038, %ax + call outidx # disable writing to special regs + movb %cl, %al # check whether we can write special reg 0x35 + call inidx + movb %al, %bl # save the current value of CRT reg 0x35 + andb $0xf0, %al # clear bits 0-3 + movb %al, %ah + movb %cl, %al # and write it to CRT reg 0x35 + call outidx + call inidx # now read it back + andb %ch, %al # clear the upper 4 bits + jz s3_2 # the first test failed. But we have a + + movb %bl, %ah # second chance + movb %cl, %al + call outidx + jmp s3_1 # do the other tests + +s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35 + orb %bl, %ah # set the upper 4 bits of ah with the orig value + call outidx # write ... + call inidx # ... and reread + andb %cl, %al # turn off the upper 4 bits + pushw %ax + movb %bl, %ah # restore old value in register 0x35 + movb %cl, %al + call outidx + popw %ax + cmpb %ch, %al # setting lower 4 bits was successful => bad + je no_s3 # writing is allowed => this is not an S3 + +s3_1: movw $0x4838, %ax # allow writing to special regs by putting + call outidx # magic number into CRT-register 0x38 + movb %cl, %al # check whether we can write special reg 0x35 + call inidx + movb %al, %bl + andb $0xf0, %al + movb %al, %ah + movb %cl, %al + call outidx + call inidx + andb %ch, %al + jnz no_s3 # no, we can't write => no S3 + + movw %cx, %ax + orb %bl, %ah + call outidx + call inidx + andb %ch, %al + pushw %ax + movb %bl, %ah # restore old value in register 0x35 + movb %cl, %al + call outidx + popw %ax + cmpb %ch, %al + jne no_s31 # writing not possible => no S3 + movb $0x30, %al + call inidx # now get the S3 id ... + leaw idS3, %di + movw $0x10, %cx + repne + scasb + je no_s31 + + movb %bh, %ah + movb $0x38, %al + jmp s3rest + +no_s3: movb $0x35, %al # restore CRT register 0x35 + movb %bl, %ah + call outidx +no_s31: xorw %bp, %bp # Detection failed +s3rest: movb %bh, %ah + movb $0x38, %al # restore old value of CRT register 0x38 + jmp outidx + +idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 + .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 + +s3_md: .byte 0x54, 0x2b, 0x84 + .byte 0x55, 0x19, 0x84 + .byte 0 + .ascii "S3" + .byte 0 + +# ATI cards. +ati_test: + leaw idati, %si + movw $0x31, %di + movw $0x09, %cx + repe + cmpsb + je atiok + + xorw %bp, %bp +atiok: ret + +idati: .ascii "761295520" + +ati_md: .byte 0x23, 0x19, 0x84 + .byte 0x33, 0x2c, 0x84 + .byte 0x22, 0x1e, 0x64 + .byte 0x21, 0x19, 0x64 + .byte 0x58, 0x21, 0x50 + .byte 0x5b, 0x1e, 0x50 + .byte 0 + .ascii "ATI" + .byte 0 + +# AHEAD +ahead_test: + movw $0x200f, %ax + movw $0x3ce, %dx + outw %ax, %dx + incw %dx + inb %dx, %al + cmpb $0x20, %al + je isahed + + cmpb $0x21, %al + je isahed + + xorw %bp, %bp +isahed: ret + +ahead_md: + .byte 0x22, 0x2c, 0x84 + .byte 0x23, 0x19, 0x84 + .byte 0x24, 0x1c, 0x84 + .byte 0x2f, 0x32, 0xa0 + .byte 0x32, 0x22, 0x50 + .byte 0x34, 0x42, 0x50 + .byte 0 + .ascii "Ahead" + .byte 0 + +# Chips & Tech. +chips_test: + movw $0x3c3, %dx + inb %dx, %al + orb $0x10, %al + outb %al, %dx + movw $0x104, %dx + inb %dx, %al + movb %al, %bl + movw $0x3c3, %dx + inb %dx, %al + andb $0xef, %al + outb %al, %dx + cmpb $0xa5, %bl + je cantok + + xorw %bp, %bp +cantok: ret + +chips_md: + .byte 0x60, 0x19, 0x84 + .byte 0x61, 0x32, 0x84 + .byte 0 + .ascii "Chips & Technologies" + .byte 0 + +# Cirrus Logic 5X0 +cirrus1_test: + movw $0x3d4, %dx + movb $0x0c, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bl + xorb %al, %al + outb %al, %dx + decw %dx + movb $0x1f, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bh + xorb %ah, %ah + shlb $4, %al + movw %ax, %cx + movb %bh, %al + shrb $4, %al + addw %ax, %cx + shlw $8, %cx + addw $6, %cx + movw %cx, %ax + movw $0x3c4, %dx + outw %ax, %dx + incw %dx + inb %dx, %al + andb %al, %al + jnz nocirr + + movb %bh, %al + outb %al, %dx + inb %dx, %al + cmpb $0x01, %al + je iscirr + +nocirr: xorw %bp, %bp +iscirr: movw $0x3d4, %dx + movb %bl, %al + xorb %ah, %ah + shlw $8, %ax + addw $0x0c, %ax + outw %ax, %dx + ret + +cirrus1_md: + .byte 0x1f, 0x19, 0x84 + .byte 0x20, 0x2c, 0x84 + .byte 0x22, 0x1e, 0x84 + .byte 0x31, 0x25, 0x64 + .byte 0 + .ascii "Cirrus Logic 5X0" + .byte 0 + +# Cirrus Logic 54XX +cirrus5_test: + movw $0x3c4, %dx + movb $6, %al + call inidx + movb %al, %bl # BL=backup + movw $6, %ax + call tstidx + cmpb $0x0f, %al + jne c5fail + + movw $0x1206, %ax + call tstidx + cmpb $0x12, %al + jne c5fail + + movb $0x1e, %al + call inidx + movb %al, %bh + movb %bh, %ah + andb $0xc0, %ah + movb $0x1e, %al + call tstidx + andb $0x3f, %al + jne c5xx + + movb $0x1e, %al + movb %bh, %ah + orb $0x3f, %ah + call tstidx + xorb $0x3f, %al + andb $0x3f, %al +c5xx: pushf + movb $0x1e, %al + movb %bh, %ah + outw %ax, %dx + popf + je c5done + +c5fail: xorw %bp, %bp +c5done: movb $6, %al + movb %bl, %ah + outw %ax, %dx + ret + +cirrus5_md: + .byte 0x14, 0x19, 0x84 + .byte 0x54, 0x2b, 0x84 + .byte 0 + .ascii "Cirrus Logic 54XX" + .byte 0 + +# Cirrus Logic 64XX -- no known extra modes, but must be identified, because +# it's misidentified by the Ahead test. +cirrus6_test: + movw $0x3ce, %dx + movb $0x0a, %al + call inidx + movb %al, %bl # BL=backup + movw $0xce0a, %ax + call tstidx + orb %al, %al + jne c2fail + + movw $0xec0a, %ax + call tstidx + cmpb $0x01, %al + jne c2fail + + movb $0xaa, %al + call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's. + shrb $4, %al + subb $4, %al + jz c6done + + decb %al + jz c6done + + subb $2, %al + jz c6done + + decb %al + jz c6done + +c2fail: xorw %bp, %bp +c6done: movb $0x0a, %al + movb %bl, %ah + outw %ax, %dx + ret + +cirrus6_md: + .byte 0 + .ascii "Cirrus Logic 64XX" + .byte 0 + +# Everex / Trident +everex_test: + movw $0x7000, %ax + xorw %bx, %bx + int $0x10 + cmpb $0x70, %al + jne noevrx + + shrw $4, %dx + cmpw $0x678, %dx + je evtrid + + cmpw $0x236, %dx + jne evrxok + +evtrid: leaw trident_md, %bp +evrxok: ret + +noevrx: xorw %bp, %bp + ret + +everex_md: + .byte 0x03, 0x22, 0x50 + .byte 0x04, 0x3c, 0x50 + .byte 0x07, 0x2b, 0x64 + .byte 0x08, 0x4b, 0x64 + .byte 0x0a, 0x19, 0x84 + .byte 0x0b, 0x2c, 0x84 + .byte 0x16, 0x1e, 0x50 + .byte 0x18, 0x1b, 0x64 + .byte 0x21, 0x40, 0xa0 + .byte 0x40, 0x1e, 0x84 + .byte 0 + .ascii "Everex/Trident" + .byte 0 + +# Genoa. +genoa_test: + leaw idgenoa, %si # Check Genoa 'clues' + xorw %ax, %ax + movb %es:(0x37), %al + movw %ax, %di + movw $0x04, %cx + decw %si + decw %di +l1: incw %si + incw %di + movb (%si), %al + testb %al, %al + jz l2 + + cmpb %es:(%di), %al +l2: loope l1 + orw %cx, %cx + je isgen + + xorw %bp, %bp +isgen: ret + +idgenoa: .byte 0x77, 0x00, 0x99, 0x66 + +genoa_md: + .byte 0x58, 0x20, 0x50 + .byte 0x5a, 0x2a, 0x64 + .byte 0x60, 0x19, 0x84 + .byte 0x61, 0x1d, 0x84 + .byte 0x62, 0x20, 0x84 + .byte 0x63, 0x2c, 0x84 + .byte 0x64, 0x3c, 0x84 + .byte 0x6b, 0x4f, 0x64 + .byte 0x72, 0x3c, 0x50 + .byte 0x74, 0x42, 0x50 + .byte 0x78, 0x4b, 0x64 + .byte 0 + .ascii "Genoa" + .byte 0 + +# OAK +oak_test: + leaw idoakvga, %si + movw $0x08, %di + movw $0x08, %cx + repe + cmpsb + je isoak + + xorw %bp, %bp +isoak: ret + +idoakvga: .ascii "OAK VGA " + +oak_md: .byte 0x4e, 0x3c, 0x50 + .byte 0x4f, 0x3c, 0x84 + .byte 0x50, 0x19, 0x84 + .byte 0x51, 0x2b, 0x84 + .byte 0 + .ascii "OAK" + .byte 0 + +# WD Paradise. +paradise_test: + leaw idparadise, %si + movw $0x7d, %di + movw $0x04, %cx + repe + cmpsb + je ispara + + xorw %bp, %bp +ispara: ret + +idparadise: .ascii "VGA=" + +paradise_md: + .byte 0x41, 0x22, 0x50 + .byte 0x47, 0x1c, 0x84 + .byte 0x55, 0x19, 0x84 + .byte 0x54, 0x2c, 0x84 + .byte 0 + .ascii "Paradise" + .byte 0 + +# Trident. +trident_test: + movw $0x3c4, %dx + movb $0x0e, %al + outb %al, %dx + incw %dx + inb %dx, %al + xchgb %al, %ah + xorb %al, %al + outb %al, %dx + inb %dx, %al + xchgb %ah, %al + movb %al, %bl # Strange thing ... in the book this wasn't + andb $0x02, %bl # necessary but it worked on my card which + jz setb2 # is a trident. Without it the screen goes + # blurred ... + andb $0xfd, %al + jmp clrb2 + +setb2: orb $0x02, %al +clrb2: outb %al, %dx + andb $0x0f, %ah + cmpb $0x02, %ah + je istrid + + xorw %bp, %bp +istrid: ret + +trident_md: + .byte 0x50, 0x1e, 0x50 + .byte 0x51, 0x2b, 0x50 + .byte 0x52, 0x3c, 0x50 + .byte 0x57, 0x19, 0x84 + .byte 0x58, 0x1e, 0x84 + .byte 0x59, 0x2b, 0x84 + .byte 0x5a, 0x3c, 0x84 + .byte 0 + .ascii "Trident" + .byte 0 + +# Tseng. +tseng_test: + movw $0x3cd, %dx + inb %dx, %al # Could things be this simple ! :-) + movb %al, %bl + movb $0x55, %al + outb %al, %dx + inb %dx, %al + movb %al, %ah + movb %bl, %al + outb %al, %dx + cmpb $0x55, %ah + je istsen + +isnot: xorw %bp, %bp +istsen: ret + +tseng_md: + .byte 0x26, 0x3c, 0x50 + .byte 0x2a, 0x28, 0x64 + .byte 0x23, 0x19, 0x84 + .byte 0x24, 0x1c, 0x84 + .byte 0x22, 0x2c, 0x84 + .byte 0x21, 0x3c, 0x84 + .byte 0 + .ascii "Tseng" + .byte 0 + +# Video7. +video7_test: + movw $0x3cc, %dx + inb %dx, %al + movw $0x3b4, %dx + andb $0x01, %al + jz even7 + + movw $0x3d4, %dx +even7: movb $0x0c, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bl + movb $0x55, %al + outb %al, %dx + inb %dx, %al + decw %dx + movb $0x1f, %al + outb %al, %dx + incw %dx + inb %dx, %al + movb %al, %bh + decw %dx + movb $0x0c, %al + outb %al, %dx + incw %dx + movb %bl, %al + outb %al, %dx + movb $0x55, %al + xorb $0xea, %al + cmpb %bh, %al + jne isnot + + movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching + ret + +video7_md: + .byte 0x40, 0x2b, 0x50 + .byte 0x43, 0x3c, 0x50 + .byte 0x44, 0x3c, 0x64 + .byte 0x41, 0x19, 0x84 + .byte 0x42, 0x2c, 0x84 + .byte 0x45, 0x1c, 0x84 + .byte 0 + .ascii "Video 7" + .byte 0 + +# Realtek VGA +realtek_test: + leaw idrtvga, %si + movw $0x45, %di + movw $0x0b, %cx + repe + cmpsb + je isrt + + xorw %bp, %bp +isrt: ret + +idrtvga: .ascii "REALTEK VGA" + +realtek_md: + .byte 0x1a, 0x3c, 0x50 + .byte 0x1b, 0x19, 0x84 + .byte 0x1c, 0x1e, 0x84 + .byte 0x1d, 0x2b, 0x84 + .byte 0x1e, 0x3c, 0x84 + .byte 0 + .ascii "REALTEK" + .byte 0 + +#endif /* CONFIG_VIDEO_SVGA */ + +# User-defined local mode table (VGA only) +#ifdef CONFIG_VIDEO_LOCAL +local_modes: + leaw local_mode_table, %si +locm1: lodsw + orw %ax, %ax + jz locm2 + + stosw + movsw + jmp locm1 + +locm2: ret + +# This is the table of local video modes which can be supplied manually +# by the user. Each entry consists of mode ID (word) and dimensions +# (byte for column count and another byte for row count). These modes +# are placed before all SVGA and VESA modes and override them if table +# compacting is enabled. The table must end with a zero word followed +# by NUL-terminated video adapter name. +local_mode_table: + .word 0x0100 # Example: 40x25 + .byte 25,40 + .word 0 + .ascii "Local" + .byte 0 +#endif /* CONFIG_VIDEO_LOCAL */ + +# Read a key and return the ASCII code in al, scan code in ah +getkey: xorb %ah, %ah + int $0x16 + ret + +# Read a key with a timeout of 30 seconds. +# The hardware clock is used to get the time. +getkt: call gettime + addb $30, %al # Wait 30 seconds + cmpb $60, %al + jl lminute + + subb $60, %al +lminute: + movb %al, %cl +again: movb $0x01, %ah + int $0x16 + jnz getkey # key pressed, so get it + + call gettime + cmpb %cl, %al + jne again + + movb $0x20, %al # timeout, return `space' + ret + +# Flush the keyboard buffer +flush: movb $0x01, %ah + int $0x16 + jz empty + + xorb %ah, %ah + int $0x16 + jmp flush + +empty: ret + +# Print hexadecimal number. +prthw: pushw %ax + movb %ah, %al + call prthb + popw %ax +prthb: pushw %ax + shrb $4, %al + call prthn + popw %ax + andb $0x0f, %al +prthn: cmpb $0x0a, %al + jc prth1 + + addb $0x07, %al +prth1: addb $0x30, %al + jmp prtchr + +# Print decimal number in al +prtdec: pushw %ax + pushw %cx + xorb %ah, %ah + movb $0x0a, %cl + idivb %cl + cmpb $0x09, %al + jbe lt100 + + call prtdec + jmp skip10 + +lt100: addb $0x30, %al + call prtchr +skip10: movb %ah, %al + addb $0x30, %al + call prtchr + popw %cx + popw %ax + ret + +store_edid: +#ifdef CONFIG_FIRMWARE_EDID + pushw %es # just save all registers + pushw %ax + pushw %bx + pushw %cx + pushw %dx + pushw %di + + pushw %fs + popw %es + + movl $0x13131313, %eax # memset block with 0x13 + movw $32, %cx + movw $0x140, %di + cld + rep + stosl + + cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0 + jl no_edid + + pushw %es # save ES + xorw %di, %di # Report Capability + pushw %di + popw %es # ES:DI must be 0:0 + movw $0x4f15, %ax + xorw %bx, %bx + xorw %cx, %cx + int $0x10 + popw %es # restore ES + + cmpb $0x00, %ah # call successful + jne no_edid + + cmpb $0x4f, %al # function supported + jne no_edid + + movw $0x4f15, %ax # do VBE/DDC + movw $0x01, %bx + movw $0x00, %cx + movw $0x01, %dx + movw $0x140, %di + int $0x10 + +no_edid: + popw %di # restore all registers + popw %dx + popw %cx + popw %bx + popw %ax + popw %es +#endif + ret + +# VIDEO_SELECT-only variables +mt_end: .word 0 # End of video mode table if built +edit_buf: .space 6 # Line editor buffer +card_name: .word 0 # Pointer to adapter name +scanning: .byte 0 # Performing mode scan +do_restore: .byte 0 # Screen contents altered during mode change +svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes +graphic_mode: .byte 0 # Graphic mode with a linear frame buffer +dac_size: .byte 6 # DAC bit depth +vbe_version: .word 0 # VBE bios version + +# Status messages +keymsg: .ascii "Press to see video modes available, " + .ascii " to continue or wait 30 secs" + .byte 0x0d, 0x0a, 0 + +listhdr: .byte 0x0d, 0x0a + .ascii "Mode: COLSxROWS:" + +crlft: .byte 0x0d, 0x0a, 0 + +prompt: .byte 0x0d, 0x0a + .asciz "Enter mode number or `scan': " + +unknt: .asciz "Unknown mode ID. Try again." + +badmdt: .ascii "You passed an undefined mode number." + .byte 0x0d, 0x0a, 0 + +vesaer: .ascii "Error: Scanning of VESA modes failed. Please " + .ascii "report to ." + .byte 0x0d, 0x0a, 0 + +old_name: .asciz "CGA/MDA/HGA" + +ega_name: .asciz "EGA" + +svga_name: .ascii " " + +vga_name: .asciz "VGA" + +vesa_name: .asciz "VESA" + +name_bann: .asciz "Video adapter: " +#endif /* CONFIG_VIDEO_SELECT */ + +# Other variables: +adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA +video_segment: .word 0xb800 # Video memory segment +force_size: .word 0 # Use this size instead of the one in BIOS vars diff --git a/trunk/arch/x86_64/defconfig b/trunk/arch/x86_64/defconfig index 941a7e3aa5fb..7a1e251e333d 100644 --- a/trunk/arch/x86_64/defconfig +++ b/trunk/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-git3 -# Tue May 1 07:30:48 2007 +# Linux kernel version: 2.6.21-rc3 +# Wed Mar 7 15:29:47 2007 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -118,11 +118,11 @@ CONFIG_X86_PC=y # CONFIG_X86_VSMP is not set # CONFIG_MK8 is not set # CONFIG_MPSC is not set -CONFIG_MCORE2=y -# CONFIG_GENERIC_CPU is not set -CONFIG_X86_L1_CACHE_BYTES=64 -CONFIG_X86_L1_CACHE_SHIFT=6 -CONFIG_X86_INTERNODE_CACHE_BYTES=64 +# CONFIG_MCORE2 is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_INTERNODE_CACHE_BYTES=128 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y # CONFIG_MICROCODE is not set @@ -174,7 +174,6 @@ CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_AMD=y # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set -# CONFIG_RELOCATABLE is not set CONFIG_PHYSICAL_START=0x200000 CONFIG_SECCOMP=y # CONFIG_CC_STACKPROTECTOR is not set @@ -183,6 +182,7 @@ CONFIG_HZ_250=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# CONFIG_REORDER is not set CONFIG_K8_NB=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y @@ -218,6 +218,7 @@ CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=y CONFIG_ACPI_NUMA=y # CONFIG_ACPI_ASUS is not set +# CONFIG_ACPI_IBM is not set # CONFIG_ACPI_TOSHIBA is not set CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set @@ -242,7 +243,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # # CPUFreq processor drivers @@ -298,6 +299,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -332,7 +334,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set -# CONFIG_IPV6_OPTIMISTIC_DAD is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set @@ -388,13 +389,6 @@ CONFIG_IPV6_SIT=y # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_AF_RXRPC is not set - -# -# Wireless -# -# CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_EXT is not set # CONFIG_IEEE80211 is not set # @@ -415,6 +409,10 @@ CONFIG_FW_LOADER=y # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# # CONFIG_MTD is not set # @@ -461,7 +459,6 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set # CONFIG_SONY_LAPTOP is not set -# CONFIG_THINKPAD_ACPI is not set # # ATA/ATAPI/MFM/RLL support @@ -497,6 +494,7 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set @@ -527,6 +525,7 @@ CONFIG_BLK_DEV_PDC202XX_NEW=y # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y # CONFIG_BLK_DEV_HD is not set # @@ -585,9 +584,11 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set # CONFIG_SCSI_AIC94XX is not set # CONFIG_SCSI_ARCMSR is not set -# CONFIG_MEGARAID_NEWGEN is not set +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=y +CONFIG_MEGARAID_MAILBOX=y # CONFIG_MEGARAID_LEGACY is not set -# CONFIG_MEGARAID_SAS is not set +CONFIG_MEGARAID_SAS=y # CONFIG_SCSI_HPTIOP is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set @@ -607,7 +608,6 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_ESP_CORE is not set # CONFIG_SCSI_SRP is not set # @@ -631,12 +631,12 @@ CONFIG_SATA_SIL=y CONFIG_SATA_VIA=y # CONFIG_SATA_VITESSE is not set # CONFIG_SATA_INIC162X is not set +CONFIG_SATA_INTEL_COMBINED=y CONFIG_SATA_ACPI=y # CONFIG_PATA_ALI is not set # CONFIG_PATA_AMD is not set # CONFIG_PATA_ARTOP is not set # CONFIG_PATA_ATIIXP is not set -# CONFIG_PATA_CMD640_PCI is not set # CONFIG_PATA_CMD64X is not set # CONFIG_PATA_CS5520 is not set # CONFIG_PATA_CS5530 is not set @@ -688,7 +688,7 @@ CONFIG_BLK_DEV_DM=y CONFIG_FUSION=y CONFIG_FUSION_SPI=y # CONFIG_FUSION_FC is not set -# CONFIG_FUSION_SAS is not set +CONFIG_FUSION_SAS=y CONFIG_FUSION_MAX_SGE=128 # CONFIG_FUSION_CTL is not set @@ -701,22 +701,19 @@ CONFIG_IEEE1394=y # Subsystem Options # # CONFIG_IEEE1394_VERBOSEDEBUG is not set +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set # -# Controllers -# - -# -# Texas Instruments PCILynx requires I2C +# Device Drivers # +# CONFIG_IEEE1394_PCILYNX is not set CONFIG_IEEE1394_OHCI1394=y # -# Protocols +# Protocol Drivers # # CONFIG_IEEE1394_VIDEO1394 is not set # CONFIG_IEEE1394_SBP2 is not set -# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set # CONFIG_IEEE1394_ETH1394 is not set # CONFIG_IEEE1394_DV1394 is not set CONFIG_IEEE1394_RAWIO=y @@ -779,8 +776,7 @@ CONFIG_TULIP=y # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set -CONFIG_AMD8111_ETH=y -# CONFIG_AMD8111E_NAPI is not set +# CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set CONFIG_B44=y CONFIG_FORCEDETH=y @@ -842,10 +838,9 @@ CONFIG_S2IO=m # CONFIG_TR is not set # -# Wireless LAN +# Wireless LAN (non-hamradio) # -# CONFIG_WLAN_PRE80211 is not set -# CONFIG_WLAN_80211 is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces @@ -859,6 +854,7 @@ CONFIG_S2IO=m # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set # CONFIG_NETPOLL_TRAP is not set CONFIG_NET_POLL_CONTROLLER=y @@ -992,7 +988,57 @@ CONFIG_HPET_MMAP=y # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_ISA=m +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PASEMI is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # # SPI support @@ -1008,8 +1054,54 @@ CONFIG_HPET_MMAP=y # # Hardware Monitoring support # -# CONFIG_HWMON is not set +CONFIG_HWMON=y # CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +CONFIG_SENSORS_SMSC47B397=m +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multifunction device drivers @@ -1056,9 +1148,8 @@ CONFIG_SOUND=y # Open Sound System # CONFIG_SOUND_PRIME=y -CONFIG_OBSOLETE_OSS=y +# CONFIG_OBSOLETE_OSS is not set # CONFIG_SOUND_BT878 is not set -# CONFIG_SOUND_ES1371 is not set CONFIG_SOUND_ICH=y # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set @@ -1072,14 +1163,6 @@ CONFIG_SOUND_ICH=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set -# -# USB Input Devices -# -CONFIG_USB_HID=y -# CONFIG_USB_HIDINPUT_POWERBOOK is not set -# CONFIG_HID_FF is not set -# CONFIG_USB_HIDDEV is not set - # # USB support # @@ -1093,7 +1176,6 @@ CONFIG_USB=y # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set @@ -1144,6 +1226,10 @@ CONFIG_USB_STORAGE=y # # USB Input Devices # +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set # CONFIG_USB_ACECAD is not set @@ -1471,7 +1557,7 @@ CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -CONFIG_TIMER_STATS=y +# CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set diff --git a/trunk/arch/x86_64/ia32/ia32_binfmt.c b/trunk/arch/x86_64/ia32/ia32_binfmt.c index 185399baaf6d..071100ea1251 100644 --- a/trunk/arch/x86_64/ia32/ia32_binfmt.c +++ b/trunk/arch/x86_64/ia32/ia32_binfmt.c @@ -5,11 +5,6 @@ * This tricks binfmt_elf.c into loading 32bit binaries using lots * of ugly preprocessor tricks. Talk about very very poor man's inheritance. */ -#define __ASM_X86_64_ELF_H 1 - -#undef ELF_CLASS -#define ELF_CLASS ELFCLASS32 - #include #include #include @@ -55,6 +50,9 @@ struct elf_phdr; #undef ELF_ARCH #define ELF_ARCH EM_386 +#undef ELF_CLASS +#define ELF_CLASS ELFCLASS32 + #define ELF_DATA ELFDATA2LSB #define USE_ELF_CORE_DUMP 1 @@ -138,7 +136,7 @@ struct elf_prpsinfo #define user user32 -#undef elf_read_implies_exec +#define __ASM_X86_64_ELF_H 1 #define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X) //#include #include diff --git a/trunk/arch/x86_64/ia32/ia32entry.S b/trunk/arch/x86_64/ia32/ia32entry.S index c48087db6f75..796df6992f62 100644 --- a/trunk/arch/x86_64/ia32/ia32entry.S +++ b/trunk/arch/x86_64/ia32/ia32entry.S @@ -481,7 +481,11 @@ ia32_sys_call_table: .quad sys_symlink .quad sys_lstat .quad sys_readlink /* 85 */ +#ifdef CONFIG_IA32_AOUT .quad sys_uselib +#else + .quad quiet_ni_syscall +#endif .quad sys_swapon .quad sys_reboot .quad compat_sys_old_readdir diff --git a/trunk/arch/x86_64/ia32/syscall32.c b/trunk/arch/x86_64/ia32/syscall32.c index fc4419ff0355..568ff0df89e7 100644 --- a/trunk/arch/x86_64/ia32/syscall32.c +++ b/trunk/arch/x86_64/ia32/syscall32.c @@ -13,7 +13,6 @@ #include #include #include -#include extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; diff --git a/trunk/arch/x86_64/kernel/Makefile b/trunk/arch/x86_64/kernel/Makefile index 4d94c51803d8..bb47e86f3d02 100644 --- a/trunk/arch/x86_64/kernel/Makefile +++ b/trunk/arch/x86_64/kernel/Makefile @@ -8,8 +8,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \ - perfctr-watchdog.o + pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o @@ -22,7 +21,8 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o -obj-y += io_apic.o mpparse.o genapic.o genapic_flat.o +obj-y += io_apic.o mpparse.o \ + genapic.o genapic_cluster.o genapic_flat.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += suspend.o @@ -58,4 +58,3 @@ i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o alternative-y += ../../i386/kernel/alternative.o pcspeaker-y += ../../i386/kernel/pcspeaker.o -perfctr-watchdog-y += ../../i386/kernel/cpu/perfctr-watchdog.o diff --git a/trunk/arch/x86_64/kernel/acpi/sleep.c b/trunk/arch/x86_64/kernel/acpi/sleep.c index 195b7034a148..e1548fbe95ae 100644 --- a/trunk/arch/x86_64/kernel/acpi/sleep.c +++ b/trunk/arch/x86_64/kernel/acpi/sleep.c @@ -60,6 +60,19 @@ extern char wakeup_start, wakeup_end; extern unsigned long acpi_copy_wakeup_routine(unsigned long); +static pgd_t low_ptr; + +static void init_low_mapping(void) +{ + pgd_t *slot0 = pgd_offset(current->mm, 0UL); + low_ptr = *slot0; + /* FIXME: We're playing with the current task's page tables here, which + * is potentially dangerous on SMP systems. + */ + set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET)); + local_flush_tlb(); +} + /** * acpi_save_state_mem - save kernel state * @@ -68,6 +81,8 @@ extern unsigned long acpi_copy_wakeup_routine(unsigned long); */ int acpi_save_state_mem(void) { + init_low_mapping(); + memcpy((void *)acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); acpi_copy_wakeup_routine(acpi_wakeup_address); @@ -80,6 +95,8 @@ int acpi_save_state_mem(void) */ void acpi_restore_state_mem(void) { + set_pgd(pgd_offset(current->mm, 0UL), low_ptr); + local_flush_tlb(); } /** @@ -92,11 +109,10 @@ void acpi_restore_state_mem(void) */ void __init acpi_reserve_bootmem(void) { - acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); - if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2)) + acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); + if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) printk(KERN_CRIT - "ACPI: Wakeup code way too big, will crash on attempt" - " to suspend\n"); + "ACPI: Wakeup code way too big, will crash on attempt to suspend\n"); } static int __init acpi_sleep_setup(char *str) diff --git a/trunk/arch/x86_64/kernel/acpi/wakeup.S b/trunk/arch/x86_64/kernel/acpi/wakeup.S index 8550a6ffa275..185faa911db5 100644 --- a/trunk/arch/x86_64/kernel/acpi/wakeup.S +++ b/trunk/arch/x86_64/kernel/acpi/wakeup.S @@ -1,7 +1,6 @@ .text #include #include -#include #include #include @@ -31,28 +30,22 @@ wakeup_code: cld # setup data segment movw %cs, %ax - movw %ax, %ds # Make ds:0 point to wakeup_start + movw %ax, %ds # Make ds:0 point to wakeup_start movw %ax, %ss - # Private stack is needed for ASUS board - mov $(wakeup_stack - wakeup_code), %sp + mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board - pushl $0 # Kill any dangerous flags + pushl $0 # Kill any dangerous flags popfl movl real_magic - wakeup_code, %eax cmpl $0x12345678, %eax jne bogus_real_magic - call verify_cpu # Verify the cpu supports long - # mode - testl %eax, %eax - jnz no_longmode - testl $1, video_flags - wakeup_code jz 1f lcall $0xc000,$3 movw %cs, %ax - movw %ax, %ds # Bios might have played with that + movw %ax, %ds # Bios might have played with that movw %ax, %ss 1: @@ -68,15 +61,12 @@ wakeup_code: movb $0xa2, %al ; outb %al, $0x80 - mov %ds, %ax # Find 32bit wakeup_code addr - movzx %ax, %esi # (Convert %ds:gdt to a liner ptr) - shll $4, %esi - # Fix up the vectors - addl %esi, wakeup_32_vector - wakeup_code - addl %esi, wakeup_long64_vector - wakeup_code - addl %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer - - lidtl %ds:idt_48a - wakeup_code + lidt %ds:idt_48a - wakeup_code + xorl %eax, %eax + movw %ds, %ax # (Convert %ds:gdt to a linear ptr) + shll $4, %eax + addl $(gdta - wakeup_code), %eax + movl %eax, gdt_48a +2 - wakeup_code lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is # appropriate @@ -85,63 +75,86 @@ wakeup_code: jmp 1f 1: - ljmpl *(wakeup_32_vector - wakeup_code) - - .balign 4 -wakeup_32_vector: - .long wakeup_32 - wakeup_code - .word __KERNEL32_CS, 0 + .byte 0x66, 0xea # prefix + jmpi-opcode + .long wakeup_32 - __START_KERNEL_map + .word __KERNEL_CS .code32 wakeup_32: # Running in this code, but at low address; paging is not yet turned on. movb $0xa5, %al ; outb %al, $0x80 - movl $__KERNEL_DS, %eax - movl %eax, %ds + /* Check if extended functions are implemented */ + movl $0x80000000, %eax + cpuid + cmpl $0x80000000, %eax + jbe bogus_cpu + wbinvd + mov $0x80000001, %eax + cpuid + btl $29, %edx + jnc bogus_cpu + movl %edx,%edi + + movw $__KERNEL_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs - movw $0x0e00 + 'i', %ds:(0xb8012) - movb $0xa8, %al ; outb %al, $0x80; + movw $__KERNEL_DS, %ax + movw %ax, %ss + + mov $(wakeup_stack - __START_KERNEL_map), %esp + movl saved_magic - __START_KERNEL_map, %eax + cmpl $0x9abcdef0, %eax + jne bogus_32_magic /* * Prepare for entering 64bits mode */ - /* Enable PAE */ + /* Enable PAE mode and PGE */ xorl %eax, %eax btsl $5, %eax + btsl $7, %eax movl %eax, %cr4 /* Setup early boot stage 4 level pagetables */ - leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax + movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax movl %eax, %cr3 - /* Check if nx is implemented */ - movl $0x80000001, %eax - cpuid - movl %edx,%edi - + /* Setup EFER (Extended Feature Enable Register) */ + movl $MSR_EFER, %ecx + rdmsr + /* Fool rdmsr and reset %eax to avoid dependences */ + xorl %eax, %eax /* Enable Long Mode */ - xorl %eax, %eax btsl $_EFER_LME, %eax + /* Enable System Call */ + btsl $_EFER_SCE, %eax - /* No Execute supported? */ + /* No Execute supported? */ btl $20,%edi jnc 1f btsl $_EFER_NX, %eax +1: /* Make changes effective */ -1: movl $MSR_EFER, %ecx - xorl %edx, %edx wrmsr + wbinvd xorl %eax, %eax btsl $31, %eax /* Enable paging and in turn activate Long Mode */ btsl $0, %eax /* Enable protected mode */ + btsl $1, %eax /* Enable MP */ + btsl $4, %eax /* Enable ET */ + btsl $5, %eax /* Enable NE */ + btsl $16, %eax /* Enable WP */ + btsl $18, %eax /* Enable AM */ /* Make changes effective */ movl %eax, %cr0 - /* At this point: CR4.PAE must be 1 CS.L must be 0 @@ -149,6 +162,11 @@ wakeup_32: Next instruction must be a branch This must be on identity-mapped page */ + jmp reach_compatibility_mode +reach_compatibility_mode: + movw $0x0e00 + 'i', %ds:(0xb8012) + movb $0xa8, %al ; outb %al, $0x80; + /* * At this point we're in long mode but in 32bit compatibility mode * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn @@ -156,19 +174,24 @@ wakeup_32: * the new gdt/idt that has __KERNEL_CS with CS.L = 1. */ + movw $0x0e00 + 'n', %ds:(0xb8014) + movb $0xa9, %al ; outb %al, $0x80 + + /* Load new GDT with the 64bit segment using 32bit descriptor */ + movl $(pGDT32 - __START_KERNEL_map), %eax + lgdt (%eax) + + movl $(wakeup_jumpvector - __START_KERNEL_map), %eax /* Finally jump in 64bit mode */ - ljmp *(wakeup_long64_vector - wakeup_code)(%esi) + ljmp *(%eax) - .balign 4 -wakeup_long64_vector: - .long wakeup_long64 - wakeup_code - .word __KERNEL_CS, 0 +wakeup_jumpvector: + .long wakeup_long64 - __START_KERNEL_map + .word __KERNEL_CS .code64 - /* Hooray, we are in Long 64-bit mode (but still running in - * low memory) - */ + /* Hooray, we are in Long 64-bit mode (but still running in low memory) */ wakeup_long64: /* * We must switch to a new descriptor in kernel space for the GDT @@ -176,15 +199,7 @@ wakeup_long64: * 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 cpu_gdt_descr - - movw $0x0e00 + 'n', %ds:(0xb8014) - movb $0xa9, %al ; outb %al, $0x80 - - movq saved_magic, %rax - movq $0x123456789abcdef0, %rdx - cmpq %rdx, %rax - jne bogus_64_magic + lgdt cpu_gdt_descr - __START_KERNEL_map movw $0x0e00 + 'u', %ds:(0xb8016) @@ -196,58 +211,75 @@ wakeup_long64: movw %ax, %es movw %ax, %fs movw %ax, %gs - movq saved_rsp, %rsp + movq saved_esp, %rsp movw $0x0e00 + 'x', %ds:(0xb8018) - movq saved_rbx, %rbx - movq saved_rdi, %rdi - movq saved_rsi, %rsi - movq saved_rbp, %rbp + movq saved_ebx, %rbx + movq saved_edi, %rdi + movq saved_esi, %rsi + movq saved_ebp, %rbp movw $0x0e00 + '!', %ds:(0xb801a) - movq saved_rip, %rax + movq saved_eip, %rax jmp *%rax .code32 .align 64 gdta: - /* Its good to keep gdt in sync with one in trampoline.S */ .word 0, 0, 0, 0 # dummy - /* ??? Why I need the accessed bit set in order for this to work? */ - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS + + .word 0, 0, 0, 0 # unused + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9B00 # code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?) + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9200 # data read/write + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) +# this is 64bit descriptor for code + .word 0xFFFF + .word 0 + .word 0x9A00 # code read/exec + .word 0x00AF # as above, but it is long mode and with D=0 idt_48a: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L gdt_48a: - .word 0x800 # gdt limit=2048, + .word 0x8000 # gdt limit=2048, # 256 GDT entries - .long gdta - wakeup_code # gdt base (relocated in later) + .word 0, 0 # gdt base (filled in later) + +real_save_gdt: .word 0 + .quad 0 real_magic: .quad 0 video_mode: .quad 0 video_flags: .quad 0 -.code16 bogus_real_magic: - movb $0xba,%al ; outb %al,$0x80 + movb $0xba,%al ; outb %al,$0x80 jmp bogus_real_magic -.code64 -bogus_64_magic: +bogus_32_magic: movb $0xb3,%al ; outb %al,$0x80 - jmp bogus_64_magic + jmp bogus_32_magic -.code16 -no_longmode: - movb $0xbc,%al ; outb %al,$0x80 - jmp no_longmode +bogus_31_magic: + movb $0xb1,%al ; outb %al,$0x80 + jmp bogus_31_magic + +bogus_cpu: + movb $0xbc,%al ; outb %al,$0x80 + jmp bogus_cpu -#include "../verify_cpu.S" /* This code uses an extended set of video mode numbers. These include: * Aliases for standard modes @@ -269,7 +301,6 @@ no_longmode: #define VIDEO_FIRST_V7 0x0900 # Setting of user mode (AX=mode ID) => CF=success -.code16 mode_seta: movw %ax, %bx #if 0 @@ -315,18 +346,21 @@ check_vesaa: _setbada: jmp setbada + .code64 +bogus_magic: + movw $0x0e00 + 'B', %ds:(0xb8018) + jmp bogus_magic + +bogus_magic2: + movw $0x0e00 + '2', %ds:(0xb8018) + jmp bogus_magic2 + + wakeup_stack_begin: # Stack grows down .org 0xff0 wakeup_stack: # Just below end of page -.org 0x1000 -ENTRY(wakeup_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 510,8,0 - /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE - ENTRY(wakeup_end) ## @@ -339,11 +373,28 @@ ENTRY(wakeup_end) # # Returned address is location of code in low memory (past data and stack) # - .code64 ENTRY(acpi_copy_wakeup_routine) pushq %rax + pushq %rcx pushq %rdx + sgdt saved_gdt + sidt saved_idt + sldt saved_ldt + str saved_tss + + movq %cr3, %rdx + movq %rdx, saved_cr3 + movq %cr4, %rdx + movq %rdx, saved_cr4 + movq %cr0, %rdx + movq %rdx, saved_cr0 + sgdt real_save_gdt - wakeup_start (,%rdi) + movl $MSR_EFER, %ecx + rdmsr + movl %eax, saved_efer + movl %edx, saved_efer2 + movl saved_video_mode, %edx movl %edx, video_mode - wakeup_start (,%rdi) movl acpi_video_flags, %edx @@ -352,13 +403,21 @@ ENTRY(acpi_copy_wakeup_routine) movq $0x123456789abcdef0, %rdx movq %rdx, saved_magic - movq saved_magic, %rax - movq $0x123456789abcdef0, %rdx - cmpq %rdx, %rax - jne bogus_64_magic + movl saved_magic - __START_KERNEL_map, %eax + cmpl $0x9abcdef0, %eax + jne bogus_32_magic + + # make sure %cr4 is set correctly (features, etc) + movl saved_cr4 - __START_KERNEL_map, %eax + movq %rax, %cr4 + movl saved_cr0 - __START_KERNEL_map, %eax + movq %rax, %cr0 + jmp 1f # Flush pipelines +1: # restore the regs we used popq %rdx + popq %rcx popq %rax ENTRY(do_suspend_lowlevel_s4bios) ret @@ -391,13 +450,13 @@ do_suspend_lowlevel: movq %r15, saved_context_r15(%rip) pushfq ; popq saved_context_eflags(%rip) - movq $.L97, saved_rip(%rip) + movq $.L97, saved_eip(%rip) - movq %rsp,saved_rsp - movq %rbp,saved_rbp - movq %rbx,saved_rbx - movq %rdi,saved_rdi - movq %rsi,saved_rsi + movq %rsp,saved_esp + movq %rbp,saved_ebp + movq %rbx,saved_ebx + movq %rdi,saved_edi + movq %rsi,saved_esi addq $8, %rsp movl $3, %edi @@ -444,12 +503,25 @@ do_suspend_lowlevel: .data ALIGN -ENTRY(saved_rbp) .quad 0 -ENTRY(saved_rsi) .quad 0 -ENTRY(saved_rdi) .quad 0 -ENTRY(saved_rbx) .quad 0 +ENTRY(saved_ebp) .quad 0 +ENTRY(saved_esi) .quad 0 +ENTRY(saved_edi) .quad 0 +ENTRY(saved_ebx) .quad 0 -ENTRY(saved_rip) .quad 0 -ENTRY(saved_rsp) .quad 0 +ENTRY(saved_eip) .quad 0 +ENTRY(saved_esp) .quad 0 ENTRY(saved_magic) .quad 0 + +ALIGN +# saved registers +saved_gdt: .quad 0,0 +saved_idt: .quad 0,0 +saved_ldt: .quad 0 +saved_tss: .quad 0 + +saved_cr0: .quad 0 +saved_cr3: .quad 0 +saved_cr4: .quad 0 +saved_efer: .quad 0 +saved_efer2: .quad 0 diff --git a/trunk/arch/x86_64/kernel/aperture.c b/trunk/arch/x86_64/kernel/aperture.c index a52af5820592..b487396c4c5b 100644 --- a/trunk/arch/x86_64/kernel/aperture.c +++ b/trunk/arch/x86_64/kernel/aperture.c @@ -51,6 +51,7 @@ static void __init insert_aperture_resource(u32 aper_base, u32 aper_size) static u32 __init allocate_aperture(void) { + pg_data_t *nd0 = NODE_DATA(0); u32 aper_size; void *p; @@ -64,12 +65,12 @@ static u32 __init allocate_aperture(void) * Unfortunately we cannot move it up because that would make the * IOMMU useless. */ - p = __alloc_bootmem_nopanic(aper_size, aper_size, 0); + 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(__pa(p), aper_size); + free_bootmem_node(nd0, __pa(p), aper_size); return 0; } printk("Mapping aperture over %d KB of RAM @ %lx\n", diff --git a/trunk/arch/x86_64/kernel/apic.c b/trunk/arch/x86_64/kernel/apic.c index d198f7d82e5a..bd3e45d47c37 100644 --- a/trunk/arch/x86_64/kernel/apic.c +++ b/trunk/arch/x86_64/kernel/apic.c @@ -68,28 +68,6 @@ int using_apic_timer __read_mostly = 0; static void apic_pm_activate(void); -void apic_wait_icr_idle(void) -{ - while (apic_read(APIC_ICR) & APIC_ICR_BUSY) - cpu_relax(); -} - -unsigned int safe_apic_wait_icr_idle(void) -{ - unsigned int send_status; - int timeout; - - timeout = 0; - do { - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; - if (!send_status) - break; - udelay(100); - } while (timeout++ < 1000); - - return send_status; -} - void enable_NMI_through_LVT0 (void * dummy) { unsigned int v; @@ -839,15 +817,14 @@ static void setup_APIC_timer(unsigned int clocks) static int __init calibrate_APIC_clock(void) { - unsigned apic, apic_start; - unsigned long tsc, tsc_start; + int apic, apic_start, tsc, tsc_start; int result; /* * Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the * counter running for calibration. */ - __setup_APIC_LVTT(4000000000); + __setup_APIC_LVTT(1000000000); apic_start = apic_read(APIC_TMCCT); #ifdef CONFIG_X86_PM_TIMER @@ -858,15 +835,15 @@ static int __init calibrate_APIC_clock(void) } else #endif { - rdtscll(tsc_start); + rdtscl(tsc_start); do { apic = apic_read(APIC_TMCCT); - rdtscll(tsc); + rdtscl(tsc); } while ((tsc - tsc_start) < TICK_COUNT && - (apic_start - apic) < TICK_COUNT); + (apic - apic_start) < TICK_COUNT); - result = (apic_start - apic) * 1000L * tsc_khz / + result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start); } printk("result %d\n", result); diff --git a/trunk/arch/x86_64/kernel/asm-offsets.c b/trunk/arch/x86_64/kernel/asm-offsets.c index 778953bc636c..96687e2beb2c 100644 --- a/trunk/arch/x86_64/kernel/asm-offsets.c +++ b/trunk/arch/x86_64/kernel/asm-offsets.c @@ -21,14 +21,6 @@ #define BLANK() asm volatile("\n->" : : ) -#define __NO_STUBS 1 -#undef __SYSCALL -#undef _ASM_X86_64_UNISTD_H_ -#define __SYSCALL(nr, sym) [nr] = 1, -static char syscalls[] = { -#include -}; - int main(void) { #define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry)) @@ -79,7 +71,5 @@ int main(void) DEFINE(TSS_ist, offsetof(struct tss_struct, ist)); BLANK(); DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); - BLANK(); - DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); return 0; } diff --git a/trunk/arch/x86_64/kernel/bugs.c b/trunk/arch/x86_64/kernel/bugs.c deleted file mode 100644 index 12b585b5345d..000000000000 --- a/trunk/arch/x86_64/kernel/bugs.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * arch/x86_64/kernel/bugs.c - * - * Copyright (C) 1994 Linus Torvalds - * Copyright (C) 2000 SuSE - */ - -#include -#include -#include -#include - -void __init check_bugs(void) -{ - identify_cpu(&boot_cpu_data); -#if !defined(CONFIG_SMP) - printk("CPU: "); - print_cpu_info(&boot_cpu_data); -#endif - alternative_instructions(); -} diff --git a/trunk/arch/x86_64/kernel/cpufreq/Kconfig b/trunk/arch/x86_64/kernel/cpufreq/Kconfig index c0749d2479f5..40acb67fb882 100644 --- a/trunk/arch/x86_64/kernel/cpufreq/Kconfig +++ b/trunk/arch/x86_64/kernel/cpufreq/Kconfig @@ -16,9 +16,6 @@ config X86_POWERNOW_K8 help This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors. - To compile this driver as a module, choose M here: the - module will be called powernow-k8. - For details, take a look at . If in doubt, say N. @@ -41,9 +38,6 @@ config X86_SPEEDSTEP_CENTRINO mobile CPUs. This means Intel Pentium M (Centrino) CPUs or 64bit enabled Intel Xeons. - To compile this driver as a module, choose M here: the - module will be called speedstep-centrino. - For details, take a look at . If in doubt, say N. @@ -61,9 +55,6 @@ config X86_ACPI_CPUFREQ Processor Performance States. This driver also supports Intel Enhanced Speedstep. - To compile this driver as a module, choose M here: the - module will be called acpi-cpufreq. - For details, take a look at . If in doubt, say N. @@ -71,7 +62,7 @@ config X86_ACPI_CPUFREQ comment "shared options" config X86_ACPI_CPUFREQ_PROC_INTF - bool "/proc/acpi/processor/../performance interface (deprecated)" + bool "/proc/acpi/processor/../performance interface (deprecated)" depends on PROC_FS depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI help @@ -95,18 +86,16 @@ config X86_P4_CLOCKMOD slowdowns and noticeable latencies. Normally Speedstep should be used instead. - To compile this driver as a module, choose M here: the - module will be called p4-clockmod. - For details, take a look at . Unless you are absolutely sure say N. config X86_SPEEDSTEP_LIB - tristate - default X86_P4_CLOCKMOD + tristate + default X86_P4_CLOCKMOD endif endmenu + diff --git a/trunk/arch/x86_64/kernel/e820.c b/trunk/arch/x86_64/kernel/e820.c index be8965427a93..a490fabfcf47 100644 --- a/trunk/arch/x86_64/kernel/e820.c +++ b/trunk/arch/x86_64/kernel/e820.c @@ -25,7 +25,7 @@ #include #include -struct e820map e820; +struct e820map e820 __initdata; /* * PFN of last memory page. @@ -98,7 +98,7 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size) * This function checks if any part of the range is mapped * with type. */ -int +int __meminit e820_any_mapped(unsigned long start, unsigned long end, unsigned type) { int i; @@ -112,7 +112,6 @@ e820_any_mapped(unsigned long start, unsigned long end, unsigned type) } return 0; } -EXPORT_SYMBOL_GPL(e820_any_mapped); /* * This function checks if the entire range is mapped with type. diff --git a/trunk/arch/x86_64/kernel/early-quirks.c b/trunk/arch/x86_64/kernel/early-quirks.c index 990d9c218a5d..fede55a53995 100644 --- a/trunk/arch/x86_64/kernel/early-quirks.c +++ b/trunk/arch/x86_64/kernel/early-quirks.c @@ -71,6 +71,18 @@ static void __init ati_bugs(void) } } +static void intel_bugs(void) +{ + u16 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID); + +#ifdef CONFIG_SMP + if (device == PCI_DEVICE_ID_INTEL_E7320_MCH || + device == PCI_DEVICE_ID_INTEL_E7520_MCH || + device == PCI_DEVICE_ID_INTEL_E7525_MCH) + quirk_intel_irqbalance(); +#endif +} + struct chipset { u16 vendor; void (*f)(void); @@ -80,6 +92,7 @@ static struct chipset early_qrk[] __initdata = { { PCI_VENDOR_ID_NVIDIA, nvidia_bugs }, { PCI_VENDOR_ID_VIA, via_bugs }, { PCI_VENDOR_ID_ATI, ati_bugs }, + { PCI_VENDOR_ID_INTEL, intel_bugs}, {} }; diff --git a/trunk/arch/x86_64/kernel/early_printk.c b/trunk/arch/x86_64/kernel/early_printk.c index 92213d2b7c11..47b6d90349da 100644 --- a/trunk/arch/x86_64/kernel/early_printk.c +++ b/trunk/arch/x86_64/kernel/early_printk.c @@ -11,10 +11,11 @@ #ifdef __i386__ #include +#define VGABASE (__ISA_IO_base + 0xb8000) #else #include +#define VGABASE ((void __iomem *)0xffffffff800b8000UL) #endif -#define VGABASE (__ISA_IO_base + 0xb8000) static int max_ypos = 25, max_xpos = 80; static int current_ypos = 25, current_xpos = 0; @@ -175,7 +176,7 @@ static noinline long simnow(long cmd, long a, long b, long c) return ret; } -static void __init simnow_init(char *str) +void __init simnow_init(char *str) { char *fn = "klog"; if (*str == '=') diff --git a/trunk/arch/x86_64/kernel/entry.S b/trunk/arch/x86_64/kernel/entry.S index fa984b53e7e6..ed4350ced3d0 100644 --- a/trunk/arch/x86_64/kernel/entry.S +++ b/trunk/arch/x86_64/kernel/entry.S @@ -701,7 +701,6 @@ END(spurious_interrupt) CFI_ADJUST_CFA_OFFSET 8 pushq %rax /* push real oldrax to the rdi slot */ CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rax,0 leaq \sym(%rip),%rax jmp error_entry CFI_ENDPROC @@ -711,7 +710,6 @@ END(spurious_interrupt) XCPT_FRAME pushq %rax CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rax,0 leaq \sym(%rip),%rax jmp error_entry CFI_ENDPROC @@ -819,7 +817,6 @@ paranoid_schedule\trace: */ KPROBE_ENTRY(error_entry) _frame RDI - CFI_REL_OFFSET rax,0 /* rdi slot contains rax, oldrax contains error code */ cld subq $14*8,%rsp @@ -827,7 +824,6 @@ KPROBE_ENTRY(error_entry) movq %rsi,13*8(%rsp) CFI_REL_OFFSET rsi,RSI movq 14*8(%rsp),%rsi /* load rax from rdi slot */ - CFI_REGISTER rax,rsi movq %rdx,12*8(%rsp) CFI_REL_OFFSET rdx,RDX movq %rcx,11*8(%rsp) @@ -861,7 +857,6 @@ error_swapgs: swapgs error_sti: movq %rdi,RDI(%rsp) - CFI_REL_OFFSET rdi,RDI movq %rsp,%rdi movq ORIG_RAX(%rsp),%rsi /* get error code */ movq $-1,ORIG_RAX(%rsp) diff --git a/trunk/arch/x86_64/kernel/functionlist b/trunk/arch/x86_64/kernel/functionlist new file mode 100644 index 000000000000..7ae18ec12454 --- /dev/null +++ b/trunk/arch/x86_64/kernel/functionlist @@ -0,0 +1,1284 @@ +*(.text.flush_thread) +*(.text.check_poison_obj) +*(.text.copy_page) +*(.text.__set_personality) +*(.text.gart_map_sg) +*(.text.kmem_cache_free) +*(.text.find_get_page) +*(.text._raw_spin_lock) +*(.text.ide_outb) +*(.text.unmap_vmas) +*(.text.copy_page_range) +*(.text.kprobe_handler) +*(.text.__handle_mm_fault) +*(.text.__d_lookup) +*(.text.copy_user_generic) +*(.text.__link_path_walk) +*(.text.get_page_from_freelist) +*(.text.kmem_cache_alloc) +*(.text.drive_cmd_intr) +*(.text.ia32_setup_sigcontext) +*(.text.huge_pte_offset) +*(.text.do_page_fault) +*(.text.page_remove_rmap) +*(.text.release_pages) +*(.text.ide_end_request) +*(.text.__mutex_lock_slowpath) +*(.text.__find_get_block) +*(.text.kfree) +*(.text.vfs_read) +*(.text._raw_spin_unlock) +*(.text.free_hot_cold_page) +*(.text.fget_light) +*(.text.schedule) +*(.text.memcmp) +*(.text.touch_atime) +*(.text.__might_sleep) +*(.text.__down_read_trylock) +*(.text.arch_pick_mmap_layout) +*(.text.find_vma) +*(.text.__make_request) +*(.text.do_generic_mapping_read) +*(.text.mutex_lock_interruptible) +*(.text.__generic_file_aio_read) +*(.text._atomic_dec_and_lock) +*(.text.__wake_up_bit) +*(.text.add_to_page_cache) +*(.text.cache_alloc_debugcheck_after) +*(.text.vm_normal_page) +*(.text.mutex_debug_check_no_locks_freed) +*(.text.net_rx_action) +*(.text.__find_first_zero_bit) +*(.text.put_page) +*(.text._raw_read_lock) +*(.text.__delay) +*(.text.dnotify_parent) +*(.text.do_path_lookup) +*(.text.do_sync_read) +*(.text.do_lookup) +*(.text.bit_waitqueue) +*(.text.file_read_actor) +*(.text.strncpy_from_user) +*(.text.__pagevec_lru_add_active) +*(.text.fget) +*(.text.dput) +*(.text.__strnlen_user) +*(.text.inotify_inode_queue_event) +*(.text.rw_verify_area) +*(.text.ide_intr) +*(.text.inotify_dentry_parent_queue_event) +*(.text.permission) +*(.text.memscan) +*(.text.hpet_rtc_interrupt) +*(.text.do_mmap_pgoff) +*(.text.current_fs_time) +*(.text.vfs_getattr) +*(.text.kmem_flagcheck) +*(.text.mark_page_accessed) +*(.text.free_pages_and_swap_cache) +*(.text.generic_fillattr) +*(.text.__block_prepare_write) +*(.text.__set_page_dirty_nobuffers) +*(.text.link_path_walk) +*(.text.find_get_pages_tag) +*(.text.ide_do_request) +*(.text.__alloc_pages) +*(.text.generic_permission) +*(.text.mod_page_state_offset) +*(.text.free_pgd_range) +*(.text.generic_file_buffered_write) +*(.text.number) +*(.text.ide_do_rw_disk) +*(.text.__brelse) +*(.text.__mod_page_state_offset) +*(.text.rotate_reclaimable_page) +*(.text.find_vma_prepare) +*(.text.find_vma_prev) +*(.text.lru_cache_add_active) +*(.text.__kmalloc_track_caller) +*(.text.smp_invalidate_interrupt) +*(.text.handle_IRQ_event) +*(.text.__find_get_block_slow) +*(.text.do_wp_page) +*(.text.do_select) +*(.text.set_user_nice) +*(.text.sys_read) +*(.text.do_munmap) +*(.text.csum_partial) +*(.text.__do_softirq) +*(.text.may_open) +*(.text.getname) +*(.text.get_empty_filp) +*(.text.__fput) +*(.text.remove_mapping) +*(.text.filp_ctor) +*(.text.poison_obj) +*(.text.unmap_region) +*(.text.test_set_page_writeback) +*(.text.__do_page_cache_readahead) +*(.text.sock_def_readable) +*(.text.ide_outl) +*(.text.shrink_zone) +*(.text.rb_insert_color) +*(.text.get_request) +*(.text.sys_pread64) +*(.text.spin_bug) +*(.text.ide_outsl) +*(.text.mask_and_ack_8259A) +*(.text.filemap_nopage) +*(.text.page_add_file_rmap) +*(.text.find_lock_page) +*(.text.tcp_poll) +*(.text.__mark_inode_dirty) +*(.text.file_ra_state_init) +*(.text.generic_file_llseek) +*(.text.__pagevec_lru_add) +*(.text.page_cache_readahead) +*(.text.n_tty_receive_buf) +*(.text.zonelist_policy) +*(.text.vma_adjust) +*(.text.test_clear_page_dirty) +*(.text.sync_buffer) +*(.text.do_exit) +*(.text.__bitmap_weight) +*(.text.alloc_pages_current) +*(.text.get_unused_fd) +*(.text.zone_watermark_ok) +*(.text.cpuset_update_task_memory_state) +*(.text.__bitmap_empty) +*(.text.sys_munmap) +*(.text.__inode_dir_notify) +*(.text.__generic_file_aio_write_nolock) +*(.text.__pte_alloc) +*(.text.sys_select) +*(.text.vm_acct_memory) +*(.text.vfs_write) +*(.text.__lru_add_drain) +*(.text.prio_tree_insert) +*(.text.generic_file_aio_read) +*(.text.vma_merge) +*(.text.block_write_full_page) +*(.text.__page_set_anon_rmap) +*(.text.apic_timer_interrupt) +*(.text.release_console_sem) +*(.text.sys_write) +*(.text.sys_brk) +*(.text.dup_mm) +*(.text.read_current_timer) +*(.text.ll_rw_block) +*(.text.blk_rq_map_sg) +*(.text.dbg_userword) +*(.text.__block_commit_write) +*(.text.cache_grow) +*(.text.copy_strings) +*(.text.release_task) +*(.text.do_sync_write) +*(.text.unlock_page) +*(.text.load_elf_binary) +*(.text.__follow_mount) +*(.text.__getblk) +*(.text.do_sys_open) +*(.text.current_kernel_time) +*(.text.call_rcu) +*(.text.write_chan) +*(.text.vsnprintf) +*(.text.dummy_inode_setsecurity) +*(.text.submit_bh) +*(.text.poll_freewait) +*(.text.bio_alloc_bioset) +*(.text.skb_clone) +*(.text.page_waitqueue) +*(.text.__mutex_lock_interruptible_slowpath) +*(.text.get_index) +*(.text.csum_partial_copy_generic) +*(.text.bad_range) +*(.text.remove_vma) +*(.text.cp_new_stat) +*(.text.alloc_arraycache) +*(.text.test_clear_page_writeback) +*(.text.strsep) +*(.text.open_namei) +*(.text._raw_read_unlock) +*(.text.get_vma_policy) +*(.text.__down_write_trylock) +*(.text.find_get_pages) +*(.text.tcp_rcv_established) +*(.text.generic_make_request) +*(.text.__block_write_full_page) +*(.text.cfq_set_request) +*(.text.sys_inotify_init) +*(.text.split_vma) +*(.text.__mod_timer) +*(.text.get_options) +*(.text.vma_link) +*(.text.mpage_writepages) +*(.text.truncate_complete_page) +*(.text.tcp_recvmsg) +*(.text.sigprocmask) +*(.text.filemap_populate) +*(.text.sys_close) +*(.text.inotify_dev_queue_event) +*(.text.do_task_stat) +*(.text.__dentry_open) +*(.text.unlink_file_vma) +*(.text.__pollwait) +*(.text.packet_rcv_spkt) +*(.text.drop_buffers) +*(.text.free_pgtables) +*(.text.generic_file_direct_write) +*(.text.copy_process) +*(.text.netif_receive_skb) +*(.text.dnotify_flush) +*(.text.print_bad_pte) +*(.text.anon_vma_unlink) +*(.text.sys_mprotect) +*(.text.sync_sb_inodes) +*(.text.find_inode_fast) +*(.text.dummy_inode_readlink) +*(.text.putname) +*(.text.init_smp_flush) +*(.text.dbg_redzone2) +*(.text.sk_run_filter) +*(.text.may_expand_vm) +*(.text.generic_file_aio_write) +*(.text.find_next_zero_bit) +*(.text.file_kill) +*(.text.audit_getname) +*(.text.arch_unmap_area_topdown) +*(.text.alloc_page_vma) +*(.text.tcp_transmit_skb) +*(.text.rb_next) +*(.text.dbg_redzone1) +*(.text.generic_file_mmap) +*(.text.vfs_fstat) +*(.text.sys_time) +*(.text.page_lock_anon_vma) +*(.text.get_unmapped_area) +*(.text.remote_llseek) +*(.text.__up_read) +*(.text.fd_install) +*(.text.eventpoll_init_file) +*(.text.dma_alloc_coherent) +*(.text.create_empty_buffers) +*(.text.__mutex_unlock_slowpath) +*(.text.dup_fd) +*(.text.d_alloc) +*(.text.tty_ldisc_try) +*(.text.sys_stime) +*(.text.__rb_rotate_right) +*(.text.d_validate) +*(.text.rb_erase) +*(.text.path_release) +*(.text.memmove) +*(.text.invalidate_complete_page) +*(.text.clear_inode) +*(.text.cache_estimate) +*(.text.alloc_buffer_head) +*(.text.smp_call_function_interrupt) +*(.text.flush_tlb_others) +*(.text.file_move) +*(.text.balance_dirty_pages_ratelimited) +*(.text.vma_prio_tree_add) +*(.text.timespec_trunc) +*(.text.mempool_alloc) +*(.text.iget_locked) +*(.text.d_alloc_root) +*(.text.cpuset_populate_dir) +*(.text.anon_vma_prepare) +*(.text.sys_newstat) +*(.text.alloc_page_interleave) +*(.text.__path_lookup_intent_open) +*(.text.__pagevec_free) +*(.text.inode_init_once) +*(.text.free_vfsmnt) +*(.text.__user_walk_fd) +*(.text.cfq_idle_slice_timer) +*(.text.sys_mmap) +*(.text.sys_llseek) +*(.text.prio_tree_remove) +*(.text.filp_close) +*(.text.file_permission) +*(.text.vma_prio_tree_remove) +*(.text.tcp_ack) +*(.text.nameidata_to_filp) +*(.text.sys_lseek) +*(.text.percpu_counter_mod) +*(.text.igrab) +*(.text.__bread) +*(.text.alloc_inode) +*(.text.filldir) +*(.text.__rb_rotate_left) +*(.text.irq_affinity_write_proc) +*(.text.init_request_from_bio) +*(.text.find_or_create_page) +*(.text.tty_poll) +*(.text.tcp_sendmsg) +*(.text.ide_wait_stat) +*(.text.free_buffer_head) +*(.text.flush_signal_handlers) +*(.text.tcp_v4_rcv) +*(.text.nr_blockdev_pages) +*(.text.locks_remove_flock) +*(.text.__iowrite32_copy) +*(.text.do_filp_open) +*(.text.try_to_release_page) +*(.text.page_add_new_anon_rmap) +*(.text.kmem_cache_size) +*(.text.eth_type_trans) +*(.text.try_to_free_buffers) +*(.text.schedule_tail) +*(.text.proc_lookup) +*(.text.no_llseek) +*(.text.kfree_skbmem) +*(.text.do_wait) +*(.text.do_mpage_readpage) +*(.text.vfs_stat_fd) +*(.text.tty_write) +*(.text.705) +*(.text.sync_page) +*(.text.__remove_shared_vm_struct) +*(.text.__kfree_skb) +*(.text.sock_poll) +*(.text.get_request_wait) +*(.text.do_sigaction) +*(.text.do_brk) +*(.text.tcp_event_data_recv) +*(.text.read_chan) +*(.text.pipe_writev) +*(.text.__emul_lookup_dentry) +*(.text.rtc_get_rtc_time) +*(.text.print_objinfo) +*(.text.file_update_time) +*(.text.do_signal) +*(.text.disable_8259A_irq) +*(.text.blk_queue_bounce) +*(.text.__anon_vma_link) +*(.text.__vma_link) +*(.text.vfs_rename) +*(.text.sys_newlstat) +*(.text.sys_newfstat) +*(.text.sys_mknod) +*(.text.__show_regs) +*(.text.iput) +*(.text.get_signal_to_deliver) +*(.text.flush_tlb_page) +*(.text.debug_mutex_wake_waiter) +*(.text.copy_thread) +*(.text.clear_page_dirty_for_io) +*(.text.buffer_io_error) +*(.text.vfs_permission) +*(.text.truncate_inode_pages_range) +*(.text.sys_recvfrom) +*(.text.remove_suid) +*(.text.mark_buffer_dirty) +*(.text.local_bh_enable) +*(.text.get_zeroed_page) +*(.text.get_vmalloc_info) +*(.text.flush_old_exec) +*(.text.dummy_inode_permission) +*(.text.__bio_add_page) +*(.text.prio_tree_replace) +*(.text.notify_change) +*(.text.mntput_no_expire) +*(.text.fput) +*(.text.__end_that_request_first) +*(.text.wake_up_bit) +*(.text.unuse_mm) +*(.text.shrink_icache_memory) +*(.text.sched_balance_self) +*(.text.__pmd_alloc) +*(.text.pipe_poll) +*(.text.normal_poll) +*(.text.__free_pages) +*(.text.follow_mount) +*(.text.cdrom_start_packet_command) +*(.text.blk_recount_segments) +*(.text.bio_put) +*(.text.__alloc_skb) +*(.text.__wake_up) +*(.text.vm_stat_account) +*(.text.sys_fcntl) +*(.text.sys_fadvise64) +*(.text._raw_write_unlock) +*(.text.__pud_alloc) +*(.text.alloc_page_buffers) +*(.text.vfs_llseek) +*(.text.sockfd_lookup) +*(.text._raw_write_lock) +*(.text.put_compound_page) +*(.text.prune_dcache) +*(.text.pipe_readv) +*(.text.mempool_free) +*(.text.make_ahead_window) +*(.text.lru_add_drain) +*(.text.constant_test_bit) +*(.text.__clear_user) +*(.text.arch_unmap_area) +*(.text.anon_vma_link) +*(.text.sys_chroot) +*(.text.setup_arg_pages) +*(.text.radix_tree_preload) +*(.text.init_rwsem) +*(.text.generic_osync_inode) +*(.text.generic_delete_inode) +*(.text.do_sys_poll) +*(.text.dev_queue_xmit) +*(.text.default_llseek) +*(.text.__writeback_single_inode) +*(.text.vfs_ioctl) +*(.text.__up_write) +*(.text.unix_poll) +*(.text.sys_rt_sigprocmask) +*(.text.sock_recvmsg) +*(.text.recalc_bh_state) +*(.text.__put_unused_fd) +*(.text.process_backlog) +*(.text.locks_remove_posix) +*(.text.lease_modify) +*(.text.expand_files) +*(.text.end_buffer_read_nobh) +*(.text.d_splice_alias) +*(.text.debug_mutex_init_waiter) +*(.text.copy_from_user) +*(.text.cap_vm_enough_memory) +*(.text.show_vfsmnt) +*(.text.release_sock) +*(.text.pfifo_fast_enqueue) +*(.text.half_md4_transform) +*(.text.fs_may_remount_ro) +*(.text.do_fork) +*(.text.copy_hugetlb_page_range) +*(.text.cache_free_debugcheck) +*(.text.__tcp_select_window) +*(.text.task_handoff_register) +*(.text.sys_open) +*(.text.strlcpy) +*(.text.skb_copy_datagram_iovec) +*(.text.set_up_list3s) +*(.text.release_open_intent) +*(.text.qdisc_restart) +*(.text.n_tty_chars_in_buffer) +*(.text.inode_change_ok) +*(.text.__downgrade_write) +*(.text.debug_mutex_unlock) +*(.text.add_timer_randomness) +*(.text.sock_common_recvmsg) +*(.text.set_bh_page) +*(.text.printk_lock) +*(.text.path_release_on_umount) +*(.text.ip_output) +*(.text.ide_build_dmatable) +*(.text.__get_user_8) +*(.text.end_buffer_read_sync) +*(.text.__d_path) +*(.text.d_move) +*(.text.del_timer) +*(.text.constant_test_bit) +*(.text.blockable_page_cache_readahead) +*(.text.tty_read) +*(.text.sys_readlink) +*(.text.sys_faccessat) +*(.text.read_swap_cache_async) +*(.text.pty_write_room) +*(.text.page_address_in_vma) +*(.text.kthread) +*(.text.cfq_exit_io_context) +*(.text.__tcp_push_pending_frames) +*(.text.sys_pipe) +*(.text.submit_bio) +*(.text.pid_revalidate) +*(.text.page_referenced_file) +*(.text.lock_sock) +*(.text.get_page_state_node) +*(.text.generic_block_bmap) +*(.text.do_setitimer) +*(.text.dev_queue_xmit_nit) +*(.text.copy_from_read_buf) +*(.text.__const_udelay) +*(.text.console_conditional_schedule) +*(.text.wake_up_new_task) +*(.text.wait_for_completion_interruptible) +*(.text.tcp_rcv_rtt_update) +*(.text.sys_mlockall) +*(.text.set_fs_altroot) +*(.text.schedule_timeout) +*(.text.nr_free_pagecache_pages) +*(.text.nf_iterate) +*(.text.mapping_tagged) +*(.text.ip_queue_xmit) +*(.text.ip_local_deliver) +*(.text.follow_page) +*(.text.elf_map) +*(.text.dummy_file_permission) +*(.text.dispose_list) +*(.text.dentry_open) +*(.text.dentry_iput) +*(.text.bio_alloc) +*(.text.wait_on_page_bit) +*(.text.vfs_readdir) +*(.text.vfs_lstat) +*(.text.seq_escape) +*(.text.__posix_lock_file) +*(.text.mm_release) +*(.text.kref_put) +*(.text.ip_rcv) +*(.text.__iget) +*(.text.free_pages) +*(.text.find_mergeable_anon_vma) +*(.text.find_extend_vma) +*(.text.dummy_inode_listsecurity) +*(.text.bio_add_page) +*(.text.__vm_enough_memory) +*(.text.vfs_stat) +*(.text.tty_paranoia_check) +*(.text.tcp_read_sock) +*(.text.tcp_data_queue) +*(.text.sys_uname) +*(.text.sys_renameat) +*(.text.__strncpy_from_user) +*(.text.__mutex_init) +*(.text.__lookup_hash) +*(.text.kref_get) +*(.text.ip_route_input) +*(.text.__insert_inode_hash) +*(.text.do_sock_write) +*(.text.blk_done_softirq) +*(.text.__wake_up_sync) +*(.text.__vma_link_rb) +*(.text.tty_ioctl) +*(.text.tracesys) +*(.text.sys_getdents) +*(.text.sys_dup) +*(.text.stub_execve) +*(.text.sha_transform) +*(.text.radix_tree_tag_clear) +*(.text.put_unused_fd) +*(.text.put_files_struct) +*(.text.mpage_readpages) +*(.text.may_delete) +*(.text.kmem_cache_create) +*(.text.ip_mc_output) +*(.text.interleave_nodes) +*(.text.groups_search) +*(.text.generic_drop_inode) +*(.text.generic_commit_write) +*(.text.fcntl_setlk) +*(.text.exit_mmap) +*(.text.end_page_writeback) +*(.text.__d_rehash) +*(.text.debug_mutex_free_waiter) +*(.text.csum_ipv6_magic) +*(.text.count) +*(.text.cleanup_rbuf) +*(.text.check_spinlock_acquired_node) +*(.text.can_vma_merge_after) +*(.text.bio_endio) +*(.text.alloc_pidmap) +*(.text.write_ldt) +*(.text.vmtruncate_range) +*(.text.vfs_create) +*(.text.__user_walk) +*(.text.update_send_head) +*(.text.unmap_underlying_metadata) +*(.text.tty_ldisc_deref) +*(.text.tcp_setsockopt) +*(.text.tcp_send_ack) +*(.text.sys_pause) +*(.text.sys_gettimeofday) +*(.text.sync_dirty_buffer) +*(.text.strncmp) +*(.text.release_posix_timer) +*(.text.proc_file_read) +*(.text.prepare_to_wait) +*(.text.locks_mandatory_locked) +*(.text.interruptible_sleep_on_timeout) +*(.text.inode_sub_bytes) +*(.text.in_group_p) +*(.text.hrtimer_try_to_cancel) +*(.text.filldir64) +*(.text.fasync_helper) +*(.text.dummy_sb_pivotroot) +*(.text.d_lookup) +*(.text.d_instantiate) +*(.text.__d_find_alias) +*(.text.cpu_idle_wait) +*(.text.cond_resched_lock) +*(.text.chown_common) +*(.text.blk_congestion_wait) +*(.text.activate_page) +*(.text.unlock_buffer) +*(.text.tty_wakeup) +*(.text.tcp_v4_do_rcv) +*(.text.tcp_current_mss) +*(.text.sys_openat) +*(.text.sys_fchdir) +*(.text.strnlen_user) +*(.text.strnlen) +*(.text.strchr) +*(.text.sock_common_getsockopt) +*(.text.skb_checksum) +*(.text.remove_wait_queue) +*(.text.rb_replace_node) +*(.text.radix_tree_node_ctor) +*(.text.pty_chars_in_buffer) +*(.text.profile_hit) +*(.text.prio_tree_left) +*(.text.pgd_clear_bad) +*(.text.pfifo_fast_dequeue) +*(.text.page_referenced) +*(.text.open_exec) +*(.text.mmput) +*(.text.mm_init) +*(.text.__ide_dma_off_quietly) +*(.text.ide_dma_intr) +*(.text.hrtimer_start) +*(.text.get_io_context) +*(.text.__get_free_pages) +*(.text.find_first_zero_bit) +*(.text.file_free_rcu) +*(.text.dummy_socket_sendmsg) +*(.text.do_unlinkat) +*(.text.do_arch_prctl) +*(.text.destroy_inode) +*(.text.can_vma_merge_before) +*(.text.block_sync_page) +*(.text.block_prepare_write) +*(.text.bio_init) +*(.text.arch_ptrace) +*(.text.wake_up_inode) +*(.text.wait_on_retry_sync_kiocb) +*(.text.vma_prio_tree_next) +*(.text.tcp_rcv_space_adjust) +*(.text.__tcp_ack_snd_check) +*(.text.sys_utime) +*(.text.sys_recvmsg) +*(.text.sys_mremap) +*(.text.sys_bdflush) +*(.text.sleep_on) +*(.text.set_page_dirty_lock) +*(.text.seq_path) +*(.text.schedule_timeout_interruptible) +*(.text.sched_fork) +*(.text.rt_run_flush) +*(.text.profile_munmap) +*(.text.prepare_binprm) +*(.text.__pagevec_release_nonlru) +*(.text.m_show) +*(.text.lookup_mnt) +*(.text.__lookup_mnt) +*(.text.lock_timer_base) +*(.text.is_subdir) +*(.text.invalidate_bh_lru) +*(.text.init_buffer_head) +*(.text.ifind_fast) +*(.text.ide_dma_start) +*(.text.__get_page_state) +*(.text.flock_to_posix_lock) +*(.text.__find_symbol) +*(.text.do_futex) +*(.text.do_execve) +*(.text.dirty_writeback_centisecs_handler) +*(.text.dev_watchdog) +*(.text.can_share_swap_page) +*(.text.blkdev_put) +*(.text.bio_get_nr_vecs) +*(.text.xfrm_compile_policy) +*(.text.vma_prio_tree_insert) +*(.text.vfs_lstat_fd) +*(.text.__user_path_lookup_open) +*(.text.thread_return) +*(.text.tcp_send_delayed_ack) +*(.text.sock_def_error_report) +*(.text.shrink_slab) +*(.text.serial_out) +*(.text.seq_read) +*(.text.secure_ip_id) +*(.text.search_binary_handler) +*(.text.proc_pid_unhash) +*(.text.pagevec_lookup) +*(.text.new_inode) +*(.text.memcpy_toiovec) +*(.text.locks_free_lock) +*(.text.__lock_page) +*(.text.__lock_buffer) +*(.text.load_module) +*(.text.is_bad_inode) +*(.text.invalidate_inode_buffers) +*(.text.insert_vm_struct) +*(.text.inode_setattr) +*(.text.inode_add_bytes) +*(.text.ide_read_24) +*(.text.ide_get_error_location) +*(.text.ide_do_drive_cmd) +*(.text.get_locked_pte) +*(.text.get_filesystem_list) +*(.text.generic_file_open) +*(.text.follow_down) +*(.text.find_next_bit) +*(.text.__find_first_bit) +*(.text.exit_mm) +*(.text.exec_keys) +*(.text.end_buffer_write_sync) +*(.text.end_bio_bh_io_sync) +*(.text.dummy_socket_shutdown) +*(.text.d_rehash) +*(.text.d_path) +*(.text.do_ioctl) +*(.text.dget_locked) +*(.text.copy_thread_group_keys) +*(.text.cdrom_end_request) +*(.text.cap_bprm_apply_creds) +*(.text.blk_rq_bio_prep) +*(.text.__bitmap_intersects) +*(.text.bio_phys_segments) +*(.text.bio_free) +*(.text.arch_get_unmapped_area_topdown) +*(.text.writeback_in_progress) +*(.text.vfs_follow_link) +*(.text.tcp_rcv_state_process) +*(.text.tcp_check_space) +*(.text.sys_stat) +*(.text.sys_rt_sigreturn) +*(.text.sys_rt_sigaction) +*(.text.sys_remap_file_pages) +*(.text.sys_pwrite64) +*(.text.sys_fchownat) +*(.text.sys_fchmodat) +*(.text.strncat) +*(.text.strlcat) +*(.text.strcmp) +*(.text.steal_locks) +*(.text.sock_create) +*(.text.sk_stream_rfree) +*(.text.sk_stream_mem_schedule) +*(.text.skip_atoi) +*(.text.sk_alloc) +*(.text.show_stat) +*(.text.set_fs_pwd) +*(.text.set_binfmt) +*(.text.pty_unthrottle) +*(.text.proc_symlink) +*(.text.pipe_release) +*(.text.pageout) +*(.text.n_tty_write_wakeup) +*(.text.n_tty_ioctl) +*(.text.nr_free_zone_pages) +*(.text.migration_thread) +*(.text.mempool_free_slab) +*(.text.meminfo_read_proc) +*(.text.max_sane_readahead) +*(.text.lru_cache_add) +*(.text.kill_fasync) +*(.text.kernel_read) +*(.text.invalidate_mapping_pages) +*(.text.inode_has_buffers) +*(.text.init_once) +*(.text.inet_sendmsg) +*(.text.idedisk_issue_flush) +*(.text.generic_file_write) +*(.text.free_more_memory) +*(.text.__free_fdtable) +*(.text.filp_dtor) +*(.text.exit_sem) +*(.text.exit_itimers) +*(.text.error_interrupt) +*(.text.end_buffer_async_write) +*(.text.eligible_child) +*(.text.elf_map) +*(.text.dump_task_regs) +*(.text.dummy_task_setscheduler) +*(.text.dummy_socket_accept) +*(.text.dummy_file_free_security) +*(.text.__down_read) +*(.text.do_sock_read) +*(.text.do_sigaltstack) +*(.text.do_mremap) +*(.text.current_io_context) +*(.text.cpu_swap_callback) +*(.text.copy_vma) +*(.text.cap_bprm_set_security) +*(.text.blk_insert_request) +*(.text.bio_map_kern_endio) +*(.text.bio_hw_segments) +*(.text.bictcp_cong_avoid) +*(.text.add_interrupt_randomness) +*(.text.wait_for_completion) +*(.text.version_read_proc) +*(.text.unix_write_space) +*(.text.tty_ldisc_ref_wait) +*(.text.tty_ldisc_put) +*(.text.try_to_wake_up) +*(.text.tcp_v4_tw_remember_stamp) +*(.text.tcp_try_undo_dsack) +*(.text.tcp_may_send_now) +*(.text.sys_waitid) +*(.text.sys_sched_getparam) +*(.text.sys_getppid) +*(.text.sys_getcwd) +*(.text.sys_dup2) +*(.text.sys_chmod) +*(.text.sys_chdir) +*(.text.sprintf) +*(.text.sock_wfree) +*(.text.sock_aio_write) +*(.text.skb_drop_fraglist) +*(.text.skb_dequeue) +*(.text.set_close_on_exec) +*(.text.set_brk) +*(.text.seq_puts) +*(.text.SELECT_DRIVE) +*(.text.sched_exec) +*(.text.return_EIO) +*(.text.remove_from_page_cache) +*(.text.rcu_start_batch) +*(.text.__put_task_struct) +*(.text.proc_pid_readdir) +*(.text.proc_get_inode) +*(.text.prepare_to_wait_exclusive) +*(.text.pipe_wait) +*(.text.pipe_new) +*(.text.pdflush_operation) +*(.text.__pagevec_release) +*(.text.pagevec_lookup_tag) +*(.text.packet_rcv) +*(.text.n_tty_set_room) +*(.text.nr_free_pages) +*(.text.__net_timestamp) +*(.text.mpage_end_io_read) +*(.text.mod_timer) +*(.text.__memcpy) +*(.text.mb_cache_shrink_fn) +*(.text.lock_rename) +*(.text.kstrdup) +*(.text.is_ignored) +*(.text.int_very_careful) +*(.text.inotify_inode_is_dead) +*(.text.inotify_get_cookie) +*(.text.inode_get_bytes) +*(.text.init_timer) +*(.text.init_dev) +*(.text.inet_getname) +*(.text.ide_map_sg) +*(.text.__ide_dma_end) +*(.text.hrtimer_get_remaining) +*(.text.get_task_mm) +*(.text.get_random_int) +*(.text.free_pipe_info) +*(.text.filemap_write_and_wait_range) +*(.text.exit_thread) +*(.text.enter_idle) +*(.text.end_that_request_first) +*(.text.end_8259A_irq) +*(.text.dummy_file_alloc_security) +*(.text.do_group_exit) +*(.text.debug_mutex_init) +*(.text.cpuset_exit) +*(.text.cpu_idle) +*(.text.copy_semundo) +*(.text.copy_files) +*(.text.chrdev_open) +*(.text.cdrom_transfer_packet_command) +*(.text.cdrom_mode_sense) +*(.text.blk_phys_contig_segment) +*(.text.blk_get_queue) +*(.text.bio_split) +*(.text.audit_alloc) +*(.text.anon_pipe_buf_release) +*(.text.add_wait_queue_exclusive) +*(.text.add_wait_queue) +*(.text.acct_process) +*(.text.account) +*(.text.zeromap_page_range) +*(.text.yield) +*(.text.writeback_acquire) +*(.text.worker_thread) +*(.text.wait_on_page_writeback_range) +*(.text.__wait_on_buffer) +*(.text.vscnprintf) +*(.text.vmalloc_to_pfn) +*(.text.vgacon_save_screen) +*(.text.vfs_unlink) +*(.text.vfs_rmdir) +*(.text.unregister_md_personality) +*(.text.unlock_new_inode) +*(.text.unix_stream_sendmsg) +*(.text.unix_stream_recvmsg) +*(.text.unhash_process) +*(.text.udp_v4_lookup_longway) +*(.text.tty_ldisc_flush) +*(.text.tty_ldisc_enable) +*(.text.tty_hung_up_p) +*(.text.tty_buffer_free_all) +*(.text.tso_fragment) +*(.text.try_to_del_timer_sync) +*(.text.tcp_v4_err) +*(.text.tcp_unhash) +*(.text.tcp_seq_next) +*(.text.tcp_select_initial_window) +*(.text.tcp_sacktag_write_queue) +*(.text.tcp_cwnd_validate) +*(.text.sys_vhangup) +*(.text.sys_uselib) +*(.text.sys_symlink) +*(.text.sys_signal) +*(.text.sys_poll) +*(.text.sys_mount) +*(.text.sys_kill) +*(.text.sys_ioctl) +*(.text.sys_inotify_add_watch) +*(.text.sys_getuid) +*(.text.sys_getrlimit) +*(.text.sys_getitimer) +*(.text.sys_getgroups) +*(.text.sys_ftruncate) +*(.text.sysfs_lookup) +*(.text.sys_exit_group) +*(.text.stub_fork) +*(.text.sscanf) +*(.text.sock_map_fd) +*(.text.sock_get_timestamp) +*(.text.__sock_create) +*(.text.smp_call_function_single) +*(.text.sk_stop_timer) +*(.text.skb_copy_and_csum_datagram) +*(.text.__skb_checksum_complete) +*(.text.single_next) +*(.text.sigqueue_alloc) +*(.text.shrink_dcache_parent) +*(.text.select_idle_routine) +*(.text.run_workqueue) +*(.text.run_local_timers) +*(.text.remove_inode_hash) +*(.text.remove_dquot_ref) +*(.text.register_binfmt) +*(.text.read_cache_pages) +*(.text.rb_last) +*(.text.pty_open) +*(.text.proc_root_readdir) +*(.text.proc_pid_flush) +*(.text.proc_pident_lookup) +*(.text.proc_fill_super) +*(.text.proc_exe_link) +*(.text.posix_locks_deadlock) +*(.text.pipe_iov_copy_from_user) +*(.text.opost) +*(.text.nf_register_hook) +*(.text.netif_rx_ni) +*(.text.m_start) +*(.text.mpage_writepage) +*(.text.mm_alloc) +*(.text.memory_open) +*(.text.mark_buffer_async_write) +*(.text.lru_add_drain_all) +*(.text.locks_init_lock) +*(.text.locks_delete_lock) +*(.text.lock_hrtimer_base) +*(.text.load_script) +*(.text.__kill_fasync) +*(.text.ip_mc_sf_allow) +*(.text.__ioremap) +*(.text.int_with_check) +*(.text.int_sqrt) +*(.text.install_thread_keyring) +*(.text.init_page_buffers) +*(.text.inet_sock_destruct) +*(.text.idle_notifier_register) +*(.text.ide_execute_command) +*(.text.ide_end_drive_cmd) +*(.text.__ide_dma_host_on) +*(.text.hrtimer_run_queues) +*(.text.hpet_mask_rtc_irq_bit) +*(.text.__get_zone_counts) +*(.text.get_zone_counts) +*(.text.get_write_access) +*(.text.get_fs_struct) +*(.text.get_dirty_limits) +*(.text.generic_readlink) +*(.text.free_hot_page) +*(.text.finish_wait) +*(.text.find_inode) +*(.text.find_first_bit) +*(.text.__filemap_fdatawrite_range) +*(.text.__filemap_copy_from_user_iovec) +*(.text.exit_aio) +*(.text.elv_set_request) +*(.text.elv_former_request) +*(.text.dup_namespace) +*(.text.dupfd) +*(.text.dummy_socket_getsockopt) +*(.text.dummy_sb_post_mountroot) +*(.text.dummy_quotactl) +*(.text.dummy_inode_rename) +*(.text.__do_SAK) +*(.text.do_pipe) +*(.text.do_fsync) +*(.text.d_instantiate_unique) +*(.text.d_find_alias) +*(.text.deny_write_access) +*(.text.dentry_unhash) +*(.text.d_delete) +*(.text.datagram_poll) +*(.text.cpuset_fork) +*(.text.cpuid_read) +*(.text.copy_namespace) +*(.text.cond_resched) +*(.text.check_version) +*(.text.__change_page_attr) +*(.text.cfq_slab_kill) +*(.text.cfq_completed_request) +*(.text.cdrom_pc_intr) +*(.text.cdrom_decode_status) +*(.text.cap_capset_check) +*(.text.blk_put_request) +*(.text.bio_fs_destructor) +*(.text.bictcp_min_cwnd) +*(.text.alloc_chrdev_region) +*(.text.add_element) +*(.text.acct_update_integrals) +*(.text.write_boundary_block) +*(.text.writeback_release) +*(.text.writeback_inodes) +*(.text.wake_up_state) +*(.text.__wake_up_locked) +*(.text.wake_futex) +*(.text.wait_task_inactive) +*(.text.__wait_on_freeing_inode) +*(.text.wait_noreap_copyout) +*(.text.vmstat_start) +*(.text.vgacon_do_font_op) +*(.text.vfs_readv) +*(.text.vfs_quota_sync) +*(.text.update_queue) +*(.text.unshare_files) +*(.text.unmap_vm_area) +*(.text.unix_socketpair) +*(.text.unix_release_sock) +*(.text.unix_detach_fds) +*(.text.unix_create1) +*(.text.unix_bind) +*(.text.udp_sendmsg) +*(.text.udp_rcv) +*(.text.udp_queue_rcv_skb) +*(.text.uart_write) +*(.text.uart_startup) +*(.text.uart_open) +*(.text.tty_vhangup) +*(.text.tty_termios_baud_rate) +*(.text.tty_release) +*(.text.tty_ldisc_ref) +*(.text.throttle_vm_writeout) +*(.text.058) +*(.text.tcp_xmit_probe_skb) +*(.text.tcp_v4_send_check) +*(.text.tcp_v4_destroy_sock) +*(.text.tcp_sync_mss) +*(.text.tcp_snd_test) +*(.text.tcp_slow_start) +*(.text.tcp_send_fin) +*(.text.tcp_rtt_estimator) +*(.text.tcp_parse_options) +*(.text.tcp_ioctl) +*(.text.tcp_init_tso_segs) +*(.text.tcp_init_cwnd) +*(.text.tcp_getsockopt) +*(.text.tcp_fin) +*(.text.tcp_connect) +*(.text.tcp_cong_avoid) +*(.text.__tcp_checksum_complete_user) +*(.text.task_dumpable) +*(.text.sys_wait4) +*(.text.sys_utimes) +*(.text.sys_symlinkat) +*(.text.sys_socketpair) +*(.text.sys_rmdir) +*(.text.sys_readahead) +*(.text.sys_nanosleep) +*(.text.sys_linkat) +*(.text.sys_fstat) +*(.text.sysfs_readdir) +*(.text.sys_execve) +*(.text.sysenter_tracesys) +*(.text.sys_chown) +*(.text.stub_clone) +*(.text.strrchr) +*(.text.strncpy) +*(.text.stopmachine_set_state) +*(.text.sock_sendmsg) +*(.text.sock_release) +*(.text.sock_fasync) +*(.text.sock_close) +*(.text.sk_stream_write_space) +*(.text.sk_reset_timer) +*(.text.skb_split) +*(.text.skb_recv_datagram) +*(.text.skb_queue_tail) +*(.text.sk_attach_filter) +*(.text.si_swapinfo) +*(.text.simple_strtoll) +*(.text.set_termios) +*(.text.set_task_comm) +*(.text.set_shrinker) +*(.text.set_normalized_timespec) +*(.text.set_brk) +*(.text.serial_in) +*(.text.seq_printf) +*(.text.secure_dccp_sequence_number) +*(.text.rwlock_bug) +*(.text.rt_hash_code) +*(.text.__rta_fill) +*(.text.__request_resource) +*(.text.relocate_new_kernel) +*(.text.release_thread) +*(.text.release_mem) +*(.text.rb_prev) +*(.text.rb_first) +*(.text.random_poll) +*(.text.__put_super_and_need_restart) +*(.text.pty_write) +*(.text.ptrace_stop) +*(.text.proc_self_readlink) +*(.text.proc_root_lookup) +*(.text.proc_root_link) +*(.text.proc_pid_make_inode) +*(.text.proc_pid_attr_write) +*(.text.proc_lookupfd) +*(.text.proc_delete_inode) +*(.text.posix_same_owner) +*(.text.posix_block_lock) +*(.text.poll_initwait) +*(.text.pipe_write) +*(.text.pipe_read_fasync) +*(.text.pipe_ioctl) +*(.text.pdflush) +*(.text.pci_user_read_config_dword) +*(.text.page_readlink) +*(.text.null_lseek) +*(.text.nf_hook_slow) +*(.text.netlink_sock_destruct) +*(.text.netlink_broadcast) +*(.text.neigh_resolve_output) +*(.text.name_to_int) +*(.text.mwait_idle) +*(.text.mutex_trylock) +*(.text.mutex_debug_check_no_locks_held) +*(.text.m_stop) +*(.text.mpage_end_io_write) +*(.text.mpage_alloc) +*(.text.move_page_tables) +*(.text.mounts_open) +*(.text.__memset) +*(.text.memcpy_fromiovec) +*(.text.make_8259A_irq) +*(.text.lookup_user_key_possessed) +*(.text.lookup_create) +*(.text.locks_insert_lock) +*(.text.locks_alloc_lock) +*(.text.kthread_should_stop) +*(.text.kswapd) +*(.text.kobject_uevent) +*(.text.kobject_get_path) +*(.text.kobject_get) +*(.text.klist_children_put) +*(.text.__ip_route_output_key) +*(.text.ip_flush_pending_frames) +*(.text.ip_compute_csum) +*(.text.ip_append_data) +*(.text.ioc_set_batching) +*(.text.invalidate_inode_pages) +*(.text.__invalidate_device) +*(.text.install_arg_page) +*(.text.in_sched_functions) +*(.text.inotify_unmount_inodes) +*(.text.init_once) +*(.text.init_cdrom_command) +*(.text.inet_stream_connect) +*(.text.inet_sk_rebuild_header) +*(.text.inet_csk_addr2sockaddr) +*(.text.inet_create) +*(.text.ifind) +*(.text.ide_setup_dma) +*(.text.ide_outsw) +*(.text.ide_fixstring) +*(.text.ide_dma_setup) +*(.text.ide_cdrom_packet) +*(.text.ide_cd_put) +*(.text.ide_build_sglist) +*(.text.i8259A_shutdown) +*(.text.hung_up_tty_ioctl) +*(.text.hrtimer_nanosleep) +*(.text.hrtimer_init) +*(.text.hrtimer_cancel) +*(.text.hash_futex) +*(.text.group_send_sig_info) +*(.text.grab_cache_page_nowait) +*(.text.get_wchan) +*(.text.get_stack) +*(.text.get_page_state) +*(.text.getnstimeofday) +*(.text.get_node) +*(.text.get_kprobe) +*(.text.generic_unplug_device) +*(.text.free_task) +*(.text.frag_show) +*(.text.find_next_zero_string) +*(.text.filp_open) +*(.text.fillonedir) +*(.text.exit_io_context) +*(.text.exit_idle) +*(.text.exact_lock) +*(.text.eth_header) +*(.text.dummy_unregister_security) +*(.text.dummy_socket_post_create) +*(.text.dummy_socket_listen) +*(.text.dummy_quota_on) +*(.text.dummy_inode_follow_link) +*(.text.dummy_file_receive) +*(.text.dummy_file_mprotect) +*(.text.dummy_file_lock) +*(.text.dummy_file_ioctl) +*(.text.dummy_bprm_post_apply_creds) +*(.text.do_writepages) +*(.text.__down_interruptible) +*(.text.do_notify_resume) +*(.text.do_acct_process) +*(.text.del_timer_sync) +*(.text.default_rebuild_header) +*(.text.d_callback) +*(.text.dcache_readdir) +*(.text.ctrl_dumpfamily) +*(.text.cpuset_rmdir) +*(.text.copy_strings_kernel) +*(.text.con_write_room) +*(.text.complete_all) +*(.text.collect_sigign_sigcatch) +*(.text.clear_user) +*(.text.check_unthrottle) +*(.text.cdrom_release) +*(.text.cdrom_newpc_intr) +*(.text.cdrom_ioctl) +*(.text.cdrom_check_status) +*(.text.cdev_put) +*(.text.cdev_add) +*(.text.cap_ptrace) +*(.text.cap_bprm_secureexec) +*(.text.cache_alloc_refill) +*(.text.bmap) +*(.text.blk_run_queue) +*(.text.blk_queue_dma_alignment) +*(.text.blk_ordered_req_seq) +*(.text.blk_backing_dev_unplug) +*(.text.__bitmap_subset) +*(.text.__bitmap_and) +*(.text.bio_unmap_user) +*(.text.__bforget) +*(.text.bd_forget) +*(.text.bad_pipe_w) +*(.text.bad_get_user) +*(.text.audit_free) +*(.text.anon_vma_ctor) +*(.text.anon_pipe_buf_map) +*(.text.alloc_sock_iocb) +*(.text.alloc_fdset) +*(.text.aio_kick_handler) +*(.text.__add_entropy_words) +*(.text.add_disk_randomness) diff --git a/trunk/arch/x86_64/kernel/genapic.c b/trunk/arch/x86_64/kernel/genapic.c index 47496a40e84f..0b3603adf56d 100644 --- a/trunk/arch/x86_64/kernel/genapic.c +++ b/trunk/arch/x86_64/kernel/genapic.c @@ -11,54 +11,120 @@ #include #include #include -#include #include #include #include +#include #include #include -#include -#ifdef CONFIG_ACPI +#if defined(CONFIG_ACPI) #include #endif /* which logical CPU number maps to which CPU (physical APIC ID) */ -u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly - = { [0 ... NR_CPUS-1] = BAD_APICID }; +u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; EXPORT_SYMBOL(x86_cpu_to_apicid); +u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; -u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; +extern struct genapic apic_cluster; +extern struct genapic apic_flat; +extern struct genapic apic_physflat; -struct genapic __read_mostly *genapic = &apic_flat; +struct genapic *genapic = &apic_flat; +struct genapic *genapic_force; /* * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. */ -void __init setup_apic_routing(void) +void __init clustered_apic_check(void) { -#ifdef CONFIG_ACPI + long i; + u8 clusters, max_cluster; + u8 id; + u8 cluster_cnt[NUM_APIC_CLUSTERS]; + int max_apic = 0; + + /* genapic selection can be forced because of certain quirks. + */ + if (genapic_force) { + genapic = genapic_force; + goto print; + } + +#if defined(CONFIG_ACPI) /* - * Quirk: some x86_64 machines can only use physical APIC mode - * regardless of how many processors are present (x86_64 ES7000 - * is an example). + * Some x86_64 machines use physical APIC mode regardless of how many + * procs/clusters are present (x86_64 ES7000 is an example). */ - if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID && - (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) + if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID) + if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) { + genapic = &apic_cluster; + goto print; + } +#endif + + memset(cluster_cnt, 0, sizeof(cluster_cnt)); + for (i = 0; i < NR_CPUS; i++) { + id = bios_cpu_apicid[i]; + if (id == BAD_APICID) + continue; + if (id > max_apic) + max_apic = id; + cluster_cnt[APIC_CLUSTERID(id)]++; + } + + /* Don't use clustered mode on AMD platforms. */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { genapic = &apic_physflat; - else +#ifndef CONFIG_HOTPLUG_CPU + /* In the CPU hotplug case we cannot use broadcast mode + because that opens a race when a CPU is removed. + Stay at physflat mode in this case. + It is bad to do this unconditionally though. Once + we have ACPI platform support for CPU hotplug + we should detect hotplug capablity from ACPI tables and + only do this when really needed. -AK */ + if (max_apic <= 8) + genapic = &apic_flat; #endif + goto print; + } - if (cpus_weight(cpu_possible_map) <= 8) - genapic = &apic_flat; - else + clusters = 0; + max_cluster = 0; + + for (i = 0; i < NUM_APIC_CLUSTERS; i++) { + if (cluster_cnt[i] > 0) { + ++clusters; + if (cluster_cnt[i] > max_cluster) + max_cluster = cluster_cnt[i]; + } + } + + /* + * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode, + * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical + * else physical mode. + * (We don't use lowest priority delivery + HW APIC IRQ steering, so + * can ignore the clustered logical case and go straight to physical.) + */ + if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) { +#ifdef CONFIG_HOTPLUG_CPU + /* Don't use APIC shortcuts in CPU hotplug to avoid races */ genapic = &apic_physflat; +#else + genapic = &apic_flat; +#endif + } else + genapic = &apic_cluster; +print: printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); } -/* Same for both flat and physical. */ +/* Same for both flat and clustered. */ void send_IPI_self(int vector) { diff --git a/trunk/arch/x86_64/kernel/genapic_cluster.c b/trunk/arch/x86_64/kernel/genapic_cluster.c new file mode 100644 index 000000000000..73d76308b955 --- /dev/null +++ b/trunk/arch/x86_64/kernel/genapic_cluster.c @@ -0,0 +1,137 @@ +/* + * Copyright 2004 James Cleverdon, IBM. + * Subject to the GNU Public License, v.2 + * + * Clustered APIC subarch code. Up to 255 CPUs, physical delivery. + * (A more realistic maximum is around 230 CPUs.) + * + * Hacked for x86-64 by James Cleverdon from i386 architecture code by + * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and + * James Cleverdon. + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Set up the logical destination ID. + * + * Intel recommends to set DFR, LDR and TPR before enabling + * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel + * document number 292116). So here it goes... + */ +static void cluster_init_apic_ldr(void) +{ + unsigned long val, id; + long i, count; + u8 lid; + u8 my_id = hard_smp_processor_id(); + u8 my_cluster = APIC_CLUSTER(my_id); + + /* Create logical APIC IDs by counting CPUs already in cluster. */ + for (count = 0, i = NR_CPUS; --i >= 0; ) { + lid = x86_cpu_to_log_apicid[i]; + if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster) + ++count; + } + /* + * We only have a 4 wide bitmap in cluster mode. There's no way + * to get above 60 CPUs and still give each one it's own bit. + * But, we're using physical IRQ delivery, so we don't care. + * Use bit 3 for the 4th through Nth CPU in each cluster. + */ + if (count >= XAPIC_DEST_CPUS_SHIFT) + count = 3; + id = my_cluster | (1UL << count); + x86_cpu_to_log_apicid[smp_processor_id()] = id; + apic_write(APIC_DFR, APIC_DFR_CLUSTER); + val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; + val |= SET_APIC_LOGICAL_ID(id); + apic_write(APIC_LDR, val); +} + +/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + +static cpumask_t cluster_target_cpus(void) +{ + return cpumask_of_cpu(0); +} + +static cpumask_t cluster_vector_allocation_domain(int cpu) +{ + cpumask_t domain = CPU_MASK_NONE; + cpu_set(cpu, domain); + return domain; +} + +static void cluster_send_IPI_mask(cpumask_t mask, int vector) +{ + send_IPI_mask_sequence(mask, vector); +} + +static void cluster_send_IPI_allbutself(int vector) +{ + cpumask_t mask = cpu_online_map; + + cpu_clear(smp_processor_id(), mask); + + if (!cpus_empty(mask)) + cluster_send_IPI_mask(mask, vector); +} + +static void cluster_send_IPI_all(int vector) +{ + cluster_send_IPI_mask(cpu_online_map, vector); +} + +static int cluster_apic_id_registered(void) +{ + return 1; +} + +static unsigned int cluster_cpu_mask_to_apicid(cpumask_t cpumask) +{ + int cpu; + + /* + * We're using fixed IRQ delivery, can only return one phys APIC ID. + * May as well be the first. + */ + cpu = first_cpu(cpumask); + if ((unsigned)cpu < NR_CPUS) + return x86_cpu_to_apicid[cpu]; + else + return BAD_APICID; +} + +/* cpuid returns the value latched in the HW at reset, not the APIC ID + * register's value. For any box whose BIOS changes APIC IDs, like + * clustered APIC systems, we must use hard_smp_processor_id. + * + * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID. + */ +static unsigned int phys_pkg_id(int index_msb) +{ + return hard_smp_processor_id() >> index_msb; +} + +struct genapic apic_cluster = { + .name = "clustered", + .int_delivery_mode = dest_Fixed, + .int_dest_mode = (APIC_DEST_PHYSICAL != 0), + .target_cpus = cluster_target_cpus, + .vector_allocation_domain = cluster_vector_allocation_domain, + .apic_id_registered = cluster_apic_id_registered, + .init_apic_ldr = cluster_init_apic_ldr, + .send_IPI_all = cluster_send_IPI_all, + .send_IPI_allbutself = cluster_send_IPI_allbutself, + .send_IPI_mask = cluster_send_IPI_mask, + .cpu_mask_to_apicid = cluster_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +}; diff --git a/trunk/arch/x86_64/kernel/genapic_flat.c b/trunk/arch/x86_64/kernel/genapic_flat.c index ecb01eefdd27..7c01db8fa9d1 100644 --- a/trunk/arch/x86_64/kernel/genapic_flat.c +++ b/trunk/arch/x86_64/kernel/genapic_flat.c @@ -8,7 +8,6 @@ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and * James Cleverdon. */ -#include #include #include #include @@ -17,7 +16,6 @@ #include #include #include -#include static cpumask_t flat_target_cpus(void) { @@ -62,10 +60,31 @@ static void flat_init_apic_ldr(void) static void flat_send_IPI_mask(cpumask_t cpumask, int vector) { unsigned long mask = cpus_addr(cpumask)[0]; + unsigned long cfg; unsigned long flags; local_irq_save(flags); - __send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL); + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + + /* + * prepare target chip field + */ + cfg = __prepare_ICR2(mask); + apic_write(APIC_ICR2, cfg); + + /* + * program the ICR + */ + cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL); + + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write(APIC_ICR, cfg); local_irq_restore(flags); } diff --git a/trunk/arch/x86_64/kernel/head.S b/trunk/arch/x86_64/kernel/head.S index 1fab487dee86..598a4d0351fc 100644 --- a/trunk/arch/x86_64/kernel/head.S +++ b/trunk/arch/x86_64/kernel/head.S @@ -5,7 +5,6 @@ * Copyright (C) 2000 Pavel Machek * Copyright (C) 2000 Karsten Keil * Copyright (C) 2001,2002 Andi Kleen - * Copyright (C) 2005 Eric Biederman */ @@ -14,131 +13,97 @@ #include #include #include -#include #include #include #include - + /* we are not able to switch in one step to the final KERNEL ADRESS SPACE - * because we need identity-mapped pages. - * + * because we need identity-mapped pages on setup so define __START_KERNEL to + * 0x100000 for this stage + * */ .text .section .bootstrap.text - .code64 - .globl startup_64 -startup_64: - + .code32 + .globl startup_32 +/* %bx: 1 if coming from smp trampoline on secondary cpu */ +startup_32: + /* - * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1, - * and someone has loaded an identity mapped page table - * for us. These identity mapped page tables map all of the - * kernel pages and possibly all of memory. - * - * %esi holds a physical pointer to real_mode_data. - * - * We come here either directly from a 64bit bootloader, or from - * arch/x86_64/boot/compressed/head.S. - * - * We only come here initially at boot nothing else comes here. - * - * Since we may be loaded at an address different from what we were - * compiled to run at we first fixup the physical addresses in our page - * tables and then reload them. + * At this point the CPU runs in 32bit protected mode (CS.D = 1) with + * paging disabled and the point of this file is to switch to 64bit + * long mode with a kernel mapping for kerneland to jump into the + * kernel virtual addresses. + * There is no stack until we set one up. */ - /* Compute the delta between the address I am compiled to run at and the - * address I am actually running at. - */ - leaq _text(%rip), %rbp - subq $_text - __START_KERNEL_map, %rbp - - /* Is the address not 2M aligned? */ - movq %rbp, %rax - andl $~LARGE_PAGE_MASK, %eax - testl %eax, %eax - jnz bad_address - - /* Is the address too large? */ - leaq _text(%rip), %rdx - movq $PGDIR_SIZE, %rax - cmpq %rax, %rdx - jae bad_address - - /* Fixup the physical addresses in the page table + /* Initialize the %ds segment register */ + movl $__KERNEL_DS,%eax + movl %eax,%ds + + /* Load new GDT with the 64bit segments using 32bit descriptor */ + lgdt pGDT32 - __START_KERNEL_map + + /* If the CPU doesn't support CPUID this will double fault. + * Unfortunately it is hard to check for CPUID without a stack. */ - addq %rbp, init_level4_pgt + 0(%rip) - addq %rbp, init_level4_pgt + (258*8)(%rip) - addq %rbp, init_level4_pgt + (511*8)(%rip) - - addq %rbp, level3_ident_pgt + 0(%rip) - addq %rbp, level3_kernel_pgt + (510*8)(%rip) - - /* Add an Identity mapping if I am above 1G */ - leaq _text(%rip), %rdi - andq $LARGE_PAGE_MASK, %rdi - - movq %rdi, %rax - shrq $PUD_SHIFT, %rax - andq $(PTRS_PER_PUD - 1), %rax - jz ident_complete - - leaq (level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx - leaq level3_ident_pgt(%rip), %rbx - movq %rdx, 0(%rbx, %rax, 8) - - movq %rdi, %rax - shrq $PMD_SHIFT, %rax - andq $(PTRS_PER_PMD - 1), %rax - leaq __PAGE_KERNEL_LARGE_EXEC(%rdi), %rdx - leaq level2_spare_pgt(%rip), %rbx - movq %rdx, 0(%rbx, %rax, 8) -ident_complete: - - /* Fixup the kernel text+data virtual addresses + + /* Check if extended functions are implemented */ + movl $0x80000000, %eax + cpuid + cmpl $0x80000000, %eax + jbe no_long_mode + /* Check if long mode is implemented */ + mov $0x80000001, %eax + cpuid + btl $29, %edx + jnc no_long_mode + + /* + * Prepare for entering 64bits mode */ - leaq level2_kernel_pgt(%rip), %rdi - leaq 4096(%rdi), %r8 - /* See if it is a valid page table entry */ -1: testq $1, 0(%rdi) - jz 2f - addq %rbp, 0(%rdi) - /* Go to the next page */ -2: addq $8, %rdi - cmp %r8, %rdi - jne 1b - - /* Fixup phys_base */ - addq %rbp, phys_base(%rip) -#ifdef CONFIG_SMP - addq %rbp, trampoline_level4_pgt + 0(%rip) - addq %rbp, trampoline_level4_pgt + (511*8)(%rip) -#endif -#ifdef CONFIG_ACPI_SLEEP - addq %rbp, wakeup_level4_pgt + 0(%rip) - addq %rbp, wakeup_level4_pgt + (511*8)(%rip) -#endif + /* Enable PAE mode */ + xorl %eax, %eax + btsl $5, %eax + movl %eax, %cr4 - /* Due to ENTRY(), sometimes the empty space gets filled with - * zeros. Better take a jmp than relying on empty space being - * filled with 0x90 (nop) - */ - jmp secondary_startup_64 -ENTRY(secondary_startup_64) + /* Setup early boot stage 4 level pagetables */ + movl $(boot_level4_pgt - __START_KERNEL_map), %eax + movl %eax, %cr3 + + /* Setup EFER (Extended Feature Enable Register) */ + movl $MSR_EFER, %ecx + rdmsr + + /* Enable Long Mode */ + btsl $_EFER_LME, %eax + + /* Make changes effective */ + wrmsr + + xorl %eax, %eax + btsl $31, %eax /* Enable paging and in turn activate Long Mode */ + btsl $0, %eax /* Enable protected mode */ + /* Make changes effective */ + movl %eax, %cr0 /* - * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1, - * and someone has loaded a mapped page table. - * - * %esi holds a physical pointer to real_mode_data. - * - * We come here either from startup_64 (using physical addresses) - * or from trampoline.S (using virtual addresses). - * - * Using virtual addresses from trampoline.S removes the need - * to have any identity mapped pages in the kernel page table - * after the boot processor executes this code. + * At this point we're in long mode but in 32bit compatibility mode + * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn + * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use + * the new gdt/idt that has __KERNEL_CS with CS.L = 1. + */ + ljmp $__KERNEL_CS, $(startup_64 - __START_KERNEL_map) + + .code64 + .org 0x100 + .globl startup_64 +startup_64: + /* We come here either from startup_32 + * or directly from a 64bit bootloader. + * Since we may have come directly from a bootloader we + * reload the page tables here. */ /* Enable PAE mode and PGE */ @@ -148,15 +113,9 @@ ENTRY(secondary_startup_64) movq %rax, %cr4 /* Setup early boot stage 4 level pagetables. */ - movq $(init_level4_pgt - __START_KERNEL_map), %rax - addq phys_base(%rip), %rax + movq $(boot_level4_pgt - __START_KERNEL_map), %rax movq %rax, %cr3 - /* Ensure I am executing from virtual addresses */ - movq $1f, %rax - jmp *%rax -1: - /* Check if nx is implemented */ movl $0x80000001, %eax cpuid @@ -165,11 +124,17 @@ ENTRY(secondary_startup_64) /* Setup EFER (Extended Feature Enable Register) */ movl $MSR_EFER, %ecx rdmsr - btsl $_EFER_SCE, %eax /* Enable System Call */ - btl $20,%edi /* No Execute supported? */ + + /* Enable System Call */ + btsl $_EFER_SCE, %eax + + /* No Execute supported? */ + btl $20,%edi jnc 1f btsl $_EFER_NX, %eax -1: wrmsr /* Make changes effective */ +1: + /* Make changes effective */ + wrmsr /* Setup cr0 */ #define CR0_PM 1 /* protected mode */ @@ -196,7 +161,7 @@ ENTRY(secondary_startup_64) * 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 cpu_gdt_descr(%rip) + lgdt cpu_gdt_descr /* set up data segments. actually 0 would do too */ movl $__KERNEL_DS,%eax @@ -247,9 +212,6 @@ initial_code: init_rsp: .quad init_thread_union+THREAD_SIZE-8 -bad_address: - jmp bad_address - ENTRY(early_idt_handler) cmpl $2,early_recursion_flag(%rip) jz 1f @@ -278,66 +240,110 @@ early_idt_msg: early_idt_ripmsg: .asciz "RIP %s\n" -.balign PAGE_SIZE +.code32 +ENTRY(no_long_mode) + /* This isn't an x86-64 CPU so hang */ +1: + jmp 1b + +.org 0xf00 + .globl pGDT32 +pGDT32: + .word gdt_end-cpu_gdt_table-1 + .long cpu_gdt_table-__START_KERNEL_map + +.org 0xf10 +ljumpvector: + .long startup_64-__START_KERNEL_map + .word __KERNEL_CS +ENTRY(stext) +ENTRY(_stext) + + $page = 0 #define NEXT_PAGE(name) \ - .balign PAGE_SIZE; \ + $page = $page + 1; \ + .org $page * 0x1000; \ + phys_/**/name = $page * 0x1000 + __PHYSICAL_START; \ ENTRY(name) -/* Automate the creation of 1 to 1 mapping pmd entries */ -#define PMDS(START, PERM, COUNT) \ - i = 0 ; \ - .rept (COUNT) ; \ - .quad (START) + (i << 21) + (PERM) ; \ - i = i + 1 ; \ - .endr - - /* - * This default setting generates an ident mapping at address 0x100000 - * and a mapping for the kernel that precisely maps virtual address - * 0xffffffff80000000 to physical address 0x000000. (always using - * 2Mbyte large pages provided by PAE mode) - */ NEXT_PAGE(init_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 257,8,0 - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 252,8,0 - /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE + /* This gets initialized in x86_64_start_kernel */ + .fill 512,8,0 NEXT_PAGE(level3_ident_pgt) - .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .quad phys_level2_ident_pgt | 0x007 .fill 511,8,0 NEXT_PAGE(level3_kernel_pgt) .fill 510,8,0 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ - .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE + .quad phys_level2_kernel_pgt | 0x007 .fill 1,8,0 NEXT_PAGE(level2_ident_pgt) - /* Since I easily can, map the first 1G. - * Don't set NX because code runs from these pages. - */ - PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD) - + /* 40MB for bootup. */ + i = 0 + .rept 20 + .quad i << 21 | 0x083 + i = i + 1 + .endr + /* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */ + .globl temp_boot_pmds +temp_boot_pmds: + .fill 492,8,0 + NEXT_PAGE(level2_kernel_pgt) /* 40MB kernel mapping. The kernel code cannot be bigger than that. 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 */ - PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL, - KERNEL_TEXT_SIZE/PMD_SIZE) + i = 0 + .rept 20 + .quad i << 21 | 0x183 + i = i + 1 + .endr /* Module mapping starts here */ - .fill (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0 + .fill 492,8,0 -NEXT_PAGE(level2_spare_pgt) - .fill 512,8,0 +NEXT_PAGE(level3_physmem_pgt) + .quad phys_level2_kernel_pgt | 0x007 /* so that __va works even before pagetable_init */ + .fill 511,8,0 -#undef PMDS #undef NEXT_PAGE .data + +#ifdef CONFIG_ACPI_SLEEP + .align PAGE_SIZE +ENTRY(wakeup_level4_pgt) + .quad phys_level3_ident_pgt | 0x007 + .fill 255,8,0 + .quad phys_level3_physmem_pgt | 0x007 + .fill 254,8,0 + /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ + .quad phys_level3_kernel_pgt | 0x007 +#endif + +#ifndef CONFIG_HOTPLUG_CPU + __INITDATA +#endif + /* + * This default setting generates an ident mapping at address 0x100000 + * and a mapping for the kernel that precisely maps virtual address + * 0xffffffff80000000 to physical address 0x000000. (always using + * 2Mbyte large pages provided by PAE mode) + */ + .align PAGE_SIZE +ENTRY(boot_level4_pgt) + .quad phys_level3_ident_pgt | 0x007 + .fill 255,8,0 + .quad phys_level3_physmem_pgt | 0x007 + .fill 254,8,0 + /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ + .quad phys_level3_kernel_pgt | 0x007 + + .data + .align 16 .globl cpu_gdt_descr cpu_gdt_descr: @@ -351,10 +357,6 @@ gdt: .endr #endif -ENTRY(phys_base) - /* This must match the first entry in level2_kernel_pgt */ - .quad 0x0000000000000000 - /* We need valid kernel segments for data and code in long mode too * IRET will check the segment types kkeil 2000/10/28 * Also sysret mandates a special GDT layout @@ -368,13 +370,13 @@ ENTRY(phys_base) ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ - .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ - .quad 0x00af9b000000ffff /* __KERNEL_CS */ - .quad 0x00cf93000000ffff /* __KERNEL_DS */ - .quad 0x00cffb000000ffff /* __USER32_CS */ - .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ - .quad 0x00affb000000ffff /* __USER_CS */ .quad 0x0 /* unused */ + .quad 0x00af9a000000ffff /* __KERNEL_CS */ + .quad 0x00cf92000000ffff /* __KERNEL_DS */ + .quad 0x00cffa000000ffff /* __USER32_CS */ + .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */ + .quad 0x00affa000000ffff /* __USER_CS */ + .quad 0x00cf9a000000ffff /* __KERNEL32_CS */ .quad 0,0 /* TSS */ .quad 0,0 /* LDT */ .quad 0,0,0 /* three TLS descriptors */ diff --git a/trunk/arch/x86_64/kernel/head64.c b/trunk/arch/x86_64/kernel/head64.c index 213d90e04755..5f197b0a330a 100644 --- a/trunk/arch/x86_64/kernel/head64.c +++ b/trunk/arch/x86_64/kernel/head64.c @@ -18,16 +18,8 @@ #include #include #include -#include #include -static void __init zap_identity_mappings(void) -{ - pgd_t *pgd = pgd_offset_k(0UL); - pgd_clear(pgd); - __flush_tlb(); -} - /* Don't add a printk in there. printk relies on the PDA which is not initialized yet. */ static void __init clear_bss(void) @@ -37,24 +29,25 @@ static void __init clear_bss(void) } #define NEW_CL_POINTER 0x228 /* Relative to real mode data */ -#define OLD_CL_MAGIC_ADDR 0x20 +#define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F -#define OLD_CL_OFFSET 0x22 +#define OLD_CL_BASE_ADDR 0x90000 +#define OLD_CL_OFFSET 0x90022 static void __init copy_bootdata(char *real_mode_data) { - unsigned long new_data; + int new_data; char * command_line; memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE); - new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER); + new_data = *(int *) (x86_boot_params + NEW_CL_POINTER); if (!new_data) { - if (OLD_CL_MAGIC != *(u16 *)(real_mode_data + OLD_CL_MAGIC_ADDR)) { + if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) { return; } - new_data = __pa(real_mode_data) + *(u16 *)(real_mode_data + OLD_CL_OFFSET); + new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET; } - command_line = __va(new_data); + command_line = (char *) ((u64)(new_data)); memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); } @@ -62,30 +55,26 @@ void __init x86_64_start_kernel(char * real_mode_data) { int i; - /* - * Make sure kernel is aligned to 2MB address. Catching it at compile - * time is better. Change your config file and compile the kernel - * for a 2MB aligned address (CONFIG_PHYSICAL_START) - */ - BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1)); - /* clear bss before set_intr_gate with early_idt_handler */ clear_bss(); - /* Make NULL pointers segfault */ - zap_identity_mappings(); - for (i = 0; i < IDT_ENTRIES; i++) set_intr_gate(i, early_idt_handler); asm volatile("lidt %0" :: "m" (idt_descr)); early_printk("Kernel alive\n"); + /* + * switch to init_level4_pgt from boot_level4_pgt + */ + memcpy(init_level4_pgt, boot_level4_pgt, PTRS_PER_PGD*sizeof(pgd_t)); + asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt))); + for (i = 0; i < NR_CPUS; i++) cpu_pda(i) = &boot_cpu_pda[i]; pda_init(0); - copy_bootdata(__va(real_mode_data)); + copy_bootdata(real_mode_data); #ifdef CONFIG_SMP cpu_set(0, cpu_online_map); #endif diff --git a/trunk/arch/x86_64/kernel/io_apic.c b/trunk/arch/x86_64/kernel/io_apic.c index 2a2df14dab7e..c6a5bc7e8118 100644 --- a/trunk/arch/x86_64/kernel/io_apic.c +++ b/trunk/arch/x86_64/kernel/io_apic.c @@ -907,6 +907,10 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in enable_8259A_irq(0); } +void __init UNEXPECTED_IO_APIC(void) +{ +} + void __apicdebuginit print_IO_APIC(void) { int apic, i; @@ -942,16 +946,40 @@ void __apicdebuginit print_IO_APIC(void) printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); + if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) + UNEXPECTED_IO_APIC(); printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); + if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ + (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ + (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ + (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ + (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ + (reg_01.bits.entries != 0x2E) && + (reg_01.bits.entries != 0x3F) && + (reg_01.bits.entries != 0x03) + ) + UNEXPECTED_IO_APIC(); printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); + if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.bits.version != 0x02) && /* 82801BA IO-APICs (ICH2) */ + (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ + (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ + (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ + (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ + ) + UNEXPECTED_IO_APIC(); + if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) + UNEXPECTED_IO_APIC(); if (reg_01.bits.version >= 0x10) { printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); + if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) + UNEXPECTED_IO_APIC(); } printk(KERN_DEBUG ".... IRQ redirection table:\n"); @@ -1379,7 +1407,8 @@ static void irq_complete_move(unsigned int irq) vector = ~get_irq_regs()->orig_rax; me = smp_processor_id(); - if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) { + if ((vector == cfg->vector) && + cpu_isset(smp_processor_id(), cfg->domain)) { cpumask_t cleanup_mask; cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); @@ -1954,18 +1983,18 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) if (irq < 0) return irq; + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); if (ret < 0) { destroy_irq(irq); return ret; } - set_irq_msi(irq, desc); write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) diff --git a/trunk/arch/x86_64/kernel/ioport.c b/trunk/arch/x86_64/kernel/ioport.c index 387d347b0e07..745b1f0f494e 100644 --- a/trunk/arch/x86_64/kernel/ioport.c +++ b/trunk/arch/x86_64/kernel/ioport.c @@ -16,7 +16,6 @@ #include #include #include -#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) diff --git a/trunk/arch/x86_64/kernel/machine_kexec.c b/trunk/arch/x86_64/kernel/machine_kexec.c index a8bb33c1a8f2..0497e3bd5bff 100644 --- a/trunk/arch/x86_64/kernel/machine_kexec.c +++ b/trunk/arch/x86_64/kernel/machine_kexec.c @@ -191,19 +191,19 @@ NORET_TYPE void machine_kexec(struct kimage *image) page_list[PA_CONTROL_PAGE] = __pa(control_page); page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; - page_list[PA_PGD] = __pa_symbol(&kexec_pgd); + page_list[PA_PGD] = __pa(kexec_pgd); page_list[VA_PGD] = (unsigned long)kexec_pgd; - page_list[PA_PUD_0] = __pa_symbol(&kexec_pud0); + page_list[PA_PUD_0] = __pa(kexec_pud0); page_list[VA_PUD_0] = (unsigned long)kexec_pud0; - page_list[PA_PMD_0] = __pa_symbol(&kexec_pmd0); + page_list[PA_PMD_0] = __pa(kexec_pmd0); page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; - page_list[PA_PTE_0] = __pa_symbol(&kexec_pte0); + page_list[PA_PTE_0] = __pa(kexec_pte0); page_list[VA_PTE_0] = (unsigned long)kexec_pte0; - page_list[PA_PUD_1] = __pa_symbol(&kexec_pud1); + page_list[PA_PUD_1] = __pa(kexec_pud1); page_list[VA_PUD_1] = (unsigned long)kexec_pud1; - page_list[PA_PMD_1] = __pa_symbol(&kexec_pmd1); + page_list[PA_PMD_1] = __pa(kexec_pmd1); page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; - page_list[PA_PTE_1] = __pa_symbol(&kexec_pte1); + page_list[PA_PTE_1] = __pa(kexec_pte1); page_list[VA_PTE_1] = (unsigned long)kexec_pte1; page_list[PA_TABLE_PAGE] = diff --git a/trunk/arch/x86_64/kernel/mce.c b/trunk/arch/x86_64/kernel/mce.c index fa2672682477..8011a8e1c7d4 100644 --- a/trunk/arch/x86_64/kernel/mce.c +++ b/trunk/arch/x86_64/kernel/mce.c @@ -323,13 +323,10 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status) #endif /* CONFIG_X86_MCE_INTEL */ /* - * Periodic polling timer for "silent" machine check errors. If the - * poller finds an MCE, poll 2x faster. When the poller finds no more - * errors, poll 2x slower (up to check_interval seconds). + * Periodic polling timer for "silent" machine check errors. */ static int check_interval = 5 * 60; /* 5 minutes */ -static int next_interval; /* in jiffies */ static void mcheck_timer(struct work_struct *work); static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer); @@ -342,6 +339,7 @@ static void mcheck_check_cpu(void *info) static void mcheck_timer(struct work_struct *work) { on_each_cpu(mcheck_check_cpu, NULL, 1, 1); + schedule_delayed_work(&mcheck_work, check_interval * HZ); /* * It's ok to read stale data here for notify_user and @@ -351,30 +349,17 @@ static void mcheck_timer(struct work_struct *work) * writes. */ if (notify_user && console_logged) { - static unsigned long last_print; - unsigned long now = jiffies; - - /* if we logged an MCE, reduce the polling interval */ - next_interval = max(next_interval/2, HZ/100); notify_user = 0; clear_bit(0, &console_logged); - if (time_after_eq(now, last_print + (check_interval*HZ))) { - last_print = now; - printk(KERN_INFO "Machine check events logged\n"); - } - } else { - next_interval = min(next_interval*2, check_interval*HZ); + printk(KERN_INFO "Machine check events logged\n"); } - - schedule_delayed_work(&mcheck_work, next_interval); } static __init int periodic_mcheck_init(void) { - next_interval = check_interval * HZ; - if (next_interval) - schedule_delayed_work(&mcheck_work, next_interval); + if (check_interval) + schedule_delayed_work(&mcheck_work, check_interval*HZ); return 0; } __initcall(periodic_mcheck_init); @@ -612,13 +597,12 @@ static int mce_resume(struct sys_device *dev) /* Reinit MCEs after user configuration changes */ static void mce_restart(void) { - if (next_interval) + if (check_interval) cancel_delayed_work(&mcheck_work); /* Timer race is harmless here */ on_each_cpu(mce_init, NULL, 1, 1); - next_interval = check_interval * HZ; - if (next_interval) - schedule_delayed_work(&mcheck_work, next_interval); + if (check_interval) + schedule_delayed_work(&mcheck_work, check_interval*HZ); } static struct sysdev_class mce_sysclass = { diff --git a/trunk/arch/x86_64/kernel/mpparse.c b/trunk/arch/x86_64/kernel/mpparse.c index d0dc4891599b..455aa0b932f0 100644 --- a/trunk/arch/x86_64/kernel/mpparse.c +++ b/trunk/arch/x86_64/kernel/mpparse.c @@ -300,7 +300,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } } } - setup_apic_routing(); + clustered_apic_check(); if (!num_processors) printk(KERN_ERR "MPTABLE: no processors registered!\n"); return num_processors; diff --git a/trunk/arch/x86_64/kernel/nmi.c b/trunk/arch/x86_64/kernel/nmi.c index 6cd2b30e2ffc..dfab9f167366 100644 --- a/trunk/arch/x86_64/kernel/nmi.c +++ b/trunk/arch/x86_64/kernel/nmi.c @@ -27,11 +27,28 @@ #include #include #include +#include int unknown_nmi_panic; int nmi_watchdog_enabled; int panic_on_unrecovered_nmi; +/* perfctr_nmi_owner tracks the ownership of the perfctr registers: + * evtsel_nmi_owner tracks the ownership of the event selection + * - different performance counters/ event selection may be reserved for + * different subsystems this reservation system just tries to coordinate + * things a little + */ + +/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's + * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now) + */ +#define NMI_MAX_COUNTER_BITS 66 +#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS) + +static DEFINE_PER_CPU(unsigned, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]); +static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]); + static cpumask_t backtrace_mask = CPU_MASK_NONE; /* nmi_active: @@ -46,11 +63,191 @@ int panic_on_timeout; unsigned int nmi_watchdog = NMI_DEFAULT; static unsigned int nmi_hz = HZ; -static DEFINE_PER_CPU(short, wd_enabled); +struct nmi_watchdog_ctlblk { + int enabled; + u64 check_bit; + unsigned int cccr_msr; + unsigned int perfctr_msr; /* the MSR to reset in NMI handler */ + unsigned int evntsel_msr; /* the MSR to select the events to handle */ +}; +static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk); /* local prototypes */ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); +/* converts an msr to an appropriate reservation bit */ +static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) +{ + /* returns the bit offset of the performance counter register */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return (msr - MSR_K7_PERFCTR0); + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return (msr - MSR_ARCH_PERFMON_PERFCTR0); + else + return (msr - MSR_P4_BPU_PERFCTR0); + } + return 0; +} + +/* converts an msr to an appropriate reservation bit */ +static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) +{ + /* returns the bit offset of the event selection register */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return (msr - MSR_K7_EVNTSEL0); + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return (msr - MSR_ARCH_PERFMON_EVENTSEL0); + else + return (msr - MSR_P4_BSU_ESCR0); + } + return 0; +} + +/* checks for a bit availability (hack for oprofile) */ +int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) +{ + int cpu; + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + for_each_possible_cpu (cpu) { + if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 0; + } + return 1; +} + +/* checks the an msr for availability */ +int avail_to_resrv_perfctr_nmi(unsigned int msr) +{ + unsigned int counter; + int cpu; + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + for_each_possible_cpu (cpu) { + if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 0; + } + return 1; +} + +static int __reserve_perfctr_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) + return 1; + return 0; +} + +static void __release_perfctr_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_perfctr_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)); +} + +int reserve_perfctr_nmi(unsigned int msr) +{ + int cpu, i; + for_each_possible_cpu (cpu) { + if (!__reserve_perfctr_nmi(cpu, msr)) { + for_each_possible_cpu (i) { + if (i >= cpu) + break; + __release_perfctr_nmi(i, msr); + } + return 0; + } + } + return 1; +} + +void release_perfctr_nmi(unsigned int msr) +{ + int cpu; + for_each_possible_cpu (cpu) + __release_perfctr_nmi(cpu, msr); +} + +int __reserve_evntsel_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_evntsel_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0])) + return 1; + return 0; +} + +static void __release_evntsel_nmi(int cpu, unsigned int msr) +{ + unsigned int counter; + if (cpu < 0) + cpu = smp_processor_id(); + + counter = nmi_evntsel_msr_to_bit(msr); + BUG_ON(counter > NMI_MAX_COUNTER_BITS); + + clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]); +} + +int reserve_evntsel_nmi(unsigned int msr) +{ + int cpu, i; + for_each_possible_cpu (cpu) { + if (!__reserve_evntsel_nmi(cpu, msr)) { + for_each_possible_cpu (i) { + if (i >= cpu) + break; + __release_evntsel_nmi(i, msr); + } + return 0; + } + } + return 1; +} + +void release_evntsel_nmi(unsigned int msr) +{ + int cpu; + for_each_possible_cpu (cpu) { + __release_evntsel_nmi(cpu, msr); + } +} + +static __cpuinit inline int nmi_known_cpu(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return boot_cpu_data.x86 == 15 || boot_cpu_data.x86 == 16; + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return 1; + else + return (boot_cpu_data.x86 == 15); + } + return 0; +} + /* Run after command line and cpu_init init, but before all other checks */ void nmi_watchdog_default(void) { @@ -80,6 +277,23 @@ static __init void nmi_cpu_busy(void *data) } #endif +static unsigned int adjust_for_32bit_ctr(unsigned int hz) +{ + unsigned int retval = hz; + + /* + * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter + * are writable, with higher bits sign extending from bit 31. + * So, we can only program the counter with 31 bit values and + * 32nd bit should be 1, for 33.. to be 1. + * Find the appropriate nmi_hz + */ + if ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) { + retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1; + } + return retval; +} + int __init check_nmi_watchdog (void) { int *counts; @@ -108,14 +322,14 @@ int __init check_nmi_watchdog (void) mdelay((20*1000)/nmi_hz); // wait 20 ticks for_each_online_cpu(cpu) { - if (!per_cpu(wd_enabled, cpu)) + if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled) continue; if (cpu_pda(cpu)->__nmi_count - counts[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n", cpu, counts[cpu], cpu_pda(cpu)->__nmi_count); - per_cpu(wd_enabled, cpu) = 0; + per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0; atomic_dec(&nmi_active); } } @@ -130,8 +344,13 @@ int __init check_nmi_watchdog (void) /* now that we know it works we can reduce NMI frequency to something more reasonable; makes a difference in some configs */ - if (nmi_watchdog == NMI_LOCAL_APIC) - nmi_hz = lapic_adjust_nmi_hz(1); + if (nmi_watchdog == NMI_LOCAL_APIC) { + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + nmi_hz = 1; + if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + } kfree(counts); return 0; @@ -160,6 +379,57 @@ int __init setup_nmi_watchdog(char *str) __setup("nmi_watchdog=", setup_nmi_watchdog); +static void disable_lapic_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); + + if (atomic_read(&nmi_active) <= 0) + return; + + on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1); + + BUG_ON(atomic_read(&nmi_active) != 0); +} + +static void enable_lapic_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_LOCAL_APIC); + + /* are we already enabled */ + if (atomic_read(&nmi_active) != 0) + return; + + /* are we lapic aware */ + if (nmi_known_cpu() <= 0) + return; + + on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1); + touch_nmi_watchdog(); +} + +void disable_timer_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_IO_APIC); + + if (atomic_read(&nmi_active) <= 0) + return; + + disable_irq(0); + on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1); + + BUG_ON(atomic_read(&nmi_active) != 0); +} + +void enable_timer_nmi_watchdog(void) +{ + BUG_ON(nmi_watchdog != NMI_IO_APIC); + + if (atomic_read(&nmi_active) == 0) { + touch_nmi_watchdog(); + on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1); + enable_irq(0); + } +} static void __acpi_nmi_disable(void *__unused) { @@ -245,9 +515,275 @@ late_initcall(init_lapic_nmi_sysfs); #endif /* CONFIG_PM */ +/* + * Activate the NMI watchdog via the local APIC. + * Original code written by Keith Owens. + */ + +/* Note that these events don't tick when the CPU idles. This means + the frequency varies with CPU load. */ + +#define K7_EVNTSEL_ENABLE (1 << 22) +#define K7_EVNTSEL_INT (1 << 20) +#define K7_EVNTSEL_OS (1 << 17) +#define K7_EVNTSEL_USR (1 << 16) +#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 +#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING + +static int setup_k7_watchdog(void) +{ + unsigned int perfctr_msr, evntsel_msr; + unsigned int evntsel; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + perfctr_msr = MSR_K7_PERFCTR0; + evntsel_msr = MSR_K7_EVNTSEL0; + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + /* Simulator may not support it */ + if (checking_wrmsrl(evntsel_msr, 0UL)) + goto fail2; + wrmsrl(perfctr_msr, 0UL); + + evntsel = K7_EVNTSEL_INT + | K7_EVNTSEL_OS + | K7_EVNTSEL_USR + | K7_NMI_EVENT; + + /* setup the timer */ + wrmsr(evntsel_msr, evntsel, 0); + wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= K7_EVNTSEL_ENABLE; + wrmsr(evntsel_msr, evntsel, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = 0; //unused + wd->check_bit = 1ULL<<63; + return 1; +fail2: + __release_evntsel_nmi(-1, evntsel_msr); +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_k7_watchdog(void) +{ + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + +/* Note that these events don't tick when the CPU idles. This means + the frequency varies with CPU load. */ + +#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) +#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) +#define P4_ESCR_OS (1<<3) +#define P4_ESCR_USR (1<<2) +#define P4_CCCR_OVF_PMI0 (1<<26) +#define P4_CCCR_OVF_PMI1 (1<<27) +#define P4_CCCR_THRESHOLD(N) ((N)<<20) +#define P4_CCCR_COMPLEMENT (1<<19) +#define P4_CCCR_COMPARE (1<<18) +#define P4_CCCR_REQUIRED (3<<16) +#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) +#define P4_CCCR_ENABLE (1<<12) +#define P4_CCCR_OVF (1<<31) +/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter + CRU_ESCR0 (with any non-null event selector) through a complemented + max threshold. [IA32-Vol3, Section 14.9.9] */ + +static int setup_p4_watchdog(void) +{ + unsigned int perfctr_msr, evntsel_msr, cccr_msr; + unsigned int evntsel, cccr_val; + unsigned int misc_enable, dummy; + unsigned int ht_num; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy); + if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) + return 0; + +#ifdef CONFIG_SMP + /* detect which hyperthread we are on */ + if (smp_num_siblings == 2) { + unsigned int ebx, apicid; + + ebx = cpuid_ebx(1); + apicid = (ebx >> 24) & 0xff; + ht_num = apicid & 1; + } else +#endif + ht_num = 0; + + /* performance counters are shared resources + * assign each hyperthread its own set + * (re-use the ESCR0 register, seems safe + * and keeps the cccr_val the same) + */ + if (!ht_num) { + /* logical cpu 0 */ + perfctr_msr = MSR_P4_IQ_PERFCTR0; + evntsel_msr = MSR_P4_CRU_ESCR0; + cccr_msr = MSR_P4_IQ_CCCR0; + cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4); + } else { + /* logical cpu 1 */ + perfctr_msr = MSR_P4_IQ_PERFCTR1; + evntsel_msr = MSR_P4_CRU_ESCR0; + cccr_msr = MSR_P4_IQ_CCCR1; + cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4); + } + + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + evntsel = P4_ESCR_EVENT_SELECT(0x3F) + | P4_ESCR_OS + | P4_ESCR_USR; + + cccr_val |= P4_CCCR_THRESHOLD(15) + | P4_CCCR_COMPLEMENT + | P4_CCCR_COMPARE + | P4_CCCR_REQUIRED; + + wrmsr(evntsel_msr, evntsel, 0); + wrmsr(cccr_msr, cccr_val, 0); + wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); + apic_write(APIC_LVTPC, APIC_DM_NMI); + cccr_val |= P4_CCCR_ENABLE; + wrmsr(cccr_msr, cccr_val, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = cccr_msr; + wd->check_bit = 1ULL<<39; + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_p4_watchdog(void) +{ + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + wrmsr(wd->cccr_msr, 0, 0); + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + +#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL +#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK + +static int setup_intel_arch_watchdog(void) +{ + unsigned int ebx; + union cpuid10_eax eax; + unsigned int unused; + unsigned int perfctr_msr, evntsel_msr; + unsigned int evntsel; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* + * Check whether the Architectural PerfMon supports + * Unhalted Core Cycles Event or not. + * NOTE: Corresponding bit = 0 in ebx indicates event present. + */ + cpuid(10, &(eax.full), &ebx, &unused, &unused); + if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || + (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) + goto fail; + + perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0; + evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0; + + if (!__reserve_perfctr_nmi(-1, perfctr_msr)) + goto fail; + + if (!__reserve_evntsel_nmi(-1, evntsel_msr)) + goto fail1; + + wrmsrl(perfctr_msr, 0UL); + + evntsel = ARCH_PERFMON_EVENTSEL_INT + | ARCH_PERFMON_EVENTSEL_OS + | ARCH_PERFMON_EVENTSEL_USR + | ARCH_PERFMON_NMI_EVENT_SEL + | ARCH_PERFMON_NMI_EVENT_UMASK; + + /* setup the timer */ + wrmsr(evntsel_msr, evntsel, 0); + + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0); + + apic_write(APIC_LVTPC, APIC_DM_NMI); + evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsr(evntsel_msr, evntsel, 0); + + wd->perfctr_msr = perfctr_msr; + wd->evntsel_msr = evntsel_msr; + wd->cccr_msr = 0; //unused + wd->check_bit = 1ULL << (eax.split.bit_width - 1); + return 1; +fail1: + __release_perfctr_nmi(-1, perfctr_msr); +fail: + return 0; +} + +static void stop_intel_arch_watchdog(void) +{ + unsigned int ebx; + union cpuid10_eax eax; + unsigned int unused; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* + * Check whether the Architectural PerfMon supports + * Unhalted Core Cycles Event or not. + * NOTE: Corresponding bit = 0 in ebx indicates event present. + */ + cpuid(10, &(eax.full), &ebx, &unused, &unused); + if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || + (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) + return; + + wrmsr(wd->evntsel_msr, 0, 0); + + __release_evntsel_nmi(-1, wd->evntsel_msr); + __release_perfctr_nmi(-1, wd->perfctr_msr); +} + void setup_apic_nmi_watchdog(void *unused) { - if (__get_cpu_var(wd_enabled) == 1) + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + + /* only support LOCAL and IO APICs for now */ + if ((nmi_watchdog != NMI_LOCAL_APIC) && + (nmi_watchdog != NMI_IO_APIC)) + return; + + if (wd->enabled == 1) return; /* cheap hack to support suspend/resume */ @@ -255,31 +791,62 @@ void setup_apic_nmi_watchdog(void *unused) if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0)) return; - switch (nmi_watchdog) { - case NMI_LOCAL_APIC: - __get_cpu_var(wd_enabled) = 1; - if (lapic_watchdog_init(nmi_hz) < 0) { - __get_cpu_var(wd_enabled) = 0; + if (nmi_watchdog == NMI_LOCAL_APIC) { + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) + return; + if (!setup_k7_watchdog()) + return; + break; + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { + if (!setup_intel_arch_watchdog()) + return; + break; + } + if (!setup_p4_watchdog()) + return; + break; + default: return; } - /* FALL THROUGH */ - case NMI_IO_APIC: - __get_cpu_var(wd_enabled) = 1; - atomic_inc(&nmi_active); } + wd->enabled = 1; + atomic_inc(&nmi_active); } void stop_apic_nmi_watchdog(void *unused) { + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + /* only support LOCAL and IO APICs for now */ if ((nmi_watchdog != NMI_LOCAL_APIC) && (nmi_watchdog != NMI_IO_APIC)) return; - if (__get_cpu_var(wd_enabled) == 0) + + if (wd->enabled == 0) return; - if (nmi_watchdog == NMI_LOCAL_APIC) - lapic_watchdog_stop(); - __get_cpu_var(wd_enabled) = 0; + + if (nmi_watchdog == NMI_LOCAL_APIC) { + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) + return; + stop_k7_watchdog(); + break; + case X86_VENDOR_INTEL: + if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { + stop_intel_arch_watchdog(); + break; + } + stop_p4_watchdog(); + break; + default: + return; + } + } + wd->enabled = 0; atomic_dec(&nmi_active); } @@ -318,7 +885,9 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) int sum; int touched = 0; int cpu = smp_processor_id(); - int rc = 0; + struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); + u64 dummy; + int rc=0; /* check for other users first */ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) @@ -365,20 +934,55 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) } /* see if the nmi watchdog went off */ - if (!__get_cpu_var(wd_enabled)) - return rc; - switch (nmi_watchdog) { - case NMI_LOCAL_APIC: - rc |= lapic_wd_event(nmi_hz); - break; - case NMI_IO_APIC: - /* don't know how to accurately check for this. - * just assume it was a watchdog timer interrupt - * This matches the old behaviour. - */ - rc = 1; - break; + if (wd->enabled) { + if (nmi_watchdog == NMI_LOCAL_APIC) { + rdmsrl(wd->perfctr_msr, dummy); + if (dummy & wd->check_bit){ + /* this wasn't a watchdog timer interrupt */ + goto done; + } + + /* only Intel uses the cccr msr */ + if (wd->cccr_msr != 0) { + /* + * P4 quirks: + * - An overflown perfctr will assert its interrupt + * until the OVF flag in its CCCR is cleared. + * - LVTPC is masked on interrupt and must be + * unmasked by the LVTPC handler. + */ + rdmsrl(wd->cccr_msr, dummy); + dummy &= ~P4_CCCR_OVF; + wrmsrl(wd->cccr_msr, dummy); + apic_write(APIC_LVTPC, APIC_DM_NMI); + /* start the cycle over again */ + wrmsrl(wd->perfctr_msr, + -((u64)cpu_khz * 1000 / nmi_hz)); + } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { + /* + * ArchPerfom/Core Duo needs to re-unmask + * the apic vector + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + /* ARCH_PERFMON has 32 bit counter writes */ + wrmsr(wd->perfctr_msr, + (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0); + } else { + /* start the cycle over again */ + wrmsrl(wd->perfctr_msr, + -((u64)cpu_khz * 1000 / nmi_hz)); + } + rc = 1; + } else if (nmi_watchdog == NMI_IO_APIC) { + /* don't know how to accurately check for this. + * just assume it was a watchdog timer interrupt + * This matches the old behaviour. + */ + rc = 1; + } else + printk(KERN_WARNING "Unknown enabled NMI hardware?!\n"); } +done: return rc; } @@ -463,4 +1067,12 @@ void __trigger_all_cpu_backtrace(void) EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_watchdog); +EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi); +EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit); +EXPORT_SYMBOL(reserve_perfctr_nmi); +EXPORT_SYMBOL(release_perfctr_nmi); +EXPORT_SYMBOL(reserve_evntsel_nmi); +EXPORT_SYMBOL(release_evntsel_nmi); +EXPORT_SYMBOL(disable_timer_nmi_watchdog); +EXPORT_SYMBOL(enable_timer_nmi_watchdog); EXPORT_SYMBOL(touch_nmi_watchdog); diff --git a/trunk/arch/x86_64/kernel/pci-calgary.c b/trunk/arch/x86_64/kernel/pci-calgary.c index 5bd20b542c1e..04480c3b68f5 100644 --- a/trunk/arch/x86_64/kernel/pci-calgary.c +++ b/trunk/arch/x86_64/kernel/pci-calgary.c @@ -507,7 +507,7 @@ void* calgary_alloc_coherent(struct device *dev, size_t size, return ret; } -static const struct dma_mapping_ops calgary_dma_ops = { +static struct dma_mapping_ops calgary_dma_ops = { .alloc_coherent = calgary_alloc_coherent, .map_single = calgary_map_single, .unmap_single = calgary_unmap_single, diff --git a/trunk/arch/x86_64/kernel/pci-gart.c b/trunk/arch/x86_64/kernel/pci-gart.c index 0a762e10f2be..2bac8c60ad61 100644 --- a/trunk/arch/x86_64/kernel/pci-gart.c +++ b/trunk/arch/x86_64/kernel/pci-gart.c @@ -519,11 +519,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info) 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"); - if (change_page_attr_addr((unsigned long)gatt, gatt_size >> PAGE_SHIFT, PAGE_KERNEL_NOCACHE)) - panic("Could not set GART PTEs to uncacheable pages"); - global_flush_tlb(); - + panic("Cannot allocate GATT table"); memset(gatt, 0, gatt_size); agp_gatt_table = gatt; @@ -556,7 +552,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info) extern int agp_amd64_init(void); -static const struct dma_mapping_ops gart_dma_ops = { +static struct dma_mapping_ops gart_dma_ops = { .mapping_error = NULL, .map_single = gart_map_single, .map_simple = gart_map_simple, diff --git a/trunk/arch/x86_64/kernel/pci-nommu.c b/trunk/arch/x86_64/kernel/pci-nommu.c index 6dade0c867cc..df09ab05a1bd 100644 --- a/trunk/arch/x86_64/kernel/pci-nommu.c +++ b/trunk/arch/x86_64/kernel/pci-nommu.c @@ -79,7 +79,7 @@ void nommu_unmap_sg(struct device *dev, struct scatterlist *sg, { } -const struct dma_mapping_ops nommu_dma_ops = { +struct dma_mapping_ops nommu_dma_ops = { .map_single = nommu_map_single, .unmap_single = nommu_unmap_single, .map_sg = nommu_map_sg, diff --git a/trunk/arch/x86_64/kernel/pci-swiotlb.c b/trunk/arch/x86_64/kernel/pci-swiotlb.c index 4b4569abc60c..eb18be5a6569 100644 --- a/trunk/arch/x86_64/kernel/pci-swiotlb.c +++ b/trunk/arch/x86_64/kernel/pci-swiotlb.c @@ -12,7 +12,7 @@ int swiotlb __read_mostly; EXPORT_SYMBOL(swiotlb); -const struct dma_mapping_ops swiotlb_dma_ops = { +struct dma_mapping_ops swiotlb_dma_ops = { .mapping_error = swiotlb_dma_mapping_error, .alloc_coherent = swiotlb_alloc_coherent, .free_coherent = swiotlb_free_coherent, diff --git a/trunk/arch/x86_64/kernel/process.c b/trunk/arch/x86_64/kernel/process.c index 4f21765078b7..d8d5ccc245c8 100644 --- a/trunk/arch/x86_64/kernel/process.c +++ b/trunk/arch/x86_64/kernel/process.c @@ -288,18 +288,16 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) static int __init idle_setup (char *str) { - if (!strcmp(str, "poll")) { + if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); pm_idle = poll_idle; - } else if (!strcmp(str, "mwait")) - force_mwait = 1; - else - return -1; + } boot_option_idle_override = 1; - return 0; + return 1; } -early_param("idle", idle_setup); + +__setup("idle=", idle_setup); /* Prints also some state that isn't saved in the pt_regs */ void __show_regs(struct pt_regs * regs) diff --git a/trunk/arch/x86_64/kernel/setup.c b/trunk/arch/x86_64/kernel/setup.c index db30b5bcef61..3d98b696881d 100644 --- a/trunk/arch/x86_64/kernel/setup.c +++ b/trunk/arch/x86_64/kernel/setup.c @@ -79,8 +79,6 @@ int bootloader_type; unsigned long saved_video_mode; -int force_mwait __cpuinitdata; - /* * Early DMI memory */ @@ -207,10 +205,10 @@ static void discover_ebda(void) * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E */ - ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER); + ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER; ebda_addr <<= 4; - ebda_size = *(unsigned short *)__va(ebda_addr); + ebda_size = *(unsigned short *)(unsigned long)ebda_addr; /* Round EBDA up to pages */ if (ebda_size == 0) @@ -245,12 +243,11 @@ void __init setup_arch(char **cmdline_p) init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - init_mm.pgd = __va(__pa_symbol(&init_level4_pgt)); - code_resource.start = __pa_symbol(&_text); - code_resource.end = __pa_symbol(&_etext)-1; - data_resource.start = __pa_symbol(&_etext); - data_resource.end = __pa_symbol(&_edata)-1; + code_resource.start = virt_to_phys(&_text); + code_resource.end = virt_to_phys(&_etext)-1; + data_resource.start = virt_to_phys(&_etext); + data_resource.end = virt_to_phys(&_edata)-1; early_identify_cpu(&boot_cpu_data); @@ -277,6 +274,8 @@ void __init setup_arch(char **cmdline_p) dmi_scan_machine(); + zap_low_mappings(0); + #ifdef CONFIG_ACPI /* * Initialize the ACPI boot-time table parser (gets the RSDP and SDT). @@ -330,8 +329,15 @@ void __init setup_arch(char **cmdline_p) #endif #ifdef CONFIG_SMP + /* + * But first pinch a few for the stack/trampoline stuff + * FIXME: Don't need the extra page at 4K, but need to fix + * trampoline before removing it. (see the GDT stuff) + */ + reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE); + /* Reserve SMP trampoline */ - reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE); + reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE); #endif #ifdef CONFIG_ACPI_SLEEP @@ -606,10 +612,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) /* RDTSC can be speculated around */ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); - - /* Family 10 doesn't support C states in MWAIT so don't use it */ - if (c->x86 == 0x10 && !force_mwait) - clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); } static void __cpuinit detect_ht(struct cpuinfo_x86 *c) @@ -985,8 +987,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) "stc", "100mhzsteps", "hwpstate", - "", /* tsc invariant mapped to constant_tsc */ - /* nothing */ + NULL, /* tsc invariant mapped to constant_tsc */ + NULL, + /* nothing */ /* constant_tsc - moved to flags */ }; diff --git a/trunk/arch/x86_64/kernel/setup64.c b/trunk/arch/x86_64/kernel/setup64.c index 64379a80d763..6a70b55f719d 100644 --- a/trunk/arch/x86_64/kernel/setup64.c +++ b/trunk/arch/x86_64/kernel/setup64.c @@ -103,9 +103,9 @@ void __init setup_per_cpu_areas(void) if (!NODE_DATA(cpu_to_node(i))) { printk("cpu with no node %d, num_online_nodes %d\n", i, num_online_nodes()); - ptr = alloc_bootmem_pages(size); + ptr = alloc_bootmem(size); } else { - ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); + ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size); } if (!ptr) panic("Cannot allocate cpu data for CPU %d\n", i); @@ -201,6 +201,7 @@ void __cpuinit cpu_init (void) /* CPU 0 is initialised in head64.c */ if (cpu != 0) { pda_init(cpu); + zap_low_mappings(cpu); } else estacks = boot_exception_stacks; diff --git a/trunk/arch/x86_64/kernel/signal.c b/trunk/arch/x86_64/kernel/signal.c index c819625f3316..49ec324cd141 100644 --- a/trunk/arch/x86_64/kernel/signal.c +++ b/trunk/arch/x86_64/kernel/signal.c @@ -141,7 +141,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) goto badframe; #ifdef DEBUG_SIG - printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs->rip,regs->rsp,frame,eax); + printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax); #endif if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT) @@ -301,7 +301,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); #ifdef DEBUG_SIG - printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%p\n", + printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); #endif @@ -463,7 +463,7 @@ void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { #ifdef DEBUG_SIG - printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%p pending:%x\n", + printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n", thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current)); #endif diff --git a/trunk/arch/x86_64/kernel/smp.c b/trunk/arch/x86_64/kernel/smp.c index 22abae4e9f39..af1ec4d23cf8 100644 --- a/trunk/arch/x86_64/kernel/smp.c +++ b/trunk/arch/x86_64/kernel/smp.c @@ -76,7 +76,7 @@ static inline void leave_mm(int cpu) if (read_pda(mmu_state) == TLBSTATE_OK) BUG(); cpu_clear(cpu, read_pda(active_mm)->cpu_vm_mask); - load_cr3(init_mm.pgd); + load_cr3(swapper_pg_dir); } /* @@ -452,34 +452,42 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, } EXPORT_SYMBOL(smp_call_function); -static void stop_this_cpu(void *dummy) +void smp_stop_cpu(void) { - local_irq_disable(); + unsigned long flags; /* * Remove this CPU: */ cpu_clear(smp_processor_id(), cpu_online_map); + local_irq_save(flags); disable_local_APIC(); + local_irq_restore(flags); +} + +static void smp_really_stop_cpu(void *dummy) +{ + smp_stop_cpu(); for (;;) halt(); } void smp_send_stop(void) { - int nolock; - unsigned long flags; - + int nolock = 0; if (reboot_force) return; - /* Don't deadlock on the call lock in panic */ - nolock = !spin_trylock(&call_lock); - local_irq_save(flags); - __smp_call_function(stop_this_cpu, NULL, 0, 0); + if (!spin_trylock(&call_lock)) { + /* ignore locking because we have panicked anyways */ + nolock = 1; + } + __smp_call_function(smp_really_stop_cpu, NULL, 0, 0); if (!nolock) spin_unlock(&call_lock); + + local_irq_disable(); disable_local_APIC(); - local_irq_restore(flags); + local_irq_enable(); } /* diff --git a/trunk/arch/x86_64/kernel/smpboot.c b/trunk/arch/x86_64/kernel/smpboot.c index 4d9dacfae575..cd4643a37022 100644 --- a/trunk/arch/x86_64/kernel/smpboot.c +++ b/trunk/arch/x86_64/kernel/smpboot.c @@ -60,6 +60,7 @@ #include #include #include +#include /* Number of siblings per CPU package */ int smp_num_siblings = 1; @@ -67,6 +68,7 @@ EXPORT_SYMBOL(smp_num_siblings); /* Last level cache ID of each logical CPU */ u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; +EXPORT_SYMBOL(cpu_llc_id); /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map __read_mostly; @@ -390,8 +392,7 @@ static void inquire_remote_apic(int apicid) { unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; char *names[] = { "ID", "VERSION", "SPIV" }; - int timeout; - unsigned int status; + int timeout, status; printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid); @@ -401,9 +402,7 @@ static void inquire_remote_apic(int apicid) /* * Wait for idle. */ - status = safe_apic_wait_icr_idle(); - if (status) - printk("a previous APIC delivery may have failed\n"); + apic_wait_icr_idle(); apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]); @@ -431,8 +430,8 @@ static void inquire_remote_apic(int apicid) */ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip) { - unsigned long send_status, accept_status = 0; - int maxlvt, num_starts, j; + unsigned long send_status = 0, accept_status = 0; + int maxlvt, timeout, num_starts, j; Dprintk("Asserting INIT.\n"); @@ -448,7 +447,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); mdelay(10); @@ -461,7 +465,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); mb(); atomic_set(&init_deasserted, 1); @@ -500,7 +509,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta Dprintk("Startup point 1.\n"); Dprintk("Waiting for send to finish...\n"); - send_status = safe_apic_wait_icr_idle(); + timeout = 0; + do { + Dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); /* * Give the other CPU some time to accept the IPI. @@ -931,12 +945,6 @@ int __cpuinit __cpu_up(unsigned int cpu) return -ENOSYS; } - /* - * Save current MTRR state in case it was changed since early boot - * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync: - */ - mtrr_save_state(); - per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; /* Boot it! */ err = do_boot_cpu(cpu, apicid); @@ -957,6 +965,13 @@ int __cpuinit __cpu_up(unsigned int cpu) while (!cpu_isset(cpu, cpu_online_map)) cpu_relax(); + + if (num_online_cpus() > 8 && genapic == &apic_flat) { + printk(KERN_WARNING + "flat APIC routing can't be used with > 8 cpus\n"); + BUG(); + } + err = 0; return err; diff --git a/trunk/arch/x86_64/kernel/suspend.c b/trunk/arch/x86_64/kernel/suspend.c index 6a5a98f2a75c..91f7e678bae7 100644 --- a/trunk/arch/x86_64/kernel/suspend.c +++ b/trunk/arch/x86_64/kernel/suspend.c @@ -12,10 +12,6 @@ #include #include #include -#include - -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; struct saved_context saved_context; @@ -37,6 +33,7 @@ void __save_processor_state(struct saved_context *ctxt) asm volatile ("str %0" : "=m" (ctxt->tr)); /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */ + /* EFER should be constant for kernel version, no need to handle it. */ /* * segment registers */ @@ -49,12 +46,10 @@ void __save_processor_state(struct saved_context *ctxt) rdmsrl(MSR_FS_BASE, ctxt->fs_base); rdmsrl(MSR_GS_BASE, ctxt->gs_base); rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); - mtrr_save_fixed_ranges(NULL); /* * control registers */ - rdmsrl(MSR_EFER, ctxt->efer); asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0)); asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2)); asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3)); @@ -80,7 +75,6 @@ void __restore_processor_state(struct saved_context *ctxt) /* * control registers */ - wrmsrl(MSR_EFER, ctxt->efer); asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8)); asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4)); asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3)); @@ -225,15 +219,4 @@ int swsusp_arch_resume(void) restore_image(); return 0; } - -/* - * pfn_is_nosave - check if given pfn is in the 'nosave' section - */ - -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT; - unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; - return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); -} #endif /* CONFIG_SOFTWARE_SUSPEND */ diff --git a/trunk/arch/x86_64/kernel/suspend_asm.S b/trunk/arch/x86_64/kernel/suspend_asm.S index 16d183f67bc1..bfbe00763c68 100644 --- a/trunk/arch/x86_64/kernel/suspend_asm.S +++ b/trunk/arch/x86_64/kernel/suspend_asm.S @@ -71,10 +71,9 @@ loop: jmp loop done: /* go back to the original page tables */ - movq $(init_level4_pgt - __START_KERNEL_map), %rax - addq phys_base(%rip), %rax - movq %rax, %cr3 - + leaq init_level4_pgt(%rip), %rax + subq $__START_KERNEL_map, %rax + movq %rax, %cr3 /* Flush TLB, including "global" things (vmalloc) */ movq mmu_cr4_features(%rip), %rax movq %rax, %rdx diff --git a/trunk/arch/x86_64/kernel/syscall.c b/trunk/arch/x86_64/kernel/syscall.c index 63d592c276cc..213fd6ab789d 100644 --- a/trunk/arch/x86_64/kernel/syscall.c +++ b/trunk/arch/x86_64/kernel/syscall.c @@ -3,7 +3,6 @@ #include #include #include -#include #define __NO_STUBS diff --git a/trunk/arch/x86_64/kernel/time.c b/trunk/arch/x86_64/kernel/time.c index 0652e173813b..75d73a9aa9ff 100644 --- a/trunk/arch/x86_64/kernel/time.c +++ b/trunk/arch/x86_64/kernel/time.c @@ -39,11 +39,13 @@ #include #include #include +#include #include #include #include -#include -#include + +extern void i8254_timer_resume(void); +extern int using_apic_timer; static char *timename = NULL; @@ -250,51 +252,6 @@ static unsigned long get_cmos_time(void) return mktime(year, mon, day, hour, min, sec); } -/* calibrate_cpu is used on systems with fixed rate TSCs to determine - * processor frequency */ -#define TICK_COUNT 100000000 -static unsigned int __init tsc_calibrate_cpu_khz(void) -{ - int tsc_start, tsc_now; - int i, no_ctr_free; - unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0; - unsigned long flags; - - for (i = 0; i < 4; i++) - if (avail_to_resrv_perfctr_nmi_bit(i)) - break; - no_ctr_free = (i == 4); - if (no_ctr_free) { - i = 3; - rdmsrl(MSR_K7_EVNTSEL3, evntsel3); - wrmsrl(MSR_K7_EVNTSEL3, 0); - rdmsrl(MSR_K7_PERFCTR3, pmc3); - } else { - reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i); - reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i); - } - local_irq_save(flags); - /* start meauring cycles, incrementing from 0 */ - wrmsrl(MSR_K7_PERFCTR0 + i, 0); - wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76); - rdtscl(tsc_start); - do { - rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now); - tsc_now = get_cycles_sync(); - } while ((tsc_now - tsc_start) < TICK_COUNT); - - local_irq_restore(flags); - if (no_ctr_free) { - wrmsrl(MSR_K7_EVNTSEL3, 0); - wrmsrl(MSR_K7_PERFCTR3, pmc3); - wrmsrl(MSR_K7_EVNTSEL3, evntsel3); - } else { - release_perfctr_nmi(MSR_K7_PERFCTR0 + i); - release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); - } - - return pmc_now * tsc_khz / (tsc_now - tsc_start); -} /* * pit_calibrate_tsc() uses the speaker output (channel 2) of @@ -328,7 +285,7 @@ static unsigned int __init pit_calibrate_tsc(void) #define PIT_MODE 0x43 #define PIT_CH0 0x40 -static void __pit_init(int val, u8 mode) +static void __init __pit_init(int val, u8 mode) { unsigned long flags; @@ -344,12 +301,12 @@ void __init pit_init(void) __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ } -void pit_stop_interrupt(void) +void __init pit_stop_interrupt(void) { __pit_init(0, 0x30); /* mode 0 */ } -void stop_timer_interrupt(void) +void __init stop_timer_interrupt(void) { char *name; if (hpet_address) { @@ -382,29 +339,23 @@ void __init time_init(void) if (hpet_use_timer) { /* set tick_nsec to use the proper rate for HPET */ tick_nsec = TICK_NSEC_HPET; - tsc_khz = hpet_calibrate_tsc(); + cpu_khz = hpet_calibrate_tsc(); timename = "HPET"; } else { pit_init(); - tsc_khz = pit_calibrate_tsc(); + cpu_khz = pit_calibrate_tsc(); timename = "PIT"; } - cpu_khz = tsc_khz; - if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && - boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 16) - cpu_khz = tsc_calibrate_cpu_khz(); - if (unsynchronized_tsc()) - mark_tsc_unstable("TSCs unsynchronized"); + mark_tsc_unstable(); if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) vgetcpu_mode = VGETCPU_RDTSCP; else vgetcpu_mode = VGETCPU_LSL; - set_cyc2ns_scale(tsc_khz); + set_cyc2ns_scale(cpu_khz); printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); init_tsc_clocksource(); diff --git a/trunk/arch/x86_64/kernel/trampoline.S b/trunk/arch/x86_64/kernel/trampoline.S index e7e2764c461b..c79b99a9e2f6 100644 --- a/trunk/arch/x86_64/kernel/trampoline.S +++ b/trunk/arch/x86_64/kernel/trampoline.S @@ -3,7 +3,6 @@ * Trampoline.S Derived from Setup.S by Linus Torvalds * * 4 Jan 1997 Michael Chastain: changed to gnu as. - * 15 Sept 2005 Eric Biederman: 64bit PIC support * * Entry: CS:IP point to the start of our code, we are * in real mode with no stack, but the rest of the @@ -18,20 +17,15 @@ * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. * - * With the addition of trampoline_level4_pgt this code can - * now enter a 64bit kernel that lives at arbitrary 64bit - * physical addresses. - * * If you work on this file, check the object module with objdump * --full-contents --reloc to make sure there are no relocation - * entries. + * entries. For the GDT entry we do hand relocation in smpboot.c + * because of 64bit linker limitations. */ #include -#include -#include -#include #include +#include .data @@ -39,33 +33,15 @@ ENTRY(trampoline_data) r_base = . - cli # We should be safe anyway wbinvd mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov %ax, %es - mov %ax, %ss + cli # We should be safe anyway movl $0xA5A5A5A5, trampoline_data - r_base # write marker for master knows we're running - # Setup stack - movw $(trampoline_stack_end - r_base), %sp - - call verify_cpu # Verify the cpu supports long mode - testl %eax, %eax # Check for return code - jnz no_longmode - - mov %cs, %ax - movzx %ax, %esi # Find the 32bit trampoline location - shll $4, %esi - - # Fixup the vectors - addl %esi, startup_32_vector - r_base - addl %esi, startup_64_vector - r_base - addl %esi, tgdt + 2 - r_base # Fixup the gdt pointer - /* * GDT tables in non default location kernel can be beyond 16MB and * lgdt will not be able to load the address as in real mode default @@ -73,94 +49,23 @@ r_base = . * to 32 bit. */ - lidtl tidt - r_base # load idt with 0, 0 - lgdtl tgdt - r_base # load gdt with whatever is appropriate + lidtl idt_48 - r_base # load idt with 0, 0 + lgdtl gdt_48 - r_base # load gdt with whatever is appropriate xor %ax, %ax inc %ax # protected mode (PE) bit lmsw %ax # into protected mode - - # flush prefetch and jump to startup_32 - ljmpl *(startup_32_vector - r_base) - - .code32 - .balign 4 -startup_32: - movl $__KERNEL_DS, %eax # Initialize the %ds segment register - movl %eax, %ds - - xorl %eax, %eax - btsl $5, %eax # Enable PAE mode - movl %eax, %cr4 - - # Setup trampoline 4 level pagetables - leal (trampoline_level4_pgt - r_base)(%esi), %eax - movl %eax, %cr3 - - movl $MSR_EFER, %ecx - movl $(1 << _EFER_LME), %eax # Enable Long Mode - xorl %edx, %edx - wrmsr - - xorl %eax, %eax - btsl $31, %eax # Enable paging and in turn activate Long Mode - btsl $0, %eax # Enable protected mode - movl %eax, %cr0 - - /* - * At this point we're in long mode but in 32bit compatibility mode - * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn - * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use - * the new gdt/idt that has __KERNEL_CS with CS.L = 1. - */ - ljmp *(startup_64_vector - r_base)(%esi) - - .code64 - .balign 4 -startup_64: - # Now jump into the kernel using virtual addresses - movq $secondary_startup_64, %rax - jmp *%rax - - .code16 -no_longmode: - hlt - jmp no_longmode -#include "verify_cpu.S" + # flaush prefetch and jump to startup_32 in arch/x86_64/kernel/head.S + ljmpl $__KERNEL32_CS, $(startup_32-__START_KERNEL_map) # Careful these need to be in the same 64K segment as the above; -tidt: +idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L - # Duplicate the global descriptor table - # so the kernel can live anywhere - .balign 4 -tgdt: - .short tgdt_end - tgdt # gdt limit - .long tgdt - r_base - .short 0 - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS -tgdt_end: - - .balign 4 -startup_32_vector: - .long startup_32 - r_base - .word __KERNEL32_CS, 0 - - .balign 4 -startup_64_vector: - .long startup_64 - r_base - .word __KERNEL_CS, 0 - -trampoline_stack: - .org 0x1000 -trampoline_stack_end: -ENTRY(trampoline_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 510,8,0 - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE +gdt_48: + .short GDT_ENTRIES*8 - 1 # gdt limit + .long cpu_gdt_table-__START_KERNEL_map -ENTRY(trampoline_end) +.globl trampoline_end +trampoline_end: diff --git a/trunk/arch/x86_64/kernel/traps.c b/trunk/arch/x86_64/kernel/traps.c index d76fc32d4599..09d2e8a10a49 100644 --- a/trunk/arch/x86_64/kernel/traps.c +++ b/trunk/arch/x86_64/kernel/traps.c @@ -426,7 +426,8 @@ void show_registers(struct pt_regs *regs) const int cpu = smp_processor_id(); struct task_struct *cur = cpu_pda(cpu)->pcurrent; - rsp = regs->rsp; + rsp = regs->rsp; + printk("CPU %d ", cpu); __show_regs(regs); printk("Process %s (pid: %d, threadinfo %p, task %p)\n", @@ -437,6 +438,7 @@ void show_registers(struct pt_regs *regs) * time of the fault.. */ if (in_kernel) { + printk("Stack: "); _show_stack(NULL, regs, (unsigned long*)rsp); @@ -579,20 +581,10 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, { struct task_struct *tsk = current; - if (user_mode(regs)) { - /* - * We want error_code and trap_no set for userspace - * faults and kernelspace faults which result in - * die(), but not kernelspace faults which are fixed - * up. die() gives the process no chance to handle - * the signal and notice the kernel fault information, - * so that won't result in polluting the information - * about previously queued, but not yet delivered, - * faults. See also do_general_protection below. - */ - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (user_mode(regs)) { if (exception_trace && unhandled_signal(tsk, signr)) printk(KERN_INFO "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", @@ -613,11 +605,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, fixup = search_exception_tables(regs->rip); if (fixup) regs->rip = fixup->fixup; - else { - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr; + else die(str, regs, error_code); - } return; } } @@ -693,10 +682,10 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, conditional_sti(regs); - if (user_mode(regs)) { - tsk->thread.error_code = error_code; - tsk->thread.trap_no = 13; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 13; + if (user_mode(regs)) { if (exception_trace && unhandled_signal(tsk, SIGSEGV)) printk(KERN_INFO "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", @@ -715,9 +704,6 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, regs->rip = fixup->fixup; return; } - - tsk->thread.error_code = error_code; - tsk->thread.trap_no = 13; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; diff --git a/trunk/arch/x86_64/kernel/tsc.c b/trunk/arch/x86_64/kernel/tsc.c index 48f9a8e6aa91..1a0edbbffaa0 100644 --- a/trunk/arch/x86_64/kernel/tsc.c +++ b/trunk/arch/x86_64/kernel/tsc.c @@ -13,8 +13,6 @@ static int notsc __initdata = 0; unsigned int cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); -unsigned int tsc_khz; -EXPORT_SYMBOL(tsc_khz); static unsigned int cyc2ns_scale __read_mostly; @@ -79,7 +77,7 @@ static void handle_cpufreq_delayed_get(struct work_struct *v) static unsigned int ref_freq = 0; static unsigned long loops_per_jiffy_ref = 0; -static unsigned long tsc_khz_ref = 0; +static unsigned long cpu_khz_ref = 0; static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) @@ -101,7 +99,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!ref_freq) { ref_freq = freq->old; loops_per_jiffy_ref = *lpj; - tsc_khz_ref = tsc_khz; + cpu_khz_ref = cpu_khz; } if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || @@ -109,12 +107,12 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, *lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); - tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new); + cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); if (!(freq->flags & CPUFREQ_CONST_LOOPS)) - mark_tsc_unstable("cpufreq changes"); + mark_tsc_unstable(); } - set_cyc2ns_scale(tsc_khz_ref); + set_cyc2ns_scale(cpu_khz_ref); return 0; } @@ -199,11 +197,10 @@ static struct clocksource clocksource_tsc = { .vread = vread_tsc, }; -void mark_tsc_unstable(char *reason) +void mark_tsc_unstable(void) { if (!tsc_unstable) { tsc_unstable = 1; - printk("Marking TSC unstable due to %s\n", reason); /* Change only the rating, when not registered */ if (clocksource_tsc.mult) clocksource_change_rating(&clocksource_tsc, 0); @@ -216,7 +213,7 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable); void __init init_tsc_clocksource(void) { if (!notsc) { - clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, + clocksource_tsc.mult = clocksource_khz2mult(cpu_khz, clocksource_tsc.shift); if (check_tsc_unstable()) clocksource_tsc.rating = 0; diff --git a/trunk/arch/x86_64/kernel/tsc_sync.c b/trunk/arch/x86_64/kernel/tsc_sync.c index 355f5f506c81..014f0db45dfa 100644 --- a/trunk/arch/x86_64/kernel/tsc_sync.c +++ b/trunk/arch/x86_64/kernel/tsc_sync.c @@ -50,7 +50,7 @@ static __cpuinit void check_tsc_warp(void) /* * The measurement runs for 20 msecs: */ - end = start + tsc_khz * 20ULL; + end = start + cpu_khz * 20ULL; now = start; for (i = 0; ; i++) { @@ -138,7 +138,7 @@ void __cpuinit check_tsc_sync_source(int cpu) printk("\n"); printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," " turning off TSC clock.\n", max_warp); - mark_tsc_unstable("check_tsc_sync_source failed"); + mark_tsc_unstable(); nr_warps = 0; max_warp = 0; last_tsc = 0; diff --git a/trunk/arch/x86_64/kernel/verify_cpu.S b/trunk/arch/x86_64/kernel/verify_cpu.S deleted file mode 100644 index e035f5948199..000000000000 --- a/trunk/arch/x86_64/kernel/verify_cpu.S +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * verify_cpu.S - Code for cpu long mode and SSE verification. This - * code has been borrowed from boot/setup.S and was introduced by - * Andi Kleen. - * - * Copyright (c) 2007 Andi Kleen (ak@suse.de) - * Copyright (c) 2007 Eric Biederman (ebiederm@xmission.com) - * Copyright (c) 2007 Vivek Goyal (vgoyal@in.ibm.com) - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - * - * This is a common code for verification whether CPU supports - * long mode and SSE or not. It is not called directly instead this - * file is included at various places and compiled in that context. - * Following are the current usage. - * - * This file is included by both 16bit and 32bit code. - * - * arch/x86_64/boot/setup.S : Boot cpu verification (16bit) - * arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit) - * arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit) - * arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit) - * - * verify_cpu, returns the status of cpu check in register %eax. - * 0: Success 1: Failure - * - * The caller needs to check for the error code and take the action - * appropriately. Either display a message or halt. - */ - -#include - -verify_cpu: - pushfl # Save caller passed flags - pushl $0 # Kill any dangerous flags - popfl - - /* minimum CPUID flags for x86-64 as defined by AMD */ -#define M(x) (1<<(x)) -#define M2(a,b) M(a)|M(b) -#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d) - -#define SSE_MASK \ - (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2)) -#define REQUIRED_MASK1 \ - (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\ - M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\ - M(X86_FEATURE_FXSR)) -#define REQUIRED_MASK2 \ - (M(X86_FEATURE_LM - 32)) - - pushfl # standard way to check for cpuid - popl %eax - movl %eax,%ebx - xorl $0x200000,%eax - pushl %eax - popfl - pushfl - popl %eax - cmpl %eax,%ebx - jz verify_cpu_no_longmode # cpu has no cpuid - - movl $0x0,%eax # See if cpuid 1 is implemented - cpuid - cmpl $0x1,%eax - jb verify_cpu_no_longmode # no cpuid 1 - - xor %di,%di - cmpl $0x68747541,%ebx # AuthenticAMD - jnz verify_cpu_noamd - cmpl $0x69746e65,%edx - jnz verify_cpu_noamd - cmpl $0x444d4163,%ecx - jnz verify_cpu_noamd - mov $1,%di # cpu is from AMD - -verify_cpu_noamd: - movl $0x1,%eax # Does the cpu have what it takes - cpuid - andl $REQUIRED_MASK1,%edx - xorl $REQUIRED_MASK1,%edx - jnz verify_cpu_no_longmode - - movl $0x80000000,%eax # See if extended cpuid is implemented - cpuid - cmpl $0x80000001,%eax - jb verify_cpu_no_longmode # no extended cpuid - - movl $0x80000001,%eax # Does the cpu have what it takes - cpuid - andl $REQUIRED_MASK2,%edx - xorl $REQUIRED_MASK2,%edx - jnz verify_cpu_no_longmode - -verify_cpu_sse_test: - movl $1,%eax - cpuid - andl $SSE_MASK,%edx - cmpl $SSE_MASK,%edx - je verify_cpu_sse_ok - test %di,%di - jz verify_cpu_no_longmode # only try to force SSE on AMD - movl $0xc0010015,%ecx # HWCR - rdmsr - btr $15,%eax # enable SSE - wrmsr - xor %di,%di # don't loop - jmp verify_cpu_sse_test # try again - -verify_cpu_no_longmode: - popfl # Restore caller passed flags - movl $1,%eax - ret -verify_cpu_sse_ok: - popfl # Restore caller passed flags - xorl %eax, %eax - ret diff --git a/trunk/arch/x86_64/kernel/vmlinux.lds.S b/trunk/arch/x86_64/kernel/vmlinux.lds.S index 88cfa50b424d..5176ecf006ee 100644 --- a/trunk/arch/x86_64/kernel/vmlinux.lds.S +++ b/trunk/arch/x86_64/kernel/vmlinux.lds.S @@ -29,7 +29,9 @@ SECTIONS .text : AT(ADDR(.text) - LOAD_OFFSET) { /* First the code that has to be first for bootstrapping */ *(.bootstrap.text) - _stext = .; + /* Then all the functions that are "hot" in profiles, to group them + onto the same hugetlb entry */ + #include "functionlist" /* Then the rest */ *(.text) SCHED_TEXT @@ -48,10 +50,10 @@ SECTIONS __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } __stop___ex_table = .; - BUG_TABLE - RODATA + BUG_TABLE + . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { @@ -92,12 +94,6 @@ SECTIONS { *(.vsyscall_gtod_data) } vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); - - .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) - { *(.vsyscall_1) } - .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) - { *(.vsyscall_2) } - .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } vgetcpu_mode = VVIRT(.vgetcpu_mode); @@ -105,6 +101,10 @@ SECTIONS .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } jiffies = VVIRT(.jiffies); + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) + { *(.vsyscall_1) } + .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) + { *(.vsyscall_2) } .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { *(.vsyscall_3) } @@ -194,7 +194,7 @@ SECTIONS __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); __per_cpu_start = .; .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/x86_64/kernel/vsyscall.c b/trunk/arch/x86_64/kernel/vsyscall.c index dc32cef96195..b43c698cf7d3 100644 --- a/trunk/arch/x86_64/kernel/vsyscall.c +++ b/trunk/arch/x86_64/kernel/vsyscall.c @@ -45,34 +45,14 @@ #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) #define __syscall_clobber "r11","rcx","memory" -#define __pa_vsymbol(x) \ - ({unsigned long v; \ - extern char __vsyscall_0; \ - asm("" : "=r" (v) : "0" (x)); \ - ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) -/* - * vsyscall_gtod_data contains data that is : - * - readonly from vsyscalls - * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64) - * Try to keep this structure as small as possible to avoid cache line ping pongs - */ struct vsyscall_gtod_data_t { - seqlock_t lock; - - /* open coded 'struct timespec' */ - time_t wall_time_sec; - u32 wall_time_nsec; - - int sysctl_enabled; + seqlock_t lock; + int sysctl_enabled; + struct timeval wall_time_tv; struct timezone sys_tz; - struct { /* extract of a clocksource struct */ - cycle_t (*vread)(void); - cycle_t cycle_last; - cycle_t mask; - u32 mult; - u32 shift; - } clock; + cycle_t offset_base; + struct clocksource clock; }; int __vgetcpu_mode __section_vgetcpu_mode; @@ -88,13 +68,9 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); /* copy vsyscall data */ - vsyscall_gtod_data.clock.vread = clock->vread; - vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; - vsyscall_gtod_data.clock.mask = clock->mask; - vsyscall_gtod_data.clock.mult = clock->mult; - vsyscall_gtod_data.clock.shift = clock->shift; - vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; - vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.clock = *clock; + vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; + vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; vsyscall_gtod_data.sys_tz = sys_tz; write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); } @@ -129,8 +105,7 @@ static __always_inline long time_syscall(long *t) static __always_inline void do_vgettimeofday(struct timeval * tv) { cycle_t now, base, mask, cycle_delta; - unsigned seq; - unsigned long mult, shift, nsec; + unsigned long seq, mult, shift, nsec_delta; cycle_t (*vread)(void); do { seq = read_seqbegin(&__vsyscall_gtod_data.lock); @@ -146,20 +121,21 @@ static __always_inline void do_vgettimeofday(struct timeval * tv) mult = __vsyscall_gtod_data.clock.mult; shift = __vsyscall_gtod_data.clock.shift; - tv->tv_sec = __vsyscall_gtod_data.wall_time_sec; - nsec = __vsyscall_gtod_data.wall_time_nsec; + *tv = __vsyscall_gtod_data.wall_time_tv; + } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); /* calculate interval: */ cycle_delta = (now - base) & mask; /* convert to nsecs: */ - nsec += (cycle_delta * mult) >> shift; + nsec_delta = (cycle_delta * mult) >> shift; - while (nsec >= NSEC_PER_SEC) { + /* convert to usecs and add to timespec: */ + tv->tv_usec += nsec_delta / NSEC_PER_USEC; + while (tv->tv_usec > USEC_PER_SEC) { tv->tv_sec += 1; - nsec -= NSEC_PER_SEC; + tv->tv_usec -= USEC_PER_SEC; } - tv->tv_usec = nsec / NSEC_PER_USEC; } int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) @@ -175,13 +151,11 @@ int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) * unlikely */ time_t __vsyscall(1) vtime(time_t *t) { - time_t result; if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) return time_syscall(t); - result = __vsyscall_gtod_data.wall_time_sec; - if (t) - *t = result; - return result; + else if (t) + *t = __vsyscall_gtod_data.wall_time_tv.tv_sec; + return __vsyscall_gtod_data.wall_time_tv.tv_sec; } /* Fast way to get current CPU and node. @@ -250,10 +224,10 @@ static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp, return ret; /* gcc has some trouble with __va(__pa()), so just do it this way. */ - map1 = ioremap(__pa_vsymbol(&vsysc1), 2); + map1 = ioremap(__pa_symbol(&vsysc1), 2); if (!map1) return -ENOMEM; - map2 = ioremap(__pa_vsymbol(&vsysc2), 2); + map2 = ioremap(__pa_symbol(&vsysc2), 2); if (!map2) { ret = -ENOMEM; goto out; diff --git a/trunk/arch/x86_64/mm/fault.c b/trunk/arch/x86_64/mm/fault.c index de99dba2c515..6ada7231f3ab 100644 --- a/trunk/arch/x86_64/mm/fault.c +++ b/trunk/arch/x86_64/mm/fault.c @@ -585,7 +585,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, } DEFINE_SPINLOCK(pgd_lock); -LIST_HEAD(pgd_list); +struct page *pgd_list; void vmalloc_sync_all(void) { @@ -605,7 +605,8 @@ void vmalloc_sync_all(void) if (pgd_none(*pgd_ref)) continue; spin_lock(&pgd_lock); - list_for_each_entry(page, &pgd_list, lru) { + for (page = pgd_list; page; + page = (struct page *)page->index) { pgd_t *pgd; pgd = (pgd_t *)page_address(page) + pgd_index(address); if (pgd_none(*pgd)) diff --git a/trunk/arch/x86_64/mm/init.c b/trunk/arch/x86_64/mm/init.c index 282b0a8f00ad..ec31534eb104 100644 --- a/trunk/arch/x86_64/mm/init.c +++ b/trunk/arch/x86_64/mm/init.c @@ -22,12 +22,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include @@ -48,7 +46,7 @@ #define Dprintk(x...) #endif -const struct dma_mapping_ops* dma_ops; +struct dma_mapping_ops* dma_ops; EXPORT_SYMBOL(dma_ops); static unsigned long dma_reserve __initdata; @@ -74,11 +72,6 @@ void show_mem(void) for_each_online_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; ++i) { - /* this loop can take a while with 256 GB and 4k pages - so update the NMI watchdog */ - if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) { - touch_nmi_watchdog(); - } page = pfn_to_page(pgdat->node_start_pfn + i); total++; if (PageReserved(page)) @@ -174,9 +167,23 @@ __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot) unsigned long __initdata table_start, table_end; -static __meminit void *alloc_low_page(unsigned long *phys) +extern pmd_t temp_boot_pmds[]; + +static struct temp_map { + pmd_t *pmd; + void *address; + int allocated; +} temp_mappings[] __initdata = { + { &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) }, + { &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) }, + {} +}; + +static __meminit void *alloc_low_page(int *index, unsigned long *phys) { - unsigned long pfn = table_end++; + struct temp_map *ti; + int i; + unsigned long pfn = table_end++, paddr; void *adr; if (after_bootmem) { @@ -187,63 +194,57 @@ static __meminit void *alloc_low_page(unsigned long *phys) if (pfn >= end_pfn) panic("alloc_low_page: ran out of memory"); - - adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE); + for (i = 0; temp_mappings[i].allocated; i++) { + if (!temp_mappings[i].pmd) + panic("alloc_low_page: ran out of temp mappings"); + } + ti = &temp_mappings[i]; + paddr = (pfn << PAGE_SHIFT) & PMD_MASK; + set_pmd(ti->pmd, __pmd(paddr | _KERNPG_TABLE | _PAGE_PSE)); + ti->allocated = 1; + __flush_tlb(); + adr = ti->address + ((pfn << PAGE_SHIFT) & ~PMD_MASK); memset(adr, 0, PAGE_SIZE); - *phys = pfn * PAGE_SIZE; - return adr; -} + *index = i; + *phys = pfn * PAGE_SIZE; + return adr; +} -static __meminit void unmap_low_page(void *adr) +static __meminit void unmap_low_page(int i) { + struct temp_map *ti; if (after_bootmem) return; - early_iounmap(adr, PAGE_SIZE); + ti = &temp_mappings[i]; + set_pmd(ti->pmd, __pmd(0)); + ti->allocated = 0; } /* Must run before zap_low_mappings */ __init void *early_ioremap(unsigned long addr, unsigned long size) { - unsigned long vaddr; - pmd_t *pmd, *last_pmd; - int i, pmds; - - pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE; - vaddr = __START_KERNEL_map; - pmd = level2_kernel_pgt; - last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1; - for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) { - for (i = 0; i < pmds; i++) { - if (pmd_present(pmd[i])) - goto next; - } - vaddr += addr & ~PMD_MASK; - addr &= PMD_MASK; - for (i = 0; i < pmds; i++, addr += PMD_SIZE) - set_pmd(pmd + i,__pmd(addr | _KERNPG_TABLE | _PAGE_PSE)); - __flush_tlb(); - return (void *)vaddr; - next: - ; + unsigned long map = round_down(addr, LARGE_PAGE_SIZE); + + /* actually usually some more */ + if (size >= LARGE_PAGE_SIZE) { + return NULL; } - printk("early_ioremap(0x%lx, %lu) failed\n", addr, size); - return NULL; + set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); + map += LARGE_PAGE_SIZE; + set_pmd(temp_mappings[1].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); + __flush_tlb(); + return temp_mappings[0].address + (addr & (LARGE_PAGE_SIZE-1)); } /* To avoid virtual aliases later */ __init void early_iounmap(void *addr, unsigned long size) { - unsigned long vaddr; - pmd_t *pmd; - int i, pmds; - - vaddr = (unsigned long)addr; - pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE; - pmd = level2_kernel_pgt + pmd_index(vaddr); - for (i = 0; i < pmds; i++) - pmd_clear(pmd + i); + if ((void *)round_down((unsigned long)addr, LARGE_PAGE_SIZE) != temp_mappings[0].address) + printk("early_iounmap: bad address %p\n", addr); + set_pmd(temp_mappings[0].pmd, __pmd(0)); + set_pmd(temp_mappings[1].pmd, __pmd(0)); __flush_tlb(); } @@ -288,6 +289,7 @@ static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigne for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) { + int map; unsigned long pmd_phys; pud_t *pud = pud_page + pud_index(addr); pmd_t *pmd; @@ -305,12 +307,12 @@ static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigne continue; } - pmd = alloc_low_page(&pmd_phys); + pmd = alloc_low_page(&map, &pmd_phys); spin_lock(&init_mm.page_table_lock); set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE)); phys_pmd_init(pmd, addr, end); spin_unlock(&init_mm.page_table_lock); - unmap_low_page(pmd); + unmap_low_page(map); } __flush_tlb(); } @@ -362,6 +364,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end) end = (unsigned long)__va(end); for (; start < end; start = next) { + int map; unsigned long pud_phys; pgd_t *pgd = pgd_offset_k(start); pud_t *pud; @@ -369,7 +372,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end) if (after_bootmem) pud = pud_offset(pgd, start & PGDIR_MASK); else - pud = alloc_low_page(&pud_phys); + pud = alloc_low_page(&map, &pud_phys); next = start + PGDIR_SIZE; if (next > end) @@ -377,7 +380,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end) phys_pud_init(pud, __pa(start), __pa(next)); if (!after_bootmem) set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys)); - unmap_low_page(pud); + unmap_low_page(map); } if (!after_bootmem) @@ -385,6 +388,21 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end) __flush_tlb_all(); } +void __cpuinit zap_low_mappings(int cpu) +{ + if (cpu == 0) { + pgd_t *pgd = pgd_offset_k(0UL); + pgd_clear(pgd); + } else { + /* + * For AP's, zap the low identity mappings by changing the cr3 + * to init_level4_pgt and doing local flush tlb all + */ + asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt))); + } + __flush_tlb_all(); +} + #ifndef CONFIG_NUMA void __init paging_init(void) { @@ -561,6 +579,15 @@ void __init mem_init(void) reservedpages << (PAGE_SHIFT-10), datasize >> 10, initsize >> 10); + +#ifdef CONFIG_SMP + /* + * Sync boot_level4_pgt mappings with the init_level4_pgt + * except for the low identity mappings which are already zapped + * in init_level4_pgt. This sync-up is essential for AP's bringup + */ + memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t)); +#endif } void free_init_pages(char *what, unsigned long begin, unsigned long end) @@ -570,44 +597,37 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) if (begin >= end) return; - printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); + printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); for (addr = begin; addr < end; addr += PAGE_SIZE) { - struct page *page = pfn_to_page(addr >> PAGE_SHIFT); - ClearPageReserved(page); - init_page_count(page); - memset(page_address(page), POISON_FREE_INITMEM, PAGE_SIZE); - if (addr >= __START_KERNEL_map) - change_page_attr_addr(addr, 1, __pgprot(0)); - __free_page(page); + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + memset((void *)(addr & ~(PAGE_SIZE-1)), + POISON_FREE_INITMEM, PAGE_SIZE); + free_page(addr); totalram_pages++; } - if (addr > __START_KERNEL_map) - global_flush_tlb(); } void free_initmem(void) { + memset(__initdata_begin, POISON_FREE_INITDATA, + __initdata_end - __initdata_begin); free_init_pages("unused kernel memory", - __pa_symbol(&__init_begin), - __pa_symbol(&__init_end)); + (unsigned long)(&__init_begin), + (unsigned long)(&__init_end)); } #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void) { - unsigned long start = PFN_ALIGN(__va(__pa_symbol(&_stext))), size; + unsigned long addr = (unsigned long)__start_rodata; -#ifdef CONFIG_HOTPLUG_CPU - /* It must still be possible to apply SMP alternatives. */ - if (num_possible_cpus() > 1) - start = PFN_ALIGN(__va(__pa_symbol(&_etext))); -#endif - size = (unsigned long)__va(__pa_symbol(&__end_rodata)) - start; - change_page_attr_addr(start, size >> PAGE_SHIFT, PAGE_KERNEL_RO); + for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) + change_page_attr_addr(addr, 1, PAGE_KERNEL_RO); - printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - size >> 10); + printk ("Write protecting the kernel read-only data: %luk\n", + (__end_rodata - __start_rodata) >> 10); /* * change_page_attr_addr() requires a global_flush_tlb() call after it. @@ -622,7 +642,7 @@ void mark_rodata_ro(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", __pa(start), __pa(end)); + free_init_pages("initrd memory", start, end); } #endif diff --git a/trunk/arch/x86_64/mm/k8topology.c b/trunk/arch/x86_64/mm/k8topology.c index f983c75825d0..b5b8dba28b4e 100644 --- a/trunk/arch/x86_64/mm/k8topology.c +++ b/trunk/arch/x86_64/mm/k8topology.c @@ -49,8 +49,11 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) int found = 0; u32 reg; unsigned numnodes; + nodemask_t nodes_parsed; unsigned dualcore = 0; + nodes_clear(nodes_parsed); + if (!early_pci_allowed()) return -1; @@ -62,8 +65,6 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) reg = read_pci_config(0, nb, 0, 0x60); numnodes = ((reg >> 4) & 0xF) + 1; - if (numnodes <= 1) - return -1; printk(KERN_INFO "Number of nodes %d\n", numnodes); @@ -101,7 +102,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) nodeid, (base>>8)&3, (limit>>8) & 3); return -1; } - if (node_isset(nodeid, node_possible_map)) { + if (node_isset(nodeid, nodes_parsed)) { printk(KERN_INFO "Node %d already present. Skipping\n", nodeid); continue; @@ -154,7 +155,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) prevbase = base; - node_set(nodeid, node_possible_map); + node_set(nodeid, nodes_parsed); } if (!found) diff --git a/trunk/arch/x86_64/mm/numa.c b/trunk/arch/x86_64/mm/numa.c index 51548947ad3b..41b8fb069924 100644 --- a/trunk/arch/x86_64/mm/numa.c +++ b/trunk/arch/x86_64/mm/numa.c @@ -273,213 +273,125 @@ void __init numa_init_array(void) #ifdef CONFIG_NUMA_EMU /* Numa emulation */ -#define E820_ADDR_HOLE_SIZE(start, end) \ - (e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) << \ - PAGE_SHIFT) -char *cmdline __initdata; +int numa_fake __initdata = 0; /* - * Setups up nid to range from addr to addr + size. If the end boundary is - * greater than max_addr, then max_addr is used instead. The return value is 0 - * if there is additional memory left for allocation past addr and -1 otherwise. - * addr is adjusted to be at the end of the node. + * This function is used to find out if the start and end correspond to + * different zones. */ -static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr, - u64 size, u64 max_addr) +int zone_cross_over(unsigned long start, unsigned long end) { - int ret = 0; - nodes[nid].start = *addr; - *addr += size; - if (*addr >= max_addr) { - *addr = max_addr; - ret = -1; - } - nodes[nid].end = *addr; - node_set(nid, node_possible_map); - printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid, - nodes[nid].start, nodes[nid].end, - (nodes[nid].end - nodes[nid].start) >> 20); - return ret; + if ((start < (MAX_DMA32_PFN << PAGE_SHIFT)) && + (end >= (MAX_DMA32_PFN << PAGE_SHIFT))) + return 1; + return 0; } -/* - * Splits num_nodes nodes up equally starting at node_start. The return value - * is the number of nodes split up and addr is adjusted to be at the end of the - * last node allocated. - */ -static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr, - u64 max_addr, int node_start, - int num_nodes) +static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn) { - unsigned int big; - u64 size; - int i; + int i, big; + struct bootnode nodes[MAX_NUMNODES]; + unsigned long sz, old_sz; + unsigned long hole_size; + unsigned long start, end; + unsigned long max_addr = (end_pfn << PAGE_SHIFT); - if (num_nodes <= 0) - return -1; - if (num_nodes > MAX_NUMNODES) - num_nodes = MAX_NUMNODES; - size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) / - num_nodes; - /* - * Calculate the number of big nodes that can be allocated as a result - * of consolidating the leftovers. - */ - big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * num_nodes) / - FAKE_NODE_MIN_SIZE; - - /* Round down to nearest FAKE_NODE_MIN_SIZE. */ - size &= FAKE_NODE_MIN_HASH_MASK; - if (!size) { - printk(KERN_ERR "Not enough memory for each node. " - "NUMA emulation disabled.\n"); - return -1; - } + start = (start_pfn << PAGE_SHIFT); + hole_size = e820_hole_size(start, max_addr); + sz = (max_addr - start - hole_size) / numa_fake; - for (i = node_start; i < num_nodes + node_start; i++) { - u64 end = *addr + size; - if (i < big) - end += FAKE_NODE_MIN_SIZE; - /* - * The final node can have the remaining system RAM. Other - * nodes receive roughly the same amount of available pages. - */ - if (i == num_nodes + node_start - 1) - end = max_addr; - else - while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) < - size) { - end += FAKE_NODE_MIN_SIZE; - if (end > max_addr) { - end = max_addr; - break; - } - } - if (setup_node_range(i, nodes, addr, end - *addr, max_addr) < 0) - break; - } - return i - node_start + 1; -} + /* Kludge needed for the hash function */ -/* - * Splits the remaining system RAM into chunks of size. The remaining memory is - * always assigned to a final node and can be asymmetric. Returns the number of - * nodes split. - */ -static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr, - u64 max_addr, int node_start, u64 size) -{ - int i = node_start; - size = (size << 20) & FAKE_NODE_MIN_HASH_MASK; - while (!setup_node_range(i++, nodes, addr, size, max_addr)) - ; - return i - node_start; -} - -/* - * Sets up the system RAM area from start_pfn to end_pfn according to the - * numa=fake command-line option. - */ -static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn) -{ - struct bootnode nodes[MAX_NUMNODES]; - u64 addr = start_pfn << PAGE_SHIFT; - u64 max_addr = end_pfn << PAGE_SHIFT; - int num_nodes = 0; - int coeff_flag; - int coeff = -1; - int num = 0; - u64 size; - int i; + old_sz = sz; + /* + * Round down to the nearest FAKE_NODE_MIN_SIZE. + */ + sz &= FAKE_NODE_MIN_HASH_MASK; - memset(&nodes, 0, sizeof(nodes)); /* - * If the numa=fake command-line is just a single number N, split the - * system RAM into N fake nodes. + * We ensure that each node is at least 64MB big. Smaller than this + * size can cause VM hiccups. */ - if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) { - num_nodes = split_nodes_equally(nodes, &addr, max_addr, 0, - simple_strtol(cmdline, NULL, 0)); - if (num_nodes < 0) - return num_nodes; - goto out; + if (sz == 0) { + printk(KERN_INFO "Not enough memory for %d nodes. Reducing " + "the number of nodes\n", numa_fake); + numa_fake = (max_addr - start - hole_size) / FAKE_NODE_MIN_SIZE; + printk(KERN_INFO "Number of fake nodes will be = %d\n", + numa_fake); + sz = FAKE_NODE_MIN_SIZE; } - - /* Parse the command line. */ - for (coeff_flag = 0; ; cmdline++) { - if (*cmdline && isdigit(*cmdline)) { - num = num * 10 + *cmdline - '0'; - continue; - } - if (*cmdline == '*') { - if (num > 0) - coeff = num; - coeff_flag = 1; + /* + * Find out how many nodes can get an extra NODE_MIN_SIZE granule. + * This logic ensures the extra memory gets distributed among as many + * nodes as possible (as compared to one single node getting all that + * extra memory. + */ + big = ((old_sz - sz) * numa_fake) / FAKE_NODE_MIN_SIZE; + printk(KERN_INFO "Fake node Size: %luMB hole_size: %luMB big nodes: " + "%d\n", + (sz >> 20), (hole_size >> 20), big); + memset(&nodes,0,sizeof(nodes)); + end = start; + for (i = 0; i < numa_fake; i++) { + /* + * In case we are not able to allocate enough memory for all + * the nodes, we reduce the number of fake nodes. + */ + if (end >= max_addr) { + numa_fake = i - 1; + break; } - if (!*cmdline || *cmdline == ',') { - if (!coeff_flag) - coeff = 1; - /* - * Round down to the nearest FAKE_NODE_MIN_SIZE. - * Command-line coefficients are in megabytes. - */ - size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK; - if (size) - for (i = 0; i < coeff; i++, num_nodes++) - if (setup_node_range(num_nodes, nodes, - &addr, size, max_addr) < 0) - goto done; - if (!*cmdline) + start = nodes[i].start = end; + /* + * Final node can have all the remaining memory. + */ + if (i == numa_fake-1) + sz = max_addr - start; + end = nodes[i].start + sz; + /* + * Fir "big" number of nodes get extra granule. + */ + if (i < big) + end += FAKE_NODE_MIN_SIZE; + /* + * Iterate over the range to ensure that this node gets at + * least sz amount of RAM (excluding holes) + */ + while ((end - start - e820_hole_size(start, end)) < sz) { + end += FAKE_NODE_MIN_SIZE; + if (end >= max_addr) break; - coeff_flag = 0; - coeff = -1; - } - num = 0; - } -done: - if (!num_nodes) - return -1; - /* Fill remainder of system RAM, if appropriate. */ - if (addr < max_addr) { - if (coeff_flag && coeff < 0) { - /* Split remaining nodes into num-sized chunks */ - num_nodes += split_nodes_by_size(nodes, &addr, max_addr, - num_nodes, num); - goto out; } - switch (*(cmdline - 1)) { - case '*': - /* Split remaining nodes into coeff chunks */ - if (coeff <= 0) + /* + * Look at the next node to make sure there is some real memory + * to map. Bad things happen when the only memory present + * in a zone on a fake node is IO hole. + */ + while (e820_hole_size(end, end + FAKE_NODE_MIN_SIZE) > 0) { + if (zone_cross_over(start, end + sz)) { + end = (MAX_DMA32_PFN << PAGE_SHIFT); break; - num_nodes += split_nodes_equally(nodes, &addr, max_addr, - num_nodes, coeff); - break; - case ',': - /* Do not allocate remaining system RAM */ - break; - default: - /* Give one final node */ - setup_node_range(num_nodes, nodes, &addr, - max_addr - addr, max_addr); - num_nodes++; + } + if (end >= max_addr) + break; + end += FAKE_NODE_MIN_SIZE; } - } -out: - memnode_shift = compute_hash_shift(nodes, num_nodes); - if (memnode_shift < 0) { - memnode_shift = 0; - printk(KERN_ERR "No NUMA hash function found. NUMA emulation " - "disabled.\n"); - return -1; - } - - /* - * We need to vacate all active ranges that may have been registered by - * SRAT. - */ - remove_all_active_ranges(); - for_each_node_mask(i, node_possible_map) { + if (end > max_addr) + end = max_addr; + nodes[i].end = end; + printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", + i, + nodes[i].start, nodes[i].end, + (nodes[i].end - nodes[i].start) >> 20); + node_set_online(i); + } + memnode_shift = compute_hash_shift(nodes, numa_fake); + if (memnode_shift < 0) { + memnode_shift = 0; + printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n"); + return -1; + } + for_each_online_node(i) { e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT, nodes[i].end >> PAGE_SHIFT); setup_node_bootmem(i, nodes[i].start, nodes[i].end); @@ -487,32 +399,26 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn) numa_init_array(); return 0; } -#undef E820_ADDR_HOLE_SIZE -#endif /* CONFIG_NUMA_EMU */ +#endif void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) { int i; - nodes_clear(node_possible_map); - #ifdef CONFIG_NUMA_EMU - if (cmdline && !numa_emulation(start_pfn, end_pfn)) + if (numa_fake && !numa_emulation(start_pfn, end_pfn)) return; - nodes_clear(node_possible_map); #endif #ifdef CONFIG_ACPI_NUMA if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT)) return; - nodes_clear(node_possible_map); #endif #ifdef CONFIG_K8_NUMA if (!numa_off && !k8_scan_nodes(start_pfn<> PAGE_SHIFT; large_pte = pfn_pte(pfn, ref_prot); large_pte = pte_mkhuge(large_pte); set_pte((pte_t *)pmd, large_pte); @@ -138,8 +141,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, */ struct page *split; ref_prot2 = pte_pgprot(pte_clrhuge(*kpte)); - split = split_large_page(pfn << PAGE_SHIFT, prot, - ref_prot2); + split = split_large_page(address, prot, ref_prot2); if (!split) return -ENOMEM; set_pte(kpte, mk_pte(split, ref_prot2)); @@ -158,7 +160,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, if (page_private(kpte_page) == 0) { save_page(kpte_page); - revert_page(address, pfn, ref_prot); + revert_page(address, ref_prot); } return 0; } @@ -178,32 +180,22 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, */ int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) { - unsigned long phys_base_pfn = __pa_symbol(__START_KERNEL_map) >> PAGE_SHIFT; - int err = 0, kernel_map = 0; + int err = 0; int i; - if (address >= __START_KERNEL_map - && address < __START_KERNEL_map + KERNEL_TEXT_SIZE) { - address = (unsigned long)__va(__pa(address)); - kernel_map = 1; - } - down_write(&init_mm.mmap_sem); for (i = 0; i < numpages; i++, address += PAGE_SIZE) { unsigned long pfn = __pa(address) >> PAGE_SHIFT; - if (!kernel_map || pte_present(pfn_pte(0, prot))) { - err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); - if (err) - break; - } + err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); + if (err) + break; /* Handle kernel mapping too which aliases part of the * lowmem */ - if ((pfn >= phys_base_pfn) && - ((pfn - phys_base_pfn) < (KERNEL_TEXT_SIZE >> PAGE_SHIFT))) { + if (__pa(address) < KERNEL_TEXT_SIZE) { unsigned long addr2; pgprot_t prot2; - addr2 = __START_KERNEL_map + ((pfn - phys_base_pfn) << PAGE_SHIFT); + addr2 = __START_KERNEL_map + __pa(address); /* Make sure the kernel mappings stay executable */ prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); err = __change_page_attr(addr2, pfn, prot2, diff --git a/trunk/arch/x86_64/mm/srat.c b/trunk/arch/x86_64/mm/srat.c index 1e76bb0a7277..2efe215fc76a 100644 --- a/trunk/arch/x86_64/mm/srat.c +++ b/trunk/arch/x86_64/mm/srat.c @@ -419,21 +419,19 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return -1; } - node_possible_map = nodes_parsed; - /* Finally register nodes */ - for_each_node_mask(i, node_possible_map) + for_each_node_mask(i, nodes_parsed) setup_node_bootmem(i, nodes[i].start, nodes[i].end); /* Try again in case setup_node_bootmem missed one due to missing bootmem */ - for_each_node_mask(i, node_possible_map) + for_each_node_mask(i, nodes_parsed) if (!node_online(i)) setup_node_bootmem(i, nodes[i].start, nodes[i].end); for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; - if (!node_isset(cpu_to_node[i], node_possible_map)) + if (!node_isset(cpu_to_node[i], nodes_parsed)) numa_set_node(i, NUMA_NO_NODE); } numa_init_array(); diff --git a/trunk/arch/xtensa/kernel/vmlinux.lds.S b/trunk/arch/xtensa/kernel/vmlinux.lds.S index 4fbd66a52a88..ab6370054cee 100644 --- a/trunk/arch/xtensa/kernel/vmlinux.lds.S +++ b/trunk/arch/xtensa/kernel/vmlinux.lds.S @@ -198,7 +198,7 @@ SECTIONS __ftr_fixup : { *(__ftr_fixup) } __stop___ftr_fixup = .; - . = ALIGN(4096); + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; diff --git a/trunk/arch/xtensa/kernel/xtensa_ksyms.c b/trunk/arch/xtensa/kernel/xtensa_ksyms.c index cd7e6a020602..0b4cb93db5a3 100644 --- a/trunk/arch/xtensa/kernel/xtensa_ksyms.c +++ b/trunk/arch/xtensa/kernel/xtensa_ksyms.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/xtensa/lib/Makefile b/trunk/arch/xtensa/lib/Makefile index 6c4fdd86acd8..ed935b58e8a4 100644 --- a/trunk/arch/xtensa/lib/Makefile +++ b/trunk/arch/xtensa/lib/Makefile @@ -2,6 +2,6 @@ # Makefile for Xtensa-specific library files. # -lib-y += memcopy.o memset.o checksum.o \ +lib-y += memcopy.o memset.o checksum.o strcasecmp.o \ usercopy.o strncpy_user.o strnlen_user.o lib-$(CONFIG_PCI) += pci-auto.o diff --git a/trunk/arch/xtensa/lib/strcasecmp.c b/trunk/arch/xtensa/lib/strcasecmp.c new file mode 100644 index 000000000000..165b2d6effa5 --- /dev/null +++ b/trunk/arch/xtensa/lib/strcasecmp.c @@ -0,0 +1,32 @@ +/* + * linux/arch/xtensa/lib/strcasecmp.c + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2002 Tensilica Inc. + */ + +#include + + +/* We handle nothing here except the C locale. Since this is used in + only one place, on strings known to contain only 7 bit ASCII, this + is ok. */ + +int strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } while (ca == cb && ca != '\0'); + + return ca - cb; +} diff --git a/trunk/arch/xtensa/platform-iss/network.c b/trunk/arch/xtensa/platform-iss/network.c index ab05bff40104..8ebfc8761229 100644 --- a/trunk/arch/xtensa/platform-iss/network.c +++ b/trunk/arch/xtensa/platform-iss/network.c @@ -386,7 +386,7 @@ static int iss_net_rx(struct net_device *dev) /* Setup skb */ skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; pkt_len = lp->tp.read(lp, &skb); skb_put(skb, pkt_len); diff --git a/trunk/arch/xtensa/platform-iss/setup.c b/trunk/arch/xtensa/platform-iss/setup.c index f60c8cf6dfbe..c8a42b60c57a 100644 --- a/trunk/arch/xtensa/platform-iss/setup.c +++ b/trunk/arch/xtensa/platform-iss/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 64df3fa303b0..b6491c020f26 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -25,17 +26,19 @@ static int cfq_slice_async = HZ / 25; static const int cfq_slice_async_rq = 2; static int cfq_slice_idle = HZ / 125; -/* - * grace period before allowing idle class to get disk access - */ #define CFQ_IDLE_GRACE (HZ / 10) +#define CFQ_SLICE_SCALE (5) + +#define CFQ_KEY_ASYNC (0) /* - * below this threshold, we consider thinktime immediate + * for the hash of cfqq inside the cfqd */ -#define CFQ_MIN_TT (2) +#define CFQ_QHASH_SHIFT 6 +#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) +#define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash) -#define CFQ_SLICE_SCALE (5) +#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) #define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) #define RQ_CFQQ(rq) ((rq)->elevator_private2) @@ -53,19 +56,15 @@ static struct completion *ioc_gone; #define ASYNC (0) #define SYNC (1) -#define sample_valid(samples) ((samples) > 80) +#define cfq_cfqq_dispatched(cfqq) \ + ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC]) -/* - * Most of our rbtree usage is for sorting with min extraction, so - * if we cache the leftmost node we don't have to walk down the tree - * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should - * move this into the elevator for the rq sorting as well. - */ -struct cfq_rb_root { - struct rb_root rb; - struct rb_node *left; -}; -#define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, } +#define cfq_cfqq_class_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC) + +#define cfq_cfqq_sync(cfqq) \ + (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC]) + +#define sample_valid(samples) ((samples) > 80) /* * Per block device queue structure @@ -76,11 +75,18 @@ struct cfq_data { /* * rr list of queues with requests and the count of them */ - struct cfq_rb_root service_tree; + struct list_head rr_list[CFQ_PRIO_LISTS]; + struct list_head busy_rr; + struct list_head cur_rr; + struct list_head idle_rr; unsigned int busy_queues; + /* + * cfqq lookup hash + */ + struct hlist_head *cfq_hash; + int rq_in_driver; - int sync_flight; int hw_tag; /* @@ -91,10 +97,12 @@ struct cfq_data { struct cfq_queue *active_queue; struct cfq_io_context *active_cic; + int cur_prio, cur_end_prio; + unsigned int dispatch_slice; struct timer_list idle_class_timer; - sector_t last_position; + sector_t last_sector; unsigned long last_end_request; /* @@ -109,9 +117,6 @@ struct cfq_data { unsigned int cfq_slice_idle; struct list_head cic_list; - - sector_t new_seek_mean; - u64 new_seek_total; }; /* @@ -122,10 +127,12 @@ struct cfq_queue { atomic_t ref; /* parent cfq_data */ struct cfq_data *cfqd; - /* service_tree member */ - struct rb_node rb_node; - /* service_tree key */ - unsigned long rb_key; + /* cfqq lookup hash */ + struct hlist_node cfq_hash; + /* hash key */ + unsigned int key; + /* member of the rr/busy/cur/idle cfqd list */ + struct list_head cfq_list; /* sorted list of pending requests */ struct rb_root sort_list; /* if fifo isn't expired, next request to serve */ @@ -140,10 +147,11 @@ struct cfq_queue { struct list_head fifo; unsigned long slice_end; + unsigned long service_last; long slice_resid; - /* number of requests that are on the dispatch list or inside driver */ - int dispatched; + /* number of requests that are on the dispatch list */ + int on_dispatch[2]; /* io prio of this group */ unsigned short ioprio, org_ioprio; @@ -151,8 +159,6 @@ struct cfq_queue { /* various state flags, see below */ unsigned int flags; - - sector_t last_request_pos; }; enum cfqq_state_flags { @@ -166,7 +172,6 @@ enum cfqq_state_flags { CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */ CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ - CFQ_CFQQ_FLAG_sync, /* synchronous queue */ }; #define CFQ_CFQQ_FNS(name) \ @@ -193,38 +198,11 @@ CFQ_CFQQ_FNS(idle_window); CFQ_CFQQ_FNS(prio_changed); CFQ_CFQQ_FNS(queue_new); CFQ_CFQQ_FNS(slice_new); -CFQ_CFQQ_FNS(sync); #undef CFQ_CFQQ_FNS +static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); static void cfq_dispatch_insert(request_queue_t *, struct request *); -static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, - struct task_struct *, gfp_t); -static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *, - struct io_context *); - -static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic, - int is_sync) -{ - return cic->cfqq[!!is_sync]; -} - -static inline void cic_set_cfqq(struct cfq_io_context *cic, - struct cfq_queue *cfqq, int is_sync) -{ - cic->cfqq[!!is_sync] = cfqq; -} - -/* - * We regard a request as SYNC, if it's either a read or has the SYNC bit - * set (in which case it could also be direct WRITE). - */ -static inline int cfq_bio_sync(struct bio *bio) -{ - if (bio_data_dir(bio) == READ || bio_sync(bio)) - return 1; - - return 0; -} +static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); /* * scheduler run of queue, if there are requests pending and no one in the @@ -243,31 +221,44 @@ static int cfq_queue_empty(request_queue_t *q) return !cfqd->busy_queues; } +static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync) +{ + /* + * Use the per-process queue, for read requests and syncronous writes + */ + if (!(rw & REQ_RW) || is_sync) + return task->pid; + + return CFQ_KEY_ASYNC; +} + /* * Scale schedule slice based on io priority. Use the sync time slice only * if a queue is marked sync and has sync io queued. A sync queue with async * io only, should not get full sync slice length. */ -static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync, - unsigned short prio) -{ - const int base_slice = cfqd->cfq_slice[sync]; - - WARN_ON(prio >= IOPRIO_BE_NR); - - return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - prio)); -} - static inline int cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio); + const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)]; + + WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR); + + return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio)); } static inline void cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) { cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; + cfqq->slice_end += cfqq->slice_resid; + + /* + * Don't carry over residual for more than one slice, we only want + * to slightly correct the fairness. Carrying over forever would + * easily introduce oscillations. + */ + cfqq->slice_resid = 0; } /* @@ -316,7 +307,7 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2) s1 = rq1->sector; s2 = rq2->sector; - last = cfqd->last_position; + last = cfqd->last_sector; /* * by definition, 1KiB is 2 sectors @@ -380,26 +371,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2) } } -/* - * The below is leftmost cache rbtree addon - */ -static struct rb_node *cfq_rb_first(struct cfq_rb_root *root) -{ - if (!root->left) - root->left = rb_first(&root->rb); - - return root->left; -} - -static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root) -{ - if (root->left == n) - root->left = NULL; - - rb_erase(n, &root->rb); - RB_CLEAR_NODE(n); -} - /* * would be nice to take fifo expire time into account as well */ @@ -427,96 +398,78 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq, return cfq_choose_req(cfqd, next, prev); } -static unsigned long cfq_slice_offset(struct cfq_data *cfqd, - struct cfq_queue *cfqq) +static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) { + struct cfq_data *cfqd = cfqq->cfqd; + struct list_head *list, *n; + struct cfq_queue *__cfqq; + /* - * just an approximation, should be ok. + * Resorting requires the cfqq to be on the RR list already. */ - return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) - - cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio)); -} + if (!cfq_cfqq_on_rr(cfqq)) + return; -/* - * The cfqd->service_tree holds all pending cfq_queue's that have - * requests waiting to be processed. It is sorted in the order that - * we will service the queues. - */ -static void cfq_service_tree_add(struct cfq_data *cfqd, - struct cfq_queue *cfqq, int add_front) -{ - struct rb_node **p = &cfqd->service_tree.rb.rb_node; - struct rb_node *parent = NULL; - unsigned long rb_key; - int left; - - if (!add_front) { - rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; - rb_key += cfqq->slice_resid; - cfqq->slice_resid = 0; - } else - rb_key = 0; + list_del(&cfqq->cfq_list); - if (!RB_EMPTY_NODE(&cfqq->rb_node)) { + if (cfq_class_rt(cfqq)) + list = &cfqd->cur_rr; + else if (cfq_class_idle(cfqq)) + list = &cfqd->idle_rr; + else { /* - * same position, nothing more to do + * if cfqq has requests in flight, don't allow it to be + * found in cfq_set_active_queue before it has finished them. + * this is done to increase fairness between a process that + * has lots of io pending vs one that only generates one + * sporadically or synchronously */ - if (rb_key == cfqq->rb_key) - return; - - cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); + if (cfq_cfqq_dispatched(cfqq)) + list = &cfqd->busy_rr; + else + list = &cfqd->rr_list[cfqq->ioprio]; } - left = 1; - while (*p) { - struct cfq_queue *__cfqq; - struct rb_node **n; - - parent = *p; - __cfqq = rb_entry(parent, struct cfq_queue, rb_node); - + if (preempted || cfq_cfqq_queue_new(cfqq)) { /* - * sort RT queues first, we always want to give - * preference to them. IDLE queues goes to the back. - * after that, sort on the next service time. + * If this queue was preempted or is new (never been serviced), + * let it be added first for fairness but beind other new + * queues. */ - if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq)) - n = &(*p)->rb_left; - else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq)) - n = &(*p)->rb_right; - else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq)) - n = &(*p)->rb_left; - else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq)) - n = &(*p)->rb_right; - else if (rb_key < __cfqq->rb_key) - n = &(*p)->rb_left; - else - n = &(*p)->rb_right; + n = list; + while (n->next != list) { + __cfqq = list_entry_cfqq(n->next); + if (!cfq_cfqq_queue_new(__cfqq)) + break; - if (n == &(*p)->rb_right) - left = 0; + n = n->next; + } + list_add_tail(&cfqq->cfq_list, n); + } else if (!cfq_cfqq_class_sync(cfqq)) { + /* + * async queue always goes to the end. this wont be overly + * unfair to writes, as the sort of the sync queue wont be + * allowed to pass the async queue again. + */ + list_add_tail(&cfqq->cfq_list, list); + } else { + /* + * sort by last service, but don't cross a new or async + * queue. we don't cross a new queue because it hasn't been + * service before, and we don't cross an async queue because + * it gets added to the end on expire. + */ + n = list; + while ((n = n->prev) != list) { + struct cfq_queue *__cfqq = list_entry_cfqq(n); - p = n; + if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last) + break; + if (time_before(__cfqq->service_last, cfqq->service_last)) + break; + } + list_add(&cfqq->cfq_list, n); } - - if (left) - cfqd->service_tree.left = &cfqq->rb_node; - - cfqq->rb_key = rb_key; - rb_link_node(&cfqq->rb_node, parent, p); - rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb); -} - -/* - * Update cfqq's position in the service tree. - */ -static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - /* - * Resorting requires the cfqq to be on the RR list already. - */ - if (cfq_cfqq_on_rr(cfqq)) - cfq_service_tree_add(cfqd, cfqq, 0); } /* @@ -530,21 +483,15 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; - cfq_resort_rr_list(cfqd, cfqq); + cfq_resort_rr_list(cfqq, 0); } -/* - * Called when the cfqq no longer has requests pending, remove it from - * the service tree. - */ static inline void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { BUG_ON(!cfq_cfqq_on_rr(cfqq)); cfq_clear_cfqq_on_rr(cfqq); - - if (!RB_EMPTY_NODE(&cfqq->rb_node)) - cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); + list_del_init(&cfqq->cfq_list); BUG_ON(!cfqd->busy_queues); cfqd->busy_queues--; @@ -585,12 +532,6 @@ static void cfq_add_rq_rb(struct request *rq) if (!cfq_cfqq_on_rr(cfqq)) cfq_add_cfqq_rr(cfqd, cfqq); - - /* - * check if this request is a better next-serve candidate - */ - cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq); - BUG_ON(!cfqq->next_rq); } static inline void @@ -605,14 +546,10 @@ static struct request * cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio) { struct task_struct *tsk = current; - struct cfq_io_context *cic; + pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio)); struct cfq_queue *cfqq; - cic = cfq_cic_rb_lookup(cfqd, tsk->io_context); - if (!cic) - return NULL; - - cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio)); + cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio); if (cfqq) { sector_t sector = bio->bi_sector + bio_sectors(bio); @@ -636,8 +573,6 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq) */ if (!cfqd->hw_tag && cfqd->rq_in_driver > 4) cfqd->hw_tag = 1; - - cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors; } static void cfq_deactivate_request(request_queue_t *q, struct request *rq) @@ -664,7 +599,8 @@ static void cfq_remove_request(struct request *rq) } } -static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) +static int +cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; struct request *__rq; @@ -706,24 +642,23 @@ static int cfq_allow_merge(request_queue_t *q, struct request *rq, struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_io_context *cic; + const int rw = bio_data_dir(bio); struct cfq_queue *cfqq; + pid_t key; /* * Disallow merge of a sync bio into an async request. */ - if (cfq_bio_sync(bio) && !rq_is_sync(rq)) + if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq)) return 0; /* * Lookup the cfqq that this bio will be queued with. Allow * merge only if rq is queued there. */ - cic = cfq_cic_rb_lookup(cfqd, current->io_context); - if (!cic) - return 0; + key = cfq_queue_pid(current, rw, bio_sync(bio)); + cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio); - cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio)); if (cfqq == RQ_CFQQ(rq)) return 1; @@ -743,7 +678,6 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) cfq_clear_cfqq_must_alloc_slice(cfqq); cfq_clear_cfqq_fifo_expire(cfqq); cfq_mark_cfqq_slice_new(cfqq); - cfq_clear_cfqq_queue_new(cfqq); } cfqd->active_queue = cfqq; @@ -754,21 +688,23 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) */ static void __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, - int timed_out) + int preempted, int timed_out) { if (cfq_cfqq_wait_request(cfqq)) del_timer(&cfqd->idle_slice_timer); cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); + cfq_clear_cfqq_queue_new(cfqq); /* - * store what was left of this slice, if the queue idled/timed out + * store what was left of this slice, if the queue idled out + * or was preempted */ if (timed_out && !cfq_cfqq_slice_new(cfqq)) cfqq->slice_resid = cfqq->slice_end - jiffies; - cfq_resort_rr_list(cfqd, cfqq); + cfq_resort_rr_list(cfqq, preempted); if (cfqq == cfqd->active_queue) cfqd->active_queue = NULL; @@ -777,152 +713,163 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, put_io_context(cfqd->active_cic->ioc); cfqd->active_cic = NULL; } + + cfqd->dispatch_slice = 0; } -static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out) +static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted, + int timed_out) { struct cfq_queue *cfqq = cfqd->active_queue; if (cfqq) - __cfq_slice_expired(cfqd, cfqq, timed_out); + __cfq_slice_expired(cfqd, cfqq, preempted, timed_out); } /* - * Get next queue for service. Unless we have a queue preemption, - * we'll simply select the first cfqq in the service tree. + * 0 + * 0,1 + * 0,1,2 + * 0,1,2,3 + * 0,1,2,3,4 + * 0,1,2,3,4,5 + * 0,1,2,3,4,5,6 + * 0,1,2,3,4,5,6,7 */ -static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) +static int cfq_get_next_prio_level(struct cfq_data *cfqd) { - struct cfq_queue *cfqq; - struct rb_node *n; - - if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) - return NULL; + int prio, wrap; - n = cfq_rb_first(&cfqd->service_tree); - cfqq = rb_entry(n, struct cfq_queue, rb_node); + prio = -1; + wrap = 0; + do { + int p; - if (cfq_class_idle(cfqq)) { - unsigned long end; + for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) { + if (!list_empty(&cfqd->rr_list[p])) { + prio = p; + break; + } + } - /* - * if we have idle queues and no rt or be queues had - * pending requests, either allow immediate service if - * the grace period has passed or arm the idle grace - * timer - */ - end = cfqd->last_end_request + CFQ_IDLE_GRACE; - if (time_before(jiffies, end)) { - mod_timer(&cfqd->idle_class_timer, end); - cfqq = NULL; + if (prio != -1) + break; + cfqd->cur_prio = 0; + if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) { + cfqd->cur_end_prio = 0; + if (wrap) + break; + wrap = 1; } - } + } while (1); - return cfqq; -} + if (unlikely(prio == -1)) + return -1; -/* - * Get and set a new active queue for service. - */ -static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd) -{ - struct cfq_queue *cfqq; + BUG_ON(prio >= CFQ_PRIO_LISTS); - cfqq = cfq_get_next_queue(cfqd); - __cfq_set_active_queue(cfqd, cfqq); - return cfqq; -} + list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr); -static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd, - struct request *rq) -{ - if (rq->sector >= cfqd->last_position) - return rq->sector - cfqd->last_position; - else - return cfqd->last_position - rq->sector; + cfqd->cur_prio = prio + 1; + if (cfqd->cur_prio > cfqd->cur_end_prio) { + cfqd->cur_end_prio = cfqd->cur_prio; + cfqd->cur_prio = 0; + } + if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) { + cfqd->cur_prio = 0; + cfqd->cur_end_prio = 0; + } + + return prio; } -static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq) +static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd) { - struct cfq_io_context *cic = cfqd->active_cic; + struct cfq_queue *cfqq = NULL; - if (!sample_valid(cic->seek_samples)) - return 0; + if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) { + /* + * if current list is non-empty, grab first entry. if it is + * empty, get next prio level and grab first entry then if any + * are spliced + */ + cfqq = list_entry_cfqq(cfqd->cur_rr.next); + } else if (!list_empty(&cfqd->busy_rr)) { + /* + * If no new queues are available, check if the busy list has + * some before falling back to idle io. + */ + cfqq = list_entry_cfqq(cfqd->busy_rr.next); + } else if (!list_empty(&cfqd->idle_rr)) { + /* + * if we have idle queues and no rt or be queues had pending + * requests, either allow immediate service if the grace period + * has passed or arm the idle grace timer + */ + unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE; - return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean; -} + if (time_after_eq(jiffies, end)) + cfqq = list_entry_cfqq(cfqd->idle_rr.next); + else + mod_timer(&cfqd->idle_class_timer, end); + } -static int cfq_close_cooperator(struct cfq_data *cfq_data, - struct cfq_queue *cfqq) -{ - /* - * We should notice if some of the queues are cooperating, eg - * working closely on the same area of the disk. In that case, - * we can group them together and don't waste time idling. - */ - return 0; + __cfq_set_active_queue(cfqd, cfqq); + return cfqq; } -#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024)) +#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024)) -static void cfq_arm_slice_timer(struct cfq_data *cfqd) +static int cfq_arm_slice_timer(struct cfq_data *cfqd) { struct cfq_queue *cfqq = cfqd->active_queue; struct cfq_io_context *cic; unsigned long sl; WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); - WARN_ON(cfq_cfqq_slice_new(cfqq)); /* * idle is disabled, either manually or by past process history */ - if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq)) - return; - + if (!cfqd->cfq_slice_idle) + return 0; + if (!cfq_cfqq_idle_window(cfqq)) + return 0; /* * task has exited, don't wait */ cic = cfqd->active_cic; if (!cic || !cic->ioc->task) - return; - - /* - * See if this prio level has a good candidate - */ - if (cfq_close_cooperator(cfqd, cfqq) && - (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2)) - return; + return 0; cfq_mark_cfqq_must_dispatch(cfqq); cfq_mark_cfqq_wait_request(cfqq); + sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle); + /* * we don't want to idle for seeks, but we do want to allow * fair distribution of slice time for a process doing back-to-back * seeks. so allow a little bit of time for him to submit a new rq */ - sl = cfqd->cfq_slice_idle; if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic)) - sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT)); + sl = min(sl, msecs_to_jiffies(2)); mod_timer(&cfqd->idle_slice_timer, jiffies + sl); + return 1; } -/* - * Move request from internal lists to the request queue dispatch list. - */ static void cfq_dispatch_insert(request_queue_t *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); cfq_remove_request(rq); - cfqq->dispatched++; + cfqq->on_dispatch[rq_is_sync(rq)]++; elv_dispatch_sort(q, rq); - if (cfq_cfqq_sync(cfqq)) - cfqd->sync_flight++; + rq = list_entry(q->queue_head.prev, struct request, queuelist); + cfqd->last_sector = rq->sector + rq->nr_sectors; } /* @@ -942,13 +889,13 @@ static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq) if (list_empty(&cfqq->fifo)) return NULL; - fifo = cfq_cfqq_sync(cfqq); + fifo = cfq_cfqq_class_sync(cfqq); rq = rq_entry_fifo(cfqq->fifo.next); - if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) - return NULL; + if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) + return rq; - return rq; + return NULL; } static inline int @@ -962,8 +909,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq) } /* - * Select a queue for service. If we have a current active queue, - * check whether to continue servicing it, or retrieve and set a new one. + * get next queue for service */ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) { @@ -974,41 +920,33 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) goto new_queue; /* - * The active queue has run out of time, expire it and select new. + * slice has expired */ - if (cfq_slice_used(cfqq)) + if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq)) goto expire; /* - * The active queue has requests and isn't expired, allow it to - * dispatch. + * if queue has requests, dispatch one. if not, check if + * enough slice is left to wait for one */ if (!RB_EMPTY_ROOT(&cfqq->sort_list)) goto keep_queue; - - /* - * No requests pending. If the active queue still has requests in - * flight or is idling for a new request, allow either of these - * conditions to happen (or time out) before selecting a new queue. - */ - if (timer_pending(&cfqd->idle_slice_timer) || - (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) { + else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) { cfqq = NULL; goto keep_queue; + } else if (cfq_cfqq_class_sync(cfqq)) { + if (cfq_arm_slice_timer(cfqd)) + return NULL; } expire: - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); new_queue: cfqq = cfq_set_active_queue(cfqd); keep_queue: return cfqq; } -/* - * Dispatch some requests from cfqq, moving them to the request queue - * dispatch list. - */ static int __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, int max_dispatch) @@ -1031,6 +969,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, */ cfq_dispatch_insert(cfqd->queue, rq); + cfqd->dispatch_slice++; dispatched++; if (!cfqd->active_cic) { @@ -1047,55 +986,58 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, * expire an async queue immediately if it has used up its slice. idle * queue always expire after 1 dispatch round. */ - if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && - dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) || - cfq_class_idle(cfqq))) { + if ((!cfq_cfqq_sync(cfqq) && + cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) || + cfq_class_idle(cfqq)) { cfqq->slice_end = jiffies + 1; - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); } return dispatched; } -static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) +static int +cfq_forced_dispatch_cfqqs(struct list_head *list) { - int dispatched = 0; + struct cfq_queue *cfqq, *next; + int dispatched; - while (cfqq->next_rq) { - cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq); - dispatched++; + dispatched = 0; + list_for_each_entry_safe(cfqq, next, list, cfq_list) { + while (cfqq->next_rq) { + cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq); + dispatched++; + } + BUG_ON(!list_empty(&cfqq->fifo)); } - BUG_ON(!list_empty(&cfqq->fifo)); return dispatched; } -/* - * Drain our current requests. Used for barriers and when switching - * io schedulers on-the-fly. - */ -static int cfq_forced_dispatch(struct cfq_data *cfqd) +static int +cfq_forced_dispatch(struct cfq_data *cfqd) { - int dispatched = 0; - struct rb_node *n; + int i, dispatched = 0; - while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) { - struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node); + for (i = 0; i < CFQ_PRIO_LISTS; i++) + dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]); - dispatched += __cfq_forced_dispatch_cfqq(cfqq); - } + dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr); + dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr); + dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr); - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); BUG_ON(cfqd->busy_queues); return dispatched; } -static int cfq_dispatch_requests(request_queue_t *q, int force) +static int +cfq_dispatch_requests(request_queue_t *q, int force) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_queue *cfqq; + struct cfq_queue *cfqq, *prev_cfqq; int dispatched; if (!cfqd->busy_queues) @@ -1105,28 +1047,34 @@ static int cfq_dispatch_requests(request_queue_t *q, int force) return cfq_forced_dispatch(cfqd); dispatched = 0; + prev_cfqq = NULL; while ((cfqq = cfq_select_queue(cfqd)) != NULL) { int max_dispatch; - max_dispatch = cfqd->cfq_quantum; - if (cfq_class_idle(cfqq)) - max_dispatch = 1; - - if (cfqq->dispatched >= max_dispatch) { - if (cfqd->busy_queues > 1) - break; - if (cfqq->dispatched >= 4 * max_dispatch) - break; - } + /* + * Don't repeat dispatch from the previous queue. + */ + if (prev_cfqq == cfqq) + break; - if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq)) + /* + * So we have dispatched before in this round, if the + * next queue has idling enabled (must be sync), don't + * allow it service until the previous have continued. + */ + if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq)) break; cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); del_timer(&cfqd->idle_slice_timer); + max_dispatch = cfqd->cfq_quantum; + if (cfq_class_idle(cfqq)) + max_dispatch = 1; + dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); + prev_cfqq = cfqq; } return dispatched; @@ -1152,21 +1100,48 @@ static void cfq_put_queue(struct cfq_queue *cfqq) BUG_ON(cfq_cfqq_on_rr(cfqq)); if (unlikely(cfqd->active_queue == cfqq)) { - __cfq_slice_expired(cfqd, cfqq, 0); + __cfq_slice_expired(cfqd, cfqq, 0, 0); cfq_schedule_dispatch(cfqd); } + /* + * it's on the empty list and still hashed + */ + list_del(&cfqq->cfq_list); + hlist_del(&cfqq->cfq_hash); kmem_cache_free(cfq_pool, cfqq); } +static struct cfq_queue * +__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio, + const int hashval) +{ + struct hlist_head *hash_list = &cfqd->cfq_hash[hashval]; + struct hlist_node *entry; + struct cfq_queue *__cfqq; + + hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) { + const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio); + + if (__cfqq->key == key && (__p == prio || !prio)) + return __cfqq; + } + + return NULL; +} + +static struct cfq_queue * +cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio) +{ + return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT)); +} + static void cfq_free_io_context(struct io_context *ioc) { struct cfq_io_context *__cic; struct rb_node *n; int freed = 0; - ioc->ioc_data = NULL; - while ((n = rb_first(&ioc->cic_root)) != NULL) { __cic = rb_entry(n, struct cfq_io_context, rb_node); rb_erase(&__cic->rb_node, &ioc->cic_root); @@ -1183,7 +1158,7 @@ static void cfq_free_io_context(struct io_context *ioc) static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) { if (unlikely(cfqq == cfqd->active_queue)) { - __cfq_slice_expired(cfqd, cfqq, 0); + __cfq_slice_expired(cfqd, cfqq, 0, 0); cfq_schedule_dispatch(cfqd); } @@ -1208,6 +1183,10 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, } } + +/* + * Called with interrupts disabled + */ static void cfq_exit_single_io_context(struct cfq_io_context *cic) { struct cfq_data *cfqd = cic->key; @@ -1221,20 +1200,15 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic) } } -/* - * The process that ioc belongs to has exited, we need to clean up - * and put the internal structures we have that belongs to that process. - */ static void cfq_exit_io_context(struct io_context *ioc) { struct cfq_io_context *__cic; struct rb_node *n; - ioc->ioc_data = NULL; - /* * put the reference this task is holding to the various queues */ + n = rb_first(&ioc->cic_root); while (n != NULL) { __cic = rb_entry(n, struct cfq_io_context, rb_node); @@ -1302,6 +1276,8 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq) */ cfqq->org_ioprio = cfqq->ioprio; cfqq->org_ioprio_class = cfqq->ioprio_class; + + cfq_resort_rr_list(cfqq, 0); cfq_clear_cfqq_prio_changed(cfqq); } @@ -1319,7 +1295,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic) cfqq = cic->cfqq[ASYNC]; if (cfqq) { struct cfq_queue *new_cfqq; - new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task, + new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task, GFP_ATOMIC); if (new_cfqq) { cic->cfqq[ASYNC] = new_cfqq; @@ -1351,16 +1327,16 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc) } static struct cfq_queue * -cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, +cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask) { + const int hashval = hash_long(key, CFQ_QHASH_SHIFT); struct cfq_queue *cfqq, *new_cfqq = NULL; - struct cfq_io_context *cic; + unsigned short ioprio; retry: - cic = cfq_cic_rb_lookup(cfqd, tsk->io_context); - /* cic always exists here */ - cfqq = cic_to_cfqq(cic, is_sync); + ioprio = tsk->ioprio; + cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval); if (!cfqq) { if (new_cfqq) { @@ -1385,20 +1361,18 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, memset(cfqq, 0, sizeof(*cfqq)); - RB_CLEAR_NODE(&cfqq->rb_node); + INIT_HLIST_NODE(&cfqq->cfq_hash); + INIT_LIST_HEAD(&cfqq->cfq_list); INIT_LIST_HEAD(&cfqq->fifo); + cfqq->key = key; + hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); atomic_set(&cfqq->ref, 0); cfqq->cfqd = cfqd; - if (is_sync) { - cfq_mark_cfqq_idle_window(cfqq); - cfq_mark_cfqq_sync(cfqq); - } - + cfq_mark_cfqq_idle_window(cfqq); cfq_mark_cfqq_prio_changed(cfqq); cfq_mark_cfqq_queue_new(cfqq); - cfq_init_prio_data(cfqq); } @@ -1411,17 +1385,10 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, return cfqq; } -/* - * We drop cfq io contexts lazily, so we may find a dead one. - */ static void cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic) { WARN_ON(!list_empty(&cic->queue_list)); - - if (ioc->ioc_data == cic) - ioc->ioc_data = NULL; - rb_erase(&cic->rb_node, &ioc->cic_root); kmem_cache_free(cfq_ioc_pool, cic); elv_ioc_count_dec(ioc_count); @@ -1434,16 +1401,6 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc) struct cfq_io_context *cic; void *k, *key = cfqd; - if (unlikely(!ioc)) - return NULL; - - /* - * we maintain a last-hit cache, to avoid browsing over the tree - */ - cic = ioc->ioc_data; - if (cic && cic->key == cfqd) - return cic; - restart: n = ioc->cic_root.rb_node; while (n) { @@ -1459,10 +1416,8 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc) n = n->rb_left; else if (key > k) n = n->rb_right; - else { - ioc->ioc_data = cic; + else return cic; - } } return NULL; @@ -1559,8 +1514,7 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic) } static void -cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, - struct request *rq) +cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq) { sector_t sdist; u64 total; @@ -1570,11 +1524,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, else sdist = cic->last_request_pos - rq->sector; - if (!cic->seek_samples) { - cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8; - cfqd->new_seek_mean = cfqd->new_seek_total / 256; - } - /* * Don't allow the seek distance to get too large from the * odd fragment, pagein, etc @@ -1599,12 +1548,7 @@ static void cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_io_context *cic) { - int enable_idle; - - if (!cfq_cfqq_sync(cfqq)) - return; - - enable_idle = cfq_cfqq_idle_window(cfqq); + int enable_idle = cfq_cfqq_idle_window(cfqq); if (!cic->ioc->task || !cfqd->cfq_slice_idle || (cfqd->hw_tag && CIC_SEEKY(cic))) @@ -1630,28 +1574,24 @@ static int cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, struct request *rq) { - struct cfq_queue *cfqq; + struct cfq_queue *cfqq = cfqd->active_queue; - cfqq = cfqd->active_queue; - if (!cfqq) + if (cfq_class_idle(new_cfqq)) return 0; - if (cfq_slice_used(cfqq)) - return 1; - - if (cfq_class_idle(new_cfqq)) + if (!cfqq) return 0; if (cfq_class_idle(cfqq)) return 1; - + if (!cfq_cfqq_wait_request(new_cfqq)) + return 0; /* * if the new request is sync, but the currently running queue is * not, let the sync request have priority. */ if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq)) return 1; - /* * So both queues are sync. Let the new request get disk time if * it's a metadata request and the current queue is doing regular IO. @@ -1659,16 +1599,6 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, if (rq_is_meta(rq) && !cfqq->meta_pending) return 1; - if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq)) - return 0; - - /* - * if this request is as-good as one we would expect from the - * current cfqq, let it preempt - */ - if (cfq_rq_close(cfqd, rq)) - return 1; - return 0; } @@ -1678,15 +1608,14 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, */ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_slice_expired(cfqd, 1); + cfq_slice_expired(cfqd, 1, 1); /* * Put the new queue at the front of the of the current list, * so we know that it will be selected next. */ BUG_ON(!cfq_cfqq_on_rr(cfqq)); - - cfq_service_tree_add(cfqd, cfqq, 1); + list_move(&cfqq->cfq_list, &cfqd->cur_rr); cfqq->slice_end = 0; cfq_mark_cfqq_slice_new(cfqq); @@ -1705,12 +1634,34 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (rq_is_meta(rq)) cfqq->meta_pending++; + /* + * check if this request is a better next-serve candidate)) { + */ + cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq); + BUG_ON(!cfqq->next_rq); + + /* + * we never wait for an async request and we don't allow preemption + * of an async request. so just return early + */ + if (!rq_is_sync(rq)) { + /* + * sync process issued an async request, if it's waiting + * then expire it and kick rq handling. + */ + if (cic == cfqd->active_cic && + del_timer(&cfqd->idle_slice_timer)) { + cfq_slice_expired(cfqd, 0, 0); + blk_start_queueing(cfqd->queue); + } + return; + } + cfq_update_io_thinktime(cfqd, cic); - cfq_update_io_seektime(cfqd, cic, rq); + cfq_update_io_seektime(cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); cic->last_request_pos = rq->sector + rq->nr_sectors; - cfqq->last_request_pos = cic->last_request_pos; if (cfqq == cfqd->active_queue) { /* @@ -1759,16 +1710,16 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq) now = jiffies; WARN_ON(!cfqd->rq_in_driver); - WARN_ON(!cfqq->dispatched); + WARN_ON(!cfqq->on_dispatch[sync]); cfqd->rq_in_driver--; - cfqq->dispatched--; - - if (cfq_cfqq_sync(cfqq)) - cfqd->sync_flight--; + cfqq->on_dispatch[sync]--; + cfqq->service_last = now; if (!cfq_class_idle(cfqq)) cfqd->last_end_request = now; + cfq_resort_rr_list(cfqq, 0); + if (sync) RQ_CIC(rq)->last_end_request = now; @@ -1782,13 +1733,12 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq) cfq_clear_cfqq_slice_new(cfqq); } if (cfq_slice_used(cfqq)) - cfq_slice_expired(cfqd, 1); - else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) - cfq_arm_slice_timer(cfqd); + cfq_slice_expired(cfqd, 0, 1); + else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) { + if (!cfq_arm_slice_timer(cfqd)) + cfq_schedule_dispatch(cfqd); + } } - - if (!cfqd->rq_in_driver) - cfq_schedule_dispatch(cfqd); } /* @@ -1797,6 +1747,9 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq) */ static void cfq_prio_boost(struct cfq_queue *cfqq) { + const int ioprio_class = cfqq->ioprio_class; + const int ioprio = cfqq->ioprio; + if (has_fs_excl()) { /* * boost idle prio on transactions that would lock out other @@ -1815,6 +1768,12 @@ static void cfq_prio_boost(struct cfq_queue *cfqq) if (cfqq->ioprio != cfqq->org_ioprio) cfqq->ioprio = cfqq->org_ioprio; } + + /* + * refile between round-robin lists if we moved the priority class + */ + if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio)) + cfq_resort_rr_list(cfqq, 0); } static inline int __cfq_may_queue(struct cfq_queue *cfqq) @@ -1832,8 +1791,10 @@ static int cfq_may_queue(request_queue_t *q, int rw) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; - struct cfq_io_context *cic; struct cfq_queue *cfqq; + unsigned int key; + + key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC); /* * don't force setup of a queue from here, as a call to may_queue @@ -1841,11 +1802,7 @@ static int cfq_may_queue(request_queue_t *q, int rw) * so just lookup a possibly existing queue, or return 'may queue' * if that fails */ - cic = cfq_cic_rb_lookup(cfqd, tsk->io_context); - if (!cic) - return ELV_MQUEUE_MAY; - - cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC); + cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio); if (cfqq) { cfq_init_prio_data(cfqq); cfq_prio_boost(cfqq); @@ -1889,6 +1846,7 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) struct cfq_io_context *cic; const int rw = rq_data_dir(rq); const int is_sync = rq_is_sync(rq); + pid_t key = cfq_queue_pid(tsk, rw, is_sync); struct cfq_queue *cfqq; unsigned long flags; @@ -1901,15 +1859,14 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) if (!cic) goto queue_fail; - cfqq = cic_to_cfqq(cic, is_sync); - if (!cfqq) { - cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask); - + if (!cic->cfqq[is_sync]) { + cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask); if (!cfqq) goto queue_fail; - cic_set_cfqq(cic, cfqq, is_sync); - } + cic->cfqq[is_sync] = cfqq; + } else + cfqq = cic->cfqq[is_sync]; cfqq->allocated[rw]++; cfq_clear_cfqq_must_alloc(cfqq); @@ -1979,7 +1936,7 @@ static void cfq_idle_slice_timer(unsigned long data) } } expire: - cfq_slice_expired(cfqd, timed_out); + cfq_slice_expired(cfqd, 0, timed_out); out_kick: cfq_schedule_dispatch(cfqd); out_cont: @@ -2025,7 +1982,7 @@ static void cfq_exit_queue(elevator_t *e) spin_lock_irq(q->queue_lock); if (cfqd->active_queue) - __cfq_slice_expired(cfqd, cfqd->active_queue, 0); + __cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0); while (!list_empty(&cfqd->cic_list)) { struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, @@ -2039,12 +1996,14 @@ static void cfq_exit_queue(elevator_t *e) cfq_shutdown_timer_wq(cfqd); + kfree(cfqd->cfq_hash); kfree(cfqd); } static void *cfq_init_queue(request_queue_t *q) { struct cfq_data *cfqd; + int i; cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node); if (!cfqd) @@ -2052,9 +2011,21 @@ static void *cfq_init_queue(request_queue_t *q) memset(cfqd, 0, sizeof(*cfqd)); - cfqd->service_tree = CFQ_RB_ROOT; + for (i = 0; i < CFQ_PRIO_LISTS; i++) + INIT_LIST_HEAD(&cfqd->rr_list[i]); + + INIT_LIST_HEAD(&cfqd->busy_rr); + INIT_LIST_HEAD(&cfqd->cur_rr); + INIT_LIST_HEAD(&cfqd->idle_rr); INIT_LIST_HEAD(&cfqd->cic_list); + cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node); + if (!cfqd->cfq_hash) + goto out_free; + + for (i = 0; i < CFQ_QHASH_ENTRIES; i++) + INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); + cfqd->queue = q; init_timer(&cfqd->idle_slice_timer); @@ -2078,6 +2049,9 @@ static void *cfq_init_queue(request_queue_t *q) cfqd->cfq_slice_idle = cfq_slice_idle; return cfqd; +out_free: + kfree(cfqd); + return NULL; } static void cfq_slab_kill(void) @@ -2109,6 +2083,7 @@ static int __init cfq_slab_setup(void) /* * sysfs parts below --> */ + static ssize_t cfq_var_show(unsigned int var, char *page) { diff --git a/trunk/block/elevator.c b/trunk/block/elevator.c index ce866eb75f6a..96a00c822748 100644 --- a/trunk/block/elevator.c +++ b/trunk/block/elevator.c @@ -134,13 +134,13 @@ static struct elevator_type *elevator_get(const char *name) { struct elevator_type *e; - spin_lock(&elv_list_lock); + spin_lock_irq(&elv_list_lock); e = elevator_find(name); if (e && !try_module_get(e->elevator_owner)) e = NULL; - spin_unlock(&elv_list_lock); + spin_unlock_irq(&elv_list_lock); return e; } @@ -965,11 +965,10 @@ void elv_unregister_queue(struct request_queue *q) int elv_register(struct elevator_type *e) { char *def = ""; - - spin_lock(&elv_list_lock); + spin_lock_irq(&elv_list_lock); BUG_ON(elevator_find(e->elevator_name)); list_add_tail(&e->list, &elv_list); - spin_unlock(&elv_list_lock); + spin_unlock_irq(&elv_list_lock); if (!strcmp(e->elevator_name, chosen_elevator) || (!*chosen_elevator && @@ -999,9 +998,9 @@ void elv_unregister(struct elevator_type *e) read_unlock(&tasklist_lock); } - spin_lock(&elv_list_lock); + spin_lock_irq(&elv_list_lock); list_del_init(&e->list); - spin_unlock(&elv_list_lock); + spin_unlock_irq(&elv_list_lock); } EXPORT_SYMBOL_GPL(elv_unregister); @@ -1119,7 +1118,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) struct list_head *entry; int len = 0; - spin_lock(&elv_list_lock); + spin_lock_irq(&elv_list_lock); list_for_each(entry, &elv_list) { struct elevator_type *__e; @@ -1129,7 +1128,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) else len += sprintf(name+len, "%s ", __e->elevator_name); } - spin_unlock(&elv_list_lock); + spin_unlock_irq(&elv_list_lock); len += sprintf(len+name, "\n"); return len; diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index b5664440896c..441432a142f2 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -17,7 +17,7 @@ #include #include -struct kset block_subsys; +struct subsystem block_subsys; static DEFINE_MUTEX(block_subsys_lock); /* @@ -221,7 +221,7 @@ static void *part_start(struct seq_file *part, loff_t *pos) loff_t l = *pos; mutex_lock(&block_subsys_lock); - list_for_each(p, &block_subsys.list) + list_for_each(p, &block_subsys.kset.list) if (!l--) return list_entry(p, struct gendisk, kobj.entry); return NULL; @@ -231,7 +231,7 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos) { struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; ++*pos; - return p==&block_subsys.list ? NULL : + return p==&block_subsys.kset.list ? NULL : list_entry(p, struct gendisk, kobj.entry); } @@ -246,7 +246,7 @@ static int show_partition(struct seq_file *part, void *v) int n; char buf[BDEVNAME_SIZE]; - if (&sgp->kobj.entry == block_subsys.list.next) + if (&sgp->kobj.entry == block_subsys.kset.list.next) seq_puts(part, "major minor #blocks name\n\n"); /* Don't show non-partitionable removeable devices or empty devices */ @@ -565,7 +565,7 @@ static void *diskstats_start(struct seq_file *part, loff_t *pos) struct list_head *p; mutex_lock(&block_subsys_lock); - list_for_each(p, &block_subsys.list) + list_for_each(p, &block_subsys.kset.list) if (!k--) return list_entry(p, struct gendisk, kobj.entry); return NULL; @@ -575,7 +575,7 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) { struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; ++*pos; - return p==&block_subsys.list ? NULL : + return p==&block_subsys.kset.list ? NULL : list_entry(p, struct gendisk, kobj.entry); } diff --git a/trunk/block/ll_rw_blk.c b/trunk/block/ll_rw_blk.c index 5873861e1dbb..3de06953ac33 100644 --- a/trunk/block/ll_rw_blk.c +++ b/trunk/block/ll_rw_blk.c @@ -1925,8 +1925,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); - q->sg_reserved_size = INT_MAX; - /* * all done */ @@ -3743,7 +3741,6 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node) ret->nr_batch_requests = 0; /* because this is 0 */ ret->aic = NULL; ret->cic_root.rb_node = NULL; - ret->ioc_data = NULL; /* make sure set_task_ioprio() sees the settings above */ smp_wmb(); tsk->io_context = ret; diff --git a/trunk/block/scsi_ioctl.c b/trunk/block/scsi_ioctl.c index e83f1dbf7c29..65c6a3cba6d6 100644 --- a/trunk/block/scsi_ioctl.c +++ b/trunk/block/scsi_ioctl.c @@ -78,9 +78,7 @@ static int sg_set_timeout(request_queue_t *q, int __user *p) static int sg_get_reserved_size(request_queue_t *q, int __user *p) { - unsigned val = min(q->sg_reserved_size, q->max_sectors << 9); - - return put_user(val, p); + return put_user(q->sg_reserved_size, p); } static int sg_set_reserved_size(request_queue_t *q, int __user *p) diff --git a/trunk/crypto/Kconfig b/trunk/crypto/Kconfig index 620e14cabdc6..086fcec44720 100644 --- a/trunk/crypto/Kconfig +++ b/trunk/crypto/Kconfig @@ -16,10 +16,6 @@ config CRYPTO_ALGAPI help This option provides the API for cryptographic algorithms. -config CRYPTO_ABLKCIPHER - tristate - select CRYPTO_BLKCIPHER - config CRYPTO_BLKCIPHER tristate select CRYPTO_ALGAPI @@ -175,15 +171,6 @@ config CRYPTO_LRW The first 128, 192 or 256 bits in the key are used for AES and the rest is used to tie each cipher block to its logical position. -config CRYPTO_CRYPTD - tristate "Software async crypto daemon" - select CRYPTO_ABLKCIPHER - select CRYPTO_MANAGER - help - This is a generic software asynchronous crypto daemon that - converts an arbitrary synchronous software crypto algorithm - into an asynchronous algorithm that executes in a kernel thread. - config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" select CRYPTO_ALGAPI diff --git a/trunk/crypto/Makefile b/trunk/crypto/Makefile index cce46a1c9dc7..12f93f578171 100644 --- a/trunk/crypto/Makefile +++ b/trunk/crypto/Makefile @@ -8,7 +8,6 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o crypto_algapi-objs := algapi.o $(crypto_algapi-y) obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o -obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o crypto_hash-objs := hash.o @@ -30,7 +29,6 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o -obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o diff --git a/trunk/crypto/ablkcipher.c b/trunk/crypto/ablkcipher.c deleted file mode 100644 index 9348ddd84a56..000000000000 --- a/trunk/crypto/ablkcipher.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Asynchronous block chaining cipher operations. - * - * This is the asynchronous version of blkcipher.c indicating completion - * via a callback. - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include - -static int setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm); - - if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return cipher->setkey(tfm, key, keylen); -} - -static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type, - u32 mask) -{ - return alg->cra_ctxsize; -} - -static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, - u32 mask) -{ - struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; - struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; - - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - - crt->setkey = setkey; - crt->encrypt = alg->encrypt; - crt->decrypt = alg->decrypt; - crt->ivsize = alg->ivsize; - - return 0; -} - -static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; - - seq_printf(m, "type : ablkcipher\n"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); - seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); - seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); - seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen); - seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen); -} - -const struct crypto_type crypto_ablkcipher_type = { - .ctxsize = crypto_ablkcipher_ctxsize, - .init = crypto_init_ablkcipher_ops, -#ifdef CONFIG_PROC_FS - .show = crypto_ablkcipher_show, -#endif -}; -EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Asynchronous block chaining cipher type"); diff --git a/trunk/crypto/algapi.c b/trunk/crypto/algapi.c index f137a432061f..f7d2185b2c8f 100644 --- a/trunk/crypto/algapi.c +++ b/trunk/crypto/algapi.c @@ -84,47 +84,36 @@ static void crypto_destroy_instance(struct crypto_alg *alg) crypto_tmpl_put(tmpl); } -static void crypto_remove_spawn(struct crypto_spawn *spawn, - struct list_head *list, - struct list_head *secondary_spawns) -{ - struct crypto_instance *inst = spawn->inst; - struct crypto_template *tmpl = inst->tmpl; - - list_del_init(&spawn->list); - spawn->alg = NULL; - - if (crypto_is_dead(&inst->alg)) - return; - - inst->alg.cra_flags |= CRYPTO_ALG_DEAD; - if (!tmpl || !crypto_tmpl_get(tmpl)) - return; - - crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); - list_move(&inst->alg.cra_list, list); - hlist_del(&inst->list); - inst->alg.cra_destroy = crypto_destroy_instance; - - list_splice(&inst->alg.cra_users, secondary_spawns); -} - static void crypto_remove_spawns(struct list_head *spawns, - struct list_head *list, u32 new_type) + struct list_head *list) { struct crypto_spawn *spawn, *n; - LIST_HEAD(secondary_spawns); list_for_each_entry_safe(spawn, n, spawns, list) { - if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) + struct crypto_instance *inst = spawn->inst; + struct crypto_template *tmpl = inst->tmpl; + + list_del_init(&spawn->list); + spawn->alg = NULL; + + if (crypto_is_dead(&inst->alg)) continue; - crypto_remove_spawn(spawn, list, &secondary_spawns); - } + inst->alg.cra_flags |= CRYPTO_ALG_DEAD; + if (!tmpl || !crypto_tmpl_get(tmpl)) + continue; + + crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); + list_move(&inst->alg.cra_list, list); + hlist_del(&inst->list); + inst->alg.cra_destroy = crypto_destroy_instance; - while (!list_empty(&secondary_spawns)) { - list_for_each_entry_safe(spawn, n, &secondary_spawns, list) - crypto_remove_spawn(spawn, list, &secondary_spawns); + if (!list_empty(&inst->alg.cra_users)) { + if (&n->list == spawns) + n = list_entry(inst->alg.cra_users.next, + typeof(*n), list); + __list_splice(&inst->alg.cra_users, spawns->prev); + } } } @@ -175,7 +164,7 @@ static int __crypto_register_alg(struct crypto_alg *alg, q->cra_priority > alg->cra_priority) continue; - crypto_remove_spawns(&q->cra_users, list, alg->cra_flags); + crypto_remove_spawns(&q->cra_users, list); } list_add(&alg->cra_list, &crypto_alg_list); @@ -225,7 +214,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); list_del_init(&alg->cra_list); - crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags); + crypto_remove_spawns(&alg->cra_users, list); return 0; } @@ -362,12 +351,11 @@ int crypto_register_instance(struct crypto_template *tmpl, EXPORT_SYMBOL_GPL(crypto_register_instance); int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst, u32 mask) + struct crypto_instance *inst) { int err = -EAGAIN; spawn->inst = inst; - spawn->mask = mask; down_write(&crypto_alg_sem); if (!crypto_is_moribund(alg)) { @@ -437,45 +425,15 @@ int crypto_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(crypto_unregister_notifier); -struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb) -{ - struct rtattr *rta = tb[CRYPTOA_TYPE - 1]; - struct crypto_attr_type *algt; - - if (!rta) - return ERR_PTR(-ENOENT); - if (RTA_PAYLOAD(rta) < sizeof(*algt)) - return ERR_PTR(-EINVAL); - - algt = RTA_DATA(rta); - - return algt; -} -EXPORT_SYMBOL_GPL(crypto_get_attr_type); - -int crypto_check_attr_type(struct rtattr **tb, u32 type) +struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len, + u32 type, u32 mask) { - struct crypto_attr_type *algt; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return PTR_ERR(algt); - - if ((algt->type ^ type) & algt->mask) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_check_attr_type); - -struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) -{ - struct rtattr *rta = tb[CRYPTOA_ALG - 1]; + struct rtattr *rta = param; struct crypto_attr_alg *alga; - if (!rta) - return ERR_PTR(-ENOENT); - if (RTA_PAYLOAD(rta) < sizeof(*alga)) + if (!RTA_OK(rta, len)) + return ERR_PTR(-EBADR); + if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga)) return ERR_PTR(-EINVAL); alga = RTA_DATA(rta); @@ -506,8 +464,7 @@ struct crypto_instance *crypto_alloc_instance(const char *name, goto err_free_inst; spawn = crypto_instance_ctx(inst); - err = crypto_init_spawn(spawn, alg, inst, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + err = crypto_init_spawn(spawn, alg, inst); if (err) goto err_free_inst; @@ -520,68 +477,6 @@ struct crypto_instance *crypto_alloc_instance(const char *name, } EXPORT_SYMBOL_GPL(crypto_alloc_instance); -void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen) -{ - INIT_LIST_HEAD(&queue->list); - queue->backlog = &queue->list; - queue->qlen = 0; - queue->max_qlen = max_qlen; -} -EXPORT_SYMBOL_GPL(crypto_init_queue); - -int crypto_enqueue_request(struct crypto_queue *queue, - struct crypto_async_request *request) -{ - int err = -EINPROGRESS; - - if (unlikely(queue->qlen >= queue->max_qlen)) { - err = -EBUSY; - if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - goto out; - if (queue->backlog == &queue->list) - queue->backlog = &request->list; - } - - queue->qlen++; - list_add_tail(&request->list, &queue->list); - -out: - return err; -} -EXPORT_SYMBOL_GPL(crypto_enqueue_request); - -struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue) -{ - struct list_head *request; - - if (unlikely(!queue->qlen)) - return NULL; - - queue->qlen--; - - if (queue->backlog != &queue->list) - queue->backlog = queue->backlog->next; - - request = queue->list.next; - list_del(request); - - return list_entry(request, struct crypto_async_request, list); -} -EXPORT_SYMBOL_GPL(crypto_dequeue_request); - -int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm) -{ - struct crypto_async_request *req; - - list_for_each_entry(req, &queue->list, list) { - if (req->tfm == tfm) - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_tfm_in_queue); - static int __init crypto_algapi_init(void) { crypto_init_proc(); diff --git a/trunk/crypto/blkcipher.c b/trunk/crypto/blkcipher.c index 8edf40c835a7..b5befe8c3a96 100644 --- a/trunk/crypto/blkcipher.c +++ b/trunk/crypto/blkcipher.c @@ -349,48 +349,13 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, return cipher->setkey(tfm, key, keylen); } -static int async_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - return setkey(crypto_ablkcipher_tfm(tfm), key, keylen); -} - -static int async_encrypt(struct ablkcipher_request *req) -{ - struct crypto_tfm *tfm = req->base.tfm; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - struct blkcipher_desc desc = { - .tfm = __crypto_blkcipher_cast(tfm), - .info = req->info, - .flags = req->base.flags, - }; - - - return alg->encrypt(&desc, req->dst, req->src, req->nbytes); -} - -static int async_decrypt(struct ablkcipher_request *req) -{ - struct crypto_tfm *tfm = req->base.tfm; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - struct blkcipher_desc desc = { - .tfm = __crypto_blkcipher_cast(tfm), - .info = req->info, - .flags = req->base.flags, - }; - - return alg->decrypt(&desc, req->dst, req->src, req->nbytes); -} - static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { struct blkcipher_alg *cipher = &alg->cra_blkcipher; unsigned int len = alg->cra_ctxsize; - type ^= CRYPTO_ALG_ASYNC; - mask &= CRYPTO_ALG_ASYNC; - if ((type & mask) && cipher->ivsize) { + if (cipher->ivsize) { len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); len += cipher->ivsize; } @@ -398,26 +363,16 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, return len; } -static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) -{ - struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - crt->setkey = async_setkey; - crt->encrypt = async_encrypt; - crt->decrypt = async_decrypt; - crt->ivsize = alg->ivsize; - - return 0; -} - -static int crypto_init_blkcipher_ops_sync(struct crypto_tfm *tfm) +static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct blkcipher_tfm *crt = &tfm->crt_blkcipher; struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; unsigned long align = crypto_tfm_alg_alignmask(tfm) + 1; unsigned long addr; + if (alg->ivsize > PAGE_SIZE / 8) + return -EINVAL; + crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; @@ -430,23 +385,8 @@ static int crypto_init_blkcipher_ops_sync(struct crypto_tfm *tfm) return 0; } -static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - - type ^= CRYPTO_ALG_ASYNC; - mask &= CRYPTO_ALG_ASYNC; - if (type & mask) - return crypto_init_blkcipher_ops_sync(tfm); - else - return crypto_init_blkcipher_ops_async(tfm); -} - static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); + __attribute_used__; static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) { seq_printf(m, "type : blkcipher\n"); diff --git a/trunk/crypto/cbc.c b/trunk/crypto/cbc.c index 1f2649e13b42..136fea7e7000 100644 --- a/trunk/crypto/cbc.c +++ b/trunk/crypto/cbc.c @@ -275,18 +275,13 @@ static void crypto_cbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb) +static struct crypto_instance *crypto_cbc_alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); - if (err) - return ERR_PTR(err); - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/crypto/cryptd.c b/trunk/crypto/cryptd.c deleted file mode 100644 index 3ff4e1f0f032..000000000000 --- a/trunk/crypto/cryptd.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Software async crypto daemon. - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CRYPTD_MAX_QLEN 100 - -struct cryptd_state { - spinlock_t lock; - struct mutex mutex; - struct crypto_queue queue; - struct task_struct *task; -}; - -struct cryptd_instance_ctx { - struct crypto_spawn spawn; - struct cryptd_state *state; -}; - -struct cryptd_blkcipher_ctx { - struct crypto_blkcipher *child; -}; - -struct cryptd_blkcipher_request_ctx { - crypto_completion_t complete; -}; - - -static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm) -{ - struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); - return ictx->state; -} - -static int cryptd_blkcipher_setkey(struct crypto_ablkcipher *parent, - const u8 *key, unsigned int keylen) -{ - struct cryptd_blkcipher_ctx *ctx = crypto_ablkcipher_ctx(parent); - struct crypto_blkcipher *child = ctx->child; - int err; - - crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_blkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) & - CRYPTO_TFM_REQ_MASK); - err = crypto_blkcipher_setkey(child, key, keylen); - crypto_ablkcipher_set_flags(parent, crypto_blkcipher_get_flags(child) & - CRYPTO_TFM_RES_MASK); - return err; -} - -static void cryptd_blkcipher_crypt(struct ablkcipher_request *req, - struct crypto_blkcipher *child, - int err, - int (*crypt)(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int len)) -{ - struct cryptd_blkcipher_request_ctx *rctx; - struct blkcipher_desc desc; - - rctx = ablkcipher_request_ctx(req); - - if (unlikely(err == -EINPROGRESS)) { - rctx->complete(&req->base, err); - return; - } - - desc.tfm = child; - desc.info = req->info; - desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - err = crypt(&desc, req->dst, req->src, req->nbytes); - - req->base.complete = rctx->complete; - - local_bh_disable(); - req->base.complete(&req->base, err); - local_bh_enable(); -} - -static void cryptd_blkcipher_encrypt(struct crypto_async_request *req, int err) -{ - struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm); - struct crypto_blkcipher *child = ctx->child; - - cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err, - crypto_blkcipher_crt(child)->encrypt); -} - -static void cryptd_blkcipher_decrypt(struct crypto_async_request *req, int err) -{ - struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm); - struct crypto_blkcipher *child = ctx->child; - - cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err, - crypto_blkcipher_crt(child)->decrypt); -} - -static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req, - crypto_completion_t complete) -{ - struct cryptd_blkcipher_request_ctx *rctx = ablkcipher_request_ctx(req); - struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); - struct cryptd_state *state = - cryptd_get_state(crypto_ablkcipher_tfm(tfm)); - int err; - - rctx->complete = req->base.complete; - req->base.complete = complete; - - spin_lock_bh(&state->lock); - err = ablkcipher_enqueue_request(crypto_ablkcipher_alg(tfm), req); - spin_unlock_bh(&state->lock); - - wake_up_process(state->task); - return err; -} - -static int cryptd_blkcipher_encrypt_enqueue(struct ablkcipher_request *req) -{ - return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_encrypt); -} - -static int cryptd_blkcipher_decrypt_enqueue(struct ablkcipher_request *req) -{ - return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_decrypt); -} - -static int cryptd_blkcipher_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); - struct crypto_spawn *spawn = &ictx->spawn; - struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_blkcipher *cipher; - - cipher = crypto_spawn_blkcipher(spawn); - if (IS_ERR(cipher)) - return PTR_ERR(cipher); - - ctx->child = cipher; - tfm->crt_ablkcipher.reqsize = - sizeof(struct cryptd_blkcipher_request_ctx); - return 0; -} - -static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm) -{ - struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm); - struct cryptd_state *state = cryptd_get_state(tfm); - int active; - - mutex_lock(&state->mutex); - active = ablkcipher_tfm_in_queue(__crypto_ablkcipher_cast(tfm)); - mutex_unlock(&state->mutex); - - BUG_ON(active); - - crypto_free_blkcipher(ctx->child); -} - -static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, - struct cryptd_state *state) -{ - struct crypto_instance *inst; - struct cryptd_instance_ctx *ctx; - int err; - - inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); - if (IS_ERR(inst)) - goto out; - - err = -ENAMETOOLONG; - if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) - goto out_free_inst; - - ctx = crypto_instance_ctx(inst); - err = crypto_init_spawn(&ctx->spawn, alg, inst, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); - if (err) - goto out_free_inst; - - ctx->state = state; - - memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); - - inst->alg.cra_priority = alg->cra_priority + 50; - inst->alg.cra_blocksize = alg->cra_blocksize; - inst->alg.cra_alignmask = alg->cra_alignmask; - -out: - return inst; - -out_free_inst: - kfree(inst); - inst = ERR_PTR(err); - goto out; -} - -static struct crypto_instance *cryptd_alloc_blkcipher( - struct rtattr **tb, struct cryptd_state *state) -{ - struct crypto_instance *inst; - struct crypto_alg *alg; - - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); - if (IS_ERR(alg)) - return ERR_PTR(PTR_ERR(alg)); - - inst = cryptd_alloc_instance(alg, state); - if (IS_ERR(inst)) - goto out_put_alg; - - inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC; - inst->alg.cra_type = &crypto_ablkcipher_type; - - inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize; - inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize; - inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize; - - inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx); - - inst->alg.cra_init = cryptd_blkcipher_init_tfm; - inst->alg.cra_exit = cryptd_blkcipher_exit_tfm; - - inst->alg.cra_ablkcipher.setkey = cryptd_blkcipher_setkey; - inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue; - inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue; - - inst->alg.cra_ablkcipher.queue = &state->queue; - -out_put_alg: - crypto_mod_put(alg); - return inst; -} - -static struct cryptd_state state; - -static struct crypto_instance *cryptd_alloc(struct rtattr **tb) -{ - struct crypto_attr_type *algt; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return ERR_PTR(PTR_ERR(algt)); - - switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { - case CRYPTO_ALG_TYPE_BLKCIPHER: - return cryptd_alloc_blkcipher(tb, &state); - } - - return ERR_PTR(-EINVAL); -} - -static void cryptd_free(struct crypto_instance *inst) -{ - struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst); - - crypto_drop_spawn(&ctx->spawn); - kfree(inst); -} - -static struct crypto_template cryptd_tmpl = { - .name = "cryptd", - .alloc = cryptd_alloc, - .free = cryptd_free, - .module = THIS_MODULE, -}; - -static inline int cryptd_create_thread(struct cryptd_state *state, - int (*fn)(void *data), const char *name) -{ - spin_lock_init(&state->lock); - mutex_init(&state->mutex); - crypto_init_queue(&state->queue, CRYPTD_MAX_QLEN); - - state->task = kthread_create(fn, state, name); - if (IS_ERR(state->task)) - return PTR_ERR(state->task); - - return 0; -} - -static inline void cryptd_stop_thread(struct cryptd_state *state) -{ - BUG_ON(state->queue.qlen); - kthread_stop(state->task); -} - -static int cryptd_thread(void *data) -{ - struct cryptd_state *state = data; - int stop; - - do { - struct crypto_async_request *req, *backlog; - - mutex_lock(&state->mutex); - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_bh(&state->lock); - backlog = crypto_get_backlog(&state->queue); - req = crypto_dequeue_request(&state->queue); - spin_unlock_bh(&state->lock); - - stop = kthread_should_stop(); - - if (stop || req) { - __set_current_state(TASK_RUNNING); - if (req) { - if (backlog) - backlog->complete(backlog, - -EINPROGRESS); - req->complete(req, 0); - } - } - - mutex_unlock(&state->mutex); - - schedule(); - } while (!stop); - - return 0; -} - -static int __init cryptd_init(void) -{ - int err; - - err = cryptd_create_thread(&state, cryptd_thread, "cryptd"); - if (err) - return err; - - err = crypto_register_template(&cryptd_tmpl); - if (err) - kthread_stop(state.task); - - return err; -} - -static void __exit cryptd_exit(void) -{ - cryptd_stop_thread(&state); - crypto_unregister_template(&cryptd_tmpl); -} - -module_init(cryptd_init); -module_exit(cryptd_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Software async crypto daemon"); diff --git a/trunk/crypto/cryptomgr.c b/trunk/crypto/cryptomgr.c index 6958ea83ee44..2ebffb84f1d9 100644 --- a/trunk/crypto/cryptomgr.c +++ b/trunk/crypto/cryptomgr.c @@ -14,24 +14,17 @@ #include #include #include -#include #include #include #include #include #include +#include #include "internal.h" struct cryptomgr_param { - struct task_struct *thread; - - struct rtattr *tb[CRYPTOA_MAX]; - - struct { - struct rtattr attr; - struct crypto_attr_type data; - } type; + struct work_struct work; struct { struct rtattr attr; @@ -39,15 +32,18 @@ struct cryptomgr_param { } alg; struct { + u32 type; + u32 mask; char name[CRYPTO_MAX_ALG_NAME]; } larval; char template[CRYPTO_MAX_ALG_NAME]; }; -static int cryptomgr_probe(void *data) +static void cryptomgr_probe(struct work_struct *work) { - struct cryptomgr_param *param = data; + struct cryptomgr_param *param = + container_of(work, struct cryptomgr_param, work); struct crypto_template *tmpl; struct crypto_instance *inst; int err; @@ -57,7 +53,7 @@ static int cryptomgr_probe(void *data) goto err; do { - inst = tmpl->alloc(param->tb); + inst = tmpl->alloc(¶m->alg, sizeof(param->alg)); if (IS_ERR(inst)) err = PTR_ERR(inst); else if ((err = crypto_register_instance(tmpl, inst))) @@ -71,11 +67,11 @@ static int cryptomgr_probe(void *data) out: kfree(param); - module_put_and_exit(0); + return; err: - crypto_larval_error(param->larval.name, param->type.data.type, - param->type.data.mask); + crypto_larval_error(param->larval.name, param->larval.type, + param->larval.mask); goto out; } @@ -86,12 +82,9 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) const char *p; unsigned int len; - if (!try_module_get(THIS_MODULE)) - goto err; - - param = kzalloc(sizeof(*param), GFP_KERNEL); + param = kmalloc(sizeof(*param), GFP_KERNEL); if (!param) - goto err_put_module; + goto err; for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) ; @@ -101,45 +94,32 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) goto err_free_param; memcpy(param->template, name, len); + param->template[len] = 0; name = p + 1; - len = 0; - for (p = name; *p; p++) { - for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++) - ; - - if (*p != ')') - goto err_free_param; - - len = p - name; - } + for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) + ; - if (!len || name[len + 1]) + len = p - name; + if (!len || *p != ')' || p[1]) goto err_free_param; - param->type.attr.rta_len = sizeof(param->type); - param->type.attr.rta_type = CRYPTOA_TYPE; - param->type.data.type = larval->alg.cra_flags; - param->type.data.mask = larval->mask; - param->tb[CRYPTOA_TYPE - 1] = ¶m->type.attr; - param->alg.attr.rta_len = sizeof(param->alg); param->alg.attr.rta_type = CRYPTOA_ALG; memcpy(param->alg.data.name, name, len); - param->tb[CRYPTOA_ALG - 1] = ¶m->alg.attr; + param->alg.data.name[len] = 0; memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); + param->larval.type = larval->alg.cra_flags; + param->larval.mask = larval->mask; - param->thread = kthread_run(cryptomgr_probe, param, "cryptomgr"); - if (IS_ERR(param->thread)) - goto err_free_param; + INIT_WORK(¶m->work, cryptomgr_probe); + schedule_work(¶m->work); return NOTIFY_STOP; err_free_param: kfree(param); -err_put_module: - module_put(THIS_MODULE); err: return NOTIFY_OK; } diff --git a/trunk/crypto/ecb.c b/trunk/crypto/ecb.c index 6310387a872c..839a0aed8c22 100644 --- a/trunk/crypto/ecb.c +++ b/trunk/crypto/ecb.c @@ -115,18 +115,13 @@ static void crypto_ecb_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb) +static struct crypto_instance *crypto_ecb_alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); - if (err) - return ERR_PTR(err); - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/crypto/hash.c b/trunk/crypto/hash.c index 4ccd22deef39..12c4514f3478 100644 --- a/trunk/crypto/hash.c +++ b/trunk/crypto/hash.c @@ -41,7 +41,7 @@ static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) } static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); + __attribute_used__; static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) { seq_printf(m, "type : hash\n"); diff --git a/trunk/crypto/hmac.c b/trunk/crypto/hmac.c index 8802fb6dd5a6..44187c5ee593 100644 --- a/trunk/crypto/hmac.c +++ b/trunk/crypto/hmac.c @@ -197,18 +197,13 @@ static void hmac_free(struct crypto_instance *inst) kfree(inst); } -static struct crypto_instance *hmac_alloc(struct rtattr **tb) +static struct crypto_instance *hmac_alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); - if (err) - return ERR_PTR(err); - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_HASH_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH, + CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/crypto/lrw.c b/trunk/crypto/lrw.c index 621095db28b3..b4105080ac7a 100644 --- a/trunk/crypto/lrw.c +++ b/trunk/crypto/lrw.c @@ -228,18 +228,13 @@ static void exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *alloc(struct rtattr **tb) +static struct crypto_instance *alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); - if (err) - return ERR_PTR(err); - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/crypto/michael_mic.c b/trunk/crypto/michael_mic.c index 9e917b8011b1..094397b48849 100644 --- a/trunk/crypto/michael_mic.c +++ b/trunk/crypto/michael_mic.c @@ -3,7 +3,7 @@ * * Michael MIC (IEEE 802.11i/TKIP) keyed digest * - * Copyright (c) 2004 Jouni Malinen + * Copyright (c) 2004 Jouni Malinen * * 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 @@ -173,4 +173,4 @@ module_exit(michael_mic_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Michael MIC"); -MODULE_AUTHOR("Jouni Malinen "); +MODULE_AUTHOR("Jouni Malinen "); diff --git a/trunk/crypto/pcbc.c b/trunk/crypto/pcbc.c index c3ed8a1c9f46..5174d7fdad6e 100644 --- a/trunk/crypto/pcbc.c +++ b/trunk/crypto/pcbc.c @@ -279,18 +279,13 @@ static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb) +static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); - if (err) - return ERR_PTR(err); - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/crypto/tcrypt.c b/trunk/crypto/tcrypt.c index f0aed0106adb..8eaa5aa210b0 100644 --- a/trunk/crypto/tcrypt.c +++ b/trunk/crypto/tcrypt.c @@ -57,11 +57,6 @@ #define ENCRYPT 1 #define DECRYPT 0 -struct tcrypt_result { - struct completion completion; - int err; -}; - static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; /* @@ -89,17 +84,6 @@ static void hexdump(unsigned char *buf, unsigned int len) printk("\n"); } -static void tcrypt_complete(struct crypto_async_request *req, int err) -{ - struct tcrypt_result *res = req->data; - - if (err == -EINPROGRESS) - return; - - res->err = err; - complete(&res->completion); -} - static void test_hash(char *algo, struct hash_testvec *template, unsigned int tcount) { @@ -219,14 +203,15 @@ static void test_cipher(char *algo, int enc, { unsigned int ret, i, j, k, temp; unsigned int tsize; + unsigned int iv_len; + unsigned int len; char *q; - struct crypto_ablkcipher *tfm; + struct crypto_blkcipher *tfm; char *key; struct cipher_testvec *cipher_tv; - struct ablkcipher_request *req; + struct blkcipher_desc desc; struct scatterlist sg[8]; const char *e; - struct tcrypt_result result; if (enc == ENCRYPT) e = "encryption"; @@ -247,24 +232,15 @@ static void test_cipher(char *algo, int enc, memcpy(tvmem, template, tsize); cipher_tv = (void *)tvmem; - init_completion(&result.completion); - - tfm = crypto_alloc_ablkcipher(algo, 0, 0); + tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { printk("failed to load transform for %s: %ld\n", algo, PTR_ERR(tfm)); return; } - - req = ablkcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) { - printk("failed to allocate request for %s\n", algo); - goto out; - } - - ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); + desc.tfm = tfm; + desc.flags = 0; j = 0; for (i = 0; i < tcount; i++) { @@ -273,17 +249,17 @@ static void test_cipher(char *algo, int enc, printk("test %u (%d bit key):\n", j, cipher_tv[i].klen * 8); - crypto_ablkcipher_clear_flags(tfm, ~0); + crypto_blkcipher_clear_flags(tfm, ~0); if (cipher_tv[i].wk) - crypto_ablkcipher_set_flags( + crypto_blkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = cipher_tv[i].key; - ret = crypto_ablkcipher_setkey(tfm, key, - cipher_tv[i].klen); + ret = crypto_blkcipher_setkey(tfm, key, + cipher_tv[i].klen); if (ret) { printk("setkey() failed flags=%x\n", - crypto_ablkcipher_get_flags(tfm)); + crypto_blkcipher_get_flags(tfm)); if (!cipher_tv[i].fail) goto out; @@ -292,28 +268,19 @@ static void test_cipher(char *algo, int enc, sg_set_buf(&sg[0], cipher_tv[i].input, cipher_tv[i].ilen); - ablkcipher_request_set_crypt(req, sg, sg, - cipher_tv[i].ilen, - cipher_tv[i].iv); + iv_len = crypto_blkcipher_ivsize(tfm); + if (iv_len) + crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv, + iv_len); + len = cipher_tv[i].ilen; ret = enc ? - crypto_ablkcipher_encrypt(req) : - crypto_ablkcipher_decrypt(req); + crypto_blkcipher_encrypt(&desc, sg, sg, len) : + crypto_blkcipher_decrypt(&desc, sg, sg, len); - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - ret = wait_for_completion_interruptible( - &result.completion); - if (!ret && !((ret = result.err))) { - INIT_COMPLETION(result.completion); - break; - } - /* fall through */ - default: - printk("%s () failed err=%d\n", e, -ret); + if (ret) { + printk("%s () failed flags=%x\n", e, + desc.flags); goto out; } @@ -336,17 +303,17 @@ static void test_cipher(char *algo, int enc, printk("test %u (%d bit key):\n", j, cipher_tv[i].klen * 8); - crypto_ablkcipher_clear_flags(tfm, ~0); + crypto_blkcipher_clear_flags(tfm, ~0); if (cipher_tv[i].wk) - crypto_ablkcipher_set_flags( + crypto_blkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = cipher_tv[i].key; - ret = crypto_ablkcipher_setkey(tfm, key, - cipher_tv[i].klen); + ret = crypto_blkcipher_setkey(tfm, key, + cipher_tv[i].klen); if (ret) { printk("setkey() failed flags=%x\n", - crypto_ablkcipher_get_flags(tfm)); + crypto_blkcipher_get_flags(tfm)); if (!cipher_tv[i].fail) goto out; @@ -362,28 +329,19 @@ static void test_cipher(char *algo, int enc, cipher_tv[i].tap[k]); } - ablkcipher_request_set_crypt(req, sg, sg, - cipher_tv[i].ilen, - cipher_tv[i].iv); + iv_len = crypto_blkcipher_ivsize(tfm); + if (iv_len) + crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv, + iv_len); + len = cipher_tv[i].ilen; ret = enc ? - crypto_ablkcipher_encrypt(req) : - crypto_ablkcipher_decrypt(req); + crypto_blkcipher_encrypt(&desc, sg, sg, len) : + crypto_blkcipher_decrypt(&desc, sg, sg, len); - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - ret = wait_for_completion_interruptible( - &result.completion); - if (!ret && !((ret = result.err))) { - INIT_COMPLETION(result.completion); - break; - } - /* fall through */ - default: - printk("%s () failed err=%d\n", e, -ret); + if (ret) { + printk("%s () failed flags=%x\n", e, + desc.flags); goto out; } @@ -402,8 +360,7 @@ static void test_cipher(char *algo, int enc, } out: - crypto_free_ablkcipher(tfm); - ablkcipher_request_free(req); + crypto_free_blkcipher(tfm); } static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p, @@ -875,7 +832,7 @@ static void test_available(void) while (*name) { printk("alg %s ", *name); - printk(crypto_has_alg(*name, 0, 0) ? + printk(crypto_has_alg(*name, 0, CRYPTO_ALG_ASYNC) ? "found\n" : "not found\n"); name++; } diff --git a/trunk/crypto/xcbc.c b/trunk/crypto/xcbc.c index 9f502b86e0ea..53e8ccbf0f5f 100644 --- a/trunk/crypto/xcbc.c +++ b/trunk/crypto/xcbc.c @@ -288,18 +288,12 @@ static void xcbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *xcbc_alloc(struct rtattr **tb) +static struct crypto_instance *xcbc_alloc(void *param, unsigned int len) { struct crypto_instance *inst; struct crypto_alg *alg; - int err; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); - if (err) - return ERR_PTR(err); - - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK); + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/trunk/drivers/Makefile b/trunk/drivers/Makefile index 26ca9031ea49..3a718f51350e 100644 --- a/trunk/drivers/Makefile +++ b/trunk/drivers/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_RTC_LIB) += rtc/ -obj-y += i2c/ +obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_PHONE) += telephony/ @@ -72,6 +72,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ +obj-$(CONFIG_IPATH_CORE) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ diff --git a/trunk/drivers/acpi/Kconfig b/trunk/drivers/acpi/Kconfig index 139f41f033d8..e2ce4a9c1c92 100644 --- a/trunk/drivers/acpi/Kconfig +++ b/trunk/drivers/acpi/Kconfig @@ -85,8 +85,8 @@ config ACPI_PROCFS depends on ACPI default y ---help--- - The Procfs interface for ACPI is made optional for backward compatibility. - As the same functions are duplicated in the sysfs interface + Procfs interface for ACPI is made optional for back-compatible. + As the same functions are duplicated in sysfs interface and this proc interface will be removed some time later, it's marked as deprecated. ( /proc/acpi/debug_layer && debug_level are deprecated by @@ -218,6 +218,43 @@ config ACPI_ASUS NOTE: This driver is deprecated and will probably be removed soon, use asus-laptop instead. +config ACPI_IBM + tristate "IBM ThinkPad Laptop Extras" + depends on X86 + select BACKLIGHT_CLASS_DEVICE + ---help--- + This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds + support for Fn-Fx key combinations, Bluetooth control, video + output switching, ThinkLight control, UltraBay eject and more. + For more information about this driver see + and . + + If you have an IBM ThinkPad laptop, say Y or M here. + +config ACPI_IBM_DOCK + bool "Legacy Docking Station Support" + depends on ACPI_IBM + depends on ACPI_DOCK=n + default n + ---help--- + Allows the ibm_acpi driver to handle docking station events. + This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will + allow locking and removing the laptop from the docking station, + but will not properly connect PCI devices. + + If you are not sure, say N here. + +config ACPI_IBM_BAY + bool "Legacy Removable Bay Support" + depends on ACPI_IBM + default y + ---help--- + Allows the ibm_acpi driver to handle removable bays. It will allow + disabling the device in the bay, and also generate notifications when + the bay lever is ejected or inserted. + + If you are not sure, say Y here. + config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on X86 @@ -351,10 +388,11 @@ config ACPI_HOTPLUG_MEMORY config ACPI_SBS tristate "Smart Battery System (EXPERIMENTAL)" - depends on X86 + depends on X86 && I2C depends on EXPERIMENTAL help This driver adds support for the Smart Battery System. + Depends on I2C (Device Drivers ---> I2C support) A "Smart Battery" is quite old and quite rare compared to today's ACPI "Control Method" battery. diff --git a/trunk/drivers/acpi/Makefile b/trunk/drivers/acpi/Makefile index d4336f1730e9..5956e9f64a8b 100644 --- a/trunk/drivers/acpi/Makefile +++ b/trunk/drivers/acpi/Makefile @@ -1,6 +1,6 @@ # # Makefile for the Linux ACPI interpreter -# +# export ACPI_CFLAGS @@ -32,17 +32,16 @@ obj-y += osl.o utils.o \ processor-objs += processor_core.o processor_throttling.o \ processor_idle.o processor_thermal.o ifdef CONFIG_CPU_FREQ -processor-objs += processor_perflib.o +processor-objs += processor_perflib.o endif obj-y += sleep/ obj-y += bus.o glue.o obj-y += scan.o -# Keep EC driver first. Initialization of others depend on it. -obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o +obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_BAY) += bay.o @@ -56,7 +55,8 @@ obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o +obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o -obj-$(CONFIG_ACPI_SBS) += sbs.o +obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o diff --git a/trunk/drivers/acpi/acpi_memhotplug.c b/trunk/drivers/acpi/acpi_memhotplug.c index e65628a03085..c26172671fd8 100644 --- a/trunk/drivers/acpi/acpi_memhotplug.c +++ b/trunk/drivers/acpi/acpi_memhotplug.c @@ -44,6 +44,11 @@ MODULE_AUTHOR("Naveen B S "); MODULE_DESCRIPTION("Hotplug Mem Driver"); MODULE_LICENSE("GPL"); +/* ACPI _STA method values */ +#define ACPI_MEMORY_STA_PRESENT (0x00000001UL) +#define ACPI_MEMORY_STA_ENABLED (0x00000002UL) +#define ACPI_MEMORY_STA_FUNCTIONAL (0x00000008UL) + /* Memory Device States */ #define MEMORY_INVALID_STATE 0 #define MEMORY_POWER_ON_STATE 1 @@ -199,9 +204,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device) * Check for device status. Device should be * present/enabled/functioning. */ - if (!((current_status & ACPI_STA_DEVICE_PRESENT) - && (current_status & ACPI_STA_DEVICE_ENABLED) - && (current_status & ACPI_STA_DEVICE_FUNCTIONING))) + if (!((current_status & ACPI_MEMORY_STA_PRESENT) + && (current_status & ACPI_MEMORY_STA_ENABLED) + && (current_status & ACPI_MEMORY_STA_FUNCTIONAL))) return -ENODEV; return 0; @@ -281,7 +286,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) return -ENODEV; /* Check for device status. Device should be disabled */ - if (current_status & ACPI_STA_DEVICE_ENABLED) + if (current_status & ACPI_MEMORY_STA_ENABLED) return -EINVAL; return 0; diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c index e5084ececb6f..dd49ea0d0ed3 100644 --- a/trunk/drivers/acpi/bus.c +++ b/trunk/drivers/acpi/bus.c @@ -103,9 +103,7 @@ int acpi_bus_get_status(struct acpi_device *device) else if (device->parent) device->status = device->parent->status; else - STRUCT_TO_INT(device->status) = - ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | - ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + STRUCT_TO_INT(device->status) = 0x0F; if (device->status.functional && !device->status.present) { printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " diff --git a/trunk/drivers/acpi/container.c b/trunk/drivers/acpi/container.c index 0dd3bf7c0ed1..0930d9413dfa 100644 --- a/trunk/drivers/acpi/container.c +++ b/trunk/drivers/acpi/container.c @@ -49,6 +49,8 @@ MODULE_AUTHOR("Anil S Keshavamurthy"); MODULE_DESCRIPTION("ACPI container driver"); MODULE_LICENSE("GPL"); +#define ACPI_STA_PRESENT (0x00000001) + static int acpi_container_add(struct acpi_device *device); static int acpi_container_remove(struct acpi_device *device, int type); @@ -73,13 +75,13 @@ static int is_device_present(acpi_handle handle) status = acpi_get_handle(handle, "_STA", &temp); if (ACPI_FAILURE(status)) - return 1; /* _STA not found, assume device present */ + return 1; /* _STA not found, assmue device present */ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_FAILURE(status)) return 0; /* Firmware error */ - return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT); + return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT); } /*******************************************************************/ diff --git a/trunk/drivers/acpi/dock.c b/trunk/drivers/acpi/dock.c index 4546bf873aea..54a697f9aa18 100644 --- a/trunk/drivers/acpi/dock.c +++ b/trunk/drivers/acpi/dock.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -668,23 +667,6 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, } DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); -/* - * show_dock_uid - read method for "uid" file in sysfs - */ -static ssize_t show_dock_uid(struct device *dev, - struct device_attribute *attr, char *buf) -{ - unsigned long lbuf; - acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); - if(ACPI_FAILURE(status)) { - return 0; - } - return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); -} -DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); - - - /** * dock_add - add a new dock station * @handle: the dock station handle @@ -733,13 +715,6 @@ static int dock_add(acpi_handle handle) kfree(dock_station); return ret; } - ret = device_create_file(&dock_device.dev, &dev_attr_uid); - if (ret) { - printk("Error %d adding sysfs file\n", ret); - platform_device_unregister(&dock_device); - kfree(dock_station); - return ret; - } /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, diff --git a/trunk/drivers/acpi/ec.c b/trunk/drivers/acpi/ec.c index e08cf98f504f..a802962ff2b4 100644 --- a/trunk/drivers/acpi/ec.c +++ b/trunk/drivers/acpi/ec.c @@ -1,8 +1,6 @@ /* - * ec.c - ACPI Embedded Controller Driver (v2.0) + * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $) * - * Copyright (C) 2006, 2007 Alexey Starikovskiy - * Copyright (C) 2006 Denis Sadykov * Copyright (C) 2004 Luming Yu * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -93,9 +91,9 @@ static struct acpi_driver acpi_ec_driver = { }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ -/* External interfaces use first EC only, so remember */ static struct acpi_ec { acpi_handle handle; + unsigned long uid; unsigned long gpe; unsigned long command_addr; unsigned long data_addr; @@ -103,8 +101,12 @@ static struct acpi_ec { struct mutex lock; atomic_t query_pending; atomic_t event_count; + atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ wait_queue_head_t wait; -} *boot_ec, *first_ec; +} *ec_ecdt; + +/* External interfaces use first EC only, so remember */ +static struct acpi_device *first_ec; /* -------------------------------------------------------------------------- Transaction Management @@ -171,6 +173,56 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count) return -ETIME; } +#ifdef ACPI_FUTURE_USAGE +/* + * Note: samsung nv5000 doesn't work with ec burst mode. + * http://bugzilla.kernel.org/show_bug.cgi?id=4980 + */ +int acpi_ec_enter_burst_mode(struct acpi_ec *ec) +{ + u8 tmp = 0; + u8 status = 0; + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + if (status) + goto end; + acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); + tmp = acpi_ec_read_data(ec); + if (tmp != 0x90) { /* Burst ACK byte */ + return -EINVAL; + } + } + + atomic_set(&ec->leaving_burst, 0); + return 0; + end: + ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); + return -1; +} + +int acpi_ec_leave_burst_mode(struct acpi_ec *ec) +{ + u8 status = 0; + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) { + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + if (status) + goto end; + acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); + acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); + } + atomic_set(&ec->leaving_burst, 1); + return 0; + end: + ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); + return -1; +} +#endif /* ACPI_FUTURE_USAGE */ + static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, const u8 * wdata, unsigned wdata_len, u8 * rdata, unsigned rdata_len) @@ -260,21 +312,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, return status; } -/* - * Note: samsung nv5000 doesn't work with ec burst mode. - * http://bugzilla.kernel.org/show_bug.cgi?id=4980 - */ -int acpi_ec_burst_enable(struct acpi_ec *ec) -{ - u8 d; - return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1); -} - -int acpi_ec_burst_disable(struct acpi_ec *ec) -{ - return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0); -} - static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) { int result; @@ -296,33 +333,18 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) /* * Externally callable EC access functions. For now, assume 1 EC only */ -int ec_burst_enable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_enable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_enable); - -int ec_burst_disable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_disable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_disable); - int ec_read(u8 addr, u8 * val) { + struct acpi_ec *ec; int err; u8 temp_data; if (!first_ec) return -ENODEV; - err = acpi_ec_read(first_ec, addr, &temp_data); + ec = acpi_driver_data(first_ec); + + err = acpi_ec_read(ec, addr, &temp_data); if (!err) { *val = temp_data; @@ -335,12 +357,15 @@ EXPORT_SYMBOL(ec_read); int ec_write(u8 addr, u8 val) { + struct acpi_ec *ec; int err; if (!first_ec) return -ENODEV; - err = acpi_ec_write(first_ec, addr, val); + ec = acpi_driver_data(first_ec); + + err = acpi_ec_write(ec, addr, val); return err; } @@ -351,10 +376,14 @@ int ec_transaction(u8 command, const u8 * wdata, unsigned wdata_len, u8 * rdata, unsigned rdata_len) { + struct acpi_ec *ec; + if (!first_ec) return -ENODEV; - return acpi_ec_transaction(first_ec, command, wdata, + ec = acpi_driver_data(first_ec); + + return acpi_ec_transaction(ec, command, wdata, wdata_len, rdata, rdata_len); } @@ -391,7 +420,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) static void acpi_ec_gpe_query(void *ec_cxt) { - struct acpi_ec *ec = ec_cxt; + struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; u8 value = 0; char object_name[8]; @@ -409,9 +438,8 @@ static u32 acpi_ec_gpe_handler(void *data) { acpi_status status = AE_OK; u8 value; - struct acpi_ec *ec = data; + struct acpi_ec *ec = (struct acpi_ec *)data; atomic_inc(&ec->event_count); - if (acpi_ec_mode == EC_INTR) { wake_up(&ec->wait); } @@ -454,7 +482,7 @@ acpi_ec_space_handler(u32 function, void *handler_context, void *region_context) { int result = 0; - struct acpi_ec *ec = handler_context; + struct acpi_ec *ec = NULL; u64 temp = *value; acpi_integer f_v = 0; int i = 0; @@ -466,6 +494,8 @@ acpi_ec_space_handler(u32 function, return AE_BAD_PARAMETER; } + ec = (struct acpi_ec *)handler_context; + next_byte: switch (function) { case ACPI_READ: @@ -521,16 +551,18 @@ static struct proc_dir_entry *acpi_ec_dir; static int acpi_ec_read_info(struct seq_file *seq, void *offset) { - struct acpi_ec *ec = seq->private; + struct acpi_ec *ec = (struct acpi_ec *)seq->private; if (!ec) goto end; - seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe); - seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n", - (unsigned)ec->command_addr, (unsigned)ec->data_addr); - seq_printf(seq, "use global lock:\t%s\n", + seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe); + seq_printf(seq, "ports: 0x%02x, 0x%02x\n", + (u32) ec->command_addr, (u32) ec->data_addr); + seq_printf(seq, "use global lock: %s\n", ec->global_lock ? "yes" : "no"); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + end: return 0; } @@ -587,122 +619,154 @@ static int acpi_ec_remove_fs(struct acpi_device *device) /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ -static acpi_status -ec_parse_io_ports(struct acpi_resource *resource, void *context); - -static acpi_status -ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval); - -static struct acpi_ec *make_acpi_ec(void) -{ - struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); - if (!ec) - return NULL; - - atomic_set(&ec->query_pending, 1); - atomic_set(&ec->event_count, 1); - mutex_init(&ec->lock); - init_waitqueue_head(&ec->wait); - - return ec; -} static int acpi_ec_add(struct acpi_device *device) { + int result = 0; acpi_status status = AE_OK; struct acpi_ec *ec = NULL; if (!device) return -EINVAL; + ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + ec->handle = device->handle; + ec->uid = -1; + mutex_init(&ec->lock); + atomic_set(&ec->query_pending, 0); + atomic_set(&ec->event_count, 1); + if (acpi_ec_mode == EC_INTR) { + atomic_set(&ec->leaving_burst, 1); + init_waitqueue_head(&ec->wait); + } strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); + acpi_driver_data(device) = ec; - ec = make_acpi_ec(); - if (!ec) - return -ENOMEM; + /* Use the global lock for all EC transactions? */ + acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock); - status = ec_parse_device(device->handle, 0, ec, NULL); - if (status != AE_CTRL_TERMINATE) { - kfree(ec); - return -EINVAL; + /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: + http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ + if (ec_ecdt) { + acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, + ACPI_ADR_SPACE_EC, + &acpi_ec_space_handler); + + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, + &acpi_ec_gpe_handler); + + kfree(ec_ecdt); } - /* Check if we found the boot EC */ - if (boot_ec) { - if (boot_ec->gpe == ec->gpe) { - /* We might have incorrect info for GL at boot time */ - mutex_lock(&boot_ec->lock); - boot_ec->global_lock = ec->global_lock; - mutex_unlock(&boot_ec->lock); - kfree(ec); - ec = boot_ec; - } - } else - first_ec = ec; - ec->handle = device->handle; - acpi_driver_data(device) = ec; + /* Get GPE bit assignment (EC events). */ + /* TODO: Add support for _GPE returning a package */ + status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Obtaining GPE bit assignment")); + result = -ENODEV; + goto end; + } - acpi_ec_add_fs(device); + result = acpi_ec_add_fs(device); + if (result) + goto end; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", acpi_device_name(device), acpi_device_bid(device), (u32) ec->gpe)); - return 0; + if (!first_ec) + first_ec = device; + + end: + if (result) + kfree(ec); + + return result; } static int acpi_ec_remove(struct acpi_device *device, int type) { - struct acpi_ec *ec; + struct acpi_ec *ec = NULL; if (!device) return -EINVAL; ec = acpi_driver_data(device); + acpi_ec_remove_fs(device); - acpi_driver_data(device) = NULL; - if (ec == first_ec) - first_ec = NULL; - /* Don't touch boot EC */ - if (boot_ec != ec) - kfree(ec); + kfree(ec); + return 0; } static acpi_status -ec_parse_io_ports(struct acpi_resource *resource, void *context) +acpi_ec_io_ports(struct acpi_resource *resource, void *context) { - struct acpi_ec *ec = context; + struct acpi_ec *ec = (struct acpi_ec *)context; - if (resource->type != ACPI_RESOURCE_TYPE_IO) + if (resource->type != ACPI_RESOURCE_TYPE_IO) { return AE_OK; + } /* * The first address region returned is the data port, and * the second address region returned is the status/command * port. */ - if (ec->data_addr == 0) + if (ec->data_addr == 0) { ec->data_addr = resource->data.io.minimum; - else if (ec->command_addr == 0) + } else if (ec->command_addr == 0) { ec->command_addr = resource->data.io.minimum; - else + } else { return AE_CTRL_TERMINATE; + } return AE_OK; } -static int ec_install_handlers(struct acpi_ec *ec) +static int acpi_ec_start(struct acpi_device *device) { - acpi_status status; + acpi_status status = AE_OK; + struct acpi_ec *ec = NULL; + + if (!device) + return -EINVAL; + + ec = acpi_driver_data(device); + + if (!ec) + return -EINVAL; + + /* + * Get I/O port addresses. Convert to GAS format. + */ + status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS, + acpi_ec_io_ports, ec); + if (ACPI_FAILURE(status) || ec->command_addr == 0) { + ACPI_EXCEPTION((AE_INFO, status, + "Error getting I/O port addresses")); + return -ENODEV; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", + ec->gpe, ec->command_addr, ec->data_addr)); + + /* + * Install GPE handler + */ status = acpi_install_gpe_handler(NULL, ec->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { return -ENODEV; - + } acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); @@ -715,49 +779,18 @@ static int ec_install_handlers(struct acpi_ec *ec) return -ENODEV; } - /* EC is fully operational, allow queries */ - atomic_set(&ec->query_pending, 0); - - return 0; -} - -static int acpi_ec_start(struct acpi_device *device) -{ - struct acpi_ec *ec; - - if (!device) - return -EINVAL; - - ec = acpi_driver_data(device); - - if (!ec) - return -EINVAL; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", - ec->gpe, ec->command_addr, ec->data_addr)); - - /* Boot EC is already working */ - if (ec == boot_ec) - return 0; - - return ec_install_handlers(ec); + return AE_OK; } static int acpi_ec_stop(struct acpi_device *device, int type) { - acpi_status status; - struct acpi_ec *ec; + acpi_status status = AE_OK; + struct acpi_ec *ec = NULL; if (!device) return -EINVAL; ec = acpi_driver_data(device); - if (!ec) - return -EINVAL; - - /* Don't touch boot EC */ - if (ec == boot_ec) - return 0; status = acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, @@ -772,67 +805,164 @@ static int acpi_ec_stop(struct acpi_device *device, int type) return 0; } -static acpi_status -ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) +static acpi_status __init +acpi_fake_ecdt_callback(acpi_handle handle, + u32 Level, void *context, void **retval) { acpi_status status; - struct acpi_ec *ec = context; + mutex_init(&ec_ecdt->lock); + atomic_set(&ec_ecdt->event_count, 1); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); + } status = acpi_walk_resources(handle, METHOD_NAME__CRS, - ec_parse_io_ports, ec); + acpi_ec_io_ports, ec_ecdt); if (ACPI_FAILURE(status)) return status; - /* Get GPE bit assignment (EC events). */ - /* TODO: Add support for _GPE returning a package */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); + ec_ecdt->uid = -1; + acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); + + status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe); if (ACPI_FAILURE(status)) return status; - - /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); - - ec->handle = handle; + ec_ecdt->global_lock = TRUE; + ec_ecdt->handle = handle; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", - ec->gpe, ec->command_addr, ec->data_addr)); + ec_ecdt->gpe, ec_ecdt->command_addr, + ec_ecdt->data_addr)); return AE_CTRL_TERMINATE; } -int __init acpi_ec_ecdt_probe(void) +/* + * Some BIOS (such as some from Gateway laptops) access EC region very early + * such as in BAT0._INI or EC._INI before an EC device is found and + * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily + * required, but if EC regison is accessed early, it is required. + * The routine tries to workaround the BIOS bug by pre-scan EC device + * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any + * op region (since _REG isn't invoked yet). The assumption is true for + * all systems found. + */ +static int __init acpi_ec_fake_ecdt(void) { - int ret; acpi_status status; - struct acpi_table_ecdt *ecdt_ptr; + int ret = 0; - boot_ec = make_acpi_ec(); - if (!boot_ec) - return -ENOMEM; - /* - * Generate a boot ec context - */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT")); + + ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); + if (!ec_ecdt) { + ret = -ENOMEM; + goto error; + } + + status = acpi_get_devices(ACPI_EC_HID, + acpi_fake_ecdt_callback, NULL, NULL); + if (ACPI_FAILURE(status)) { + kfree(ec_ecdt); + ec_ecdt = NULL; + ret = -ENODEV; + ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT")); + goto error; + } + return 0; + error: + return ret; +} + +static int __init acpi_ec_get_real_ecdt(void) +{ + acpi_status status; + struct acpi_table_ecdt *ecdt_ptr; status = acpi_get_table(ACPI_SIG_ECDT, 1, (struct acpi_table_header **)&ecdt_ptr); if (ACPI_FAILURE(status)) - goto error; + return -ENODEV; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); - boot_ec->command_addr = ecdt_ptr->control.address; - boot_ec->data_addr = ecdt_ptr->data.address; - boot_ec->gpe = ecdt_ptr->gpe; - boot_ec->handle = ACPI_ROOT_OBJECT; + /* + * Generate a temporary ec context to use until the namespace is scanned + */ + ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); + if (!ec_ecdt) + return -ENOMEM; + + mutex_init(&ec_ecdt->lock); + atomic_set(&ec_ecdt->event_count, 1); + if (acpi_ec_mode == EC_INTR) { + init_waitqueue_head(&ec_ecdt->wait); + } + ec_ecdt->command_addr = ecdt_ptr->control.address; + ec_ecdt->data_addr = ecdt_ptr->data.address; + ec_ecdt->gpe = ecdt_ptr->gpe; + /* use the GL just to be safe */ + ec_ecdt->global_lock = TRUE; + ec_ecdt->uid = ecdt_ptr->uid; + + status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle); + if (ACPI_FAILURE(status)) { + goto error; + } + + return 0; + error: + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); + kfree(ec_ecdt); + ec_ecdt = NULL; - ret = ec_install_handlers(boot_ec); - if (!ret) { - first_ec = boot_ec; + return -ENODEV; +} + +static int __initdata acpi_fake_ecdt_enabled; +int __init acpi_ec_ecdt_probe(void) +{ + acpi_status status; + int ret; + + ret = acpi_ec_get_real_ecdt(); + /* Try to make a fake ECDT */ + if (ret && acpi_fake_ecdt_enabled) { + ret = acpi_ec_fake_ecdt(); + } + + if (ret) return 0; + + /* + * Install GPE handler + */ + status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe, + ACPI_GPE_EDGE_TRIGGERED, + &acpi_ec_gpe_handler, ec_ecdt); + if (ACPI_FAILURE(status)) { + goto error; } + acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR); + + status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, + ACPI_ADR_SPACE_EC, + &acpi_ec_space_handler, + &acpi_ec_space_setup, + ec_ecdt); + if (ACPI_FAILURE(status)) { + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, + &acpi_ec_gpe_handler); + goto error; + } + + return 0; + error: - kfree(boot_ec); - boot_ec = NULL; + ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); + kfree(ec_ecdt); + ec_ecdt = NULL; return -ENODEV; } @@ -873,6 +1003,13 @@ static void __exit acpi_ec_exit(void) } #endif /* 0 */ +static int __init acpi_fake_ecdt_setup(char *str) +{ + acpi_fake_ecdt_enabled = 1; + return 1; +} + +__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup); static int __init acpi_ec_set_intr_mode(char *str) { int intr; @@ -880,8 +1017,12 @@ static int __init acpi_ec_set_intr_mode(char *str) if (!get_option(&str, &intr)) return 0; - acpi_ec_mode = (intr) ? EC_INTR : EC_POLL; - + if (intr) { + acpi_ec_mode = EC_INTR; + } else { + acpi_ec_mode = EC_POLL; + } + acpi_ec_driver.ops.add = acpi_ec_add; printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling"); return 1; diff --git a/trunk/drivers/acpi/i2c_ec.c b/trunk/drivers/acpi/i2c_ec.c new file mode 100644 index 000000000000..acab4a481897 --- /dev/null +++ b/trunk/drivers/acpi/i2c_ec.c @@ -0,0 +1,403 @@ +/* + * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $) + * + * Copyright (c) 2002, 2005 Ducrot Bruno + * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c_ec.h" + +#define xudelay(t) udelay(t) +#define xmsleep(t) msleep(t) + +#define ACPI_EC_HC_COMPONENT 0x00080000 +#define ACPI_EC_HC_CLASS "ec_hc_smbus" +#define ACPI_EC_HC_HID "ACPI0001" +#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus" + +#define _COMPONENT ACPI_EC_HC_COMPONENT + +ACPI_MODULE_NAME("i2c_ec"); + +static int acpi_ec_hc_add(struct acpi_device *device); +static int acpi_ec_hc_remove(struct acpi_device *device, int type); + +static struct acpi_driver acpi_ec_hc_driver = { + .name = "i2c_ec", + .class = ACPI_EC_HC_CLASS, + .ids = ACPI_EC_HC_HID, + .ops = { + .add = acpi_ec_hc_add, + .remove = acpi_ec_hc_remove, + }, +}; + +/* Various bit mask for EC_SC (R) */ +#define OBF 0x01 +#define IBF 0x02 +#define CMD 0x08 +#define BURST 0x10 +#define SCI_EVT 0x20 +#define SMI_EVT 0x40 + +/* Commands for EC_SC (W) */ +#define RD_EC 0x80 +#define WR_EC 0x81 +#define BE_EC 0x82 +#define BD_EC 0x83 +#define QR_EC 0x84 + +/* + * ACPI 2.0 chapter 13 SMBus 2.0 EC register model + */ + +#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */ +#define ACPI_EC_SMB_STS 0x01 /* status */ +#define ACPI_EC_SMB_ADDR 0x02 /* address */ +#define ACPI_EC_SMB_CMD 0x03 /* command */ +#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */ +#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */ +#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */ +#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */ + +#define ACPI_EC_SMB_STS_DONE 0x80 +#define ACPI_EC_SMB_STS_ALRM 0x40 +#define ACPI_EC_SMB_STS_RES 0x20 +#define ACPI_EC_SMB_STS_STATUS 0x1f + +#define ACPI_EC_SMB_STATUS_OK 0x00 +#define ACPI_EC_SMB_STATUS_FAIL 0x07 +#define ACPI_EC_SMB_STATUS_DNAK 0x10 +#define ACPI_EC_SMB_STATUS_DERR 0x11 +#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12 +#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13 +#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17 +#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18 +#define ACPI_EC_SMB_STATUS_NOTSUP 0x19 +#define ACPI_EC_SMB_STATUS_BUSY 0x1A +#define ACPI_EC_SMB_STATUS_PEC 0x1F + +#define ACPI_EC_SMB_PRTCL_WRITE 0x00 +#define ACPI_EC_SMB_PRTCL_READ 0x01 +#define ACPI_EC_SMB_PRTCL_QUICK 0x02 +#define ACPI_EC_SMB_PRTCL_BYTE 0x04 +#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06 +#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08 +#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a +#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c +#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d +#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a +#define ACPI_EC_SMB_PRTCL_PEC 0x80 + +/* Length of pre/post transaction sleep (msec) */ +#define ACPI_EC_SMB_TRANSACTION_SLEEP 1 +#define ACPI_EC_SMB_ACCESS_SLEEP1 1 +#define ACPI_EC_SMB_ACCESS_SLEEP2 10 + +static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data) +{ + u8 val; + int err; + + err = ec_read(smbus->base + address, &val); + if (!err) { + *data = val; + } + xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP); + return (err); +} + +static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data) +{ + int err; + + err = ec_write(smbus->base + address, data); + return (err); +} + +static int +acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) +{ + struct acpi_ec_smbus *smbus = adap->algo_data; + unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 }; + int i; + + if (read_write == I2C_SMBUS_READ) { + protocol = ACPI_EC_SMB_PRTCL_READ; + } else { + protocol = ACPI_EC_SMB_PRTCL_WRITE; + } + pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0; + + switch (size) { + + case I2C_SMBUS_QUICK: + protocol |= ACPI_EC_SMB_PRTCL_QUICK; + read_write = I2C_SMBUS_WRITE; + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) { + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte); + } + protocol |= ACPI_EC_SMB_PRTCL_BYTE; + break; + + case I2C_SMBUS_BYTE_DATA: + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte); + } + protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA; + break; + + case I2C_SMBUS_WORD_DATA: + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, + data->word >> 8); + } + protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec; + break; + + case I2C_SMBUS_BLOCK_DATA: + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + len = min_t(u8, data->block[0], 32); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len); + for (i = 0; i < len; i++) + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i, + data->block[i + 1]); + } + protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec; + break; + + case I2C_SMBUS_I2C_BLOCK_DATA: + len = min_t(u8, data->block[0], 32); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len); + if (read_write == I2C_SMBUS_WRITE) { + for (i = 0; i < len; i++) { + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i, + data->block[i + 1]); + } + } + protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA; + break; + + case I2C_SMBUS_PROC_CALL: + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8); + protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + case I2C_SMBUS_BLOCK_PROC_CALL: + protocol |= pec; + len = min_t(u8, data->block[0], 31); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len); + for (i = 0; i < len; i++) + acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i, + data->block[i + 1]); + protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec; + read_write = I2C_SMBUS_READ; + break; + + default: + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: " + "Unsupported transaction %d\n", size)); + return (-1); + } + + acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1); + acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol); + + acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0); + + if (~temp[0] & ACPI_EC_SMB_STS_DONE) { + xudelay(500); + acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0); + } + if (~temp[0] & ACPI_EC_SMB_STS_DONE) { + xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2); + acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0); + } + if ((~temp[0] & ACPI_EC_SMB_STS_DONE) + || (temp[0] & ACPI_EC_SMB_STS_STATUS)) { + return (-1); + } + + if (read_write == I2C_SMBUS_WRITE) { + return (0); + } + + switch (size) { + + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte); + break; + + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0); + acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1); + data->word = (temp[1] << 8) | temp[0]; + break; + + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + len = 0; + acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len); + len = min_t(u8, len, 32); + case I2C_SMBUS_I2C_BLOCK_DATA: + for (i = 0; i < len; i++) + acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i, + data->block + i + 1); + data->block[0] = len; + break; + } + + return (0); +} + +static u32 acpi_ec_smb_func(struct i2c_adapter *adapter) +{ + + return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC); +} + +static const struct i2c_algorithm acpi_ec_smbus_algorithm = { + .smbus_xfer = acpi_ec_smb_access, + .functionality = acpi_ec_smb_func, +}; + +static int acpi_ec_hc_add(struct acpi_device *device) +{ + int status; + unsigned long val; + struct acpi_ec_hc *ec_hc; + struct acpi_ec_smbus *smbus; + + if (!device) { + return -EINVAL; + } + + ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL); + if (!ec_hc) { + return -ENOMEM; + } + + smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL); + if (!smbus) { + kfree(ec_hc); + return -ENOMEM; + } + + ec_hc->handle = device->handle; + strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS); + acpi_driver_data(device) = ec_hc; + + status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n")); + kfree(ec_hc); + kfree(smbus); + return -EIO; + } + + smbus->ec = acpi_driver_data(device->parent); + smbus->base = (val & 0xff00ull) >> 8; + smbus->alert = val & 0xffull; + + smbus->adapter.owner = THIS_MODULE; + smbus->adapter.algo = &acpi_ec_smbus_algorithm; + smbus->adapter.algo_data = smbus; + smbus->adapter.dev.parent = &device->dev; + + if (i2c_add_adapter(&smbus->adapter)) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "EC SMBus adapter: Failed to register adapter\n")); + kfree(smbus); + kfree(ec_hc); + return -EIO; + } + + ec_hc->smbus = smbus; + + printk(KERN_INFO PREFIX "%s [%s]\n", + acpi_device_name(device), acpi_device_bid(device)); + + return AE_OK; +} + +static int acpi_ec_hc_remove(struct acpi_device *device, int type) +{ + struct acpi_ec_hc *ec_hc; + + if (!device) { + return -EINVAL; + } + ec_hc = acpi_driver_data(device); + + i2c_del_adapter(&ec_hc->smbus->adapter); + kfree(ec_hc->smbus); + kfree(ec_hc); + + return AE_OK; +} + +static int __init acpi_ec_hc_init(void) +{ + int result; + + result = acpi_bus_register_driver(&acpi_ec_hc_driver); + if (result < 0) { + return -ENODEV; + } + return 0; +} + +static void __exit acpi_ec_hc_exit(void) +{ + acpi_bus_unregister_driver(&acpi_ec_hc_driver); +} + +struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device) +{ + return acpi_driver_data(device->parent); +} + +EXPORT_SYMBOL(acpi_get_ec_hc); + +module_init(acpi_ec_hc_init); +module_exit(acpi_ec_hc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ducrot Bruno"); +MODULE_DESCRIPTION("ACPI EC SMBus driver"); diff --git a/trunk/drivers/acpi/i2c_ec.h b/trunk/drivers/acpi/i2c_ec.h new file mode 100644 index 000000000000..7c53fb732d61 --- /dev/null +++ b/trunk/drivers/acpi/i2c_ec.h @@ -0,0 +1,23 @@ +/* + * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $) + * + * Copyright (c) 2002, 2005 Ducrot Bruno + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + */ + +struct acpi_ec_smbus { + struct i2c_adapter adapter; + union acpi_ec *ec; + int base; + int alert; +}; + +struct acpi_ec_hc { + acpi_handle handle; + struct acpi_ec_smbus *smbus; +}; + +struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device); diff --git a/trunk/drivers/acpi/ibm_acpi.c b/trunk/drivers/acpi/ibm_acpi.c new file mode 100644 index 000000000000..dc1096608f43 --- /dev/null +++ b/trunk/drivers/acpi/ibm_acpi.c @@ -0,0 +1,2798 @@ +/* + * ibm_acpi.c - IBM ThinkPad ACPI Extras + * + * + * Copyright (C) 2004-2005 Borislav Deianov + * Copyright (C) 2006 Henrique de Moraes Holschuh + * + * 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 + */ + +#define IBM_VERSION "0.13" + +/* + * Changelog: + * + * 2006-11-22 0.13 new maintainer + * changelog now lives in git commit history, and will + * not be updated further in-file. + * + * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels + * 2005-03-17 0.11 support for 600e, 770x + * thanks to Jamie Lentin + * support for 770e, G41 + * G40 and G41 don't have a thinklight + * temperatures no longer experimental + * experimental brightness control + * experimental volume control + * experimental fan enable/disable + * 2005-01-16 0.10 fix module loading on R30, R31 + * 2005-01-16 0.9 support for 570, R30, R31 + * ultrabay support on A22p, A3x + * limit arg for cmos, led, beep, drop experimental status + * more capable led control on A21e, A22p, T20-22, X20 + * experimental temperatures and fan speed + * experimental embedded controller register dump + * mark more functions as __init, drop incorrect __exit + * use MODULE_VERSION + * thanks to Henrik Brix Andersen + * fix parameter passing on module loading + * thanks to Rusty Russell + * thanks to Jim Radford + * 2004-11-08 0.8 fix init error case, don't return from a macro + * thanks to Chris Wright + * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 + * fix led control on A21e + * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device + * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 + * proc file format changed + * video_switch command + * experimental cmos control + * experimental led control + * experimental acpi sounds + * 2004-09-16 0.4 support for module parameters + * hotkey mask can be prefixed by 0x + * video output switching + * video expansion control + * ultrabay eject support + * removed lcd brightness/on/off control, didn't work + * 2004-08-17 0.3 support for R40 + * lcd off, brightness control + * thinklight on/off + * 2004-08-14 0.2 support for T series, X20 + * bluetooth enable/disable + * hotkey events disabled by default + * removed fan control, currently useless + * 2004-08-09 0.1 initial release, support for X series + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define IBM_NAME "ibm" +#define IBM_DESC "IBM ThinkPad ACPI Extras" +#define IBM_FILE "ibm_acpi" +#define IBM_URL "http://ibm-acpi.sf.net/" + +MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); +MODULE_DESCRIPTION(IBM_DESC); +MODULE_VERSION(IBM_VERSION); +MODULE_LICENSE("GPL"); + +#define IBM_DIR IBM_NAME + +#define IBM_LOG IBM_FILE ": " +#define IBM_ERR KERN_ERR IBM_LOG +#define IBM_NOTICE KERN_NOTICE IBM_LOG +#define IBM_INFO KERN_INFO IBM_LOG +#define IBM_DEBUG KERN_DEBUG IBM_LOG + +#define IBM_MAX_ACPI_ARGS 3 + +#define __unused __attribute__ ((unused)) + +static int experimental; +module_param(experimental, int, 0); + +static acpi_handle root_handle = NULL; + +#define IBM_HANDLE(object, parent, paths...) \ + static acpi_handle object##_handle; \ + static acpi_handle *object##_parent = &parent##_handle; \ + static char *object##_path; \ + static char *object##_paths[] = { paths } + +IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ + "\\_SB.PCI.ISA.EC", /* 570 */ + "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ + "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ + "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ + "\\_SB.PCI0.ICH3.EC0", /* R31 */ + "\\_SB.PCI0.LPC.EC", /* all others */ + ); + +IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ + "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ + "\\_SB.PCI0.VID0", /* 770e */ + "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ + "\\_SB.PCI0.AGP.VID", /* all others */ + ); /* R30, R31 */ + +IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ + +IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ + "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ + "\\CMS", /* R40, R40e */ + ); /* all others */ +#ifdef CONFIG_ACPI_IBM_DOCK +IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ + "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ + "\\_SB.PCI0.PCI1.DOCK", /* all others */ + "\\_SB.PCI.ISA.SLCE", /* 570 */ + ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ +#endif +#ifdef CONFIG_ACPI_IBM_BAY +IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ + "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ + "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ + "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ + ); /* A21e, R30, R31 */ + +IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ + "_EJ0", /* all others */ + ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ + +IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ + "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ + ); /* all others */ + +IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ + "_EJ0", /* 770x */ + ); /* all others */ +#endif /* CONFIG_ACPI_IBM_BAY */ + +/* don't list other alternatives as we install a notify handler on the 570 */ +IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ + +IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ + "^HKEY", /* R30, R31 */ + "HKEY", /* all others */ + ); /* 570 */ + +IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ +IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ + +IBM_HANDLE(led, ec, "SLED", /* 570 */ + "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + "LED", /* all others */ + ); /* R30, R31 */ + +IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ +IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ +IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ +IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ + +IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ + "\\FSPD", /* 600e/x, 770e, 770x */ + ); /* all others */ + +IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ + "JFNS", /* 770x-JL */ + ); /* all others */ + +#define IBM_HKEY_HID "IBM0068" +#define IBM_PCI_HID "PNP0A03" + +enum thermal_access_mode { + IBMACPI_THERMAL_NONE = 0, /* No thermal support */ + IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ +}; + +#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +struct ibm_thermal_sensors_struct { + s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; +}; + +/* + * FAN ACCESS MODES + * + * IBMACPI_FAN_RD_ACPI_GFAN: + * ACPI GFAN method: returns fan level + * + * see IBMACPI_FAN_WR_ACPI_SFAN + * EC 0x2f not available if GFAN exists + * + * IBMACPI_FAN_WR_ACPI_SFAN: + * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) + * + * EC 0x2f might be available *for reading*, but never for writing. + * + * IBMACPI_FAN_WR_TPEC: + * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported + * on almost all ThinkPads + * + * Fan speed changes of any sort (including those caused by the + * disengaged mode) are usually done slowly by the firmware as the + * maximum ammount of fan duty cycle change per second seems to be + * limited. + * + * Reading is not available if GFAN exists. + * Writing is not available if SFAN exists. + * + * Bits + * 7 automatic mode engaged; + * (default operation mode of the ThinkPad) + * fan level is ignored in this mode. + * 6 disengage mode (takes precedence over bit 7); + * not available on all thinkpads. May disable + * the tachometer, and speeds up fan to 100% duty-cycle, + * which speeds it up far above the standard RPM + * levels. It is not impossible that it could cause + * hardware damage. + * 5-3 unused in some models. Extra bits for fan level + * in others, but still useless as all values above + * 7 map to the same speed as level 7 in these models. + * 2-0 fan level (0..7 usually) + * 0x00 = stop + * 0x07 = max (set when temperatures critical) + * Some ThinkPads may have other levels, see + * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41) + * + * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at + * boot. Apparently the EC does not intialize it, so unless ACPI DSDT + * does so, its initial value is meaningless (0x07). + * + * For firmware bugs, refer to: + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues + * + * ---- + * + * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): + * Main fan tachometer reading (in RPM) + * + * This register is present on all ThinkPads with a new-style EC, and + * it is known not to be present on the A21m/e, and T22, as there is + * something else in offset 0x84 according to the ACPI DSDT. Other + * ThinkPads from this same time period (and earlier) probably lack the + * tachometer as well. + * + * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare + * was never fixed by IBM to report the EC firmware version string + * probably support the tachometer (like the early X models), so + * detecting it is quite hard. We need more data to know for sure. + * + * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings + * might result. + * + * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this + * register is not invalidated in ThinkPads that disable tachometer + * readings. Thus, the tachometer readings go stale. + * + * For firmware bugs, refer to: + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues + * + * IBMACPI_FAN_WR_ACPI_FANS: + * ThinkPad X31, X40, X41. Not available in the X60. + * + * FANS ACPI handle: takes three arguments: low speed, medium speed, + * high speed. ACPI DSDT seems to map these three speeds to levels + * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH + * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") + * + * The speeds are stored on handles + * (FANA:FAN9), (FANC:FANB), (FANE:FAND). + * + * There are three default speed sets, acessible as handles: + * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H + * + * ACPI DSDT switches which set is in use depending on various + * factors. + * + * IBMACPI_FAN_WR_TPEC is also available and should be used to + * command the fan. The X31/X40/X41 seems to have 8 fan levels, + * but the ACPI tables just mention level 7. + */ + +enum fan_status_access_mode { + IBMACPI_FAN_NONE = 0, /* No fan status or control */ + IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ +}; + +enum fan_control_access_mode { + IBMACPI_FAN_WR_NONE = 0, /* No fan control */ + IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ +}; + +enum fan_control_commands { + IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + * and also watchdog cmd */ +}; + +enum { /* Fan control constants */ + fan_status_offset = 0x2f, /* EC register 0x2f */ + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) + * 0x84 must be read before 0x85 */ + + IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer + * disengaged */ + IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan + * control */ +}; + +static char *ibm_thinkpad_ec_found = NULL; + +struct ibm_struct { + char *name; + char param[32]; + + char *hid; + struct acpi_driver *driver; + + int (*init) (void); + int (*read) (char *); + int (*write) (char *); + void (*exit) (void); + + void (*notify) (struct ibm_struct *, u32); + acpi_handle *handle; + int type; + struct acpi_device *device; + + int driver_registered; + int proc_created; + int init_called; + int notify_installed; + + int experimental; +}; + +static struct proc_dir_entry *proc_dir = NULL; + +static struct backlight_device *ibm_backlight_device = NULL; + +#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") +#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") +#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) + +static int acpi_evalf(acpi_handle handle, + void *res, char *method, char *fmt, ...) +{ + char *fmt0 = fmt; + struct acpi_object_list params; + union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; + struct acpi_buffer result, *resultp; + union acpi_object out_obj; + acpi_status status; + va_list ap; + char res_type; + int success; + int quiet; + + if (!*fmt) { + printk(IBM_ERR "acpi_evalf() called with empty format\n"); + return 0; + } + + if (*fmt == 'q') { + quiet = 1; + fmt++; + } else + quiet = 0; + + res_type = *(fmt++); + + params.count = 0; + params.pointer = &in_objs[0]; + + va_start(ap, fmt); + while (*fmt) { + char c = *(fmt++); + switch (c) { + case 'd': /* int */ + in_objs[params.count].integer.value = va_arg(ap, int); + in_objs[params.count++].type = ACPI_TYPE_INTEGER; + break; + /* add more types as needed */ + default: + printk(IBM_ERR "acpi_evalf() called " + "with invalid format character '%c'\n", c); + return 0; + } + } + va_end(ap); + + if (res_type != 'v') { + result.length = sizeof(out_obj); + result.pointer = &out_obj; + resultp = &result; + } else + resultp = NULL; + + status = acpi_evaluate_object(handle, method, ¶ms, resultp); + + switch (res_type) { + case 'd': /* int */ + if (res) + *(int *)res = out_obj.integer.value; + success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; + break; + case 'v': /* void */ + success = status == AE_OK; + break; + /* add more types as needed */ + default: + printk(IBM_ERR "acpi_evalf() called " + "with invalid format character '%c'\n", res_type); + return 0; + } + + if (!success && !quiet) + printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", + method, fmt0, status); + + return success; +} + +static void __unused acpi_print_int(acpi_handle handle, char *method) +{ + int i; + + if (acpi_evalf(handle, &i, method, "d")) + printk(IBM_INFO "%s = 0x%x\n", method, i); + else + printk(IBM_ERR "error calling %s\n", method); +} + +static char *next_cmd(char **cmds) +{ + char *start = *cmds; + char *end; + + while ((end = strchr(start, ',')) && end == start) + start = end + 1; + + if (!end) + return NULL; + + *end = 0; + *cmds = end + 1; + return start; +} + +static int ibm_acpi_driver_init(void) +{ + printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); + printk(IBM_INFO "%s\n", IBM_URL); + + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + + return 0; +} + +static int driver_read(char *p) +{ + int len = 0; + + len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); + len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); + + return len; +} + +static int hotkey_supported; +static int hotkey_mask_supported; +static int hotkey_orig_status; +static int hotkey_orig_mask; + +static int hotkey_get(int *status, int *mask) +{ + if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) + return 0; + + if (hotkey_mask_supported) + if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) + return 0; + + return 1; +} + +static int hotkey_set(int status, int mask) +{ + int i; + + if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) + return 0; + + if (hotkey_mask_supported) + for (i = 0; i < 32; i++) { + int bit = ((1 << i) & mask) != 0; + if (!acpi_evalf(hkey_handle, + NULL, "MHKM", "vdd", i + 1, bit)) + return 0; + } + + return 1; +} + +static int hotkey_init(void) +{ + /* hotkey not supported on 570 */ + hotkey_supported = hkey_handle != NULL; + + if (hotkey_supported) { + /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + A30, R30, R31, T20-22, X20-21, X22-24 */ + hotkey_mask_supported = + acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); + + if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask)) + return -ENODEV; + } + + return 0; +} + +static int hotkey_read(char *p) +{ + int status, mask; + int len = 0; + + if (!hotkey_supported) { + len += sprintf(p + len, "status:\t\tnot supported\n"); + return len; + } + + if (!hotkey_get(&status, &mask)) + return -EIO; + + len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); + if (hotkey_mask_supported) { + len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); + len += sprintf(p + len, + "commands:\tenable, disable, reset, \n"); + } else { + len += sprintf(p + len, "mask:\t\tnot supported\n"); + len += sprintf(p + len, "commands:\tenable, disable, reset\n"); + } + + return len; +} + +static int hotkey_write(char *buf) +{ + int status, mask; + char *cmd; + int do_cmd = 0; + + if (!hotkey_supported) + return -ENODEV; + + if (!hotkey_get(&status, &mask)) + return -EIO; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) { + status = 1; + } else if (strlencmp(cmd, "disable") == 0) { + status = 0; + } else if (strlencmp(cmd, "reset") == 0) { + status = hotkey_orig_status; + mask = hotkey_orig_mask; + } else if (sscanf(cmd, "0x%x", &mask) == 1) { + /* mask set */ + } else if (sscanf(cmd, "%x", &mask) == 1) { + /* mask set */ + } else + return -EINVAL; + do_cmd = 1; + } + + if (do_cmd && !hotkey_set(status, mask)) + return -EIO; + + return 0; +} + +static void hotkey_exit(void) +{ + if (hotkey_supported) + hotkey_set(hotkey_orig_status, hotkey_orig_mask); +} + +static void hotkey_notify(struct ibm_struct *ibm, u32 event) +{ + int hkey; + + if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) + acpi_bus_generate_event(ibm->device, event, hkey); + else { + printk(IBM_ERR "unknown hotkey event %d\n", event); + acpi_bus_generate_event(ibm->device, event, 0); + } +} + +static int bluetooth_supported; + +static int bluetooth_init(void) +{ + /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ + bluetooth_supported = hkey_handle && + acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); + + return 0; +} + +static int bluetooth_status(void) +{ + int status; + + if (!bluetooth_supported || + !acpi_evalf(hkey_handle, &status, "GBDC", "d")) + status = 0; + + return status; +} + +static int bluetooth_read(char *p) +{ + int len = 0; + int status = bluetooth_status(); + + if (!bluetooth_supported) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else if (!(status & 1)) + len += sprintf(p + len, "status:\t\tnot installed\n"); + else { + len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1)); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + + return len; +} + +static int bluetooth_write(char *buf) +{ + int status = bluetooth_status(); + char *cmd; + int do_cmd = 0; + + if (!bluetooth_supported) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) { + status |= 2; + } else if (strlencmp(cmd, "disable") == 0) { + status &= ~2; + } else + return -EINVAL; + do_cmd = 1; + } + + if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) + return -EIO; + + return 0; +} + +static int wan_supported; + +static int wan_init(void) +{ + wan_supported = hkey_handle && + acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); + + return 0; +} + +static int wan_status(void) +{ + int status; + + if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d")) + status = 0; + + return status; +} + +static int wan_read(char *p) +{ + int len = 0; + int status = wan_status(); + + if (!wan_supported) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else if (!(status & 1)) + len += sprintf(p + len, "status:\t\tnot installed\n"); + else { + len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1)); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + + return len; +} + +static int wan_write(char *buf) +{ + int status = wan_status(); + char *cmd; + int do_cmd = 0; + + if (!wan_supported) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) { + status |= 2; + } else if (strlencmp(cmd, "disable") == 0) { + status &= ~2; + } else + return -EINVAL; + do_cmd = 1; + } + + if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) + return -EIO; + + return 0; +} + +enum video_access_mode { + IBMACPI_VIDEO_NONE = 0, + IBMACPI_VIDEO_570, /* 570 */ + IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + IBMACPI_VIDEO_NEW, /* all others */ +}; + +static enum video_access_mode video_supported; +static int video_orig_autosw; + +static int video_init(void) +{ + int ivga; + + if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) + /* G41, assume IVGA doesn't change */ + vid_handle = vid2_handle; + + if (!vid_handle) + /* video switching not supported on R30, R31 */ + video_supported = IBMACPI_VIDEO_NONE; + else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) + /* 570 */ + video_supported = IBMACPI_VIDEO_570; + else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) + /* 600e/x, 770e, 770x */ + video_supported = IBMACPI_VIDEO_770; + else + /* all others */ + video_supported = IBMACPI_VIDEO_NEW; + + return 0; +} + +static int video_status(void) +{ + int status = 0; + int i; + + if (video_supported == IBMACPI_VIDEO_570) { + if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) + status = i & 3; + } else if (video_supported == IBMACPI_VIDEO_770) { + if (acpi_evalf(NULL, &i, "\\VCDL", "d")) + status |= 0x01 * i; + if (acpi_evalf(NULL, &i, "\\VCDC", "d")) + status |= 0x02 * i; + } else if (video_supported == IBMACPI_VIDEO_NEW) { + acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); + if (acpi_evalf(NULL, &i, "\\VCDC", "d")) + status |= 0x02 * i; + + acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0); + if (acpi_evalf(NULL, &i, "\\VCDL", "d")) + status |= 0x01 * i; + if (acpi_evalf(NULL, &i, "\\VCDD", "d")) + status |= 0x08 * i; + } + + return status; +} + +static int video_autosw(void) +{ + int autosw = 0; + + if (video_supported == IBMACPI_VIDEO_570) + acpi_evalf(vid_handle, &autosw, "SWIT", "d"); + else if (video_supported == IBMACPI_VIDEO_770 || + video_supported == IBMACPI_VIDEO_NEW) + acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); + + return autosw & 1; +} + +static int video_read(char *p) +{ + int status = video_status(); + int autosw = video_autosw(); + int len = 0; + + if (!video_supported) { + len += sprintf(p + len, "status:\t\tnot supported\n"); + return len; + } + + len += sprintf(p + len, "status:\t\tsupported\n"); + len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); + len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); + if (video_supported == IBMACPI_VIDEO_NEW) + len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); + len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); + len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); + len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); + if (video_supported == IBMACPI_VIDEO_NEW) + len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); + len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); + len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); + + return len; +} + +static int video_switch(void) +{ + int autosw = video_autosw(); + int ret; + + if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) + return -EIO; + ret = video_supported == IBMACPI_VIDEO_570 ? + acpi_evalf(ec_handle, NULL, "_Q16", "v") : + acpi_evalf(vid_handle, NULL, "VSWT", "v"); + acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); + + return ret; +} + +static int video_expand(void) +{ + if (video_supported == IBMACPI_VIDEO_570) + return acpi_evalf(ec_handle, NULL, "_Q17", "v"); + else if (video_supported == IBMACPI_VIDEO_770) + return acpi_evalf(vid_handle, NULL, "VEXP", "v"); + else + return acpi_evalf(NULL, NULL, "\\VEXP", "v"); +} + +static int video_switch2(int status) +{ + int ret; + + if (video_supported == IBMACPI_VIDEO_570) { + ret = acpi_evalf(NULL, NULL, + "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); + } else if (video_supported == IBMACPI_VIDEO_770) { + int autosw = video_autosw(); + if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) + return -EIO; + + ret = acpi_evalf(vid_handle, NULL, + "ASWT", "vdd", status * 0x100, 0); + + acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); + } else { + ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && + acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); + } + + return ret; +} + +static int video_write(char *buf) +{ + char *cmd; + int enable, disable, status; + + if (!video_supported) + return -ENODEV; + + enable = disable = 0; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "lcd_enable") == 0) { + enable |= 0x01; + } else if (strlencmp(cmd, "lcd_disable") == 0) { + disable |= 0x01; + } else if (strlencmp(cmd, "crt_enable") == 0) { + enable |= 0x02; + } else if (strlencmp(cmd, "crt_disable") == 0) { + disable |= 0x02; + } else if (video_supported == IBMACPI_VIDEO_NEW && + strlencmp(cmd, "dvi_enable") == 0) { + enable |= 0x08; + } else if (video_supported == IBMACPI_VIDEO_NEW && + strlencmp(cmd, "dvi_disable") == 0) { + disable |= 0x08; + } else if (strlencmp(cmd, "auto_enable") == 0) { + if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) + return -EIO; + } else if (strlencmp(cmd, "auto_disable") == 0) { + if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0)) + return -EIO; + } else if (strlencmp(cmd, "video_switch") == 0) { + if (!video_switch()) + return -EIO; + } else if (strlencmp(cmd, "expand_toggle") == 0) { + if (!video_expand()) + return -EIO; + } else + return -EINVAL; + } + + if (enable || disable) { + status = (video_status() & 0x0f & ~disable) | enable; + if (!video_switch2(status)) + return -EIO; + } + + return 0; +} + +static void video_exit(void) +{ + acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw); +} + +static int light_supported; +static int light_status_supported; + +static int light_init(void) +{ + /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ + light_supported = (cmos_handle || lght_handle) && !ledb_handle; + + if (light_supported) + /* light status not supported on + 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ + light_status_supported = acpi_evalf(ec_handle, NULL, + "KBLT", "qv"); + + return 0; +} + +static int light_read(char *p) +{ + int len = 0; + int status = 0; + + if (!light_supported) { + len += sprintf(p + len, "status:\t\tnot supported\n"); + } else if (!light_status_supported) { + len += sprintf(p + len, "status:\t\tunknown\n"); + len += sprintf(p + len, "commands:\ton, off\n"); + } else { + if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) + return -EIO; + len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); + len += sprintf(p + len, "commands:\ton, off\n"); + } + + return len; +} + +static int light_write(char *buf) +{ + int cmos_cmd, lght_cmd; + char *cmd; + int success; + + if (!light_supported) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "on") == 0) { + cmos_cmd = 0x0c; + lght_cmd = 1; + } else if (strlencmp(cmd, "off") == 0) { + cmos_cmd = 0x0d; + lght_cmd = 0; + } else + return -EINVAL; + + success = cmos_handle ? + acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) : + acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd); + if (!success) + return -EIO; + } + + return 0; +} + +#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY) +static int _sta(acpi_handle handle) +{ + int status; + + if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) + status = 0; + + return status; +} +#endif + +#ifdef CONFIG_ACPI_IBM_DOCK +#define dock_docked() (_sta(dock_handle) & 1) + +static int dock_read(char *p) +{ + int len = 0; + int docked = dock_docked(); + + if (!dock_handle) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else if (!docked) + len += sprintf(p + len, "status:\t\tundocked\n"); + else { + len += sprintf(p + len, "status:\t\tdocked\n"); + len += sprintf(p + len, "commands:\tdock, undock\n"); + } + + return len; +} + +static int dock_write(char *buf) +{ + char *cmd; + + if (!dock_docked()) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "undock") == 0) { + if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || + !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) + return -EIO; + } else if (strlencmp(cmd, "dock") == 0) { + if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) + return -EIO; + } else + return -EINVAL; + } + + return 0; +} + +static void dock_notify(struct ibm_struct *ibm, u32 event) +{ + int docked = dock_docked(); + int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID); + + if (event == 1 && !pci) /* 570 */ + acpi_bus_generate_event(ibm->device, event, 1); /* button */ + else if (event == 1 && pci) /* 570 */ + acpi_bus_generate_event(ibm->device, event, 3); /* dock */ + else if (event == 3 && docked) + acpi_bus_generate_event(ibm->device, event, 1); /* button */ + else if (event == 3 && !docked) + acpi_bus_generate_event(ibm->device, event, 2); /* undock */ + else if (event == 0 && docked) + acpi_bus_generate_event(ibm->device, event, 3); /* dock */ + else { + printk(IBM_ERR "unknown dock event %d, status %d\n", + event, _sta(dock_handle)); + acpi_bus_generate_event(ibm->device, event, 0); /* unknown */ + } +} +#endif + +#ifdef CONFIG_ACPI_IBM_BAY +static int bay_status_supported; +static int bay_status2_supported; +static int bay_eject_supported; +static int bay_eject2_supported; + +static int bay_init(void) +{ + bay_status_supported = bay_handle && + acpi_evalf(bay_handle, NULL, "_STA", "qv"); + bay_status2_supported = bay2_handle && + acpi_evalf(bay2_handle, NULL, "_STA", "qv"); + + bay_eject_supported = bay_handle && bay_ej_handle && + (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); + bay_eject2_supported = bay2_handle && bay2_ej_handle && + (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); + + return 0; +} + +#define bay_occupied(b) (_sta(b##_handle) & 1) + +static int bay_read(char *p) +{ + int len = 0; + int occupied = bay_occupied(bay); + int occupied2 = bay_occupied(bay2); + int eject, eject2; + + len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ? + (occupied ? "occupied" : "unoccupied") : + "not supported"); + if (bay_status2_supported) + len += sprintf(p + len, "status2:\t%s\n", occupied2 ? + "occupied" : "unoccupied"); + + eject = bay_eject_supported && occupied; + eject2 = bay_eject2_supported && occupied2; + + if (eject && eject2) + len += sprintf(p + len, "commands:\teject, eject2\n"); + else if (eject) + len += sprintf(p + len, "commands:\teject\n"); + else if (eject2) + len += sprintf(p + len, "commands:\teject2\n"); + + return len; +} + +static int bay_write(char *buf) +{ + char *cmd; + + if (!bay_eject_supported && !bay_eject2_supported) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (bay_eject_supported && strlencmp(cmd, "eject") == 0) { + if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) + return -EIO; + } else if (bay_eject2_supported && + strlencmp(cmd, "eject2") == 0) { + if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) + return -EIO; + } else + return -EINVAL; + } + + return 0; +} + +static void bay_notify(struct ibm_struct *ibm, u32 event) +{ + acpi_bus_generate_event(ibm->device, event, 0); +} +#endif /* CONFIG_ACPI_IBM_BAY */ + +static int cmos_read(char *p) +{ + int len = 0; + + /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + R30, R31, T20-22, X20-21 */ + if (!cmos_handle) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + len += sprintf(p + len, "status:\t\tsupported\n"); + len += sprintf(p + len, "commands:\t ( is 0-21)\n"); + } + + return len; +} + +static int cmos_eval(int cmos_cmd) +{ + if (cmos_handle) + return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd); + else + return 1; +} + +static int cmos_write(char *buf) +{ + char *cmd; + int cmos_cmd; + + if (!cmos_handle) + return -EINVAL; + + while ((cmd = next_cmd(&buf))) { + if (sscanf(cmd, "%u", &cmos_cmd) == 1 && + cmos_cmd >= 0 && cmos_cmd <= 21) { + /* cmos_cmd set */ + } else + return -EINVAL; + + if (!cmos_eval(cmos_cmd)) + return -EIO; + } + + return 0; +} + +enum led_access_mode { + IBMACPI_LED_NONE = 0, + IBMACPI_LED_570, /* 570 */ + IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + IBMACPI_LED_NEW, /* all others */ +}; +static enum led_access_mode led_supported; + +static int led_init(void) +{ + if (!led_handle) + /* led not supported on R30, R31 */ + led_supported = IBMACPI_LED_NONE; + else if (strlencmp(led_path, "SLED") == 0) + /* 570 */ + led_supported = IBMACPI_LED_570; + else if (strlencmp(led_path, "SYSL") == 0) + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + led_supported = IBMACPI_LED_OLD; + else + /* all others */ + led_supported = IBMACPI_LED_NEW; + + return 0; +} + +#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) + +static int led_read(char *p) +{ + int len = 0; + + if (!led_supported) { + len += sprintf(p + len, "status:\t\tnot supported\n"); + return len; + } + len += sprintf(p + len, "status:\t\tsupported\n"); + + if (led_supported == IBMACPI_LED_570) { + /* 570 */ + int i, status; + for (i = 0; i < 8; i++) { + if (!acpi_evalf(ec_handle, + &status, "GLED", "dd", 1 << i)) + return -EIO; + len += sprintf(p + len, "%d:\t\t%s\n", + i, led_status(status)); + } + } + + len += sprintf(p + len, "commands:\t" + " on, off, blink ( is 0-7)\n"); + + return len; +} + +/* off, on, blink */ +static const int led_sled_arg1[] = { 0, 1, 3 }; +static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ +static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ +static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; + +#define EC_HLCL 0x0c +#define EC_HLBL 0x0d +#define EC_HLMS 0x0e + +static int led_write(char *buf) +{ + char *cmd; + int led, ind, ret; + + if (!led_supported) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) + return -EINVAL; + + if (strstr(cmd, "off")) { + ind = 0; + } else if (strstr(cmd, "on")) { + ind = 1; + } else if (strstr(cmd, "blink")) { + ind = 2; + } else + return -EINVAL; + + if (led_supported == IBMACPI_LED_570) { + /* 570 */ + led = 1 << led; + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + led, led_sled_arg1[ind])) + return -EIO; + } else if (led_supported == IBMACPI_LED_OLD) { + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ + led = 1 << led; + ret = ec_write(EC_HLMS, led); + if (ret >= 0) + ret = + ec_write(EC_HLBL, led * led_exp_hlbl[ind]); + if (ret >= 0) + ret = + ec_write(EC_HLCL, led * led_exp_hlcl[ind]); + if (ret < 0) + return ret; + } else { + /* all others */ + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + led, led_led_arg1[ind])) + return -EIO; + } + } + + return 0; +} + +static int beep_read(char *p) +{ + int len = 0; + + if (!beep_handle) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + len += sprintf(p + len, "status:\t\tsupported\n"); + len += sprintf(p + len, "commands:\t ( is 0-17)\n"); + } + + return len; +} + +static int beep_write(char *buf) +{ + char *cmd; + int beep_cmd; + + if (!beep_handle) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (sscanf(cmd, "%u", &beep_cmd) == 1 && + beep_cmd >= 0 && beep_cmd <= 17) { + /* beep_cmd set */ + } else + return -EINVAL; + if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) + return -EIO; + } + + return 0; +} + +static int acpi_ec_read(int i, u8 * p) +{ + int v; + + if (ecrd_handle) { + if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) + return 0; + *p = v; + } else { + if (ec_read(i, p) < 0) + return 0; + } + + return 1; +} + +static int acpi_ec_write(int i, u8 v) +{ + if (ecwr_handle) { + if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) + return 0; + } else { + if (ec_write(i, v) < 0) + return 0; + } + + return 1; +} + +static enum thermal_access_mode thermal_read_mode; + +static int thermal_init(void) +{ + u8 t, ta1, ta2; + int i; + int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); + + if (ibm_thinkpad_ec_found && experimental) { + /* + * Direct EC access mode: sensors at registers + * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for + * non-implemented, thermal sensors return 0x80 when + * not available + */ + + ta1 = ta2 = 0; + for (i = 0; i < 8; i++) { + if (likely(acpi_ec_read(0x78 + i, &t))) { + ta1 |= t; + } else { + ta1 = 0; + break; + } + if (likely(acpi_ec_read(0xC0 + i, &t))) { + ta2 |= t; + } else { + ta1 = 0; + break; + } + } + if (ta1 == 0) { + /* This is sheer paranoia, but we handle it anyway */ + if (acpi_tmp7) { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "falling back to ACPI TMPx access mode\n"); + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + } else { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "disabling thermal sensors access\n"); + thermal_read_mode = IBMACPI_THERMAL_NONE; + } + } else { + thermal_read_mode = + (ta2 != 0) ? + IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8; + } + } else if (acpi_tmp7) { + if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { + /* 600e/x, 770e, 770x */ + thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; + } else { + /* Standard ACPI TMPx access, max 8 sensors */ + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + } + } else { + /* temperatures not supported on 570, G4x, R30, R31, R32 */ + thermal_read_mode = IBMACPI_THERMAL_NONE; + } + + return 0; +} + +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) +{ + int i, t; + s8 tmp; + char tmpi[] = "TMPi"; + + if (!s) + return -EINVAL; + + switch (thermal_read_mode) { +#if IBMACPI_MAX_THERMAL_SENSORS >= 16 + case IBMACPI_THERMAL_TPEC_16: + for (i = 0; i < 8; i++) { + if (!acpi_ec_read(0xC0 + i, &tmp)) + return -EIO; + s->temp[i + 8] = tmp * 1000; + } + /* fallthrough */ +#endif + case IBMACPI_THERMAL_TPEC_8: + for (i = 0; i < 8; i++) { + if (!acpi_ec_read(0x78 + i, &tmp)) + return -EIO; + s->temp[i] = tmp * 1000; + } + return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8; + + case IBMACPI_THERMAL_ACPI_UPDT: + if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) + return -EIO; + for (i = 0; i < 8; i++) { + tmpi[3] = '0' + i; + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) + return -EIO; + s->temp[i] = (t - 2732) * 100; + } + return 8; + + case IBMACPI_THERMAL_ACPI_TMP07: + for (i = 0; i < 8; i++) { + tmpi[3] = '0' + i; + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) + return -EIO; + s->temp[i] = t * 1000; + } + return 8; + + case IBMACPI_THERMAL_NONE: + default: + return 0; + } +} + +static int thermal_read(char *p) +{ + int len = 0; + int n, i; + struct ibm_thermal_sensors_struct t; + + n = thermal_get_sensors(&t); + if (unlikely(n < 0)) + return n; + + len += sprintf(p + len, "temperatures:\t"); + + if (n > 0) { + for (i = 0; i < (n - 1); i++) + len += sprintf(p + len, "%d ", t.temp[i] / 1000); + len += sprintf(p + len, "%d\n", t.temp[i] / 1000); + } else + len += sprintf(p + len, "not supported\n"); + + return len; +} + +static u8 ecdump_regs[256]; + +static int ecdump_read(char *p) +{ + int len = 0; + int i, j; + u8 v; + + len += sprintf(p + len, "EC " + " +00 +01 +02 +03 +04 +05 +06 +07" + " +08 +09 +0a +0b +0c +0d +0e +0f\n"); + for (i = 0; i < 256; i += 16) { + len += sprintf(p + len, "EC 0x%02x:", i); + for (j = 0; j < 16; j++) { + if (!acpi_ec_read(i + j, &v)) + break; + if (v != ecdump_regs[i + j]) + len += sprintf(p + len, " *%02x", v); + else + len += sprintf(p + len, " %02x", v); + ecdump_regs[i + j] = v; + } + len += sprintf(p + len, "\n"); + if (j != 16) + break; + } + + /* These are way too dangerous to advertise openly... */ +#if 0 + len += sprintf(p + len, "commands:\t0x 0x" + " ( is 00-ff, is 00-ff)\n"); + len += sprintf(p + len, "commands:\t0x " + " ( is 00-ff, is 0-255)\n"); +#endif + return len; +} + +static int ecdump_write(char *buf) +{ + char *cmd; + int i, v; + + while ((cmd = next_cmd(&buf))) { + if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { + /* i and v set */ + } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { + /* i and v set */ + } else + return -EINVAL; + if (i >= 0 && i < 256 && v >= 0 && v < 256) { + if (!acpi_ec_write(i, v)) + return -EIO; + } else + return -EINVAL; + } + + return 0; +} + +static int brightness_offset = 0x31; + +static int brightness_get(struct backlight_device *bd) +{ + u8 level; + if (!acpi_ec_read(brightness_offset, &level)) + return -EIO; + + level &= 0x7; + + return level; +} + +static int brightness_read(char *p) +{ + int len = 0; + int level; + + if ((level = brightness_get(NULL)) < 0) { + len += sprintf(p + len, "level:\t\tunreadable\n"); + } else { + len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); + len += sprintf(p + len, "commands:\tup, down\n"); + len += sprintf(p + len, "commands:\tlevel " + " ( is 0-7)\n"); + } + + return len; +} + +#define BRIGHTNESS_UP 4 +#define BRIGHTNESS_DOWN 5 + +static int brightness_set(int value) +{ + int cmos_cmd, inc, i; + int current_value = brightness_get(NULL); + + value &= 7; + + cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; + inc = value > current_value ? 1 : -1; + for (i = current_value; i != value; i += inc) { + if (!cmos_eval(cmos_cmd)) + return -EIO; + if (!acpi_ec_write(brightness_offset, i + inc)) + return -EIO; + } + + return 0; +} + +static int brightness_write(char *buf) +{ + int level; + int new_level; + char *cmd; + + while ((cmd = next_cmd(&buf))) { + if ((level = brightness_get(NULL)) < 0) + return level; + level &= 7; + + if (strlencmp(cmd, "up") == 0) { + new_level = level == 7 ? 7 : level + 1; + } else if (strlencmp(cmd, "down") == 0) { + new_level = level == 0 ? 0 : level - 1; + } else if (sscanf(cmd, "level %d", &new_level) == 1 && + new_level >= 0 && new_level <= 7) { + /* new_level set */ + } else + return -EINVAL; + + brightness_set(new_level); + } + + return 0; +} + +static int brightness_update_status(struct backlight_device *bd) +{ + return brightness_set( + (bd->props.fb_blank == FB_BLANK_UNBLANK && + bd->props.power == FB_BLANK_UNBLANK) ? + bd->props.brightness : 0); +} + +static struct backlight_ops ibm_backlight_data = { + .get_brightness = brightness_get, + .update_status = brightness_update_status, +}; + +static int brightness_init(void) +{ + int b; + + b = brightness_get(NULL); + if (b < 0) + return b; + + ibm_backlight_device = backlight_device_register("ibm", NULL, NULL, + &ibm_backlight_data); + if (IS_ERR(ibm_backlight_device)) { + printk(IBM_ERR "Could not register backlight device\n"); + return PTR_ERR(ibm_backlight_device); + } + + ibm_backlight_device->props.max_brightness = 7; + ibm_backlight_device->props.brightness = b; + backlight_update_status(ibm_backlight_device); + + return 0; +} + +static void brightness_exit(void) +{ + if (ibm_backlight_device) { + backlight_device_unregister(ibm_backlight_device); + ibm_backlight_device = NULL; + } +} + +static int volume_offset = 0x30; + +static int volume_read(char *p) +{ + int len = 0; + u8 level; + + if (!acpi_ec_read(volume_offset, &level)) { + len += sprintf(p + len, "level:\t\tunreadable\n"); + } else { + len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); + len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); + len += sprintf(p + len, "commands:\tup, down, mute\n"); + len += sprintf(p + len, "commands:\tlevel " + " ( is 0-15)\n"); + } + + return len; +} + +#define VOLUME_DOWN 0 +#define VOLUME_UP 1 +#define VOLUME_MUTE 2 + +static int volume_write(char *buf) +{ + int cmos_cmd, inc, i; + u8 level, mute; + int new_level, new_mute; + char *cmd; + + while ((cmd = next_cmd(&buf))) { + if (!acpi_ec_read(volume_offset, &level)) + return -EIO; + new_mute = mute = level & 0x40; + new_level = level = level & 0xf; + + if (strlencmp(cmd, "up") == 0) { + if (mute) + new_mute = 0; + else + new_level = level == 15 ? 15 : level + 1; + } else if (strlencmp(cmd, "down") == 0) { + if (mute) + new_mute = 0; + else + new_level = level == 0 ? 0 : level - 1; + } else if (sscanf(cmd, "level %d", &new_level) == 1 && + new_level >= 0 && new_level <= 15) { + /* new_level set */ + } else if (strlencmp(cmd, "mute") == 0) { + new_mute = 0x40; + } else + return -EINVAL; + + if (new_level != level) { /* mute doesn't change */ + cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN; + inc = new_level > level ? 1 : -1; + + if (mute && (!cmos_eval(cmos_cmd) || + !acpi_ec_write(volume_offset, level))) + return -EIO; + + for (i = level; i != new_level; i += inc) + if (!cmos_eval(cmos_cmd) || + !acpi_ec_write(volume_offset, i + inc)) + return -EIO; + + if (mute && (!cmos_eval(VOLUME_MUTE) || + !acpi_ec_write(volume_offset, + new_level + mute))) + return -EIO; + } + + if (new_mute != mute) { /* level doesn't change */ + cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP; + + if (!cmos_eval(cmos_cmd) || + !acpi_ec_write(volume_offset, level + new_mute)) + return -EIO; + } + } + + return 0; +} + +static enum fan_status_access_mode fan_status_access_mode; +static enum fan_control_access_mode fan_control_access_mode; +static enum fan_control_commands fan_control_commands; + +static int fan_control_status_known; +static u8 fan_control_initial_status; + +static void fan_watchdog_fire(struct work_struct *ignored); +static int fan_watchdog_maxinterval; +static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); + +static int fan_init(void) +{ + fan_status_access_mode = IBMACPI_FAN_NONE; + fan_control_access_mode = IBMACPI_FAN_WR_NONE; + fan_control_commands = 0; + fan_control_status_known = 1; + fan_watchdog_maxinterval = 0; + + if (gfan_handle) { + /* 570, 600e/x, 770e, 770x */ + fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN; + } else { + /* all other ThinkPads: note that even old-style + * ThinkPad ECs supports the fan control register */ + if (likely(acpi_ec_read(fan_status_offset, + &fan_control_initial_status))) { + fan_status_access_mode = IBMACPI_FAN_RD_TPEC; + + /* In some ThinkPads, neither the EC nor the ACPI + * DSDT initialize the fan status, and it ends up + * being set to 0x07 when it *could* be either + * 0x07 or 0x80. + * + * Enable for TP-1Y (T43), TP-78 (R51e), + * TP-76 (R52), TP-70 (T43, R52), which are known + * to be buggy. */ + if (fan_control_initial_status == 0x07 && + ibm_thinkpad_ec_found && + ((ibm_thinkpad_ec_found[0] == '1' && + ibm_thinkpad_ec_found[1] == 'Y') || + (ibm_thinkpad_ec_found[0] == '7' && + (ibm_thinkpad_ec_found[1] == '6' || + ibm_thinkpad_ec_found[1] == '8' || + ibm_thinkpad_ec_found[1] == '0')) + )) { + printk(IBM_NOTICE + "fan_init: initial fan status is " + "unknown, assuming it is in auto " + "mode\n"); + fan_control_status_known = 0; + } + } else { + printk(IBM_ERR + "ThinkPad ACPI EC access misbehaving, " + "fan status and control unavailable\n"); + return 0; + } + } + + if (sfan_handle) { + /* 570, 770x-JL */ + fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN; + fan_control_commands |= + IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE; + } else { + if (!gfan_handle) { + /* gfan without sfan means no fan control */ + /* all other models implement TP EC 0x2f control */ + + if (fans_handle) { + /* X31, X40, X41 */ + fan_control_access_mode = + IBMACPI_FAN_WR_ACPI_FANS; + fan_control_commands |= + IBMACPI_FAN_CMD_SPEED | + IBMACPI_FAN_CMD_LEVEL | + IBMACPI_FAN_CMD_ENABLE; + } else { + fan_control_access_mode = IBMACPI_FAN_WR_TPEC; + fan_control_commands |= + IBMACPI_FAN_CMD_LEVEL | + IBMACPI_FAN_CMD_ENABLE; + } + } + } + + return 0; +} + +static int fan_get_status(u8 *status) +{ + u8 s; + + /* TODO: + * Add IBMACPI_FAN_RD_ACPI_FANS ? */ + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_ACPI_GFAN: + /* 570, 600e/x, 770e, 770x */ + + if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) + return -EIO; + + if (likely(status)) + *status = s & 0x07; + + break; + + case IBMACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!acpi_ec_read(fan_status_offset, &s))) + return -EIO; + + if (likely(status)) + *status = s; + + break; + + default: + return -ENXIO; + } + + return 0; +} + +static int fan_get_speed(unsigned int *speed) +{ + u8 hi, lo; + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || + !acpi_ec_read(fan_rpm_offset + 1, &hi))) + return -EIO; + + if (likely(speed)) + *speed = (hi << 8) | lo; + + break; + + default: + return -ENXIO; + } + + return 0; +} + +static void fan_exit(void) +{ + cancel_delayed_work(&fan_watchdog_task); + flush_scheduled_work(); +} + +static void fan_watchdog_reset(void) +{ + static int fan_watchdog_active = 0; + + if (fan_watchdog_active) + cancel_delayed_work(&fan_watchdog_task); + + if (fan_watchdog_maxinterval > 0) { + fan_watchdog_active = 1; + if (!schedule_delayed_work(&fan_watchdog_task, + msecs_to_jiffies(fan_watchdog_maxinterval + * 1000))) { + printk(IBM_ERR "failed to schedule the fan watchdog, " + "watchdog will not trigger\n"); + } + } else + fan_watchdog_active = 0; +} + +static int fan_read(char *p) +{ + int len = 0; + int rc; + u8 status; + unsigned int speed = 0; + + switch (fan_status_access_mode) { + case IBMACPI_FAN_RD_ACPI_GFAN: + /* 570, 600e/x, 770e, 770x */ + if ((rc = fan_get_status(&status)) < 0) + return rc; + + len += sprintf(p + len, "status:\t\t%s\n" + "level:\t\t%d\n", + (status != 0) ? "enabled" : "disabled", status); + break; + + case IBMACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if ((rc = fan_get_status(&status)) < 0) + return rc; + + if (unlikely(!fan_control_status_known)) { + if (status != fan_control_initial_status) + fan_control_status_known = 1; + else + /* Return most likely status. In fact, it + * might be the only possible status */ + status = IBMACPI_FAN_EC_AUTO; + } + + len += sprintf(p + len, "status:\t\t%s\n", + (status != 0) ? "enabled" : "disabled"); + + /* No ThinkPad boots on disengaged mode, we can safely + * assume the tachometer is online if fan control status + * was unknown */ + if ((rc = fan_get_speed(&speed)) < 0) + return rc; + + len += sprintf(p + len, "speed:\t\t%d\n", speed); + + if (status & IBMACPI_FAN_EC_DISENGAGED) + /* Disengaged mode takes precedence */ + len += sprintf(p + len, "level:\t\tdisengaged\n"); + else if (status & IBMACPI_FAN_EC_AUTO) + len += sprintf(p + len, "level:\t\tauto\n"); + else + len += sprintf(p + len, "level:\t\t%d\n", status); + break; + + case IBMACPI_FAN_NONE: + default: + len += sprintf(p + len, "status:\t\tnot supported\n"); + } + + if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) { + len += sprintf(p + len, "commands:\tlevel "); + + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_SFAN: + len += sprintf(p + len, " ( is 0-7)\n"); + break; + + default: + len += sprintf(p + len, " ( is 0-7, " + "auto, disengaged)\n"); + break; + } + } + + if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) + len += sprintf(p + len, "commands:\tenable, disable\n" + "commands:\twatchdog ( is 0 (off), " + "1-120 (seconds))\n"); + + if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) + len += sprintf(p + len, "commands:\tspeed " + " ( is 0-65535)\n"); + + return len; +} + +static int fan_set_level(int level) +{ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_SFAN: + if (level >= 0 && level <= 7) { + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) + return -EIO; + } else + return -EINVAL; + break; + + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if ((level != IBMACPI_FAN_EC_AUTO) && + (level != IBMACPI_FAN_EC_DISENGAGED) && + ((level < 0) || (level > 7))) + return -EINVAL; + + if (!acpi_ec_write(fan_status_offset, level)) + return -EIO; + else + fan_control_status_known = 1; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_enable(void) +{ + u8 s; + int rc; + + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if ((rc = fan_get_status(&s)) < 0) + return rc; + + /* Don't go out of emergency fan mode */ + if (s != 7) + s = IBMACPI_FAN_EC_AUTO; + + if (!acpi_ec_write(fan_status_offset, s)) + return -EIO; + else + fan_control_status_known = 1; + break; + + case IBMACPI_FAN_WR_ACPI_SFAN: + if ((rc = fan_get_status(&s)) < 0) + return rc; + + s &= 0x07; + + /* Set fan to at least level 4 */ + if (s < 4) + s = 4; + + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) + return -EIO; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_disable(void) +{ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + case IBMACPI_FAN_WR_TPEC: + if (!acpi_ec_write(fan_status_offset, 0x00)) + return -EIO; + else + fan_control_status_known = 1; + break; + + case IBMACPI_FAN_WR_ACPI_SFAN: + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) + return -EIO; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_set_speed(int speed) +{ + switch (fan_control_access_mode) { + case IBMACPI_FAN_WR_ACPI_FANS: + if (speed >= 0 && speed <= 65535) { + if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", + speed, speed, speed)) + return -EIO; + } else + return -EINVAL; + break; + + default: + return -ENXIO; + } + return 0; +} + +static int fan_write_cmd_level(const char *cmd, int *rc) +{ + int level; + + if (strlencmp(cmd, "level auto") == 0) + level = IBMACPI_FAN_EC_AUTO; + else if (strlencmp(cmd, "level disengaged") == 0) + level = IBMACPI_FAN_EC_DISENGAGED; + else if (sscanf(cmd, "level %d", &level) != 1) + return 0; + + if ((*rc = fan_set_level(level)) == -ENXIO) + printk(IBM_ERR "level command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_enable(const char *cmd, int *rc) +{ + if (strlencmp(cmd, "enable") != 0) + return 0; + + if ((*rc = fan_set_enable()) == -ENXIO) + printk(IBM_ERR "enable command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_disable(const char *cmd, int *rc) +{ + if (strlencmp(cmd, "disable") != 0) + return 0; + + if ((*rc = fan_set_disable()) == -ENXIO) + printk(IBM_ERR "disable command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_speed(const char *cmd, int *rc) +{ + int speed; + + /* TODO: + * Support speed ? */ + + if (sscanf(cmd, "speed %d", &speed) != 1) + return 0; + + if ((*rc = fan_set_speed(speed)) == -ENXIO) + printk(IBM_ERR "speed command accepted for unsupported " + "access mode %d", fan_control_access_mode); + + return 1; +} + +static int fan_write_cmd_watchdog(const char *cmd, int *rc) +{ + int interval; + + if (sscanf(cmd, "watchdog %d", &interval) != 1) + return 0; + + if (interval < 0 || interval > 120) + *rc = -EINVAL; + else + fan_watchdog_maxinterval = interval; + + return 1; +} + +static int fan_write(char *buf) +{ + char *cmd; + int rc = 0; + + while (!rc && (cmd = next_cmd(&buf))) { + if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) && + fan_write_cmd_level(cmd, &rc)) && + !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && + (fan_write_cmd_enable(cmd, &rc) || + fan_write_cmd_disable(cmd, &rc) || + fan_write_cmd_watchdog(cmd, &rc))) && + !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && + fan_write_cmd_speed(cmd, &rc)) + ) + rc = -EINVAL; + else if (!rc) + fan_watchdog_reset(); + } + + return rc; +} + +static void fan_watchdog_fire(struct work_struct *ignored) +{ + printk(IBM_NOTICE "fan watchdog: enabling fan\n"); + if (fan_set_enable()) { + printk(IBM_ERR "fan watchdog: error while enabling fan\n"); + /* reschedule for later */ + fan_watchdog_reset(); + } +} + +static struct ibm_struct ibms[] = { + { + .name = "driver", + .init = ibm_acpi_driver_init, + .read = driver_read, + }, + { + .name = "hotkey", + .hid = IBM_HKEY_HID, + .init = hotkey_init, + .read = hotkey_read, + .write = hotkey_write, + .exit = hotkey_exit, + .notify = hotkey_notify, + .handle = &hkey_handle, + .type = ACPI_DEVICE_NOTIFY, + }, + { + .name = "bluetooth", + .init = bluetooth_init, + .read = bluetooth_read, + .write = bluetooth_write, + }, + { + .name = "wan", + .init = wan_init, + .read = wan_read, + .write = wan_write, + .experimental = 1, + }, + { + .name = "video", + .init = video_init, + .read = video_read, + .write = video_write, + .exit = video_exit, + }, + { + .name = "light", + .init = light_init, + .read = light_read, + .write = light_write, + }, +#ifdef CONFIG_ACPI_IBM_DOCK + { + .name = "dock", + .read = dock_read, + .write = dock_write, + .notify = dock_notify, + .handle = &dock_handle, + .type = ACPI_SYSTEM_NOTIFY, + }, + { + .name = "dock", + .hid = IBM_PCI_HID, + .notify = dock_notify, + .handle = &pci_handle, + .type = ACPI_SYSTEM_NOTIFY, + }, +#endif +#ifdef CONFIG_ACPI_IBM_BAY + { + .name = "bay", + .init = bay_init, + .read = bay_read, + .write = bay_write, + .notify = bay_notify, + .handle = &bay_handle, + .type = ACPI_SYSTEM_NOTIFY, + }, +#endif /* CONFIG_ACPI_IBM_BAY */ + { + .name = "cmos", + .read = cmos_read, + .write = cmos_write, + }, + { + .name = "led", + .init = led_init, + .read = led_read, + .write = led_write, + }, + { + .name = "beep", + .read = beep_read, + .write = beep_write, + }, + { + .name = "thermal", + .init = thermal_init, + .read = thermal_read, + }, + { + .name = "ecdump", + .read = ecdump_read, + .write = ecdump_write, + .experimental = 1, + }, + { + .name = "brightness", + .read = brightness_read, + .write = brightness_write, + .init = brightness_init, + .exit = brightness_exit, + }, + { + .name = "volume", + .read = volume_read, + .write = volume_write, + }, + { + .name = "fan", + .read = fan_read, + .write = fan_write, + .init = fan_init, + .exit = fan_exit, + .experimental = 1, + }, +}; + +static int dispatch_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct ibm_struct *ibm = data; + int len; + + if (!ibm || !ibm->read) + return -EINVAL; + + len = ibm->read(page); + if (len < 0) + return len; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +static int dispatch_write(struct file *file, const char __user * userbuf, + unsigned long count, void *data) +{ + struct ibm_struct *ibm = data; + char *kernbuf; + int ret; + + if (!ibm || !ibm->write) + return -EINVAL; + + kernbuf = kmalloc(count + 2, GFP_KERNEL); + if (!kernbuf) + return -ENOMEM; + + if (copy_from_user(kernbuf, userbuf, count)) { + kfree(kernbuf); + return -EFAULT; + } + + kernbuf[count] = 0; + strcat(kernbuf, ","); + ret = ibm->write(kernbuf); + if (ret == 0) + ret = count; + + kfree(kernbuf); + + return ret; +} + +static void dispatch_notify(acpi_handle handle, u32 event, void *data) +{ + struct ibm_struct *ibm = data; + + if (!ibm || !ibm->notify) + return; + + ibm->notify(ibm, event); +} + +static int __init setup_notify(struct ibm_struct *ibm) +{ + acpi_status status; + int ret; + + if (!*ibm->handle) + return 0; + + ret = acpi_bus_get_device(*ibm->handle, &ibm->device); + if (ret < 0) { + printk(IBM_ERR "%s device not present\n", ibm->name); + return -ENODEV; + } + + acpi_driver_data(ibm->device) = ibm; + sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name); + + status = acpi_install_notify_handler(*ibm->handle, ibm->type, + dispatch_notify, ibm); + if (ACPI_FAILURE(status)) { + if (status == AE_ALREADY_EXISTS) { + printk(IBM_NOTICE "another device driver is already handling %s events\n", + ibm->name); + } else { + printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", + ibm->name, status); + } + return -ENODEV; + } + ibm->notify_installed = 1; + return 0; +} + +static int __init ibm_device_add(struct acpi_device *device) +{ + return 0; +} + +static int __init register_driver(struct ibm_struct *ibm) +{ + int ret; + + ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); + if (!ibm->driver) { + printk(IBM_ERR "kmalloc(ibm->driver) failed\n"); + return -1; + } + + sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name); + ibm->driver->ids = ibm->hid; + ibm->driver->ops.add = &ibm_device_add; + + ret = acpi_bus_register_driver(ibm->driver); + if (ret < 0) { + printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", + ibm->hid, ret); + kfree(ibm->driver); + } + + return ret; +} + +static void ibm_exit(struct ibm_struct *ibm); + +static int __init ibm_init(struct ibm_struct *ibm) +{ + int ret; + struct proc_dir_entry *entry; + + if (ibm->experimental && !experimental) + return 0; + + if (ibm->hid) { + ret = register_driver(ibm); + if (ret < 0) + return ret; + ibm->driver_registered = 1; + } + + if (ibm->init) { + ret = ibm->init(); + if (ret != 0) + return ret; + ibm->init_called = 1; + } + + if (ibm->read) { + entry = create_proc_entry(ibm->name, + S_IFREG | S_IRUGO | S_IWUSR, + proc_dir); + if (!entry) { + printk(IBM_ERR "unable to create proc entry %s\n", + ibm->name); + return -ENODEV; + } + entry->owner = THIS_MODULE; + entry->data = ibm; + entry->read_proc = &dispatch_read; + if (ibm->write) + entry->write_proc = &dispatch_write; + ibm->proc_created = 1; + } + + if (ibm->notify) { + ret = setup_notify(ibm); + if (ret == -ENODEV) { + printk(IBM_NOTICE "disabling subdriver %s\n", + ibm->name); + ibm_exit(ibm); + return 0; + } + if (ret < 0) + return ret; + } + + return 0; +} + +static void ibm_exit(struct ibm_struct *ibm) +{ + if (ibm->notify_installed) + acpi_remove_notify_handler(*ibm->handle, ibm->type, + dispatch_notify); + + if (ibm->proc_created) + remove_proc_entry(ibm->name, proc_dir); + + if (ibm->init_called && ibm->exit) + ibm->exit(); + + if (ibm->driver_registered) { + acpi_bus_unregister_driver(ibm->driver); + kfree(ibm->driver); + } +} + +static void __init ibm_handle_init(char *name, + acpi_handle * handle, acpi_handle parent, + char **paths, int num_paths, char **path) +{ + int i; + acpi_status status; + + for (i = 0; i < num_paths; i++) { + status = acpi_get_handle(parent, paths[i], handle); + if (ACPI_SUCCESS(status)) { + *path = paths[i]; + return; + } + } + + *handle = NULL; +} + +#define IBM_HANDLE_INIT(object) \ + ibm_handle_init(#object, &object##_handle, *object##_parent, \ + object##_paths, ARRAY_SIZE(object##_paths), &object##_path) + +static int __init set_ibm_param(const char *val, struct kernel_param *kp) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ibms); i++) + if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) { + if (strlen(val) > sizeof(ibms[i].param) - 2) + return -ENOSPC; + strcpy(ibms[i].param, val); + strcat(ibms[i].param, ","); + return 0; + } + + return -EINVAL; +} + +#define IBM_PARAM(feature) \ + module_param_call(feature, set_ibm_param, NULL, NULL, 0) + +IBM_PARAM(hotkey); +IBM_PARAM(bluetooth); +IBM_PARAM(video); +IBM_PARAM(light); +#ifdef CONFIG_ACPI_IBM_DOCK +IBM_PARAM(dock); +#endif +#ifdef CONFIG_ACPI_IBM_BAY +IBM_PARAM(bay); +#endif /* CONFIG_ACPI_IBM_BAY */ +IBM_PARAM(cmos); +IBM_PARAM(led); +IBM_PARAM(beep); +IBM_PARAM(ecdump); +IBM_PARAM(brightness); +IBM_PARAM(volume); +IBM_PARAM(fan); + +static void acpi_ibm_exit(void) +{ + int i; + + for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) + ibm_exit(&ibms[i]); + + if (proc_dir) + remove_proc_entry(IBM_DIR, acpi_root_dir); + + if (ibm_thinkpad_ec_found) + kfree(ibm_thinkpad_ec_found); +} + +static char* __init check_dmi_for_ec(void) +{ + struct dmi_device *dev = NULL; + char ec_fw_string[18]; + + /* + * ThinkPad T23 or newer, A31 or newer, R50e or newer, + * X32 or newer, all Z series; Some models must have an + * up-to-date BIOS or they will not be detected. + * + * See http://thinkwiki.org/wiki/List_of_DMI_IDs + */ + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + if (sscanf(dev->name, + "IBM ThinkPad Embedded Controller -[%17c", + ec_fw_string) == 1) { + ec_fw_string[sizeof(ec_fw_string) - 1] = 0; + ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; + return kstrdup(ec_fw_string, GFP_KERNEL); + } + } + return NULL; +} + +static int __init acpi_ibm_init(void) +{ + int ret, i; + + if (acpi_disabled) + return -ENODEV; + + /* ec is required because many other handles are relative to it */ + IBM_HANDLE_INIT(ec); + if (!ec_handle) { + printk(IBM_ERR "ec object not found\n"); + return -ENODEV; + } + + /* Models with newer firmware report the EC in DMI */ + ibm_thinkpad_ec_found = check_dmi_for_ec(); + + /* these handles are not required */ + IBM_HANDLE_INIT(vid); + IBM_HANDLE_INIT(vid2); + IBM_HANDLE_INIT(ledb); + IBM_HANDLE_INIT(led); + IBM_HANDLE_INIT(hkey); + IBM_HANDLE_INIT(lght); + IBM_HANDLE_INIT(cmos); +#ifdef CONFIG_ACPI_IBM_DOCK + IBM_HANDLE_INIT(dock); +#endif + IBM_HANDLE_INIT(pci); +#ifdef CONFIG_ACPI_IBM_BAY + IBM_HANDLE_INIT(bay); + if (bay_handle) + IBM_HANDLE_INIT(bay_ej); + IBM_HANDLE_INIT(bay2); + if (bay2_handle) + IBM_HANDLE_INIT(bay2_ej); +#endif /* CONFIG_ACPI_IBM_BAY */ + IBM_HANDLE_INIT(beep); + IBM_HANDLE_INIT(ecrd); + IBM_HANDLE_INIT(ecwr); + IBM_HANDLE_INIT(fans); + IBM_HANDLE_INIT(gfan); + IBM_HANDLE_INIT(sfan); + + proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); + if (!proc_dir) { + printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + acpi_ibm_exit(); + return -ENODEV; + } + proc_dir->owner = THIS_MODULE; + + for (i = 0; i < ARRAY_SIZE(ibms); i++) { + ret = ibm_init(&ibms[i]); + if (ret >= 0 && *ibms[i].param) + ret = ibms[i].write(ibms[i].param); + if (ret < 0) { + acpi_ibm_exit(); + return ret; + } + } + + return 0; +} + +module_init(acpi_ibm_init); +module_exit(acpi_ibm_exit); diff --git a/trunk/drivers/acpi/processor_core.c b/trunk/drivers/acpi/processor_core.c index f7de02a6f497..99d1516d1e70 100644 --- a/trunk/drivers/acpi/processor_core.c +++ b/trunk/drivers/acpi/processor_core.c @@ -70,6 +70,8 @@ #define ACPI_PROCESSOR_LIMIT_USER 0 #define ACPI_PROCESSOR_LIMIT_THERMAL 1 +#define ACPI_STA_PRESENT 0x00000001 + #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); @@ -777,7 +779,7 @@ static int is_processor_present(acpi_handle handle) status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) { + if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) { ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); return 0; } diff --git a/trunk/drivers/acpi/processor_idle.c b/trunk/drivers/acpi/processor_idle.c index ee5759bef945..cdf78943af4d 100644 --- a/trunk/drivers/acpi/processor_idle.c +++ b/trunk/drivers/acpi/processor_idle.c @@ -51,6 +51,14 @@ #include #endif +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + */ +#ifdef CONFIG_X86 +#include +#endif + #include #include @@ -475,7 +483,7 @@ static void acpi_processor_idle(void) #ifdef CONFIG_GENERIC_TIME /* TSC halts in C2, so notify users */ - mark_tsc_unstable("possible TSC halt in C2"); + mark_tsc_unstable(); #endif /* Re-enable interrupts */ local_irq_enable(); @@ -517,7 +525,7 @@ static void acpi_processor_idle(void) #ifdef CONFIG_GENERIC_TIME /* TSC halts in C3, so notify users */ - mark_tsc_unstable("TSC halts in C3"); + mark_tsc_unstable(); #endif /* Re-enable interrupts */ local_irq_enable(); diff --git a/trunk/drivers/acpi/processor_perflib.c b/trunk/drivers/acpi/processor_perflib.c index c4efc0c17f8f..2f2e7964226d 100644 --- a/trunk/drivers/acpi/processor_perflib.c +++ b/trunk/drivers/acpi/processor_perflib.c @@ -433,6 +433,49 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } +static ssize_t +acpi_processor_write_performance(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + int result = 0; + struct seq_file *m = file->private_data; + struct acpi_processor *pr = m->private; + struct acpi_processor_performance *perf; + char state_string[12] = { '\0' }; + unsigned int new_state = 0; + struct cpufreq_policy policy; + + + if (!pr || (count > sizeof(state_string) - 1)) + return -EINVAL; + + perf = pr->performance; + if (!perf) + return -EINVAL; + + if (copy_from_user(state_string, buffer, count)) + return -EFAULT; + + state_string[count] = '\0'; + new_state = simple_strtoul(state_string, NULL, 0); + + if (new_state >= perf->state_count) + return -EINVAL; + + cpufreq_get_policy(&policy, pr->id); + + policy.cpu = pr->id; + policy.min = perf->states[new_state].core_frequency * 1000; + policy.max = perf->states[new_state].core_frequency * 1000; + + result = cpufreq_set_policy(&policy); + if (result) + return result; + + return count; +} + static void acpi_cpufreq_add_file(struct acpi_processor *pr) { struct proc_dir_entry *entry = NULL; @@ -444,9 +487,10 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) /* add file 'performance' [R/W] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG | S_IRUGO, + S_IFREG | S_IRUGO | S_IWUSR, acpi_device_dir(device)); if (entry){ + acpi_processor_perf_fops.write = acpi_processor_write_performance; entry->proc_fops = &acpi_processor_perf_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; diff --git a/trunk/drivers/acpi/sbs.c b/trunk/drivers/acpi/sbs.c index c1bae106833c..59640d9a0acc 100644 --- a/trunk/drivers/acpi/sbs.c +++ b/trunk/drivers/acpi/sbs.c @@ -30,10 +30,30 @@ #include #include #include -#include -#include +#include #include +#include "i2c_ec.h" + +#define DEF_CAPACITY_UNIT 3 +#define MAH_CAPACITY_UNIT 1 +#define MWH_CAPACITY_UNIT 2 +#define CAPACITY_UNIT DEF_CAPACITY_UNIT + +#define REQUEST_UPDATE_MODE 1 +#define QUEUE_UPDATE_MODE 2 + +#define DATA_TYPE_COMMON 0 +#define DATA_TYPE_INFO 1 +#define DATA_TYPE_STATE 2 +#define DATA_TYPE_ALARM 3 +#define DATA_TYPE_AC_STATE 4 + +extern struct proc_dir_entry *acpi_lock_ac_dir(void); +extern struct proc_dir_entry *acpi_lock_battery_dir(void); +extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); +extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); + #define ACPI_SBS_COMPONENT 0x00080000 #define ACPI_SBS_CLASS "sbs" #define ACPI_AC_CLASS "ac_adapter" @@ -54,75 +74,39 @@ #define _COMPONENT ACPI_SBS_COMPONENT +#define MAX_SBS_BAT 4 +#define MAX_SMBUS_ERR 1 + ACPI_MODULE_NAME("sbs"); MODULE_AUTHOR("Rich Townsend"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); MODULE_LICENSE("GPL"); -#define xmsleep(t) msleep(t) - -#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */ - -#define ACPI_EC_SMB_STS 0x01 /* status */ -#define ACPI_EC_SMB_ADDR 0x02 /* address */ -#define ACPI_EC_SMB_CMD 0x03 /* command */ -#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */ -#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */ +static struct semaphore sbs_sem; -#define ACPI_EC_SMB_STS_DONE 0x80 -#define ACPI_EC_SMB_STS_STATUS 0x1f +#define UPDATE_MODE QUEUE_UPDATE_MODE +/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */ +#define UPDATE_INFO_MODE 0 +#define UPDATE_TIME 60 +#define UPDATE_TIME2 0 -#define ACPI_EC_SMB_PRTCL_WRITE 0x00 -#define ACPI_EC_SMB_PRTCL_READ 0x01 -#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08 -#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a +static int capacity_mode = CAPACITY_UNIT; +static int update_mode = UPDATE_MODE; +static int update_info_mode = UPDATE_INFO_MODE; +static int update_time = UPDATE_TIME; +static int update_time2 = UPDATE_TIME2; -#define ACPI_EC_SMB_TRANSACTION_SLEEP 1 -#define ACPI_EC_SMB_ACCESS_SLEEP1 1 -#define ACPI_EC_SMB_ACCESS_SLEEP2 10 - -#define DEF_CAPACITY_UNIT 3 -#define MAH_CAPACITY_UNIT 1 -#define MWH_CAPACITY_UNIT 2 -#define CAPACITY_UNIT DEF_CAPACITY_UNIT - -#define REQUEST_UPDATE_MODE 1 -#define QUEUE_UPDATE_MODE 2 - -#define DATA_TYPE_COMMON 0 -#define DATA_TYPE_INFO 1 -#define DATA_TYPE_STATE 2 -#define DATA_TYPE_ALARM 3 -#define DATA_TYPE_AC_STATE 4 - -extern struct proc_dir_entry *acpi_lock_ac_dir(void); -extern struct proc_dir_entry *acpi_lock_battery_dir(void); -extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); -extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); - -#define MAX_SBS_BAT 4 -#define ACPI_SBS_BLOCK_MAX 32 - -#define ACPI_SBS_SMBUS_READ 1 -#define ACPI_SBS_SMBUS_WRITE 2 - -#define ACPI_SBS_WORD_DATA 1 -#define ACPI_SBS_BLOCK_DATA 2 - -#define UPDATE_DELAY 10 - -/* 0 - every time, > 0 - by update_time */ -static unsigned int update_time = 120; - -static unsigned int capacity_mode = CAPACITY_UNIT; - -module_param(update_time, uint, 0644); -module_param(capacity_mode, uint, 0444); +module_param(capacity_mode, int, 0); +module_param(update_mode, int, 0); +module_param(update_info_mode, int, 0); +module_param(update_time, int, 0); +module_param(update_time2, int, 0); static int acpi_sbs_add(struct acpi_device *device); static int acpi_sbs_remove(struct acpi_device *device, int type); -static int acpi_sbs_resume(struct acpi_device *device); +static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus); +static void acpi_sbs_update_queue(void *data); static struct acpi_driver acpi_sbs_driver = { .name = "sbs", @@ -131,14 +115,9 @@ static struct acpi_driver acpi_sbs_driver = { .ops = { .add = acpi_sbs_add, .remove = acpi_sbs_remove, - .resume = acpi_sbs_resume, }, }; -struct acpi_ac { - int ac_present; -}; - struct acpi_battery_info { int capacity_mode; s16 full_charge_capacity; @@ -147,16 +126,18 @@ struct acpi_battery_info { int vscale; int ipscale; s16 serial_number; - char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_name[ACPI_SBS_BLOCK_MAX + 3]; - char device_chemistry[ACPI_SBS_BLOCK_MAX + 3]; + char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3]; + char device_name[I2C_SMBUS_BLOCK_MAX + 3]; + char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3]; }; struct acpi_battery_state { s16 voltage; s16 amperage; s16 remaining_capacity; - s16 battery_state; + s16 average_time_to_empty; + s16 average_time_to_full; + s16 battery_status; }; struct acpi_battery_alarm { @@ -165,9 +146,9 @@ struct acpi_battery_alarm { struct acpi_battery { int alive; + int battery_present; int id; int init_state; - int battery_present; struct acpi_sbs *sbs; struct acpi_battery_info info; struct acpi_battery_state state; @@ -177,251 +158,186 @@ struct acpi_battery { struct acpi_sbs { acpi_handle handle; - int base; struct acpi_device *device; struct acpi_ec_smbus *smbus; - struct mutex mutex; int sbsm_present; int sbsm_batteries_supported; + int ac_present; struct proc_dir_entry *ac_entry; - struct acpi_ac ac; struct acpi_battery battery[MAX_SBS_BAT]; + int update_info_mode; int zombie; + int update_time; + int update_time2; struct timer_list update_timer; - int run_cnt; - int update_proc_flg; }; -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type); -static void acpi_sbs_update_time(void *data); - -union sbs_rw_data { - u16 word; - u8 block[ACPI_SBS_BLOCK_MAX + 2]; -}; - -static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data); +static void acpi_update_delay(struct acpi_sbs *sbs); +static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type); /* -------------------------------------------------------------------------- SMBus Communication -------------------------------------------------------------------------- */ -static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data) +static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus) { - u8 val; - int err; - - err = ec_read(sbs->base + address, &val); - if (!err) { - *data = val; - } - xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP); - return (err); -} - -static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data) -{ - int err; - - err = ec_write(sbs->base + address, data); - return (err); -} + union i2c_smbus_data data; + int result = 0; + char *err_str; + int err_number; -static int -acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr, - char read_write, u8 command, int size, - union sbs_rw_data *data) -{ - unsigned char protocol, len = 0, temp[2] = { 0, 0 }; - int i; + data.word = 0; - if (read_write == ACPI_SBS_SMBUS_READ) { - protocol = ACPI_EC_SMB_PRTCL_READ; - } else { - protocol = ACPI_EC_SMB_PRTCL_WRITE; - } + result = smbus->adapter.algo-> + smbus_xfer(&smbus->adapter, + ACPI_SB_SMBUS_ADDR, + 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data); - switch (size) { + err_number = (data.word & 0x000f); - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1, - data->word >> 8); - } - protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA; + switch (data.word & 0x000f) { + case 0x0000: + err_str = "unexpected bus error"; break; - case ACPI_SBS_BLOCK_DATA: - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command); - if (read_write == ACPI_SBS_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len); - for (i = 0; i < len; i++) - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i, - data->block[i + 1]); - } - protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA; + case 0x0001: + err_str = "busy"; break; - default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); - } - - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1); - acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol); - - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if (~temp[0] & ACPI_EC_SMB_STS_DONE) { - xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp); - } - if ((~temp[0] & ACPI_EC_SMB_STS_DONE) - || (temp[0] & ACPI_EC_SMB_STS_STATUS)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "transaction %d error", size)); - return (-1); - } - - if (read_write == ACPI_SBS_SMBUS_WRITE) { - return (0); - } - - switch (size) { - - case ACPI_SBS_WORD_DATA: - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp); - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1); - data->word = (temp[1] << 8) | temp[0]; + case 0x0002: + err_str = "reserved command"; break; - - case ACPI_SBS_BLOCK_DATA: - len = 0; - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len); - len = min_t(u8, len, 32); - for (i = 0; i < len; i++) - acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i, - data->block + i + 1); - data->block[0] = len; + case 0x0003: + err_str = "unsupported command"; + break; + case 0x0004: + err_str = "access denied"; + break; + case 0x0005: + err_str = "overflow/underflow"; + break; + case 0x0006: + err_str = "bad size"; + break; + case 0x0007: + err_str = "unknown error"; break; default: - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "unsupported transaction %d", size)); - return (-1); + err_str = "unrecognized error"; } - - return (0); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "%s: ret %i, err %i\n", err_str, result, err_number)); } static int -acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word) +acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func, + u16 * word, + void (*err_handler) (struct acpi_ec_smbus * smbus)) { - union sbs_rw_data data; + union i2c_smbus_data data; int result = 0; + int i; - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - *word = data.word; + if (err_handler == NULL) { + err_handler = acpi_battery_smbus_err_handler; + } + + for (i = 0; i < MAX_SMBUS_ERR; i++) { + result = + smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0, + I2C_SMBUS_READ, func, + I2C_SMBUS_WORD_DATA, &data); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "try %i: smbus->adapter.algo->smbus_xfer() failed\n", + i)); + if (err_handler) { + err_handler(smbus); + } + } else { + *word = data.word; + break; + } } return result; } static int -acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str) +acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func, + char *str, + void (*err_handler) (struct acpi_ec_smbus * smbus)) { - union sbs_rw_data data; + union i2c_smbus_data data; int result = 0; + int i; - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_READ, func, - ACPI_SBS_BLOCK_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); - } else { - strncpy(str, (const char *)data.block + 1, data.block[0]); - str[data.block[0]] = 0; + if (err_handler == NULL) { + err_handler = acpi_battery_smbus_err_handler; + } + + for (i = 0; i < MAX_SMBUS_ERR; i++) { + result = + smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0, + I2C_SMBUS_READ, func, + I2C_SMBUS_BLOCK_DATA, + &data); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "try %i: smbus->adapter.algo->smbus_xfer() failed\n", + i)); + if (err_handler) { + err_handler(smbus); + } + } else { + strncpy(str, (const char *)data.block + 1, + data.block[0]); + str[data.block[0]] = 0; + break; + } } return result; } static int -acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word) +acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func, + int word, + void (*err_handler) (struct acpi_ec_smbus * smbus)) { - union sbs_rw_data data; + union i2c_smbus_data data; int result = 0; + int i; - data.word = word; - - result = acpi_ec_sbs_access(sbs, addr, - ACPI_SBS_SMBUS_WRITE, func, - ACPI_SBS_WORD_DATA, &data); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ec_sbs_access() failed")); + if (err_handler == NULL) { + err_handler = acpi_battery_smbus_err_handler; } - return result; -} - -static int sbs_zombie(struct acpi_sbs *sbs) -{ - return (sbs->zombie); -} + data.word = word; -static int sbs_mutex_lock(struct acpi_sbs *sbs) -{ - if (sbs_zombie(sbs)) { - return -ENODEV; + for (i = 0; i < MAX_SMBUS_ERR; i++) { + result = + smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0, + I2C_SMBUS_WRITE, func, + I2C_SMBUS_WORD_DATA, &data); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "try %i: smbus->adapter.algo" + "->smbus_xfer() failed\n", i)); + if (err_handler) { + err_handler(smbus); + } + } else { + break; + } } - mutex_lock(&sbs->mutex); - return 0; -} -static void sbs_mutex_unlock(struct acpi_sbs *sbs) -{ - mutex_unlock(&sbs->mutex); + return result; } /* -------------------------------------------------------------------------- Smart Battery System Management -------------------------------------------------------------------------- */ -static int acpi_check_update_proc(struct acpi_sbs *sbs) -{ - acpi_status status = AE_OK; - - if (update_time == 0) { - sbs->update_proc_flg = 0; - return 0; - } - if (sbs->update_proc_flg == 0) { - status = acpi_os_execute(OSL_GPE_HANDLER, - acpi_sbs_update_time, sbs); - if (status != AE_OK) { - ACPI_EXCEPTION((AE_INFO, status, - "acpi_os_execute() failed")); - return 1; - } - sbs->update_proc_flg = 1; - } - return 0; -} +/* Smart Battery */ static int acpi_sbs_generate_event(struct acpi_device *device, int event, int state, char *bid, char *class) @@ -450,11 +366,12 @@ static int acpi_battery_get_present(struct acpi_battery *battery) int result = 0; int is_present = 0; - result = acpi_sbs_read_word(battery->sbs, - ACPI_SBSM_SMBUS_ADDR, 0x01, &state); + result = acpi_sbs_smbus_read_word(battery->sbs->smbus, + ACPI_SBSM_SMBUS_ADDR, 0x01, + &state, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed")); } if (!result) { is_present = (state & 0x000f) & (1 << battery->id); @@ -464,33 +381,45 @@ static int acpi_battery_get_present(struct acpi_battery *battery) return result; } +static int acpi_battery_is_present(struct acpi_battery *battery) +{ + return (battery->battery_present); +} + +static int acpi_ac_is_present(struct acpi_sbs *sbs) +{ + return (sbs->ac_present); +} + static int acpi_battery_select(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; + struct acpi_ec_smbus *smbus = battery->sbs->smbus; int result = 0; s16 state; int foo; - if (sbs->sbsm_present) { + if (battery->sbs->sbsm_present) { /* Take special care not to knobble other nibbles of * state (aka selector_state), since * it causes charging to halt on SBSELs */ result = - acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state); + acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01, + &state, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } foo = (state & 0x0fff) | (1 << (battery->id + 12)); result = - acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo); + acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01, + foo, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_write_word() failed\n")); goto end; } } @@ -501,14 +430,15 @@ static int acpi_battery_select(struct acpi_battery *battery) static int acpi_sbsm_get_info(struct acpi_sbs *sbs) { + struct acpi_ec_smbus *smbus = sbs->smbus; int result = 0; s16 battery_system_info; - result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04, - &battery_system_info); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04, + &battery_system_info, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } @@ -521,50 +451,53 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) static int acpi_battery_get_info(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; + struct acpi_ec_smbus *smbus = battery->sbs->smbus; int result = 0; s16 battery_mode; s16 specification_info; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03, + &battery_mode, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } battery->info.capacity_mode = (battery_mode & 0x8000) >> 15; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10, - &battery->info.full_charge_capacity); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10, + &battery->info.full_charge_capacity, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18, - &battery->info.design_capacity); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18, + &battery->info.design_capacity, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19, - &battery->info.design_voltage); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19, + &battery->info.design_voltage, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a, - &specification_info); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a, + &specification_info, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } @@ -596,35 +529,37 @@ static int acpi_battery_get_info(struct acpi_battery *battery) battery->info.ipscale = 1; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c, - &battery->info.serial_number); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c, + &battery->info.serial_number, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20, - battery->info.manufacturer_name); + result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20, + battery->info.manufacturer_name, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_str() failed\n")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21, - battery->info.device_name); + result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21, + battery->info.device_name, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_str() failed\n")); goto end; } - result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22, - battery->info.device_chemistry); + result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22, + battery->info.device_chemistry, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_str() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_str() failed\n")); goto end; } @@ -632,60 +567,103 @@ static int acpi_battery_get_info(struct acpi_battery *battery) return result; } +static void acpi_update_delay(struct acpi_sbs *sbs) +{ + if (sbs->zombie) { + return; + } + if (sbs->update_time2 > 0) { + msleep(sbs->update_time2 * 1000); + } +} + static int acpi_battery_get_state(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; + struct acpi_ec_smbus *smbus = battery->sbs->smbus; int result = 0; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09, - &battery->state.voltage); + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09, + &battery->state.voltage, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a, - &battery->state.amperage); + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a, + &battery->state.amperage, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f, - &battery->state.remaining_capacity); + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f, + &battery->state.remaining_capacity, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16, - &battery->state.battery_state); + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12, + &battery->state.average_time_to_empty, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13, + &battery->state.average_time_to_full, + &acpi_battery_smbus_err_handler); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); + goto end; + } + + acpi_update_delay(battery->sbs); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16, + &battery->state.battery_status, + &acpi_battery_smbus_err_handler); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); + goto end; + } + + acpi_update_delay(battery->sbs); + end: return result; } static int acpi_battery_get_alarm(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; + struct acpi_ec_smbus *smbus = battery->sbs->smbus; int result = 0; - result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - &battery->alarm.remaining_capacity); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01, + &battery->alarm.remaining_capacity, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } + acpi_update_delay(battery->sbs); + end: return result; @@ -694,15 +672,15 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) { - struct acpi_sbs *sbs = battery->sbs; + struct acpi_ec_smbus *smbus = battery->sbs->smbus; int result = 0; s16 battery_mode; int foo; result = acpi_battery_select(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_select() failed\n")); goto end; } @@ -710,29 +688,33 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, if (alarm > 0) { result = - acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03, - &battery_mode); + acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03, + &battery_mode, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } result = - acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, - battery_mode & 0xbfff); + acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01, + battery_mode & 0xbfff, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_write_word() failed\n")); goto end; } } foo = alarm / (battery->info.capacity_mode ? 10 : 1); - result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo); + result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01, + foo, + &acpi_battery_smbus_err_handler); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_write_word() failed\n")); goto end; } @@ -743,7 +725,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery, static int acpi_battery_set_mode(struct acpi_battery *battery) { - struct acpi_sbs *sbs = battery->sbs; int result = 0; s16 battery_mode; @@ -751,11 +732,12 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) goto end; } - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); + result = acpi_sbs_smbus_read_word(battery->sbs->smbus, + ACPI_SB_SMBUS_ADDR, 0x03, + &battery_mode, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } @@ -764,19 +746,21 @@ static int acpi_battery_set_mode(struct acpi_battery *battery) } else { battery_mode |= 0x8000; } - result = acpi_sbs_write_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, battery_mode); + result = acpi_sbs_smbus_write_word(battery->sbs->smbus, + ACPI_SB_SMBUS_ADDR, 0x03, + battery_mode, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_write_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_write_word() failed\n")); goto end; } - result = acpi_sbs_read_word(sbs, - ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode); + result = acpi_sbs_smbus_read_word(battery->sbs->smbus, + ACPI_SB_SMBUS_ADDR, 0x03, + &battery_mode, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } @@ -790,36 +774,36 @@ static int acpi_battery_init(struct acpi_battery *battery) result = acpi_battery_select(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_init() failed\n")); goto end; } result = acpi_battery_set_mode(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_mode() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_set_mode() failed\n")); goto end; } result = acpi_battery_get_info(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_info() failed\n")); goto end; } result = acpi_battery_get_state(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_state() failed\n")); goto end; } result = acpi_battery_get_alarm(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_alarm() failed\n")); goto end; } @@ -829,19 +813,20 @@ static int acpi_battery_init(struct acpi_battery *battery) static int acpi_ac_get_present(struct acpi_sbs *sbs) { + struct acpi_ec_smbus *smbus = sbs->smbus; int result = 0; s16 charger_status; - result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13, - &charger_status); + result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13, + &charger_status, NULL); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_read_word() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_smbus_read_word() failed\n")); goto end; } - sbs->ac.ac_present = (charger_status & 0x8000) >> 15; + sbs->ac_present = (charger_status & 0x8000) >> 15; end: @@ -867,8 +852,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "proc_mkdir() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "proc_mkdir() failed\n")); return -ENODEV; } (*dir)->owner = THIS_MODULE; @@ -878,8 +863,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, if (info_fops) { entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "create_proc_entry() failed\n")); } else { entry->proc_fops = info_fops; entry->data = data; @@ -891,8 +876,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, if (state_fops) { entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "create_proc_entry() failed\n")); } else { entry->proc_fops = state_fops; entry->data = data; @@ -904,8 +889,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir, if (alarm_fops) { entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); if (!entry) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "create_proc_entry() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "create_proc_entry() failed\n")); } else { entry->proc_fops = alarm_fops; entry->data = data; @@ -938,27 +923,24 @@ static struct proc_dir_entry *acpi_battery_dir = NULL; static int acpi_battery_read_info(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; - struct acpi_sbs *sbs = battery->sbs; int cscale; int result = 0; - if (sbs_mutex_lock(sbs)) { + if (battery->sbs->zombie) { return -ENODEV; } - result = acpi_check_update_proc(sbs); - if (result) - goto end; + down(&sbs_sem); - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO); + if (update_mode == REQUEST_UPDATE_MODE) { + result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_update_run() failed\n")); } } - if (battery->battery_present) { + if (acpi_battery_is_present(battery)) { seq_printf(seq, "present: yes\n"); } else { seq_printf(seq, "present: no\n"); @@ -970,13 +952,13 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) } else { cscale = battery->info.ipscale; } - seq_printf(seq, "design capacity: %i%s\n", + seq_printf(seq, "design capacity: %i%s", battery->info.design_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->info.capacity_mode ? "0 mWh\n" : " mAh\n"); - seq_printf(seq, "last full capacity: %i%s\n", + seq_printf(seq, "last full capacity: %i%s", battery->info.full_charge_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->info.capacity_mode ? "0 mWh\n" : " mAh\n"); seq_printf(seq, "battery technology: rechargeable\n"); @@ -1002,7 +984,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) end: - sbs_mutex_unlock(sbs); + up(&sbs_sem); return result; } @@ -1014,29 +996,26 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) static int acpi_battery_read_state(struct seq_file *seq, void *offset) { - struct acpi_battery *battery = seq->private; - struct acpi_sbs *sbs = battery->sbs; + struct acpi_battery *battery = (struct acpi_battery *)seq->private; int result = 0; int cscale; int foo; - if (sbs_mutex_lock(sbs)) { + if (battery->sbs->zombie) { return -ENODEV; } - result = acpi_check_update_proc(sbs); - if (result) - goto end; + down(&sbs_sem); - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE); + if (update_mode == REQUEST_UPDATE_MODE) { + result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_update_run() failed\n")); } } - if (battery->battery_present) { + if (acpi_battery_is_present(battery)) { seq_printf(seq, "present: yes\n"); } else { seq_printf(seq, "present: no\n"); @@ -1049,7 +1028,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) cscale = battery->info.ipscale; } - if (battery->state.battery_state & 0x0010) { + if (battery->state.battery_status & 0x0010) { seq_printf(seq, "capacity state: critical\n"); } else { seq_printf(seq, "capacity state: ok\n"); @@ -1073,16 +1052,16 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) battery->info.capacity_mode ? "mW" : "mA"); } - seq_printf(seq, "remaining capacity: %i%s\n", + seq_printf(seq, "remaining capacity: %i%s", battery->state.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->info.capacity_mode ? "0 mWh\n" : " mAh\n"); seq_printf(seq, "present voltage: %i mV\n", battery->state.voltage * battery->info.vscale); end: - sbs_mutex_unlock(sbs); + up(&sbs_sem); return result; } @@ -1095,27 +1074,24 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; - struct acpi_sbs *sbs = battery->sbs; int result = 0; int cscale; - if (sbs_mutex_lock(sbs)) { + if (battery->sbs->zombie) { return -ENODEV; } - result = acpi_check_update_proc(sbs); - if (result) - goto end; + down(&sbs_sem); - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM); + if (update_mode == REQUEST_UPDATE_MODE) { + result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_update_run() failed\n")); } } - if (!battery->battery_present) { + if (!acpi_battery_is_present(battery)) { seq_printf(seq, "present: no\n"); goto end; } @@ -1128,16 +1104,16 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) seq_printf(seq, "alarm: "); if (battery->alarm.remaining_capacity) { - seq_printf(seq, "%i%s\n", + seq_printf(seq, "%i%s", battery->alarm.remaining_capacity * cscale, - battery->info.capacity_mode ? "0 mWh" : " mAh"); + battery->info.capacity_mode ? "0 mWh\n" : " mAh\n"); } else { seq_printf(seq, "disabled\n"); } end: - sbs_mutex_unlock(sbs); + up(&sbs_sem); return result; } @@ -1148,19 +1124,16 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, { struct seq_file *seq = file->private_data; struct acpi_battery *battery = seq->private; - struct acpi_sbs *sbs = battery->sbs; char alarm_string[12] = { '\0' }; int result, old_alarm, new_alarm; - if (sbs_mutex_lock(sbs)) { + if (battery->sbs->zombie) { return -ENODEV; } - result = acpi_check_update_proc(sbs); - if (result) - goto end; + down(&sbs_sem); - if (!battery->battery_present) { + if (!acpi_battery_is_present(battery)) { result = -ENODEV; goto end; } @@ -1182,21 +1155,21 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, result = acpi_battery_set_alarm(battery, new_alarm); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_set_alarm() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_set_alarm() failed\n")); acpi_battery_set_alarm(battery, old_alarm); goto end; } result = acpi_battery_get_alarm(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_alarm() failed\n")); acpi_battery_set_alarm(battery, old_alarm); goto end; } end: - sbs_mutex_unlock(sbs); + up(&sbs_sem); if (result) { return result; @@ -1244,22 +1217,24 @@ static int acpi_ac_read_state(struct seq_file *seq, void *offset) struct acpi_sbs *sbs = seq->private; int result; - if (sbs_mutex_lock(sbs)) { + if (sbs->zombie) { return -ENODEV; } - if (update_time == 0) { - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE); + down(&sbs_sem); + + if (update_mode == REQUEST_UPDATE_MODE) { + result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_update_run() failed\n")); } } seq_printf(seq, "state: %s\n", - sbs->ac.ac_present ? "on-line" : "off-line"); + sbs->ac_present ? "on-line" : "off-line"); - sbs_mutex_unlock(sbs); + up(&sbs_sem); return 0; } @@ -1300,25 +1275,25 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) result = acpi_battery_select(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_select() failed\n")); goto end; } result = acpi_battery_get_present(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_present() failed\n")); goto end; } - is_present = battery->battery_present; + is_present = acpi_battery_is_present(battery); if (is_present) { result = acpi_battery_init(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_init() failed\n")); goto end; } battery->init_state = 1; @@ -1333,16 +1308,12 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) &acpi_battery_state_fops, &acpi_battery_alarm_fops, battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_generic_add_fs() failed\n")); goto end; } battery->alive = 1; - printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", - ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name, - sbs->battery->battery_present ? "present" : "absent"); - end: return result; } @@ -1362,8 +1333,8 @@ static int acpi_ac_add(struct acpi_sbs *sbs) result = acpi_ac_get_present(sbs); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_ac_get_present() failed\n")); goto end; } @@ -1372,15 +1343,11 @@ static int acpi_ac_add(struct acpi_sbs *sbs) ACPI_AC_DIR_NAME, NULL, &acpi_ac_state_fops, NULL, sbs); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generic_add_fs() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_generic_add_fs() failed\n")); goto end; } - printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", - ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), - ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line"); - end: return result; @@ -1394,85 +1361,45 @@ static void acpi_ac_remove(struct acpi_sbs *sbs) } } -static void acpi_sbs_update_time_run(unsigned long data) +static void acpi_sbs_update_queue_run(unsigned long data) { - acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data); + acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data); } -static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) +static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type) { struct acpi_battery *battery; - int result = 0, cnt; - int old_ac_present = -1; - int old_battery_present = -1; - int new_ac_present = -1; - int new_battery_present = -1; - int id_min = 0, id_max = MAX_SBS_BAT - 1; + int result = 0; + int old_ac_present; + int old_battery_present; + int new_ac_present; + int new_battery_present; + int id; char dir_name[32]; - int do_battery_init = 0, do_ac_init = 0; - int old_remaining_capacity = 0; - int update_ac = 1, update_battery = 1; - int up_tm = update_time; + int do_battery_init, do_ac_init; + s16 old_remaining_capacity; - if (sbs_zombie(sbs)) { + if (sbs->zombie) { goto end; } - if (id >= 0) { - id_min = id_max = id; - } - - if (data_type == DATA_TYPE_COMMON && up_tm > 0) { - cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - if (sbs->run_cnt % cnt != 0) { - update_battery = 0; - } - } - - sbs->run_cnt++; - - if (!update_ac && !update_battery) { - goto end; - } - - old_ac_present = sbs->ac.ac_present; + old_ac_present = acpi_ac_is_present(sbs); result = acpi_ac_get_present(sbs); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_ac_get_present() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_ac_get_present() failed\n")); } - new_ac_present = sbs->ac.ac_present; + new_ac_present = acpi_ac_is_present(sbs); do_ac_init = (old_ac_present != new_ac_present); - if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) { - do_ac_init = 1; - } - if (do_ac_init) { - result = acpi_sbs_generate_event(sbs->device, - ACPI_SBS_AC_NOTIFY_STATUS, - new_ac_present, - ACPI_AC_DIR_NAME, - ACPI_AC_CLASS); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() failed")); - } - } - - if (data_type == DATA_TYPE_COMMON) { - if (!do_ac_init && !update_battery) { - goto end; - } - } - - if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) { + if (data_type == DATA_TYPE_AC_STATE) { goto end; } - for (id = id_min; id <= id_max; id++) { + for (id = 0; id < MAX_SBS_BAT; id++) { battery = &sbs->battery[id]; if (battery->alive == 0) { continue; @@ -1480,92 +1407,94 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) old_remaining_capacity = battery->state.remaining_capacity; - old_battery_present = battery->battery_present; + old_battery_present = acpi_battery_is_present(battery); result = acpi_battery_select(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_select() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_select() failed\n")); + } + if (sbs->zombie) { + goto end; } result = acpi_battery_get_present(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_present() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_present() failed\n")); + } + if (sbs->zombie) { + goto end; } - new_battery_present = battery->battery_present; + new_battery_present = acpi_battery_is_present(battery); do_battery_init = ((old_battery_present != new_battery_present) && new_battery_present); - if (!new_battery_present) - goto event; - if (do_ac_init || do_battery_init) { - result = acpi_battery_init(battery); - if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_init() " - "failed")); - } - } - if (sbs_zombie(sbs)) { + + if (sbs->zombie) { goto end; } - - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_INFO) - && new_battery_present) { - result = acpi_battery_get_info(battery); + if (do_ac_init || do_battery_init || + update_info_mode || sbs->update_info_mode) { + if (sbs->update_info_mode) { + sbs->update_info_mode = 0; + } else { + sbs->update_info_mode = 1; + } + result = acpi_battery_init(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_info() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_init() " + "failed\n")); } } if (data_type == DATA_TYPE_INFO) { continue; } - if (sbs_zombie(sbs)) { + + if (sbs->zombie) { goto end; } + if (new_battery_present) { + result = acpi_battery_get_alarm(battery); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_alarm() " + "failed\n")); + } + if (data_type == DATA_TYPE_ALARM) { + continue; + } - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_STATE) - && new_battery_present) { result = acpi_battery_get_state(battery); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_state() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_get_state() " + "failed\n")); } } - if (data_type == DATA_TYPE_STATE) { - goto event; - } - if (sbs_zombie(sbs)) { + if (sbs->zombie) { goto end; } + if (data_type != DATA_TYPE_COMMON) { + continue; + } - if ((data_type == DATA_TYPE_COMMON - || data_type == DATA_TYPE_ALARM) - && new_battery_present) { - result = acpi_battery_get_alarm(battery); + if (old_battery_present != new_battery_present) { + sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); + result = acpi_sbs_generate_event(sbs->device, + ACPI_SBS_BATTERY_NOTIFY_STATUS, + new_battery_present, + dir_name, + ACPI_BATTERY_CLASS); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_get_alarm() " - "failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_generate_event() " + "failed\n")); } } - if (data_type == DATA_TYPE_ALARM) { - continue; - } - if (sbs_zombie(sbs)) { - goto end; - } - - event: - - if (old_battery_present != new_battery_present || do_ac_init || - old_remaining_capacity != - battery->state.remaining_capacity) { + if (old_remaining_capacity != battery->state.remaining_capacity) { sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id); result = acpi_sbs_generate_event(sbs->device, ACPI_SBS_BATTERY_NOTIFY_STATUS, @@ -1573,120 +1502,138 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type) dir_name, ACPI_BATTERY_CLASS); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_generate_event() " - "failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_generate_event() failed\n")); } } + + } + if (sbs->zombie) { + goto end; + } + if (data_type != DATA_TYPE_COMMON) { + goto end; } - end: + if (old_ac_present != new_ac_present) { + result = acpi_sbs_generate_event(sbs->device, + ACPI_SBS_AC_NOTIFY_STATUS, + new_ac_present, + ACPI_AC_DIR_NAME, + ACPI_AC_CLASS); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_generate_event() failed\n")); + } + } + end: return result; } -static void acpi_sbs_update_time(void *data) +static void acpi_sbs_update_queue(void *data) { struct acpi_sbs *sbs = data; unsigned long delay = -1; int result; - unsigned int up_tm = update_time; - if (sbs_mutex_lock(sbs)) - return; + if (sbs->zombie) { + goto end; + } - result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON); + result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_update_run() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_update_run() failed\n")); } - if (sbs_zombie(sbs)) { + if (sbs->zombie) { goto end; } - if (!up_tm) { - if (timer_pending(&sbs->update_timer)) - del_timer(&sbs->update_timer); - } else { - delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm); - delay = jiffies + HZ * delay; - if (timer_pending(&sbs->update_timer)) { - mod_timer(&sbs->update_timer, delay); - } else { - sbs->update_timer.data = (unsigned long)data; - sbs->update_timer.function = acpi_sbs_update_time_run; - sbs->update_timer.expires = delay; - add_timer(&sbs->update_timer); - } + if (update_mode == REQUEST_UPDATE_MODE) { + goto end; } + delay = jiffies + HZ * update_time; + sbs->update_timer.data = (unsigned long)data; + sbs->update_timer.function = acpi_sbs_update_queue_run; + sbs->update_timer.expires = delay; + add_timer(&sbs->update_timer); end: - - sbs_mutex_unlock(sbs); + ; } static int acpi_sbs_add(struct acpi_device *device) { struct acpi_sbs *sbs = NULL; - int result = 0, remove_result = 0; + struct acpi_ec_hc *ec_hc = NULL; + int result, remove_result = 0; unsigned long sbs_obj; - int id; + int id, cnt; acpi_status status = AE_OK; - unsigned long val; - - status = - acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); - return -EIO; - } sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed")); - result = -ENOMEM; - goto end; + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n")); + return -ENOMEM; } - mutex_init(&sbs->mutex); + cnt = 0; + while (cnt < 10) { + cnt++; + ec_hc = acpi_get_ec_hc(device); + if (ec_hc) { + break; + } + msleep(1000); + } - sbs_mutex_lock(sbs); + if (!ec_hc) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_get_ec_hc() failed: " + "NO driver found for EC HC SMBus\n")); + result = -ENODEV; + goto end; + } - sbs->base = (val & 0xff00ull) >> 8; sbs->device = device; + sbs->smbus = ec_hc->smbus; strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_SBS_CLASS); acpi_driver_data(device) = sbs; + sbs->update_time = 0; + sbs->update_time2 = 0; + result = acpi_ac_add(sbs); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n")); goto end; } - status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj); - if (status) { - ACPI_EXCEPTION((AE_INFO, status, - "acpi_evaluate_integer() failed")); + result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj); + if (ACPI_FAILURE(result)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_evaluate_integer() failed\n")); result = -EIO; goto end; } + if (sbs_obj > 0) { result = acpi_sbsm_get_info(sbs); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbsm_get_info() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbsm_get_info() failed\n")); goto end; } sbs->sbsm_present = 1; } - if (sbs->sbsm_present == 0) { result = acpi_battery_add(sbs, 0); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_add() failed\n")); goto end; } } else { @@ -1694,8 +1641,9 @@ static int acpi_sbs_add(struct acpi_device *device) if ((sbs->sbsm_batteries_supported & (1 << id))) { result = acpi_battery_add(sbs, id); if (result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_battery_add() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_battery_add() " + "failed\n")); goto end; } } @@ -1705,26 +1653,33 @@ static int acpi_sbs_add(struct acpi_device *device) sbs->handle = device->handle; init_timer(&sbs->update_timer); - result = acpi_check_update_proc(sbs); - if (result) - goto end; - - end: + if (update_mode == QUEUE_UPDATE_MODE) { + status = acpi_os_execute(OSL_GPE_HANDLER, + acpi_sbs_update_queue, sbs); + if (status != AE_OK) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_os_execute() failed\n")); + } + } + sbs->update_time = update_time; + sbs->update_time2 = update_time2; - sbs_mutex_unlock(sbs); + printk(KERN_INFO PREFIX "%s [%s]\n", + acpi_device_name(device), acpi_device_bid(device)); + end: if (result) { remove_result = acpi_sbs_remove(device, 0); if (remove_result) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_sbs_remove() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_sbs_remove() failed\n")); } } return result; } -static int acpi_sbs_remove(struct acpi_device *device, int type) +int acpi_sbs_remove(struct acpi_device *device, int type) { struct acpi_sbs *sbs; int id; @@ -1733,14 +1688,15 @@ static int acpi_sbs_remove(struct acpi_device *device, int type) return -EINVAL; } - sbs = acpi_driver_data(device); + sbs = (struct acpi_sbs *)acpi_driver_data(device); + if (!sbs) { return -EINVAL; } - sbs_mutex_lock(sbs); - sbs->zombie = 1; + sbs->update_time = 0; + sbs->update_time2 = 0; del_timer_sync(&sbs->update_timer); acpi_os_wait_events_complete(NULL); del_timer_sync(&sbs->update_timer); @@ -1751,41 +1707,11 @@ static int acpi_sbs_remove(struct acpi_device *device, int type) acpi_ac_remove(sbs); - sbs_mutex_unlock(sbs); - - mutex_destroy(&sbs->mutex); - kfree(sbs); return 0; } -static void acpi_sbs_rmdirs(void) -{ - if (acpi_ac_dir) { - acpi_unlock_ac_dir(acpi_ac_dir); - acpi_ac_dir = NULL; - } - if (acpi_battery_dir) { - acpi_unlock_battery_dir(acpi_battery_dir); - acpi_battery_dir = NULL; - } -} - -static int acpi_sbs_resume(struct acpi_device *device) -{ - struct acpi_sbs *sbs; - - if (!device) - return -EINVAL; - - sbs = device->driver_data; - - sbs->run_cnt = 0; - - return 0; -} - static int __init acpi_sbs_init(void) { int result = 0; @@ -1793,34 +1719,35 @@ static int __init acpi_sbs_init(void) if (acpi_disabled) return -ENODEV; + init_MUTEX(&sbs_sem); + if (capacity_mode != DEF_CAPACITY_UNIT && capacity_mode != MAH_CAPACITY_UNIT && capacity_mode != MWH_CAPACITY_UNIT) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "invalid capacity_mode = %d", capacity_mode)); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: " + "invalid capacity_mode = %d\n", + capacity_mode)); return -EINVAL; } acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_ac_dir() failed")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_lock_ac_dir() failed\n")); return -ENODEV; } acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_lock_battery_dir() failed")); - acpi_sbs_rmdirs(); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_lock_battery_dir() failed\n")); return -ENODEV; } result = acpi_bus_register_driver(&acpi_sbs_driver); if (result < 0) { - ACPI_EXCEPTION((AE_INFO, AE_ERROR, - "acpi_bus_register_driver() failed")); - acpi_sbs_rmdirs(); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "acpi_bus_register_driver() failed\n")); return -ENODEV; } @@ -1829,9 +1756,13 @@ static int __init acpi_sbs_init(void) static void __exit acpi_sbs_exit(void) { + acpi_bus_unregister_driver(&acpi_sbs_driver); - acpi_sbs_rmdirs(); + acpi_unlock_ac_dir(acpi_ac_dir); + acpi_ac_dir = NULL; + acpi_unlock_battery_dir(acpi_battery_dir); + acpi_battery_dir = NULL; return; } diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index d80dd84e5bfd..bb0e0da39fb1 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -1068,9 +1068,7 @@ acpi_add_single_object(struct acpi_device **child, } break; default: - STRUCT_TO_INT(device->status) = - ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | - ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + STRUCT_TO_INT(device->status) = 0x0F; break; } diff --git a/trunk/drivers/acpi/sleep/main.c b/trunk/drivers/acpi/sleep/main.c index f8c63410bcbf..37a0930fc0a6 100644 --- a/trunk/drivers/acpi/sleep/main.c +++ b/trunk/drivers/acpi/sleep/main.c @@ -168,18 +168,9 @@ int acpi_suspend(u32 acpi_state) static int acpi_pm_state_valid(suspend_state_t pm_state) { - u32 acpi_state; - - switch (pm_state) { - case PM_SUSPEND_ON: - case PM_SUSPEND_STANDBY: - case PM_SUSPEND_MEM: - acpi_state = acpi_suspend_states[pm_state]; + u32 acpi_state = acpi_suspend_states[pm_state]; - return sleep_states[acpi_state]; - default: - return 0; - } + return sleep_states[acpi_state]; } static struct pm_ops acpi_pm_ops = { diff --git a/trunk/drivers/acpi/sleep/proc.c b/trunk/drivers/acpi/sleep/proc.c index 2d912b71e543..ccc11b33d89c 100644 --- a/trunk/drivers/acpi/sleep/proc.c +++ b/trunk/drivers/acpi/sleep/proc.c @@ -350,31 +350,21 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) { struct list_head *node, *next; - seq_printf(seq, "Device\tS-state\t Status Sysfs node\n"); + seq_printf(seq, "Device Sleep state Status\n"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - struct device *ldev; if (!dev->wakeup.flags.valid) continue; spin_unlock(&acpi_device_lock); - - ldev = acpi_get_physical_device(dev->handle); - seq_printf(seq, "%s\t S%d\t%c%-8s ", + seq_printf(seq, "%4s %4d %s%8s\n", dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, - dev->wakeup.flags.run_wake ? '*' : ' ', + dev->wakeup.flags.run_wake ? "*" : "", dev->wakeup.state.enabled ? "enabled" : "disabled"); - if (ldev) - seq_printf(seq, "%s:%s", - ldev->bus ? ldev->bus->name : "no-bus", - ldev->bus_id); - seq_printf(seq, "\n"); - put_device(ldev); - spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); diff --git a/trunk/drivers/acpi/tables/tbfadt.c b/trunk/drivers/acpi/tables/tbfadt.c index 1db833eb2417..807c7116e94b 100644 --- a/trunk/drivers/acpi/tables/tbfadt.c +++ b/trunk/drivers/acpi/tables/tbfadt.c @@ -347,18 +347,6 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; } - - /* - * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero) - * are indeed zero. This will workaround BIOSs that inadvertently placed - * values in these fields. - */ - if (acpi_gbl_FADT.header.revision < 3) { - acpi_gbl_FADT.preferred_profile = 0; - acpi_gbl_FADT.pstate_control = 0; - acpi_gbl_FADT.cst_control = 0; - acpi_gbl_FADT.boot_flags = 0; - } } /****************************************************************************** diff --git a/trunk/drivers/acpi/thermal.c b/trunk/drivers/acpi/thermal.c index 589b98b7b216..0ae8b9310cbf 100644 --- a/trunk/drivers/acpi/thermal.c +++ b/trunk/drivers/acpi/thermal.c @@ -758,8 +758,7 @@ static void acpi_thermal_check(void *data) del_timer(&(tz->timer)); } else { if (timer_pending(&(tz->timer))) - mod_timer(&(tz->timer), - jiffies + (HZ * sleep_time) / 1000); + mod_timer(&(tz->timer), (HZ * sleep_time) / 1000); else { tz->timer.data = (unsigned long)tz; tz->timer.function = acpi_thermal_run; diff --git a/trunk/drivers/amba/bus.c b/trunk/drivers/amba/bus.c index 268e301775fc..fd5475071acc 100644 --- a/trunk/drivers/amba/bus.c +++ b/trunk/drivers/amba/bus.c @@ -47,13 +47,14 @@ static int amba_match(struct device *dev, struct device_driver *drv) static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; - return retval; + if (nr_env < 2) + return -ENOMEM; + + snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid); + *envp++ = buf; + *envp++ = NULL; + return 0; } #else #define amba_uevent NULL diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index 365c306c7cf8..7bdbe5a914d0 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -156,6 +156,11 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config SATA_INTEL_COMBINED + bool + depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX) + default y + config SATA_ACPI bool depends on ACPI && PCI @@ -179,7 +184,7 @@ config PATA_ALI If unsure, say N. config PATA_AMD - tristate "AMD/NVidia PATA support" + tristate "AMD/NVidia PATA support (Experimental)" depends on PCI help This option enables support for the AMD and NVidia PATA @@ -204,16 +209,6 @@ config PATA_ATIIXP If unsure, say N. -config PATA_CMD640_PCI - tristate "CMD640 PCI PATA support (Very Experimental)" - depends on PCI && EXPERIMENTAL - help - This option enables support for the CMD640 PCI IDE - interface chip. Only the primary channel is currently - supported. - - If unsure, say N. - config PATA_CMD64X tristate "CMD64x PATA support (Very Experimental)" depends on PCI&& EXPERIMENTAL @@ -278,7 +273,7 @@ config ATA_GENERIC If unsure, say N. config PATA_HPT366 - tristate "HPT 366/368 PATA support (Experimental)" + tristate "HPT 366/368 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the HPT 366 and 368 @@ -287,7 +282,7 @@ config PATA_HPT366 If unsure, say N. config PATA_HPT37X - tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)" + tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the majority of the later HPT @@ -314,7 +309,7 @@ config PATA_HPT3X3 If unsure, say N. config PATA_ISAPNP - tristate "ISA Plug and Play PATA support (Experimental)" + tristate "ISA Plug and Play PATA support (Very Experimental)" depends on EXPERIMENTAL && ISAPNP help This option enables support for ISA plug & play ATA @@ -323,8 +318,8 @@ config PATA_ISAPNP If unsure, say N. config PATA_IT821X - tristate "IT8211/2 PATA support" - depends on PCI + tristate "IT8211/2 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL help This option enables support for the ITE 8211 and 8212 PATA controllers via the new ATA layer, including RAID @@ -395,10 +390,10 @@ config PATA_MPIIX If unsure, say N. config PATA_OLDPIIX - tristate "Intel PATA old PIIX support" - depends on PCI + tristate "Intel PATA old PIIX support (Experimental)" + depends on PCI && EXPERIMENTAL help - This option enables support for early PIIX PATA support. + This option enables support for old(?) PIIX PATA support. If unsure, say N. @@ -449,7 +444,7 @@ config PATA_PCMCIA If unsure, say N. config PATA_PDC_OLD - tristate "Older Promise PATA controller support (Experimental)" + tristate "Older Promise PATA controller support (Very Experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the Promise 20246, 20262, 20263, @@ -464,7 +459,7 @@ config PATA_QDI Support for QDI 6500 and 6580 PATA controllers on VESA local bus. config PATA_RADISYS - tristate "RADISYS 82600 PATA support (Very Experimental)" + tristate "RADISYS 82600 PATA support (Very experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the RADISYS 82600 @@ -482,7 +477,7 @@ config PATA_RZ1000 If unsure, say N. config PATA_SC1200 - tristate "SC1200 PATA support (Very Experimental)" + tristate "SC1200 PATA support (Raving Lunatic)" depends on PCI && EXPERIMENTAL help This option enables support for the NatSemi/AMD SC1200 SoC @@ -491,8 +486,8 @@ config PATA_SC1200 If unsure, say N. config PATA_SERVERWORKS - tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support" - depends on PCI + tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL help This option enables support for the Serverworks OSB4/CSB5/CSB6 and HT1000 PATA controllers, via the new ATA layer. diff --git a/trunk/drivers/ata/Makefile b/trunk/drivers/ata/Makefile index b7055e302650..13d7397e0008 100644 --- a/trunk/drivers/ata/Makefile +++ b/trunk/drivers/ata/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_PATA_ALI) += pata_ali.o obj-$(CONFIG_PATA_AMD) += pata_amd.o obj-$(CONFIG_PATA_ARTOP) += pata_artop.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o -obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index 34c5534ed64c..fd27227771b4 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -170,10 +170,6 @@ enum { AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ - - AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY, }; struct ahci_cmd_hdr { @@ -192,10 +188,8 @@ struct ahci_sg { }; struct ahci_host_priv { - u32 cap; /* cap to use */ - u32 port_map; /* port map to use */ - u32 saved_cap; /* saved initial cap */ - u32 saved_port_map; /* saved initial port_map */ + u32 cap; /* cache of HOST_CAP register */ + u32 port_map; /* cache of HOST_PORTS_IMPL reg */ }; struct ahci_port_priv { @@ -215,6 +209,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t ahci_interrupt (int irq, void *dev_instance); static void ahci_irq_clear(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); @@ -268,6 +263,7 @@ static const struct ata_port_operations ahci_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, + .irq_handler = ahci_interrupt, .irq_clear = ahci_irq_clear, .irq_on = ata_dummy_irq_on, .irq_ack = ata_dummy_irq_ack, @@ -302,6 +298,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, + .irq_handler = ahci_interrupt, .irq_clear = ahci_irq_clear, .irq_on = ata_dummy_irq_on, .irq_ack = ata_dummy_irq_ack, @@ -327,41 +324,58 @@ static const struct ata_port_operations ahci_vt8251_ops = { static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { - .flags = AHCI_FLAG_COMMON, + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, /* board_ahci_pi */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | - AHCI_FLAG_NO_NCQ, + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | + ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_vt8251_ops, }, /* board_ahci_ign_iferr */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | + AHCI_FLAG_IGN_IRQ_IF_ERR, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, /* board_ahci_sb600 */ { - .flags = AHCI_FLAG_COMMON | + .sht = &ahci_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_IGN_SERR_INTERNAL, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, + }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -399,11 +413,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, /* ATI */ - { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ + { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 non-raid */ + { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */ /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ - { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ /* NVIDIA */ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ @@ -457,100 +471,10 @@ static inline int ahci_nr_ports(u32 cap) return (cap & 0x1f) + 1; } -static inline void __iomem *ahci_port_base(struct ata_port *ap) -{ - void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; - - return mmio + 0x100 + (ap->port_no * 0x80); -} - -/** - * ahci_save_initial_config - Save and fixup initial config values - * @pdev: target PCI device - * @pi: associated ATA port info - * @hpriv: host private area to store config values - * - * Some registers containing configuration info might be setup by - * BIOS and might be cleared on reset. This function saves the - * initial values of those registers into @hpriv such that they - * can be restored after controller reset. - * - * If inconsistent, config values are fixed up by this function. - * - * LOCKING: - * None. - */ -static void ahci_save_initial_config(struct pci_dev *pdev, - const struct ata_port_info *pi, - struct ahci_host_priv *hpriv) +static inline void __iomem *ahci_port_base(void __iomem *base, + unsigned int port) { - void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; - u32 cap, port_map; - int i; - - /* Values prefixed with saved_ are written back to host after - * reset. Values without are used for driver operation. - */ - hpriv->saved_cap = cap = readl(mmio + HOST_CAP); - hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); - - /* fixup zero port_map */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1; - dev_printk(KERN_WARNING, &pdev->dev, - "PORTS_IMPL is zero, forcing 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; - } - - /* cross check port_map and cap.n_ports */ - if (pi->flags & AHCI_FLAG_HONOR_PI) { - u32 tmp_port_map = port_map; - int n_ports = ahci_nr_ports(cap); - - for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { - if (tmp_port_map & (1 << i)) { - n_ports--; - tmp_port_map &= ~(1 << i); - } - } - - /* Whine if inconsistent. No need to update cap. - * port_map is used to determine number of ports. - */ - if (n_ports || tmp_port_map) - dev_printk(KERN_WARNING, &pdev->dev, - "nr_ports (%u) and implemented port map " - "(0x%x) don't match\n", - ahci_nr_ports(cap), port_map); - } else { - /* fabricate port_map from cap.nr_ports */ - port_map = (1 << ahci_nr_ports(cap)) - 1; - } - - /* record values to use during operation */ - hpriv->cap = cap; - hpriv->port_map = port_map; -} - -/** - * ahci_restore_initial_config - Restore initial config - * @host: target ATA host - * - * Restore initial config stored by ahci_save_initial_config(). - * - * LOCKING: - * None. - */ -static void ahci_restore_initial_config(struct ata_host *host) -{ - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - - writel(hpriv->saved_cap, mmio + HOST_CAP); - writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); - (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ + return base + 0x100 + (port * 0x80); } static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) @@ -587,9 +511,8 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void ahci_start_engine(struct ata_port *ap) +static void ahci_start_engine(void __iomem *port_mmio) { - void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; /* start DMA */ @@ -599,9 +522,8 @@ static void ahci_start_engine(struct ata_port *ap) readl(port_mmio + PORT_CMD); /* flush */ } -static int ahci_stop_engine(struct ata_port *ap) +static int ahci_stop_engine(void __iomem *port_mmio) { - void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; tmp = readl(port_mmio + PORT_CMD); @@ -623,23 +545,19 @@ static int ahci_stop_engine(struct ata_port *ap) return 0; } -static void ahci_start_fis_rx(struct ata_port *ap) +static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap, + dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) { - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; u32 tmp; /* set FIS registers */ - if (hpriv->cap & HOST_CAP_64) - writel((pp->cmd_slot_dma >> 16) >> 16, - port_mmio + PORT_LST_ADDR_HI); - writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); + if (cap & HOST_CAP_64) + writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); + writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); - if (hpriv->cap & HOST_CAP_64) - writel((pp->rx_fis_dma >> 16) >> 16, - port_mmio + PORT_FIS_ADDR_HI); - writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); + if (cap & HOST_CAP_64) + writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI); + writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); /* enable FIS reception */ tmp = readl(port_mmio + PORT_CMD); @@ -650,9 +568,8 @@ static void ahci_start_fis_rx(struct ata_port *ap) readl(port_mmio + PORT_CMD); } -static int ahci_stop_fis_rx(struct ata_port *ap) +static int ahci_stop_fis_rx(void __iomem *port_mmio) { - void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; /* disable FIS reception */ @@ -669,16 +586,14 @@ static int ahci_stop_fis_rx(struct ata_port *ap) return 0; } -static void ahci_power_up(struct ata_port *ap) +static void ahci_power_up(void __iomem *port_mmio, u32 cap) { - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); u32 cmd; cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; /* spin up device */ - if (hpriv->cap & HOST_CAP_SSS) { + if (cap & HOST_CAP_SSS) { cmd |= PORT_CMD_SPIN_UP; writel(cmd, port_mmio + PORT_CMD); } @@ -688,13 +603,11 @@ static void ahci_power_up(struct ata_port *ap) } #ifdef CONFIG_PM -static void ahci_power_down(struct ata_port *ap) +static void ahci_power_down(void __iomem *port_mmio, u32 cap) { - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); u32 cmd, scontrol; - if (!(hpriv->cap & HOST_CAP_SSS)) + if (!(cap & HOST_CAP_SSS)) return; /* put device into listen mode, first set PxSCTL.DET to 0 */ @@ -709,28 +622,29 @@ static void ahci_power_down(struct ata_port *ap) } #endif -static void ahci_init_port(struct ata_port *ap) +static void ahci_init_port(void __iomem *port_mmio, u32 cap, + dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) { /* enable FIS reception */ - ahci_start_fis_rx(ap); + ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); /* enable DMA */ - ahci_start_engine(ap); + ahci_start_engine(port_mmio); } -static int ahci_deinit_port(struct ata_port *ap, const char **emsg) +static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) { int rc; /* disable DMA */ - rc = ahci_stop_engine(ap); + rc = ahci_stop_engine(port_mmio); if (rc) { *emsg = "failed to stop engine"; return rc; } /* disable FIS reception */ - rc = ahci_stop_fis_rx(ap); + rc = ahci_stop_fis_rx(port_mmio); if (rc) { *emsg = "failed stop FIS RX"; return rc; @@ -739,11 +653,12 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg) return 0; } -static int ahci_reset_controller(struct ata_host *host) +static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) { - struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - u32 tmp; + u32 cap_save, impl_save, tmp; + + cap_save = readl(mmio + HOST_CAP); + impl_save = readl(mmio + HOST_PORTS_IMPL); /* global controller reset */ tmp = readl(mmio + HOST_CTL); @@ -759,7 +674,7 @@ static int ahci_reset_controller(struct ata_host *host) tmp = readl(mmio + HOST_CTL); if (tmp & HOST_RESET) { - dev_printk(KERN_ERR, host->dev, + dev_printk(KERN_ERR, &pdev->dev, "controller reset failed (0x%x)\n", tmp); return -EIO; } @@ -768,8 +683,18 @@ static int ahci_reset_controller(struct ata_host *host) writel(HOST_AHCI_EN, mmio + HOST_CTL); (void) readl(mmio + HOST_CTL); /* flush */ - /* some registers might be cleared on reset. restore initial values */ - ahci_restore_initial_config(host); + /* These write-once registers are normally cleared on reset. + * Restore BIOS values... which we HOPE were present before + * reset. + */ + if (!impl_save) { + impl_save = (1 << ahci_nr_ports(cap_save)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); + } + writel(cap_save, mmio + HOST_CAP); + writel(impl_save, mmio + HOST_PORTS_IMPL); + (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { u16 tmp16; @@ -783,23 +708,23 @@ static int ahci_reset_controller(struct ata_host *host) return 0; } -static void ahci_init_controller(struct ata_host *host) +static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, + int n_ports, unsigned int port_flags, + struct ahci_host_priv *hpriv) { - struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int i, rc; u32 tmp; - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - void __iomem *port_mmio = ahci_port_base(ap); + for (i = 0; i < n_ports; i++) { + void __iomem *port_mmio = ahci_port_base(mmio, i); const char *emsg = NULL; - if (ata_port_is_dummy(ap)) + if ((port_flags & AHCI_FLAG_HONOR_PI) && + !(hpriv->port_map & (1 << i))) continue; /* make sure port is not active */ - rc = ahci_deinit_port(ap, &emsg); + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc) dev_printk(KERN_WARNING, &pdev->dev, "%s (%d)\n", emsg, rc); @@ -827,7 +752,7 @@ static void ahci_init_controller(struct ata_host *host) static unsigned int ahci_dev_classify(struct ata_port *ap) { - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ata_taskfile tf; u32 tmp; @@ -877,7 +802,8 @@ static int ahci_clo(struct ata_port *ap) static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const u32 cmd_fis_len = 5; /* five dwords */ const char *reason = NULL; struct ata_taskfile tf; @@ -894,7 +820,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) } /* prepare for SRST (AHCI-1.1 10.4.1) */ - rc = ahci_stop_engine(ap); + rc = ahci_stop_engine(port_mmio); if (rc) { reason = "failed to stop engine"; goto fail_restart; @@ -914,7 +840,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) } /* restart engine */ - ahci_start_engine(ap); + ahci_start_engine(port_mmio); ata_tf_init(ap->device, &tf); fis = pp->cmd_tbl; @@ -973,7 +899,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) return 0; fail_restart: - ahci_start_engine(ap); + ahci_start_engine(port_mmio); fail: ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); return rc; @@ -984,11 +910,13 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + ahci_stop_engine(port_mmio); /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(ap->device, &tf); @@ -997,7 +925,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) rc = sata_std_hardreset(ap, class); - ahci_start_engine(ap); + ahci_start_engine(port_mmio); if (rc == 0 && ata_port_online(ap)) *class = ahci_dev_classify(ap); @@ -1010,18 +938,20 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) { + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + ahci_stop_engine(port_mmio); rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); /* vt8251 needs SError cleared for the port to operate */ ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); - ahci_start_engine(ap); + ahci_start_engine(port_mmio); DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); @@ -1033,7 +963,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) static void ahci_postreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *port_mmio = ap->ioaddr.cmd_addr; u32 new_tmp, tmp; ata_std_postreset(ap, class); @@ -1201,7 +1131,8 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) static void ahci_host_intr(struct ata_port *ap) { - void __iomem *port_mmio = ap->ioaddr.cmd_addr; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_eh_info *ehi = &ap->eh_info; struct ahci_port_priv *pp = ap->private_data; u32 status, qc_active; @@ -1352,7 +1283,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance) static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *port_mmio = ap->ioaddr.cmd_addr; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1364,7 +1295,8 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) static void ahci_freeze(struct ata_port *ap) { - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); /* turn IRQ off */ writel(0, port_mmio + PORT_IRQ_MASK); @@ -1373,7 +1305,7 @@ static void ahci_freeze(struct ata_port *ap) static void ahci_thaw(struct ata_port *ap) { void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; - void __iomem *port_mmio = ahci_port_base(ap); + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; /* clear IRQ */ @@ -1387,10 +1319,13 @@ static void ahci_thaw(struct ata_port *ap) static void ahci_error_handler(struct ata_port *ap) { + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ - ahci_stop_engine(ap); - ahci_start_engine(ap); + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); } /* perform recovery */ @@ -1400,10 +1335,13 @@ static void ahci_error_handler(struct ata_port *ap) static void ahci_vt8251_error_handler(struct ata_port *ap) { + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ - ahci_stop_engine(ap); - ahci_start_engine(ap); + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); } /* perform recovery */ @@ -1414,26 +1352,36 @@ static void ahci_vt8251_error_handler(struct ata_port *ap) static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); - if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->flags & ATA_QCFLAG_FAILED) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask) { /* make DMA engine forget about the failed command */ - ahci_stop_engine(ap); - ahci_start_engine(ap); + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); } } #ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) { + struct ahci_host_priv *hpriv = ap->host->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; - rc = ahci_deinit_port(ap, &emsg); + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc == 0) - ahci_power_down(ap); + ahci_power_down(port_mmio, hpriv->cap); else { ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); - ahci_init_port(ap); + ahci_init_port(port_mmio, hpriv->cap, + pp->cmd_slot_dma, pp->rx_fis_dma); } return rc; @@ -1441,8 +1389,13 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) static int ahci_port_resume(struct ata_port *ap) { - ahci_power_up(ap); - ahci_init_port(ap); + struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + ahci_power_up(port_mmio, hpriv->cap); + ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); return 0; } @@ -1470,6 +1423,8 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) static int ahci_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int rc; rc = ata_pci_device_do_resume(pdev); @@ -1477,11 +1432,12 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_reset_controller(host); + rc = ahci_reset_controller(mmio, pdev); if (rc) return rc; - ahci_init_controller(host); + ahci_init_controller(mmio, pdev, host->n_ports, + host->ports[0]->flags, hpriv); } ata_host_resume(host); @@ -1493,7 +1449,10 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) static int ahci_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); void *mem; dma_addr_t mem_dma; int rc; @@ -1541,29 +1500,85 @@ static int ahci_port_start(struct ata_port *ap) ap->private_data = pp; /* power up port */ - ahci_power_up(ap); + ahci_power_up(port_mmio, hpriv->cap); /* initialize port */ - ahci_init_port(ap); + ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); return 0; } static void ahci_port_stop(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; /* de-initialize port */ - rc = ahci_deinit_port(ap, &emsg); + rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc) ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); } -static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) +static void ahci_setup_port(struct ata_ioports *port, void __iomem *base, + unsigned int port_idx) { + VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); + base = ahci_port_base(base, port_idx); + VPRINTK("base now==0x%lx\n", base); + + port->cmd_addr = base; + port->scr_addr = base + PORT_SCR; + + VPRINTK("EXIT\n"); +} + +static int ahci_host_init(struct ata_probe_ent *probe_ent) +{ + struct ahci_host_priv *hpriv = probe_ent->private_data; + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; + unsigned int i, cap_n_ports, using_dac; int rc; + rc = ahci_reset_controller(mmio, pdev); + if (rc) + return rc; + + hpriv->cap = readl(mmio + HOST_CAP); + hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); + cap_n_ports = ahci_nr_ports(hpriv->cap); + + VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", + hpriv->cap, hpriv->port_map, cap_n_ports); + + if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { + unsigned int n_ports = cap_n_ports; + u32 port_map = hpriv->port_map; + int max_port = 0; + + for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { + if (port_map & (1 << i)) { + n_ports--; + port_map &= ~(1 << i); + max_port = i; + } else + probe_ent->dummy_port_mask |= 1 << i; + } + + if (n_ports || port_map) + dev_printk(KERN_WARNING, &pdev->dev, + "nr_ports (%u) and implemented port map " + "(0x%x) don't match\n", + cap_n_ports, hpriv->port_map); + + probe_ent->n_ports = max_port + 1; + } else + probe_ent->n_ports = cap_n_ports; + + using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); @@ -1589,14 +1604,23 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) return rc; } } + + for (i = 0; i < probe_ent->n_ports; i++) + ahci_setup_port(&probe_ent->port[i], mmio, i); + + ahci_init_controller(mmio, pdev, probe_ent->n_ports, + probe_ent->port_flags, hpriv); + + pci_set_master(pdev); + return 0; } -static void ahci_print_info(struct ata_host *host) +static void ahci_print_info(struct ata_probe_ent *probe_ent) { - struct ahci_host_priv *hpriv = host->private_data; - struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; + struct ahci_host_priv *hpriv = probe_ent->private_data; + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; u32 vers, cap, impl, speed; const char *speed_s; u16 cc; @@ -1666,12 +1690,11 @@ static void ahci_print_info(struct ata_host *host) static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info pi = ahci_port_info[ent->driver_data]; - const struct ata_port_info *ppi[] = { &pi, NULL }; + unsigned int board_idx = (unsigned int) ent->driver_data; struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; struct ahci_host_priv *hpriv; - struct ata_host *host; - int i, rc; + int rc; VPRINTK("ENTER\n"); @@ -1680,7 +1703,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* acquire resources */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -1694,49 +1716,44 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_enable_msi(pdev)) pci_intx(pdev, 1); + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - /* save initial config */ - ahci_save_initial_config(pdev, &pi, hpriv); + probe_ent->sht = ahci_port_info[board_idx].sht; + probe_ent->port_flags = ahci_port_info[board_idx].flags; + probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask; + probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask; + probe_ent->port_ops = ahci_port_info[board_idx].port_ops; - /* prepare host */ - if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ)) - pi.flags |= ATA_FLAG_NCQ; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); - if (!host) - return -ENOMEM; - host->iomap = pcim_iomap_table(pdev); - host->private_data = hpriv; - - for (i = 0; i < host->n_ports; i++) { - if (hpriv->port_map & (1 << i)) { - struct ata_port *ap = host->ports[i]; - void __iomem *port_mmio = ahci_port_base(ap); - - ap->ioaddr.cmd_addr = port_mmio; - ap->ioaddr.scr_addr = port_mmio + PORT_SCR; - } else - host->ports[i]->ops = &ata_dummy_port_ops; - } + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + probe_ent->private_data = hpriv; /* initialize adapter */ - rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); + rc = ahci_host_init(probe_ent); if (rc) return rc; - rc = ahci_reset_controller(host); - if (rc) - return rc; + if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) && + (hpriv->cap & HOST_CAP_NCQ)) + probe_ent->port_flags |= ATA_FLAG_NCQ; - ahci_init_controller(host); - ahci_print_info(host); + ahci_print_info(probe_ent); - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, - &ahci_sht); + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } static int __init ahci_init(void) diff --git a/trunk/drivers/ata/ata_generic.c b/trunk/drivers/ata/ata_generic.c index 92a491ddd030..d8e79882b880 100644 --- a/trunk/drivers/ata/ata_generic.c +++ b/trunk/drivers/ata/ata_generic.c @@ -32,6 +32,35 @@ * A generic parallel ATA driver using libata */ +/** + * generic_pre_reset - probe begin + * @ap: ATA port + * + * Set up cable type and use generic probe init + */ + +static int generic_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + + +/** + * generic_error_handler - Probe specified port on PATA host controller + * @ap: Port to probe + * @classes: + * + * LOCKING: + * None (inherited from caller). + */ + + +static void generic_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + /** * generic_set_mode - mode setting * @ap: interface to set up @@ -115,9 +144,8 @@ static struct ata_port_operations generic_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = generic_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, diff --git a/trunk/drivers/ata/ata_piix.c b/trunk/drivers/ata/ata_piix.c index 55d306a3e538..b952c584338f 100644 --- a/trunk/drivers/ata/ata_piix.c +++ b/trunk/drivers/ata/ata_piix.c @@ -93,7 +93,7 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.11" +#define DRV_VERSION "2.10ac1" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -155,11 +155,11 @@ struct piix_host_priv { static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void piix_pata_error_handler(struct ata_port *ap); +static void ich_pata_error_handler(struct ata_port *ap); static void piix_sata_error_handler(struct ata_port *ap); static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); -static int ich_pata_cable_detect(struct ata_port *ap); static unsigned int in_module_init = 1; @@ -305,7 +305,6 @@ static const struct ata_port_operations piix_pata_ops = { .thaw = ata_bmdma_thaw, .error_handler = piix_pata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -337,9 +336,8 @@ static const struct ata_port_operations ich_pata_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = piix_pata_error_handler, + .error_handler = ich_pata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ich_pata_cable_detect, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -582,13 +580,12 @@ static const struct ich_laptop ich_laptop[] = { /* devid, subvendor, subdev */ { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ - { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ /* end marker */ { 0, } }; /** - * ich_pata_cable_detect - Probe host controller cable detect info + * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired * * Read 80c cable indicator from ATA PCI device's PCI config @@ -598,18 +595,23 @@ static const struct ich_laptop ich_laptop[] = { * None (inherited from caller). */ -static int ich_pata_cable_detect(struct ata_port *ap) +static void ich_pata_cbl_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; + /* no 80c support in host controller? */ + if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) + goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ while (lap->device) { if (lap->device == pdev->device && lap->subvendor == pdev->subsystem_vendor && lap->subdevice == pdev->subsystem_device) { - return ATA_CBL_PATA40_SHORT; + ap->cbl = ATA_CBL_PATA40_SHORT; + return; } lap++; } @@ -618,14 +620,20 @@ static int ich_pata_cable_detect(struct ata_port *ap) mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); if ((tmp & mask) == 0) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + goto cbl40; + + ap->cbl = ATA_CBL_PATA80; + return; + +cbl40: + ap->cbl = ATA_CBL_PATA40; } /** * piix_pata_prereset - prereset for PATA host controller * @ap: Target port * + * * LOCKING: * None (inherited from caller). */ @@ -635,6 +643,8 @@ static int piix_pata_prereset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; + + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -645,6 +655,30 @@ static void piix_pata_error_handler(struct ata_port *ap) } +/** + * ich_pata_prereset - prereset for PATA host controller + * @ap: Target port + * + * + * LOCKING: + * None (inherited from caller). + */ +static int ich_pata_prereset(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) + return -ENOENT; + ich_pata_cbl_detect(ap); + return ata_std_prereset(ap); +} + +static void ich_pata_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL, + ata_std_postreset); +} + static void piix_sata_error_handler(struct ata_port *ap) { ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c index ca67484af1eb..0abd72d0dec2 100644 --- a/trunk/drivers/ata/libata-core.c +++ b/trunk/drivers/ata/libata-core.c @@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); -unsigned int ata_print_id = 1; +static unsigned int ata_print_id = 1; static struct workqueue_struct *ata_wq; struct workqueue_struct *ata_aux_wq; @@ -89,10 +89,6 @@ int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); -static int ata_ignore_hpa = 0; -module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); -MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); - static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); @@ -812,205 +808,6 @@ void ata_id_c_string(const u16 *id, unsigned char *s, *p = '\0'; } -static u64 ata_tf_to_lba48(struct ata_taskfile *tf) -{ - u64 sectors = 0; - - sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40; - sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32; - sectors |= (tf->hob_lbal & 0xff) << 24; - sectors |= (tf->lbah & 0xff) << 16; - sectors |= (tf->lbam & 0xff) << 8; - sectors |= (tf->lbal & 0xff); - - return ++sectors; -} - -static u64 ata_tf_to_lba(struct ata_taskfile *tf) -{ - u64 sectors = 0; - - sectors |= (tf->device & 0x0f) << 24; - sectors |= (tf->lbah & 0xff) << 16; - sectors |= (tf->lbam & 0xff) << 8; - sectors |= (tf->lbal & 0xff); - - return ++sectors; -} - -/** - * ata_read_native_max_address_ext - LBA48 native max query - * @dev: Device to query - * - * Perform an LBA48 size query upon the device in question. Return the - * actual LBA48 size or zero if the command fails. - */ - -static u64 ata_read_native_max_address_ext(struct ata_device *dev) -{ - unsigned int err; - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_read_native_max_address - LBA28 native max query - * @dev: Device to query - * - * Performa an LBA28 size query upon the device in question. Return the - * actual LBA28 size or zero if the command fails. - */ - -static u64 ata_read_native_max_address(struct ata_device *dev) -{ - unsigned int err; - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_READ_NATIVE_MAX; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba(&tf); -} - -/** - * ata_set_native_max_address_ext - LBA48 native max set - * @dev: Device to query - * - * Perform an LBA48 size set max upon the device in question. Return the - * actual LBA48 size or zero if the command fails. - */ - -static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors) -{ - unsigned int err; - struct ata_taskfile tf; - - new_sectors--; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_SET_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - tf.lbal = (new_sectors >> 0) & 0xff; - tf.lbam = (new_sectors >> 8) & 0xff; - tf.lbah = (new_sectors >> 16) & 0xff; - - tf.hob_lbal = (new_sectors >> 24) & 0xff; - tf.hob_lbam = (new_sectors >> 32) & 0xff; - tf.hob_lbah = (new_sectors >> 40) & 0xff; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_set_native_max_address - LBA28 native max set - * @dev: Device to query - * - * Perform an LBA28 size set max upon the device in question. Return the - * actual LBA28 size or zero if the command fails. - */ - -static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) -{ - unsigned int err; - struct ata_taskfile tf; - - new_sectors--; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_SET_MAX; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - - tf.lbal = (new_sectors >> 0) & 0xff; - tf.lbam = (new_sectors >> 8) & 0xff; - tf.lbah = (new_sectors >> 16) & 0xff; - tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba(&tf); -} - -/** - * ata_hpa_resize - Resize a device with an HPA set - * @dev: Device to resize - * - * Read the size of an LBA28 or LBA48 disk with HPA features and resize - * it if required to the full size of the media. The caller must check - * the drive has the HPA feature set enabled. - */ - -static u64 ata_hpa_resize(struct ata_device *dev) -{ - u64 sectors = dev->n_sectors; - u64 hpa_sectors; - - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_read_native_max_address_ext(dev); - else - hpa_sectors = ata_read_native_max_address(dev); - - /* if no hpa, both should be equal */ - ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, " - "hpa_sectors = %lld\n", - __FUNCTION__, (long long)sectors, (long long)hpa_sectors); - - if (hpa_sectors > sectors) { - ata_dev_printk(dev, KERN_INFO, - "Host Protected Area detected:\n" - "\tcurrent size: %lld sectors\n" - "\tnative size: %lld sectors\n", - (long long)sectors, (long long)hpa_sectors); - - if (ata_ignore_hpa) { - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors); - else - hpa_sectors = ata_set_native_max_address(dev, - hpa_sectors); - - if (hpa_sectors) { - ata_dev_printk(dev, KERN_INFO, "native size " - "increased to %lld sectors\n", - (long long)hpa_sectors); - return hpa_sectors; - } - } - } - return sectors; -} - static u64 ata_id_n_sectors(const u16 *id) { if (ata_id_has_lba(id)) { @@ -1473,16 +1270,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, if (ap->ops->post_internal_cmd) ap->ops->post_internal_cmd(qc); - /* perform minimal error analysis */ - if (qc->flags & ATA_QCFLAG_FAILED) { - if (qc->result_tf.command & (ATA_ERR | ATA_DF)) - qc->err_mask |= AC_ERR_DEV; - - if (!qc->err_mask) - qc->err_mask |= AC_ERR_OTHER; - - if (qc->err_mask & ~AC_ERR_OTHER) - qc->err_mask &= ~AC_ERR_OTHER; + if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) { + if (ata_msg_warn(ap)) + ata_dev_printk(dev, KERN_WARNING, + "zero err_mask for failed " + "internal command, assuming AC_ERR_OTHER\n"); + qc->err_mask |= AC_ERR_OTHER; } /* finish up */ @@ -1586,44 +1379,30 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) * Check if the current speed of the device requires IORDY. Used * by various controllers for chip configuration. */ - + unsigned int ata_pio_need_iordy(const struct ata_device *adev) { - /* Controller doesn't support IORDY. Probably a pointless check - as the caller should know this */ - if (adev->ap->flags & ATA_FLAG_NO_IORDY) + int pio; + int speed = adev->pio_mode - XFER_PIO_0; + + if (speed < 2) return 0; - /* PIO3 and higher it is mandatory */ - if (adev->pio_mode > XFER_PIO_2) - return 1; - /* We turn it on when possible */ - if (ata_id_has_iordy(adev->id)) + if (speed > 2) return 1; - return 0; -} -/** - * ata_pio_mask_no_iordy - Return the non IORDY mask - * @adev: ATA device - * - * Compute the highest mode possible if we are not using iordy. Return - * -1 if no iordy mode is available. - */ - -static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) -{ /* If we have no drive specific rule, then PIO 2 is non IORDY */ + if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */ - u16 pio = adev->id[ATA_ID_EIDE_PIO]; + pio = adev->id[ATA_ID_EIDE_PIO]; /* Is the speed faster than the drive allows non IORDY ? */ if (pio) { /* This is cycle times not frequency - watch the logic! */ if (pio > 240) /* PIO2 is 240nS per cycle */ - return 3 << ATA_SHIFT_PIO; - return 7 << ATA_SHIFT_PIO; + return 1; + return 0; } } - return 3 << ATA_SHIFT_PIO; + return 0; } /** @@ -1652,13 +1431,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, struct ata_taskfile tf; unsigned int err_mask = 0; const char *reason; - int tried_spinup = 0; int rc; if (ata_msg_ctl(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ + retry: ata_tf_init(dev, &tf); @@ -1715,32 +1494,6 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, goto err_out; } - if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { - tried_spinup = 1; - /* - * Drive powered-up in standby mode, and requires a specific - * SET_FEATURES spin-up subcommand before it will accept - * anything other than the original IDENTIFY command. - */ - ata_tf_init(dev, &tf); - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_SPINUP; - tf.protocol = ATA_PROT_NODATA; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err_mask) { - rc = -EIO; - reason = "SPINUP failed"; - goto err_out; - } - /* - * If the drive initially returned incomplete IDENTIFY info, - * we now must reissue the IDENTIFY command. - */ - if (id[2] == 0x37c8) - goto retry; - } - if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { /* * The exact sequence expected by certain pre-ATA4 drives is: @@ -1807,6 +1560,20 @@ static void ata_dev_config_ncq(struct ata_device *dev, snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); } +static void ata_set_port_max_cmd_len(struct ata_port *ap) +{ + int i; + + if (ap->scsi_host) { + unsigned int len = 0; + + for (i = 0; i < ATA_MAX_DEVICES; i++) + len = max(len, ap->device[i].cdb_len); + + ap->scsi_host->max_cmd_len = len; + } +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -1891,7 +1658,6 @@ int ata_dev_configure(struct ata_device *dev) snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); dev->n_sectors = ata_id_n_sectors(id); - dev->n_sectors_boot = dev->n_sectors; /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */ ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV, @@ -1918,9 +1684,6 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_FLUSH_EXT; } - if (ata_id_hpa_enabled(dev->id)) - dev->n_sectors = ata_hpa_resize(dev); - /* config NCQ */ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); @@ -2010,6 +1773,8 @@ int ata_dev_configure(struct ata_device *dev) } } + ata_set_port_max_cmd_len(ap); + /* limit bridge transfers to udma5, 200 sectors */ if (ata_dev_knobble(dev)) { if (ata_msg_drv(ap) && print_info) @@ -2020,15 +1785,14 @@ int ata_dev_configure(struct ata_device *dev) } if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, - dev->max_sectors); + dev->max_sectors = min(ATA_MAX_SECTORS_128, dev->max_sectors); /* limit ATAPI DMA to R/W commands only */ if (ata_device_blacklisted(dev) & ATA_HORKAGE_DMA_RW_ONLY) dev->horkage |= ATA_HORKAGE_DMA_RW_ONLY; if (ap->ops->dev_config) - ap->ops->dev_config(dev); + ap->ops->dev_config(ap, dev); if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", @@ -2042,56 +1806,6 @@ int ata_dev_configure(struct ata_device *dev) return rc; } -/** - * ata_cable_40wire - return 40 wire cable type - * @ap: port - * - * Helper method for drivers which want to hardwire 40 wire cable - * detection. - */ - -int ata_cable_40wire(struct ata_port *ap) -{ - return ATA_CBL_PATA40; -} - -/** - * ata_cable_80wire - return 80 wire cable type - * @ap: port - * - * Helper method for drivers which want to hardwire 80 wire cable - * detection. - */ - -int ata_cable_80wire(struct ata_port *ap) -{ - return ATA_CBL_PATA80; -} - -/** - * ata_cable_unknown - return unknown PATA cable. - * @ap: port - * - * Helper method for drivers which have no PATA cable detection. - */ - -int ata_cable_unknown(struct ata_port *ap) -{ - return ATA_CBL_PATA_UNK; -} - -/** - * ata_cable_sata - return SATA cable type - * @ap: port - * - * Helper method for drivers which have SATA cables - */ - -int ata_cable_sata(struct ata_port *ap) -{ - return ATA_CBL_SATA; -} - /** * ata_bus_probe - Reset and probe ATA bus * @ap: Bus to probe @@ -2162,10 +1876,6 @@ int ata_bus_probe(struct ata_port *ap) goto fail; } - /* Now ask for the cable type as PDIAG- should have been released */ - if (ap->ops->cable_detect) - ap->cbl = ap->ops->cable_detect(ap); - /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ @@ -2248,7 +1958,7 @@ void ata_port_probe(struct ata_port *ap) * LOCKING: * None. */ -void sata_print_link_status(struct ata_port *ap) +static void sata_print_link_status(struct ata_port *ap) { u32 sstatus, scontrol, tmp; @@ -2642,12 +2352,6 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, t->active += (t->cycle - (t->active + t->recover)) / 2; t->recover = t->cycle - t->active; } - - /* In a few cases quantisation may produce enough errors to - leave t->cycle too low for the sum of active and recovery - if so we must correct this */ - if (t->active + t->recover > t->cycle) - t->cycle = t->active + t->recover; return 0; } @@ -2777,13 +2481,12 @@ static int ata_dev_set_mode(struct ata_device *dev) } /** - * ata_do_set_mode - Program timings and issue SET FEATURES - XFER + * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed * @r_failed_dev: out paramter for failed device * - * Standard implementation of the function used to tune and set - * ATA device disk transfer mode (PIO3, UDMA6, etc.). If - * ata_dev_set_mode() fails, pointer to the failing device is + * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If + * ata_set_mode() fails, pointer to the failing device is * returned in @r_failed_dev. * * LOCKING: @@ -2792,12 +2495,14 @@ static int ata_dev_set_mode(struct ata_device *dev) * RETURNS: * 0 on success, negative errno otherwise */ - -int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) { struct ata_device *dev; int i, rc = 0, used_dma = 0, found = 0; + /* has private set_mode? */ + if (ap->ops->set_mode) + return ap->ops->set_mode(ap, r_failed_dev); /* step 1: calculate xfer_mask */ for (i = 0; i < ATA_MAX_DEVICES; i++) { @@ -2881,29 +2586,6 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) return rc; } -/** - * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed - * @r_failed_dev: out paramter for failed device - * - * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If - * ata_set_mode() fails, pointer to the failing device is - * returned in @r_failed_dev. - * - * LOCKING: - * PCI/etc. bus probe sem. - * - * RETURNS: - * 0 on success, negative errno otherwise - */ -int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) -{ - /* has private set_mode? */ - if (ap->ops->set_mode) - return ap->ops->set_mode(ap, r_failed_dev); - return ata_do_set_mode(ap, r_failed_dev); -} - /** * ata_tf_to_host - issue ATA taskfile to host controller * @ap: port to which command is being issued @@ -3585,11 +3267,6 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, "%llu != %llu\n", (unsigned long long)dev->n_sectors, (unsigned long long)new_n_sectors); - /* Are we the boot time size - if so we appear to be the - same disk at this point and our HPA got reapplied */ - if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors - && ata_id_hpa_enabled(new_id)) - return 1; return 0; } @@ -3764,7 +3441,19 @@ static void ata_dev_xfermask(struct ata_device *dev) xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - /* drive modes available */ + /* Apply cable rule here. Don't apply it early because when + * we handle hot plug the cable type can itself change. + */ + if (ap->cbl == ATA_CBL_PATA40) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + /* Apply drive side cable rule. Unknown or 80 pin cables reported + * host side are checked drive side as well. Cases where we know a + * 40wire cable is used safely for 80 are not checked here. + */ + if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80)) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + + xfer_mask &= ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, dev->udma_mask); xfer_mask &= ata_id_xfermask(dev->id); @@ -3793,30 +3482,8 @@ static void ata_dev_xfermask(struct ata_device *dev) "other device, disabling DMA\n"); } - if (ap->flags & ATA_FLAG_NO_IORDY) - xfer_mask &= ata_pio_mask_no_iordy(dev); - if (ap->ops->mode_filter) - xfer_mask = ap->ops->mode_filter(dev, xfer_mask); - - /* Apply cable rule here. Don't apply it early because when - * we handle hot plug the cable type can itself change. - * Check this last so that we know if the transfer rate was - * solely limited by the cable. - * Unknown or 80 wire cables reported host side are checked - * drive side as well. Cases where we know a 40wire cable - * is used safely for 80 are not checked here. - */ - if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA)) - /* UDMA/44 or higher would be available */ - if((ap->cbl == ATA_CBL_PATA40) || - (ata_drive_40wire(dev->id) && - (ap->cbl == ATA_CBL_PATA_UNK || - ap->cbl == ATA_CBL_PATA80))) { - ata_dev_printk(dev, KERN_WARNING, - "limited to UDMA/33 due to 40-wire cable\n"); - xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); - } + xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask); ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, &dev->udma_mask); @@ -4355,10 +4022,10 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, /** - * ata_pio_sector - Transfer a sector of data. + * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. * @qc: Command on going * - * Transfer qc->sect_size bytes of data from/to the ATA device. + * Transfer ATA_SECT_SIZE of data from/to the ATA device. * * LOCKING: * Inherited from caller. @@ -4373,7 +4040,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned int offset; unsigned char *buf; - if (qc->curbytes == qc->nbytes - qc->sect_size) + if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE) ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; @@ -4393,17 +4060,17 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); } - qc->curbytes += qc->sect_size; - qc->cursg_ofs += qc->sect_size; + qc->curbytes += ATA_SECT_SIZE; + qc->cursg_ofs += ATA_SECT_SIZE; if (qc->cursg_ofs == (&sg[qc->cursg])->length) { qc->cursg++; @@ -4412,10 +4079,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) } /** - * ata_pio_sectors - Transfer one or many sectors. + * ata_pio_sectors - Transfer one or many 512-byte sectors. * @qc: Command on going * - * Transfer one or many sectors of data from/to the + * Transfer one or many ATA_SECT_SIZE of data from/to the * ATA device for the DRQ request. * * LOCKING: @@ -4430,7 +4097,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) WARN_ON(qc->dev->multi_count == 0); - nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, + nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE, qc->dev->multi_count); while (nsect--) ata_pio_sector(qc); @@ -5910,35 +5577,42 @@ void ata_dev_init(struct ata_device *dev) } /** - * ata_port_alloc - allocate and initialize basic ATA port resources - * @host: ATA host this allocated port belongs to + * ata_port_init - Initialize an ata_port structure + * @ap: Structure to initialize + * @host: Collection of hosts to which @ap belongs + * @ent: Probe information provided by low-level driver + * @port_no: Port number associated with this ata_port * - * Allocate and initialize basic ATA port resources. - * - * RETURNS: - * Allocate ATA port on success, NULL on failure. + * Initialize a new ata_port structure. * * LOCKING: - * Inherited from calling layer (may sleep). + * Inherited from caller. */ -struct ata_port *ata_port_alloc(struct ata_host *host) +void ata_port_init(struct ata_port *ap, struct ata_host *host, + const struct ata_probe_ent *ent, unsigned int port_no) { - struct ata_port *ap; unsigned int i; - DPRINTK("ENTER\n"); - - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - if (!ap) - return NULL; - ap->lock = &host->lock; ap->flags = ATA_FLAG_DISABLED; - ap->print_id = -1; + ap->print_id = ata_print_id++; ap->ctl = ATA_DEVCTL_OBS; ap->host = host; - ap->dev = host->dev; - + ap->dev = ent->dev; + ap->port_no = port_no; + if (port_no == 1 && ent->pinfo2) { + ap->pio_mask = ent->pinfo2->pio_mask; + ap->mwdma_mask = ent->pinfo2->mwdma_mask; + ap->udma_mask = ent->pinfo2->udma_mask; + ap->flags |= ent->pinfo2->flags; + ap->ops = ent->pinfo2->port_ops; + } else { + ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; + ap->udma_mask = ent->udma_mask; + ap->flags |= ent->port_flags; + ap->ops = ent->port_ops; + } ap->hw_sata_spd_limit = UINT_MAX; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; @@ -5958,7 +5632,10 @@ struct ata_port *ata_port_alloc(struct ata_host *host) INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); + /* set cable type */ ap->cbl = ATA_CBL_NONE; + if (ap->flags & ATA_FLAG_SATA) + ap->cbl = ATA_CBL_SATA; for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -5971,209 +5648,100 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; #endif - return ap; -} -static void ata_host_release(struct device *gendev, void *res) -{ - struct ata_host *host = dev_get_drvdata(gendev); - int i; - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - if (!ap) - continue; - - if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop) - ap->ops->port_stop(ap); - } - - if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop) - host->ops->host_stop(host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - if (!ap) - continue; - - if (ap->scsi_host) - scsi_host_put(ap->scsi_host); - - kfree(ap); - host->ports[i] = NULL; - } - - dev_set_drvdata(gendev, NULL); + memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports)); } /** - * ata_host_alloc - allocate and init basic ATA host resources - * @dev: generic device this host is associated with - * @max_ports: maximum number of ATA ports associated with this host + * ata_port_init_shost - Initialize SCSI host associated with ATA port + * @ap: ATA port to initialize SCSI host for + * @shost: SCSI host associated with @ap * - * Allocate and initialize basic ATA host resources. LLD calls - * this function to allocate a host, initializes it fully and - * attaches it using ata_host_register(). - * - * @max_ports ports are allocated and host->n_ports is - * initialized to @max_ports. The caller is allowed to decrease - * host->n_ports before calling ata_host_register(). The unused - * ports will be automatically freed on registration. - * - * RETURNS: - * Allocate ATA host on success, NULL on failure. + * Initialize SCSI host @shost associated with ATA port @ap. * * LOCKING: - * Inherited from calling layer (may sleep). + * Inherited from caller. */ -struct ata_host *ata_host_alloc(struct device *dev, int max_ports) +static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost) { - struct ata_host *host; - size_t sz; - int i; - - DPRINTK("ENTER\n"); - - if (!devres_open_group(dev, NULL, GFP_KERNEL)) - return NULL; - - /* alloc a container for our list of ATA ports (buses) */ - sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *); - /* alloc a container for our list of ATA ports (buses) */ - host = devres_alloc(ata_host_release, sz, GFP_KERNEL); - if (!host) - goto err_out; - - devres_add(dev, host); - dev_set_drvdata(dev, host); + ap->scsi_host = shost; - spin_lock_init(&host->lock); - host->dev = dev; - host->n_ports = max_ports; - - /* allocate ports bound to this host */ - for (i = 0; i < max_ports; i++) { - struct ata_port *ap; - - ap = ata_port_alloc(host); - if (!ap) - goto err_out; - - ap->port_no = i; - host->ports[i] = ap; - } - - devres_remove_group(dev, NULL); - return host; - - err_out: - devres_release_group(dev, NULL); - return NULL; + shost->unique_id = ap->print_id; + shost->max_id = 16; + shost->max_lun = 1; + shost->max_channel = 1; + shost->max_cmd_len = 12; } /** - * ata_host_alloc_pinfo - alloc host and init with port_info array - * @dev: generic device this host is associated with - * @ppi: array of ATA port_info to initialize host with - * @n_ports: number of ATA ports attached to this host + * ata_port_add - Attach low-level ATA driver to system + * @ent: Information provided by low-level driver + * @host: Collections of ports to which we add + * @port_no: Port number associated with this host * - * Allocate ATA host and initialize with info from @ppi. If NULL - * terminated, @ppi may contain fewer entries than @n_ports. The - * last entry will be used for the remaining ports. - * - * RETURNS: - * Allocate ATA host on success, NULL on failure. + * Attach low-level ATA driver to system. * * LOCKING: - * Inherited from calling layer (may sleep). + * PCI/etc. bus probe sem. + * + * RETURNS: + * New ata_port on success, for NULL on error. */ -struct ata_host *ata_host_alloc_pinfo(struct device *dev, - const struct ata_port_info * const * ppi, - int n_ports) +static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, + struct ata_host *host, + unsigned int port_no) { - const struct ata_port_info *pi; - struct ata_host *host; - int i, j; + struct Scsi_Host *shost; + struct ata_port *ap; - host = ata_host_alloc(dev, n_ports); - if (!host) + DPRINTK("ENTER\n"); + + if (!ent->port_ops->error_handler && + !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) { + printk(KERN_ERR "ata%u: no reset mechanism available\n", + port_no); return NULL; + } - for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; + shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port)); + if (!shost) + return NULL; - if (ppi[j]) - pi = ppi[j++]; + shost->transportt = &ata_scsi_transport_template; - ap->pio_mask = pi->pio_mask; - ap->mwdma_mask = pi->mwdma_mask; - ap->udma_mask = pi->udma_mask; - ap->flags |= pi->flags; - ap->ops = pi->port_ops; + ap = ata_shost_to_port(shost); - if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) - host->ops = pi->port_ops; - if (!host->private_data && pi->private_data) - host->private_data = pi->private_data; - } + ata_port_init(ap, host, ent, port_no); + ata_port_init_shost(ap, shost); - return host; + return ap; } -/** - * ata_host_start - start and freeze ports of an ATA host - * @host: ATA host to start ports for - * - * Start and then freeze ports of @host. Started status is - * recorded in host->flags, so this function can be called - * multiple times. Ports are guaranteed to get started only - * once. If host->ops isn't initialized yet, its set to the - * first non-dummy port ops. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 if all ports are started successfully, -errno otherwise. - */ -int ata_host_start(struct ata_host *host) +static void ata_host_release(struct device *gendev, void *res) { - int i, rc; - - if (host->flags & ATA_HOST_STARTED) - return 0; + struct ata_host *host = dev_get_drvdata(gendev); + int i; for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - if (!host->ops && !ata_port_is_dummy(ap)) - host->ops = ap->ops; - - if (ap->ops->port_start) { - rc = ap->ops->port_start(ap); - if (rc) { - ata_port_printk(ap, KERN_ERR, "failed to " - "start port (errno=%d)\n", rc); - goto err_out; - } - } - - ata_eh_freeze_port(ap); + if (ap && ap->ops->port_stop) + ap->ops->port_stop(ap); } - host->flags |= ATA_HOST_STARTED; - return 0; + if (host->ops->host_stop) + host->ops->host_stop(host); - err_out: - while (--i >= 0) { + for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - if (ap->ops->port_stop) - ap->ops->port_stop(ap); + if (ap) + scsi_host_put(ap->scsi_host); + + host->ports[i] = NULL; } - return rc; + + dev_set_drvdata(gendev, NULL); } /** @@ -6187,7 +5755,7 @@ int ata_host_start(struct ata_host *host) * PCI/etc. bus probe sem. * */ -/* KILLME - the only user left is ipr */ + void ata_host_init(struct ata_host *host, struct device *dev, unsigned long flags, const struct ata_port_operations *ops) { @@ -6198,95 +5766,155 @@ void ata_host_init(struct ata_host *host, struct device *dev, } /** - * ata_host_register - register initialized ATA host - * @host: ATA host to register - * @sht: template for SCSI host + * ata_device_add - Register hardware device with ATA and SCSI layers + * @ent: Probe information describing hardware device to be registered * - * Register initialized ATA host. @host is allocated using - * ata_host_alloc() and fully initialized by LLD. This function - * starts ports, registers @host with ATA and SCSI layers and - * probe registered devices. + * This function processes the information provided in the probe + * information struct @ent, allocates the necessary ATA and SCSI + * host information structures, initializes them, and registers + * everything with requisite kernel subsystems. + * + * This function requests irqs, probes the ATA bus, and probes + * the SCSI bus. * * LOCKING: - * Inherited from calling layer (may sleep). + * PCI/etc. bus probe sem. * * RETURNS: - * 0 on success, -errno otherwise. + * Number of ports registered. Zero on error (no ports registered). */ -int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) +int ata_device_add(const struct ata_probe_ent *ent) { - int i, rc; + unsigned int i; + struct device *dev = ent->dev; + struct ata_host *host; + int rc; - /* host must have been started */ - if (!(host->flags & ATA_HOST_STARTED)) { - dev_printk(KERN_ERR, host->dev, - "BUG: trying to register unstarted host\n"); - WARN_ON(1); - return -EINVAL; + DPRINTK("ENTER\n"); + + if (ent->irq == 0) { + dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n"); + return 0; } - /* Blow away unused ports. This happens when LLD can't - * determine the exact number of ports to allocate at - * allocation time. - */ - for (i = host->n_ports; host->ports[i]; i++) - kfree(host->ports[i]); + if (!devres_open_group(dev, ata_device_add, GFP_KERNEL)) + return 0; - /* give ports names and add SCSI hosts */ - for (i = 0; i < host->n_ports; i++) - host->ports[i]->print_id = ata_print_id++; + /* alloc a container for our list of ATA ports (buses) */ + host = devres_alloc(ata_host_release, sizeof(struct ata_host) + + (ent->n_ports * sizeof(void *)), GFP_KERNEL); + if (!host) + goto err_out; + devres_add(dev, host); + dev_set_drvdata(dev, host); - rc = ata_scsi_add_hosts(host, sht); - if (rc) - return rc; + ata_host_init(host, dev, ent->_host_flags, ent->port_ops); + host->n_ports = ent->n_ports; + host->irq = ent->irq; + host->irq2 = ent->irq2; + host->iomap = ent->iomap; + host->private_data = ent->private_data; - /* set cable, sata_spd_limit and report */ + /* register each port bound to this device */ for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - int irq_line; - u32 scontrol; - unsigned long xfer_mask; + struct ata_port *ap; + unsigned long xfer_mode_mask; + int irq_line = ent->irq; - /* set SATA cable type if still unset */ - if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA)) - ap->cbl = ATA_CBL_SATA; + ap = ata_port_add(ent, host, i); + host->ports[i] = ap; + if (!ap) + goto err_out; - /* init sata_spd_limit to the current value */ - if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { - int spd = (scontrol >> 4) & 0xf; - ap->hw_sata_spd_limit &= (1 << spd) - 1; + /* dummy? */ + if (ent->dummy_port_mask & (1 << i)) { + ata_port_printk(ap, KERN_INFO, "DUMMY\n"); + ap->ops = &ata_dummy_port_ops; + continue; } - ap->sata_spd_limit = ap->hw_sata_spd_limit; - /* report the secondary IRQ for second channel legacy */ - irq_line = host->irq; - if (i == 1 && host->irq2) - irq_line = host->irq2; + /* start port */ + rc = ap->ops->port_start(ap); + if (rc) { + host->ports[i] = NULL; + scsi_host_put(ap->scsi_host); + goto err_out; + } - xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, - ap->udma_mask); + /* Report the secondary IRQ for second channel legacy */ + if (i == 1 && ent->irq2) + irq_line = ent->irq2; + + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ - if (!ata_port_is_dummy(ap)) - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " - "ctl 0x%p bmdma 0x%p irq %d\n", - ap->cbl == ATA_CBL_SATA ? 'S' : 'P', - ata_mode_string(xfer_mask), - ap->ioaddr.cmd_addr, - ap->ioaddr.ctl_addr, - ap->ioaddr.bmdma_addr, - irq_line); - else - ata_port_printk(ap, KERN_INFO, "DUMMY\n"); + ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " + "ctl 0x%p bmdma 0x%p irq %d\n", + ap->flags & ATA_FLAG_SATA ? 'S' : 'P', + ata_mode_string(xfer_mode_mask), + ap->ioaddr.cmd_addr, + ap->ioaddr.ctl_addr, + ap->ioaddr.bmdma_addr, + irq_line); + + /* freeze port before requesting IRQ */ + ata_eh_freeze_port(ap); + } + + /* obtain irq, that may be shared between channels */ + rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler, + ent->irq_flags, DRV_NAME, host); + if (rc) { + dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", + ent->irq, rc); + goto err_out; + } + + /* do we have a second IRQ for the other channel, eg legacy mode */ + if (ent->irq2) { + /* We will get weird core code crashes later if this is true + so trap it now */ + BUG_ON(ent->irq == ent->irq2); + + rc = devm_request_irq(dev, ent->irq2, + ent->port_ops->irq_handler, ent->irq_flags, + DRV_NAME, host); + if (rc) { + dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", + ent->irq2, rc); + goto err_out; + } } + /* resource acquisition complete */ + devres_remove_group(dev, ata_device_add); + /* perform each probe synchronously */ DPRINTK("probe begin\n"); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + u32 scontrol; int rc; - /* probe */ + /* init sata_spd_limit to the current value */ + if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { + int spd = (scontrol >> 4) & 0xf; + ap->hw_sata_spd_limit &= (1 << spd) - 1; + } + ap->sata_spd_limit = ap->hw_sata_spd_limit; + + rc = scsi_add_host(ap->scsi_host, dev); + if (rc) { + ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n"); + /* FIXME: do something useful here */ + /* FIXME: handle unconditional calls to + * scsi_scan_host and ata_host_remove, below, + * at the very least + */ + } + if (ap->ops->error_handler) { struct ata_eh_info *ehi = &ap->eh_info; unsigned long flags; @@ -6331,49 +5959,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ata_scsi_scan_host(ap); } - return 0; -} + VPRINTK("EXIT, returning %u\n", ent->n_ports); + return ent->n_ports; /* success */ -/** - * ata_host_activate - start host, request IRQ and register it - * @host: target ATA host - * @irq: IRQ to request - * @irq_handler: irq_handler used when requesting IRQ - * @irq_flags: irq_flags used when requesting IRQ - * @sht: scsi_host_template to use when registering the host - * - * After allocating an ATA host and initializing it, most libata - * LLDs perform three steps to activate the host - start host, - * request IRQ and register it. This helper takes necessasry - * arguments and performs the three steps in one go. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_host_activate(struct ata_host *host, int irq, - irq_handler_t irq_handler, unsigned long irq_flags, - struct scsi_host_template *sht) -{ - int rc; - - rc = ata_host_start(host); - if (rc) - return rc; - - rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, - dev_driver_string(host->dev), host); - if (rc) - return rc; - - rc = ata_host_register(host, sht); - /* if failed, just free the IRQ and leave ports alone */ - if (rc) - devm_free_irq(host->dev, irq, host); - - return rc; + err_out: + devres_release_group(dev, ata_device_add); + VPRINTK("EXIT, returning %d\n", rc); + return 0; } /** @@ -6451,6 +6043,32 @@ void ata_host_detach(struct ata_host *host) ata_port_detach(host->ports[i]); } +struct ata_probe_ent * +ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) +{ + struct ata_probe_ent *probe_ent; + + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) { + printk(KERN_ERR DRV_NAME "(%s): out of memory\n", + kobject_name(&(dev->kobj))); + return NULL; + } + + INIT_LIST_HEAD(&probe_ent->node); + probe_ent->dev = dev; + + probe_ent->sht = port->sht; + probe_ent->port_flags = port->flags; + probe_ent->pio_mask = port->pio_mask; + probe_ent->mwdma_mask = port->mwdma_mask; + probe_ent->udma_mask = port->udma_mask; + probe_ent->port_ops = port->port_ops; + probe_ent->private_data = port->private_data; + + return probe_ent; +} + /** * ata_std_ports - initialize ioaddr with standard port offsets. * @ioaddr: IO address structure to be initialized @@ -6716,10 +6334,6 @@ const struct ata_port_operations ata_dummy_port_ops = { .port_stop = ata_dummy_noret, }; -const struct ata_port_info ata_dummy_port_info = { - .port_ops = &ata_dummy_port_ops, -}; - /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -6731,15 +6345,10 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_normal); EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_long); EXPORT_SYMBOL_GPL(ata_dummy_port_ops); -EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_init); -EXPORT_SYMBOL_GPL(ata_host_alloc); -EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); -EXPORT_SYMBOL_GPL(ata_host_start); -EXPORT_SYMBOL_GPL(ata_host_register); -EXPORT_SYMBOL_GPL(ata_host_activate); +EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); @@ -6751,7 +6360,6 @@ EXPORT_SYMBOL_GPL(ata_tf_load); EXPORT_SYMBOL_GPL(ata_tf_read); EXPORT_SYMBOL_GPL(ata_noop_dev_select); EXPORT_SYMBOL_GPL(ata_std_dev_select); -EXPORT_SYMBOL_GPL(sata_print_link_status); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_check_status); @@ -6759,7 +6367,6 @@ EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_data_xfer); EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_qc_prep); @@ -6822,8 +6429,7 @@ EXPORT_SYMBOL_GPL(ata_timing_merge); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); -EXPORT_SYMBOL_GPL(ata_pci_init_native_host); -EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host); +EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM @@ -6855,8 +6461,3 @@ EXPORT_SYMBOL_GPL(ata_dummy_irq_on); EXPORT_SYMBOL_GPL(ata_irq_ack); EXPORT_SYMBOL_GPL(ata_dummy_irq_ack); EXPORT_SYMBOL_GPL(ata_dev_try_classify); - -EXPORT_SYMBOL_GPL(ata_cable_40wire); -EXPORT_SYMBOL_GPL(ata_cable_80wire); -EXPORT_SYMBOL_GPL(ata_cable_unknown); -EXPORT_SYMBOL_GPL(ata_cable_sata); diff --git a/trunk/drivers/ata/libata-eh.c b/trunk/drivers/ata/libata-eh.c index 2bff9adcacf1..39f556c02992 100644 --- a/trunk/drivers/ata/libata-eh.c +++ b/trunk/drivers/ata/libata-eh.c @@ -1056,7 +1056,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap) } if (serror & SERR_INTERNAL) { err_mask |= AC_ERR_SYSTEM; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_SOFTRESET; } if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) ata_ehi_hotplugged(&ehc->i); @@ -1151,9 +1151,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return ATA_EH_SOFTRESET; } - if (stat & (ATA_ERR | ATA_DF)) - qc->err_mask |= AC_ERR_DEV; - else + if (!(qc->err_mask & AC_ERR_DEV)) return 0; switch (qc->dev->class) { @@ -1671,10 +1669,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ - if (reset == hardreset) - ehc->i.flags |= ATA_EHI_DID_HARDRESET; - else - ehc->i.flags |= ATA_EHI_DID_SOFTRESET; + ehc->i.flags |= ATA_EHI_DID_RESET; rc = ata_do_reset(ap, reset, classes); @@ -1813,10 +1808,6 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } } - /* PDIAG- should have been released, ask cable type if post-reset */ - if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect) - ap->cbl = ap->ops->cable_detect(ap); - /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ diff --git a/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c index 9afba2ba489e..e9364434182c 100644 --- a/trunk/drivers/ata/libata-scsi.c +++ b/trunk/drivers/ata/libata-scsi.c @@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { * libata transport template. libata doesn't do real transport stuff. * It just needs the eh_timed_out hook. */ -static struct scsi_transport_template ata_scsi_transport_template = { +struct scsi_transport_template ata_scsi_transport_template = { .eh_strategy_handler = ata_scsi_error, .eh_timed_out = ata_scsi_timed_out, .user_scan = ata_scsi_user_scan, @@ -2678,18 +2678,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) tf->device = qc->dev->devno ? tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; - /* READ/WRITE LONG use a non-standard sect_size */ - qc->sect_size = ATA_SECT_SIZE; - switch (tf->command) { - case ATA_CMD_READ_LONG: - case ATA_CMD_READ_LONG_ONCE: - case ATA_CMD_WRITE_LONG: - case ATA_CMD_WRITE_LONG_ONCE: - if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) - goto invalid_fld; - qc->sect_size = scmd->request_bufflen; - } - /* * Filter SET_FEATURES - XFER MODE command -- otherwise, * SET_FEATURES - XFER MODE must be preceded/succeeded @@ -2804,9 +2792,8 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, { int rc = 0; - if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) { - DPRINTK("bad CDB len=%u, max=%u\n", - scmd->cmd_len, dev->cdb_len); + if (unlikely(!scmd->cmd_len)) { + ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n"); scmd->result = DID_ERROR << 16; done(scmd); return 0; @@ -2961,48 +2948,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, } } -int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) -{ - int i, rc; - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - struct Scsi_Host *shost; - - rc = -ENOMEM; - shost = scsi_host_alloc(sht, sizeof(struct ata_port *)); - if (!shost) - goto err_alloc; - - *(struct ata_port **)&shost->hostdata[0] = ap; - ap->scsi_host = shost; - - shost->transportt = &ata_scsi_transport_template; - shost->unique_id = ap->print_id; - shost->max_id = 16; - shost->max_lun = 1; - shost->max_channel = 1; - shost->max_cmd_len = 16; - - rc = scsi_add_host(ap->scsi_host, ap->host->dev); - if (rc) - goto err_add; - } - - return 0; - - err_add: - scsi_host_put(host->ports[i]->scsi_host); - err_alloc: - while (--i >= 0) { - struct Scsi_Host *shost = host->ports[i]->scsi_host; - - scsi_remove_host(shost); - scsi_host_put(shost); - } - return rc; -} - void ata_scsi_scan_host(struct ata_port *ap) { unsigned int i; @@ -3279,21 +3224,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, struct ata_port_info *port_info, struct Scsi_Host *shost) { - struct ata_port *ap; + struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL); + struct ata_probe_ent *ent; - ap = ata_port_alloc(host); if (!ap) return NULL; - ap->port_no = 0; - ap->lock = shost->host_lock; - ap->pio_mask = port_info->pio_mask; - ap->mwdma_mask = port_info->mwdma_mask; - ap->udma_mask = port_info->udma_mask; - ap->flags |= port_info->flags; - ap->ops = port_info->port_ops; - ap->cbl = ATA_CBL_SATA; + ent = ata_probe_ent_alloc(host->dev, port_info); + if (!ent) { + kfree(ap); + return NULL; + } + ata_port_init(ap, host, ent, 0); + ap->lock = shost->host_lock; + devm_kfree(host->dev, ent); return ap; } EXPORT_SYMBOL_GPL(ata_sas_port_alloc); @@ -3349,10 +3294,8 @@ int ata_sas_port_init(struct ata_port *ap) { int rc = ap->ops->port_start(ap); - if (!rc) { - ap->print_id = ata_print_id++; + if (!rc) rc = ata_bus_probe(ap); - } return rc; } diff --git a/trunk/drivers/ata/libata-sff.c b/trunk/drivers/ata/libata-sff.c index d211db6b35a2..2ffcca063d80 100644 --- a/trunk/drivers/ata/libata-sff.c +++ b/trunk/drivers/ata/libata-sff.c @@ -526,400 +526,169 @@ static int ata_resources_present(struct pci_dev *pdev, int port) port = port * 2; for (i = 0; i < 2; i ++) { if (pci_resource_start(pdev, port + i) == 0 || - pci_resource_len(pdev, port + i) == 0) - return 0; + pci_resource_len(pdev, port + i) == 0) + return 0; } return 1; } /** - * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host - * @host: target ATA host - * - * Acquire PCI BMDMA resources and initialize @host accordingly. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. + * ata_pci_init_native_mode - Initialize native-mode driver + * @pdev: pci device to be initialized + * @port: array[2] of pointers to port info structures. + * @ports: bitmap of ports present + * + * Utility function which allocates and initializes an + * ata_probe_ent structure for a standard dual-port + * PIO-based IDE controller. The returned ata_probe_ent + * structure can be passed to ata_device_add(). The returned + * ata_probe_ent structure should then be freed with kfree(). + * + * The caller need only pass the address of the primary port, the + * secondary will be deduced automatically. If the device has non + * standard secondary port mappings this function can be called twice, + * once for each interface. */ -static int ata_pci_init_bmdma(struct ata_host *host) -{ - struct device *gdev = host->dev; - struct pci_dev *pdev = to_pci_dev(gdev); - int i, rc; - - /* TODO: If we get no DMA mask we should fall back to PIO */ - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; - - /* request and iomap DMA region */ - rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME); - if (rc) { - dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n"); - return -ENOMEM; - } - host->iomap = pcim_iomap_table(pdev); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - void __iomem *bmdma = host->iomap[4] + 8 * i; - - if (ata_port_is_dummy(ap)) - continue; - - ap->ioaddr.bmdma_addr = bmdma; - if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) && - (ioread8(bmdma + 2) & 0x80)) - host->flags |= ATA_HOST_SIMPLEX; - } - - return 0; -} -/** - * ata_pci_init_native_host - acquire native ATA resources and init host - * @host: target ATA host - * @port_mask: ports to consider - * - * Acquire native PCI ATA resources for @host and initialize - * @host accordoingly. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_pci_init_native_host(struct ata_host *host, unsigned int port_mask) +struct ata_probe_ent * +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { - struct device *gdev = host->dev; - struct pci_dev *pdev = to_pci_dev(gdev); - int i, rc; - - /* Discard disabled ports. Some controllers show their unused - * channels this way. Disabled ports are made dummy. - */ - for (i = 0; i < 2; i++) { - if ((port_mask & (1 << i)) && !ata_resources_present(pdev, i)) { - host->ports[i]->ops = &ata_dummy_port_ops; - port_mask &= ~(1 << i); + struct ata_probe_ent *probe_ent; + int i, p = 0; + void __iomem * const *iomap; + + /* iomap BARs */ + for (i = 0; i < 4; i++) { + if (pcim_iomap(pdev, i, 0) == NULL) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to iomap PCI BAR %d\n", i); + return NULL; } } - if (!port_mask) { - dev_printk(KERN_ERR, gdev, "no available port\n"); - return -ENODEV; - } - - /* request, iomap BARs and init port addresses accordingly */ - for (i = 0; i < 2; i++) { - struct ata_port *ap = host->ports[i]; - int base = i * 2; - void __iomem * const *iomap; - - if (!(port_mask & (1 << i))) - continue; - - rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME); - if (rc) { - dev_printk(KERN_ERR, gdev, "failed to request/iomap " - "BARs for port %d (errno=%d)\n", i, rc); - if (rc == -EBUSY) - pcim_pin_device(pdev); - return rc; + pcim_iomap(pdev, 4, 0); /* may fail */ + iomap = pcim_iomap_table(pdev); + + /* alloc and init probe_ent */ + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + if (!probe_ent) + return NULL; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + + /* Discard disabled ports. Some controllers show their + unused channels this way */ + if (ata_resources_present(pdev, 0) == 0) + ports &= ~ATA_PORT_PRIMARY; + if (ata_resources_present(pdev, 1) == 0) + ports &= ~ATA_PORT_SECONDARY; + + if (ports & ATA_PORT_PRIMARY) { + probe_ent->port[p].cmd_addr = iomap[0]; + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS); + if (iomap[4]) { + if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (ioread8(iomap[4] + 2) & 0x80)) + probe_ent->_host_flags |= ATA_HOST_SIMPLEX; + probe_ent->port[p].bmdma_addr = iomap[4]; } - host->iomap = iomap = pcim_iomap_table(pdev); - - ap->ioaddr.cmd_addr = iomap[base]; - ap->ioaddr.altstatus_addr = - ap->ioaddr.ctl_addr = (void __iomem *) - ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS); - ata_std_ports(&ap->ioaddr); + ata_std_ports(&probe_ent->port[p]); + p++; } - return 0; -} - -/** - * ata_pci_prepare_native_host - helper to prepare native PCI ATA host - * @pdev: target PCI device - * @ppi: array of port_info - * @n_ports: number of ports to allocate - * @r_host: out argument for the initialized ATA host - * - * Helper to allocate ATA host for @pdev, acquire all native PCI - * resources and initialize it accordingly in one go. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_pci_prepare_native_host(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, - int n_ports, struct ata_host **r_host) -{ - struct ata_host *host; - unsigned int port_mask; - int rc; - - if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); - if (!host) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to allocate ATA host\n"); - rc = -ENOMEM; - goto err_out; - } - - port_mask = ATA_PORT_PRIMARY; - if (n_ports > 1) - port_mask |= ATA_PORT_SECONDARY; - - rc = ata_pci_init_native_host(host, port_mask); - if (rc) - goto err_out; - - /* init DMA related stuff */ - rc = ata_pci_init_bmdma(host); - if (rc) - goto err_bmdma; - - devres_remove_group(&pdev->dev, NULL); - *r_host = host; - return 0; - - err_bmdma: - /* This is necessary because PCI and iomap resources are - * merged and releasing the top group won't release the - * acquired resources if some of those have been acquired - * before entering this function. - */ - pcim_iounmap_regions(pdev, 0xf); - err_out: - devres_release_group(&pdev->dev, NULL); - return rc; -} - -struct ata_legacy_devres { - unsigned int mask; - unsigned long cmd_port[2]; - void __iomem * cmd_addr[2]; - void __iomem * ctl_addr[2]; - unsigned int irq[2]; - void * irq_dev_id[2]; -}; - -static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr) -{ - int i; - - for (i = 0; i < 2; i++) { - if (!legacy_dr->irq[i]) - continue; - - free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]); - legacy_dr->irq[i] = 0; - legacy_dr->irq_dev_id[i] = NULL; + if (ports & ATA_PORT_SECONDARY) { + probe_ent->port[p].cmd_addr = iomap[2]; + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS); + if (iomap[4]) { + if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (ioread8(iomap[4] + 10) & 0x80)) + probe_ent->_host_flags |= ATA_HOST_SIMPLEX; + probe_ent->port[p].bmdma_addr = iomap[4] + 8; + } + ata_std_ports(&probe_ent->port[p]); + probe_ent->pinfo2 = port[1]; + p++; } -} - -static void ata_legacy_release(struct device *gdev, void *res) -{ - struct ata_legacy_devres *this = res; - int i; - ata_legacy_free_irqs(this); - - for (i = 0; i < 2; i++) { - if (this->cmd_addr[i]) - ioport_unmap(this->cmd_addr[i]); - if (this->ctl_addr[i]) - ioport_unmap(this->ctl_addr[i]); - if (this->cmd_port[i]) - release_region(this->cmd_port[i], 8); - } + probe_ent->n_ports = p; + return probe_ent; } -static int ata_init_legacy_port(struct ata_port *ap, - struct ata_legacy_devres *legacy_dr) +static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, + struct ata_port_info **port, int port_mask) { - struct ata_host *host = ap->host; - int port_no = ap->port_no; - unsigned long cmd_port, ctl_port; - - if (port_no == 0) { - cmd_port = ATA_PRIMARY_CMD; - ctl_port = ATA_PRIMARY_CTL; - } else { - cmd_port = ATA_SECONDARY_CMD; - ctl_port = ATA_SECONDARY_CTL; - } - - /* request cmd_port */ - if (request_region(cmd_port, 8, "libata")) - legacy_dr->cmd_port[port_no] = cmd_port; - else { - dev_printk(KERN_WARNING, host->dev, - "0x%0lX IDE port busy\n", cmd_port); - return -EBUSY; + struct ata_probe_ent *probe_ent; + void __iomem *iomap[5] = { }, *bmdma; + + if (port_mask & ATA_PORT_PRIMARY) { + iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8); + iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1); + if (!iomap[0] || !iomap[1]) + return NULL; } - /* iomap cmd and ctl ports */ - legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8); - legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1); - if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no]) - return -ENOMEM; - - /* init IO addresses */ - ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no]; - ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no]; - ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no]; - ata_std_ports(&ap->ioaddr); - - return 0; -} - -/** - * ata_init_legacy_host - acquire legacy ATA resources and init ATA host - * @host: target ATA host - * @legacy_mask: out parameter, mask indicating ports is in legacy mode - * @was_busy: out parameter, indicates whether any port was busy - * - * Acquire legacy ATA resources for ports. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int ata_init_legacy_host(struct ata_host *host, - unsigned int *legacy_mask, int *was_busy) -{ - struct device *gdev = host->dev; - struct ata_legacy_devres *legacy_dr; - int i, rc; - - if (!devres_open_group(gdev, NULL, GFP_KERNEL)) - return -ENOMEM; - - rc = -ENOMEM; - legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr), - GFP_KERNEL); - if (!legacy_dr) - goto err_out; - devres_add(gdev, legacy_dr); - - for (i = 0; i < 2; i++) { - *legacy_mask &= ~(1 << i); - rc = ata_init_legacy_port(host->ports[i], legacy_dr); - if (rc == 0) - legacy_dr->mask |= 1 << i; - else if (rc == -EBUSY) - (*was_busy)++; + if (port_mask & ATA_PORT_SECONDARY) { + iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8); + iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1); + if (!iomap[2] || !iomap[3]) + return NULL; } - if (!legacy_dr->mask) - return -EBUSY; - - for (i = 0; i < 2; i++) - if (!(legacy_dr->mask & (1 << i))) - host->ports[i]->ops = &ata_dummy_port_ops; - - *legacy_mask |= legacy_dr->mask; - - devres_remove_group(gdev, NULL); - return 0; - - err_out: - devres_release_group(gdev, NULL); - return rc; -} - -/** - * ata_request_legacy_irqs - request legacy ATA IRQs - * @host: target ATA host - * @handler: array of IRQ handlers - * @irq_flags: array of IRQ flags - * @dev_id: array of IRQ dev_ids - * - * Request legacy IRQs for non-dummy legacy ports in @host. All - * IRQ parameters are passed as array to allow ports to have - * separate IRQ handlers. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int ata_request_legacy_irqs(struct ata_host *host, - irq_handler_t const *handler, - const unsigned int *irq_flags, - void * const *dev_id) -{ - struct device *gdev = host->dev; - struct ata_legacy_devres *legacy_dr; - int i, rc; - - legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL); - BUG_ON(!legacy_dr); - - for (i = 0; i < host->n_ports; i++) { - unsigned int irq; - - /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */ - if (i == 0) - irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev)); - else - irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev)); - - if (!(legacy_dr->mask & (1 << i))) - continue; - - if (!handler[i]) { - dev_printk(KERN_ERR, gdev, - "NULL handler specified for port %d\n", i); - rc = -EINVAL; - goto err_out; + bmdma = pcim_iomap(pdev, 4, 16); /* may fail */ + + /* alloc and init probe_ent */ + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + if (!probe_ent) + return NULL; + + probe_ent->n_ports = 2; + probe_ent->irq_flags = IRQF_SHARED; + + if (port_mask & ATA_PORT_PRIMARY) { + probe_ent->irq = ATA_PRIMARY_IRQ(pdev); + probe_ent->port[0].cmd_addr = iomap[0]; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = iomap[1]; + if (bmdma) { + probe_ent->port[0].bmdma_addr = bmdma; + if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (ioread8(bmdma + 2) & 0x80)) + probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } + ata_std_ports(&probe_ent->port[0]); + } else + probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY; - rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME, - dev_id[i]); - if (rc) { - dev_printk(KERN_ERR, gdev, - "irq %u request failed (errno=%d)\n", irq, rc); - goto err_out; + if (port_mask & ATA_PORT_SECONDARY) { + if (probe_ent->irq) + probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev); + else + probe_ent->irq = ATA_SECONDARY_IRQ(pdev); + probe_ent->port[1].cmd_addr = iomap[2]; + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = iomap[3]; + if (bmdma) { + probe_ent->port[1].bmdma_addr = bmdma + 8; + if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) && + (ioread8(bmdma + 10) & 0x80)) + probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } + ata_std_ports(&probe_ent->port[1]); - /* record irq allocation in legacy_dr */ - legacy_dr->irq[i] = irq; - legacy_dr->irq_dev_id[i] = dev_id[i]; - - /* only used to print info */ - if (i == 0) - host->irq = irq; - else - host->irq2 = irq; - } + /* FIXME: could be pointing to stack area; must copy */ + probe_ent->pinfo2 = port[1]; + } else + probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY; - return 0; - - err_out: - ata_legacy_free_irqs(legacy_dr); - return rc; + return probe_ent; } + /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -949,8 +718,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { struct device *dev = &pdev->dev; - struct ata_host *host = NULL; - const struct ata_port_info *port[2]; + struct ata_probe_ent *probe_ent = NULL; + struct ata_port_info *port[2]; u8 mask; unsigned int legacy_mode = 0; int rc; @@ -963,7 +732,10 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, BUG_ON(n_ports < 1 || n_ports > 2); port[0] = port_info[0]; - port[1] = (n_ports > 1) ? port_info[1] : NULL; + if (n_ports > 1) + port[1] = port_info[1]; + else + port[1] = port[0]; /* FIXME: Really for ATA it isn't safe because the device may be multi-purpose and we want to leave it alone if it was already @@ -971,7 +743,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, Checking dev->is_enabled is insufficient as this is not set at boot for the primary video which is BIOS enabled - */ + */ rc = pcim_enable_device(pdev); if (rc) @@ -997,68 +769,96 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, #endif } - /* alloc and init host */ - host = ata_host_alloc_pinfo(dev, port, n_ports); - if (!host) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to allocate ATA host\n"); - rc = -ENOMEM; - goto err_out; - } - if (!legacy_mode) { - unsigned int port_mask; - - port_mask = ATA_PORT_PRIMARY; - if (n_ports > 1) - port_mask |= ATA_PORT_SECONDARY; - - rc = ata_pci_init_native_host(host, port_mask); - if (rc) - goto err_out; - } else { - int was_busy = 0; - - rc = ata_init_legacy_host(host, &legacy_mode, &was_busy); - if (was_busy) + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { pcim_pin_device(pdev); - if (rc) goto err_out; - - /* request respective PCI regions, may fail */ - rc = pci_request_region(pdev, 1, DRV_NAME); - rc = pci_request_region(pdev, 3, DRV_NAME); + } + } else { + /* Deal with combined mode hack. This side of the logic all + goes away once the combined mode hack is killed in 2.6.21 */ + if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) { + struct resource *conflict, res; + res.start = ATA_PRIMARY_CMD; + res.end = ATA_PRIMARY_CMD + 8 - 1; + conflict = ____request_resource(&ioport_resource, &res); + while (conflict->child) + conflict = ____request_resource(conflict, &res); + if (!strcmp(conflict->name, "libata")) + legacy_mode |= ATA_PORT_PRIMARY; + else { + pcim_pin_device(pdev); + printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \ + "ata: conflict with %s\n", + ATA_PRIMARY_CMD, + conflict->name); + } + } else + legacy_mode |= ATA_PORT_PRIMARY; + + if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) { + struct resource *conflict, res; + res.start = ATA_SECONDARY_CMD; + res.end = ATA_SECONDARY_CMD + 8 - 1; + conflict = ____request_resource(&ioport_resource, &res); + while (conflict->child) + conflict = ____request_resource(conflict, &res); + if (!strcmp(conflict->name, "libata")) + legacy_mode |= ATA_PORT_SECONDARY; + else { + pcim_pin_device(pdev); + printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \ + "ata: conflict with %s\n", + ATA_SECONDARY_CMD, + conflict->name); + } + } else + legacy_mode |= ATA_PORT_SECONDARY; + + if (legacy_mode & ATA_PORT_PRIMARY) + pci_request_region(pdev, 1, DRV_NAME); + if (legacy_mode & ATA_PORT_SECONDARY) + pci_request_region(pdev, 3, DRV_NAME); + /* If there is a DMA resource, allocate it */ + pci_request_region(pdev, 4, DRV_NAME); } - /* init BMDMA, may fail */ - ata_pci_init_bmdma(host); - pci_set_master(pdev); + /* we have legacy mode, but all ports are unavailable */ + if (legacy_mode == (1 << 3)) { + rc = -EBUSY; + goto err_out; + } - /* start host and request IRQ */ - rc = ata_host_start(host); + /* TODO: If we get no DMA mask we should fall back to PIO */ + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out; - if (!legacy_mode) - rc = devm_request_irq(dev, pdev->irq, - port_info[0]->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - else { - irq_handler_t handler[2] = { host->ops->irq_handler, - host->ops->irq_handler }; - unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED }; - void *dev_id[2] = { host, host }; - - rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id); + if (legacy_mode) { + probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode); + } else { + if (n_ports == 2) + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + else + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY); } - if (rc) + if (!probe_ent) { + rc = -ENOMEM; goto err_out; + } - /* register */ - rc = ata_host_register(host, port_info[0]->sht); - if (rc) + pci_set_master(pdev); + + if (!ata_device_add(probe_ent)) { + rc = -ENODEV; goto err_out; + } + devm_kfree(dev, probe_ent); devres_remove_group(dev, NULL); return 0; @@ -1093,12 +893,12 @@ int ata_pci_clear_simplex(struct pci_dev *pdev) return 0; } -unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask) +unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask) { /* Filter out DMA modes if the device has been configured by the BIOS as PIO only */ - if (adev->ap->ioaddr.bmdma_addr == 0) + if (ap->ioaddr.bmdma_addr == 0) xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); return xfer_mask; } diff --git a/trunk/drivers/ata/libata.h b/trunk/drivers/ata/libata.h index 5f4d40cd3288..1f1e3a51f859 100644 --- a/trunk/drivers/ata/libata.h +++ b/trunk/drivers/ata/libata.h @@ -52,7 +52,6 @@ enum { ATA_DNXFER_QUIET = (1 << 31), }; -extern unsigned int ata_print_id; extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; @@ -93,7 +92,10 @@ extern int ata_flush_cache(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); -extern struct ata_port *ata_port_alloc(struct ata_host *host); +extern void ata_port_init(struct ata_port *ap, struct ata_host *host, + const struct ata_probe_ent *ent, unsigned int port_no); +extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev, + const struct ata_port_info *port); /* libata-acpi.c */ #ifdef CONFIG_SATA_ACPI @@ -111,8 +113,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) #endif /* libata-scsi.c */ -extern int ata_scsi_add_hosts(struct ata_host *host, - struct scsi_host_template *sht); +extern struct scsi_transport_template ata_scsi_transport_template; + extern void ata_scsi_scan_host(struct ata_port *ap); extern int ata_scsi_offline_dev(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); diff --git a/trunk/drivers/ata/pata_ali.c b/trunk/drivers/ata/pata_ali.c index d40edebb510a..11ea552a58ca 100644 --- a/trunk/drivers/ata/pata_ali.c +++ b/trunk/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.7.4" +#define DRV_VERSION "0.7.3" /* * Cable special cases @@ -89,6 +89,59 @@ static int ali_c2_cable_detect(struct ata_port *ap) return ATA_CBL_PATA80; } +/** + * ali_early_error_handler - reset for eary chip + * @ap: ATA port + * + * Handle the reset callback for the later chips with cable detect + */ + +static int ali_c2_pre_reset(struct ata_port *ap) +{ + ap->cbl = ali_c2_cable_detect(ap); + return ata_std_prereset(ap); +} + +static void ali_c2_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ali_c2_pre_reset, + ata_std_softreset, NULL, + ata_std_postreset); +} + +/** + * ali_early_cable_detect - cable detection + * @ap: ATA port + * + * Perform cable detection for older chipsets. This turns out to be + * rather easy to implement + */ + +static int ali_early_cable_detect(struct ata_port *ap) +{ + return ATA_CBL_PATA40; +} + +/** + * ali_early_probe_init - reset for early chip + * @ap: ATA port + * + * Handle the reset callback for the early (pre cable detect) chips. + */ + +static int ali_early_pre_reset(struct ata_port *ap) +{ + ap->cbl = ali_early_cable_detect(ap); + return ata_std_prereset(ap); +} + +static void ali_early_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, ali_early_pre_reset, + ata_std_softreset, NULL, + ata_std_postreset); +} + /** * ali_20_filter - filter for earlier ALI DMA * @ap: ALi ATA port @@ -98,7 +151,7 @@ static int ali_c2_cable_detect(struct ata_port *ap) * fix that later on. Also ensure we do not do UDMA on WDC drives */ -static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask) +static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { char model_num[ATA_ID_PROD_LEN + 1]; /* No DMA on anything but a disk for now */ @@ -107,7 +160,7 @@ static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask) ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strstr(model_num, "WDC")) return mask &= ~ATA_MASK_UDMA; - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } /** @@ -261,6 +314,7 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * ali_lock_sectors - Keep older devices to 255 sector mode + * @ap: ATA port * @adev: Device * * Called during the bus probe for each device that is found. We use @@ -270,7 +324,7 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev) * slower PIO methods */ -static void ali_lock_sectors(struct ata_device *adev) +static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev) { adev->max_sectors = 255; } @@ -312,9 +366,8 @@ static struct ata_port_operations ali_early_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = ali_early_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -349,9 +402,8 @@ static struct ata_port_operations ali_20_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = ali_early_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -388,9 +440,8 @@ static struct ata_port_operations ali_c2_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = ali_c2_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ali_c2_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -426,9 +477,8 @@ static struct ata_port_operations ali_c5_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = ali_c2_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ali_c2_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_amd.c b/trunk/drivers/ata/pata_amd.c index 536ee892ab72..18381762908b 100644 --- a/trunk/drivers/ata/pata_amd.c +++ b/trunk/drivers/ata/pata_amd.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.8" +#define DRV_VERSION "0.2.8" /** * timing_setup - shared timing computation and load @@ -119,25 +119,32 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse } /** - * amd_probe_init - perform reset handling + * amd_probe_init - cable detection * @ap: ATA port * - * Reset sequence checking enable bits to see which ports are - * active. + * Perform cable detection. The BIOS stores this in PCI config + * space for us. */ static int amd_pre_reset(struct ata_port *ap) { + static const u32 bitmask[2] = {0x03, 0x0C}; static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 ata66; if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; + pci_read_config_byte(pdev, 0x42, &ata66); + if (ata66 & bitmask[ap->port_no]) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -149,16 +156,28 @@ static void amd_error_handler(struct ata_port *ap) ata_std_postreset); } -static int amd_cable_detect(struct ata_port *ap) +static int amd_early_pre_reset(struct ata_port *ap) { - static const u32 bitmask[2] = {0x03, 0x0C}; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 ata66; + static struct pci_bits amd_enable_bits[] = { + { 0x40, 1, 0x02, 0x02 }, + { 0x40, 1, 0x01, 0x01 } + }; - pci_read_config_byte(pdev, 0x42, &ata66); - if (ata66 & bitmask[ap->port_no]) - return ATA_CBL_PATA80; - return ATA_CBL_PATA40; + if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) + return -ENOENT; + + /* No host side cable detection */ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); + +} + +static void amd_early_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, amd_early_pre_reset, + ata_std_softreset, NULL, + ata_std_postreset); } /** @@ -228,16 +247,31 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) */ static int nv_pre_reset(struct ata_port *ap) { + static const u8 bitmask[2] = {0x03, 0x0C}; static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 ata66; + u16 udma; if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; + pci_read_config_byte(pdev, 0x52, &ata66); + if (ata66 & bitmask[ap->port_no]) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + /* We now have to double check because the Nvidia boxes BIOS + doesn't always set the cable bits but does set mode bits */ + + pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); + if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) + ap->cbl = ATA_CBL_PATA80; return ata_std_prereset(ap); } @@ -247,29 +281,6 @@ static void nv_error_handler(struct ata_port *ap) ata_std_softreset, NULL, ata_std_postreset); } - -static int nv_cable_detect(struct ata_port *ap) -{ - static const u8 bitmask[2] = {0x03, 0x0C}; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 ata66; - u16 udma; - int cbl; - - pci_read_config_byte(pdev, 0x52, &ata66); - if (ata66 & bitmask[ap->port_no]) - cbl = ATA_CBL_PATA80; - else - cbl = ATA_CBL_PATA40; - - /* We now have to double check because the Nvidia boxes BIOS - doesn't always set the cable bits but does set mode bits */ - pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); - if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) - cbl = ATA_CBL_PATA80; - return cbl; -} - /** * nv100_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -342,9 +353,8 @@ static struct ata_port_operations amd33_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, + .error_handler = amd_early_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -377,9 +387,8 @@ static struct ata_port_operations amd66_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = amd_error_handler, + .error_handler = amd_early_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -414,7 +423,6 @@ static struct ata_port_operations amd100_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = amd_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -449,7 +457,6 @@ static struct ata_port_operations amd133_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = amd_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = amd_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -484,7 +491,6 @@ static struct ata_port_operations nv100_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = nv_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -519,7 +525,6 @@ static struct ata_port_operations nv133_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = nv_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_artop.c b/trunk/drivers/ata/pata_artop.c index 00e9ec342db0..21c30282717c 100644 --- a/trunk/drivers/ata/pata_artop.c +++ b/trunk/drivers/ata/pata_artop.c @@ -49,6 +49,8 @@ static int artop6210_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; + + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -83,28 +85,18 @@ static int artop6260_pre_reset(struct ata_port *ap) }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; /* Odd numbered device ids are the units with enable bits (the -R cards) */ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); -} -/** - * artop6260_cable_detect - identify cable type - * @ap: Port - * - * Identify the cable type for the ARTOp interface in question - */ - -static int artop6260_cable_detect(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 tmp; pci_read_config_byte(pdev, 0x49, &tmp); if (tmp & (1 << ap->port_no)) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); } /** @@ -233,7 +225,7 @@ static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev) /** * artop6210_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring - * @adev: Device whose timings we are configuring + * @adev: um * * Set DMA mode for device, in host controller PCI config space. * @@ -341,7 +333,6 @@ static const struct ata_port_operations artop6210_ops = { .thaw = ata_bmdma_thaw, .error_handler = artop6210_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -375,7 +366,6 @@ static const struct ata_port_operations artop6260_ops = { .thaw = ata_bmdma_thaw, .error_handler = artop6260_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = artop6260_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_atiixp.c b/trunk/drivers/ata/pata_atiixp.c index 39c871a3ddac..51d9923be02e 100644 --- a/trunk/drivers/ata/pata_atiixp.c +++ b/trunk/drivers/ata/pata_atiixp.c @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_atiixp" -#define DRV_VERSION "0.4.5" +#define DRV_VERSION "0.4.4" enum { ATIIXP_IDE_PIO_TIMING = 0x40, @@ -35,15 +35,23 @@ enum { static int atiixp_pre_reset(struct ata_port *ap) { + struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, { 0x48, 1, 0x08, 0x00 } }; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 udma; if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; + /* Hack from drivers/ide/pci. Really we want to know how to do the + raw detection not play follow the bios mode guess */ + pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma); + if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -52,19 +60,6 @@ static void atiixp_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -static int atiixp_cable_detect(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 udma; - - /* Hack from drivers/ide/pci. Really we want to know how to do the - raw detection not play follow the bios mode guess */ - pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma); - if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40) - return ATA_CBL_PATA80; - return ATA_CBL_PATA40; -} - /** * atiixp_set_pio_timing - set initial PIO mode data * @ap: ATA interface @@ -250,7 +245,6 @@ static struct ata_port_operations atiixp_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = atiixp_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = atiixp_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = atiixp_bmdma_start, diff --git a/trunk/drivers/ata/pata_cmd640.c b/trunk/drivers/ata/pata_cmd640.c deleted file mode 100644 index 2105985a8013..000000000000 --- a/trunk/drivers/ata/pata_cmd640.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * pata_cmd640.c - CMD640 PCI PATA for new ATA layer - * (C) 2007 Red Hat Inc - * Alan Cox - * - * Based upon - * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996 - * - * Copyright (C) 1995-1996 Linus Torvalds & authors (see driver) - * - * This drives only the PCI version of the controller. If you have a - * VLB one then we have enough docs to support it but you can write - * your own code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "pata_cmd640" -#define DRV_VERSION "0.0.5" - -struct cmd640_reg { - int last; - u8 reg58[ATA_MAX_DEVICES]; -}; - -enum { - CFR = 0x50, - CNTRL = 0x51, - CMDTIM = 0x52, - ARTIM0 = 0x53, - DRWTIM0 = 0x54, - ARTIM23 = 0x57, - DRWTIM23 = 0x58, - BRST = 0x59 -}; - -/** - * cmd640_set_piomode - set initial PIO mode data - * @ap: ATA port - * @adev: ATA device - * - * Called to do the PIO mode setup. - */ - -static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct cmd640_reg *timing = ap->private_data; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - struct ata_timing t; - const unsigned long T = 1000000 / 33; - const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 }; - u8 reg; - int arttim = ARTIM0 + 2 * adev->devno; - struct ata_device *pair = ata_dev_pair(adev); - - if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) { - printk(KERN_ERR DRV_NAME ": mode computation failed.\n"); - return; - } - - /* The second channel has shared timings and the setup timing is - messy to switch to merge it for worst case */ - if (ap->port_no && pair) { - struct ata_timing p; - ata_timing_compute(pair, pair->pio_mode, &p, T, 1); - ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP); - } - - /* Make the timings fit */ - if (t.recover > 16) { - t.active += t.recover - 16; - t.recover = 16; - } - if (t.active > 16) - t.active = 16; - - /* Now convert the clocks into values we can actually stuff into - the chip */ - - if (t.recover > 1) - t.recover--; /* 640B only */ - else - t.recover = 15; - - if (t.setup > 4) - t.setup = 0xC0; - else - t.setup = setup_data[t.setup]; - - if (ap->port_no == 0) { - t.active &= 0x0F; /* 0 = 16 */ - - /* Load setup timing */ - pci_read_config_byte(pdev, arttim, ®); - reg &= 0x3F; - reg |= t.setup; - pci_write_config_byte(pdev, arttim, reg); - - /* Load active/recovery */ - pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover); - } else { - /* Save the shared timings for channel, they will be loaded - by qc_issue_prot. Reloading the setup time is expensive - so we keep a merged one loaded */ - pci_read_config_byte(pdev, ARTIM23, ®); - reg &= 0x3F; - reg |= t.setup; - pci_write_config_byte(pdev, ARTIM23, reg); - timing->reg58[adev->devno] = (t.active << 4) | t.recover; - } -} - - -/** - * cmd640_qc_issue_prot - command preparation hook - * @qc: Command to be issued - * - * Channel 1 has shared timings. We must reprogram the - * clock each drive 2/3 switch we do. - */ - -static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_device *adev = qc->dev; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - struct cmd640_reg *timing = ap->private_data; - - if (ap->port_no != 0 && adev->devno != timing->last) { - pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]); - timing->last = adev->devno; - } - return ata_qc_issue_prot(qc); -} - -/** - * cmd640_port_start - port setup - * @ap: ATA port being set up - * - * The CMD640 needs to maintain private data structures so we - * allocate space here. - */ - -static int cmd640_port_start(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - struct cmd640_reg *timing; - - int ret = ata_port_start(ap); - if (ret < 0) - return ret; - - timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL); - if (timing == NULL) - return -ENOMEM; - timing->last = -1; /* Force a load */ - ap->private_data = timing; - return ret; -} - -static struct scsi_host_template cmd640_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = DRV_NAME, - .dma_boundary = ATA_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, -#ifdef CONFIG_PM - .resume = ata_scsi_device_resume, - .suspend = ata_scsi_device_suspend, -#endif -}; - -static struct ata_port_operations cmd640_port_ops = { - .port_disable = ata_port_disable, - .set_piomode = cmd640_set_piomode, - .mode_filter = ata_pci_default_filter, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = cmd640_qc_issue_prot, - - /* In theory this is not needed once we kill the prefetcher */ - .data_xfer = ata_data_xfer_noirq, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, - - .port_start = cmd640_port_start, -}; - -static void cmd640_hardware_init(struct pci_dev *pdev) -{ - u8 r; - u8 ctrl; - - /* CMD640 detected, commiserations */ - pci_write_config_byte(pdev, 0x5B, 0x00); - /* Get version info */ - pci_read_config_byte(pdev, CFR, &r); - /* PIO0 command cycles */ - pci_write_config_byte(pdev, CMDTIM, 0); - /* 512 byte bursts (sector) */ - pci_write_config_byte(pdev, BRST, 0x40); - /* - * A reporter a long time ago - * Had problems with the data fifo - * So don't run the risk - * Of putting crap on the disk - * For its better just to go slow - */ - /* Do channel 0 */ - pci_read_config_byte(pdev, CNTRL, &ctrl); - pci_write_config_byte(pdev, CNTRL, ctrl | 0xC0); - /* Ditto for channel 1 */ - pci_read_config_byte(pdev, ARTIM23, &ctrl); - ctrl |= 0x0C; - pci_write_config_byte(pdev, ARTIM23, ctrl); -} - -static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - static struct ata_port_info info = { - .sht = &cmd640_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, - .port_ops = &cmd640_port_ops - }; - - static struct ata_port_info *port_info[2] = { &info, &info }; - - cmd640_hardware_init(pdev); - return ata_pci_init_one(pdev, port_info, 2); -} - -static int cmd640_reinit_one(struct pci_dev *pdev) -{ - cmd640_hardware_init(pdev); -#ifdef CONFIG_PM - return ata_pci_device_resume(pdev); -#else - return 0; -#endif -} - -static const struct pci_device_id cmd640[] = { - { PCI_VDEVICE(CMD, 0x640), 0 }, - { }, -}; - -static struct pci_driver cmd640_pci_driver = { - .name = DRV_NAME, - .id_table = cmd640, - .probe = cmd640_init_one, - .remove = ata_pci_remove_one, -#ifdef CONFIG_PM - .suspend = ata_pci_device_suspend, -#endif - .resume = cmd640_reinit_one, -}; - -static int __init cmd640_init(void) -{ - return pci_register_driver(&cmd640_pci_driver); -} - -static void __exit cmd640_exit(void) -{ - pci_unregister_driver(&cmd640_pci_driver); -} - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, cmd640); -MODULE_VERSION(DRV_VERSION); - -module_init(cmd640_init); -module_exit(cmd640_exit); diff --git a/trunk/drivers/ata/pata_cmd64x.c b/trunk/drivers/ata/pata_cmd64x.c index 3989cc577fcd..5b13bdd1edc0 100644 --- a/trunk/drivers/ata/pata_cmd64x.c +++ b/trunk/drivers/ata/pata_cmd64x.c @@ -75,7 +75,13 @@ enum { DTPR1 = 0x7C }; -static int cmd648_cable_detect(struct ata_port *ap) +static int cmd64x_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +static int cmd648_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 r; @@ -83,8 +89,21 @@ static int cmd648_cable_detect(struct ata_port *ap) /* Check cable detect bits */ pci_read_config_byte(pdev, BMIDECSR, &r); if (r & (1 << ap->port_no)) - return ATA_CBL_PATA80; - return ATA_CBL_PATA40; + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + return ata_std_prereset(ap); +} + +static void cmd64x_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + +static void cmd648_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } /** @@ -285,9 +304,8 @@ static struct ata_port_operations cmd64x_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cmd64x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -320,9 +338,8 @@ static struct ata_port_operations cmd646r1_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cmd64x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -355,9 +372,8 @@ static struct ata_port_operations cmd648_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cmd648_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = cmd648_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_cs5520.c b/trunk/drivers/ata/pata_cs5520.c index 79bef0d1fad3..55cc293e7487 100644 --- a/trunk/drivers/ata/pata_cs5520.c +++ b/trunk/drivers/ata/pata_cs5520.c @@ -139,6 +139,18 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev) cs5520_set_timings(ap, adev, adev->pio_mode); } + +static int cs5520_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +static void cs5520_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + static struct scsi_host_template cs5520_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -174,9 +186,8 @@ static struct ata_port_operations cs5520_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cs5520_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -186,6 +197,7 @@ static struct ata_port_operations cs5520_port_ops = { .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -193,104 +205,91 @@ static struct ata_port_operations cs5520_port_ops = { .port_start = ata_port_start, }; -static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - struct ata_port_info pi = { - .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .port_ops = &cs5520_port_ops, - }; - const struct ata_port_info *ppi[2]; u8 pcicfg; - void *iomap[5]; - struct ata_host *host; - struct ata_ioports *ioaddr; - int i, rc; + void __iomem *iomap[5]; + static struct ata_probe_ent probe[2]; + int ports = 0; /* IDE port enable bits */ - pci_read_config_byte(pdev, 0x60, &pcicfg); + pci_read_config_byte(dev, 0x60, &pcicfg); /* Check if the ATA ports are enabled */ if ((pcicfg & 3) == 0) return -ENODEV; - ppi[0] = ppi[1] = &ata_dummy_port_info; - if (pcicfg & 1) - ppi[0] = π - if (pcicfg & 2) - ppi[1] = π - if ((pcicfg & 0x40) == 0) { - dev_printk(KERN_WARNING, &pdev->dev, - "DMA mode disabled. Enabling.\n"); - pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); + printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n"); + pci_write_config_byte(dev, 0x60, pcicfg | 0x40); } - pi.mwdma_mask = id->driver_data; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); - if (!host) - return -ENOMEM; - /* Perform set up for DMA */ - if (pci_enable_device_bars(pdev, 1<<2)) { + if (pci_enable_device_bars(dev, 1<<2)) { printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n"); return -ENODEV; } - - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + pci_set_master(dev); + if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n"); return -ENODEV; } - if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) { printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n"); return -ENODEV; } - /* Map IO ports and initialize host accordingly */ - iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8); - iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1); - iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8); - iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1); - iomap[4] = pcim_iomap(pdev, 2, 0); + /* Map IO ports */ + iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8); + iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1); + iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8); + iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1); + iomap[4] = pcim_iomap(dev, 2, 0); if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) return -ENOMEM; - ioaddr = &host->ports[0]->ioaddr; - ioaddr->cmd_addr = iomap[0]; - ioaddr->ctl_addr = iomap[1]; - ioaddr->altstatus_addr = iomap[1]; - ioaddr->bmdma_addr = iomap[4]; - ata_std_ports(ioaddr); - - ioaddr = &host->ports[1]->ioaddr; - ioaddr->cmd_addr = iomap[2]; - ioaddr->ctl_addr = iomap[3]; - ioaddr->altstatus_addr = iomap[3]; - ioaddr->bmdma_addr = iomap[4] + 8; - ata_std_ports(ioaddr); - - /* activate the host */ - pci_set_master(pdev); - rc = ata_host_start(host); - if (rc) - return rc; - - for (i = 0; i < 2; i++) { - static const int irq[] = { 14, 15 }; - struct ata_port *ap = host->ports[0]; - - if (ata_port_is_dummy(ap)) - continue; - - rc = devm_request_irq(&pdev->dev, irq[ap->port_no], - ata_interrupt, 0, DRV_NAME, host); - if (rc) - return rc; - } - - return ata_host_register(host, &cs5520_sht); + /* We have to do our own plumbing as the PCI setup for this + chipset is non-standard so we can't punt to the libata code */ + + INIT_LIST_HEAD(&probe[0].node); + probe[0].dev = pci_dev_to_dev(dev); + probe[0].port_ops = &cs5520_port_ops; + probe[0].sht = &cs5520_sht; + probe[0].pio_mask = 0x1F; + probe[0].mwdma_mask = id->driver_data; + probe[0].irq = 14; + probe[0].irq_flags = 0; + probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; + probe[0].n_ports = 1; + probe[0].port[0].cmd_addr = iomap[0]; + probe[0].port[0].ctl_addr = iomap[1]; + probe[0].port[0].altstatus_addr = iomap[1]; + probe[0].port[0].bmdma_addr = iomap[4]; + + /* The secondary lurks at different addresses but is otherwise + the same beastie */ + + probe[1] = probe[0]; + INIT_LIST_HEAD(&probe[1].node); + probe[1].irq = 15; + probe[1].port[0].cmd_addr = iomap[2]; + probe[1].port[0].ctl_addr = iomap[3]; + probe[1].port[0].altstatus_addr = iomap[3]; + probe[1].port[0].bmdma_addr = iomap[4] + 8; + + /* Let libata fill in the port details */ + ata_std_ports(&probe[0].port[0]); + ata_std_ports(&probe[1].port[0]); + + /* Now add the ports that are active */ + if (pcicfg & 1) + ports += ata_device_add(&probe[0]); + if (pcicfg & 2) + ports += ata_device_add(&probe[1]); + if (ports) + return 0; + return -ENODEV; } /** diff --git a/trunk/drivers/ata/pata_cs5530.c b/trunk/drivers/ata/pata_cs5530.c index 29642d5ee189..db63e80e608b 100644 --- a/trunk/drivers/ata/pata_cs5530.c +++ b/trunk/drivers/ata/pata_cs5530.c @@ -160,6 +160,18 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } +static int cs5530_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +static void cs5530_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + + static struct scsi_host_template cs5530_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -201,9 +213,8 @@ static struct ata_port_operations cs5530_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cs5530_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = cs5530_qc_issue_prot, diff --git a/trunk/drivers/ata/pata_cs5535.c b/trunk/drivers/ata/pata_cs5535.c index 08cccc9c659b..1572e5c9031a 100644 --- a/trunk/drivers/ata/pata_cs5535.c +++ b/trunk/drivers/ata/pata_cs5535.c @@ -70,23 +70,36 @@ #define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 ) /** - * cs5535_cable_detect - detect cable type + * cs5535_pre_reset - detect cable type * @ap: Port to detect on * * Perform cable detection for ATA66 capable cable. Return a libata * cable type. */ -static int cs5535_cable_detect(struct ata_port *ap) +static int cs5535_pre_reset(struct ata_port *ap) { u8 cable; struct pci_dev *pdev = to_pci_dev(ap->host->dev); pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable); if (cable & 1) - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA80; else - return ATA_CBL_PATA40; + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +/** + * cs5535_error_handler - reset/probe + * @ap: Port to reset + * + * Reset and configure a port + */ + +static void cs5535_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } /** @@ -192,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cs5535_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = cs5535_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_cypress.c b/trunk/drivers/ata/pata_cypress.c index 6ec049c3b1dc..f69dde5f7066 100644 --- a/trunk/drivers/ata/pata_cypress.c +++ b/trunk/drivers/ata/pata_cypress.c @@ -41,6 +41,17 @@ enum { CY82_INDEX_TIMEOUT = 0x32 }; +static int cy82c693_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +static void cy82c693_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + /** * cy82c693_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -145,9 +156,8 @@ static struct ata_port_operations cy82c693_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = cy82c693_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_efar.c b/trunk/drivers/ata/pata_efar.c index a3216850bba1..dac7a6554f6c 100644 --- a/trunk/drivers/ata/pata_efar.c +++ b/trunk/drivers/ata/pata_efar.c @@ -22,10 +22,10 @@ #include #define DRV_NAME "pata_efar" -#define DRV_VERSION "0.4.4" +#define DRV_VERSION "0.4.3" /** - * efar_pre_reset - Enable bits + * efar_pre_reset - check for 40/80 pin * @ap: Port * * Perform cable detection for the EFAR ATA interface. This is @@ -38,11 +38,18 @@ static int efar_pre_reset(struct ata_port *ap) { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; + pci_read_config_byte(pdev, 0x47, &tmp); + if (tmp & (2 >> ap->port_no)) + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; return ata_std_prereset(ap); } @@ -59,25 +66,6 @@ static void efar_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -/** - * efar_cable_detect - check for 40/80 pin - * @ap: Port - * - * Perform cable detection for the EFAR ATA interface. This is - * different to the PIIX arrangement - */ - -static int efar_cable_detect(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 tmp; - - pci_read_config_byte(pdev, 0x47, &tmp); - if (tmp & (2 >> ap->port_no)) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; -} - /** * efar_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring @@ -268,7 +256,6 @@ static const struct ata_port_operations efar_ops = { .thaw = ata_bmdma_thaw, .error_handler = efar_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = efar_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_hpt366.c b/trunk/drivers/ata/pata_hpt366.c index 93cfa6d300a5..baf35f876030 100644 --- a/trunk/drivers/ata/pata_hpt366.c +++ b/trunk/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.6.1" +#define DRV_VERSION "0.6.0" struct hpt_clock { u8 xfer_speed; @@ -169,12 +169,13 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons /** * hpt366_filter - mode selection filter + * @ap: ATA interface * @adev: ATA device * * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) +static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) @@ -184,7 +185,7 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) mask &= ~(0x0F << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } /** @@ -209,28 +210,24 @@ static u32 hpt36x_find_mode(struct ata_port *ap, int speed) return 0xffffffffU; /* silence compiler warning */ } -static int hpt36x_cable_detect(struct ata_port *ap) -{ - u8 ata66; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - - pci_read_config_byte(pdev, 0x5A, &ata66); - if (ata66 & (1 << ap->port_no)) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; -} - static int hpt36x_pre_reset(struct ata_port *ap) { static const struct pci_bits hpt36x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, { 0x54, 1, 0x04, 0x04 } }; + + u8 ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) return -ENOENT; + pci_read_config_byte(pdev, 0x5A, &ata66); + if (ata66 & (1 << ap->port_no)) + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; return ata_std_prereset(ap); } @@ -357,7 +354,6 @@ static struct ata_port_operations hpt366_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = hpt36x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = hpt36x_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_hpt37x.c b/trunk/drivers/ata/pata_hpt37x.c index 41d831296347..f331eeeafa0f 100644 --- a/trunk/drivers/ata/pata_hpt37x.c +++ b/trunk/drivers/ata/pata_hpt37x.c @@ -8,7 +8,6 @@ * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2006 MontaVista Software, Inc. * * TODO * PLL mode @@ -26,7 +25,7 @@ #include #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.5" +#define DRV_VERSION "0.6.0" struct hpt_clock { u8 xfer_speed; @@ -62,75 +61,201 @@ struct hpt_chip { * 31 FIFO enable. */ -static struct hpt_clock hpt37x_timings_33[] = { - { XFER_UDMA_6, 0x12446231 }, /* 0x12646231 ?? */ - { XFER_UDMA_5, 0x12446231 }, - { XFER_UDMA_4, 0x12446231 }, - { XFER_UDMA_3, 0x126c6231 }, - { XFER_UDMA_2, 0x12486231 }, - { XFER_UDMA_1, 0x124c6233 }, - { XFER_UDMA_0, 0x12506297 }, - - { XFER_MW_DMA_2, 0x22406c31 }, - { XFER_MW_DMA_1, 0x22406c33 }, - { XFER_MW_DMA_0, 0x22406c97 }, - - { XFER_PIO_4, 0x06414e31 }, - { XFER_PIO_3, 0x06414e42 }, - { XFER_PIO_2, 0x06414e53 }, - { XFER_PIO_1, 0x06814e93 }, - { XFER_PIO_0, 0x06814ea7 } +/* from highpoint documentation. these are old values */ +static const struct hpt_clock hpt370_timings_33[] = { +/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */ + { XFER_UDMA_5, 0x16454e31 }, + { XFER_UDMA_4, 0x16454e31 }, + { XFER_UDMA_3, 0x166d4e31 }, + { XFER_UDMA_2, 0x16494e31 }, + { XFER_UDMA_1, 0x164d4e31 }, + { XFER_UDMA_0, 0x16514e31 }, + + { XFER_MW_DMA_2, 0x26514e21 }, + { XFER_MW_DMA_1, 0x26514e33 }, + { XFER_MW_DMA_0, 0x26514e97 }, + + { XFER_PIO_4, 0x06514e21 }, + { XFER_PIO_3, 0x06514e22 }, + { XFER_PIO_2, 0x06514e33 }, + { XFER_PIO_1, 0x06914e43 }, + { XFER_PIO_0, 0x06914e57 }, + { 0, 0x06514e57 } }; -static struct hpt_clock hpt37x_timings_50[] = { - { XFER_UDMA_6, 0x12848242 }, - { XFER_UDMA_5, 0x12848242 }, - { XFER_UDMA_4, 0x12ac8242 }, - { XFER_UDMA_3, 0x128c8242 }, - { XFER_UDMA_2, 0x120c8242 }, - { XFER_UDMA_1, 0x12148254 }, - { XFER_UDMA_0, 0x121882ea }, - - { XFER_MW_DMA_2, 0x22808242 }, - { XFER_MW_DMA_1, 0x22808254 }, - { XFER_MW_DMA_0, 0x228082ea }, - - { XFER_PIO_4, 0x0a81f442 }, - { XFER_PIO_3, 0x0a81f443 }, - { XFER_PIO_2, 0x0a81f454 }, - { XFER_PIO_1, 0x0ac1f465 }, - { XFER_PIO_0, 0x0ac1f48a } +static const struct hpt_clock hpt370_timings_66[] = { + { XFER_UDMA_5, 0x14846231 }, + { XFER_UDMA_4, 0x14886231 }, + { XFER_UDMA_3, 0x148c6231 }, + { XFER_UDMA_2, 0x148c6231 }, + { XFER_UDMA_1, 0x14906231 }, + { XFER_UDMA_0, 0x14986231 }, + + { XFER_MW_DMA_2, 0x26514e21 }, + { XFER_MW_DMA_1, 0x26514e33 }, + { XFER_MW_DMA_0, 0x26514e97 }, + + { XFER_PIO_4, 0x06514e21 }, + { XFER_PIO_3, 0x06514e22 }, + { XFER_PIO_2, 0x06514e33 }, + { XFER_PIO_1, 0x06914e43 }, + { XFER_PIO_0, 0x06914e57 }, + { 0, 0x06514e57 } }; -static struct hpt_clock hpt37x_timings_66[] = { - { XFER_UDMA_6, 0x1c869c62 }, - { XFER_UDMA_5, 0x1cae9c62 }, /* 0x1c8a9c62 */ - { XFER_UDMA_4, 0x1c8a9c62 }, - { XFER_UDMA_3, 0x1c8e9c62 }, - { XFER_UDMA_2, 0x1c929c62 }, - { XFER_UDMA_1, 0x1c9a9c62 }, - { XFER_UDMA_0, 0x1c829c62 }, - - { XFER_MW_DMA_2, 0x2c829c62 }, - { XFER_MW_DMA_1, 0x2c829c66 }, - { XFER_MW_DMA_0, 0x2c829d2e }, - - { XFER_PIO_4, 0x0c829c62 }, - { XFER_PIO_3, 0x0c829c84 }, - { XFER_PIO_2, 0x0c829ca6 }, - { XFER_PIO_1, 0x0d029d26 }, - { XFER_PIO_0, 0x0d029d5e } +/* these are the current (4 sep 2001) timings from highpoint */ +static const struct hpt_clock hpt370a_timings_33[] = { + { XFER_UDMA_5, 0x12446231 }, + { XFER_UDMA_4, 0x12446231 }, + { XFER_UDMA_3, 0x126c6231 }, + { XFER_UDMA_2, 0x12486231 }, + { XFER_UDMA_1, 0x124c6233 }, + { XFER_UDMA_0, 0x12506297 }, + + { XFER_MW_DMA_2, 0x22406c31 }, + { XFER_MW_DMA_1, 0x22406c33 }, + { XFER_MW_DMA_0, 0x22406c97 }, + + { XFER_PIO_4, 0x06414e31 }, + { XFER_PIO_3, 0x06414e42 }, + { XFER_PIO_2, 0x06414e53 }, + { XFER_PIO_1, 0x06814e93 }, + { XFER_PIO_0, 0x06814ea7 }, + { 0, 0x06814ea7 } }; +/* 2x 33MHz timings */ +static const struct hpt_clock hpt370a_timings_66[] = { + { XFER_UDMA_5, 0x1488e673 }, + { XFER_UDMA_4, 0x1488e673 }, + { XFER_UDMA_3, 0x1498e673 }, + { XFER_UDMA_2, 0x1490e673 }, + { XFER_UDMA_1, 0x1498e677 }, + { XFER_UDMA_0, 0x14a0e73f }, + + { XFER_MW_DMA_2, 0x2480fa73 }, + { XFER_MW_DMA_1, 0x2480fa77 }, + { XFER_MW_DMA_0, 0x2480fb3f }, + + { XFER_PIO_4, 0x0c82be73 }, + { XFER_PIO_3, 0x0c82be95 }, + { XFER_PIO_2, 0x0c82beb7 }, + { XFER_PIO_1, 0x0d02bf37 }, + { XFER_PIO_0, 0x0d02bf5f }, + { 0, 0x0d02bf5f } +}; + +static const struct hpt_clock hpt370a_timings_50[] = { + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x0ac1f48a } +}; + +static const struct hpt_clock hpt372_timings_33[] = { + { XFER_UDMA_6, 0x1c81dc62 }, + { XFER_UDMA_5, 0x1c6ddc62 }, + { XFER_UDMA_4, 0x1c8ddc62 }, + { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */ + { XFER_UDMA_2, 0x1c91dc62 }, + { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */ + { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */ + + { XFER_MW_DMA_2, 0x2c829262 }, + { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */ + { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */ + + { XFER_PIO_4, 0x0c829c62 }, + { XFER_PIO_3, 0x0c829c84 }, + { XFER_PIO_2, 0x0c829ca6 }, + { XFER_PIO_1, 0x0d029d26 }, + { XFER_PIO_0, 0x0d029d5e }, + { 0, 0x0d029d5e } +}; + +static const struct hpt_clock hpt372_timings_50[] = { + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x0a81f443 } +}; + +static const struct hpt_clock hpt372_timings_66[] = { + { XFER_UDMA_6, 0x1c869c62 }, + { XFER_UDMA_5, 0x1cae9c62 }, + { XFER_UDMA_4, 0x1c8a9c62 }, + { XFER_UDMA_3, 0x1c8e9c62 }, + { XFER_UDMA_2, 0x1c929c62 }, + { XFER_UDMA_1, 0x1c9a9c62 }, + { XFER_UDMA_0, 0x1c829c62 }, + + { XFER_MW_DMA_2, 0x2c829c62 }, + { XFER_MW_DMA_1, 0x2c829c66 }, + { XFER_MW_DMA_0, 0x2c829d2e }, + + { XFER_PIO_4, 0x0c829c62 }, + { XFER_PIO_3, 0x0c829c84 }, + { XFER_PIO_2, 0x0c829ca6 }, + { XFER_PIO_1, 0x0d029d26 }, + { XFER_PIO_0, 0x0d029d5e }, + { 0, 0x0d029d26 } +}; + +static const struct hpt_clock hpt374_timings_33[] = { + { XFER_UDMA_6, 0x12808242 }, + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x06814e93 } +}; static const struct hpt_chip hpt370 = { "HPT370", 48, { - hpt37x_timings_33, + hpt370_timings_33, NULL, NULL, - NULL + hpt370_timings_66 } }; @@ -138,10 +263,10 @@ static const struct hpt_chip hpt370a = { "HPT370A", 48, { - hpt37x_timings_33, + hpt370a_timings_33, NULL, - hpt37x_timings_50, - NULL + hpt370a_timings_50, + hpt370a_timings_66 } }; @@ -149,10 +274,10 @@ static const struct hpt_chip hpt372 = { "HPT372", 55, { - hpt37x_timings_33, + hpt372_timings_33, NULL, - hpt37x_timings_50, - hpt37x_timings_66 + hpt372_timings_50, + hpt372_timings_66 } }; @@ -160,10 +285,10 @@ static const struct hpt_chip hpt302 = { "HPT302", 66, { - hpt37x_timings_33, + hpt372_timings_33, NULL, - hpt37x_timings_50, - hpt37x_timings_66 + hpt372_timings_50, + hpt372_timings_66 } }; @@ -171,10 +296,10 @@ static const struct hpt_chip hpt371 = { "HPT371", 66, { - hpt37x_timings_33, + hpt372_timings_33, NULL, - hpt37x_timings_50, - hpt37x_timings_66 + hpt372_timings_50, + hpt372_timings_66 } }; @@ -182,10 +307,10 @@ static const struct hpt_chip hpt372a = { "HPT372A", 66, { - hpt37x_timings_33, + hpt372_timings_33, NULL, - hpt37x_timings_50, - hpt37x_timings_66 + hpt372_timings_50, + hpt372_timings_66 } }; @@ -193,7 +318,7 @@ static const struct hpt_chip hpt374 = { "HPT374", 48, { - hpt37x_timings_33, + hpt374_timings_33, NULL, NULL, NULL @@ -272,12 +397,13 @@ static const char *bad_ata100_5[] = { /** * hpt370_filter - mode selection filter + * @ap: ATA interface * @adev: ATA device * * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) +static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) @@ -285,23 +411,24 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) mask &= ~(0x1F << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } /** * hpt370a_filter - mode selection filter + * @ap: ATA interface * @adev: ATA device * * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) +static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { if (adev->class != ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) mask &= ~ (0x1F << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } /** @@ -335,7 +462,8 @@ static int hpt37x_pre_reset(struct ata_port *ap) ap->cbl = ATA_CBL_PATA80; /* Reset the state machine */ - pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); + pci_write_config_byte(pdev, 0x50, 0x37); + pci_write_config_byte(pdev, 0x54, 0x37); udelay(100); return ata_std_prereset(ap); @@ -385,7 +513,8 @@ static int hpt374_pre_reset(struct ata_port *ap) ap->cbl = ATA_CBL_PATA80; /* Reset the state machine */ - pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); + pci_write_config_byte(pdev, 0x50, 0x37); + pci_write_config_byte(pdev, 0x54, 0x37); udelay(100); return ata_std_prereset(ap); @@ -903,24 +1032,6 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = 0x3f, .port_ops = &hpt370a_port_ops }; - /* HPT370 - UDMA100 */ - static struct ata_port_info info_hpt370_33 = { - .sht = &hpt37x_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x0f, - .port_ops = &hpt370_port_ops - }; - /* HPT370A - UDMA100 */ - static struct ata_port_info info_hpt370a_33 = { - .sht = &hpt37x_sht, - .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x0f, - .port_ops = &hpt370a_port_ops - }; /* HPT371, 372 and friends - UDMA133 */ static struct ata_port_info info_hpt372 = { .sht = &hpt37x_sht, @@ -956,11 +1067,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) u8 irqmask; u32 class_rev; - u8 mcr1; u32 freq; - int prefer_dpll = 1; - - unsigned long iobase = pci_resource_start(dev, 4); const struct hpt_chip *chip_table; int clock_slot; @@ -981,12 +1088,10 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) case 3: port = &info_hpt370; chip_table = &hpt370; - prefer_dpll = 0; break; case 4: port = &info_hpt370a; chip_table = &hpt370a; - prefer_dpll = 0; break; case 5: port = &info_hpt372; @@ -1014,16 +1119,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) chip_table = &hpt302; break; case PCI_DEVICE_ID_TTI_HPT371: - if (class_rev > 1) - return -ENODEV; port = &info_hpt372; chip_table = &hpt371; - /* Single channel device, master is not present - but the BIOS (or us for non x86) must mark it - absent */ - pci_read_config_byte(dev, 0x50, &mcr1); - mcr1 &= ~0x04; - pci_write_config_byte(dev, 0x50, mcr1); break; case PCI_DEVICE_ID_TTI_HPT374: chip_table = &hpt374; @@ -1053,18 +1150,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) */ pci_write_config_byte(dev, 0x5b, 0x23); - - /* - * HighPoint does this for HPT372A. - * NOTE: This register is only writeable via I/O space. - */ - if (chip_table == &hpt372a) - outb(0x0e, iobase + 0x9c); - /* Some devices do not let this value be accessed via PCI space - according to the old driver */ - - freq = inl(iobase + 0x90); + pci_read_config_dword(dev, 0x70, &freq); if ((freq >> 12) != 0xABCDE) { int i; u8 sr; @@ -1075,7 +1162,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* This is the process the HPT371 BIOS is reported to use */ for(i = 0; i < 128; i++) { pci_read_config_byte(dev, 0x78, &sr); - total += sr & 0x1FF; + total += sr; udelay(15); } freq = total / 128; @@ -1086,27 +1173,15 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) * Turn the frequency check into a band and then find a timing * table to match it. */ - + clock_slot = hpt37x_clock_slot(freq, chip_table->base); - if (chip_table->clocks[clock_slot] == NULL || prefer_dpll) { + if (chip_table->clocks[clock_slot] == NULL) { /* * We need to try PLL mode instead - * - * For non UDMA133 capable devices we should - * use a 50MHz DPLL by choice */ - unsigned int f_low, f_high; + unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192; + unsigned int f_high = f_low + 2; int adjust; - - clock_slot = 2; - if (port->udma_mask & 0xE0) - clock_slot = 3; - - f_low = (MHz[clock_slot] * chip_table->base) / 192; - f_high = f_low + 2; - - /* Select the DPLL clock. */ - pci_write_config_byte(dev, 0x5b, 0x21); for(adjust = 0; adjust < 8; adjust++) { if (hpt37x_calibrate_dpll(dev)) @@ -1122,27 +1197,25 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n"); return -ENODEV; } - if (clock_slot == 3) - port->private_data = (void *)hpt37x_timings_66; - else - port->private_data = (void *)hpt37x_timings_50; + /* Check if this works for all cases */ + port->private_data = (void *)hpt370_timings_66; printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]); } else { port->private_data = (void *)chip_table->clocks[clock_slot]; /* - * Perform a final fixup. Note that we will have used the - * DPLL on the HPT372 which means we don't have to worry - * about lack of UDMA133 support on lower clocks - */ - - if (clock_slot < 2 && port == &info_hpt370) - port = &info_hpt370_33; - if (clock_slot < 2 && port == &info_hpt370a) - port = &info_hpt370a_33; + * Perform a final fixup. The 371 and 372 clock determines + * if UDMA133 is available. + */ + + if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */ + printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n"); + if (port == &info_hpt372) + port = &info_hpt372_50; + else BUG(); + } printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]); } - port_info[0] = port_info[1] = port; /* Now kick off ATA set up */ return ata_pci_init_one(dev, port_info, 2); diff --git a/trunk/drivers/ata/pata_hpt3x2n.c b/trunk/drivers/ata/pata_hpt3x2n.c index 6a34521b9e01..65f2e180e7fa 100644 --- a/trunk/drivers/ata/pata_hpt3x2n.c +++ b/trunk/drivers/ata/pata_hpt3x2n.c @@ -8,10 +8,10 @@ * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2006 MontaVista Software, Inc. * * * TODO + * 371N * Work out best PLL policy */ @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.3" +#define DRV_VERSION "0.3.2" enum { HPT_PCI_FAST = (1 << 31), @@ -115,13 +115,14 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) } /** - * hpt3x2n_cable_detect - Detect the cable type - * @ap: ATA port to detect on + * hpt3x2n_pre_reset - reset the hpt3x2n bus + * @ap: ATA port to reset * - * Return the cable type attached to this port + * Perform the initial reset handling for the 3x2n series controllers. + * Reset the hardware and state machine, obtain the cable type. */ -static int hpt3x2n_cable_detect(struct ata_port *ap) +static int hpt3xn_pre_reset(struct ata_port *ap) { u8 scr2, ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); @@ -134,26 +135,15 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) pci_write_config_byte(pdev, 0x5B, scr2); if (ata66 & (1 << ap->port_no)) - return ATA_CBL_PATA40; + ap->cbl = ATA_CBL_PATA40; else - return ATA_CBL_PATA80; -} - -/** - * hpt3x2n_pre_reset - reset the hpt3x2n bus - * @ap: ATA port to reset - * @deadline: deadline jiffies for the operation - * - * Perform the initial reset handling for the 3x2n series controllers. - * Reset the hardware and state machine, - */ + ap->cbl = ATA_CBL_PATA80; -static int hpt3xn_pre_reset(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Reset the state machine */ - pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); + pci_write_config_byte(pdev, 0x50, 0x37); + pci_write_config_byte(pdev, 0x54, 0x37); udelay(100); + return ata_std_prereset(ap); } @@ -374,7 +364,6 @@ static struct ata_port_operations hpt3x2n_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = hpt3x2n_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = hpt3x2n_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -433,9 +422,8 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) { unsigned long freq; u32 fcnt; - unsigned long iobase = pci_resource_start(pdev, 4); - fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */ + pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt); if ((fcnt >> 12) != 0xABCDE) { printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n"); return 33; /* Not BIOS set */ @@ -504,7 +492,6 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) unsigned int pci_mhz; unsigned int f_low, f_high; int adjust; - unsigned long iobase = pci_resource_start(dev, 4); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xFF; @@ -514,11 +501,6 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (class_rev < 6) return -ENODEV; break; - case PCI_DEVICE_ID_TTI_HPT371: - if (class_rev < 2) - return -ENODEV; - /* 371N if rev > 1 */ - break; case PCI_DEVICE_ID_TTI_HPT372: /* 372N if rev >= 1*/ if (class_rev == 0) @@ -546,19 +528,6 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) irqmask &= ~0x10; pci_write_config_byte(dev, 0x5a, irqmask); - /* - * HPT371 chips physically have only one channel, the secondary one, - * but the primary channel registers do exist! Go figure... - * So, we manually disable the non-existing channel here - * (if the BIOS hasn't done this already). - */ - if (dev->device == PCI_DEVICE_ID_TTI_HPT371) { - u8 mcr1; - pci_read_config_byte(dev, 0x50, &mcr1); - mcr1 &= ~0x04; - pci_write_config_byte(dev, 0x50, mcr1); - } - /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or 50 for UDMA100. Right now we always use 66 */ @@ -577,24 +546,14 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); } - if (adjust == 8) { - printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n"); - return -ENODEV; - } + if (adjust == 8) + printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n"); /* Set our private data up. We only need a few flags so we use it directly */ port->private_data = NULL; - if (pci_mhz > 60) { + if (pci_mhz > 60) port->private_data = (void *)PCI66; - /* - * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in - * the MISC. register to stretch the UltraDMA Tss timing. - * NOTE: This register is only writeable via I/O space. - */ - if (dev->device == PCI_DEVICE_ID_TTI_HPT371) - outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c); - } /* Now kick off ATA set up */ port_info[0] = port_info[1] = port; @@ -603,7 +562,6 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) static const struct pci_device_id hpt3x2n[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, - { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), }, { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), }, { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), }, { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), }, diff --git a/trunk/drivers/ata/pata_hpt3x3.c b/trunk/drivers/ata/pata_hpt3x3.c index ac28ec8c50aa..813485c8526c 100644 --- a/trunk/drivers/ata/pata_hpt3x3.c +++ b/trunk/drivers/ata/pata_hpt3x3.c @@ -25,6 +25,25 @@ #define DRV_NAME "pata_hpt3x3" #define DRV_VERSION "0.4.2" +static int hpt3x3_probe_init(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +/** + * hpt3x3_probe_reset - reset the hpt3x3 bus + * @ap: ATA port to reset + * + * Perform the housekeeping when doing an ATA bus reeset. We just + * need to force the cable type. + */ + +static void hpt3x3_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset); +} + /** * hpt3x3_set_piomode - PIO setup * @ap: ATA interface @@ -120,9 +139,8 @@ static struct ata_port_operations hpt3x3_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = hpt3x3_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_isapnp.c b/trunk/drivers/ata/pata_isapnp.c index d042efdfbac4..1a61cc891741 100644 --- a/trunk/drivers/ata/pata_isapnp.c +++ b/trunk/drivers/ata/pata_isapnp.c @@ -49,13 +49,13 @@ static struct ata_port_operations isapnp_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -74,10 +74,8 @@ static struct ata_port_operations isapnp_port_ops = { static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) { - struct ata_host *host; - struct ata_port *ap; + struct ata_probe_ent ae; void __iomem *cmd_addr, *ctl_addr; - int rc; if (pnp_port_valid(idev, 0) == 0) return -ENODEV; @@ -86,36 +84,34 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev if (pnp_irq_valid(idev, 0) == 0) return -ENODEV; - /* allocate host */ - host = ata_host_alloc(&idev->dev, 1); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8); if (!cmd_addr) return -ENOMEM; - ap = host->ports[0]; - - ap->ops = &isapnp_port_ops; - ap->pio_mask = 1; - ap->flags |= ATA_FLAG_SLAVE_POSS; - - ap->ioaddr.cmd_addr = cmd_addr; + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &idev->dev; + ae.port_ops = &isapnp_port_ops; + ae.sht = &isapnp_sht; + ae.n_ports = 1; + ae.pio_mask = 1; /* ISA so PIO 0 cycles */ + ae.irq = pnp_irq(idev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS; + ae.port[0].cmd_addr = cmd_addr; if (pnp_port_valid(idev, 1) == 0) { ctl_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 1), 1); - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; + ae.port_flags |= ATA_FLAG_SRST; } + ata_std_ports(&ae.port[0]); - ata_std_ports(&ap->ioaddr); - - /* activate */ - return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0, - &isapnp_sht); + if (ata_device_add(&ae) == 0) + return -ENODEV; + return 0; } /** diff --git a/trunk/drivers/ata/pata_it8213.c b/trunk/drivers/ata/pata_it8213.c index 011306ef8334..ea734701555e 100644 --- a/trunk/drivers/ata/pata_it8213.c +++ b/trunk/drivers/ata/pata_it8213.c @@ -25,8 +25,8 @@ * it8213_pre_reset - check for 40/80 pin * @ap: Port * - * Filter out ports by the enable bits before doing the normal reset - * and probe. + * Perform cable detection for the 8213 ATA interface. This is + * different to the PIIX arrangement */ static int it8213_pre_reset(struct ata_port *ap) @@ -34,14 +34,23 @@ static int it8213_pre_reset(struct ata_port *ap) static const struct pci_bits it8213_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; + if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; + + pci_read_config_byte(pdev, 0x42, &tmp); + if (tmp & 2) /* The initial docs are incorrect */ + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; return ata_std_prereset(ap); } /** - * it8213_error_handler - Probe specified port on PATA host controller + * it8213_probe_reset - Probe specified port on PATA host controller * @ap: Port to probe * * LOCKING: @@ -53,28 +62,10 @@ static void it8213_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -/** - * it8213_cable_detect - check for 40/80 pin - * @ap: Port - * - * Perform cable detection for the 8213 ATA interface. This is - * different to the PIIX arrangement - */ - -static int it8213_cable_detect(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 tmp; - pci_read_config_byte(pdev, 0x42, &tmp); - if (tmp & 2) /* The initial docs are incorrect */ - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; -} - /** * it8213_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring - * @adev: Device whose timings we are configuring + * @adev: um * * Set PIO mode for device, in host controller PCI config space. * @@ -277,7 +268,6 @@ static const struct ata_port_operations it8213_ops = { .thaw = ata_bmdma_thaw, .error_handler = it8213_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = it8213_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_it821x.c b/trunk/drivers/ata/pata_it821x.c index f1f8cec8c224..35ecb2ba067b 100644 --- a/trunk/drivers/ata/pata_it821x.c +++ b/trunk/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.3.6" +#define DRV_VERSION "0.3.4" struct it821x_dev { @@ -112,6 +112,31 @@ struct it821x_dev static int it8212_noraid; +/** + * it821x_pre_reset - probe + * @ap: ATA port + * + * Set the cable type + */ + +static int it821x_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + +/** + * it821x_error_handler - probe/reset + * @ap: ATA port + * + * Set the cable type and trigger a probe + */ + +static void it821x_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + /** * it821x_program - program the PIO/MWDMA registers * @ap: ATA port @@ -495,6 +520,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused /** * it821x_dev_config - Called each device identify + * @ap: ATA port * @adev: Device that has just been identified * * Perform the initial setup needed for each device that is chip @@ -505,7 +531,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused * basically we need to filter commands for this chip. */ -static void it821x_dev_config(struct ata_device *adev) +static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -641,9 +667,8 @@ static struct ata_port_operations it821x_smart_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = it821x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -678,9 +703,8 @@ static struct ata_port_operations it821x_passthru_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = it821x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = it821x_passthru_bmdma_start, diff --git a/trunk/drivers/ata/pata_ixp4xx_cf.c b/trunk/drivers/ata/pata_ixp4xx_cf.c index 420c343e5711..c6f0e1927551 100644 --- a/trunk/drivers/ata/pata_ixp4xx_cf.c +++ b/trunk/drivers/ata/pata_ixp4xx_cf.c @@ -129,8 +129,8 @@ static struct ata_port_operations ixp4xx_port_ops = { .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .data_xfer = ixp4xx_mmio_data_xfer, - .cable_detect = ata_cable_40wire, + .irq_handler = ata_interrupt, .irq_clear = ixp4xx_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -173,12 +173,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr, static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) { + int ret; unsigned int irq; struct resource *cs0, *cs1; - struct ata_host *host; - struct ata_port *ap; + struct ata_probe_ent ae; + struct ixp4xx_pata_data *data = pdev->dev.platform_data; - int rc; cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -186,12 +186,6 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) if (!cs0 || !cs1) return -EINVAL; - /* allocate host */ - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ pdev->dev.coherent_dma_mask = DMA_32BIT_MASK; data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000); @@ -205,22 +199,32 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) *data->cs0_cfg = data->cs0_bits; *data->cs1_cfg = data->cs1_bits; - ap = host->ports[0]; + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); - ap->ops = &ixp4xx_port_ops; - ap->pio_mask = 0x1f; /* PIO4 */ - ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; + ae.dev = &pdev->dev; + ae.port_ops = &ixp4xx_port_ops; + ae.sht = &ixp4xx_sht; + ae.n_ports = 1; + ae.pio_mask = 0x1f; /* PIO4 */ + ae.irq = irq; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY + | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST; /* run in polling mode if no irq has been assigned */ if (!irq) - ap->flags |= ATA_FLAG_PIO_POLLING; + ae.port_flags |= ATA_FLAG_PIO_POLLING; - ixp4xx_setup_port(&ap->ioaddr, data); + ixp4xx_setup_port(&ae.port[0], data); dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - /* activate host */ - return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht); + ret = ata_device_add(&ae); + if (ret == 0) + return -ENODEV; + + return 0; } static __devexit int ixp4xx_pata_remove(struct platform_device *dev) diff --git a/trunk/drivers/ata/pata_legacy.c b/trunk/drivers/ata/pata_legacy.c index 707099291e01..86fbcd6a742b 100644 --- a/trunk/drivers/ata/pata_legacy.c +++ b/trunk/drivers/ata/pata_legacy.c @@ -162,7 +162,6 @@ static struct ata_port_operations simple_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -186,7 +185,6 @@ static struct ata_port_operations legacy_port_ops = { .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .cable_detect = ata_cable_40wire, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -307,7 +305,6 @@ static struct ata_port_operations pdc20230_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -363,7 +360,6 @@ static struct ata_port_operations ht6560a_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -430,7 +426,6 @@ static struct ata_port_operations ht6560b_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -552,7 +547,6 @@ static struct ata_port_operations opti82c611a_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -686,7 +680,6 @@ static struct ata_port_operations opti82c46x_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = opti82c46x_qc_issue_prot, @@ -716,8 +709,7 @@ static struct ata_port_operations opti82c46x_port_ops = { static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq) { struct legacy_data *ld = &legacy_data[nr_legacy_host]; - struct ata_host *host; - struct ata_port *ap; + struct ata_probe_ent ae; struct platform_device *pdev; struct ata_port_operations *ops = &legacy_port_ops; void __iomem *io_addr, *ctrl_addr; @@ -799,23 +791,24 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl if (ops == &legacy_port_ops && (autospeed & mask)) ops = &simple_port_ops; - ret = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - goto fail; - ap = host->ports[0]; - - ap->ops = ops; - ap->pio_mask = pio_modes; - ap->flags |= ATA_FLAG_SLAVE_POSS | iordy; - ap->ioaddr.cmd_addr = io_addr; - ap->ioaddr.altstatus_addr = ctrl_addr; - ap->ioaddr.ctl_addr = ctrl_addr; - ata_std_ports(&ap->ioaddr); - ap->private_data = ld; - - ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); - if (ret) + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = ops; + ae.sht = &legacy_sht; + ae.n_ports = 1; + ae.pio_mask = pio_modes; + ae.irq = irq; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctrl_addr; + ae.port[0].ctl_addr = ctrl_addr; + ata_std_ports(&ae.port[0]); + ae.private_data = ld; + + ret = -ENODEV; + if (!ata_device_add(&ae)) goto fail; legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev); diff --git a/trunk/drivers/ata/pata_marvell.c b/trunk/drivers/ata/pata_marvell.c index d9b94a1b6954..6dd7c4ef3e66 100644 --- a/trunk/drivers/ata/pata_marvell.c +++ b/trunk/drivers/ata/pata_marvell.c @@ -20,7 +20,7 @@ #include #define DRV_NAME "pata_marvell" -#define DRV_VERSION "0.1.4" +#define DRV_VERSION "0.1.1" /** * marvell_pre_reset - check for 40/80 pin @@ -52,23 +52,22 @@ static int marvell_pre_reset(struct ata_port *ap) if ((pdev->device == 0x6145) && (ap->port_no == 0) && (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(ap); -} -static int marvell_cable_detect(struct ata_port *ap) -{ /* Cable type */ switch(ap->port_no) { case 0: if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + break; + case 1: /* Legacy SATA port */ - return ATA_CBL_SATA; + ap->cbl = ATA_CBL_SATA; + break; } - BUG(); - return 0; /* Our BUG macro needs the right markup */ + return ata_std_prereset(ap); } /** @@ -124,7 +123,6 @@ static const struct ata_port_operations marvell_ops = { .thaw = ata_bmdma_thaw, .error_handler = marvell_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = marvell_cable_detect, /* BMDMA handling is PCI ATA format, use helpers */ .bmdma_setup = ata_bmdma_setup, diff --git a/trunk/drivers/ata/pata_mpc52xx.c b/trunk/drivers/ata/pata_mpc52xx.c index 9587a89f9683..882c36eaf293 100644 --- a/trunk/drivers/ata/pata_mpc52xx.c +++ b/trunk/drivers/ata/pata_mpc52xx.c @@ -24,7 +24,7 @@ #define DRV_NAME "mpc52xx_ata" -#define DRV_VERSION "0.1.0ac2" +#define DRV_VERSION "0.1.0" /* Private structures used by the driver */ @@ -297,37 +297,38 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = mpc52xx_ata_error_handler, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; +static struct ata_probe_ent mpc52xx_ata_probe_ent = { + .port_ops = &mpc52xx_ata_port_ops, + .sht = &mpc52xx_ata_sht, + .n_ports = 1, + .pio_mask = 0x1f, /* Up to PIO4 */ + .mwdma_mask = 0x00, /* No MWDMA */ + .udma_mask = 0x00, /* No UDMA */ + .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .irq_flags = 0, +}; + static int __devinit mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) { - struct ata_host *host; - struct ata_port *ap; - struct ata_ioports *aio; - int rc; - - host = ata_host_alloc(dev, 1); - if (!host) - return -ENOMEM; - - ap = host->ports[0]; - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->pio_mask = 0x1f; /* Up to PIO4 */ - ap->mwdma_mask = 0x00; /* No MWDMA */ - ap->udma_mask = 0x00; /* No UDMA */ - ap->ops = &mpc52xx_ata_port_ops; - host->private_data = priv; - - aio = &ap->ioaddr; + struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent; + struct ata_ioports *aio = &ae->port[0]; + int rv; + + INIT_LIST_HEAD(&ae->node); + ae->dev = dev; + ae->irq = priv->ata_irq; + aio->cmd_addr = NULL; /* Don't have a classic reg block */ aio->altstatus_addr = &priv->ata_regs->tf_control; aio->ctl_addr = &priv->ata_regs->tf_control; @@ -342,9 +343,11 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) aio->status_addr = &priv->ata_regs->tf_command; aio->command_addr = &priv->ata_regs->tf_command; - /* activate host */ - return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, - &mpc52xx_ata_sht); + ae->private_data = priv; + + rv = ata_device_add(ae); + + return rv ? 0 : -EINVAL; } static struct mpc52xx_ata_priv * diff --git a/trunk/drivers/ata/pata_mpiix.c b/trunk/drivers/ata/pata_mpiix.c index 987c5fafab08..4abe45ac19a2 100644 --- a/trunk/drivers/ata/pata_mpiix.c +++ b/trunk/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.6" +#define DRV_VERSION "0.7.5" enum { IDETIM = 0x6C, /* IDE control register */ @@ -53,6 +53,7 @@ static int mpiix_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -184,12 +185,12 @@ static struct ata_port_operations mpiix_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = mpiix_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = mpiix_qc_issue_prot, .data_xfer = ata_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -200,9 +201,8 @@ static struct ata_port_operations mpiix_port_ops = { static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* Single threaded by the PCI probe logic */ + static struct ata_probe_ent probe; static int printed_version; - struct ata_host *host; - struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; u16 idetim; int irq; @@ -210,10 +210,6 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); - host = ata_host_alloc(&dev->dev, 1); - if (!host) - return -ENOMEM; - /* MPIIX has many functions which can be turned on or off according to other devices present. Make sure IDE is enabled before we try and use it */ @@ -242,21 +238,27 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) without BARs set fools the setup. #2 If you pci_disable_device the MPIIX your box goes castors up */ - ap = host->ports[0]; - ap->ops = &mpiix_port_ops; - ap->pio_mask = 0x1F; - ap->flags |= ATA_FLAG_SLAVE_POSS; + INIT_LIST_HEAD(&probe.node); + probe.dev = pci_dev_to_dev(dev); + probe.port_ops = &mpiix_port_ops; + probe.sht = &mpiix_sht; + probe.pio_mask = 0x1F; + probe.irq_flags = IRQF_SHARED; + probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + probe.n_ports = 1; - ap->ioaddr.cmd_addr = cmd_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ap->ioaddr.altstatus_addr = ctl_addr; + probe.irq = irq; + probe.port[0].cmd_addr = cmd_addr; + probe.port[0].ctl_addr = ctl_addr; + probe.port[0].altstatus_addr = ctl_addr; /* Let libata fill in the port details */ - ata_std_ports(&ap->ioaddr); + ata_std_ports(&probe.port[0]); - /* activate host */ - return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED, - &mpiix_sht); + /* Now add the port that is active */ + if (ata_device_add(&probe)) + return 0; + return -ENODEV; } static const struct pci_device_id mpiix[] = { diff --git a/trunk/drivers/ata/pata_netcell.c b/trunk/drivers/ata/pata_netcell.c index dbba5b77d79c..38f99b38a5ea 100644 --- a/trunk/drivers/ata/pata_netcell.c +++ b/trunk/drivers/ata/pata_netcell.c @@ -16,7 +16,33 @@ #include #define DRV_NAME "pata_netcell" -#define DRV_VERSION "0.1.7" +#define DRV_VERSION "0.1.6" + +/** + * netcell_probe_init - check for 40/80 pin + * @ap: Port + * + * Cables are handled by the RAID controller. Report 80 pin. + */ + +static int netcell_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + +/** + * netcell_probe_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * LOCKING: + * None (inherited from caller). + */ + +static void netcell_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} /* No PIO or DMA methods needed for this device */ @@ -55,9 +81,8 @@ static const struct ata_port_operations netcell_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = netcell_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_80wire, /* BMDMA handling is PCI ATA format, use helpers */ .bmdma_setup = ata_bmdma_setup, diff --git a/trunk/drivers/ata/pata_ns87410.c b/trunk/drivers/ata/pata_ns87410.c index 078aeda9cf8d..9944a28daa9c 100644 --- a/trunk/drivers/ata/pata_ns87410.c +++ b/trunk/drivers/ata/pata_ns87410.c @@ -28,13 +28,13 @@ #include #define DRV_NAME "pata_ns87410" -#define DRV_VERSION "0.4.6" +#define DRV_VERSION "0.4.3" /** * ns87410_pre_reset - probe begin * @ap: ATA port * - * Check enabled ports + * Set up cable type and use generic probe init */ static int ns87410_pre_reset(struct ata_port *ap) @@ -47,6 +47,7 @@ static int ns87410_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -176,7 +177,6 @@ static struct ata_port_operations ns87410_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ns87410_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ns87410_qc_issue_prot, diff --git a/trunk/drivers/ata/pata_oldpiix.c b/trunk/drivers/ata/pata_oldpiix.c index dea4690340d1..da68cd19efd6 100644 --- a/trunk/drivers/ata/pata_oldpiix.c +++ b/trunk/drivers/ata/pata_oldpiix.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_oldpiix" -#define DRV_VERSION "0.5.5" +#define DRV_VERSION "0.5.4" /** * oldpiix_pre_reset - probe begin @@ -44,6 +44,7 @@ static int oldpiix_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -64,7 +65,7 @@ static void oldpiix_pata_error_handler(struct ata_port *ap) /** * oldpiix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring - * @adev: Device whose timings we are configuring + * @adev: um * * Set PIO mode for device, in host controller PCI config space. * @@ -254,7 +255,6 @@ static const struct ata_port_operations oldpiix_pata_ops = { .thaw = ata_bmdma_thaw, .error_handler = oldpiix_pata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_opti.c b/trunk/drivers/ata/pata_opti.c index 13b63e21838d..3fd3a35c2241 100644 --- a/trunk/drivers/ata/pata_opti.c +++ b/trunk/drivers/ata/pata_opti.c @@ -34,7 +34,7 @@ #include #define DRV_NAME "pata_opti" -#define DRV_VERSION "0.2.9" +#define DRV_VERSION "0.2.8" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -61,6 +61,8 @@ static int opti_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; + + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -196,7 +198,6 @@ static struct ata_port_operations opti_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = opti_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_optidma.c b/trunk/drivers/ata/pata_optidma.c index b70e04c144df..9764907e8a13 100644 --- a/trunk/drivers/ata/pata_optidma.c +++ b/trunk/drivers/ata/pata_optidma.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_optidma" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.2.4" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -62,6 +62,7 @@ static int optidma_pre_reset(struct ata_port *ap) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -114,7 +115,7 @@ static void optidma_lock(struct ata_port *ap) } /** - * optidma_mode_setup - set mode data + * optidma_set_mode - set mode data * @ap: ATA interface * @adev: ATA device * @mode: Mode to set @@ -127,7 +128,7 @@ static void optidma_lock(struct ata_port *ap) * IRQ here we depend on the host set locking to avoid catastrophe. */ -static void optidma_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode) +static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) { struct ata_device *pair = ata_dev_pair(adev); int pio = adev->pio_mode - XFER_PIO_0; @@ -201,7 +202,7 @@ static void optidma_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 } /** - * optiplus_mode_setup - DMA setup for Firestar Plus + * optiplus_set_mode - DMA setup for Firestar Plus * @ap: ATA port * @adev: device * @mode: desired mode @@ -212,7 +213,7 @@ static void optidma_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 * one */ -static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode) +static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 udcfg; @@ -224,7 +225,7 @@ static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 pci_read_config_byte(pdev, 0x44, &udcfg); if (mode <= XFER_UDMA_0) { udcfg &= ~(1 << unit); - optidma_mode_setup(ap, adev, adev->dma_mode); + optidma_set_mode(ap, adev, adev->dma_mode); } else { udcfg |= (1 << unit); if (ap->port_no) { @@ -252,7 +253,7 @@ static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev) { - optidma_mode_setup(ap, adev, adev->pio_mode); + optidma_set_mode(ap, adev, adev->pio_mode); } /** @@ -267,7 +268,7 @@ static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev) static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev) { - optidma_mode_setup(ap, adev, adev->dma_mode); + optidma_set_mode(ap, adev, adev->dma_mode); } /** @@ -282,7 +283,7 @@ static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev) static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev) { - optiplus_mode_setup(ap, adev, adev->pio_mode); + optiplus_set_mode(ap, adev, adev->pio_mode); } /** @@ -297,7 +298,7 @@ static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev) static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev) { - optiplus_mode_setup(ap, adev, adev->dma_mode); + optiplus_set_mode(ap, adev, adev->dma_mode); } /** @@ -321,29 +322,26 @@ static u8 optidma_make_bits43(struct ata_device *adev) } /** - * optidma_set_mode - mode setup + * optidma_post_set_mode - finalize PCI setup * @ap: port to set up * - * Use the standard setup to tune the chipset and then finalise the - * configuration by writing the nibble of extra bits of data into - * the chip. + * Finalise the configuration by writing the nibble of extra bits + * of data into the chip. */ -static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static void optidma_post_set_mode(struct ata_port *ap) { u8 r; int nybble = 4 * ap->port_no; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int rc = ata_do_set_mode(ap, r_failed); - if (rc == 0) { - pci_read_config_byte(pdev, 0x43, &r); - - r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->device[0]) + - (optidma_make_bits43(&ap->device[0]) << 2)) << nybble; - pci_write_config_byte(pdev, 0x43, r); - } - return rc; + + pci_read_config_byte(pdev, 0x43, &r); + + r &= (0x0F << nybble); + r |= (optidma_make_bits43(&ap->device[0]) + + (optidma_make_bits43(&ap->device[0]) << 2)) << nybble; + + pci_write_config_byte(pdev, 0x43, r); } static struct scsi_host_template optidma_sht = { @@ -383,8 +381,7 @@ static struct ata_port_operations optidma_port_ops = { .thaw = ata_bmdma_thaw, .post_internal_cmd = ata_bmdma_post_internal_cmd, .error_handler = optidma_error_handler, - .set_mode = optidma_set_mode, - .cable_detect = ata_cable_40wire, + .post_set_mode = optidma_post_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -419,8 +416,7 @@ static struct ata_port_operations optiplus_port_ops = { .thaw = ata_bmdma_thaw, .post_internal_cmd = ata_bmdma_post_internal_cmd, .error_handler = optidma_error_handler, - .set_mode = optidma_set_mode, - .cable_detect = ata_cable_40wire, + .post_set_mode = optidma_post_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_pcmcia.c b/trunk/drivers/ata/pata_pcmcia.c index 75dc84797ff3..103720f873c8 100644 --- a/trunk/drivers/ata/pata_pcmcia.c +++ b/trunk/drivers/ata/pata_pcmcia.c @@ -42,7 +42,7 @@ #define DRV_NAME "pata_pcmcia" -#define DRV_VERSION "0.3.1" +#define DRV_VERSION "0.3.0" /* * Private data structure to glue stuff together @@ -54,39 +54,6 @@ struct ata_pcmcia_info { dev_node_t node; }; -/** - * pcmcia_set_mode - PCMCIA specific mode setup - * @ap: Port - * @r_failed_dev: Return pointer for failed device - * - * Perform the tuning and setup of the devices and timings, which - * for PCMCIA is the same as any other controller. We wrap it however - * as we need to spot hardware with incorrect or missing master/slave - * decode, which alas is embarrassingly common in the PC world - */ - -static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) -{ - struct ata_device *master = &ap->device[0]; - struct ata_device *slave = &ap->device[1]; - - if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) - return ata_do_set_mode(ap, r_failed_dev); - - if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV, - ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0) - { - /* Suspicious match, but could be two cards from - the same vendor - check serial */ - if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO, - ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) { - ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n"); - ata_dev_disable(slave); - } - } - return ata_do_set_mode(ap, r_failed_dev); -} - static struct scsi_host_template pcmcia_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -106,7 +73,6 @@ static struct scsi_host_template pcmcia_sht = { }; static struct ata_port_operations pcmcia_port_ops = { - .set_mode = pcmcia_set_mode, .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -118,13 +84,13 @@ static struct ata_port_operations pcmcia_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer_noirq, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -145,8 +111,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int pcmcia_init_one(struct pcmcia_device *pdev) { - struct ata_host *host; - struct ata_port *ap; + struct ata_probe_ent ae; struct ata_pcmcia_info *info; tuple_t tuple; struct { @@ -290,24 +255,24 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) * Having done the PCMCIA plumbing the ATA side is relatively * sane. */ - ret = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - goto failed; - ap = host->ports[0]; - - ap->ops = &pcmcia_port_ops; - ap->pio_mask = 1; /* ISA so PIO 0 cycles */ - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->ioaddr.cmd_addr = io_addr; - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); - - /* activate */ - ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, - IRQF_SHARED, &pcmcia_sht); - if (ret) + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pcmcia_port_ops; + ae.sht = &pcmcia_sht; + ae.n_ports = 1; + ae.pio_mask = 1; /* ISA so PIO 0 cycles */ + ae.irq = pdev->irq.AssignedIRQ; + ae.irq_flags = IRQF_SHARED; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; + ata_std_ports(&ae.port[0]); + + ret = -ENODEV; + if (ata_device_add(&ae) == 0) goto failed; info->ndev = 1; diff --git a/trunk/drivers/ata/pata_pdc2027x.c b/trunk/drivers/ata/pata_pdc2027x.c index a61cbc110688..93bcdadb7be3 100644 --- a/trunk/drivers/ata/pata_pdc2027x.c +++ b/trunk/drivers/ata/pata_pdc2027x.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "pata_pdc2027x" -#define DRV_VERSION "0.9" +#define DRV_VERSION "0.8" #undef PDC_DEBUG #ifdef PDC_DEBUG @@ -66,10 +66,8 @@ static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *e static void pdc2027x_error_handler(struct ata_port *ap); static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); +static void pdc2027x_post_set_mode(struct ata_port *ap); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); -static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); -static int pdc2027x_cable_detect(struct ata_port *ap); -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed); /* * ATA Timing Tables based on 133MHz controller clock. @@ -148,7 +146,6 @@ static struct scsi_host_template pdc2027x_sht = { static struct ata_port_operations pdc2027x_pata100_ops = { .port_disable = ata_port_disable, - .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -169,8 +166,8 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .thaw = ata_bmdma_thaw, .error_handler = pdc2027x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pdc2027x_cable_detect, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -182,8 +179,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .port_disable = ata_port_disable, .set_piomode = pdc2027x_set_piomode, .set_dmamode = pdc2027x_set_dmamode, - .set_mode = pdc2027x_set_mode, - .mode_filter = pdc2027x_mode_filter, + .post_set_mode = pdc2027x_post_set_mode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -204,8 +200,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .thaw = ata_bmdma_thaw, .error_handler = pdc2027x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pdc2027x_cable_detect, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -216,6 +212,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = { static struct ata_port_info pdc2027x_port_info[] = { /* PDC_UDMA_100 */ { + .sht = &pdc2027x_sht, .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO, .pio_mask = 0x1f, /* pio0-4 */ @@ -225,6 +222,7 @@ static struct ata_port_info pdc2027x_port_info[] = { }, /* PDC_UDMA_133 */ { + .sht = &pdc2027x_sht, .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO, .pio_mask = 0x1f, /* pio0-4 */ @@ -263,7 +261,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade } /** - * pdc2027x_pata_cable_detect - Probe host controller cable detect info + * pdc2027x_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired * * Read 80c cable indicator from Promise extended register. @@ -272,7 +270,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade * LOCKING: * None (inherited from caller). */ -static int pdc2027x_cable_detect(struct ata_port *ap) +static void pdc2027x_cbl_detect(struct ata_port *ap) { u32 cgcr; @@ -283,10 +281,13 @@ static int pdc2027x_cable_detect(struct ata_port *ap) PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no); - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA80; + return; + cbl40: printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no); - return ATA_CBL_PATA40; + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; } /** @@ -313,6 +314,7 @@ static int pdc2027x_prereset(struct ata_port *ap) /* Check whether port enabled */ if (!pdc2027x_port_enabled(ap)) return -ENOENT; + pdc2027x_cbl_detect(ap); return ata_std_prereset(ap); } @@ -331,32 +333,6 @@ static void pdc2027x_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset); } -/** - * pdc2720x_mode_filter - mode selection filter - * @adev: ATA device - * @mask: list of modes proposed - * - * Block UDMA on devices that cause trouble with this controller. - */ - -static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask) -{ - unsigned char model_num[ATA_ID_PROD_LEN + 1]; - struct ata_device *pair = ata_dev_pair(adev); - - if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL) - return ata_pci_default_filter(adev, mask); - - /* Check for slave of a Maxtor at UDMA6 */ - ata_id_c_string(pair->id, model_num, ATA_ID_PROD, - ATA_ID_PROD_LEN + 1); - /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */ - if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6) - mask &= ~ (1 << (6 + ATA_SHIFT_UDMA)); - - return ata_pci_default_filter(adev, mask); -} - /** * pdc2027x_set_piomode - Initialize host controller PATA PIO timings * @ap: Port to configure @@ -468,22 +444,17 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * pdc2027x_set_mode - Set the timing registers back to correct values. + * pdc2027x_post_set_mode - Set the timing registers back to correct values. * @ap: Port to configure - * @r_failed: Returned device for failure * * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. * This function overwrites the possibly incorrect values set by the hardware to be correct. */ -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static void pdc2027x_post_set_mode(struct ata_port *ap) { int i; - i = ata_do_set_mode(ap, r_failed); - if (i < 0) - return i; - for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -505,7 +476,6 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) } } } - return 0; } /** @@ -551,12 +521,12 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc) /** * pdc_read_counter - Read the ctr counter - * @host: target ATA host + * @probe_ent: for the port address */ -static long pdc_read_counter(struct ata_host *host) +static long pdc_read_counter(struct ata_probe_ent *probe_ent) { - void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; long counter; int retry = 1; u32 bccrl, bccrh, bccrlv, bccrhv; @@ -594,12 +564,12 @@ static long pdc_read_counter(struct ata_host *host) * adjust_pll - Adjust the PLL input clock in Hz. * * @pdc_controller: controller specific information - * @host: target ATA host + * @probe_ent: For the port address * @pll_clock: The input of PLL in HZ */ -static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx) +static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx) { - void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u16 pll_ctl; long pll_clock_khz = pll_clock / 1000; long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; @@ -679,19 +649,19 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b /** * detect_pll_input_clock - Detect the PLL input clock in Hz. - * @host: target ATA host + * @probe_ent: for the port address * Ex. 16949000 on 33MHz PCI bus for pdc20275. * Half of the PCI clock. */ -static long pdc_detect_pll_input_clock(struct ata_host *host) +static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) { - void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u32 scr; long start_count, end_count; long pll_clock; /* Read current counter value */ - start_count = pdc_read_counter(host); + start_count = pdc_read_counter(probe_ent); /* Start the test mode */ scr = readl(mmio_base + PDC_SYS_CTL); @@ -703,7 +673,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) mdelay(100); /* Read the counter values again */ - end_count = pdc_read_counter(host); + end_count = pdc_read_counter(probe_ent); /* Stop the test mode */ scr = readl(mmio_base + PDC_SYS_CTL); @@ -722,10 +692,11 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) /** * pdc_hardware_init - Initialize the hardware. - * @host: target ATA host - * @board_idx: board identifier + * @pdev: instance of pci_dev found + * @pdc_controller: controller specific information + * @pe: for the port address */ -static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) +static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx) { long pll_clock; @@ -735,15 +706,15 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) * Ex. 25MHz or 40MHz, we have to adjust the cycle_time. * The pdc20275 controller employs PLL circuit to help correct timing registers setting. */ - pll_clock = pdc_detect_pll_input_clock(host); + pll_clock = pdc_detect_pll_input_clock(pe); if (pll_clock < 0) /* counter overflow? Try again. */ - pll_clock = pdc_detect_pll_input_clock(host); + pll_clock = pdc_detect_pll_input_clock(pe); - dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); + dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000); /* Adjust PLL control register */ - pdc_adjust_pll(host, pll_clock, board_idx); + pdc_adjust_pll(pe, pll_clock, board_idx); return 0; } @@ -775,7 +746,8 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) * Called when an instance of PCI adapter is inserted. * This function checks whether the hardware is supported, * initialize hardware and register an instance of ata_host to - * libata. (implements struct pci_driver.probe() ) + * libata by providing struct ata_probe_ent and ata_device_add(). + * (implements struct pci_driver.probe() ) * * @pdev: instance of pci_dev found * @ent: matching entry in the id_tbl[] @@ -784,21 +756,14 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de { static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; - const struct ata_port_info *ppi[] = - { &pdc2027x_port_info[board_idx], NULL }; - struct ata_host *host; + + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* alloc host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -806,7 +771,6 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -816,22 +780,46 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de if (rc) return rc; - mmio_base = host->iomap[PDC_MMIO_BAR]; + /* Prepare the probe entry */ + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pdc2027x_port_info[board_idx].sht; + probe_ent->port_flags = pdc2027x_port_info[board_idx].flags; + probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask; + probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops; - pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0); - host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000; - pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0); - host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; + + pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0); + probe_ent->port[0].bmdma_addr = mmio_base + 0x1000; + pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0); + probe_ent->port[1].bmdma_addr = mmio_base + 0x1008; + + probe_ent->n_ports = 2; + + pci_set_master(pdev); //pci_enable_intx(pdev); /* initialize adapter */ - if (pdc_hardware_init(host, board_idx) != 0) + if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0) return -EIO; - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &pdc2027x_sht); + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } /** diff --git a/trunk/drivers/ata/pata_pdc202xx_old.c b/trunk/drivers/ata/pata_pdc202xx_old.c index ee636beb05e1..0a1493398913 100644 --- a/trunk/drivers/ata/pata_pdc202xx_old.c +++ b/trunk/drivers/ata/pata_pdc202xx_old.c @@ -22,17 +22,45 @@ #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.0" -static int pdc2026x_cable_detect(struct ata_port *ap) +/** + * pdc2024x_pre_reset - probe begin + * @ap: ATA port + * + * Set up cable type and use generic probe init + */ + +static int pdc2024x_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + + +static void pdc2024x_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + + +static int pdc2026x_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u16 cis; pci_read_config_word(pdev, 0x50, &cis); if (cis & (1 << (10 + ap->port_no))) - return ATA_CBL_PATA80; - return ATA_CBL_PATA40; + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + return ata_std_prereset(ap); +} + +static void pdc2026x_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } /** @@ -216,6 +244,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) /** * pdc2026x_dev_config - device setup hook + * @ap: ATA port * @adev: newly found device * * Perform chip specific early setup. We need to lock the transfer @@ -223,7 +252,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) * barf. */ -static void pdc2026x_dev_config(struct ata_device *adev) +static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev) { adev->max_sectors = 256; } @@ -263,9 +292,8 @@ static struct ata_port_operations pdc2024x_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = pdc2024x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -298,9 +326,8 @@ static struct ata_port_operations pdc2026x_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = pdc2026x_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = pdc2026x_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = pdc2026x_bmdma_start, diff --git a/trunk/drivers/ata/pata_platform.c b/trunk/drivers/ata/pata_platform.c index a0a650c7f272..4b82a5435a4e 100644 --- a/trunk/drivers/ata/pata_platform.c +++ b/trunk/drivers/ata/pata_platform.c @@ -80,13 +80,13 @@ static struct ata_port_operations pata_platform_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer_noirq, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -135,8 +135,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr, static int __devinit pata_platform_probe(struct platform_device *pdev) { struct resource *io_res, *ctl_res; - struct ata_host *host; - struct ata_port *ap; + struct ata_probe_ent ae; unsigned int mmio; /* @@ -176,41 +175,44 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) /* * Now that that's out of the way, wire up the port.. */ - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - return -ENOMEM; - ap = host->ports[0]; - - ap->ops = &pata_platform_port_ops; - ap->pio_mask = pio_mask; - ap->flags |= ATA_FLAG_SLAVE_POSS; + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pata_platform_port_ops; + ae.sht = &pata_platform_sht; + ae.n_ports = 1; + ae.pio_mask = pio_mask; + ae.irq = platform_get_irq(pdev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; /* * Handle the MMIO case */ if (mmio) { - ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start, + ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start, io_res->end - io_res->start + 1); - ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, + ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, ctl_res->end - ctl_res->start + 1); } else { - ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start, + ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start, io_res->end - io_res->start + 1); - ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start, + ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start, ctl_res->end - ctl_res->start + 1); } - if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) { + if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) { dev_err(&pdev->dev, "failed to map IO/CTL base\n"); return -ENOMEM; } - ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; + ae.port[0].altstatus_addr = ae.port[0].ctl_addr; - pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data); + pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); - /* activate */ - return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, - 0, &pata_platform_sht); + if (unlikely(ata_device_add(&ae) == 0)) + return -ENODEV; + + return 0; } /** diff --git a/trunk/drivers/ata/pata_qdi.c b/trunk/drivers/ata/pata_qdi.c index 27685ce63ceb..c3810012f3f4 100644 --- a/trunk/drivers/ata/pata_qdi.c +++ b/trunk/drivers/ata/pata_qdi.c @@ -183,13 +183,13 @@ static struct ata_port_operations qdi6500_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = qdi_qc_issue_prot, .data_xfer = qdi_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -211,13 +211,13 @@ static struct ata_port_operations qdi6580_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = qdi_qc_issue_prot, .data_xfer = qdi_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -238,9 +238,8 @@ static struct ata_port_operations qdi6580_port_ops = { static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) { + struct ata_probe_ent ae; struct platform_device *pdev; - struct ata_host *host; - struct ata_port *ap; void __iomem *io_addr, *ctl_addr; int ret; @@ -258,31 +257,34 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i if (!io_addr || !ctl_addr) goto fail; - ret = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - goto fail; - ap = host->ports[0]; + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; if (type == 6580) { - ap->ops = &qdi6580_port_ops; - ap->pio_mask = 0x1F; - ap->flags |= ATA_FLAG_SLAVE_POSS; + ae.port_ops = &qdi6580_port_ops; + ae.pio_mask = 0x1F; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; } else { - ap->ops = &qdi6500_port_ops; - ap->pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */ - ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; + ae.port_ops = &qdi6500_port_ops; + ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */ + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_IORDY; } - ap->ioaddr.cmd_addr = io_addr; - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); + ae.sht = &qdi_sht; + ae.n_ports = 1; + ae.irq = irq; + ae.irq_flags = 0; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; + ata_std_ports(&ae.port[0]); /* * Hook in a private data structure per channel */ - ap->private_data = &qdi_data[nr_qdi_host]; + ae.private_data = &qdi_data[nr_qdi_host]; qdi_data[nr_qdi_host].timing = port; qdi_data[nr_qdi_host].fast = fast; @@ -290,9 +292,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); - /* activate */ - ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht); - if (ret) + ret = -ENODEV; + if (!ata_device_add(&ae)) goto fail; qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev); diff --git a/trunk/drivers/ata/pata_radisys.c b/trunk/drivers/ata/pata_radisys.c index 1c54673e008d..9a9132c9e331 100644 --- a/trunk/drivers/ata/pata_radisys.c +++ b/trunk/drivers/ata/pata_radisys.c @@ -24,12 +24,40 @@ #include #define DRV_NAME "pata_radisys" -#define DRV_VERSION "0.4.4" +#define DRV_VERSION "0.4.1" /** - * radisys_set_piomode - Initialize host controller PATA PIO timings + * radisys_probe_init - probe begin * @ap: ATA port - * @adev: Device whose timings we are configuring + * + * Set up cable type and use generic probe init + */ + +static int radisys_pre_reset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + + +/** + * radisys_pata_error_handler - Probe specified port on PATA host controller + * @ap: Port to probe + * @classes: + * + * LOCKING: + * None (inherited from caller). + */ + +static void radisys_pata_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + +/** + * radisys_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um * * Set PIO mode for device, in host controller PCI config space. * @@ -220,9 +248,8 @@ static const struct ata_port_operations radisys_pata_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = radisys_pata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_rz1000.c b/trunk/drivers/ata/pata_rz1000.c index 85c45290eeee..f522daa2a6aa 100644 --- a/trunk/drivers/ata/pata_rz1000.c +++ b/trunk/drivers/ata/pata_rz1000.c @@ -24,6 +24,31 @@ #define DRV_VERSION "0.2.3" +/** + * rz1000_prereset - probe begin + * @ap: ATA port + * + * Set up cable type and use generics + */ + +static int rz1000_prereset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA40; + return ata_std_prereset(ap); +} + +/** + * rz1000_error_handler - probe reset + * @ap: ATA port + * + * Perform the ATA standard reset sequence + */ + +static void rz1000_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset); +} + /** * rz1000_set_mode - mode setting function * @ap: ATA interface @@ -97,9 +122,8 @@ static struct ata_port_operations rz1000_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = rz1000_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/trunk/drivers/ata/pata_sc1200.c b/trunk/drivers/ata/pata_sc1200.c index 66e8ff467c8d..93b3ed0f9e8a 100644 --- a/trunk/drivers/ata/pata_sc1200.c +++ b/trunk/drivers/ata/pata_sc1200.c @@ -216,7 +216,6 @@ static struct ata_port_operations sc1200_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_scc.c b/trunk/drivers/ata/pata_scc.c index 5df354d573e8..f3ed141fdc0e 100644 --- a/trunk/drivers/ata/pata_scc.c +++ b/trunk/drivers/ata/pata_scc.c @@ -1016,6 +1016,7 @@ static const struct ata_port_operations scc_pata_ops = { .error_handler = scc_error_handler, .post_internal_cmd = scc_bmdma_stop, + .irq_handler = ata_interrupt, .irq_clear = scc_bmdma_irq_clear, .irq_on = scc_irq_on, .irq_ack = scc_irq_ack, @@ -1026,6 +1027,7 @@ static const struct ata_port_operations scc_pata_ops = { static struct ata_port_info scc_port_info[] = { { + .sht = &scc_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x00, @@ -1038,10 +1040,10 @@ static struct ata_port_info scc_port_info[] = { * scc_reset_controller - initialize SCC PATA controller. */ -static int scc_reset_controller(struct ata_host *host) +static int scc_reset_controller(struct ata_probe_ent *probe_ent) { - void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR]; - void __iomem *bmid_base = host->iomap[SCC_BMID_BAR]; + void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR]; + void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR]; void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG; void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE; @@ -1102,15 +1104,17 @@ static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base) ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD; } -static int scc_host_init(struct ata_host *host) +static int scc_host_init(struct ata_probe_ent *probe_ent) { - struct pci_dev *pdev = to_pci_dev(host->dev); + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); int rc; - rc = scc_reset_controller(host); + rc = scc_reset_controller(probe_ent); if (rc) return rc; + probe_ent->n_ports = 1; + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; @@ -1118,7 +1122,7 @@ static int scc_host_init(struct ata_host *host) if (rc) return rc; - scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]); + scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]); pci_set_master(pdev); @@ -1141,18 +1145,14 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; - const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL }; struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1); - if (!host) - return -ENOMEM; - rc = pcim_enable_device(pdev); if (rc) return rc; @@ -1162,14 +1162,33 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - rc = scc_host_init(host); + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return -ENOMEM; + + probe_ent->dev = dev; + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = scc_port_info[board_idx].sht; + probe_ent->port_flags = scc_port_info[board_idx].flags; + probe_ent->pio_mask = scc_port_info[board_idx].pio_mask; + probe_ent->udma_mask = scc_port_info[board_idx].udma_mask; + probe_ent->port_ops = scc_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + + rc = scc_host_init(probe_ent); if (rc) return rc; - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &scc_sht); + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } static struct pci_driver scc_pci_driver = { diff --git a/trunk/drivers/ata/pata_serverworks.c b/trunk/drivers/ata/pata_serverworks.c index 3956ef26936d..598eef810a74 100644 --- a/trunk/drivers/ata/pata_serverworks.c +++ b/trunk/drivers/ata/pata_serverworks.c @@ -1,5 +1,5 @@ /* - * pata_serverworks.c - Serverworks PATA for new ATA layer + * ata-serverworks.c - Serverworks PATA for new ATA layer * (C) 2005 Red Hat Inc * Alan Cox * @@ -137,14 +137,14 @@ static struct sv_cable_table cable_detect[] = { }; /** - * serverworks_cable_detect - cable detection + * serverworks_pre_reset - cable detection * @ap: ATA port * * Perform cable detection according to the device and subvendor * identifications */ -static int serverworks_cable_detect(struct ata_port *ap) { +static int serverworks_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct sv_cable_table *cb = cable_detect; @@ -152,7 +152,8 @@ static int serverworks_cable_detect(struct ata_port *ap) { if (cb->device == pdev->device && (cb->subvendor == pdev->subsystem_vendor || cb->subvendor == PCI_ANY_ID)) { - return cb->cable_detect(ap); + ap->cbl = cb->cable_detect(ap); + return ata_std_prereset(ap); } cb++; } @@ -161,6 +162,11 @@ static int serverworks_cable_detect(struct ata_port *ap) { return -1; /* kill compiler warning */ } +static void serverworks_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + /** * serverworks_is_csb - Check for CSB or OSB * @pdev: PCI device to check @@ -185,31 +191,31 @@ static u8 serverworks_is_csb(struct pci_dev *pdev) /** * serverworks_osb4_filter - mode selection filter + * @ap: ATA interface * @adev: ATA device - * @mask: Mask of proposed modes * * Filter the offered modes for the device to apply controller * specific rules. OSB4 requires no UDMA for disks due to a FIFO * bug we hit. */ -static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned long mask) +static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { if (adev->class == ATA_DEV_ATA) mask &= ~ATA_MASK_UDMA; - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } /** * serverworks_csb_filter - mode selection filter + * @ap: ATA interface * @adev: ATA device - * @mask: Mask of proposed modes * * Check the blacklist and disable UDMA5 if matched */ -static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned long mask) +static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { const char *p; char model_num[ATA_ID_PROD_LEN + 1]; @@ -217,7 +223,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo /* Disk, UDMA */ if (adev->class != ATA_DEV_ATA) - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); /* Actually do need to check */ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); @@ -226,7 +232,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo if (!strcmp(p, model_num)) mask &= ~(0x1F << ATA_SHIFT_UDMA); } - return ata_pci_default_filter(adev, mask); + return ata_pci_default_filter(ap, adev, mask); } @@ -333,9 +339,8 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = serverworks_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = serverworks_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -369,9 +374,8 @@ static struct ata_port_operations serverworks_csb_port_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = serverworks_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = serverworks_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_sil680.c b/trunk/drivers/ata/pata_sil680.c index 6770820cfca9..dab2889a556f 100644 --- a/trunk/drivers/ata/pata_sil680.c +++ b/trunk/drivers/ata/pata_sil680.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.4.6" +#define DRV_VERSION "0.4.5" /** * sil680_selreg - return register base @@ -91,6 +91,12 @@ static int sil680_cable_detect(struct ata_port *ap) { return ATA_CBL_PATA40; } +static int sil680_pre_reset(struct ata_port *ap) +{ + ap->cbl = sil680_cable_detect(ap); + return ata_std_prereset(ap); +} + /** * sil680_bus_reset - reset the SIL680 bus * @ap: ATA port to reset @@ -113,7 +119,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes) static void sil680_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, ata_std_prereset, sil680_bus_reset, NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset); } /** @@ -251,7 +257,6 @@ static struct ata_port_operations sil680_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = sil680_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = sil680_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_sis.c b/trunk/drivers/ata/pata_sis.c index a3fbcee6fb33..8dc3bc4f5863 100644 --- a/trunk/drivers/ata/pata_sis.c +++ b/trunk/drivers/ata/pata_sis.c @@ -35,7 +35,7 @@ #include "sis.h" #define DRV_NAME "pata_sis" -#define DRV_VERSION "0.5.1" +#define DRV_VERSION "0.5.0" struct sis_chipset { u16 device; /* PCI host ID */ @@ -86,55 +86,106 @@ static int sis_port_base(struct ata_device *adev) } /** - * sis_133_cable_detect - check for 40/80 pin + * sis_133_pre_reset - check for 40/80 pin * @ap: Port * * Perform cable detection for the later UDMA133 capable * SiS chipset. */ -static int sis_133_cable_detect(struct ata_port *ap) +static int sis_133_pre_reset(struct ata_port *ap) { + static const struct pci_bits sis_enable_bits[] = { + { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ + { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ + }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); u16 tmp; + if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) + return -ENOENT; + /* The top bit of this register is the cable detect bit */ pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp); if ((tmp & 0x8000) && !sis_short_ata40(pdev)) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + + return ata_std_prereset(ap); } /** - * sis_66_cable_detect - check for 40/80 pin + * sis_error_handler - Probe specified port on PATA host controller + * @ap: Port to probe + * + * LOCKING: + * None (inherited from caller). + */ + +static void sis_133_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + + +/** + * sis_66_pre_reset - check for 40/80 pin * @ap: Port * * Perform cable detection on the UDMA66, UDMA100 and early UDMA133 * SiS IDE controllers. */ -static int sis_66_cable_detect(struct ata_port *ap) +static int sis_66_pre_reset(struct ata_port *ap) { + static const struct pci_bits sis_enable_bits[] = { + { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ + { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ + }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 tmp; + if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) { + ata_port_disable(ap); + ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); + return 0; + } /* Older chips keep cable detect in bits 4/5 of reg 0x48 */ pci_read_config_byte(pdev, 0x48, &tmp); tmp >>= ap->port_no; if ((tmp & 0x10) && !sis_short_ata40(pdev)) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + + return ata_std_prereset(ap); } +/** + * sis_66_error_handler - Probe specified port on PATA host controller + * @ap: Port to probe + * @classes: + * + * LOCKING: + * None (inherited from caller). + */ + +static void sis_66_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} /** - * sis_pre_reset - probe begin + * sis_old_pre_reset - probe begin * @ap: ATA port * * Set up cable type and use generic probe init */ -static int sis_pre_reset(struct ata_port *ap) +static int sis_old_pre_reset(struct ata_port *ap) { static const struct pci_bits sis_enable_bits[] = { { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -143,23 +194,27 @@ static int sis_pre_reset(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); - if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) - return -ENOENT; + if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) { + ata_port_disable(ap); + ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); + return 0; + } + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } /** - * sis_error_handler - Probe specified port on PATA host controller + * sis_old_error_handler - Probe specified port on PATA host controller * @ap: Port to probe * * LOCKING: * None (inherited from caller). */ -static void sis_error_handler(struct ata_port *ap) +static void sis_old_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, sis_pre_reset, ata_std_softreset, NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } /** @@ -439,7 +494,7 @@ static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *a int drive_pci = sis_port_base(adev); u16 timing; - static const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100}; + const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100}; pci_read_config_word(pdev, drive_pci, &timing); @@ -476,8 +531,8 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev) u32 reg54; /* bits 4- cycle time 8 - cvs time */ - static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 }; - static const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 }; + const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 }; + const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 }; /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */ pci_read_config_dword(pdev, 0x54, ®54); @@ -540,9 +595,8 @@ static const struct ata_port_operations sis_133_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, + .error_handler = sis_133_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = sis_133_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -574,9 +628,8 @@ static const struct ata_port_operations sis_133_early_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, + .error_handler = sis_66_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = sis_66_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -608,9 +661,9 @@ static const struct ata_port_operations sis_100_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, + .error_handler = sis_66_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = sis_66_cable_detect, + .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -639,11 +692,10 @@ static const struct ata_port_operations sis_66_ops = { .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .cable_detect = sis_66_cable_detect, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, + .error_handler = sis_66_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .bmdma_setup = ata_bmdma_setup, @@ -676,9 +728,8 @@ static const struct ata_port_operations sis_old_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = sis_error_handler, + .error_handler = sis_old_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_sl82c105.c b/trunk/drivers/ata/pata_sl82c105.c index da9e22b25753..b681441cfcb9 100644 --- a/trunk/drivers/ata/pata_sl82c105.c +++ b/trunk/drivers/ata/pata_sl82c105.c @@ -58,6 +58,7 @@ static int sl82c105_pre_reset(struct ata_port *ap) if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -237,7 +238,6 @@ static struct ata_port_operations sl82c105_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = sl82c105_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = sl82c105_bmdma_start, diff --git a/trunk/drivers/ata/pata_triflex.c b/trunk/drivers/ata/pata_triflex.c index e618ffd6e944..71418f2a0cdb 100644 --- a/trunk/drivers/ata/pata_triflex.c +++ b/trunk/drivers/ata/pata_triflex.c @@ -43,7 +43,7 @@ #include #define DRV_NAME "pata_triflex" -#define DRV_VERSION "0.2.8" +#define DRV_VERSION "0.2.7" /** * triflex_prereset - probe begin @@ -63,6 +63,7 @@ static int triflex_prereset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -213,7 +214,6 @@ static struct ata_port_operations triflex_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = triflex_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .bmdma_setup = ata_bmdma_setup, .bmdma_start = triflex_bmdma_start, diff --git a/trunk/drivers/ata/pata_via.c b/trunk/drivers/ata/pata_via.c index 96b71791d2f4..946ade0e1f1b 100644 --- a/trunk/drivers/ata/pata_via.c +++ b/trunk/drivers/ata/pata_via.c @@ -62,7 +62,7 @@ #include #define DRV_NAME "pata_via" -#define DRV_VERSION "0.3.1" +#define DRV_VERSION "0.2.1" /* * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx @@ -135,23 +135,16 @@ static const struct via_isa_bridge { */ static int via_cable_detect(struct ata_port *ap) { - const struct via_isa_bridge *config = ap->host->private_data; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 ata66; - /* Early chips are 40 wire */ - if ((config->flags & VIA_UDMA) < VIA_UDMA_66) - return ATA_CBL_PATA40; - /* UDMA 66 chips have only drive side logic */ - else if((config->flags & VIA_UDMA) < VIA_UDMA_100) - return ATA_CBL_PATA_UNK; - /* UDMA 100 or later */ pci_read_config_dword(pdev, 0x50, &ata66); /* Check both the drive cable reporting bits, we might not have two drives */ if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; - return ATA_CBL_PATA40; + else + return ATA_CBL_PATA40; } static int via_pre_reset(struct ata_port *ap) @@ -163,10 +156,22 @@ static int via_pre_reset(struct ata_port *ap) { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no])) return -ENOENT; } + + if ((config->flags & VIA_UDMA) >= VIA_UDMA_100) + ap->cbl = via_cable_detect(ap); + /* The UDMA66 series has no cable detect so do drive side detect */ + else if ((config->flags & VIA_UDMA) < VIA_UDMA_66) + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA_UNK; + + return ata_std_prereset(ap); } @@ -322,7 +327,6 @@ static struct ata_port_operations via_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = via_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = via_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -358,7 +362,6 @@ static struct ata_port_operations via_port_ops_noirq = { .thaw = ata_bmdma_thaw, .error_handler = via_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = via_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_winbond.c b/trunk/drivers/ata/pata_winbond.c index cc4ad271afb5..6c111035fc84 100644 --- a/trunk/drivers/ata/pata_winbond.c +++ b/trunk/drivers/ata/pata_winbond.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,7 @@ static int probe_winbond = 1; static int probe_winbond; #endif -static DEFINE_SPINLOCK(winbond_lock); +static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED; static void winbond_writecfg(unsigned long port, u8 reg, u8 val) { @@ -151,13 +152,13 @@ static struct ata_port_operations winbond_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = winbond_data_xfer, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -178,9 +179,11 @@ static struct ata_port_operations winbond_port_ops = { static __init int winbond_init_one(unsigned long port) { + struct ata_probe_ent ae; struct platform_device *pdev; + int ret; u8 reg; - int i, rc; + int i; reg = winbond_readcfg(port, 0x81); reg |= 0x80; /* jumpered mode off */ @@ -199,56 +202,58 @@ static __init int winbond_init_one(unsigned long port) for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); - struct ata_host *host; - struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; - if (!(reg & (1 << i))) - continue; - - pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - rc = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - goto err_unregister; - - rc = -ENOMEM; - cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); - ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); - if (!cmd_addr || !ctl_addr) - goto err_unregister; - - ap = host->ports[0]; - ap->ops = &winbond_port_ops; - ap->pio_mask = 0x1F; - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->ioaddr.cmd_addr = cmd_addr; - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); - - /* hook in a private data structure per channel */ - host->private_data = &winbond_data[nr_winbond_host]; - winbond_data[nr_winbond_host].config = port; - winbond_data[nr_winbond_host].platform_dev = pdev; - - /* activate */ - rc = ata_host_activate(host, 14 + i, ata_interrupt, 0, - &winbond_sht); - if (rc) - goto err_unregister; - - winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); + if (reg & (1 << i)) { + /* + * Fill in a probe structure first of all + */ + + pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); + ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + if (!cmd_addr || !ctl_addr) { + platform_device_unregister(pdev); + return -ENOMEM; + } + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + + ae.port_ops = &winbond_port_ops; + ae.pio_mask = 0x1F; + + ae.sht = &winbond_sht; + + ae.n_ports = 1; + ae.irq = 14 + i; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae.port[0].cmd_addr = cmd_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; + ata_std_ports(&ae.port[0]); + /* + * Hook in a private data structure per channel + */ + ae.private_data = &winbond_data[nr_winbond_host]; + winbond_data[nr_winbond_host].config = port; + winbond_data[nr_winbond_host].platform_dev = pdev; + + ret = ata_device_add(&ae); + if (ret == 0) { + platform_device_unregister(pdev); + return -ENODEV; + } + winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); + } } return 0; - - err_unregister: - platform_device_unregister(pdev); - return rc; } /** diff --git a/trunk/drivers/ata/pdc_adma.c b/trunk/drivers/ata/pdc_adma.c index 52b69530ab29..5dd3ca8b5f29 100644 --- a/trunk/drivers/ata/pdc_adma.c +++ b/trunk/drivers/ata/pdc_adma.c @@ -52,9 +52,9 @@ /* macro to calculate base address for ADMA regs */ #define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) -/* macro to obtain addresses from ata_port */ -#define ADMA_PORT_REGS(ap) \ - ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no) +/* macro to obtain addresses from ata_host */ +#define ADMA_HOST_REGS(host,port_no) \ + ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no) enum { ADMA_MMIO_BAR = 4, @@ -128,6 +128,7 @@ struct adma_port_priv { static int adma_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static irqreturn_t adma_intr (int irq, void *dev_instance); static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); @@ -171,6 +172,7 @@ static const struct ata_port_operations adma_ata_ops = { .qc_issue = adma_qc_issue, .eng_timeout = adma_eng_timeout, .data_xfer = ata_data_xfer, + .irq_handler = adma_intr, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -184,6 +186,7 @@ static const struct ata_port_operations adma_ata_ops = { static struct ata_port_info adma_port_info[] = { /* board_1841_idx */ { + .sht = &adma_ata_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, @@ -226,10 +229,8 @@ static void adma_irq_clear(struct ata_port *ap) /* nothing */ } -static void adma_reset_engine(struct ata_port *ap) +static void adma_reset_engine(void __iomem *chan) { - void __iomem *chan = ADMA_PORT_REGS(ap); - /* reset ADMA to idle state */ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); udelay(2); @@ -240,14 +241,14 @@ static void adma_reset_engine(struct ata_port *ap) static void adma_reinit_engine(struct ata_port *ap) { struct adma_port_priv *pp = ap->private_data; - void __iomem *chan = ADMA_PORT_REGS(ap); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); /* mask/clear ATA interrupts */ writeb(ATA_NIEN, ap->ioaddr.ctl_addr); ata_check_status(ap); /* reset the ADMA engine */ - adma_reset_engine(ap); + adma_reset_engine(chan); /* set in-FIFO threshold to 0x100 */ writew(0x100, chan + ADMA_FIFO_IN); @@ -267,7 +268,7 @@ static void adma_reinit_engine(struct ata_port *ap) static inline void adma_enter_reg_mode(struct ata_port *ap) { - void __iomem *chan = ADMA_PORT_REGS(ap); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); writew(aPIOMD4, chan + ADMA_CONTROL); readb(chan + ADMA_STATUS); /* flush */ @@ -414,7 +415,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc) static inline void adma_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *chan = ADMA_PORT_REGS(ap); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); VPRINTK("ENTER, ap %p\n", ap); @@ -452,7 +453,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) struct ata_port *ap = host->ports[port_no]; struct adma_port_priv *pp; struct ata_queued_cmd *qc; - void __iomem *chan = ADMA_PORT_REGS(ap); + void __iomem *chan = ADMA_HOST_REGS(host, port_no); u8 status = readb(chan + ADMA_STATUS); if (status == 0) @@ -574,7 +575,7 @@ static int adma_port_start(struct ata_port *ap) static void adma_port_stop(struct ata_port *ap) { - adma_reset_engine(ap); + adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no)); } static void adma_host_stop(struct ata_host *host) @@ -582,19 +583,21 @@ static void adma_host_stop(struct ata_host *host) unsigned int port_no; for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_reset_engine(host->ports[port_no]); + adma_reset_engine(ADMA_HOST_REGS(host, port_no)); } -static void adma_host_init(struct ata_host *host, unsigned int chip_id) +static void adma_host_init(unsigned int chip_id, + struct ata_probe_ent *probe_ent) { unsigned int port_no; + void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR]; /* enable/lock aGO operation */ - writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK); + writeb(7, mmio_base + ADMA_MODE_LOCK); /* reset the ADMA logic */ for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_reset_engine(host->ports[port_no]); + adma_reset_engine(ADMA_REGS(mmio_base, port_no)); } static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) @@ -620,21 +623,14 @@ static int adma_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - unsigned int board_idx = (unsigned int) ent->driver_data; - const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL }; - struct ata_host *host; + struct ata_probe_ent *probe_ent = NULL; void __iomem *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; int rc, port_no; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* alloc host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -645,23 +641,46 @@ static int adma_ata_init_one(struct pci_dev *pdev, rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - mmio_base = host->iomap[ADMA_MMIO_BAR]; + mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR]; rc = adma_set_dma_masks(pdev, mmio_base); if (rc) return rc; - for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_ata_setup_port(&host->ports[port_no]->ioaddr, + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = adma_port_info[board_idx].sht; + probe_ent->port_flags = adma_port_info[board_idx].flags; + probe_ent->pio_mask = adma_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = adma_port_info[board_idx].udma_mask; + probe_ent->port_ops = adma_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->n_ports = ADMA_PORTS; + probe_ent->iomap = pcim_iomap_table(pdev); + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { + adma_ata_setup_port(&probe_ent->port[port_no], ADMA_ATA_REGS(mmio_base, port_no)); + } + + pci_set_master(pdev); /* initialize adapter */ - adma_host_init(host, board_idx); + adma_host_init(board_idx, probe_ent); - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED, - &adma_ata_sht); + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init adma_ata_init(void) diff --git a/trunk/drivers/ata/sata_inic162x.c b/trunk/drivers/ata/sata_inic162x.c index f099a1d83a00..1e21688bfcf2 100644 --- a/trunk/drivers/ata/sata_inic162x.c +++ b/trunk/drivers/ata/sata_inic162x.c @@ -488,11 +488,11 @@ static void inic_error_handler(struct ata_port *ap) static void inic_post_internal_cmd(struct ata_queued_cmd *qc) { /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->err_mask) inic_reset_port(inic_port_base(qc->ap)); } -static void inic_dev_config(struct ata_device *dev) +static void inic_dev_config(struct ata_port *ap, struct ata_device *dev) { /* inic can only handle upto LBA28 max sectors */ if (dev->max_sectors > ATA_MAX_SECTORS) @@ -559,6 +559,7 @@ static struct ata_port_operations inic_port_ops = { .bmdma_stop = inic_bmdma_stop, .bmdma_status = inic_bmdma_status, + .irq_handler = inic_interrupt, .irq_clear = inic_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -579,6 +580,7 @@ static struct ata_port_operations inic_port_ops = { }; static struct ata_port_info inic_port_info = { + .sht = &inic_sht, /* For some reason, ATA_PROT_ATAPI is broken on this * controller, and no, PIO_POLLING does't fix it. It somehow * manages to report the wrong ireason and ignoring ireason @@ -640,9 +642,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev) void __iomem *mmio_base = host->iomap[MMIO_BAR]; int rc; - rc = ata_pci_device_do_resume(pdev); - if (rc) - return rc; + ata_pci_device_do_resume(pdev); if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { rc = init_controller(mmio_base, hpriv->cached_hctl); @@ -659,8 +659,8 @@ static int inic_pci_device_resume(struct pci_dev *pdev) static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - const struct ata_port_info *ppi[] = { &inic_port_info, NULL }; - struct ata_host *host; + struct ata_port_info *pinfo = &inic_port_info; + struct ata_probe_ent *probe_ent; struct inic_host_priv *hpriv; void __iomem * const *iomap; int i, rc; @@ -668,15 +668,6 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* alloc host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS); - hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); - if (!host || !hpriv) - return -ENOMEM; - - host->private_data = hpriv; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -684,22 +675,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); if (rc) return rc; - host->iomap = iomap = pcim_iomap_table(pdev); - - for (i = 0; i < NR_PORTS; i++) { - struct ata_ioports *port = &host->ports[i]->ioaddr; - void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; - - port->cmd_addr = iomap[2 * i]; - port->altstatus_addr = - port->ctl_addr = (void __iomem *) - ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); - port->scr_addr = port_base + PORT_SCR; - - ata_std_ports(port); - } - - hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); + iomap = pcim_iomap_table(pdev); /* Set dma_mask. This devices doesn't support 64bit addressing. */ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); @@ -716,6 +692,43 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!probe_ent || !hpriv) + return -ENOMEM; + + probe_ent->dev = &pdev->dev; + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pinfo->sht; + probe_ent->port_flags = pinfo->flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->mwdma_mask = pinfo->mwdma_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = NR_PORTS; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + + probe_ent->iomap = iomap; + + for (i = 0; i < NR_PORTS; i++) { + struct ata_ioports *port = &probe_ent->port[i]; + void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; + + port->cmd_addr = iomap[2 * i]; + port->altstatus_addr = + port->ctl_addr = (void __iomem *) + ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); + port->scr_addr = port_base + PORT_SCR; + + ata_std_ports(port); + } + + probe_ent->private_data = hpriv; + hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); + rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl); if (rc) { dev_printk(KERN_ERR, &pdev->dev, @@ -724,8 +737,13 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, inic_interrupt, IRQF_SHARED, - &inic_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + + return 0; } static const struct pci_device_id inic_pci_tbl[] = { diff --git a/trunk/drivers/ata/sata_mv.c b/trunk/drivers/ata/sata_mv.c index cb9b9ac12b4c..a65ba636aaa8 100644 --- a/trunk/drivers/ata/sata_mv.c +++ b/trunk/drivers/ata/sata_mv.c @@ -253,7 +253,10 @@ enum { #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) enum { - MV_DMA_BOUNDARY = 0xffffffffU, + /* Our DMA boundary is determined by an ePRD being unable to handle + * anything larger than 64KB + */ + MV_DMA_BOUNDARY = 0xffffU, EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, @@ -347,6 +350,7 @@ static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); static void mv_qc_prep_iie(struct ata_queued_cmd *qc); static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t mv_interrupt(int irq, void *dev_instance); static void mv_eng_timeout(struct ata_port *ap); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -380,10 +384,10 @@ static struct scsi_host_template mv_sht = { .queuecommand = ata_scsi_queuecmd, .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = MV_MAX_SG_CT, + .sg_tablesize = MV_MAX_SG_CT / 2, .cmd_per_lun = ATA_SHT_CMD_PER_LUN, .emulated = ATA_SHT_EMULATED, - .use_clustering = 1, + .use_clustering = ATA_SHT_USE_CLUSTERING, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, @@ -401,7 +405,6 @@ static const struct ata_port_operations mv5_ops = { .dev_select = ata_std_dev_select, .phy_reset = mv_phy_reset, - .cable_detect = ata_cable_sata, .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, @@ -409,6 +412,7 @@ static const struct ata_port_operations mv5_ops = { .eng_timeout = mv_eng_timeout, + .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -430,7 +434,6 @@ static const struct ata_port_operations mv6_ops = { .dev_select = ata_std_dev_select, .phy_reset = mv_phy_reset, - .cable_detect = ata_cable_sata, .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, @@ -438,6 +441,7 @@ static const struct ata_port_operations mv6_ops = { .eng_timeout = mv_eng_timeout, + .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -459,7 +463,6 @@ static const struct ata_port_operations mv_iie_ops = { .dev_select = ata_std_dev_select, .phy_reset = mv_phy_reset, - .cable_detect = ata_cable_sata, .qc_prep = mv_qc_prep_iie, .qc_issue = mv_qc_issue, @@ -467,6 +470,7 @@ static const struct ata_port_operations mv_iie_ops = { .eng_timeout = mv_eng_timeout, + .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -480,30 +484,35 @@ static const struct ata_port_operations mv_iie_ops = { static const struct ata_port_info mv_port_info[] = { { /* chip_504x */ + .sht = &mv_sht, .flags = MV_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv5_ops, }, { /* chip_508x */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv5_ops, }, { /* chip_5080 */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv5_ops, }, { /* chip_604x */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv6_ops, }, { /* chip_608x */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio0-4 */ @@ -511,12 +520,14 @@ static const struct ata_port_info mv_port_info[] = { .port_ops = &mv6_ops, }, { /* chip_6042 */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &mv_iie_ops, }, { /* chip_7042 */ + .sht = &mv_sht, .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 */ @@ -540,9 +551,6 @@ static const struct pci_device_id mv_pci_tbl[] = { { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, - /* add Marvell 7042 support */ - { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, - { } /* terminate list */ }; @@ -577,39 +585,6 @@ static const struct mv_hw_ops mv6xxx_ops = { static int msi; /* Use PCI msi; either zero (off, default) or non-zero */ -/* move to PCI layer or libata core? */ -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} - /* * Functions */ @@ -823,18 +798,20 @@ static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (0xffffffffU != ofs) + if (0xffffffffU != ofs) { return readl(mv_ap_base(ap) + ofs); - else + } else { return (u32) ofs; + } } static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (0xffffffffU != ofs) + if (0xffffffffU != ofs) { writelfl(val, mv_ap_base(ap) + ofs); + } } static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio) @@ -982,30 +959,38 @@ static void mv_port_stop(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) +static void mv_fill_sg(struct ata_queued_cmd *qc) { struct mv_port_priv *pp = qc->ap->private_data; - unsigned int n_sg = 0; + unsigned int i = 0; struct scatterlist *sg; - struct mv_sg *mv_sg; - mv_sg = pp->sg_tbl; ata_for_each_sg(sg, qc) { - dma_addr_t addr = sg_dma_address(sg); - u32 sg_len = sg_dma_len(sg); + dma_addr_t addr; + u32 sg_len, len, offset; - mv_sg->addr = cpu_to_le32(addr & 0xffffffff); - mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); - mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff); + addr = sg_dma_address(sg); + sg_len = sg_dma_len(sg); - if (ata_sg_is_last(sg, qc)) - mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + while (sg_len) { + offset = addr & MV_DMA_BOUNDARY; + len = sg_len; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; - mv_sg++; - n_sg++; - } + pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); + pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); + pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff); + + sg_len -= len; + addr += len; - return n_sg; + if (!sg_len && ata_sg_is_last(sg, qc)) + pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); + + i++; + } + } } static inline unsigned mv_inc_q_index(unsigned index) @@ -1335,15 +1320,17 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) int shift, port, port0, hard_port, handled; unsigned int err_mask; - if (hc == 0) + if (hc == 0) { port0 = 0; - else + } else { port0 = MV_PORTS_PER_HC; + } /* we'll need the HC success int register in most cases */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); - if (hc_irq_cause) + if (hc_irq_cause) { writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); + } VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", hc,relevant,hc_irq_cause); @@ -1438,8 +1425,9 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault */ - if (!irq_stat || (0xffffffffU == irq_stat)) + if (!irq_stat || (0xffffffffU == irq_stat)) { return IRQ_NONE; + } n_hcs = mv_get_hc_count(host->ports[0]->flags); spin_lock(&host->lock); @@ -1964,6 +1952,7 @@ static void __mv_phy_reset(struct ata_port *ap, int can_sleep) ata_port_disable(ap); return; } + ap->cbl = ATA_CBL_SATA; /* even after SStatus reflects that device is ready, * it seems to take a while for link to be fully @@ -2088,10 +2077,9 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); } -static int mv_chip_id(struct ata_host *host, unsigned int board_idx) +static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv, + unsigned int board_idx) { - struct pci_dev *pdev = to_pci_dev(host->dev); - struct mv_host_priv *hpriv = host->private_data; u8 rev_id; u32 hp_flags = hpriv->hp_flags; @@ -2189,8 +2177,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) /** * mv_init_host - Perform some early initialization of the host. - * @host: ATA host to initialize - * @board_idx: controller index + * @pdev: host PCI device + * @probe_ent: early data struct representing the host * * If possible, do an early global reset of the host. Then do * our port init and clear/unmask all/relevant host interrupts. @@ -2198,23 +2186,24 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) * LOCKING: * Inherited from caller. */ -static int mv_init_host(struct ata_host *host, unsigned int board_idx) +static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, + unsigned int board_idx) { int rc = 0, n_hc, port, hc; - struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; - struct mv_host_priv *hpriv = host->private_data; + void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = probe_ent->private_data; /* global interrupt mask */ writel(0, mmio + HC_MAIN_IRQ_MASK_OFS); - rc = mv_chip_id(host, board_idx); + rc = mv_chip_id(pdev, hpriv, board_idx); if (rc) goto done; - n_hc = mv_get_hc_count(host->ports[0]->flags); + n_hc = mv_get_hc_count(probe_ent->port_flags); + probe_ent->n_ports = MV_PORTS_PER_HC * n_hc; - for (port = 0; port < host->n_ports; port++) + for (port = 0; port < probe_ent->n_ports; port++) hpriv->ops->read_preamp(hpriv, port, mmio); rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc); @@ -2225,7 +2214,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) hpriv->ops->reset_bus(pdev, mmio); hpriv->ops->enable_leds(hpriv, mmio); - for (port = 0; port < host->n_ports; port++) { + for (port = 0; port < probe_ent->n_ports; port++) { if (IS_60XX(hpriv)) { void __iomem *port_mmio = mv_port_base(mmio, port); @@ -2238,9 +2227,9 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) hpriv->ops->phy_errata(hpriv, mmio, port); } - for (port = 0; port < host->n_ports; port++) { + for (port = 0; port < probe_ent->n_ports; port++) { void __iomem *port_mmio = mv_port_base(mmio, port); - mv_port_init(&host->ports[port]->ioaddr, port_mmio); + mv_port_init(&probe_ent->port[port], port_mmio); } for (hc = 0; hc < n_hc; hc++) { @@ -2279,17 +2268,17 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) /** * mv_print_info - Dump key info to kernel log for perusal. - * @host: ATA host to print info about + * @probe_ent: early data struct representing the host * * FIXME: complete this. * * LOCKING: * Inherited from caller. */ -static void mv_print_info(struct ata_host *host) +static void mv_print_info(struct ata_probe_ent *probe_ent) { - struct pci_dev *pdev = to_pci_dev(host->dev); - struct mv_host_priv *hpriv = host->private_data; + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + struct mv_host_priv *hpriv = probe_ent->private_data; u8 rev_id, scc; const char *scc_s; @@ -2308,7 +2297,7 @@ static void mv_print_info(struct ata_host *host) dev_printk(KERN_INFO, &pdev->dev, "%u slots %u ports %s mode IRQ via %s\n", - (unsigned)MV_MAX_Q_DEPTH, host->n_ports, + (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); } @@ -2323,42 +2312,50 @@ static void mv_print_info(struct ata_host *host) static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; - unsigned int board_idx = (unsigned int)ent->driver_data; - const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL }; - struct ata_host *host; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; struct mv_host_priv *hpriv; - int n_ports, rc; + unsigned int board_idx = (unsigned int)ent->driver_data; + int rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - /* allocate host */ - n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); - hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); - if (!host || !hpriv) - return -ENOMEM; - host->private_data = hpriv; - - /* acquire resources */ rc = pcim_enable_device(pdev); if (rc) return rc; + pci_set_master(pdev); rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - rc = pci_go_64(pdev); - if (rc) - return rc; + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + probe_ent->sht = mv_port_info[board_idx].sht; + probe_ent->port_flags = mv_port_info[board_idx].flags; + probe_ent->pio_mask = mv_port_info[board_idx].pio_mask; + probe_ent->udma_mask = mv_port_info[board_idx].udma_mask; + probe_ent->port_ops = mv_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + probe_ent->private_data = hpriv; /* initialize adapter */ - rc = mv_init_host(host, board_idx); + rc = mv_init_host(pdev, probe_ent, board_idx); if (rc) return rc; @@ -2367,11 +2364,13 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_intx(pdev, 1); mv_dump_pci_cfg(pdev, 0x68); - mv_print_info(host); + mv_print_info(probe_ent); - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED, - &mv_sht); + if (ata_device_add(probe_ent) == 0) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } static int __init mv_init(void) diff --git a/trunk/drivers/ata/sata_nv.c b/trunk/drivers/ata/sata_nv.c index 02169740ed24..9d9670a9b117 100644 --- a/trunk/drivers/ata/sata_nv.c +++ b/trunk/drivers/ata/sata_nv.c @@ -260,7 +260,6 @@ static int nv_adma_port_resume(struct ata_port *ap); static void nv_adma_error_handler(struct ata_port *ap); static void nv_adma_host_stop(struct ata_host *host); static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); -static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf); enum nv_host_type { @@ -369,6 +368,7 @@ static const struct ata_port_operations nv_generic_ops = { .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .data_xfer = ata_data_xfer, + .irq_handler = nv_generic_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -395,6 +395,7 @@ static const struct ata_port_operations nv_nf2_ops = { .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .data_xfer = ata_data_xfer, + .irq_handler = nv_nf2_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -421,6 +422,7 @@ static const struct ata_port_operations nv_ck804_ops = { .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .data_xfer = ata_data_xfer, + .irq_handler = nv_ck804_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -433,7 +435,7 @@ static const struct ata_port_operations nv_ck804_ops = { static const struct ata_port_operations nv_adma_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, - .tf_read = nv_adma_tf_read, + .tf_read = ata_tf_read, .check_atapi_dma = nv_adma_check_atapi_dma, .exec_command = ata_exec_command, .check_status = ata_check_status, @@ -449,6 +451,7 @@ static const struct ata_port_operations nv_adma_ops = { .error_handler = nv_adma_error_handler, .post_internal_cmd = nv_adma_post_internal_cmd, .data_xfer = ata_data_xfer, + .irq_handler = nv_adma_interrupt, .irq_clear = nv_adma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -473,7 +476,6 @@ static struct ata_port_info nv_port_info[] = { .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_generic_ops, - .irq_handler = nv_generic_interrupt, }, /* nforce2/3 */ { @@ -484,7 +486,6 @@ static struct ata_port_info nv_port_info[] = { .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_nf2_ops, - .irq_handler = nv_nf2_interrupt, }, /* ck804 */ { @@ -495,7 +496,6 @@ static struct ata_port_info nv_port_info[] = { .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_ck804_ops, - .irq_handler = nv_ck804_interrupt, }, /* ADMA */ { @@ -507,7 +507,6 @@ static struct ata_port_info nv_port_info[] = { .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_adma_ops, - .irq_handler = nv_adma_interrupt, }, }; @@ -668,18 +667,6 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc) return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); } -static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - /* Since commands where a result TF is requested are not - executed in ADMA mode, the only time this function will be called - in ADMA mode will be if a command fails. In this case we - don't care about going into register mode with ADMA commands - pending, as the commands will all shortly be aborted anyway. */ - nv_adma_register_mode(ap); - - ata_tf_read(ap, tf); -} - static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) { unsigned int idx = 0; @@ -751,11 +738,19 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) return 1; } - if (likely(flags & NV_CPB_RESP_DONE)) { + if (flags & NV_CPB_RESP_DONE) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); VPRINTK("CPB flags done, flags=0x%x\n", flags); if (likely(qc)) { - DPRINTK("Completing qc from tag %d\n",cpb_num); + /* Grab the ATA port status for non-NCQ commands. + For NCQ commands the current status may have nothing to do with + the command just completed. */ + if (qc->tf.protocol != ATA_PROT_NCQ) { + u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4)); + qc->err_mask |= ac_err_mask(ata_status); + } + DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, + qc->err_mask); ata_qc_complete(qc); } else { struct ata_eh_info *ehi = &ap->eh_info; @@ -1079,14 +1074,14 @@ static int nv_adma_port_resume(struct ata_port *ap) } #endif -static void nv_adma_setup_port(struct ata_port *ap) +static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) { - void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; - struct ata_ioports *ioport = &ap->ioaddr; + void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR]; + struct ata_ioports *ioport = &probe_ent->port[port]; VPRINTK("ENTER\n"); - mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE; + mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; ioport->cmd_addr = mmio; ioport->data_addr = mmio + (ATA_REG_DATA * 4); @@ -1103,9 +1098,9 @@ static void nv_adma_setup_port(struct ata_port *ap) ioport->ctl_addr = mmio + 0x20; } -static int nv_adma_host_init(struct ata_host *host) +static int nv_adma_host_init(struct ata_probe_ent *probe_ent) { - struct pci_dev *pdev = to_pci_dev(host->dev); + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); unsigned int i; u32 tmp32; @@ -1120,8 +1115,8 @@ static int nv_adma_host_init(struct ata_host *host) pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); - for (i = 0; i < host->n_ports; i++) - nv_adma_setup_port(host->ports[i]); + for (i = 0; i < probe_ent->n_ports; i++) + nv_adma_setup_port(probe_ent, i); return 0; } @@ -1172,11 +1167,9 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc) struct nv_adma_port_priv *pp = qc->ap->private_data; /* ADMA engine can only be used for non-ATAPI DMA commands, - or interrupt-driven no-data commands, where a result taskfile - is not required. */ + or interrupt-driven no-data commands. */ if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) || - (qc->tf.flags & ATA_TFLAG_POLLING) || - (qc->flags & ATA_QCFLAG_RESULT_TF)) + (qc->tf.flags & ATA_TFLAG_POLLING)) return 1; if((qc->flags & ATA_QCFLAG_DMAMAP) || @@ -1480,13 +1473,14 @@ static void nv_adma_error_handler(struct ata_port *ap) static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; - const struct ata_port_info *ppi[2]; - struct ata_host *host; + struct ata_port_info *ppi[2]; + struct ata_probe_ent *probe_ent; struct nv_host_priv *hpriv; int rc; u32 bar; void __iomem *base; unsigned long type = ent->driver_data; + int mask_set = 0; // Make sure this is a SATA controller by counting the number of bars // (NVIDIA SATA controllers will always have six bars). Otherwise, @@ -1502,38 +1496,50 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - /* determine type and allocate host */ - if (type >= CK804 && adma_enabled) { + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + pcim_pin_device(pdev); + return rc; + } + + if(type >= CK804 && adma_enabled) { dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; + if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + mask_set = 1; } - ppi[0] = ppi[1] = &nv_port_info[type]; - rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host); - if (rc) - return rc; + if(!mask_set) { + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + } + + rc = -ENOMEM; hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - hpriv->type = type; - host->private_data = hpriv; - /* set 64bit dma masks, may fail */ - if (type == ADMA) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) - pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - } + ppi[0] = ppi[1] = &nv_port_info[type]; + probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + if (!probe_ent) + return -ENOMEM; - /* request and iomap NV_MMIO_BAR */ - rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME); - if (rc) - return rc; + if (!pcim_iomap(pdev, NV_MMIO_BAR, 0)) + return -EIO; + probe_ent->iomap = pcim_iomap_table(pdev); + + probe_ent->private_data = hpriv; + hpriv->type = type; - /* configure SCR access */ - base = host->iomap[NV_MMIO_BAR]; - host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET; - host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET; + base = probe_ent->iomap[NV_MMIO_BAR]; + probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; + probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; /* enable SATA space for CK804 */ if (type >= CK804) { @@ -1544,16 +1550,20 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); } - /* init ADMA */ + pci_set_master(pdev); + if (type == ADMA) { - rc = nv_adma_host_init(host); + rc = nv_adma_host_init(probe_ent); if (rc) return rc; } - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler, - IRQF_SHARED, ppi[0]->sht); + rc = ata_device_add(probe_ent); + if (rc != NV_PORTS) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static void nv_remove_one (struct pci_dev *pdev) diff --git a/trunk/drivers/ata/sata_promise.c b/trunk/drivers/ata/sata_promise.c index f56549b90aa6..2339813ce9f6 100644 --- a/trunk/drivers/ata/sata_promise.c +++ b/trunk/drivers/ata/sata_promise.c @@ -45,11 +45,10 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "2.05" +#define DRV_VERSION "2.00" enum { - PDC_MAX_PORTS = 4, PDC_MMIO_BAR = 3, /* register offsets */ @@ -71,31 +70,14 @@ enum { PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */ PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */ - /* PDC_GLOBAL_CTL bit definitions */ - PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */ - PDC_SH_ERR = (1 << 9), /* PCI error while loading S/G table */ - PDC_DH_ERR = (1 << 10), /* PCI error while loading data */ - PDC2_HTO_ERR = (1 << 12), /* host bus timeout */ - PDC2_ATA_HBA_ERR = (1 << 13), /* error during SATA DATA FIS transmission */ - PDC2_ATA_DMA_CNT_ERR = (1 << 14), /* DMA DATA FIS size differs from S/G count */ - PDC_OVERRUN_ERR = (1 << 19), /* S/G byte count larger than HD requires */ - PDC_UNDERRUN_ERR = (1 << 20), /* S/G byte count less than HD requires */ - PDC_DRIVE_ERR = (1 << 21), /* drive error */ - PDC_PCI_SYS_ERR = (1 << 22), /* PCI system error */ - PDC1_PCI_PARITY_ERR = (1 << 23), /* PCI parity error (from SATA150 driver) */ - PDC1_ERR_MASK = PDC1_PCI_PARITY_ERR, - PDC2_ERR_MASK = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR, - PDC_ERR_MASK = (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR - | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR - | PDC1_ERR_MASK | PDC2_ERR_MASK), + PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) | + (1<<8) | (1<<9) | (1<<10), board_2037x = 0, /* FastTrak S150 TX2plus */ - board_2037x_pata = 1, /* FastTrak S150 TX2plus PATA port */ - board_20319 = 2, /* FastTrak S150 TX4 */ - board_20619 = 3, /* FastTrak TX4000 */ - board_2057x = 4, /* SATAII150 Tx2plus */ - board_2057x_pata = 5, /* SATAII150 Tx2plus */ - board_40518 = 6, /* SATAII150 Tx4 */ + board_20319 = 1, /* FastTrak S150 TX4 */ + board_20619 = 2, /* FastTrak TX4000 */ + board_2057x = 3, /* SATAII150 Tx2plus */ + board_40518 = 4, /* SATAII150 Tx4 */ PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */ @@ -118,10 +100,8 @@ enum { ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, - /* ap->flags bits */ - PDC_FLAG_GEN_II = (1 << 24), - PDC_FLAG_SATA_PATA = (1 << 25), /* supports SATA + PATA */ - PDC_FLAG_4_PORTS = (1 << 26), /* 4 ports */ + /* hp->flags bits */ + PDC_FLAG_GEN_II = (1 << 0), }; @@ -130,25 +110,28 @@ struct pdc_port_priv { dma_addr_t pkt_dma; }; +struct pdc_host_priv { + unsigned long flags; + unsigned long port_flags[ATA_MAX_PORTS]; +}; + static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static int pdc_common_port_start(struct ata_port *ap); -static int pdc_sata_port_start(struct ata_port *ap); +static irqreturn_t pdc_interrupt (int irq, void *dev_instance); +static int pdc_port_start(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static int pdc_check_atapi_dma(struct ata_queued_cmd *qc); -static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc); +static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc); static void pdc_irq_clear(struct ata_port *ap); static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static void pdc_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); -static void pdc_pata_error_handler(struct ata_port *ap); -static void pdc_sata_error_handler(struct ata_port *ap); +static void pdc_error_handler(struct ata_port *ap); static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); -static int pdc_pata_cable_detect(struct ata_port *ap); -static int pdc_sata_cable_detect(struct ata_port *ap); + static struct scsi_host_template pdc_ata_sht = { .module = THIS_MODULE, @@ -181,17 +164,17 @@ static const struct ata_port_operations pdc_sata_ops = { .qc_issue = pdc_qc_issue_prot, .freeze = pdc_freeze, .thaw = pdc_thaw, - .error_handler = pdc_sata_error_handler, + .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, .data_xfer = ata_data_xfer, + .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, - .port_start = pdc_sata_port_start, + .port_start = pdc_port_start, }; /* First-generation chips need a more restrictive ->check_atapi_dma op */ @@ -202,23 +185,23 @@ static const struct ata_port_operations pdc_old_sata_ops = { .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, .dev_select = ata_std_dev_select, - .check_atapi_dma = pdc_old_sata_check_atapi_dma, + .check_atapi_dma = pdc_old_check_atapi_dma, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, .freeze = pdc_freeze, .thaw = pdc_thaw, - .error_handler = pdc_sata_error_handler, + .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_sata_cable_detect, .data_xfer = ata_data_xfer, + .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, - .port_start = pdc_sata_port_start, + .port_start = pdc_port_start, }; static const struct ata_port_operations pdc_pata_ops = { @@ -234,41 +217,32 @@ static const struct ata_port_operations pdc_pata_ops = { .qc_issue = pdc_qc_issue_prot, .freeze = pdc_freeze, .thaw = pdc_thaw, - .error_handler = pdc_pata_error_handler, + .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .cable_detect = pdc_pata_cable_detect, .data_xfer = ata_data_xfer, + .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, - .port_start = pdc_common_port_start, + .port_start = pdc_port_start, }; static const struct ata_port_info pdc_port_info[] = { /* board_2037x */ { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA | - PDC_FLAG_SATA_PATA, + .sht = &pdc_ata_sht, + .flags = PDC_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_old_sata_ops, }, - /* board_2037x_pata */ - { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_pata_ops, - }, - /* board_20319 */ { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA | - PDC_FLAG_4_PORTS, + .sht = &pdc_ata_sht, + .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -277,8 +251,8 @@ static const struct ata_port_info pdc_port_info[] = { /* board_20619 */ { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS | - PDC_FLAG_4_PORTS, + .sht = &pdc_ata_sht, + .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -287,28 +261,18 @@ static const struct ata_port_info pdc_port_info[] = { /* board_2057x */ { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA | - PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA, + .sht = &pdc_ata_sht, + .flags = PDC_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, - /* board_2057x_pata */ - { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, - PDC_FLAG_GEN_II, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_pata_ops, - }, - /* board_40518 */ { - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA | - PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS, + .sht = &pdc_ata_sht, + .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -349,12 +313,18 @@ static struct pci_driver pdc_ata_pci_driver = { }; -static int pdc_common_port_start(struct ata_port *ap) +static int pdc_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; + struct pdc_host_priv *hp = ap->host->private_data; struct pdc_port_priv *pp; int rc; + /* fix up port flags and cable type for SATA+PATA chips */ + ap->flags |= hp->port_flags[ap->port_no]; + if (ap->flags & ATA_FLAG_SATA) + ap->cbl = ATA_CBL_SATA; + rc = ata_port_start(ap); if (rc) return rc; @@ -369,19 +339,8 @@ static int pdc_common_port_start(struct ata_port *ap) ap->private_data = pp; - return 0; -} - -static int pdc_sata_port_start(struct ata_port *ap) -{ - int rc; - - rc = pdc_common_port_start(ap); - if (rc) - return rc; - /* fix up PHYMODE4 align timing */ - if (ap->flags & PDC_FLAG_GEN_II) { + if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) { void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr; unsigned int tmp; @@ -415,25 +374,23 @@ static void pdc_reset_port(struct ata_port *ap) readl(mmio); /* flush */ } -static int pdc_pata_cable_detect(struct ata_port *ap) +static void pdc_pata_cbl_detect(struct ata_port *ap) { u8 tmp; void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; tmp = readb(mmio); - if (tmp & 0x01) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; -} -static int pdc_sata_cable_detect(struct ata_port *ap) -{ - return ATA_CBL_SATA; + if (tmp & 0x01) { + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; + } else + ap->cbl = ATA_CBL_PATA80; } static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { - if (sc_reg > SCR_CONTROL) + if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return 0xffffffffU; return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -442,7 +399,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - if (sc_reg > SCR_CONTROL) + if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return; writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -598,79 +555,52 @@ static void pdc_thaw(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } -static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset) +static int pdc_pre_reset(struct ata_port *ap) +{ + if (!sata_scr_valid(ap)) + pdc_pata_cbl_detect(ap); + return ata_std_prereset(ap); +} + +static void pdc_error_handler(struct ata_port *ap) { + ata_reset_fn_t hardreset; + if (!(ap->pflags & ATA_PFLAG_FROZEN)) pdc_reset_port(ap); + hardreset = NULL; + if (sata_scr_valid(ap)) + hardreset = sata_std_hardreset; + /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset, ata_std_postreset); } -static void pdc_pata_error_handler(struct ata_port *ap) -{ - pdc_common_error_handler(ap, NULL); -} - -static void pdc_sata_error_handler(struct ata_port *ap) -{ - pdc_common_error_handler(ap, sata_std_hardreset); -} - static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - /* make DMA engine forget about the failed command */ if (qc->flags & ATA_QCFLAG_FAILED) - pdc_reset_port(ap); -} + qc->err_mask |= AC_ERR_OTHER; -static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, - u32 port_status, u32 err_mask) -{ - struct ata_eh_info *ehi = &ap->eh_info; - unsigned int ac_err_mask = 0; - - ata_ehi_clear_desc(ehi); - ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status); - port_status &= err_mask; - - if (port_status & PDC_DRIVE_ERR) - ac_err_mask |= AC_ERR_DEV; - if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR)) - ac_err_mask |= AC_ERR_HSM; - if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR)) - ac_err_mask |= AC_ERR_ATA_BUS; - if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR - | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) - ac_err_mask |= AC_ERR_HOST_BUS; - - if (sata_scr_valid(ap)) - ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR); - - qc->err_mask |= ac_err_mask; - - pdc_reset_port(ap); + /* make DMA engine forget about the failed command */ + if (qc->err_mask) + pdc_reset_port(ap); } static inline unsigned int pdc_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc) { unsigned int handled = 0; - void __iomem *port_mmio = ap->ioaddr.cmd_addr; - u32 port_status, err_mask; + u32 tmp; + void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; - err_mask = PDC_ERR_MASK; - if (ap->flags & PDC_FLAG_GEN_II) - err_mask &= ~PDC1_ERR_MASK; - else - err_mask &= ~PDC2_ERR_MASK; - port_status = readl(port_mmio + PDC_GLOBAL_CTL); - if (unlikely(port_status & err_mask)) { - pdc_error_intr(ap, qc, port_status, err_mask); - return 1; + tmp = readl(mmio); + if (tmp & PDC_ERR_MASK) { + qc->err_mask |= AC_ERR_DEV; + pdc_reset_port(ap); } switch (qc->tf.protocol) { @@ -837,40 +767,44 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc) return pio; } -static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc) +static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; + /* First generation chips cannot use ATAPI DMA on SATA ports */ - return 1; + if (sata_scr_valid(ap)) + return 1; + return pdc_check_atapi_dma(qc); } -static void pdc_ata_setup_port(struct ata_port *ap, - void __iomem *base, void __iomem *scr_addr) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base, + void __iomem *scr_addr) { - ap->ioaddr.cmd_addr = base; - ap->ioaddr.data_addr = base; - ap->ioaddr.feature_addr = - ap->ioaddr.error_addr = base + 0x4; - ap->ioaddr.nsect_addr = base + 0x8; - ap->ioaddr.lbal_addr = base + 0xc; - ap->ioaddr.lbam_addr = base + 0x10; - ap->ioaddr.lbah_addr = base + 0x14; - ap->ioaddr.device_addr = base + 0x18; - ap->ioaddr.command_addr = - ap->ioaddr.status_addr = base + 0x1c; - ap->ioaddr.altstatus_addr = - ap->ioaddr.ctl_addr = base + 0x38; - ap->ioaddr.scr_addr = scr_addr; + port->cmd_addr = base; + port->data_addr = base; + port->feature_addr = + port->error_addr = base + 0x4; + port->nsect_addr = base + 0x8; + port->lbal_addr = base + 0xc; + port->lbam_addr = base + 0x10; + port->lbah_addr = base + 0x14; + port->device_addr = base + 0x18; + port->command_addr = + port->status_addr = base + 0x1c; + port->altstatus_addr = + port->ctl_addr = base + 0x38; + port->scr_addr = scr_addr; } -static void pdc_host_init(struct ata_host *host) +static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; - int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + struct pdc_host_priv *hp = pe->private_data; int hotplug_offset; u32 tmp; - if (is_gen2) + if (hp->flags & PDC_FLAG_GEN_II) hotplug_offset = PDC2_SATA_PLUG_CSR; else hotplug_offset = PDC_SATA_PLUG_CSR; @@ -884,7 +818,7 @@ static void pdc_host_init(struct ata_host *host) /* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */ tmp = readl(mmio + PDC_FLASH_CTL); tmp |= 0x02000; /* bit 13 (enable bmr burst) */ - if (!is_gen2) + if (!(hp->flags & PDC_FLAG_GEN_II)) tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */ writel(tmp, mmio + PDC_FLASH_CTL); @@ -897,7 +831,7 @@ static void pdc_host_init(struct ata_host *host) writel(tmp | 0xff0000, mmio + hotplug_offset); /* don't initialise TBG or SLEW on 2nd generation chips */ - if (is_gen2) + if (hp->flags & PDC_FLAG_GEN_II) return; /* reduce TBG clock to 133 Mhz. */ @@ -919,16 +853,16 @@ static void pdc_host_init(struct ata_host *host) static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - const struct ata_port_info *pi = &pdc_port_info[ent->driver_data]; - const struct ata_port_info *ppi[PDC_MAX_PORTS]; - struct ata_host *host; + struct ata_probe_ent *probe_ent; + struct pdc_host_priv *hp; void __iomem *base; - int n_ports, i, rc; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc; + u8 tmp; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* enable and acquire resources */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -938,49 +872,89 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e pcim_pin_device(pdev); if (rc) return rc; - base = pcim_iomap_table(pdev)[PDC_MMIO_BAR]; - /* determine port configuration and setup host */ - n_ports = 2; - if (pi->flags & PDC_FLAG_4_PORTS) - n_ports = 4; - for (i = 0; i < n_ports; i++) - ppi[i] = pi; + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - if (pi->flags & PDC_FLAG_SATA_PATA) { - u8 tmp = readb(base + PDC_FLASH_CTL+1); - if (!(tmp & 0x80)) { - ppi[n_ports++] = pi + 1; - dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n"); - } - } + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); - host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); - if (!host) { - dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); + hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL); + if (hp == NULL) return -ENOMEM; + + probe_ent->private_data = hp; + + probe_ent->sht = pdc_port_info[board_idx].sht; + probe_ent->port_flags = pdc_port_info[board_idx].flags; + probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; + probe_ent->port_ops = pdc_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + + base = probe_ent->iomap[PDC_MMIO_BAR]; + + pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400); + pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500); + + /* notice 4-port boards */ + switch (board_idx) { + case board_40518: + hp->flags |= PDC_FLAG_GEN_II; + /* Fall through */ + case board_20319: + probe_ent->n_ports = 4; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600); + pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700); + break; + case board_2057x: + hp->flags |= PDC_FLAG_GEN_II; + /* Fall through */ + case board_2037x: + /* TX2plus boards also have a PATA port */ + tmp = readb(base + PDC_FLASH_CTL+1); + if (!(tmp & 0x80)) { + probe_ent->n_ports = 3; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL); + hp->port_flags[2] = ATA_FLAG_SLAVE_POSS; + printk(KERN_INFO DRV_NAME " PATA port found\n"); + } else + probe_ent->n_ports = 2; + hp->port_flags[0] = ATA_FLAG_SATA; + hp->port_flags[1] = ATA_FLAG_SATA; + break; + case board_20619: + probe_ent->n_ports = 4; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL); + pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL); + break; + default: + BUG(); + break; } - host->iomap = pcim_iomap_table(pdev); - for (i = 0; i < host->n_ports; i++) - pdc_ata_setup_port(host->ports[i], - base + 0x200 + i * 0x80, - base + 0x400 + i * 0x100); + pci_set_master(pdev); /* initialize adapter */ - pdc_host_init(host); + pdc_host_init(board_idx, probe_ent); - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; + if (!ata_device_add(probe_ent)) + return -ENODEV; - /* start host, request IRQ and attach */ - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED, - &pdc_ata_sht); + devm_kfree(&pdev->dev, probe_ent); + return 0; } diff --git a/trunk/drivers/ata/sata_qstor.c b/trunk/drivers/ata/sata_qstor.c index f5a05de0093d..8786b45f291b 100644 --- a/trunk/drivers/ata/sata_qstor.c +++ b/trunk/drivers/ata/sata_qstor.c @@ -114,6 +114,7 @@ struct qs_port_priv { static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static irqreturn_t qs_intr (int irq, void *dev_instance); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); static void qs_phy_reset(struct ata_port *ap); @@ -157,6 +158,7 @@ static const struct ata_port_operations qs_ata_ops = { .qc_issue = qs_qc_issue, .data_xfer = ata_data_xfer, .eng_timeout = qs_eng_timeout, + .irq_handler = qs_intr, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -171,6 +173,7 @@ static const struct ata_port_operations qs_ata_ops = { static const struct ata_port_info qs_port_info[] = { /* board_2068_idx */ { + .sht = &qs_ata_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | //FIXME ATA_FLAG_SRST | @@ -527,16 +530,16 @@ static void qs_host_stop(struct ata_host *host) writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ } -static void qs_host_init(struct ata_host *host, unsigned int chip_id) +static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio_base = host->iomap[QS_MMIO_BAR]; + void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR]; unsigned int port_no; writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ /* reset each channel in turn */ - for (port_no = 0; port_no < host->n_ports; ++port_no) { + for (port_no = 0; port_no < pe->n_ports; ++port_no) { u8 __iomem *chan = mmio_base + (port_no * 0x4000); writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); @@ -544,7 +547,7 @@ static void qs_host_init(struct ata_host *host, unsigned int chip_id) } writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ - for (port_no = 0; port_no < host->n_ports; ++port_no) { + for (port_no = 0; port_no < pe->n_ports; ++port_no) { u8 __iomem *chan = mmio_base + (port_no * 0x4000); /* set FIFO depths to same settings as Windows driver */ writew(32, chan + QS_CFC_HUFT); @@ -604,20 +607,14 @@ static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; + struct ata_probe_ent *probe_ent; + void __iomem * const *iomap; unsigned int board_idx = (unsigned int) ent->driver_data; - const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL }; - struct ata_host *host; int rc, port_no; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* alloc host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -628,24 +625,47 @@ static int qs_ata_init_one(struct pci_dev *pdev, rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); + iomap = pcim_iomap_table(pdev); - rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]); + rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]); if (rc) return rc; - for (port_no = 0; port_no < host->n_ports; ++port_no) { + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = qs_port_info[board_idx].sht; + probe_ent->port_flags = qs_port_info[board_idx].flags; + probe_ent->pio_mask = qs_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = qs_port_info[board_idx].udma_mask; + probe_ent->port_ops = qs_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = iomap; + probe_ent->n_ports = QS_PORTS; + + for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { void __iomem *chan = - host->iomap[QS_MMIO_BAR] + (port_no * 0x4000); - qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan); + probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000); + qs_ata_setup_port(&probe_ent->port[port_no], chan); } + pci_set_master(pdev); + /* initialize adapter */ - qs_host_init(host, board_idx); + qs_host_init(board_idx, probe_ent); - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, - &qs_ata_sht); + if (ata_device_add(probe_ent) != QS_PORTS) + return -EIO; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init qs_ata_init(void) diff --git a/trunk/drivers/ata/sata_sil.c b/trunk/drivers/ata/sata_sil.c index 0a1e417f309c..917b7ea4ef7c 100644 --- a/trunk/drivers/ata/sata_sil.c +++ b/trunk/drivers/ata/sata_sil.c @@ -46,7 +46,7 @@ #include #define DRV_NAME "sata_sil" -#define DRV_VERSION "2.2" +#define DRV_VERSION "2.1" enum { SIL_MMIO_BAR = 5, @@ -114,10 +114,11 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); #ifdef CONFIG_PM static int sil_pci_device_resume(struct pci_dev *pdev); #endif -static void sil_dev_config(struct ata_device *dev); +static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); +static void sil_post_set_mode (struct ata_port *ap); +static irqreturn_t sil_interrupt(int irq, void *dev_instance); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -196,7 +197,7 @@ static const struct ata_port_operations sil_ops = { .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .set_mode = sil_set_mode, + .post_set_mode = sil_post_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, @@ -208,6 +209,7 @@ static const struct ata_port_operations sil_ops = { .thaw = sil_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = sil_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -219,6 +221,7 @@ static const struct ata_port_operations sil_ops = { static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { + .sht = &sil_sht, .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -227,6 +230,7 @@ static const struct ata_port_info sil_port_info[] = { }, /* sil_3112_no_sata_irq */ { + .sht = &sil_sht, .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, .pio_mask = 0x1f, /* pio0-4 */ @@ -236,6 +240,7 @@ static const struct ata_port_info sil_port_info[] = { }, /* sil_3512 */ { + .sht = &sil_sht, .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -244,6 +249,7 @@ static const struct ata_port_info sil_port_info[] = { }, /* sil_3114 */ { + .sht = &sil_sht, .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -291,16 +297,7 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev) return cache_line; } -/** - * sil_set_mode - wrap set_mode functions - * @ap: port to set up - * @r_failed: returned device when we fail - * - * Wrap the libata method for device setup as after the setup we need - * to inspect the results and do some configuration work - */ - -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) +static void sil_post_set_mode (struct ata_port *ap) { struct ata_host *host = ap->host; struct ata_device *dev; @@ -308,11 +305,6 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; u32 tmp, dev_mode[2]; unsigned int i; - int rc; - - rc = ata_do_set_mode(ap, r_failed); - if (rc) - return rc; for (i = 0; i < 2; i++) { dev = &ap->device[i]; @@ -331,7 +323,6 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) tmp |= (dev_mode[1] << 4); writel(tmp, addr); readl(addr); /* flush */ - return 0; } static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) @@ -530,6 +521,7 @@ static void sil_thaw(struct ata_port *ap) /** * sil_dev_config - Apply device/host-specific errata fixups + * @ap: Port containing device to be examined * @dev: Device to be examined * * After the IDENTIFY [PACKET] DEVICE step is complete, and a @@ -556,9 +548,8 @@ static void sil_thaw(struct ata_port *ap) * appreciated. * - But then again UDMA5 is hardly anything to complain about */ -static void sil_dev_config(struct ata_device *dev) +static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { - struct ata_port *ap = dev->ap; int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -592,10 +583,10 @@ static void sil_dev_config(struct ata_device *dev) } } -static void sil_init_controller(struct ata_host *host) +static void sil_init_controller(struct pci_dev *pdev, + int n_ports, unsigned long port_flags, + void __iomem *mmio_base) { - struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; u8 cls; u32 tmp; int i; @@ -605,7 +596,7 @@ static void sil_init_controller(struct ata_host *host) if (cls) { cls >>= 3; cls++; /* cls = (line_size/8)+1 */ - for (i = 0; i < host->n_ports; i++) + for (i = 0; i < n_ports; i++) writew(cls << 8 | cls, mmio_base + sil_port[i].fifo_cfg); } else @@ -613,10 +604,10 @@ static void sil_init_controller(struct ata_host *host) "cache line size not set. Driver may not function\n"); /* Apply R_ERR on DMA activate FIS errata workaround */ - if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) { + if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) { int cnt; - for (i = 0, cnt = 0; i < host->n_ports; i++) { + for (i = 0, cnt = 0; i < n_ports; i++) { tmp = readl(mmio_base + sil_port[i].sfis_cfg); if ((tmp & 0x3) != 0x01) continue; @@ -629,7 +620,7 @@ static void sil_init_controller(struct ata_host *host) } } - if (host->n_ports == 4) { + if (n_ports == 4) { /* flip the magic "make 4 ports work" bit */ tmp = readl(mmio_base + sil_port[2].bmdma); if ((tmp & SIL_INTR_STEERING) == 0) @@ -641,26 +632,15 @@ static void sil_init_controller(struct ata_host *host) static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - int board_id = ent->driver_data; - const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL }; - struct ata_host *host; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; - int n_ports, rc; + int rc; unsigned int i; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* allocate host */ - n_ports = 2; - if (board_id == sil_3114) - n_ports = 4; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); - if (!host) - return -ENOMEM; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -670,7 +650,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -679,25 +658,45 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - mmio_base = host->iomap[SIL_MMIO_BAR]; + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; - - ioaddr->cmd_addr = mmio_base + sil_port[i].tf; - ioaddr->altstatus_addr = - ioaddr->ctl_addr = mmio_base + sil_port[i].ctl; - ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; - ioaddr->scr_addr = mmio_base + sil_port[i].scr; - ata_std_ports(ioaddr); + INIT_LIST_HEAD(&probe_ent->node); + probe_ent->dev = pci_dev_to_dev(pdev); + probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops; + probe_ent->sht = sil_port_info[ent->driver_data].sht; + probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; + probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; + probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->port_flags = sil_port_info[ent->driver_data].flags; + + probe_ent->iomap = pcim_iomap_table(pdev); + + mmio_base = probe_ent->iomap[SIL_MMIO_BAR]; + + for (i = 0; i < probe_ent->n_ports; i++) { + probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf; + probe_ent->port[i].altstatus_addr = + probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl; + probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma; + probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr; + ata_std_ports(&probe_ent->port[i]); } - /* initialize and activate */ - sil_init_controller(host); + sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags, + mmio_base); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED, - &sil_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } #ifdef CONFIG_PM @@ -710,7 +709,8 @@ static int sil_pci_device_resume(struct pci_dev *pdev) if (rc) return rc; - sil_init_controller(host); + sil_init_controller(pdev, host->n_ports, host->ports[0]->flags, + host->iomap[SIL_MMIO_BAR]); ata_host_resume(host); return 0; diff --git a/trunk/drivers/ata/sata_sil24.c b/trunk/drivers/ata/sata_sil24.c index e6223ba667da..5614df8c1ce2 100644 --- a/trunk/drivers/ata/sata_sil24.c +++ b/trunk/drivers/ata/sata_sil24.c @@ -323,7 +323,7 @@ struct sil24_port_priv { struct ata_taskfile tf; /* Cached taskfile registers */ }; -static void sil24_dev_config(struct ata_device *dev); +static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev); static u8 sil24_check_status(struct ata_port *ap); static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); @@ -331,6 +331,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -400,6 +401,7 @@ static const struct ata_port_operations sil24_ops = { .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, + .irq_handler = sil24_interrupt, .irq_clear = sil24_irq_clear, .irq_on = ata_dummy_irq_on, .irq_ack = ata_dummy_irq_ack, @@ -422,9 +424,10 @@ static const struct ata_port_operations sil24_ops = { #define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) #define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) -static const struct ata_port_info sil24_port_info[] = { +static struct ata_port_info sil24_port_info[] = { /* sil_3124 */ { + .sht = &sil24_sht, .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | SIL24_FLAG_PCIX_IRQ_WOC, .pio_mask = 0x1f, /* pio0-4 */ @@ -434,6 +437,7 @@ static const struct ata_port_info sil24_port_info[] = { }, /* sil_3132 */ { + .sht = &sil24_sht, .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -442,6 +446,7 @@ static const struct ata_port_info sil24_port_info[] = { }, /* sil_3131/sil_3531 */ { + .sht = &sil24_sht, .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -457,9 +462,9 @@ static int sil24_tag(int tag) return tag; } -static void sil24_dev_config(struct ata_device *dev) +static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) { - void __iomem *port = dev->ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -919,8 +924,11 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - /* make DMA engine forget about the failed command */ if (qc->flags & ATA_QCFLAG_FAILED) + qc->err_mask |= AC_ERR_OTHER; + + /* make DMA engine forget about the failed command */ + if (qc->err_mask) sil24_init_port(ap); } @@ -956,10 +964,11 @@ static int sil24_port_start(struct ata_port *ap) return 0; } -static void sil24_init_controller(struct ata_host *host) +static void sil24_init_controller(struct pci_dev *pdev, int n_ports, + unsigned long port_flags, + void __iomem *host_base, + void __iomem *port_base) { - void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; - void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; u32 tmp; int i; @@ -970,7 +979,7 @@ static void sil24_init_controller(struct ata_host *host) writel(0, host_base + HOST_CTRL); /* init ports */ - for (i = 0; i < host->n_ports; i++) { + for (i = 0; i < n_ports; i++) { void __iomem *port = port_base + i * PORT_REGS_SIZE; /* Initial PHY setting */ @@ -984,12 +993,12 @@ static void sil24_init_controller(struct ata_host *host) PORT_CS_PORT_RST, PORT_CS_PORT_RST, 10, 100); if (tmp & PORT_CS_PORT_RST) - dev_printk(KERN_ERR, host->dev, + dev_printk(KERN_ERR, &pdev->dev, "failed to clear port RST\n"); } /* Configure IRQ WoC */ - if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) + if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC) writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); else writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); @@ -1017,17 +1026,18 @@ static void sil24_init_controller(struct ata_host *host) static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; - struct ata_port_info pi = sil24_port_info[ent->driver_data]; - const struct ata_port_info *ppi[] = { &pi, NULL }; - void __iomem * const *iomap; - struct ata_host *host; + struct device *dev = &pdev->dev; + unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_port_info *pinfo = &sil24_port_info[board_id]; + struct ata_probe_ent *probe_ent; + void __iomem *host_base; + void __iomem *port_base; int i, rc; u32 tmp; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* acquire resources */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -1037,36 +1047,33 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) DRV_NAME); if (rc) return rc; - iomap = pcim_iomap_table(pdev); - /* apply workaround for completion IRQ loss on PCI-X errata */ - if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) { - tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL); - if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL)) - dev_printk(KERN_INFO, &pdev->dev, - "Applying completion IRQ loss on PCI-X " - "errata fix\n"); - else - pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; - } - - /* allocate and fill host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, - SIL24_FLAG2NPORTS(ppi[0]->flags)); - if (!host) + /* allocate & init probe_ent */ + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) return -ENOMEM; - host->iomap = iomap; - for (i = 0; i < host->n_ports; i++) { - void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE; + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); - host->ports[i]->ioaddr.cmd_addr = port; - host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL; + probe_ent->sht = pinfo->sht; + probe_ent->port_flags = pinfo->flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->mwdma_mask = pinfo->mwdma_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags); - ata_std_ports(&host->ports[i]->ioaddr); - } + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); - /* configure and activate the device */ + host_base = probe_ent->iomap[SIL24_HOST_BAR]; + port_base = probe_ent->iomap[SIL24_PORT_BAR]; + + /* + * Configure the device + */ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (rc) { @@ -1092,11 +1099,36 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } } - sil24_init_controller(host); + /* Apply workaround for completion IRQ loss on PCI-X errata */ + if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) { + tmp = readl(host_base + HOST_CTRL); + if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL)) + dev_printk(KERN_INFO, &pdev->dev, + "Applying completion IRQ loss on PCI-X " + "errata fix\n"); + else + probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; + } + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *port = port_base + i * PORT_REGS_SIZE; + + probe_ent->port[i].cmd_addr = port; + probe_ent->port[i].scr_addr = port + PORT_SCONTROL; + + ata_std_ports(&probe_ent->port[i]); + } + + sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags, + host_base, port_base); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED, - &sil24_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } #ifdef CONFIG_PM @@ -1104,6 +1136,7 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; + void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; int rc; rc = ata_pci_device_do_resume(pdev); @@ -1113,7 +1146,8 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL); - sil24_init_controller(host); + sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags, + host_base, port_base); ata_host_resume(host); diff --git a/trunk/drivers/ata/sata_sis.c b/trunk/drivers/ata/sata_sis.c index d8ee062e82fc..a787f0d4a5ba 100644 --- a/trunk/drivers/ata/sata_sis.c +++ b/trunk/drivers/ata/sata_sis.c @@ -121,6 +121,7 @@ static const struct ata_port_operations sis_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -130,6 +131,7 @@ static const struct ata_port_operations sis_ops = { }; static struct ata_port_info sis_port_info = { + .sht = &sis_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, .mwdma_mask = 0x7, @@ -254,13 +256,12 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info pi = sis_port_info; - const struct ata_port_info *ppi[2] = { &pi, &pi }; - struct ata_host *host; + struct ata_probe_ent *probe_ent = NULL; + int rc; u32 genctl, val; + struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; u8 pmr; u8 port2_start = 0x20; - int rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); @@ -269,6 +270,19 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + pcim_pin_device(pdev); + return rc; + } + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) @@ -335,26 +349,30 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) break; } - rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host); - if (rc) - return rc; + probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + if (!probe_ent) + return -ENOMEM; - if (!(pi.flags & SIS_FLAG_CFGSCR)) { + if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) { void __iomem *mmio; - rc = pcim_iomap_regions(pdev, 1 << SIS_SCR_PCI_BAR, DRV_NAME); - if (rc) - return rc; - mmio = host->iomap[SIS_SCR_PCI_BAR]; + mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0); + if (!mmio) + return -ENOMEM; - host->ports[0]->ioaddr.scr_addr = mmio; - host->ports[1]->ioaddr.scr_addr = mmio + port2_start; + probe_ent->port[0].scr_addr = mmio; + probe_ent->port[1].scr_addr = mmio + port2_start; } pci_set_master(pdev); pci_intx(pdev, 1); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &sis_sht); + + if (!ata_device_add(probe_ent)) + return -EIO; + + devm_kfree(&pdev->dev, probe_ent); + return 0; + } static int __init sis_init(void) diff --git a/trunk/drivers/ata/sata_svw.c b/trunk/drivers/ata/sata_svw.c index cc07aac10e8c..b121195cc598 100644 --- a/trunk/drivers/ata/sata_svw.c +++ b/trunk/drivers/ata/sata_svw.c @@ -56,9 +56,7 @@ #define DRV_VERSION "2.1" enum { - /* ap->flags bits */ - K2_FLAG_SATA_8_PORTS = (1 << 24), - K2_FLAG_NO_ATAPI_DMA = (1 << 25), + K2_FLAG_NO_ATAPI_DMA = (1 << 29), /* Taskfile registers offsets */ K2_SATA_TF_CMD_OFFSET = 0x00, @@ -92,6 +90,17 @@ enum { board_svw8 = 1, }; +static const struct k2_board_info { + unsigned int n_ports; + unsigned long port_flags; +} k2_board_info[] = { + /* board_svw4 */ + { 4, K2_FLAG_NO_ATAPI_DMA }, + + /* board_svw8 */ + { 8, K2_FLAG_NO_ATAPI_DMA }, +}; + static u8 k2_stat_check_status(struct ata_port *ap); @@ -345,6 +354,7 @@ static const struct ata_port_operations k2_sata_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -353,28 +363,6 @@ static const struct ata_port_operations k2_sata_ops = { .port_start = ata_port_start, }; -static const struct ata_port_info k2_port_info[] = { - /* board_svw4 */ - { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &k2_sata_ops, - }, - /* board_svw8 */ - { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA | - K2_FLAG_SATA_8_PORTS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &k2_sata_ops, - }, -}; - static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; @@ -398,24 +386,17 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - const struct ata_port_info *ppi[] = - { &k2_port_info[ent->driver_data], NULL }; - struct ata_host *host; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; - int n_ports, i, rc; + const struct k2_board_info *board_info = + &k2_board_info[ent->driver_data]; + int rc; + int i; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* allocate host */ - n_ports = 4; - if (ppi[0]->flags & K2_FLAG_SATA_8_PORTS) - n_ports = 8; - - host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); - if (!host) - return -ENOMEM; - /* * If this driver happens to only be useful on Apple's K2, then * we should check that here as it has a normal Serverworks ID @@ -423,7 +404,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e rc = pcim_enable_device(pdev); if (rc) return rc; - /* * Check if we have resources mapped at all (second function may * have been disabled by firmware) @@ -437,15 +417,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - mmio_base = host->iomap[5]; - - /* different controllers have different number of ports - currently 4 or 8 */ - /* All ports are on the same function. Multi-function device is no - * longer available. This should not be seen in any system. */ - for (i = 0; i < host->n_ports; i++) - k2_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + i * K2_SATA_PORT_OFFSET); rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -454,6 +425,38 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e if (rc) return rc; + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = &k2_sata_sht; + probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | board_info->port_flags; + probe_ent->port_ops = &k2_sata_ops; + probe_ent->n_ports = 4; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + + /* We don't care much about the PIO/UDMA masks, but the core won't like us + * if we don't fill these + */ + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; + probe_ent->udma_mask = 0x7f; + + mmio_base = probe_ent->iomap[5]; + + /* different controllers have different number of ports - currently 4 or 8 */ + /* All ports are on the same function. Multi-function device is no + * longer available. This should not be seen in any system. */ + for (i = 0; i < board_info->n_ports; i++) + k2_sata_setup_port(&probe_ent->port[i], + mmio_base + i * K2_SATA_PORT_OFFSET); + /* Clear a magic bit in SCR1 according to Darwin, those help * some funky seagate drives (though so far, those were already * set by the firmware on the machines I had access to) @@ -466,8 +469,12 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &k2_sata_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; } /* 0x240 is device ID for Apple K2 device diff --git a/trunk/drivers/ata/sata_sx4.c b/trunk/drivers/ata/sata_sx4.c index 3a4f44559d0a..1a081c3a8c06 100644 --- a/trunk/drivers/ata/sata_sx4.c +++ b/trunk/drivers/ata/sata_sx4.c @@ -151,23 +151,24 @@ struct pdc_host_priv { static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); -static unsigned int pdc20621_dimm_init(struct ata_host *host); -static int pdc20621_detect_dimm(struct ata_host *host); -static unsigned int pdc20621_i2c_read(struct ata_host *host, +static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); +static int pdc20621_detect_dimm(struct ata_probe_ent *pe); +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata); -static int pdc20621_prog_dimm0(struct ata_host *host); -static unsigned int pdc20621_prog_dimm_global(struct ata_host *host); +static int pdc20621_prog_dimm0(struct ata_probe_ent *pe); +static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe); #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_host *host, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); #endif -static void pdc20621_put_to_dimm(struct ata_host *host, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); @@ -203,6 +204,7 @@ static const struct ata_port_operations pdc_20621_ops = { .qc_issue = pdc20621_qc_issue_prot, .data_xfer = ata_data_xfer, .eng_timeout = pdc_eng_timeout, + .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -212,6 +214,7 @@ static const struct ata_port_operations pdc_20621_ops = { static const struct ata_port_info pdc_port_info[] = { /* board_20621 */ { + .sht = &pdc_sata_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING, @@ -879,15 +882,15 @@ static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base) #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; u16 idx; u8 page_mask; long dist; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; - void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -934,15 +937,15 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, #endif -static void pdc20621_put_to_dimm(struct ata_host *host, void *psource, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; u16 idx; u8 page_mask; long dist; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; - void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -984,10 +987,10 @@ static void pdc20621_put_to_dimm(struct ata_host *host, void *psource, } -static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device, +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata) { - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; u32 i2creg = 0; u32 status; u32 count =0; @@ -1020,17 +1023,17 @@ static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device, } -static int pdc20621_detect_dimm(struct ata_host *host) +static int pdc20621_detect_dimm(struct ata_probe_ent *pe) { u32 data=0 ; - if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { if (data == 100) return 100; } else return 0; - if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { if(data <= 0x75) return 133; } else @@ -1040,13 +1043,13 @@ static int pdc20621_detect_dimm(struct ata_host *host) } -static int pdc20621_prog_dimm0(struct ata_host *host) +static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) { u32 spd0[50]; u32 data = 0; int size, i; u8 bdimmsize; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; static const struct { unsigned int reg; unsigned int ofs; @@ -1069,7 +1072,7 @@ static int pdc20621_prog_dimm0(struct ata_host *host) mmio += PDC_CHIP0_OFS; for(i=0; iiomap[PDC_MMIO_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1126,7 +1129,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host) readl(mmio + PDC_SDRAM_CONTROL_OFFSET); /* Turn on for ECC */ - pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { data |= (0x01 << 16); @@ -1153,7 +1156,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host) } -static unsigned int pdc20621_dimm_init(struct ata_host *host) +static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) { int speed, size, length; u32 addr,spd0,pci_status; @@ -1163,7 +1166,7 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) u32 ticks=0; u32 clock=0; u32 fparam=0; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1222,18 +1225,18 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) Read SPD of DIMM by I2C interface, and program the DIMM Module Controller. */ - if (!(speed = pdc20621_detect_dimm(host))) { + if (!(speed = pdc20621_detect_dimm(pe))) { printk(KERN_ERR "Detect Local DIMM Fail\n"); return 1; /* DIMM error */ } VPRINTK("Local DIMM Speed = %d\n", speed); /* Programming DIMM0 Module Control Register (index_CID0:80h) */ - size = pdc20621_prog_dimm0(host); + size = pdc20621_prog_dimm0(pe); VPRINTK("Local DIMM Size = %dMB\n",size); /* Programming DIMM Module Global Control Register (index_CID0:88h) */ - if (pdc20621_prog_dimm_global(host)) { + if (pdc20621_prog_dimm_global(pe)) { printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n"); return 1; } @@ -1246,20 +1249,20 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) '9','8','0','3','1','6','1','2',0,0}; u8 test_parttern2[40] = {0}; - pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x10040, 40); - pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x40, 40); + pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40); + pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40); - pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40); - pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40); + pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40); + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); - pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x10040, + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); - pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40); - pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40); + pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40); + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); } @@ -1267,14 +1270,14 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) /* ECC initiliazation. */ - pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { VPRINTK("Start ECC initialization\n"); addr = 0; length = size * 1024 * 1024; while (addr < length) { - pdc20621_put_to_dimm(host, (void *) &tmp, addr, + pdc20621_put_to_dimm(pe, (void *) &tmp, addr, sizeof(u32)); addr += sizeof(u32); } @@ -1284,10 +1287,10 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) } -static void pdc_20621_init(struct ata_host *host) +static void pdc_20621_init(struct ata_probe_ent *pe) { u32 tmp; - void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1318,25 +1321,15 @@ static void pdc_20621_init(struct ata_host *host) static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - const struct ata_port_info *ppi[] = - { &pdc_port_info[ent->driver_data], NULL }; - struct ata_host *host; + struct ata_probe_ent *probe_ent; void __iomem *base; struct pdc_host_priv *hpriv; + unsigned int board_idx = (unsigned int) ent->driver_data; int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* allocate host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4); - hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); - if (!host || !hpriv) - return -ENOMEM; - - host->private_data = hpriv; - - /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; @@ -1347,15 +1340,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - - base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; - pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200); - pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280); - pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300); - pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380); - /* configure and activate */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; @@ -1363,13 +1348,50 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * if (rc) return rc; - if (pdc20621_dimm_init(host)) + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) return -ENOMEM; - pdc_20621_init(host); + + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + probe_ent->sht = pdc_port_info[board_idx].sht; + probe_ent->port_flags = pdc_port_info[board_idx].flags; + probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; + probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; + probe_ent->port_ops = pdc_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + + probe_ent->private_data = hpriv; + base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; + + probe_ent->n_ports = 4; + pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); + pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, pdc20621_interrupt, - IRQF_SHARED, &pdc_sata_sht); + + /* initialize adapter */ + /* initialize local dimm */ + if (pdc20621_dimm_init(probe_ent)) + return -ENOMEM; + pdc_20621_init(probe_ent); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } diff --git a/trunk/drivers/ata/sata_uli.c b/trunk/drivers/ata/sata_uli.c index f74e383de083..d659ace80f4f 100644 --- a/trunk/drivers/ata/sata_uli.c +++ b/trunk/drivers/ata/sata_uli.c @@ -115,6 +115,7 @@ static const struct ata_port_operations uli_ops = { .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -126,6 +127,7 @@ static const struct ata_port_operations uli_ops = { }; static struct ata_port_info uli_port_info = { + .sht = &uli_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_IGN_SIMPLEX, .pio_mask = 0x1f, /* pio0-4 */ @@ -183,13 +185,12 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - const struct ata_port_info *ppi[] = { &uli_port_info, NULL }; + struct ata_probe_ent *probe_ent; + struct ata_port_info *ppi[2]; + int rc; unsigned int board_idx = (unsigned int) ent->driver_data; - struct ata_host *host; struct uli_priv *hpriv; void __iomem * const *iomap; - struct ata_ioports *ioaddr; - int n_ports, rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); @@ -198,42 +199,54 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - n_ports = 2; - if (board_idx == uli_5287) - n_ports = 4; - rc = ata_pci_prepare_native_host(pdev, ppi, n_ports, &host); + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + pcim_pin_device(pdev); + return rc; + } + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; + ppi[0] = ppi[1] = &uli_port_info; + probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + if (!probe_ent) + return -ENOMEM; + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - host->private_data = hpriv; - iomap = host->iomap; + probe_ent->private_data = hpriv; + + iomap = pcim_iomap_table(pdev); switch (board_idx) { case uli_5287: hpriv->scr_cfg_addr[0] = ULI5287_BASE; hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; + probe_ent->n_ports = 4; - ioaddr = &host->ports[2]->ioaddr; - ioaddr->cmd_addr = iomap[0] + 8; - ioaddr->altstatus_addr = - ioaddr->ctl_addr = (void __iomem *) + probe_ent->port[2].cmd_addr = iomap[0] + 8; + probe_ent->port[2].altstatus_addr = + probe_ent->port[2].ctl_addr = (void __iomem *) ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4; - ioaddr->bmdma_addr = iomap[4] + 16; + probe_ent->port[2].bmdma_addr = iomap[4] + 16; hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; - ata_std_ports(ioaddr); - ioaddr = &host->ports[3]->ioaddr; - ioaddr->cmd_addr = iomap[2] + 8; - ioaddr->altstatus_addr = - ioaddr->ctl_addr = (void __iomem *) + probe_ent->port[3].cmd_addr = iomap[2] + 8; + probe_ent->port[3].altstatus_addr = + probe_ent->port[3].ctl_addr = (void __iomem *) ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4; - ioaddr->bmdma_addr = iomap[4] + 24; + probe_ent->port[3].bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; - ata_std_ports(ioaddr); + + ata_std_ports(&probe_ent->port[2]); + ata_std_ports(&probe_ent->port[3]); break; case uli_5289: @@ -253,8 +266,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); pci_intx(pdev, 1); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &uli_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init uli_init(void) diff --git a/trunk/drivers/ata/sata_via.c b/trunk/drivers/ata/sata_via.c index 1d855f55f5f7..598e6a26a481 100644 --- a/trunk/drivers/ata/sata_via.c +++ b/trunk/drivers/ata/sata_via.c @@ -64,6 +64,8 @@ enum { PORT0 = (1 << 1), PORT1 = (1 << 0), ALL_PORTS = PORT0 | PORT1, + PATA_PORT = 2, /* PATA is port 2 */ + N_PORTS = 3, NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), @@ -76,9 +78,11 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void svia_noop_freeze(struct ata_port *ap); static void vt6420_error_handler(struct ata_port *ap); -static int vt6421_pata_cable_detect(struct ata_port *ap); +static void vt6421_sata_error_handler(struct ata_port *ap); +static void vt6421_pata_error_handler(struct ata_port *ap); static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); +static int vt6421_port_start(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { { PCI_VDEVICE(VIA, 0x5337), vt6420 }, @@ -137,6 +141,7 @@ static const struct ata_port_operations vt6420_sata_ops = { .error_handler = vt6420_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -167,15 +172,15 @@ static const struct ata_port_operations vt6421_pata_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = vt6421_pata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = vt6421_pata_cable_detect, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, - .port_start = ata_port_start, + .port_start = vt6421_port_start, }; static const struct ata_port_operations vt6421_sata_ops = { @@ -198,10 +203,10 @@ static const struct ata_port_operations vt6421_sata_ops = { .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = vt6421_sata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_sata, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -209,10 +214,11 @@ static const struct ata_port_operations vt6421_sata_ops = { .scr_read = svia_scr_read, .scr_write = svia_scr_write, - .port_start = ata_port_start, + .port_start = vt6421_port_start, }; -static const struct ata_port_info vt6420_port_info = { +static struct ata_port_info vt6420_port_info = { + .sht = &svia_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -220,22 +226,6 @@ static const struct ata_port_info vt6420_port_info = { .port_ops = &vt6420_sata_ops, }; -static struct ata_port_info vt6421_sport_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &vt6421_sata_ops, -}; - -static struct ata_port_info vt6421_pport_info = { - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY, - .pio_mask = 0x1f, - .mwdma_mask = 0, - .udma_mask = 0x7f, - .port_ops = &vt6421_pata_ops, -}; - MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); MODULE_LICENSE("GPL"); @@ -340,15 +330,35 @@ static void vt6420_error_handler(struct ata_port *ap) NULL, ata_std_postreset); } -static int vt6421_pata_cable_detect(struct ata_port *ap) +static int vt6421_pata_prereset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 tmp; pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp); if (tmp & 0x10) - return ATA_CBL_PATA40; - return ATA_CBL_PATA80; + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + return 0; +} + +static void vt6421_pata_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset, + NULL, ata_std_postreset); +} + +static int vt6421_sata_prereset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_SATA; + return 0; +} + +static void vt6421_sata_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset, + NULL, ata_std_postreset); } static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev) @@ -365,6 +375,16 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]); } +static int vt6421_port_start(struct ata_port *ap) +{ + if (ap->port_no == PATA_PORT) { + ap->ops = &vt6421_pata_ops; + ap->mwdma_mask = 0; + ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST; + } + return ata_port_start(ap); +} + static const unsigned int svia_bar_sizes[] = { 8, 4, 8, 4, 16, 256 }; @@ -383,78 +403,79 @@ static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port) return addr + (port * 64); } -static void vt6421_init_addrs(struct ata_port *ap) +static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, + void __iomem * const *iomap, unsigned int port) { - void __iomem * const * iomap = ap->host->iomap; - void __iomem *reg_addr = iomap[ap->port_no]; - void __iomem *bmdma_addr = iomap[4] + (ap->port_no * 8); - struct ata_ioports *ioaddr = &ap->ioaddr; - - ioaddr->cmd_addr = reg_addr; - ioaddr->altstatus_addr = - ioaddr->ctl_addr = (void __iomem *) + void __iomem *reg_addr = iomap[port]; + void __iomem *bmdma_addr = iomap[4] + (port * 8); + + probe_ent->port[port].cmd_addr = reg_addr; + probe_ent->port[port].altstatus_addr = + probe_ent->port[port].ctl_addr = (void __iomem *) ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS); - ioaddr->bmdma_addr = bmdma_addr; - ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); + probe_ent->port[port].bmdma_addr = bmdma_addr; + probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port); - ata_std_ports(ioaddr); + ata_std_ports(&probe_ent->port[port]); } -static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) +static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) { - const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL }; - struct ata_host *host; - int rc; + struct ata_probe_ent *probe_ent; + struct ata_port_info *ppi[2]; + void __iomem *bar5; - rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host); - if (rc) - return rc; - *r_host = host; + ppi[0] = ppi[1] = &vt6420_port_info; + probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + if (!probe_ent) + return NULL; - rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); - if (rc) { + bar5 = pcim_iomap(pdev, 5, 0); + if (!bar5) { dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); - return rc; + return NULL; } - host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0); - host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1); + probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0); + probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1); - return 0; + return probe_ent; } -static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) +static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) { - const struct ata_port_info *ppi[] = - { &vt6421_sport_info, &vt6421_sport_info, &vt6421_pport_info }; - struct ata_host *host; - int i, rc; - - *r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi)); - if (!host) { - dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n"); - return -ENOMEM; - } - - rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap " - "PCI BARs (errno=%d)\n", rc); - return rc; - } - host->iomap = pcim_iomap_table(pdev); + struct ata_probe_ent *probe_ent; + unsigned int i; - for (i = 0; i < host->n_ports; i++) - vt6421_init_addrs(host->ports[i]); + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return NULL; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = &svia_sht; + probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &vt6421_sata_ops; + probe_ent->n_ports = N_PORTS; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; + probe_ent->udma_mask = 0x7f; + + for (i = 0; i < 6; i++) + if (!pcim_iomap(pdev, i, 0)) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to iomap PCI BAR %d\n", i); + return NULL; + } - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - return rc; + for (i = 0; i < N_PORTS; i++) + vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i); - return 0; + return probe_ent; } static void svia_configure(struct pci_dev *pdev) @@ -501,7 +522,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; unsigned int i; int rc; - struct ata_host *host; + struct ata_probe_ent *probe_ent; int board_id = (int) ent->driver_data; const int *bar_sizes; u8 tmp8; @@ -513,6 +534,12 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) { + pcim_pin_device(pdev); + return rc; + } + if (board_id == vt6420) { pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); if (tmp8 & SATA_2DEV) { @@ -538,18 +565,32 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } - if (board_id == vt6420) - rc = vt6420_prepare_host(pdev, &host); - else - rc = vt6421_prepare_host(pdev, &host); + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; + if (board_id == vt6420) + probe_ent = vt6420_init_probe_ent(pdev); + else + probe_ent = vt6421_init_probe_ent(pdev); + + if (!probe_ent) { + dev_printk(KERN_ERR, &pdev->dev, "out of memory\n"); + return -ENOMEM; + } + svia_configure(pdev); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, - &svia_sht); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init svia_init(void) diff --git a/trunk/drivers/ata/sata_vsc.c b/trunk/drivers/ata/sata_vsc.c index 80126f835d32..170bad1b415b 100644 --- a/trunk/drivers/ata/sata_vsc.c +++ b/trunk/drivers/ata/sata_vsc.c @@ -333,6 +333,7 @@ static const struct ata_port_operations vsc_sata_ops = { .thaw = vsc_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = vsc_sata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -366,50 +367,30 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port, static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static const struct ata_port_info pi = { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - .port_ops = &vsc_sata_ops, - }; - const struct ata_port_info *ppi[] = { &pi, NULL }; static int printed_version; - struct ata_host *host; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; - int i, rc; + int rc; u8 cls; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* allocate host */ - host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4); - if (!host) - return -ENOMEM; - rc = pcim_enable_device(pdev); if (rc) return rc; - /* check if we have needed resource mapped */ + /* + * Check if we have needed resource mapped. + */ if (pci_resource_len(pdev, 0) == 0) return -ENODEV; - /* map IO regions and intialize host accordingly */ rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) return rc; - host->iomap = pcim_iomap_table(pdev); - - mmio_base = host->iomap[VSC_MMIO_BAR]; - - for (i = 0; i < host->n_ports; i++) - vsc_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET); /* * Use 32 bit DMA mask, because 64 bit address support is poor. @@ -421,6 +402,12 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d if (rc) return rc; + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + /* * Due to a bug in the chip, the default cache line size can't be * used (unless the default is non-zero). @@ -431,6 +418,33 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d if (pci_enable_msi(pdev) == 0) pci_intx(pdev, 0); + else + probe_ent->irq_flags = IRQF_SHARED; + + probe_ent->sht = &vsc_sata_sht; + probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO; + probe_ent->port_ops = &vsc_sata_ops; + probe_ent->n_ports = 4; + probe_ent->irq = pdev->irq; + probe_ent->iomap = pcim_iomap_table(pdev); + + /* We don't care much about the PIO/UDMA masks, but the core won't like us + * if we don't fill these + */ + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; + probe_ent->udma_mask = 0x7f; + + mmio_base = probe_ent->iomap[VSC_MMIO_BAR]; + + /* We have 4 ports per PCI function */ + vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET); + + pci_set_master(pdev); /* * Config offset 0x98 is "Extended Control and Status Register 0" @@ -440,9 +454,11 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d */ pci_write_config_dword(pdev, 0x98, 0); - pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, vsc_sata_interrupt, - IRQF_SHARED, &vsc_sata_sht); + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + return 0; } static const struct pci_device_id vsc_sata_pci_tbl[] = { diff --git a/trunk/drivers/atm/adummy.c b/trunk/drivers/atm/adummy.c index 2ebd07f2ef81..8d60c4eb54fe 100644 --- a/trunk/drivers/atm/adummy.c +++ b/trunk/drivers/atm/adummy.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/atm/ambassador.c b/trunk/drivers/atm/ambassador.c index 59651abfa4f8..3c372e08f77d 100644 --- a/trunk/drivers/atm/ambassador.c +++ b/trunk/drivers/atm/ambassador.c @@ -821,7 +821,7 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, } // cast needed as there is no %? for pointer differences PRINTD (DBG_SKB, "allocated skb at %p, head %p, area %li", - skb, skb->head, (long) (skb_end_pointer(skb) - skb->head)); + skb, skb->head, (long) (skb->end - skb->head)); rx.handle = virt_to_bus (skb); rx.host_address = cpu_to_be32 (virt_to_bus (skb->data)); if (rx_give (dev, &rx, pool)) diff --git a/trunk/drivers/atm/atmtcp.c b/trunk/drivers/atm/atmtcp.c index 02ad83d6b562..fc518d85543d 100644 --- a/trunk/drivers/atm/atmtcp.c +++ b/trunk/drivers/atm/atmtcp.c @@ -221,7 +221,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) hdr->vpi = htons(vcc->vpi); hdr->vci = htons(vcc->vci); hdr->length = htonl(skb->len); - skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len); + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); @@ -310,7 +310,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) goto done; } __net_timestamp(new_skb); - skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len); + memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); out_vcc->push(out_vcc,new_skb); atomic_inc(&vcc->stats->tx); atomic_inc(&out_vcc->stats->rx); @@ -352,7 +352,7 @@ static struct atm_dev atmtcp_control_dev = { .ops = &atmtcp_c_dev_ops, .type = "atmtcp", .number = 999, - .lock = __SPIN_LOCK_UNLOCKED(atmtcp_control_dev.lock) + .lock = SPIN_LOCK_UNLOCKED }; diff --git a/trunk/drivers/atm/eni.c b/trunk/drivers/atm/eni.c index 0d3a38b1cb0b..8fccf018f165 100644 --- a/trunk/drivers/atm/eni.c +++ b/trunk/drivers/atm/eni.c @@ -536,7 +536,7 @@ static int rx_aal0(struct atm_vcc *vcc) return 0; } skb_put(skb,length); - skb->tstamp = eni_vcc->timestamp; + skb_set_timestamp(skb, &eni_vcc->timestamp); DPRINTK("got len %ld\n",length); if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1; eni_vcc->rxing++; @@ -701,7 +701,7 @@ static void get_service(struct atm_dev *dev) DPRINTK("Grr, servicing VCC %ld twice\n",vci); continue; } - ENI_VCC(vcc)->timestamp = ktime_get_real(); + do_gettimeofday(&ENI_VCC(vcc)->timestamp); ENI_VCC(vcc)->next = NULL; if (vcc->qos.rxtp.traffic_class == ATM_CBR) { if (eni_dev->fast) diff --git a/trunk/drivers/atm/eni.h b/trunk/drivers/atm/eni.h index d04fefb0841f..385090c2a580 100644 --- a/trunk/drivers/atm/eni.h +++ b/trunk/drivers/atm/eni.h @@ -59,7 +59,7 @@ struct eni_vcc { int rxing; /* number of pending PDUs */ int servicing; /* number of waiting VCs (0 or 1) */ int txing; /* number of pending TX bytes */ - ktime_t timestamp; /* for RX timing */ + struct timeval timestamp; /* for RX timing */ struct atm_vcc *next; /* next pending RX */ struct sk_buff *last; /* last PDU being DMAed (used to carry discard information) */ diff --git a/trunk/drivers/atm/fore200e.c b/trunk/drivers/atm/fore200e.c index 405ee5e09221..a7c0ed3107e3 100644 --- a/trunk/drivers/atm/fore200e.c +++ b/trunk/drivers/atm/fore200e.c @@ -1,4 +1,6 @@ /* + $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ + A FORE Systems 200E-series driver for ATM on Linux. Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003. @@ -1500,9 +1502,9 @@ fore200e_open(struct atm_vcc *vcc) /* pseudo-CBR bandwidth requested? */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { - mutex_lock(&fore200e->rate_mtx); + down(&fore200e->rate_sf); if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { - mutex_unlock(&fore200e->rate_mtx); + up(&fore200e->rate_sf); kfree(fore200e_vcc); vc_map->vcc = NULL; @@ -1511,7 +1513,7 @@ fore200e_open(struct atm_vcc *vcc) /* reserve bandwidth */ fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); + up(&fore200e->rate_sf); } vcc->itf = vcc->dev->number; @@ -1597,9 +1599,9 @@ fore200e_close(struct atm_vcc* vcc) /* release reserved bandwidth, if any */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { - mutex_lock(&fore200e->rate_mtx); + down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); + up(&fore200e->rate_sf); clear_bit(ATM_VF_HASQOS, &vcc->flags); } @@ -2062,16 +2064,16 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { - mutex_lock(&fore200e->rate_mtx); + down(&fore200e->rate_sf); if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { - mutex_unlock(&fore200e->rate_mtx); + up(&fore200e->rate_sf); return -EAGAIN; } fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate -= qos->txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); + up(&fore200e->rate_sf); memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); @@ -2457,7 +2459,7 @@ fore200e_initialize(struct fore200e* fore200e) DPRINTK(2, "device %s being initialized\n", fore200e->name); - mutex_init(&fore200e->rate_mtx); + init_MUTEX(&fore200e->rate_sf); spin_lock_init(&fore200e->q_lock); cpq = fore200e->cp_queues = fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET; diff --git a/trunk/drivers/atm/fore200e.h b/trunk/drivers/atm/fore200e.h index b85a54613dea..f9abfdac33e4 100644 --- a/trunk/drivers/atm/fore200e.h +++ b/trunk/drivers/atm/fore200e.h @@ -869,7 +869,7 @@ typedef struct fore200e { struct stats* stats; /* last snapshot of the stats */ - struct mutex rate_mtx; /* protects rate reservation ops */ + struct semaphore rate_sf; /* protects rate reservation ops */ spinlock_t q_lock; /* protects queue ops */ #ifdef FORE200E_USE_TASKLET struct tasklet_struct tx_tasklet; /* performs tx interrupt work */ diff --git a/trunk/drivers/atm/he.c b/trunk/drivers/atm/he.c index d33aba6864c2..8510026b690a 100644 --- a/trunk/drivers/atm/he.c +++ b/trunk/drivers/atm/he.c @@ -1901,13 +1901,13 @@ he_service_rbrq(struct he_dev *he_dev, int group) case ATM_AAL0: /* 2.10.1.5 raw cell receive */ skb->len = ATM_AAL0_SDU; - skb_set_tail_pointer(skb, skb->len); + skb->tail = skb->data + skb->len; break; case ATM_AAL5: /* 2.10.1.2 aal5 receive */ skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); - skb_set_tail_pointer(skb, skb->len); + skb->tail = skb->data + skb->len; #ifdef USE_CHECKSUM_HW if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { skb->ip_summed = CHECKSUM_COMPLETE; diff --git a/trunk/drivers/atm/idt77252.c b/trunk/drivers/atm/idt77252.c index 057efbc55d38..b4b80140c398 100644 --- a/trunk/drivers/atm/idt77252.c +++ b/trunk/drivers/atm/idt77252.c @@ -1065,8 +1065,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) vcc = vc->rx_vcc; pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + skb->end - skb->data, PCI_DMA_FROMDEVICE); if ((vcc->qos.aal == ATM_AAL0) || (vcc->qos.aal == ATM_AAL34)) { @@ -1195,8 +1194,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) } pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + skb->end - skb->data, PCI_DMA_FROMDEVICE); sb_pool_remove(card, skb); skb_trim(skb, len); @@ -1269,7 +1267,7 @@ idt77252_rx_raw(struct idt77252_dev *card) tail = readl(SAR_REG_RAWCT); pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue), - skb_end_pointer(queue) - queue->head - 16, + queue->end - queue->head - 16, PCI_DMA_FROMDEVICE); while (head != tail) { @@ -1365,8 +1363,7 @@ idt77252_rx_raw(struct idt77252_dev *card) queue = card->raw_cell_head; pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue), - (skb_end_pointer(queue) - - queue->data), + queue->end - queue->data, PCI_DMA_FROMDEVICE); } else { card->raw_cell_head = NULL; @@ -1819,8 +1816,7 @@ push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue) u32 handle; u32 addr; - skb->data = skb->head; - skb_reset_tail_pointer(skb); + skb->data = skb->tail = skb->head; skb->len = 0; skb_reserve(skb, 16); @@ -1839,6 +1835,7 @@ push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue) skb_put(skb, SAR_FB_SIZE_3); break; default: + dev_kfree_skb(skb); return -1; } @@ -1877,7 +1874,7 @@ add_rx_skb(struct idt77252_dev *card, int queue, } paddr = pci_map_single(card->pcidev, skb->data, - skb_end_pointer(skb) - skb->data, + skb->end - skb->data, PCI_DMA_FROMDEVICE); IDT77252_PRV_PADDR(skb) = paddr; @@ -1891,7 +1888,7 @@ add_rx_skb(struct idt77252_dev *card, int queue, outunmap: pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, PCI_DMA_FROMDEVICE); + skb->end - skb->data, PCI_DMA_FROMDEVICE); handle = IDT77252_PRV_POOL(skb); card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL; @@ -1908,14 +1905,12 @@ recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb) int err; pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + skb->end - skb->data, PCI_DMA_FROMDEVICE); err = push_rx_skb(card, skb, POOL_QUEUE(handle)); if (err) { pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + skb->end - skb->data, PCI_DMA_FROMDEVICE); sb_pool_remove(card, skb); dev_kfree_skb(skb); } @@ -3127,8 +3122,7 @@ deinit_card(struct idt77252_dev *card) if (skb) { pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - (skb_end_pointer(skb) - - skb->data), + skb->end - skb->data, PCI_DMA_FROMDEVICE); card->sbpool[i].skb[j] = NULL; dev_kfree_skb(skb); diff --git a/trunk/drivers/atm/nicstar.c b/trunk/drivers/atm/nicstar.c index 14ced85b3f54..aab9b3733d52 100644 --- a/trunk/drivers/atm/nicstar.c +++ b/trunk/drivers/atm/nicstar.c @@ -2208,7 +2208,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) if (i == 1 && ns_rsqe_eopdu(rsqe)) *((u32 *) sb->data) |= 0x00000002; skb_put(sb, NS_AAL0_HEADER); - memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD); + memcpy(sb->tail, cell, ATM_CELL_PAYLOAD); skb_put(sb, ATM_CELL_PAYLOAD); ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); @@ -2252,8 +2252,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) vc->rx_iov = iovb; NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; - iovb->data = iovb->head; - skb_reset_tail_pointer(iovb); + iovb->tail = iovb->data = iovb->head; NS_SKB(iovb)->vcc = vcc; /* IMPORTANT: a pointer to the sk_buff containing the small or large buffer is stored as iovec base, NOT a pointer to the @@ -2266,8 +2265,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; - iovb->data = iovb->head; - skb_reset_tail_pointer(iovb); + iovb->tail = iovb->data = iovb->head; NS_SKB(iovb)->vcc = vcc; } iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++]; @@ -2395,7 +2393,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) skb->destructor = ns_lb_destructor; #endif /* NS_USE_DESTRUCTORS */ skb_push(skb, NS_SMBUFSIZE); - skb_copy_from_linear_data(sb, skb->data, NS_SMBUFSIZE); + memcpy(skb->data, sb->data, NS_SMBUFSIZE); skb_put(skb, len - NS_SMBUFSIZE); ATM_SKB(skb)->vcc = vcc; __net_timestamp(skb); @@ -2479,7 +2477,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) { /* Copy the small buffer to the huge buffer */ sb = (struct sk_buff *) iov->iov_base; - skb_copy_from_linear_data(sb, hb->data, iov->iov_len); + memcpy(hb->data, sb->data, iov->iov_len); skb_put(hb, iov->iov_len); remaining = len - iov->iov_len; iov++; @@ -2491,7 +2489,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) { lb = (struct sk_buff *) iov->iov_base; tocopy = min_t(int, remaining, iov->iov_len); - skb_copy_from_linear_data(lb, skb_tail_pointer(hb), tocopy); + memcpy(hb->tail, lb->data, tocopy); skb_put(hb, tocopy); iov++; remaining -= tocopy; diff --git a/trunk/drivers/base/attribute_container.c b/trunk/drivers/base/attribute_container.c index 1ec0654665cf..22220733f76f 100644 --- a/trunk/drivers/base/attribute_container.c +++ b/trunk/drivers/base/attribute_container.c @@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); static struct list_head attribute_container_list; -static DEFINE_MUTEX(attribute_container_mutex); +static DECLARE_MUTEX(attribute_container_mutex); /** * attribute_container_register - register an attribute container @@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont) klist_init(&cont->containers,internal_container_klist_get, internal_container_klist_put); - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); list_add_tail(&cont->node, &attribute_container_list); - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); return 0; } @@ -94,7 +94,7 @@ int attribute_container_unregister(struct attribute_container *cont) { int retval = -EBUSY; - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); spin_lock(&cont->containers.k_lock); if (!list_empty(&cont->containers.k_list)) goto out; @@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont) list_del(&cont->node); out: spin_unlock(&cont->containers.k_lock); - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); return retval; } @@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev, { struct attribute_container *cont; - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { struct internal_container *ic; @@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev, attribute_container_add_class_device(&ic->classdev); klist_add_tail(&ic->node, &cont->containers); } - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); } /* FIXME: can't break out of this unless klist_iter_exit is also @@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev, { struct attribute_container *cont; - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { struct internal_container *ic; struct klist_iter iter; @@ -234,7 +234,7 @@ attribute_container_remove_device(struct device *dev, } } } - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); } /** @@ -255,7 +255,7 @@ attribute_container_device_trigger(struct device *dev, { struct attribute_container *cont; - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { struct internal_container *ic; struct klist_iter iter; @@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev, fn(cont, dev, &ic->classdev); } } - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); } /** @@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev, { struct attribute_container *cont; - mutex_lock(&attribute_container_mutex); + down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { if (cont->match(cont, dev)) fn(cont, dev); } - mutex_unlock(&attribute_container_mutex); + up(&attribute_container_mutex); } /** diff --git a/trunk/drivers/base/base.h b/trunk/drivers/base/base.h index 5512d84452f2..de7e1442ce60 100644 --- a/trunk/drivers/base/base.h +++ b/trunk/drivers/base/base.h @@ -16,7 +16,7 @@ extern int cpu_dev_init(void); extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); -extern void bus_attach_device(struct device * dev); +extern int bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); extern struct bus_type *get_bus(struct bus_type * bus); extern void put_bus(struct bus_type * bus); @@ -45,5 +45,3 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) extern char *make_class_name(const char *name, struct kobject *kobj); extern void devres_release_all(struct device *dev); - -extern struct kset devices_subsys; diff --git a/trunk/drivers/base/bus.c b/trunk/drivers/base/bus.c index dca734819e50..253868e03c70 100644 --- a/trunk/drivers/base/bus.c +++ b/trunk/drivers/base/bus.c @@ -17,7 +17,7 @@ #include "power/power.h" #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) -#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj) +#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj) /* * sysfs bindings for drivers @@ -27,9 +27,6 @@ #define to_driver(obj) container_of(obj, struct device_driver, kobj) -static int __must_check bus_rescan_devices_helper(struct device *dev, - void *data); - static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -63,19 +60,8 @@ static struct sysfs_ops driver_sysfs_ops = { static void driver_release(struct kobject * kobj) { - /* - * Yes this is an empty release function, it is this way because struct - * device is always a static object, not a dynamic one. Yes, this is - * not nice and bad, but remember, drivers are code, reference counted - * by the module count, not a device, which is really data. And yes, - * in the future I do want to have all drivers be created dynamically, - * and am working toward that goal, but it will take a bit longer... - * - * But do not let this example give _anyone_ the idea that they can - * create a release function without any code in it at all, to do that - * is almost always wrong. If you have any questions about this, - * please send an email to - */ + struct device_driver * drv = to_driver(kobj); + complete(&drv->unloaded); } static struct kobj_type ktype_driver = { @@ -123,7 +109,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; if (get_bus(bus)) { - error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); + error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr); put_bus(bus); } else error = -EINVAL; @@ -133,7 +119,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (get_bus(bus)) { - sysfs_remove_file(&bus->subsys.kobj, &attr->attr); + sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr); put_bus(bus); } } @@ -147,6 +133,7 @@ static decl_subsys(bus, &ktype_bus, NULL); #ifdef CONFIG_HOTPLUG + /* Manually detach a device from its associated driver. */ static int driver_helper(struct device *dev, void *data) { @@ -212,33 +199,6 @@ static ssize_t driver_bind(struct device_driver *drv, } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); -static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) -{ - return sprintf(buf, "%d\n", bus->drivers_autoprobe); -} - -static ssize_t store_drivers_autoprobe(struct bus_type *bus, - const char *buf, size_t count) -{ - if (buf[0] == '0') - bus->drivers_autoprobe = 0; - else - bus->drivers_autoprobe = 1; - return count; -} - -static ssize_t store_drivers_probe(struct bus_type *bus, - const char *buf, size_t count) -{ - struct device *dev; - - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); - if (!dev) - return -ENODEV; - if (bus_rescan_devices_helper(dev, NULL) != 0) - return -EINVAL; - return count; -} #endif static struct device * next_device(struct klist_iter * i) @@ -397,7 +357,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) static int make_deprecated_bus_links(struct device *dev) { return sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "bus"); + &dev->bus->subsys.kset.kobj, "bus"); } static void remove_deprecated_bus_links(struct device *dev) @@ -431,7 +391,7 @@ int bus_add_device(struct device * dev) if (error) goto out_id; error = sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "subsystem"); + &dev->bus->subsys.kset.kobj, "subsystem"); if (error) goto out_subsys; error = make_deprecated_bus_links(dev); @@ -458,21 +418,21 @@ int bus_add_device(struct device * dev) * - Add device to bus's list of devices. * - Try to attach to driver. */ -void bus_attach_device(struct device * dev) +int bus_attach_device(struct device * dev) { struct bus_type *bus = dev->bus; int ret = 0; if (bus) { dev->is_registered = 1; - if (bus->drivers_autoprobe) - ret = device_attach(dev); - WARN_ON(ret < 0); - if (ret >= 0) + ret = device_attach(dev); + if (ret >= 0) { klist_add_tail(&dev->knode_bus, &bus->klist_devices); - else + ret = 0; + } else dev->is_registered = 0; } + return ret; } /** @@ -555,41 +515,9 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_bind); driver_remove_file(drv, &driver_attr_unbind); } - -static int add_probe_files(struct bus_type *bus) -{ - int retval; - - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.attr.owner = bus->owner; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); - if (retval) - goto out; - - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.attr.owner = bus->owner; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); - if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); -out: - return retval; -} - -static void remove_probe_files(struct bus_type *bus) -{ - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); -} #else static inline int add_bind_files(struct device_driver *drv) { return 0; } static inline void remove_bind_files(struct device_driver *drv) {} -static inline int add_probe_files(struct bus_type *bus) { return 0; } -static inline void remove_probe_files(struct bus_type *bus) {} #endif /** @@ -603,7 +531,7 @@ int bus_add_driver(struct device_driver *drv) int error = 0; if (!bus) - return -EINVAL; + return 0; pr_debug("bus %s: add driver %s\n", bus->name, drv->name); error = kobject_set_name(&drv->kobj, "%s", drv->name); @@ -613,11 +541,9 @@ int bus_add_driver(struct device_driver *drv) if ((error = kobject_register(&drv->kobj))) goto out_put_bus; - if (drv->bus->drivers_autoprobe) { - error = driver_attach(drv); - if (error) - goto out_unregister; - } + error = driver_attach(drv); + if (error) + goto out_unregister; klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); @@ -679,6 +605,8 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, ret = device_attach(dev); if (dev->parent) up(&dev->parent->sem); + if (ret > 0) + ret = 0; } return ret < 0 ? ret : 0; } @@ -810,7 +738,7 @@ int bus_register(struct bus_type * bus) BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); - retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); + retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); if (retval) goto out; @@ -820,13 +748,13 @@ int bus_register(struct bus_type * bus) goto out; kobject_set_name(&bus->devices.kobj, "devices"); - bus->devices.kobj.parent = &bus->subsys.kobj; + bus->devices.subsys = &bus->subsys; retval = kset_register(&bus->devices); if (retval) goto bus_devices_fail; kobject_set_name(&bus->drivers.kobj, "drivers"); - bus->drivers.kobj.parent = &bus->subsys.kobj; + bus->drivers.subsys = &bus->subsys; bus->drivers.ktype = &ktype_driver; retval = kset_register(&bus->drivers); if (retval) @@ -834,12 +762,6 @@ int bus_register(struct bus_type * bus) klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, NULL, NULL); - - bus->drivers_autoprobe = 1; - retval = add_probe_files(bus); - if (retval) - goto bus_probe_files_fail; - retval = bus_add_attrs(bus); if (retval) goto bus_attrs_fail; @@ -848,8 +770,6 @@ int bus_register(struct bus_type * bus) return 0; bus_attrs_fail: - remove_probe_files(bus); -bus_probe_files_fail: kset_unregister(&bus->drivers); bus_drivers_fail: kset_unregister(&bus->devices); @@ -859,6 +779,7 @@ int bus_register(struct bus_type * bus) return retval; } + /** * bus_unregister - remove a bus from the system * @bus: bus. @@ -870,7 +791,6 @@ void bus_unregister(struct bus_type * bus) { pr_debug("bus %s: unregistering\n", bus->name); bus_remove_attrs(bus); - remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); subsystem_unregister(&bus->subsys); diff --git a/trunk/drivers/base/class.c b/trunk/drivers/base/class.c index 20c4ea6eb50d..d5968128be2b 100644 --- a/trunk/drivers/base/class.c +++ b/trunk/drivers/base/class.c @@ -19,8 +19,10 @@ #include #include "base.h" +extern struct subsystem devices_subsys; + #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) -#define to_class(obj) container_of(obj, struct class, subsys.kobj) +#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj) static ssize_t class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) @@ -78,7 +80,7 @@ int class_create_file(struct class * cls, const struct class_attribute * attr) { int error; if (cls) { - error = sysfs_create_file(&cls->subsys.kobj, &attr->attr); + error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr); } else error = -EINVAL; return error; @@ -87,7 +89,7 @@ int class_create_file(struct class * cls, const struct class_attribute * attr) void class_remove_file(struct class * cls, const struct class_attribute * attr) { if (cls) - sysfs_remove_file(&cls->subsys.kobj, &attr->attr); + sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); } static struct class *class_get(struct class *cls) @@ -143,9 +145,8 @@ int class_register(struct class * cls) INIT_LIST_HEAD(&cls->children); INIT_LIST_HEAD(&cls->devices); INIT_LIST_HEAD(&cls->interfaces); - kset_init(&cls->class_dirs); init_MUTEX(&cls->sem); - error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name); + error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); if (error) return error; @@ -162,6 +163,7 @@ int class_register(struct class * cls) void class_unregister(struct class * cls) { pr_debug("device class '%s': unregistering\n", cls->name); + kobject_unregister(cls->virtual_dir); remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } @@ -609,7 +611,7 @@ int class_device_add(struct class_device *class_dev) if (parent_class_dev) class_dev->kobj.parent = &parent_class_dev->kobj; else - class_dev->kobj.parent = &parent_class->subsys.kobj; + class_dev->kobj.parent = &parent_class->subsys.kset.kobj; error = kobject_add(&class_dev->kobj); if (error) @@ -617,7 +619,7 @@ int class_device_add(struct class_device *class_dev) /* add the needed attributes to this device */ error = sysfs_create_link(&class_dev->kobj, - &parent_class->subsys.kobj, "subsystem"); + &parent_class->subsys.kset.kobj, "subsystem"); if (error) goto out3; class_dev->uevent_attr.attr.name = "uevent"; @@ -915,8 +917,8 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ subsystem_init(&class_obj_subsys); - if (!class_obj_subsys.kobj.parent) - class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; + if (!class_obj_subsys.kset.subsys) + class_obj_subsys.kset.subsys = &class_obj_subsys; return 0; } diff --git a/trunk/drivers/base/core.c b/trunk/drivers/base/core.c index b78fc1e68264..d7fcf823a42a 100644 --- a/trunk/drivers/base/core.c +++ b/trunk/drivers/base/core.c @@ -43,8 +43,7 @@ int (*platform_notify_remove)(struct device * dev) = NULL; const char *dev_driver_string(struct device *dev) { return dev->driver ? dev->driver->name : - (dev->bus ? dev->bus->name : - (dev->class ? dev->class->name : "")); + (dev->bus ? dev->bus->name : ""); } EXPORT_SYMBOL(dev_driver_string); @@ -120,8 +119,6 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) if (ktype == &ktype_device) { struct device *dev = to_dev(kobj); - if (dev->uevent_suppress) - return 0; if (dev->bus) return 1; if (dev->class) @@ -159,11 +156,6 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, "MINOR=%u", MINOR(dev->devt)); } - if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); - if (dev->driver) add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, @@ -246,157 +238,71 @@ static struct kset_uevent_ops device_uevent_ops = { .uevent = dev_uevent, }; -static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct kobject *top_kobj; - struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; - int i; - size_t count = 0; - int retval; - - /* search the kset, the device belongs to */ - top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } - if (!top_kobj->kset) - goto out; - kset = top_kobj->kset; - if (!kset->uevent_ops || !kset->uevent_ops->uevent) - goto out; - - /* respect filter */ - if (kset->uevent_ops && kset->uevent_ops->filter) - if (!kset->uevent_ops->filter(kset, &dev->kobj)) - goto out; - - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* let the kset specific function add its keys */ - pos = data; - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); - if (retval) - goto out; - - /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } -out: - free_page((unsigned long)data); - return count; -} - static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (memcmp(buf, "add", 3) != 0) - dev_err(dev, "uevent: unsupported action-string; this will " - "be ignored in a future kernel version"); kobject_uevent(&dev->kobj, KOBJ_ADD); return count; } -static int device_add_attributes(struct device *dev, - struct device_attribute *attrs) +static int device_add_groups(struct device *dev) { - int error = 0; int i; - - if (attrs) { - for (i = 0; attr_name(attrs[i]); i++) { - error = device_create_file(dev, &attrs[i]); - if (error) - break; - } - if (error) - while (--i >= 0) - device_remove_file(dev, &attrs[i]); - } - return error; -} - -static void device_remove_attributes(struct device *dev, - struct device_attribute *attrs) -{ - int i; - - if (attrs) - for (i = 0; attr_name(attrs[i]); i++) - device_remove_file(dev, &attrs[i]); -} - -static int device_add_groups(struct device *dev, - struct attribute_group **groups) -{ int error = 0; - int i; - if (groups) { - for (i = 0; groups[i]; i++) { - error = sysfs_create_group(&dev->kobj, groups[i]); + if (dev->groups) { + for (i = 0; dev->groups[i]; i++) { + error = sysfs_create_group(&dev->kobj, dev->groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&dev->kobj, groups[i]); - break; + sysfs_remove_group(&dev->kobj, dev->groups[i]); + goto out; } } } +out: return error; } -static void device_remove_groups(struct device *dev, - struct attribute_group **groups) +static void device_remove_groups(struct device *dev) { int i; - - if (groups) - for (i = 0; groups[i]; i++) - sysfs_remove_group(&dev->kobj, groups[i]); + if (dev->groups) { + for (i = 0; dev->groups[i]; i++) { + sysfs_remove_group(&dev->kobj, dev->groups[i]); + } + } } static int device_add_attrs(struct device *dev) { struct class *class = dev->class; struct device_type *type = dev->type; - int error; + int error = 0; + int i; - if (class) { - error = device_add_attributes(dev, class->dev_attrs); + if (class && class->dev_attrs) { + for (i = 0; attr_name(class->dev_attrs[i]); i++) { + error = device_create_file(dev, &class->dev_attrs[i]); + if (error) + break; + } if (error) - return error; + while (--i >= 0) + device_remove_file(dev, &class->dev_attrs[i]); } - if (type) { - error = device_add_groups(dev, type->groups); + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) { + error = device_create_file(dev, &type->attrs[i]); + if (error) + break; + } if (error) - goto err_remove_class_attrs; + while (--i >= 0) + device_remove_file(dev, &type->attrs[i]); } - error = device_add_groups(dev, dev->groups); - if (error) - goto err_remove_type_groups; - - return 0; - - err_remove_type_groups: - if (type) - device_remove_groups(dev, type->groups); - err_remove_class_attrs: - if (class) - device_remove_attributes(dev, class->dev_attrs); - return error; } @@ -404,14 +310,17 @@ static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; struct device_type *type = dev->type; + int i; - device_remove_groups(dev, dev->groups); - - if (type) - device_remove_groups(dev, type->groups); + if (class && class->dev_attrs) { + for (i = 0; attr_name(class->dev_attrs[i]); i++) + device_remove_file(dev, &class->dev_attrs[i]); + } - if (class) - device_remove_attributes(dev, class->dev_attrs); + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) + device_remove_file(dev, &type->attrs[i]); + } } @@ -485,10 +394,9 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) EXPORT_SYMBOL_GPL(device_remove_bin_file); /** - * device_schedule_callback_owner - helper to schedule a callback for a device + * device_schedule_callback - helper to schedule a callback for a device * @dev: device. * @func: callback function to invoke later. - * @owner: module owning the callback routine * * Attribute methods must not unregister themselves or their parent device * (which would amount to the same thing). Attempts to do so will deadlock, @@ -499,23 +407,20 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file); * argument in the workqueue's process context. @dev will be pinned until * @func returns. * - * This routine is usually called via the inline device_schedule_callback(), - * which automatically sets @owner to THIS_MODULE. - * * Returns 0 if the request was submitted, -ENOMEM if storage could not - * be allocated, -ENODEV if a reference to @owner isn't available. + * be allocated. * * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an * underlying sysfs routine (since it is intended for use by attribute * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. */ -int device_schedule_callback_owner(struct device *dev, - void (*func)(struct device *), struct module *owner) +int device_schedule_callback(struct device *dev, + void (*func)(struct device *)) { return sysfs_schedule_callback(&dev->kobj, - (void (*)(void *)) func, dev, owner); + (void (*)(void *)) func, dev); } -EXPORT_SYMBOL_GPL(device_schedule_callback_owner); +EXPORT_SYMBOL_GPL(device_schedule_callback); static void klist_children_get(struct klist_node *n) { @@ -565,65 +470,41 @@ static struct kobject * get_device_parent(struct device *dev, /* Set the parent to the class, not the parent device */ /* this keeps sysfs from having a symlink to make old udevs happy */ if (dev->class) - return &dev->class->subsys.kobj; + return &dev->class->subsys.kset.kobj; else if (parent) return &parent->kobj; return NULL; } #else -static struct kobject *virtual_device_parent(struct device *dev) +static struct kobject * virtual_device_parent(struct device *dev) { - static struct kobject *virtual_dir = NULL; + if (!dev->class) + return ERR_PTR(-ENODEV); - if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual"); + if (!dev->class->virtual_dir) { + static struct kobject *virtual_dir = NULL; - return virtual_dir; + if (!virtual_dir) + virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); + dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); + } + + return dev->class->virtual_dir; } static struct kobject * get_device_parent(struct device *dev, struct device *parent) { - if (dev->class) { - struct kobject *kobj = NULL; - struct kobject *parent_kobj; - struct kobject *k; - - /* - * If we have no parent, we live in "virtual". - * Class-devices with a bus-device as parent, live - * in a class-directory to prevent namespace collisions. - */ - if (parent == NULL) - parent_kobj = virtual_device_parent(dev); - else if (parent->class) - return &parent->kobj; - else - parent_kobj = &parent->kobj; - - /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->class_dirs.list_lock); - list_for_each_entry(k, &dev->class->class_dirs.list, entry) - if (k->parent == parent_kobj) { - kobj = kobject_get(k); - break; - } - spin_unlock(&dev->class->class_dirs.list_lock); - if (kobj) - return kobj; - - /* or create a new class-directory at the parent device */ - return kobject_kset_add_dir(&dev->class->class_dirs, - parent_kobj, dev->class->name); - } - - if (parent) + /* if this is a class device, and has no parent, create one */ + if ((dev->class) && (parent == NULL)) { + return virtual_device_parent(dev); + } else if (parent) return &parent->kobj; return NULL; } -#endif +#endif static int setup_parent(struct device *dev, struct device *parent) { struct kobject *kobj; @@ -660,6 +541,7 @@ int device_add(struct device *dev) pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); parent = get_device(dev->parent); + error = setup_parent(dev, parent); if (error) goto Error; @@ -680,11 +562,10 @@ int device_add(struct device *dev) BUS_NOTIFY_ADD_DEVICE, dev); dev->uevent_attr.attr.name = "uevent"; - dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR; + dev->uevent_attr.attr.mode = S_IWUSR; if (dev->driver) dev->uevent_attr.attr.owner = dev->driver->owner; dev->uevent_attr.store = store_uevent; - dev->uevent_attr.show = show_uevent; error = device_create_file(dev, &dev->uevent_attr); if (error) goto attrError; @@ -711,12 +592,12 @@ int device_add(struct device *dev) } if (dev->class) { - sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, + sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, "subsystem"); /* If this is not a "fake" compatible device, then create the * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_create_link(&dev->class->subsys.kobj, + if (dev->kobj.parent != &dev->class->subsys.kset.kobj) + sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, dev->bus_id); if (parent) { sysfs_create_link(&dev->kobj, &dev->parent->kobj, @@ -733,12 +614,16 @@ int device_add(struct device *dev) if ((error = device_add_attrs(dev))) goto AttrsError; + if ((error = device_add_groups(dev))) + goto GroupError; if ((error = device_pm_add(dev))) goto PMError; if ((error = bus_add_device(dev))) goto BusError; - kobject_uevent(&dev->kobj, KOBJ_ADD); - bus_attach_device(dev); + if (!dev->uevent_suppress) + kobject_uevent(&dev->kobj, KOBJ_ADD); + if ((error = bus_attach_device(dev))) + goto AttachError; if (parent) klist_add_tail(&dev->knode_parent, &parent->klist_children); @@ -754,15 +639,19 @@ int device_add(struct device *dev) up(&dev->class->sem); } Done: - kfree(class_name); + kfree(class_name); put_device(dev); return error; + AttachError: + bus_remove_device(dev); BusError: device_pm_remove(dev); PMError: if (dev->bus) blocking_notifier_call_chain(&dev->bus->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); + device_remove_groups(dev); + GroupError: device_remove_attrs(dev); AttrsError: if (dev->devt_attr) { @@ -774,8 +663,8 @@ int device_add(struct device *dev) sysfs_remove_link(&dev->kobj, "subsystem"); /* If this is not a "fake" compatible device, remove the * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, + if (dev->kobj.parent != &dev->class->subsys.kset.kobj) + sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); if (parent) { #ifdef CONFIG_SYSFS_DEPRECATED @@ -788,6 +677,15 @@ int device_add(struct device *dev) #endif sysfs_remove_link(&dev->kobj, "device"); } + + down(&dev->class->sem); + /* notify any interfaces that the device is now gone */ + list_for_each_entry(class_intf, &dev->class->interfaces, node) + if (class_intf->remove_dev) + class_intf->remove_dev(dev, class_intf); + /* remove the device from the class list */ + list_del_init(&dev->node); + up(&dev->class->sem); } ueventattrError: device_remove_file(dev, &dev->uevent_attr); @@ -875,8 +773,8 @@ void device_del(struct device * dev) sysfs_remove_link(&dev->kobj, "subsystem"); /* If this is not a "fake" compatible device, remove the * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, + if (dev->kobj.parent != &dev->class->subsys.kset.kobj) + sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); if (parent) { #ifdef CONFIG_SYSFS_DEPRECATED @@ -898,33 +796,9 @@ void device_del(struct device * dev) /* remove the device from the class list */ list_del_init(&dev->node); up(&dev->class->sem); - - /* If we live in a parent class-directory, unreference it */ - if (dev->kobj.parent->kset == &dev->class->class_dirs) { - struct device *d; - int other = 0; - - /* - * if we are the last child of our class, delete - * our class-directory at this parent - */ - down(&dev->class->sem); - list_for_each_entry(d, &dev->class->devices, node) { - if (d == dev) - continue; - if (d->kobj.parent == dev->kobj.parent) { - other = 1; - break; - } - } - if (!other) - kobject_del(dev->kobj.parent); - - kobject_put(dev->kobj.parent); - up(&dev->class->sem); - } } device_remove_file(dev, &dev->uevent_attr); + device_remove_groups(dev); device_remove_attrs(dev); bus_remove_device(dev); @@ -1192,9 +1066,9 @@ int device_rename(struct device *dev, char *new_name) #endif if (dev->class) { - sysfs_remove_link(&dev->class->subsys.kobj, + sysfs_remove_link(&dev->class->subsys.kset.kobj, old_symlink_name); - sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, + sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, dev->bus_id); } put_device(dev); diff --git a/trunk/drivers/base/dd.c b/trunk/drivers/base/dd.c index 92428e55b0c2..6a48824e43ff 100644 --- a/trunk/drivers/base/dd.c +++ b/trunk/drivers/base/dd.c @@ -94,11 +94,19 @@ int device_bind_driver(struct device *dev) return ret; } +struct stupid_thread_structure { + struct device_driver *drv; + struct device *dev; +}; + static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); -static int really_probe(struct device *dev, struct device_driver *drv) +static int really_probe(void *void_data) { + struct stupid_thread_structure *data = void_data; + struct device_driver *drv = data->drv; + struct device *dev = data->dev; int ret = 0; atomic_inc(&probe_count); @@ -146,6 +154,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) */ ret = 0; done: + kfree(data); atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; @@ -177,14 +186,16 @@ int driver_probe_done(void) * format of the ID structures, nor what is to be considered a match and * what is not. * - * This function returns 1 if a match is found, -ENODEV if the device is - * not registered, and 0 otherwise. + * This function returns 1 if a match is found, an error if one occurs + * (that is not -ENODEV or -ENXIO), and 0 otherwise. * * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. */ int driver_probe_device(struct device_driver * drv, struct device * dev) { + struct stupid_thread_structure *data; + struct task_struct *probe_task; int ret = 0; if (!device_is_registered(dev)) @@ -195,7 +206,19 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) pr_debug("%s: Matched Device %s with Driver %s\n", drv->bus->name, dev->bus_id, drv->name); - ret = really_probe(dev, drv); + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->drv = drv; + data->dev = dev; + + if (drv->multithread_probe) { + probe_task = kthread_run(really_probe, data, + "probe-%s", dev->bus_id); + if (IS_ERR(probe_task)) + ret = really_probe(data); + } else + ret = really_probe(data); done: return ret; @@ -207,19 +230,6 @@ static int __device_attach(struct device_driver * drv, void * data) return driver_probe_device(drv, dev); } -static int device_probe_drivers(void *data) -{ - struct device *dev = data; - int ret = 0; - - if (dev->bus) { - down(&dev->sem); - ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); - up(&dev->sem); - } - return ret; -} - /** * device_attach - try to attach device to a driver. * @dev: device. @@ -229,8 +239,7 @@ static int device_probe_drivers(void *data) * pair is found, break out and return. * * Returns 1 if the device was bound to a driver; - * 0 if no matching device was found; - * -ENODEV if the device is not registered. + * 0 if no matching device was found; error code otherwise. * * When called for a USB interface, @dev->parent->sem must be held. */ @@ -243,13 +252,8 @@ int device_attach(struct device * dev) ret = device_bind_driver(dev); if (ret == 0) ret = 1; - else { - dev->driver = NULL; - ret = 0; - } - } else { + } else ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); - } up(&dev->sem); return ret; } @@ -375,6 +379,33 @@ void driver_detach(struct device_driver * drv) } } +#ifdef CONFIG_PCI_MULTITHREAD_PROBE +static int __init wait_for_probes(void) +{ + DEFINE_WAIT(wait); + + printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__, + atomic_read(&probe_count)); + if (!atomic_read(&probe_count)) + return 0; + while (atomic_read(&probe_count)) { + prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&probe_count)) + schedule(); + } + finish_wait(&probe_waitqueue, &wait); + return 0; +} + +core_initcall_sync(wait_for_probes); +postcore_initcall_sync(wait_for_probes); +arch_initcall_sync(wait_for_probes); +subsys_initcall_sync(wait_for_probes); +fs_initcall_sync(wait_for_probes); +device_initcall_sync(wait_for_probes); +late_initcall_sync(wait_for_probes); +#endif + EXPORT_SYMBOL_GPL(device_bind_driver); EXPORT_SYMBOL_GPL(device_release_driver); EXPORT_SYMBOL_GPL(device_attach); diff --git a/trunk/drivers/base/dmapool.c b/trunk/drivers/base/dmapool.c index 9406259754ad..cd467c9f33b3 100644 --- a/trunk/drivers/base/dmapool.c +++ b/trunk/drivers/base/dmapool.c @@ -37,7 +37,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) -static DEFINE_MUTEX (pools_lock); +static DECLARE_MUTEX (pools_lock); static ssize_t show_pools (struct device *dev, struct device_attribute *attr, char *buf) @@ -55,7 +55,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) size -= temp; next += temp; - mutex_lock(&pools_lock); + down (&pools_lock); list_for_each_entry(pool, &dev->dma_pools, pools) { unsigned pages = 0; unsigned blocks = 0; @@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) size -= temp; next += temp; } - mutex_unlock(&pools_lock); + up (&pools_lock); return PAGE_SIZE - size; } @@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev, if (dev) { int ret; - mutex_lock(&pools_lock); + down (&pools_lock); if (list_empty (&dev->dma_pools)) ret = device_create_file (dev, &dev_attr_pools); else @@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev, kfree(retval); retval = NULL; } - mutex_unlock(&pools_lock); + up (&pools_lock); } else INIT_LIST_HEAD (&retval->pools); @@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page) void dma_pool_destroy (struct dma_pool *pool) { - mutex_lock(&pools_lock); + down (&pools_lock); list_del (&pool->pools); if (pool->dev && list_empty (&pool->dev->dma_pools)) device_remove_file (pool->dev, &dev_attr_pools); - mutex_unlock(&pools_lock); + up (&pools_lock); while (!list_empty (&pool->page_list)) { struct dma_page *page; diff --git a/trunk/drivers/base/driver.c b/trunk/drivers/base/driver.c index eb11475293ed..082bfded3854 100644 --- a/trunk/drivers/base/driver.c +++ b/trunk/drivers/base/driver.c @@ -149,6 +149,10 @@ void put_driver(struct device_driver * drv) * We pass off most of the work to the bus_add_driver() call, * since most of the things we have to do deal with the bus * structures. + * + * The one interesting aspect is that we setup @drv->unloaded + * as a completion that gets complete when the driver reference + * count reaches 0. */ int driver_register(struct device_driver * drv) { @@ -158,19 +162,35 @@ int driver_register(struct device_driver * drv) printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); } klist_init(&drv->klist_devices, NULL, NULL); + init_completion(&drv->unloaded); return bus_add_driver(drv); } + /** * driver_unregister - remove driver from system. * @drv: driver. * * Again, we pass off most of the work to the bus-level call. + * + * Though, once that is done, we wait until @drv->unloaded is completed. + * This will block until the driver refcount reaches 0, and it is + * released. Only modular drivers will call this function, and we + * have to guarantee that it won't complete, letting the driver + * unload until all references are gone. */ void driver_unregister(struct device_driver * drv) { bus_remove_driver(drv); + /* + * If the driver is a module, we are probably in + * the module unload path, and we want to wait + * for everything to unload before we can actually + * finish the unload. + */ + if (drv->owner) + wait_for_completion(&drv->unloaded); } /** diff --git a/trunk/drivers/base/firmware.c b/trunk/drivers/base/firmware.c index 90c862932169..cb1b98ae0d58 100644 --- a/trunk/drivers/base/firmware.c +++ b/trunk/drivers/base/firmware.c @@ -17,13 +17,13 @@ static decl_subsys(firmware, NULL, NULL); -int firmware_register(struct kset *s) +int firmware_register(struct subsystem * s) { - kobj_set_kset_s(s, firmware_subsys); + kset_set_kset_s(s, firmware_subsys); return subsystem_register(s); } -void firmware_unregister(struct kset *s) +void firmware_unregister(struct subsystem * s) { subsystem_unregister(s); } diff --git a/trunk/drivers/base/firmware_class.c b/trunk/drivers/base/firmware_class.c index 97ab5bd1c4d6..c0a979a5074b 100644 --- a/trunk/drivers/base/firmware_class.c +++ b/trunk/drivers/base/firmware_class.c @@ -31,6 +31,8 @@ enum { FW_STATUS_LOADING, FW_STATUS_DONE, FW_STATUS_ABORT, + FW_STATUS_READY, + FW_STATUS_READY_NOHOTPLUG, }; static int loading_timeout = 60; /* In seconds */ @@ -94,6 +96,9 @@ static int firmware_uevent(struct device *dev, char **envp, int num_envp, struct firmware_priv *fw_priv = dev_get_drvdata(dev); int i = 0, len = 0; + if (!test_bit(FW_STATUS_READY, &fw_priv->status)) + return -ENODEV; + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; @@ -328,7 +333,6 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, f_dev->parent = device; f_dev->class = &firmware_class; dev_set_drvdata(f_dev, fw_priv); - f_dev->uevent_suppress = 1; retval = device_register(f_dev); if (retval) { printk(KERN_ERR "%s: device_register failed\n", @@ -378,7 +382,9 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p, } if (uevent) - f_dev->uevent_suppress = 0; + set_bit(FW_STATUS_READY, &fw_priv->status); + else + set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status); *dev_p = f_dev; goto out; diff --git a/trunk/drivers/base/platform.c b/trunk/drivers/base/platform.c index 17b5ece8f82c..30480f6f2af2 100644 --- a/trunk/drivers/base/platform.c +++ b/trunk/drivers/base/platform.c @@ -292,22 +292,20 @@ EXPORT_SYMBOL_GPL(platform_device_add); * @pdev: platform device we're removing * * Note that this function will also release all memory- and port-based - * resources owned by the device (@dev->resource). This function - * must _only_ be externally called in error cases. All other usage - * is a bug. + * resources owned by the device (@dev->resource). */ void platform_device_del(struct platform_device *pdev) { int i; if (pdev) { - device_del(&pdev->dev); - for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO)) release_resource(r); } + + device_del(&pdev->dev); } } EXPORT_SYMBOL_GPL(platform_device_del); diff --git a/trunk/drivers/base/power/main.c b/trunk/drivers/base/power/main.c index 05dc8764e765..bbbb973a9d3c 100644 --- a/trunk/drivers/base/power/main.c +++ b/trunk/drivers/base/power/main.c @@ -29,9 +29,6 @@ LIST_HEAD(dpm_off_irq); DECLARE_MUTEX(dpm_sem); DECLARE_MUTEX(dpm_list_sem); -int (*platform_enable_wakeup)(struct device *dev, int is_on); - - /** * device_pm_set_parent - Specify power dependency. * @dev: Device who needs power. diff --git a/trunk/drivers/base/power/resume.c b/trunk/drivers/base/power/resume.c index a2c64188d713..020be36705a6 100644 --- a/trunk/drivers/base/power/resume.c +++ b/trunk/drivers/base/power/resume.c @@ -26,9 +26,7 @@ int resume_device(struct device * dev) TRACE_DEVICE(dev); TRACE_RESUME(0); - down(&dev->sem); - if (dev->power.pm_parent && dev->power.pm_parent->power.power_state.event) { dev_err(dev, "PM: resume from %d, parent %s still %d\n", @@ -36,24 +34,15 @@ int resume_device(struct device * dev) dev->power.pm_parent->bus_id, dev->power.pm_parent->power.power_state.event); } - if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); error = dev->bus->resume(dev); } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { + if (dev->class && dev->class->resume) { dev_dbg(dev,"class resume\n"); error = dev->class->resume(dev); } - up(&dev->sem); - TRACE_RESUME(error); return error; } diff --git a/trunk/drivers/base/power/shutdown.c b/trunk/drivers/base/power/shutdown.c index a47ee1b70d20..3483ae4d57f5 100644 --- a/trunk/drivers/base/power/shutdown.c +++ b/trunk/drivers/base/power/shutdown.c @@ -16,6 +16,8 @@ #define to_dev(node) container_of(node, struct device, kobj.entry) +extern struct subsystem devices_subsys; + /** * We handle system devices differently - we suspend and shut them @@ -34,7 +36,8 @@ void device_shutdown(void) { struct device * dev, *devn; - list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list, + down_write(&devices_subsys.rwsem); + list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list, kobj.entry) { if (dev->bus && dev->bus->shutdown) { dev_dbg(dev, "shutdown\n"); @@ -44,6 +47,7 @@ void device_shutdown(void) dev->driver->shutdown(dev); } } + up_write(&devices_subsys.rwsem); sysdev_shutdown(); } diff --git a/trunk/drivers/base/power/suspend.c b/trunk/drivers/base/power/suspend.c index 42d2b86ba765..ece136bf97e3 100644 --- a/trunk/drivers/base/power/suspend.c +++ b/trunk/drivers/base/power/suspend.c @@ -78,18 +78,6 @@ int suspend_device(struct device * dev, pm_message_t state) suspend_report_result(dev->class->suspend, error); } - if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) { - dev_dbg(dev, "%s%s\n", - suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) - && device_may_wakeup(dev)) - ? ", may wakeup" - : "" - ); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) { dev_dbg(dev, "%s%s\n", suspend_verb(state.event), diff --git a/trunk/drivers/base/sys.c b/trunk/drivers/base/sys.c index 29f1291966c1..04e5db445c74 100644 --- a/trunk/drivers/base/sys.c +++ b/trunk/drivers/base/sys.c @@ -25,7 +25,7 @@ #include "base.h" -extern struct kset devices_subsys; +extern struct subsystem devices_subsys; #define to_sysdev(k) container_of(k, struct sys_device, kobj) #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) @@ -138,7 +138,7 @@ int sysdev_class_register(struct sysdev_class * cls) pr_debug("Registering sysdev class '%s'\n", kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); - cls->kset.kobj.parent = &system_subsys.kobj; + cls->kset.subsys = &system_subsys; kset_set_kset_s(cls, system_subsys); return kset_register(&cls->kset); } @@ -309,7 +309,7 @@ void sysdev_shutdown(void) pr_debug("Shutting Down System Devices\n"); down(&sysdev_drivers_lock); - list_for_each_entry_reverse(cls, &system_subsys.list, + list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; @@ -384,7 +384,7 @@ int sysdev_suspend(pm_message_t state) pr_debug("Suspending System Devices\n"); - list_for_each_entry_reverse(cls, &system_subsys.list, + list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { pr_debug("Suspending type '%s':\n", @@ -457,7 +457,7 @@ int sysdev_suspend(pm_message_t state) } /* resume other classes */ - list_for_each_entry_continue(cls, &system_subsys.list, + list_for_each_entry_continue(cls, &system_subsys.kset.list, kset.kobj.entry) { list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&err_dev->kobj)); @@ -483,7 +483,7 @@ int sysdev_resume(void) pr_debug("Resuming System Devices\n"); - list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) { + list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Resuming type '%s':\n", @@ -501,7 +501,7 @@ int sysdev_resume(void) int __init system_bus_init(void) { - system_subsys.kobj.parent = &devices_subsys.kobj; + system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; return subsystem_register(&system_subsys); } diff --git a/trunk/drivers/block/aoe/aoe.h b/trunk/drivers/block/aoe/aoe.h index 1d8466817943..2308e83e5f33 100644 --- a/trunk/drivers/block/aoe/aoe.h +++ b/trunk/drivers/block/aoe/aoe.h @@ -48,15 +48,6 @@ struct aoe_hdr { __be32 tag; }; -#ifdef __KERNEL__ -#include - -static inline struct aoe_hdr *aoe_hdr(const struct sk_buff *skb) -{ - return (struct aoe_hdr *)skb_mac_header(skb); -} -#endif - struct aoe_atahdr { unsigned char aflags; unsigned char errfeat; diff --git a/trunk/drivers/block/aoe/aoecmd.c b/trunk/drivers/block/aoe/aoecmd.c index 01fbdd38e3be..8d17d8df3662 100644 --- a/trunk/drivers/block/aoe/aoecmd.c +++ b/trunk/drivers/block/aoe/aoecmd.c @@ -27,8 +27,7 @@ new_skb(ulong len) skb = alloc_skb(len, GFP_ATOMIC); if (skb) { - skb_reset_mac_header(skb); - skb_reset_network_header(skb); + skb->nh.raw = skb->mac.raw = skb->data; skb->protocol = __constant_htons(ETH_P_AOE); skb->priority = 0; skb->next = skb->prev = NULL; @@ -119,7 +118,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) /* initialize the headers & frame */ skb = f->skb; - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); @@ -194,21 +193,21 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) sl = sl_tail = NULL; read_lock(&dev_base_lock); - for_each_netdev(ifp) { + for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) { dev_hold(ifp); if (!is_aoe_netif(ifp)) - goto cont; + continue; skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { printk(KERN_INFO "aoe: skb alloc failure\n"); - goto cont; + continue; } skb_put(skb, sizeof *h + sizeof *ch); skb->dev = ifp; if (sl_tail == NULL) sl_tail = skb; - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; memset(h, 0, sizeof *h + sizeof *ch); memset(h->dst, 0xff, sizeof h->dst); @@ -221,8 +220,6 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) skb->next = sl; sl = skb; -cont: - dev_put(ifp); } read_unlock(&dev_base_lock); @@ -303,7 +300,7 @@ rexmit(struct aoedev *d, struct frame *f) aoechr_error(buf); skb = f->skb; - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); f->tag = n; h->tag = cpu_to_be32(n); @@ -532,7 +529,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) char ebuf[128]; u16 aoemajor; - hin = aoe_hdr(skb); + hin = (struct aoe_hdr *) skb->mac.raw; aoemajor = be16_to_cpu(get_unaligned(&hin->major)); d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { @@ -564,7 +561,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) calc_rttavg(d, tsince(f->tag)); ahin = (struct aoe_atahdr *) (hin+1); - hout = aoe_hdr(f->skb); + hout = (struct aoe_hdr *) f->skb->mac.raw; ahout = (struct aoe_atahdr *) (hout+1); buf = f->buf; @@ -698,7 +695,7 @@ aoecmd_ata_id(struct aoedev *d) /* initialize the headers & frame */ skb = f->skb; - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); @@ -729,7 +726,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) enum { MAXFRAMES = 16 }; u16 n; - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; ch = (struct aoe_cfghdr *) (h+1); /* diff --git a/trunk/drivers/block/aoe/aoenet.c b/trunk/drivers/block/aoe/aoenet.c index f9ddfda4d9cb..aab6d91a2c22 100644 --- a/trunk/drivers/block/aoe/aoenet.c +++ b/trunk/drivers/block/aoe/aoenet.c @@ -123,7 +123,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, goto exit; skb_push(skb, ETH_HLEN); /* (1) */ - h = aoe_hdr(skb); + h = (struct aoe_hdr *) skb->mac.raw; n = be32_to_cpu(get_unaligned(&h->tag)); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; diff --git a/trunk/drivers/block/paride/pcd.c b/trunk/drivers/block/paride/pcd.c index 1eeb8f2cde71..c852eed91e4b 100644 --- a/trunk/drivers/block/paride/pcd.c +++ b/trunk/drivers/block/paride/pcd.c @@ -140,7 +140,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include #include -static DEFINE_SPINLOCK(pcd_lock); +static spinlock_t pcd_lock; module_param(verbose, bool, 0644); module_param(major, int, 0); diff --git a/trunk/drivers/block/paride/pf.c b/trunk/drivers/block/paride/pf.c index 5826508f6731..7cdaa1951260 100644 --- a/trunk/drivers/block/paride/pf.c +++ b/trunk/drivers/block/paride/pf.c @@ -154,7 +154,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; #include #include -static DEFINE_SPINLOCK(pf_spin_lock); +static spinlock_t pf_spin_lock; module_param(verbose, bool, 0644); module_param(major, int, 0); diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index f1b9dd7d47d6..a4fb70383188 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -777,8 +777,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->cmd_flags |= REQ_QUIET; blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0); - if (rq->errors) - ret = -EIO; + ret = rq->errors; out: blk_put_request(rq); return ret; diff --git a/trunk/drivers/block/ub.c b/trunk/drivers/block/ub.c index 746a118a9b52..2098eff91e14 100644 --- a/trunk/drivers/block/ub.c +++ b/trunk/drivers/block/ub.c @@ -2132,13 +2132,10 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { /* BULK in or out? */ - if (ep->bEndpointAddress & USB_DIR_IN) { - if (ep_in == NULL) - ep_in = ep; - } else { - if (ep_out == NULL) - ep_out = ep; - } + if (ep->bEndpointAddress & USB_DIR_IN) + ep_in = ep; + else + ep_out = ep; } } diff --git a/trunk/drivers/bluetooth/bfusb.c b/trunk/drivers/bluetooth/bfusb.c index b990805806af..4c766f36d884 100644 --- a/trunk/drivers/bluetooth/bfusb.c +++ b/trunk/drivers/bluetooth/bfusb.c @@ -527,7 +527,7 @@ static int bfusb_send_frame(struct sk_buff *skb) buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; memcpy(skb_put(nskb, 3), buf, 3); - skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size); + memcpy(skb_put(nskb, size), skb->data + sent, size); sent += size; count -= size; diff --git a/trunk/drivers/bluetooth/bluecard_cs.c b/trunk/drivers/bluetooth/bluecard_cs.c index 851de4d5b7de..acfb6a430dcc 100644 --- a/trunk/drivers/bluetooth/bluecard_cs.c +++ b/trunk/drivers/bluetooth/bluecard_cs.c @@ -461,20 +461,20 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); + eh = (struct hci_event_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); + ah = (struct hci_acl_hdr *)(info->rx_skb->data); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); + sh = (struct hci_sco_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; diff --git a/trunk/drivers/bluetooth/bpa10x.c b/trunk/drivers/bluetooth/bpa10x.c index e8ebd5d3de86..9fca6513562d 100644 --- a/trunk/drivers/bluetooth/bpa10x.c +++ b/trunk/drivers/bluetooth/bpa10x.c @@ -231,7 +231,7 @@ static void bpa10x_wakeup(struct bpa10x_data *data) cr = (struct usb_ctrlrequest *) urb->setup_packet; cr->wLength = __cpu_to_le16(skb->len); - skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len); + memcpy(urb->transfer_buffer, skb->data, skb->len); urb->transfer_buffer_length = skb->len; err = usb_submit_urb(urb, GFP_ATOMIC); @@ -250,7 +250,7 @@ static void bpa10x_wakeup(struct bpa10x_data *data) skb = skb_dequeue(&data->tx_queue); if (skb) { - skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len); + memcpy(urb->transfer_buffer, skb->data, skb->len); urb->transfer_buffer_length = skb->len; err = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/trunk/drivers/bluetooth/bt3c_cs.c b/trunk/drivers/bluetooth/bt3c_cs.c index 39516074636b..18b0f3992c5b 100644 --- a/trunk/drivers/bluetooth/bt3c_cs.c +++ b/trunk/drivers/bluetooth/bt3c_cs.c @@ -303,20 +303,20 @@ static void bt3c_receive(bt3c_info_t *info) switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); + eh = (struct hci_event_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); + ah = (struct hci_acl_hdr *)(info->rx_skb->data); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); + sh = (struct hci_sco_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; diff --git a/trunk/drivers/bluetooth/btuart_cs.c b/trunk/drivers/bluetooth/btuart_cs.c index d7d2ea0d86a1..c1bce75148fe 100644 --- a/trunk/drivers/bluetooth/btuart_cs.c +++ b/trunk/drivers/bluetooth/btuart_cs.c @@ -250,20 +250,20 @@ static void btuart_receive(btuart_info_t *info) switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: - eh = hci_event_hdr(info->rx_skb); + eh = (struct hci_event_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: - ah = hci_acl_hdr(info->rx_skb); + ah = (struct hci_acl_hdr *)(info->rx_skb->data); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: - sh = hci_sco_hdr(info->rx_skb); + sh = (struct hci_sco_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; diff --git a/trunk/drivers/bluetooth/dtl1_cs.c b/trunk/drivers/bluetooth/dtl1_cs.c index 7f9c54b9964a..459aa97937ab 100644 --- a/trunk/drivers/bluetooth/dtl1_cs.c +++ b/trunk/drivers/bluetooth/dtl1_cs.c @@ -425,7 +425,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb) return -ENOMEM; skb_reserve(s, NSHL); - skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len); + memcpy(skb_put(s, skb->len), skb->data, skb->len); if (skb->len & 0x0001) *skb_put(s, 1) = 0; /* PAD */ diff --git a/trunk/drivers/bluetooth/hci_h4.c b/trunk/drivers/bluetooth/hci_h4.c index bfbae14cf93d..34f0afc42407 100644 --- a/trunk/drivers/bluetooth/hci_h4.c +++ b/trunk/drivers/bluetooth/hci_h4.c @@ -188,7 +188,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) continue; case H4_W4_EVENT_HDR: - eh = hci_event_hdr(h4->rx_skb); + eh = (struct hci_event_hdr *) h4->rx_skb->data; BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); @@ -196,7 +196,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) continue; case H4_W4_ACL_HDR: - ah = hci_acl_hdr(h4->rx_skb); + ah = (struct hci_acl_hdr *) h4->rx_skb->data; dlen = __le16_to_cpu(ah->dlen); BT_DBG("ACL header: dlen %d", dlen); @@ -205,7 +205,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count) continue; case H4_W4_SCO_HDR: - sh = hci_sco_hdr(h4->rx_skb); + sh = (struct hci_sco_hdr *) h4->rx_skb->data; BT_DBG("SCO header: dlen %d", sh->dlen); diff --git a/trunk/drivers/char/agp/ali-agp.c b/trunk/drivers/char/agp/ali-agp.c index 4941ddb78939..5b684fddcc03 100644 --- a/trunk/drivers/char/agp/ali-agp.c +++ b/trunk/drivers/char/agp/ali-agp.c @@ -145,7 +145,6 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) void *addr = agp_generic_alloc_page(agp_bridge); u32 temp; - global_flush_tlb(); if (!addr) return NULL; @@ -161,7 +160,6 @@ static void ali_destroy_page(void * addr) if (addr) { global_cache_flush(); /* is this really needed? --hch */ agp_generic_destroy_page(addr); - global_flush_tlb(); } } diff --git a/trunk/drivers/char/agp/alpha-agp.c b/trunk/drivers/char/agp/alpha-agp.c index aa8f3a39a704..b0acf41c0db9 100644 --- a/trunk/drivers/char/agp/alpha-agp.c +++ b/trunk/drivers/char/agp/alpha-agp.c @@ -173,7 +173,7 @@ alpha_core_agp_setup(void) /* * Build a fake pci_dev struct */ - pdev = alloc_pci_dev(); + pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!pdev) return -ENOMEM; pdev->vendor = 0xffff; diff --git a/trunk/drivers/char/agp/amd64-agp.c b/trunk/drivers/char/agp/amd64-agp.c index c9f0f250d78f..485720486d60 100644 --- a/trunk/drivers/char/agp/amd64-agp.c +++ b/trunk/drivers/char/agp/amd64-agp.c @@ -14,7 +14,6 @@ #include #include #include /* PAGE_SIZE */ -#include #include #include "agp.h" @@ -260,6 +259,7 @@ static const struct agp_bridge_driver amd_8151_driver = { /* Some basic sanity checks for the aperture. */ static int __devinit aperture_valid(u64 aper, u32 size) { + u32 pfn, c; if (aper == 0) { printk(KERN_ERR PFX "No aperture\n"); return 0; @@ -272,9 +272,14 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "Aperture out of bounds\n"); return 0; } - if (e820_any_mapped(aper, aper + size, E820_RAM)) { - printk(KERN_ERR PFX "Aperture pointing to RAM\n"); - return 0; + pfn = aper >> PAGE_SHIFT; + for (c = 0; c < size/PAGE_SIZE; c++) { + if (!pfn_valid(pfn + c)) + break; + if (!PageReserved(pfn_to_page(pfn + c))) { + printk(KERN_ERR PFX "Aperture pointing to RAM\n"); + return 0; + } } /* Request the Aperture. This catches cases when someone else diff --git a/trunk/drivers/char/agp/generic.c b/trunk/drivers/char/agp/generic.c index 45aeb917ec63..f902d71947ba 100644 --- a/trunk/drivers/char/agp/generic.c +++ b/trunk/drivers/char/agp/generic.c @@ -51,6 +51,28 @@ int agp_memory_reserved; */ EXPORT_SYMBOL_GPL(agp_memory_reserved); +#if defined(CONFIG_X86) +int map_page_into_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); + /* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ + return i; +} +EXPORT_SYMBOL_GPL(map_page_into_agp); + +int unmap_page_from_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL); + /* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ + return i; +} +EXPORT_SYMBOL_GPL(unmap_page_from_agp); +#endif + /* * Generic routines for handling agp_memory structures - * They use the basic page allocation routines to do the brunt of the work. diff --git a/trunk/drivers/char/agp/intel-agp.c b/trunk/drivers/char/agp/intel-agp.c index 9c69f2e761f5..55392a45a14b 100644 --- a/trunk/drivers/char/agp/intel-agp.c +++ b/trunk/drivers/char/agp/intel-agp.c @@ -186,9 +186,8 @@ static void *i8xx_alloc_pages(void) return NULL; if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { - change_page_attr(page, 4, PAGE_KERNEL); global_flush_tlb(); - __free_pages(page, 2); + __free_page(page); return NULL; } global_flush_tlb(); @@ -210,7 +209,7 @@ static void i8xx_destroy_pages(void *addr) global_flush_tlb(); put_page(page); unlock_page(page); - __free_pages(page, 2); + free_pages((unsigned long)addr, 2); atomic_dec(&agp_bridge->current_memory_agp); } @@ -316,6 +315,9 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) struct agp_memory *new; void *addr; + if (pg_count != 1 && pg_count != 4) + return NULL; + switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); global_flush_tlb(); diff --git a/trunk/drivers/char/agp/nvidia-agp.c b/trunk/drivers/char/agp/nvidia-agp.c index 6cd7373dcdf4..0c9dab557c94 100644 --- a/trunk/drivers/char/agp/nvidia-agp.c +++ b/trunk/drivers/char/agp/nvidia-agp.c @@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, u8 cap_ptr; nvidia_private.dev_1 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); nvidia_private.dev_2 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); nvidia_private.dev_3 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 " @@ -443,9 +443,6 @@ static int __init agp_nvidia_init(void) static void __exit agp_nvidia_cleanup(void) { pci_unregister_driver(&agp_nvidia_pci_driver); - pci_dev_put(nvidia_private.dev_1); - pci_dev_put(nvidia_private.dev_2); - pci_dev_put(nvidia_private.dev_3); } module_init(agp_nvidia_init); diff --git a/trunk/drivers/char/agp/parisc-agp.c b/trunk/drivers/char/agp/parisc-agp.c index f4562cc22343..3d83b461ccad 100644 --- a/trunk/drivers/char/agp/parisc-agp.c +++ b/trunk/drivers/char/agp/parisc-agp.c @@ -329,7 +329,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) struct agp_bridge_data *bridge; int error = 0; - fake_bridge_dev = alloc_pci_dev(); + fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL); if (!fake_bridge_dev) { error = -ENOMEM; goto fail; diff --git a/trunk/drivers/char/agp/sgi-agp.c b/trunk/drivers/char/agp/sgi-agp.c index cda608c42bea..ee8f50edde1b 100644 --- a/trunk/drivers/char/agp/sgi-agp.c +++ b/trunk/drivers/char/agp/sgi-agp.c @@ -47,8 +47,9 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) nid = info->ca_closest_node; page = alloc_pages_node(nid, GFP_KERNEL, 0); - if (!page) - return NULL; + if (page == NULL) { + return 0; + } get_page(page); SetPageLocked(page); diff --git a/trunk/drivers/char/agp/sis-agp.c b/trunk/drivers/char/agp/sis-agp.c index eb1a1c738190..125f4282d955 100644 --- a/trunk/drivers/char/agp/sis-agp.c +++ b/trunk/drivers/char/agp/sis-agp.c @@ -143,6 +143,96 @@ static struct agp_bridge_driver sis_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; +static struct agp_device_ids sis_agp_device_ids[] __devinitdata = +{ + { + .device_id = PCI_DEVICE_ID_SI_5591_AGP, + .chipset_name = "5591", + }, + { + .device_id = PCI_DEVICE_ID_SI_530, + .chipset_name = "530", + }, + { + .device_id = PCI_DEVICE_ID_SI_540, + .chipset_name = "540", + }, + { + .device_id = PCI_DEVICE_ID_SI_550, + .chipset_name = "550", + }, + { + .device_id = PCI_DEVICE_ID_SI_620, + .chipset_name = "620", + }, + { + .device_id = PCI_DEVICE_ID_SI_630, + .chipset_name = "630", + }, + { + .device_id = PCI_DEVICE_ID_SI_635, + .chipset_name = "635", + }, + { + .device_id = PCI_DEVICE_ID_SI_645, + .chipset_name = "645", + }, + { + .device_id = PCI_DEVICE_ID_SI_646, + .chipset_name = "646", + }, + { + .device_id = PCI_DEVICE_ID_SI_648, + .chipset_name = "648", + }, + { + .device_id = PCI_DEVICE_ID_SI_650, + .chipset_name = "650", + }, + { + .device_id = PCI_DEVICE_ID_SI_651, + .chipset_name = "651", + }, + { + .device_id = PCI_DEVICE_ID_SI_655, + .chipset_name = "655", + }, + { + .device_id = PCI_DEVICE_ID_SI_661, + .chipset_name = "661", + }, + { + .device_id = PCI_DEVICE_ID_SI_730, + .chipset_name = "730", + }, + { + .device_id = PCI_DEVICE_ID_SI_735, + .chipset_name = "735", + }, + { + .device_id = PCI_DEVICE_ID_SI_740, + .chipset_name = "740", + }, + { + .device_id = PCI_DEVICE_ID_SI_741, + .chipset_name = "741", + }, + { + .device_id = PCI_DEVICE_ID_SI_745, + .chipset_name = "745", + }, + { + .device_id = PCI_DEVICE_ID_SI_746, + .chipset_name = "746", + }, + { + .device_id = PCI_DEVICE_ID_SI_760, + .chipset_name = "760", + }, + { }, /* dummy final entry, always present */ +}; + + // chipsets that require the 'delay hack' static int sis_broken_chipsets[] __devinitdata = { PCI_DEVICE_ID_SI_648, @@ -179,15 +269,29 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge) static int __devinit agp_sis_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct agp_device_ids *devs = sis_agp_device_ids; struct agp_bridge_data *bridge; u8 cap_ptr; + int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; + /* probe for known chipsets */ + for (j = 0; devs[j].chipset_name; j++) { + if (pdev->device == devs[j].device_id) { + printk(KERN_INFO PFX "Detected SiS %s chipset\n", + devs[j].chipset_name); + goto found; + } + } + + printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n", + pdev->device); + return -ENODEV; - printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device); +found: bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; @@ -216,172 +320,12 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev) static struct pci_device_id agp_sis_pci_table[] = { { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5591_AGP, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_530, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_540, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_620, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_630, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_635, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_645, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_646, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_648, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_651, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_655, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_661, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_730, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_735, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_740, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_741, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_745, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_746, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_760, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { } }; diff --git a/trunk/drivers/char/agp/sworks-agp.c b/trunk/drivers/char/agp/sworks-agp.c index 551ef25063ef..55212a3811fd 100644 --- a/trunk/drivers/char/agp/sworks-agp.c +++ b/trunk/drivers/char/agp/sworks-agp.c @@ -455,6 +455,15 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, u32 temp, temp2; u8 cap_ptr = 0; + /* Everything is on func 1 here so we are hardcoding function one */ + bridge_dev = pci_find_slot((unsigned int)pdev->bus->number, + PCI_DEVFN(0, 1)); + if (!bridge_dev) { + printk(KERN_INFO PFX "Detected a Serverworks chipset " + "but could not find the secondary device.\n"); + return -ENODEV; + } + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); switch (pdev->device) { @@ -474,15 +483,6 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, return -ENODEV; } - /* Everything is on func 1 here so we are hardcoding function one */ - bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, - PCI_DEVFN(0, 1)); - if (!bridge_dev) { - printk(KERN_INFO PFX "Detected a Serverworks chipset " - "but could not find the secondary device.\n"); - return -ENODEV; - } - serverworks_private.svrwrks_dev = bridge_dev; serverworks_private.gart_addr_ofs = 0x10; @@ -515,7 +515,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, bridge->driver = &sworks_driver; bridge->dev_private_data = &serverworks_private, - bridge->dev = pci_dev_get(pdev); + bridge->dev = pdev; pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); @@ -525,11 +525,8 @@ static void __devexit agp_serverworks_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - pci_dev_put(bridge->dev); agp_remove_bridge(bridge); agp_put_bridge(bridge); - pci_dev_put(serverworks_private.svrwrks_dev); - serverworks_private.svrwrks_dev = NULL; } static struct pci_device_id agp_serverworks_pci_table[] = { diff --git a/trunk/drivers/char/briq_panel.c b/trunk/drivers/char/briq_panel.c index c70d52ace8b2..8dcf9d20f449 100644 --- a/trunk/drivers/char/briq_panel.c +++ b/trunk/drivers/char/briq_panel.c @@ -202,16 +202,13 @@ static struct miscdevice briq_panel_miscdev = { static int __init briq_panel_init(void) { - struct device_node *root = of_find_node_by_path("/"); + struct device_node *root = find_path_device("/"); const char *machine; int i; machine = get_property(root, "model", NULL); - if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) { - of_node_put(root); + if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) return -ENODEV; - } - of_node_put(root); printk(KERN_INFO "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n", diff --git a/trunk/drivers/char/hvc_console.c b/trunk/drivers/char/hvc_console.c index 0f9ed7b46a6d..a0a88aa23f5b 100644 --- a/trunk/drivers/char/hvc_console.c +++ b/trunk/drivers/char/hvc_console.c @@ -47,6 +47,8 @@ #define HVC_MAJOR 229 #define HVC_MINOR 0 +#define TIMEOUT (10) + /* * Wait this long per iteration while trying to push buffered data to the * hypervisor before allowing the tty to complete a close operation. @@ -102,12 +104,12 @@ static DEFINE_SPINLOCK(hvc_structs_lock); /* * This value is used to assign a tty->index value to a hvc_struct based * upon order of exposure via hvc_probe(), when we can not match it to - * a console candidate registered with hvc_instantiate(). + * a console canidate registered with hvc_instantiate(). */ static int last_hvc = -1; /* - * Do not call this function with either the hvc_structs_lock or the hvc_struct + * Do not call this function with either the hvc_strucst_lock or the hvc_struct * lock held. If successful, this function increments the kobject reference * count against the target hvc_struct so it should be released when finished. */ @@ -160,7 +162,7 @@ void hvc_console_print(struct console *co, const char *b, unsigned count) if (index >= MAX_NR_HVC_CONSOLES) return; - /* This console adapter was removed so it is not usable. */ + /* This console adapter was removed so it is not useable. */ if (vtermnos[index] < 0) return; @@ -218,7 +220,7 @@ struct console hvc_con_driver = { }; /* - * Early console initialization. Precedes driver initialization. + * Early console initialization. Preceeds driver initialization. * * (1) we are first, and the user specified another driver * -- index will remain -1 @@ -255,7 +257,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) if (vtermnos[index] != -1) return -1; - /* make sure no no tty has been registered in this index */ + /* make sure no no tty has been registerd in this index */ hp = hvc_get_by_index(index); if (hp) { kobject_put(&hp->kobj); @@ -265,7 +267,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) vtermnos[index] = vtermno; cons_ops[index] = ops; - /* reserve all indices up to and including this index */ + /* reserve all indices upto and including this index */ if (last_hvc < index) last_hvc = index; @@ -526,7 +528,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count /* * This is actually a contract between the driver and the tty layer outlining - * how much write room the driver can guarantee will be sent OR BUFFERED. This + * how much write room the driver can guarentee will be sent OR BUFFERED. This * driver MUST honor the return value. */ static int hvc_write_room(struct tty_struct *tty) @@ -548,18 +550,6 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) return hp->n_outbuf; } -/* - * timeout will vary between the MIN and MAX values defined here. By default - * and during console activity we will use a default MIN_TIMEOUT of 10. When - * the console is idle, we increase the timeout value on each pass through - * msleep until we reach the max. This may be noticeable as a brief (average - * one second) delay on the console before the console responds to input when - * there has been no input for some time. - */ -#define MIN_TIMEOUT (10) -#define MAX_TIMEOUT (2000) -static u32 timeout = MIN_TIMEOUT; - #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 @@ -652,14 +642,9 @@ static int hvc_poll(struct hvc_struct *hp) bail: spin_unlock_irqrestore(&hp->lock, flags); - if (read_total) { - /* Activity is occurring, so reset the polling backoff value to - a minimum for performance. */ - timeout = MIN_TIMEOUT; - + if (read_total) tty_flip_buffer_push(tty); - } - + return poll_mask; } @@ -703,12 +688,8 @@ int khvcd(void *unused) if (!hvc_kicked) { if (poll_mask == 0) schedule(); - else { - if (timeout < MAX_TIMEOUT) - timeout += (timeout >> 6) + 1; - - msleep_interruptible(timeout); - } + else + msleep_interruptible(TIMEOUT); } __set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); @@ -813,7 +794,7 @@ int __devexit hvc_remove(struct hvc_struct *hp) /* * We 'put' the instance that was grabbed when the kobject instance - * was initialized using kobject_init(). Let the last holder of this + * was intialized using kobject_init(). Let the last holder of this * kobject cause it to be removed, which will probably be the tty_hangup * below. */ @@ -869,7 +850,7 @@ int __init hvc_init(void) } module_init(hvc_init); -/* This isn't particularly necessary due to this being a console driver +/* This isn't particularily necessary due to this being a console driver * but it is nice to be thorough. */ static void __exit hvc_exit(void) diff --git a/trunk/drivers/char/hvc_iseries.c b/trunk/drivers/char/hvc_iseries.c index ec420fe8a908..f144a947bd17 100644 --- a/trunk/drivers/char/hvc_iseries.c +++ b/trunk/drivers/char/hvc_iseries.c @@ -575,7 +575,7 @@ static int hvc_find_vtys(void) (num_found >= VTTY_PORTS)) break; - vtermno = of_get_property(vty, "reg", NULL); + vtermno = get_property(vty, "reg", NULL); if (!vtermno) continue; diff --git a/trunk/drivers/char/hvc_vio.c b/trunk/drivers/char/hvc_vio.c index 94a542e20efb..f9c00844d2bf 100644 --- a/trunk/drivers/char/hvc_vio.c +++ b/trunk/drivers/char/hvc_vio.c @@ -153,7 +153,7 @@ static int hvc_find_vtys(void) if (num_found >= MAX_NR_HVC_CONSOLES) break; - vtermno = of_get_property(vty, "reg", NULL); + vtermno = get_property(vty, "reg", NULL); if (!vtermno) continue; diff --git a/trunk/drivers/char/hvsi.c b/trunk/drivers/char/hvsi.c index d5a752da322f..50315d6364fd 100644 --- a/trunk/drivers/char/hvsi.c +++ b/trunk/drivers/char/hvsi.c @@ -1279,8 +1279,8 @@ static int __init hvsi_console_init(void) struct hvsi_struct *hp; const uint32_t *vtermno, *irq; - vtermno = of_get_property(vty, "reg", NULL); - irq = of_get_property(vty, "interrupts", NULL); + vtermno = get_property(vty, "reg", NULL); + irq = get_property(vty, "interrupts", NULL); if (!vtermno || !irq) continue; diff --git a/trunk/drivers/char/hw_random/via-rng.c b/trunk/drivers/char/hw_random/via-rng.c index ec435cb25c4f..9ebf84d18655 100644 --- a/trunk/drivers/char/hw_random/via-rng.c +++ b/trunk/drivers/char/hw_random/via-rng.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/char/keyboard.c b/trunk/drivers/char/keyboard.c index c06e86ad1dab..cb8d691576da 100644 --- a/trunk/drivers/char/keyboard.c +++ b/trunk/drivers/char/keyboard.c @@ -41,6 +41,7 @@ #include #include +static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); /* @@ -158,41 +159,65 @@ static int sysrq_alt_use; static int sysrq_alt; /* - * Translation of scancodes to keycodes. We set them on only the first - * keyboard in the list that accepts the scancode and keycode. - * Explanation for not choosing the first attached keyboard anymore: - * USB keyboards for example have two event devices: one for all "normal" - * keys and one for extra function keys (like "volume up", "make coffee", - * etc.). So this means that scancodes for the extra function keys won't - * be valid for the first event device, but will be for the second. + * Translation of scancodes to keycodes. We set them on only the first attached + * keyboard - for per-keyboard setting, /dev/input/event is more useful. */ int getkeycode(unsigned int scancode) { - struct input_handle *handle; - int keycode; - int error = -ENODEV; + struct list_head *node; + struct input_dev *dev = NULL; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = handle->dev->getkeycode(handle->dev, scancode, &keycode); - if (!error) - return keycode; + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + if (handle->dev->keycodesize) { + dev = handle->dev; + break; + } } - return error; + if (!dev) + return -ENODEV; + + if (scancode >= dev->keycodemax) + return -EINVAL; + + return INPUT_KEYCODE(dev, scancode); } int setkeycode(unsigned int scancode, unsigned int keycode) { - struct input_handle *handle; - int error = -ENODEV; + struct list_head *node; + struct input_dev *dev = NULL; + unsigned int i, oldkey; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = handle->dev->setkeycode(handle->dev, scancode, keycode); - if (!error) + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + if (handle->dev->keycodesize) { + dev = handle->dev; break; + } } - return error; + if (!dev) + return -ENODEV; + + if (scancode >= dev->keycodemax) + return -EINVAL; + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) + return -EINVAL; + + oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); + + clear_bit(oldkey, dev->keybit); + set_bit(keycode, dev->keybit); + + for (i = 0; i < dev->keycodemax; i++) + if (INPUT_KEYCODE(dev,i) == oldkey) + set_bit(oldkey, dev->keybit); + + return 0; } /* @@ -200,9 +225,10 @@ int setkeycode(unsigned int scancode, unsigned int keycode) */ static void kd_nosound(unsigned long ignored) { - struct input_handle *handle; + struct list_head *node; - list_for_each_entry(handle, &kbd_handler.h_list, h_node) { + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) input_inject_event(handle, EV_SND, SND_TONE, 0); @@ -1135,7 +1161,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) - if (keycode < BTN_MISC && printk_ratelimit()) + if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ @@ -1259,11 +1285,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static int kbd_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *kbd_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; - int error; int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) @@ -1271,37 +1297,24 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev, break; if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) - return -ENODEV; + return NULL; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) - return -ENOMEM; + return NULL; handle->dev = dev; handle->handler = handler; handle->name = "kbd"; - error = input_register_handle(handle); - if (error) - goto err_free_handle; - - error = input_open_device(handle); - if (error) - goto err_unregister_handle; - - return 0; + input_open_device(handle); - err_unregister_handle: - input_unregister_handle(handle); - err_free_handle: - kfree(handle); - return error; + return handle; } static void kbd_disconnect(struct input_handle *handle) { input_close_device(handle); - input_unregister_handle(handle); kfree(handle); } diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 80a01150b86c..a61fb6da5d03 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -1338,23 +1338,43 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */ - case TIOCMIWAIT: - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* note the counters on entry */ - spin_unlock_irqrestore(&info->slock, flags); - - wait_event_interruptible(info->delta_msr_wait, ({ - cprev = cnow; + case TIOCMIWAIT: { + DECLARE_WAITQUEUE(wait, current); + int ret; spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* atomic copy */ + cprev = info->icount; /* note the counters on entry */ spin_unlock_irqrestore(&info->slock, flags); - ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)); - })); - break; + add_wait_queue(&info->delta_msr_wait, &wait); + while (1) { + spin_lock_irqsave(&info->slock, flags); + cnow = info->icount; /* atomic copy */ + spin_unlock_irqrestore(&info->slock, flags); + + set_current_state(TASK_INTERRUPTIBLE); + if (((arg & TIOCM_RNG) && + (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && + (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && + (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && + (cnow.cts != cprev.cts))) { + ret = 0; + break; + } + /* see if a signal did it */ + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + cprev = cnow; + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->delta_msr_wait, &wait); + break; + } + /* NOTREACHED */ /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct diff --git a/trunk/drivers/char/mxser_new.c b/trunk/drivers/char/mxser_new.c index f7603b6aeb87..9af07e4999d5 100644 --- a/trunk/drivers/char/mxser_new.c +++ b/trunk/drivers/char/mxser_new.c @@ -1758,23 +1758,43 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */ - case TIOCMIWAIT: + case TIOCMIWAIT: { + DECLARE_WAITQUEUE(wait, current); + int ret; spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* note the counters on entry */ + cprev = info->icount; /* note the counters on entry */ spin_unlock_irqrestore(&info->slock, flags); - wait_event_interruptible(info->delta_msr_wait, ({ - cprev = cnow; + add_wait_queue(&info->delta_msr_wait, &wait); + while (1) { spin_lock_irqsave(&info->slock, flags); cnow = info->icount; /* atomic copy */ spin_unlock_irqrestore(&info->slock, flags); - ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)); - })); + set_current_state(TASK_INTERRUPTIBLE); + if (((arg & TIOCM_RNG) && + (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && + (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && + (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && + (cnow.cts != cprev.cts))) { + ret = 0; + break; + } + /* see if a signal did it */ + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + cprev = cnow; + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->delta_msr_wait, &wait); break; + } + /* NOTREACHED */ /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct @@ -2210,14 +2230,7 @@ static void mxser_receive_chars(struct mxser_port *port, int *status) port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; - /* - * We are called from an interrupt context with &port->slock - * being held. Drop it temporarily in order to prevent - * recursive locking. - */ - spin_unlock(&port->slock); tty_flip_buffer_push(tty); - spin_lock(&port->slock); } static void mxser_transmit_chars(struct mxser_port *port) diff --git a/trunk/drivers/char/pcmcia/synclink_cs.c b/trunk/drivers/char/pcmcia/synclink_cs.c index 13808f6083a0..8d025e9b5bce 100644 --- a/trunk/drivers/char/pcmcia/synclink_cs.c +++ b/trunk/drivers/char/pcmcia/synclink_cs.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -4168,7 +4169,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); /* copy data to device buffers */ - skb_copy_from_linear_data(skb, info->tx_buf, skb->len); + memcpy(info->tx_buf, skb->data, skb->len); info->tx_get = 0; info->tx_put = info->tx_count = skb->len; diff --git a/trunk/drivers/char/random.c b/trunk/drivers/char/random.c index 46c1b97748b6..b9dc7aa1dfb3 100644 --- a/trunk/drivers/char/random.c +++ b/trunk/drivers/char/random.c @@ -881,15 +881,15 @@ EXPORT_SYMBOL(get_random_bytes); */ static void init_std_data(struct entropy_store *r) { - ktime_t now; + struct timeval tv; unsigned long flags; spin_lock_irqsave(&r->lock, flags); r->entropy_count = 0; spin_unlock_irqrestore(&r->lock, flags); - now = ktime_get_real(); - add_entropy_words(r, (__u32 *)&now, sizeof(now)/4); + do_gettimeofday(&tv); + add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); add_entropy_words(r, (__u32 *)utsname(), sizeof(*(utsname()))/4); } @@ -911,12 +911,14 @@ void rand_initialize_irq(int irq) return; /* - * If kzalloc returns null, we just won't use that entropy + * If kmalloc returns null, we just won't use that entropy * source. */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) + state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) { + memset(state, 0, sizeof(struct timer_rand_state)); irq_timer_state[irq] = state; + } } #ifdef CONFIG_BLOCK @@ -925,12 +927,14 @@ void rand_initialize_disk(struct gendisk *disk) struct timer_rand_state *state; /* - * If kzalloc returns null, we just won't use that entropy + * If kmalloc returns null, we just won't use that entropy * source. */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) + state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) { + memset(state, 0, sizeof(struct timer_rand_state)); disk->random = state; + } } #endif @@ -1465,6 +1469,7 @@ late_initcall(seqgen_init); __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, __be16 sport, __be16 dport) { + struct timeval tv; __u32 seq; __u32 hash[12]; struct keydata *keyptr = get_keyptr(); @@ -1480,7 +1485,8 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; - seq += ktime_get_real().tv64; + do_gettimeofday(&tv); + seq += tv.tv_usec + tv.tv_sec * 1000000; return seq; } @@ -1515,6 +1521,7 @@ __u32 secure_ip_id(__be32 daddr) __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) { + struct timeval tv; __u32 seq; __u32 hash[4]; struct keydata *keyptr = get_keyptr(); @@ -1536,11 +1543,12 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * As close as possible to RFC 793, which * suggests using a 250 kHz clock. * Further reading shows this assumes 2 Mb/s networks. - * For 10 Gb/s Ethernet, a 1 GHz clock is appropriate. + * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. * That's funny, Linux has one built in! Use it! * (Networks are faster now - should this be increased?) */ - seq += ktime_get_real().tv64; + do_gettimeofday(&tv); + seq += tv.tv_usec + tv.tv_sec * 1000000; #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", saddr, daddr, sport, dport, seq); @@ -1548,6 +1556,8 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, return seq; } +EXPORT_SYMBOL(secure_tcp_sequence_number); + /* Generate secure starting point for ephemeral IPV4 transport port search */ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) { @@ -1588,6 +1598,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport) { + struct timeval tv; u64 seq; __u32 hash[4]; struct keydata *keyptr = get_keyptr(); @@ -1600,7 +1611,8 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, seq = half_md4_transform(hash, keyptr->secret); seq |= ((u64)keyptr->count) << (32 - HASH_BITS); - seq += ktime_get_real().tv64; + do_gettimeofday(&tv); + seq += tv.tv_usec + tv.tv_sec * 1000000; seq &= (1ull << 48) - 1; #if 0 printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n", diff --git a/trunk/drivers/char/sonypi.c b/trunk/drivers/char/sonypi.c index 3ef593a9015f..78237577b05a 100644 --- a/trunk/drivers/char/sonypi.c +++ b/trunk/drivers/char/sonypi.c @@ -1,8 +1,6 @@ /* * Sony Programmable I/O Control Device driver for VAIO * - * Copyright (C) 2007 Mattia Dongili - * * Copyright (C) 2001-2005 Stelian Pop * * Copyright (C) 2005 Narayanan R S @@ -97,11 +95,6 @@ module_param(useinput, int, 0444); MODULE_PARM_DESC(useinput, "set this if you would like sonypi to feed events to the input subsystem"); -static int check_ioport = 1; -module_param(check_ioport, int, 0444); -MODULE_PARM_DESC(check_ioport, - "set this to 0 if you think the automatic ioport check for sony-laptop is wrong"); - #define SONYPI_DEVICE_MODEL_TYPE1 1 #define SONYPI_DEVICE_MODEL_TYPE2 2 #define SONYPI_DEVICE_MODEL_TYPE3 3 @@ -484,7 +477,7 @@ static struct sonypi_device { u16 evtype_offset; int camera_power; int bluetooth_power; - struct mutex lock; + struct semaphore lock; struct kfifo *fifo; spinlock_t fifo_lock; wait_queue_head_t fifo_proc_list; @@ -891,7 +884,7 @@ int sonypi_camera_command(int command, u8 value) if (!camera) return -EIO; - mutex_lock(&sonypi_device.lock); + down(&sonypi_device.lock); switch (command) { case SONYPI_COMMAND_SETCAMERA: @@ -926,7 +919,7 @@ int sonypi_camera_command(int command, u8 value) command); break; } - mutex_unlock(&sonypi_device.lock); + up(&sonypi_device.lock); return 0; } @@ -945,20 +938,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on) static int sonypi_misc_release(struct inode *inode, struct file *file) { sonypi_misc_fasync(-1, file, 0); - mutex_lock(&sonypi_device.lock); + down(&sonypi_device.lock); sonypi_device.open_count--; - mutex_unlock(&sonypi_device.lock); + up(&sonypi_device.lock); return 0; } static int sonypi_misc_open(struct inode *inode, struct file *file) { - mutex_lock(&sonypi_device.lock); + down(&sonypi_device.lock); /* Flush input queue on first open */ if (!sonypi_device.open_count) kfifo_reset(sonypi_device.fifo); sonypi_device.open_count++; - mutex_unlock(&sonypi_device.lock); + up(&sonypi_device.lock); return 0; } @@ -1008,7 +1001,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, u8 val8; u16 val16; - mutex_lock(&sonypi_device.lock); + down(&sonypi_device.lock); switch (cmd) { case SONYPI_IOCGBRT: if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) { @@ -1108,7 +1101,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, default: ret = -EINVAL; } - mutex_unlock(&sonypi_device.lock); + up(&sonypi_device.lock); return ret; } @@ -1267,28 +1260,6 @@ static int __devinit sonypi_create_input_devices(void) static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, const struct sonypi_ioport_list *ioport_list) { - /* try to detect if sony-laptop is being used and thus - * has already requested one of the known ioports. - * As in the deprecated check_region this is racy has we have - * multiple ioports available and one of them can be requested - * between this check and the subsequent request. Anyway, as an - * attempt to be some more user-friendly as we currently are, - * this is enough. - */ - const struct sonypi_ioport_list *check = ioport_list; - while (check_ioport && check->port1) { - if (!request_region(check->port1, - sonypi_device.region_size, - "Sony Programable I/O Device Check")) { - printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? " - "if not use check_ioport=0\n", - check->port1); - return -EBUSY; - } - release_region(check->port1, sonypi_device.region_size); - check++; - } - while (ioport_list->port1) { if (request_region(ioport_list->port1, @@ -1350,10 +1321,6 @@ static int __devinit sonypi_probe(struct platform_device *dev) struct pci_dev *pcidev; int error; - printk(KERN_WARNING "sonypi: please try the sony-laptop module instead " - "and report failures, see also " - "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n"); - spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, &sonypi_device.fifo_lock); @@ -1363,7 +1330,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) } init_waitqueue_head(&sonypi_device.fifo_proc_list); - mutex_init(&sonypi_device.lock); + init_MUTEX(&sonypi_device.lock); sonypi_device.bluetooth_power = -1; if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index 9f273f032b0f..bb9a43c6cf3d 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -19,6 +19,7 @@ * */ #include +#include #include #include #include diff --git a/trunk/drivers/char/tpm/tpm_atmel.h b/trunk/drivers/char/tpm/tpm_atmel.h index 3c852009196e..aefd683c60b7 100644 --- a/trunk/drivers/char/tpm/tpm_atmel.h +++ b/trunk/drivers/char/tpm/tpm_atmel.h @@ -53,8 +53,8 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) } reg = get_property(dn, "reg", ®len); - naddrc = of_n_addr_cells(dn); - nsizec = of_n_size_cells(dn); + naddrc = prom_n_addr_cells(dn); + nsizec = prom_n_size_cells(dn); of_node_put(dn); diff --git a/trunk/drivers/char/watchdog/Kconfig b/trunk/drivers/char/watchdog/Kconfig index 60198a78974c..e812aa129e28 100644 --- a/trunk/drivers/char/watchdog/Kconfig +++ b/trunk/drivers/char/watchdog/Kconfig @@ -548,7 +548,7 @@ config MV64X60_WDT depends on WATCHDOG && MV64X60 config BOOKE_WDT - bool "PowerPC Book-E Watchdog Timer" + tristate "PowerPC Book-E Watchdog Timer" depends on WATCHDOG && (BOOKE || 4xx) ---help--- Please see Documentation/watchdog/watchdog-api.txt for diff --git a/trunk/drivers/char/watchdog/sc1200wdt.c b/trunk/drivers/char/watchdog/sc1200wdt.c index 2f7ba7a514fe..1e4a8d751a71 100644 --- a/trunk/drivers/char/watchdog/sc1200wdt.c +++ b/trunk/drivers/char/watchdog/sc1200wdt.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/char/watchdog/scx200_wdt.c b/trunk/drivers/char/watchdog/scx200_wdt.c index d4fd0fa2f176..fc0e0347f9d2 100644 --- a/trunk/drivers/char/watchdog/scx200_wdt.c +++ b/trunk/drivers/char/watchdog/scx200_wdt.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/trunk/drivers/clocksource/acpi_pm.c b/trunk/drivers/clocksource/acpi_pm.c index 5cfcff532545..5ac309ee7f05 100644 --- a/trunk/drivers/clocksource/acpi_pm.c +++ b/trunk/drivers/clocksource/acpi_pm.c @@ -26,7 +26,7 @@ /* * The I/O port the PMTMR resides at. * The location is detected during setup_arch(), - * in arch/i386/kernel/acpi/boot.c + * in arch/i386/acpi/boot.c */ u32 pmtmr_ioport __read_mostly; diff --git a/trunk/drivers/connector/connector.c b/trunk/drivers/connector/connector.c index a7b9e9bb3e8d..a905f7820331 100644 --- a/trunk/drivers/connector/connector.c +++ b/trunk/drivers/connector/connector.c @@ -212,7 +212,7 @@ static void cn_rx_skb(struct sk_buff *__skb) skb = skb_get(__skb); if (skb->len >= NLMSG_SPACE(0)) { - nlh = nlmsg_hdr(skb); + nlh = (struct nlmsghdr *)skb->data; if (nlh->nlmsg_len < sizeof(struct cn_msg) || skb->len < nlh->nlmsg_len || @@ -448,7 +448,7 @@ static int __devinit cn_init(void) dev->nls = netlink_kernel_create(NETLINK_CONNECTOR, CN_NETLINK_USERS + 0xf, - dev->input, NULL, THIS_MODULE); + dev->input, THIS_MODULE); if (!dev->nls) return -EIO; diff --git a/trunk/drivers/cpufreq/Kconfig b/trunk/drivers/cpufreq/Kconfig index 993fa7b89253..d155e81b5c97 100644 --- a/trunk/drivers/cpufreq/Kconfig +++ b/trunk/drivers/cpufreq/Kconfig @@ -9,9 +9,6 @@ config CPU_FREQ clock speed, you need to either enable a dynamic cpufreq governor (see below) after boot, or use a userspace tool. - To compile this driver as a module, choose M here: the - module will be called cpufreq. - For details, take a look at . If in doubt, say N. @@ -19,7 +16,7 @@ config CPU_FREQ if CPU_FREQ config CPU_FREQ_TABLE - tristate + tristate config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" @@ -35,26 +32,19 @@ config CPU_FREQ_DEBUG 4 to activate CPUfreq governor debugging config CPU_FREQ_STAT - tristate "CPU frequency translation statistics" - select CPU_FREQ_TABLE - default y - help - This driver exports CPU frequency statistics information through sysfs - file system. - - To compile this driver as a module, choose M here: the - module will be called cpufreq_stats. - - If in doubt, say N. + tristate "CPU frequency translation statistics" + select CPU_FREQ_TABLE + default y + help + This driver exports CPU frequency statistics information through sysfs + file system config CPU_FREQ_STAT_DETAILS - bool "CPU frequency translation statistics details" - depends on CPU_FREQ_STAT - help - This will show detail CPU frequency translation table in sysfs file - system. - - If in doubt, say N. + bool "CPU frequency translation statistics details" + depends on CPU_FREQ_STAT + help + This will show detail CPU frequency translation table in sysfs file + system # Note that it is not currently possible to set the other governors (such as ondemand) # as the default, since if they fail to initialise, cpufreq will be @@ -88,38 +78,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE endchoice config CPU_FREQ_GOV_PERFORMANCE - tristate "'performance' governor" - help + tristate "'performance' governor" + help This cpufreq governor sets the frequency statically to the highest available CPU frequency. - To compile this driver as a module, choose M here: the - module will be called cpufreq_performance. - If in doubt, say Y. config CPU_FREQ_GOV_POWERSAVE - tristate "'powersave' governor" - help + tristate "'powersave' governor" + help This cpufreq governor sets the frequency statically to the lowest available CPU frequency. - To compile this driver as a module, choose M here: the - module will be called cpufreq_powersave. - If in doubt, say Y. config CPU_FREQ_GOV_USERSPACE - tristate "'userspace' governor for userspace frequency scaling" - help + tristate "'userspace' governor for userspace frequency scaling" + help Enable this cpufreq governor when you either want to set the CPU frequency manually or when an userspace program shall be able to set the CPU dynamically, like on LART . - To compile this driver as a module, choose M here: the - module will be called cpufreq_userspace. - For details, take a look at . If in doubt, say Y. @@ -135,9 +116,6 @@ config CPU_FREQ_GOV_ONDEMAND do fast frequency switching (i.e, very low latency frequency transitions). - To compile this driver as a module, choose M here: the - module will be called cpufreq_ondemand. - For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. @@ -158,9 +136,6 @@ config CPU_FREQ_GOV_CONSERVATIVE step-by-step latency issues between the minimum and maximum frequency transitions in the CPU) you will probably want to use this governor. - To compile this driver as a module, choose M here: the - module will be called cpufreq_conservative. - For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. diff --git a/trunk/drivers/cpufreq/cpufreq.c b/trunk/drivers/cpufreq/cpufreq.c index 893dbaf386fb..3162010900c9 100644 --- a/trunk/drivers/cpufreq/cpufreq.c +++ b/trunk/drivers/cpufreq/cpufreq.c @@ -768,9 +768,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) unlock_policy_rwsem_write(cpu); goto err_out; } - policy->user_policy.min = policy->cpuinfo.min_freq; - policy->user_policy.max = policy->cpuinfo.max_freq; - policy->user_policy.governor = policy->governor; #ifdef CONFIG_SMP for_each_cpu_mask(j, policy->cpus) { @@ -861,13 +858,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) policy->governor = NULL; /* to assure that the starting sequence is * run in cpufreq_set_policy */ - - /* set default policy */ - ret = __cpufreq_set_policy(policy, &new_policy); - policy->user_policy.policy = policy->policy; - unlock_policy_rwsem_write(cpu); + /* set default policy */ + ret = cpufreq_set_policy(&new_policy); if (ret) { dprintk("setting policy failed\n"); goto err_out_unregister; @@ -1625,6 +1619,43 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, return ret; } +/** + * cpufreq_set_policy - set a new CPUFreq policy + * @policy: policy to be set. + * + * Sets a new CPU frequency and voltage scaling policy. + */ +int cpufreq_set_policy(struct cpufreq_policy *policy) +{ + int ret = 0; + struct cpufreq_policy *data; + + if (!policy) + return -EINVAL; + + data = cpufreq_cpu_get(policy->cpu); + if (!data) + return -EINVAL; + + if (unlikely(lock_policy_rwsem_write(policy->cpu))) + return -EINVAL; + + + ret = __cpufreq_set_policy(data, policy); + data->user_policy.min = data->min; + data->user_policy.max = data->max; + data->user_policy.policy = data->policy; + data->user_policy.governor = data->governor; + + unlock_policy_rwsem_write(policy->cpu); + + cpufreq_cpu_put(data); + + return ret; +} +EXPORT_SYMBOL(cpufreq_set_policy); + + /** * cpufreq_update_policy - re-evaluate an existing cpufreq policy * @cpu: CPU which shall be re-evaluated diff --git a/trunk/drivers/crypto/Kconfig b/trunk/drivers/crypto/Kconfig index f21fe66c9eef..ff8c4beaace4 100644 --- a/trunk/drivers/crypto/Kconfig +++ b/trunk/drivers/crypto/Kconfig @@ -1,10 +1,10 @@ menu "Hardware crypto devices" config CRYPTO_DEV_PADLOCK - bool "Support for VIA PadLock ACE" + tristate "Support for VIA PadLock ACE" depends on X86_32 select CRYPTO_ALGAPI - default y + default m help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -14,6 +14,16 @@ config CRYPTO_DEV_PADLOCK The instructions are used only when the CPU supports them. Otherwise software encryption is used. + Selecting M for this option will compile a helper module + padlock.ko that should autoload all below configured + algorithms. Don't worry if your hardware does not support + some or all of them. In such case padlock.ko will + simply write a single line into the kernel log informing + about its failure but everything will keep working fine. + + If you are unsure, say M. The compiled module will be + called padlock.ko + config CRYPTO_DEV_PADLOCK_AES tristate "PadLock driver for AES algorithm" depends on CRYPTO_DEV_PADLOCK @@ -45,7 +55,7 @@ source "arch/s390/crypto/Kconfig" config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" - depends on X86_32 && PCI + depends on CRYPTO && X86_32 && PCI select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER default m diff --git a/trunk/drivers/crypto/Makefile b/trunk/drivers/crypto/Makefile index d070030f7d7e..6059cf869414 100644 --- a/trunk/drivers/crypto/Makefile +++ b/trunk/drivers/crypto/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o diff --git a/trunk/drivers/crypto/padlock.c b/trunk/drivers/crypto/padlock.c new file mode 100644 index 000000000000..d6d7dd5bb98c --- /dev/null +++ b/trunk/drivers/crypto/padlock.c @@ -0,0 +1,58 @@ +/* + * Cryptographic API. + * + * Support for VIA PadLock hardware crypto engine. + * + * Copyright (c) 2006 Michal Ludvig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "padlock.h" + +static int __init padlock_init(void) +{ + int success = 0; + + if (crypto_has_cipher("aes-padlock", 0, 0)) + success++; + + if (crypto_has_hash("sha1-padlock", 0, 0)) + success++; + + if (crypto_has_hash("sha256-padlock", 0, 0)) + success++; + + if (!success) { + printk(KERN_WARNING PFX "No VIA PadLock drivers have been loaded.\n"); + return -ENODEV; + } + + printk(KERN_NOTICE PFX "%d drivers are available.\n", success); + + return 0; +} + +static void __exit padlock_fini(void) +{ +} + +module_init(padlock_init); +module_exit(padlock_fini); + +MODULE_DESCRIPTION("Load all configured PadLock algorithms."); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Ludvig"); + diff --git a/trunk/drivers/firmware/efivars.c b/trunk/drivers/firmware/efivars.c index 1324984a4c35..c6281ccd4fe7 100644 --- a/trunk/drivers/firmware/efivars.c +++ b/trunk/drivers/firmware/efivars.c @@ -409,7 +409,7 @@ static struct kobj_type ktype_efivar = { }; static ssize_t -dummy(struct kset *kset, char *buf) +dummy(struct subsystem *sub, char *buf) { return -ENODEV; } @@ -422,7 +422,7 @@ efivar_unregister(struct efivar_entry *var) static ssize_t -efivar_create(struct kset *kset, const char *buf, size_t count) +efivar_create(struct subsystem *sub, const char *buf, size_t count) { struct efi_variable *new_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -480,7 +480,7 @@ efivar_create(struct kset *kset, const char *buf, size_t count) } static ssize_t -efivar_delete(struct kset *kset, const char *buf, size_t count) +efivar_delete(struct subsystem *sub, const char *buf, size_t count) { struct efi_variable *del_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -551,11 +551,11 @@ static struct subsys_attribute *var_subsys_attrs[] = { * the efivars driver */ static ssize_t -systab_read(struct kset *kset, char *buf) +systab_read(struct subsystem *entry, char *buf) { char *str = buf; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; if (efi.mps != EFI_INVALID_TABLE_ADDR) @@ -687,7 +687,7 @@ efivars_init(void) goto out_free; } - kobj_set_kset_s(&vars_subsys, efi_subsys); + kset_set_kset_s(&vars_subsys, efi_subsys); error = subsystem_register(&vars_subsys); diff --git a/trunk/drivers/hid/Kconfig b/trunk/drivers/hid/Kconfig index 8fbe9fdac128..850788f4dd2e 100644 --- a/trunk/drivers/hid/Kconfig +++ b/trunk/drivers/hid/Kconfig @@ -36,7 +36,5 @@ config HID_DEBUG If unsure, say N -source "drivers/hid/usbhid/Kconfig" - endmenu diff --git a/trunk/drivers/hid/Makefile b/trunk/drivers/hid/Makefile index 68d1376a53fb..52e97d8f3c95 100644 --- a/trunk/drivers/hid/Makefile +++ b/trunk/drivers/hid/Makefile @@ -6,7 +6,3 @@ hid-objs := hid-core.o hid-input.o obj-$(CONFIG_HID) += hid.o hid-$(CONFIG_HID_DEBUG) += hid-debug.o -obj-$(CONFIG_USB_HID) += usbhid/ -obj-$(CONFIG_USB_MOUSE) += usbhid/ -obj-$(CONFIG_USB_KBD) += usbhid/ - diff --git a/trunk/drivers/hid/hid-core.c b/trunk/drivers/hid/hid-core.c index 62e21cc73938..1cca32f46947 100644 --- a/trunk/drivers/hid/hid-core.c +++ b/trunk/drivers/hid/hid-core.c @@ -4,7 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2006 Jiri Kosina */ /* @@ -37,7 +37,7 @@ */ #define DRIVER_VERSION "v2.6" -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" #define DRIVER_DESC "HID core driver" #define DRIVER_LICENSE "GPL" @@ -872,13 +872,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data) unsigned count = field->report_count; unsigned offset = field->report_offset; unsigned size = field->report_size; - unsigned bitsused = offset + count * size; unsigned n; - /* make sure the unused bits in the last byte are zeros */ - if (count > 0 && size > 0 && (bitsused % 8) != 0) - data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1; - for (n = 0; n < count; n++) { if (field->logical_minimum < 0) /* signed values */ implement(data, offset + n * size, size, s32ton(field->value[n], size)); diff --git a/trunk/drivers/hid/hid-input.c b/trunk/drivers/hid/hid-input.c index a19b65ed3119..c8434023ba65 100644 --- a/trunk/drivers/hid/hid-input.c +++ b/trunk/drivers/hid/hid-input.c @@ -431,15 +431,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x000: goto ignore; case 0x034: map_key_clear(KEY_SLEEP); break; case 0x036: map_key_clear(BTN_MISC); break; - /* - * The next three are reported by Belkin wireless - * keyboard (1020:0006). These values are "reserved" - * in HUT 1.12. - */ - case 0x03a: map_key_clear(KEY_SOUND); break; - case 0x03b: map_key_clear(KEY_CAMERA); break; - case 0x03c: map_key_clear(KEY_DOCUMENTS); break; - case 0x040: map_key_clear(KEY_MENU); break; case 0x045: map_key_clear(KEY_RADIO); break; @@ -540,26 +531,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x302: map_key_clear(KEY_PROG2); break; case 0x303: map_key_clear(KEY_PROG3); break; - /* Reported on certain Logitech wireless keyboards */ - case 0x1001: map_key_clear(KEY_MESSENGER); break; - case 0x1003: map_key_clear(KEY_SOUND); break; - case 0x1004: map_key_clear(KEY_VIDEO); break; - case 0x1005: map_key_clear(KEY_AUDIO); break; - case 0x100a: map_key_clear(KEY_DOCUMENTS); break; - case 0x1011: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x1012: map_key_clear(KEY_NEXTSONG); break; - case 0x1013: map_key_clear(KEY_CAMERA); break; - case 0x1014: map_key_clear(KEY_MESSENGER); break; - case 0x1015: map_key_clear(KEY_RECORD); break; - case 0x1016: map_key_clear(KEY_PLAYER); break; - case 0x1017: map_key_clear(KEY_EJECTCD); break; - case 0x1019: map_key_clear(KEY_PROG1); break; - case 0x101a: map_key_clear(KEY_PROG2); break; - case 0x101b: map_key_clear(KEY_PROG3); break; + /* Reported on Logitech S510 wireless keyboard */ case 0x101f: map_key_clear(KEY_ZOOMIN); break; case 0x1020: map_key_clear(KEY_ZOOMOUT); break; case 0x1021: map_key_clear(KEY_ZOOMRESET); break; - case 0x1023: map_key_clear(KEY_CLOSE); break; /* this one is marked as 'Rotate' */ case 0x1028: map_key_clear(KEY_ANGLE); break; case 0x1029: map_key_clear(KEY_SHUFFLE); break; diff --git a/trunk/drivers/hid/usbhid/Kconfig b/trunk/drivers/hid/usbhid/Kconfig deleted file mode 100644 index 7c87bdc538bc..000000000000 --- a/trunk/drivers/hid/usbhid/Kconfig +++ /dev/null @@ -1,149 +0,0 @@ -comment "USB Input Devices" - depends on USB - -config USB_HID - tristate "USB Human Interface Device (full HID) support" - default y - depends on USB && INPUT - select HID - ---help--- - Say Y here if you want full HID support to connect USB keyboards, - mice, joysticks, graphic tablets, or any other HID based devices - to your computer via USB, as well as Uninterruptible Power Supply - (UPS) and monitor control devices. - - You can't use this driver and the HIDBP (Boot Protocol) keyboard - and mouse drivers at the same time. More information is available: - . - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called usbhid. - -comment "Input core support is needed for USB HID input layer or HIDBP support" - depends on USB_HID && INPUT=n - -config USB_HIDINPUT_POWERBOOK - bool "Enable support for iBook/PowerBook special keys" - default n - depends on USB_HID - help - Say Y here if you want support for the special keys (Fn, Numlock) on - Apple iBooks and PowerBooks. - - If unsure, say N. - -config HID_FF - bool "Force feedback support (EXPERIMENTAL)" - depends on USB_HID && EXPERIMENTAL - help - Say Y here is you want force feedback support for a few HID devices. - See below for a list of supported devices. - - See for a description of the force - feedback API. - - If unsure, say N. - -config HID_PID - bool "PID device support" - depends on HID_FF - help - Say Y here if you have a PID-compliant device and wish to enable force - feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such - devices. - -config LOGITECH_FF - bool "Logitech devices support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have one of these devices: - - Logitech WingMan Cordless RumblePad - - Logitech WingMan Cordless RumblePad 2 - - Logitech WingMan Force 3D - - Logitech Formula Force EX - - Logitech MOMO Force wheel - - and if you want to enable force feedback for them. - Note: if you say N here, this device will still be supported, but without - force feedback. - -config PANTHERLORD_FF - bool "PantherLord USB/PS2 2in1 Adapter support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want - to enable force feedback support for it. - -config THRUSTMASTER_FF - bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" - depends on HID_FF && EXPERIMENTAL - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, - and want to enable force feedback support for it. - Note: if you say N here, this device will still be supported, but without - force feedback. - -config ZEROPLUS_FF - bool "Zeroplus based game controller support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a Zeroplus based game controller and want to - enable force feedback for it. - -config USB_HIDDEV - bool "/dev/hiddev raw HID device support" - depends on USB_HID - help - Say Y here if you want to support HID devices (from the USB - specification standpoint) that aren't strictly user interface - devices, like monitor controls and Uninterruptable Power Supplies. - - This module supports these devices separately using a separate - event interface on /dev/usb/hiddevX (char 180:96 to 180:111). - - If unsure, say Y. - -menu "USB HID Boot Protocol drivers" - depends on USB!=n && USB_HID!=y - -config USB_KBD - tristate "USB HIDBP Keyboard (simple Boot) support" - depends on USB && INPUT - ---help--- - Say Y here only if you are absolutely sure that you don't want - to use the generic HID driver for your USB keyboard and prefer - to use the keyboard in its limited Boot Protocol mode instead. - - This is almost certainly not what you want. This is mostly - useful for embedded applications or simple keyboards. - - To compile this driver as a module, choose M here: the - module will be called usbkbd. - - If even remotely unsure, say N. - -config USB_MOUSE - tristate "USB HIDBP Mouse (simple Boot) support" - depends on USB && INPUT - ---help--- - Say Y here only if you are absolutely sure that you don't want - to use the generic HID driver for your USB mouse and prefer - to use the mouse in its limited Boot Protocol mode instead. - - This is almost certainly not what you want. This is mostly - useful for embedded applications or simple mice. - - To compile this driver as a module, choose M here: the - module will be called usbmouse. - - If even remotely unsure, say N. - -endmenu - - diff --git a/trunk/drivers/hid/usbhid/Makefile b/trunk/drivers/hid/usbhid/Makefile deleted file mode 100644 index 8e6ab5b164a2..000000000000 --- a/trunk/drivers/hid/usbhid/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# Makefile for the USB input drivers -# - -# Multipart objects. -usbhid-objs := hid-core.o hid-quirks.o - -# Optional parts of multipart objects. - -ifeq ($(CONFIG_USB_HIDDEV),y) - usbhid-objs += hiddev.o -endif -ifeq ($(CONFIG_HID_PID),y) - usbhid-objs += hid-pidff.o -endif -ifeq ($(CONFIG_LOGITECH_FF),y) - usbhid-objs += hid-lgff.o -endif -ifeq ($(CONFIG_PANTHERLORD_FF),y) - usbhid-objs += hid-plff.o -endif -ifeq ($(CONFIG_THRUSTMASTER_FF),y) - usbhid-objs += hid-tmff.o -endif -ifeq ($(CONFIG_ZEROPLUS_FF),y) - usbhid-objs += hid-zpff.o -endif -ifeq ($(CONFIG_HID_FF),y) - usbhid-objs += hid-ff.o -endif - -obj-$(CONFIG_USB_HID) += usbhid.o -obj-$(CONFIG_USB_KBD) += usbkbd.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o - diff --git a/trunk/drivers/hid/usbhid/hid-quirks.c b/trunk/drivers/hid/usbhid/hid-quirks.c deleted file mode 100644 index 17a87555e32f..000000000000 --- a/trunk/drivers/hid/usbhid/hid-quirks.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * USB HID quirks support for Linux - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina - * Copyright (c) 2007 Paul Walmsley - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include - -#define USB_VENDOR_ID_A4TECH 0x09da -#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 - -#define USB_VENDOR_ID_AASHIMA 0x06d6 -#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 -#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026 - -#define USB_VENDOR_ID_ACECAD 0x0460 -#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 -#define USB_DEVICE_ID_ACECAD_302 0x0008 - -#define USB_VENDOR_ID_AIPTEK 0x08ca -#define USB_DEVICE_ID_AIPTEK_01 0x0001 -#define USB_DEVICE_ID_AIPTEK_10 0x0010 -#define USB_DEVICE_ID_AIPTEK_20 0x0020 -#define USB_DEVICE_ID_AIPTEK_21 0x0021 -#define USB_DEVICE_ID_AIPTEK_22 0x0022 -#define USB_DEVICE_ID_AIPTEK_23 0x0023 -#define USB_DEVICE_ID_AIPTEK_24 0x0024 - -#define USB_VENDOR_ID_AIRCABLE 0x16CA -#define USB_DEVICE_ID_AIRCABLE1 0x1502 - -#define USB_VENDOR_ID_ALCOR 0x058f -#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 - -#define USB_VENDOR_ID_ALPS 0x0433 -#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 - -#define USB_VENDOR_ID_APPLE 0x05ac -#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 -#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e -#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f -#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 -#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215 -#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216 -#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217 -#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218 -#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219 -#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a -#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b -#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c -#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a -#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b -#define USB_DEVICE_ID_APPLE_IR 0x8240 - -#define USB_VENDOR_ID_ATEN 0x0557 -#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 -#define USB_DEVICE_ID_ATEN_CS124U 0x2202 -#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 -#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 -#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 - -#define USB_VENDOR_ID_BELKIN 0x050d -#define USB_DEVICE_ID_FLIP_KVM 0x3201 - -#define USB_VENDOR_ID_BERKSHIRE 0x0c98 -#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 - -#define USB_VENDOR_ID_CHERRY 0x046a -#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 - -#define USB_VENDOR_ID_CHIC 0x05fe -#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 - -#define USB_VENDOR_ID_CIDC 0x1677 - -#define USB_VENDOR_ID_CODEMERCS 0x07c0 -#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 -#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff - -#define USB_VENDOR_ID_CYPRESS 0x04b4 -#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 -#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 -#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 - -#define USB_VENDOR_ID_DELL 0x413c -#define USB_DEVICE_ID_DELL_W7658 0x2005 - -#define USB_VENDOR_ID_DELORME 0x1163 -#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 -#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 - -#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f -#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 - -#define USB_VENDOR_ID_GLAB 0x06c2 -#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 -#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 -#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 -#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044 -#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 -#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051 -#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 -#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 - -#define USB_VENDOR_ID_GRIFFIN 0x077d -#define USB_DEVICE_ID_POWERMATE 0x0410 -#define USB_DEVICE_ID_SOUNDKNOB 0x04AA - -#define USB_VENDOR_ID_GTCO 0x078c -#define USB_DEVICE_ID_GTCO_90 0x0090 -#define USB_DEVICE_ID_GTCO_100 0x0100 -#define USB_DEVICE_ID_GTCO_101 0x0101 -#define USB_DEVICE_ID_GTCO_103 0x0103 -#define USB_DEVICE_ID_GTCO_104 0x0104 -#define USB_DEVICE_ID_GTCO_105 0x0105 -#define USB_DEVICE_ID_GTCO_106 0x0106 -#define USB_DEVICE_ID_GTCO_107 0x0107 -#define USB_DEVICE_ID_GTCO_108 0x0108 -#define USB_DEVICE_ID_GTCO_200 0x0200 -#define USB_DEVICE_ID_GTCO_201 0x0201 -#define USB_DEVICE_ID_GTCO_202 0x0202 -#define USB_DEVICE_ID_GTCO_203 0x0203 -#define USB_DEVICE_ID_GTCO_204 0x0204 -#define USB_DEVICE_ID_GTCO_205 0x0205 -#define USB_DEVICE_ID_GTCO_206 0x0206 -#define USB_DEVICE_ID_GTCO_207 0x0207 -#define USB_DEVICE_ID_GTCO_300 0x0300 -#define USB_DEVICE_ID_GTCO_301 0x0301 -#define USB_DEVICE_ID_GTCO_302 0x0302 -#define USB_DEVICE_ID_GTCO_303 0x0303 -#define USB_DEVICE_ID_GTCO_304 0x0304 -#define USB_DEVICE_ID_GTCO_305 0x0305 -#define USB_DEVICE_ID_GTCO_306 0x0306 -#define USB_DEVICE_ID_GTCO_307 0x0307 -#define USB_DEVICE_ID_GTCO_308 0x0308 -#define USB_DEVICE_ID_GTCO_309 0x0309 -#define USB_DEVICE_ID_GTCO_400 0x0400 -#define USB_DEVICE_ID_GTCO_401 0x0401 -#define USB_DEVICE_ID_GTCO_402 0x0402 -#define USB_DEVICE_ID_GTCO_403 0x0403 -#define USB_DEVICE_ID_GTCO_404 0x0404 -#define USB_DEVICE_ID_GTCO_405 0x0405 -#define USB_DEVICE_ID_GTCO_500 0x0500 -#define USB_DEVICE_ID_GTCO_501 0x0501 -#define USB_DEVICE_ID_GTCO_502 0x0502 -#define USB_DEVICE_ID_GTCO_503 0x0503 -#define USB_DEVICE_ID_GTCO_504 0x0504 -#define USB_DEVICE_ID_GTCO_1000 0x1000 -#define USB_DEVICE_ID_GTCO_1001 0x1001 -#define USB_DEVICE_ID_GTCO_1002 0x1002 -#define USB_DEVICE_ID_GTCO_1003 0x1003 -#define USB_DEVICE_ID_GTCO_1004 0x1004 -#define USB_DEVICE_ID_GTCO_1005 0x1005 -#define USB_DEVICE_ID_GTCO_1006 0x1006 - -#define USB_VENDOR_ID_HAPP 0x078b -#define USB_DEVICE_ID_UGCI_DRIVING 0x0010 -#define USB_DEVICE_ID_UGCI_FLYING 0x0020 -#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 - -#define USB_VENDOR_ID_IMATION 0x0718 -#define USB_DEVICE_ID_DISC_STAKKA 0xd000 - -#define USB_VENDOR_ID_KBGEAR 0x084e -#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 - -#define USB_VENDOR_ID_LD 0x0f11 -#define USB_DEVICE_ID_LD_CASSY 0x1000 -#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 -#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 -#define USB_DEVICE_ID_LD_JWM 0x1080 -#define USB_DEVICE_ID_LD_DMMP 0x1081 -#define USB_DEVICE_ID_LD_UMIP 0x1090 -#define USB_DEVICE_ID_LD_XRAY1 0x1100 -#define USB_DEVICE_ID_LD_XRAY2 0x1101 -#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 -#define USB_DEVICE_ID_LD_COM3LAB 0x2000 -#define USB_DEVICE_ID_LD_TELEPORT 0x2010 -#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 -#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 -#define USB_DEVICE_ID_LD_MACHINETEST 0x2040 - -#define USB_VENDOR_ID_LOGITECH 0x046d -#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 -#define USB_DEVICE_ID_S510_RECEIVER 0xc50c -#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 -#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 -#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 - -#define USB_VENDOR_ID_MCC 0x09db -#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 -#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a - -#define USB_VENDOR_ID_MGE 0x0463 -#define USB_DEVICE_ID_MGE_UPS 0xffff -#define USB_DEVICE_ID_MGE_UPS1 0x0001 - -#define USB_VENDOR_ID_NEC 0x073e -#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 - -#define USB_VENDOR_ID_ONTRAK 0x0a07 -#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 - -#define USB_VENDOR_ID_PANJIT 0x134c - -#define USB_VENDOR_ID_PANTHERLORD 0x0810 -#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 - -#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 -#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 - -#define USB_VENDOR_ID_SAITEK 0x06a3 -#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 - -#define USB_VENDOR_ID_SONY 0x054c -#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 - -#define USB_VENDOR_ID_SUN 0x0430 -#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab - -#define USB_VENDOR_ID_TOPMAX 0x0663 -#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 - -#define USB_VENDOR_ID_TURBOX 0x062a -#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 - -#define USB_VENDOR_ID_VERNIER 0x08f7 -#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 -#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 -#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 - -#define USB_VENDOR_ID_WACOM 0x056a - -#define USB_VENDOR_ID_WISEGROUP 0x0925 -#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 -#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 -#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 -#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800 -#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 - -#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677 -#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 - -#define USB_VENDOR_ID_YEALINK 0x6993 -#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 - -/* - * Alphabetically sorted blacklist by quirk type. - */ - -static const struct hid_blacklist { - __u16 idVendor; - __u16 idProduct; - __u32 quirks; -} hid_blacklist[] = { - - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, - - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, - - { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, - - { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, - - { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, - - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE }, - - { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, - - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR }, - - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, - - { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, - { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, - - { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, - - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - - { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - - { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, - - { 0, 0 } -}; - -/* Dynamic HID quirks list - specified at runtime */ -struct quirks_list_struct { - struct hid_blacklist hid_bl_item; - struct list_head node; -}; - -static LIST_HEAD(dquirks_list); -static DECLARE_RWSEM(dquirks_rwsem); - -/* Runtime ("dynamic") quirks manipulation functions */ - -/** - * usbhid_exists_dquirk: find any dynamic quirks for a USB HID device - * @idVendor: the 16-bit USB vendor ID, in native byteorder - * @idProduct: the 16-bit USB product ID, in native byteorder - * - * Description: - * Scans dquirks_list for a matching dynamic quirk and returns - * the pointer to the relevant struct hid_blacklist if found. - * Must be called with a read lock held on dquirks_rwsem. - * - * Returns: NULL if no quirk found, struct hid_blacklist * if found. - */ -static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor, - const u16 idProduct) -{ - struct quirks_list_struct *q; - struct hid_blacklist *bl_entry = NULL; - - list_for_each_entry(q, &dquirks_list, node) { - if (q->hid_bl_item.idVendor == idVendor && - q->hid_bl_item.idProduct == idProduct) { - bl_entry = &q->hid_bl_item; - break; - } - } - - if (bl_entry != NULL) - dbg("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", - bl_entry->quirks, bl_entry->idVendor, - bl_entry->idProduct); - - return bl_entry; -} - - -/** - * usbhid_modify_dquirk: add/replace a HID quirk - * @idVendor: the 16-bit USB vendor ID, in native byteorder - * @idProduct: the 16-bit USB product ID, in native byteorder - * @quirks: the u32 quirks value to add/replace - * - * Description: - * If an dynamic quirk exists in memory for this (idVendor, - * idProduct) pair, replace its quirks value with what was - * provided. Otherwise, add the quirk to the dynamic quirks list. - * - * Returns: 0 OK, -error on failure. - */ -int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, - const u32 quirks) -{ - struct quirks_list_struct *q_new, *q; - int list_edited = 0; - - if (!idVendor) { - dbg("Cannot add a quirk with idVendor = 0"); - return -EINVAL; - } - - q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL); - if (!q_new) { - dbg("Could not allocate quirks_list_struct"); - return -ENOMEM; - } - - q_new->hid_bl_item.idVendor = idVendor; - q_new->hid_bl_item.idProduct = idProduct; - q_new->hid_bl_item.quirks = quirks; - - down_write(&dquirks_rwsem); - - list_for_each_entry(q, &dquirks_list, node) { - - if (q->hid_bl_item.idVendor == idVendor && - q->hid_bl_item.idProduct == idProduct) { - - list_replace(&q->node, &q_new->node); - kfree(q); - list_edited = 1; - break; - - } - - } - - if (!list_edited) - list_add_tail(&q_new->node, &dquirks_list); - - up_write(&dquirks_rwsem); - - return 0; -} - - -/** - * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory - * - * Description: - * Free all memory associated with dynamic quirks - called before - * module unload. - * - */ -static void usbhid_remove_all_dquirks(void) -{ - struct quirks_list_struct *q, *temp; - - down_write(&dquirks_rwsem); - list_for_each_entry_safe(q, temp, &dquirks_list, node) { - list_del(&q->node); - kfree(q); - } - up_write(&dquirks_rwsem); - -} - -/** - * usbhid_quirks_init: apply USB HID quirks specified at module load time - */ -int usbhid_quirks_init(char **quirks_param) -{ - u16 idVendor, idProduct; - u32 quirks; - int n = 0, m; - - for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { - - m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", - &idVendor, &idProduct, &quirks); - - if (m != 3 || - usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) { - printk(KERN_WARNING - "Could not parse HID quirk module param %s\n", - quirks_param[n]); - } - } - - return 0; -} - -/** - * usbhid_quirks_exit: release memory associated with dynamic_quirks - * - * Description: - * Release all memory associated with dynamic quirks. Called upon - * module unload. - * - * Returns: nothing - */ -void usbhid_quirks_exit(void) -{ - usbhid_remove_all_dquirks(); -} - -/** - * usbhid_exists_squirk: return any static quirks for a USB HID device - * @idVendor: the 16-bit USB vendor ID, in native byteorder - * @idProduct: the 16-bit USB product ID, in native byteorder - * - * Description: - * Given a USB vendor ID and product ID, return a pointer to - * the hid_blacklist entry associated with that device. - * - * Returns: pointer if quirk found, or NULL if no quirks found. - */ -static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor, - const u16 idProduct) -{ - const struct hid_blacklist *bl_entry = NULL; - int n = 0; - - for (; hid_blacklist[n].idVendor; n++) - if (hid_blacklist[n].idVendor == idVendor && - hid_blacklist[n].idProduct == idProduct) - bl_entry = &hid_blacklist[n]; - - if (bl_entry != NULL) - dbg("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", - bl_entry->quirks, bl_entry->idVendor, - bl_entry->idProduct); - return bl_entry; -} - -/** - * usbhid_lookup_quirk: return any quirks associated with a USB HID device - * @idVendor: the 16-bit USB vendor ID, in native byteorder - * @idProduct: the 16-bit USB product ID, in native byteorder - * - * Description: - * Given a USB vendor ID and product ID, return any quirks associated - * with that device. - * - * Returns: a u32 quirks value. - */ -u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) -{ - u32 quirks = 0; - const struct hid_blacklist *bl_entry = NULL; - - /* Ignore all Wacom devices */ - if (idVendor == USB_VENDOR_ID_WACOM) - return HID_QUIRK_IGNORE; - - /* ignore all Code Mercenaries IOWarrior devices */ - if (idVendor == USB_VENDOR_ID_CODEMERCS) - if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST && - idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) - return HID_QUIRK_IGNORE; - - down_read(&dquirks_rwsem); - bl_entry = usbhid_exists_dquirk(idVendor, idProduct); - if (!bl_entry) - bl_entry = usbhid_exists_squirk(idVendor, idProduct); - if (bl_entry) - quirks = bl_entry->quirks; - up_read(&dquirks_rwsem); - - return quirks; -} - diff --git a/trunk/drivers/hwmon/ams/ams-core.c b/trunk/drivers/hwmon/ams/ams-core.c index f5ebad561412..f1f0f5d0442c 100644 --- a/trunk/drivers/hwmon/ams/ams-core.c +++ b/trunk/drivers/hwmon/ams/ams-core.c @@ -141,10 +141,10 @@ static void ams_worker(struct work_struct *work) int ams_sensor_attach(void) { int result; - const u32 *prop; + u32 *prop; /* Get orientation */ - prop = get_property(ams_info.of_node, "orientation", NULL); + prop = (u32*)get_property(ams_info.of_node, "orientation", NULL); if (!prop) return -ENODEV; ams_info.orient1 = *prop; diff --git a/trunk/drivers/hwmon/ams/ams-i2c.c b/trunk/drivers/hwmon/ams/ams-i2c.c index 485d333bcb3e..0d24bdfea53e 100644 --- a/trunk/drivers/hwmon/ams/ams-i2c.c +++ b/trunk/drivers/hwmon/ams/ams-i2c.c @@ -263,7 +263,7 @@ int __init ams_i2c_init(struct device_node *np) { char *tmp_bus; int result; - const u32 *prop; + u32 *prop; mutex_lock(&ams_info.lock); @@ -276,7 +276,7 @@ int __init ams_i2c_init(struct device_node *np) ams_info.bustype = BUS_I2C; /* look for bus either using "reg" or by path */ - prop = get_property(ams_info.of_node, "reg", NULL); + prop = (u32*)get_property(ams_info.of_node, "reg", NULL); if (!prop) { result = -ENODEV; diff --git a/trunk/drivers/hwmon/ams/ams-pmu.c b/trunk/drivers/hwmon/ams/ams-pmu.c index 1b01c215bfe7..4636ae031a53 100644 --- a/trunk/drivers/hwmon/ams/ams-pmu.c +++ b/trunk/drivers/hwmon/ams/ams-pmu.c @@ -146,7 +146,7 @@ static void ams_pmu_exit(void) int __init ams_pmu_init(struct device_node *np) { - const u32 *prop; + u32 *prop; int result; mutex_lock(&ams_info.lock); @@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_node *np) ams_info.bustype = BUS_HOST; /* Get PMU command, should be 0x4e, but we can never know */ - prop = get_property(ams_info.of_node, "reg", NULL); + prop = (u32*)get_property(ams_info.of_node, "reg", NULL); if (!prop) { result = -ENODEV; goto exit; diff --git a/trunk/drivers/hwmon/w83627ehf.c b/trunk/drivers/hwmon/w83627ehf.c index 30a76404f0af..01206ebb1cf2 100644 --- a/trunk/drivers/hwmon/w83627ehf.c +++ b/trunk/drivers/hwmon/w83627ehf.c @@ -121,9 +121,9 @@ superio_exit(void) * ISA constants */ -#define IOREGION_ALIGNMENT ~7 -#define IOREGION_OFFSET 5 -#define IOREGION_LENGTH 2 +#define REGION_ALIGNMENT ~7 +#define REGION_OFFSET 5 +#define REGION_LENGTH 2 #define ADDR_REG_OFFSET 5 #define DATA_REG_OFFSET 6 @@ -1194,7 +1194,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) u8 fan4pin, fan5pin; int i, err = 0; - if (!request_region(address + IOREGION_OFFSET, IOREGION_LENGTH, + if (!request_region(address + REGION_OFFSET, REGION_LENGTH, w83627ehf_driver.driver.name)) { err = -EBUSY; goto exit; @@ -1322,7 +1322,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) exit_free: kfree(data); exit_release: - release_region(address + IOREGION_OFFSET, IOREGION_LENGTH); + release_region(address + REGION_OFFSET, REGION_LENGTH); exit: return err; } @@ -1337,7 +1337,7 @@ static int w83627ehf_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - release_region(client->addr + IOREGION_OFFSET, IOREGION_LENGTH); + release_region(client->addr + REGION_OFFSET, REGION_LENGTH); kfree(data); return 0; @@ -1380,7 +1380,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr) superio_select(W83627EHF_LD_HWM); val = (superio_inb(SIO_REG_ADDR) << 8) | superio_inb(SIO_REG_ADDR + 1); - *addr = val & IOREGION_ALIGNMENT; + *addr = val & REGION_ALIGNMENT; if (*addr == 0) { superio_exit(); return -ENODEV; diff --git a/trunk/drivers/i2c/Kconfig b/trunk/drivers/i2c/Kconfig index 434a61b415a3..11935f66fcd8 100644 --- a/trunk/drivers/i2c/Kconfig +++ b/trunk/drivers/i2c/Kconfig @@ -2,7 +2,9 @@ # I2C subsystem configuration # -menuconfig I2C +menu "I2C support" + +config I2C tristate "I2C support" ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in @@ -20,14 +22,9 @@ menuconfig I2C This I2C support can also be built as a module. If so, the module will be called i2c-core. -if I2C - -config I2C_BOARDINFO - boolean - default y - config I2C_CHARDEV tristate "I2C device interface" + depends on I2C help Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space @@ -43,6 +40,7 @@ source drivers/i2c/chips/Kconfig config I2C_DEBUG_CORE bool "I2C Core debugging messages" + depends on I2C help Say Y here if you want the I2C core to produce a bunch of debug messages to the system log. Select this if you are having a @@ -50,6 +48,7 @@ config I2C_DEBUG_CORE config I2C_DEBUG_ALGO bool "I2C Algorithm debugging messages" + depends on I2C help Say Y here if you want the I2C algorithm drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -58,6 +57,7 @@ config I2C_DEBUG_ALGO config I2C_DEBUG_BUS bool "I2C Bus debugging messages" + depends on I2C help Say Y here if you want the I2C bus drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -66,10 +66,12 @@ config I2C_DEBUG_BUS config I2C_DEBUG_CHIP bool "I2C Chip debugging messages" + depends on I2C help Say Y here if you want the I2C chip drivers to produce a bunch of debug messages to the system log. Select this if you are having a problem with I2C support and want to see more of what is going on. -endif # I2C +endmenu + diff --git a/trunk/drivers/i2c/Makefile b/trunk/drivers/i2c/Makefile index ba26e6cbe74e..71c5a854ac5d 100644 --- a/trunk/drivers/i2c/Makefile +++ b/trunk/drivers/i2c/Makefile @@ -2,7 +2,6 @@ # Makefile for the i2c core. # -obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-y += busses/ chips/ algos/ diff --git a/trunk/drivers/i2c/algos/Kconfig b/trunk/drivers/i2c/algos/Kconfig index 58899078810b..af0203409dd1 100644 --- a/trunk/drivers/i2c/algos/Kconfig +++ b/trunk/drivers/i2c/algos/Kconfig @@ -3,9 +3,11 @@ # menu "I2C Algorithms" + depends on I2C config I2C_ALGOBIT tristate "I2C bit-banging interfaces" + depends on I2C help This allows you to use a range of I2C adapters called bit-banging adapters. Say Y if you own an I2C adapter belonging to this class @@ -16,6 +18,7 @@ config I2C_ALGOBIT config I2C_ALGOPCF tristate "I2C PCF 8584 interfaces" + depends on I2C help This allows you to use a range of I2C adapters called PCF adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -26,6 +29,7 @@ config I2C_ALGOPCF config I2C_ALGOPCA tristate "I2C PCA 9564 interfaces" + depends on I2C help This allows you to use a range of I2C adapters called PCA adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -36,11 +40,11 @@ config I2C_ALGOPCA config I2C_ALGO8XX tristate "MPC8xx CPM I2C interface" - depends on 8xx + depends on 8xx && I2C config I2C_ALGO_SGI tristate "I2C SGI interfaces" - depends on SGI_IP22 || SGI_IP32 || X86_VISWS + depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS) help Supports the SGI interfaces like the ones found on SGI Indy VINO or SGI O2 MACE. diff --git a/trunk/drivers/i2c/algos/i2c-algo-bit.c b/trunk/drivers/i2c/algos/i2c-algo-bit.c index 8a5f5825bb72..95aa5395a5be 100644 --- a/trunk/drivers/i2c/algos/i2c-algo-bit.c +++ b/trunk/drivers/i2c/algos/i2c-algo-bit.c @@ -33,30 +33,19 @@ /* ----- global defines ----------------------------------------------- */ +#define DEB(x) if (i2c_debug>=1) x; +#define DEB2(x) if (i2c_debug>=2) x; +#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/ +#define DEBPROTO(x) if (i2c_debug>=9) { x; } + /* debug the protocol by showing transferred bits */ -#ifdef DEBUG -#define bit_dbg(level, dev, format, args...) \ - do { \ - if (i2c_debug >= level) \ - dev_dbg(dev, format, ##args); \ - } while (0) -#else -#define bit_dbg(level, dev, format, args...) \ - do {} while (0) -#endif /* DEBUG */ /* ----- global variables --------------------------------------------- */ +/* module parameters: + */ +static int i2c_debug; static int bit_test; /* see if the line-setting functions work */ -module_param(bit_test, bool, 0); -MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); - -#ifdef DEBUG -static int i2c_debug = 1; -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); -#endif /* --- setting states on the bus with the right timing: --------------- */ @@ -68,19 +57,19 @@ MODULE_PARM_DESC(i2c_debug, static inline void sdalo(struct i2c_algo_bit_data *adap) { setsda(adap,0); - udelay((adap->udelay + 1) / 2); + udelay(adap->udelay); } static inline void sdahi(struct i2c_algo_bit_data *adap) { setsda(adap,1); - udelay((adap->udelay + 1) / 2); + udelay(adap->udelay); } static inline void scllo(struct i2c_algo_bit_data *adap) { setscl(adap,0); - udelay(adap->udelay / 2); + udelay(adap->udelay); } /* @@ -109,11 +98,7 @@ static int sclhi(struct i2c_algo_bit_data *adap) } cond_resched(); } -#ifdef DEBUG - if (jiffies != start && i2c_debug >= 3) - pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " - "high\n", jiffies - start); -#endif + DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); done: udelay(adap->udelay); @@ -125,29 +110,30 @@ static int sclhi(struct i2c_algo_bit_data *adap) static void i2c_start(struct i2c_algo_bit_data *adap) { /* assert: scl, sda are high */ - setsda(adap, 0); - udelay(adap->udelay); + DEBPROTO(printk("S ")); + sdalo(adap); scllo(adap); } static void i2c_repstart(struct i2c_algo_bit_data *adap) { - /* assert: scl is low */ - sdahi(adap); + /* scl, sda may not be high */ + DEBPROTO(printk(" Sr ")); + setsda(adap,1); sclhi(adap); - setsda(adap, 0); - udelay(adap->udelay); + + sdalo(adap); scllo(adap); } static void i2c_stop(struct i2c_algo_bit_data *adap) { + DEBPROTO(printk("P\n")); /* assert: scl is low */ sdalo(adap); sclhi(adap); - setsda(adap, 1); - udelay(adap->udelay); + sdahi(adap); } @@ -159,7 +145,7 @@ static void i2c_stop(struct i2c_algo_bit_data *adap) * 0 if the device did not ack * -ETIMEDOUT if an error occurred (while raising the scl line) */ -static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) +static int i2c_outb(struct i2c_adapter *i2c_adap, char c) { int i; int sb; @@ -168,32 +154,34 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) /* assert: scl is low */ for ( i=7 ; i>=0 ; i-- ) { - sb = (c >> i) & 1; + sb = c & ( 1 << i ); setsda(adap,sb); - udelay((adap->udelay + 1) / 2); + udelay(adap->udelay); + DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); if (sclhi(adap)<0) { /* timed out */ - bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " - "timeout at bit #%d\n", (int)c, i); + sdahi(adap); /* we don't want to block the net */ + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); return -ETIMEDOUT; }; /* do arbitration here: * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. */ - scllo(adap); + setscl(adap, 0 ); + udelay(adap->udelay); } sdahi(adap); if (sclhi(adap)<0){ /* timeout */ - bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " - "timeout at ack\n", (int)c); - return -ETIMEDOUT; + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff)); + return -ETIMEDOUT; }; /* read ack: SDA should be pulled down by slave */ - ack = !getsda(adap); /* ack: sda is pulled low -> success */ - bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, - ack ? "A" : "NA"); + ack=getsda(adap); /* ack: sda is pulled low ->success. */ + DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack)); + DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); + DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); scllo(adap); - return ack; + return 0==ack; /* return 1 if device acked */ /* assert: scl is low (sda undef) */ } @@ -210,18 +198,19 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) sdahi(adap); for (i=0;i<8;i++) { if (sclhi(adap)<0) { /* timeout */ - bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " - "#%d\n", 7 - i); + DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i)); return -ETIMEDOUT; }; indata *= 2; if ( getsda(adap) ) indata |= 0x01; - setscl(adap, 0); - udelay(i == 7 ? adap->udelay / 2 : adap->udelay); + scllo(adap); } /* assert: scl is low */ - return indata; + DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); + + DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff)); + return (int) (indata & 0xff); } /* @@ -232,67 +221,73 @@ static int test_bus(struct i2c_algo_bit_data *adap, char* name) { int scl,sda; if (adap->getscl==NULL) - pr_info("%s: Testing SDA only, SCL is not readable\n", name); + printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, " + "SCL is not readable.\n"); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); + printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda); if (!scl || !sda ) { - printk(KERN_WARNING "%s: bus seems to be busy\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name); goto bailout; } sdalo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); + printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda); if ( 0 != sda ) { - printk(KERN_WARNING "%s: SDA stuck high!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n"); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "%s: SCL unexpected low " - "while pulling SDA low!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " + "while pulling SDA low!\n"); goto bailout; } sdahi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); + printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda); if ( 0 == sda ) { - printk(KERN_WARNING "%s: SDA stuck low!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n"); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "%s: SCL unexpected low " - "while pulling SDA high!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " + "while pulling SDA high!\n"); goto bailout; } scllo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?0:getscl(adap)); + printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda); if ( 0 != scl ) { - printk(KERN_WARNING "%s: SCL stuck high!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n"); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "%s: SDA unexpected low " - "while pulling SCL low!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " + "while pulling SCL low!\n"); goto bailout; } sclhi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); + printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda); if ( 0 == scl ) { - printk(KERN_WARNING "%s: SCL stuck low!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n"); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "%s: SDA unexpected low " - "while pulling SCL high!\n", name); + printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " + "while pulling SCL high!\n"); goto bailout; } - pr_info("%s: Test OK\n", name); + printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name); return 0; bailout: sdahi(adap); @@ -317,39 +312,44 @@ static int try_address(struct i2c_adapter *i2c_adap, int i,ret = -1; for (i=0;i<=retries;i++) { ret = i2c_outb(i2c_adap,addr); - if (ret == 1 || i == retries) - break; - bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + if (ret==1) + break; /* success! */ i2c_stop(adap); - udelay(adap->udelay); - yield(); - bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + udelay(5/*adap->udelay*/); + if (i==retries) /* no success */ + break; i2c_start(adap); + udelay(adap->udelay); } - if (i && ret) - bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " - "0x%02x: %s\n", i + 1, - addr & 1 ? "read from" : "write to", addr >> 1, - ret == 1 ? "success" : "failed, timeout?"); + DEB2(if (i) + printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", + i+1, addr & 1 ? "read" : "write", addr>>1, + ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) + ); return ret; } static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { - const unsigned char *temp = msg->buf; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + char c; + const char *temp = msg->buf; int count = msg->len; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount=0; while (count > 0) { - retval = i2c_outb(i2c_adap, *temp); + c = *temp; + DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff)); + retval = i2c_outb(i2c_adap,c); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); + i2c_stop(adap); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ } @@ -362,7 +362,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) int inval; int rdcount=0; /* counts bytes read */ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - unsigned char *temp = msg->buf; + char *temp = msg->buf; int count = msg->len; while (count > 0) { @@ -371,44 +371,30 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) *temp = inval; rdcount++; } else { /* read timed out */ + printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n"); break; } temp++; count--; - if (msg->flags & I2C_M_NO_RD_ACK) { - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n", - inval); + if (msg->flags & I2C_M_NO_RD_ACK) continue; - } - /* assert: sda is high */ - if (count) /* send ack */ - setsda(adap, 0); - udelay((adap->udelay + 1) / 2); - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval, - count ? "A" : "NA"); + if ( count > 0 ) { /* send ack */ + sdalo(adap); + DEBPROTO(printk(" Am ")); + } else { + sdahi(adap); /* neg. ack on last byte */ + DEBPROTO(printk(" NAm ")); + } if (sclhi(adap)<0) { /* timeout */ - dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n"); + sdahi(adap); + printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); - - /* Some SMBus transactions require that we receive the - transaction length as the first read byte. */ - if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { - if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { - dev_err(&i2c_adap->dev, "readbytes: invalid " - "block length (%d)\n", inval); - return -EREMOTEIO; - } - /* The original count value accounts for the extra - bytes, that is, either 1 for a regular transaction, - or 2 for a PEC transaction. */ - count += inval; - msg->len += inval; - } + sdahi(adap); } return rdcount; } @@ -435,31 +421,27 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); + DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if ((ret != 1) && !nak_ok) { - dev_err(&i2c_adap->dev, - "died at extended address code\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ - dev_err(&i2c_adap->dev, "died at 2nd address code\n"); + printk(KERN_ERR "died at 2nd address code.\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { - bit_dbg(3, &i2c_adap->dev, "emitting repeated " - "start condition\n"); i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { - dev_err(&i2c_adap->dev, - "died at repeated address code\n"); + printk(KERN_ERR "died at extended address code.\n"); return -EREMOTEIO; } } @@ -486,62 +468,44 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, int i,ret; unsigned short nak_ok; - bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); for (i=0;iflags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { - bit_dbg(3, &i2c_adap->dev, "emitting " - "repeated start condition\n"); i2c_repstart(adap); } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { - bit_dbg(1, &i2c_adap->dev, "NAK from " - "device addr 0x%02x msg #%d\n", - msgs[i].addr, i); - goto bailout; + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n" + ,msgs[i].addr,i)); + return (ret<0) ? ret : -EREMOTEIO; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); - if (ret >= 1) - bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", - ret, ret == 1 ? "" : "s"); - if (ret < pmsg->len) { - if (ret >= 0) - ret = -EREMOTEIO; - goto bailout; + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0)? ret : -EREMOTEIO; } } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); - if (ret >= 1) - bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", - ret, ret == 1 ? "" : "s"); - if (ret < pmsg->len) { - if (ret >= 0) - ret = -EREMOTEIO; - goto bailout; + DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); + if (ret < pmsg->len ) { + return (ret<0) ? ret : -EREMOTEIO; } } } - ret = i; - -bailout: - bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); - return ret; + return num; } static u32 bit_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_SMBUS_READ_BLOCK_DATA | - I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } @@ -556,7 +520,7 @@ static const struct i2c_algorithm i2c_bit_algo = { /* * registering functions to load algorithms at runtime */ -static int i2c_bit_prepare_bus(struct i2c_adapter *adap) +int i2c_bit_add_bus(struct i2c_adapter *adap) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; @@ -566,39 +530,25 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap) return -ENODEV; } + DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); + /* register new adapter to i2c module... */ adap->algo = &i2c_bit_algo; adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ - return 0; -} - -int i2c_bit_add_bus(struct i2c_adapter *adap) -{ - int err; - - err = i2c_bit_prepare_bus(adap); - if (err) - return err; - return i2c_add_adapter(adap); } EXPORT_SYMBOL(i2c_bit_add_bus); -int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) -{ - int err; - - err = i2c_bit_prepare_bus(adap); - if (err) - return err; - - return i2c_add_numbered_adapter(adap); -} -EXPORT_SYMBOL(i2c_bit_add_numbered_bus); - MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); + +module_param(bit_test, bool, 0); +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); + +MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); diff --git a/trunk/drivers/i2c/algos/i2c-algo-sgi.c b/trunk/drivers/i2c/algos/i2c-algo-sgi.c index 6eaf145e1ada..ac2d5053078a 100644 --- a/trunk/drivers/i2c/algos/i2c-algo-sgi.c +++ b/trunk/drivers/i2c/algos/i2c-algo-sgi.c @@ -1,7 +1,6 @@ /* - * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and - * MACE (SGI O2) chips. - * + * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters. + * * This file is subject to the terms and conditions of the GNU General Public * License version 2 as published by the Free Software Foundation. * @@ -163,8 +162,8 @@ static const struct i2c_algorithm sgi_algo = { .functionality = sgi_func, }; -/* - * registering functions to load algorithms at runtime +/* + * registering functions to load algorithms at runtime */ int i2c_sgi_add_bus(struct i2c_adapter *adap) { diff --git a/trunk/drivers/i2c/busses/Kconfig b/trunk/drivers/i2c/busses/Kconfig index 838dc1c19d61..ece31d2c6c64 100644 --- a/trunk/drivers/i2c/busses/Kconfig +++ b/trunk/drivers/i2c/busses/Kconfig @@ -3,10 +3,11 @@ # menu "I2C Hardware Bus support" + depends on I2C config I2C_ALI1535 tristate "ALI 1535" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -18,7 +19,7 @@ config I2C_ALI1535 config I2C_ALI1563 tristate "ALI 1563" - depends on PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB @@ -30,7 +31,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -40,7 +41,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -65,7 +66,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -75,14 +76,14 @@ config I2C_AMD8111 config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 && EXPERIMENTAL + depends on I2C && ARCH_AT91 && EXPERIMENTAL help This supports the use of the I2C interface on Atmel AT91 processors. config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" - depends on SOC_AU1550 || SOC_AU1200 + depends on I2C && (SOC_AU1550 || SOC_AU1200) help If you say yes to this option, support will be included for the Au1550 and Au1200 SMBus interface. @@ -90,25 +91,9 @@ config I2C_AU1550 This driver can also be built as a module. If so, the module will be called i2c-au1550. -config I2C_BLACKFIN_TWI - tristate "Blackfin TWI I2C support" - depends on BF534 || BF536 || BF537 - help - This is the TWI I2C device driver for Blackfin 534/536/537. - This driver can also be built as a module. If so, the module - will be called i2c-bfin-twi. - -config I2C_BLACKFIN_TWI_CLK_KHZ - int "Blackfin TWI I2C clock (kHz)" - depends on I2C_BLACKFIN_TWI - range 10 400 - default 50 - help - The unit of the TWI clock is kHz. - config I2C_ELEKTOR tristate "Elektor ISA card" - depends on ISA && BROKEN_ON_SMP + depends on I2C && ISA && BROKEN_ON_SMP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own @@ -117,17 +102,9 @@ config I2C_ELEKTOR This support is also available as a module. If so, the module will be called i2c-elektor. -config I2C_GPIO - tristate "GPIO-based bitbanging I2C" - depends on GENERIC_GPIO - select I2C_ALGOBIT - help - This is a very simple bitbanging I2C driver utilizing the - arch-neutral GPIO API to control the SCL and SDA lines. - config I2C_HYDRA tristate "CHRP Apple Hydra Mac I/O I2C interface" - depends on PCI && PPC_CHRP && EXPERIMENTAL + depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL select I2C_ALGOBIT help This supports the use of the I2C interface in the Apple Hydra Mac @@ -139,7 +116,7 @@ config I2C_HYDRA config I2C_I801 tristate "Intel 82801 (ICH)" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -162,7 +139,7 @@ config I2C_I801 config I2C_I810 tristate "Intel 810/815" - depends on PCI + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the Intel @@ -179,7 +156,7 @@ config I2C_I810 config I2C_PXA tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" - depends on EXPERIMENTAL && ARCH_PXA + depends on I2C && EXPERIMENTAL && ARCH_PXA help If you have devices in the PXA I2C bus, say yes to this option. This driver can also be built as a module. If so, the module @@ -195,7 +172,7 @@ config I2C_PXA_SLAVE config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following @@ -218,7 +195,7 @@ config I2C_PIIX4 config I2C_IBM_IIC tristate "IBM PPC 4xx on-chip I2C interface" - depends on IBM_OCP + depends on IBM_OCP && I2C help Say Y here if you want to use IIC peripheral found on embedded IBM PPC 4xx based systems. @@ -228,7 +205,7 @@ config I2C_IBM_IIC config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX + depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C help Say Y here if you want to use the IIC bus controller on the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. @@ -238,10 +215,11 @@ config I2C_IOP3XX config I2C_ISA tristate + depends on I2C config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" - depends on ARCH_IXP4XX + tristate "IXP4xx GPIO-Based I2C Interface" + depends on I2C && ARCH_IXP4XX select I2C_ALGOBIT help Say Y here if you have an Intel IXP4xx(420,421,422,425) based @@ -250,12 +228,9 @@ config I2C_IXP4XX This support is also available as a module. If so, the module will be called i2c-ixp4xx. - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - config I2C_IXP2000 - tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" - depends on ARCH_IXP2000 + tristate "IXP2000 GPIO-Based I2C Interface" + depends on I2C && ARCH_IXP2000 select I2C_ALGOBIT help Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based @@ -264,12 +239,9 @@ config I2C_IXP2000 This support is also available as a module. If so, the module will be called i2c-ixp2000. - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - config I2C_POWERMAC tristate "Powermac I2C interface" - depends on PPC_PMAC + depends on I2C && PPC_PMAC default y help This exposes the various PowerMac i2c interfaces to the linux i2c @@ -281,7 +253,7 @@ config I2C_POWERMAC config I2C_MPC tristate "MPC107/824x/85xx/52xx/86xx" - depends on PPC32 + depends on I2C && PPC32 help If you say yes to this option, support will be included for the built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and @@ -293,7 +265,7 @@ config I2C_MPC config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the Nvidia nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. @@ -303,7 +275,7 @@ config I2C_NFORCE2 config I2C_OCORES tristate "OpenCores I2C Controller" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see @@ -314,7 +286,7 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" - depends on ARCH_OMAP + depends on I2C && ARCH_OMAP default y if MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes to this option, support will be included for the @@ -324,7 +296,7 @@ config I2C_OMAP config I2C_PARPORT tristate "Parallel port adapter" - depends on PARPORT + depends on I2C && PARPORT select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -348,6 +320,7 @@ config I2C_PARPORT config I2C_PARPORT_LIGHT tristate "Parallel port adapter (light)" + depends on I2C select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -371,13 +344,13 @@ config I2C_PARPORT_LIGHT config I2C_PASEMI tristate "PA Semi SMBus interface" - depends on PPC_PASEMI && PCI + depends on PPC_PASEMI && I2C && PCI help Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" - depends on PCI + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -392,19 +365,19 @@ config I2C_PROSAVAGE config I2C_RPXLITE tristate "Embedded Planet RPX Lite/Classic support" - depends on RPXLITE || RPXCLASSIC + depends on (RPXLITE || RPXCLASSIC) && I2C select I2C_ALGO8XX config I2C_S3C2410 tristate "S3C2410 I2C Driver" - depends on ARCH_S3C2410 + depends on I2C && ARCH_S3C2410 help Say Y here to include support for I2C controller in the Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 tristate "S3 Savage 4" - depends on PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -415,25 +388,13 @@ config I2C_SAVAGE4 config I2C_SIBYTE tristate "SiByte SMBus interface" - depends on SIBYTE_SB1xxx_SOC + depends on SIBYTE_SB1xxx_SOC && I2C help Supports the SiByte SOC on-chip I2C interfaces (2 channels). -config I2C_SIMTEC - tristate "Simtec Generic I2C interface" - select I2C_ALGOBIT - help - If you say yes to this option, support will be inclyded for - the Simtec Generic I2C interface. This driver is for the - simple I2C bus used on newer Simtec products for general - I2C, such as DDC on the Simtec BBD2016A. - - This driver can also be build as a module. If so, the module - will be called i2c-simtec. - config SCx200_I2C - tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" - depends on SCx200_GPIO + tristate "NatSemi SCx200 I2C using GPIO pins" + depends on SCx200_GPIO && I2C select I2C_ALGOBIT help Enable the use of two GPIO pins of a SCx200 processor as an I2C bus. @@ -443,9 +404,6 @@ config SCx200_I2C This support is also available as a module. If so, the module will be called scx200_i2c. - This driver is deprecated and will be dropped soon. Use i2c-gpio - (or scx200_acb) instead. - config SCx200_I2C_SCL int "GPIO pin used for SCL" depends on SCx200_I2C @@ -464,7 +422,7 @@ config SCx200_I2C_SDA config SCx200_ACB tristate "Geode ACCESS.bus support" - depends on X86_32 && PCI + depends on X86_32 && I2C && PCI help Enable the use of the ACCESS.bus controllers on the Geode SCx200 and SC1100 processors and the CS5535 and CS5536 Geode companion devices. @@ -476,7 +434,7 @@ config SCx200_ACB config I2C_SIS5595 tristate "SiS 5595" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -486,7 +444,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS630 and SiS730 SMBus (a subset of I2C) interface. @@ -496,7 +454,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -514,7 +472,7 @@ config I2C_SIS96X config I2C_STUB tristate "I2C/SMBus Test Stub" - depends on EXPERIMENTAL && m + depends on I2C && EXPERIMENTAL && 'm' default 'n' help This module may be useful to developers of SMBus client drivers, @@ -525,20 +483,9 @@ config I2C_STUB If you don't know what to do here, definitely say N. -config I2C_TINY_USB - tristate "I2C-Tiny-USB" - depends on USB - help - If you say yes to this option, support will be included for the - i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See - http://www.harbaum.org/till/i2c_tiny_usb for hardware details. - - This driver can also be built as a module. If so, the module - will be called i2c-tiny-usb. - config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW + depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW) select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile @@ -549,7 +496,7 @@ config I2C_VERSATILE config I2C_ACORN bool "Acorn IOC/IOMD I2C bus support" - depends on ARCH_ACORN + depends on I2C && ARCH_ACORN default y select I2C_ALGOBIT help @@ -559,7 +506,7 @@ config I2C_ACORN config I2C_VIA tristate "VIA 82C586B" - depends on PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the VIA @@ -570,7 +517,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA VT82C596/82C686/82xx and CX700" - depends on PCI + depends on I2C && PCI help If you say yes to this option, support will be included for the VIA VT82C596 and later SMBus interface. Specifically, the following @@ -589,7 +536,7 @@ config I2C_VIAPRO config I2C_VOODOO3 tristate "Voodoo 3" - depends on PCI + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -600,7 +547,7 @@ config I2C_VOODOO3 config I2C_PCA_ISA tristate "PCA9564 on an ISA bus" - depends on ISA + depends on I2C select I2C_ALGOPCA default n help @@ -617,7 +564,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on MV64X60 && EXPERIMENTAL + depends on I2C && MV64X60 && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. @@ -627,7 +574,7 @@ config I2C_MV64XXX config I2C_PNX tristate "I2C bus support for Philips PNX targets" - depends on ARCH_PNX4008 + depends on ARCH_PNX4008 && I2C help This driver supports the Philips IP3204 I2C IP block master and/or slave controller diff --git a/trunk/drivers/i2c/busses/Makefile b/trunk/drivers/i2c/busses/Makefile index 14d1432f698b..290b54018354 100644 --- a/trunk/drivers/i2c/busses/Makefile +++ b/trunk/drivers/i2c/busses/Makefile @@ -10,9 +10,7 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o -obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o @@ -39,12 +37,10 @@ obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o -obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o -obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_VIA) += i2c-via.o diff --git a/trunk/drivers/i2c/busses/i2c-ali1535.c b/trunk/drivers/i2c/busses/i2c-ali1535.c index f14372ac2fc5..1e277ba5a9f3 100644 --- a/trunk/drivers/i2c/busses/i2c-ali1535.c +++ b/trunk/drivers/i2c/busses/i2c-ali1535.c @@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali1535_adapter.dev.parent = &dev->dev; - snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), + snprintf(ali1535_adapter.name, I2C_NAME_SIZE, "SMBus ALI1535 adapter at %04x", ali1535_smba); return i2c_add_adapter(&ali1535_adapter); } diff --git a/trunk/drivers/i2c/busses/i2c-ali15x3.c b/trunk/drivers/i2c/busses/i2c-ali15x3.c index 93bf87d70961..e47fe01bf42a 100644 --- a/trunk/drivers/i2c/busses/i2c-ali15x3.c +++ b/trunk/drivers/i2c/busses/i2c-ali15x3.c @@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; - snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), + snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, "SMBus ALI15X3 adapter at %04x", ali15x3_smba); return i2c_add_adapter(&ali15x3_adapter); } diff --git a/trunk/drivers/i2c/busses/i2c-amd8111.c b/trunk/drivers/i2c/busses/i2c-amd8111.c index c9fca7b49267..0c70f8293341 100644 --- a/trunk/drivers/i2c/busses/i2c-amd8111.c +++ b/trunk/drivers/i2c/busses/i2c-amd8111.c @@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), + snprintf(smbus->adapter.name, I2C_NAME_SIZE, "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_HW_SMBUS_AMD8111; smbus->adapter.class = I2C_CLASS_HWMON; diff --git a/trunk/drivers/i2c/busses/i2c-at91.c b/trunk/drivers/i2c/busses/i2c-at91.c index f35156c58922..67f91bdda089 100644 --- a/trunk/drivers/i2c/busses/i2c-at91.c +++ b/trunk/drivers/i2c/busses/i2c-at91.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-bfin-twi.c b/trunk/drivers/i2c/busses/i2c-bfin-twi.c deleted file mode 100644 index 6311039dfe60..000000000000 --- a/trunk/drivers/i2c/busses/i2c-bfin-twi.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * drivers/i2c/busses/i2c-bfin-twi.c - * - * Description: Driver for Blackfin Two Wire Interface - * - * Author: sonicz - * - * Copyright (c) 2005-2007 Analog Devices, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 - -#define POLL_TIMEOUT (2 * HZ) - -/* SMBus mode*/ -#define TWI_I2C_MODE_STANDARD 0x01 -#define TWI_I2C_MODE_STANDARDSUB 0x02 -#define TWI_I2C_MODE_COMBINED 0x04 - -struct bfin_twi_iface { - struct mutex twi_lock; - int irq; - spinlock_t lock; - char read_write; - u8 command; - u8 *transPtr; - int readNum; - int writeNum; - int cur_mode; - int manual_stop; - int result; - int timeout_count; - struct timer_list timeout_timer; - struct i2c_adapter adap; - struct completion complete; -}; - -static struct bfin_twi_iface twi_iface; - -static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) -{ - unsigned short twi_int_status = bfin_read_TWI_INT_STAT(); - unsigned short mast_stat = bfin_read_TWI_MASTER_STAT(); - - if (twi_int_status & XMTSERV) { - /* Transmit next data */ - if (iface->writeNum > 0) { - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); - iface->writeNum--; - } - /* start receive immediately after complete sending in - * combine mode. - */ - else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() - | MDIR | RSTART); - } else if (iface->manual_stop) - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() - | STOP); - SSYNC(); - /* Clear status */ - bfin_write_TWI_INT_STAT(XMTSERV); - SSYNC(); - } - if (twi_int_status & RCVSERV) { - if (iface->readNum > 0) { - /* Receive next data */ - *(iface->transPtr) = bfin_read_TWI_RCV_DATA8(); - if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { - /* Change combine mode into sub mode after - * read first data. - */ - iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; - /* Get read number from first byte in block - * combine mode. - */ - if (iface->readNum == 1 && iface->manual_stop) - iface->readNum = *iface->transPtr + 1; - } - iface->transPtr++; - iface->readNum--; - } else if (iface->manual_stop) { - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() - | STOP); - SSYNC(); - } - /* Clear interrupt source */ - bfin_write_TWI_INT_STAT(RCVSERV); - SSYNC(); - } - if (twi_int_status & MERR) { - bfin_write_TWI_INT_STAT(MERR); - bfin_write_TWI_INT_MASK(0); - bfin_write_TWI_MASTER_STAT(0x3e); - bfin_write_TWI_MASTER_CTL(0); - SSYNC(); - iface->result = -1; - /* if both err and complete int stats are set, return proper - * results. - */ - if (twi_int_status & MCOMP) { - bfin_write_TWI_INT_STAT(MCOMP); - bfin_write_TWI_INT_MASK(0); - bfin_write_TWI_MASTER_CTL(0); - SSYNC(); - /* If it is a quick transfer, only address bug no data, - * not an err, return 1. - */ - if (iface->writeNum == 0 && (mast_stat & BUFRDERR)) - iface->result = 1; - /* If address not acknowledged return -1, - * else return 0. - */ - else if (!(mast_stat & ANAK)) - iface->result = 0; - } - complete(&iface->complete); - return; - } - if (twi_int_status & MCOMP) { - bfin_write_TWI_INT_STAT(MCOMP); - SSYNC(); - if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { - if (iface->readNum == 0) { - /* set the read number to 1 and ask for manual - * stop in block combine mode - */ - iface->readNum = 1; - iface->manual_stop = 1; - bfin_write_TWI_MASTER_CTL( - bfin_read_TWI_MASTER_CTL() - | (0xff << 6)); - } else { - /* set the readd number in other - * combine mode. - */ - bfin_write_TWI_MASTER_CTL( - (bfin_read_TWI_MASTER_CTL() & - (~(0xff << 6))) | - ( iface->readNum << 6)); - } - /* remove restart bit and enable master receive */ - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & - ~RSTART); - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | - MEN | MDIR); - SSYNC(); - } else { - iface->result = 1; - bfin_write_TWI_INT_MASK(0); - bfin_write_TWI_MASTER_CTL(0); - SSYNC(); - complete(&iface->complete); - } - } -} - -/* Interrupt handler */ -static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) -{ - struct bfin_twi_iface *iface = dev_id; - unsigned long flags; - - spin_lock_irqsave(&iface->lock, flags); - del_timer(&iface->timeout_timer); - bfin_twi_handle_interrupt(iface); - spin_unlock_irqrestore(&iface->lock, flags); - return IRQ_HANDLED; -} - -static void bfin_twi_timeout(unsigned long data) -{ - struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data; - unsigned long flags; - - spin_lock_irqsave(&iface->lock, flags); - bfin_twi_handle_interrupt(iface); - if (iface->result == 0) { - iface->timeout_count--; - if (iface->timeout_count > 0) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } else { - iface->result = -1; - complete(&iface->complete); - } - } - spin_unlock_irqrestore(&iface->lock, flags); -} - -/* - * Generic i2c master transfer entrypoint - */ -static int bfin_twi_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct bfin_twi_iface *iface = adap->algo_data; - struct i2c_msg *pmsg; - int i, ret; - int rc = 0; - - if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) - return -ENXIO; - - mutex_lock(&iface->twi_lock); - - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); - yield(); - mutex_lock(&iface->twi_lock); - } - - ret = 0; - for (i = 0; rc >= 0 && i < num; i++) { - pmsg = &msgs[i]; - if (pmsg->flags & I2C_M_TEN) { - dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr " - "not supported !\n"); - rc = -EINVAL; - break; - } - - iface->cur_mode = TWI_I2C_MODE_STANDARD; - iface->manual_stop = 0; - iface->transPtr = pmsg->buf; - iface->writeNum = iface->readNum = pmsg->len; - iface->result = 0; - iface->timeout_count = 10; - /* Set Transmit device address */ - bfin_write_TWI_MASTER_ADDR(pmsg->addr); - - /* FIFO Initiation. Data in FIFO should be - * discarded before start a new operation. - */ - bfin_write_TWI_FIFO_CTL(0x3); - SSYNC(); - bfin_write_TWI_FIFO_CTL(0); - SSYNC(); - - if (pmsg->flags & I2C_M_RD) - iface->read_write = I2C_SMBUS_READ; - else { - iface->read_write = I2C_SMBUS_WRITE; - /* Transmit first data */ - if (iface->writeNum > 0) { - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); - iface->writeNum--; - SSYNC(); - } - } - - /* clear int stat */ - bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); - - /* Interrupt mask . Enable XMT, RCV interrupt */ - bfin_write_TWI_INT_MASK(MCOMP | MERR | - ((iface->read_write == I2C_SMBUS_READ)? - RCVSERV : XMTSERV)); - SSYNC(); - - if (pmsg->len > 0 && pmsg->len <= 255) - bfin_write_TWI_MASTER_CTL(pmsg->len << 6); - else if (pmsg->len > 255) { - bfin_write_TWI_MASTER_CTL(0xff << 6); - iface->manual_stop = 1; - } else - break; - - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - - /* Master enable */ - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | - ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | - ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); - SSYNC(); - - wait_for_completion(&iface->complete); - - rc = iface->result; - if (rc == 1) - ret++; - else if (rc == -1) - break; - } - - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - - return ret; -} - -/* - * SMBus type transfer entrypoint - */ - -int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data) -{ - struct bfin_twi_iface *iface = adap->algo_data; - int rc = 0; - - if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) - return -ENXIO; - - mutex_lock(&iface->twi_lock); - - while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { - mutex_unlock(&iface->twi_lock); - yield(); - mutex_lock(&iface->twi_lock); - } - - iface->writeNum = 0; - iface->readNum = 0; - - /* Prepare datas & select mode */ - switch (size) { - case I2C_SMBUS_QUICK: - iface->transPtr = NULL; - iface->cur_mode = TWI_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE: - if (data == NULL) - iface->transPtr = NULL; - else { - if (read_write == I2C_SMBUS_READ) - iface->readNum = 1; - else - iface->writeNum = 1; - iface->transPtr = &data->byte; - } - iface->cur_mode = TWI_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE_DATA: - if (read_write == I2C_SMBUS_READ) { - iface->readNum = 1; - iface->cur_mode = TWI_I2C_MODE_COMBINED; - } else { - iface->writeNum = 1; - iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; - } - iface->transPtr = &data->byte; - break; - case I2C_SMBUS_WORD_DATA: - if (read_write == I2C_SMBUS_READ) { - iface->readNum = 2; - iface->cur_mode = TWI_I2C_MODE_COMBINED; - } else { - iface->writeNum = 2; - iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; - } - iface->transPtr = (u8 *)&data->word; - break; - case I2C_SMBUS_PROC_CALL: - iface->writeNum = 2; - iface->readNum = 2; - iface->cur_mode = TWI_I2C_MODE_COMBINED; - iface->transPtr = (u8 *)&data->word; - break; - case I2C_SMBUS_BLOCK_DATA: - if (read_write == I2C_SMBUS_READ) { - iface->readNum = 0; - iface->cur_mode = TWI_I2C_MODE_COMBINED; - } else { - iface->writeNum = data->block[0] + 1; - iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; - } - iface->transPtr = data->block; - break; - default: - return -1; - } - - iface->result = 0; - iface->manual_stop = 0; - iface->read_write = read_write; - iface->command = command; - iface->timeout_count = 10; - - /* FIFO Initiation. Data in FIFO should be discarded before - * start a new operation. - */ - bfin_write_TWI_FIFO_CTL(0x3); - SSYNC(); - bfin_write_TWI_FIFO_CTL(0); - - /* clear int stat */ - bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); - - /* Set Transmit device address */ - bfin_write_TWI_MASTER_ADDR(addr); - SSYNC(); - - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - - switch (iface->cur_mode) { - case TWI_I2C_MODE_STANDARDSUB: - bfin_write_TWI_XMT_DATA8(iface->command); - bfin_write_TWI_INT_MASK(MCOMP | MERR | - ((iface->read_write == I2C_SMBUS_READ) ? - RCVSERV : XMTSERV)); - SSYNC(); - - if (iface->writeNum + 1 <= 255) - bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); - else { - bfin_write_TWI_MASTER_CTL(0xff << 6); - iface->manual_stop = 1; - } - /* Master enable */ - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | - ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); - break; - case TWI_I2C_MODE_COMBINED: - bfin_write_TWI_XMT_DATA8(iface->command); - bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV); - SSYNC(); - - if (iface->writeNum > 0) - bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); - else - bfin_write_TWI_MASTER_CTL(0x1 << 6); - /* Master enable */ - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | - ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); - break; - default: - bfin_write_TWI_MASTER_CTL(0); - if (size != I2C_SMBUS_QUICK) { - /* Don't access xmit data register when this is a - * read operation. - */ - if (iface->read_write != I2C_SMBUS_READ) { - if (iface->writeNum > 0) { - bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); - if (iface->writeNum <= 255) - bfin_write_TWI_MASTER_CTL(iface->writeNum << 6); - else { - bfin_write_TWI_MASTER_CTL(0xff << 6); - iface->manual_stop = 1; - } - iface->writeNum--; - } else { - bfin_write_TWI_XMT_DATA8(iface->command); - bfin_write_TWI_MASTER_CTL(1 << 6); - } - } else { - if (iface->readNum > 0 && iface->readNum <= 255) - bfin_write_TWI_MASTER_CTL(iface->readNum << 6); - else if (iface->readNum > 255) { - bfin_write_TWI_MASTER_CTL(0xff << 6); - iface->manual_stop = 1; - } else { - del_timer(&iface->timeout_timer); - break; - } - } - } - bfin_write_TWI_INT_MASK(MCOMP | MERR | - ((iface->read_write == I2C_SMBUS_READ) ? - RCVSERV : XMTSERV)); - SSYNC(); - - /* Master enable */ - bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | - ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | - ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); - break; - } - SSYNC(); - - wait_for_completion(&iface->complete); - - rc = (iface->result >= 0) ? 0 : -1; - - /* Release mutex */ - mutex_unlock(&iface->twi_lock); - - return rc; -} - -/* - * Return what the adapter supports - */ -static u32 bfin_twi_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_I2C; -} - - -static struct i2c_algorithm bfin_twi_algorithm = { - .master_xfer = bfin_twi_master_xfer, - .smbus_xfer = bfin_twi_smbus_xfer, - .functionality = bfin_twi_functionality, -}; - - -static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state) -{ -/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ - - /* Disable TWI */ - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA); - SSYNC(); - - return 0; -} - -static int i2c_bfin_twi_resume(struct platform_device *dev) -{ -/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ - - /* Enable TWI */ - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); - SSYNC(); - - return 0; -} - -static int i2c_bfin_twi_probe(struct platform_device *dev) -{ - struct bfin_twi_iface *iface = &twi_iface; - struct i2c_adapter *p_adap; - int rc; - - mutex_init(&(iface->twi_lock)); - spin_lock_init(&(iface->lock)); - init_completion(&(iface->complete)); - iface->irq = IRQ_TWI; - - init_timer(&(iface->timeout_timer)); - iface->timeout_timer.function = bfin_twi_timeout; - iface->timeout_timer.data = (unsigned long)iface; - - p_adap = &iface->adap; - p_adap->id = I2C_HW_BLACKFIN; - strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); - p_adap->algo = &bfin_twi_algorithm; - p_adap->algo_data = iface; - p_adap->class = I2C_CLASS_ALL; - p_adap->dev.parent = &dev->dev; - - rc = request_irq(iface->irq, bfin_twi_interrupt_entry, - IRQF_DISABLED, dev->name, iface); - if (rc) { - dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n", - iface->irq); - return -ENODEV; - } - - /* Set TWI internal clock as 10MHz */ - bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); - - /* Set Twi interface clock as specified */ - bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) - << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) - & 0xFF)); - - /* Enable TWI */ - bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); - SSYNC(); - - rc = i2c_add_adapter(p_adap); - if (rc < 0) - free_irq(iface->irq, iface); - else - platform_set_drvdata(dev, iface); - - return rc; -} - -static int i2c_bfin_twi_remove(struct platform_device *pdev) -{ - struct bfin_twi_iface *iface = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - i2c_del_adapter(&(iface->adap)); - free_irq(iface->irq, iface); - - return 0; -} - -static struct platform_driver i2c_bfin_twi_driver = { - .probe = i2c_bfin_twi_probe, - .remove = i2c_bfin_twi_remove, - .suspend = i2c_bfin_twi_suspend, - .resume = i2c_bfin_twi_resume, - .driver = { - .name = "i2c-bfin-twi", - .owner = THIS_MODULE, - }, -}; - -static int __init i2c_bfin_twi_init(void) -{ - pr_info("I2C: Blackfin I2C TWI driver\n"); - - return platform_driver_register(&i2c_bfin_twi_driver); -} - -static void __exit i2c_bfin_twi_exit(void) -{ - platform_driver_unregister(&i2c_bfin_twi_driver); -} - -MODULE_AUTHOR("Sonic Zhang "); -MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI"); -MODULE_LICENSE("GPL"); - -module_init(i2c_bfin_twi_init); -module_exit(i2c_bfin_twi_exit); diff --git a/trunk/drivers/i2c/busses/i2c-elektor.c b/trunk/drivers/i2c/busses/i2c-elektor.c index 804f0a551c05..834967464814 100644 --- a/trunk/drivers/i2c/busses/i2c-elektor.c +++ b/trunk/drivers/i2c/busses/i2c-elektor.c @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -208,7 +207,7 @@ static struct i2c_adapter pcf_isa_ops = { .name = "i2c-elektor", }; -static int __devinit elektor_match(struct device *dev, unsigned int id) +static int __init i2c_pcfisa_init(void) { #ifdef __alpha__ /* check to see we have memory mapped PCF8584 connected to the @@ -223,8 +222,9 @@ static int __devinit elektor_match(struct device *dev, unsigned int id) /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - dev_dbg(dev, "found cy82c693, config " - "register 0x47 = 0x%02x\n", config); + pr_debug("%s: found cy82c693, config " + "register 0x47 = 0x%02x\n", + pcf_isa_ops.name, config); /* UP2000 board has this register set to 0xe1, but the most significant bit as seems can be @@ -244,9 +244,9 @@ static int __devinit elektor_match(struct device *dev, unsigned int id) 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - dev_info(dev, "found API UP2000 like " - "board, will probe PCF8584 " - "later\n"); + pr_info("%s: found API UP2000 like " + "board, will probe PCF8584 " + "later\n", pcf_isa_ops.name); } } pci_dev_put(cy693_dev); @@ -256,27 +256,22 @@ static int __devinit elektor_match(struct device *dev, unsigned int id) /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - dev_err(dev, "incorrect base address (%#x) specified " - "for mmapped I/O\n", base); - return 0; + printk(KERN_ERR "%s: incorrect base address (%#x) specified " + "for mmapped I/O\n", pcf_isa_ops.name, base); + return -ENODEV; } if (base == 0) { base = DEFAULT_BASE; } - return 1; -} -static int __devinit elektor_probe(struct device *dev, unsigned int id) -{ init_waitqueue_head(&pcf_wait); if (pcf_isa_init()) return -ENODEV; - pcf_isa_ops.dev.parent = dev; if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) goto fail; - dev_info(dev, "found device at %#x\n", base); + dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); return 0; @@ -296,7 +291,7 @@ static int __devinit elektor_probe(struct device *dev, unsigned int id) return -ENODEV; } -static int __devexit elektor_remove(struct device *dev, unsigned int id) +static void i2c_pcfisa_exit(void) { i2c_del_adapter(&pcf_isa_ops); @@ -312,28 +307,6 @@ static int __devexit elektor_remove(struct device *dev, unsigned int id) iounmap(base_iomem); release_mem_region(base, 2); } - - return 0; -} - -static struct isa_driver i2c_elektor_driver = { - .match = elektor_match, - .probe = elektor_probe, - .remove = __devexit_p(elektor_remove), - .driver = { - .owner = THIS_MODULE, - .name = "i2c-elektor", - }, -}; - -static int __init i2c_pcfisa_init(void) -{ - return isa_register_driver(&i2c_elektor_driver, 1); -} - -static void __exit i2c_pcfisa_exit(void) -{ - isa_unregister_driver(&i2c_elektor_driver); } MODULE_AUTHOR("Hans Berglund "); diff --git a/trunk/drivers/i2c/busses/i2c-gpio.c b/trunk/drivers/i2c/busses/i2c-gpio.c deleted file mode 100644 index a7dd54654a9a..000000000000 --- a/trunk/drivers/i2c/busses/i2c-gpio.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Bitbanging I2C bus driver using the GPIO API - * - * Copyright (C) 2007 Atmel Corporation - * - * 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 - -/* Toggle SDA by changing the direction of the pin */ -static void i2c_gpio_setsda_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->sda_pin); - else - gpio_direction_output(pdata->sda_pin, 0); -} - -/* - * Toggle SDA by changing the output value of the pin. This is only - * valid for pins configured as open drain (i.e. setting the value - * high effectively turns off the output driver.) - */ -static void i2c_gpio_setsda_val(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - gpio_set_value(pdata->sda_pin, state); -} - -/* Toggle SCL by changing the direction of the pin. */ -static void i2c_gpio_setscl_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->scl_pin); - else - gpio_direction_output(pdata->scl_pin, 0); -} - -/* - * Toggle SCL by changing the output value of the pin. This is used - * for pins that are configured as open drain and for output-only - * pins. The latter case will break the i2c protocol, but it will - * often work in practice. - */ -static void i2c_gpio_setscl_val(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - gpio_set_value(pdata->scl_pin, state); -} - -int i2c_gpio_getsda(void *data) -{ - struct i2c_gpio_platform_data *pdata = data; - - return gpio_get_value(pdata->sda_pin); -} - -int i2c_gpio_getscl(void *data) -{ - struct i2c_gpio_platform_data *pdata = data; - - return gpio_get_value(pdata->scl_pin); -} - -static int __init i2c_gpio_probe(struct platform_device *pdev) -{ - struct i2c_gpio_platform_data *pdata; - struct i2c_algo_bit_data *bit_data; - struct i2c_adapter *adap; - int ret; - - pdata = pdev->dev.platform_data; - if (!pdata) - return -ENXIO; - - ret = -ENOMEM; - adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (!adap) - goto err_alloc_adap; - bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); - if (!bit_data) - goto err_alloc_bit_data; - - ret = gpio_request(pdata->sda_pin, "sda"); - if (ret) - goto err_request_sda; - ret = gpio_request(pdata->scl_pin, "scl"); - if (ret) - goto err_request_scl; - - if (pdata->sda_is_open_drain) { - gpio_direction_output(pdata->sda_pin, 1); - bit_data->setsda = i2c_gpio_setsda_val; - } else { - gpio_direction_input(pdata->sda_pin); - bit_data->setsda = i2c_gpio_setsda_dir; - } - - if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { - gpio_direction_output(pdata->scl_pin, 1); - bit_data->setscl = i2c_gpio_setscl_val; - } else { - gpio_direction_input(pdata->scl_pin); - bit_data->setscl = i2c_gpio_setscl_dir; - } - - if (!pdata->scl_is_output_only) - bit_data->getscl = i2c_gpio_getscl; - bit_data->getsda = i2c_gpio_getsda; - - if (pdata->udelay) - bit_data->udelay = pdata->udelay; - else if (pdata->scl_is_output_only) - bit_data->udelay = 50; /* 10 kHz */ - else - bit_data->udelay = 5; /* 100 kHz */ - - if (pdata->timeout) - bit_data->timeout = pdata->timeout; - else - bit_data->timeout = HZ / 10; /* 100 ms */ - - bit_data->data = pdata; - - adap->owner = THIS_MODULE; - snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); - adap->algo_data = bit_data; - adap->dev.parent = &pdev->dev; - - ret = i2c_bit_add_bus(adap); - if (ret) - goto err_add_bus; - - platform_set_drvdata(pdev, adap); - - dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", - pdata->sda_pin, pdata->scl_pin, - pdata->scl_is_output_only - ? ", no clock stretching" : ""); - - return 0; - -err_add_bus: - gpio_free(pdata->scl_pin); -err_request_scl: - gpio_free(pdata->sda_pin); -err_request_sda: - kfree(bit_data); -err_alloc_bit_data: - kfree(adap); -err_alloc_adap: - return ret; -} - -static int __exit i2c_gpio_remove(struct platform_device *pdev) -{ - struct i2c_gpio_platform_data *pdata; - struct i2c_adapter *adap; - - adap = platform_get_drvdata(pdev); - pdata = pdev->dev.platform_data; - - i2c_del_adapter(adap); - gpio_free(pdata->scl_pin); - gpio_free(pdata->sda_pin); - kfree(adap->algo_data); - kfree(adap); - - return 0; -} - -static struct platform_driver i2c_gpio_driver = { - .driver = { - .name = "i2c-gpio", - .owner = THIS_MODULE, - }, - .remove = __exit_p(i2c_gpio_remove), -}; - -static int __init i2c_gpio_init(void) -{ - int ret; - - ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); - if (ret) - printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); - - return ret; -} -module_init(i2c_gpio_init); - -static void __exit i2c_gpio_exit(void) -{ - platform_driver_unregister(&i2c_gpio_driver); -} -module_exit(i2c_gpio_exit); - -MODULE_AUTHOR("Haavard Skinnemoen "); -MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/i2c/busses/i2c-i801.c b/trunk/drivers/i2c/busses/i2c-i801.c index 611b57192c96..a320e7d82c1f 100644 --- a/trunk/drivers/i2c/busses/i2c-i801.c +++ b/trunk/drivers/i2c/busses/i2c-i801.c @@ -527,7 +527,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; - snprintf(i801_adapter.name, sizeof(i801_adapter.name), + snprintf(i801_adapter.name, I2C_NAME_SIZE, "SMBus I801 adapter at %04lx", i801_smba); err = i2c_add_adapter(&i801_adapter); if (err) { diff --git a/trunk/drivers/i2c/busses/i2c-isa.c b/trunk/drivers/i2c/busses/i2c-isa.c index b0e1370075de..5f33bc9c1e02 100644 --- a/trunk/drivers/i2c/busses/i2c-isa.c +++ b/trunk/drivers/i2c/busses/i2c-isa.c @@ -41,10 +41,6 @@ #include #include -/* Exported by i2c-core for i2c-isa only */ -extern void i2c_adapter_dev_release(struct device *dev); -extern struct class i2c_adapter_class; - static u32 isa_func(struct i2c_adapter *adapter); /* This is the actual algorithm we define */ @@ -68,6 +64,16 @@ static u32 isa_func(struct i2c_adapter *adapter) } +/* Copied from i2c-core */ +static ssize_t show_adapter_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + return sprintf(buf, "%s\n", adap->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); + + /* We implement an interface which resembles i2c_{add,del}_driver, but for i2c-isa drivers. We don't have to remember and handle lists of drivers and adapters so this is much more simple, of course. */ @@ -133,18 +139,41 @@ static int __init i2c_isa_init(void) isa_adapter.nr = ANY_I2C_ISA_BUS; isa_adapter.dev.parent = &platform_bus; sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr); + isa_adapter.dev.driver = &i2c_adapter_driver; isa_adapter.dev.release = &i2c_adapter_dev_release; - isa_adapter.dev.class = &i2c_adapter_class; err = device_register(&isa_adapter.dev); if (err) { printk(KERN_ERR "i2c-isa: Failed to register device\n"); goto exit; } + err = device_create_file(&isa_adapter.dev, &dev_attr_name); + if (err) { + printk(KERN_ERR "i2c-isa: Failed to create name file\n"); + goto exit_unregister; + } + + /* Add this adapter to the i2c_adapter class */ + memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device)); + isa_adapter.class_dev.dev = &isa_adapter.dev; + isa_adapter.class_dev.class = &i2c_adapter_class; + strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id, + BUS_ID_SIZE); + err = class_device_register(&isa_adapter.class_dev); + if (err) { + printk(KERN_ERR "i2c-isa: Failed to register class device\n"); + goto exit_remove_name; + } dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name); return 0; +exit_remove_name: + device_remove_file(&isa_adapter.dev, &dev_attr_name); +exit_unregister: + init_completion(&isa_adapter.dev_released); /* Needed? */ + device_unregister(&isa_adapter.dev); + wait_for_completion(&isa_adapter.dev_released); exit: return err; } @@ -172,11 +201,15 @@ static void __exit i2c_isa_exit(void) /* Clean up the sysfs representation */ dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n"); init_completion(&isa_adapter.dev_released); + init_completion(&isa_adapter.class_dev_released); + class_device_unregister(&isa_adapter.class_dev); + device_remove_file(&isa_adapter.dev, &dev_attr_name); device_unregister(&isa_adapter.dev); /* Wait for sysfs to drop all references */ dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n"); wait_for_completion(&isa_adapter.dev_released); + wait_for_completion(&isa_adapter.class_dev_released); dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name); } diff --git a/trunk/drivers/i2c/busses/i2c-ixp2000.c b/trunk/drivers/i2c/busses/i2c-ixp2000.c index 6352121a2827..efa3ecc5522a 100644 --- a/trunk/drivers/i2c/busses/i2c-ixp2000.c +++ b/trunk/drivers/i2c/busses/i2c-ixp2000.c @@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP2000, strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - sizeof(drv_data->adapter.name)); + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data, drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/trunk/drivers/i2c/busses/i2c-ixp4xx.c b/trunk/drivers/i2c/busses/i2c-ixp4xx.c index 069ed7f3b395..08e89b83984a 100644 --- a/trunk/drivers/i2c/busses/i2c-ixp4xx.c +++ b/trunk/drivers/i2c/busses/i2c-ixp4xx.c @@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP4XX; drv_data->adapter.class = I2C_CLASS_HWMON; strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - sizeof(drv_data->adapter.name)); + I2C_NAME_SIZE); drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/trunk/drivers/i2c/busses/i2c-mpc.c b/trunk/drivers/i2c/busses/i2c-mpc.c index c6b6898592b1..ee65aa1be13a 100644 --- a/trunk/drivers/i2c/busses/i2c-mpc.c +++ b/trunk/drivers/i2c/busses/i2c-mpc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/i2c/busses/i2c-mv64xxx.c b/trunk/drivers/i2c/busses/i2c-mv64xxx.c index a55b3335d1be..a3283b907eb8 100644 --- a/trunk/drivers/i2c/busses/i2c-mv64xxx.c +++ b/trunk/drivers/i2c/busses/i2c-mv64xxx.c @@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) } strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", - sizeof(drv_data->adapter.name)); + I2C_NAME_SIZE); init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); diff --git a/trunk/drivers/i2c/busses/i2c-nforce2.c b/trunk/drivers/i2c/busses/i2c-nforce2.c index 3cd0d63e7b50..1514ec5b77f8 100644 --- a/trunk/drivers/i2c/busses/i2c-nforce2.c +++ b/trunk/drivers/i2c/busses/i2c-nforce2.c @@ -33,8 +33,6 @@ nForce4 MCP-04 0034 nForce4 MCP51 0264 nForce4 MCP55 0368 - nForce MCP61 03EB - nForce MCP65 0446 This driver supports the 2 SMBuses that are included in the MCP of the nForce2/3/4/5xx chipsets. @@ -202,8 +200,6 @@ static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) }, { 0 } }; @@ -244,7 +240,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; - snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), + snprintf(smbus->adapter.name, I2C_NAME_SIZE, "SMBus nForce2 adapter at %04x", smbus->base); error = i2c_add_adapter(&smbus->adapter); diff --git a/trunk/drivers/i2c/busses/i2c-omap.c b/trunk/drivers/i2c/busses/i2c-omap.c index e471e3bfdc1e..bcd8367cede1 100644 --- a/trunk/drivers/i2c/busses/i2c-omap.c +++ b/trunk/drivers/i2c/busses/i2c-omap.c @@ -605,8 +605,7 @@ omap_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; /* i2c device drivers may be active on return from add_adapter() */ - adap->nr = pdev->id; - r = i2c_add_numbered_adapter(adap); + r = i2c_add_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); goto err_free_irq; diff --git a/trunk/drivers/i2c/busses/i2c-parport-light.c b/trunk/drivers/i2c/busses/i2c-parport-light.c index 49a95e2887bc..4bc42810b9aa 100644 --- a/trunk/drivers/i2c/busses/i2c-parport-light.c +++ b/trunk/drivers/i2c/busses/i2c-parport-light.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * - * i2c-parport-light.c I2C bus over parallel port * + * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2007 Jean Delvare + Copyright (C) 2003-2004 Jean Delvare Based on older i2c-velleman.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -35,9 +34,6 @@ #include "i2c-parport.h" #define DEFAULT_BASE 0x378 -#define DRVNAME "i2c-parport-light" - -static struct platform_device *pdev; static u16 base; module_param(base, ushort, 0); @@ -110,7 +106,7 @@ static struct i2c_algo_bit_data parport_algo_data = { .timeout = HZ, }; -/* ----- Driver registration ---------------------------------------------- */ +/* ----- I2c structure ---------------------------------------------------- */ static struct i2c_adapter parport_adapter = { .owner = THIS_MODULE, @@ -120,141 +116,55 @@ static struct i2c_adapter parport_adapter = { .name = "Parallel port adapter (light)", }; -static int __devinit i2c_parport_probe(struct platform_device *pdev) -{ - int err; - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) - return -EBUSY; - - /* Reset hardware to a sane state (SCL and SDA high) */ - parport_setsda(NULL, 1); - parport_setscl(NULL, 1); - /* Other init if needed (power on...) */ - if (adapter_parm[type].init.val) - line_set(1, &adapter_parm[type].init); - - parport_adapter.dev.parent = &pdev->dev; - err = i2c_bit_add_bus(&parport_adapter); - if (err) { - dev_err(&pdev->dev, "Unable to register with I2C\n"); - goto exit_region; - } - return 0; - -exit_region: - release_region(res->start, res->end - res->start + 1); - return err; -} - -static int __devexit i2c_parport_remove(struct platform_device *pdev) -{ - struct resource *res; - - i2c_del_adapter(&parport_adapter); - - /* Un-init if needed (power off...) */ - if (adapter_parm[type].init.val) - line_set(0, &adapter_parm[type].init); - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, res->end - res->start + 1); - return 0; -} - -static struct platform_driver i2c_parport_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRVNAME, - }, - .probe = i2c_parport_probe, - .remove = __devexit_p(i2c_parport_remove), -}; - -static int __init i2c_parport_device_add(u16 address) -{ - struct resource res = { - .start = address, - .end = address + 2, - .name = DRVNAME, - .flags = IORESOURCE_IO, - }; - int err; - - pdev = platform_device_alloc(DRVNAME, -1); - if (!pdev) { - err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); - goto exit; - } - - err = platform_device_add_resources(pdev, &res, 1); - if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); - goto exit_device_put; - } - - err = platform_device_add(pdev); - if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); - goto exit_device_put; - } - - return 0; - -exit_device_put: - platform_device_put(pdev); -exit: - return err; -} +/* ----- Module loading, unloading and information ------------------------ */ static int __init i2c_parport_init(void) { - int err; - if (type < 0) { - printk(KERN_ERR DRVNAME ": adapter type unspecified\n"); + printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); return -ENODEV; } if (type >= ARRAY_SIZE(adapter_parm)) { - printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type); + printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); return -ENODEV; } if (base == 0) { - pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE); + printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); base = DEFAULT_BASE; } + if (!request_region(base, 3, "i2c-parport")) + return -ENODEV; + if (!adapter_parm[type].getscl.val) parport_algo_data.getscl = NULL; - /* Sets global pdev as a side effect */ - err = i2c_parport_device_add(base); - if (err) - goto exit; + /* Reset hardware to a sane state (SCL and SDA high) */ + parport_setsda(NULL, 1); + parport_setscl(NULL, 1); + /* Other init if needed (power on...) */ + if (adapter_parm[type].init.val) + line_set(1, &adapter_parm[type].init); - err = platform_driver_register(&i2c_parport_driver); - if (err) - goto exit_device; + if (i2c_bit_add_bus(&parport_adapter) < 0) { + printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); + release_region(base, 3); + return -ENODEV; + } return 0; - -exit_device: - platform_device_unregister(pdev); -exit: - return err; } static void __exit i2c_parport_exit(void) { - platform_driver_unregister(&i2c_parport_driver); - platform_device_unregister(pdev); + /* Un-init if needed (power off...) */ + if (adapter_parm[type].init.val) + line_set(0, &adapter_parm[type].init); + + i2c_del_adapter(&parport_adapter); + release_region(base, 3); } MODULE_AUTHOR("Jean Delvare "); diff --git a/trunk/drivers/i2c/busses/i2c-parport.c b/trunk/drivers/i2c/busses/i2c-parport.c index 8c953707253f..66696a40c7b5 100644 --- a/trunk/drivers/i2c/busses/i2c-parport.c +++ b/trunk/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2007 Jean Delvare + Copyright (C) 2003-2004 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -137,12 +137,19 @@ static struct i2c_algo_bit_data parport_algo_data = { .setscl = parport_setscl, .getsda = parport_getsda, .getscl = parport_getscl, - .udelay = 10, /* ~50 kbps */ + .udelay = 60, .timeout = HZ, }; /* ----- I2c and parallel port call-back functions and structures --------- */ +static struct i2c_adapter parport_adapter = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .id = I2C_HW_B_LP, + .name = "Parallel port adapter", +}; + static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; @@ -162,17 +169,10 @@ static void i2c_parport_attach (struct parport *port) } /* Fill the rest of the structure */ - adapter->adapter.owner = THIS_MODULE; - adapter->adapter.class = I2C_CLASS_HWMON; - adapter->adapter.id = I2C_HW_B_LP; - strlcpy(adapter->adapter.name, "Parallel port adapter", - sizeof(adapter->adapter.name)); + adapter->adapter = parport_adapter; adapter->algo_data = parport_algo_data; - /* Slow down if we can't sense SCL */ - if (!adapter_parm[type].getscl.val) { + if (!adapter_parm[type].getscl.val) adapter->algo_data.getscl = NULL; - adapter->algo_data.udelay = 50; /* ~10 kbps */ - } adapter->algo_data.data = port; adapter->adapter.algo_data = &adapter->algo_data; @@ -214,12 +214,11 @@ static void i2c_parport_detach (struct parport *port) for (prev = NULL, adapter = adapter_list; adapter; prev = adapter, adapter = adapter->next) { if (adapter->pdev->port == port) { - i2c_del_adapter(&adapter->adapter); - /* Un-init if needed (power off...) */ if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); + i2c_del_adapter(&adapter->adapter); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; diff --git a/trunk/drivers/i2c/busses/i2c-pasemi.c b/trunk/drivers/i2c/busses/i2c-pasemi.c index 58e32714afb5..bf89eeef74e9 100644 --- a/trunk/drivers/i2c/busses/i2c-pasemi.c +++ b/trunk/drivers/i2c/busses/i2c-pasemi.c @@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), + snprintf(smbus->adapter.name, I2C_NAME_SIZE, "PA Semi SMBus adapter at 0x%lx", smbus->base); smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; diff --git a/trunk/drivers/i2c/busses/i2c-pca-isa.c b/trunk/drivers/i2c/busses/i2c-pca-isa.c index 5161aaf9341b..cc6536a19eca 100644 --- a/trunk/drivers/i2c/busses/i2c-pca-isa.c +++ b/trunk/drivers/i2c/busses/i2c-pca-isa.c @@ -25,9 +25,9 @@ #include #include #include +#include #include -#include #include #include @@ -119,26 +119,27 @@ static struct i2c_adapter pca_isa_ops = { .name = "PCA9564 ISA Adapter", }; -static int __devinit pca_isa_probe(struct device *dev, unsigned int id) +static int __init pca_isa_init(void) { + init_waitqueue_head(&pca_wait); - dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq); + printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq); if (!request_region(base, IO_SIZE, "i2c-pca-isa")) { - dev_err(dev, "I/O address %#08lx is in use\n", base); + printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base); goto out; } if (irq > -1) { if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) { - dev_err(dev, "Request irq%d failed\n", irq); + printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq); goto out_region; } } if (i2c_pca_add_bus(&pca_isa_ops) < 0) { - dev_err(dev, "Failed to add i2c bus\n"); + printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n"); goto out_irq; } @@ -153,7 +154,7 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id) return -ENODEV; } -static int __devexit pca_isa_remove(struct device *dev, unsigned int id) +static void pca_isa_exit(void) { i2c_del_adapter(&pca_isa_ops); @@ -162,27 +163,6 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id) free_irq(irq, &pca_isa_ops); } release_region(base, IO_SIZE); - - return 0; -} - -static struct isa_driver pca_isa_driver = { - .probe = pca_isa_probe, - .remove = __devexit_p(pca_isa_remove), - .driver = { - .owner = THIS_MODULE, - .name = "i2c-pca-isa", - } -}; - -static int __init pca_isa_init(void) -{ - return isa_register_driver(&pca_isa_driver, 1); -} - -static void __exit pca_isa_exit(void) -{ - isa_unregister_driver(&pca_isa_driver); } MODULE_AUTHOR("Ian Campbell "); diff --git a/trunk/drivers/i2c/busses/i2c-piix4.c b/trunk/drivers/i2c/busses/i2c-piix4.c index 5a52bf5e3fb0..21b180904085 100644 --- a/trunk/drivers/i2c/busses/i2c-piix4.c +++ b/trunk/drivers/i2c/busses/i2c-piix4.c @@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; - snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), + snprintf(piix4_adapter.name, I2C_NAME_SIZE, "SMBus PIIX4 adapter at %04x", piix4_smba); if ((retval = i2c_add_adapter(&piix4_adapter))) { diff --git a/trunk/drivers/i2c/busses/i2c-pxa.c b/trunk/drivers/i2c/busses/i2c-pxa.c index c059b27fa881..14e83d0aac8c 100644 --- a/trunk/drivers/i2c/busses/i2c-pxa.c +++ b/trunk/drivers/i2c/busses/i2c-pxa.c @@ -539,18 +539,6 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) writel(icr | ICR_START | ICR_TB, _ICR(i2c)); } -static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) -{ - u32 icr; - - /* - * Clear the STOP and ACK flags - */ - icr = readl(_ICR(i2c)); - icr &= ~(ICR_STOP | ICR_ACKNAK); - writel(icr, _IRC(i2c)); -} - /* * We are protected by the adapter bus mutex. */ @@ -593,7 +581,6 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) * The rest of the processing occurs in the interrupt handler. */ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - i2c_pxa_stop_message(i2c); /* * We place the return code in i2c->msg_idx. @@ -838,7 +825,7 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { }; static struct pxa_i2c i2c_pxa = { - .lock = __SPIN_LOCK_UNLOCKED(i2c_pxa.lock), + .lock = SPIN_LOCK_UNLOCKED, .adap = { .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, diff --git a/trunk/drivers/i2c/busses/i2c-s3c2410.c b/trunk/drivers/i2c/busses/i2c-s3c2410.c index e68a96f589fd..556f244aae76 100644 --- a/trunk/drivers/i2c/busses/i2c-s3c2410.c +++ b/trunk/drivers/i2c/busses/i2c-s3c2410.c @@ -61,8 +61,6 @@ struct s3c24xx_i2c { unsigned int msg_idx; unsigned int msg_ptr; - unsigned int tx_setup; - enum s3c24xx_i2c_state state; void __iomem *regs; @@ -201,11 +199,8 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr); writeb(addr, i2c->regs + S3C2410_IICDS); - /* delay here to ensure the data byte has gotten onto the bus - * before the transaction is started */ - - ndelay(i2c->tx_setup); - + // delay a bit and reset iiccon before setting start (per samsung) + udelay(1); dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon); writel(iiccon, i2c->regs + S3C2410_IICCON); @@ -327,15 +322,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) if (!is_msgend(i2c)) { byte = i2c->msg->buf[i2c->msg_ptr++]; writeb(byte, i2c->regs + S3C2410_IICDS); - - /* delay after writing the byte to allow the - * data setup time on the bus, as writing the - * data to the register causes the first bit - * to appear on SDA, and SCL will change as - * soon as the interrupt is acknowledged */ - - ndelay(i2c->tx_setup); - + } else if (!is_lastmsg(i2c)) { /* we need to go to the next i2c message */ @@ -583,10 +570,9 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { }; static struct s3c24xx_i2c s3c24xx_i2c = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock), - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), - .tx_setup = 50, - .adap = { + .lock = SPIN_LOCK_UNLOCKED, + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), + .adap = { .name = "s3c2410-i2c", .owner = THIS_MODULE, .algo = &s3c24xx_i2c_algorithm, @@ -745,6 +731,26 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) return 0; } +static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c) +{ + if (i2c->clk != NULL && !IS_ERR(i2c->clk)) { + clk_disable(i2c->clk); + clk_put(i2c->clk); + i2c->clk = NULL; + } + + if (i2c->regs != NULL) { + iounmap(i2c->regs); + i2c->regs = NULL; + } + + if (i2c->ioarea != NULL) { + release_resource(i2c->ioarea); + kfree(i2c->ioarea); + i2c->ioarea = NULL; + } +} + /* s3c24xx_i2c_probe * * called by the bus driver when a suitable device is found @@ -763,7 +769,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); ret = -ENOENT; - goto err_noclk; + goto out; } dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); @@ -776,7 +782,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IO resource\n"); ret = -ENOENT; - goto err_clk; + goto out; } i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, @@ -785,7 +791,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->ioarea == NULL) { dev_err(&pdev->dev, "cannot request IO\n"); ret = -ENXIO; - goto err_clk; + goto out; } i2c->regs = ioremap(res->start, (res->end-res->start)+1); @@ -793,7 +799,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); ret = -ENXIO; - goto err_ioarea; + goto out; } dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res); @@ -807,7 +813,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_init(i2c); if (ret != 0) - goto err_iomap; + goto out; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -817,7 +823,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IRQ\n"); ret = -ENOENT; - goto err_iomap; + goto out; } ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED, @@ -825,7 +831,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ\n"); - goto err_iomap; + goto out; } i2c->irq = res; @@ -835,29 +841,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto err_irq; + goto out; } platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); - return 0; - - err_irq: - free_irq(i2c->irq->start, i2c); - - err_iomap: - iounmap(i2c->regs); - err_ioarea: - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - - err_clk: - clk_disable(i2c->clk); - clk_put(i2c->clk); + out: + if (ret < 0) + s3c24xx_i2c_free(i2c); - err_noclk: return ret; } @@ -869,17 +863,11 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq->start, i2c); - - clk_disable(i2c->clk); - clk_put(i2c->clk); - - iounmap(i2c->regs); - - release_resource(i2c->ioarea); - kfree(i2c->ioarea); + + if (i2c != NULL) { + s3c24xx_i2c_free(i2c); + platform_set_drvdata(pdev, NULL); + } return 0; } diff --git a/trunk/drivers/i2c/busses/i2c-simtec.c b/trunk/drivers/i2c/busses/i2c-simtec.c deleted file mode 100644 index 10af8d31e12a..000000000000 --- a/trunk/drivers/i2c/busses/i2c-simtec.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2005 Simtec Electronics - * Ben Dooks - * - * Simtec Generic I2C Controller - * - * 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 - * - * 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 - -struct simtec_i2c_data { - struct resource *ioarea; - void __iomem *reg; - struct i2c_adapter adap; - struct i2c_algo_bit_data bit; -}; - -#define CMD_SET_SDA (1<<2) -#define CMD_SET_SCL (1<<3) - -#define STATE_SDA (1<<0) -#define STATE_SCL (1<<1) - -/* i2c bit-bus functions */ - -static void simtec_i2c_setsda(void *pw, int state) -{ - struct simtec_i2c_data *pd = pw; - writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg); -} - -static void simtec_i2c_setscl(void *pw, int state) -{ - struct simtec_i2c_data *pd = pw; - writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg); -} - -static int simtec_i2c_getsda(void *pw) -{ - struct simtec_i2c_data *pd = pw; - return readb(pd->reg) & STATE_SDA ? 1 : 0; -} - -static int simtec_i2c_getscl(void *pw) -{ - struct simtec_i2c_data *pd = pw; - return readb(pd->reg) & STATE_SCL ? 1 : 0; -} - -/* device registration */ - -static int simtec_i2c_probe(struct platform_device *dev) -{ - struct simtec_i2c_data *pd; - struct resource *res; - int size; - int ret; - - pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL); - if (pd == NULL) { - dev_err(&dev->dev, "cannot allocate private data\n"); - return -ENOMEM; - } - - platform_set_drvdata(dev, pd); - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&dev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err; - } - - size = (res->end-res->start)+1; - - pd->ioarea = request_mem_region(res->start, size, dev->name); - if (pd->ioarea == NULL) { - dev_err(&dev->dev, "cannot request IO\n"); - ret = -ENXIO; - goto err; - } - - pd->reg = ioremap(res->start, size); - if (pd->reg == NULL) { - dev_err(&dev->dev, "cannot map IO\n"); - ret = -ENXIO; - goto err_res; - } - - /* setup the private data */ - - pd->adap.owner = THIS_MODULE; - pd->adap.algo_data = &pd->bit; - pd->adap.dev.parent = &dev->dev; - - strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name)); - - pd->bit.data = pd; - pd->bit.setsda = simtec_i2c_setsda; - pd->bit.setscl = simtec_i2c_setscl; - pd->bit.getsda = simtec_i2c_getsda; - pd->bit.getscl = simtec_i2c_getscl; - pd->bit.timeout = HZ; - pd->bit.udelay = 20; - - ret = i2c_bit_add_bus(&pd->adap); - if (ret) - goto err_all; - - return 0; - - err_all: - iounmap(pd->reg); - - err_res: - release_resource(pd->ioarea); - kfree(pd->ioarea); - - err: - kfree(pd); - return ret; -} - -static int simtec_i2c_remove(struct platform_device *dev) -{ - struct simtec_i2c_data *pd = platform_get_drvdata(dev); - - i2c_del_adapter(&pd->adap); - - iounmap(pd->reg); - release_resource(pd->ioarea); - kfree(pd->ioarea); - kfree(pd); - - return 0; -} - - -/* device driver */ - -static struct platform_driver simtec_i2c_driver = { - .driver = { - .name = "simtec-i2c", - .owner = THIS_MODULE, - }, - .probe = simtec_i2c_probe, - .remove = simtec_i2c_remove, -}; - -static int __init i2c_adap_simtec_init(void) -{ - return platform_driver_register(&simtec_i2c_driver); -} - -static void __exit i2c_adap_simtec_exit(void) -{ - platform_driver_unregister(&simtec_i2c_driver); -} - -module_init(i2c_adap_simtec_init); -module_exit(i2c_adap_simtec_exit); - -MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/i2c/busses/i2c-sis96x.c b/trunk/drivers/i2c/busses/i2c-sis96x.c index dc235bb8e24d..4157b0cd604c 100644 --- a/trunk/drivers/i2c/busses/i2c-sis96x.c +++ b/trunk/drivers/i2c/busses/i2c-sis96x.c @@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ sis96x_adapter.dev.parent = &dev->dev; - snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name), + snprintf(sis96x_adapter.name, I2C_NAME_SIZE, "SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base); if ((retval = i2c_add_adapter(&sis96x_adapter))) { diff --git a/trunk/drivers/i2c/busses/i2c-tiny-usb.c b/trunk/drivers/i2c/busses/i2c-tiny-usb.c deleted file mode 100644 index 907999049d50..000000000000 --- a/trunk/drivers/i2c/busses/i2c-tiny-usb.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * driver for the i2c-tiny-usb adapter - 1.0 - * http://www.harbaum.org/till/i2c_tiny_usb - * - * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include - -/* include interfaces to usb layer */ -#include - -/* include interface to i2c layer */ -#include - -/* commands via USB, must match command ids in the firmware */ -#define CMD_ECHO 0 -#define CMD_GET_FUNC 1 -#define CMD_SET_DELAY 2 -#define CMD_GET_STATUS 3 - -#define CMD_I2C_IO 4 -#define CMD_I2C_IO_BEGIN (1<<0) -#define CMD_I2C_IO_END (1<<1) - -/* i2c bit delay, default is 10us -> 100kHz */ -static int delay = 10; -module_param(delay, int, 0); -MODULE_PARM_DESC(delay, "bit delay in microseconds, " - "e.g. 10 for 100kHz (default is 100kHz)"); - -static int usb_read(struct i2c_adapter *adapter, int cmd, - int value, int index, void *data, int len); - -static int usb_write(struct i2c_adapter *adapter, int cmd, - int value, int index, void *data, int len); - -/* ----- begin of i2c layer ---------------------------------------------- */ - -#define STATUS_IDLE 0 -#define STATUS_ADDRESS_ACK 1 -#define STATUS_ADDRESS_NAK 2 - -static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) -{ - unsigned char status; - struct i2c_msg *pmsg; - int i; - - dev_dbg(&adapter->dev, "master xfer %d messages:\n", num); - - for (i = 0 ; i < num ; i++) { - int cmd = CMD_I2C_IO; - - if (i == 0) - cmd |= CMD_I2C_IO_BEGIN; - - if (i == num-1) - cmd |= CMD_I2C_IO_END; - - pmsg = &msgs[i]; - - dev_dbg(&adapter->dev, - " %d: %s (flags %d) %d bytes to 0x%02x\n", - i, pmsg->flags & I2C_M_RD ? "read" : "write", - pmsg->flags, pmsg->len, pmsg->addr); - - /* and directly send the message */ - if (pmsg->flags & I2C_M_RD) { - /* read data */ - if (usb_read(adapter, cmd, - pmsg->flags, pmsg->addr, - pmsg->buf, pmsg->len) != pmsg->len) { - dev_err(&adapter->dev, - "failure reading data\n"); - return -EREMOTEIO; - } - } else { - /* write data */ - if (usb_write(adapter, cmd, - pmsg->flags, pmsg->addr, - pmsg->buf, pmsg->len) != pmsg->len) { - dev_err(&adapter->dev, - "failure writing data\n"); - return -EREMOTEIO; - } - } - - /* read status */ - if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) { - dev_err(&adapter->dev, "failure reading status\n"); - return -EREMOTEIO; - } - - dev_dbg(&adapter->dev, " status = %d\n", status); - if (status == STATUS_ADDRESS_NAK) - return -EREMOTEIO; - } - - return i; -} - -static u32 usb_func(struct i2c_adapter *adapter) -{ - u32 func; - - /* get functionality from adapter */ - if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) != - sizeof(func)) { - dev_err(&adapter->dev, "failure reading functionality\n"); - return 0; - } - - return func; -} - -/* This is the actual algorithm we define */ -static const struct i2c_algorithm usb_algorithm = { - .master_xfer = usb_xfer, - .functionality = usb_func, -}; - -/* ----- end of i2c layer ------------------------------------------------ */ - -/* ----- begin of usb layer ---------------------------------------------- */ - -/* The usb i2c interface uses a vid/pid pair donated by */ -/* Future Technology Devices International Ltd. */ -static struct usb_device_id i2c_tiny_usb_table [] = { - { USB_DEVICE(0x0403, 0xc631) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table); - -/* Structure to hold all of our device specific stuff */ -struct i2c_tiny_usb { - struct usb_device *usb_dev; /* the usb device for this device */ - struct usb_interface *interface; /* the interface for this device */ - struct i2c_adapter adapter; /* i2c related things */ -}; - -static int usb_read(struct i2c_adapter *adapter, int cmd, - int value, int index, void *data, int len) -{ - struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; - - /* do control transfer */ - return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0), - cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | - USB_DIR_IN, value, index, data, len, 2000); -} - -static int usb_write(struct i2c_adapter *adapter, int cmd, - int value, int index, void *data, int len) -{ - struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; - - /* do control transfer */ - return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0), - cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, index, data, len, 2000); -} - -static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev) -{ - usb_put_dev(dev->usb_dev); - kfree(dev); -} - -static int i2c_tiny_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct i2c_tiny_usb *dev; - int retval = -ENOMEM; - u16 version; - - dev_dbg(&interface->dev, "probing usb device\n"); - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - goto error; - } - - dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice); - dev_info(&interface->dev, - "version %x.%02x found at bus %03d address %03d\n", - version >> 8, version & 0xff, - dev->usb_dev->bus->busnum, dev->usb_dev->devnum); - - /* setup i2c adapter description */ - dev->adapter.owner = THIS_MODULE; - dev->adapter.class = I2C_CLASS_HWMON; - dev->adapter.algo = &usb_algorithm; - dev->adapter.algo_data = dev; - snprintf(dev->adapter.name, I2C_NAME_SIZE, - "i2c-tiny-usb at bus %03d device %03d", - dev->usb_dev->bus->busnum, dev->usb_dev->devnum); - - if (usb_write(&dev->adapter, CMD_SET_DELAY, - cpu_to_le16(delay), 0, NULL, 0) != 0) { - dev_err(&dev->adapter.dev, - "failure setting delay to %dus\n", delay); - retval = -EIO; - goto error; - } - - dev->adapter.dev.parent = &dev->interface->dev; - - /* and finally attach to i2c layer */ - i2c_add_adapter(&dev->adapter); - - /* inform user about successful attachment to i2c layer */ - dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n"); - - return 0; - - error: - if (dev) - i2c_tiny_usb_free(dev); - - return retval; -} - -static void i2c_tiny_usb_disconnect(struct usb_interface *interface) -{ - struct i2c_tiny_usb *dev = usb_get_intfdata(interface); - - i2c_del_adapter(&dev->adapter); - usb_set_intfdata(interface, NULL); - i2c_tiny_usb_free(dev); - - dev_dbg(&interface->dev, "disconnected\n"); -} - -static struct usb_driver i2c_tiny_usb_driver = { - .name = "i2c-tiny-usb", - .probe = i2c_tiny_usb_probe, - .disconnect = i2c_tiny_usb_disconnect, - .id_table = i2c_tiny_usb_table, -}; - -static int __init usb_i2c_tiny_usb_init(void) -{ - /* register this driver with the USB subsystem */ - return usb_register(&i2c_tiny_usb_driver); -} - -static void __exit usb_i2c_tiny_usb_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&i2c_tiny_usb_driver); -} - -module_init(usb_i2c_tiny_usb_init); -module_exit(usb_i2c_tiny_usb_exit); - -/* ----- end of usb layer ------------------------------------------------ */ - -MODULE_AUTHOR("Till Harbaum "); -MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/i2c/busses/i2c-viapro.c b/trunk/drivers/i2c/busses/i2c-viapro.c index 7a2bc06304fc..03c5fc868548 100644 --- a/trunk/drivers/i2c/busses/i2c-viapro.c +++ b/trunk/drivers/i2c/busses/i2c-viapro.c @@ -404,7 +404,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, } vt596_adapter.dev.parent = &pdev->dev; - snprintf(vt596_adapter.name, sizeof(vt596_adapter.name), + snprintf(vt596_adapter.name, I2C_NAME_SIZE, "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); diff --git a/trunk/drivers/i2c/busses/scx200_acb.c b/trunk/drivers/i2c/busses/scx200_acb.c index 0db56e7bc34e..0b082c5a0195 100644 --- a/trunk/drivers/i2c/busses/scx200_acb.c +++ b/trunk/drivers/i2c/busses/scx200_acb.c @@ -441,7 +441,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); - snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index); + snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index); adapter->owner = THIS_MODULE; adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; @@ -599,7 +599,6 @@ static __init int scx200_scan_pci(void) else { int i; - pci_dev_put(pdev); for (i = 0; i < MAX_DEVICES; ++i) { if (base[i] == 0) continue; diff --git a/trunk/drivers/i2c/chips/Kconfig b/trunk/drivers/i2c/chips/Kconfig index ea085a006ead..87ee3ce58618 100644 --- a/trunk/drivers/i2c/chips/Kconfig +++ b/trunk/drivers/i2c/chips/Kconfig @@ -3,10 +3,11 @@ # menu "Miscellaneous I2C Chip support" + depends on I2C config SENSORS_DS1337 tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1337 and DS1339 real-time clock chips. @@ -16,7 +17,7 @@ config SENSORS_DS1337 config SENSORS_DS1374 tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1374 real-time clock chips. @@ -26,7 +27,7 @@ config SENSORS_DS1374 config SENSORS_EEPROM tristate "EEPROM reader" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get read-only access to the EEPROM data available on modern memory DIMMs and Sony Vaio laptops. Such @@ -37,7 +38,7 @@ config SENSORS_EEPROM config SENSORS_PCF8574 tristate "Philips PCF8574 and PCF8574A" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8574 and @@ -51,7 +52,7 @@ config SENSORS_PCF8574 config SENSORS_PCA9539 tristate "Philips PCA9539 16-bit I/O port" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for the Philips PCA9539 16-bit I/O port. @@ -61,7 +62,7 @@ config SENSORS_PCA9539 config SENSORS_PCF8591 tristate "Philips PCF8591" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8591 chips. @@ -74,7 +75,7 @@ config SENSORS_PCF8591 config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" - depends on ARCH_OMAP_OTG + depends on I2C && ARCH_OMAP_OTG help If you say yes here you get support for the Philips ISP1301 USB-On-The-Go transceiver working with the OMAP OTG controller. @@ -89,7 +90,7 @@ config ISP1301_OMAP # and having mostly OMAP-specific board support config TPS65010 tristate "TPS6501x Power Management chips" - depends on ARCH_OMAP + depends on I2C && ARCH_OMAP default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of @@ -102,7 +103,7 @@ config TPS65010 config SENSORS_M41T00 tristate "ST M41T00 RTC chip" - depends on PPC32 + depends on I2C && PPC32 help If you say yes here you get support for the ST M41T00 RTC chip. @@ -111,7 +112,7 @@ config SENSORS_M41T00 config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for the Maxim MAX6875 EEPROM-programmable, quad power-supply sequencer/supervisor. diff --git a/trunk/drivers/i2c/i2c-boardinfo.c b/trunk/drivers/i2c/i2c-boardinfo.c deleted file mode 100644 index ffb35f09df03..000000000000 --- a/trunk/drivers/i2c/i2c-boardinfo.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * i2c-boardinfo.h - collect pre-declarations of I2C devices - * - * 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. - */ - -#include -#include - -#include "i2c-core.h" - - -/* These symbols are exported ONLY FOR the i2c core. - * No other users will be supported. - */ -DEFINE_MUTEX(__i2c_board_lock); -EXPORT_SYMBOL_GPL(__i2c_board_lock); - -LIST_HEAD(__i2c_board_list); -EXPORT_SYMBOL_GPL(__i2c_board_list); - -int __i2c_first_dynamic_bus_num; -EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); - - -/** - * i2c_register_board_info - statically declare I2C devices - * @busnum: identifies the bus to which these devices belong - * @info: vector of i2c device descriptors - * @len: how many descriptors in the vector; may be zero to reserve - * the specified bus number. - * - * Systems using the Linux I2C driver stack can declare tables of board info - * while they initialize. This should be done in board-specific init code - * near arch_initcall() time, or equivalent, before any I2C adapter driver is - * registered. For example, mainboard init code could define several devices, - * as could the init code for each daughtercard in a board stack. - * - * The I2C devices will be created later, after the adapter for the relevant - * bus has been registered. After that moment, standard driver model tools - * are used to bind "new style" I2C drivers to the devices. The bus number - * for any device declared using this routine is not available for dynamic - * allocation. - * - * The board info passed can safely be __initdata, but be careful of embedded - * pointers (for platform_data, functions, etc) since that won't be copied. - */ -int __init -i2c_register_board_info(int busnum, - struct i2c_board_info const *info, unsigned len) -{ - int status; - - mutex_lock(&__i2c_board_lock); - - /* dynamic bus numbers will be assigned after the last static one */ - if (busnum >= __i2c_first_dynamic_bus_num) - __i2c_first_dynamic_bus_num = busnum + 1; - - for (status = 0; len; len--, info++) { - struct i2c_devinfo *devinfo; - - devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); - if (!devinfo) { - pr_debug("i2c-core: can't register boardinfo!\n"); - status = -ENOMEM; - break; - } - - devinfo->busnum = busnum; - devinfo->board_info = *info; - list_add_tail(&devinfo->list, &__i2c_board_list); - } - - mutex_unlock(&__i2c_board_lock); - - return status; -} diff --git a/trunk/drivers/i2c/i2c-core.c b/trunk/drivers/i2c/i2c-core.c index 64f8e56d300e..21fe1406c8b4 100644 --- a/trunk/drivers/i2c/i2c-core.c +++ b/trunk/drivers/i2c/i2c-core.c @@ -35,92 +35,29 @@ #include #include -#include "i2c-core.h" - static LIST_HEAD(adapters); static LIST_HEAD(drivers); static DEFINE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove) /* ------------------------------------------------------------------------- */ +/* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_driver *driver = to_i2c_driver(drv); - - /* make legacy i2c drivers bypass driver model probing entirely; - * such drivers scan each i2c adapter/bus themselves. - */ - if (!is_newstyle_driver(driver)) - return 0; - - /* new style drivers use the same kind of driver matching policy - * as platform devices or SPI: compare device and driver IDs. - */ - return strcmp(client->driver_name, drv->name) == 0; -} - -#ifdef CONFIG_HOTPLUG - -/* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; - - /* by definition, legacy drivers can't hotplug */ - if (dev->driver || !client->driver_name) - return 0; - - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) - return -ENOMEM; - envp[i] = NULL; - dev_dbg(dev, "uevent\n"); - return 0; + return 1; } -#else -#define i2c_device_uevent NULL -#endif /* CONFIG_HOTPLUG */ - static int i2c_device_probe(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_driver *driver = to_i2c_driver(dev->driver); - - if (!driver->probe) - return -ENODEV; - client->driver = driver; - dev_dbg(dev, "probe\n"); - return driver->probe(client); + return -ENODEV; } static int i2c_device_remove(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_driver *driver; - int status; - - if (!dev->driver) - return 0; - - driver = to_i2c_driver(dev->driver); - if (driver->remove) { - dev_dbg(dev, "remove\n"); - status = driver->remove(client); - } else { - dev->driver = NULL; - status = 0; - } - if (status == 0) - client->driver = NULL; - return status; + return 0; } static void i2c_device_shutdown(struct device *dev) @@ -158,184 +95,122 @@ static int i2c_device_resume(struct device * dev) return driver->resume(to_i2c_client(dev)); } -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - -static void i2c_client_dev_release(struct device *dev) -{ - kfree(to_i2c_client(dev)); -} - -static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - return sprintf(buf, "%s\n", client->name); -} - -static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - return client->driver_name - ? sprintf(buf, "%s\n", client->driver_name) - : 0; -} - -static struct device_attribute i2c_dev_attrs[] = { - __ATTR(name, S_IRUGO, show_client_name, NULL), - /* modalias helps coldplug: modprobe $(cat .../modalias) */ - __ATTR(modalias, S_IRUGO, show_modalias, NULL), - { }, -}; - struct bus_type i2c_bus_type = { .name = "i2c", - .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, - .uevent = i2c_device_uevent, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .suspend = i2c_device_suspend, .resume = i2c_device_resume, }; -EXPORT_SYMBOL_GPL(i2c_bus_type); - -/** - * i2c_new_device - instantiate an i2c device for use with a new style driver - * @adap: the adapter managing the device - * @info: describes one I2C device; bus_num is ignored - * - * Create a device to work with a new style i2c driver, where binding is - * handled through driver model probe()/remove() methods. This call is not - * appropriate for use by mainboad initialization logic, which usually runs - * during an arch_initcall() long before any i2c_adapter could exist. - * - * This returns the new i2c client, which may be saved for later use with - * i2c_unregister_device(); or NULL to indicate an error. - */ -struct i2c_client * -i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) -{ - struct i2c_client *client; - int status; - - client = kzalloc(sizeof *client, GFP_KERNEL); - if (!client) - return NULL; - - client->adapter = adap; - - client->dev.platform_data = info->platform_data; - client->flags = info->flags; - client->addr = info->addr; - client->irq = info->irq; - - strlcpy(client->driver_name, info->driver_name, - sizeof(client->driver_name)); - strlcpy(client->name, info->type, sizeof(client->name)); - - /* a new style driver may be bound to this device when we - * return from this function, or any later moment (e.g. maybe - * hotplugging will load the driver module). and the device - * refcount model is the standard driver model one. - */ - status = i2c_attach_client(client); - if (status < 0) { - kfree(client); - client = NULL; - } - return client; -} -EXPORT_SYMBOL_GPL(i2c_new_device); +/* ------------------------------------------------------------------------- */ -/** - * i2c_unregister_device - reverse effect of i2c_new_device() - * @client: value returned from i2c_new_device() - */ -void i2c_unregister_device(struct i2c_client *client) +void i2c_adapter_dev_release(struct device *dev) { - struct i2c_adapter *adapter = client->adapter; - struct i2c_driver *driver = client->driver; - - if (driver && !is_newstyle_driver(driver)) { - dev_err(&client->dev, "can't unregister devices " - "with legacy drivers\n"); - WARN_ON(1); - return; - } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - - device_unregister(&client->dev); + struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + complete(&adap->dev_released); } -EXPORT_SYMBOL_GPL(i2c_unregister_device); +struct device_driver i2c_adapter_driver = { + .owner = THIS_MODULE, + .name = "i2c_adapter", + .bus = &i2c_bus_type, +}; /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -void i2c_adapter_dev_release(struct device *dev) +static void i2c_adapter_class_dev_release(struct class_device *dev) { - struct i2c_adapter *adap = to_i2c_adapter(dev); - complete(&adap->dev_released); + struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev); + complete(&adap->class_dev_released); } -EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */ -static ssize_t -show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf) { - struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev); return sprintf(buf, "%s\n", adap->name); } -static struct device_attribute i2c_adapter_attrs[] = { - __ATTR(name, S_IRUGO, show_adapter_name, NULL), +static struct class_device_attribute i2c_adapter_attrs[] = { + __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL), { }, }; struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", - .dev_attrs = i2c_adapter_attrs, + .class_dev_attrs = i2c_adapter_attrs, + .release = &i2c_adapter_class_dev_release, }; -EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */ -static void i2c_scan_static_board_info(struct i2c_adapter *adapter) +static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_devinfo *devinfo; - - mutex_lock(&__i2c_board_lock); - list_for_each_entry(devinfo, &__i2c_board_list, list) { - if (devinfo->busnum == adapter->nr - && !i2c_new_device(adapter, - &devinfo->board_info)) - printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n", - i2c_adapter_id(adapter), - devinfo->board_info.addr); - } - mutex_unlock(&__i2c_board_lock); + struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + return sprintf(buf, "%s\n", adap->name); } +static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); + -static int i2c_register_adapter(struct i2c_adapter *adap) +static void i2c_client_release(struct device *dev) { - int res = 0; + struct i2c_client *client = to_i2c_client(dev); + complete(&client->released); +} + +static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%s\n", client->name); +} + +/* + * We can't use the DEVICE_ATTR() macro here, as we used the same name for + * an i2c adapter attribute (above). + */ +static struct device_attribute dev_attr_client_name = + __ATTR(name, S_IRUGO, &show_client_name, NULL); + + +/* --------------------------------------------------- + * registering functions + * --------------------------------------------------- + */ + +/* ----- + * i2c_add_adapter is called from within the algorithm layer, + * when a new hw adapter registers. A new device is register to be + * available for clients. + */ +int i2c_add_adapter(struct i2c_adapter *adap) +{ + int id, res = 0; struct list_head *item; struct i2c_driver *driver; + mutex_lock(&core_lists); + + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) { + res = -ENOMEM; + goto out_unlock; + } + + res = idr_get_new(&i2c_adapter_idr, adap, &id); + if (res < 0) { + if (res == -EAGAIN) + res = -ENOMEM; + goto out_unlock; + } + + adap->nr = id & MAX_ID_MASK; mutex_init(&adap->bus_lock); mutex_init(&adap->clist_lock); + list_add_tail(&adap->list,&adapters); INIT_LIST_HEAD(&adap->clients); - mutex_lock(&core_lists); - list_add_tail(&adap->list, &adapters); - /* Add the adapter to the driver core. * If the parent pointer is not set up, * we add this adapter to the host bus. @@ -346,19 +221,27 @@ static int i2c_register_adapter(struct i2c_adapter *adap) "physical device\n", adap->name); } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); + adap->dev.driver = &i2c_adapter_driver; adap->dev.release = &i2c_adapter_dev_release; - adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); if (res) goto out_list; + res = device_create_file(&adap->dev, &dev_attr_name); + if (res) + goto out_unregister; + + /* Add this adapter to the i2c_adapter class */ + memset(&adap->class_dev, 0x00, sizeof(struct class_device)); + adap->class_dev.dev = &adap->dev; + adap->class_dev.class = &i2c_adapter_class; + strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE); + res = class_device_register(&adap->class_dev); + if (res) + goto out_remove_name; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* create pre-declared device nodes for new-style drivers */ - if (adap->nr < __i2c_first_dynamic_bus_num) - i2c_scan_static_board_info(adap); - - /* let legacy drivers scan this bus for matching devices */ + /* inform drivers of new adapters */ list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); if (driver->attach_adapter) @@ -370,98 +253,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_unlock(&core_lists); return res; +out_remove_name: + device_remove_file(&adap->dev, &dev_attr_name); +out_unregister: + init_completion(&adap->dev_released); /* Needed? */ + device_unregister(&adap->dev); + wait_for_completion(&adap->dev_released); out_list: list_del(&adap->list); idr_remove(&i2c_adapter_idr, adap->nr); goto out_unlock; } -/** - * i2c_add_adapter - declare i2c adapter, use dynamic bus number - * @adapter: the adapter to add - * - * This routine is used to declare an I2C adapter when its bus number - * doesn't matter. Examples: for I2C adapters dynamically added by - * USB links or PCI plugin cards. - * - * When this returns zero, a new bus number was allocated and stored - * in adap->nr, and the specified adapter became available for clients. - * Otherwise, a negative errno value is returned. - */ -int i2c_add_adapter(struct i2c_adapter *adapter) -{ - int id, res = 0; - -retry: - if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) - return -ENOMEM; - - mutex_lock(&core_lists); - /* "above" here means "above or equal to", sigh */ - res = idr_get_new_above(&i2c_adapter_idr, adapter, - __i2c_first_dynamic_bus_num, &id); - mutex_unlock(&core_lists); - - if (res < 0) { - if (res == -EAGAIN) - goto retry; - return res; - } - - adapter->nr = id; - return i2c_register_adapter(adapter); -} -EXPORT_SYMBOL(i2c_add_adapter); - -/** - * i2c_add_numbered_adapter - declare i2c adapter, use static bus number - * @adap: the adapter to register (with adap->nr initialized) - * - * This routine is used to declare an I2C adapter when its bus number - * matters. Example: for I2C adapters from system-on-chip CPUs, or - * otherwise built in to the system's mainboard, and where i2c_board_info - * is used to properly configure I2C devices. - * - * If no devices have pre-been declared for this bus, then be sure to - * register the adapter before any dynamically allocated ones. Otherwise - * the required bus ID may not be available. - * - * When this returns zero, the specified adapter became available for - * clients using the bus number provided in adap->nr. Also, the table - * of I2C devices pre-declared using i2c_register_board_info() is scanned, - * and the appropriate driver model device nodes are created. Otherwise, a - * negative errno value is returned. - */ -int i2c_add_numbered_adapter(struct i2c_adapter *adap) -{ - int id; - int status; - - if (adap->nr & ~MAX_ID_MASK) - return -EINVAL; - -retry: - if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) - return -ENOMEM; - - mutex_lock(&core_lists); - /* "above" here means "above or equal to", sigh; - * we need the "equal to" result to force the result - */ - status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id); - if (status == 0 && id != adap->nr) { - status = -EBUSY; - idr_remove(&i2c_adapter_idr, id); - } - mutex_unlock(&core_lists); - if (status == -EAGAIN) - goto retry; - - if (status == 0) - status = i2c_register_adapter(adap); - return status; -} -EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); int i2c_del_adapter(struct i2c_adapter *adap) { @@ -499,19 +302,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ list_for_each_safe(item, _n, &adap->clients) { - struct i2c_driver *driver; - client = list_entry(item, struct i2c_client, list); - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { + if ((res=client->driver->detach_client(client))) { dev_err(&adap->dev, "detach_client failed for client " "[%s] at address 0x%02x\n", client->name, client->addr); @@ -521,13 +314,17 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* clean up the sysfs representation */ init_completion(&adap->dev_released); + init_completion(&adap->class_dev_released); + class_device_unregister(&adap->class_dev); + device_remove_file(&adap->dev, &dev_attr_name); device_unregister(&adap->dev); list_del(&adap->list); /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); + wait_for_completion(&adap->class_dev_released); - /* free bus id */ + /* free dynamically allocated bus id */ idr_remove(&i2c_adapter_idr, adap->nr); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -536,42 +333,24 @@ int i2c_del_adapter(struct i2c_adapter *adap) mutex_unlock(&core_lists); return res; } -EXPORT_SYMBOL(i2c_del_adapter); - -/* ------------------------------------------------------------------------- */ -/* - * An i2c_driver is used with one or more i2c_client (device) nodes to access - * i2c slave chips, on a bus instance associated with some i2c_adapter. There - * are two models for binding the driver to its device: "new style" drivers - * follow the standard Linux driver model and just respond to probe() calls - * issued if the driver core sees they match(); "legacy" drivers create device - * nodes themselves. +/* ----- + * What follows is the "upwards" interface: commands for talking to clients, + * which implement the functions to access the physical information of the + * chips. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { + struct list_head *item; + struct i2c_adapter *adapter; int res; - /* new style driver methods can't mix with legacy ones */ - if (is_newstyle_driver(driver)) { - if (driver->attach_adapter || driver->detach_adapter - || driver->detach_client) { - printk(KERN_WARNING - "i2c-core: driver [%s] is confused\n", - driver->driver.name); - return -EINVAL; - } - } - /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; - /* for new style drivers, when registration returns the driver core - * will have called probe() for all matching-but-unbound devices. - */ res = driver_register(&driver->driver); if (res) return res; @@ -581,11 +360,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) list_add_tail(&driver->list,&drivers); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); - /* legacy drivers scan i2c busses directly */ + /* now look for instances of driver on our adapters */ if (driver->attach_adapter) { - struct i2c_adapter *adapter; - - list_for_each_entry(adapter, &adapters, list) { + list_for_each(item,&adapters) { + adapter = list_entry(item, struct i2c_adapter, list); driver->attach_adapter(adapter); } } @@ -595,21 +373,15 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) } EXPORT_SYMBOL(i2c_register_driver); -/** - * i2c_del_driver - unregister I2C driver - * @driver: the driver being unregistered - */ -void i2c_del_driver(struct i2c_driver *driver) +int i2c_del_driver(struct i2c_driver *driver) { struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; - mutex_lock(&core_lists); + int res = 0; - /* new-style driver? */ - if (is_newstyle_driver(driver)) - goto unregister; + mutex_lock(&core_lists); /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver @@ -618,10 +390,11 @@ void i2c_del_driver(struct i2c_driver *driver) list_for_each(item1,&adapters) { adap = list_entry(item1, struct i2c_adapter, list); if (driver->detach_adapter) { - if (driver->detach_adapter(adap)) { + if ((res = driver->detach_adapter(adap))) { dev_err(&adap->dev, "detach_adapter failed " "for driver [%s]\n", driver->driver.name); + goto out_unlock; } } else { list_for_each_safe(item2, _n, &adap->clients) { @@ -631,26 +404,25 @@ void i2c_del_driver(struct i2c_driver *driver) dev_dbg(&adap->dev, "detaching client [%s] " "at 0x%02x\n", client->name, client->addr); - if (driver->detach_client(client)) { + if ((res = driver->detach_client(client))) { dev_err(&adap->dev, "detach_client " "failed for client [%s] at " "0x%02x\n", client->name, client->addr); + goto out_unlock; } } } } - unregister: driver_unregister(&driver->driver); list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); + out_unlock: mutex_unlock(&core_lists); + return 0; } -EXPORT_SYMBOL(i2c_del_driver); - -/* ------------------------------------------------------------------------- */ static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) { @@ -675,7 +447,6 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr) return rval; } -EXPORT_SYMBOL(i2c_check_addr); int i2c_attach_client(struct i2c_client *client) { @@ -692,15 +463,9 @@ int i2c_attach_client(struct i2c_client *client) client->usage_count = 0; client->dev.parent = &client->adapter->dev; + client->dev.driver = &client->driver->driver; client->dev.bus = &i2c_bus_type; - - if (client->driver) - client->dev.driver = &client->driver->driver; - - if (client->driver && !is_newstyle_driver(client->driver)) - client->dev.release = i2c_client_release; - else - client->dev.release = i2c_client_dev_release; + client->dev.release = &i2c_client_release; snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); @@ -709,6 +474,9 @@ int i2c_attach_client(struct i2c_client *client) res = device_register(&client->dev); if (res) goto out_list; + res = device_create_file(&client->dev, &dev_attr_client_name); + if (res) + goto out_unregister; mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { @@ -721,6 +489,10 @@ int i2c_attach_client(struct i2c_client *client) return 0; +out_unregister: + init_completion(&client->released); /* Needed? */ + device_unregister(&client->dev); + wait_for_completion(&client->released); out_list: list_del(&client->list); dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " @@ -729,7 +501,7 @@ int i2c_attach_client(struct i2c_client *client) mutex_unlock(&adapter->clist_lock); return res; } -EXPORT_SYMBOL(i2c_attach_client); + int i2c_detach_client(struct i2c_client *client) { @@ -755,6 +527,7 @@ int i2c_detach_client(struct i2c_client *client) mutex_lock(&adapter->clist_lock); list_del(&client->list); init_completion(&client->released); + device_remove_file(&client->dev, &dev_attr_client_name); device_unregister(&client->dev); mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); @@ -762,7 +535,6 @@ int i2c_detach_client(struct i2c_client *client) out: return res; } -EXPORT_SYMBOL(i2c_detach_client); static int i2c_inc_use_client(struct i2c_client *client) { @@ -795,7 +567,6 @@ int i2c_use_client(struct i2c_client *client) return 0; } -EXPORT_SYMBOL(i2c_use_client); int i2c_release_client(struct i2c_client *client) { @@ -810,7 +581,6 @@ int i2c_release_client(struct i2c_client *client) return 0; } -EXPORT_SYMBOL(i2c_release_client); void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { @@ -831,13 +601,15 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) } mutex_unlock(&adap->clist_lock); } -EXPORT_SYMBOL(i2c_clients_command); static int __init i2c_init(void) { int retval; retval = bus_register(&i2c_bus_type); + if (retval) + return retval; + retval = driver_register(&i2c_adapter_driver); if (retval) return retval; return class_register(&i2c_adapter_class); @@ -846,6 +618,7 @@ static int __init i2c_init(void) static void __exit i2c_exit(void) { class_unregister(&i2c_adapter_class); + driver_unregister(&i2c_adapter_driver); bus_unregister(&i2c_bus_type); } @@ -865,9 +638,8 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) #ifdef DEBUG for (ret = 0; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " - "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) - ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, - (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); + "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? + 'R' : 'W', msgs[ret].addr, msgs[ret].len); } #endif @@ -881,7 +653,6 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) return -ENOSYS; } } -EXPORT_SYMBOL(i2c_transfer); int i2c_master_send(struct i2c_client *client,const char *buf ,int count) { @@ -900,7 +671,6 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_send); int i2c_master_recv(struct i2c_client *client, char *buf ,int count) { @@ -920,7 +690,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_recv); + int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg) @@ -942,7 +712,6 @@ int i2c_control(struct i2c_client *client, } return ret; } -EXPORT_SYMBOL(i2c_control); /* ---------------------------------------------------- * the i2c address scanning function @@ -1084,70 +853,6 @@ int i2c_probe(struct i2c_adapter *adapter, return 0; } -EXPORT_SYMBOL(i2c_probe); - -struct i2c_client * -i2c_new_probed_device(struct i2c_adapter *adap, - struct i2c_board_info *info, - unsigned short const *addr_list) -{ - int i; - - /* Stop here if the bus doesn't support probing */ - if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) { - dev_err(&adap->dev, "Probing not supported\n"); - return NULL; - } - - mutex_lock(&adap->clist_lock); - for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { - /* Check address validity */ - if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { - dev_warn(&adap->dev, "Invalid 7-bit address " - "0x%02x\n", addr_list[i]); - continue; - } - - /* Check address availability */ - if (__i2c_check_addr(adap, addr_list[i])) { - dev_dbg(&adap->dev, "Address 0x%02x already in " - "use, not probing\n", addr_list[i]); - continue; - } - - /* Test address responsiveness - The default probe method is a quick write, but it is known - to corrupt the 24RF08 EEPROMs due to a state machine bug, - and could also irreversibly write-protect some EEPROMs, so - for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte - read instead. Also, some bus drivers don't implement - quick write, so we fallback to a byte read it that case - too. */ - if ((addr_list[i] & ~0x07) == 0x30 - || (addr_list[i] & ~0x0f) == 0x50 - || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE, NULL) >= 0) - break; - } else { - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL) >= 0) - break; - } - } - mutex_unlock(&adap->clist_lock); - - if (addr_list[i] == I2C_CLIENT_END) { - dev_dbg(&adap->dev, "Probing failed, no device found\n"); - return NULL; - } - - info->addr = addr_list[i]; - return i2c_new_device(adap, info); -} -EXPORT_SYMBOL_GPL(i2c_new_probed_device); struct i2c_adapter* i2c_get_adapter(int id) { @@ -1161,13 +866,11 @@ struct i2c_adapter* i2c_get_adapter(int id) mutex_unlock(&core_lists); return adapter; } -EXPORT_SYMBOL(i2c_get_adapter); void i2c_put_adapter(struct i2c_adapter *adap) { module_put(adap->owner); } -EXPORT_SYMBOL(i2c_put_adapter); /* The SMBus parts */ @@ -1236,7 +939,6 @@ s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value) return i2c_smbus_xfer(client->adapter,client->addr,client->flags, value,0,I2C_SMBUS_QUICK,NULL); } -EXPORT_SYMBOL(i2c_smbus_write_quick); s32 i2c_smbus_read_byte(struct i2c_client *client) { @@ -1247,14 +949,12 @@ s32 i2c_smbus_read_byte(struct i2c_client *client) else return data.byte; } -EXPORT_SYMBOL(i2c_smbus_read_byte); s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } -EXPORT_SYMBOL(i2c_smbus_write_byte); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) { @@ -1265,7 +965,6 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) else return data.byte; } -EXPORT_SYMBOL(i2c_smbus_read_byte_data); s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) { @@ -1275,7 +974,6 @@ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data); } -EXPORT_SYMBOL(i2c_smbus_write_byte_data); s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) { @@ -1286,7 +984,6 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) else return data.word; } -EXPORT_SYMBOL(i2c_smbus_read_word_data); s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) { @@ -1296,23 +993,6 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA,&data); } -EXPORT_SYMBOL(i2c_smbus_write_word_data); - -/* Returns the number of read bytes */ -s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, - u8 *values) -{ - union i2c_smbus_data data; - - if (i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BLOCK_DATA, &data)) - return -1; - - memcpy(values, &data.block[1], data.block[0]); - return data.block[0]; -} -EXPORT_SYMBOL(i2c_smbus_read_block_data); s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1327,7 +1007,6 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data); } -EXPORT_SYMBOL(i2c_smbus_write_block_data); /* Returns the number of read bytes */ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) @@ -1342,7 +1021,6 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val memcpy(values, &data.block[1], data.block[0]); return data.block[0]; } -EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1357,7 +1035,6 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); } -EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ @@ -1421,9 +1098,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - msg[1].flags |= I2C_M_RECV_LEN; - msg[1].len = 1; /* block length will be added by - the underlying bus driver */ + dev_err(&adapter->dev, "Block read not supported " + "under I2C emulation!\n"); + return -1; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -1437,21 +1114,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } break; case I2C_SMBUS_BLOCK_PROC_CALL: - num = 2; /* Another special case */ - read_write = I2C_SMBUS_READ; - if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { - dev_err(&adapter->dev, "%s called with invalid " - "block proc call size (%d)\n", __FUNCTION__, - data->block[0]); - return -1; - } - msg[0].len = data->block[0] + 2; - for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; - msg[1].flags |= I2C_M_RECV_LEN; - msg[1].len = 1; /* block length will be added by - the underlying bus driver */ - break; + dev_dbg(&adapter->dev, "Block process call not supported " + "under I2C emulation!\n"); + return -1; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_BLOCK_MAX; @@ -1515,11 +1180,6 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_PROC_CALL: - for (i = 0; i < msgbuf1[0] + 1; i++) - data->block[i] = msgbuf1[i]; - break; } return 0; } @@ -1544,7 +1204,43 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, return res; } + + +/* Next four are needed by i2c-isa */ +EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); +EXPORT_SYMBOL_GPL(i2c_adapter_driver); +EXPORT_SYMBOL_GPL(i2c_adapter_class); +EXPORT_SYMBOL_GPL(i2c_bus_type); + +EXPORT_SYMBOL(i2c_add_adapter); +EXPORT_SYMBOL(i2c_del_adapter); +EXPORT_SYMBOL(i2c_del_driver); +EXPORT_SYMBOL(i2c_attach_client); +EXPORT_SYMBOL(i2c_detach_client); +EXPORT_SYMBOL(i2c_use_client); +EXPORT_SYMBOL(i2c_release_client); +EXPORT_SYMBOL(i2c_clients_command); +EXPORT_SYMBOL(i2c_check_addr); + +EXPORT_SYMBOL(i2c_master_send); +EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_control); +EXPORT_SYMBOL(i2c_transfer); +EXPORT_SYMBOL(i2c_get_adapter); +EXPORT_SYMBOL(i2c_put_adapter); +EXPORT_SYMBOL(i2c_probe); + EXPORT_SYMBOL(i2c_smbus_xfer); +EXPORT_SYMBOL(i2c_smbus_write_quick); +EXPORT_SYMBOL(i2c_smbus_read_byte); +EXPORT_SYMBOL(i2c_smbus_write_byte); +EXPORT_SYMBOL(i2c_smbus_read_byte_data); +EXPORT_SYMBOL(i2c_smbus_write_byte_data); +EXPORT_SYMBOL(i2c_smbus_read_word_data); +EXPORT_SYMBOL(i2c_smbus_write_word_data); +EXPORT_SYMBOL(i2c_smbus_write_block_data); +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); +EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); diff --git a/trunk/drivers/i2c/i2c-core.h b/trunk/drivers/i2c/i2c-core.h deleted file mode 100644 index cd5bff874855..000000000000 --- a/trunk/drivers/i2c/i2c-core.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * i2c-core.h - interfaces internal to the I2C framework - * - * 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. - */ - -struct i2c_devinfo { - struct list_head list; - int busnum; - struct i2c_board_info board_info; -}; - -/* board_lock protects board_list and first_dynamic_bus_num. - * only i2c core components are allowed to use these symbols. - */ -extern struct mutex __i2c_board_lock; -extern struct list_head __i2c_board_list; -extern int __i2c_first_dynamic_bus_num; - diff --git a/trunk/drivers/ide/Kconfig b/trunk/drivers/ide/Kconfig index 5bdf64b77913..ca2e4f830c39 100644 --- a/trunk/drivers/ide/Kconfig +++ b/trunk/drivers/ide/Kconfig @@ -57,7 +57,6 @@ if IDE config IDE_MAX_HWIFS int "Max IDE interfaces" depends on ALPHA || SUPERH || IA64 || EMBEDDED - range 1 10 default 4 help This is the maximum number of IDE hardware interfaces that will diff --git a/trunk/drivers/ide/cris/ide-cris.c b/trunk/drivers/ide/cris/ide-cris.c index 5e8efc89255a..556455fbfa2b 100644 --- a/trunk/drivers/ide/cris/ide-cris.c +++ b/trunk/drivers/ide/cris/ide-cris.c @@ -730,7 +730,7 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed) if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { tune_cris_ide(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); + return 0; } switch(speed) @@ -760,8 +760,7 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed) hold = ATA_DMA2_HOLD; break; default: - BUG(); - break; + return 0; } if (speed >= XFER_UDMA_0) @@ -769,7 +768,7 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed) else cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); - return ide_config_drive_speed(drive, speed); + return 0; } void __init @@ -822,6 +821,7 @@ init_e100_ide (void) hwif->udma_four = 0; hwif->ultra_mask = cris_ultra_mask; hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */ + hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */ hwif->autodma = 1; hwif->drives[0].autodma = 1; hwif->drives[1].autodma = 1; @@ -1010,6 +1010,7 @@ static int cris_config_drive_for_dma (ide_drive_t *drive) return 0; speed_cris_ide(drive, speed); + ide_config_drive_speed(drive, speed); return ide_dma_enable(drive); } diff --git a/trunk/drivers/ide/ide-proc.c b/trunk/drivers/ide/ide-proc.c index a9e0b30fb1f2..afb71c66b6f3 100644 --- a/trunk/drivers/ide/ide-proc.c +++ b/trunk/drivers/ide/ide-proc.c @@ -310,12 +310,14 @@ static int proc_ide_read_driver ide_driver_t *ide_drv; int len; + down_read(&dev->bus->subsys.rwsem); if (dev->driver) { ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); len = sprintf(page, "%s version %s\n", dev->driver->name, ide_drv->version); } else len = sprintf(page, "ide-default version 0.9.newide\n"); + up_read(&dev->bus->subsys.rwsem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -325,6 +327,7 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) int ret = 1; int err; + down_write(&dev->bus->subsys.rwsem); device_release_driver(dev); /* FIXME: device can still be in use by previous driver */ strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); @@ -342,6 +345,7 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) } if (dev->driver && !strcmp(dev->driver->name, driver)) ret = 0; + up_write(&dev->bus->subsys.rwsem); return ret; } diff --git a/trunk/drivers/ide/legacy/ide-cs.c b/trunk/drivers/ide/legacy/ide-cs.c index c6522a64d7ec..b08c37c9f956 100644 --- a/trunk/drivers/ide/legacy/ide-cs.c +++ b/trunk/drivers/ide/legacy/ide-cs.c @@ -401,7 +401,6 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), - PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), diff --git a/trunk/drivers/ide/pci/aec62xx.c b/trunk/drivers/ide/pci/aec62xx.c index 73bdf64dbbfc..990eafe5ea11 100644 --- a/trunk/drivers/ide/pci/aec62xx.c +++ b/trunk/drivers/ide/pci/aec62xx.c @@ -1,8 +1,7 @@ /* - * linux/drivers/ide/pci/aec62xx.c Version 0.21 Apr 21, 2007 + * linux/drivers/ide/pci/aec62xx.c Version 0.11 March 27, 2002 * * Copyright (C) 1999-2002 Andre Hedrick - * Copyright (C) 2007 MontaVista Software, Inc. * */ @@ -194,8 +193,18 @@ static int config_chipset_for_dma (ide_drive_t *drive) static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - (void) aec62xx_tune_chipset(drive, pio + XFER_PIO_0); + u8 speed = 0; + u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + + switch(pio) { + case 5: speed = new_pio; break; + case 4: speed = XFER_PIO_4; break; + case 3: speed = XFER_PIO_3; break; + case 2: speed = XFER_PIO_2; break; + case 1: speed = XFER_PIO_1; break; + default: speed = XFER_PIO_0; break; + } + (void) aec62xx_tune_chipset(drive, speed); } static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) @@ -204,7 +213,7 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - aec62xx_tune_drive(drive, 255); + aec62xx_tune_drive(drive, 5); return -1; } @@ -279,10 +288,11 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate; hwif->ide_dma_lostirq = &aec62xx_irq_timeout; - + hwif->ide_dma_timeout = &aec62xx_irq_timeout; if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; diff --git a/trunk/drivers/ide/pci/alim15x3.c b/trunk/drivers/ide/pci/alim15x3.c index 946a12746cb5..83e0aa65a431 100644 --- a/trunk/drivers/ide/pci/alim15x3.c +++ b/trunk/drivers/ide/pci/alim15x3.c @@ -534,7 +534,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive) struct hd_driveid *id = drive->id; if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) - goto ata_pio; + goto no_dma_set; drive->init_speed = 0; @@ -555,19 +555,20 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive) (id->dma_1word & hwif->swdma_mask)) { /* Force if Capable regular DMA modes */ if (!config_chipset_for_dma(drive)) - goto ata_pio; + goto no_dma_set; } } else if (__ide_dma_good_drive(drive) && (id->eide_dma_time < 150)) { /* Consult the list of known "good" drives */ if (!config_chipset_for_dma(drive)) - goto ata_pio; + goto no_dma_set; } else { goto ata_pio; } } else { ata_pio: hwif->tuneproc(drive, 255); +no_dma_set: return -1; } diff --git a/trunk/drivers/ide/pci/cmd64x.c b/trunk/drivers/ide/pci/cmd64x.c index 77f51ab6d439..561197f7b5bb 100644 --- a/trunk/drivers/ide/pci/cmd64x.c +++ b/trunk/drivers/ide/pci/cmd64x.c @@ -1,7 +1,10 @@ -/* - * linux/drivers/ide/pci/cmd64x.c Version 1.47 Mar 19, 2007 +/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 + * + * linux/drivers/ide/pci/cmd64x.c Version 1.42 Feb 8, 2007 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. + * Note, this driver is not used at all on other systems because + * there the "BIOS" has done all of the following already. * Due to massive hardware bugs, UltraDMA is only supported * on the 646U2 and not on the 646U. * @@ -36,12 +39,11 @@ * CMD64x specific registers definition. */ #define CFR 0x50 -#define CFR_INTR_CH0 0x04 +#define CFR_INTR_CH0 0x02 #define CNTRL 0x51 -#define CNTRL_ENA_1ST 0x04 -#define CNTRL_ENA_2ND 0x08 -#define CNTRL_DIS_RA0 0x40 -#define CNTRL_DIS_RA1 0x80 +#define CNTRL_DIS_RA0 0x40 +#define CNTRL_DIS_RA1 0x80 +#define CNTRL_ENA_2ND 0x08 #define CMDTIM 0x52 #define ARTTIM0 0x53 @@ -88,67 +90,86 @@ static int n_cmd_devs; static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) { char *p = buf; + + u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */ + u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */ u8 reg72 = 0, reg73 = 0; /* primary */ u8 reg7a = 0, reg7b = 0; /* secondary */ - u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0; /* extra */ - u8 rev = 0; + u8 reg50 = 0, reg71 = 0; /* extra */ p += sprintf(p, "\nController: %d\n", index); - p += sprintf(p, "PCI-%x Chipset.\n", dev->device); - + p += sprintf(p, "CMD%x Chipset.\n", dev->device); (void) pci_read_config_byte(dev, CFR, ®50); - (void) pci_read_config_byte(dev, CNTRL, ®51); - (void) pci_read_config_byte(dev, ARTTIM23, ®57); + (void) pci_read_config_byte(dev, ARTTIM0, ®53); + (void) pci_read_config_byte(dev, DRWTIM0, ®54); + (void) pci_read_config_byte(dev, ARTTIM1, ®55); + (void) pci_read_config_byte(dev, DRWTIM1, ®56); + (void) pci_read_config_byte(dev, ARTTIM2, ®57); + (void) pci_read_config_byte(dev, DRWTIM2, ®58); + (void) pci_read_config_byte(dev, DRWTIM3, ®5b); (void) pci_read_config_byte(dev, MRDMODE, ®71); (void) pci_read_config_byte(dev, BMIDESR0, ®72); (void) pci_read_config_byte(dev, UDIDETCR0, ®73); (void) pci_read_config_byte(dev, BMIDESR1, ®7a); (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); - /* PCI0643/6 originally didn't have the primary channel enable bit */ - (void) pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if ((dev->device == PCI_DEVICE_ID_CMD_643) || - (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 3)) - reg51 |= CNTRL_ENA_1ST; - - p += sprintf(p, "---------------- Primary Channel " - "---------------- Secondary Channel ------------\n"); - p += sprintf(p, " %s %s\n", - (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled", - (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled"); - p += sprintf(p, "---------------- drive0 --------- drive1 " - "-------- drive0 --------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s" - " %s %s\n", - (reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ", - (reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no "); - p += sprintf(p, "UltraDMA mode: %s (%c) %s (%c)", - ( reg73 & 0x01) ? " on" : "off", - ((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') : - ((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') : - ((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') : - ((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?', - ( reg73 & 0x02) ? " on" : "off", - ((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') : - ((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') : - ((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') : - ((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?'); - p += sprintf(p, " %s (%c) %s (%c)\n", - ( reg7b & 0x01) ? " on" : "off", - ((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') : - ((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') : - ((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') : - ((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?', - ( reg7b & 0x02) ? " on" : "off", - ((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') : - ((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') : - ((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') : - ((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?'); - p += sprintf(p, "Interrupt: %s, %s %s, %s\n", - (reg71 & MRDMODE_BLK_CH0 ) ? "blocked" : "enabled", - (reg50 & CFR_INTR_CH0 ) ? "pending" : "clear ", - (reg71 & MRDMODE_BLK_CH1 ) ? "blocked" : "enabled", - (reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear "); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", + (reg72&0x80)?"dis":" en", + (reg7a&0x80)?"dis":" en"); + p += sprintf(p, "--------------- drive0 " + "--------- drive1 -------- drive0 " + "---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s" + " %s %s\n", + (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ", + (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no "); + + p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", + (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO", + (reg72&0x20)?( + ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): + ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): + ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"): + "X"):"?", + (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO", + (reg72&0x40)?( + ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): + ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): + ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"): + "X"):"?"); + p += sprintf(p, " %s(%s) %s(%s)\n", + (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO", + (reg7a&0x20)?( + ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): + ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): + ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"): + "X"):"?", + (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO", + (reg7a&0x40)?( + ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): + ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): + ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"): + "X"):"?" ); + p += sprintf(p, "PIO Mode: %s %s" + " %s %s\n", + "?", "?", "?", "?"); + p += sprintf(p, " %s %s\n", + (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ", + (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling"); + p += sprintf(p, " %s %s\n", + (reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear ", + (reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear"); + p += sprintf(p, " %s %s\n", + (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", + (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); return (char *)p; } @@ -158,6 +179,7 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) char *p = buffer; int i; + p += sprintf(p, "\n"); for (i = 0; i < n_cmd_devs; i++) { struct pci_dev *dev = cmd_devs[i]; p = print_cmd64x_get_info(p, dev, i); @@ -173,103 +195,116 @@ static u8 quantize_timing(int timing, int quant) } /* - * This routine calculates active/recovery counts and then writes them into - * the chipset registers. + * This routine writes the prepared setup/active/recovery counts + * for a drive into the cmd646 chipset registers to active them. */ -static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time) +static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int clock_time = 1000 / system_bus_clock(); - u8 cycle_count, active_count, recovery_count, drwtim; - static const u8 recovery_values[] = + unsigned long flags; + struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_drive_t *drives = HWIF(drive)->drives; + u8 temp_b; + static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const u8 recovery_counts[] = {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; - static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; - - cmdprintk("program_cycle_times parameters: total=%d, active=%d\n", - cycle_time, active_time); - - cycle_count = quantize_timing( cycle_time, clock_time); - active_count = quantize_timing(active_time, clock_time); - recovery_count = cycle_count - active_count; - + static const u8 arttim_regs[2][2] = { + { ARTTIM0, ARTTIM1 }, + { ARTTIM23, ARTTIM23 } + }; + static const u8 drwtim_regs[2][2] = { + { DRWTIM0, DRWTIM1 }, + { DRWTIM2, DRWTIM3 } + }; + int channel = (int) HWIF(drive)->channel; + int slave = (drives != drive); /* Is this really the best way to determine this?? */ + + cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", + setup_count, active_count, recovery_count, drive->present); /* - * In case we've got too long recovery phase, try to lengthen - * the active phase + * Set up address setup count registers. + * Primary interface has individual count/timing registers for + * each drive. Secondary interface has one common set of registers, + * for address setup so we merge these timings, using the slowest + * value. */ - if (recovery_count > 16) { - active_count += recovery_count - 16; - recovery_count = 16; + if (channel) { + drive->drive_data = setup_count; + setup_count = max(drives[0].drive_data, + drives[1].drive_data); + cmdprintk("Secondary interface, setup_count = %d\n", + setup_count); } - if (active_count > 16) /* shouldn't actually happen... */ - active_count = 16; - - cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n", - cycle_count, active_count, recovery_count); /* * Convert values to internal chipset representation */ - recovery_count = recovery_values[recovery_count]; - active_count &= 0x0f; + setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count]; + active_count &= 0xf; /* Remember, max value is 16 */ + recovery_count = (int) recovery_counts[recovery_count]; - /* Program the active/recovery counts into the DRWTIM register */ - drwtim = (active_count << 4) | recovery_count; - (void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim); - cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]); + cmdprintk("Final values = %d,%d,%d\n", + setup_count, active_count, recovery_count); + + /* + * Now that everything is ready, program the new timings + */ + local_irq_save(flags); + /* + * Program the address_setup clocks into ARTTIM reg, + * and then the active/recovery counts into the DRWTIM reg + */ + (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b); + (void) pci_write_config_byte(dev, arttim_regs[channel][slave], + ((u8) setup_count) | (temp_b & 0x3f)); + (void) pci_write_config_byte(dev, drwtim_regs[channel][slave], + (u8) ((active_count << 4) | recovery_count)); + cmdprintk ("Write %x to %x\n", + ((u8) setup_count) | (temp_b & 0x3f), + arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", + (u8) ((active_count << 4) | recovery_count), + drwtim_regs[channel][slave]); + local_irq_restore(flags); } /* - * This routine selects drive's best PIO mode and writes into the chipset - * registers setup/active/recovery timings. + * This routine selects drive's best PIO mode, calculates setup/active/recovery + * counts, and then writes them into the chipset registers. */ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + int setup_time, active_time, cycle_time; + u8 cycle_count, setup_count, active_count, recovery_count; + u8 pio_mode; + int clock_time = 1000 / system_bus_clock(); ide_pio_data_t pio; - u8 pio_mode, setup_count, arttim = 0; - static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; - static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; - pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio); - - cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n", - drive->name, mode_wanted, pio_mode, pio.cycle_time, - pio.overridden ? " (overriding vendor mode)" : ""); - program_cycle_times(drive, pio.cycle_time, - ide_pio_timings[pio_mode].active_time); + pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio); + cycle_time = pio.cycle_time; - setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time, - 1000 / system_bus_clock()); + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; - /* - * The primary channel has individual address setup timing registers - * for each drive and the hardware selects the slowest timing itself. - * The secondary channel has one common register and we have to select - * the slowest address setup timing ourselves. - */ - if (hwif->channel) { - ide_drive_t *drives = hwif->drives; + setup_count = quantize_timing( setup_time, clock_time); + cycle_count = quantize_timing( cycle_time, clock_time); + active_count = quantize_timing(active_time, clock_time); - drive->drive_data = setup_count; - setup_count = max(drives[0].drive_data, drives[1].drive_data); + recovery_count = cycle_count - active_count; + /* program_drive_counts() takes care of zero recovery cycles */ + if (recovery_count > 16) { + active_count += recovery_count - 16; + recovery_count = 16; } + if (active_count > 16) + active_count = 16; /* maximum allowed by cmd64x */ - if (setup_count > 5) /* shouldn't actually happen... */ - setup_count = 5; - cmdprintk("Final address setup count: %d\n", setup_count); + program_drive_counts (drive, setup_count, active_count, recovery_count); - /* - * Program the address setup clocks into the ARTTIM registers. - * Avoid clearing the secondary channel's interrupt bit. - */ - (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim); - if (hwif->channel) - arttim &= ~ARTTIM23_INTR_CH1; - arttim &= ~0xc0; - arttim |= setup_values[setup_count]; - (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); - cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]); + cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, " + "clocks=%d/%d/%d\n", + drive->name, mode_wanted, pio_mode, cycle_time, + pio.overridden ? " (overriding vendor mode)" : "", + setup_count, active_count, recovery_count); return pio_mode; } @@ -341,64 +376,61 @@ static u8 cmd64x_ratemask (ide_drive_t *drive) return mode; } -static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed) +static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 unit = drive->dn & 0x01; - u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; - speed = ide_rate_filter(cmd64x_ratemask(drive), speed); + u8 unit = (drive->select.b.unit & 0x01); + u8 regU = 0, pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; + u8 regD = 0, pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; + + u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed); if (speed >= XFER_SW_DMA_0) { + (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); + regD &= ~(unit ? 0x40 : 0x20); regU &= ~(unit ? 0xCA : 0x35); + (void) pci_write_config_byte(dev, pciD, regD); + (void) pci_write_config_byte(dev, pciU, regU); + (void) pci_read_config_byte(dev, pciD, ®D); + (void) pci_read_config_byte(dev, pciU, ®U); } switch(speed) { - case XFER_UDMA_5: - regU |= unit ? 0x0A : 0x05; - break; - case XFER_UDMA_4: - regU |= unit ? 0x4A : 0x15; - break; - case XFER_UDMA_3: - regU |= unit ? 0x8A : 0x25; - break; - case XFER_UDMA_2: - regU |= unit ? 0x42 : 0x11; - break; - case XFER_UDMA_1: - regU |= unit ? 0x82 : 0x21; - break; - case XFER_UDMA_0: - regU |= unit ? 0xC2 : 0x31; - break; - case XFER_MW_DMA_2: - program_cycle_times(drive, 120, 70); - break; - case XFER_MW_DMA_1: - program_cycle_times(drive, 150, 80); - break; - case XFER_MW_DMA_0: - program_cycle_times(drive, 480, 215); - break; - case XFER_PIO_5: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0); - break; - default: - return 1; + case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break; + case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; + case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; + case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break; + case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break; + case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break; + case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; + case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; + case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; + case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; + case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; + case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; + case XFER_PIO_5: + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0); + break; + + default: + return 1; } - if (speed >= XFER_SW_DMA_0) + if (speed >= XFER_SW_DMA_0) { (void) pci_write_config_byte(dev, pciU, regU); + regD |= (unit ? 0x40 : 0x20); + (void) pci_write_config_byte(dev, pciD, regD); + } - return ide_config_drive_speed(drive, speed); + return (ide_config_drive_speed(drive, speed)); } static int config_chipset_for_dma (ide_drive_t *drive) @@ -425,80 +457,67 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive) return -1; } -static int cmd648_ide_dma_end (ide_drive_t *drive) +static int cmd64x_alt_dma_status (struct pci_dev *dev) { - ide_hwif_t *hwif = HWIF(drive); - int err = __ide_dma_end(drive); - u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : - MRDMODE_INTR_CH0; - u8 mrdmode = inb(hwif->dma_master + 0x01); - - /* clear the interrupt bit */ - outb(mrdmode | irq_mask, hwif->dma_master + 0x01); - - return err; + switch(dev->device) { + case PCI_DEVICE_ID_CMD_648: + case PCI_DEVICE_ID_CMD_649: + return 1; + default: + break; + } + return 0; } static int cmd64x_ide_dma_end (ide_drive_t *drive) { + u8 dma_stat = 0, dma_cmd = 0; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int irq_reg = hwif->channel ? ARTTIM23 : CFR; - u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : - CFR_INTR_CH0; - u8 irq_stat = 0; - int err = __ide_dma_end(drive); - - (void) pci_read_config_byte(dev, irq_reg, &irq_stat); - /* clear the interrupt bit */ - (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask); - - return err; -} - -static int cmd648_ide_dma_test_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : - MRDMODE_INTR_CH0; - u8 dma_stat = inb(hwif->dma_status); - u8 mrdmode = inb(hwif->dma_master + 0x01); - -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, mrdmode, irq_mask); -#endif - if (!(mrdmode & irq_mask)) - return 0; - /* return 1 if INTR asserted */ - if (dma_stat & 4) - return 1; - - return 0; + drive->waiting_for_dma = 0; + /* read DMA command state */ + dma_cmd = inb(hwif->dma_command); + /* stop DMA */ + outb(dma_cmd & ~1, hwif->dma_command); + /* get DMA status */ + dma_stat = inb(hwif->dma_status); + /* clear the INTR & ERROR bits */ + outb(dma_stat | 6, hwif->dma_status); + if (cmd64x_alt_dma_status(dev)) { + u8 dma_intr = 0; + u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 : + CFR_INTR_CH0; + u8 dma_reg = (hwif->channel) ? ARTTIM2 : CFR; + (void) pci_read_config_byte(dev, dma_reg, &dma_intr); + /* clear the INTR bit */ + (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); + } + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4; } static int cmd64x_ide_dma_test_irq (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int irq_reg = hwif->channel ? ARTTIM23 : CFR; - u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : - CFR_INTR_CH0; - u8 dma_stat = inb(hwif->dma_status); - u8 irq_stat = 0; - - (void) pci_read_config_byte(dev, irq_reg, &irq_stat); + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 : + MRDMODE_INTR_CH0; + u8 dma_stat = inb(hwif->dma_status); + (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); #ifdef DEBUG - printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, irq_stat, irq_mask); + printk("%s: dma_stat: 0x%02x dma_alt_stat: " + "0x%02x mask: 0x%02x\n", drive->name, + dma_stat, dma_alt_stat, mask); #endif - if (!(irq_stat & irq_mask)) + if (!(dma_alt_stat & mask)) return 0; /* return 1 if INTR asserted */ - if (dma_stat & 4) + if ((dma_stat & 4) == 4) return 1; return 0; @@ -646,6 +665,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) hwif->ultra_mask = 0x3f; hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; if (dev->device == PCI_DEVICE_ID_CMD_643) hwif->ultra_mask = 0x80; @@ -658,25 +678,17 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) if (!(hwif->udma_four)) hwif->udma_four = ata66_cmd64x(hwif); - switch(dev->device) { - case PCI_DEVICE_ID_CMD_648: - case PCI_DEVICE_ID_CMD_649: - alt_irq_bits: - hwif->ide_dma_end = &cmd648_ide_dma_end; - hwif->ide_dma_test_irq = &cmd648_ide_dma_test_irq; - break; - case PCI_DEVICE_ID_CMD_646: + if (dev->device == PCI_DEVICE_ID_CMD_646) { hwif->chipset = ide_cmd646; if (class_rev == 0x01) { hwif->ide_dma_end = &cmd646_1_ide_dma_end; - break; - } else if (class_rev >= 0x03) - goto alt_irq_bits; - /* fall thru */ - default: - hwif->ide_dma_end = &cmd64x_ide_dma_end; - hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq; - break; + } else { + hwif->ide_dma_end = &cmd64x_ide_dma_end; + hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq; + } + } else { + hwif->ide_dma_end = &cmd64x_ide_dma_end; + hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq; } @@ -686,75 +698,42 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_cmd646(struct pci_dev *dev, ide_pci_device_t *d) -{ - u8 rev = 0; - - /* - * The original PCI0646 didn't have the primary channel enable bit, - * it appeared starting with PCI0646U (i.e. revision ID 3). - */ - pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if (rev < 3) - d->enablebits[0].reg = 0; - - return ide_setup_pci_device(dev, d); -} - static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { { /* 0 */ .name = "CMD643", - .init_setup = init_setup_cmd64x, .init_chipset = init_chipset_cmd64x, .init_hwif = init_hwif_cmd64x, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, },{ /* 1 */ .name = "CMD646", - .init_setup = init_setup_cmd646, .init_chipset = init_chipset_cmd64x, .init_hwif = init_hwif_cmd64x, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, + .enablebits = {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, .bootable = ON_BOARD, },{ /* 2 */ .name = "CMD648", - .init_setup = init_setup_cmd64x, .init_chipset = init_chipset_cmd64x, .init_hwif = init_hwif_cmd64x, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, },{ /* 3 */ .name = "CMD649", - .init_setup = init_setup_cmd64x, .init_chipset = init_chipset_cmd64x, .init_hwif = init_hwif_cmd64x, .channels = 2, .autodma = AUTODMA, - .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, } }; -/* - * We may have to modify enablebits for PCI0646, so we'd better pass - * a local copy of the ide_pci_device_t structure down the call chain... - */ static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_pci_device_t d = cmd64x_chipsets[id->driver_data]; - - return d.init_setup(dev, &d); + return ide_setup_pci_device(dev, &cmd64x_chipsets[id->driver_data]); } static struct pci_device_id cmd64x_pci_tbl[] = { diff --git a/trunk/drivers/ide/pci/delkin_cb.c b/trunk/drivers/ide/pci/delkin_cb.c index dd7ec37fdeab..d4b753e70119 100644 --- a/trunk/drivers/ide/pci/delkin_cb.c +++ b/trunk/drivers/ide/pci/delkin_cb.c @@ -108,7 +108,6 @@ delkin_cb_remove (struct pci_dev *dev) static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); diff --git a/trunk/drivers/ide/pci/hpt366.c b/trunk/drivers/ide/pci/hpt366.c index cf9d344d19f8..60ecdc258c7c 100644 --- a/trunk/drivers/ide/pci/hpt366.c +++ b/trunk/drivers/ide/pci/hpt366.c @@ -1,10 +1,10 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.03 May 4, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2007 MontaVista Software, Inc. + * Portions Copyright (C) 2005-2006 MontaVista Software, Inc. * * Thanks to HighPoint Technologies for their assistance, and hardware. * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his @@ -494,7 +494,6 @@ static struct hpt_info hpt302n __devinitdata = { .chip_type = HPT302N, .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3, .dpll_clk = 77, - .settings = hpt37x_settings }; static struct hpt_info hpt371n __devinitdata = { @@ -1527,12 +1526,7 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) if (rev > 2) goto init_single; - /* - * HPT36x chips are single channel and - * do not seem to have the channel enable bit... - */ d->channels = 1; - d->enablebits[0].reg = 0; if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) { u8 pin1 = 0, pin2 = 0; diff --git a/trunk/drivers/ide/pci/it821x.c b/trunk/drivers/ide/pci/it821x.c index 4e1254813ee0..a132767f7d90 100644 --- a/trunk/drivers/ide/pci/it821x.c +++ b/trunk/drivers/ide/pci/it821x.c @@ -1,9 +1,8 @@ /* - * linux/drivers/ide/pci/it821x.c Version 0.10 Mar 10 2007 + * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 * * Copyright (C) 2004 Red Hat - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public License * Based in part on the ITE vendor provided SCSI driver. @@ -105,7 +104,6 @@ static int it8212_noraid; /** * it821x_program - program the PIO/MWDMA registers * @drive: drive to tune - * @timing: timing info * * Program the PIO/MWDMA timing for this channel according to the * current clock. @@ -129,7 +127,6 @@ static void it821x_program(ide_drive_t *drive, u16 timing) /** * it821x_program_udma - program the UDMA registers * @drive: drive to tune - * @timing: timing info * * Program the UDMA timing for this drive according to the * current clock. @@ -156,9 +153,10 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing) } } + /** * it821x_clock_strategy - * @drive: drive to set up + * @hwif: hardware interface * * Select between the 50 and 66Mhz base clocks to get the best * results for this interface. @@ -184,11 +182,8 @@ static void it821x_clock_strategy(ide_drive_t *drive) altclock = itdev->want[0][1]; } - /* - * if both clocks can be used for the mode with the higher priority - * use the clock needed by the mode with the lower priority - */ - if (clock == ATA_ANY) + /* Master doesn't care does the slave ? */ + if(clock == ATA_ANY) clock = altclock; /* Nobody cares - keep the same clock */ @@ -245,56 +240,37 @@ static u8 it821x_ratemask (ide_drive_t *drive) } /** - * it821x_tunepio - tune a drive + * it821x_tuneproc - tune a drive * @drive: drive to tune - * @pio: the desired PIO mode + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. By the time we are called the mode has been + * modified as neccessary to handle the absence of seperate + * master/slave timers for MWDMA/PIO. * - * Try to tune the drive/host to the desired PIO mode taking into - * the consideration the maximum PIO mode supported by the other - * device on the cable. + * This code is only used in pass through mode. */ -static int it821x_tunepio(ide_drive_t *drive, u8 set_pio) +static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); int unit = drive->select.b.unit; - ide_drive_t *pair = &hwif->drives[1 - unit]; /* Spec says 89 ref driver uses 88 */ static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; - /* - * Compute the best PIO mode we can for a given device. We must - * pick a speed that does not cause problems with the other device - * on the cable. - */ - if (pair) { - u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL); - /* trim PIO to the slowest of the master/slave */ - if (pair_pio < set_pio) - set_pio = pair_pio; - } - - if (itdev->smart) - goto set_drive_speed; + if(itdev->smart) + return; /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ - itdev->want[unit][1] = pio_want[set_pio]; + itdev->want[unit][1] = pio_want[mode_wanted]; itdev->want[unit][0] = 1; /* PIO is lowest priority */ - itdev->pio[unit] = pio[set_pio]; + itdev->pio[unit] = pio[mode_wanted]; it821x_clock_strategy(drive); it821x_program(drive, itdev->pio[unit]); - -set_drive_speed: - return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio); -} - -static void it821x_tuneproc(ide_drive_t *drive, u8 pio) -{ - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - (void)it821x_tunepio(drive, pio); } /** @@ -377,6 +353,40 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) } +/** + * config_it821x_chipset_for_pio - set drive timings + * @drive: drive to tune + * @speed we want + * + * Compute the best pio mode we can for a given device. We must + * pick a speed that does not cause problems with the other device + * on the cable. + */ + +static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + u8 unit = drive->select.b.unit; + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *pair = &hwif->drives[1-unit]; + u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + u8 pair_pio; + + /* We have to deal with this mess in pairs */ + if(pair != NULL) { + pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL); + /* Trim PIO to the slowest of the master/slave */ + if(pair_pio < set_pio) + set_pio = pair_pio; + } + it821x_tuneproc(drive, set_pio); + speed = XFER_PIO_0 + set_pio; + /* XXX - We trim to the lowest of the pair so the other drive + will always be fine at this point until we do hotplug passthru */ + + if (set_speed) + (void) ide_config_drive_speed(drive, speed); +} + /** * it821x_dma_read - DMA hook * @drive: drive for DMA @@ -440,17 +450,15 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) struct it821x_dev *itdev = ide_get_hwifdata(hwif); u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); - switch (speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - return it821x_tunepio(drive, speed - XFER_PIO_0); - } - - if (itdev->smart == 0) { - switch (speed) { + if(!itdev->smart) { + switch(speed) { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + it821x_tuneproc(drive, (speed - XFER_PIO_0)); + break; /* MWDMA tuning is really hard because our MWDMA and PIO timings are kept in the same place. We can switch in the host dma on/off callbacks */ @@ -490,12 +498,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); - if (speed == 0) - return 0; + if (speed) { + config_it821x_chipset_for_pio(drive, 0); + it821x_tune_chipset(drive, speed); - it821x_tune_chipset(drive, speed); + return ide_dma_enable(drive); + } - return ide_dma_enable(drive); + return 0; } /** @@ -513,7 +523,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive) if (ide_use_dma(drive) && config_chipset_for_dma(drive)) return 0; - it821x_tuneproc(drive, 255); + config_it821x_chipset_for_pio(drive, 1); return -1; } diff --git a/trunk/drivers/ide/pci/pdc202xx_new.c b/trunk/drivers/ide/pci/pdc202xx_new.c index 2da5cbb53566..ace98929cc3d 100644 --- a/trunk/drivers/ide/pci/pdc202xx_new.c +++ b/trunk/drivers/ide/pci/pdc202xx_new.c @@ -255,6 +255,9 @@ static int config_chipset_for_dma(ide_drive_t *drive) printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name); } + if (drive->media != ide_disk && drive->media != ide_cdrom) + return 0; + if (id->capability & 4) { /* * Set IORDY_EN & PREFETCH_EN (this seems to have diff --git a/trunk/drivers/ide/pci/siimage.c b/trunk/drivers/ide/pci/siimage.c index c0188de3cc66..71eccdf5f817 100644 --- a/trunk/drivers/ide/pci/siimage.c +++ b/trunk/drivers/ide/pci/siimage.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.12 Mar 10 2007 + * linux/drivers/ide/pci/siimage.c Version 1.11 Jan 27, 2007 * * Copyright (C) 2001-2002 Andre Hedrick * Copyright (C) 2003 Red Hat @@ -287,6 +287,11 @@ static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed) (void) ide_config_drive_speed(drive, speed); } +static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + config_siimage_chipset_for_pio(drive, set_speed); +} + /** * siimage_tune_chipset - set controller timings * @drive: Drive to set up @@ -391,6 +396,8 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, siimage_ratemask(drive)); + config_chipset_for_pio(drive, !speed); + if (!speed) return 0; @@ -416,7 +423,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - config_siimage_chipset_for_pio(drive, 1); + config_chipset_for_pio(drive, 1); return -1; } @@ -1008,6 +1015,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; if (!is_sata(hwif)) hwif->atapi_dma = 1; diff --git a/trunk/drivers/ide/pci/sl82c105.c b/trunk/drivers/ide/pci/sl82c105.c index fe3b4b91f854..3a8a76fc78c7 100644 --- a/trunk/drivers/ide/pci/sl82c105.c +++ b/trunk/drivers/ide/pci/sl82c105.c @@ -11,8 +11,6 @@ * Merge in Russell's HW workarounds, fix various problems * with the timing registers setup. * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org - * - * Copyright (C) 2006-2007 MontaVista Software, Inc. */ #include @@ -49,19 +47,25 @@ #define CTRL_P0EN (1 << 0) /* - * Convert a PIO mode and cycle time to the required on/off times - * for the interface. This has protection against runaway timings. + * Convert a PIO mode and cycle time to the required on/off + * times for the interface. This has protection against run-away + * timings. */ -static unsigned int get_pio_timings(ide_pio_data_t *p) +static unsigned int get_timing_sl82c105(ide_pio_data_t *p) { - unsigned int cmd_on, cmd_off; + unsigned int cmd_on; + unsigned int cmd_off; - cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; + cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30; + if (cmd_on > 32) + cmd_on = 32; if (cmd_on == 0) cmd_on = 1; + if (cmd_off > 32) + cmd_off = 32; if (cmd_off == 0) cmd_off = 1; @@ -69,59 +73,100 @@ static unsigned int get_pio_timings(ide_pio_data_t *p) } /* - * Configure the chipset for PIO mode. + * Configure the drive and chipset for PIO */ -static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) +static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int reg = 0x44 + drive->dn * 4; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; ide_pio_data_t p; - u16 drv_ctrl; + u16 drv_ctrl = 0x909; + unsigned int xfer_mode, reg; - DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio)); + DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n", + drive->name, pio, report, chipset_only)); + + reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); pio = ide_get_best_pio_mode(drive, pio, 5, &p); - drive->drive_data = drv_ctrl = get_pio_timings(&p); + xfer_mode = XFER_PIO_0 + pio; + + if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) { + drv_ctrl = get_timing_sl82c105(&p); + drive->pio_speed = xfer_mode; + } else + drive->pio_speed = XFER_PIO_0; - if (!drive->using_dma) { + if (drive->using_dma == 0) { /* * If we are actually using MW DMA, then we can not * reprogram the interface drive control register. */ - pci_write_config_word(dev, reg, drv_ctrl); - pci_read_config_word (dev, reg, &drv_ctrl); - } + pci_write_config_word(dev, reg, drv_ctrl); + pci_read_config_word(dev, reg, &drv_ctrl); - printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, - ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl); - - return pio; + if (report) { + printk("%s: selected %s (%dns) (%04X)\n", drive->name, + ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl); + } + } } /* - * Configure the drive for DMA. - * We'll program the chipset only when DMA is actually turned on. + * Configure the drive and the chipset for DMA */ -static int config_for_dma(ide_drive_t *drive) +static int config_for_dma (ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned int reg; + DBG(("config_for_dma(drive:%s)\n", drive->name)); + reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); + if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) - return 0; + return 1; - return ide_dma_enable(drive); + pci_write_config_word(dev, reg, 0x0240); + + return 0; } /* - * Check to see if the drive and chipset are capable of DMA mode. + * Check to see if the drive and + * chipset is capable of DMA mode */ -static int sl82c105_ide_dma_check(ide_drive_t *drive) + +static int sl82c105_check_drive (ide_drive_t *drive) { - DBG(("sl82c105_ide_dma_check(drive:%s)\n", drive->name)); + ide_hwif_t *hwif = HWIF(drive); + + DBG(("sl82c105_check_drive(drive:%s)\n", drive->name)); + + do { + struct hd_driveid *id = drive->id; + + if (!drive->autodma) + break; + + if (!id || !(id->capability & 1)) + break; - if (ide_use_dma(drive) && config_for_dma(drive)) - return 0; + /* Consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + break; + + if (id->field_valid & 2) { + if ((id->dma_mword & hwif->mwdma_mask) || + (id->dma_1word & hwif->swdma_mask)) + return 0; + } + + if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150) + return 0; + } while (0); return -1; } @@ -150,14 +195,14 @@ static inline void sl82c105_reset_host(struct pci_dev *dev) * This function is called when the IDE timer expires, the drive * indicates that it is READY, and we were waiting for DMA to complete. */ -static int sl82c105_ide_dma_lostirq(ide_drive_t *drive) +static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; - u8 dma_cmd; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + unsigned long dma_base = hwif->dma_base; - printk("sl82c105: lost IRQ, resetting host\n"); + printk("sl82c105: lost IRQ: resetting host\n"); /* * Check the raw interrupt from the drive. @@ -170,15 +215,15 @@ static int sl82c105_ide_dma_lostirq(ide_drive_t *drive) * Was DMA enabled? If so, disable it - we're resetting the * host. The IDE layer will be handling the drive for us. */ - dma_cmd = inb(hwif->dma_command); - if (dma_cmd & 1) { - outb(dma_cmd & ~1, hwif->dma_command); + val = inb(dma_base); + if (val & 1) { + outb(val & ~1, dma_base); printk("sl82c105: DMA was enabled\n"); } sl82c105_reset_host(dev); - /* __ide_dma_lostirq would return 1, so we do as well */ + /* ide_dmaproc would return 1, so we do as well */ return 1; } @@ -190,10 +235,10 @@ static int sl82c105_ide_dma_lostirq(ide_drive_t *drive) * The generic IDE core will have disabled the BMEN bit before this * function is called. */ -static void sl82c105_dma_start(ide_drive_t *drive) +static void sl82c105_ide_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; sl82c105_reset_host(dev); ide_dma_start(drive); @@ -201,8 +246,8 @@ static void sl82c105_dma_start(ide_drive_t *drive) static int sl82c105_ide_dma_timeout(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name)); @@ -210,32 +255,26 @@ static int sl82c105_ide_dma_timeout(ide_drive_t *drive) return __ide_dma_timeout(drive); } -static int sl82c105_ide_dma_on(ide_drive_t *drive) +static int sl82c105_ide_dma_on (ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int rc, reg = 0x44 + drive->dn * 4; - DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name)); - rc = __ide_dma_on(drive); - if (rc == 0) { - pci_write_config_word(dev, reg, 0x0200); - - printk(KERN_INFO "%s: DMA enabled\n", drive->name); - } - return rc; + if (config_for_dma(drive)) + return 1; + printk(KERN_INFO "%s: DMA enabled\n", drive->name); + return __ide_dma_on(drive); } static void sl82c105_dma_off_quietly(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int reg = 0x44 + drive->dn * 4; + u8 speed = XFER_PIO_0; DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name)); - pci_write_config_word(dev, reg, drive->drive_data); - ide_dma_off_quietly(drive); + if (drive->pio_speed) + speed = drive->pio_speed - XFER_PIO_0; + config_for_pio(drive, speed, 0, 1); } /* @@ -247,8 +286,8 @@ static void sl82c105_dma_off_quietly(ide_drive_t *drive) */ static void sl82c105_selectproc(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; u32 val, old, mask; //DBG(("sl82c105_selectproc(drive:%s)\n", drive->name)); @@ -284,12 +323,18 @@ static void sl82c105_resetproc(ide_drive_t *drive) * We only deal with PIO mode here - DMA mode 'using_dma' is not * initialised at the point that this function is called. */ -static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio) +static void tune_sl82c105(ide_drive_t *drive, u8 pio) { - DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio)); + DBG(("tune_sl82c105(drive:%s)\n", drive->name)); + + config_for_pio(drive, pio, 1, 0); - pio = sl82c105_tune_pio(drive, pio); - (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); + /* + * We support 32-bit I/O on this interface, and it + * doesn't have problems with interrupts. + */ + drive->io_32bit = 1; + drive->unmask = 1; } /* @@ -348,7 +393,7 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c } /* - * Initialise IDE channel + * Initialise the chip */ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) { @@ -356,22 +401,24 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); - hwif->tuneproc = &sl82c105_tune_drive; - hwif->selectproc = &sl82c105_selectproc; - hwif->resetproc = &sl82c105_resetproc; - - /* - * We support 32-bit I/O on this interface, and - * it doesn't have problems with interrupts. - */ - hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1; - hwif->drives[0].unmask = hwif->drives[1].unmask = 1; + hwif->tuneproc = tune_sl82c105; + hwif->selectproc = sl82c105_selectproc; + hwif->resetproc = sl82c105_resetproc; /* + * Default to PIO 0 for fallback unless tuned otherwise. * We always autotune PIO, this is done before DMA is checked, * so there's no risk of accidentally disabling DMA */ - hwif->drives[0].autotune = hwif->drives[1].autotune = 1; + hwif->drives[0].pio_speed = XFER_PIO_0; + hwif->drives[0].autotune = 1; + hwif->drives[1].pio_speed = XFER_PIO_0; + hwif->drives[1].autotune = 1; + + hwif->atapi_dma = 0; + hwif->mwdma_mask = 0; + hwif->swdma_mask = 0; + hwif->autodma = 0; if (!hwif->dma_base) return; @@ -382,27 +429,27 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) * Never ever EVER under any circumstances enable * DMA when the bridge is this old. */ - printk(" %s: Winbond W83C553 bridge revision %d, " - "BM-DMA disabled\n", hwif->name, rev); - return; + printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n", + hwif->name, rev); + } else { + hwif->atapi_dma = 1; + hwif->mwdma_mask = 0x04; + + hwif->ide_dma_check = &sl82c105_check_drive; + hwif->ide_dma_on = &sl82c105_ide_dma_on; + hwif->dma_off_quietly = &sl82c105_dma_off_quietly; + hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; + hwif->dma_start = &sl82c105_ide_dma_start; + hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; + + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; + + if (hwif->mate) + hwif->serialized = hwif->mate->serialized = 1; } - - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x04; - - hwif->ide_dma_check = &sl82c105_ide_dma_check; - hwif->ide_dma_on = &sl82c105_ide_dma_on; - hwif->dma_off_quietly = &sl82c105_dma_off_quietly; - hwif->ide_dma_lostirq = &sl82c105_ide_dma_lostirq; - hwif->dma_start = &sl82c105_dma_start; - hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; - - if (hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; } static ide_pci_device_t sl82c105_chipset __devinitdata = { diff --git a/trunk/drivers/ieee1394/Kconfig b/trunk/drivers/ieee1394/Kconfig index 61d7809a5a26..cd84a55ecf20 100644 --- a/trunk/drivers/ieee1394/Kconfig +++ b/trunk/drivers/ieee1394/Kconfig @@ -1,8 +1,11 @@ +# -*- shell-script -*- + menu "IEEE 1394 (FireWire) support" config IEEE1394 tristate "IEEE 1394 (FireWire) support" depends on PCI || BROKEN + select NET help IEEE 1394 describes a high performance serial bus, which is also known as FireWire(tm) or i.Link(tm) and is used for connecting all @@ -32,7 +35,24 @@ config IEEE1394_VERBOSEDEBUG Say Y if you really want or need the debugging output, everyone else says N. -comment "Controllers" +config IEEE1394_EXTRA_CONFIG_ROMS + bool "Build in extra config rom entries for certain functionality" + depends on IEEE1394 + help + Some IEEE1394 functionality depends on extra config rom entries + being available in the host adapters CSR. These options will + allow you to choose which ones. + +config IEEE1394_CONFIG_ROM_IP1394 + bool "IP-1394 Entry" + depends on IEEE1394_EXTRA_CONFIG_ROMS && IEEE1394 + help + Adds an entry for using IP-over-1394. If you want to use your + IEEE1394 bus as a network for IP systems (including interacting + with MacOSX and WinXP IP-over-1394), enable this option and the + eth1394 option below. + +comment "Device Drivers" depends on IEEE1394 comment "Texas Instruments PCILynx requires I2C" @@ -50,10 +70,6 @@ config IEEE1394_PCILYNX To compile this driver as a module, say M here: the module will be called pcilynx. - Only some old and now very rare PCI and CardBus cards and - PowerMacs G3 B&W contain the PCILynx controller. Therefore - almost everybody can say N here. - config IEEE1394_OHCI1394 tristate "OHCI-1394 support" depends on PCI && IEEE1394 @@ -67,7 +83,7 @@ config IEEE1394_OHCI1394 To compile this driver as a module, say M here: the module will be called ohci1394. -comment "Protocols" +comment "Protocol Drivers" depends on IEEE1394 config IEEE1394_VIDEO1394 @@ -105,15 +121,11 @@ config IEEE1394_SBP2_PHYS_DMA This option is buggy and currently broken on some architectures. If unsure, say N. -config IEEE1394_ETH1394_ROM_ENTRY - depends on IEEE1394 - bool - default n - config IEEE1394_ETH1394 - tristate "IP over 1394" + tristate "Ethernet over 1394" depends on IEEE1394 && EXPERIMENTAL && INET - select IEEE1394_ETH1394_ROM_ENTRY + select IEEE1394_CONFIG_ROM_IP1394 + select IEEE1394_EXTRA_CONFIG_ROMS help This driver implements a functional majority of RFC 2734: IPv4 over 1394. It will provide IP connectivity with implementations of RFC @@ -122,8 +134,6 @@ config IEEE1394_ETH1394 This driver is still considered experimental. It does not yet support MCAP, therefore multicast support is significantly limited. - The module is called eth1394 although it does not emulate Ethernet. - config IEEE1394_DV1394 tristate "OHCI-DV I/O support (deprecated)" depends on IEEE1394 && IEEE1394_OHCI1394 @@ -136,12 +146,12 @@ config IEEE1394_RAWIO tristate "Raw IEEE1394 I/O support" depends on IEEE1394 help - This option adds support for the raw1394 device file which enables - direct communication of user programs with the IEEE 1394 bus and thus - with the attached peripherals. Almost all application programs which - access FireWire require this option. + Say Y here if you want support for the raw device. This is generally + a good idea, so you should say Y here. The raw device enables + direct communication of user programs with the IEEE 1394 bus and + thus with the attached peripherals. - To compile this driver as a module, say M here: the module will be - called raw1394. + To compile this driver as a module, say M here: the + module will be called raw1394. endmenu diff --git a/trunk/drivers/ieee1394/config_roms.c b/trunk/drivers/ieee1394/config_roms.c index 1b981207fa76..e2de6fa0c9fe 100644 --- a/trunk/drivers/ieee1394/config_roms.c +++ b/trunk/drivers/ieee1394/config_roms.c @@ -26,6 +26,12 @@ struct hpsb_config_rom_entry { /* Base initialization, called at module load */ int (*init)(void); + /* Add entry to specified host */ + int (*add)(struct hpsb_host *host); + + /* Remove entry from specified host */ + void (*remove)(struct hpsb_host *host); + /* Cleanup called at module exit */ void (*cleanup)(void); @@ -33,7 +39,7 @@ struct hpsb_config_rom_entry { unsigned int flag; }; -/* The default host entry. This must succeed. */ + int hpsb_default_host_entry(struct hpsb_host *host) { struct csr1212_keyval *root; @@ -57,9 +63,9 @@ int hpsb_default_host_entry(struct hpsb_host *host) return -ENOMEM; } - csr1212_associate_keyval(vend_id, text); + ret = csr1212_associate_keyval(vend_id, text); csr1212_release_keyval(text); - ret = csr1212_attach_keyval_to_directory(root, vend_id); + ret |= csr1212_attach_keyval_to_directory(root, vend_id); csr1212_release_keyval(vend_id); if (ret != CSR1212_SUCCESS) { csr1212_destroy_csr(host->csr.rom); @@ -72,7 +78,7 @@ int hpsb_default_host_entry(struct hpsb_host *host) } -#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY +#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394 #include "eth1394.h" static struct csr1212_keyval *ip1394_ud; @@ -97,12 +103,10 @@ static int config_rom_ip1394_init(void) if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc) goto ip1394_fail; - csr1212_associate_keyval(spec_id, spec_desc); - csr1212_associate_keyval(ver, ver_desc); - if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id) - == CSR1212_SUCCESS && - csr1212_attach_keyval_to_directory(ip1394_ud, ver) - == CSR1212_SUCCESS) + if (csr1212_associate_keyval(spec_id, spec_desc) == CSR1212_SUCCESS && + csr1212_associate_keyval(ver, ver_desc) == CSR1212_SUCCESS && + csr1212_attach_keyval_to_directory(ip1394_ud, spec_id) == CSR1212_SUCCESS && + csr1212_attach_keyval_to_directory(ip1394_ud, ver) == CSR1212_SUCCESS) ret = 0; ip1394_fail: @@ -131,7 +135,7 @@ static void config_rom_ip1394_cleanup(void) } } -int hpsb_config_rom_ip1394_add(struct hpsb_host *host) +static int config_rom_ip1394_add(struct hpsb_host *host) { if (!ip1394_ud) return -ENODEV; @@ -140,55 +144,92 @@ int hpsb_config_rom_ip1394_add(struct hpsb_host *host) ip1394_ud) != CSR1212_SUCCESS) return -ENOMEM; - host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394; - host->update_config_rom = 1; return 0; } -EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add); -void hpsb_config_rom_ip1394_remove(struct hpsb_host *host) +static void config_rom_ip1394_remove(struct hpsb_host *host) { csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud); - host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394; - host->update_config_rom = 1; } -EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove); static struct hpsb_config_rom_entry ip1394_entry = { .name = "ip1394", .init = config_rom_ip1394_init, + .add = config_rom_ip1394_add, + .remove = config_rom_ip1394_remove, .cleanup = config_rom_ip1394_cleanup, .flag = HPSB_CONFIG_ROM_ENTRY_IP1394, }; +#endif /* CONFIG_IEEE1394_CONFIG_ROM_IP1394 */ -#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */ static struct hpsb_config_rom_entry *const config_rom_entries[] = { -#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY +#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394 &ip1394_entry, #endif + NULL, }; -/* Initialize all config roms */ + int hpsb_init_config_roms(void) { int i, error = 0; - for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++) + for (i = 0; config_rom_entries[i]; i++) { + if (!config_rom_entries[i]->init) + continue; + if (config_rom_entries[i]->init()) { HPSB_ERR("Failed to initialize config rom entry `%s'", config_rom_entries[i]->name); error = -1; - } + } else + HPSB_DEBUG("Initialized config rom entry `%s'", + config_rom_entries[i]->name); + } return error; } -/* Cleanup all config roms */ void hpsb_cleanup_config_roms(void) { int i; - for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++) - config_rom_entries[i]->cleanup(); + for (i = 0; config_rom_entries[i]; i++) { + if (config_rom_entries[i]->cleanup) + config_rom_entries[i]->cleanup(); + } +} + +int hpsb_add_extra_config_roms(struct hpsb_host *host) +{ + int i, error = 0; + + for (i = 0; config_rom_entries[i]; i++) { + if (config_rom_entries[i]->add(host)) { + HPSB_ERR("fw-host%d: Failed to attach config rom entry `%s'", + host->id, config_rom_entries[i]->name); + error = -1; + } else { + host->config_roms |= config_rom_entries[i]->flag; + host->update_config_rom = 1; + } + } + + return error; +} + +void hpsb_remove_extra_config_roms(struct hpsb_host *host) +{ + int i; + + for (i = 0; config_rom_entries[i]; i++) { + if (!(host->config_roms & config_rom_entries[i]->flag)) + continue; + + config_rom_entries[i]->remove(host); + + host->config_roms &= ~config_rom_entries[i]->flag; + host->update_config_rom = 1; + } } diff --git a/trunk/drivers/ieee1394/config_roms.h b/trunk/drivers/ieee1394/config_roms.h index 1f5cd1f16c44..0a70544cfe65 100644 --- a/trunk/drivers/ieee1394/config_roms.h +++ b/trunk/drivers/ieee1394/config_roms.h @@ -1,19 +1,27 @@ #ifndef _IEEE1394_CONFIG_ROMS_H #define _IEEE1394_CONFIG_ROMS_H -struct hpsb_host; +#include "ieee1394_types.h" +#include "hosts.h" +/* The default host entry. This must succeed. */ int hpsb_default_host_entry(struct hpsb_host *host); + +/* Initialize all config roms */ int hpsb_init_config_roms(void); + +/* Cleanup all config roms */ void hpsb_cleanup_config_roms(void); +/* Add extra config roms to specified host */ +int hpsb_add_extra_config_roms(struct hpsb_host *host); + +/* Remove extra config roms from specified host */ +void hpsb_remove_extra_config_roms(struct hpsb_host *host); + + /* List of flags to check if a host contains a certain extra config rom * entry. Available in the host->config_roms member. */ #define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001 -#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY -int hpsb_config_rom_ip1394_add(struct hpsb_host *host); -void hpsb_config_rom_ip1394_remove(struct hpsb_host *host); -#endif - #endif /* _IEEE1394_CONFIG_ROMS_H */ diff --git a/trunk/drivers/ieee1394/csr1212.c b/trunk/drivers/ieee1394/csr1212.c index d08166bda1c5..c28f639823d2 100644 --- a/trunk/drivers/ieee1394/csr1212.c +++ b/trunk/drivers/ieee1394/csr1212.c @@ -31,13 +31,12 @@ /* TODO List: * - Verify interface consistency: i.e., public functions that take a size * parameter expect size to be in bytes. + * - Convenience functions for reading a block of data from a given offset. */ -#include -#include -#include -#include -#include +#ifndef __KERNEL__ +#include +#endif #include "csr1212.h" @@ -47,7 +46,7 @@ #define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET) #define __D (1 << CSR1212_KV_TYPE_DIRECTORY) #define __L (1 << CSR1212_KV_TYPE_LEAF) -static const u8 csr1212_key_id_type_map[0x30] = { +static const u_int8_t csr1212_key_id_type_map[0x30] = { __C, /* used by Apple iSight */ __D | __L, /* Descriptor */ __I | __D | __L, /* Bus_Dependent_Info */ @@ -83,10 +82,10 @@ static const u8 csr1212_key_id_type_map[0x30] = { #undef __L -#define quads_to_bytes(_q) ((_q) * sizeof(u32)) -#define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32)) +#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t)) +#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t)) -static void free_keyval(struct csr1212_keyval *kv) +static inline void free_keyval(struct csr1212_keyval *kv) { if ((kv->key.type == CSR1212_KV_TYPE_LEAF) && (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)) @@ -95,14 +94,14 @@ static void free_keyval(struct csr1212_keyval *kv) CSR1212_FREE(kv); } -static u16 csr1212_crc16(const u32 *buffer, size_t length) +static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length) { int shift; - u32 data; - u16 sum, crc = 0; + u_int32_t data; + u_int16_t sum, crc = 0; for (; length; length--) { - data = be32_to_cpu(*buffer); + data = CSR1212_BE32_TO_CPU(*buffer); buffer++; for (shift = 28; shift >= 0; shift -= 4 ) { sum = ((crc >> 12) ^ (data >> shift)) & 0xf; @@ -111,18 +110,21 @@ static u16 csr1212_crc16(const u32 *buffer, size_t length) crc &= 0xffff; } - return cpu_to_be16(crc); + return CSR1212_CPU_TO_BE16(crc); } -/* Microsoft computes the CRC with the bytes in reverse order. */ -static u16 csr1212_msft_crc16(const u32 *buffer, size_t length) +#if 0 +/* Microsoft computes the CRC with the bytes in reverse order. Therefore we + * have a special version of the CRC algorithm to account for their buggy + * software. */ +static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length) { int shift; - u32 data; - u16 sum, crc = 0; + u_int32_t data; + u_int16_t sum, crc = 0; for (; length; length--) { - data = le32_to_cpu(*buffer); + data = CSR1212_LE32_TO_CPU(*buffer); buffer++; for (shift = 28; shift >= 0; shift -= 4 ) { sum = ((crc >> 12) ^ (data >> shift)) & 0xf; @@ -131,35 +133,38 @@ static u16 csr1212_msft_crc16(const u32 *buffer, size_t length) crc &= 0xffff; } - return cpu_to_be16(crc); + return CSR1212_CPU_TO_BE16(crc); } +#endif -static struct csr1212_dentry * -csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv) +static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir, + struct csr1212_keyval *kv) { struct csr1212_dentry *pos; for (pos = dir->value.directory.dentries_head; - pos != NULL; pos = pos->next) + pos != NULL; pos = pos->next) { if (pos->kv == kv) return pos; + } return NULL; } -static struct csr1212_keyval * -csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset) + +static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, + u_int32_t offset) { struct csr1212_keyval *kv; - for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) + for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) { if (kv->offset == offset) return kv; + } return NULL; } /* Creation Routines */ - struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, size_t bus_info_size, void *private) { @@ -197,17 +202,27 @@ struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, return csr; } + + void csr1212_init_local_csr(struct csr1212_csr *csr, - const u32 *bus_info_data, int max_rom) + const u_int32_t *bus_info_data, int max_rom) { static const int mr_map[] = { 4, 64, 1024, 0 }; +#ifdef __KERNEL__ BUG_ON(max_rom & ~0x3); csr->max_rom = mr_map[max_rom]; +#else + if (max_rom & ~0x3) /* caller supplied invalid argument */ + csr->max_rom = 0; + else + csr->max_rom = mr_map[max_rom]; +#endif memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len); } -static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key) + +static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key) { struct csr1212_keyval *kv; @@ -231,11 +246,10 @@ static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key) return kv; } -struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value) +struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value) { - struct csr1212_keyval *kv; + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key); - kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key); if (!kv) return NULL; @@ -244,12 +258,10 @@ struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value) return kv; } -static struct csr1212_keyval * -csr1212_new_leaf(u8 key, const void *data, size_t data_len) +struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len) { - struct csr1212_keyval *kv; + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key); - kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key); if (!kv) return NULL; @@ -273,12 +285,10 @@ csr1212_new_leaf(u8 key, const void *data, size_t data_len) return kv; } -static struct csr1212_keyval * -csr1212_new_csr_offset(u8 key, u32 csr_offset) +struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset) { - struct csr1212_keyval *kv; + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key); - kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key); if (!kv) return NULL; @@ -289,11 +299,10 @@ csr1212_new_csr_offset(u8 key, u32 csr_offset) return kv; } -struct csr1212_keyval *csr1212_new_directory(u8 key) +struct csr1212_keyval *csr1212_new_directory(u_int8_t key) { - struct csr1212_keyval *kv; + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key); - kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key); if (!kv) return NULL; @@ -305,29 +314,43 @@ struct csr1212_keyval *csr1212_new_directory(u8 key) return kv; } -void csr1212_associate_keyval(struct csr1212_keyval *kv, - struct csr1212_keyval *associate) +int csr1212_associate_keyval(struct csr1212_keyval *kv, + struct csr1212_keyval *associate) { - BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR || - (associate->key.id != CSR1212_KV_ID_DESCRIPTOR && - associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO && - associate->key.id != CSR1212_KV_ID_EXTENDED_KEY && - associate->key.id != CSR1212_KV_ID_EXTENDED_DATA && - associate->key.id < 0x30) || - (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID && - associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) || - (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY && - associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) || - (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY && - kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) || - (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA && - kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)); + if (!kv || !associate) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR || + (associate->key.id != CSR1212_KV_ID_DESCRIPTOR && + associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO && + associate->key.id != CSR1212_KV_ID_EXTENDED_KEY && + associate->key.id != CSR1212_KV_ID_EXTENDED_DATA && + associate->key.id < 0x30)) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID && + associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY && + associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) + return CSR1212_EINVAL; + + if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY && + kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) + return CSR1212_EINVAL; + + if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA && + kv->key.id != CSR1212_KV_ID_EXTENDED_KEY) + return CSR1212_EINVAL; if (kv->associate) csr1212_release_keyval(kv->associate); associate->refcnt++; kv->associate = associate; + + return CSR1212_SUCCESS; } int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, @@ -335,11 +358,12 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, { struct csr1212_dentry *dentry; - BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY); + if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) + return CSR1212_EINVAL; dentry = CSR1212_MALLOC(sizeof(*dentry)); if (!dentry) - return -ENOMEM; + return CSR1212_ENOMEM; dentry->kv = kv; @@ -358,22 +382,66 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, return CSR1212_SUCCESS; } -#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ - (&((kv)->value.leaf.data[1])) - -#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \ - ((kv)->value.leaf.data[0] = \ - cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \ - ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT))) -#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \ - ((kv)->value.leaf.data[0] = \ - cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \ - CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \ - ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK))) - -static struct csr1212_keyval * -csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id, - const void *data, size_t data_len) +struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key, + u_int32_t value) +{ + struct csr1212_keyval *kvs, *kvk, *kvv; + + kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec); + kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key); + kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value); + + if (!kvs || !kvk || !kvv) { + if (kvs) + free_keyval(kvs); + if (kvk) + free_keyval(kvk); + if (kvv) + free_keyval(kvv); + return NULL; + } + + /* Don't keep a local reference to the extended key or value. */ + kvk->refcnt = 0; + kvv->refcnt = 0; + + csr1212_associate_keyval(kvk, kvv); + csr1212_associate_keyval(kvs, kvk); + + return kvs; +} + +struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, u_int32_t key, + const void *data, size_t data_len) +{ + struct csr1212_keyval *kvs, *kvk, *kvv; + + kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec); + kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key); + kvv = csr1212_new_leaf(CSR1212_KV_ID_EXTENDED_DATA, data, data_len); + + if (!kvs || !kvk || !kvv) { + if (kvs) + free_keyval(kvs); + if (kvk) + free_keyval(kvk); + if (kvv) + free_keyval(kvv); + return NULL; + } + + /* Don't keep a local reference to the extended key or value. */ + kvk->refcnt = 0; + kvv->refcnt = 0; + + csr1212_associate_keyval(kvk, kvv); + csr1212_associate_keyval(kvs, kvk); + + return kvs; +} + +struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id, + const void *data, size_t data_len) { struct csr1212_keyval *kv; @@ -385,72 +453,197 @@ csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id, CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype); CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id); - if (data) + if (data) { memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len); + } + + return kv; +} + + +struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth, + u_int16_t cset, + u_int16_t language, + const void *data, + size_t data_len) +{ + struct csr1212_keyval *kv; + char *lstr; + + kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len + + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD); + if (!kv) + return NULL; + + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth); + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset); + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); + + lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv); + + /* make sure last quadlet is zeroed out */ + *((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0; + + /* don't copy the NUL terminator */ + memcpy(lstr, data, data_len); return kv; } -/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */ static int csr1212_check_minimal_ascii(const char *s) { static const char minimal_ascii_table[] = { - /* 1 2 4 8 16 32 64 128 */ - 128, /* --, --, --, --, --, --, --, 07, */ - 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */ - 0, /* --, --, --, --, --, --, --, --, */ - 0, /* --, --, --, --, --, --, --, --, */ - 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */ - 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */ - 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */ - 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */ - 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */ - 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */ - 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */ - 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */ - 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */ - 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */ - 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */ - 1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f, + 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, }; - int i, j; - for (; *s; s++) { - i = *s >> 3; /* i = *s / 8; */ - j = 1 << (*s & 3); /* j = 1 << (*s % 8); */ - - if (i >= ARRAY_SIZE(minimal_ascii_table) || - !(minimal_ascii_table[i] & j)) - return -EINVAL; + if (minimal_ascii_table[*s & 0x7F] != *s) + return -1; /* failed */ } + /* String conforms to minimal-ascii, as specified by IEEE 1212, + * par. 7.4 */ return 0; } -/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */ struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s) { + /* Check if string conform to minimal_ascii format */ + if (csr1212_check_minimal_ascii(s)) + return NULL; + + /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */ + return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s)); +} + +struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version, + u_int8_t palette_depth, + u_int8_t color_space, + u_int16_t language, + u_int16_t hscan, + u_int16_t vscan, + u_int32_t *palette, + u_int32_t *pixels) +{ + static const int pd[4] = { 0, 4, 16, 256 }; + static const int cs[16] = { 4, 2 }; struct csr1212_keyval *kv; - u32 *text; - size_t str_len, quads; + int palette_size; + int pixel_size = (hscan * vscan + 3) & ~0x3; - if (!s || !*s || csr1212_check_minimal_ascii(s)) + if (!pixels || (!palette && palette_depth) || + (palette_depth & ~0x3) || (color_space & ~0xf)) return NULL; - str_len = strlen(s); - quads = bytes_to_quads(str_len); - kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) + - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD); + palette_size = pd[palette_depth] * cs[color_space]; + + kv = csr1212_new_descriptor_leaf(1, 0, NULL, + palette_size + pixel_size + + CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD); if (!kv) return NULL; - kv->value.leaf.data[1] = 0; /* width, character_set, language */ - text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv); - text[quads - 1] = 0; /* padding */ - memcpy(text, s, str_len); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan); + + if (palette_size) + memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette, + palette_size); + + memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size); + + return kv; +} + +struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size, + u_int64_t address) +{ + struct csr1212_keyval *kv; + + /* IEEE 1212, par. 7.5.4.3 Modifiable descriptors */ + kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t)); + if(!kv) + return NULL; + + CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size); + CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address); + CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address); return kv; } +static int csr1212_check_keyword(const char *s) +{ + for (; *s; s++) { + + if (('A' <= *s) && (*s <= 'Z')) + continue; + if (('0' <= *s) && (*s <= '9')) + continue; + if (*s == '-') + continue; + + return -1; /* failed */ + } + /* String conforms to keyword, as specified by IEEE 1212, + * par. 7.6.5 */ + return CSR1212_SUCCESS; +} + +struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[]) +{ + struct csr1212_keyval *kv; + char *buffer; + int i, data_len = 0; + + /* Check all keywords to see if they conform to restrictions: + * Only the following characters is allowed ['A'..'Z','0'..'9','-'] + * Each word is zero-terminated. + * Also calculate the total length of the keywords. + */ + for (i = 0; i < strc; i++) { + if (!strv[i] || csr1212_check_keyword(strv[i])) { + return NULL; + } + data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */ + } + + /* IEEE 1212, par. 7.6.5 Keyword leaves */ + kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len); + if (!kv) + return NULL; + + buffer = (char *)kv->value.leaf.data; + + /* make sure last quadlet is zeroed out */ + *((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0; + + /* Copy keyword(s) into leaf data buffer */ + for (i = 0; i < strc; i++) { + int len = strlen(strv[i]) + 1; + memcpy(buffer, strv[i], len); + buffer += len; + } + return kv; +} + /* Destruction Routines */ @@ -481,12 +674,23 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, csr1212_release_keyval(kv); } + +void csr1212_disassociate_keyval(struct csr1212_keyval *kv) +{ + if (kv->associate) { + csr1212_release_keyval(kv->associate); + } + + kv->associate = NULL; +} + + /* This function is used to free the memory taken by a keyval. If the given * keyval is a directory type, then any keyvals contained in that directory * will be destroyed as well if their respective refcnts are 0. By means of * list manipulation, this routine will descend a directory structure in a * non-recursive manner. */ -static void csr1212_destroy_keyval(struct csr1212_keyval *kv) +void _csr1212_destroy_keyval(struct csr1212_keyval *kv) { struct csr1212_keyval *k, *a; struct csr1212_dentry dentry; @@ -511,13 +715,11 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv) a = k->associate; if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) { - /* If the current entry is a directory, move all + /* If the current entry is a directory, then move all * the entries to the destruction list. */ if (k->value.directory.dentries_head) { - tail->next = - k->value.directory.dentries_head; - k->value.directory.dentries_head->prev = - tail; + tail->next = k->value.directory.dentries_head; + k->value.directory.dentries_head->prev = tail; tail = k->value.directory.dentries_tail; } } @@ -527,22 +729,15 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv) head = head->next; if (head) { - if (head->prev && head->prev != &dentry) + if (head->prev && head->prev != &dentry) { CSR1212_FREE(head->prev); + } head->prev = NULL; - } else if (tail != &dentry) { + } else if (tail != &dentry) CSR1212_FREE(tail); - } } } -void csr1212_release_keyval(struct csr1212_keyval *kv) -{ - if (kv->refcnt > 1) - kv->refcnt--; - else - csr1212_destroy_keyval(kv); -} void csr1212_destroy_csr(struct csr1212_csr *csr) { @@ -568,51 +763,49 @@ void csr1212_destroy_csr(struct csr1212_csr *csr) } + /* CSR Image Creation */ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) { struct csr1212_csr_rom_cache *cache; - u64 csr_addr; + u_int64_t csr_addr; - BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range || - !csr->ops->release_addr || csr->max_rom < 1); + if (!csr || !csr->ops || !csr->ops->allocate_addr_range || + !csr->ops->release_addr || csr->max_rom < 1) + return CSR1212_EINVAL; /* ROM size must be a multiple of csr->max_rom */ romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); - csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, - csr->private); - if (csr_addr == CSR1212_INVALID_ADDR_SPACE) - return -ENOMEM; - + csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private); + if (csr_addr == CSR1212_INVALID_ADDR_SPACE) { + return CSR1212_ENOMEM; + } if (csr_addr < CSR1212_REGISTER_SPACE_BASE) { /* Invalid address returned from allocate_addr_range(). */ csr->ops->release_addr(csr_addr, csr->private); - return -ENOMEM; + return CSR1212_ENOMEM; } - cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, - romsize); + cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize); if (!cache) { csr->ops->release_addr(csr_addr, csr->private); - return -ENOMEM; + return CSR1212_ENOMEM; } - cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, - CSR1212_KV_ID_EXTENDED_ROM); + cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM); if (!cache->ext_rom) { csr->ops->release_addr(csr_addr, csr->private); CSR1212_FREE(cache); - return -ENOMEM; + return CSR1212_ENOMEM; } - if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != - CSR1212_SUCCESS) { + if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) { csr1212_release_keyval(cache->ext_rom); csr->ops->release_addr(csr_addr, csr->private); CSR1212_FREE(cache); - return -ENOMEM; + return CSR1212_ENOMEM; } cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; cache->ext_rom->value.leaf.len = -1; @@ -625,8 +818,8 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) return CSR1212_SUCCESS; } -static void csr1212_remove_cache(struct csr1212_csr *csr, - struct csr1212_csr_rom_cache *cache) +static inline void csr1212_remove_cache(struct csr1212_csr *csr, + struct csr1212_csr_rom_cache *cache) { if (csr->cache_head == cache) csr->cache_head = cache->next; @@ -639,8 +832,7 @@ static void csr1212_remove_cache(struct csr1212_csr *csr, cache->next->prev = cache->prev; if (cache->ext_rom) { - csr1212_detach_keyval_from_directory(csr->root_kv, - cache->ext_rom); + csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom); csr1212_release_keyval(cache->ext_rom); } @@ -660,29 +852,28 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, dentry = dentry->next) { for (dkv = dentry->kv; dkv; dkv = dkv->associate) { /* Special Case: Extended Key Specifier_ID */ - if (dkv->key.id == - CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { - if (last_extkey_spec == NULL) + if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { + if (last_extkey_spec == NULL) { last_extkey_spec = dkv; - else if (dkv->value.immediate != - last_extkey_spec->value.immediate) + } else if (dkv->value.immediate != last_extkey_spec->value.immediate) { last_extkey_spec = dkv; - else + } else { continue; + } /* Special Case: Extended Key */ } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) { - if (last_extkey == NULL) + if (last_extkey == NULL) { last_extkey = dkv; - else if (dkv->value.immediate != - last_extkey->value.immediate) + } else if (dkv->value.immediate != last_extkey->value.immediate) { last_extkey = dkv; - else + } else { continue; + } } num_entries += 1; - switch (dkv->key.type) { + switch(dkv->key.type) { default: case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_CSR_OFFSET: @@ -700,9 +891,8 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, /* Special case: Extended ROM leafs */ if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { dkv->value.leaf.len = -1; - /* Don't add Extended ROM leafs in the - * layout list, they are handled - * differently. */ + /* Don't add Extended ROM leafs in the layout list, + * they are handled differently. */ break; } @@ -718,21 +908,20 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, return num_entries; } -static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) +size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) { struct csr1212_keyval *ltail = kv; size_t agg_size = 0; - while (kv) { - switch (kv->key.type) { + while(kv) { + switch(kv->key.type) { case CSR1212_KV_TYPE_LEAF: /* Add 1 quadlet for crc/len field */ agg_size += kv->value.leaf.len + 1; break; case CSR1212_KV_TYPE_DIRECTORY: - kv->value.directory.len = - csr1212_generate_layout_subdir(kv, <ail); + kv->value.directory.len = csr1212_generate_layout_subdir(kv, <ail); /* Add 1 quadlet for crc/len field */ agg_size += kv->value.directory.len + 1; break; @@ -742,9 +931,9 @@ static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) return quads_to_bytes(agg_size); } -static struct csr1212_keyval * -csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, - struct csr1212_keyval *start_kv, int start_pos) +struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, + struct csr1212_keyval *start_kv, + int start_pos) { struct csr1212_keyval *kv = start_kv; struct csr1212_keyval *okv = start_kv; @@ -753,12 +942,13 @@ csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, cache->layout_head = kv; - while (kv && pos < cache->size) { + while(kv && pos < cache->size) { /* Special case: Extended ROM leafs */ - if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { kv->offset = cache->offset + pos; + } - switch (kv->key.type) { + switch(kv->key.type) { case CSR1212_KV_TYPE_LEAF: kv_len = kv->value.leaf.len; break; @@ -769,7 +959,6 @@ csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, default: /* Should never get here */ - WARN_ON(1); break; } @@ -783,55 +972,46 @@ csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, } cache->layout_tail = okv; - cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1); + cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1); return kv; } -#define CSR1212_KV_KEY_SHIFT 24 -#define CSR1212_KV_KEY_TYPE_SHIFT 6 -#define CSR1212_KV_KEY_ID_MASK 0x3f -#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */ - -static void -csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer) +static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir, + u_int32_t *data_buffer) { struct csr1212_dentry *dentry; struct csr1212_keyval *last_extkey_spec = NULL; struct csr1212_keyval *last_extkey = NULL; int index = 0; - for (dentry = dir->value.directory.dentries_head; - dentry; - dentry = dentry->next) { + for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) { struct csr1212_keyval *a; for (a = dentry->kv; a; a = a->associate) { - u32 value = 0; + u_int32_t value = 0; /* Special Case: Extended Key Specifier_ID */ - if (a->key.id == - CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { - if (last_extkey_spec == NULL) + if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { + if (last_extkey_spec == NULL) { last_extkey_spec = a; - else if (a->value.immediate != - last_extkey_spec->value.immediate) + } else if (a->value.immediate != last_extkey_spec->value.immediate) { last_extkey_spec = a; - else + } else { continue; - + } /* Special Case: Extended Key */ } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) { - if (last_extkey == NULL) + if (last_extkey == NULL) { last_extkey = a; - else if (a->value.immediate != - last_extkey->value.immediate) + } else if (a->value.immediate != last_extkey->value.immediate) { last_extkey = a; - else + } else { continue; + } } - switch (a->key.type) { + switch(a->key.type) { case CSR1212_KV_TYPE_IMMEDIATE: value = a->value.immediate; break; @@ -850,46 +1030,32 @@ csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer) break; default: /* Should never get here */ - WARN_ON(1); - break; + break; /* GDB breakpoint */ } - value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << - CSR1212_KV_KEY_SHIFT; + value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT; value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) << - (CSR1212_KV_KEY_SHIFT + - CSR1212_KV_KEY_TYPE_SHIFT); - data_buffer[index] = cpu_to_be32(value); + (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT); + data_buffer[index] = CSR1212_CPU_TO_BE32(value); index++; } } } -struct csr1212_keyval_img { - u16 length; - u16 crc; - - /* Must be last */ - u32 data[0]; /* older gcc can't handle [] which is standard */ -}; - -static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) +void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) { struct csr1212_keyval *kv, *nkv; struct csr1212_keyval_img *kvi; - for (kv = cache->layout_head; - kv != cache->layout_tail->next; - kv = nkv) { - kvi = (struct csr1212_keyval_img *)(cache->data + - bytes_to_quads(kv->offset - cache->offset)); - switch (kv->key.type) { + for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) { + kvi = (struct csr1212_keyval_img *) + (cache->data + bytes_to_quads(kv->offset - cache->offset)); + switch(kv->key.type) { default: case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_CSR_OFFSET: /* Should never get here */ - WARN_ON(1); - break; + break; /* GDB breakpoint */ case CSR1212_KV_TYPE_LEAF: /* Don't copy over Extended ROM areas, they are @@ -898,16 +1064,15 @@ static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) memcpy(kvi->data, kv->value.leaf.data, quads_to_bytes(kv->value.leaf.len)); - kvi->length = cpu_to_be16(kv->value.leaf.len); + kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len); kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len); break; case CSR1212_KV_TYPE_DIRECTORY: csr1212_generate_tree_subdir(kv, kvi->data); - kvi->length = cpu_to_be16(kv->value.directory.len); - kvi->crc = csr1212_crc16(kvi->data, - kv->value.directory.len); + kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len); + kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len); break; } @@ -921,10 +1086,6 @@ static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) } } -/* This size is arbitrarily chosen. - * The struct overhead is subtracted for more economic allocations. */ -#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache)) - int csr1212_generate_csr_image(struct csr1212_csr *csr) { struct csr1212_bus_info_block_img *bi; @@ -934,7 +1095,8 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) int ret; int init_offset; - BUG_ON(!csr); + if (!csr) + return CSR1212_EINVAL; cache = csr->cache_head; @@ -951,21 +1113,18 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) init_offset = csr->bus_info_len; - for (kv = csr->root_kv, cache = csr->cache_head; - kv; - cache = cache->next) { + for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) { if (!cache) { /* Estimate approximate number of additional cache * regions needed (it assumes that the cache holding * the first 1K Config ROM space always exists). */ int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE - - (2 * sizeof(u32))) + 1; + (2 * sizeof(u_int32_t))) + 1; /* Add additional cache regions, extras will be * removed later */ for (; est_c; est_c--) { - ret = csr1212_append_new_cache(csr, - CSR1212_EXTENDED_ROM_SIZE); + ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE); if (ret != CSR1212_SUCCESS) return ret; } @@ -977,7 +1136,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) } kv = csr1212_generate_positions(cache, kv, init_offset); agg_size -= cache->len; - init_offset = sizeof(u32); + init_offset = sizeof(u_int32_t); } /* Remove unused, excess cache regions */ @@ -990,14 +1149,15 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) /* Go through the list backward so that when done, the correct CRC * will be calculated for the Extended ROM areas. */ - for (cache = csr->cache_tail; cache; cache = cache->prev) { + for(cache = csr->cache_tail; cache; cache = cache->prev) { /* Only Extended ROM caches should have this set. */ if (cache->ext_rom) { int leaf_size; /* Make sure the Extended ROM leaf is a multiple of * max_rom in size. */ - BUG_ON(csr->max_rom < 1); + if (csr->max_rom < 1) + return CSR1212_EINVAL; leaf_size = (cache->len + (csr->max_rom - 1)) & ~(csr->max_rom - 1); @@ -1006,7 +1166,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) leaf_size - cache->len); /* Subtract leaf header */ - leaf_size -= sizeof(u32); + leaf_size -= sizeof(u_int32_t); /* Update the Extended ROM leaf length */ cache->ext_rom->value.leaf.len = @@ -1024,33 +1184,35 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) /* Set the length and CRC of the extended ROM. */ struct csr1212_keyval_img *kvi = (struct csr1212_keyval_img*)cache->data; - u16 len = bytes_to_quads(cache->len) - 1; - kvi->length = cpu_to_be16(len); - kvi->crc = csr1212_crc16(kvi->data, len); + kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1); + kvi->crc = csr1212_crc16(kvi->data, + bytes_to_quads(cache->len) - 1); + } } return CSR1212_SUCCESS; } -int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len) +int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len) { struct csr1212_csr_rom_cache *cache; - for (cache = csr->cache_head; cache; cache = cache->next) + for (cache = csr->cache_head; cache; cache = cache->next) { if (offset >= cache->offset && (offset + len) <= (cache->offset + cache->size)) { - memcpy(buffer, &cache->data[ - bytes_to_quads(offset - cache->offset)], + memcpy(buffer, + &cache->data[bytes_to_quads(offset - cache->offset)], len); return CSR1212_SUCCESS; } - - return -ENOENT; + } + return CSR1212_ENOENT; } + /* Parse a chunk of data as a Config ROM */ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) @@ -1065,43 +1227,46 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) * Unfortunately, many IEEE 1394 devices do not abide by that, so the * bus info block will be read 1 quadlet at a time. The rest of the * ConfigROM will be read according to the max_rom field. */ - for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) { + for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) { ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, - sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)], - csr->private); + sizeof(csr1212_quad_t), + &csr->cache_head->data[bytes_to_quads(i)], + csr->private); if (ret != CSR1212_SUCCESS) return ret; /* check ROM header's info_length */ if (i == 0 && - be32_to_cpu(csr->cache_head->data[0]) >> 24 != + CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 != bytes_to_quads(csr->bus_info_len) - 1) - return -EINVAL; + return CSR1212_EINVAL; } bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data; csr->crc_len = quads_to_bytes(bi->crc_length); - /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that - * is not always the case, so read the rest of the crc area 1 quadlet at - * a time. */ - for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) { + /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not + * always the case, so read the rest of the crc area 1 quadlet at a time. */ + for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) { ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, - sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)], - csr->private); + sizeof(csr1212_quad_t), + &csr->cache_head->data[bytes_to_quads(i)], + csr->private); if (ret != CSR1212_SUCCESS) return ret; } - /* Apparently there are many different wrong implementations of the CRC - * algorithm. We don't fail, we just warn. */ +#if 0 + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) && (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc)) - printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n"); + return CSR1212_EINVAL; +#endif cr = CSR1212_MALLOC(sizeof(*cr)); if (!cr) - return -ENOMEM; + return CSR1212_ENOMEM; cr->next = NULL; cr->prev = NULL; @@ -1114,26 +1279,21 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) return CSR1212_SUCCESS; } -#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT) -#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT) -#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK) -#define CSR1212_KV_VAL_MASK 0xffffff -#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK) - -static int -csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) +static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, + csr1212_quad_t ki, + u_int32_t kv_pos) { int ret = CSR1212_SUCCESS; struct csr1212_keyval *k = NULL; - u32 offset; + u_int32_t offset; - switch (CSR1212_KV_KEY_TYPE(ki)) { + switch(CSR1212_KV_KEY_TYPE(ki)) { case CSR1212_KV_TYPE_IMMEDIATE: k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki), CSR1212_KV_VAL(ki)); if (!k) { - ret = -ENOMEM; - goto out; + ret = CSR1212_ENOMEM; + goto fail; } k->refcnt = 0; /* Don't keep local reference when parsing. */ @@ -1143,8 +1303,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki), CSR1212_KV_VAL(ki)); if (!k) { - ret = -ENOMEM; - goto out; + ret = CSR1212_ENOMEM; + goto fail; } k->refcnt = 0; /* Don't keep local reference when parsing. */ break; @@ -1156,8 +1316,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) /* Uh-oh. Can't have a relative offset of 0 for Leaves * or Directories. The Config ROM image is most likely * messed up, so we'll just abort here. */ - ret = -EIO; - goto out; + ret = CSR1212_EIO; + goto fail; } k = csr1212_find_keyval_offset(dir, offset); @@ -1165,14 +1325,14 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) if (k) break; /* Found it. */ - if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) + if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) { k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki)); - else + } else { k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0); - + } if (!k) { - ret = -ENOMEM; - goto out; + ret = CSR1212_ENOMEM; + goto fail; } k->refcnt = 0; /* Don't keep local reference when parsing. */ k->valid = 0; /* Contents not read yet so it's not valid. */ @@ -1184,12 +1344,16 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) dir->next = k; } ret = csr1212_attach_keyval_to_directory(dir, k); -out: - if (ret != CSR1212_SUCCESS && k != NULL) - free_keyval(k); + +fail: + if (ret != CSR1212_SUCCESS) { + if (k) + free_keyval(k); + } return ret; } + int csr1212_parse_keyval(struct csr1212_keyval *kv, struct csr1212_csr_rom_cache *cache) { @@ -1198,20 +1362,24 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv, int ret = CSR1212_SUCCESS; int kvi_len; - kvi = (struct csr1212_keyval_img*) - &cache->data[bytes_to_quads(kv->offset - cache->offset)]; - kvi_len = be16_to_cpu(kvi->length); + kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset - + cache->offset)]; + kvi_len = CSR1212_BE16_TO_CPU(kvi->length); - /* Apparently there are many different wrong implementations of the CRC - * algorithm. We don't fail, we just warn. */ +#if 0 + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) && - (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) - printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n"); + (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) { + ret = CSR1212_EINVAL; + goto fail; + } +#endif - switch (kv->key.type) { + switch(kv->key.type) { case CSR1212_KV_TYPE_DIRECTORY: for (i = 0; i < kvi_len; i++) { - u32 ki = kvi->data[i]; + csr1212_quad_t ki = kvi->data[i]; /* Some devices put null entries in their unit * directories. If we come across such an entry, @@ -1219,72 +1387,76 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv, if (ki == 0x0) continue; ret = csr1212_parse_dir_entry(kv, ki, - kv->offset + quads_to_bytes(i + 1)); + (kv->offset + + quads_to_bytes(i + 1))); } kv->value.directory.len = kvi_len; break; case CSR1212_KV_TYPE_LEAF: if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { - size_t size = quads_to_bytes(kvi_len); - - kv->value.leaf.data = CSR1212_MALLOC(size); + kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len)); if (!kv->value.leaf.data) { - ret = -ENOMEM; - goto out; + ret = CSR1212_ENOMEM; + goto fail; } kv->value.leaf.len = kvi_len; - memcpy(kv->value.leaf.data, kvi->data, size); + memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len)); } break; } kv->valid = 1; -out: + +fail: return ret; } -static int -csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) + +int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) { struct csr1212_cache_region *cr, *ncr, *newcr = NULL; struct csr1212_keyval_img *kvi = NULL; struct csr1212_csr_rom_cache *cache; int cache_index; - u64 addr; - u32 *cache_ptr; - u16 kv_len = 0; + u_int64_t addr; + u_int32_t *cache_ptr; + u_int16_t kv_len = 0; - BUG_ON(!csr || !kv || csr->max_rom < 1); + if (!csr || !kv || csr->max_rom < 1) + return CSR1212_EINVAL; /* First find which cache the data should be in (or go in if not read * yet). */ - for (cache = csr->cache_head; cache; cache = cache->next) + for (cache = csr->cache_head; cache; cache = cache->next) { if (kv->offset >= cache->offset && kv->offset < (cache->offset + cache->size)) break; + } if (!cache) { - u32 q, cache_size; + csr1212_quad_t q; + u_int32_t cache_size; /* Only create a new cache for Extended ROM leaves. */ if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) - return -EINVAL; + return CSR1212_EINVAL; if (csr->ops->bus_read(csr, CSR1212_REGISTER_SPACE_BASE + kv->offset, - sizeof(u32), &q, csr->private)) - return -EIO; + sizeof(csr1212_quad_t), &q, csr->private)) { + return CSR1212_EIO; + } - kv->value.leaf.len = be32_to_cpu(q) >> 16; + kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16; cache_size = (quads_to_bytes(kv->value.leaf.len + 1) + (csr->max_rom - 1)) & ~(csr->max_rom - 1); cache = csr1212_rom_cache_malloc(kv->offset, cache_size); if (!cache) - return -ENOMEM; + return CSR1212_ENOMEM; kv->value.leaf.data = &cache->data[1]; csr->cache_tail->next = cache; @@ -1293,11 +1465,12 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) csr->cache_tail = cache; cache->filled_head = CSR1212_MALLOC(sizeof(*cache->filled_head)); - if (!cache->filled_head) - return -ENOMEM; + if (!cache->filled_head) { + return CSR1212_ENOMEM; + } cache->filled_head->offset_start = 0; - cache->filled_head->offset_end = sizeof(u32); + cache->filled_head->offset_end = sizeof(csr1212_quad_t); cache->filled_tail = cache->filled_head; cache->filled_head->next = NULL; cache->filled_head->prev = NULL; @@ -1315,7 +1488,7 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) if (cache_index < cr->offset_start) { newcr = CSR1212_MALLOC(sizeof(*newcr)); if (!newcr) - return -ENOMEM; + return CSR1212_ENOMEM; newcr->offset_start = cache_index & ~(csr->max_rom - 1); newcr->offset_end = newcr->offset_start; @@ -1328,18 +1501,18 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) (cache_index < cr->offset_end)) { kvi = (struct csr1212_keyval_img*) (&cache->data[bytes_to_quads(cache_index)]); - kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1); + kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + + 1); break; - } else if (cache_index == cr->offset_end) { + } else if (cache_index == cr->offset_end) break; - } } if (!cr) { cr = cache->filled_tail; newcr = CSR1212_MALLOC(sizeof(*newcr)); if (!newcr) - return -ENOMEM; + return CSR1212_ENOMEM; newcr->offset_start = cache_index & ~(csr->max_rom - 1); newcr->offset_end = newcr->offset_start; @@ -1361,7 +1534,7 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) csr->private)) { if (csr->max_rom == 4) /* We've got problems! */ - return -EIO; + return CSR1212_EIO; /* Apperently the max_rom value was a lie, set it to * do quadlet reads and try again. */ @@ -1375,7 +1548,8 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) if (!kvi && (cr->offset_end > cache_index)) { kvi = (struct csr1212_keyval_img*) (&cache->data[bytes_to_quads(cache_index)]); - kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1); + kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + + 1); } if ((kv_len + (kv->offset - cache->offset)) > cache->size) { @@ -1383,7 +1557,7 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) * beyond the ConfigROM image region and thus beyond the * end of our cache region. Therefore, we abort now * rather than seg faulting later. */ - return -EIO; + return CSR1212_EIO; } ncr = cr->next; @@ -1405,16 +1579,7 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) return csr1212_parse_keyval(kv, cache); } -struct csr1212_keyval * -csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) -{ - if (!kv) - return NULL; - if (!kv->valid) - if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS) - return NULL; - return kv; -} + int csr1212_parse_csr(struct csr1212_csr *csr) { @@ -1422,19 +1587,20 @@ int csr1212_parse_csr(struct csr1212_csr *csr) struct csr1212_dentry *dentry; int ret; - BUG_ON(!csr || !csr->ops || !csr->ops->bus_read); + if (!csr || !csr->ops || !csr->ops->bus_read) + return CSR1212_EINVAL; ret = csr1212_parse_bus_info_block(csr); if (ret != CSR1212_SUCCESS) return ret; - if (!csr->ops->get_max_rom) { + if (!csr->ops->get_max_rom) csr->max_rom = mr_map[0]; /* default value */ - } else { + else { int i = csr->ops->get_max_rom(csr->bus_info_data, csr->private); if (i & ~0x3) - return -EINVAL; + return CSR1212_EINVAL; csr->max_rom = mr_map[i]; } @@ -1447,7 +1613,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr) csr->root_kv->valid = 0; csr->root_kv->next = csr->root_kv; csr->root_kv->prev = csr->root_kv; - ret = csr1212_read_keyval(csr, csr->root_kv); + ret = _csr1212_read_keyval(csr, csr->root_kv); if (ret != CSR1212_SUCCESS) return ret; @@ -1457,7 +1623,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr) dentry; dentry = dentry->next) { if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM && !dentry->kv->valid) { - ret = csr1212_read_keyval(csr, dentry->kv); + ret = _csr1212_read_keyval(csr, dentry->kv); if (ret != CSR1212_SUCCESS) return ret; } diff --git a/trunk/drivers/ieee1394/csr1212.h b/trunk/drivers/ieee1394/csr1212.h index df909ce66304..17ddd72dee4e 100644 --- a/trunk/drivers/ieee1394/csr1212.h +++ b/trunk/drivers/ieee1394/csr1212.h @@ -30,13 +30,94 @@ #ifndef __CSR1212_H__ #define __CSR1212_H__ + +/* Compatibility layer */ +#ifdef __KERNEL__ + #include #include +#include +#include +#include + +#define CSR1212_MALLOC(size) vmalloc((size)) +#define CSR1212_FREE(ptr) vfree(ptr) +#define CSR1212_BE16_TO_CPU(quad) be16_to_cpu(quad) +#define CSR1212_CPU_TO_BE16(quad) cpu_to_be16(quad) +#define CSR1212_BE32_TO_CPU(quad) be32_to_cpu(quad) +#define CSR1212_CPU_TO_BE32(quad) cpu_to_be32(quad) +#define CSR1212_BE64_TO_CPU(quad) be64_to_cpu(quad) +#define CSR1212_CPU_TO_BE64(quad) cpu_to_be64(quad) + +#define CSR1212_LE16_TO_CPU(quad) le16_to_cpu(quad) +#define CSR1212_CPU_TO_LE16(quad) cpu_to_le16(quad) +#define CSR1212_LE32_TO_CPU(quad) le32_to_cpu(quad) +#define CSR1212_CPU_TO_LE32(quad) cpu_to_le32(quad) +#define CSR1212_LE64_TO_CPU(quad) le64_to_cpu(quad) +#define CSR1212_CPU_TO_LE64(quad) cpu_to_le64(quad) + +#include +#define CSR1212_SUCCESS (0) +#define CSR1212_EINVAL (-EINVAL) +#define CSR1212_ENOMEM (-ENOMEM) +#define CSR1212_ENOENT (-ENOENT) +#define CSR1212_EIO (-EIO) +#define CSR1212_EBUSY (-EBUSY) + +#else /* Userspace */ + +#include +#include +#define CSR1212_MALLOC(size) malloc(size) +#define CSR1212_FREE(ptr) free(ptr) +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#include +#define CSR1212_BE16_TO_CPU(quad) bswap_16(quad) +#define CSR1212_CPU_TO_BE16(quad) bswap_16(quad) +#define CSR1212_BE32_TO_CPU(quad) bswap_32(quad) +#define CSR1212_CPU_TO_BE32(quad) bswap_32(quad) +#define CSR1212_BE64_TO_CPU(quad) bswap_64(quad) +#define CSR1212_CPU_TO_BE64(quad) bswap_64(quad) + +#define CSR1212_LE16_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE16(quad) (quad) +#define CSR1212_LE32_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE32(quad) (quad) +#define CSR1212_LE64_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE64(quad) (quad) +#else +#define CSR1212_BE16_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE16(quad) (quad) +#define CSR1212_BE32_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE32(quad) (quad) +#define CSR1212_BE64_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE64(quad) (quad) + +#define CSR1212_LE16_TO_CPU(quad) bswap_16(quad) +#define CSR1212_CPU_TO_LE16(quad) bswap_16(quad) +#define CSR1212_LE32_TO_CPU(quad) bswap_32(quad) +#define CSR1212_CPU_TO_LE32(quad) bswap_32(quad) +#define CSR1212_LE64_TO_CPU(quad) bswap_64(quad) +#define CSR1212_CPU_TO_LE64(quad) bswap_64(quad) +#endif + +#include +#define CSR1212_SUCCESS (0) +#define CSR1212_EINVAL (EINVAL) +#define CSR1212_ENOMEM (ENOMEM) +#define CSR1212_ENOENT (ENOENT) +#define CSR1212_EIO (EIO) +#define CSR1212_EBUSY (EBUSY) -#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL) -#define CSR1212_FREE(ptr) kfree(ptr) +#endif -#define CSR1212_SUCCESS (0) + +#define CSR1212_KV_VAL_MASK 0xffffff +#define CSR1212_KV_KEY_SHIFT 24 +#define CSR1212_KV_KEY_TYPE_SHIFT 6 +#define CSR1212_KV_KEY_ID_MASK 0x3f +#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* After shift */ /* CSR 1212 key types */ @@ -109,22 +190,48 @@ #define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE) #define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE) -#define CSR1212_INVALID_ADDR_SPACE -1 +#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t)) +#define CSR1212_INVALID_ADDR_SPACE -1 /* Config ROM image structures */ struct csr1212_bus_info_block_img { - u8 length; - u8 crc_length; - u16 crc; + u_int8_t length; + u_int8_t crc_length; + u_int16_t crc; /* Must be last */ - u32 data[0]; /* older gcc can't handle [] which is standard */ + u_int32_t data[0]; /* older gcc can't handle [] which is standard */ +}; + +#define CSR1212_KV_KEY(quad) (CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT) +#define CSR1212_KV_KEY_TYPE(quad) (CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT) +#define CSR1212_KV_KEY_ID(quad) (CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK) +#define CSR1212_KV_VAL(quad) (CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK) + +#define CSR1212_SET_KV_KEY(quad, key) ((quad) = \ + CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT))) +#define CSR1212_SET_KV_VAL(quad, val) ((quad) = \ + CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val))) +#define CSR1212_SET_KV_TYPEID(quad, type, id) ((quad) = \ + CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \ + (((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \ + ((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT))) + +typedef u_int32_t csr1212_quad_t; + + +struct csr1212_keyval_img { + u_int16_t length; + u_int16_t crc; + + /* Must be last */ + csr1212_quad_t data[0]; /* older gcc can't handle [] which is standard */ }; struct csr1212_leaf { int len; - u32 *data; + u_int32_t *data; }; struct csr1212_dentry { @@ -139,12 +246,12 @@ struct csr1212_directory { struct csr1212_keyval { struct { - u8 type; - u8 id; + u_int8_t type; + u_int8_t id; } key; union { - u32 immediate; - u32 csr_offset; + u_int32_t immediate; + u_int32_t csr_offset; struct csr1212_leaf leaf; struct csr1212_directory directory; } value; @@ -153,15 +260,15 @@ struct csr1212_keyval { /* used in generating and/or parsing CSR image */ struct csr1212_keyval *next, *prev; /* flat list of CSR elements */ - u32 offset; /* position in CSR from 0xffff f000 0000 */ - u8 valid; /* flag indicating keyval has valid data*/ + u_int32_t offset; /* position in CSR from 0xffff f000 0000 */ + u_int8_t valid; /* flag indicating keyval has valid data*/ }; struct csr1212_cache_region { struct csr1212_cache_region *next, *prev; - u32 offset_start; /* inclusive */ - u32 offset_end; /* exclusive */ + u_int32_t offset_start; /* inclusive */ + u_int32_t offset_end; /* exclusive */ }; struct csr1212_csr_rom_cache { @@ -169,18 +276,18 @@ struct csr1212_csr_rom_cache { struct csr1212_cache_region *filled_head, *filled_tail; struct csr1212_keyval *layout_head, *layout_tail; size_t size; - u32 offset; + u_int32_t offset; struct csr1212_keyval *ext_rom; size_t len; /* Must be last */ - u32 data[0]; /* older gcc can't handle [] which is standard */ + u_int32_t data[0]; /* older gcc can't handle [] which is standard */ }; struct csr1212_csr { size_t bus_info_len; /* bus info block length in bytes */ size_t crc_len; /* crc length in bytes */ - u32 *bus_info_data; /* bus info data incl bus name and EUI */ + u_int32_t *bus_info_data; /* bus info data incl bus name and EUI */ void *private; /* private, bus specific data */ struct csr1212_bus_ops *ops; @@ -198,38 +305,52 @@ struct csr1212_bus_ops { * from remote nodes when parsing a Config ROM (i.e., read Config ROM * entries located in the Units Space. Must return 0 on success * anything else indicates an error. */ - int (*bus_read) (struct csr1212_csr *csr, u64 addr, - u16 length, void *buffer, void *private); + int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr, + u_int16_t length, void *buffer, void *private); /* This function is used by csr1212 to allocate a region in units space * in the event that Config ROM entries don't all fit in the predefined * 1K region. The void *private parameter is private member of struct * csr1212_csr. */ - u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private); + u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment, + void *private); + /* This function is used by csr1212 to release a region in units space * that is no longer needed. */ - void (*release_addr) (u64 addr, void *private); + void (*release_addr) (u_int64_t addr, void *private); /* This function is used by csr1212 to determine the max read request * supported by a remote node when reading the ConfigROM space. Must * return 0, 1, or 2 per IEEE 1212. */ - int (*get_max_rom) (u32 *bus_info, void *private); + int (*get_max_rom) (u_int32_t *bus_info, void *private); }; + + /* Descriptor Leaf manipulation macros */ #define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24 #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff -#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32)) +#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) #define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \ - (be32_to_cpu((kv)->value.leaf.data[0]) >> \ - CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \ - (be32_to_cpu((kv)->value.leaf.data[0]) & \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \ CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK) - +#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ + (&((kv)->value.leaf.data[1])) + +#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \ + ((kv)->value.leaf.data[0] = \ + CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \ + ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT))) +#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \ + ((kv)->value.leaf.data[0] = \ + CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \ + CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \ + ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK))) /* Text Descriptor Leaf manipulation macros */ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28 @@ -237,21 +358,182 @@ struct csr1212_bus_ops { #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff -#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32)) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \ - (be32_to_cpu((kv)->value.leaf.data[1]) >> \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT) #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \ - ((be32_to_cpu((kv)->value.leaf.data[1]) >> \ - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \ - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \ - (be32_to_cpu((kv)->value.leaf.data[1]) & \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK) #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \ (&((kv)->value.leaf.data[2])) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((width) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((char_set) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT)) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \ + CSR1212_CPU_TO_BE32(((language) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) + + +/* Icon Descriptor Leaf manipulation macros */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30 +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3 /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16 +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16 +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \ + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \ + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \ + (&((kv)->value.leaf.data[5])) + +static inline u_int32_t *CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(struct csr1212_keyval *kv) +{ + static const int pd[4] = { 0, 4, 16, 256 }; + static const int cs[16] = { 4, 2 }; + int ps = pd[CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv)]; + + return &kv->value.leaf.data[5 + + (ps * cs[CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv)]) / + sizeof(u_int32_t)]; +} + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \ + ((kv)->value.leaf.data[2] = \ + ((kv)->value.leaf.data[2] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \ + CSR1212_CPU_TO_BE32(((version) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((palette_depth) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((color_space) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \ + CSR1212_CPU_TO_BE32(((language) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \ + ((kv)->value.leaf.data[4] = \ + ((kv)->value.leaf.data[4] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((hscan) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \ + ((kv)->value.leaf.data[4] = \ + (((kv)->value.leaf.data[4] & \ + CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \ + CSR1212_CPU_TO_BE32(((vscan) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) + + +/* Modifiable Descriptor Leaf manipulation macros */ +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16 +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32 +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL + +#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \ + CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \ + (CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \ + CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \ + CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1])) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \ + ((kv)->value.leaf.data[0] = \ + ((kv)->value.leaf.data[0] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((size) & \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT)) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \ + ((kv)->value.leaf.data[0] = \ + ((kv)->value.leaf.data[0] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \ + CSR1212_CPU_TO_BE32(((addr) & \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \ + ((kv)->value.leaf.data[1] = \ + CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK)) + + /* The following 2 function are for creating new Configuration ROM trees. The * first function is used for both creating local trees and parsing remote @@ -261,10 +543,11 @@ extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, size_t bus_info_size, void *private); extern void csr1212_init_local_csr(struct csr1212_csr *csr, - const u32 *bus_info_data, int max_rom); + const u_int32_t *bus_info_data, int max_rom); -/* Destroy a Configuration ROM tree and release all memory taken by the tree. */ +/* The following function destroys a Configuration ROM tree and release all + * memory taken by the tree. */ extern void csr1212_destroy_csr(struct csr1212_csr *csr); @@ -272,20 +555,50 @@ extern void csr1212_destroy_csr(struct csr1212_csr *csr); * a Configuration ROM tree. Code that creates new keyvals with these functions * must release those keyvals with csr1212_release_keyval() when they are no * longer needed. */ -extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value); -extern struct csr1212_keyval *csr1212_new_directory(u8 key); +extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value); +extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, + u_int32_t csr_offset); +extern struct csr1212_keyval *csr1212_new_directory(u_int8_t key); +extern struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, + u_int32_t key, + u_int32_t value); +extern struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, + u_int32_t key, + const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, + u_int32_t specifier_id, + const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth, + u_int16_t cset, + u_int16_t language, + const void *data, + size_t data_len); extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s); - - -/* The following function manages association between keyvals. Typically, +extern struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version, + u_int8_t palette_depth, + u_int8_t color_space, + u_int16_t language, + u_int16_t hscan, + u_int16_t vscan, + u_int32_t *palette, + u_int32_t *pixels); +extern struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size, + u_int64_t address); +extern struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, + const char *strv[]); + + +/* The following functions manage association between keyvals. Typically, * Descriptor Leaves and Directories will be associated with another keyval and * it is desirable for the Descriptor keyval to be place immediately after the - * keyval that it is associated with. - * Take care with subsequent ROM modifications: There is no function to remove - * previously specified associations. - */ -extern void csr1212_associate_keyval(struct csr1212_keyval *kv, - struct csr1212_keyval *associate); + * keyval that it is associated with.*/ +extern int csr1212_associate_keyval(struct csr1212_keyval *kv, + struct csr1212_keyval *associate); +extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv); /* The following functions manage the association of a keyval and directories. @@ -296,15 +609,23 @@ extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, struct csr1212_keyval *kv); -/* Creates a complete Configuration ROM image in the list of caches available - * via csr->cache_head. */ +/* The following functions create a Configuration ROM image from the tree of + * keyvals provided. csr1212_generate_csr_image() creates a complete image in + * the list of caches available via csr->cache_head. The other functions are + * provided should there be a need to create a flat image without restrictions + * placed by IEEE 1212. */ +extern struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, + struct csr1212_keyval *start_kv, + int start_pos); +extern size_t csr1212_generate_layout_order(struct csr1212_keyval *kv); +extern void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache); extern int csr1212_generate_csr_image(struct csr1212_csr *csr); /* This is a convience function for reading a block of data out of one of the * caches in the csr->cache_head list. */ -extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, - u32 len); +extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, + u_int32_t len); /* The following functions are in place for parsing Configuration ROM images. @@ -314,11 +635,15 @@ extern int csr1212_parse_keyval(struct csr1212_keyval *kv, struct csr1212_csr_rom_cache *cache); extern int csr1212_parse_csr(struct csr1212_csr *csr); +/* These are internal functions referenced by inline functions below. */ +extern int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv); +extern void _csr1212_destroy_keyval(struct csr1212_keyval *kv); + /* This function allocates a new cache which may be used for either parsing or * generating sub-sets of Configuration ROM images. */ -static inline struct csr1212_csr_rom_cache * -csr1212_rom_cache_malloc(u32 offset, size_t size) +static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset, + size_t size) { struct csr1212_csr_rom_cache *cache; @@ -342,8 +667,16 @@ csr1212_rom_cache_malloc(u32 offset, size_t size) /* This function ensures that a keyval contains data when referencing a keyval * created by parsing a Configuration ROM. */ -extern struct csr1212_keyval * -csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv); +static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr, + struct csr1212_keyval *kv) +{ + if (!kv) + return NULL; + if (!kv->valid) + if (_csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS) + return NULL; + return kv; +} /* This function increments the reference count for a keyval should there be a @@ -358,29 +691,37 @@ static inline void csr1212_keep_keyval(struct csr1212_keyval *kv) * keyval when there are no more users of the keyval. This should be called by * any code that calls csr1212_keep_keyval() or any of the keyval creation * routines csr1212_new_*(). */ -extern void csr1212_release_keyval(struct csr1212_keyval *kv); +static inline void csr1212_release_keyval(struct csr1212_keyval *kv) +{ + if (kv->refcnt > 1) + kv->refcnt--; + else + _csr1212_destroy_keyval(kv); +} /* * This macro allows for looping over the keyval entries in a directory and it * ensures that keyvals from remote ConfigROMs are parsed properly. * - * struct csr1212_csr *_csr points to the CSR associated with dir. - * struct csr1212_keyval *_kv points to the current keyval (loop index). - * struct csr1212_keyval *_dir points to the directory to be looped. - * struct csr1212_dentry *_pos is used internally for indexing. + * _csr is a struct csr1212_csr * that points to CSR associated with dir. + * _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index). + * _dir is a struct csr1212_keyval * that points to the directory to be looped. + * _pos is a struct csr1212_dentry * that is used internally for indexing. * * kv will be NULL upon exit of the loop. */ -#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \ - for (csr1212_get_keyval((_csr), (_dir)), \ - _pos = (_dir)->value.directory.dentries_head, \ - _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\ - (_kv) && (_pos); \ - (_kv->associate == NULL) ? \ - ((_pos = _pos->next), (_kv = (_pos) ? \ - csr1212_get_keyval((_csr), _pos->kv) : \ - NULL)) : \ +#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \ + for (csr1212_get_keyval((_csr), (_dir)), \ + _pos = (_dir)->value.directory.dentries_head, \ + _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL; \ + (_kv) && (_pos); \ + (_kv->associate == NULL) ? \ + ((_pos = _pos->next), \ + (_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : \ + NULL)) : \ (_kv = csr1212_get_keyval((_csr), _kv->associate))) + + #endif /* __CSR1212_H__ */ diff --git a/trunk/drivers/ieee1394/dma.c b/trunk/drivers/ieee1394/dma.c index 45d605581922..c68f328e1a29 100644 --- a/trunk/drivers/ieee1394/dma.c +++ b/trunk/drivers/ieee1394/dma.c @@ -62,9 +62,6 @@ void dma_prog_region_free(struct dma_prog_region *prog) /* dma_region */ -/** - * dma_region_init - clear out all fields but do not allocate anything - */ void dma_region_init(struct dma_region *dma) { dma->kvirt = NULL; @@ -74,9 +71,6 @@ void dma_region_init(struct dma_region *dma) dma->sglist = NULL; } -/** - * dma_region_alloc - allocate the buffer and map it to the IOMMU - */ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction) { @@ -134,9 +128,6 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, return -ENOMEM; } -/** - * dma_region_free - unmap and free the buffer - */ void dma_region_free(struct dma_region *dma) { if (dma->n_dma_pages) { @@ -176,12 +167,6 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset, return i; } -/** - * dma_region_offset_to_bus - get bus address of an offset within a DMA region - * - * Returns the DMA bus address of the byte with the given @offset relative to - * the beginning of the @dma. - */ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma, unsigned long offset) { @@ -192,9 +177,6 @@ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma, return sg_dma_address(sg) + rem; } -/** - * dma_region_sync_for_cpu - sync the CPU's view of the buffer - */ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len) { @@ -211,9 +193,6 @@ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, dma->direction); } -/** - * dma_region_sync_for_device - sync the IO bus' view of the buffer - */ void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len) { @@ -265,9 +244,6 @@ static struct vm_operations_struct dma_region_vm_ops = { .nopage = dma_region_pagefault, }; -/** - * dma_region_mmap - map the buffer into a user space process - */ int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) { diff --git a/trunk/drivers/ieee1394/dma.h b/trunk/drivers/ieee1394/dma.h index 2727bcd24194..a1682aba71c7 100644 --- a/trunk/drivers/ieee1394/dma.h +++ b/trunk/drivers/ieee1394/dma.h @@ -66,23 +66,35 @@ struct dma_region { int direction; }; +/* clear out all fields but do not allocate anything */ void dma_region_init(struct dma_region *dma); + +/* allocate the buffer and map it to the IOMMU */ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction); + +/* unmap and free the buffer */ void dma_region_free(struct dma_region *dma); + +/* sync the CPU's view of the buffer */ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len); + +/* sync the IO bus' view of the buffer */ void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len); + +/* map the buffer into a user space process */ int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); -dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, - unsigned long offset); -/** - * dma_region_i - macro to index into a DMA region (or dma_prog_region) - */ +/* macro to index into a DMA region (or dma_prog_region) */ #define dma_region_i(_dma, _type, _index) \ ( ((_type*) ((_dma)->kvirt)) + (_index) ) +/* return the DMA bus address of the byte with the given offset + * relative to the beginning of the dma_region */ +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, + unsigned long offset); + #endif /* IEEE1394_DMA_H */ diff --git a/trunk/drivers/ieee1394/eth1394.c b/trunk/drivers/ieee1394/eth1394.c index 2296d43a2414..03e44b337eb0 100644 --- a/trunk/drivers/ieee1394/eth1394.c +++ b/trunk/drivers/ieee1394/eth1394.c @@ -1,5 +1,5 @@ /* - * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem + * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem * * Copyright (C) 2001-2003 Ben Collins * 2000 Bonin Franck @@ -22,9 +22,10 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - * This driver intends to support RFC 2734, which describes a method for - * transporting IPv4 datagrams over IEEE-1394 serial busses. +/* This driver intends to support RFC 2734, which describes a method for + * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver + * will ultimately support that method, but currently falls short in + * several areas. * * TODO: * RFC 2734 related: @@ -39,6 +40,7 @@ * - Consider garbage collecting old partial datagrams after X amount of time */ + #include #include @@ -50,6 +52,7 @@ #include #include +#include #include #include #include @@ -81,6 +84,10 @@ #define ETH1394_PRINT(level, dev_name, fmt, args...) \ printk(level "%s: %s: " fmt, driver_name, dev_name, ## args) +#define DEBUG(fmt, args...) \ + printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args) +#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) + struct fragment_info { struct list_head list; int offset; @@ -98,9 +105,9 @@ struct partial_datagram { }; struct pdg_list { - struct list_head list; /* partial datagram list per node */ - unsigned int sz; /* partial datagram list size per node */ - spinlock_t lock; /* partial datagram lock */ + struct list_head list; /* partial datagram list per node */ + unsigned int sz; /* partial datagram list size per node */ + spinlock_t lock; /* partial datagram lock */ }; struct eth1394_host_info { @@ -114,14 +121,16 @@ struct eth1394_node_ref { }; struct eth1394_node_info { - u16 maxpayload; /* max payload */ - u8 sspd; /* max speed */ - u64 fifo; /* FIFO address */ - struct pdg_list pdg; /* partial RX datagram lists */ - int dgl; /* outgoing datagram label */ + u16 maxpayload; /* Max payload */ + u8 sspd; /* Max speed */ + u64 fifo; /* FIFO address */ + struct pdg_list pdg; /* partial RX datagram lists */ + int dgl; /* Outgoing datagram label */ }; -static const char driver_name[] = "eth1394"; +/* Our ieee1394 highlevel driver */ +#define ETH1394_DRIVER_NAME "eth1394" +static const char driver_name[] = ETH1394_DRIVER_NAME; static struct kmem_cache *packet_task_cache; @@ -129,12 +138,18 @@ static struct hpsb_highlevel eth1394_highlevel; /* Use common.lf to determine header len */ static const int hdr_type_len[] = { - sizeof(struct eth1394_uf_hdr), - sizeof(struct eth1394_ff_hdr), - sizeof(struct eth1394_sf_hdr), - sizeof(struct eth1394_sf_hdr) + sizeof (struct eth1394_uf_hdr), + sizeof (struct eth1394_ff_hdr), + sizeof (struct eth1394_sf_hdr), + sizeof (struct eth1394_sf_hdr) }; +/* Change this to IEEE1394_SPEED_S100 to make testing easier */ +#define ETH1394_SPEED_DEF IEEE1394_SPEED_MAX + +/* For now, this needs to be 1500, so that XP works with us */ +#define ETH1394_DATA_LEN ETH_DATA_LEN + static const u16 eth1394_speedto_maxpayload[] = { /* S100, S200, S400, S800, S1600, S3200 */ 512, 1024, 2048, 4096, 4096, 4096 @@ -144,8 +159,7 @@ MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_LICENSE("GPL"); -/* - * The max_partial_datagrams parameter is the maximum number of fragmented +/* The max_partial_datagrams parameter is the maximum number of fragmented * datagrams per node that eth1394 will keep in memory. Providing an upper * bound allows us to limit the amount of memory that partial datagrams * consume in the event that some partial datagrams are never completed. @@ -165,7 +179,10 @@ static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char *haddr); + unsigned char * haddr); +static int ether1394_mac_addr(struct net_device *dev, void *p); + +static void purge_partial_datagram(struct list_head *old); static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); @@ -173,9 +190,9 @@ static struct ethtool_ops ethtool_ops; static int ether1394_write(struct hpsb_host *host, int srcid, int destid, quadlet_t *data, u64 addr, size_t len, u16 flags); -static void ether1394_add_host(struct hpsb_host *host); -static void ether1394_remove_host(struct hpsb_host *host); -static void ether1394_host_reset(struct hpsb_host *host); +static void ether1394_add_host (struct hpsb_host *host); +static void ether1394_remove_host (struct hpsb_host *host); +static void ether1394_host_reset (struct hpsb_host *host); /* Function for incoming 1394 packets */ static struct hpsb_address_ops addr_ops = { @@ -190,107 +207,89 @@ static struct hpsb_highlevel eth1394_highlevel = { .host_reset = ether1394_host_reset, }; -static int ether1394_recv_init(struct eth1394_priv *priv) -{ - unsigned int iso_buf_size; - - /* FIXME: rawiso limits us to PAGE_SIZE */ - iso_buf_size = min((unsigned int)PAGE_SIZE, - 2 * (1U << (priv->host->csr.max_rec + 1))); - - priv->iso = hpsb_iso_recv_init(priv->host, - ETHER1394_GASP_BUFFERS * iso_buf_size, - ETHER1394_GASP_BUFFERS, - priv->broadcast_channel, - HPSB_ISO_DMA_PACKET_PER_BUFFER, - 1, ether1394_iso); - if (priv->iso == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n"); - priv->bc_state = ETHER1394_BC_ERROR; - return -EAGAIN; - } - - if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) - priv->bc_state = ETHER1394_BC_STOPPED; - else - priv->bc_state = ETHER1394_BC_RUNNING; - return 0; -} /* This is called after an "ifup" */ -static int ether1394_open(struct net_device *dev) +static int ether1394_open (struct net_device *dev) { struct eth1394_priv *priv = netdev_priv(dev); - int ret; + int ret = 0; + /* Something bad happened, don't even try */ if (priv->bc_state == ETHER1394_BC_ERROR) { - ret = ether1394_recv_init(priv); - if (ret) - return ret; + /* we'll try again */ + priv->iso = hpsb_iso_recv_init(priv->host, + ETHER1394_ISO_BUF_SIZE, + ETHER1394_GASP_BUFFERS, + priv->broadcast_channel, + HPSB_ISO_DMA_PACKET_PER_BUFFER, + 1, ether1394_iso); + if (priv->iso == NULL) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not allocate isochronous receive " + "context for the broadcast channel\n"); + priv->bc_state = ETHER1394_BC_ERROR; + ret = -EAGAIN; + } else { + if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) + priv->bc_state = ETHER1394_BC_STOPPED; + else + priv->bc_state = ETHER1394_BC_RUNNING; + } } - netif_start_queue(dev); + + if (ret) + return ret; + + netif_start_queue (dev); return 0; } /* This is called after an "ifdown" */ -static int ether1394_stop(struct net_device *dev) +static int ether1394_stop (struct net_device *dev) { - netif_stop_queue(dev); + netif_stop_queue (dev); return 0; } /* Return statistics to the caller */ -static struct net_device_stats *ether1394_stats(struct net_device *dev) +static struct net_device_stats *ether1394_stats (struct net_device *dev) { return &(((struct eth1394_priv *)netdev_priv(dev))->stats); } -/* FIXME: What to do if we timeout? I think a host reset is probably in order, - * so that's what we do. Should we increment the stat counters too? */ -static void ether1394_tx_timeout(struct net_device *dev) +/* What to do if we timeout. I think a host reset is probably in order, so + * that's what we do. Should we increment the stat counters too? */ +static void ether1394_tx_timeout (struct net_device *dev) { - struct hpsb_host *host = - ((struct eth1394_priv *)netdev_priv(dev))->host; + ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", + ((struct eth1394_priv *)netdev_priv(dev))->host->driver->name); - ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n"); - ether1394_host_reset(host); -} + highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host); -static inline int ether1394_max_mtu(struct hpsb_host* host) -{ - return (1 << (host->csr.max_rec + 1)) - - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD; + netif_wake_queue (dev); } static int ether1394_change_mtu(struct net_device *dev, int new_mtu) { - int max_mtu; + struct eth1394_priv *priv = netdev_priv(dev); - if (new_mtu < 68) + if ((new_mtu < 68) || + (new_mtu > min(ETH1394_DATA_LEN, + (int)((1 << (priv->host->csr.max_rec + 1)) - + (sizeof(union eth1394_hdr) + + ETHER1394_GASP_OVERHEAD))))) return -EINVAL; - - max_mtu = ether1394_max_mtu( - ((struct eth1394_priv *)netdev_priv(dev))->host); - if (new_mtu > max_mtu) { - ETH1394_PRINT(KERN_INFO, dev->name, - "Local node constrains MTU to %d\n", max_mtu); - return -ERANGE; - } - dev->mtu = new_mtu; return 0; } static void purge_partial_datagram(struct list_head *old) { - struct partial_datagram *pd; + struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); struct list_head *lh, *n; - struct fragment_info *fi; - - pd = list_entry(old, struct partial_datagram, list); list_for_each_safe(lh, n, &pd->frag_info) { - fi = list_entry(lh, struct fragment_info, list); + struct fragment_info *fi = list_entry(lh, struct fragment_info, list); list_del(lh); kfree(fi); } @@ -331,26 +330,35 @@ static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl, nodeid_t nodeid) { struct eth1394_node_ref *node; - - list_for_each_entry(node, inl, list) + list_for_each_entry(node, inl, list) { if (node->ud->ne->nodeid == nodeid) return node; + } return NULL; } -static int eth1394_new_node(struct eth1394_host_info *hi, - struct unit_directory *ud) +static int eth1394_probe(struct device *dev) { + struct unit_directory *ud; + struct eth1394_host_info *hi; struct eth1394_priv *priv; struct eth1394_node_ref *new_node; struct eth1394_node_info *node_info; - new_node = kmalloc(sizeof(*new_node), GFP_KERNEL); + ud = container_of(dev, struct unit_directory, device); + + hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); + if (!hi) + return -ENOENT; + + new_node = kmalloc(sizeof(*new_node), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!new_node) return -ENOMEM; - node_info = kmalloc(sizeof(*node_info), GFP_KERNEL); + node_info = kmalloc(sizeof(*node_info), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!node_info) { kfree(new_node); return -ENOMEM; @@ -366,20 +374,8 @@ static int eth1394_new_node(struct eth1394_host_info *hi, priv = netdev_priv(hi->dev); list_add_tail(&new_node->list, &priv->ip_node_list); - return 0; -} - -static int eth1394_probe(struct device *dev) -{ - struct unit_directory *ud; - struct eth1394_host_info *hi; - - ud = container_of(dev, struct unit_directory, device); - hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); - if (!hi) - return -ENOENT; - return eth1394_new_node(hi, ud); + return 0; } static int eth1394_remove(struct device *dev) @@ -400,23 +396,24 @@ static int eth1394_remove(struct device *dev) priv = netdev_priv(hi->dev); old_node = eth1394_find_node(&priv->ip_node_list, ud); - if (!old_node) - return 0; - list_del(&old_node->list); - kfree(old_node); + if (old_node) { + list_del(&old_node->list); + kfree(old_node); - node_info = (struct eth1394_node_info*)ud->device.driver_data; + node_info = (struct eth1394_node_info*)ud->device.driver_data; - spin_lock_irqsave(&node_info->pdg.lock, flags); - /* The partial datagram list should be empty, but we'll just - * make sure anyway... */ - list_for_each_safe(lh, n, &node_info->pdg.list) - purge_partial_datagram(lh); - spin_unlock_irqrestore(&node_info->pdg.lock, flags); + spin_lock_irqsave(&node_info->pdg.lock, flags); + /* The partial datagram list should be empty, but we'll just + * make sure anyway... */ + list_for_each_safe(lh, n, &node_info->pdg.list) { + purge_partial_datagram(lh); + } + spin_unlock_irqrestore(&node_info->pdg.lock, flags); - kfree(node_info); - ud->device.driver_data = NULL; + kfree(node_info); + ud->device.driver_data = NULL; + } return 0; } @@ -425,19 +422,44 @@ static int eth1394_update(struct unit_directory *ud) struct eth1394_host_info *hi; struct eth1394_priv *priv; struct eth1394_node_ref *node; + struct eth1394_node_info *node_info; hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); if (!hi) return -ENOENT; priv = netdev_priv(hi->dev); + node = eth1394_find_node(&priv->ip_node_list, ud); - if (node) - return 0; - return eth1394_new_node(hi, ud); + if (!node) { + node = kmalloc(sizeof(*node), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!node) + return -ENOMEM; + + node_info = kmalloc(sizeof(*node_info), + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!node_info) { + kfree(node); + return -ENOMEM; + } + + spin_lock_init(&node_info->pdg.lock); + INIT_LIST_HEAD(&node_info->pdg.list); + node_info->pdg.sz = 0; + + ud->device.driver_data = node_info; + node->ud = ud; + + priv = netdev_priv(hi->dev); + list_add_tail(&node->list, &priv->ip_node_list); + } + + return 0; } + static struct ieee1394_device_id eth1394_id_table[] = { { .match_flags = (IEEE1394_MATCH_SPECIFIER_ID | @@ -451,7 +473,7 @@ static struct ieee1394_device_id eth1394_id_table[] = { MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table); static struct hpsb_protocol_driver eth1394_proto_driver = { - .name = driver_name, + .name = ETH1394_DRIVER_NAME, .id_table = eth1394_id_table, .update = eth1394_update, .driver = { @@ -460,50 +482,47 @@ static struct hpsb_protocol_driver eth1394_proto_driver = { }, }; -static void ether1394_reset_priv(struct net_device *dev, int set_mtu) + +static void ether1394_reset_priv (struct net_device *dev, int set_mtu) { unsigned long flags; int i; struct eth1394_priv *priv = netdev_priv(dev); struct hpsb_host *host = priv->host; - u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3])); + u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3])); + u16 maxpayload = 1 << (host->csr.max_rec + 1); int max_speed = IEEE1394_SPEED_MAX; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave (&priv->lock, flags); - memset(priv->ud_list, 0, sizeof(priv->ud_list)); + memset(priv->ud_list, 0, sizeof(struct node_entry*) * ALL_NODES); priv->bc_maxpayload = 512; /* Determine speed limit */ - /* FIXME: This is broken for nodes with link speed < PHY speed, - * and it is suboptimal for S200B...S800B hardware. - * The result of nodemgr's speed probe should be used somehow. */ - for (i = 0; i < host->node_count; i++) { - /* take care of S100B...S400B PHY ports */ - if (host->speed[i] == SELFID_SPEED_UNKNOWN) { - max_speed = IEEE1394_SPEED_100; - break; - } + for (i = 0; i < host->node_count; i++) if (max_speed > host->speed[i]) max_speed = host->speed[i]; - } priv->bc_sspd = max_speed; + /* We'll use our maxpayload as the default mtu */ if (set_mtu) { - /* Use the RFC 2734 default 1500 octets or the maximum payload - * as initial MTU */ - dev->mtu = min(1500, ether1394_max_mtu(host)); + dev->mtu = min(ETH1394_DATA_LEN, + (int)(maxpayload - + (sizeof(union eth1394_hdr) + + ETHER1394_GASP_OVERHEAD))); /* Set our hardware address while we're at it */ memcpy(dev->dev_addr, &guid, sizeof(u64)); memset(dev->broadcast, 0xff, sizeof(u64)); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore (&priv->lock, flags); } -static void ether1394_init_dev(struct net_device *dev) +/* This function is called right before register_netdev */ +static void ether1394_init_dev (struct net_device *dev) { + /* Our functions */ dev->open = ether1394_open; dev->stop = ether1394_stop; dev->hard_start_xmit = ether1394_tx; @@ -516,9 +535,10 @@ static void ether1394_init_dev(struct net_device *dev) dev->hard_header_cache = ether1394_header_cache; dev->header_cache_update= ether1394_header_cache_update; dev->hard_header_parse = ether1394_header_parse; - + dev->set_mac_address = ether1394_mac_addr; SET_ETHTOOL_OPS(dev, ðtool_ops); + /* Some constants */ dev->watchdog_timeo = ETHER1394_TIMEOUT; dev->flags = IFF_BROADCAST | IFF_MULTICAST; dev->features = NETIF_F_HIGHDMA; @@ -526,8 +546,7 @@ static void ether1394_init_dev(struct net_device *dev) dev->hard_header_len = ETH1394_HLEN; dev->type = ARPHRD_IEEE1394; - /* FIXME: This value was copied from ether_setup(). Is it too much? */ - dev->tx_queue_len = 1000; + ether1394_reset_priv (dev, 1); } /* @@ -535,33 +554,34 @@ static void ether1394_init_dev(struct net_device *dev) * when the module is installed. This is where we add all of our ethernet * devices. One for each host. */ -static void ether1394_add_host(struct hpsb_host *host) +static void ether1394_add_host (struct hpsb_host *host) { struct eth1394_host_info *hi = NULL; struct net_device *dev = NULL; struct eth1394_priv *priv; u64 fifo_addr; - if (hpsb_config_rom_ip1394_add(host) != 0) { - ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n"); + if (!(host->config_roms & HPSB_CONFIG_ROM_ENTRY_IP1394)) return; - } fifo_addr = hpsb_allocate_and_register_addrspace( ð1394_highlevel, host, &addr_ops, ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN, CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE); - if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) { - ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n"); - hpsb_config_rom_ip1394_remove(host); - return; - } + if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) + goto out; + + /* We should really have our own alloc_hpsbdev() function in + * net_init.c instead of calling the one for ethernet then hijacking + * it for ourselves. That way we'd be a real networking device. */ + dev = alloc_etherdev(sizeof (struct eth1394_priv)); - dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev); if (dev == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); + ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate " + "etherdevice for IEEE 1394 device %s-%d\n", + host->driver->name, host->id); goto out; - } + } SET_MODULE_OWNER(dev); #if 0 @@ -570,26 +590,31 @@ static void ether1394_add_host(struct hpsb_host *host) #endif priv = netdev_priv(dev); + INIT_LIST_HEAD(&priv->ip_node_list); + spin_lock_init(&priv->lock); priv->host = host; priv->local_fifo = fifo_addr; hi = hpsb_create_hostinfo(ð1394_highlevel, host, sizeof(*hi)); + if (hi == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); + ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create " + "hostinfo for IEEE 1394 device %s-%d\n", + host->driver->name, host->id); goto out; - } + } - ether1394_reset_priv(dev, 1); + ether1394_init_dev(dev); - if (register_netdev(dev)) { - ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n"); + if (register_netdev (dev)) { + ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); goto out; } - ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n", - host->id); + ETH1394_PRINT (KERN_INFO, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n", + host->id); hi->host = host; hi->dev = dev; @@ -598,37 +623,61 @@ static void ether1394_add_host(struct hpsb_host *host) * be checked when the eth device is opened. */ priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; - ether1394_recv_init(priv); + priv->iso = hpsb_iso_recv_init(host, + ETHER1394_ISO_BUF_SIZE, + ETHER1394_GASP_BUFFERS, + priv->broadcast_channel, + HPSB_ISO_DMA_PACKET_PER_BUFFER, + 1, ether1394_iso); + if (priv->iso == NULL) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not allocate isochronous receive context " + "for the broadcast channel\n"); + priv->bc_state = ETHER1394_BC_ERROR; + } else { + if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) + priv->bc_state = ETHER1394_BC_STOPPED; + else + priv->bc_state = ETHER1394_BC_RUNNING; + } + return; + out: - if (dev) + if (dev != NULL) free_netdev(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); - hpsb_unregister_addrspace(ð1394_highlevel, host, fifo_addr); - hpsb_config_rom_ip1394_remove(host); + + return; } /* Remove a card from our list */ -static void ether1394_remove_host(struct hpsb_host *host) +static void ether1394_remove_host (struct hpsb_host *host) { struct eth1394_host_info *hi; - struct eth1394_priv *priv; hi = hpsb_get_hostinfo(ð1394_highlevel, host); - if (!hi) - return; - priv = netdev_priv(hi->dev); - hpsb_unregister_addrspace(ð1394_highlevel, host, priv->local_fifo); - hpsb_config_rom_ip1394_remove(host); - if (priv->iso) - hpsb_iso_shutdown(priv->iso); - unregister_netdev(hi->dev); - free_netdev(hi->dev); + if (hi != NULL) { + struct eth1394_priv *priv = netdev_priv(hi->dev); + + hpsb_unregister_addrspace(ð1394_highlevel, host, + priv->local_fifo); + + if (priv->iso != NULL) + hpsb_iso_shutdown(priv->iso); + + if (hi->dev) { + unregister_netdev (hi->dev); + free_netdev(hi->dev); + } + } + + return; } -/* A bus reset happened */ -static void ether1394_host_reset(struct hpsb_host *host) +/* A reset has just arisen */ +static void ether1394_host_reset (struct hpsb_host *host) { struct eth1394_host_info *hi; struct eth1394_priv *priv; @@ -641,23 +690,24 @@ static void ether1394_host_reset(struct hpsb_host *host) hi = hpsb_get_hostinfo(ð1394_highlevel, host); /* This can happen for hosts that we don't use */ - if (!hi) + if (hi == NULL) return; dev = hi->dev; - priv = netdev_priv(dev); + priv = (struct eth1394_priv *)netdev_priv(dev); - /* Reset our private host data, but not our MTU */ - netif_stop_queue(dev); - ether1394_reset_priv(dev, 0); + /* Reset our private host data, but not our mtu */ + netif_stop_queue (dev); + ether1394_reset_priv (dev, 0); list_for_each_entry(node, &priv->ip_node_list, list) { - node_info = node->ud->device.driver_data; + node_info = (struct eth1394_node_info*)node->ud->device.driver_data; spin_lock_irqsave(&node_info->pdg.lock, flags); - list_for_each_safe(lh, n, &node_info->pdg.list) + list_for_each_safe(lh, n, &node_info->pdg.list) { purge_partial_datagram(lh); + } INIT_LIST_HEAD(&(node_info->pdg.list)); node_info->pdg.sz = 0; @@ -665,7 +715,7 @@ static void ether1394_host_reset(struct hpsb_host *host) spin_unlock_irqrestore(&node_info->pdg.lock, flags); } - netif_wake_queue(dev); + netif_wake_queue (dev); } /****************************************** @@ -673,6 +723,7 @@ static void ether1394_host_reset(struct hpsb_host *host) ******************************************/ /* These functions have been adapted from net/ethernet/eth.c */ + /* Create a fake MAC header for an arbitrary protocol layer. * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp). */ @@ -680,24 +731,25 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - struct eth1394hdr *eth = - (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); + struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); eth->h_proto = htons(type); - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) { memset(eth->h_dest, 0, dev->addr_len); - return dev->hard_header_len; + return(dev->hard_header_len); } if (daddr) { - memcpy(eth->h_dest, daddr, dev->addr_len); + memcpy(eth->h_dest,daddr,dev->addr_len); return dev->hard_header_len; } return -dev->hard_header_len; + } + /* Rebuild the faked MAC header. This is called after an ARP * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. @@ -708,30 +760,38 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, static int ether1394_rebuild_header(struct sk_buff *skb) { struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; + struct net_device *dev = skb->dev; - if (eth->h_proto == htons(ETH_P_IP)) - return arp_find((unsigned char *)ð->h_dest, skb); + switch (eth->h_proto) { + +#ifdef CONFIG_INET + case __constant_htons(ETH_P_IP): + return arp_find((unsigned char*)ð->h_dest, skb); +#endif + default: + ETH1394_PRINT(KERN_DEBUG, dev->name, + "unable to resolve type %04x addresses.\n", + ntohs(eth->h_proto)); + break; + } - ETH1394_PRINT(KERN_DEBUG, skb->dev->name, - "unable to resolve type %04x addresses\n", - ntohs(eth->h_proto)); return 0; } static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) { struct net_device *dev = skb->dev; - memcpy(haddr, dev->dev_addr, ETH1394_ALEN); return ETH1394_ALEN; } + static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; + struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) + + (16 - ETH1394_HLEN)); struct net_device *dev = neigh->dev; - struct eth1394hdr *eth = - (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN); if (type == htons(ETH_P_802_3)) return -1; @@ -748,25 +808,38 @@ static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + (16 - ETH1394_HLEN), haddr, dev->addr_len); } +static int ether1394_mac_addr(struct net_device *dev, void *p) +{ + if (netif_running(dev)) + return -EBUSY; + + /* Not going to allow setting the MAC address, we really need to use + * the real one supplied by the hardware */ + return -EINVAL; + } + + + /****************************************** * Datagram reception code ******************************************/ /* Copied from net/ethernet/eth.c */ -static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev) +static inline u16 ether1394_type_trans(struct sk_buff *skb, + struct net_device *dev) { struct eth1394hdr *eth; unsigned char *rawp; - skb_reset_mac_header(skb); - skb_pull(skb, ETH1394_HLEN); + skb->mac.raw = skb->data; + skb_pull (skb, ETH1394_HLEN); eth = eth1394_hdr(skb); if (*eth->h_dest & 1) { - if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0) + if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) skb->pkt_type = PACKET_BROADCAST; #if 0 else @@ -775,45 +848,47 @@ static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev) } else { if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) skb->pkt_type = PACKET_OTHERHOST; - } + } - if (ntohs(eth->h_proto) >= 1536) + if (ntohs (eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); + if (*(unsigned short *)rawp == 0xFFFF) + return htons (ETH_P_802_3); - return htons(ETH_P_802_2); + return htons (ETH_P_802_2); } /* Parse an encapsulated IP1394 header into an ethernet frame packet. * We also perform ARP translation here, if need be. */ -static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, - nodeid_t srcid, nodeid_t destid, - u16 ether_type) +static inline u16 ether1394_parse_encap(struct sk_buff *skb, + struct net_device *dev, + nodeid_t srcid, nodeid_t destid, + u16 ether_type) { struct eth1394_priv *priv = netdev_priv(dev); u64 dest_hw; unsigned short ret = 0; - /* Setup our hw addresses. We use these to build the ethernet header. */ + /* Setup our hw addresses. We use these to build the + * ethernet header. */ if (destid == (LOCAL_BUS | ALL_NODES)) dest_hw = ~0ULL; /* broadcast */ else - dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 | + dest_hw = cpu_to_be64((((u64)priv->host->csr.guid_hi) << 32) | priv->host->csr.guid_lo); /* If this is an ARP packet, convert it. First, we want to make * use of some of the fields, since they tell us a little bit * about the sending machine. */ if (ether_type == htons(ETH_P_ARP)) { - struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; + struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data; struct arphdr *arp = (struct arphdr *)skb->data; unsigned char *arp_ptr = (unsigned char *)(arp + 1); u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | - ntohl(arp1394->fifo_lo); + ntohl(arp1394->fifo_lo); u8 max_rec = min(priv->host->csr.max_rec, (u8)(arp1394->max_rec)); int sspd = arp1394->sspd; @@ -827,17 +902,16 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, if (sspd > 5 || sspd < 0) sspd = 0; - maxpayload = min(eth1394_speedto_maxpayload[sspd], - (u16)(1 << (max_rec + 1))); + maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); guid = get_unaligned(&arp1394->s_uniq_id); node = eth1394_find_node_guid(&priv->ip_node_list, be64_to_cpu(guid)); - if (!node) + if (!node) { return 0; + } - node_info = - (struct eth1394_node_info *)node->ud->device.driver_data; + node_info = (struct eth1394_node_info*)node->ud->device.driver_data; /* Update our speed/payload/fifo_offset table */ node_info->maxpayload = maxpayload; @@ -856,7 +930,7 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, arp->ar_hln = 8; arp_ptr += arp->ar_hln; /* skip over sender unique id */ - *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */ + *(u32*)arp_ptr = arp1394->sip; /* move sender IP addr */ arp_ptr += arp->ar_pln; /* skip over sender IP addr */ if (arp->ar_op == htons(ARPOP_REQUEST)) @@ -873,65 +947,65 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, return ret; } -static int fragment_overlap(struct list_head *frag_list, int offset, int len) +static inline int fragment_overlap(struct list_head *frag_list, int offset, int len) { struct fragment_info *fi; - int end = offset + len; - list_for_each_entry(fi, frag_list, list) - if (offset < fi->offset + fi->len && end > fi->offset) + list_for_each_entry(fi, frag_list, list) { + if ( ! ((offset > (fi->offset + fi->len - 1)) || + ((offset + len - 1) < fi->offset))) return 1; - + } return 0; } -static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) +static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) { struct partial_datagram *pd; - list_for_each_entry(pd, pdgl, list) + list_for_each_entry(pd, pdgl, list) { if (pd->dgl == dgl) return &pd->list; - + } return NULL; } /* Assumes that new fragment does not overlap any existing fragments */ -static int new_fragment(struct list_head *frag_info, int offset, int len) +static inline int new_fragment(struct list_head *frag_info, int offset, int len) { struct list_head *lh; struct fragment_info *fi, *fi2, *new; list_for_each(lh, frag_info) { fi = list_entry(lh, struct fragment_info, list); - if (fi->offset + fi->len == offset) { + if ((fi->offset + fi->len) == offset) { /* The new fragment can be tacked on to the end */ fi->len += len; /* Did the new fragment plug a hole? */ fi2 = list_entry(lh->next, struct fragment_info, list); - if (fi->offset + fi->len == fi2->offset) { + if ((fi->offset + fi->len) == fi2->offset) { /* glue fragments together */ fi->len += fi2->len; list_del(lh->next); kfree(fi2); } return 0; - } else if (offset + len == fi->offset) { + } else if ((offset + len) == fi->offset) { /* The new fragment can be tacked on to the beginning */ fi->offset = offset; fi->len += len; /* Did the new fragment plug a hole? */ fi2 = list_entry(lh->prev, struct fragment_info, list); - if (fi2->offset + fi2->len == fi->offset) { + if ((fi2->offset + fi2->len) == fi->offset) { /* glue fragments together */ fi2->len += fi->len; list_del(lh); kfree(fi); } return 0; - } else if (offset > fi->offset + fi->len) { + } else if (offset > (fi->offset + fi->len)) { break; - } else if (offset + len < fi->offset) { + } else if ((offset + len) < fi->offset) { lh = lh->prev; break; } @@ -945,12 +1019,14 @@ static int new_fragment(struct list_head *frag_info, int offset, int len) new->len = len; list_add(&new->list, lh); + return 0; } -static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl, - int dgl, int dg_size, char *frag_buf, - int frag_off, int frag_len) +static inline int new_partial_datagram(struct net_device *dev, + struct list_head *pdgl, int dgl, + int dg_size, char *frag_buf, + int frag_off, int frag_len) { struct partial_datagram *new; @@ -983,33 +1059,33 @@ static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl, memcpy(new->pbuf + frag_off, frag_buf, frag_len); list_add(&new->list, pdgl); + return 0; } -static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, - char *frag_buf, int frag_off, int frag_len) +static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, + char *frag_buf, int frag_off, int frag_len) { - struct partial_datagram *pd = - list_entry(lh, struct partial_datagram, list); + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); - if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) + if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) { return -ENOMEM; + } memcpy(pd->pbuf + frag_off, frag_buf, frag_len); /* Move list entry to beginnig of list so that oldest partial * datagrams percolate to the end of the list */ list_move(lh, pdgl); + return 0; } -static int is_datagram_complete(struct list_head *lh, int dg_size) +static inline int is_datagram_complete(struct list_head *lh, int dg_size) { - struct partial_datagram *pd; - struct fragment_info *fi; - - pd = list_entry(lh, struct partial_datagram, list); - fi = list_entry(pd->frag_info.next, struct fragment_info, list); + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); + struct fragment_info *fi = list_entry(pd->frag_info.next, + struct fragment_info, list); return (fi->len == dg_size); } @@ -1032,7 +1108,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, if (!ud) { struct eth1394_node_ref *node; node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid); - if (unlikely(!node)) { + if (!node) { HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid " "lookup failure: " NODE_BUS_FMT, NODE_BUS_ARGS(priv->host, srcid)); @@ -1044,7 +1120,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, priv->ud_list[NODEID_TO_NODE(srcid)] = ud; } - node_info = (struct eth1394_node_info *)ud->device.driver_data; + node_info = (struct eth1394_node_info*)ud->device.driver_data; /* First, did we receive a fragmented or unfragmented datagram? */ hdr->words.word1 = ntohs(hdr->words.word1); @@ -1057,14 +1133,13 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, * high level network layer. */ skb = dev_alloc_skb(len + dev->hard_header_len + 15); - if (unlikely(!skb)) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); priv->stats.rx_dropped++; return -1; } skb_reserve(skb, (dev->hard_header_len + 15) & ~15); - memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, - len - hdr_len); + memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len); ether_type = hdr->uf.ether_type; } else { /* A datagram fragment has been received, now the fun begins. */ @@ -1149,8 +1224,9 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, pd = list_entry(lh, struct partial_datagram, list); - if (hdr->common.lf == ETH1394_HDR_LF_FF) + if (hdr->common.lf == ETH1394_HDR_LF_FF) { pd->ether_type = ether_type; + } if (is_datagram_complete(lh, dg_size)) { ether_type = pd->ether_type; @@ -1177,8 +1253,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid, ether_type); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (!skb->protocol) { priv->stats.rx_errors++; priv->stats.rx_dropped++; @@ -1212,9 +1288,9 @@ static int ether1394_write(struct hpsb_host *host, int srcid, int destid, struct eth1394_host_info *hi; hi = hpsb_get_hostinfo(ð1394_highlevel, host); - if (unlikely(!hi)) { - ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n", - host->id); + if (hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + host->driver->name); return RCODE_ADDRESS_ERROR; } @@ -1238,9 +1314,9 @@ static void ether1394_iso(struct hpsb_iso *iso) int nready; hi = hpsb_get_hostinfo(ð1394_highlevel, iso->host); - if (unlikely(!hi)) { - ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n", - iso->host->id); + if (hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + iso->host->driver->name); return; } @@ -1250,20 +1326,20 @@ static void ether1394_iso(struct hpsb_iso *iso) for (i = 0; i < nready; i++) { struct hpsb_iso_packet_info *info = &iso->infos[(iso->first_packet + i) % iso->buf_packets]; - data = (quadlet_t *)(iso->data_buf.kvirt + info->offset); + data = (quadlet_t*) (iso->data_buf.kvirt + info->offset); /* skip over GASP header */ buf = (char *)data + 8; len = info->len - 8; - specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 | - (be32_to_cpu(data[1]) & 0xff000000) >> 24; + specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) | + ((be32_to_cpu(data[1]) & 0xff000000) >> 24)); source_id = be32_to_cpu(data[0]) >> 16; priv = netdev_priv(dev); - if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) - || specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { /* This packet is not for us */ continue; } @@ -1291,31 +1367,35 @@ static void ether1394_iso(struct hpsb_iso *iso) * speed, and unicast FIFO address information between the sender_unique_id * and the IP addresses. */ -static void ether1394_arp_to_1394arp(struct sk_buff *skb, - struct net_device *dev) +static inline void ether1394_arp_to_1394arp(struct sk_buff *skb, + struct net_device *dev) { struct eth1394_priv *priv = netdev_priv(dev); + struct arphdr *arp = (struct arphdr *)skb->data; unsigned char *arp_ptr = (unsigned char *)(arp + 1); struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; + /* Believe it or not, all that need to happen is sender IP get moved + * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */ arp1394->hw_addr_len = 16; arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); arp1394->max_rec = priv->host->csr.max_rec; arp1394->sspd = priv->host->csr.lnk_spd; - arp1394->fifo_hi = htons(priv->local_fifo >> 32); - arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0); + arp1394->fifo_hi = htons (priv->local_fifo >> 32); + arp1394->fifo_lo = htonl (priv->local_fifo & ~0x0); + + return; } /* We need to encapsulate the standard header with our own. We use the * ethernet header's proto for our own. */ -static unsigned int ether1394_encapsulate_prep(unsigned int max_payload, - __be16 proto, - union eth1394_hdr *hdr, - u16 dg_size, u16 dgl) +static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, + __be16 proto, + union eth1394_hdr *hdr, + u16 dg_size, u16 dgl) { - unsigned int adj_max_payload = - max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; + unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; /* Does it all fit in one packet? */ if (dg_size <= adj_max_payload) { @@ -1328,19 +1408,19 @@ static unsigned int ether1394_encapsulate_prep(unsigned int max_payload, hdr->ff.dgl = dgl; adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; } - return (dg_size + adj_max_payload - 1) / adj_max_payload; + return((dg_size + (adj_max_payload - 1)) / adj_max_payload); } -static unsigned int ether1394_encapsulate(struct sk_buff *skb, - unsigned int max_payload, - union eth1394_hdr *hdr) +static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, + unsigned int max_payload, + union eth1394_hdr *hdr) { union eth1394_hdr *bufhdr; int ftype = hdr->common.lf; int hdrsz = hdr_type_len[ftype]; unsigned int adj_max_payload = max_payload - hdrsz; - switch (ftype) { + switch(ftype) { case ETH1394_HDR_LF_UF: bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); bufhdr->words.word1 = htons(hdr->words.word1); @@ -1369,10 +1449,11 @@ static unsigned int ether1394_encapsulate(struct sk_buff *skb, bufhdr->words.word3 = htons(hdr->words.word3); bufhdr->words.word4 = 0; } + return min(max_payload, skb->len); } -static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) +static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) { struct hpsb_packet *p; @@ -1385,57 +1466,61 @@ static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) return p; } -static int ether1394_prep_write_packet(struct hpsb_packet *p, - struct hpsb_host *host, nodeid_t node, - u64 addr, void *data, int tx_len) +static inline int ether1394_prep_write_packet(struct hpsb_packet *p, + struct hpsb_host *host, + nodeid_t node, u64 addr, + void * data, int tx_len) { p->node_id = node; p->data = NULL; p->tcode = TCODE_WRITEB; - p->header[1] = host->node_id << 16 | addr >> 32; + p->header[1] = (host->node_id << 16) | (addr >> 32); p->header[2] = addr & 0xffffffff; p->header_size = 16; p->expect_response = 1; if (hpsb_get_tlabel(p)) { - ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n"); + ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending " + "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node)); return -1; } - p->header[0] = - p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4; + p->header[0] = (p->node_id << 16) | (p->tlabel << 10) + | (1 << 8) | (TCODE_WRITEB << 4); p->header[3] = tx_len << 16; p->data_size = (tx_len + 3) & ~3; - p->data = data; + p->data = (quadlet_t*)data; return 0; } -static void ether1394_prep_gasp_packet(struct hpsb_packet *p, - struct eth1394_priv *priv, - struct sk_buff *skb, int length) +static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p, + struct eth1394_priv *priv, + struct sk_buff *skb, int length) { p->header_size = 4; p->tcode = TCODE_STREAM_DATA; - p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 | - TCODE_STREAM_DATA << 4; + p->header[0] = (length << 16) | (3 << 14) + | ((priv->broadcast_channel) << 8) + | (TCODE_STREAM_DATA << 4); p->data_size = length; - p->data = (quadlet_t *)skb->data - 2; - p->data[0] = cpu_to_be32(priv->host->node_id << 16 | + p->data = ((quadlet_t*)skb->data) - 2; + p->data[0] = cpu_to_be32((priv->host->node_id << 16) | ETHER1394_GASP_SPECIFIER_ID_HI); - p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 | + p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) | ETHER1394_GASP_VERSION); + /* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES) + * prevents hpsb_send_packet() from setting the speed to an arbitrary + * value based on packet->node_id if packet->node_id is not set. */ + p->node_id = ALL_NODES; p->speed_code = priv->bc_sspd; - - /* prevent hpsb_send_packet() from overriding our speed code */ - p->node_id = LOCAL_BUS | ALL_NODES; } -static void ether1394_free_packet(struct hpsb_packet *packet) +static inline void ether1394_free_packet(struct hpsb_packet *packet) { if (packet->tcode != TCODE_STREAM_DATA) hpsb_free_tlabel(packet); @@ -1454,7 +1539,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) return -1; if (ptask->tx_type == ETH1394_GASP) { - int length = tx_len + 2 * sizeof(quadlet_t); + int length = tx_len + (2 * sizeof(quadlet_t)); ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); } else if (ether1394_prep_write_packet(packet, priv->host, @@ -1477,11 +1562,13 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) return 0; } + /* Task function to be run when a datagram transmission is completed */ -static void ether1394_dg_complete(struct packet_task *ptask, int fail) +static inline void ether1394_dg_complete(struct packet_task *ptask, int fail) { struct sk_buff *skb = ptask->skb; - struct eth1394_priv *priv = netdev_priv(skb->dev); + struct net_device *dev = skb->dev; + struct eth1394_priv *priv = netdev_priv(dev); unsigned long flags; /* Statistics */ @@ -1499,6 +1586,7 @@ static void ether1394_dg_complete(struct packet_task *ptask, int fail) kmem_cache_free(packet_task_cache, ptask); } + /* Callback for when a packet has been sent and the status of that packet is * known */ static void ether1394_complete_cb(void *__ptask) @@ -1526,15 +1614,19 @@ static void ether1394_complete_cb(void *__ptask) } } + + /* Transmit a packet (called by kernel) */ -static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) +static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) { + gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct eth1394hdr *eth; struct eth1394_priv *priv = netdev_priv(dev); __be16 proto; unsigned long flags; nodeid_t dest_node; eth1394_tx_type tx_type; + int ret = 0; unsigned int tx_len; unsigned int max_payload; u16 dg_size; @@ -1543,24 +1635,29 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) struct eth1394_node_ref *node; struct eth1394_node_info *node_info = NULL; - ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC); - if (ptask == NULL) + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; goto fail; + } /* XXX Ignore this for now. Noticed that when MacOSX is the IRM, * it does not set our validity bit. We need to compensate for * that somewhere else, but not in eth1394. */ #if 0 - if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) + if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) { + ret = -EAGAIN; goto fail; + } #endif - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) + if ((skb = skb_share_check (skb, kmflags)) == NULL) { + ret = -ENOMEM; goto fail; + } /* Get rid of the fake eth1394 header, but save a pointer */ - eth = (struct eth1394hdr *)skb->data; + eth = (struct eth1394hdr*)skb->data; skb_pull(skb, ETH1394_HLEN); proto = eth->h_proto; @@ -1571,11 +1668,11 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 || proto == htons(ETH_P_ARP) || (proto == htons(ETH_P_IP) && - IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { + IN_MULTICAST(ntohl(skb->nh.iph->daddr)))) { tx_type = ETH1394_GASP; dest_node = LOCAL_BUS | ALL_NODES; max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD; - BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD); + BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); dgl = priv->bc_dgl; if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) priv->bc_dgl++; @@ -1584,17 +1681,19 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) node = eth1394_find_node_guid(&priv->ip_node_list, be64_to_cpu(guid)); - if (!node) + if (!node) { + ret = -EAGAIN; goto fail; - - node_info = - (struct eth1394_node_info *)node->ud->device.driver_data; - if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) + } + node_info = (struct eth1394_node_info*)node->ud->device.driver_data; + if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) { + ret = -EAGAIN; goto fail; + } dest_node = node->ud->ne->nodeid; max_payload = node_info->maxpayload; - BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD); + BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); dgl = node_info->dgl; if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) @@ -1604,7 +1703,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) /* If this is an ARP packet, convert it */ if (proto == htons(ETH_P_ARP)) - ether1394_arp_to_1394arp(skb, dev); + ether1394_arp_to_1394arp (skb, dev); ptask->hdr.words.word1 = 0; ptask->hdr.words.word2 = 0; @@ -1627,8 +1726,9 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) ptask->tx_type = tx_type; ptask->max_payload = max_payload; - ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, - proto, &ptask->hdr, dg_size, dgl); + ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto, + &ptask->hdr, dg_size, + dgl); /* Add the encapsulation header to the fragment */ tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); @@ -1637,7 +1737,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) goto fail; netif_wake_queue(dev); - return NETDEV_TX_OK; + return 0; fail: if (ptask) kmem_cache_free(packet_task_cache, ptask); @@ -1645,56 +1745,40 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (skb != NULL) dev_kfree_skb(skb); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave (&priv->lock, flags); priv->stats.tx_dropped++; priv->stats.tx_errors++; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore (&priv->lock, flags); if (netif_queue_stopped(dev)) netif_wake_queue(dev); - /* - * FIXME: According to a patch from 2003-02-26, "returning non-zero - * causes serious problems" here, allegedly. Before that patch, - * -ERRNO was returned which is not appropriate under Linux 2.6. - * Perhaps more needs to be done? Stop the queue in serious - * conditions and restart it elsewhere? - */ - /* return NETDEV_TX_BUSY; */ - return NETDEV_TX_OK; + return 0; /* returning non-zero causes serious problems */ } -static void ether1394_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) +static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - strcpy(info->driver, driver_name); - strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */ + strcpy (info->driver, driver_name); + /* FIXME XXX provide sane businfo */ + strcpy (info->bus_info, "ieee1394"); } static struct ethtool_ops ethtool_ops = { .get_drvinfo = ether1394_get_drvinfo }; -static int __init ether1394_init_module(void) +static int __init ether1394_init_module (void) { - int err; - - packet_task_cache = kmem_cache_create("packet_task", - sizeof(struct packet_task), + packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), 0, 0, NULL, NULL); - if (!packet_task_cache) - return -ENOMEM; + /* Register ourselves as a highlevel driver */ hpsb_register_highlevel(ð1394_highlevel); - err = hpsb_register_protocol(ð1394_proto_driver); - if (err) { - hpsb_unregister_highlevel(ð1394_highlevel); - kmem_cache_destroy(packet_task_cache); - } - return err; + + return hpsb_register_protocol(ð1394_proto_driver); } -static void __exit ether1394_exit_module(void) +static void __exit ether1394_exit_module (void) { hpsb_unregister_protocol(ð1394_proto_driver); hpsb_unregister_highlevel(ð1394_highlevel); diff --git a/trunk/drivers/ieee1394/eth1394.h b/trunk/drivers/ieee1394/eth1394.h index a3439ee7cb4e..c45cbff9138d 100644 --- a/trunk/drivers/ieee1394/eth1394.h +++ b/trunk/drivers/ieee1394/eth1394.h @@ -25,11 +25,8 @@ #define __ETH1394_H #include -#include -#include #include "ieee1394.h" -#include "ieee1394_types.h" /* Register for incoming packets. This is 4096 bytes, which supports up to * S3200 (per Table 16-3 of IEEE 1394b-2002). */ @@ -37,15 +34,22 @@ /* GASP identifier numbers for IPv4 over IEEE 1394 */ #define ETHER1394_GASP_SPECIFIER_ID 0x00005E -#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff) -#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff) +#define ETHER1394_GASP_SPECIFIER_ID_HI ((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff) +#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff) #define ETHER1394_GASP_VERSION 1 -#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */ +#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */ -#define ETHER1394_GASP_BUFFERS 16 +#define ETHER1394_GASP_BUFFERS 16 -#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */ +/* rawiso buffer size - due to a limitation in rawiso, we must limit each + * GASP buffer to be less than PAGE_SIZE. */ +#define ETHER1394_ISO_BUF_SIZE ETHER1394_GASP_BUFFERS * \ + min((unsigned int)PAGE_SIZE, \ + 2 * (1U << (priv->host->csr.max_rec + 1))) + +/* Node set == 64 */ +#define NODE_SET (ALL_NODES + 1) enum eth1394_bc_states { ETHER1394_BC_ERROR, ETHER1394_BC_RUNNING, @@ -81,14 +85,19 @@ struct eth1394hdr { unsigned short h_proto; /* packet type ID field */ } __attribute__((packed)); +#ifdef __KERNEL__ +#include + static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb) { - return (struct eth1394hdr *)skb_mac_header(skb); + return (struct eth1394hdr *)skb->mac.raw; } +#endif typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; /* IP1394 headers */ +#include /* Unfragmented */ #if defined __BIG_ENDIAN_BITFIELD diff --git a/trunk/drivers/ieee1394/highlevel.c b/trunk/drivers/ieee1394/highlevel.c index 83a493312751..694da82d820b 100644 --- a/trunk/drivers/ieee1394/highlevel.c +++ b/trunk/drivers/ieee1394/highlevel.c @@ -70,12 +70,8 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl, return NULL; } -/** - * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host - * - * Returns a per @host and @hl driver data structure that was previously stored - * by hpsb_create_hostinfo. - */ +/* Returns a per host/driver data structure that was previously stored by + * hpsb_create_hostinfo. */ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) { struct hl_host_info *hi = hl_get_hostinfo(hl, host); @@ -83,13 +79,7 @@ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) return hi ? hi->data : NULL; } -/** - * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host - * - * Allocate a hostinfo pointer backed by memory with @data_size and bind it to - * to this @hl driver and @host. If @data_size is zero, then the return here is - * only valid for error checking. - */ +/* If size is zero, then the return here is only valid for error checking */ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, size_t data_size) { @@ -123,11 +113,6 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, return data; } -/** - * hpsb_set_hostinfo - set the hostinfo pointer to something useful - * - * Usually follows a call to hpsb_create_hostinfo, where the size is 0. - */ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data) { @@ -147,11 +132,6 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, return -EINVAL; } -/** - * hpsb_destroy_hostinfo - free and remove a hostinfo pointer - * - * Free and remove the hostinfo pointer bound to this @hl driver and @host. - */ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) { struct hl_host_info *hi; @@ -167,12 +147,6 @@ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) return; } -/** - * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo - * - * Sets an alternate lookup key for the hostinfo bound to this @hl driver and - * @host. - */ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key) { @@ -184,9 +158,6 @@ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, return; } -/** - * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key - */ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key) { struct hl_host_info *hi; @@ -218,12 +189,6 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data) return 0; } -/** - * hpsb_register_highlevel - register highlevel driver - * - * The name pointer in @hl has to stay valid at all times because the string is - * not copied. - */ void hpsb_register_highlevel(struct hpsb_highlevel *hl) { unsigned long flags; @@ -293,9 +258,6 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data) return 0; } -/** - * hpsb_unregister_highlevel - unregister highlevel driver - */ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) { unsigned long flags; @@ -311,19 +273,6 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) nodemgr_for_each_host(hl, highlevel_for_each_host_unreg); } -/** - * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space - * - * @start and @end are 48 bit pointers and have to be quadlet aligned. - * @end points to the first address behind the handled addresses. This - * function can be called multiple times for a single hpsb_highlevel @hl to - * implement sparse register sets. The requested region must not overlap any - * previously allocated region, otherwise registering will fail. - * - * It returns true for successful allocation. Address spaces can be - * unregistered with hpsb_unregister_addrspace. All remaining address spaces - * are automatically deallocated together with the hpsb_highlevel @hl. - */ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, struct hpsb_address_ops *ops, @@ -399,19 +348,6 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, return retval; } -/** - * hpsb_register_addrspace - register a host address space - * - * @start and @end are 48 bit pointers and have to be quadlet aligned. - * @end points to the first address behind the handled addresses. This - * function can be called multiple times for a single hpsb_highlevel @hl to - * implement sparse register sets. The requested region must not overlap any - * previously allocated region, otherwise registering will fail. - * - * It returns true for successful allocation. Address spaces can be - * unregistered with hpsb_unregister_addrspace. All remaining address spaces - * are automatically deallocated together with the hpsb_highlevel @hl. - */ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, struct hpsb_address_ops *ops, u64 start, u64 end) { @@ -483,11 +419,6 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, return retval; } -/** - * hpsb_listen_channel - enable receving a certain isochronous channel - * - * Reception is handled through the @hl's iso_receive op. - */ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel) { @@ -500,9 +431,6 @@ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, return 0; } -/** - * hpsb_unlisten_channel - disable receving a certain isochronous channel - */ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel) { @@ -600,17 +528,6 @@ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, read_unlock_irqrestore(&hl_irqs_lock, flags); } -/* - * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64: - * - * 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 latter case, no response will be sent and the driver which - * handled the request will send the response itself. - */ int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr, unsigned int length, u16 flags) { diff --git a/trunk/drivers/ieee1394/highlevel.h b/trunk/drivers/ieee1394/highlevel.h index 63474f7ee69d..4b330117067a 100644 --- a/trunk/drivers/ieee1394/highlevel.h +++ b/trunk/drivers/ieee1394/highlevel.h @@ -99,6 +99,16 @@ struct hpsb_address_ops { void highlevel_add_host(struct hpsb_host *host); void highlevel_remove_host(struct hpsb_host *host); void highlevel_host_reset(struct hpsb_host *host); + +/* + * These functions are called to handle transactions. They are called when a + * packet arrives. The flags argument contains the second word of the first + * header quadlet of the incoming packet (containing transaction label, retry + * code, transaction code and priority). These functions either return a + * response code or a negative number. In the first case a response will be + * generated. In the latter case, no response will be sent and the driver which + * handled the request will send the response itself. + */ int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr, unsigned int length, u16 flags); int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data, @@ -109,13 +119,30 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); + void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length); void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, void *data, size_t length); +/* + * Register highlevel driver. The name pointer has to stay valid at all times + * because the string is not copied. + */ void hpsb_register_highlevel(struct hpsb_highlevel *hl); void hpsb_unregister_highlevel(struct hpsb_highlevel *hl); +/* + * Register handlers for host address spaces. Start and end are 48 bit pointers + * and have to be quadlet aligned. Argument "end" points to the first address + * behind the handled addresses. This function can be called multiple times for + * a single hpsb_highlevel to implement sparse register sets. The requested + * region must not overlap any previously allocated region, otherwise + * registering will fail. + * + * It returns true for successful allocation. Address spaces can be + * unregistered with hpsb_unregister_addrspace. All remaining address spaces + * are automatically deallocated together with the hpsb_highlevel. + */ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, struct hpsb_address_ops *ops, @@ -125,19 +152,45 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, struct hpsb_address_ops *ops, u64 start, u64 end); int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, u64 start); + +/* + * Enable or disable receving a certain isochronous channel through the + * iso_receive op. + */ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, - unsigned int channel); + unsigned int channel); void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel); +/* Retrieve a hostinfo pointer bound to this driver/host */ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); + +/* Allocate a hostinfo pointer of data_size bound to this driver/host */ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, size_t data_size); + +/* Free and remove the hostinfo pointer bound to this driver/host */ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); + +/* Set an alternate lookup key for the hostinfo bound to this driver/host */ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key); + +/* Retrieve the alternate lookup key for the hostinfo bound to this + * driver/host */ +unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, + struct hpsb_host *host); + +/* Retrieve a hostinfo pointer bound to this driver using its alternate key */ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key); + +/* Set the hostinfo pointer to something useful. Usually follows a call to + * hpsb_create_hostinfo, where the size is 0. */ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data); +/* Retrieve hpsb_host using a highlevel handle and a key */ +struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, + unsigned long key); + #endif /* IEEE1394_HIGHLEVEL_H */ diff --git a/trunk/drivers/ieee1394/hosts.c b/trunk/drivers/ieee1394/hosts.c index bd0755c789c5..32a130921938 100644 --- a/trunk/drivers/ieee1394/hosts.c +++ b/trunk/drivers/ieee1394/hosts.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,14 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data) return 0; } +/* + * The pending_packet_queue is special in that it's processed + * from hardirq context too (such as hpsb_bus_reset()). Hence + * split the lock class from the usual networking skb-head + * lock class by using a separate key for it: + */ +static struct lock_class_key pending_packet_queue_key; + static DEFINE_MUTEX(host_num_alloc); /** @@ -128,7 +137,9 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, h->hostdata = h + 1; h->driver = drv; - INIT_LIST_HEAD(&h->pending_packets); + skb_queue_head_init(&h->pending_packet_queue); + lockdep_set_class(&h->pending_packet_queue.lock, + &pending_packet_queue_key); INIT_LIST_HEAD(&h->addr_space); for (i = 2; i < 16; i++) @@ -179,7 +190,7 @@ int hpsb_add_host(struct hpsb_host *host) { if (hpsb_default_host_entry(host)) return -ENOMEM; - + hpsb_add_extra_config_roms(host); highlevel_add_host(host); return 0; } @@ -201,19 +212,12 @@ void hpsb_remove_host(struct hpsb_host *host) host->driver = &dummy_driver; highlevel_remove_host(host); + hpsb_remove_extra_config_roms(host); class_device_unregister(&host->class_dev); device_unregister(&host->device); } -/** - * hpsb_update_config_rom_image - updates configuration ROM image of a host - * - * Updates the configuration ROM image of a host. rom_version must be the - * current version, otherwise it will fail with return value -1. If this - * host does not support config-rom-update, it will return -%EINVAL. - * Return value 0 indicates success. - */ int hpsb_update_config_rom_image(struct hpsb_host *host) { unsigned long reset_delay; diff --git a/trunk/drivers/ieee1394/hosts.h b/trunk/drivers/ieee1394/hosts.h index feb55d032294..4bf4fb7f67b7 100644 --- a/trunk/drivers/ieee1394/hosts.h +++ b/trunk/drivers/ieee1394/hosts.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -24,7 +25,8 @@ struct hpsb_host { atomic_t generation; - struct list_head pending_packets; + struct sk_buff_head pending_packet_queue; + struct timer_list timeout; unsigned long timeout_interval; @@ -200,6 +202,12 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, int hpsb_add_host(struct hpsb_host *host); void hpsb_resume_host(struct hpsb_host *host); void hpsb_remove_host(struct hpsb_host *host); + +/* Updates the configuration rom image of a host. rom_version must be the + * current version, otherwise it will fail with return value -1. If this + * host does not support config-rom-update, it will return -EINVAL. + * Return value 0 indicates success. + */ int hpsb_update_config_rom_image(struct hpsb_host *host); #endif /* _IEEE1394_HOSTS_H */ diff --git a/trunk/drivers/ieee1394/ieee1394_core.c b/trunk/drivers/ieee1394/ieee1394_core.c index 8f71b6a06aa0..d791d08c743c 100644 --- a/trunk/drivers/ieee1394/ieee1394_core.c +++ b/trunk/drivers/ieee1394/ieee1394_core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -95,15 +96,13 @@ static void queue_packet_complete(struct hpsb_packet *packet); /** - * hpsb_set_packet_complete_task - set task that runs when a packet completes + * hpsb_set_packet_complete_task - set the task that runs when a packet + * completes. You cannot call this more than once on a single packet + * before it is sent. + * * @packet: the packet whose completion we want the task added to * @routine: function to call * @data: data (if any) to pass to the above function - * - * Set the task that runs when a packet completes. You cannot call this more - * than once on a single packet before it is sent. - * - * Typically, the complete @routine is responsible to call hpsb_free_packet(). */ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, void (*routine)(void *), void *data) @@ -116,12 +115,12 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, /** * hpsb_alloc_packet - allocate new packet structure - * @data_size: size of the data block to be allocated, in bytes + * @data_size: size of the data block to be allocated * * This function allocates, initializes and returns a new &struct hpsb_packet. - * It can be used in interrupt context. A header block is always included and - * initialized with zeros. Its size is big enough to contain all possible 1394 - * headers. The data block is only allocated if @data_size is not zero. + * It can be used in interrupt context. A header block is always included, its + * size is big enough to contain all possible 1394 headers. The data block is + * only allocated when @data_size is not zero. * * For packets for which responses will be received the @data_size has to be big * enough to contain the response's data block since no further allocation @@ -136,49 +135,50 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, */ struct hpsb_packet *hpsb_alloc_packet(size_t data_size) { - struct hpsb_packet *packet; + struct hpsb_packet *packet = NULL; + struct sk_buff *skb; data_size = ((data_size + 3) & ~3); - packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC); - if (!packet) + skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC); + if (skb == NULL) return NULL; + memset(skb->data, 0, data_size + sizeof(*packet)); + + packet = (struct hpsb_packet *)skb->data; + packet->skb = skb; + + packet->header = packet->embedded_header; packet->state = hpsb_unused; packet->generation = -1; INIT_LIST_HEAD(&packet->driver_list); - INIT_LIST_HEAD(&packet->queue); atomic_set(&packet->refcnt, 1); if (data_size) { - packet->data = packet->embedded_data; - packet->allocated_data_size = data_size; + packet->data = (quadlet_t *)(skb->data + sizeof(*packet)); + packet->data_size = data_size; } + return packet; } + /** * hpsb_free_packet - free packet and data associated with it * @packet: packet to free (is NULL safe) * - * Frees @packet->data only if it was allocated through hpsb_alloc_packet(). + * This function will free packet->data and finally the packet itself. */ void hpsb_free_packet(struct hpsb_packet *packet) { if (packet && atomic_dec_and_test(&packet->refcnt)) { - BUG_ON(!list_empty(&packet->driver_list) || - !list_empty(&packet->queue)); - kfree(packet); + BUG_ON(!list_empty(&packet->driver_list)); + kfree_skb(packet->skb); } } -/** - * hpsb_reset_bus - initiate bus reset on the given host - * @host: host controller whose bus to reset - * @type: one of enum reset_types - * - * Returns 1 if bus reset already in progress, 0 otherwise. - */ + int hpsb_reset_bus(struct hpsb_host *host, int type) { if (!host->in_bus_reset) { @@ -229,14 +229,6 @@ int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, return 0; } -/** - * hpsb_bus_reset - notify a bus reset to the core - * - * For host driver module usage. Safe to use in interrupt context, although - * quite complex; so you may want to run it in the bottom rather than top half. - * - * Returns 1 if bus reset already in progress, 0 otherwise. - */ int hpsb_bus_reset(struct hpsb_host *host) { if (host->in_bus_reset) { @@ -413,14 +405,6 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) } -/** - * hpsb_selfid_received - hand over received selfid packet to the core - * - * For host driver module usage. Safe to use in interrupt context. - * - * The host driver should have done a successful complement check (second - * quadlet is complement of first) beforehand. - */ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) { if (host->in_bus_reset) { @@ -432,15 +416,6 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) } } -/** - * hpsb_selfid_complete - notify completion of SelfID stage to the core - * - * For host driver module usage. Safe to use in interrupt context, although - * quite complex; so you may want to run it in the bottom rather than top half. - * - * Notify completion of SelfID stage to the core and report new physical ID - * and whether host is root now. - */ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) { if (!host->in_bus_reset) @@ -487,41 +462,30 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) highlevel_host_reset(host); } -static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED; -/** - * hpsb_packet_sent - notify core of sending a packet - * - * For host driver module usage. Safe to call from within a transmit packet - * routine. - * - * Notify core of sending a packet. Ackcode is the ack code returned for async - * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE - * for other cases (internal errors that don't justify a panic). - */ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode) { unsigned long flags; - spin_lock_irqsave(&pending_packets_lock, flags); + spin_lock_irqsave(&host->pending_packet_queue.lock, flags); packet->ack_code = ackcode; if (packet->no_waiter || packet->state == hpsb_complete) { /* if packet->no_waiter, must not have a tlabel allocated */ - spin_unlock_irqrestore(&pending_packets_lock, flags); + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); hpsb_free_packet(packet); return; } atomic_dec(&packet->refcnt); /* drop HC's reference */ - /* here the packet must be on the host->pending_packets queue */ + /* here the packet must be on the host->pending_packet_queue */ if (ackcode != ACK_PENDING || !packet->expect_response) { packet->state = hpsb_complete; - list_del_init(&packet->queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); + __skb_unlink(packet->skb, &host->pending_packet_queue); + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); queue_packet_complete(packet); return; } @@ -529,7 +493,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, packet->state = hpsb_pending; packet->sendtime = jiffies; - spin_unlock_irqrestore(&pending_packets_lock, flags); + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); mod_timer(&host->timeout, jiffies + host->timeout_interval); } @@ -540,10 +504,9 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, * @rootid: root whose force_root bit should get set (-1 = don't set force_root) * @gapcnt: gap count value to set (-1 = don't set gap count) * - * This function sends a PHY config packet on the bus through the specified - * host. + * This function sends a PHY config packet on the bus through the specified host. * - * Return value: 0 for success or negative error number otherwise. + * Return value: 0 for success or error number otherwise. */ int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt) { @@ -604,16 +567,12 @@ int hpsb_send_packet(struct hpsb_packet *packet) WARN_ON(packet->no_waiter && packet->expect_response); if (!packet->no_waiter || packet->expect_response) { - unsigned long flags; - atomic_inc(&packet->refcnt); /* Set the initial "sendtime" to 10 seconds from now, to prevent premature expiry. If a packet takes more than 10 seconds to hit the wire, we have bigger problems :) */ packet->sendtime = jiffies + 10 * HZ; - spin_lock_irqsave(&pending_packets_lock, flags); - list_add_tail(&packet->queue, &host->pending_packets); - spin_unlock_irqrestore(&pending_packets_lock, flags); + skb_queue_tail(&host->pending_packet_queue, packet->skb); } if (packet->node_id == host->node_id) { @@ -662,12 +621,6 @@ static void complete_packet(void *data) complete((struct completion *) data); } -/** - * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes - * @packet: packet to send - * - * Return value: 0 on success, negative errno on failure. - */ int hpsb_send_packet_and_wait(struct hpsb_packet *packet) { struct completion done; @@ -689,97 +642,86 @@ static void send_packet_nocare(struct hpsb_packet *packet) } } -static size_t packet_size_to_data_size(size_t packet_size, size_t header_size, - size_t buffer_size, int tcode) -{ - size_t ret = packet_size <= header_size ? 0 : packet_size - header_size; - - if (unlikely(ret > buffer_size)) - ret = buffer_size; - - if (unlikely(ret + header_size != packet_size)) - HPSB_ERR("unexpected packet size %zd (tcode %d), bug?", - packet_size, tcode); - return ret; -} static void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data, size_t size) { - struct hpsb_packet *packet; - int tlabel = (data[0] >> 10) & 0x3f; - size_t header_size; + struct hpsb_packet *packet = NULL; + struct sk_buff *skb; + int tcode_match = 0; + int tlabel; unsigned long flags; - spin_lock_irqsave(&pending_packets_lock, flags); + tlabel = (data[0] >> 10) & 0x3f; - list_for_each_entry(packet, &host->pending_packets, queue) - if (packet->tlabel == tlabel && - packet->node_id == (data[1] >> 16)) - goto found; + spin_lock_irqsave(&host->pending_packet_queue.lock, flags); - spin_unlock_irqrestore(&pending_packets_lock, flags); - HPSB_DEBUG("unsolicited response packet received - %s", - "no tlabel match"); - dump_packet("contents", data, 16, -1); - return; + skb_queue_walk(&host->pending_packet_queue, skb) { + packet = (struct hpsb_packet *)skb->data; + if ((packet->tlabel == tlabel) + && (packet->node_id == (data[1] >> 16))){ + break; + } + + packet = NULL; + } + + if (packet == NULL) { + HPSB_DEBUG("unsolicited response packet received - no tlabel match"); + dump_packet("contents", data, 16, -1); + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); + return; + } -found: switch (packet->tcode) { case TCODE_WRITEQ: case TCODE_WRITEB: - if (unlikely(tcode != TCODE_WRITE_RESPONSE)) + if (tcode != TCODE_WRITE_RESPONSE) break; - header_size = 12; - size = 0; - goto dequeue; - + tcode_match = 1; + memcpy(packet->header, data, 12); + break; case TCODE_READQ: - if (unlikely(tcode != TCODE_READQ_RESPONSE)) + if (tcode != TCODE_READQ_RESPONSE) break; - header_size = 16; - size = 0; - goto dequeue; - + tcode_match = 1; + memcpy(packet->header, data, 16); + break; case TCODE_READB: - if (unlikely(tcode != TCODE_READB_RESPONSE)) + if (tcode != TCODE_READB_RESPONSE) break; - header_size = 16; - size = packet_size_to_data_size(size, header_size, - packet->allocated_data_size, - tcode); - goto dequeue; - + tcode_match = 1; + BUG_ON(packet->skb->len - sizeof(*packet) < size - 16); + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, size - 16); + break; case TCODE_LOCK_REQUEST: - if (unlikely(tcode != TCODE_LOCK_RESPONSE)) + if (tcode != TCODE_LOCK_RESPONSE) break; - header_size = 16; - size = packet_size_to_data_size(min(size, (size_t)(16 + 8)), - header_size, - packet->allocated_data_size, - tcode); - goto dequeue; + tcode_match = 1; + size = min((size - 16), (size_t)8); + BUG_ON(packet->skb->len - sizeof(*packet) < size); + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, size); + break; } - spin_unlock_irqrestore(&pending_packets_lock, flags); - HPSB_DEBUG("unsolicited response packet received - %s", - "tcode mismatch"); - dump_packet("contents", data, 16, -1); - return; + if (!tcode_match) { + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); + HPSB_INFO("unsolicited response packet received - tcode mismatch"); + dump_packet("contents", data, 16, -1); + return; + } -dequeue: - list_del_init(&packet->queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); + __skb_unlink(skb, &host->pending_packet_queue); if (packet->state == hpsb_queued) { packet->sendtime = jiffies; packet->ack_code = ACK_PENDING; } - packet->state = hpsb_complete; - memcpy(packet->header, data, header_size); - if (size) - memcpy(packet->data, data + 4, size); + packet->state = hpsb_complete; + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); queue_packet_complete(packet); } @@ -793,7 +735,6 @@ static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, p = hpsb_alloc_packet(dsize); if (unlikely(p == NULL)) { /* FIXME - send data_error response */ - HPSB_ERR("out of memory, cannot send response packet"); return NULL; } @@ -843,6 +784,7 @@ static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, static void fill_async_write_resp(struct hpsb_packet *packet, int rcode) { PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE); + packet->header[2] = 0; packet->header_size = 12; packet->data_size = 0; } @@ -859,9 +801,12 @@ static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extc packet->data_size = length; } +#define PREP_REPLY_PACKET(length) \ + packet = create_reply_packet(host, data, length); \ + if (packet == NULL) break + static void handle_incoming_packet(struct hpsb_host *host, int tcode, - quadlet_t *data, size_t size, - int write_acked) + quadlet_t *data, size_t size, int write_acked) { struct hpsb_packet *packet; int length, rcode, extcode; @@ -871,72 +816,74 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, u16 flags = (u16) data[0]; u64 addr; - /* FIXME? - * Out-of-bounds lengths are left for highlevel_read|write to cap. */ + /* big FIXME - no error checking is done for an out of bounds length */ switch (tcode) { case TCODE_WRITEQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, dest, data + 3, + rcode = highlevel_write(host, source, dest, data+3, addr, 4, flags); - goto handle_write_request; + + if (!write_acked + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) + && (rcode >= 0)) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); + fill_async_write_resp(packet, rcode); + send_packet_nocare(packet); + } + break; case TCODE_WRITEB: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, dest, data + 4, - addr, data[3] >> 16, flags); -handle_write_request: - if (rcode < 0 || write_acked || - NODEID_TO_NODE(data[0] >> 16) == NODE_MASK) - return; - /* not a broadcast write, reply */ - packet = create_reply_packet(host, data, 0); - if (packet) { + rcode = highlevel_write(host, source, dest, data+4, + addr, data[3]>>16, flags); + + if (!write_acked + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) + && (rcode >= 0)) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); fill_async_write_resp(packet, rcode); send_packet_nocare(packet); } - return; + break; case TCODE_READQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_read(host, source, &buffer, addr, 4, flags); - if (rcode < 0) - return; - packet = create_reply_packet(host, data, 0); - if (packet) { + if (rcode >= 0) { + PREP_REPLY_PACKET(0); fill_async_readquad_resp(packet, rcode, buffer); send_packet_nocare(packet); } - return; + break; case TCODE_READB: length = data[3] >> 16; - packet = create_reply_packet(host, data, length); - if (!packet) - return; + PREP_REPLY_PACKET(length); addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_read(host, source, packet->data, addr, length, flags); - if (rcode < 0) { + + if (rcode >= 0) { + fill_async_readblock_resp(packet, rcode, length); + send_packet_nocare(packet); + } else { hpsb_free_packet(packet); - return; } - fill_async_readblock_resp(packet, rcode, length); - send_packet_nocare(packet); - return; + break; case TCODE_LOCK_REQUEST: length = data[3] >> 16; extcode = data[3] & 0xffff; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - packet = create_reply_packet(host, data, 8); - if (!packet) - return; + PREP_REPLY_PACKET(8); - if (extcode == 0 || extcode >= 7) { + if ((extcode == 0) || (extcode >= 7)) { /* let switch default handle error */ length = 0; } @@ -944,12 +891,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, switch (length) { case 4: rcode = highlevel_lock(host, source, packet->data, addr, - data[4], 0, extcode, flags); + data[4], 0, extcode,flags); fill_async_lock_resp(packet, rcode, extcode, 4); break; case 8: - if (extcode != EXTCODE_FETCH_ADD && - extcode != EXTCODE_LITTLE_ADD) { + if ((extcode != EXTCODE_FETCH_ADD) + && (extcode != EXTCODE_LITTLE_ADD)) { rcode = highlevel_lock(host, source, packet->data, addr, data[5], data[4], @@ -973,38 +920,29 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, break; default: rcode = RCODE_TYPE_ERROR; - fill_async_lock_resp(packet, rcode, extcode, 0); + fill_async_lock_resp(packet, rcode, + extcode, 0); } - if (rcode < 0) - hpsb_free_packet(packet); - else + if (rcode >= 0) { send_packet_nocare(packet); - return; + } else { + hpsb_free_packet(packet); + } + break; } + } +#undef PREP_REPLY_PACKET + -/** - * hpsb_packet_received - hand over received packet to the core - * - * For host driver module usage. - * - * The contents of data are expected to be the full packet but with the CRCs - * left out (data block follows header immediately), with the header (i.e. the - * first four quadlets) in machine byte order and the data block in big endian. - * *@data can be safely overwritten after this call. - * - * If the packet is a write request, @write_acked is to be set to true if it was - * ack_complete'd already, false otherwise. This argument is ignored for any - * other packet type. - */ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, int write_acked) { int tcode; - if (unlikely(host->in_bus_reset)) { - HPSB_DEBUG("received packet during reset; ignoring"); + if (host->in_bus_reset) { + HPSB_INFO("received packet during reset; ignoring"); return; } @@ -1038,27 +976,23 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, break; default: - HPSB_DEBUG("received packet with bogus transaction code %d", - tcode); + HPSB_NOTICE("received packet with bogus transaction code %d", + tcode); break; } } + static void abort_requests(struct hpsb_host *host) { - struct hpsb_packet *packet, *p; - struct list_head tmp; - unsigned long flags; + struct hpsb_packet *packet; + struct sk_buff *skb; host->driver->devctl(host, CANCEL_REQUESTS, 0); - INIT_LIST_HEAD(&tmp); - spin_lock_irqsave(&pending_packets_lock, flags); - list_splice_init(&host->pending_packets, &tmp); - spin_unlock_irqrestore(&pending_packets_lock, flags); + while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) { + packet = (struct hpsb_packet *)skb->data; - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; queue_packet_complete(packet); @@ -1068,90 +1002,87 @@ static void abort_requests(struct hpsb_host *host) void abort_timedouts(unsigned long __opaque) { struct hpsb_host *host = (struct hpsb_host *)__opaque; - struct hpsb_packet *packet, *p; - struct list_head tmp; - unsigned long flags, expire, j; + unsigned long flags; + struct hpsb_packet *packet; + struct sk_buff *skb; + unsigned long expire; spin_lock_irqsave(&host->csr.lock, flags); expire = host->csr.expire; spin_unlock_irqrestore(&host->csr.lock, flags); - j = jiffies; - INIT_LIST_HEAD(&tmp); - spin_lock_irqsave(&pending_packets_lock, flags); + /* Hold the lock around this, since we aren't dequeuing all + * packets, just ones we need. */ + spin_lock_irqsave(&host->pending_packet_queue.lock, flags); + + while (!skb_queue_empty(&host->pending_packet_queue)) { + skb = skb_peek(&host->pending_packet_queue); + + packet = (struct hpsb_packet *)skb->data; - list_for_each_entry_safe(packet, p, &host->pending_packets, queue) { - if (time_before(packet->sendtime + expire, j)) - list_move_tail(&packet->queue, &tmp); - else + if (time_before(packet->sendtime + expire, jiffies)) { + __skb_unlink(skb, &host->pending_packet_queue); + packet->state = hpsb_complete; + packet->ack_code = ACKX_TIMEOUT; + queue_packet_complete(packet); + } else { /* Since packets are added to the tail, the oldest * ones are first, always. When we get to one that * isn't timed out, the rest aren't either. */ break; + } } - if (!list_empty(&host->pending_packets)) - mod_timer(&host->timeout, j + host->timeout_interval); - spin_unlock_irqrestore(&pending_packets_lock, flags); + if (!skb_queue_empty(&host->pending_packet_queue)) + mod_timer(&host->timeout, jiffies + host->timeout_interval); - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); - packet->state = hpsb_complete; - packet->ack_code = ACKX_TIMEOUT; - queue_packet_complete(packet); - } + spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); } + +/* Kernel thread and vars, which handles packets that are completed. Only + * packets that have a "complete" function are sent here. This way, the + * completion is run out of kernel context, and doesn't block the rest of + * the stack. */ static struct task_struct *khpsbpkt_thread; -static LIST_HEAD(hpsbpkt_queue); +static struct sk_buff_head hpsbpkt_queue; static void queue_packet_complete(struct hpsb_packet *packet) { - unsigned long flags; - if (packet->no_waiter) { hpsb_free_packet(packet); return; } if (packet->complete_routine != NULL) { - spin_lock_irqsave(&pending_packets_lock, flags); - list_add_tail(&packet->queue, &hpsbpkt_queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); + skb_queue_tail(&hpsbpkt_queue, packet->skb); wake_up_process(khpsbpkt_thread); } return; } -/* - * Kernel thread which handles packets that are completed. This way the - * packet's "complete" function is asynchronously run in process context. - * Only packets which have a "complete" function may be sent here. - */ static int hpsbpkt_thread(void *__hi) { - struct hpsb_packet *packet, *p; - struct list_head tmp; - int may_schedule; + struct sk_buff *skb; + struct hpsb_packet *packet; + void (*complete_routine)(void*); + void *complete_data; current->flags |= PF_NOFREEZE; while (!kthread_should_stop()) { + while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) { + packet = (struct hpsb_packet *)skb->data; + + complete_routine = packet->complete_routine; + complete_data = packet->complete_data; - INIT_LIST_HEAD(&tmp); - spin_lock_irq(&pending_packets_lock); - list_splice_init(&hpsbpkt_queue, &tmp); - spin_unlock_irq(&pending_packets_lock); + packet->complete_routine = packet->complete_data = NULL; - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); - packet->complete_routine(packet->complete_data); + complete_routine(complete_data); } set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&pending_packets_lock); - may_schedule = list_empty(&hpsbpkt_queue); - spin_unlock_irq(&pending_packets_lock); - if (may_schedule) + if (!skb_peek(&hpsbpkt_queue)) schedule(); __set_current_state(TASK_RUNNING); } @@ -1162,6 +1093,8 @@ static int __init ieee1394_init(void) { int i, ret; + skb_queue_head_init(&hpsbpkt_queue); + /* non-fatal error */ if (hpsb_init_config_roms()) { HPSB_ERR("Failed to initialize some config rom entries.\n"); @@ -1335,6 +1268,7 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo); EXPORT_SYMBOL(hpsb_set_hostinfo_key); EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); EXPORT_SYMBOL(hpsb_set_hostinfo); +EXPORT_SYMBOL(highlevel_host_reset); /** nodemgr.c **/ EXPORT_SYMBOL(hpsb_node_fill_packet); @@ -1377,10 +1311,11 @@ EXPORT_SYMBOL(hpsb_iso_wake); EXPORT_SYMBOL(hpsb_iso_recv_flush); /** csr1212.c **/ +EXPORT_SYMBOL(csr1212_new_directory); EXPORT_SYMBOL(csr1212_attach_keyval_to_directory); EXPORT_SYMBOL(csr1212_detach_keyval_from_directory); -EXPORT_SYMBOL(csr1212_get_keyval); -EXPORT_SYMBOL(csr1212_new_directory); -EXPORT_SYMBOL(csr1212_parse_keyval); -EXPORT_SYMBOL(csr1212_read); EXPORT_SYMBOL(csr1212_release_keyval); +EXPORT_SYMBOL(csr1212_read); +EXPORT_SYMBOL(csr1212_parse_keyval); +EXPORT_SYMBOL(_csr1212_read_keyval); +EXPORT_SYMBOL(_csr1212_destroy_keyval); diff --git a/trunk/drivers/ieee1394/ieee1394_core.h b/trunk/drivers/ieee1394/ieee1394_core.h index ad526523d0ef..bd29d8ef5bbd 100644 --- a/trunk/drivers/ieee1394/ieee1394_core.h +++ b/trunk/drivers/ieee1394/ieee1394_core.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -12,7 +13,7 @@ struct hpsb_packet { /* This struct is basically read-only for hosts with the exception of - * the data buffer contents and driver_list. */ + * the data buffer contents and xnext - see below. */ /* This can be used for host driver internal linking. * @@ -48,65 +49,134 @@ struct hpsb_packet { /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */ unsigned speed_code:2; + /* + * *header and *data are guaranteed to be 32-bit DMAable and may be + * overwritten to allow in-place byte swapping. Neither of these is + * CRCed (the sizes also don't include CRC), but contain space for at + * least one additional quadlet to allow in-place CRCing. The memory is + * also guaranteed to be DMA mappable. + */ + quadlet_t *header; + quadlet_t *data; + size_t header_size; + size_t data_size; + struct hpsb_host *host; unsigned int generation; atomic_t refcnt; - struct list_head queue; /* Function (and possible data to pass to it) to call when this * packet is completed. */ void (*complete_routine)(void *); void *complete_data; + /* XXX This is just a hack at the moment */ + struct sk_buff *skb; + /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; - /* Sizes are in bytes. *data can be DMA-mapped. */ - size_t allocated_data_size; /* as allocated */ - size_t data_size; /* as filled in */ - size_t header_size; /* as filled in, not counting the CRC */ - quadlet_t *data; - quadlet_t header[5]; - quadlet_t embedded_data[0]; /* keep as last member */ + quadlet_t embedded_header[5]; }; +/* Set a task for when a packet completes */ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, void (*routine)(void *), void *data); + static inline struct hpsb_packet *driver_packet(struct list_head *l) { return list_entry(l, struct hpsb_packet, driver_list); } + void abort_timedouts(unsigned long __opaque); + struct hpsb_packet *hpsb_alloc_packet(size_t data_size); void hpsb_free_packet(struct hpsb_packet *packet); -/** - * get_hpsb_generation - generation counter for the complete 1394 subsystem +/* + * Generation counter for the complete 1394 subsystem. Generation gets + * incremented on every change in the subsystem (e.g. bus reset). * - * Generation gets incremented on every change in the subsystem (notably on bus - * resets). Use the functions, not the variable. + * Use the functions, not the variable. */ static inline unsigned int get_hpsb_generation(struct hpsb_host *host) { return atomic_read(&host->generation); } +/* + * Send a PHY configuration packet, return 0 on success, negative + * errno on failure. + */ int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt); + +/* + * Queue packet for transmitting, return 0 on success, negative errno + * on failure. + */ int hpsb_send_packet(struct hpsb_packet *packet); + +/* + * Queue packet for transmitting, and block until the transaction + * completes. Return 0 on success, negative errno on failure. + */ int hpsb_send_packet_and_wait(struct hpsb_packet *packet); + +/* Initiate bus reset on the given host. Returns 1 if bus reset already in + * progress, 0 otherwise. */ int hpsb_reset_bus(struct hpsb_host *host, int type); + int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, u64 *local_time); +/* + * The following functions are exported for host driver module usage. All of + * them are safe to use in interrupt contexts, although some are quite + * complicated so you may want to run them in bottom halves instead of calling + * them directly. + */ + +/* Notify a bus reset to the core. Returns 1 if bus reset already in progress, + * 0 otherwise. */ int hpsb_bus_reset(struct hpsb_host *host); + +/* + * Hand over received selfid packet to the core. Complement check (second + * quadlet is complement of first) is expected to be done and successful. + */ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); + +/* + * Notify completion of SelfID stage to the core and report new physical ID + * and whether host is root now. + */ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot); + +/* + * Notify core of sending a packet. Ackcode is the ack code returned for async + * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE + * for other cases (internal errors that don't justify a panic). Safe to call + * from within a transmit packet routine. + */ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode); + +/* + * Hand over received packet to the core. The contents of data are expected to + * be the full packet but with the CRCs left out (data block follows header + * immediately), with the header (i.e. the first four quadlets) in machine byte + * order and the data block in big endian. *data can be safely overwritten + * after this call. + * + * If the packet is a write request, write_acked is to be set to true if it was + * ack_complete'd already, false otherwise. This arg is ignored for any other + * packet type. + */ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, int write_acked); + /* * CHARACTER DEVICE DISPATCHING * @@ -147,9 +217,7 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, #define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \ IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16) -/** - * ieee1394_file_to_instance - get the index within a minor number block - */ +/* return the index (within a minor number block) of a file */ static inline unsigned char ieee1394_file_to_instance(struct file *file) { return file->f_path.dentry->d_inode->i_cindex; diff --git a/trunk/drivers/ieee1394/ieee1394_transactions.c b/trunk/drivers/ieee1394/ieee1394_transactions.c index 40078ce930c8..0833fc9f50c4 100644 --- a/trunk/drivers/ieee1394/ieee1394_transactions.c +++ b/trunk/drivers/ieee1394/ieee1394_transactions.c @@ -10,16 +10,11 @@ */ #include -#include -#include #include -#include -#include /* because linux/wait.h is broken if CONFIG_SMP=n */ #include #include #include -#include #include "ieee1394.h" #include "ieee1394_types.h" @@ -37,7 +32,7 @@ #ifndef HPSB_DEBUG_TLABELS static #endif -DEFINE_SPINLOCK(hpsb_tlabel_lock); +spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED; static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq); @@ -217,15 +212,6 @@ void hpsb_free_tlabel(struct hpsb_packet *packet) wake_up_interruptible(&tlabel_wq); } -/** - * hpsb_packet_success - Make sense of the ack and reply codes - * - * Make sense of the ack and reply codes and return more convenient error codes: - * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can - * probably resolved by retry. -%EREMOTEIO = node suffers from an internal - * error. -%EACCES = this transaction is not allowed on requested address. - * -%EINVAL = invalid address at node. - */ int hpsb_packet_success(struct hpsb_packet *packet) { switch (packet->ack_code) { @@ -378,13 +364,6 @@ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer, } packet->host = host; - /* Because it is too difficult to determine all PHY speeds and link - * speeds here, we use S100... */ - packet->speed_code = IEEE1394_SPEED_100; - - /* ...and prevent hpsb_send_packet() from overriding it. */ - packet->node_id = LOCAL_BUS | ALL_NODES; - if (hpsb_get_tlabel(packet)) { hpsb_free_packet(packet); return NULL; @@ -514,16 +493,6 @@ struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, * avoid in kernel buffers for user space callers */ -/** - * hpsb_read - generic read function - * - * Recognizes the local node ID and act accordingly. Automatically uses a - * quadlet read request if @length == 4 and and a block read request otherwise. - * It does not yet support lengths that are not a multiple of 4. - * - * You must explicitly specifiy the @generation for which the node ID is valid, - * to avoid sending packets to the wrong nodes when we race with a bus reset. - */ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t * buffer, size_t length) { @@ -563,16 +532,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, return retval; } -/** - * hpsb_write - generic write function - * - * Recognizes the local node ID and act accordingly. Automatically uses a - * quadlet write request if @length == 4 and and a block write request - * otherwise. It does not yet support lengths that are not a multiple of 4. - * - * You must explicitly specifiy the @generation for which the node ID is valid, - * to avoid sending packets to the wrong nodes when we race with a bus reset. - */ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t * buffer, size_t length) { diff --git a/trunk/drivers/ieee1394/ieee1394_transactions.h b/trunk/drivers/ieee1394/ieee1394_transactions.h index 86b8ee692ea7..c1369c41469b 100644 --- a/trunk/drivers/ieee1394/ieee1394_transactions.h +++ b/trunk/drivers/ieee1394/ieee1394_transactions.h @@ -27,7 +27,27 @@ struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer, int length, int channel, int tag, int sync); + +/* + * hpsb_packet_success - Make sense of the ack and reply codes and + * return more convenient error codes: + * 0 success + * -EBUSY node is busy, try again + * -EAGAIN error which can probably resolved by retry + * -EREMOTEIO node suffers from an internal error + * -EACCES this transaction is not allowed on requested address + * -EINVAL invalid address at node + */ int hpsb_packet_success(struct hpsb_packet *packet); + +/* + * The generic read and write functions. All recognize the local node ID + * and act accordingly. Read and write automatically use quadlet commands if + * length == 4 and and block commands otherwise (however, they do not yet + * support lengths that are not a multiple of 4). You must explicitly specifiy + * the generation for which the node ID is valid, to avoid sending packets to + * the wrong nodes when we race with a bus reset. + */ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t *buffer, size_t length); int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, diff --git a/trunk/drivers/ieee1394/iso.c b/trunk/drivers/ieee1394/iso.c index 07ca35c98f96..c6227e51136d 100644 --- a/trunk/drivers/ieee1394/iso.c +++ b/trunk/drivers/ieee1394/iso.c @@ -10,15 +10,11 @@ */ #include -#include #include #include "hosts.h" #include "iso.h" -/** - * hpsb_iso_stop - stop DMA - */ void hpsb_iso_stop(struct hpsb_iso *iso) { if (!(iso->flags & HPSB_ISO_DRIVER_STARTED)) @@ -29,9 +25,6 @@ void hpsb_iso_stop(struct hpsb_iso *iso) iso->flags &= ~HPSB_ISO_DRIVER_STARTED; } -/** - * hpsb_iso_shutdown - deallocate buffer and DMA context - */ void hpsb_iso_shutdown(struct hpsb_iso *iso) { if (iso->flags & HPSB_ISO_DRIVER_INIT) { @@ -137,9 +130,6 @@ static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host, return NULL; } -/** - * hpsb_iso_n_ready - returns number of packets ready to send or receive - */ int hpsb_iso_n_ready(struct hpsb_iso *iso) { unsigned long flags; @@ -152,9 +142,6 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso) return val; } -/** - * hpsb_iso_xmit_init - allocate the buffer and DMA context - */ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host, unsigned int data_buf_size, unsigned int buf_packets, @@ -185,11 +172,6 @@ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host, return NULL; } -/** - * hpsb_iso_recv_init - allocate the buffer and DMA context - * - * Note, if channel = -1, multi-channel receive is enabled. - */ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host, unsigned int data_buf_size, unsigned int buf_packets, @@ -217,11 +199,6 @@ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host, return NULL; } -/** - * hpsb_iso_recv_listen_channel - * - * multi-channel only - */ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) { if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) @@ -229,11 +206,6 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel); } -/** - * hpsb_iso_recv_unlisten_channel - * - * multi-channel only - */ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) { if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) @@ -241,11 +213,6 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel); } -/** - * hpsb_iso_recv_set_channel_mask - * - * multi-channel only - */ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) { if (iso->type != HPSB_ISO_RECV || iso->channel != -1) @@ -254,12 +221,6 @@ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) (unsigned long)&mask); } -/** - * hpsb_iso_recv_flush - check for arrival of new packets - * - * check for arrival of new packets immediately (even if irq_interval - * has not yet been reached) - */ int hpsb_iso_recv_flush(struct hpsb_iso *iso) { if (iso->type != HPSB_ISO_RECV) @@ -277,9 +238,6 @@ static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) return retval; } -/** - * hpsb_iso_xmit_start - start DMA - */ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) { if (iso->type != HPSB_ISO_XMIT) @@ -312,9 +270,6 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) return 0; } -/** - * hpsb_iso_recv_start - start DMA - */ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) { int retval = 0; @@ -351,7 +306,8 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) } /* check to make sure the user has not supplied bogus values of offset/len - * that would cause the kernel to access memory outside the buffer */ + that would cause the kernel to access memory outside the buffer */ + static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, unsigned int offset, unsigned short len, unsigned int *out_offset, @@ -375,12 +331,6 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, return 0; } -/** - * hpsb_iso_xmit_queue_packet - queue a packet for transmission. - * - * @offset is relative to the beginning of the DMA buffer, where the packet's - * data payload should already have been placed. - */ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy) { @@ -430,9 +380,6 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, return rv; } -/** - * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted - */ int hpsb_iso_xmit_sync(struct hpsb_iso *iso) { if (iso->type != HPSB_ISO_XMIT) @@ -443,15 +390,6 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso) iso->buf_packets); } -/** - * hpsb_iso_packet_sent - * - * Available to low-level drivers. - * - * Call after a packet has been transmitted to the bus (interrupt context is - * OK). @cycle is the _exact_ cycle the packet was sent on. @error should be - * non-zero if some sort of error occurred when sending the packet. - */ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) { unsigned long flags; @@ -475,13 +413,6 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) spin_unlock_irqrestore(&iso->lock, flags); } -/** - * hpsb_iso_packet_received - * - * Available to low-level drivers. - * - * Call after a packet has been received (interrupt context is OK). - */ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy) @@ -511,11 +442,6 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, spin_unlock_irqrestore(&iso->lock, flags); } -/** - * hpsb_iso_recv_release_packets - release packets, reuse buffer - * - * @n_packets have been read out of the buffer, re-use the buffer space - */ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) { unsigned long flags; @@ -551,13 +477,6 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) return rv; } -/** - * hpsb_iso_wake - * - * Available to low-level drivers. - * - * Call to wake waiting processes after buffer space has opened up. - */ void hpsb_iso_wake(struct hpsb_iso *iso) { wake_up_interruptible(&iso->waitq); diff --git a/trunk/drivers/ieee1394/iso.h b/trunk/drivers/ieee1394/iso.h index b94e55e6eaa5..1210a97e8685 100644 --- a/trunk/drivers/ieee1394/iso.h +++ b/trunk/drivers/ieee1394/iso.h @@ -150,6 +150,8 @@ struct hpsb_iso { /* functions available to high-level drivers (e.g. raw1394) */ +/* allocate the buffer and DMA context */ + struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, unsigned int data_buf_size, unsigned int buf_packets, @@ -157,6 +159,8 @@ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, int speed, int irq_interval, void (*callback)(struct hpsb_iso*)); + +/* note: if channel = -1, multi-channel receive is enabled */ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, unsigned int data_buf_size, unsigned int buf_packets, @@ -164,29 +168,56 @@ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, int dma_mode, int irq_interval, void (*callback)(struct hpsb_iso*)); + +/* multi-channel only */ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); + +/* start/stop DMA */ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync); void hpsb_iso_stop(struct hpsb_iso *iso); + +/* deallocate buffer and DMA context */ void hpsb_iso_shutdown(struct hpsb_iso *iso); + +/* queue a packet for transmission. + * 'offset' is relative to the beginning of the DMA buffer, where the packet's + * data payload should already have been placed. */ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy); + +/* wait until all queued packets have been transmitted to the bus */ int hpsb_iso_xmit_sync(struct hpsb_iso *iso); -int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, - unsigned int n_packets); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, + unsigned int n_packets); + +/* check for arrival of new packets immediately (even if irq_interval + * has not yet been reached) */ int hpsb_iso_recv_flush(struct hpsb_iso *iso); + +/* returns # of packets ready to send or receive */ int hpsb_iso_n_ready(struct hpsb_iso *iso); /* the following are callbacks available to low-level drivers */ +/* call after a packet has been transmitted to the bus (interrupt context is OK) + * 'cycle' is the _exact_ cycle the packet was sent on + * 'error' should be non-zero if some sort of error occurred when sending the + * packet */ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); + +/* call after a packet has been received (interrupt context OK) */ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy); + +/* call to wake waiting processes after buffer space has opened up. */ void hpsb_iso_wake(struct hpsb_iso *iso); #endif /* IEEE1394_ISO_H */ diff --git a/trunk/drivers/ieee1394/nodemgr.c b/trunk/drivers/ieee1394/nodemgr.c index 6a1a0572275e..c5ace190bfe6 100644 --- a/trunk/drivers/ieee1394/nodemgr.c +++ b/trunk/drivers/ieee1394/nodemgr.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -116,7 +115,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci) { - return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3; + return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3; } static struct csr1212_bus_ops nodemgr_csr_ops = { @@ -371,7 +370,9 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute if (state == 1) { ud->ignore_driver = 1; + down_write(&ieee1394_bus_type.subsys.rwsem); device_release_driver(dev); + up_write(&ieee1394_bus_type.subsys.rwsem); } else if (state == 0) ud->ignore_driver = 0; @@ -581,7 +582,7 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute"); + HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name); } @@ -605,7 +606,8 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute"); + HPSB_ERR("Failed to add sysfs attribute for node %016Lx", + (unsigned long long)ne->guid); } @@ -619,7 +621,7 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute"); + HPSB_ERR("Failed to add sysfs attribute for host %d", host->id); } @@ -679,7 +681,8 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud) } return; fail: - HPSB_ERR("Failed to add sysfs attribute"); + HPSB_ERR("Failed to add sysfs attributes for unit %s", + ud->device.bus_id); } @@ -1143,13 +1146,13 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent last_key_id = kv->key.id; } - if (ne->vendor_name_kv) { - int error = device_create_file(&ne->device, - &dev_attr_ne_vendor_name_kv); - - if (error && error != -EEXIST) - HPSB_ERR("Failed to add sysfs attribute"); - } + if (ne->vendor_name_kv && + device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv)) + goto fail; + return; +fail: + HPSB_ERR("Failed to add sysfs attribute for node %016Lx", + (unsigned long long)ne->guid); } #ifdef CONFIG_HOTPLUG @@ -1160,7 +1163,6 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, struct unit_directory *ud; int i = 0; int length = 0; - int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1174,11 +1176,14 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ - if (retval) \ - return retval; \ + int printed; \ + envp[i++] = buffer; \ + printed = snprintf(buffer, buffer_size - length, \ + fmt, val); \ + if ((buffer_size - (length+printed) <= 0) || (i >= num_envp)) \ + return -ENOMEM; \ + length += printed+1; \ + buffer += printed+1; \ } while (0) PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id); @@ -1388,10 +1393,12 @@ static void nodemgr_suspend_ne(struct node_entry *ne) if (ud->ne != ne) continue; + down_write(&ieee1394_bus_type.subsys.rwsem); if (ud->device.driver && (!ud->device.driver->suspend || ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) device_release_driver(&ud->device); + up_write(&ieee1394_bus_type.subsys.rwsem); } up(&nodemgr_ud_class.sem); } @@ -1411,8 +1418,10 @@ static void nodemgr_resume_ne(struct node_entry *ne) if (ud->ne != ne) continue; + down_read(&ieee1394_bus_type.subsys.rwsem); if (ud->device.driver && ud->device.driver->resume) ud->device.driver->resume(&ud->device); + up_read(&ieee1394_bus_type.subsys.rwsem); } up(&nodemgr_ud_class.sem); @@ -1433,6 +1442,7 @@ static void nodemgr_update_pdrv(struct node_entry *ne) if (ud->ne != ne) continue; + down_write(&ieee1394_bus_type.subsys.rwsem); if (ud->device.driver) { pdrv = container_of(ud->device.driver, struct hpsb_protocol_driver, @@ -1440,6 +1450,7 @@ static void nodemgr_update_pdrv(struct node_entry *ne) if (pdrv->update && pdrv->update(ud)) device_release_driver(&ud->device); } + up_write(&ieee1394_bus_type.subsys.rwsem); } up(&nodemgr_ud_class.sem); } @@ -1737,19 +1748,7 @@ static int nodemgr_host_thread(void *__hi) return 0; } -/** - * nodemgr_for_each_host - call a function for each IEEE 1394 host - * @data: an address to supply to the callback - * @cb: function to call for each host - * - * Iterate the hosts, calling a given function with supplied data for each host. - * If the callback fails on a host, i.e. if it returns a non-zero value, the - * iteration is stopped. - * - * Return value: 0 on success, non-zero on failure (same as returned by last run - * of the callback). - */ -int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) +int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) { struct class_device *cdev; struct hpsb_host *host; @@ -1759,7 +1758,7 @@ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) list_for_each_entry(cdev, &hpsb_host_class.children, node) { host = container_of(cdev, struct hpsb_host, class_dev); - if ((error = cb(host, data))) + if ((error = cb(host, __data))) break; } up(&hpsb_host_class.sem); @@ -1767,7 +1766,7 @@ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) return error; } -/* The following two convenience functions use a struct node_entry +/* The following four convenience functions use a struct node_entry * for addressing a node on the bus. They are intended for use by any * process context, not just the nodemgr thread, so we need to be a * little careful when reading out the node ID and generation. The @@ -1782,20 +1781,12 @@ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) * ID's. */ -/** - * hpsb_node_fill_packet - fill some destination information into a packet - * @ne: destination node - * @packet: packet to fill in - * - * This will fill in the given, pre-initialised hpsb_packet with the current - * information from the node entry (host, node ID, bus generation number). - */ -void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet) +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) { - packet->host = ne->host; - packet->generation = ne->generation; + pkt->host = ne->host; + pkt->generation = ne->generation; barrier(); - packet->node_id = ne->nodeid; + pkt->node_id = ne->nodeid; } int hpsb_node_write(struct node_entry *ne, u64 addr, diff --git a/trunk/drivers/ieee1394/nodemgr.h b/trunk/drivers/ieee1394/nodemgr.h index e7ac683c72c7..4147303ad448 100644 --- a/trunk/drivers/ieee1394/nodemgr.h +++ b/trunk/drivers/ieee1394/nodemgr.h @@ -153,10 +153,30 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne) { return ne->generation == get_hpsb_generation(ne->host); } -void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet); + +/* + * This will fill in the given, pre-initialised hpsb_packet with the current + * information from the node entry (host, node ID, generation number). It will + * return false if the node owning the GUID is not accessible (and not modify + * the hpsb_packet) and return true otherwise. + * + * Note that packet sending may still fail in hpsb_send_packet if a bus reset + * happens while you are trying to set up the packet (due to obsolete generation + * number). It will at least reliably fail so that you don't accidentally and + * unknowingly send your packet to the wrong node. + */ +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt); + +int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length); int hpsb_node_write(struct node_entry *ne, u64 addr, quadlet_t *buffer, size_t length); -int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)); +int hpsb_node_lock(struct node_entry *ne, u64 addr, + int extcode, quadlet_t *data, quadlet_t arg); + +/* Iterate the hosts, calling a given function with supplied data for each + * host. */ +int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)); int init_ieee1394_nodemgr(void); void cleanup_ieee1394_nodemgr(void); diff --git a/trunk/drivers/ieee1394/ohci1394.c b/trunk/drivers/ieee1394/ohci1394.c index 5dadfd296f79..06fac0d21264 100644 --- a/trunk/drivers/ieee1394/ohci1394.c +++ b/trunk/drivers/ieee1394/ohci1394.c @@ -507,8 +507,9 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Set up self-id dma buffer */ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); - /* enable self-id */ - reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID); + /* enable self-id and phys */ + reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID | + OHCI1394_LinkControl_RcvPhyPkt); /* Set the Config ROM mapping register */ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); @@ -517,6 +518,9 @@ static void ohci_initialize(struct ti_ohci *ohci) ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); + /* Don't accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); + /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); @@ -613,7 +617,7 @@ static void ohci_initialize(struct ti_ohci *ohci) #endif PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, " - "attempting to set max_packet_size to 512 bytes"); + "attempting to setting max_packet_size to 512 bytes"); reg_write(ohci, OHCI1394_BusOptions, (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002); ohci->max_packet_size = 512; @@ -2373,7 +2377,6 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id) if (event & OHCI1394_postedWriteErr) { PRINT(KERN_ERR, "physical posted write error"); /* no recovery strategy yet, had to involve protocol drivers */ - event &= ~OHCI1394_postedWriteErr; } if (event & OHCI1394_cycleTooLong) { if(printk_ratelimit()) @@ -3655,7 +3658,6 @@ static struct pci_driver ohci1394_pci_driver = { /* essentially the only purpose of this code is to allow another module to hook into ohci's interrupt handler */ -/* returns zero if successful, one if DMA context is locked up */ int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) { int i=0; diff --git a/trunk/drivers/ieee1394/ohci1394.h b/trunk/drivers/ieee1394/ohci1394.h index f1ad539e7c1b..fa05f113f7f0 100644 --- a/trunk/drivers/ieee1394/ohci1394.h +++ b/trunk/drivers/ieee1394/ohci1394.h @@ -461,7 +461,9 @@ int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, struct ohci1394_iso_tasklet *tasklet); void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, struct ohci1394_iso_tasklet *tasklet); -int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg); + +/* returns zero if successful, one if DMA context is locked up */ +int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); struct ti_ohci *ohci1394_get_struct(int card_num); #endif diff --git a/trunk/drivers/ieee1394/raw1394.c b/trunk/drivers/ieee1394/raw1394.c index c6aefd9ad0e8..bb897a37d9f7 100644 --- a/trunk/drivers/ieee1394/raw1394.c +++ b/trunk/drivers/ieee1394/raw1394.c @@ -938,8 +938,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req) int header_length = req->req.misc & 0xffff; int expect_response = req->req.misc >> 16; - if (header_length > req->req.length || header_length < 12 || - header_length > FIELD_SIZEOF(struct hpsb_packet, header)) { + if ((header_length > req->req.length) || (header_length < 12)) { req->req.error = RAW1394_ERROR_INVALID_ARG; req->req.length = 0; queue_complete_req(req); diff --git a/trunk/drivers/ieee1394/sbp2.c b/trunk/drivers/ieee1394/sbp2.c index 4cb6fa2bcfb7..4edfff46b1e6 100644 --- a/trunk/drivers/ieee1394/sbp2.c +++ b/trunk/drivers/ieee1394/sbp2.c @@ -59,10 +59,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -471,13 +469,19 @@ static void sbp2util_write_doorbell(struct work_struct *work) static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) { struct sbp2_fwhost_info *hi = lu->hi; + int i; + unsigned long flags, orbs; struct sbp2_command_info *cmd; - int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS; + orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS; + + spin_lock_irqsave(&lu->cmd_orb_lock, flags); for (i = 0; i < orbs; i++) { - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) { + spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return -ENOMEM; + } cmd->command_orb_dma = dma_map_single(hi->host->device.parent, &cmd->command_orb, sizeof(struct sbp2_command_orb), @@ -485,10 +489,11 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) cmd->sge_dma = dma_map_single(hi->host->device.parent, &cmd->scatter_gather_element, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); INIT_LIST_HEAD(&cmd->list); list_add_tail(&cmd->list, &lu->cmd_orb_completed); } + spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return 0; } @@ -509,7 +514,7 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu) DMA_TO_DEVICE); dma_unmap_single(host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); kfree(cmd); } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); @@ -752,11 +757,6 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud) SBP2_ERR("failed to register lower 4GB address range"); goto failed_alloc; } -#else - if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) { - SBP2_ERR("failed to set 4GB DMA mask"); - goto failed_alloc; - } #endif } @@ -865,8 +865,11 @@ static int sbp2_start_device(struct sbp2_lu *lu) if (!lu->login_orb) goto alloc_fail; - if (sbp2util_create_command_orb_pool(lu)) - goto alloc_fail; + if (sbp2util_create_command_orb_pool(lu)) { + SBP2_ERR("sbp2util_create_command_orb_pool failed!"); + sbp2_remove_device(lu); + return -ENOMEM; + } /* Wait a second before trying to log in. Previously logged in * initiators need a chance to reconnect. */ @@ -1625,7 +1628,7 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu, DMA_TO_DEVICE); dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); /* check to see if there are any previous orbs to use */ spin_lock_irqsave(&lu->cmd_orb_lock, flags); @@ -1791,7 +1794,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, DMA_TO_DEVICE); dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); /* Grab SCSI command pointers and check status. */ /* * FIXME: If the src field in the status is 1, the ORB DMA must @@ -1923,7 +1926,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status) DMA_TO_DEVICE); dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); if (cmd->Current_SCpnt) { cmd->Current_SCpnt->result = status << 16; @@ -2054,7 +2057,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(lu, cmd); if (cmd->Current_SCpnt) { cmd->Current_SCpnt->result = DID_ABORT << 16; diff --git a/trunk/drivers/ieee1394/sbp2.h b/trunk/drivers/ieee1394/sbp2.h index 44402b9d82a8..9ae842329bf3 100644 --- a/trunk/drivers/ieee1394/sbp2.h +++ b/trunk/drivers/ieee1394/sbp2.h @@ -250,15 +250,15 @@ enum sbp2_dma_types { /* Per SCSI command */ struct sbp2_command_info { struct list_head list; - struct sbp2_command_orb command_orb; - dma_addr_t command_orb_dma; + struct sbp2_command_orb command_orb ____cacheline_aligned; + dma_addr_t command_orb_dma ____cacheline_aligned; struct scsi_cmnd *Current_SCpnt; void (*Current_done)(struct scsi_cmnd *); /* Also need s/g structure for each sbp2 command */ struct sbp2_unrestricted_page_table - scatter_gather_element[SG_ALL] __attribute__((aligned(8))); - dma_addr_t sge_dma; + scatter_gather_element[SG_ALL] ____cacheline_aligned; + dma_addr_t sge_dma ____cacheline_aligned; void *sge_buffer; dma_addr_t cmd_dma; enum sbp2_dma_types dma_type; diff --git a/trunk/drivers/infiniband/core/cm.c b/trunk/drivers/infiniband/core/cm.c index eff591deeb46..842cd0b53e91 100644 --- a/trunk/drivers/infiniband/core/cm.c +++ b/trunk/drivers/infiniband/core/cm.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/infiniband/core/iwcm.c b/trunk/drivers/infiniband/core/iwcm.c index 223b1aa7d92b..891d1fa7b2eb 100644 --- a/trunk/drivers/infiniband/core/iwcm.c +++ b/trunk/drivers/infiniband/core/iwcm.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/infiniband/core/mad.c b/trunk/drivers/infiniband/core/mad.c index 6edfecf1be72..13efd4170349 100644 --- a/trunk/drivers/infiniband/core/mad.c +++ b/trunk/drivers/infiniband/core/mad.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. * @@ -31,6 +31,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * + * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ */ #include #include @@ -667,7 +668,7 @@ static void build_smp_wc(struct ib_qp *qp, static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, struct ib_mad_send_wr_private *mad_send_wr) { - int ret = 0; + int ret; struct ib_smp *smp = mad_send_wr->send_buf.mad; unsigned long flags; struct ib_mad_local_private *local; @@ -687,15 +688,14 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, */ if ((ib_get_smp_direction(smp) ? smp->dr_dlid : smp->dr_slid) == IB_LID_PERMISSIVE && - smi_handle_dr_smp_send(smp, device->node_type, port_num) == - IB_SMI_DISCARD) { + !smi_handle_dr_smp_send(smp, device->node_type, port_num)) { ret = -EINVAL; printk(KERN_ERR PFX "Invalid directed route\n"); goto out; } - /* Check to post send on QP or process locally */ - if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD) + ret = smi_check_local_smp(smp, device); + if (!ret) goto out; local = kmalloc(sizeof *local, GFP_ATOMIC); @@ -1874,22 +1874,18 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, if (recv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - if (smi_handle_dr_smp_recv(&recv->mad.smp, - port_priv->device->node_type, - port_priv->port_num, - port_priv->device->phys_port_cnt) == - IB_SMI_DISCARD) + if (!smi_handle_dr_smp_recv(&recv->mad.smp, + port_priv->device->node_type, + port_priv->port_num, + port_priv->device->phys_port_cnt)) goto out; - - if (smi_check_forward_dr_smp(&recv->mad.smp) == IB_SMI_LOCAL) + if (!smi_check_forward_dr_smp(&recv->mad.smp)) goto local; - - if (smi_handle_dr_smp_send(&recv->mad.smp, - port_priv->device->node_type, - port_priv->port_num) == IB_SMI_DISCARD) + if (!smi_handle_dr_smp_send(&recv->mad.smp, + port_priv->device->node_type, + port_priv->port_num)) goto out; - - if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD) + if (!smi_check_local_smp(&recv->mad.smp, port_priv->device)) goto out; } diff --git a/trunk/drivers/infiniband/core/mad_priv.h b/trunk/drivers/infiniband/core/mad_priv.h index 9be5cc00a3a9..de89717f49fe 100644 --- a/trunk/drivers/infiniband/core/mad_priv.h +++ b/trunk/drivers/infiniband/core/mad_priv.h @@ -39,6 +39,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/infiniband/core/multicast.c b/trunk/drivers/infiniband/core/multicast.c index 1e13ab42b70b..4a579b3a1c90 100644 --- a/trunk/drivers/infiniband/core/multicast.c +++ b/trunk/drivers/infiniband/core/multicast.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/infiniband/core/sa_query.c b/trunk/drivers/infiniband/core/sa_query.c index 6469406ea9d8..68db633711c5 100644 --- a/trunk/drivers/infiniband/core/sa_query.c +++ b/trunk/drivers/infiniband/core/sa_query.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,6 @@ MODULE_LICENSE("Dual BSD/GPL"); struct ib_sa_sm_ah { struct ib_ah *ah; struct kref ref; - u8 src_path_mask; }; struct ib_sa_port { @@ -380,7 +380,6 @@ static void update_sm_ah(struct work_struct *work) } kref_init(&new_ah->ref); - new_ah->src_path_mask = (1 << port_attr.lmc) - 1; memset(&ah_attr, 0, sizeof ah_attr); ah_attr.dlid = port_attr.sm_lid; @@ -461,25 +460,6 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) } EXPORT_SYMBOL(ib_sa_cancel_query); -static u8 get_src_path_mask(struct ib_device *device, u8 port_num) -{ - struct ib_sa_device *sa_dev; - struct ib_sa_port *port; - unsigned long flags; - u8 src_path_mask; - - sa_dev = ib_get_client_data(device, &sa_client); - if (!sa_dev) - return 0x7f; - - port = &sa_dev->port[port_num - sa_dev->start_port]; - spin_lock_irqsave(&port->ah_lock, flags); - src_path_mask = port->sm_ah ? port->sm_ah->src_path_mask : 0x7f; - spin_unlock_irqrestore(&port->ah_lock, flags); - - return src_path_mask; -} - int ib_init_ah_from_path(struct ib_device *device, u8 port_num, struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr) { @@ -489,8 +469,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, memset(ah_attr, 0, sizeof *ah_attr); ah_attr->dlid = be16_to_cpu(rec->dlid); ah_attr->sl = rec->sl; - ah_attr->src_path_bits = be16_to_cpu(rec->slid) & - get_src_path_mask(device, port_num); + ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; ah_attr->port_num = port_num; ah_attr->static_rate = rec->rate; diff --git a/trunk/drivers/infiniband/core/smi.c b/trunk/drivers/infiniband/core/smi.c index 2bca753eb622..54b81e17ad50 100644 --- a/trunk/drivers/infiniband/core/smi.c +++ b/trunk/drivers/infiniband/core/smi.c @@ -3,7 +3,7 @@ * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. - * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. * * This software is available to you under a choice of one of two @@ -34,6 +34,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * + * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $ */ #include @@ -43,8 +44,9 @@ * Fixup a directed route SMP for sending * Return 0 if the SMP should be discarded */ -enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, - u8 node_type, int port_num) +int smi_handle_dr_smp_send(struct ib_smp *smp, + u8 node_type, + int port_num) { u8 hop_ptr, hop_cnt; @@ -57,18 +59,18 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, if (hop_cnt && hop_ptr == 0) { smp->hop_ptr++; return (smp->initial_path[smp->hop_ptr] == - port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + port_num); } /* C14-9:2 */ if (hop_ptr && hop_ptr < hop_cnt) { if (node_type != RDMA_NODE_IB_SWITCH) - return IB_SMI_DISCARD; + return 0; /* smp->return_path set when received */ smp->hop_ptr++; return (smp->initial_path[smp->hop_ptr] == - port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + port_num); } /* C14-9:3 -- We're at the end of the DR segment of path */ @@ -76,30 +78,29 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, /* smp->return_path set when received */ smp->hop_ptr++; return (node_type == RDMA_NODE_IB_SWITCH || - smp->dr_dlid == IB_LID_PERMISSIVE ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + smp->dr_dlid == IB_LID_PERMISSIVE); } /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ /* C14-9:5 -- Fail unreasonable hop pointer */ - return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + return (hop_ptr == hop_cnt + 1); } else { /* C14-13:1 */ if (hop_cnt && hop_ptr == hop_cnt + 1) { smp->hop_ptr--; return (smp->return_path[smp->hop_ptr] == - port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + port_num); } /* C14-13:2 */ if (2 <= hop_ptr && hop_ptr <= hop_cnt) { if (node_type != RDMA_NODE_IB_SWITCH) - return IB_SMI_DISCARD; + return 0; smp->hop_ptr--; return (smp->return_path[smp->hop_ptr] == - port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + port_num); } /* C14-13:3 -- at the end of the DR segment of path */ @@ -107,16 +108,15 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, smp->hop_ptr--; /* C14-13:3 -- SMPs destined for SM shouldn't be here */ return (node_type == RDMA_NODE_IB_SWITCH || - smp->dr_slid == IB_LID_PERMISSIVE ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + smp->dr_slid == IB_LID_PERMISSIVE); } /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ if (hop_ptr == 0) - return IB_SMI_HANDLE; + return 1; /* C14-13:5 -- Check for unreasonable hop pointer */ - return IB_SMI_DISCARD; + return 0; } } @@ -124,8 +124,10 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, * Adjust information for a received SMP * Return 0 if the SMP should be dropped */ -enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, - int port_num, int phys_port_cnt) +int smi_handle_dr_smp_recv(struct ib_smp *smp, + u8 node_type, + int port_num, + int phys_port_cnt) { u8 hop_ptr, hop_cnt; @@ -136,17 +138,16 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, if (!ib_get_smp_direction(smp)) { /* C14-9:1 -- sender should have incremented hop_ptr */ if (hop_cnt && hop_ptr == 0) - return IB_SMI_DISCARD; + return 0; /* C14-9:2 -- intermediate hop */ if (hop_ptr && hop_ptr < hop_cnt) { if (node_type != RDMA_NODE_IB_SWITCH) - return IB_SMI_DISCARD; + return 0; smp->return_path[hop_ptr] = port_num; /* smp->hop_ptr updated when sending */ - return (smp->initial_path[hop_ptr+1] <= phys_port_cnt ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + return (smp->initial_path[hop_ptr+1] <= phys_port_cnt); } /* C14-9:3 -- We're at the end of the DR segment of path */ @@ -156,13 +157,12 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, /* smp->hop_ptr updated when sending */ return (node_type == RDMA_NODE_IB_SWITCH || - smp->dr_dlid == IB_LID_PERMISSIVE ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + smp->dr_dlid == IB_LID_PERMISSIVE); } /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ /* C14-9:5 -- fail unreasonable hop pointer */ - return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + return (hop_ptr == hop_cnt + 1); } else { @@ -170,17 +170,16 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, if (hop_cnt && hop_ptr == hop_cnt + 1) { smp->hop_ptr--; return (smp->return_path[smp->hop_ptr] == - port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + port_num); } /* C14-13:2 */ if (2 <= hop_ptr && hop_ptr <= hop_cnt) { if (node_type != RDMA_NODE_IB_SWITCH) - return IB_SMI_DISCARD; + return 0; /* smp->hop_ptr updated when sending */ - return (smp->return_path[hop_ptr-1] <= phys_port_cnt ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + return (smp->return_path[hop_ptr-1] <= phys_port_cnt); } /* C14-13:3 -- We're at the end of the DR segment of path */ @@ -188,20 +187,23 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, if (smp->dr_slid == IB_LID_PERMISSIVE) { /* giving SMP to SM - update hop_ptr */ smp->hop_ptr--; - return IB_SMI_HANDLE; + return 1; } /* smp->hop_ptr updated when sending */ - return (node_type == RDMA_NODE_IB_SWITCH ? - IB_SMI_HANDLE: IB_SMI_DISCARD); + return (node_type == RDMA_NODE_IB_SWITCH); } /* C14-13:4 -- hop_ptr = 0 -> give to SM */ /* C14-13:5 -- Check for unreasonable hop pointer */ - return (hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + return (hop_ptr == 0); } } -enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) +/* + * Return 1 if the received DR SMP should be forwarded to the send queue + * Return 0 if the SMP should be completed up the stack + */ +int smi_check_forward_dr_smp(struct ib_smp *smp) { u8 hop_ptr, hop_cnt; @@ -211,25 +213,23 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) if (!ib_get_smp_direction(smp)) { /* C14-9:2 -- intermediate hop */ if (hop_ptr && hop_ptr < hop_cnt) - return IB_SMI_SEND; + return 1; /* C14-9:3 -- at the end of the DR segment of path */ if (hop_ptr == hop_cnt) - return (smp->dr_dlid == IB_LID_PERMISSIVE ? - IB_SMI_SEND : IB_SMI_LOCAL); + return (smp->dr_dlid == IB_LID_PERMISSIVE); /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ if (hop_ptr == hop_cnt + 1) - return IB_SMI_SEND; + return 1; } else { - /* C14-13:2 -- intermediate hop */ + /* C14-13:2 */ if (2 <= hop_ptr && hop_ptr <= hop_cnt) - return IB_SMI_SEND; + return 1; /* C14-13:3 -- at the end of the DR segment of path */ if (hop_ptr == 1) - return (smp->dr_slid != IB_LID_PERMISSIVE ? - IB_SMI_SEND : IB_SMI_LOCAL); + return (smp->dr_slid != IB_LID_PERMISSIVE); } - return IB_SMI_LOCAL; + return 0; } diff --git a/trunk/drivers/infiniband/core/smi.h b/trunk/drivers/infiniband/core/smi.h index 9a4b349efc30..3011bfd86dc5 100644 --- a/trunk/drivers/infiniband/core/smi.h +++ b/trunk/drivers/infiniband/core/smi.h @@ -3,7 +3,7 @@ * Copyright (c) 2004 Infinicon Corporation. All rights reserved. * Copyright (c) 2004 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. - * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -33,6 +33,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * + * $Id: smi.h 1389 2004-12-27 22:56:47Z roland $ */ #ifndef __SMI_H_ @@ -40,33 +41,26 @@ #include -enum smi_action { - IB_SMI_DISCARD, - IB_SMI_HANDLE -}; - -enum smi_forward_action { - IB_SMI_LOCAL, /* SMP should be completed up the stack */ - IB_SMI_SEND, /* received DR SMP should be forwarded to the send queue */ -}; - -enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, - int port_num, int phys_port_cnt); -extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp); -extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, - u8 node_type, int port_num); +int smi_handle_dr_smp_recv(struct ib_smp *smp, + u8 node_type, + int port_num, + int phys_port_cnt); +extern int smi_check_forward_dr_smp(struct ib_smp *smp); +extern int smi_handle_dr_smp_send(struct ib_smp *smp, + u8 node_type, + int port_num); /* * Return 1 if the SMP should be handled by the local SMA/SM via process_mad */ -static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, - struct ib_device *device) +static inline int smi_check_local_smp(struct ib_smp *smp, + struct ib_device *device) { /* C14-9:3 -- We're at the end of the DR segment of path */ /* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */ return ((device->process_mad && !ib_get_smp_direction(smp) && - (smp->hop_ptr == smp->hop_cnt + 1)) ? - IB_SMI_HANDLE : IB_SMI_DISCARD); + (smp->hop_ptr == smp->hop_cnt + 1))); } + #endif /* __SMI_H_ */ diff --git a/trunk/drivers/infiniband/core/sysfs.c b/trunk/drivers/infiniband/core/sysfs.c index 08c299ebf4a8..000c086bf2e9 100644 --- a/trunk/drivers/infiniband/core/sysfs.c +++ b/trunk/drivers/infiniband/core/sysfs.c @@ -683,7 +683,6 @@ int ib_device_register_sysfs(struct ib_device *device) class_dev->class = &ib_class; class_dev->class_data = device; - class_dev->dev = device->dma_device; strlcpy(class_dev->class_id, device->name, BUS_ID_SIZE); INIT_LIST_HEAD(&device->port_list); diff --git a/trunk/drivers/infiniband/core/ucm.c b/trunk/drivers/infiniband/core/ucm.c index 2586a3ee8eba..ee51d79a7ad5 100644 --- a/trunk/drivers/infiniband/core/ucm.c +++ b/trunk/drivers/infiniband/core/ucm.c @@ -407,18 +407,29 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, mutex_lock(&file->file_mutex); while (list_empty(&file->events)) { - mutex_unlock(&file->file_mutex); - if (file->filp->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->filp->f_flags & O_NONBLOCK) { + result = -EAGAIN; + break; + } - if (wait_event_interruptible(file->poll_wait, - !list_empty(&file->events))) - return -ERESTARTSYS; + if (signal_pending(current)) { + result = -ERESTARTSYS; + break; + } + prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE); + + mutex_unlock(&file->file_mutex); + schedule(); mutex_lock(&file->file_mutex); + + finish_wait(&file->poll_wait, &wait); } + if (result) + goto done; + uevent = list_entry(file->events.next, struct ib_ucm_event, file_list); if (ib_ucm_new_cm_id(uevent->resp.event)) { diff --git a/trunk/drivers/infiniband/core/ucma.c b/trunk/drivers/infiniband/core/ucma.c index 53b4c94a7eb5..c859134c1daa 100644 --- a/trunk/drivers/infiniband/core/ucma.c +++ b/trunk/drivers/infiniband/core/ucma.c @@ -306,18 +306,26 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, mutex_lock(&file->mut); while (list_empty(&file->event_list)) { - mutex_unlock(&file->mut); - - if (file->filp->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - if (wait_event_interruptible(file->poll_wait, - !list_empty(&file->event_list))) - return -ERESTARTSYS; + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE); + mutex_unlock(&file->mut); + schedule(); mutex_lock(&file->mut); + finish_wait(&file->poll_wait, &wait); } + if (ret) + goto done; + uevent = list_entry(file->event_list.next, struct ucma_event, list); if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) { diff --git a/trunk/drivers/infiniband/core/user_mad.c b/trunk/drivers/infiniband/core/user_mad.c index d97ded25c4ff..c069ebeba8e3 100644 --- a/trunk/drivers/infiniband/core/user_mad.c +++ b/trunk/drivers/infiniband/core/user_mad.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -134,7 +135,7 @@ static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); static DEFINE_SPINLOCK(port_lock); static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS]; -static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); +static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2); static void ib_umad_add_one(struct ib_device *device); static void ib_umad_remove_one(struct ib_device *device); @@ -230,17 +231,12 @@ static void recv_handler(struct ib_mad_agent *agent, packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); if (packet->mad.hdr.grh_present) { - struct ib_ah_attr ah_attr; - - ib_init_ah_from_wc(agent->device, agent->port_num, - mad_recv_wc->wc, mad_recv_wc->recv_buf.grh, - &ah_attr); - - packet->mad.hdr.gid_index = ah_attr.grh.sgid_index; - packet->mad.hdr.hop_limit = ah_attr.grh.hop_limit; - packet->mad.hdr.traffic_class = ah_attr.grh.traffic_class; - memcpy(packet->mad.hdr.gid, &ah_attr.grh.dgid, 16); - packet->mad.hdr.flow_label = cpu_to_be32(ah_attr.grh.flow_label); + /* XXX parse GRH */ + packet->mad.hdr.gid_index = 0; + packet->mad.hdr.hop_limit = 0; + packet->mad.hdr.traffic_class = 0; + memset(packet->mad.hdr.gid, 0, 16); + packet->mad.hdr.flow_label = 0; } if (queue_packet(file, agent, packet)) @@ -477,7 +473,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, if (packet->mad.hdr.grh_present) { ah_attr.ah_flags = IB_AH_GRH; memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16); - ah_attr.grh.sgid_index = packet->mad.hdr.gid_index; ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label); ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit; ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class; diff --git a/trunk/drivers/infiniband/hw/amso1100/c2.c b/trunk/drivers/infiniband/hw/amso1100/c2.c index 58bc272bd407..59243d9aedd6 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2.c +++ b/trunk/drivers/infiniband/hw/amso1100/c2.c @@ -439,8 +439,7 @@ static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem) } /* Setup the skb for reuse since we're dropping this pkt */ - elem->skb->data = elem->skb->head; - skb_reset_tail_pointer(elem->skb); + elem->skb->tail = elem->skb->data = elem->skb->head; /* Zero out the rxp hdr in the sk_buff */ memset(elem->skb->data, 0, sizeof(*rxp_hdr)); @@ -522,8 +521,9 @@ static void c2_rx_interrupt(struct net_device *netdev) * "sizeof(struct c2_rxp_hdr)". */ skb->data += sizeof(*rxp_hdr); - skb_set_tail_pointer(skb, buflen); + skb->tail = skb->data + buflen; skb->len = buflen; + skb->dev = netdev; skb->protocol = eth_type_trans(skb, netdev); netif_rx(skb); diff --git a/trunk/drivers/infiniband/hw/amso1100/c2_provider.c b/trunk/drivers/infiniband/hw/amso1100/c2_provider.c index 607c09bf764c..fef972752912 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/trunk/drivers/infiniband/hw/amso1100/c2_provider.c @@ -796,6 +796,7 @@ int c2_register_device(struct c2_dev *dev) memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6); dev->ibdev.phys_port_cnt = 1; dev->ibdev.dma_device = &dev->pcidev->dev; + dev->ibdev.class_dev.dev = &dev->pcidev->dev; dev->ibdev.query_device = c2_query_device; dev->ibdev.query_port = c2_query_port; dev->ibdev.modify_port = c2_modify_port; diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3b4b0acd707f..2d2de9b8b729 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -477,7 +477,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) BUG_ON(skb_cloned(skb)); mpalen = sizeof(*mpa) + ep->plen; - if (skb->data + mpalen + sizeof(*req) > skb_end_pointer(skb)) { + if (skb->data + mpalen + sizeof(*req) > skb->end) { kfree_skb(skb); skb=alloc_skb(mpalen + sizeof(*req), GFP_KERNEL); if (!skb) { @@ -507,7 +507,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) */ skb_get(skb); set_arp_failure_handler(skb, arp_failure_discard); - skb_reset_transport_header(skb); + skb->h.raw = skb->data; len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); @@ -559,7 +559,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) skb_get(skb); skb->priority = CPL_PRIORITY_DATA; set_arp_failure_handler(skb, arp_failure_discard); - skb_reset_transport_header(skb); + skb->h.raw = skb->data; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); @@ -610,7 +610,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) */ skb_get(skb); set_arp_failure_handler(skb, arp_failure_discard); - skb_reset_transport_header(skb); + skb->h.raw = skb->data; len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); @@ -821,8 +821,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) /* * copy the new data into our accumulation buffer. */ - skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]), - skb->len); + memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len); ep->mpa_pkt_len += skb->len; /* @@ -941,8 +940,7 @@ static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb) /* * Copy the new data into our accumulation buffer. */ - skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]), - skb->len); + memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len); ep->mpa_pkt_len += skb->len; /* @@ -1621,8 +1619,7 @@ static int terminate(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) PDBG("%s ep %p\n", __FUNCTION__, ep); skb_pull(skb, sizeof(struct cpl_rdma_terminate)); PDBG("%s saving %d bytes of term msg\n", __FUNCTION__, skb->len); - skb_copy_from_linear_data(skb, ep->com.qp->attr.terminate_buffer, - skb->len); + memcpy(ep->com.qp->attr.terminate_buffer, skb->data, skb->len); ep->com.qp->attr.terminate_msg_len = skb->len; ep->com.qp->attr.is_terminate_local = 0; return CPL_RET_BUF_DONE; diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c index af28a317016d..24e0df04f7db 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1108,6 +1108,7 @@ int iwch_register_device(struct iwch_dev *dev) memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC)); dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports; dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev); + dev->ibdev.class_dev.dev = &(dev->rdev.rnic_info.pdev->dev); dev->ibdev.query_device = iwch_query_device; dev->ibdev.query_port = iwch_query_port; dev->ibdev.modify_port = iwch_modify_port; diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_classes.h b/trunk/drivers/infiniband/hw/ehca/ehca_classes.h index 10fb8fbafa0c..82ded44c6cee 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/trunk/drivers/infiniband/hw/ehca/ehca_classes.h @@ -106,7 +106,6 @@ struct ehca_shca { struct ehca_mr *maxmr; struct ehca_pd *pd; struct h_galpas galpas; - struct mutex modify_mutex; }; struct ehca_pd { diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_hca.c b/trunk/drivers/infiniband/hw/ehca/ehca_hca.c index 32b55a4f0e5b..30eb45df9f0b 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_hca.c @@ -147,7 +147,6 @@ int ehca_query_port(struct ib_device *ibdev, break; } - props->port_cap_flags = rblock->capability_mask; props->gid_tbl_len = rblock->gid_tbl_len; props->max_msg_sz = rblock->max_msg_sz; props->bad_pkey_cntr = rblock->bad_pkey_cntr; @@ -237,60 +236,10 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, return ret; } -const u32 allowed_port_caps = ( - IB_PORT_SM | IB_PORT_LED_INFO_SUP | IB_PORT_CM_SUP | - IB_PORT_SNMP_TUNNEL_SUP | IB_PORT_DEVICE_MGMT_SUP | - IB_PORT_VENDOR_CLASS_SUP); - int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask, struct ib_port_modify *props) { - int ret = 0; - struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); - struct hipz_query_port *rblock; - u32 cap; - u64 hret; - - if ((props->set_port_cap_mask | props->clr_port_cap_mask) - & ~allowed_port_caps) { - ehca_err(&shca->ib_device, "Non-changeable bits set in masks " - "set=%x clr=%x allowed=%x", props->set_port_cap_mask, - props->clr_port_cap_mask, allowed_port_caps); - return -EINVAL; - } - - if (mutex_lock_interruptible(&shca->modify_mutex)) - return -ERESTARTSYS; - - rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); - if (!rblock) { - ehca_err(&shca->ib_device, "Can't allocate rblock memory."); - ret = -ENOMEM; - goto modify_port1; - } - - if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { - ehca_err(&shca->ib_device, "Can't query port properties"); - ret = -EINVAL; - goto modify_port2; - } - - cap = (rblock->capability_mask | props->set_port_cap_mask) - & ~props->clr_port_cap_mask; - - hret = hipz_h_modify_port(shca->ipz_hca_handle, port, - cap, props->init_type, port_modify_mask); - if (hret != H_SUCCESS) { - ehca_err(&shca->ib_device, "Modify port failed hret=%lx", hret); - ret = -EINVAL; - } - -modify_port2: - ehca_free_fw_ctrlblock(rblock); - -modify_port1: - mutex_unlock(&shca->modify_mutex); - - return ret; + /* Not implemented yet */ + return -EFAULT; } diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_main.c b/trunk/drivers/infiniband/hw/ehca/ehca_main.c index 4700085ba834..059da9628bb5 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_main.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_main.c @@ -565,11 +565,11 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, const struct of_device_id *id) { struct ehca_shca *shca; - const u64 *handle; + u64 *handle; struct ib_pd *ibpd; int ret; - handle = get_property(dev->ofdev.node, "ibm,hca-handle", NULL); + handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL); if (!handle) { ehca_gen_err("Cannot get eHCA handle for adapter: %s.", dev->ofdev.node->full_name); @@ -587,7 +587,6 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, ehca_gen_err("Cannot allocate shca memory."); return -ENOMEM; } - mutex_init(&shca->modify_mutex); shca->ibmebus_dev = dev; shca->ipz_hca_handle.handle = *handle; diff --git a/trunk/drivers/infiniband/hw/ehca/hcp_if.c b/trunk/drivers/infiniband/hw/ehca/hcp_if.c index b564fcd3b282..3fb46e67df87 100644 --- a/trunk/drivers/infiniband/hw/ehca/hcp_if.c +++ b/trunk/drivers/infiniband/hw/ehca/hcp_if.c @@ -70,10 +70,6 @@ #define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0, 31) #define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32, 63) -#define H_MP_INIT_TYPE EHCA_BMASK_IBM(44, 47) -#define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48) -#define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49) - /* direct access qp controls */ #define DAQP_CTRL_ENABLE 0x01 #define DAQP_CTRL_SEND_COMP 0x20 @@ -368,26 +364,6 @@ u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, return ret; } -u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle, - const u8 port_id, const u32 port_cap, - const u8 init_type, const int modify_mask) -{ - u64 port_attributes = port_cap; - - if (modify_mask & IB_PORT_SHUTDOWN) - port_attributes |= EHCA_BMASK_SET(H_MP_SHUTDOWN, 1); - if (modify_mask & IB_PORT_INIT_TYPE) - port_attributes |= EHCA_BMASK_SET(H_MP_INIT_TYPE, init_type); - if (modify_mask & IB_PORT_RESET_QKEY_CNTR) - port_attributes |= EHCA_BMASK_SET(H_MP_RESET_QKEY_CTR, 1); - - return ehca_plpar_hcall_norets(H_MODIFY_PORT, - adapter_handle.handle, /* r4 */ - port_id, /* r5 */ - port_attributes, /* r6 */ - 0, 0, 0, 0); -} - u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, struct hipz_query_hca *query_hca_rblock) { diff --git a/trunk/drivers/infiniband/hw/ehca/hcp_if.h b/trunk/drivers/infiniband/hw/ehca/hcp_if.h index 2869f7dd6196..587ebd470959 100644 --- a/trunk/drivers/infiniband/hw/ehca/hcp_if.h +++ b/trunk/drivers/infiniband/hw/ehca/hcp_if.h @@ -85,10 +85,6 @@ u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, const u8 port_id, struct hipz_query_port *query_port_response_block); -u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle, - const u8 port_id, const u32 port_cap, - const u8 init_type, const int modify_mask); - u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, struct hipz_query_hca *query_hca_rblock); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_common.h b/trunk/drivers/infiniband/hw/ipath/ipath_common.h index 10c008f22ba6..54139d398181 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_common.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. + * Copyright (c) 2006 QLogic, Inc. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two @@ -78,8 +78,6 @@ #define IPATH_IB_LINKINIT 3 #define IPATH_IB_LINKDOWN_SLEEP 4 #define IPATH_IB_LINKDOWN_DISABLE 5 -#define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */ -#define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */ /* * stats maintained by the driver. For now, at least, this is global @@ -318,17 +316,11 @@ struct ipath_base_info { /* address of readonly memory copy of the rcvhdrq tail register. */ __u64 spi_rcvhdr_tailaddr; - /* shared memory pages for subports if port is shared */ + /* shared memory pages for subports if IPATH_RUNTIME_MASTER is set */ __u64 spi_subport_uregbase; __u64 spi_subport_rcvegrbuf; __u64 spi_subport_rcvhdr_base; - /* shared memory page for hardware port if it is shared */ - __u64 spi_port_uregbase; - __u64 spi_port_rcvegrbuf; - __u64 spi_port_rcvhdr_base; - __u64 spi_port_rcvhdr_tailaddr; - } __attribute__ ((aligned(8))); @@ -352,7 +344,7 @@ struct ipath_base_info { * may not be implemented; the user code must deal with this if it * cares, or it must abort after initialization reports the difference. */ -#define IPATH_USER_SWMINOR 5 +#define IPATH_USER_SWMINOR 3 #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR) @@ -426,14 +418,11 @@ struct ipath_user_info { #define IPATH_CMD_TID_UPDATE 19 /* update expected TID entries */ #define IPATH_CMD_TID_FREE 20 /* free expected TID entries */ #define IPATH_CMD_SET_PART_KEY 21 /* add partition key */ -#define __IPATH_CMD_SLAVE_INFO 22 /* return info on slave processes (for old user code) */ +#define IPATH_CMD_SLAVE_INFO 22 /* return info on slave processes */ #define IPATH_CMD_ASSIGN_PORT 23 /* allocate HCA and port */ #define IPATH_CMD_USER_INIT 24 /* set up userspace */ -#define IPATH_CMD_UNUSED_1 25 -#define IPATH_CMD_UNUSED_2 26 -#define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ -#define IPATH_CMD_MAX 27 +#define IPATH_CMD_MAX 24 struct ipath_port_info { __u32 num_active; /* number of active units */ @@ -441,7 +430,7 @@ struct ipath_port_info { __u16 port; /* port on unit assigned to caller */ __u16 subport; /* subport on unit assigned to caller */ __u16 num_ports; /* number of ports available on unit */ - __u16 num_subports; /* number of subports opened on port */ + __u16 num_subports; /* number of subport slaves opened on port */ }; struct ipath_tid_info { diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c index ea78e6dddc90..87462e0cb4d2 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c @@ -76,20 +76,7 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) } return; } - wc->queue[head].wr_id = entry->wr_id; - wc->queue[head].status = entry->status; - wc->queue[head].opcode = entry->opcode; - wc->queue[head].vendor_err = entry->vendor_err; - wc->queue[head].byte_len = entry->byte_len; - wc->queue[head].imm_data = (__u32 __force)entry->imm_data; - wc->queue[head].qp_num = entry->qp->qp_num; - wc->queue[head].src_qp = entry->src_qp; - wc->queue[head].wc_flags = entry->wc_flags; - wc->queue[head].pkey_index = entry->pkey_index; - wc->queue[head].slid = entry->slid; - wc->queue[head].sl = entry->sl; - wc->queue[head].dlid_path_bits = entry->dlid_path_bits; - wc->queue[head].port_num = entry->port_num; + wc->queue[head] = *entry; wc->head = next; if (cq->notify == IB_CQ_NEXT_COMP || @@ -135,30 +122,9 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (tail > (u32) cq->ibcq.cqe) tail = (u32) cq->ibcq.cqe; for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { - struct ipath_qp *qp; - if (tail == wc->head) break; - - qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table, - wc->queue[tail].qp_num); - entry->qp = &qp->ibqp; - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); - - entry->wr_id = wc->queue[tail].wr_id; - entry->status = wc->queue[tail].status; - entry->opcode = wc->queue[tail].opcode; - entry->vendor_err = wc->queue[tail].vendor_err; - entry->byte_len = wc->queue[tail].byte_len; - entry->imm_data = wc->queue[tail].imm_data; - entry->src_qp = wc->queue[tail].src_qp; - entry->wc_flags = wc->queue[tail].wc_flags; - entry->pkey_index = wc->queue[tail].pkey_index; - entry->slid = wc->queue[tail].slid; - entry->sl = wc->queue[tail].sl; - entry->dlid_path_bits = wc->queue[tail].dlid_path_bits; - entry->port_num = wc->queue[tail].port_num; + *entry = wc->queue[tail]; if (tail >= cq->ibcq.cqe) tail = 0; else diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_debug.h b/trunk/drivers/infiniband/hw/ipath/ipath_debug.h index 42bfbdb0d3e6..df69f0d80b8b 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_debug.h @@ -57,7 +57,6 @@ #define __IPATH_PROCDBG 0x100 /* print mmap/nopage stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x200 -#define __IPATH_ERRPKTDBG 0x400 #define __IPATH_USER_SEND 0x1000 /* use user mode send */ #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_diag.c b/trunk/drivers/infiniband/hw/ipath/ipath_diag.c index 63e8368b0e95..0f13a2182cc7 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_diag.c @@ -296,7 +296,7 @@ static int ipath_diag_open(struct inode *in, struct file *fp) } fp->private_data = dd; - ipath_diag_inuse = -2; + ipath_diag_inuse = 1; diag_set_link = 0; ret = 0; @@ -461,8 +461,6 @@ static ssize_t ipath_diag_read(struct file *fp, char __user *data, else if ((count % 4) || (*off % 4)) /* address or length is not 32-bit aligned, hence invalid */ ret = -EINVAL; - else if (ipath_diag_inuse < 1 && (*off || count != 8)) - ret = -EINVAL; /* prevent cat /dev/ipath_diag* */ else if ((count % 8) || (*off % 8)) /* address or length not 64-bit aligned; do 32-bit reads */ ret = ipath_read_umem32(dd, data, kreg_base + *off, count); @@ -472,8 +470,6 @@ static ssize_t ipath_diag_read(struct file *fp, char __user *data, if (ret >= 0) { *off += count; ret = count; - if (ipath_diag_inuse == -2) - ipath_diag_inuse++; } return ret; @@ -493,9 +489,6 @@ static ssize_t ipath_diag_write(struct file *fp, const char __user *data, else if ((count % 4) || (*off % 4)) /* address or length is not 32-bit aligned, hence invalid */ ret = -EINVAL; - else if ((ipath_diag_inuse == -1 && (*off || count != 8)) || - ipath_diag_inuse == -2) /* read qw off 0, write qw off 0 */ - ret = -EINVAL; /* before any other write allowed */ else if ((count % 8) || (*off % 8)) /* address or length not 64-bit aligned; do 32-bit writes */ ret = ipath_write_umem32(dd, kreg_base + *off, data, count); @@ -505,8 +498,6 @@ static ssize_t ipath_diag_write(struct file *fp, const char __user *data, if (ret >= 0) { *off += count; ret = count; - if (ipath_diag_inuse == -1) - ipath_diag_inuse = 1; /* all read/write OK now */ } return ret; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c index e3a223209710..ae7f21a0cdc0 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c @@ -390,23 +390,15 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, /* setup the chip-specific functions, as early as possible. */ switch (ent->device) { - case PCI_DEVICE_ID_INFINIPATH_HT: #ifdef CONFIG_HT_IRQ + case PCI_DEVICE_ID_INFINIPATH_HT: ipath_init_iba6110_funcs(dd); break; -#else - ipath_dev_err(dd, "QLogic HT device 0x%x cannot work if " - "CONFIG_HT_IRQ is not enabled\n", ent->device); - return -ENODEV; #endif - case PCI_DEVICE_ID_INFINIPATH_PE800: #ifdef CONFIG_PCI_MSI + case PCI_DEVICE_ID_INFINIPATH_PE800: ipath_init_iba6120_funcs(dd); break; -#else - ipath_dev_err(dd, "QLogic PCIE device 0x%x cannot work if " - "CONFIG_PCI_MSI is not enabled\n", ent->device); - return -ENODEV; #endif default: ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, " @@ -494,7 +486,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ret = ipath_init_chip(dd, 0); /* do the chip-specific init */ if (ret) - goto bail_irqsetup; + goto bail_iounmap; ret = ipath_enable_wc(dd); @@ -513,9 +505,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, goto bail; -bail_irqsetup: - if (pdev->irq) free_irq(pdev->irq, dd); - bail_iounmap: iounmap((volatile void __iomem *) dd->ipath_kregbase); @@ -536,6 +525,8 @@ static void __devexit cleanup_device(struct ipath_devdata *dd) { int port; + ipath_shutdown_device(dd); + if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) { /* can't do anything more with chip; needs re-init */ *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT; @@ -603,9 +594,8 @@ static void __devexit cleanup_device(struct ipath_devdata *dd) ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n", dd->ipath_pageshadow); - tmpp = dd->ipath_pageshadow; + vfree(dd->ipath_pageshadow); dd->ipath_pageshadow = NULL; - vfree(tmpp); } /* @@ -632,12 +622,6 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd); - /* - * disable the IB link early, to be sure no new packets arrive, which - * complicates the shutdown process - */ - ipath_shutdown_device(dd); - if (dd->verbs_dev) ipath_unregister_ib_device(dd->verbs_dev); @@ -770,42 +754,9 @@ static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT; } -/* - * Decode the error status into strings, deciding whether to always - * print * it or not depending on "normal packet errors" vs everything - * else. Return 1 if "real" errors, otherwise 0 if only packet - * errors, so caller can decide what to print with the string. - */ -int ipath_decode_err(char *buf, size_t blen, ipath_err_t err) +void ipath_decode_err(char *buf, size_t blen, ipath_err_t err) { - int iserr = 1; *buf = '\0'; - if (err & INFINIPATH_E_PKTERRS) { - if (!(err & ~INFINIPATH_E_PKTERRS)) - iserr = 0; // if only packet errors. - if (ipath_debug & __IPATH_ERRPKTDBG) { - if (err & INFINIPATH_E_REBP) - strlcat(buf, "EBP ", blen); - if (err & INFINIPATH_E_RVCRC) - strlcat(buf, "VCRC ", blen); - if (err & INFINIPATH_E_RICRC) { - strlcat(buf, "CRC ", blen); - // clear for check below, so only once - err &= INFINIPATH_E_RICRC; - } - if (err & INFINIPATH_E_RSHORTPKTLEN) - strlcat(buf, "rshortpktlen ", blen); - if (err & INFINIPATH_E_SDROPPEDDATAPKT) - strlcat(buf, "sdroppeddatapkt ", blen); - if (err & INFINIPATH_E_SPKTLEN) - strlcat(buf, "spktlen ", blen); - } - if ((err & INFINIPATH_E_RICRC) && - !(err&(INFINIPATH_E_RVCRC|INFINIPATH_E_REBP))) - strlcat(buf, "CRC ", blen); - if (!iserr) - goto done; - } if (err & INFINIPATH_E_RHDRLEN) strlcat(buf, "rhdrlen ", blen); if (err & INFINIPATH_E_RBADTID) @@ -816,12 +767,12 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err) strlcat(buf, "rhdr ", blen); if (err & INFINIPATH_E_RLONGPKTLEN) strlcat(buf, "rlongpktlen ", blen); + if (err & INFINIPATH_E_RSHORTPKTLEN) + strlcat(buf, "rshortpktlen ", blen); if (err & INFINIPATH_E_RMAXPKTLEN) strlcat(buf, "rmaxpktlen ", blen); if (err & INFINIPATH_E_RMINPKTLEN) strlcat(buf, "rminpktlen ", blen); - if (err & INFINIPATH_E_SMINPKTLEN) - strlcat(buf, "sminpktlen ", blen); if (err & INFINIPATH_E_RFORMATERR) strlcat(buf, "rformaterr ", blen); if (err & INFINIPATH_E_RUNSUPVL) @@ -830,20 +781,32 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err) strlcat(buf, "runexpchar ", blen); if (err & INFINIPATH_E_RIBFLOW) strlcat(buf, "ribflow ", blen); + if (err & INFINIPATH_E_REBP) + strlcat(buf, "EBP ", blen); if (err & INFINIPATH_E_SUNDERRUN) strlcat(buf, "sunderrun ", blen); if (err & INFINIPATH_E_SPIOARMLAUNCH) strlcat(buf, "spioarmlaunch ", blen); if (err & INFINIPATH_E_SUNEXPERRPKTNUM) strlcat(buf, "sunexperrpktnum ", blen); + if (err & INFINIPATH_E_SDROPPEDDATAPKT) + strlcat(buf, "sdroppeddatapkt ", blen); if (err & INFINIPATH_E_SDROPPEDSMPPKT) strlcat(buf, "sdroppedsmppkt ", blen); if (err & INFINIPATH_E_SMAXPKTLEN) strlcat(buf, "smaxpktlen ", blen); + if (err & INFINIPATH_E_SMINPKTLEN) + strlcat(buf, "sminpktlen ", blen); if (err & INFINIPATH_E_SUNSUPVL) strlcat(buf, "sunsupVL ", blen); + if (err & INFINIPATH_E_SPKTLEN) + strlcat(buf, "spktlen ", blen); if (err & INFINIPATH_E_INVALIDADDR) strlcat(buf, "invalidaddr ", blen); + if (err & INFINIPATH_E_RICRC) + strlcat(buf, "CRC ", blen); + if (err & INFINIPATH_E_RVCRC) + strlcat(buf, "VCRC ", blen); if (err & INFINIPATH_E_RRCVEGRFULL) strlcat(buf, "rcvegrfull ", blen); if (err & INFINIPATH_E_RRCVHDRFULL) @@ -856,8 +819,6 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err) strlcat(buf, "hardware ", blen); if (err & INFINIPATH_E_RESET) strlcat(buf, "reset ", blen); -done: - return iserr; } /** @@ -1701,22 +1662,6 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) lstate = IPATH_LINKACTIVE; break; - case IPATH_IB_LINK_LOOPBACK: - dev_info(&dd->pcidev->dev, "Enabling IB local loopback\n"); - dd->ipath_ibcctrl |= INFINIPATH_IBCC_LOOPBACK; - ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, - dd->ipath_ibcctrl); - ret = 0; - goto bail; // no state change to wait for - - case IPATH_IB_LINK_EXTERNAL: - dev_info(&dd->pcidev->dev, "Disabling IB local loopback (normal)\n"); - dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LOOPBACK; - ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, - dd->ipath_ibcctrl); - ret = 0; - goto bail; // no state change to wait for - default: ipath_dbg("Invalid linkstate 0x%x requested\n", newstate); ret = -EINVAL; @@ -1820,6 +1765,29 @@ int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc) return 0; } +/** + * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register + * @dd: the infinipath device + * @regno: the register number to read + * @port: the port containing the register + * + * Registers that vary with the chip implementation constants (port) + * use this routine. + */ +u64 ipath_read_kreg64_port(const struct ipath_devdata *dd, ipath_kreg regno, + unsigned port) +{ + u16 where; + + if (port < dd->ipath_portcnt && + (regno == dd->ipath_kregs->kr_rcvhdraddr || + regno == dd->ipath_kregs->kr_rcvhdrtailaddr)) + where = regno + port; + else + where = -1; + + return ipath_read_kreg64(dd, where); +} /** * ipath_write_kreg_port - write a device's per-port 64-bit kernel register @@ -2005,8 +1973,7 @@ static int __init infinipath_init(void) { int ret; - if (ipath_debug & __IPATH_DBG) - printk(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version); + ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version); /* * These must be called before the driver is registered with diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c b/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c index 030185f90ee2..a4019a6b7560 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -626,10 +626,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) } else memcpy(dd->ipath_serial, ifp->if_serial, sizeof ifp->if_serial); - if (!strstr(ifp->if_comment, "Tested successfully")) - ipath_dev_err(dd, "Board SN %s did not pass functional " - "test: %s\n", dd->ipath_serial, - ifp->if_comment); ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n", (unsigned long long) be64_to_cpu(dd->ipath_guid)); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c index 1272aaf2a785..5d64ff875297 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. + * Copyright (c) 2006 QLogic, Inc. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two @@ -41,6 +41,12 @@ #include "ipath_kernel.h" #include "ipath_common.h" +/* + * mmap64 doesn't allow all 64 bits for 32-bit applications + * so only use the low 43 bits. + */ +#define MMAP64_MASK 0x7FFFFFFFFFFUL + static int ipath_open(struct inode *, struct file *); static int ipath_close(struct inode *, struct file *); static ssize_t ipath_write(struct file *, const char __user *, size_t, @@ -57,24 +63,6 @@ static const struct file_operations ipath_file_ops = { .mmap = ipath_mmap }; -/* - * Convert kernel virtual addresses to physical addresses so they don't - * potentially conflict with the chip addresses used as mmap offsets. - * It doesn't really matter what mmap offset we use as long as we can - * interpret it correctly. - */ -static u64 cvt_kvaddr(void *p) -{ - struct page *page; - u64 paddr = 0; - - page = vmalloc_to_page(p); - if (page) - paddr = page_to_pfn(page) << PAGE_SHIFT; - - return paddr; -} - static int ipath_get_base_info(struct file *fp, void __user *ubase, size_t ubase_size) { @@ -99,7 +87,7 @@ static int ipath_get_base_info(struct file *fp, sz = sizeof(*kinfo); /* If port sharing is not requested, allow the old size structure */ if (!shared) - sz -= 7 * sizeof(u64); + sz -= 3 * sizeof(u64); if (ubase_size < sz) { ipath_cdbg(PROC, "Base size %zu, need %zu (version mismatch?)\n", @@ -177,41 +165,24 @@ static int ipath_get_base_info(struct file *fp, kinfo->spi_piobufbase = (u64) pd->port_piobufs + dd->ipath_palign * (dd->ipath_pbufsport - kinfo->spi_piocnt); + kinfo->__spi_uregbase = (u64) dd->ipath_uregbase + + dd->ipath_palign * pd->port_port; } else { unsigned slave = subport_fp(fp) - 1; kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt; kinfo->spi_piobufbase = (u64) pd->port_piobufs + dd->ipath_palign * kinfo->spi_piocnt * slave; - } - if (shared) { - kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase + - dd->ipath_palign * pd->port_port; - kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs; - kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base; - kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr; + kinfo->__spi_uregbase = ((u64) pd->subport_uregbase + + PAGE_SIZE * slave) & MMAP64_MASK; - kinfo->__spi_uregbase = cvt_kvaddr(pd->subport_uregbase + - PAGE_SIZE * subport_fp(fp)); - - kinfo->spi_rcvhdr_base = cvt_kvaddr(pd->subport_rcvhdr_base + - pd->port_rcvhdrq_size * subport_fp(fp)); - kinfo->spi_rcvhdr_tailaddr = 0; - kinfo->spi_rcv_egrbufs = cvt_kvaddr(pd->subport_rcvegrbuf + - pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size * - subport_fp(fp)); - - kinfo->spi_subport_uregbase = - cvt_kvaddr(pd->subport_uregbase); - kinfo->spi_subport_rcvegrbuf = - cvt_kvaddr(pd->subport_rcvegrbuf); - kinfo->spi_subport_rcvhdr_base = - cvt_kvaddr(pd->subport_rcvhdr_base); - ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n", - kinfo->spi_port, kinfo->spi_runtime_flags, - (unsigned long long) kinfo->spi_subport_uregbase, - (unsigned long long) kinfo->spi_subport_rcvegrbuf, - (unsigned long long) kinfo->spi_subport_rcvhdr_base); + kinfo->spi_rcvhdr_base = ((u64) pd->subport_rcvhdr_base + + pd->port_rcvhdrq_size * slave) & MMAP64_MASK; + kinfo->spi_rcvhdr_tailaddr = + (u64) pd->port_rcvhdrqtailaddr_phys & MMAP64_MASK; + kinfo->spi_rcv_egrbufs = ((u64) pd->subport_rcvegrbuf + + dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave) & + MMAP64_MASK; } kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) / @@ -228,10 +199,20 @@ static int ipath_get_base_info(struct file *fp, if (master) { kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER; + kinfo->spi_subport_uregbase = + (u64) pd->subport_uregbase & MMAP64_MASK; + kinfo->spi_subport_rcvegrbuf = + (u64) pd->subport_rcvegrbuf & MMAP64_MASK; + kinfo->spi_subport_rcvhdr_base = + (u64) pd->subport_rcvhdr_base & MMAP64_MASK; + ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n", + kinfo->spi_port, kinfo->spi_runtime_flags, + (unsigned long long) kinfo->spi_subport_uregbase, + (unsigned long long) kinfo->spi_subport_rcvegrbuf, + (unsigned long long) kinfo->spi_subport_rcvhdr_base); } - sz = (ubase_size < sizeof(*kinfo)) ? ubase_size : sizeof(*kinfo); - if (copy_to_user(ubase, kinfo, sz)) + if (copy_to_user(ubase, kinfo, sizeof(*kinfo))) ret = -EFAULT; bail: @@ -1151,55 +1132,67 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr, struct ipath_devdata *dd; void *addr; size_t size; - int ret = 0; + int ret; /* If the port is not shared, all addresses should be physical */ - if (!pd->port_subport_cnt) + if (!pd->port_subport_cnt) { + ret = -EINVAL; goto bail; + } dd = pd->port_dd; size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size; /* - * Each process has all the subport uregbase, rcvhdrq, and - * rcvegrbufs mmapped - as an array for all the processes, - * and also separately for this process. + * Master has all the slave uregbase, rcvhdrq, and + * rcvegrbufs mmapped. */ - if (pgaddr == cvt_kvaddr(pd->subport_uregbase)) { - addr = pd->subport_uregbase; - size = PAGE_SIZE * pd->port_subport_cnt; - } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base)) { - addr = pd->subport_rcvhdr_base; - size = pd->port_rcvhdrq_size * pd->port_subport_cnt; - } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf)) { - addr = pd->subport_rcvegrbuf; - size *= pd->port_subport_cnt; - } else if (pgaddr == cvt_kvaddr(pd->subport_uregbase + - PAGE_SIZE * subport)) { - addr = pd->subport_uregbase + PAGE_SIZE * subport; - size = PAGE_SIZE; - } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base + - pd->port_rcvhdrq_size * subport)) { - addr = pd->subport_rcvhdr_base + - pd->port_rcvhdrq_size * subport; - size = pd->port_rcvhdrq_size; - } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf + - size * subport)) { - addr = pd->subport_rcvegrbuf + size * subport; - /* rcvegrbufs are read-only on the slave */ - if (vma->vm_flags & VM_WRITE) { - dev_info(&dd->pcidev->dev, - "Can't map eager buffers as " - "writable (flags=%lx)\n", vma->vm_flags); - ret = -EPERM; - goto bail; - } - /* - * Don't allow permission to later change to writeable - * with mprotect. - */ - vma->vm_flags &= ~VM_MAYWRITE; + if (subport == 0) { + unsigned num_slaves = pd->port_subport_cnt - 1; + + if (pgaddr == ((u64) pd->subport_uregbase & MMAP64_MASK)) { + addr = pd->subport_uregbase; + size = PAGE_SIZE * num_slaves; + } else if (pgaddr == ((u64) pd->subport_rcvhdr_base & + MMAP64_MASK)) { + addr = pd->subport_rcvhdr_base; + size = pd->port_rcvhdrq_size * num_slaves; + } else if (pgaddr == ((u64) pd->subport_rcvegrbuf & + MMAP64_MASK)) { + addr = pd->subport_rcvegrbuf; + size *= num_slaves; + } else { + ret = -EINVAL; + goto bail; + } + } else if (pgaddr == (((u64) pd->subport_uregbase + + PAGE_SIZE * (subport - 1)) & MMAP64_MASK)) { + addr = pd->subport_uregbase + PAGE_SIZE * (subport - 1); + size = PAGE_SIZE; + } else if (pgaddr == (((u64) pd->subport_rcvhdr_base + + pd->port_rcvhdrq_size * (subport - 1)) & + MMAP64_MASK)) { + addr = pd->subport_rcvhdr_base + + pd->port_rcvhdrq_size * (subport - 1); + size = pd->port_rcvhdrq_size; + } else if (pgaddr == (((u64) pd->subport_rcvegrbuf + + size * (subport - 1)) & MMAP64_MASK)) { + addr = pd->subport_rcvegrbuf + size * (subport - 1); + /* rcvegrbufs are read-only on the slave */ + if (vma->vm_flags & VM_WRITE) { + dev_info(&dd->pcidev->dev, + "Can't map eager buffers as " + "writable (flags=%lx)\n", vma->vm_flags); + ret = -EPERM; + goto bail; + } + /* + * Don't allow permission to later change to writeable + * with mprotect. + */ + vma->vm_flags &= ~VM_MAYWRITE; } else { + ret = -EINVAL; goto bail; } len = vma->vm_end - vma->vm_start; @@ -1212,7 +1205,7 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr, vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT; vma->vm_ops = &ipath_file_vm_ops; vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND; - ret = 1; + ret = 0; bail: return ret; @@ -1272,20 +1265,19 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) * Check for kernel virtual addresses first, anything else must * match a HW or memory address. */ - ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp)); - if (ret) { - if (ret > 0) - ret = 0; + if (pgaddr >= (1ULL<<40)) { + ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp)); goto bail; } - ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; if (!pd->port_subport_cnt) { /* port is not shared */ + ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; piocnt = dd->ipath_pbufsport; piobufs = pd->port_piobufs; } else if (!subport_fp(fp)) { /* caller is the master */ + ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) + (dd->ipath_pbufsport % pd->port_subport_cnt); piobufs = pd->port_piobufs + @@ -1294,6 +1286,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) unsigned slave = subport_fp(fp) - 1; /* caller is a slave */ + ureg = 0; piocnt = dd->ipath_pbufsport / pd->port_subport_cnt; piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave; } @@ -1307,6 +1300,9 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0, (void *) dd->ipath_pioavailregs_dma, "pioavail registers"); + else if (subport_fp(fp)) + /* Subports don't mmap the physical receive buffers */ + ret = -EINVAL; else if (pgaddr == pd->port_rcvegr_phys) ret = mmap_rcvegrbufs(vma, pd); else if (pgaddr == (u64) pd->port_rcvhdrq_phys) @@ -1404,41 +1400,32 @@ static int init_subports(struct ipath_devdata *dd, const struct ipath_user_info *uinfo) { int ret = 0; - unsigned num_subports; + unsigned num_slaves; size_t size; + /* Old user binaries don't know about subports */ + if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR) + goto bail; /* * If the user is requesting zero or one port, * skip the subport allocation. */ if (uinfo->spu_subport_cnt <= 1) goto bail; - - /* Old user binaries don't know about new subport implementation */ - if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR) { - dev_info(&dd->pcidev->dev, - "Mismatched user minor version (%d) and driver " - "minor version (%d) while port sharing. Ensure " - "that driver and library are from the same " - "release.\n", - (int) (uinfo->spu_userversion & 0xffff), - IPATH_USER_SWMINOR); - goto bail; - } - if (uinfo->spu_subport_cnt > INFINIPATH_MAX_SUBPORT) { + if (uinfo->spu_subport_cnt > 4) { ret = -EINVAL; goto bail; } - num_subports = uinfo->spu_subport_cnt; - pd->subport_uregbase = vmalloc(PAGE_SIZE * num_subports); + num_slaves = uinfo->spu_subport_cnt - 1; + pd->subport_uregbase = vmalloc(PAGE_SIZE * num_slaves); if (!pd->subport_uregbase) { ret = -ENOMEM; goto bail; } /* Note: pd->port_rcvhdrq_size isn't initialized yet. */ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * - sizeof(u32), PAGE_SIZE) * num_subports; + sizeof(u32), PAGE_SIZE) * num_slaves; pd->subport_rcvhdr_base = vmalloc(size); if (!pd->subport_rcvhdr_base) { ret = -ENOMEM; @@ -1447,7 +1434,7 @@ static int init_subports(struct ipath_devdata *dd, pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size * - num_subports); + num_slaves); if (!pd->subport_rcvegrbuf) { ret = -ENOMEM; goto bail_rhdr; @@ -1456,12 +1443,6 @@ static int init_subports(struct ipath_devdata *dd, pd->port_subport_cnt = uinfo->spu_subport_cnt; pd->port_subport_id = uinfo->spu_subport_id; pd->active_slaves = 1; - set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag); - memset(pd->subport_uregbase, 0, PAGE_SIZE * num_subports); - memset(pd->subport_rcvhdr_base, 0, size); - memset(pd->subport_rcvegrbuf, 0, pd->port_rcvegrbuf_chunks * - pd->port_rcvegrbuf_size * - num_subports); goto bail; bail_rhdr: @@ -1592,19 +1573,18 @@ static int find_best_unit(struct file *fp, */ if (!cpus_empty(current->cpus_allowed) && !cpus_full(current->cpus_allowed)) { - int ncpus = num_online_cpus(), curcpu = -1, nset = 0; + int ncpus = num_online_cpus(), curcpu = -1; for (i = 0; i < ncpus; i++) if (cpu_isset(i, current->cpus_allowed)) { ipath_cdbg(PROC, "%s[%u] affinity set for " - "cpu %d/%d\n", current->comm, - current->pid, i, ncpus); + "cpu %d\n", current->comm, + current->pid, i); curcpu = i; - nset++; } - if (curcpu != -1 && nset != ncpus) { + if (curcpu != -1) { if (npresent) { prefunit = curcpu / (ncpus / npresent); - ipath_cdbg(PROC,"%s[%u] %d chips, %d cpus, " + ipath_dbg("%s[%u] %d chips, %d cpus, " "%d cpus/chip, select unit %d\n", current->comm, current->pid, npresent, ncpus, ncpus / npresent, @@ -1784,17 +1764,11 @@ static int ipath_do_user_init(struct file *fp, const struct ipath_user_info *uinfo) { int ret; - struct ipath_portdata *pd = port_fp(fp); + struct ipath_portdata *pd; struct ipath_devdata *dd; u32 head32; - /* Subports don't need to initialize anything since master did it. */ - if (subport_fp(fp)) { - ret = wait_event_interruptible(pd->port_wait, - !test_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag)); - goto done; - } - + pd = port_fp(fp); dd = pd->port_dd; if (uinfo->spu_rcvhdrsize) { @@ -1852,11 +1826,6 @@ static int ipath_do_user_init(struct file *fp, dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); - /* Notify any waiting slaves */ - if (pd->port_subport_cnt) { - clear_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag); - wake_up(&pd->port_wait); - } done: return ret; } @@ -2048,17 +2017,6 @@ static int ipath_get_slave_info(struct ipath_portdata *pd, return ret; } -static int ipath_force_pio_avail_update(struct ipath_devdata *dd) -{ - u64 reg = dd->ipath_sendctrl; - - clear_bit(IPATH_S_PIOBUFAVAILUPD, ®); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - - return 0; -} - static ssize_t ipath_write(struct file *fp, const char __user *data, size_t count, loff_t *off) { @@ -2113,35 +2071,27 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, dest = &cmd.cmd.part_key; src = &ucmd->cmd.part_key; break; - case __IPATH_CMD_SLAVE_INFO: + case IPATH_CMD_SLAVE_INFO: copy = sizeof(cmd.cmd.slave_mask_addr); dest = &cmd.cmd.slave_mask_addr; src = &ucmd->cmd.slave_mask_addr; break; - case IPATH_CMD_PIOAVAILUPD: // force an update of PIOAvail reg - copy = 0; - src = NULL; - dest = NULL; - break; default: ret = -EINVAL; goto bail; } - if (copy) { - if ((count - consumed) < copy) { - ret = -EINVAL; - goto bail; - } - - if (copy_from_user(dest, src, copy)) { - ret = -EFAULT; - goto bail; - } + if ((count - consumed) < copy) { + ret = -EINVAL; + goto bail; + } - consumed += copy; + if (copy_from_user(dest, src, copy)) { + ret = -EFAULT; + goto bail; } + consumed += copy; pd = port_fp(fp); if (!pd && cmd.type != __IPATH_CMD_USER_INIT && cmd.type != IPATH_CMD_ASSIGN_PORT) { @@ -2187,14 +2137,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, case IPATH_CMD_SET_PART_KEY: ret = ipath_set_part_key(pd, cmd.cmd.part_key); break; - case __IPATH_CMD_SLAVE_INFO: + case IPATH_CMD_SLAVE_INFO: ret = ipath_get_slave_info(pd, (void __user *) (unsigned long) cmd.cmd.slave_mask_addr); break; - case IPATH_CMD_PIOAVAILUPD: - ret = ipath_force_pio_avail_update(pd->port_dd); - break; } if (ret >= 0) diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c index 036ed1ef1796..ed55979bfd34 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "ipath_kernel.h" diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c b/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c index 4171198fc202..993482545021 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -43,9 +43,6 @@ #include "ipath_kernel.h" #include "ipath_registers.h" -static void ipath_setup_ht_setextled(struct ipath_devdata *, u64, u64); - - /* * This lists the InfiniPath registers, in the actual chip layout. * This structure should never be directly accessed. @@ -211,8 +208,8 @@ static const struct ipath_kregs ipath_ht_kregs = { .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus), .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig), /* - * These should not be used directly via ipath_write_kreg64(), - * use them with ipath_write_kreg64_port(), + * These should not be used directly via ipath_read_kreg64(), + * use them with ipath_read_kreg64_port(), */ .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0) @@ -287,14 +284,6 @@ static const struct ipath_cregs ipath_ht_cregs = { #define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000 #define INFINIPATH_EXTS_MEMBIST_CORRECT 0x0000000000008000 - -/* TID entries (memory), HT-only */ -#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */ -#define INFINIPATH_RT_VALID 0x8000000000000000ULL -#define INFINIPATH_RT_ADDR_SHIFT 0 -#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL -#define INFINIPATH_RT_BUFSIZE_SHIFT 48 - /* * masks and bits that are different in different chips, or present only * in one @@ -413,14 +402,6 @@ static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = { INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"), }; -#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \ - INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ - << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) -#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \ - << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) - -static int ipath_ht_txe_recover(struct ipath_devdata *); - /** * ipath_ht_handle_hwerrors - display hardware errors. * @dd: the infinipath device @@ -469,12 +450,13 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, /* * make sure we get this much out, unless told to be quiet, - * it's a parity error we may recover from, * or it's occurred within the last 5 seconds */ - if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY | - RXE_EAGER_PARITY)) || - (ipath_debug & __IPATH_VERBDBG)) + if ((hwerrs & ~(dd->ipath_lasthwerror | + ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) || + (ipath_debug & __IPATH_VERBDBG)) dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx " "(cleared)\n", (unsigned long long) hwerrs); dd->ipath_lasthwerror |= hwerrs; @@ -485,7 +467,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, (hwerrs & ~dd->ipath_hwe_bitsextant)); ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control); - if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) { + if (ctrl & INFINIPATH_C_FREEZEMODE) { /* * parity errors in send memory are recoverable, * just cancel the send (if indicated in * sendbuffererror), @@ -494,14 +476,50 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, * occur if a processor speculative read is done to the PIO * buffer while we are sending a packet, for example. */ - if ((hwerrs & TXE_PIO_PARITY) && ipath_ht_txe_recover(dd)) - hwerrs &= ~TXE_PIO_PARITY; - if (hwerrs & RXE_EAGER_PARITY) - ipath_dev_err(dd, "RXE parity, Eager TID error is not " - "recoverable\n"); - if (!hwerrs) { - ipath_dbg("Clearing freezemode on ignored or " - "recovered hardware error\n"); + if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { + ipath_stats.sps_txeparity++; + ipath_dbg("Recovering from TXE parity error (%llu), " + "hwerrstatus=%llx\n", + (unsigned long long) ipath_stats.sps_txeparity, + (unsigned long long) hwerrs); + ipath_disarm_senderrbufs(dd); + hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT); + if (!hwerrs) { /* else leave in freeze mode */ + ipath_write_kreg(dd, + dd->ipath_kregs->kr_control, + dd->ipath_control); + return; + } + } + if (hwerrs) { + /* + * if any set that we aren't ignoring; only + * make the complaint once, in case it's stuck + * or recurring, and we get here multiple + * times. + */ + if (dd->ipath_flags & IPATH_INITTED) { + ipath_dev_err(dd, "Fatal Hardware Error (freeze " + "mode), no longer usable, SN %.16s\n", + dd->ipath_serial); + isfatal = 1; + } + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + /* mark as having had error */ + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + /* + * mark as not usable, at a minimum until driver + * is reloaded, probably until reboot, since no + * other reset is possible. + */ + dd->ipath_flags &= ~IPATH_INITTED; + } else { + ipath_dbg("Clearing freezemode on ignored hardware " + "error\n"); ctrl &= ~INFINIPATH_C_FREEZEMODE; ipath_write_kreg(dd, dd->ipath_kregs->kr_control, ctrl); @@ -569,39 +587,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, dd->ipath_hwerrmask); } - if (hwerrs) { - /* - * if any set that we aren't ignoring; only - * make the complaint once, in case it's stuck - * or recurring, and we get here multiple - * times. - * force link down, so switch knows, and - * LEDs are turned off - */ - if (dd->ipath_flags & IPATH_INITTED) { - ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); - ipath_setup_ht_setextled(dd, - INFINIPATH_IBCS_L_STATE_DOWN, - INFINIPATH_IBCS_LT_STATE_DISABLED); - ipath_dev_err(dd, "Fatal Hardware Error (freeze " - "mode), no longer usable, SN %.16s\n", - dd->ipath_serial); - isfatal = 1; - } - *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; - /* mark as having had error */ - *dd->ipath_statusp |= IPATH_STATUS_HWERROR; - /* - * mark as not usable, at a minimum until driver - * is reloaded, probably until reboot, since no - * other reset is possible. - */ - dd->ipath_flags &= ~IPATH_INITTED; - } - else - *msg = 0; /* recovered from all of them */ - if (*msg) - ipath_dev_err(dd, "%s hardware error\n", msg); + ipath_dev_err(dd, "%s hardware error\n", msg); if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) /* * for status file; if no trailing brace is copied, @@ -672,8 +658,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, if (n) snprintf(name, namelen, "%s", n); - if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || - dd->ipath_minrev > 3)) { + if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) { /* * This version of the driver only supports Rev 3.2 and 3.3 */ @@ -1178,8 +1163,6 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd) if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) ipath_dev_err(dd, "MemBIST did not complete!\n"); - if (extsval & INFINIPATH_EXTS_MEMBIST_CORRECT) - ipath_dbg("MemBIST corrected\n"); ipath_check_htlink(dd); @@ -1383,9 +1366,6 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, u32 type, unsigned long pa) { - if (!dd->ipath_kregbase) - return; - if (pa != dd->ipath_tidinvalid) { if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) { dev_info(&dd->pcidev->dev, @@ -1402,10 +1382,10 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd, pa |= lenvalid | INFINIPATH_RT_VALID; } } - writeq(pa, tidptr); + if (dd->ipath_kregbase) + writeq(pa, tidptr); } - /** * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager * @dd: the infinipath device @@ -1535,7 +1515,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) INFINIPATH_S_ABORT); ipath_get_eeprom_info(dd); - if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && + if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { /* * Later production QHT7040 has same changes as QHT7140, so @@ -1548,24 +1528,6 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) return 0; } - -static int ipath_ht_txe_recover(struct ipath_devdata *dd) -{ - int cnt = ++ipath_stats.sps_txeparity; - if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { - if (cnt == IPATH_MAX_PARITY_ATTEMPTS) - ipath_dev_err(dd, - "Too many attempts to recover from " - "TXE parity, giving up\n"); - return 0; - } - dev_info(&dd->pcidev->dev, - "Recovering from TXE PIO parity error\n"); - ipath_disarm_senderrbufs(dd, 1); - return 1; -} - - /** * ipath_init_ht_get_base_info - set chip-specific flags for user code * @dd: the infinipath device diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c b/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c index 1b9c30857754..05918e1e7c36 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -43,8 +43,6 @@ #include "ipath_kernel.h" #include "ipath_registers.h" -static void ipath_setup_pe_setextled(struct ipath_devdata *, u64, u64); - /* * This file contains all the chip-specific register information and * access functions for the QLogic InfiniPath PCI-Express chip. @@ -209,8 +207,8 @@ static const struct ipath_kregs ipath_pe_kregs = { .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg), /* - * These should not be used directly via ipath_write_kreg64(), - * use them with ipath_write_kreg64_port(), + * These should not be used directly via ipath_read_kreg64(), + * use them with ipath_read_kreg64_port() */ .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), @@ -323,12 +321,6 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"), }; -#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \ - INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ - << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) - -static int ipath_pe_txe_recover(struct ipath_devdata *); - /** * ipath_pe_handle_hwerrors - display hardware errors. * @dd: the infinipath device @@ -402,21 +394,32 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, * occur if a processor speculative read is done to the PIO * buffer while we are sending a packet, for example. */ - if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd)) - hwerrs &= ~TXE_PIO_PARITY; + if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { + ipath_stats.sps_txeparity++; + ipath_dbg("Recovering from TXE parity error (%llu), " + "hwerrstatus=%llx\n", + (unsigned long long) ipath_stats.sps_txeparity, + (unsigned long long) hwerrs); + ipath_disarm_senderrbufs(dd); + hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | + INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT); + if (!hwerrs) { /* else leave in freeze mode */ + ipath_write_kreg(dd, + dd->ipath_kregs->kr_control, + dd->ipath_control); + return; + } + } if (hwerrs) { /* * if any set that we aren't ignoring only make the * complaint once, in case it's stuck or recurring, * and we get here multiple times - * Force link down, so switch knows, and - * LEDs are turned off */ if (dd->ipath_flags & IPATH_INITTED) { - ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); - ipath_setup_pe_setextled(dd, - INFINIPATH_IBCS_L_STATE_DOWN, - INFINIPATH_IBCS_LT_STATE_DISABLED); ipath_dev_err(dd, "Fatal Hardware Error (freeze " "mode), no longer usable, SN %.16s\n", dd->ipath_serial); @@ -490,8 +493,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, dd->ipath_hwerrmask); } - if (*msg) - ipath_dev_err(dd, "%s hardware error\n", msg); + ipath_dev_err(dd, "%s hardware error\n", msg); if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { /* * for /sys status file ; if no trailing } is copied, we'll @@ -579,8 +581,6 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd) if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) ipath_dev_err(dd, "MemBIST did not complete!\n"); - if (extsval & INFINIPATH_EXTS_MEMBIST_FOUND) - ipath_dbg("MemBIST corrected\n"); val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ @@ -1330,35 +1330,6 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd) dd->ipath_irq = 0; } -/* - * On platforms using this chip, and not having ordered WC stores, we - * can get TXE parity errors due to speculative reads to the PIO buffers, - * and this, due to a chip bug can result in (many) false parity error - * reports. So it's a debug print on those, and an info print on systems - * where the speculative reads don't occur. - * Because we can get lots of false errors, we have no upper limit - * on recovery attempts on those platforms. - */ -static int ipath_pe_txe_recover(struct ipath_devdata *dd) -{ - if (ipath_unordered_wc()) - ipath_dbg("Recovering from TXE PIO parity error\n"); - else { - int cnt = ++ipath_stats.sps_txeparity; - if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { - if (cnt == IPATH_MAX_PARITY_ATTEMPTS) - ipath_dev_err(dd, - "Too many attempts to recover from " - "TXE parity, giving up\n"); - return 0; - } - dev_info(&dd->pcidev->dev, - "Recovering from TXE PIO parity error\n"); - } - ipath_disarm_senderrbufs(dd, 1); - return 1; -} - /** * ipath_init_iba6120_funcs - set up the chip-specific function pointers * @dd: the infinipath device diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c index 7045ba689494..d4f6b5239ef8 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -216,20 +216,6 @@ static int bringup_link(struct ipath_devdata *dd) return ret; } -static struct ipath_portdata *create_portdata0(struct ipath_devdata *dd) -{ - struct ipath_portdata *pd = NULL; - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (pd) { - pd->port_dd = dd; - pd->port_cnt = 1; - /* The port 0 pkey table is used by the layer interface. */ - pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY; - } - return pd; -} - static int init_chip_first(struct ipath_devdata *dd, struct ipath_portdata **pdp) { @@ -285,16 +271,20 @@ static int init_chip_first(struct ipath_devdata *dd, goto done; } - pd = create_portdata0(dd); + dd->ipath_pd[0] = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { + if (!dd->ipath_pd[0]) { ipath_dev_err(dd, "Unable to allocate portdata for port " "0, failing\n"); ret = -ENOMEM; goto done; } - dd->ipath_pd[0] = pd; - + pd = dd->ipath_pd[0]; + pd->port_dd = dd; + pd->port_port = 0; + pd->port_cnt = 1; + /* The port 0 pkey table is used by the layer interface. */ + pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY; dd->ipath_rcvtidcnt = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt); dd->ipath_rcvtidbase = @@ -600,10 +590,6 @@ static int init_housekeeping(struct ipath_devdata *dd, goto done; } - - /* clear diagctrl register, in case diags were running and crashed */ - ipath_write_kreg (dd, dd->ipath_kregs->kr_hwdiagctrl, 0); - /* clear the initial reset flag, in case first driver load */ ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, INFINIPATH_E_RESET); @@ -682,7 +668,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) { int ret = 0, i; u32 val32, kpiobufs; - u32 piobufs, uports; u64 val; struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ gfp_t gfp_flags = GFP_USER | __GFP_COMP; @@ -717,17 +702,16 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) * the in memory DMA'ed copies of the registers. This has to * be done early, before we calculate lastport, etc. */ - piobufs = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k; + val = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k; /* * calc number of pioavail registers, and save it; we have 2 * bits per buffer. */ - dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2) + dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) / (sizeof(u64) * BITS_PER_BYTE / 2); - uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0; if (ipath_kpiobufs == 0) { /* not set by user (this is default) */ - if (piobufs >= (uports * IPATH_MIN_USER_PORT_BUFCNT) + 32) + if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128) kpiobufs = 32; else kpiobufs = 16; @@ -735,25 +719,31 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) else kpiobufs = ipath_kpiobufs; - if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) { - i = (int) piobufs - - (int) (uports * IPATH_MIN_USER_PORT_BUFCNT); + if (kpiobufs > + (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - + (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT))) { + i = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - + (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT); if (i < 0) i = 0; - dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of " - "%d for kernel leaves too few for %d user ports " + dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs for " + "kernel leaves too few for %d user ports " "(%d each); using %u\n", kpiobufs, - piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i); + dd->ipath_cfgports - 1, + IPATH_MIN_USER_PORT_BUFCNT, i); /* * shouldn't change ipath_kpiobufs, because could be * different for different devices... */ kpiobufs = i; } - dd->ipath_lastport_piobuf = piobufs - kpiobufs; - dd->ipath_pbufsport = - uports ? dd->ipath_lastport_piobuf / uports : 0; - val32 = dd->ipath_lastport_piobuf - (dd->ipath_pbufsport * uports); + dd->ipath_lastport_piobuf = + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - kpiobufs; + dd->ipath_pbufsport = dd->ipath_cfgports > 1 + ? dd->ipath_lastport_piobuf / (dd->ipath_cfgports - 1) + : 0; + val32 = dd->ipath_lastport_piobuf - + (dd->ipath_pbufsport * (dd->ipath_cfgports - 1)); if (val32 > 0) { ipath_dbg("allocating %u pbufs/port leaves %u unused, " "add to kernel\n", dd->ipath_pbufsport, val32); @@ -764,7 +754,8 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) dd->ipath_lastpioindex = dd->ipath_lastport_piobuf; ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u " "each for %u user ports\n", kpiobufs, - piobufs, dd->ipath_pbufsport, uports); + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k, + dd->ipath_pbufsport, dd->ipath_cfgports - 1); dd->ipath_f_early_init(dd); @@ -848,24 +839,11 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) * Set up the port 0 (kernel) rcvhdr q and egr TIDs. If doing * re-init, the simplest way to handle this is to free * existing, and re-allocate. - * Need to re-create rest of port 0 portdata as well. */ if (reinit) { - /* Alloc and init new ipath_portdata for port0, - * Then free old pd. Could lead to fragmentation, but also - * makes later support for hot-swap easier. - */ - struct ipath_portdata *npd; - npd = create_portdata0(dd); - if (npd) { - ipath_free_pddata(dd, pd); - dd->ipath_pd[0] = pd = npd; - } else { - ipath_dev_err(dd, "Unable to allocate portdata for" - " port 0, failing\n"); - ret = -ENOMEM; - goto done; - } + struct ipath_portdata *pd = dd->ipath_pd[0]; + dd->ipath_pd[0] = NULL; + ipath_free_pddata(dd, pd); } dd->ipath_f_tidtemplate(dd); ret = ipath_create_rcvhdrq(dd, pd); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_intr.c b/trunk/drivers/infiniband/hw/ipath/ipath_intr.c index 45d033169c6e..72b9e279d19d 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_intr.c @@ -37,40 +37,11 @@ #include "ipath_verbs.h" #include "ipath_common.h" -/* - * clear (write) a pio buffer, to clear a parity error. This routine - * should only be called when in freeze mode, and the buffer should be - * canceled afterwards. - */ -static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum) -{ - u32 __iomem *pbuf; - u32 dwcnt; /* dword count to write */ - if (pnum < dd->ipath_piobcnt2k) { - pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum * - dd->ipath_palign); - dwcnt = dd->ipath_piosize2k >> 2; - } - else { - pbuf = (u32 __iomem *) (dd->ipath_pio4kbase + - (pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign); - dwcnt = dd->ipath_piosize4k >> 2; - } - dev_info(&dd->pcidev->dev, - "Rewrite PIO buffer %u, to recover from parity error\n", - pnum); - *pbuf = dwcnt+1; /* no flush required, since already in freeze */ - while(--dwcnt) - *pbuf++ = 0; -} - /* * Called when we might have an error that is specific to a particular * PIO buffer, and may need to cancel that buffer, so it can be re-used. - * If rewrite is true, and bits are set in the sendbufferror registers, - * we'll write to the buffer, for error recovery on parity errors. */ -void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite) +void ipath_disarm_senderrbufs(struct ipath_devdata *dd) { u32 piobcnt; unsigned long sbuf[4]; @@ -103,11 +74,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite) } for (i = 0; i < piobcnt; i++) - if (test_bit(i, sbuf)) { - if (rewrite) - ipath_clrpiobuf(dd, i); + if (test_bit(i, sbuf)) ipath_disarm_piobufs(dd, i, 1); - } dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */ } } @@ -146,7 +114,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs) { u64 ignore_this_time = 0; - ipath_disarm_senderrbufs(dd, 0); + ipath_disarm_senderrbufs(dd); if ((errs & E_SUM_LINK_PKTERRS) && !(dd->ipath_flags & IPATH_LINKACTIVE)) { /* @@ -435,13 +403,10 @@ static void handle_supp_msgs(struct ipath_devdata *dd, * happens so often we never want to count it. */ if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) { - int iserr; - iserr = ipath_decode_err(msg, sizeof msg, - dd->ipath_lasterror & - ~INFINIPATH_E_IBSTATUSCHANGED); + ipath_decode_err(msg, sizeof msg, dd->ipath_lasterror & + ~INFINIPATH_E_IBSTATUSCHANGED); if (dd->ipath_lasterror & - ~(INFINIPATH_E_RRCVEGRFULL | - INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS)) + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) ipath_dev_err(dd, "Suppressed %u messages for " "fast-repeating errors (%s) (%llx)\n", supp_msgs, msg, @@ -455,13 +420,8 @@ static void handle_supp_msgs(struct ipath_devdata *dd, * them. So only complain about these at debug * level. */ - if (iserr) - ipath_dbg("Suppressed %u messages for %s\n", - supp_msgs, msg); - else - ipath_cdbg(ERRPKT, - "Suppressed %u messages for %s\n", - supp_msgs, msg); + ipath_dbg("Suppressed %u messages for %s\n", + supp_msgs, msg); } } } @@ -502,7 +462,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) { char msg[512]; u64 ignore_this_time = 0; - int i, iserr = 0; + int i; int chkerrpkts = 0, noprint = 0; unsigned supp_msgs; @@ -542,7 +502,6 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) } if (supp_msgs == 250000) { - int s_iserr; /* * It's not entirely reasonable assuming that the errors set * in the last clear period are all responsible for the @@ -552,17 +511,17 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) dd->ipath_maskederrs |= dd->ipath_lasterror | errs; ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, ~dd->ipath_maskederrs); - s_iserr = ipath_decode_err(msg, sizeof msg, + ipath_decode_err(msg, sizeof msg, (dd->ipath_maskederrs & ~dd-> ipath_ignorederrs)); if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) & - ~(INFINIPATH_E_RRCVEGRFULL | - INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS)) - ipath_dev_err(dd, "Temporarily disabling " - "error(s) %llx reporting; too frequent (%s)\n", - (unsigned long long) (dd->ipath_maskederrs & - ~dd->ipath_ignorederrs), msg); + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) + ipath_dev_err(dd, "Disabling error(s) %llx because " + "occurring too frequently (%s)\n", + (unsigned long long) + (dd->ipath_maskederrs & + ~dd->ipath_ignorederrs), msg); else { /* * rcvegrfull and rcvhdrqfull are "normal", @@ -571,15 +530,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) * processing them. So only complain about * these at debug level. */ - if (s_iserr) - ipath_dbg("Temporarily disabling reporting " - "too frequent queue full errors (%s)\n", - msg); - else - ipath_cdbg(ERRPKT, - "Temporarily disabling reporting too" - " frequent packet errors (%s)\n", - msg); + ipath_dbg("Disabling frequent queue full errors " + "(%s)\n", msg); } /* @@ -637,8 +589,6 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) ipath_stats.sps_crcerrs++; chkerrpkts = 1; } - iserr = errs & ~(E_SUM_PKTERRS | INFINIPATH_E_PKTERRS); - /* * We don't want to print these two as they happen, or we can make @@ -727,13 +677,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) *dd->ipath_statusp &= ~IPATH_STATUS_IB_CONF; } - if (!noprint && *msg) { - if (iserr) - ipath_dev_err(dd, "%s error\n", msg); - else - dev_info(&dd->pcidev->dev, "%s packet problems\n", - msg); - } + if (!noprint && *msg) + ipath_dev_err(dd, "%s error\n", msg); if (dd->ipath_state_wanted & dd->ipath_flags) { ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, " "waking\n", dd->ipath_state_wanted, @@ -874,10 +819,11 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) struct ipath_portdata *pd = dd->ipath_pd[i]; if (portr & (1 << i) && pd && pd->port_cnt && test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { + int rcbit; clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); - clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, - &dd->ipath_rcvctrl); + rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT; + clear_bit(1UL << rcbit, &dd->ipath_rcvctrl); wake_up_interruptible(&pd->port_wait); rcvdint = 1; } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h b/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h index e900c2593f44..6d8d05fb5999 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -590,6 +590,7 @@ int ipath_enable_wc(struct ipath_devdata *dd); void ipath_disable_wc(struct ipath_devdata *dd); int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp); void ipath_shutdown_device(struct ipath_devdata *); +void ipath_disarm_senderrbufs(struct ipath_devdata *); struct file_operations; int ipath_cdev_init(int minor, char *name, const struct file_operations *fops, @@ -610,7 +611,7 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t); extern int ipath_diag_inuse; irqreturn_t ipath_intr(int irq, void *devid); -int ipath_decode_err(char *buf, size_t blen, ipath_err_t err); +void ipath_decode_err(char *buf, size_t blen, ipath_err_t err); #if __IPATH_INFO || __IPATH_DBG extern const char *ipath_ibcstatus_str[]; #endif @@ -700,8 +701,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); #define IPATH_PORT_WAITING_RCV 2 /* waiting for a PIO buffer to be available */ #define IPATH_PORT_WAITING_PIO 3 - /* master has not finished initializing */ -#define IPATH_PORT_MASTER_UNINIT 4 /* free up any allocated data at closes */ void ipath_free_data(struct ipath_portdata *dd); @@ -712,7 +711,6 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *); void ipath_init_iba6110_funcs(struct ipath_devdata *); void ipath_get_eeprom_info(struct ipath_devdata *); u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); -void ipath_disarm_senderrbufs(struct ipath_devdata *, int); /* * number of words used for protocol header if not set by ipath_userinit(); @@ -756,6 +754,8 @@ int ipath_eeprom_write(struct ipath_devdata *, u8, const void *, int); /* these are used for the registers that vary with port */ void ipath_write_kreg_port(const struct ipath_devdata *, ipath_kreg, unsigned, u64); +u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg, + unsigned); /* * We could have a single register get/put routine, that takes a group type, @@ -897,8 +897,6 @@ dma_addr_t ipath_map_single(struct pci_dev *, void *, size_t, int); extern unsigned ipath_debug; /* debugging bit mask */ -#define IPATH_MAX_PARITY_ATTEMPTS 10000 /* max times to try recovery */ - const char *ipath_get_unit_name(int unit); extern struct mutex ipath_mutex; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_keys.c b/trunk/drivers/infiniband/hw/ipath/ipath_keys.c index dd487c100f5b..851763d7d2db 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_keys.c @@ -61,7 +61,7 @@ int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr) r = (r + 1) & (rkt->max - 1); if (r == n) { spin_unlock_irqrestore(&rkt->lock, flags); - ipath_dbg("LKEY table full\n"); + ipath_dbg(KERN_INFO "LKEY table full\n"); ret = 0; goto bail; } @@ -133,12 +133,6 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, * being reversible by calling bus_to_virt(). */ if (sge->lkey == 0) { - struct ipath_pd *pd = to_ipd(qp->ibqp.pd); - - if (pd->user) { - ret = 0; - goto bail; - } isge->mr = NULL; isge->vaddr = (void *) sge->addr; isge->length = sge->length; @@ -212,12 +206,6 @@ int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss, * (see ipath_get_dma_mr and ipath_dma.c). */ if (rkey == 0) { - struct ipath_pd *pd = to_ipd(qp->ibqp.pd); - - if (pd->user) { - ret = 0; - goto bail; - } sge->mr = NULL; sge->vaddr = (void *) vaddr; sge->length = len; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_layer.c b/trunk/drivers/infiniband/hw/ipath/ipath_layer.c index 05a1d2b01d9d..e46aa4ed2a7e 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_layer.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_layer.c @@ -37,6 +37,7 @@ */ #include +#include #include #include "ipath_kernel.h" diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_mr.c b/trunk/drivers/infiniband/hw/ipath/ipath_mr.c index 31e70732e369..8cc8598d6c69 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_mr.c @@ -210,15 +210,9 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, m = 0; n = 0; list_for_each_entry(chunk, ®ion->chunk_list, list) { - for (i = 0; i < chunk->nents; i++) { - void *vaddr; - - vaddr = page_address(chunk->page_list[i].page); - if (!vaddr) { - ret = ERR_PTR(-EINVAL); - goto bail; - } - mr->mr.map[m]->segs[n].vaddr = vaddr; + for (i = 0; i < chunk->nmap; i++) { + mr->mr.map[m]->segs[n].vaddr = + page_address(chunk->page_list[i].page); mr->mr.map[m]->segs[n].length = region->page_size; n++; if (n == IPATH_SEGSZ) { diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c index 16db9ac0b402..64f07b19349f 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c @@ -81,51 +81,11 @@ static u32 credit_table[31] = { 32768 /* 1E */ }; - -static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map) -{ - unsigned long page = get_zeroed_page(GFP_KERNEL); - unsigned long flags; - - /* - * Free the page if someone raced with us installing it. - */ - - spin_lock_irqsave(&qpt->lock, flags); - if (map->page) - free_page(page); - else - map->page = (void *)page; - spin_unlock_irqrestore(&qpt->lock, flags); -} - - -static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type) +static u32 alloc_qpn(struct ipath_qp_table *qpt) { u32 i, offset, max_scan, qpn; struct qpn_map *map; - u32 ret = -1; - - if (type == IB_QPT_SMI) - ret = 0; - else if (type == IB_QPT_GSI) - ret = 1; - - if (ret != -1) { - map = &qpt->map[0]; - if (unlikely(!map->page)) { - get_map_page(qpt, map); - if (unlikely(!map->page)) { - ret = -ENOMEM; - goto bail; - } - } - if (!test_and_set_bit(ret, map->page)) - atomic_dec(&map->n_free); - else - ret = -EBUSY; - goto bail; - } + u32 ret; qpn = qpt->last + 1; if (qpn >= QPN_MAX) @@ -135,7 +95,19 @@ static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type) max_scan = qpt->nmaps - !offset; for (i = 0;;) { if (unlikely(!map->page)) { - get_map_page(qpt, map); + unsigned long page = get_zeroed_page(GFP_KERNEL); + unsigned long flags; + + /* + * Free the page if someone raced with us + * installing it: + */ + spin_lock_irqsave(&qpt->lock, flags); + if (map->page) + free_page(page); + else + map->page = (void *)page; + spin_unlock_irqrestore(&qpt->lock, flags); if (unlikely(!map->page)) break; } @@ -179,7 +151,7 @@ static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type) qpn = mk_qpn(qpt, map, offset); } - ret = -ENOMEM; + ret = 0; bail: return ret; @@ -208,19 +180,29 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp, enum ib_qp_type type) { unsigned long flags; + u32 qpn; int ret; - ret = alloc_qpn(qpt, type); - if (ret < 0) - goto bail; - qp->ibqp.qp_num = ret; + if (type == IB_QPT_SMI) + qpn = 0; + else if (type == IB_QPT_GSI) + qpn = 1; + else { + /* Allocate the next available QPN */ + qpn = alloc_qpn(qpt); + if (qpn == 0) { + ret = -ENOMEM; + goto bail; + } + } + qp->ibqp.qp_num = qpn; /* Add the QP to the hash table. */ spin_lock_irqsave(&qpt->lock, flags); - ret %= qpt->max; - qp->next = qpt->table[ret]; - qpt->table[ret] = qp; + qpn %= qpt->max; + qp->next = qpt->table[qpn]; + qpt->table[qpn] = qp; atomic_inc(&qp->refcount); spin_unlock_irqrestore(&qpt->lock, flags); @@ -263,7 +245,9 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp) if (!fnd) return; - free_qpn(qpt, qp->ibqp.qp_num); + /* If QPN is not reserved, mark QPN free in the bitmap. */ + if (qp->ibqp.qp_num > 1) + free_qpn(qpt, qp->ibqp.qp_num); wait_event(qp->wait, !atomic_read(&qp->refcount)); } @@ -286,10 +270,11 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt) while (qp) { nqp = qp->next; - free_qpn(qpt, qp->ibqp.qp_num); + if (qp->ibqp.qp_num > 1) + free_qpn(qpt, qp->ibqp.qp_num); if (!atomic_dec_and_test(&qp->refcount) || !ipath_destroy_qp(&qp->ibqp)) - ipath_dbg("QP memory leak!\n"); + ipath_dbg(KERN_INFO "QP memory leak!\n"); qp = nqp; } } @@ -335,8 +320,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->remote_qpn = 0; qp->qkey = 0; qp->qp_access_flags = 0; - qp->s_busy = 0; - qp->s_flags &= ~IPATH_S_SIGNAL_REQ_WR; + clear_bit(IPATH_S_BUSY, &qp->s_flags); qp->s_hdrwords = 0; qp->s_psn = 0; qp->r_psn = 0; @@ -349,6 +333,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->r_state = IB_OPCODE_UC_SEND_LAST; } qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; + qp->r_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; qp->r_nak_state = 0; qp->r_wrid_valid = 0; qp->s_rnr_timeout = 0; @@ -359,10 +344,6 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->s_ssn = 1; qp->s_lsn = 0; qp->s_wait_credit = 0; - memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue)); - qp->r_head_ack_queue = 0; - qp->s_tail_ack_queue = 0; - qp->s_num_rd_atomic = 0; if (qp->r_rq.wq) { qp->r_rq.wq->head = 0; qp->r_rq.wq->tail = 0; @@ -376,7 +357,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) * @err: the receive completion error to signal if a RWQE is active * * Flushes both send and receive work queues. - * The QP s_lock should be held and interrupts disabled. + * QP s_lock should be held and interrupts disabled. */ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) @@ -384,7 +365,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ib_wc wc; - ipath_dbg("QP%d/%d in error state\n", + ipath_dbg(KERN_INFO "QP%d/%d in error state\n", qp->ibqp.qp_num, qp->remote_qpn); spin_lock(&dev->pending_lock); @@ -408,8 +389,6 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) wc.port_num = 0; if (qp->r_wrid_valid) { qp->r_wrid_valid = 0; - wc.wr_id = qp->r_wr_id; - wc.opcode = IB_WC_RECV; wc.status = err; ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1); } @@ -524,17 +503,13 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, attr->path_mig_state != IB_MIG_REARM) goto inval; - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) - if (attr->max_dest_rd_atomic > IPATH_MAX_RDMA_ATOMIC) - goto inval; - switch (new_state) { case IB_QPS_RESET: ipath_reset_qp(qp); break; case IB_QPS_ERR: - ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR); + ipath_error_qp(qp, IB_WC_GENERAL_ERR); break; default: @@ -584,12 +559,6 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (attr_mask & IB_QP_QKEY) qp->qkey = attr->qkey; - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) - qp->r_max_rd_atomic = attr->max_dest_rd_atomic; - - if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) - qp->s_max_rd_atomic = attr->max_rd_atomic; - qp->state = new_state; spin_unlock_irqrestore(&qp->s_lock, flags); @@ -629,8 +598,8 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, attr->alt_pkey_index = 0; attr->en_sqd_async_notify = 0; attr->sq_draining = 0; - attr->max_rd_atomic = qp->s_max_rd_atomic; - attr->max_dest_rd_atomic = qp->r_max_rd_atomic; + attr->max_rd_atomic = 1; + attr->max_dest_rd_atomic = 1; attr->min_rnr_timer = qp->r_min_rnr_timer; attr->port_num = 1; attr->timeout = qp->timeout; @@ -645,7 +614,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, init_attr->recv_cq = qp->ibqp.recv_cq; init_attr->srq = qp->ibqp.srq; init_attr->cap = attr->cap; - if (qp->s_flags & IPATH_S_SIGNAL_REQ_WR) + if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR)) init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; else init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; @@ -817,7 +786,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, qp->s_size = init_attr->cap.max_send_wr + 1; qp->s_max_sge = init_attr->cap.max_send_sge; if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) - qp->s_flags = IPATH_S_SIGNAL_REQ_WR; + qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR; else qp->s_flags = 0; dev = to_idev(ibpd->device); @@ -989,7 +958,7 @@ int ipath_init_qp_table(struct ipath_ibdev *idev, int size) * @wc: the WC responsible for putting the QP in this state * * Flushes the send work queue. - * The QP s_lock should be held and interrupts disabled. + * The QP s_lock should be held. */ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc) @@ -997,7 +966,7 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc) struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); - ipath_dbg("Send queue error on QP%d/%d: err: %d\n", + ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n", qp->ibqp.qp_num, qp->remote_qpn, wc->status); spin_lock(&dev->pending_lock); @@ -1015,12 +984,12 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc) wc->status = IB_WC_WR_FLUSH_ERR; while (qp->s_last != qp->s_head) { - wqe = get_swqe_ptr(qp, qp->s_last); wc->wr_id = wqe->wr.wr_id; wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1); if (++qp->s_last >= qp->s_size) qp->s_last = 0; + wqe = get_swqe_ptr(qp, qp->s_last); } qp->s_cur = qp->s_tail = qp->s_head; qp->state = IB_QPS_SQE; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c index b4b88d0b53f5..5ff20cb04494 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c @@ -37,19 +37,6 @@ /* cut down ridiculously long IB macro names */ #define OP(x) IB_OPCODE_RC_##x -static u32 restart_sge(struct ipath_sge_state *ss, struct ipath_swqe *wqe, - u32 psn, u32 pmtu) -{ - u32 len; - - len = ((psn - wqe->psn) & IPATH_PSN_MASK) * pmtu; - ss->sge = wqe->sg_list[0]; - ss->sg_list = wqe->sg_list + 1; - ss->num_sge = wqe->wr.num_sge; - ipath_skip_sge(ss, len); - return wqe->length - len; -} - /** * ipath_init_restart- initialize the qp->s_sge after a restart * @qp: the QP who's SGE we're restarting @@ -60,9 +47,15 @@ static u32 restart_sge(struct ipath_sge_state *ss, struct ipath_swqe *wqe, static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe) { struct ipath_ibdev *dev; + u32 len; - qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, - ib_mtu_enum_to_int(qp->path_mtu)); + len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) * + ib_mtu_enum_to_int(qp->path_mtu); + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + ipath_skip_sge(&qp->s_sge, len); + qp->s_len = wqe->length - len; dev = to_idev(qp->ibqp.device); spin_lock(&dev->pending_lock); if (list_empty(&qp->timerwait)) @@ -77,123 +70,107 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe) * @ohdr: a pointer to the IB header being constructed * @pmtu: the path MTU * - * Return 1 if constructed; otherwise, return 0. - * Note that we are in the responder's side of the QP context. + * Return bth0 if constructed; otherwise, return 0. * Note the QP s_lock must be held. */ -static int ipath_make_rc_ack(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +u32 ipath_make_rc_ack(struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 pmtu) { - struct ipath_ack_entry *e; u32 hwords; u32 len; u32 bth0; - u32 bth2; /* header size in 32-bit words LRH+BTH = (8+12)/4. */ hwords = 5; + /* + * Send a response. Note that we are in the responder's + * side of the QP context. + */ switch (qp->s_ack_state) { - case OP(RDMA_READ_RESPONSE_LAST): - case OP(RDMA_READ_RESPONSE_ONLY): - case OP(ATOMIC_ACKNOWLEDGE): - qp->s_ack_state = OP(ACKNOWLEDGE); - /* FALLTHROUGH */ - case OP(ACKNOWLEDGE): - /* Check for no next entry in the queue. */ - if (qp->r_head_ack_queue == qp->s_tail_ack_queue) { - if (qp->s_flags & IPATH_S_ACK_PENDING) - goto normal; - goto bail; - } - - e = &qp->s_ack_queue[qp->s_tail_ack_queue]; - if (e->opcode == OP(RDMA_READ_REQUEST)) { - /* Copy SGE state in case we need to resend */ - qp->s_ack_rdma_sge = e->rdma_sge; - qp->s_cur_sge = &qp->s_ack_rdma_sge; - len = e->rdma_sge.sge.sge_length; - if (len > pmtu) { - len = pmtu; - qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); - } else { - qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); - if (++qp->s_tail_ack_queue > - IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; - } - ohdr->u.aeth = ipath_compute_aeth(qp); - hwords++; - qp->s_ack_rdma_psn = e->psn; - bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK; - } else { - /* COMPARE_SWAP or FETCH_ADD */ - qp->s_cur_sge = NULL; - len = 0; - qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE); - ohdr->u.at.aeth = ipath_compute_aeth(qp); - ohdr->u.at.atomic_ack_eth[0] = - cpu_to_be32(e->atomic_data >> 32); - ohdr->u.at.atomic_ack_eth[1] = - cpu_to_be32(e->atomic_data); - hwords += sizeof(ohdr->u.at) / sizeof(u32); - bth2 = e->psn; - if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; - } + case OP(RDMA_READ_REQUEST): + qp->s_cur_sge = &qp->s_rdma_sge; + len = qp->s_rdma_len; + if (len > pmtu) { + len = pmtu; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); + } else + qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); + qp->s_rdma_len -= len; bth0 = qp->s_ack_state << 24; + ohdr->u.aeth = ipath_compute_aeth(qp); + hwords++; break; case OP(RDMA_READ_RESPONSE_FIRST): qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE); /* FALLTHROUGH */ case OP(RDMA_READ_RESPONSE_MIDDLE): - len = qp->s_ack_rdma_sge.sge.sge_length; + qp->s_cur_sge = &qp->s_rdma_sge; + len = qp->s_rdma_len; if (len > pmtu) len = pmtu; else { ohdr->u.aeth = ipath_compute_aeth(qp); hwords++; qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); - if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; } + qp->s_rdma_len -= len; bth0 = qp->s_ack_state << 24; - bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK; break; - default: - normal: + case OP(RDMA_READ_RESPONSE_LAST): + case OP(RDMA_READ_RESPONSE_ONLY): + /* + * We have to prevent new requests from changing + * the r_sge state while a ipath_verbs_send() + * is in progress. + */ + qp->s_ack_state = OP(ACKNOWLEDGE); + bth0 = 0; + goto bail; + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + qp->s_cur_sge = NULL; + len = 0; /* - * Send a regular ACK. - * Set the s_ack_state so we wait until after sending - * the ACK before setting s_ack_state to ACKNOWLEDGE - * (see above). + * Set the s_ack_state so the receive interrupt handler + * won't try to send an ACK (out of order) until this one + * is actually sent. */ - qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE); - qp->s_flags &= ~IPATH_S_ACK_PENDING; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); + bth0 = OP(ATOMIC_ACKNOWLEDGE) << 24; + ohdr->u.at.aeth = ipath_compute_aeth(qp); + ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data); + hwords += sizeof(ohdr->u.at) / 4; + break; + + default: + /* Send a regular ACK. */ qp->s_cur_sge = NULL; + len = 0; + /* + * Set the s_ack_state so the receive interrupt handler + * won't try to send an ACK (out of order) until this one + * is actually sent. + */ + qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); + bth0 = OP(ACKNOWLEDGE) << 24; if (qp->s_nak_state) - ohdr->u.aeth = - cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) | - (qp->s_nak_state << - IPATH_AETH_CREDIT_SHIFT)); + ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) | + (qp->s_nak_state << + IPATH_AETH_CREDIT_SHIFT)); else ohdr->u.aeth = ipath_compute_aeth(qp); hwords++; - len = 0; - bth0 = OP(ACKNOWLEDGE) << 24; - bth2 = qp->s_ack_psn & IPATH_PSN_MASK; } qp->s_hdrwords = hwords; qp->s_cur_size = len; - *bth0p = bth0; - *bth2p = bth2; - return 1; bail: - return 0; + return bth0; } /** @@ -220,16 +197,9 @@ int ipath_make_rc_req(struct ipath_qp *qp, u32 bth2; char newreq; - /* Sending responses has higher priority over sending requests. */ - if ((qp->r_head_ack_queue != qp->s_tail_ack_queue || - (qp->s_flags & IPATH_S_ACK_PENDING) || - qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE) && - ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p)) - goto done; - if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) || qp->s_rnr_timeout) - goto bail; + goto done; /* Limit the number of packets sent without an ACK. */ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) { @@ -240,7 +210,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, list_add_tail(&qp->timerwait, &dev->pending[dev->pending_index]); spin_unlock(&dev->pending_lock); - goto bail; + goto done; } /* header size in 32-bit words LRH+BTH = (8+12)/4. */ @@ -262,16 +232,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, if (qp->s_cur == qp->s_tail) { /* Check if send work queue is empty. */ if (qp->s_tail == qp->s_head) - goto bail; - /* - * If a fence is requested, wait for previous - * RDMA read and atomic operations to finish. - */ - if ((wqe->wr.send_flags & IB_SEND_FENCE) && - qp->s_num_rd_atomic) { - qp->s_flags |= IPATH_S_FENCE_PENDING; - goto bail; - } + goto done; wqe->psn = qp->s_next_psn; newreq = 1; } @@ -289,7 +250,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, /* If no credit, return. */ if (qp->s_lsn != (u32) -1 && ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) - goto bail; + goto done; wqe->lpsn = wqe->psn; if (len > pmtu) { wqe->lpsn += (len - 1) / pmtu; @@ -320,13 +281,13 @@ int ipath_make_rc_req(struct ipath_qp *qp, /* If no credit, return. */ if (qp->s_lsn != (u32) -1 && ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) - goto bail; + goto done; ohdr->u.rc.reth.vaddr = cpu_to_be64(wqe->wr.wr.rdma.remote_addr); ohdr->u.rc.reth.rkey = cpu_to_be32(wqe->wr.wr.rdma.rkey); ohdr->u.rc.reth.length = cpu_to_be32(len); - hwords += sizeof(struct ib_reth) / sizeof(u32); + hwords += sizeof(struct ib_reth) / 4; wqe->lpsn = wqe->psn; if (len > pmtu) { wqe->lpsn += (len - 1) / pmtu; @@ -351,17 +312,14 @@ int ipath_make_rc_req(struct ipath_qp *qp, break; case IB_WR_RDMA_READ: - /* - * Don't allow more operations to be started - * than the QP limits allow. - */ + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + qp->s_state = OP(RDMA_READ_REQUEST); + hwords += sizeof(ohdr->u.rc.reth) / 4; if (newreq) { - if (qp->s_num_rd_atomic >= - qp->s_max_rd_atomic) { - qp->s_flags |= IPATH_S_RDMAR_PENDING; - goto bail; - } - qp->s_num_rd_atomic++; if (qp->s_lsn != (u32) -1) qp->s_lsn++; /* @@ -372,13 +330,6 @@ int ipath_make_rc_req(struct ipath_qp *qp, qp->s_next_psn += (len - 1) / pmtu; wqe->lpsn = qp->s_next_psn++; } - ohdr->u.rc.reth.vaddr = - cpu_to_be64(wqe->wr.wr.rdma.remote_addr); - ohdr->u.rc.reth.rkey = - cpu_to_be32(wqe->wr.wr.rdma.rkey); - ohdr->u.rc.reth.length = cpu_to_be32(len); - qp->s_state = OP(RDMA_READ_REQUEST); - hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32); ss = NULL; len = 0; if (++qp->s_cur == qp->s_size) @@ -387,48 +338,32 @@ int ipath_make_rc_req(struct ipath_qp *qp, case IB_WR_ATOMIC_CMP_AND_SWP: case IB_WR_ATOMIC_FETCH_AND_ADD: - /* - * Don't allow more operations to be started - * than the QP limits allow. - */ - if (newreq) { - if (qp->s_num_rd_atomic >= - qp->s_max_rd_atomic) { - qp->s_flags |= IPATH_S_RDMAR_PENDING; - goto bail; - } - qp->s_num_rd_atomic++; - if (qp->s_lsn != (u32) -1) - qp->s_lsn++; - wqe->lpsn = wqe->psn; - } - if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) { + if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) qp->s_state = OP(COMPARE_SWAP); - ohdr->u.atomic_eth.swap_data = cpu_to_be64( - wqe->wr.wr.atomic.swap); - ohdr->u.atomic_eth.compare_data = cpu_to_be64( - wqe->wr.wr.atomic.compare_add); - } else { + else qp->s_state = OP(FETCH_ADD); - ohdr->u.atomic_eth.swap_data = cpu_to_be64( - wqe->wr.wr.atomic.compare_add); - ohdr->u.atomic_eth.compare_data = 0; - } - ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32( - wqe->wr.wr.atomic.remote_addr >> 32); - ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32( + ohdr->u.atomic_eth.vaddr = cpu_to_be64( wqe->wr.wr.atomic.remote_addr); ohdr->u.atomic_eth.rkey = cpu_to_be32( wqe->wr.wr.atomic.rkey); - hwords += sizeof(struct ib_atomic_eth) / sizeof(u32); - ss = NULL; - len = 0; + ohdr->u.atomic_eth.swap_data = cpu_to_be64( + wqe->wr.wr.atomic.swap); + ohdr->u.atomic_eth.compare_data = cpu_to_be64( + wqe->wr.wr.atomic.compare_add); + hwords += sizeof(struct ib_atomic_eth) / 4; + if (newreq) { + if (qp->s_lsn != (u32) -1) + qp->s_lsn++; + wqe->lpsn = wqe->psn; + } if (++qp->s_cur == qp->s_size) qp->s_cur = 0; + ss = NULL; + len = 0; break; default: - goto bail; + goto done; } qp->s_sge.sge = wqe->sg_list[0]; qp->s_sge.sg_list = wqe->sg_list + 1; @@ -444,7 +379,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, qp->s_psn = wqe->lpsn + 1; else { qp->s_psn++; - if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0) + if ((int)(qp->s_psn - qp->s_next_psn) > 0) qp->s_next_psn = qp->s_psn; } /* @@ -471,7 +406,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, /* FALLTHROUGH */ case OP(SEND_MIDDLE): bth2 = qp->s_psn++ & IPATH_PSN_MASK; - if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0) + if ((int)(qp->s_psn - qp->s_next_psn) > 0) qp->s_next_psn = qp->s_psn; ss = &qp->s_sge; len = qp->s_len; @@ -507,7 +442,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, /* FALLTHROUGH */ case OP(RDMA_WRITE_MIDDLE): bth2 = qp->s_psn++ & IPATH_PSN_MASK; - if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0) + if ((int)(qp->s_psn - qp->s_next_psn) > 0) qp->s_next_psn = qp->s_psn; ss = &qp->s_sge; len = qp->s_len; @@ -544,9 +479,9 @@ int ipath_make_rc_req(struct ipath_qp *qp, cpu_to_be32(wqe->wr.wr.rdma.rkey); ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len); qp->s_state = OP(RDMA_READ_REQUEST); - hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32); + hwords += sizeof(ohdr->u.rc.reth) / 4; bth2 = qp->s_psn++ & IPATH_PSN_MASK; - if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0) + if ((int)(qp->s_psn - qp->s_next_psn) > 0) qp->s_next_psn = qp->s_psn; ss = NULL; len = 0; @@ -554,6 +489,20 @@ int ipath_make_rc_req(struct ipath_qp *qp, if (qp->s_cur == qp->s_size) qp->s_cur = 0; break; + + case OP(RDMA_READ_REQUEST): + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + /* + * We shouldn't start anything new until this request is + * finished. The ACK will handle rescheduling us. XXX The + * number of outstanding ones is negotiated at connection + * setup time (see pg. 258,289)? XXX Also, if we support + * multiple outstanding requests, we need to check the WQE + * IB_SEND_FENCE flag and not send a new request if a RDMA + * read or atomic is pending. + */ + goto done; } if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0) bth2 |= 1 << 31; /* Request ACK. */ @@ -563,10 +512,9 @@ int ipath_make_rc_req(struct ipath_qp *qp, qp->s_cur_size = len; *bth0p = bth0 | (qp->s_state << 24); *bth2p = bth2; -done: return 1; -bail: +done: return 0; } @@ -576,8 +524,7 @@ int ipath_make_rc_req(struct ipath_qp *qp, * * This is called from ipath_rc_rcv() and only uses the receive * side QP state. - * Note that RDMA reads and atomics are handled in the - * send side QP state and tasklet. + * Note that RDMA reads are handled in the send side QP state and tasklet. */ static void send_rc_ack(struct ipath_qp *qp) { @@ -588,10 +535,6 @@ static void send_rc_ack(struct ipath_qp *qp) struct ipath_ib_header hdr; struct ipath_other_headers *ohdr; - /* Don't send ACK or NAK if a RDMA read or atomic is pending. */ - if (qp->r_head_ack_queue != qp->s_tail_ack_queue) - goto queue_ack; - /* Construct the header. */ ohdr = &hdr.u.oth; lrh0 = IPATH_LRH_BTH; @@ -605,14 +548,19 @@ static void send_rc_ack(struct ipath_qp *qp) lrh0 = IPATH_LRH_GRH; } /* read pkey_index w/o lock (its atomic) */ - bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index) | - OP(ACKNOWLEDGE) << 24; + bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index); if (qp->r_nak_state) ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) | (qp->r_nak_state << IPATH_AETH_CREDIT_SHIFT)); else ohdr->u.aeth = ipath_compute_aeth(qp); + if (qp->r_ack_state >= OP(COMPARE_SWAP)) { + bth0 |= OP(ATOMIC_ACKNOWLEDGE) << 24; + ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data); + hwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4; + } else + bth0 |= OP(ACKNOWLEDGE) << 24; lrh0 |= qp->remote_ah_attr.sl << 4; hdr.lrh[0] = cpu_to_be16(lrh0); hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); @@ -626,31 +574,31 @@ static void send_rc_ack(struct ipath_qp *qp) * If we can send the ACK, clear the ACK state. */ if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) { + qp->r_ack_state = OP(ACKNOWLEDGE); dev->n_unicast_xmit++; - goto done; - } - - /* - * We are out of PIO buffers at the moment. - * Pass responsibility for sending the ACK to the - * send tasklet so that when a PIO buffer becomes - * available, the ACK is sent ahead of other outgoing - * packets. - */ - dev->n_rc_qacks++; - -queue_ack: - spin_lock_irq(&qp->s_lock); - qp->s_flags |= IPATH_S_ACK_PENDING; - qp->s_nak_state = qp->r_nak_state; - qp->s_ack_psn = qp->r_ack_psn; - spin_unlock_irq(&qp->s_lock); - - /* Call ipath_do_rc_send() in another thread. */ - tasklet_hi_schedule(&qp->s_task); + } else { + /* + * We are out of PIO buffers at the moment. + * Pass responsibility for sending the ACK to the + * send tasklet so that when a PIO buffer becomes + * available, the ACK is sent ahead of other outgoing + * packets. + */ + dev->n_rc_qacks++; + spin_lock_irq(&qp->s_lock); + /* Don't coalesce if a RDMA read or atomic is pending. */ + if (qp->s_ack_state == OP(ACKNOWLEDGE) || + qp->s_ack_state < OP(RDMA_READ_REQUEST)) { + qp->s_ack_state = qp->r_ack_state; + qp->s_nak_state = qp->r_nak_state; + qp->s_ack_psn = qp->r_ack_psn; + qp->r_ack_state = OP(ACKNOWLEDGE); + } + spin_unlock_irq(&qp->s_lock); -done: - return; + /* Call ipath_do_rc_send() in another thread. */ + tasklet_hi_schedule(&qp->s_task); + } } /** @@ -779,7 +727,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) if (wqe->wr.opcode == IB_WR_RDMA_READ) dev->n_rc_resends++; else - dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK; + dev->n_rc_resends += (int)qp->s_psn - (int)psn; reset_psn(qp, psn); tasklet_hi_schedule(&qp->s_task); @@ -827,6 +775,10 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) list_del_init(&qp->timerwait); spin_unlock(&dev->pending_lock); + /* Nothing is pending to ACK/NAK. */ + if (unlikely(qp->s_last == qp->s_tail)) + goto bail; + /* * Note that NAKs implicitly ACK outstanding SEND and RDMA write * requests and implicitly NAK RDMA read and atomic requests issued @@ -854,7 +806,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) */ if ((wqe->wr.opcode == IB_WR_RDMA_READ && (opcode != OP(RDMA_READ_RESPONSE_LAST) || - ipath_cmp24(ack_psn, wqe->lpsn) != 0)) || + ipath_cmp24(ack_psn, wqe->lpsn) != 0)) || ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) && (opcode != OP(ATOMIC_ACKNOWLEDGE) || @@ -872,33 +824,20 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) */ goto bail; } - if (qp->s_num_rd_atomic && - (wqe->wr.opcode == IB_WR_RDMA_READ || - wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || - wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) { - qp->s_num_rd_atomic--; - /* Restart sending task if fence is complete */ - if ((qp->s_flags & IPATH_S_FENCE_PENDING) && - !qp->s_num_rd_atomic) { - qp->s_flags &= ~IPATH_S_FENCE_PENDING; - tasklet_hi_schedule(&qp->s_task); - } else if (qp->s_flags & IPATH_S_RDMAR_PENDING) { - qp->s_flags &= ~IPATH_S_RDMAR_PENDING; - tasklet_hi_schedule(&qp->s_task); - } - } + if (wqe->wr.opcode == IB_WR_RDMA_READ || + wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) + tasklet_hi_schedule(&qp->s_task); /* Post a send completion queue entry if requested. */ - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || (wqe->wr.send_flags & IB_SEND_SIGNALED)) { wc.wr_id = wqe->wr.wr_id; wc.status = IB_WC_SUCCESS; wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.imm_data = 0; wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; - wc.wc_flags = 0; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; wc.sl = qp->remote_ah_attr.sl; @@ -915,19 +854,15 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) if (qp->s_last == qp->s_cur) { if (++qp->s_cur >= qp->s_size) qp->s_cur = 0; - qp->s_last = qp->s_cur; - if (qp->s_last == qp->s_tail) - break; wqe = get_swqe_ptr(qp, qp->s_cur); qp->s_state = OP(SEND_LAST); qp->s_psn = wqe->psn; - } else { - if (++qp->s_last >= qp->s_size) - qp->s_last = 0; - if (qp->s_last == qp->s_tail) - break; - wqe = get_swqe_ptr(qp, qp->s_last); } + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + wqe = get_swqe_ptr(qp, qp->s_last); + if (qp->s_last == qp->s_tail) + break; } switch (aeth >> 29) { @@ -939,18 +874,6 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) list_add_tail(&qp->timerwait, &dev->pending[dev->pending_index]); spin_unlock(&dev->pending_lock); - /* - * If we get a partial ACK for a resent operation, - * we can stop resending the earlier packets and - * continue with the next packet the receiver wants. - */ - if (ipath_cmp24(qp->s_psn, psn) <= 0) { - reset_psn(qp, psn + 1); - tasklet_hi_schedule(&qp->s_task); - } - } else if (ipath_cmp24(qp->s_psn, psn) <= 0) { - qp->s_state = OP(SEND_LAST); - qp->s_psn = psn + 1; } ipath_get_credit(qp, aeth); qp->s_rnr_retry = qp->s_rnr_retry_cnt; @@ -961,23 +884,22 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) case 1: /* RNR NAK */ dev->n_rnr_naks++; - if (qp->s_last == qp->s_tail) - goto bail; if (qp->s_rnr_retry == 0) { + if (qp->s_last == qp->s_tail) + goto bail; + wc.status = IB_WC_RNR_RETRY_EXC_ERR; goto class_b; } if (qp->s_rnr_retry_cnt < 7) qp->s_rnr_retry--; + if (qp->s_last == qp->s_tail) + goto bail; /* The last valid PSN is the previous PSN. */ update_last_psn(qp, psn - 1); - if (wqe->wr.opcode == IB_WR_RDMA_READ) - dev->n_rc_resends++; - else - dev->n_rc_resends += - (qp->s_psn - psn) & IPATH_PSN_MASK; + dev->n_rc_resends += (int)qp->s_psn - (int)psn; reset_psn(qp, psn); @@ -988,20 +910,26 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) goto bail; case 3: /* NAK */ - if (qp->s_last == qp->s_tail) - goto bail; - /* The last valid PSN is the previous PSN. */ - update_last_psn(qp, psn - 1); + /* The last valid PSN seen is the previous request's. */ + if (qp->s_last != qp->s_tail) + update_last_psn(qp, wqe->psn - 1); switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) & IPATH_AETH_CREDIT_MASK) { case 0: /* PSN sequence error */ dev->n_seq_naks++; /* - * Back up to the responder's expected PSN. + * Back up to the responder's expected PSN. XXX * Note that we might get a NAK in the middle of an * RDMA READ response which terminates the RDMA * READ. */ + if (qp->s_last == qp->s_tail) + break; + + if (ipath_cmp24(psn, wqe->psn) < 0) + break; + + /* Retry the request. */ ipath_restart_rc(qp, psn, &wc); break; @@ -1075,7 +1003,6 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, u32 psn, u32 hdrsize, u32 pmtu, int header_in_data) { - struct ipath_swqe *wqe; unsigned long flags; struct ib_wc wc; int diff; @@ -1105,10 +1032,6 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, goto ack_done; } - if (unlikely(qp->s_last == qp->s_tail)) - goto ack_done; - wqe = get_swqe_ptr(qp, qp->s_last); - switch (opcode) { case OP(ACKNOWLEDGE): case OP(ATOMIC_ACKNOWLEDGE): @@ -1119,49 +1042,38 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, aeth = be32_to_cpu(((__be32 *) data)[0]); data += sizeof(__be32); } - if (opcode == OP(ATOMIC_ACKNOWLEDGE)) { - u64 val; - - if (!header_in_data) { - __be32 *p = ohdr->u.at.atomic_ack_eth; - - val = ((u64) be32_to_cpu(p[0]) << 32) | - be32_to_cpu(p[1]); - } else - val = be64_to_cpu(((__be64 *) data)[0]); - *(u64 *) wqe->sg_list[0].vaddr = val; - } + if (opcode == OP(ATOMIC_ACKNOWLEDGE)) + *(u64 *) qp->s_sge.sge.vaddr = *(u64 *) data; if (!do_rc_ack(qp, aeth, psn, opcode) || opcode != OP(RDMA_READ_RESPONSE_FIRST)) goto ack_done; hdrsize += 4; - if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_op_err; /* - * If this is a response to a resent RDMA read, we - * have to be careful to copy the data to the right - * location. + * do_rc_ack() has already checked the PSN so skip + * the sequence check. */ - qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, - wqe, psn, pmtu); - goto read_middle; + goto rdma_read; case OP(RDMA_READ_RESPONSE_MIDDLE): /* no AETH, no ACK */ if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) { dev->n_rdma_seq++; - ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); + if (qp->s_last != qp->s_tail) + ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); goto ack_done; } - if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_op_err; - read_middle: + rdma_read: + if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST))) + goto ack_done; if (unlikely(tlen != (hdrsize + pmtu + 4))) - goto ack_len_err; - if (unlikely(pmtu >= qp->s_rdma_read_len)) - goto ack_len_err; - + goto ack_done; + if (unlikely(pmtu >= qp->s_len)) + goto ack_done; /* We got a response so update the timeout. */ + if (unlikely(qp->s_last == qp->s_tail || + get_swqe_ptr(qp, qp->s_last)->wr.opcode != + IB_WR_RDMA_READ)) + goto ack_done; spin_lock(&dev->pending_lock); if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait)) list_move_tail(&qp->timerwait, @@ -1170,97 +1082,67 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, /* * Update the RDMA receive state but do the copy w/o * holding the locks and blocking interrupts. + * XXX Yet another place that affects relaxed RDMA order + * since we don't want s_sge modified. */ - qp->s_rdma_read_len -= pmtu; + qp->s_len -= pmtu; update_last_psn(qp, psn); spin_unlock_irqrestore(&qp->s_lock, flags); - ipath_copy_sge(&qp->s_rdma_read_sge, data, pmtu); + ipath_copy_sge(&qp->s_sge, data, pmtu); goto bail; - case OP(RDMA_READ_RESPONSE_ONLY): - if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) { - dev->n_rdma_seq++; - ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); - goto ack_done; - } - if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_op_err; - /* Get the number of bytes the message was padded by. */ - pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; - /* - * Check that the data size is >= 0 && <= pmtu. - * Remember to account for the AETH header (4) and - * ICRC (4). - */ - if (unlikely(tlen < (hdrsize + pad + 8))) - goto ack_len_err; - /* - * If this is a response to a resent RDMA read, we - * have to be careful to copy the data to the right - * location. - */ - qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, - wqe, psn, pmtu); - goto read_last; - case OP(RDMA_READ_RESPONSE_LAST): /* ACKs READ req. */ if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) { dev->n_rdma_seq++; - ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); + if (qp->s_last != qp->s_tail) + ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); goto ack_done; } - if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_op_err; - /* Get the number of bytes the message was padded by. */ + /* FALLTHROUGH */ + case OP(RDMA_READ_RESPONSE_ONLY): + if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST))) + goto ack_done; + /* + * Get the number of bytes the message was padded by. + */ pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; /* * Check that the data size is >= 1 && <= pmtu. * Remember to account for the AETH header (4) and * ICRC (4). */ - if (unlikely(tlen <= (hdrsize + pad + 8))) - goto ack_len_err; - read_last: + if (unlikely(tlen <= (hdrsize + pad + 8))) { + /* XXX Need to generate an error CQ entry. */ + goto ack_done; + } tlen -= hdrsize + pad + 8; - if (unlikely(tlen != qp->s_rdma_read_len)) - goto ack_len_err; + if (unlikely(tlen != qp->s_len)) { + /* XXX Need to generate an error CQ entry. */ + goto ack_done; + } if (!header_in_data) aeth = be32_to_cpu(ohdr->u.aeth); else { aeth = be32_to_cpu(((__be32 *) data)[0]); data += sizeof(__be32); } - ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen); - (void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST)); + ipath_copy_sge(&qp->s_sge, data, tlen); + if (do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST))) { + /* + * Change the state so we contimue + * processing new requests and wake up the + * tasklet if there are posted sends. + */ + qp->s_state = OP(SEND_LAST); + if (qp->s_tail != qp->s_head) + tasklet_hi_schedule(&qp->s_task); + } goto ack_done; } ack_done: spin_unlock_irqrestore(&qp->s_lock, flags); - goto bail; - -ack_op_err: - wc.status = IB_WC_LOC_QP_OP_ERR; - goto ack_err; - -ack_len_err: - wc.status = IB_WC_LOC_LEN_ERR; -ack_err: - wc.wr_id = wqe->wr.wr_id; - wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; - wc.vendor_err = 0; - wc.byte_len = 0; - wc.imm_data = 0; - wc.qp = &qp->ibqp; - wc.src_qp = qp->remote_qpn; - wc.wc_flags = 0; - wc.pkey_index = 0; - wc.slid = qp->remote_ah_attr.dlid; - wc.sl = qp->remote_ah_attr.sl; - wc.dlid_path_bits = 0; - wc.port_num = 0; - ipath_sqerror_qp(qp, &wc); bail: return; } @@ -1280,7 +1162,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, * incoming RC packet for the given QP. * Called at interrupt level. * Return 1 if no more processing is needed; otherwise return 0 to - * schedule a response to be sent. + * schedule a response to be sent and the s_lock unlocked. */ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, struct ipath_other_headers *ohdr, @@ -1291,23 +1173,25 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, int diff, int header_in_data) { - struct ipath_ack_entry *e; - u8 i, prev; - int old_req; + struct ib_reth *reth; if (diff > 0) { /* * Packet sequence error. * A NAK will ACK earlier sends and RDMA writes. - * Don't queue the NAK if we already sent one. + * Don't queue the NAK if a RDMA read, atomic, or + * NAK is pending though. */ - if (!qp->r_nak_state) { + if (qp->s_ack_state != OP(ACKNOWLEDGE) || + qp->r_nak_state != 0) + goto done; + if (qp->r_ack_state < OP(COMPARE_SWAP)) { + qp->r_ack_state = OP(SEND_ONLY); qp->r_nak_state = IB_NAK_PSN_ERROR; /* Use the expected PSN. */ qp->r_ack_psn = qp->r_psn; - goto send_ack; } - goto done; + goto send_ack; } /* @@ -1320,46 +1204,8 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, * can coalesce an outstanding duplicate ACK. We have to * send the earliest so that RDMA reads can be restarted at * the requester's expected PSN. - * - * First, find where this duplicate PSN falls within the - * ACKs previously sent. */ - psn &= IPATH_PSN_MASK; - e = NULL; - old_req = 1; - spin_lock_irq(&qp->s_lock); - for (i = qp->r_head_ack_queue; ; i = prev) { - if (i == qp->s_tail_ack_queue) - old_req = 0; - if (i) - prev = i - 1; - else - prev = IPATH_MAX_RDMA_ATOMIC; - if (prev == qp->r_head_ack_queue) { - e = NULL; - break; - } - e = &qp->s_ack_queue[prev]; - if (!e->opcode) { - e = NULL; - break; - } - if (ipath_cmp24(psn, e->psn) >= 0) - break; - } - switch (opcode) { - case OP(RDMA_READ_REQUEST): { - struct ib_reth *reth; - u32 offset; - u32 len; - - /* - * If we didn't find the RDMA read request in the ack queue, - * or the send tasklet is already backed up to send an - * earlier entry, we can ignore this request. - */ - if (!e || e->opcode != OP(RDMA_READ_REQUEST) || old_req) - goto unlock_done; + if (opcode == OP(RDMA_READ_REQUEST)) { /* RETH comes after BTH */ if (!header_in_data) reth = &ohdr->u.rc.reth; @@ -1368,87 +1214,88 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, data += sizeof(*reth); } /* - * Address range must be a subset of the original - * request and start on pmtu boundaries. - * We reuse the old ack_queue slot since the requester - * should not back up and request an earlier PSN for the - * same request. + * If we receive a duplicate RDMA request, it means the + * requester saw a sequence error and needs to restart + * from an earlier point. We can abort the current + * RDMA read send in that case. */ - offset = ((psn - e->psn) & IPATH_PSN_MASK) * - ib_mtu_enum_to_int(qp->path_mtu); - len = be32_to_cpu(reth->length); - if (unlikely(offset + len > e->rdma_sge.sge.sge_length)) - goto unlock_done; - if (len != 0) { + spin_lock_irq(&qp->s_lock); + if (qp->s_ack_state != OP(ACKNOWLEDGE) && + (qp->s_hdrwords || ipath_cmp24(psn, qp->s_ack_psn) >= 0)) { + /* + * We are already sending earlier requested data. + * Don't abort it to send later out of sequence data. + */ + spin_unlock_irq(&qp->s_lock); + goto done; + } + qp->s_rdma_len = be32_to_cpu(reth->length); + if (qp->s_rdma_len != 0) { u32 rkey = be32_to_cpu(reth->rkey); u64 vaddr = be64_to_cpu(reth->vaddr); int ok; - ok = ipath_rkey_ok(qp, &e->rdma_sge, - len, vaddr, rkey, + /* + * Address range must be a subset of the original + * request and start on pmtu boundaries. + */ + ok = ipath_rkey_ok(qp, &qp->s_rdma_sge, + qp->s_rdma_len, vaddr, rkey, IB_ACCESS_REMOTE_READ); - if (unlikely(!ok)) - goto unlock_done; + if (unlikely(!ok)) { + spin_unlock_irq(&qp->s_lock); + goto done; + } } else { - e->rdma_sge.sg_list = NULL; - e->rdma_sge.num_sge = 0; - e->rdma_sge.sge.mr = NULL; - e->rdma_sge.sge.vaddr = NULL; - e->rdma_sge.sge.length = 0; - e->rdma_sge.sge.sge_length = 0; + qp->s_rdma_sge.sg_list = NULL; + qp->s_rdma_sge.num_sge = 0; + qp->s_rdma_sge.sge.mr = NULL; + qp->s_rdma_sge.sge.vaddr = NULL; + qp->s_rdma_sge.sge.length = 0; + qp->s_rdma_sge.sge.sge_length = 0; } - e->psn = psn; - qp->s_ack_state = OP(ACKNOWLEDGE); - qp->s_tail_ack_queue = prev; - break; + qp->s_ack_state = opcode; + qp->s_ack_psn = psn; + spin_unlock_irq(&qp->s_lock); + tasklet_hi_schedule(&qp->s_task); + goto send_ack; } - case OP(COMPARE_SWAP): - case OP(FETCH_ADD): { - /* - * If we didn't find the atomic request in the ack queue - * or the send tasklet is already backed up to send an - * earlier entry, we can ignore this request. - */ - if (!e || e->opcode != (u8) opcode || old_req) - goto unlock_done; - qp->s_ack_state = OP(ACKNOWLEDGE); - qp->s_tail_ack_queue = prev; - break; - } + /* + * A pending RDMA read will ACK anything before it so + * ignore earlier duplicate requests. + */ + if (qp->s_ack_state != OP(ACKNOWLEDGE)) + goto done; - default: - if (old_req) - goto unlock_done; - /* - * Resend the most recent ACK if this request is - * after all the previous RDMA reads and atomics. - */ - if (i == qp->r_head_ack_queue) { - spin_unlock_irq(&qp->s_lock); - qp->r_nak_state = 0; - qp->r_ack_psn = qp->r_psn - 1; - goto send_ack; - } + /* + * If an ACK is pending, don't replace the pending ACK + * with an earlier one since the later one will ACK the earlier. + * Also, if we already have a pending atomic, send it. + */ + if (qp->r_ack_state != OP(ACKNOWLEDGE) && + (ipath_cmp24(psn, qp->r_ack_psn) <= 0 || + qp->r_ack_state >= OP(COMPARE_SWAP))) + goto send_ack; + switch (opcode) { + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): /* - * Resend the RDMA read or atomic op which - * ACKs this duplicate request. + * Check for the PSN of the last atomic operation + * performed and resend the result if found. */ - qp->s_ack_state = OP(ACKNOWLEDGE); - qp->s_tail_ack_queue = i; + if ((psn & IPATH_PSN_MASK) != qp->r_atomic_psn) + goto done; break; } + qp->r_ack_state = opcode; qp->r_nak_state = 0; - spin_unlock_irq(&qp->s_lock); - tasklet_hi_schedule(&qp->s_task); + qp->r_ack_psn = psn; +send_ack: + return 0; -unlock_done: - spin_unlock_irq(&qp->s_lock); done: return 1; - -send_ack: - return 0; } static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err) @@ -1544,7 +1391,15 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, opcode == OP(SEND_LAST_WITH_IMMEDIATE)) break; nack_inv: + /* + * A NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if a RDMA read, atomic, or NAK + * is pending though. + */ + if (qp->r_ack_state >= OP(COMPARE_SWAP)) + goto send_ack; ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR); + qp->r_ack_state = OP(SEND_ONLY); qp->r_nak_state = IB_NAK_INVALID_REQUEST; qp->r_ack_psn = qp->r_psn; goto send_ack; @@ -1586,8 +1441,9 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, * Don't queue the NAK if a RDMA read or atomic * is pending though. */ - if (qp->r_nak_state) - goto done; + if (qp->r_ack_state >= OP(COMPARE_SWAP)) + goto send_ack; + qp->r_ack_state = OP(SEND_ONLY); qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer; qp->r_ack_psn = qp->r_psn; goto send_ack; @@ -1711,19 +1567,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, goto rnr_nak; goto send_last_imm; - case OP(RDMA_READ_REQUEST): { - struct ipath_ack_entry *e; - u32 len; - u8 next; - - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) - goto nack_acc; - next = qp->r_head_ack_queue + 1; - if (next > IPATH_MAX_RDMA_ATOMIC) - next = 0; - if (unlikely(next == qp->s_tail_ack_queue)) - goto nack_inv; - e = &qp->s_ack_queue[qp->r_head_ack_queue]; + case OP(RDMA_READ_REQUEST): /* RETH comes after BTH */ if (!header_in_data) reth = &ohdr->u.rc.reth; @@ -1731,75 +1575,72 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, reth = (struct ib_reth *)data; data += sizeof(*reth); } - len = be32_to_cpu(reth->length); - if (len) { + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_READ))) + goto nack_acc; + spin_lock_irq(&qp->s_lock); + qp->s_rdma_len = be32_to_cpu(reth->length); + if (qp->s_rdma_len != 0) { u32 rkey = be32_to_cpu(reth->rkey); u64 vaddr = be64_to_cpu(reth->vaddr); int ok; /* Check rkey & NAK */ - ok = ipath_rkey_ok(qp, &e->rdma_sge, len, vaddr, - rkey, IB_ACCESS_REMOTE_READ); - if (unlikely(!ok)) + ok = ipath_rkey_ok(qp, &qp->s_rdma_sge, + qp->s_rdma_len, vaddr, rkey, + IB_ACCESS_REMOTE_READ); + if (unlikely(!ok)) { + spin_unlock_irq(&qp->s_lock); goto nack_acc; + } /* * Update the next expected PSN. We add 1 later * below, so only add the remainder here. */ - if (len > pmtu) - qp->r_psn += (len - 1) / pmtu; + if (qp->s_rdma_len > pmtu) + qp->r_psn += (qp->s_rdma_len - 1) / pmtu; } else { - e->rdma_sge.sg_list = NULL; - e->rdma_sge.num_sge = 0; - e->rdma_sge.sge.mr = NULL; - e->rdma_sge.sge.vaddr = NULL; - e->rdma_sge.sge.length = 0; - e->rdma_sge.sge.sge_length = 0; + qp->s_rdma_sge.sg_list = NULL; + qp->s_rdma_sge.num_sge = 0; + qp->s_rdma_sge.sge.mr = NULL; + qp->s_rdma_sge.sge.vaddr = NULL; + qp->s_rdma_sge.sge.length = 0; + qp->s_rdma_sge.sge.sge_length = 0; } - e->opcode = opcode; - e->psn = psn; /* * We need to increment the MSN here instead of when we * finish sending the result since a duplicate request would * increment it more than once. */ qp->r_msn++; + + qp->s_ack_state = opcode; + qp->s_ack_psn = psn; + spin_unlock_irq(&qp->s_lock); + qp->r_psn++; qp->r_state = opcode; qp->r_nak_state = 0; - barrier(); - qp->r_head_ack_queue = next; /* Call ipath_do_rc_send() in another thread. */ tasklet_hi_schedule(&qp->s_task); goto done; - } case OP(COMPARE_SWAP): case OP(FETCH_ADD): { struct ib_atomic_eth *ateth; - struct ipath_ack_entry *e; u64 vaddr; - atomic64_t *maddr; u64 sdata; u32 rkey; - u8 next; - if (unlikely(!(qp->qp_access_flags & - IB_ACCESS_REMOTE_ATOMIC))) - goto nack_acc; - next = qp->r_head_ack_queue + 1; - if (next > IPATH_MAX_RDMA_ATOMIC) - next = 0; - if (unlikely(next == qp->s_tail_ack_queue)) - goto nack_inv; if (!header_in_data) ateth = &ohdr->u.atomic_eth; - else + else { ateth = (struct ib_atomic_eth *)data; - vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) | - be32_to_cpu(ateth->vaddr[1]); + data += sizeof(*ateth); + } + vaddr = be64_to_cpu(ateth->vaddr); if (unlikely(vaddr & (sizeof(u64) - 1))) goto nack_inv; rkey = be32_to_cpu(ateth->rkey); @@ -1808,50 +1649,63 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, sizeof(u64), vaddr, rkey, IB_ACCESS_REMOTE_ATOMIC))) goto nack_acc; + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_ATOMIC))) + goto nack_acc; /* Perform atomic OP and save result. */ - maddr = (atomic64_t *) qp->r_sge.sge.vaddr; sdata = be64_to_cpu(ateth->swap_data); - e = &qp->s_ack_queue[qp->r_head_ack_queue]; - e->atomic_data = (opcode == OP(FETCH_ADD)) ? - (u64) atomic64_add_return(sdata, maddr) - sdata : - (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, - be64_to_cpu(ateth->compare_data), - sdata); - e->opcode = opcode; - e->psn = psn & IPATH_PSN_MASK; + spin_lock_irq(&dev->pending_lock); + qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr; + if (opcode == OP(FETCH_ADD)) + *(u64 *) qp->r_sge.sge.vaddr = + qp->r_atomic_data + sdata; + else if (qp->r_atomic_data == + be64_to_cpu(ateth->compare_data)) + *(u64 *) qp->r_sge.sge.vaddr = sdata; + spin_unlock_irq(&dev->pending_lock); qp->r_msn++; - qp->r_psn++; - qp->r_state = opcode; - qp->r_nak_state = 0; - barrier(); - qp->r_head_ack_queue = next; - - /* Call ipath_do_rc_send() in another thread. */ - tasklet_hi_schedule(&qp->s_task); - - goto done; + qp->r_atomic_psn = psn & IPATH_PSN_MASK; + psn |= 1 << 31; + break; } default: - /* NAK unknown opcodes. */ - goto nack_inv; + /* Drop packet for unknown opcodes. */ + goto done; } qp->r_psn++; qp->r_state = opcode; - qp->r_ack_psn = psn; qp->r_nak_state = 0; /* Send an ACK if requested or required. */ - if (psn & (1 << 31)) + if (psn & (1 << 31)) { + /* + * Coalesce ACKs unless there is a RDMA READ or + * ATOMIC pending. + */ + if (qp->r_ack_state < OP(COMPARE_SWAP)) { + qp->r_ack_state = opcode; + qp->r_ack_psn = psn; + } goto send_ack; + } goto done; nack_acc: - ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR); - qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR; - qp->r_ack_psn = qp->r_psn; - + /* + * A NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if a RDMA read, atomic, or NAK + * is pending though. + */ + if (qp->r_ack_state < OP(COMPARE_SWAP)) { + ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR); + qp->r_ack_state = OP(RDMA_WRITE_ONLY); + qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR; + qp->r_ack_psn = qp->r_psn; + } send_ack: - send_rc_ack(qp); + /* Send ACK right away unless the send tasklet has a pending ACK. */ + if (qp->s_ack_state == OP(ACKNOWLEDGE)) + send_rc_ack(qp); done: return; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_registers.h b/trunk/drivers/infiniband/hw/ipath/ipath_registers.h index c182bcd62098..dffc76016d3c 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_registers.h @@ -126,18 +126,9 @@ #define INFINIPATH_E_RESET 0x0004000000000000ULL #define INFINIPATH_E_HARDWARE 0x0008000000000000ULL -/* - * this is used to print "common" packet errors only when the - * __IPATH_ERRPKTDBG bit is set in ipath_debug. - */ -#define INFINIPATH_E_PKTERRS ( INFINIPATH_E_SPKTLEN \ - | INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_RVCRC \ - | INFINIPATH_E_RICRC | INFINIPATH_E_RSHORTPKTLEN \ - | INFINIPATH_E_REBP ) - /* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */ /* TXEMEMPARITYERR bit 0: PIObuf, 1: PIOpbc, 2: launchfifo - * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2: expTID, 3: eagerTID + * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2: eagerTID, 3: expTID * bit 4: flag buffer, 5: datainfo, 6: header info */ #define INFINIPATH_HWE_TXEMEMPARITYERR_MASK 0xFULL #define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40 @@ -152,8 +143,8 @@ /* rxe mem parity errors (shift by INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) */ #define INFINIPATH_HWE_RXEMEMPARITYERR_RCVBUF 0x01ULL #define INFINIPATH_HWE_RXEMEMPARITYERR_LOOKUPQ 0x02ULL -#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID 0x04ULL -#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x08ULL +#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x04ULL +#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID 0x08ULL #define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF 0x10ULL #define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL #define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO 0x40ULL @@ -308,6 +299,13 @@ #define INFINIPATH_XGXS_RX_POL_SHIFT 19 #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL +#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */ + +/* TID entries (memory), HT-only */ +#define INFINIPATH_RT_VALID 0x8000000000000000ULL +#define INFINIPATH_RT_ADDR_SHIFT 0 +#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF +#define INFINIPATH_RT_BUFSIZE_SHIFT 48 /* * IPATH_PIO_MAXIBHDR is the max IB header size allowed for in our diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c b/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c index d9c2a9b15d86..e86cb171872e 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -202,7 +202,6 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) wq->tail = tail; ret = 1; - qp->r_wrid_valid = 1; if (handler) { u32 n; @@ -230,6 +229,7 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) } } spin_unlock_irqrestore(&rq->lock, flags); + qp->r_wrid_valid = 1; bail: return ret; @@ -255,7 +255,6 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) unsigned long flags; struct ib_wc wc; u64 sdata; - atomic64_t *maddr; qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn); if (!qp) { @@ -266,8 +265,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) again: spin_lock_irqsave(&sqp->s_lock, flags); - if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK) || - qp->s_rnr_timeout) { + if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK)) { spin_unlock_irqrestore(&sqp->s_lock, flags); goto done; } @@ -312,7 +310,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) sqp->s_rnr_retry--; dev->n_rnr_naks++; sqp->s_rnr_timeout = - ib_ipath_rnr_table[qp->r_min_rnr_timer]; + ib_ipath_rnr_table[sqp->r_min_rnr_timer]; ipath_insert_rnr_queue(sqp); goto done; } @@ -345,22 +343,20 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) wc.sl = sqp->remote_ah_attr.sl; wc.dlid_path_bits = 0; wc.port_num = 0; - spin_lock_irqsave(&sqp->s_lock, flags); ipath_sqerror_qp(sqp, &wc); - spin_unlock_irqrestore(&sqp->s_lock, flags); goto done; } break; case IB_WR_RDMA_READ: - if (unlikely(!(qp->qp_access_flags & - IB_ACCESS_REMOTE_READ))) - goto acc_err; if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length, wqe->wr.wr.rdma.remote_addr, wqe->wr.wr.rdma.rkey, IB_ACCESS_REMOTE_READ))) goto acc_err; + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_READ))) + goto acc_err; qp->r_sge.sge = wqe->sg_list[0]; qp->r_sge.sg_list = wqe->sg_list + 1; qp->r_sge.num_sge = wqe->wr.num_sge; @@ -368,22 +364,22 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) case IB_WR_ATOMIC_CMP_AND_SWP: case IB_WR_ATOMIC_FETCH_AND_ADD: - if (unlikely(!(qp->qp_access_flags & - IB_ACCESS_REMOTE_ATOMIC))) - goto acc_err; if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64), - wqe->wr.wr.atomic.remote_addr, - wqe->wr.wr.atomic.rkey, + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, IB_ACCESS_REMOTE_ATOMIC))) goto acc_err; /* Perform atomic OP and save result. */ - maddr = (atomic64_t *) qp->r_sge.sge.vaddr; - sdata = wqe->wr.wr.atomic.compare_add; - *(u64 *) sqp->s_sge.sge.vaddr = - (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? - (u64) atomic64_add_return(sdata, maddr) - sdata : - (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, - sdata, wqe->wr.wr.atomic.swap); + sdata = wqe->wr.wr.atomic.swap; + spin_lock_irqsave(&dev->pending_lock, flags); + qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr; + if (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) + *(u64 *) qp->r_sge.sge.vaddr = + qp->r_atomic_data + sdata; + else if (qp->r_atomic_data == wqe->wr.wr.atomic.compare_add) + *(u64 *) qp->r_sge.sge.vaddr = sdata; + spin_unlock_irqrestore(&dev->pending_lock, flags); + *(u64 *) sqp->s_sge.sge.vaddr = qp->r_atomic_data; goto send_comp; default: @@ -444,7 +440,7 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) send_comp: sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &sqp->s_flags) || (wqe->wr.send_flags & IB_SEND_SIGNALED)) { wc.wr_id = wqe->wr.wr_id; wc.status = IB_WC_SUCCESS; @@ -506,7 +502,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) * We clear the tasklet flag now since we are committing to return * from the tasklet function. */ - clear_bit(IPATH_S_BUSY, &qp->s_busy); + clear_bit(IPATH_S_BUSY, &qp->s_flags); tasklet_unlock(&qp->s_task); want_buffer(dev->dd); dev->n_piowait++; @@ -545,9 +541,6 @@ int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr) wr->sg_list[0].addr & (sizeof(u64) - 1))) { ret = -EINVAL; goto bail; - } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) { - ret = -EINVAL; - goto bail; } /* IB spec says that num_sge == 0 is OK. */ if (wr->num_sge > qp->s_max_sge) { @@ -654,7 +647,7 @@ void ipath_do_ruc_send(unsigned long data) u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); struct ipath_other_headers *ohdr; - if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy)) + if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags)) goto bail; if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) { @@ -690,15 +683,19 @@ void ipath_do_ruc_send(unsigned long data) */ spin_lock_irqsave(&qp->s_lock, flags); - if (!((qp->ibqp.qp_type == IB_QPT_RC) ? - ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) : - ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) { + /* Sending responses has higher priority over sending requests. */ + if (qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE && + (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0) + bth2 = qp->s_ack_psn++ & IPATH_PSN_MASK; + else if (!((qp->ibqp.qp_type == IB_QPT_RC) ? + ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) : + ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) { /* * Clear the busy bit before unlocking to avoid races with * adding new work queue items and then failing to process * them. */ - clear_bit(IPATH_S_BUSY, &qp->s_busy); + clear_bit(IPATH_S_BUSY, &qp->s_flags); spin_unlock_irqrestore(&qp->s_lock, flags); goto bail; } @@ -731,7 +728,7 @@ void ipath_do_ruc_send(unsigned long data) goto again; clear: - clear_bit(IPATH_S_BUSY, &qp->s_busy); + clear_bit(IPATH_S_BUSY, &qp->s_flags); bail: return; } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_stats.c b/trunk/drivers/infiniband/hw/ipath/ipath_stats.c index d8b5e4cefe25..30a825928fcf 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_stats.c @@ -31,6 +31,8 @@ * SOFTWARE. */ +#include + #include "ipath_kernel.h" struct infinipath_stats ipath_stats; @@ -205,7 +207,7 @@ void ipath_get_faststats(unsigned long opaque) * don't access the chip while running diags, or memory diags can * fail */ - if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_INITTED) || + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT) || ipath_diag_inuse) /* but re-arm the timer, for diags case; won't hurt other */ goto done; @@ -235,13 +237,11 @@ void ipath_get_faststats(unsigned long opaque) if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) && time_after(jiffies, dd->ipath_unmasktime)) { char ebuf[256]; - int iserr; - iserr = ipath_decode_err(ebuf, sizeof ebuf, + ipath_decode_err(ebuf, sizeof ebuf, (dd->ipath_maskederrs & ~dd-> ipath_ignorederrs)); if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) & - ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL | - INFINIPATH_E_PKTERRS )) + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) ipath_dev_err(dd, "Re-enabling masked errors " "(%s)\n", ebuf); else { @@ -252,12 +252,8 @@ void ipath_get_faststats(unsigned long opaque) * them. So only complain about these at debug * level. */ - if (iserr) - ipath_dbg("Re-enabling queue full errors (%s)\n", - ebuf); - else - ipath_cdbg(ERRPKT, "Re-enabling packet" - " problem interrupt (%s)\n", ebuf); + ipath_dbg("Disabling frequent queue full errors " + "(%s)\n", ebuf); } dd->ipath_maskederrs = dd->ipath_ignorederrs; ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c b/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c index 4dc398d5e011..ffa6318ad0cc 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -32,6 +32,7 @@ */ #include +#include #include "ipath_kernel.h" #include "ipath_common.h" diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_uc.c b/trunk/drivers/infiniband/hw/ipath/ipath_uc.c index 1c2b03c2ef5e..325d6634ff53 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_uc.c @@ -42,7 +42,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe, { if (++qp->s_last == qp->s_size) qp->s_last = 0; - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || (wqe->wr.send_flags & IB_SEND_SIGNALED)) { wc->wr_id = wqe->wr.wr_id; wc->status = IB_WC_SUCCESS; @@ -344,13 +344,13 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, send_first: if (qp->r_reuse_sge) { qp->r_reuse_sge = 0; - qp->r_sge = qp->s_rdma_read_sge; + qp->r_sge = qp->s_rdma_sge; } else if (!ipath_get_rwqe(qp, 0)) { dev->n_pkt_drops++; goto done; } /* Save the WQE so we can reuse it in case of an error. */ - qp->s_rdma_read_sge = qp->r_sge; + qp->s_rdma_sge = qp->r_sge; qp->r_rcv_len = 0; if (opcode == OP(SEND_ONLY)) goto send_last; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_ud.c b/trunk/drivers/infiniband/hw/ipath/ipath_ud.c index a518f7c8fa83..9a3e54664ee4 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_ud.c @@ -308,11 +308,6 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) goto bail; } - if (wr->wr.ud.ah->pd != qp->ibqp.pd) { - ret = -EPERM; - goto bail; - } - /* IB spec says that num_sge == 0 is OK. */ if (wr->num_sge > qp->s_max_sge) { ret = -EINVAL; @@ -472,7 +467,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) done: /* Queue the completion status entry. */ - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || (wr->send_flags & IB_SEND_SIGNALED)) { wc.wr_id = wr->wr_id; wc.status = IB_WC_SUCCESS; @@ -652,7 +647,6 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); ipath_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh)); - qp->r_wrid_valid = 0; wc.wr_id = qp->r_wr_id; wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c index 18c6df2052c2..2aaacdb7e52a 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -438,10 +438,6 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, struct ipath_mcast *mcast; struct ipath_mcast_qp *p; - if (lnh != IPATH_LRH_GRH) { - dev->n_pkt_drops++; - goto bail; - } mcast = ipath_mcast_find(&hdr->u.l.grh.dgid); if (mcast == NULL) { dev->n_pkt_drops++; @@ -449,7 +445,8 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, } dev->n_multicast_rcv++; list_for_each_entry_rcu(p, &mcast->qp_list, list) - ipath_qp_rcv(dev, hdr, 1, data, tlen, p->qp); + ipath_qp_rcv(dev, hdr, lnh == IPATH_LRH_GRH, data, + tlen, p->qp); /* * Notify ipath_multicast_detach() if it is waiting for us * to finish. @@ -776,6 +773,7 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, /* +1 is for the qword padding of pbc */ plen = hdrwords + ((len + 3) >> 2) + 1; if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { + ipath_dbg("packet len 0x%x too long, failing\n", plen); ret = -EINVAL; goto bail; } @@ -982,14 +980,14 @@ static int ipath_query_device(struct ib_device *ibdev, props->max_cqe = ib_ipath_max_cqes; props->max_mr = dev->lk_table.max; props->max_pd = ib_ipath_max_pds; - props->max_qp_rd_atom = IPATH_MAX_RDMA_ATOMIC; - props->max_qp_init_rd_atom = 255; + props->max_qp_rd_atom = 1; + props->max_qp_init_rd_atom = 1; /* props->max_res_rd_atom */ props->max_srq = ib_ipath_max_srqs; props->max_srq_wr = ib_ipath_max_srq_wrs; props->max_srq_sge = ib_ipath_max_srq_sges; /* props->local_ca_ack_delay */ - props->atomic_cap = IB_ATOMIC_GLOB; + props->atomic_cap = IB_ATOMIC_HCA; props->max_pkeys = ipath_get_npkeys(dev->dd); props->max_mcast_grp = ib_ipath_max_mcast_grps; props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached; @@ -1559,6 +1557,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd) dev->node_type = RDMA_NODE_IB_CA; dev->phys_port_cnt = 1; dev->dma_device = &dd->pcidev->dev; + dev->class_dev.dev = dev->dma_device; dev->query_device = ipath_query_device; dev->modify_device = ipath_modify_device; dev->query_port = ipath_query_port; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h index 7c4929f1cb5b..c0c8d5b24a7d 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -40,12 +40,9 @@ #include #include #include -#include #include "ipath_layer.h" -#define IPATH_MAX_RDMA_ATOMIC 4 - #define QPN_MAX (1 << 24) #define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE) @@ -92,7 +89,7 @@ struct ib_reth { } __attribute__ ((packed)); struct ib_atomic_eth { - __be32 vaddr[2]; /* unaligned so access as 2 32-bit words */ + __be64 vaddr; __be32 rkey; __be64 swap_data; __be64 compare_data; @@ -111,7 +108,7 @@ struct ipath_other_headers { } rc; struct { __be32 aeth; - __be32 atomic_ack_eth[2]; + __be64 atomic_ack_eth; } at; __be32 imm_data; __be32 aeth; @@ -189,7 +186,7 @@ struct ipath_mmap_info { struct ipath_cq_wc { u32 head; /* index of next entry to fill */ u32 tail; /* index of next ib_poll_cq() entry */ - struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ + struct ib_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ }; /* @@ -314,19 +311,6 @@ struct ipath_sge_state { u8 num_sge; }; -/* - * This structure holds the information that the send tasklet needs - * to send a RDMA read response or atomic operation. - */ -struct ipath_ack_entry { - u8 opcode; - u32 psn; - union { - struct ipath_sge_state rdma_sge; - u64 atomic_data; - }; -}; - /* * Variables prefixed with s_ are for the requester (sender). * Variables prefixed with r_ are for the responder (receiver). @@ -349,24 +333,24 @@ struct ipath_qp { struct ipath_mmap_info *ip; struct ipath_sge_state *s_cur_sge; struct ipath_sge_state s_sge; /* current send request data */ - struct ipath_ack_entry s_ack_queue[IPATH_MAX_RDMA_ATOMIC + 1]; - struct ipath_sge_state s_ack_rdma_sge; - struct ipath_sge_state s_rdma_read_sge; + /* current RDMA read send data */ + struct ipath_sge_state s_rdma_sge; struct ipath_sge_state r_sge; /* current receive data */ spinlock_t s_lock; - unsigned long s_busy; + unsigned long s_flags; u32 s_hdrwords; /* size of s_hdr in 32 bit words */ u32 s_cur_size; /* size of send packet in bytes */ u32 s_len; /* total length of s_sge */ - u32 s_rdma_read_len; /* total length of s_rdma_read_sge */ + u32 s_rdma_len; /* total length of s_rdma_sge */ u32 s_next_psn; /* PSN for next request */ u32 s_last_psn; /* last response PSN processed */ u32 s_psn; /* current packet sequence number */ - u32 s_ack_rdma_psn; /* PSN for sending RDMA read responses */ - u32 s_ack_psn; /* PSN for acking sends and RDMA writes */ + u32 s_ack_psn; /* PSN for RDMA_READ */ u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */ u32 r_ack_psn; /* PSN for next ACK or atomic ACK */ u64 r_wr_id; /* ID for current receive WQE */ + u64 r_atomic_data; /* data for last atomic op */ + u32 r_atomic_psn; /* PSN of last atomic op */ u32 r_len; /* total length of r_sge */ u32 r_rcv_len; /* receive data len processed */ u32 r_psn; /* expected rcv packet sequence number */ @@ -376,13 +360,12 @@ struct ipath_qp { u8 s_ack_state; /* opcode of packet to ACK */ u8 s_nak_state; /* non-zero if NAK is pending */ u8 r_state; /* opcode of last packet received */ + u8 r_ack_state; /* opcode of packet to ACK */ u8 r_nak_state; /* non-zero if NAK is pending */ u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */ u8 r_reuse_sge; /* for UC receive errors */ u8 r_sge_inx; /* current index into sg_list */ u8 r_wrid_valid; /* r_wrid set but CQ entry not yet made */ - u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */ - u8 r_head_ack_queue; /* index into s_ack_queue[] */ u8 qp_access_flags; u8 s_max_sge; /* size of s_wq->sg_list */ u8 s_retry_cnt; /* number of times to retry */ @@ -391,10 +374,6 @@ struct ipath_qp { u8 s_rnr_retry; /* requester RNR retry counter */ u8 s_wait_credit; /* limit number of unacked packets sent */ u8 s_pkey_index; /* PKEY index to use */ - u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */ - u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */ - u8 s_tail_ack_queue; /* index into s_ack_queue[] */ - u8 s_flags; u8 timeout; /* Timeout for this QP */ enum ib_mtu path_mtu; u32 remote_qpn; @@ -411,16 +390,11 @@ struct ipath_qp { struct ipath_sge r_sg_list[0]; /* verified SGEs */ }; -/* Bit definition for s_busy. */ -#define IPATH_S_BUSY 0 - /* * Bit definitions for s_flags. */ -#define IPATH_S_SIGNAL_REQ_WR 0x01 -#define IPATH_S_FENCE_PENDING 0x02 -#define IPATH_S_RDMAR_PENDING 0x04 -#define IPATH_S_ACK_PENDING 0x08 +#define IPATH_S_BUSY 0 +#define IPATH_S_SIGNAL_REQ_WR 1 #define IPATH_PSN_CREDIT 2048 @@ -732,6 +706,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); int ipath_destroy_srq(struct ib_srq *ibsrq); +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); + int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, @@ -781,6 +757,9 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, void ipath_do_ruc_send(unsigned long data); +u32 ipath_make_rc_ack(struct ipath_qp *qp, struct ipath_other_headers *ohdr, + u32 pmtu); + int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, u32 pmtu, u32 *bth0p, u32 *bth2p); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_main.c b/trunk/drivers/infiniband/hw/mthca/mthca_main.c index 773145e29947..0d9b7d06bbc2 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_main.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_main.c @@ -1013,14 +1013,14 @@ static struct { u64 latest_fw; u32 flags; } mthca_hca_table[] = { - [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0), + [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 4, 0), .flags = 0 }, - [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), + [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 600), .flags = MTHCA_FLAG_PCIE }, - [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0), + [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 400), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE }, - [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), + [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 1, 0), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE | MTHCA_FLAG_SINAI_OPT } @@ -1135,7 +1135,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) goto err_cmd; if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { - mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n", + mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n", (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, (int) (mdev->fw_ver & 0xffff), (int) (mthca_hca_table[hca_type].latest_fw >> 32), diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_memfree.h b/trunk/drivers/infiniband/hw/mthca/mthca_memfree.h index a1ab06847b75..594144145f45 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/trunk/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -38,6 +38,7 @@ #define MTHCA_MEMFREE_H #include +#include #include #define MTHCA_ICM_CHUNK_LEN \ diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_mr.c b/trunk/drivers/infiniband/hw/mthca/mthca_mr.c index aa6c70a6a36f..ee561c569d5f 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_mr.c @@ -297,8 +297,7 @@ static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, int mthca_write_mtt_size(struct mthca_dev *dev) { - if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy || - !(dev->mthca_flags & MTHCA_FLAG_FMR)) + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) /* * Be friendly to WRITE_MTT command * and leave two empty slots for the @@ -356,8 +355,7 @@ int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, int size = mthca_write_mtt_size(dev); int chunk; - if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy || - !(dev->mthca_flags & MTHCA_FLAG_FMR)) + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len); while (list_len > 0) { diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_provider.c b/trunk/drivers/infiniband/hw/mthca/mthca_provider.c index 47e6fd46d9c2..0725ad7ad9bf 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1293,6 +1293,7 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.node_type = RDMA_NODE_IB_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; dev->ib_dev.dma_device = &dev->pdev->dev; + dev->ib_dev.class_dev.dev = &dev->pdev->dev; dev->ib_dev.query_device = mthca_query_device; dev->ib_dev.query_port = mthca_query_port; dev->ib_dev.modify_device = mthca_modify_device; diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_qp.c b/trunk/drivers/infiniband/hw/mthca/mthca_qp.c index 8fe6fee7a97a..1c6b63aca268 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1419,10 +1419,11 @@ void mthca_free_qp(struct mthca_dev *dev, * unref the mem-free tables and free the QPN in our table. */ if (!qp->ibqp.uobject) { - mthca_cq_clean(dev, recv_cq, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); - if (send_cq != recv_cq) - mthca_cq_clean(dev, send_cq, qp->qpn, NULL); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_free_memfree(dev, qp); mthca_free_wqe_buf(dev, qp); diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h index d8f6bb4f53fc..fd558267d1cb 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 0c4e59b906cd..2b242a4823f8 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -228,6 +228,7 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even struct net_device *dev = cm_id->context; struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_cm_rx *p; + unsigned long flags; unsigned psn; int ret; @@ -256,9 +257,9 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even cm_id->context = p; p->jiffies = jiffies; - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); list_add(&p->list, &priv->cm.passive_ids); - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); queue_delayed_work(ipoib_workqueue, &priv->cm.stale_task, IPOIB_CM_RX_DELAY); return 0; @@ -276,6 +277,7 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, { struct ipoib_cm_rx *p; struct ipoib_dev_priv *priv; + unsigned long flags; int ret; switch (event->event) { @@ -288,14 +290,14 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, case IB_CM_REJ_RECEIVED: p = cm_id->context; priv = netdev_priv(p->dev); - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); if (list_empty(&p->list)) ret = 0; /* Connection is going away already. */ else { list_del_init(&p->list); ret = -ECONNRESET; } - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); if (ret) { ib_destroy_qp(p->qp); kfree(p); @@ -349,8 +351,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) u64 mapping[IPOIB_CM_RX_SG]; int frags; - ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n", - wr_id, wc->status); + ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); if (unlikely(wr_id >= ipoib_recvq_size)) { ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n", @@ -406,7 +408,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb); skb->protocol = ((struct ipoib_header *) skb->data)->proto; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; @@ -502,8 +504,8 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx struct ipoib_tx_buf *tx_req; unsigned long flags; - ipoib_dbg_data(priv, "cm send completion: id %d, status: %d\n", - wr_id, wc->status); + ipoib_dbg_data(priv, "cm send completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); if (unlikely(wr_id >= ipoib_sendq_size)) { ipoib_warn(priv, "cm send completion event with wrid %d (> %d)\n", @@ -610,22 +612,23 @@ void ipoib_cm_dev_stop(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_cm_rx *p; + unsigned long flags; if (!IPOIB_CM_SUPPORTED(dev->dev_addr)) return; ib_destroy_cm_id(priv->cm.id); - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); while (!list_empty(&priv->cm.passive_ids)) { p = list_entry(priv->cm.passive_ids.next, typeof(*p), list); list_del_init(&p->list); - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); ib_destroy_cm_id(p->id); ib_destroy_qp(p->qp); kfree(p); - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); } - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); cancel_delayed_work(&priv->cm.stale_task); } @@ -639,6 +642,7 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even struct ib_qp_attr qp_attr; int qp_attr_mask, ret; struct sk_buff *skb; + unsigned long flags; p->mtu = be32_to_cpu(data->mtu); @@ -676,12 +680,12 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even skb_queue_head_init(&skqueue); - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); set_bit(IPOIB_FLAG_OPER_UP, &p->flags); if (p->neigh) while ((skb = __skb_dequeue(&p->neigh->queue))) __skb_queue_tail(&skqueue, skb); - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); while ((skb = __skb_dequeue(&skqueue))) { skb->dev = p->dev; @@ -891,6 +895,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, struct ipoib_dev_priv *priv = netdev_priv(tx->dev); struct net_device *dev = priv->dev; struct ipoib_neigh *neigh; + unsigned long flags; int ret; switch (event->event) { @@ -909,7 +914,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, case IB_CM_REJ_RECEIVED: case IB_CM_TIMEWAIT_EXIT: ipoib_dbg(priv, "CM error %d.\n", event->event); - spin_lock_irq(&priv->tx_lock); + spin_lock_irqsave(&priv->tx_lock, flags); spin_lock(&priv->lock); neigh = tx->neigh; @@ -929,7 +934,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, } spin_unlock(&priv->lock); - spin_unlock_irq(&priv->tx_lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); break; default: break; @@ -1018,20 +1023,21 @@ static void ipoib_cm_tx_reap(struct work_struct *work) struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, cm.reap_task); struct ipoib_cm_tx *p; + unsigned long flags; - spin_lock_irq(&priv->tx_lock); + spin_lock_irqsave(&priv->tx_lock, flags); spin_lock(&priv->lock); while (!list_empty(&priv->cm.reap_list)) { p = list_entry(priv->cm.reap_list.next, typeof(*p), list); list_del(&p->list); spin_unlock(&priv->lock); - spin_unlock_irq(&priv->tx_lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); ipoib_cm_tx_destroy(p); - spin_lock_irq(&priv->tx_lock); + spin_lock_irqsave(&priv->tx_lock, flags); spin_lock(&priv->lock); } spin_unlock(&priv->lock); - spin_unlock_irq(&priv->tx_lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); } static void ipoib_cm_skb_reap(struct work_struct *work) @@ -1040,14 +1046,15 @@ static void ipoib_cm_skb_reap(struct work_struct *work) cm.skb_task); struct net_device *dev = priv->dev; struct sk_buff *skb; + unsigned long flags; unsigned mtu = priv->mcast_mtu; - spin_lock_irq(&priv->tx_lock); + spin_lock_irqsave(&priv->tx_lock, flags); spin_lock(&priv->lock); while ((skb = skb_dequeue(&priv->cm.skb_queue))) { spin_unlock(&priv->lock); - spin_unlock_irq(&priv->tx_lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); if (skb->protocol == htons(ETH_P_IP)) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -1055,11 +1062,11 @@ static void ipoib_cm_skb_reap(struct work_struct *work) icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); #endif dev_kfree_skb_any(skb); - spin_lock_irq(&priv->tx_lock); + spin_lock_irqsave(&priv->tx_lock, flags); spin_lock(&priv->lock); } spin_unlock(&priv->lock); - spin_unlock_irq(&priv->tx_lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); } void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, @@ -1081,8 +1088,9 @@ static void ipoib_cm_stale_task(struct work_struct *work) struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, cm.stale_task.work); struct ipoib_cm_rx *p; + unsigned long flags; - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); while (!list_empty(&priv->cm.passive_ids)) { /* List if sorted by LRU, start from tail, * stop when we see a recently used entry */ @@ -1090,13 +1098,13 @@ static void ipoib_cm_stale_task(struct work_struct *work) if (time_before_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT)) break; list_del_init(&p->list); - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); ib_destroy_cm_id(p->id); ib_destroy_qp(p->qp); kfree(p); - spin_lock_irq(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); } - spin_unlock_irq(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 1bdb9101911a..ba0ee5cf2ad7 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -172,8 +172,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) struct sk_buff *skb; u64 addr; - ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n", - wr_id, wc->status); + ipoib_dbg_data(priv, "recv completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); if (unlikely(wr_id >= ipoib_recvq_size)) { ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n", @@ -216,7 +216,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) if (wc->slid != priv->local_lid || wc->src_qp != priv->qp->qp_num) { skb->protocol = ((struct ipoib_header *) skb->data)->proto; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; @@ -245,8 +245,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) struct ipoib_tx_buf *tx_req; unsigned long flags; - ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", - wr_id, wc->status); + ipoib_dbg_data(priv, "send completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); if (unlikely(wr_id >= ipoib_sendq_size)) { ipoib_warn(priv, "send completion event with wrid %d (> %d)\n", diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c index b4c380c5a3ba..f2a40ae8e7d0 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -395,10 +395,14 @@ static void path_rec_completion(int status, skb_queue_head_init(&skqueue); if (!status) { - struct ib_ah_attr av; - - if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av)) - ah = ipoib_create_ah(dev, priv->pd, &av); + struct ib_ah_attr av = { + .dlid = be16_to_cpu(pathrec->dlid), + .sl = pathrec->sl, + .port_num = priv->port, + .static_rate = pathrec->rate + }; + + ah = ipoib_create_ah(dev, priv->pd, &av); } spin_lock_irqsave(&priv->lock, flags); diff --git a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c index 3651072f6c1f..278fcbccc2d9 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c @@ -201,7 +201,7 @@ static int iser_post_receive_control(struct iscsi_conn *conn) * what's common for both schemes is that the connection is not started */ if (conn->c_stage != ISCSI_CONN_STARTED) - rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN; + rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; else /* FIXME till user space sets conn->max_recv_dlength correctly */ rx_data_size = 128; diff --git a/trunk/drivers/input/Makefile b/trunk/drivers/input/Makefile index b4cd10653c4f..da575deb3c7a 100644 --- a/trunk/drivers/input/Makefile +++ b/trunk/drivers/input/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o obj-$(CONFIG_INPUT_TSDEV) += tsdev.o +obj-$(CONFIG_INPUT_POWER) += power.o obj-$(CONFIG_INPUT_EVBUG) += evbug.o obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ diff --git a/trunk/drivers/input/evbug.c b/trunk/drivers/input/evbug.c index c21f2f127234..5a9653c3128a 100644 --- a/trunk/drivers/input/evbug.c +++ b/trunk/drivers/input/evbug.c @@ -38,43 +38,31 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input driver event debug module"); MODULE_LICENSE("GPL"); +static char evbug_name[] = "evbug"; + static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); } -static int evbug_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; - int error; - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; + if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; handle->dev = dev; handle->handler = handler; - handle->name = "evbug"; - - error = input_register_handle(handle); - if (error) - goto err_free_handle; + handle->name = evbug_name; - error = input_open_device(handle); - if (error) - goto err_unregister_handle; + input_open_device(handle); printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); - return 0; - - err_unregister_handle: - input_unregister_handle(handle); - err_free_handle: - kfree(handle); - return error; + return handle; } static void evbug_disconnect(struct input_handle *handle) @@ -82,7 +70,7 @@ static void evbug_disconnect(struct input_handle *handle) printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); input_close_device(handle); - input_unregister_handle(handle); + kfree(handle); } diff --git a/trunk/drivers/input/evdev.c b/trunk/drivers/input/evdev.c index 1f6fcec0c6fc..6439f378f6cc 100644 --- a/trunk/drivers/input/evdev.c +++ b/trunk/drivers/input/evdev.c @@ -29,11 +29,11 @@ struct evdev { char name[16]; struct input_handle handle; wait_queue_head_t wait; - struct evdev_client *grab; - struct list_head client_list; + struct evdev_list *grab; + struct list_head list; }; -struct evdev_client { +struct evdev_list { struct input_event buffer[EVDEV_BUFFER_SIZE]; int head; int tail; @@ -47,28 +47,28 @@ static struct evdev *evdev_table[EVDEV_MINORS]; static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct evdev *evdev = handle->private; - struct evdev_client *client; + struct evdev_list *list; if (evdev->grab) { - client = evdev->grab; + list = evdev->grab; - do_gettimeofday(&client->buffer[client->head].time); - client->buffer[client->head].type = type; - client->buffer[client->head].code = code; - client->buffer[client->head].value = value; - client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); + do_gettimeofday(&list->buffer[list->head].time); + list->buffer[list->head].type = type; + list->buffer[list->head].code = code; + list->buffer[list->head].value = value; + list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); - kill_fasync(&client->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); } else - list_for_each_entry(client, &evdev->client_list, node) { + list_for_each_entry(list, &evdev->list, node) { - do_gettimeofday(&client->buffer[client->head].time); - client->buffer[client->head].type = type; - client->buffer[client->head].code = code; - client->buffer[client->head].value = value; - client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); + do_gettimeofday(&list->buffer[list->head].time); + list->buffer[list->head].type = type; + list->buffer[list->head].code = code; + list->buffer[list->head].value = value; + list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); - kill_fasync(&client->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&evdev->wait); @@ -76,23 +76,22 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned static int evdev_fasync(int fd, struct file *file, int on) { - struct evdev_client *client = file->private_data; int retval; + struct evdev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &client->fasync); + retval = fasync_helper(fd, file, on, &list->fasync); return retval < 0 ? retval : 0; } static int evdev_flush(struct file *file, fl_owner_t id) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; - if (!evdev->exist) + if (!list->evdev->exist) return -ENODEV; - return input_flush_device(&evdev->handle, file); + return input_flush_device(&list->evdev->handle, file); } static void evdev_free(struct evdev *evdev) @@ -101,62 +100,48 @@ static void evdev_free(struct evdev *evdev) kfree(evdev); } -static int evdev_release(struct inode *inode, struct file *file) +static int evdev_release(struct inode * inode, struct file * file) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; - if (evdev->grab == client) { - input_release_device(&evdev->handle); - evdev->grab = NULL; + if (list->evdev->grab == list) { + input_release_device(&list->evdev->handle); + list->evdev->grab = NULL; } evdev_fasync(-1, file, 0); - list_del(&client->node); - kfree(client); + list_del(&list->node); - if (!--evdev->open) { - if (evdev->exist) - input_close_device(&evdev->handle); + if (!--list->evdev->open) { + if (list->evdev->exist) + input_close_device(&list->evdev->handle); else - evdev_free(evdev); + evdev_free(list->evdev); } + kfree(list); return 0; } -static int evdev_open(struct inode *inode, struct file *file) +static int evdev_open(struct inode * inode, struct file * file) { - struct evdev_client *client; - struct evdev *evdev; + struct evdev_list *list; int i = iminor(inode) - EVDEV_MINOR_BASE; - int error; - if (i >= EVDEV_MINORS) + if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) return -ENODEV; - evdev = evdev_table[i]; - - if (!evdev || !evdev->exist) - return -ENODEV; - - client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); - if (!client) + if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL))) return -ENOMEM; - client->evdev = evdev; - list_add_tail(&client->node, &evdev->client_list); + list->evdev = evdev_table[i]; + list_add_tail(&list->node, &evdev_table[i]->list); + file->private_data = list; - if (!evdev->open++ && evdev->exist) { - error = input_open_device(&evdev->handle); - if (error) { - list_del(&client->node); - kfree(client); - return error; - } - } + if (!list->evdev->open++) + if (list->evdev->exist) + input_open_device(&list->evdev->handle); - file->private_data = client; return 0; } @@ -258,55 +243,54 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev #endif /* CONFIG_COMPAT */ -static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; struct input_event event; int retval = 0; - if (!evdev->exist) + if (!list->evdev->exist) return -ENODEV; while (retval < count) { if (evdev_event_from_user(buffer + retval, &event)) return -EFAULT; - input_inject_event(&evdev->handle, event.type, event.code, event.value); + input_inject_event(&list->evdev->handle, event.type, event.code, event.value); retval += evdev_event_size(); } return retval; } -static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; int retval; if (count < evdev_event_size()) return -EINVAL; - if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) + if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(evdev->wait, - client->head != client->tail || !evdev->exist); + retval = wait_event_interruptible(list->evdev->wait, + list->head != list->tail || (!list->evdev->exist)); + if (retval) return retval; - if (!evdev->exist) + if (!list->evdev->exist) return -ENODEV; - while (client->head != client->tail && retval + evdev_event_size() <= count) { + while (list->head != list->tail && retval + evdev_event_size() <= count) { - struct input_event *event = (struct input_event *) client->buffer + client->tail; + struct input_event *event = (struct input_event *) list->buffer + list->tail; if (evdev_event_to_user(buffer + retval, event)) return -EFAULT; - client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1); + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); retval += evdev_event_size(); } @@ -316,12 +300,11 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, /* No kernel lock - fine */ static unsigned int evdev_poll(struct file *file, poll_table *wait) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; - poll_wait(file, &evdev->wait, wait); - return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | - (evdev->exist ? 0 : (POLLHUP | POLLERR)); + poll_wait(file, &list->evdev->wait, wait); + return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | + (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); } #ifdef CONFIG_COMPAT @@ -404,8 +387,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) static long evdev_ioctl_handler(struct file *file, unsigned int cmd, void __user *p, int compat_mode) { - struct evdev_client *client = file->private_data; - struct evdev *evdev = client->evdev; + struct evdev_list *list = file->private_data; + struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; struct ff_effect effect; @@ -451,21 +434,32 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, case EVIOCGKEYCODE: if (get_user(t, ip)) return -EFAULT; - - error = dev->getkeycode(dev, t, &v); - if (error) - return error; - - if (put_user(v, ip + 1)) + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) + return -EINVAL; + if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT; - return 0; case EVIOCSKEYCODE: - if (get_user(t, ip) || get_user(v, ip + 1)) + if (get_user(t, ip)) return -EFAULT; + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) + return -EINVAL; + if (get_user(v, ip + 1)) + return -EFAULT; + if (v < 0 || v > KEY_MAX) + return -EINVAL; + if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) + return -EINVAL; + + u = SET_INPUT_KEYCODE(dev, t, v); + clear_bit(u, dev->keybit); + set_bit(v, dev->keybit); + for (i = 0; i < dev->keycodemax; i++) + if (INPUT_KEYCODE(dev, i) == u) + set_bit(u, dev->keybit); - return dev->setkeycode(dev, t, v); + return 0; case EVIOCSFF: if (copy_from_user(&effect, p, sizeof(effect))) @@ -493,10 +487,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, return -EBUSY; if (input_grab_device(&evdev->handle)) return -EBUSY; - evdev->grab = client; + evdev->grab = list; return 0; } else { - if (evdev->grab != client) + if (evdev->grab != list) return -EINVAL; input_release_device(&evdev->handle); evdev->grab = NULL; @@ -622,26 +616,23 @@ static const struct file_operations evdev_fops = { .flush = evdev_flush }; -static int evdev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct evdev *evdev; struct class_device *cdev; - dev_t devt; int minor; - int error; for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); if (minor == EVDEV_MINORS) { printk(KERN_ERR "evdev: no more free evdev devices\n"); - return -ENFILE; + return NULL; } - evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); - if (!evdev) - return -ENOMEM; + if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) + return NULL; - INIT_LIST_HEAD(&evdev->client_list); + INIT_LIST_HEAD(&evdev->list); init_waitqueue_head(&evdev->wait); evdev->exist = 1; @@ -654,45 +645,23 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, evdev_table[minor] = evdev; - devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), - - cdev = class_device_create(&input_class, &dev->cdev, devt, - dev->cdev.dev, evdev->name); - if (IS_ERR(cdev)) { - error = PTR_ERR(cdev); - goto err_free_evdev; - } + cdev = class_device_create(&input_class, &dev->cdev, + MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), + dev->cdev.dev, evdev->name); /* temporary symlink to keep userspace happy */ - error = sysfs_create_link(&input_class.subsys.kobj, - &cdev->kobj, evdev->name); - if (error) - goto err_cdev_destroy; - - error = input_register_handle(&evdev->handle); - if (error) - goto err_remove_link; + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + evdev->name); - return 0; - - err_remove_link: - sysfs_remove_link(&input_class.subsys.kobj, evdev->name); - err_cdev_destroy: - class_device_destroy(&input_class, devt); - err_free_evdev: - kfree(evdev); - evdev_table[minor] = NULL; - return error; + return &evdev->handle; } static void evdev_disconnect(struct input_handle *handle) { struct evdev *evdev = handle->private; - struct evdev_client *client; - - input_unregister_handle(handle); + struct evdev_list *list; - sysfs_remove_link(&input_class.subsys.kobj, evdev->name); + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); evdev->exist = 0; @@ -701,8 +670,8 @@ static void evdev_disconnect(struct input_handle *handle) input_flush_device(handle, NULL); input_close_device(handle); wake_up_interruptible(&evdev->wait); - list_for_each_entry(client, &evdev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); + list_for_each_entry(list, &evdev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); } else evdev_free(evdev); } diff --git a/trunk/drivers/input/gameport/gameport.c b/trunk/drivers/input/gameport/gameport.c index bd686a2a517d..a00fe470a829 100644 --- a/trunk/drivers/input/gameport/gameport.c +++ b/trunk/drivers/input/gameport/gameport.c @@ -190,14 +190,16 @@ static void gameport_run_poll_handler(unsigned long d) * Basic gameport -> driver core mappings */ -static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) +static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv) { int error; + down_write(&gameport_bus.subsys.rwsem); + gameport->dev.driver = &drv->driver; if (drv->connect(gameport, drv)) { gameport->dev.driver = NULL; - return -ENODEV; + goto out; } error = device_bind_driver(&gameport->dev); @@ -209,21 +211,31 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive drv->description, error); drv->disconnect(gameport); gameport->dev.driver = NULL; - return error; + goto out; } - return 0; + out: + up_write(&gameport_bus.subsys.rwsem); +} + +static void gameport_release_driver(struct gameport *gameport) +{ + down_write(&gameport_bus.subsys.rwsem); + device_release_driver(&gameport->dev); + up_write(&gameport_bus.subsys.rwsem); } static void gameport_find_driver(struct gameport *gameport) { int error; + down_write(&gameport_bus.subsys.rwsem); error = device_attach(&gameport->dev); if (error < 0) printk(KERN_WARNING "gameport: device_attach() failed for %s (%s), error: %d\n", gameport->phys, gameport->name, error); + up_write(&gameport_bus.subsys.rwsem); } @@ -471,12 +483,13 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut { struct gameport *gameport = to_gameport_port(dev); struct device_driver *drv; - int error; + int retval; - error = mutex_lock_interruptible(&gameport_mutex); - if (error) - return error; + retval = mutex_lock_interruptible(&gameport_mutex); + if (retval) + return retval; + retval = count; if (!strncmp(buf, "none", count)) { gameport_disconnect_port(gameport); } else if (!strncmp(buf, "reconnect", count)) { @@ -486,15 +499,15 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut gameport_find_driver(gameport); } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) { gameport_disconnect_port(gameport); - error = gameport_bind_driver(gameport, to_gameport_driver(drv)); + gameport_bind_driver(gameport, to_gameport_driver(drv)); put_driver(drv); } else { - error = -EINVAL; + retval = -EINVAL; } mutex_unlock(&gameport_mutex); - return error ? error : count; + return retval; } static struct device_attribute gameport_device_attrs[] = { @@ -642,7 +655,7 @@ static void gameport_disconnect_port(struct gameport *gameport) do { parent = s->parent; - device_release_driver(&s->dev); + gameport_release_driver(s); gameport_destroy_port(s); } while ((s = parent) != gameport); } @@ -650,7 +663,7 @@ static void gameport_disconnect_port(struct gameport *gameport) /* * Ok, no children left, now disconnect this port */ - device_release_driver(&gameport->dev); + gameport_release_driver(gameport); } void gameport_rescan(struct gameport *gameport) diff --git a/trunk/drivers/input/input.c b/trunk/drivers/input/input.c index 915e9ab7cab0..a9a706f8fff9 100644 --- a/trunk/drivers/input/input.c +++ b/trunk/drivers/input/input.c @@ -299,87 +299,12 @@ void input_close_device(struct input_handle *handle) } EXPORT_SYMBOL(input_close_device); -static int input_fetch_keycode(struct input_dev *dev, int scancode) +static void input_link_handle(struct input_handle *handle) { - switch (dev->keycodesize) { - case 1: - return ((u8 *)dev->keycode)[scancode]; - - case 2: - return ((u16 *)dev->keycode)[scancode]; - - default: - return ((u32 *)dev->keycode)[scancode]; - } -} - -static int input_default_getkeycode(struct input_dev *dev, - int scancode, int *keycode) -{ - if (!dev->keycodesize) - return -EINVAL; - - if (scancode < 0 || scancode >= dev->keycodemax) - return -EINVAL; - - *keycode = input_fetch_keycode(dev, scancode); - - return 0; -} - -static int input_default_setkeycode(struct input_dev *dev, - int scancode, int keycode) -{ - int old_keycode; - int i; - - if (scancode < 0 || scancode >= dev->keycodemax) - return -EINVAL; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - if (!dev->keycodesize) - return -EINVAL; - - if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) - return -EINVAL; - - switch (dev->keycodesize) { - case 1: { - u8 *k = (u8 *)dev->keycode; - old_keycode = k[scancode]; - k[scancode] = keycode; - break; - } - case 2: { - u16 *k = (u16 *)dev->keycode; - old_keycode = k[scancode]; - k[scancode] = keycode; - break; - } - default: { - u32 *k = (u32 *)dev->keycode; - old_keycode = k[scancode]; - k[scancode] = keycode; - break; - } - } - - clear_bit(old_keycode, dev->keybit); - set_bit(keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == old_keycode) { - set_bit(old_keycode, dev->keybit); - break; /* Setting the bit twice is useless, so break */ - } - } - - return 0; + list_add_tail(&handle->d_node, &handle->dev->h_list); + list_add_tail(&handle->h_node, &handle->handler->h_list); } - #define MATCH_BIT(bit, max) \ for (i = 0; i < NBITS(max); i++) \ if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ @@ -426,29 +351,6 @@ static const struct input_device_id *input_match_device(const struct input_devic return NULL; } -static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) -{ - const struct input_device_id *id; - int error; - - if (handler->blacklist && input_match_device(handler->blacklist, dev)) - return -ENODEV; - - id = input_match_device(handler->id_table, dev); - if (!id) - return -ENODEV; - - error = handler->connect(handler, dev, id); - if (error && error != -ENODEV) - printk(KERN_ERR - "input: failed to attach handler %s to device %s, " - "error: %d\n", - handler->name, kobject_name(&dev->cdev.kobj), error); - - return error; -} - - #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -537,7 +439,6 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); - seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); seq_printf(seq, "H: Handlers="); list_for_each_entry(handle, &dev->h_list, d_node) @@ -852,13 +753,6 @@ static struct attribute_group input_dev_caps_attr_group = { .attrs = input_dev_caps_attrs, }; -static struct attribute_group *input_dev_attr_groups[] = { - &input_dev_attr_group, - &input_dev_id_attr_group, - &input_dev_caps_attr_group, - NULL -}; - static void input_dev_release(struct class_device *class_dev) { struct input_dev *dev = to_input_dev(class_dev); @@ -1012,7 +906,6 @@ struct input_dev *input_allocate_device(void) dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); if (dev) { dev->cdev.class = &input_class; - dev->cdev.groups = input_dev_attr_groups; class_device_initialize(&dev->cdev); mutex_init(&dev->mutex); INIT_LIST_HEAD(&dev->h_list); @@ -1041,71 +934,23 @@ EXPORT_SYMBOL(input_allocate_device); */ void input_free_device(struct input_dev *dev) { - if (dev) - input_put_device(dev); -} -EXPORT_SYMBOL(input_free_device); + if (dev) { -/** - * input_set_capability - mark device as capable of a certain event - * @dev: device that is capable of emitting or accepting event - * @type: type of the event (EV_KEY, EV_REL, etc...) - * @code: event code - * - * In addition to setting up corresponding bit in appropriate capability - * bitmap the function also adjusts dev->evbit. - */ -void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) -{ - switch (type) { - case EV_KEY: - __set_bit(code, dev->keybit); - break; - - case EV_REL: - __set_bit(code, dev->relbit); - break; - - case EV_ABS: - __set_bit(code, dev->absbit); - break; - - case EV_MSC: - __set_bit(code, dev->mscbit); - break; - - case EV_SW: - __set_bit(code, dev->swbit); - break; - - case EV_LED: - __set_bit(code, dev->ledbit); - break; - - case EV_SND: - __set_bit(code, dev->sndbit); - break; - - case EV_FF: - __set_bit(code, dev->ffbit); - break; - - default: - printk(KERN_ERR - "input_set_capability: unknown type %u (code %u)\n", - type, code); - dump_stack(); - return; - } + mutex_lock(&dev->mutex); + dev->name = dev->phys = dev->uniq = NULL; + mutex_unlock(&dev->mutex); - __set_bit(type, dev->evbit); + input_put_device(dev); + } } -EXPORT_SYMBOL(input_set_capability); +EXPORT_SYMBOL(input_free_device); int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); + struct input_handle *handle; struct input_handler *handler; + const struct input_device_id *id; const char *path; int error; @@ -1124,41 +969,55 @@ int input_register_device(struct input_dev *dev) dev->rep[REP_PERIOD] = 33; } - if (!dev->getkeycode) - dev->getkeycode = input_default_getkeycode; - - if (!dev->setkeycode) - dev->setkeycode = input_default_setkeycode; - list_add_tail(&dev->node, &input_dev_list); snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); - if (!dev->cdev.dev) - dev->cdev.dev = dev->dev.parent; - error = class_device_add(&dev->cdev); if (error) return error; + error = sysfs_create_group(&dev->cdev.kobj, &input_dev_attr_group); + if (error) + goto fail1; + + error = sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group); + if (error) + goto fail2; + + error = sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); + if (error) + goto fail3; + path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); printk(KERN_INFO "input: %s as %s\n", dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); kfree(path); list_for_each_entry(handler, &input_handler_list, node) - input_attach_handler(dev, handler); + if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) + if ((id = input_match_device(handler->id_table, dev))) + if ((handle = handler->connect(handler, dev, id))) { + input_link_handle(handle); + if (handler->start) + handler->start(handle); + } input_wakeup_procfs_readers(); return 0; + + fail3: sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); + fail2: sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); + fail1: class_device_del(&dev->cdev); + return error; } EXPORT_SYMBOL(input_register_device); void input_unregister_device(struct input_dev *dev) { - struct input_handle *handle, *next; + struct list_head *node, *next; int code; for (code = 0; code <= KEY_MAX; code++) @@ -1168,12 +1027,19 @@ void input_unregister_device(struct input_dev *dev) del_timer_sync(&dev->timer); - list_for_each_entry_safe(handle, next, &dev->h_list, d_node) + list_for_each_safe(node, next, &dev->h_list) { + struct input_handle * handle = to_handle(node); + list_del_init(&handle->d_node); + list_del_init(&handle->h_node); handle->handler->disconnect(handle); - WARN_ON(!list_empty(&dev->h_list)); + } list_del_init(&dev->node); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); + class_device_unregister(&dev->cdev); input_wakeup_procfs_readers(); @@ -1183,6 +1049,8 @@ EXPORT_SYMBOL(input_unregister_device); int input_register_handler(struct input_handler *handler) { struct input_dev *dev; + struct input_handle *handle; + const struct input_device_id *id; INIT_LIST_HEAD(&handler->h_list); @@ -1196,7 +1064,13 @@ int input_register_handler(struct input_handler *handler) list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) - input_attach_handler(dev, handler); + if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) + if ((id = input_match_device(handler->id_table, dev))) + if ((handle = handler->connect(handler, dev, id))) { + input_link_handle(handle); + if (handler->start) + handler->start(handle); + } input_wakeup_procfs_readers(); return 0; @@ -1205,11 +1079,14 @@ EXPORT_SYMBOL(input_register_handler); void input_unregister_handler(struct input_handler *handler) { - struct input_handle *handle, *next; + struct list_head *node, *next; - list_for_each_entry_safe(handle, next, &handler->h_list, h_node) + list_for_each_safe(node, next, &handler->h_list) { + struct input_handle * handle = to_handle_h(node); + list_del_init(&handle->h_node); + list_del_init(&handle->d_node); handler->disconnect(handle); - WARN_ON(!list_empty(&handler->h_list)); + } list_del_init(&handler->node); @@ -1220,27 +1097,6 @@ void input_unregister_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_unregister_handler); -int input_register_handle(struct input_handle *handle) -{ - struct input_handler *handler = handle->handler; - - list_add_tail(&handle->d_node, &handle->dev->h_list); - list_add_tail(&handle->h_node, &handler->h_list); - - if (handler->start) - handler->start(handle); - - return 0; -} -EXPORT_SYMBOL(input_register_handle); - -void input_unregister_handle(struct input_handle *handle) -{ - list_del_init(&handle->h_node); - list_del_init(&handle->d_node); -} -EXPORT_SYMBOL(input_unregister_handle); - static int input_open_file(struct inode *inode, struct file *file) { struct input_handler *handler = input_table[iminor(inode) >> 5]; diff --git a/trunk/drivers/input/joydev.c b/trunk/drivers/input/joydev.c index 9bcc5425049b..9f3529ad3fda 100644 --- a/trunk/drivers/input/joydev.c +++ b/trunk/drivers/input/joydev.c @@ -43,7 +43,7 @@ struct joydev { char name[16]; struct input_handle handle; wait_queue_head_t wait; - struct list_head client_list; + struct list_head list; struct js_corr corr[ABS_MAX + 1]; struct JS_DATA_SAVE_TYPE glue; int nabs; @@ -55,7 +55,7 @@ struct joydev { __s16 abs[ABS_MAX + 1]; }; -struct joydev_client { +struct joydev_list { struct js_event buffer[JOYDEV_BUFFER_SIZE]; int head; int tail; @@ -87,7 +87,7 @@ static int joydev_correct(int value, struct js_corr *corr) static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct joydev *joydev = handle->private; - struct joydev_client *client; + struct joydev_list *list; struct js_event event; switch (type) { @@ -115,15 +115,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne event.time = jiffies_to_msecs(jiffies); - list_for_each_entry(client, &joydev->client_list, node) { + list_for_each_entry(list, &joydev->list, node) { - memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); + memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); - if (client->startup == joydev->nabs + joydev->nkey) - if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) - client->startup = 0; + if (list->startup == joydev->nabs + joydev->nkey) + if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) + list->startup = 0; - kill_fasync(&client->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&joydev->wait); @@ -132,9 +132,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne static int joydev_fasync(int fd, struct file *file, int on) { int retval; - struct joydev_client *client = file->private_data; + struct joydev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &client->fasync); + retval = fasync_helper(fd, file, on, &list->fasync); return retval < 0 ? retval : 0; } @@ -145,73 +145,60 @@ static void joydev_free(struct joydev *joydev) kfree(joydev); } -static int joydev_release(struct inode *inode, struct file *file) +static int joydev_release(struct inode * inode, struct file * file) { - struct joydev_client *client = file->private_data; - struct joydev *joydev = client->joydev; + struct joydev_list *list = file->private_data; joydev_fasync(-1, file, 0); - list_del(&client->node); - kfree(client); + list_del(&list->node); - if (!--joydev->open) { - if (joydev->exist) - input_close_device(&joydev->handle); + if (!--list->joydev->open) { + if (list->joydev->exist) + input_close_device(&list->joydev->handle); else - joydev_free(joydev); + joydev_free(list->joydev); } + kfree(list); return 0; } static int joydev_open(struct inode *inode, struct file *file) { - struct joydev_client *client; - struct joydev *joydev; + struct joydev_list *list; int i = iminor(inode) - JOYDEV_MINOR_BASE; - int error; - - if (i >= JOYDEV_MINORS) - return -ENODEV; - joydev = joydev_table[i]; - if (!joydev || !joydev->exist) + if (i >= JOYDEV_MINORS || !joydev_table[i]) return -ENODEV; - client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); - if (!client) + if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL))) return -ENOMEM; - client->joydev = joydev; - list_add_tail(&client->node, &joydev->client_list); + list->joydev = joydev_table[i]; + list_add_tail(&list->node, &joydev_table[i]->list); + file->private_data = list; - if (!joydev->open++ && joydev->exist) { - error = input_open_device(&joydev->handle); - if (error) { - list_del(&client->node); - kfree(client); - return error; - } - } + if (!list->joydev->open++) + if (list->joydev->exist) + input_open_device(&list->joydev->handle); - file->private_data = client; return 0; } -static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { return -EINVAL; } static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct joydev_client *client = file->private_data; - struct joydev *joydev = client->joydev; + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; struct input_dev *input = joydev->handle.dev; int retval = 0; - if (!joydev->exist) + if (!list->joydev->exist) return -ENODEV; if (count < sizeof(struct js_event)) @@ -230,55 +217,56 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) return -EFAULT; - client->startup = 0; - client->tail = client->head; + list->startup = 0; + list->tail = list->head; return sizeof(struct JS_DATA_TYPE); } - if (client->startup == joydev->nabs + joydev->nkey && - client->head == client->tail && (file->f_flags & O_NONBLOCK)) + if (list->startup == joydev->nabs + joydev->nkey && + list->head == list->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(joydev->wait, - !joydev->exist || - client->startup < joydev->nabs + joydev->nkey || - client->head != client->tail); + retval = wait_event_interruptible(list->joydev->wait, + !list->joydev->exist || + list->startup < joydev->nabs + joydev->nkey || + list->head != list->tail); + if (retval) return retval; - if (!joydev->exist) + if (!list->joydev->exist) return -ENODEV; - while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { + while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { struct js_event event; event.time = jiffies_to_msecs(jiffies); - if (client->startup < joydev->nkey) { + if (list->startup < joydev->nkey) { event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; - event.number = client->startup; + event.number = list->startup; event.value = !!test_bit(joydev->keypam[event.number], input->key); } else { event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.number = client->startup - joydev->nkey; + event.number = list->startup - joydev->nkey; event.value = joydev->abs[event.number]; } if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) return -EFAULT; - client->startup++; + list->startup++; retval += sizeof(struct js_event); } - while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { + while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { - if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event))) + if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) return -EFAULT; - client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); + list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); retval += sizeof(struct js_event); } @@ -288,12 +276,11 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo /* No kernel lock - fine */ static unsigned int joydev_poll(struct file *file, poll_table *wait) { - struct joydev_client *client = file->private_data; - struct joydev *joydev = client->joydev; + struct joydev_list *list = file->private_data; - poll_wait(file, &joydev->wait, wait); - return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? - (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR)); + poll_wait(file, &list->joydev->wait, wait); + return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? + (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); } static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) @@ -387,8 +374,8 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u #ifdef CONFIG_COMPAT static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct joydev_client *client = file->private_data; - struct joydev *joydev = client->joydev; + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; void __user *argp = (void __user *)arg; s32 tmp32; struct JS_DATA_SAVE_TYPE_32 ds32; @@ -441,8 +428,8 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct joydev_client *client = file->private_data; - struct joydev *joydev = client->joydev; + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; void __user *argp = (void __user *)arg; if (!joydev->exist) @@ -478,26 +465,23 @@ static const struct file_operations joydev_fops = { .fasync = joydev_fasync, }; -static int joydev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct joydev *joydev; struct class_device *cdev; - dev_t devt; int i, j, t, minor; - int error; for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); if (minor == JOYDEV_MINORS) { printk(KERN_ERR "joydev: no more free joydev devices\n"); - return -ENFILE; + return NULL; } - joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); - if (!joydev) - return -ENOMEM; + if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) + return NULL; - INIT_LIST_HEAD(&joydev->client_list); + INIT_LIST_HEAD(&joydev->list); init_waitqueue_head(&joydev->wait); joydev->minor = minor; @@ -550,54 +534,31 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, joydev_table[minor] = joydev; - devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), - - cdev = class_device_create(&input_class, &dev->cdev, devt, - dev->cdev.dev, joydev->name); - if (IS_ERR(cdev)) { - error = PTR_ERR(cdev); - goto err_free_joydev; - } + cdev = class_device_create(&input_class, &dev->cdev, + MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + dev->cdev.dev, joydev->name); /* temporary symlink to keep userspace happy */ - error = sysfs_create_link(&input_class.subsys.kobj, - &cdev->kobj, joydev->name); - if (error) - goto err_cdev_destroy; - - error = input_register_handle(&joydev->handle); - if (error) - goto err_remove_link; - - return 0; + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + joydev->name); - err_remove_link: - sysfs_remove_link(&input_class.subsys.kobj, joydev->name); - err_cdev_destroy: - class_device_destroy(&input_class, devt); - err_free_joydev: - joydev_table[minor] = NULL; - kfree(joydev); - return error; + return &joydev->handle; } - static void joydev_disconnect(struct input_handle *handle) { struct joydev *joydev = handle->private; - struct joydev_client *client; - - input_unregister_handle(handle); + struct joydev_list *list; - sysfs_remove_link(&input_class.subsys.kobj, joydev->name); + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); joydev->exist = 0; if (joydev->open) { input_close_device(handle); wake_up_interruptible(&joydev->wait); - list_for_each_entry(client, &joydev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); + list_for_each_entry(list, &joydev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); } else joydev_free(joydev); } diff --git a/trunk/drivers/input/joystick/a3d.c b/trunk/drivers/input/joystick/a3d.c index ff701ab10d74..b11a4bbc84c4 100644 --- a/trunk/drivers/input/joystick/a3d.c +++ b/trunk/drivers/input/joystick/a3d.c @@ -241,7 +241,7 @@ static void a3d_adc_close(struct gameport *gameport) static int a3d_open(struct input_dev *dev) { - struct a3d *a3d = input_get_drvdata(dev); + struct a3d *a3d = dev->private; gameport_start_polling(a3d->gameport); return 0; @@ -253,7 +253,7 @@ static int a3d_open(struct input_dev *dev) static void a3d_close(struct input_dev *dev) { - struct a3d *a3d = input_get_drvdata(dev); + struct a3d *a3d = dev->private; gameport_stop_polling(a3d->gameport); } @@ -314,12 +314,11 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; input_dev->id.product = a3d->mode; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; + input_dev->cdev.dev = &gameport->dev; + input_dev->private = a3d; input_dev->open = a3d_open; input_dev->close = a3d_close; - input_set_drvdata(input_dev, a3d); - if (a3d->mode == A3D_MODE_PXL) { int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER }; diff --git a/trunk/drivers/input/joystick/adi.c b/trunk/drivers/input/joystick/adi.c index 28140c4a110d..6279ced8a35b 100644 --- a/trunk/drivers/input/joystick/adi.c +++ b/trunk/drivers/input/joystick/adi.c @@ -290,7 +290,7 @@ static void adi_poll(struct gameport *gameport) static int adi_open(struct input_dev *dev) { - struct adi_port *port = input_get_drvdata(dev); + struct adi_port *port = dev->private; gameport_start_polling(port->gameport); return 0; @@ -302,7 +302,7 @@ static int adi_open(struct input_dev *dev) static void adi_close(struct input_dev *dev) { - struct adi_port *port = input_get_drvdata(dev); + struct adi_port *port = dev->private; gameport_stop_polling(port->gameport); } @@ -424,9 +424,8 @@ static int adi_init_input(struct adi *adi, struct adi_port *port, int half) input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; input_dev->id.product = adi->id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &port->gameport->dev; - - input_set_drvdata(input_dev, port); + input_dev->cdev.dev = &port->gameport->dev; + input_dev->private = port; input_dev->open = adi_open; input_dev->close = adi_close; diff --git a/trunk/drivers/input/joystick/analog.c b/trunk/drivers/input/joystick/analog.c index 1c1afb5d4684..51f1e4bfff3e 100644 --- a/trunk/drivers/input/joystick/analog.c +++ b/trunk/drivers/input/joystick/analog.c @@ -343,7 +343,7 @@ static void analog_poll(struct gameport *gameport) static int analog_open(struct input_dev *dev) { - struct analog_port *port = input_get_drvdata(dev); + struct analog_port *port = dev->private; gameport_start_polling(port->gameport); return 0; @@ -355,7 +355,7 @@ static int analog_open(struct input_dev *dev) static void analog_close(struct input_dev *dev) { - struct analog_port *port = input_get_drvdata(dev); + struct analog_port *port = dev->private; gameport_stop_polling(port->gameport); } @@ -449,13 +449,10 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG; input_dev->id.product = analog->mask >> 4; input_dev->id.version = 0x0100; - input_dev->dev.parent = &port->gameport->dev; - - input_set_drvdata(input_dev, port); input_dev->open = analog_open; input_dev->close = analog_close; - + input_dev->private = port; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = j = 0; i < 4; i++) diff --git a/trunk/drivers/input/joystick/cobra.c b/trunk/drivers/input/joystick/cobra.c index d3352a849b85..034ec39c251d 100644 --- a/trunk/drivers/input/joystick/cobra.c +++ b/trunk/drivers/input/joystick/cobra.c @@ -142,7 +142,7 @@ static void cobra_poll(struct gameport *gameport) static int cobra_open(struct input_dev *dev) { - struct cobra *cobra = input_get_drvdata(dev); + struct cobra *cobra = dev->private; gameport_start_polling(cobra->gameport); return 0; @@ -150,7 +150,7 @@ static int cobra_open(struct input_dev *dev) static void cobra_close(struct input_dev *dev) { - struct cobra *cobra = input_get_drvdata(dev); + struct cobra *cobra = dev->private; gameport_stop_polling(cobra->gameport); } @@ -211,9 +211,8 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; input_dev->id.product = 0x0008; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, cobra); + input_dev->cdev.dev = &gameport->dev; + input_dev->private = cobra; input_dev->open = cobra_open; input_dev->close = cobra_close; diff --git a/trunk/drivers/input/joystick/db9.c b/trunk/drivers/input/joystick/db9.c index c27593bf9978..b41bd2eb37dd 100644 --- a/trunk/drivers/input/joystick/db9.c +++ b/trunk/drivers/input/joystick/db9.c @@ -518,7 +518,7 @@ static void db9_timer(unsigned long private) static int db9_open(struct input_dev *dev) { - struct db9 *db9 = input_get_drvdata(dev); + struct db9 *db9 = dev->private; struct parport *port = db9->pd->port; int err; @@ -542,7 +542,7 @@ static int db9_open(struct input_dev *dev) static void db9_close(struct input_dev *dev) { - struct db9 *db9 = input_get_drvdata(dev); + struct db9 *db9 = dev->private; struct parport *port = db9->pd->port; mutex_lock(&db9->mutex); @@ -625,8 +625,7 @@ static struct db9 __init *db9_probe(int parport, int mode) input_dev->id.vendor = 0x0002; input_dev->id.product = mode; input_dev->id.version = 0x0100; - - input_set_drvdata(input_dev, db9); + input_dev->private = db9; input_dev->open = db9_open; input_dev->close = db9_close; diff --git a/trunk/drivers/input/joystick/gamecon.c b/trunk/drivers/input/joystick/gamecon.c index c71b58fe225d..711e4b3e9e61 100644 --- a/trunk/drivers/input/joystick/gamecon.c +++ b/trunk/drivers/input/joystick/gamecon.c @@ -591,7 +591,7 @@ static void gc_timer(unsigned long private) static int gc_open(struct input_dev *dev) { - struct gc *gc = input_get_drvdata(dev); + struct gc *gc = dev->private; int err; err = mutex_lock_interruptible(&gc->mutex); @@ -610,7 +610,7 @@ static int gc_open(struct input_dev *dev) static void gc_close(struct input_dev *dev) { - struct gc *gc = input_get_drvdata(dev); + struct gc *gc = dev->private; mutex_lock(&gc->mutex); if (!--gc->used) { @@ -646,8 +646,7 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) input_dev->id.vendor = 0x0001; input_dev->id.product = pad_type; input_dev->id.version = 0x0100; - - input_set_drvdata(input_dev, gc); + input_dev->private = gc; input_dev->open = gc_open; input_dev->close = gc_close; diff --git a/trunk/drivers/input/joystick/gf2k.c b/trunk/drivers/input/joystick/gf2k.c index d514aebf7554..bacbab5d1b6f 100644 --- a/trunk/drivers/input/joystick/gf2k.c +++ b/trunk/drivers/input/joystick/gf2k.c @@ -220,7 +220,7 @@ static void gf2k_poll(struct gameport *gameport) static int gf2k_open(struct input_dev *dev) { - struct gf2k *gf2k = input_get_drvdata(dev); + struct gf2k *gf2k = dev->private; gameport_start_polling(gf2k->gameport); return 0; @@ -228,7 +228,7 @@ static int gf2k_open(struct input_dev *dev) static void gf2k_close(struct input_dev *dev) { - struct gf2k *gf2k = input_get_drvdata(dev); + struct gf2k *gf2k = dev->private; gameport_stop_polling(gf2k->gameport); } @@ -308,13 +308,11 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; input_dev->id.product = gf2k->id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, gf2k); + input_dev->cdev.dev = &gameport->dev; + input_dev->private = gf2k; input_dev->open = gf2k_open; input_dev->close = gf2k_close; - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < gf2k_axes[gf2k->id]; i++) diff --git a/trunk/drivers/input/joystick/grip.c b/trunk/drivers/input/joystick/grip.c index 73eb5ab6f140..17a90c436de8 100644 --- a/trunk/drivers/input/joystick/grip.c +++ b/trunk/drivers/input/joystick/grip.c @@ -285,7 +285,7 @@ static void grip_poll(struct gameport *gameport) static int grip_open(struct input_dev *dev) { - struct grip *grip = input_get_drvdata(dev); + struct grip *grip = dev->private; gameport_start_polling(grip->gameport); return 0; @@ -293,7 +293,7 @@ static int grip_open(struct input_dev *dev) static void grip_close(struct input_dev *dev) { - struct grip *grip = input_get_drvdata(dev); + struct grip *grip = dev->private; gameport_stop_polling(grip->gameport); } @@ -363,9 +363,8 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; input_dev->id.product = grip->mode[i]; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, grip); + input_dev->cdev.dev = &gameport->dev; + input_dev->private = grip; input_dev->open = grip_open; input_dev->close = grip_close; diff --git a/trunk/drivers/input/joystick/grip_mp.c b/trunk/drivers/input/joystick/grip_mp.c index 555319e6378c..8120a9c40773 100644 --- a/trunk/drivers/input/joystick/grip_mp.c +++ b/trunk/drivers/input/joystick/grip_mp.c @@ -562,7 +562,7 @@ static void grip_poll(struct gameport *gameport) static int grip_open(struct input_dev *dev) { - struct grip_mp *grip = input_get_drvdata(dev); + struct grip_mp *grip = dev->private; gameport_start_polling(grip->gameport); return 0; @@ -574,9 +574,9 @@ static int grip_open(struct input_dev *dev) static void grip_close(struct input_dev *dev) { - struct grip_mp *grip = input_get_drvdata(dev); + struct grip_mp *grip = dev->private; - gameport_stop_polling(grip->gameport); + gameport_start_polling(grip->gameport); } /* @@ -599,9 +599,8 @@ static int register_slot(int slot, struct grip_mp *grip) input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; input_dev->id.product = 0x0100 + port->mode; input_dev->id.version = 0x0100; - input_dev->dev.parent = &grip->gameport->dev; - - input_set_drvdata(input_dev, grip); + input_dev->cdev.dev = &grip->gameport->dev; + input_dev->private = grip; input_dev->open = grip_open; input_dev->close = grip_close; diff --git a/trunk/drivers/input/joystick/guillemot.c b/trunk/drivers/input/joystick/guillemot.c index d4e8073caf27..dbc5d92858b8 100644 --- a/trunk/drivers/input/joystick/guillemot.c +++ b/trunk/drivers/input/joystick/guillemot.c @@ -156,7 +156,7 @@ static void guillemot_poll(struct gameport *gameport) static int guillemot_open(struct input_dev *dev) { - struct guillemot *guillemot = input_get_drvdata(dev); + struct guillemot *guillemot = dev->private; gameport_start_polling(guillemot->gameport); return 0; @@ -168,7 +168,7 @@ static int guillemot_open(struct input_dev *dev) static void guillemot_close(struct input_dev *dev) { - struct guillemot *guillemot = input_get_drvdata(dev); + struct guillemot *guillemot = dev->private; gameport_stop_polling(guillemot->gameport); } @@ -231,9 +231,8 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; input_dev->id.product = guillemot_type[i].id; input_dev->id.version = (int)data[14] << 8 | data[15]; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, guillemot); + input_dev->cdev.dev = &gameport->dev; + input_dev->private = guillemot; input_dev->open = guillemot_open; input_dev->close = guillemot_close; diff --git a/trunk/drivers/input/joystick/iforce/iforce-ff.c b/trunk/drivers/input/joystick/iforce/iforce-ff.c index f2a4381d0ab8..8fb0c19cc60e 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-ff.c +++ b/trunk/drivers/input/joystick/iforce/iforce-ff.c @@ -2,7 +2,7 @@ * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2001-2002, 2007 Johann Deneux + * Copyright (c) 2001-2002 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ @@ -205,7 +205,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new) int i; if (new->type != FF_SPRING && new->type != FF_FRICTION) { - warn("bad effect type in need_condition_modifier"); + printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); return 0; } @@ -227,7 +227,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new) static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect) { if (effect->type != FF_CONSTANT) { - warn("bad effect type in need_envelope_modifier"); + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); return 0; } @@ -258,7 +258,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec break; default: - warn("bad effect type in need_envelope_modifier"); + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); } return 0; @@ -271,7 +271,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec static int need_period_modifier(struct ff_effect *old, struct ff_effect *new) { if (new->type != FF_PERIODIC) { - warn("bad effect type in need_period_modifier"); + printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n"); return 0; } return (old->u.periodic.period != new->u.periodic.period diff --git a/trunk/drivers/input/joystick/iforce/iforce-main.c b/trunk/drivers/input/joystick/iforce/iforce-main.c index fb129c479a66..3393a37fec39 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-main.c +++ b/trunk/drivers/input/joystick/iforce/iforce-main.c @@ -2,7 +2,7 @@ * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2001-2002, 2007 Johann Deneux + * Copyright (c) 2001-2002 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ @@ -29,7 +29,7 @@ #include "iforce.h" -MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); MODULE_LICENSE("GPL"); @@ -220,7 +220,7 @@ static void iforce_release(struct input_dev *dev) /* Check: no effects should be present in memory */ for (i = 0; i < dev->ff->max_effects; i++) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) { - warn("iforce_release: Device still owns effects"); + printk(KERN_WARNING "iforce_release: Device still owns effects\n"); break; } } @@ -232,7 +232,7 @@ static void iforce_release(struct input_dev *dev) switch (iforce->bus) { #ifdef CONFIG_JOYSTICK_IFORCE_USB case IFORCE_USB: - usb_kill_urb(iforce->irq); + usb_unlink_urb(iforce->irq); /* The device was unplugged before the file * was released */ @@ -287,13 +287,13 @@ int iforce_init_device(struct iforce *iforce) #ifdef CONFIG_JOYSTICK_IFORCE_USB case IFORCE_USB: input_dev->id.bustype = BUS_USB; - input_dev->dev.parent = &iforce->usbdev->dev; + input_dev->cdev.dev = &iforce->usbdev->dev; break; #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 case IFORCE_232: input_dev->id.bustype = BUS_RS232; - input_dev->dev.parent = &iforce->serio->dev; + input_dev->cdev.dev = &iforce->serio->dev; break; #endif } @@ -324,7 +324,7 @@ int iforce_init_device(struct iforce *iforce) break; if (i == 20) { /* 5 seconds */ - err("Timeout waiting for response from device."); + printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); error = -ENODEV; goto fail; } @@ -336,26 +336,26 @@ int iforce_init_device(struct iforce *iforce) if (!iforce_get_id_packet(iforce, "M")) input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; else - warn("Device does not respond to id packet M"); + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); if (!iforce_get_id_packet(iforce, "P")) input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; else - warn("Device does not respond to id packet P"); + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); if (!iforce_get_id_packet(iforce, "B")) iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; else - warn("Device does not respond to id packet B"); + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); if (!iforce_get_id_packet(iforce, "N")) ff_effects = iforce->edata[1]; else - warn("Device does not respond to id packet N"); + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); /* Check if the device can store more effects than the driver can really handle */ if (ff_effects > IFORCE_EFFECTS_MAX) { - warn("Limiting number of effects to %d (device reports %d)", + printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n", IFORCE_EFFECTS_MAX, ff_effects); ff_effects = IFORCE_EFFECTS_MAX; } @@ -457,6 +457,8 @@ int iforce_init_device(struct iforce *iforce) if (error) goto fail; + printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open); + return 0; fail: input_free_device(input_dev); diff --git a/trunk/drivers/input/joystick/iforce/iforce-packets.c b/trunk/drivers/input/joystick/iforce/iforce-packets.c index 21c4e13d3a50..808f05932a6f 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-packets.c +++ b/trunk/drivers/input/joystick/iforce/iforce-packets.c @@ -2,7 +2,7 @@ * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2001-2002, 2007 Johann Deneux + * Copyright (c) 2001-2002 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ @@ -39,10 +39,10 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) { int i; - printk(KERN_DEBUG __FILE__ ": %s cmd = %04x, data = ", msg, cmd); + printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); for (i = 0; i < LO(cmd); i++) printk("%02x ", data[i]); - printk("\n"); + printk(")\n"); } /* @@ -65,9 +65,8 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) head = iforce->xmit.head; tail = iforce->xmit.tail; - if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { - warn("not enough space in xmit buffer to send new packet"); + printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); spin_unlock_irqrestore(&iforce->xmit_lock, flags); return -1; } @@ -127,6 +126,8 @@ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) { unsigned char data[3]; +printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); + data[0] = LO(id); data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; data[2] = LO(value); @@ -150,7 +151,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) return 0; } } - warn("unused effect %04x updated !!!", addr); + printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); return -1; } @@ -161,7 +162,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) static int being_used = 0; if (being_used) - warn("re-entrant call to iforce_process %d", being_used); + printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); being_used++; #ifdef CONFIG_JOYSTICK_IFORCE_232 @@ -265,7 +266,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) return -1; } #else - err("iforce_get_id_packet: iforce->bus = USB!"); + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n"); #endif break; @@ -283,12 +284,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) return -1; } #else - err("iforce_get_id_packet: iforce->bus = SERIO!"); + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n"); #endif break; default: - err("iforce_get_id_packet: iforce->bus = %d", iforce->bus); + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n", + iforce->bus); break; } diff --git a/trunk/drivers/input/joystick/iforce/iforce-serio.c b/trunk/drivers/input/joystick/iforce/iforce-serio.c index 7b4bc19cef27..ec4be535f483 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-serio.c +++ b/trunk/drivers/input/joystick/iforce/iforce-serio.c @@ -2,7 +2,7 @@ * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2001, 2007 Johann Deneux + * Copyright (c) 2001 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ diff --git a/trunk/drivers/input/joystick/iforce/iforce-usb.c b/trunk/drivers/input/joystick/iforce/iforce-usb.c index 750099d8e3c6..80cdebcbcb99 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-usb.c +++ b/trunk/drivers/input/joystick/iforce/iforce-usb.c @@ -2,7 +2,7 @@ * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2001-2002, 2007 Johann Deneux + * Copyright (c) 2001-2002 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ @@ -65,7 +65,7 @@ void iforce_usb_xmit(struct iforce *iforce) XMIT_INC(iforce->xmit.tail, n); if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { - warn("usb_submit_urb failed %d\n", n); + printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); } /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. @@ -110,7 +110,7 @@ static void iforce_usb_out(struct urb *urb) struct iforce *iforce = urb->context; if (urb->status) { - dbg("urb->status %d, exiting", urb->status); + printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status); return; } @@ -190,9 +190,10 @@ static int iforce_usb_probe(struct usb_interface *intf, /* Called by iforce_delete() */ void iforce_usb_delete(struct iforce* iforce) { - usb_kill_urb(iforce->irq); - usb_kill_urb(iforce->out); - usb_kill_urb(iforce->ctrl); + usb_unlink_urb(iforce->irq); +/* Is it ok to unlink those ? */ + usb_unlink_urb(iforce->out); + usb_unlink_urb(iforce->ctrl); usb_free_urb(iforce->irq); usb_free_urb(iforce->out); diff --git a/trunk/drivers/input/joystick/iforce/iforce.h b/trunk/drivers/input/joystick/iforce/iforce.h index dadcf4fb92ae..ffaeaefa1a42 100644 --- a/trunk/drivers/input/joystick/iforce/iforce.h +++ b/trunk/drivers/input/joystick/iforce/iforce.h @@ -2,7 +2,7 @@ * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $ * * Copyright (c) 2000-2002 Vojtech Pavlik - * Copyright (c) 2001-2002, 2007 Johann Deneux + * Copyright (c) 2001-2002 Johann Deneux * * USB/RS232 I-Force joysticks and wheels. */ diff --git a/trunk/drivers/input/joystick/interact.c b/trunk/drivers/input/joystick/interact.c index 1aec1e9d7c59..fec8b3d0967d 100644 --- a/trunk/drivers/input/joystick/interact.c +++ b/trunk/drivers/input/joystick/interact.c @@ -185,7 +185,7 @@ static void interact_poll(struct gameport *gameport) static int interact_open(struct input_dev *dev) { - struct interact *interact = input_get_drvdata(dev); + struct interact *interact = dev->private; gameport_start_polling(interact->gameport); return 0; @@ -197,7 +197,7 @@ static int interact_open(struct input_dev *dev) static void interact_close(struct input_dev *dev) { - struct interact *interact = input_get_drvdata(dev); + struct interact *interact = dev->private; gameport_stop_polling(interact->gameport); } @@ -262,9 +262,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT; input_dev->id.product = interact_type[i].id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, interact); + input_dev->private = interact; input_dev->open = interact_open; input_dev->close = interact_close; diff --git a/trunk/drivers/input/joystick/magellan.c b/trunk/drivers/input/joystick/magellan.c index b35604ee43ae..4112789f1196 100644 --- a/trunk/drivers/input/joystick/magellan.c +++ b/trunk/drivers/input/joystick/magellan.c @@ -168,7 +168,8 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_MAGELLAN; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = magellan; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); diff --git a/trunk/drivers/input/joystick/sidewinder.c b/trunk/drivers/input/joystick/sidewinder.c index 2adf73f63c94..e58b22c018e4 100644 --- a/trunk/drivers/input/joystick/sidewinder.c +++ b/trunk/drivers/input/joystick/sidewinder.c @@ -509,7 +509,7 @@ static void sw_poll(struct gameport *gameport) static int sw_open(struct input_dev *dev) { - struct sw *sw = input_get_drvdata(dev); + struct sw *sw = dev->private; gameport_start_polling(sw->gameport); return 0; @@ -517,7 +517,7 @@ static int sw_open(struct input_dev *dev) static void sw_close(struct input_dev *dev) { - struct sw *sw = input_get_drvdata(dev); + struct sw *sw = dev->private; gameport_stop_polling(sw->gameport); } @@ -751,9 +751,8 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; input_dev->id.product = sw->type; input_dev->id.version = 0x0100; - input_dev->dev.parent = &gameport->dev; - - input_set_drvdata(input_dev, sw); + input_dev->cdev.dev = &gameport->dev; + input_dev->private = sw; input_dev->open = sw_open; input_dev->close = sw_close; diff --git a/trunk/drivers/input/joystick/spaceball.c b/trunk/drivers/input/joystick/spaceball.c index abb7c4cf54ad..08bf113e62eb 100644 --- a/trunk/drivers/input/joystick/spaceball.c +++ b/trunk/drivers/input/joystick/spaceball.c @@ -226,7 +226,8 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_SPACEBALL; input_dev->id.product = id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceball; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); diff --git a/trunk/drivers/input/joystick/spaceorb.c b/trunk/drivers/input/joystick/spaceorb.c index c4937f1e837c..c9c79211af71 100644 --- a/trunk/drivers/input/joystick/spaceorb.c +++ b/trunk/drivers/input/joystick/spaceorb.c @@ -183,7 +183,8 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_SPACEORB; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = spaceorb; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); diff --git a/trunk/drivers/input/joystick/stinger.c b/trunk/drivers/input/joystick/stinger.c index 8581ee991d4e..ecb0916215fa 100644 --- a/trunk/drivers/input/joystick/stinger.c +++ b/trunk/drivers/input/joystick/stinger.c @@ -154,7 +154,8 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_STINGER; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = stinger; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | diff --git a/trunk/drivers/input/joystick/tmdc.c b/trunk/drivers/input/joystick/tmdc.c index 3b36ee04f726..bb23ed2a04a6 100644 --- a/trunk/drivers/input/joystick/tmdc.c +++ b/trunk/drivers/input/joystick/tmdc.c @@ -265,7 +265,7 @@ static void tmdc_poll(struct gameport *gameport) static int tmdc_open(struct input_dev *dev) { - struct tmdc *tmdc = input_get_drvdata(dev); + struct tmdc *tmdc = dev->private; gameport_start_polling(tmdc->gameport); return 0; @@ -273,7 +273,7 @@ static int tmdc_open(struct input_dev *dev) static void tmdc_close(struct input_dev *dev) { - struct tmdc *tmdc = input_get_drvdata(dev); + struct tmdc *tmdc = dev->private; gameport_stop_polling(tmdc->gameport); } @@ -326,9 +326,8 @@ static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; input_dev->id.product = model->id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &tmdc->gameport->dev; - - input_set_drvdata(input_dev, tmdc); + input_dev->cdev.dev = &tmdc->gameport->dev; + input_dev->private = tmdc; input_dev->open = tmdc_open; input_dev->close = tmdc_close; diff --git a/trunk/drivers/input/joystick/turbografx.c b/trunk/drivers/input/joystick/turbografx.c index 0f2c60823b0b..037d3487fcc7 100644 --- a/trunk/drivers/input/joystick/turbografx.c +++ b/trunk/drivers/input/joystick/turbografx.c @@ -122,7 +122,7 @@ static void tgfx_timer(unsigned long private) static int tgfx_open(struct input_dev *dev) { - struct tgfx *tgfx = input_get_drvdata(dev); + struct tgfx *tgfx = dev->private; int err; err = mutex_lock_interruptible(&tgfx->sem); @@ -141,7 +141,7 @@ static int tgfx_open(struct input_dev *dev) static void tgfx_close(struct input_dev *dev) { - struct tgfx *tgfx = input_get_drvdata(dev); + struct tgfx *tgfx = dev->private; mutex_lock(&tgfx->sem); if (!--tgfx->used) { @@ -224,8 +224,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) input_dev->id.product = n_buttons[i]; input_dev->id.version = 0x0100; - input_set_drvdata(input_dev, tgfx); - + input_dev->private = tgfx; input_dev->open = tgfx_open; input_dev->close = tgfx_close; diff --git a/trunk/drivers/input/joystick/twidjoy.c b/trunk/drivers/input/joystick/twidjoy.c index c91504ec38eb..9cf17d6ced82 100644 --- a/trunk/drivers/input/joystick/twidjoy.c +++ b/trunk/drivers/input/joystick/twidjoy.c @@ -205,9 +205,11 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_TWIDJOY; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = twidjoy; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4); input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4); diff --git a/trunk/drivers/input/joystick/warrior.c b/trunk/drivers/input/joystick/warrior.c index 4e85f72eefd7..29d339acf430 100644 --- a/trunk/drivers/input/joystick/warrior.c +++ b/trunk/drivers/input/joystick/warrior.c @@ -160,7 +160,8 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_WARRIOR; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = warrior; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); diff --git a/trunk/drivers/input/keyboard/Kconfig b/trunk/drivers/input/keyboard/Kconfig index 9f42e4d3649e..f17e9c7d4b36 100644 --- a/trunk/drivers/input/keyboard/Kconfig +++ b/trunk/drivers/input/keyboard/Kconfig @@ -164,17 +164,6 @@ config KEYBOARD_AMIGA To compile this driver as a module, choose M here: the module will be called amikbd. -config KEYBOARD_ATARI - tristate "Atari keyboard" - depends on ATARI - select ATARI_KBD_CORE - help - Say Y here if you are running Linux on any Atari and have a keyboard - attached. - - To compile this driver as a module, choose M here: the - module will be called atakbd. - config KEYBOARD_HIL_OLD tristate "HP HIL keyboard support (simple driver)" depends on GSC || HP300 @@ -214,15 +203,6 @@ config KEYBOARD_OMAP To compile this driver as a module, choose M here: the module will be called omap-keypad. -config KEYBOARD_PXA27x - tristate "PXA27x keyboard support" - depends on PXA27x - help - Enable support for PXA27x matrix keyboard controller - - To compile this driver as a module, choose M here: the - module will be called pxa27x_keyboard. - config KEYBOARD_AAED2000 tristate "AAED-2000 keyboard" depends on MACH_AAED2000 diff --git a/trunk/drivers/input/keyboard/Makefile b/trunk/drivers/input/keyboard/Makefile index 28d211b87b14..586a0fe53be6 100644 --- a/trunk/drivers/input/keyboard/Makefile +++ b/trunk/drivers/input/keyboard/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o -obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o @@ -18,7 +17,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o -obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o diff --git a/trunk/drivers/input/keyboard/aaed2000_kbd.c b/trunk/drivers/input/keyboard/aaed2000_kbd.c index 3a37505f067c..65fcb6af63a8 100644 --- a/trunk/drivers/input/keyboard/aaed2000_kbd.c +++ b/trunk/drivers/input/keyboard/aaed2000_kbd.c @@ -97,7 +97,7 @@ static void aaedkbd_work(void *data) static int aaedkbd_open(struct input_dev *indev) { - struct aaedkbd *aaedkbd = input_get_drvdata(indev); + struct aaedkbd *aaedkbd = indev->private; schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL)); @@ -106,7 +106,7 @@ static int aaedkbd_open(struct input_dev *indev) static void aaedkbd_close(struct input_dev *indev) { - struct aaedkbd *aaedkbd = input_get_drvdata(indev); + struct aaedkbd *aaedkbd = indev->private; cancel_delayed_work(&aaedkbd->workq); flush_scheduled_work(); @@ -141,9 +141,8 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev) input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - - input_set_drvdata(input_dev, aaedkbd); + input_dev->cdev.dev = &pdev->dev; + input_dev->private = aaedkbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = aaedkbd->keycode; diff --git a/trunk/drivers/input/keyboard/atakbd.c b/trunk/drivers/input/keyboard/atakbd.c deleted file mode 100644 index ded1d6ac6ff3..000000000000 --- a/trunk/drivers/input/keyboard/atakbd.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * atakbd.c - * - * Copyright (c) 2005 Michael Schmitz - * - * Based on amikbd.c, which is - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * Based on the work of: - * Hamish Macdonald - */ - -/* - * Atari keyboard driver for Linux/m68k - * - * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c - * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard - * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). - * This driver only deals with handing key events off to the input layer. - */ - -/* - * 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 - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -MODULE_AUTHOR("Michael Schmitz "); -MODULE_DESCRIPTION("Atari keyboard driver"); -MODULE_LICENSE("GPL"); - -static unsigned char atakbd_keycode[0x72]; - -static struct input_dev *atakbd_dev; - -static void atakbd_interrupt(unsigned char scancode, char down) -{ - - if (scancode < 0x72) { /* scancodes < 0xf2 are keys */ - - // report raw events here? - - scancode = atakbd_keycode[scancode]; - - if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ - input_report_key(atakbd_dev, scancode, 1); - input_report_key(atakbd_dev, scancode, 0); - input_sync(atakbd_dev); - } else { - input_report_key(atakbd_dev, scancode, down); - input_sync(atakbd_dev); - } - } else /* scancodes >= 0xf2 are mouse data, most likely */ - printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode); - - return; -} - -static int __init atakbd_init(void) -{ - int i; - - if (!ATARIHW_PRESENT(ST_MFP)) - return -EIO; - - // TODO: request_mem_region if not done in arch code - - if (!(atakbd_dev = input_allocate_device())) - return -ENOMEM; - - // need to init core driver if not already done so - if (atari_keyb_init()) - return -ENODEV; - - atakbd_dev->name = "Atari Keyboard"; - atakbd_dev->phys = "atakbd/input0"; - atakbd_dev->id.bustype = BUS_ATARI; - atakbd_dev->id.vendor = 0x0001; - atakbd_dev->id.product = 0x0001; - atakbd_dev->id.version = 0x0100; - - atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - atakbd_dev->keycode = atakbd_keycode; - atakbd_dev->keycodesize = sizeof(unsigned char); - atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode); - - for (i = 1; i < 0x72; i++) { - atakbd_keycode[i] = i; - set_bit(atakbd_keycode[i], atakbd_dev->keybit); - } - - input_register_device(atakbd_dev); - - atari_input_keyboard_interrupt_hook = atakbd_interrupt; - - printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name); - - return 0; -} - -static void __exit atakbd_exit(void) -{ - atari_input_keyboard_interrupt_hook = NULL; - input_unregister_device(atakbd_dev); -} - -module_init(atakbd_init); -module_exit(atakbd_exit); diff --git a/trunk/drivers/input/keyboard/atkbd.c b/trunk/drivers/input/keyboard/atkbd.c index be1fe46cd308..663877076bc7 100644 --- a/trunk/drivers/input/keyboard/atkbd.c +++ b/trunk/drivers/input/keyboard/atkbd.c @@ -586,7 +586,7 @@ static void atkbd_event_work(struct work_struct *work) static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct atkbd *atkbd = input_get_drvdata(dev); + struct atkbd *atkbd = dev->private; if (!atkbd->write) return -1; @@ -883,9 +883,8 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) input_dev->id.product = atkbd->translated ? 1 : atkbd->set; input_dev->id.version = atkbd->id; input_dev->event = atkbd_event; - input_dev->dev.parent = &atkbd->ps2dev.serio->dev; - - input_set_drvdata(input_dev, atkbd); + input_dev->private = atkbd; + input_dev->cdev.dev = &atkbd->ps2dev.serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); diff --git a/trunk/drivers/input/keyboard/corgikbd.c b/trunk/drivers/input/keyboard/corgikbd.c index 6578bfff644b..1016c94e65db 100644 --- a/trunk/drivers/input/keyboard/corgikbd.c +++ b/trunk/drivers/input/keyboard/corgikbd.c @@ -323,7 +323,8 @@ static int __init corgikbd_probe(struct platform_device *pdev) input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; + input_dev->cdev.dev = &pdev->dev; + input_dev->private = corgikbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); input_dev->keycode = corgikbd->keycode; diff --git a/trunk/drivers/input/keyboard/gpio_keys.c b/trunk/drivers/input/keyboard/gpio_keys.c index 739212252b09..ccf6df387b62 100644 --- a/trunk/drivers/input/keyboard/gpio_keys.c +++ b/trunk/drivers/input/keyboard/gpio_keys.c @@ -35,14 +35,11 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) struct input_dev *input = platform_get_drvdata(pdev); for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int gpio = button->gpio; - + int gpio = pdata->buttons[i].gpio; if (irq == gpio_to_irq(gpio)) { - unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; + int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low); - input_event(input, type, button->code, !!state); + input_report_key(input, pdata->buttons[i].keycode, state); input_sync(input); } } @@ -66,7 +63,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input->name = pdev->name; input->phys = "gpio-keys/input0"; - input->dev.parent = &pdev->dev; + input->cdev.dev = &pdev->dev; + input->private = pdata; input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; @@ -74,21 +72,19 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input->id.version = 0x0100; for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int irq = gpio_to_irq(button->gpio); - unsigned int type = button->type ?: EV_KEY; + int code = pdata->buttons[i].keycode; + int irq = gpio_to_irq(pdata->buttons[i].gpio); set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, - button->desc ? button->desc : "gpio_keys", + pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", pdev); if (error) { printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, error); goto fail; } - - input_set_capability(input, type, button->code); + set_bit(code, input->keybit); } error = input_register_device(input); diff --git a/trunk/drivers/input/keyboard/hil_kbd.c b/trunk/drivers/input/keyboard/hil_kbd.c index cdd254f2e6c7..7cc9728b04df 100644 --- a/trunk/drivers/input/keyboard/hil_kbd.c +++ b/trunk/drivers/input/keyboard/hil_kbd.c @@ -51,7 +51,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define HIL_KBD_SET1_UPBIT 0x01 #define HIL_KBD_SET1_SHIFT 1 -static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly = +static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = { HIL_KEYCODES_SET1 }; #define HIL_KBD_SET2_UPBIT 0x01 @@ -60,10 +60,10 @@ static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly = #define HIL_KBD_SET3_UPBIT 0x80 #define HIL_KBD_SET3_SHIFT 0 -static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly = +static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] = { HIL_KEYCODES_SET3 }; -static const char hil_language[][16] = { HIL_LOCALE_MAP }; +static char hil_language[][16] = { HIL_LOCALE_MAP }; struct hil_kbd { struct input_dev *dev; @@ -94,12 +94,10 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) idx = kbd->idx4/4; p = data[idx - 1]; - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; + if ((p & ~HIL_CMDCT_POL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; + if ((p & ~HIL_CMDCT_RPL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; /* Not a poll response. See if we are loading config records. */ switch (p & HIL_PKT_DATA_MASK) { @@ -109,32 +107,27 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) for (; i < HIL_KBD_MAX_LENGTH; i++) kbd->idd[i] = 0; break; - case HIL_CMD_RSC: for (i = 0; i < idx; i++) kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_KBD_MAX_LENGTH; i++) kbd->rsc[i] = 0; break; - case HIL_CMD_EXD: for (i = 0; i < idx; i++) kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_KBD_MAX_LENGTH; i++) kbd->exd[i] = 0; break; - case HIL_CMD_RNM: for (i = 0; i < idx; i++) kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_KBD_MAX_LENGTH + 1; i++) kbd->rnm[i] = '\0'; break; - default: /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; + if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; /* Anything else we'd like to know about. */ printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); break; @@ -146,19 +139,16 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { case HIL_POL_CHARTYPE_NONE: break; - case HIL_POL_CHARTYPE_ASCII: while (cnt < idx - 1) input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); break; - case HIL_POL_CHARTYPE_RSVD1: case HIL_POL_CHARTYPE_RSVD2: case HIL_POL_CHARTYPE_BINARY: while (cnt < idx - 1) input_report_key(dev, kbd->data[cnt++], 1); break; - case HIL_POL_CHARTYPE_SET1: while (cnt < idx - 1) { unsigned int key; @@ -171,7 +161,6 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) input_report_key(dev, key, !up); } break; - case HIL_POL_CHARTYPE_SET2: while (cnt < idx - 1) { unsigned int key; @@ -184,7 +173,6 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) input_report_key(dev, key, !up); } break; - case HIL_POL_CHARTYPE_SET3: while (cnt < idx - 1) { unsigned int key; @@ -203,43 +191,42 @@ static void hil_kbd_process_record(struct hil_kbd *kbd) up(&kbd->sem); } -static void hil_kbd_process_err(struct hil_kbd *kbd) -{ +static void hil_kbd_process_err(struct hil_kbd *kbd) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); kbd->idx4 = 0; up(&kbd->sem); } -static irqreturn_t hil_kbd_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) +static irqreturn_t hil_kbd_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { struct hil_kbd *kbd; hil_packet packet; int idx; kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + if (kbd == NULL) { + BUG(); + return IRQ_HANDLED; + } if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { hil_kbd_process_err(kbd); return IRQ_HANDLED; } idx = kbd->idx4/4; - if (!(kbd->idx4 % 4)) - kbd->data[idx] = 0; + if (!(kbd->idx4 % 4)) kbd->data[idx] = 0; packet = kbd->data[idx]; packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); kbd->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(kbd->idx4)) % 4) - return IRQ_HANDLED; + if ((++(kbd->idx4)) % 4) return IRQ_HANDLED; if ((packet & 0xffff0000) != HIL_ERR_INT) { hil_kbd_process_err(kbd); return IRQ_HANDLED; } - if (packet & HIL_PKT_CMD) - hil_kbd_process_record(kbd); + if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd); return IRQ_HANDLED; } @@ -248,7 +235,10 @@ static void hil_kbd_disconnect(struct serio *serio) struct hil_kbd *kbd; kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + if (kbd == NULL) { + BUG(); + return; + } serio_close(serio); input_unregister_device(kbd->dev); @@ -269,40 +259,42 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) if (!kbd->dev) goto bail0; + kbd->dev->private = kbd; + if (serio_open(serio, drv)) goto bail1; serio_set_drvdata(serio, kbd); kbd->serio = serio; - init_MUTEX_LOCKED(&kbd->sem); + init_MUTEX_LOCKED(&(kbd->sem)); /* Get device info. MLC driver supplies devid/status/etc. */ serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_IDD); - down(&kbd->sem); + down(&(kbd->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_RSC); - down(&kbd->sem); + down(&(kbd->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_RNM); - down(&kbd->sem); + down(&(kbd->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_EXD); - down(&kbd->sem); + down(&(kbd->sem)); - up(&kbd->sem); + up(&(kbd->sem)); did = kbd->idd[0]; idd = kbd->idd + 1; @@ -318,11 +310,12 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) goto bail2; } - if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { + if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); goto bail2; } + kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; @@ -335,7 +328,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) kbd->dev->id.vendor = PCI_VENDOR_ID_HP; kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev->dev.parent = &serio->dev; + kbd->dev->cdev.dev = &serio->dev; for (i = 0; i < 128; i++) { set_bit(hil_kbd_set1[i], kbd->dev->keybit); @@ -351,8 +344,8 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ - down(&kbd->sem); - up(&kbd->sem); + down(&(kbd->sem)); + up(&(kbd->sem)); return 0; bail2: @@ -375,26 +368,26 @@ static struct serio_device_id hil_kbd_ids[] = { { 0 } }; -static struct serio_driver hil_kbd_serio_drv = { +struct serio_driver hil_kbd_serio_drv = { .driver = { .name = "hil_kbd", }, .description = "HP HIL keyboard driver", .id_table = hil_kbd_ids, - .connect = hil_kbd_connect, - .disconnect = hil_kbd_disconnect, - .interrupt = hil_kbd_interrupt + .connect = hil_kbd_connect, + .disconnect = hil_kbd_disconnect, + .interrupt = hil_kbd_interrupt }; static int __init hil_kbd_init(void) { return serio_register_driver(&hil_kbd_serio_drv); } - + static void __exit hil_kbd_exit(void) { serio_unregister_driver(&hil_kbd_serio_drv); } - + module_init(hil_kbd_init); module_exit(hil_kbd_exit); diff --git a/trunk/drivers/input/keyboard/hilkbd.c b/trunk/drivers/input/keyboard/hilkbd.c index 499b6974457f..4de4dc297d50 100644 --- a/trunk/drivers/input/keyboard/hilkbd.c +++ b/trunk/drivers/input/keyboard/hilkbd.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998 Philip Blundell * Copyright (C) 1999 Matthew Wilcox - * Copyright (C) 1999-2007 Helge Deller + * Copyright (C) 1999-2006 Helge Deller * * Very basic HP Human Interface Loop (HIL) driver. * This driver handles the keyboard on HP300 (m68k) and on some @@ -52,7 +52,7 @@ MODULE_LICENSE("GPL v2"); #elif defined(CONFIG_HP300) - #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */ + #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ #define HIL_DATA 0x1 #define HIL_CMD 0x3 #define HIL_IRQ 2 @@ -89,7 +89,7 @@ MODULE_LICENSE("GPL v2"); #define HIL_READKBDSADR 0xF9 #define HIL_WRITEKBDSADR 0xE9 -static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly = +static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = { HIL_KEYCODES_SET1 }; /* HIL structure */ @@ -211,10 +211,10 @@ hil_keyb_init(void) return -ENODEV; /* already initialized */ } - spin_lock_init(&hil_dev.lock); hil_dev.dev = input_allocate_device(); if (!hil_dev.dev) return -ENOMEM; + hil_dev.dev->private = &hil_dev; #if defined(CONFIG_HP300) if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { diff --git a/trunk/drivers/input/keyboard/lkkbd.c b/trunk/drivers/input/keyboard/lkkbd.c index 1b08f4e79dd2..3d4d0a0ede28 100644 --- a/trunk/drivers/input/keyboard/lkkbd.c +++ b/trunk/drivers/input/keyboard/lkkbd.c @@ -515,7 +515,7 @@ static int lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct lkkbd *lk = input_get_drvdata (dev); + struct lkkbd *lk = dev->private; unsigned char leds_on = 0; unsigned char leds_off = 0; @@ -666,10 +666,9 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_LKKBD; input_dev->id.product = 0; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; input_dev->event = lkkbd_event; - - input_set_drvdata (input_dev, lk); + input_dev->private = lk; set_bit (EV_KEY, input_dev->evbit); set_bit (EV_LED, input_dev->evbit); diff --git a/trunk/drivers/input/keyboard/locomokbd.c b/trunk/drivers/input/keyboard/locomokbd.c index 7a41b271f222..2ade5186cc41 100644 --- a/trunk/drivers/input/keyboard/locomokbd.c +++ b/trunk/drivers/input/keyboard/locomokbd.c @@ -231,7 +231,7 @@ static int locomokbd_probe(struct locomo_dev *dev) input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &dev->dev; + input_dev->private = locomokbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = locomokbd->keycode; diff --git a/trunk/drivers/input/keyboard/newtonkbd.c b/trunk/drivers/input/keyboard/newtonkbd.c index b97a41e3ee56..aa29b50765c9 100644 --- a/trunk/drivers/input/keyboard/newtonkbd.c +++ b/trunk/drivers/input/keyboard/newtonkbd.c @@ -104,7 +104,8 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_NEWTON; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = nkbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = nkbd->keycode; diff --git a/trunk/drivers/input/keyboard/omap-keypad.c b/trunk/drivers/input/keyboard/omap-keypad.c index 3a228634f101..5680a6d95b2b 100644 --- a/trunk/drivers/input/keyboard/omap-keypad.c +++ b/trunk/drivers/input/keyboard/omap-keypad.c @@ -370,7 +370,8 @@ static int __init omap_kp_probe(struct platform_device *pdev) set_bit(keymap[i] & KEY_MAX, input_dev->keybit); input_dev->name = "omap-keypad"; input_dev->phys = "omap-keypad/input0"; - input_dev->dev.parent = &pdev->dev; + input_dev->cdev.dev = &pdev->dev; + input_dev->private = omap_kp; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; diff --git a/trunk/drivers/input/keyboard/pxa27x_keyboard.c b/trunk/drivers/input/keyboard/pxa27x_keyboard.c deleted file mode 100644 index 06eaf766d9d2..000000000000 --- a/trunk/drivers/input/keyboard/pxa27x_keyboard.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * linux/drivers/input/keyboard/pxa27x_keyboard.c - * - * Driver for the pxa27x matrix keyboard controller. - * - * Created: Feb 22, 2007 - * Author: Rodolfo Giometti - * - * Based on a previous implementations by Kevin O'Connor - * and Alex Osborne and - * on some suggestions by Nicolas Pitre . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#define DRIVER_NAME "pxa27x-keyboard" - -#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \ - col/2 == 1 ? KPASMKP1 : \ - col/2 == 2 ? KPASMKP2 : KPASMKP3) -#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) - -static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id) -{ - struct platform_device *pdev = dev_id; - struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; - struct input_dev *input_dev = platform_get_drvdata(pdev); - unsigned long kpc = KPC; - int p, row, col, rel; - - if (kpc & KPC_DI) { - unsigned long kpdk = KPDK; - - if (!(kpdk & KPDK_DKP)) { - /* better luck next time */ - } else if (kpc & KPC_REE0) { - unsigned long kprec = KPREC; - KPREC = 0x7f; - - if (kprec & KPREC_OF0) - rel = (kprec & 0xff) + 0x7f; - else if (kprec & KPREC_UF0) - rel = (kprec & 0xff) - 0x7f - 0xff; - else - rel = (kprec & 0xff) - 0x7f; - - if (rel) { - input_report_rel(input_dev, REL_WHEEL, rel); - input_sync(input_dev); - } - } - } - - if (kpc & KPC_MI) { - /* report the status of every button */ - for (row = 0; row < pdata->nr_rows; row++) { - for (col = 0; col < pdata->nr_cols; col++) { - p = KPASMKP(col) & KPASMKPx_MKC(row, col) ? - 1 : 0; - pr_debug("keycode %x - pressed %x\n", - pdata->keycodes[row][col], p); - input_report_key(input_dev, - pdata->keycodes[row][col], p); - } - } - input_sync(input_dev); - } - - return IRQ_HANDLED; -} - -static int pxakbd_open(struct input_dev *dev) -{ - /* Set keypad control register */ - KPC |= (KPC_ASACT | - KPC_MS_ALL | - (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL | - KPC_ME | KPC_MIE | KPC_DE | KPC_DIE); - - KPC &= ~KPC_AS; /* disable automatic scan */ - KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */ - - /* Set rotary count to mid-point value */ - KPREC = 0x7F; - - /* Enable unit clock */ - pxa_set_cken(CKEN19_KEYPAD, 1); - - return 0; -} - -static void pxakbd_close(struct input_dev *dev) -{ - /* Disable clock unit */ - pxa_set_cken(CKEN19_KEYPAD, 0); -} - -#ifdef CONFIG_PM -static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; - - /* Save controller status */ - pdata->reg_kpc = KPC; - pdata->reg_kprec = KPREC; - - return 0; -} - -static int pxakbd_resume(struct platform_device *pdev) -{ - struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; - struct input_dev *input_dev = platform_get_drvdata(pdev); - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) { - /* Restore controller status */ - KPC = pdata->reg_kpc; - KPREC = pdata->reg_kprec; - - /* Enable unit clock */ - pxa_set_cken(CKEN19_KEYPAD, 1); - } - - mutex_unlock(&input_dev->mutex); - - return 0; -} -#else -#define pxakbd_suspend NULL -#define pxakbd_resume NULL -#endif - -static int __devinit pxakbd_probe(struct platform_device *pdev) -{ - struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; - struct input_dev *input_dev; - int i, row, col, error; - - /* Create and register the input driver. */ - input_dev = input_allocate_device(); - if (!input_dev) { - printk(KERN_ERR "Cannot request keypad device\n"); - return -ENOMEM; - } - - input_dev->name = DRIVER_NAME; - input_dev->id.bustype = BUS_HOST; - input_dev->open = pxakbd_open; - input_dev->close = pxakbd_close; - input_dev->dev.parent = &pdev->dev; - - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL); - input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL); - for (row = 0; row < pdata->nr_rows; row++) { - for (col = 0; col < pdata->nr_cols; col++) { - int code = pdata->keycodes[row][col]; - if (code > 0) - set_bit(code, input_dev->keybit); - } - } - - error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED, - DRIVER_NAME, pdev); - if (error) { - printk(KERN_ERR "Cannot request keypad IRQ\n"); - pxa_set_cken(CKEN19_KEYPAD, 0); - goto err_free_dev; - } - - platform_set_drvdata(pdev, input_dev); - - /* Register the input device */ - error = input_register_device(input_dev); - if (error) - goto err_free_irq; - - /* Setup GPIOs. */ - for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++) - pxa_gpio_mode(pdata->gpio_modes[i]); - - /* - * Store rows/cols info into keyboard registers. - */ - - KPC |= (pdata->nr_rows - 1) << 26; - KPC |= (pdata->nr_cols - 1) << 23; - - for (col = 0; col < pdata->nr_cols; col++) - KPC |= KPC_MS0 << col; - - return 0; - - err_free_irq: - platform_set_drvdata(pdev, NULL); - free_irq(IRQ_KEYPAD, pdev); - err_free_dev: - input_free_device(input_dev); - return error; -} - -static int __devexit pxakbd_remove(struct platform_device *pdev) -{ - struct input_dev *input_dev = platform_get_drvdata(pdev); - - input_unregister_device(input_dev); - free_irq(IRQ_KEYPAD, pdev); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver pxakbd_driver = { - .probe = pxakbd_probe, - .remove = __devexit_p(pxakbd_remove), - .suspend = pxakbd_suspend, - .resume = pxakbd_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -static int __init pxakbd_init(void) -{ - return platform_driver_register(&pxakbd_driver); -} - -static void __exit pxakbd_exit(void) -{ - platform_driver_unregister(&pxakbd_driver); -} - -module_init(pxakbd_init); -module_exit(pxakbd_exit); - -MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/keyboard/spitzkbd.c b/trunk/drivers/input/keyboard/spitzkbd.c index 41b80385476c..8a2166c77ff4 100644 --- a/trunk/drivers/input/keyboard/spitzkbd.c +++ b/trunk/drivers/input/keyboard/spitzkbd.c @@ -372,9 +372,10 @@ static int __init spitzkbd_probe(struct platform_device *dev) spitzkbd->input = input_dev; + input_dev->private = spitzkbd; input_dev->name = "Spitz Keyboard"; input_dev->phys = spitzkbd->phys; - input_dev->dev.parent = &dev->dev; + input_dev->cdev.dev = &dev->dev; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; diff --git a/trunk/drivers/input/keyboard/stowaway.c b/trunk/drivers/input/keyboard/stowaway.c index b44b0684d543..f7b5c5b81451 100644 --- a/trunk/drivers/input/keyboard/stowaway.c +++ b/trunk/drivers/input/keyboard/stowaway.c @@ -108,7 +108,8 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_STOWAWAY; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = skbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = skbd->keycode; diff --git a/trunk/drivers/input/keyboard/sunkbd.c b/trunk/drivers/input/keyboard/sunkbd.c index 1d4e39624cfe..cc0238366414 100644 --- a/trunk/drivers/input/keyboard/sunkbd.c +++ b/trunk/drivers/input/keyboard/sunkbd.c @@ -146,7 +146,7 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct sunkbd *sunkbd = input_get_drvdata(dev); + struct sunkbd *sunkbd = dev->private; switch (type) { @@ -271,10 +271,8 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_SUNKBD; input_dev->id.product = sunkbd->type; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; - - input_set_drvdata(input_dev, sunkbd); - + input_dev->cdev.dev = &serio->dev; + input_dev->private = sunkbd; input_dev->event = sunkbd_event; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); diff --git a/trunk/drivers/input/keyboard/xtkbd.c b/trunk/drivers/input/keyboard/xtkbd.c index f3a56eb58ed1..a82093432138 100644 --- a/trunk/drivers/input/keyboard/xtkbd.c +++ b/trunk/drivers/input/keyboard/xtkbd.c @@ -108,7 +108,8 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = xtkbd; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = xtkbd->keycode; diff --git a/trunk/drivers/input/misc/Kconfig b/trunk/drivers/input/misc/Kconfig index 1d0d3e765db6..41b42587f5e9 100644 --- a/trunk/drivers/input/misc/Kconfig +++ b/trunk/drivers/input/misc/Kconfig @@ -40,16 +40,6 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K -config INPUT_COBALT_BTNS - tristate "Cobalt button interface" - depends on MIPS_COBALT - select INPUT_POLLDEV - help - Say Y here if you want to support MIPS Cobalt button interface. - - To compile this driver as a module, choose M here: the - module will be called cobalt_btns. - config INPUT_WISTRON_BTNS tristate "x86 Wistron laptop button interface" depends on X86 && !X86_64 @@ -91,19 +81,8 @@ config INPUT_UINPUT To compile this driver as a module, choose M here: the module will be called uinput. -config INPUT_POLLDEV - tristate "Polled input device skeleton" - help - Say Y here if you are using a driver for an input - device that periodically polls hardware state. This - option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - - To compile this driver as a module, choose M here: the - module will be called input-polldev. - config HP_SDC_RTC - tristate "HP SDC Real Time Clock" + tristate "HP SDC Real Time Clock" depends on GSC || HP300 select HP_SDC help diff --git a/trunk/drivers/input/misc/Makefile b/trunk/drivers/input/misc/Makefile index 21e3cca0d33e..e0a8d58c9e9b 100644 --- a/trunk/drivers/input/misc/Makefile +++ b/trunk/drivers/input/misc/Makefile @@ -4,12 +4,10 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o -obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o diff --git a/trunk/drivers/input/misc/cobalt_btns.c b/trunk/drivers/input/misc/cobalt_btns.c deleted file mode 100644 index 064b07936019..000000000000 --- a/trunk/drivers/input/misc/cobalt_btns.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Cobalt button interface driver. - * - * Copyright (C) 2007 Yoichi Yuasa - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include -#include - -#define BUTTONS_POLL_INTERVAL 30 /* msec */ -#define BUTTONS_COUNT_THRESHOLD 3 -#define BUTTONS_STATUS_MASK 0xfe000000 - -struct buttons_dev { - struct input_polled_dev *poll_dev; - void __iomem *reg; -}; - -struct buttons_map { - uint32_t mask; - int keycode; - int count; -}; - -static struct buttons_map buttons_map[] = { - { 0x02000000, KEY_RESTART, }, - { 0x04000000, KEY_LEFT, }, - { 0x08000000, KEY_UP, }, - { 0x10000000, KEY_DOWN, }, - { 0x20000000, KEY_RIGHT, }, - { 0x40000000, KEY_ENTER, }, - { 0x80000000, KEY_SELECT, }, -}; - -static void handle_buttons(struct input_polled_dev *dev) -{ - struct buttons_map *button = buttons_map; - struct buttons_dev *bdev = dev->private; - struct input_dev *input = dev->input; - uint32_t status; - int i; - - status = readl(bdev->reg); - status = ~status & BUTTONS_STATUS_MASK; - - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { - if (status & button->mask) { - button->count++; - } else { - if (button->count >= BUTTONS_COUNT_THRESHOLD) { - input_report_key(input, button->keycode, 0); - input_sync(input); - } - button->count = 0; - } - - if (button->count == BUTTONS_COUNT_THRESHOLD) { - input_report_key(input, button->keycode, 1); - input_sync(input); - } - - button++; - } -} - -static int __devinit cobalt_buttons_probe(struct platform_device *pdev) -{ - struct buttons_dev *bdev; - struct input_polled_dev *poll_dev; - struct input_dev *input; - struct resource *res; - int error, i; - - bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL); - poll_dev = input_allocate_polled_device(); - if (!bdev || !poll_dev) { - error = -ENOMEM; - goto err_free_mem; - } - - poll_dev->private = bdev; - poll_dev->poll = handle_buttons; - poll_dev->poll_interval = BUTTONS_POLL_INTERVAL; - - input = poll_dev->input; - input->name = "Cobalt buttons"; - input->phys = "cobalt/input0"; - input->id.bustype = BUS_HOST; - input->cdev.dev = &pdev->dev; - - input->evbit[0] = BIT(EV_KEY); - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { - set_bit(buttons_map[i].keycode, input->keybit); - buttons_map[i].count = 0; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - error = -EBUSY; - goto err_free_mem; - } - - bdev->poll_dev = poll_dev; - bdev->reg = ioremap(res->start, res->end - res->start + 1); - dev_set_drvdata(&pdev->dev, bdev); - - error = input_register_polled_device(poll_dev); - if (error) - goto err_iounmap; - - return 0; - - err_iounmap: - iounmap(bdev->reg); - err_free_mem: - input_free_polled_device(poll_dev); - kfree(bdev); - dev_set_drvdata(&pdev->dev, NULL); - return error; -} - -static int __devexit cobalt_buttons_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct buttons_dev *bdev = dev_get_drvdata(dev); - - input_unregister_polled_device(bdev->poll_dev); - input_free_polled_device(bdev->poll_dev); - iounmap(bdev->reg); - kfree(bdev); - dev_set_drvdata(dev, NULL); - - return 0; -} - -static struct platform_driver cobalt_buttons_driver = { - .probe = cobalt_buttons_probe, - .remove = __devexit_p(cobalt_buttons_remove), - .driver = { - .name = "Cobalt buttons", - .owner = THIS_MODULE, - }, -}; - -static int __init cobalt_buttons_init(void) -{ - return platform_driver_register(&cobalt_buttons_driver); -} - -static void __exit cobalt_buttons_exit(void) -{ - platform_driver_unregister(&cobalt_buttons_driver); -} - -module_init(cobalt_buttons_init); -module_exit(cobalt_buttons_exit); diff --git a/trunk/drivers/input/misc/input-polldev.c b/trunk/drivers/input/misc/input-polldev.c deleted file mode 100644 index 1b2b9c9c5d88..000000000000 --- a/trunk/drivers/input/misc/input-polldev.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Generic implementation of a polled input device - - * Copyright (c) 2007 Dmitry Torokhov - * - * 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 - -static DEFINE_MUTEX(polldev_mutex); -static int polldev_users; -static struct workqueue_struct *polldev_wq; - -static int input_polldev_start_workqueue(void) -{ - int retval; - - retval = mutex_lock_interruptible(&polldev_mutex); - if (retval) - return retval; - - if (!polldev_users) { - polldev_wq = create_singlethread_workqueue("ipolldevd"); - if (!polldev_wq) { - printk(KERN_ERR "input-polldev: failed to create " - "ipolldevd workqueue\n"); - retval = -ENOMEM; - goto out; - } - } - - polldev_users++; - - out: - mutex_unlock(&polldev_mutex); - return retval; -} - -static void input_polldev_stop_workqueue(void) -{ - mutex_lock(&polldev_mutex); - - if (!--polldev_users) - destroy_workqueue(polldev_wq); - - mutex_unlock(&polldev_mutex); -} - -static void input_polled_device_work(struct work_struct *work) -{ - struct input_polled_dev *dev = - container_of(work, struct input_polled_dev, work.work); - - dev->poll(dev); - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); -} - -static int input_open_polled_device(struct input_dev *input) -{ - struct input_polled_dev *dev = input->private; - int error; - - error = input_polldev_start_workqueue(); - if (error) - return error; - - if (dev->flush) - dev->flush(dev); - - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); - - return 0; -} - -static void input_close_polled_device(struct input_dev *input) -{ - struct input_polled_dev *dev = input->private; - - cancel_rearming_delayed_workqueue(polldev_wq, &dev->work); - input_polldev_stop_workqueue(); -} - -/** - * input_allocate_polled_device - allocated memory polled device - * - * The function allocates memory for a polled device and also - * for an input device associated with this polled device. - */ -struct input_polled_dev *input_allocate_polled_device(void) -{ - struct input_polled_dev *dev; - - dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->input = input_allocate_device(); - if (!dev->input) { - kfree(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL(input_allocate_polled_device); - -/** - * input_free_polled_device - free memory allocated for polled device - * @dev: device to free - * - * The function frees memory allocated for polling device and drops - * reference to the associated input device (if present). - */ -void input_free_polled_device(struct input_polled_dev *dev) -{ - if (dev) { - input_free_device(dev->input); - kfree(dev); - } -} -EXPORT_SYMBOL(input_free_polled_device); - -/** - * input_register_polled_device - register polled device - * @dev: device to register - * - * The function registers previously initialized polled input device - * with input layer. The device should be allocated with call to - * input_allocate_polled_device(). Callers should also set up poll() - * method and set up capabilities (id, name, phys, bits) of the - * corresponing input_dev structure. - */ -int input_register_polled_device(struct input_polled_dev *dev) -{ - struct input_dev *input = dev->input; - - INIT_DELAYED_WORK(&dev->work, input_polled_device_work); - if (!dev->poll_interval) - dev->poll_interval = 500; - input->private = dev; - input->open = input_open_polled_device; - input->close = input_close_polled_device; - - return input_register_device(input); -} -EXPORT_SYMBOL(input_register_polled_device); - -/** - * input_unregister_polled_device - unregister polled device - * @dev: device to unregister - * - * The function unregisters previously registered polled input - * device from input layer. Polling is stopped and device is - * ready to be freed with call to input_free_polled_device(). - * Callers should not attempt to access dev->input pointer - * after calling this function. - */ -void input_unregister_polled_device(struct input_polled_dev *dev) -{ - input_unregister_device(dev->input); - dev->input = NULL; -} -EXPORT_SYMBOL(input_unregister_polled_device); - diff --git a/trunk/drivers/input/misc/ixp4xx-beeper.c b/trunk/drivers/input/misc/ixp4xx-beeper.c index 3d4b619dadab..105c6fc27823 100644 --- a/trunk/drivers/input/misc/ixp4xx-beeper.c +++ b/trunk/drivers/input/misc/ixp4xx-beeper.c @@ -51,7 +51,7 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - unsigned int pin = (unsigned int) input_get_drvdata(input_dev); + unsigned int pin = (unsigned int) dev->private; unsigned int count = 0; if (type != EV_SND) @@ -99,15 +99,14 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev) if (!input_dev) return -ENOMEM; - input_set_drvdata(input_dev, (void *) dev->id); - + input_dev->private = (void *) dev->id; input_dev->name = "ixp4xx beeper", input_dev->phys = "ixp4xx/gpio"; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x001f; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &dev->dev; + input_dev->cdev.dev = &dev->dev; input_dev->evbit[0] = BIT(EV_SND); input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); @@ -137,7 +136,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev) static int __devexit ixp4xx_spkr_remove(struct platform_device *dev) { struct input_dev *input_dev = platform_get_drvdata(dev); - unsigned int pin = (unsigned int) input_get_drvdata(input_dev); + unsigned int pin = (unsigned int) input_dev->private; input_unregister_device(input_dev); platform_set_drvdata(dev, NULL); @@ -154,7 +153,7 @@ static int __devexit ixp4xx_spkr_remove(struct platform_device *dev) static void ixp4xx_spkr_shutdown(struct platform_device *dev) { struct input_dev *input_dev = platform_get_drvdata(dev); - unsigned int pin = (unsigned int) input_get_drvdata(input_dev); + unsigned int pin = (unsigned int) input_dev->private; /* turn off the speaker */ disable_irq(IRQ_IXP4XX_TIMER2); diff --git a/trunk/drivers/input/misc/m68kspkr.c b/trunk/drivers/input/misc/m68kspkr.c index e9f26e766b4d..8d6c3837badb 100644 --- a/trunk/drivers/input/misc/m68kspkr.c +++ b/trunk/drivers/input/misc/m68kspkr.c @@ -63,7 +63,7 @@ static int __devinit m68kspkr_probe(struct platform_device *dev) input_dev->id.vendor = 0x001f; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = &dev->dev; + input_dev->cdev.dev = &dev->dev; input_dev->evbit[0] = BIT(EV_SND); input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); diff --git a/trunk/drivers/input/misc/pcspkr.c b/trunk/drivers/input/misc/pcspkr.c index 31989dcd922c..afd322185bbf 100644 --- a/trunk/drivers/input/misc/pcspkr.c +++ b/trunk/drivers/input/misc/pcspkr.c @@ -78,7 +78,7 @@ static int __devinit pcspkr_probe(struct platform_device *dev) pcspkr_dev->id.vendor = 0x001f; pcspkr_dev->id.product = 0x0001; pcspkr_dev->id.version = 0x0100; - pcspkr_dev->dev.parent = &dev->dev; + pcspkr_dev->cdev.dev = &dev->dev; pcspkr_dev->evbit[0] = BIT(EV_SND); pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); diff --git a/trunk/drivers/input/misc/sparcspkr.c b/trunk/drivers/input/misc/sparcspkr.c index e36ec1d92be8..106c94f33b93 100644 --- a/trunk/drivers/input/misc/sparcspkr.c +++ b/trunk/drivers/input/misc/sparcspkr.c @@ -28,7 +28,7 @@ struct sparcspkr_state { static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -61,7 +61,7 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev); unsigned int count = 0; unsigned long flags; @@ -113,7 +113,7 @@ static int __devinit sparcspkr_probe(struct device *dev) input_dev->id.vendor = 0x001f; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->dev.parent = dev; + input_dev->cdev.dev = dev; input_dev->evbit[0] = BIT(EV_SND); input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); diff --git a/trunk/drivers/input/misc/uinput.c b/trunk/drivers/input/misc/uinput.c index 031467eadd31..42556232c523 100644 --- a/trunk/drivers/input/misc/uinput.c +++ b/trunk/drivers/input/misc/uinput.c @@ -41,7 +41,9 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct uinput_device *udev = input_get_drvdata(dev); + struct uinput_device *udev; + + udev = dev->private; udev->buff[udev->head].type = type; udev->buff[udev->head].code = code; @@ -134,7 +136,7 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff request.u.upload.effect = effect; request.u.upload.old = old; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); + retval = uinput_request_reserve_slot(dev->private, &request); if (!retval) retval = uinput_request_submit(dev, &request); @@ -154,7 +156,7 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); + retval = uinput_request_reserve_slot(dev->private, &request); if (!retval) retval = uinput_request_submit(dev, &request); @@ -272,7 +274,7 @@ static int uinput_allocate_device(struct uinput_device *udev) return -ENOMEM; udev->dev->event = uinput_dev_event; - input_set_drvdata(udev->dev, udev); + udev->dev->private = udev; return 0; } diff --git a/trunk/drivers/input/misc/wistron_btns.c b/trunk/drivers/input/misc/wistron_btns.c index 961aad7a0476..e1183aeb8ed5 100644 --- a/trunk/drivers/input/misc/wistron_btns.c +++ b/trunk/drivers/input/misc/wistron_btns.c @@ -50,7 +50,7 @@ MODULE_AUTHOR("Miloslav Trmac "); MODULE_DESCRIPTION("Wistron laptop button driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.2"); +MODULE_VERSION("0.1"); static int force; /* = 0; */ module_param(force, bool, 0); @@ -58,7 +58,7 @@ MODULE_PARM_DESC(force, "Load even if computer is not in database"); static char *keymap_name; /* = NULL; */ module_param_named(keymap, keymap_name, charp, 0); -MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]"); +MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected"); static struct platform_device *wistron_device; @@ -233,20 +233,10 @@ static void bios_set_state(u8 subsys, int enable) struct key_entry { char type; /* See KE_* below */ u8 code; - union { - u16 keycode; /* For KE_KEY */ - struct { /* For KE_SW */ - u8 code; - u8 value; - } sw; - }; + unsigned keycode; /* For KE_KEY */ }; -enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; - -#define FE_MAIL_LED 0x01 -#define FE_WIFI_LED 0x02 -#define FE_UNTESTED 0x80 +enum { KE_END, KE_KEY, KE_WIFI, KE_BLUETOOTH }; static const struct key_entry *keymap; /* = NULL; Current key map */ static int have_wifi; @@ -266,341 +256,93 @@ static int __init dmi_matched(struct dmi_system_id *dmi) return 1; } -static struct key_entry keymap_empty[] __initdata = { +static struct key_entry keymap_empty[] = { { KE_END, 0 } }; -static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_WIFI, 0x30 }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, +static struct key_entry keymap_fs_amilo_pro_v2000[] = { + { KE_KEY, 0x01, KEY_HELP }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_WIFI, 0x30, 0 }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, { KE_END, 0 } }; -static struct key_entry keymap_fujitsu_n3510[] __initdata = { - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x71, {KEY_STOPCD} }, - { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, - { KE_KEY, 0x74, {KEY_REWIND} }, - { KE_KEY, 0x78, {KEY_FORWARD} }, +static struct key_entry keymap_fujitsu_n3510[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x71, KEY_STOPCD }, + { KE_KEY, 0x72, KEY_PLAYPAUSE }, + { KE_KEY, 0x74, KEY_REWIND }, + { KE_KEY, 0x78, KEY_FORWARD }, { KE_END, 0 } }; -static struct key_entry keymap_wistron_ms2111[] __initdata = { - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_END, FE_MAIL_LED } -}; - -static struct key_entry keymap_wistron_md40100[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ - { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_wistron_ms2141[] __initdata = { - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_WIFI, 0x30 }, - { KE_KEY, 0x22, {KEY_REWIND} }, - { KE_KEY, 0x23, {KEY_FORWARD} }, - { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, - { KE_KEY, 0x25, {KEY_STOPCD} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, +static struct key_entry keymap_wistron_ms2111[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x13, KEY_PROG3 }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, { KE_END, 0 } }; -static struct key_entry keymap_acer_aspire_1500[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_WIFI, 0x30 }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x49, {KEY_CONFIG} }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_UNTESTED } -}; - -static struct key_entry keymap_acer_aspire_1600[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x49, {KEY_CONFIG} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -/* 3020 has been tested */ -static struct key_entry keymap_acer_aspire_5020[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x6a, {KEY_CONFIG} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_2410[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x6d, {KEY_POWER} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x6a, {KEY_CONFIG} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_110[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x20, {KEY_VOLUMEUP} }, - { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ - { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ - { KE_WIFI, 0x30 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_300[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x20, {KEY_VOLUMEUP} }, - { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_380[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */ - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_WIFI, 0x30 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -/* unusual map */ -static struct key_entry keymap_acer_travelmate_220[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_MAIL} }, - { KE_KEY, 0x12, {KEY_WWW} }, - { KE_KEY, 0x13, {KEY_PROG2} }, - { KE_KEY, 0x31, {KEY_PROG1} }, - { KE_END, FE_WIFI_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_230[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_END, FE_WIFI_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_240[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_BLUETOOTH, 0x44 }, - { KE_WIFI, 0x30 }, - { KE_END, FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_350[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_MAIL} }, - { KE_KEY, 0x14, {KEY_PROG3} }, - { KE_KEY, 0x15, {KEY_WWW} }, - { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_acer_travelmate_360[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_MAIL} }, - { KE_KEY, 0x14, {KEY_PROG3} }, - { KE_KEY, 0x15, {KEY_WWW} }, - { KE_KEY, 0x40, {KEY_WLAN} }, - { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */ +static struct key_entry keymap_wistron_ms2141[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_WIFI, 0x30, 0 }, + { KE_KEY, 0x22, KEY_REWIND }, + { KE_KEY, 0x23, KEY_FORWARD }, + { KE_KEY, 0x24, KEY_PLAYPAUSE }, + { KE_KEY, 0x25, KEY_STOPCD }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_END, 0 } }; -/* Wifi subsystem only activates the led. Therefore we need to pass - * wifi event as a normal key, then userspace can really change the wifi state. - * TODO we need to export led state to userspace (wifi and mail) */ -static struct key_entry keymap_acer_travelmate_610[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x14, {KEY_MAIL} }, - { KE_KEY, 0x15, {KEY_WWW} }, - { KE_KEY, 0x40, {KEY_WLAN} }, - { KE_END, FE_MAIL_LED | FE_WIFI_LED } +static struct key_entry keymap_acer_aspire_1500[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_WIFI, 0x30, 0 }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_BLUETOOTH, 0x44, 0 }, + { KE_END, 0 } }; -static struct key_entry keymap_acer_travelmate_630[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */ - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x20, {KEY_VOLUMEUP} }, - { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_WIFI, 0x30 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } +static struct key_entry keymap_acer_travelmate_240[] = { + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_BLUETOOTH, 0x44, 0 }, + { KE_WIFI, 0x30, 0 }, + { KE_END, 0 } }; -static struct key_entry keymap_aopen_1559as[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x06, {KEY_PROG3} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_WIFI, 0x30 }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, +static struct key_entry keymap_aopen_1559as[] = { + { KE_KEY, 0x01, KEY_HELP }, + { KE_KEY, 0x06, KEY_PROG3 }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_WIFI, 0x30, 0 }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, { KE_END, 0 }, }; -static struct key_entry keymap_fs_amilo_d88x0[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_wistron_md2900[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_WIFI, 0x30 }, - { KE_END, FE_MAIL_LED | FE_UNTESTED } -}; - -static struct key_entry keymap_wistron_md96500[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ - { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x20, {KEY_VOLUMEUP} }, - { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, - { KE_KEY, 0x22, {KEY_REWIND} }, - { KE_KEY, 0x23, {KEY_FORWARD} }, - { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, - { KE_KEY, 0x25, {KEY_STOPCD} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, - { KE_END, FE_UNTESTED } -}; - -static struct key_entry keymap_wistron_generic[] __initdata = { - { KE_KEY, 0x01, {KEY_HELP} }, - { KE_KEY, 0x02, {KEY_CONFIG} }, - { KE_KEY, 0x03, {KEY_POWER} }, - { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ - { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ - { KE_KEY, 0x08, {KEY_MUTE} }, - { KE_KEY, 0x11, {KEY_PROG1} }, - { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_KEY, 0x13, {KEY_PROG3} }, - { KE_KEY, 0x14, {KEY_MAIL} }, - { KE_KEY, 0x15, {KEY_WWW} }, - { KE_KEY, 0x20, {KEY_VOLUMEUP} }, - { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, - { KE_KEY, 0x22, {KEY_REWIND} }, - { KE_KEY, 0x23, {KEY_FORWARD} }, - { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, - { KE_KEY, 0x25, {KEY_STOPCD} }, - { KE_KEY, 0x31, {KEY_MAIL} }, - { KE_KEY, 0x36, {KEY_WWW} }, - { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ - { KE_KEY, 0x40, {KEY_WLAN} }, - { KE_KEY, 0x49, {KEY_CONFIG} }, - { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ - { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ - { KE_KEY, 0x6a, {KEY_CONFIG} }, - { KE_KEY, 0x6d, {KEY_POWER} }, - { KE_KEY, 0x71, {KEY_STOPCD} }, - { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, - { KE_KEY, 0x74, {KEY_REWIND} }, - { KE_KEY, 0x78, {KEY_FORWARD} }, - { KE_WIFI, 0x30 }, - { KE_BLUETOOTH, 0x44 }, +static struct key_entry keymap_fs_amilo_d88x0[] = { + { KE_KEY, 0x01, KEY_HELP }, + { KE_KEY, 0x08, KEY_MUTE }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x13, KEY_PROG3 }, { KE_END, 0 } }; @@ -646,133 +388,6 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_aspire_1500 }, - { - .callback = dmi_matched, - .ident = "Acer Aspire 1600", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), - }, - .driver_data = keymap_acer_aspire_1600 - }, - { - .callback = dmi_matched, - .ident = "Acer Aspire 3020", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), - }, - .driver_data = keymap_acer_aspire_5020 - }, - { - .callback = dmi_matched, - .ident = "Acer Aspire 5020", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), - }, - .driver_data = keymap_acer_aspire_5020 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 2100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), - }, - .driver_data = keymap_acer_aspire_5020 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 2410", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), - }, - .driver_data = keymap_acer_travelmate_2410 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate C300", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), - }, - .driver_data = keymap_acer_travelmate_300 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate C100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), - }, - .driver_data = keymap_acer_travelmate_300 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate C110", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), - }, - .driver_data = keymap_acer_travelmate_110 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 380", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), - }, - .driver_data = keymap_acer_travelmate_380 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 370", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), - }, - .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 220", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), - }, - .driver_data = keymap_acer_travelmate_220 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 260", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), - }, - .driver_data = keymap_acer_travelmate_220 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 230", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), - /* acerhk looks for "TravelMate F4..." ?! */ - }, - .driver_data = keymap_acer_travelmate_230 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 280", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), - }, - .driver_data = keymap_acer_travelmate_230 - }, { .callback = dmi_matched, .ident = "Acer TravelMate 240", @@ -782,15 +397,6 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_travelmate_240 }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 250", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), - }, - .driver_data = keymap_acer_travelmate_240 - }, { .callback = dmi_matched, .ident = "Acer TravelMate 2424NWXCi", @@ -800,51 +406,6 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_acer_travelmate_240 }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 350", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), - }, - .driver_data = keymap_acer_travelmate_350 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), - }, - .driver_data = keymap_acer_travelmate_360 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 610", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ACER"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), - }, - .driver_data = keymap_acer_travelmate_610 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 620", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), - }, - .driver_data = keymap_acer_travelmate_630 - }, - { - .callback = dmi_matched, - .ident = "Acer TravelMate 630", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), - }, - .driver_data = keymap_acer_travelmate_630 - }, { .callback = dmi_matched, .ident = "AOpen 1559AS", @@ -863,51 +424,6 @@ static struct dmi_system_id dmi_ids[] __initdata = { }, .driver_data = keymap_wistron_ms2111 }, - { - .callback = dmi_matched, - .ident = "Medion MD 40100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), - DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), - }, - .driver_data = keymap_wistron_md40100 - }, - { - .callback = dmi_matched, - .ident = "Medion MD 2900", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), - DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), - }, - .driver_data = keymap_wistron_md2900 - }, - { - .callback = dmi_matched, - .ident = "Medion MD 96500", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), - DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), - }, - .driver_data = keymap_wistron_md96500 - }, - { - .callback = dmi_matched, - .ident = "Medion MD 95400", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), - DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), - }, - .driver_data = keymap_wistron_md96500 - }, - { - .callback = dmi_matched, - .ident = "Fujitsu Siemens Amilo D7820", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ - DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), - }, - .driver_data = keymap_fs_amilo_d88x0 - }, { .callback = dmi_matched, .ident = "Fujitsu Siemens Amilo D88x0", @@ -920,39 +436,17 @@ static struct dmi_system_id dmi_ids[] __initdata = { { NULL, } }; -/* Copy the good keymap, as the original ones are free'd */ -static int __init copy_keymap(void) -{ - const struct key_entry *key; - struct key_entry *new_keymap; - unsigned int length = 1; - - for (key = keymap; key->type != KE_END; key++) - length++; - - new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); - if (!new_keymap) - return -ENOMEM; - - memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); - keymap = new_keymap; - - return 0; -} - static int __init select_keymap(void) { - dmi_check_system(dmi_ids); if (keymap_name != NULL) { if (strcmp (keymap_name, "1557/MS2141") == 0) keymap = keymap_wistron_ms2141; - else if (strcmp (keymap_name, "generic") == 0) - keymap = keymap_wistron_generic; else { printk(KERN_ERR "wistron_btns: Keymap unknown\n"); return -EINVAL; } } + dmi_check_system(dmi_ids); if (keymap == NULL) { if (!force) { printk(KERN_ERR "wistron_btns: System unknown\n"); @@ -960,8 +454,7 @@ static int __init select_keymap(void) } keymap = keymap_empty; } - - return copy_keymap(); + return 0; } /* Input layer interface */ @@ -983,28 +476,12 @@ static int __devinit setup_input_dev(void) input_dev->cdev.dev = &wistron_device->dev; for (key = keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, input_dev->evbit); - set_bit(key->keycode, input_dev->keybit); - break; - - case KE_SW: - set_bit(EV_SW, input_dev->evbit); - set_bit(key->sw.code, input_dev->swbit); - break; - - default: - ; + if (key->type == KE_KEY) { + input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY); + set_bit(key->keycode, input_dev->keybit); } } - /* reads information flags on KE_END */ - if (key->code & FE_UNTESTED) - printk(KERN_WARNING "Untested laptop multimedia keys, " - "please report success or failure to eric.piel" - "@tremplin-utc.net\n"); - error = input_register_device(input_dev); if (error) { input_free_device(input_dev); @@ -1022,12 +499,6 @@ static void report_key(unsigned keycode) input_sync(input_dev); } -static void report_switch(unsigned code, int value) -{ - input_report_switch(input_dev, code, value); - input_sync(input_dev); -} - /* Driver core */ static int wifi_enabled; @@ -1048,10 +519,6 @@ static void handle_key(u8 code) report_key(key->keycode); break; - case KE_SW: - report_switch(key->sw.code, key->sw.value); - break; - case KE_WIFI: if (have_wifi) { wifi_enabled = !wifi_enabled; @@ -1067,7 +534,6 @@ static void handle_key(u8 code) break; case KE_END: - break; default: BUG(); } @@ -1224,7 +690,6 @@ static void __exit wb_module_exit(void) platform_device_unregister(wistron_device); platform_driver_unregister(&wistron_driver); unmap_bios(); - kfree(keymap); } module_init(wb_module_init); diff --git a/trunk/drivers/input/mouse/Kconfig b/trunk/drivers/input/mouse/Kconfig index 81dd8c7211a7..35d998c3e578 100644 --- a/trunk/drivers/input/mouse/Kconfig +++ b/trunk/drivers/input/mouse/Kconfig @@ -37,65 +37,6 @@ config MOUSE_PS2 To compile this driver as a module, choose M here: the module will be called psmouse. -config MOUSE_PS2_ALPS - bool "ALPS PS/2 mouse protocol extension" if EMBEDDED - default y - depends on MOUSE_PS2 - ---help--- - Say Y here if you have an ALPS PS/2 touchpad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_LOGIPS2PP - bool "Logictech PS/2++ mouse protocol extension" if EMBEDDED - default y - depends on MOUSE_PS2 - ---help--- - Say Y here if you have a Logictech PS/2++ mouse connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_SYNAPTICS - bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED - default y - depends on MOUSE_PS2 - ---help--- - Say Y here if you have a Synaptics PS/2 TouchPad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_LIFEBOOK - bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED - default y - depends on MOUSE_PS2 - ---help--- - Say Y here if you have a Fujitsu B-series Lifebook PS/2 - TouchScreen connected to your system. - - If unsure, say Y. - -config MOUSE_PS2_TRACKPOINT - bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED - default y - depends on MOUSE_PS2 - ---help--- - Say Y here if you have an IBM Trackpoint PS/2 mouse connected - to your system. - - If unsure, say Y. - -config MOUSE_PS2_TOUCHKIT - bool "eGalax TouchKit PS/2 protocol extension" - depends on MOUSE_PS2 - ---help--- - Say Y here if you have an eGalax TouchKit PS/2 touchscreen - connected to your system. - - If unsure, say N. - config MOUSE_SERIAL tristate "Serial mouse" select SERIO @@ -155,17 +96,6 @@ config MOUSE_AMIGA To compile this driver as a module, choose M here: the module will be called amimouse. -config MOUSE_ATARI - tristate "Atari mouse" - depends on ATARI - select ATARI_KBD_CORE - help - Say Y here if you have an Atari and want its native mouse - supported by the kernel. - - To compile this driver as a module, choose M here: the - module will be called atarimouse. - config MOUSE_RISCPC tristate "Acorn RiscPC mouse" depends on ARCH_ACORN @@ -188,7 +118,7 @@ config MOUSE_VSXXXAA digitizer (VSXXX-AB) DEC produced. config MOUSE_HIL - tristate "HIL pointers (mice etc)." + tristate "HIL pointers (mice etc)." depends on GSC || HP300 select HP_SDC select HIL_MLC diff --git a/trunk/drivers/input/mouse/Makefile b/trunk/drivers/input/mouse/Makefile index 6a8f622927f2..21a1de61a79b 100644 --- a/trunk/drivers/input/mouse/Makefile +++ b/trunk/drivers/input/mouse/Makefile @@ -5,7 +5,6 @@ # Each configuration option enables a list of files. obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o -obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o @@ -15,10 +14,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o synaptics.o - -psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o -psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o -psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o -psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o -psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o +psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o diff --git a/trunk/drivers/input/mouse/alps.c b/trunk/drivers/input/mouse/alps.c index cf3e4664e72b..4e71a66fc7fc 100644 --- a/trunk/drivers/input/mouse/alps.c +++ b/trunk/drivers/input/mouse/alps.c @@ -424,15 +424,14 @@ int alps_init(struct psmouse *psmouse) struct input_dev *dev1 = psmouse->dev, *dev2; int version; - priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); + psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); dev2 = input_allocate_device(); if (!priv || !dev2) goto init_fail; priv->dev2 = dev2; - priv->i = alps_get_model(psmouse, &version); - if (!priv->i) + if (!(priv->i = alps_get_model(psmouse, &version))) goto init_fail; if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) @@ -481,8 +480,7 @@ int alps_init(struct psmouse *psmouse) dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - if (input_register_device(priv->dev2)) - goto init_fail; + input_register_device(priv->dev2); psmouse->protocol_handler = alps_process_byte; psmouse->poll = alps_poll; @@ -493,11 +491,9 @@ int alps_init(struct psmouse *psmouse) /* We are having trouble resyncing ALPS touchpads so disable it for now */ psmouse->resync_time = 0; - psmouse->private = priv; return 0; init_fail: - psmouse_reset(psmouse); input_free_device(dev2); kfree(priv); return -1; @@ -508,8 +504,7 @@ int alps_detect(struct psmouse *psmouse, int set_properties) int version; const struct alps_model_info *model; - model = alps_get_model(psmouse, &version); - if (!model) + if (!(model = alps_get_model(psmouse, &version))) return -1; if (set_properties) { diff --git a/trunk/drivers/input/mouse/alps.h b/trunk/drivers/input/mouse/alps.h index 4bbddc99962b..69db7325a494 100644 --- a/trunk/drivers/input/mouse/alps.h +++ b/trunk/drivers/input/mouse/alps.h @@ -12,6 +12,9 @@ #ifndef _ALPS_H #define _ALPS_H +int alps_detect(struct psmouse *psmouse, int set_properties); +int alps_init(struct psmouse *psmouse); + struct alps_model_info { unsigned char signature[3]; unsigned char byte0, mask0; @@ -20,23 +23,10 @@ struct alps_model_info { struct alps_data { struct input_dev *dev2; /* Relative device */ + char name[32]; /* Name */ char phys[32]; /* Phys */ const struct alps_model_info *i;/* Info */ int prev_fin; /* Finger bit from previous packet */ }; -#ifdef CONFIG_MOUSE_PS2_ALPS -int alps_detect(struct psmouse *psmouse, int set_properties); -int alps_init(struct psmouse *psmouse); -#else -inline int alps_detect(struct psmouse *psmouse, int set_properties) -{ - return -ENOSYS; -} -inline int alps_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_ALPS */ - #endif diff --git a/trunk/drivers/input/mouse/atarimouse.c b/trunk/drivers/input/mouse/atarimouse.c deleted file mode 100644 index 43ab6566fb65..000000000000 --- a/trunk/drivers/input/mouse/atarimouse.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Atari mouse driver for Linux/m68k - * - * Copyright (c) 2005 Michael Schmitz - * - * Based on: - * Amiga mouse driver for Linux/m68k - * - * Copyright (c) 2000-2002 Vojtech Pavlik - * - */ -/* - * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c - * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard - * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). - * This driver only deals with handing key events off to the input layer. - * - * Largely based on the old: - * - * Atari Mouse Driver for Linux - * by Robert de Vries (robert@and.nl) 19Jul93 - * - * 16 Nov 1994 Andreas Schwab - * Compatibility with busmouse - * Support for three button mouse (shamelessly stolen from MiNT) - * third button wired to one of the joystick directions on joystick 1 - * - * 1996/02/11 Andreas Schwab - * Module support - * Allow multiple open's - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Michael Schmitz "); -MODULE_DESCRIPTION("Atari mouse driver"); -MODULE_LICENSE("GPL"); - -static int mouse_threshold[2] = {2,2}; - -#ifdef __MODULE__ -MODULE_PARM(mouse_threshold, "2i"); -#endif -#ifdef FIXED_ATARI_JOYSTICK -extern int atari_mouse_buttons; -#endif -static int atamouse_used = 0; - -static struct input_dev *atamouse_dev; - -static void atamouse_interrupt(char *buf) -{ - int buttons, dx, dy; - -/* ikbd_mouse_disable(); */ - - buttons = (buf[0] & 1) | ((buf[0] & 2) << 1); -#ifdef FIXED_ATARI_JOYSTICK - buttons |= atari_mouse_buttons & 2; - atari_mouse_buttons = buttons; -#endif -/* ikbd_mouse_rel_pos(); */ - - /* only relative events get here */ - dx = buf[1]; - dy = -buf[2]; - - input_report_rel(atamouse_dev, REL_X, dx); - input_report_rel(atamouse_dev, REL_Y, dy); - - input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1); - input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); - input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4); - - input_sync(atamouse_dev); - - return; -} - -static int atamouse_open(struct input_dev *dev) -{ - if (atamouse_used++) - return 0; - -#ifdef FIXED_ATARI_JOYSTICK - atari_mouse_buttons = 0; -#endif - ikbd_mouse_y0_top(); - ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]); - ikbd_mouse_rel_pos(); - atari_input_mouse_interrupt_hook = atamouse_interrupt; - return 0; -} - -static void atamouse_close(struct input_dev *dev) -{ - if (!--atamouse_used) { - ikbd_mouse_disable(); - atari_mouse_interrupt_hook = NULL; - } -} - -static int __init atamouse_init(void) -{ - if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) - return -ENODEV; - - if (!(atamouse_dev = input_allocate_device())) - return -ENOMEM; - - if (!(atari_keyb_init())) - return -ENODEV; - - atamouse_dev->name = "Atari mouse"; - atamouse_dev->phys = "atamouse/input0"; - atamouse_dev->id.bustype = BUS_ATARI; - atamouse_dev->id.vendor = 0x0001; - atamouse_dev->id.product = 0x0002; - atamouse_dev->id.version = 0x0100; - - atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); - atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - atamouse_dev->open = atamouse_open; - atamouse_dev->close = atamouse_close; - - input_register_device(atamouse_dev); - - printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name); - return 0; -} - -static void __exit atamouse_exit(void) -{ - input_unregister_device(atamouse_dev); -} - -module_init(atamouse_init); -module_exit(atamouse_exit); diff --git a/trunk/drivers/input/mouse/hil_ptr.c b/trunk/drivers/input/mouse/hil_ptr.c index 449bf4dcbbcc..bfb174fe3230 100644 --- a/trunk/drivers/input/mouse/hil_ptr.c +++ b/trunk/drivers/input/mouse/hil_ptr.c @@ -88,12 +88,10 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) idx = ptr->idx4/4; p = data[idx - 1]; - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; + if ((p & ~HIL_CMDCT_POL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; + if ((p & ~HIL_CMDCT_RPL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; /* Not a poll response. See if we are loading config records. */ switch (p & HIL_PKT_DATA_MASK) { @@ -103,32 +101,27 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) for (; i < HIL_PTR_MAX_LENGTH; i++) ptr->idd[i] = 0; break; - case HIL_CMD_RSC: for (i = 0; i < idx; i++) ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_PTR_MAX_LENGTH; i++) ptr->rsc[i] = 0; break; - case HIL_CMD_EXD: for (i = 0; i < idx; i++) ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_PTR_MAX_LENGTH; i++) ptr->exd[i] = 0; break; - case HIL_CMD_RNM: for (i = 0; i < idx; i++) ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK; for (; i < HIL_PTR_MAX_LENGTH + 1; i++) - ptr->rnm[i] = 0; + ptr->rnm[i] = '\0'; break; - default: /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; + if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; /* Anything else we'd like to know about. */ printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); break; @@ -137,8 +130,7 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) report: if ((p & HIL_CMDCT_POL) != idx - 1) { - printk(KERN_WARNING PREFIX - "Malformed poll packet %x (idx = %i)\n", p, idx); + printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx); goto out; } @@ -147,7 +139,7 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) laxis += i; ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ - absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; + absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; for (cnt = 1; i < laxis; i++) { unsigned int lo,hi,val; @@ -165,8 +157,7 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) input_report_abs(dev, ABS_X + i, val); } else { val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); - if (i%3) - val *= -1; + if (i%3) val *= -1; input_report_rel(dev, REL_X + i, val); } } @@ -177,11 +168,10 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) btn = ptr->data[cnt++]; up = btn & 1; btn &= 0xfe; - if (btn == 0x8e) + if (btn == 0x8e) { continue; /* TODO: proximity == touch? */ - else - if ((btn > 0x8c) || (btn < 0x80)) - continue; + } + else if ((btn > 0x8c) || (btn < 0x80)) continue; btn = (btn - 0x80) >> 1; btn = ptr->btnmap[btn]; input_report_key(dev, btn, !up); @@ -192,14 +182,14 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) up(&ptr->sem); } -static void hil_ptr_process_err(struct hil_ptr *ptr) -{ +static void hil_ptr_process_err(struct hil_ptr *ptr) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); ptr->idx4 = 0; up(&ptr->sem); + return; } -static irqreturn_t hil_ptr_interrupt(struct serio *serio, +static irqreturn_t hil_ptr_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct hil_ptr *ptr; @@ -207,29 +197,29 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio, int idx; ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); + if (ptr == NULL) { + BUG(); + return IRQ_HANDLED; + } if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) { hil_ptr_process_err(ptr); return IRQ_HANDLED; } idx = ptr->idx4/4; - if (!(ptr->idx4 % 4)) - ptr->data[idx] = 0; + if (!(ptr->idx4 % 4)) ptr->data[idx] = 0; packet = ptr->data[idx]; packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8); ptr->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(ptr->idx4)) % 4) - return IRQ_HANDLED; + if ((++(ptr->idx4)) % 4) return IRQ_HANDLED; if ((packet & 0xffff0000) != HIL_ERR_INT) { hil_ptr_process_err(ptr); return IRQ_HANDLED; } - if (packet & HIL_PKT_CMD) + if (packet & HIL_PKT_CMD) hil_ptr_process_record(ptr); - return IRQ_HANDLED; } @@ -238,7 +228,10 @@ static void hil_ptr_disconnect(struct serio *serio) struct hil_ptr *ptr; ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); + if (ptr == NULL) { + BUG(); + return; + } serio_close(serio); input_unregister_device(ptr->dev); @@ -248,7 +241,7 @@ static void hil_ptr_disconnect(struct serio *serio) static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) { struct hil_ptr *ptr; - const char *txt; + char *txt; unsigned int i, naxsets, btntype; uint8_t did, *idd; @@ -259,40 +252,42 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) if (!ptr->dev) goto bail0; + ptr->dev->private = ptr; + if (serio_open(serio, driver)) goto bail1; serio_set_drvdata(serio, ptr); ptr->serio = serio; - init_MUTEX_LOCKED(&ptr->sem); + init_MUTEX_LOCKED(&(ptr->sem)); /* Get device info. MLC driver supplies devid/status/etc. */ serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_IDD); - down(&ptr->sem); + down(&(ptr->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_RSC); - down(&ptr->sem); + down(&(ptr->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_RNM); - down(&ptr->sem); + down(&(ptr->sem)); serio->write(serio, 0); serio->write(serio, 0); serio->write(serio, HIL_PKT_CMD >> 8); serio->write(serio, HIL_CMD_EXD); - down(&ptr->sem); + down(&(ptr->sem)); - up(&ptr->sem); + up(&(ptr->sem)); did = ptr->idd[0]; idd = ptr->idd + 1; @@ -306,12 +301,12 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ptr->dev->evbit[0] = BIT(EV_ABS); txt = "absolute"; } - if (!ptr->dev->evbit[0]) + if (!ptr->dev->evbit[0]) { goto bail2; + } ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); - if (ptr->nbtn) - ptr->dev->evbit[0] |= BIT(EV_KEY); + if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY); naxsets = HIL_IDD_NUM_AXSETS(*idd); ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); @@ -320,7 +315,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) did, txt); printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", ptr->nbtn, naxsets, ptr->naxes); - + btntype = BTN_MISC; if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) #ifdef TABLET_SIMULATES_MOUSE @@ -330,7 +325,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) #endif if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) btntype = BTN_TOUCH; - + if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) btntype = BTN_MOUSE; @@ -346,10 +341,12 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) } if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - for (i = 0; i < ptr->naxes; i++) + for (i = 0; i < ptr->naxes; i++) { set_bit(REL_X + i, ptr->dev->relbit); - for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) + } + for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { set_bit(REL_X + i, ptr->dev->relbit); + } } else { for (i = 0; i < ptr->naxes; i++) { set_bit(ABS_X + i, ptr->dev->absbit); @@ -378,7 +375,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) ptr->dev->id.vendor = PCI_VENDOR_ID_HP; ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */ ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ - ptr->dev->dev.parent = &serio->dev; + ptr->dev->cdev.dev = &serio->dev; input_register_device(ptr->dev); printk(KERN_INFO "input: %s (%s), ID: %d\n", @@ -422,11 +419,11 @@ static int __init hil_ptr_init(void) { return serio_register_driver(&hil_ptr_serio_driver); } - + static void __exit hil_ptr_exit(void) { serio_unregister_driver(&hil_ptr_serio_driver); } - + module_init(hil_ptr_init); module_exit(hil_ptr_exit); diff --git a/trunk/drivers/input/mouse/lifebook.c b/trunk/drivers/input/mouse/lifebook.c index 1740cadd9594..29542f0631cb 100644 --- a/trunk/drivers/input/mouse/lifebook.c +++ b/trunk/drivers/input/mouse/lifebook.c @@ -20,27 +20,6 @@ #include "psmouse.h" #include "lifebook.h" -struct lifebook_data { - struct input_dev *dev2; /* Relative device */ - char phys[32]; -}; - -static const char *desired_serio_phys; - -static int lifebook_set_serio_phys(struct dmi_system_id *d) -{ - desired_serio_phys = d->driver_data; - return 0; -} - -static unsigned char lifebook_use_6byte_proto; - -static int lifebook_set_6byte_proto(struct dmi_system_id *d) -{ - lifebook_use_6byte_proto = 1; - return 0; -} - static struct dmi_system_id lifebook_dmi_table[] = { { .ident = "FLORA-ie 55mi", @@ -77,24 +56,6 @@ static struct dmi_system_id lifebook_dmi_table[] = { .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), }, - .callback = lifebook_set_serio_phys, - .driver_data = "isa0060/serio3", - }, - { - .ident = "Panasonic CF-28", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), - DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), - }, - .callback = lifebook_set_6byte_proto, - }, - { - .ident = "Panasonic CF-29", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), - DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), - }, - .callback = lifebook_set_6byte_proto, }, { .ident = "Lifebook B142", @@ -107,71 +68,31 @@ static struct dmi_system_id lifebook_dmi_table[] = { static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) { - struct lifebook_data *priv = psmouse->private; - struct input_dev *dev1 = psmouse->dev; - struct input_dev *dev2 = priv->dev2; unsigned char *packet = psmouse->packet; - int relative_packet = packet[0] & 0x08; + struct input_dev *dev = psmouse->dev; - if (relative_packet || !lifebook_use_6byte_proto) { - if (psmouse->pktcnt != 3) - return PSMOUSE_GOOD_DATA; - } else { - switch (psmouse->pktcnt) { - case 1: - return (packet[0] & 0xf8) == 0x00 ? - PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; - case 2: - return PSMOUSE_GOOD_DATA; - case 3: - return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ? - PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; - case 4: - return (packet[3] & 0xf8) == 0xc0 ? - PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; - case 5: - return (packet[4] & 0xc0) == (packet[2] & 0xc0) ? - PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; - case 6: - if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0)) - return PSMOUSE_BAD_DATA; - if ((packet[5] & 0xc0) != (packet[1] & 0xc0)) - return PSMOUSE_BAD_DATA; - break; /* report data */ - } - } + if (psmouse->pktcnt != 3) + return PSMOUSE_GOOD_DATA; - if (relative_packet) { - if (!dev2) - printk(KERN_WARNING "lifebook.c: got relative packet " - "but no relative device set up\n"); - } else if (lifebook_use_6byte_proto) { - input_report_abs(dev1, ABS_X, - ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); - input_report_abs(dev1, ABS_Y, - 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); - } else { - input_report_abs(dev1, ABS_X, + /* calculate X and Y */ + if ((packet[0] & 0x08) == 0x00) { + input_report_abs(dev, ABS_X, (packet[1] | ((packet[0] & 0x30) << 4))); - input_report_abs(dev1, ABS_Y, + input_report_abs(dev, ABS_Y, 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); - } - - input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); - input_sync(dev1); - - if (dev2) { - if (relative_packet) { - input_report_rel(dev2, REL_X, + } else { + input_report_rel(dev, REL_X, ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); - input_report_rel(dev2, REL_Y, + input_report_rel(dev, REL_Y, -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); - } - input_report_key(dev2, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02); - input_sync(dev2); } + input_report_key(dev, BTN_LEFT, packet[0] & 0x01); + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + input_report_key(dev, BTN_TOUCH, packet[0] & 0x04); + + input_sync(dev); + return PSMOUSE_FULL_PACKET; } @@ -188,20 +109,12 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) you leave this call out the touchsreen will never send absolute coordinates */ - param = lifebook_use_6byte_proto ? 0x08 : 0x07; + param = 0x07; ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); return 0; } -static void lifebook_relative_mode(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param = 0x06; - - ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); -} - static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) { static const unsigned char params[] = { 0, 1, 2, 2, 3 }; @@ -218,8 +131,6 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu static void lifebook_disconnect(struct psmouse *psmouse) { psmouse_reset(psmouse); - kfree(psmouse->private); - psmouse->private = NULL; } int lifebook_detect(struct psmouse *psmouse, int set_properties) @@ -227,10 +138,6 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) if (!dmi_check_system(lifebook_dmi_table)) return -1; - if (desired_serio_phys && - strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys)) - return -1; - if (set_properties) { psmouse->vendor = "Fujitsu"; psmouse->name = "Lifebook TouchScreen"; @@ -239,78 +146,24 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) return 0; } -static int lifebook_create_relative_device(struct psmouse *psmouse) -{ - struct input_dev *dev2; - struct lifebook_data *priv; - int error = -ENOMEM; - - priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL); - dev2 = input_allocate_device(); - if (!priv || !dev2) - goto err_out; - - priv->dev2 = dev2; - snprintf(priv->phys, sizeof(priv->phys), - "%s/input1", psmouse->ps2dev.serio->phys); - - dev2->phys = priv->phys; - dev2->name = "PS/2 Touchpad"; - dev2->id.bustype = BUS_I8042; - dev2->id.vendor = 0x0002; - dev2->id.product = PSMOUSE_LIFEBOOK; - dev2->id.version = 0x0000; - dev2->dev.parent = &psmouse->ps2dev.serio->dev; - - dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y); - dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); - - error = input_register_device(priv->dev2); - if (error) - goto err_out; - - psmouse->private = priv; - return 0; - - err_out: - input_free_device(dev2); - kfree(priv); - return error; -} - int lifebook_init(struct psmouse *psmouse) { - struct input_dev *dev1 = psmouse->dev; - int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; + struct input_dev *input_dev = psmouse->dev; if (lifebook_absolute_mode(psmouse)) return -1; - dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - dev1->relbit[0] = 0; - dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); - input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); - - if (!desired_serio_phys) { - if (lifebook_create_relative_device(psmouse)) { - lifebook_relative_mode(psmouse); - return -1; - } - } + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); + input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0); psmouse->protocol_handler = lifebook_process_byte; psmouse->set_resolution = lifebook_set_resolution; psmouse->disconnect = lifebook_disconnect; psmouse->reconnect = lifebook_absolute_mode; - - psmouse->model = lifebook_use_6byte_proto ? 6 : 3; - - /* - * Use packet size = 3 even when using 6-byte protocol because - * that's what POLL will return on Lifebooks (according to spec). - */ psmouse->pktsize = 3; return 0; diff --git a/trunk/drivers/input/mouse/lifebook.h b/trunk/drivers/input/mouse/lifebook.h index c1647cf036c2..be1c0943825d 100644 --- a/trunk/drivers/input/mouse/lifebook.h +++ b/trunk/drivers/input/mouse/lifebook.h @@ -11,18 +11,7 @@ #ifndef _LIFEBOOK_H #define _LIFEBOOK_H -#ifdef CONFIG_MOUSE_PS2_LIFEBOOK int lifebook_detect(struct psmouse *psmouse, int set_properties); int lifebook_init(struct psmouse *psmouse); -#else -inline int lifebook_detect(struct psmouse *psmouse, int set_properties) -{ - return -ENOSYS; -} -inline int lifebook_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif #endif diff --git a/trunk/drivers/input/mouse/logips2pp.c b/trunk/drivers/input/mouse/logips2pp.c index 9df74b72e6c4..d3ddea26b8ca 100644 --- a/trunk/drivers/input/mouse/logips2pp.c +++ b/trunk/drivers/input/mouse/logips2pp.c @@ -200,7 +200,6 @@ static void ps2pp_disconnect(struct psmouse *psmouse) static const struct ps2pp_info *get_model_info(unsigned char model) { static const struct ps2pp_info ps2pp_list[] = { - { 1, 0, 0 }, /* Simple 2-button mouse */ { 12, 0, PS2PP_SIDE_BTN}, { 13, 0, 0 }, { 15, PS2PP_KIND_MX, /* MX1000 */ @@ -339,12 +338,12 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) param[1] = 0; ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); + if (!param[1]) + return -1; + model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); buttons = param[1]; - if (!model || !buttons) - return -1; - if ((model_info = get_model_info(model)) != NULL) { /* diff --git a/trunk/drivers/input/mouse/logips2pp.h b/trunk/drivers/input/mouse/logips2pp.h index 6e5712525fd6..64a8ec52ea6d 100644 --- a/trunk/drivers/input/mouse/logips2pp.h +++ b/trunk/drivers/input/mouse/logips2pp.h @@ -11,13 +11,6 @@ #ifndef _LOGIPS2PP_H #define _LOGIPS2PP_H -#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP int ps2pp_init(struct psmouse *psmouse, int set_properties); -#else -inline int ps2pp_init(struct psmouse *psmouse, int set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */ #endif diff --git a/trunk/drivers/input/mouse/psmouse-base.c b/trunk/drivers/input/mouse/psmouse-base.c index f15f695777f8..0fe5869d7d4c 100644 --- a/trunk/drivers/input/mouse/psmouse-base.c +++ b/trunk/drivers/input/mouse/psmouse-base.c @@ -28,7 +28,6 @@ #include "alps.h" #include "lifebook.h" #include "trackpoint.h" -#include "touchkit_ps2.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -570,9 +569,7 @@ static int psmouse_extensions(struct psmouse *psmouse, return PSMOUSE_THINKPS; /* - * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol - * support is disabled in config - we need to know if it is synaptics so we - * can reset it properly after probing for intellimouse. + * Try Synaptics TouchPad */ if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) { synaptics_hardware = 1; @@ -608,20 +605,14 @@ static int psmouse_extensions(struct psmouse *psmouse, } } - if (max_proto > PSMOUSE_IMEX) { - - if (genius_detect(psmouse, set_properties) == 0) - return PSMOUSE_GENPS; + if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0) + return PSMOUSE_GENPS; - if (ps2pp_init(psmouse, set_properties) == 0) - return PSMOUSE_PS2PP; + if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0) + return PSMOUSE_PS2PP; - if (trackpoint_detect(psmouse, set_properties) == 0) - return PSMOUSE_TRACKPOINT; - - if (touchkit_ps2_detect(psmouse, set_properties) == 0) - return PSMOUSE_TOUCHKIT_PS2; - } + if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0) + return PSMOUSE_TRACKPOINT; /* * Reset to defaults in case the device got confused by extended @@ -663,14 +654,12 @@ static const struct psmouse_protocol psmouse_protocols[] = { .maxproto = 1, .detect = ps2bare_detect, }, -#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP { .type = PSMOUSE_PS2PP, .name = "PS2++", .alias = "logitech", .detect = ps2pp_init, }, -#endif { .type = PSMOUSE_THINKPS, .name = "ThinkPS/2", @@ -697,7 +686,6 @@ static const struct psmouse_protocol psmouse_protocols[] = { .maxproto = 1, .detect = im_explorer_detect, }, -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS { .type = PSMOUSE_SYNAPTICS, .name = "SynPS/2", @@ -705,8 +693,6 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = synaptics_detect, .init = synaptics_init, }, -#endif -#ifdef CONFIG_MOUSE_PS2_ALPS { .type = PSMOUSE_ALPS, .name = "AlpsPS/2", @@ -714,31 +700,18 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = alps_detect, .init = alps_init, }, -#endif -#ifdef CONFIG_MOUSE_PS2_LIFEBOOK { .type = PSMOUSE_LIFEBOOK, .name = "LBPS/2", .alias = "lifebook", .init = lifebook_init, }, -#endif -#ifdef CONFIG_MOUSE_PS2_TRACKPOINT { .type = PSMOUSE_TRACKPOINT, .name = "TPPS/2", .alias = "trackpoint", .detect = trackpoint_detect, }, -#endif -#ifdef CONFIG_MOUSE_PS2_TOUCHKIT - { - .type = PSMOUSE_TOUCHKIT_PS2, - .name = "touchkitPS/2", - .alias = "touchkit", - .detect = touchkit_ps2_detect, - }, -#endif { .type = PSMOUSE_AUTO, .name = "auto", @@ -849,6 +822,12 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) static void psmouse_initialize(struct psmouse *psmouse) { +/* + * We set the mouse into streaming mode. + */ + + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM); + /* * We set the mouse report rate, resolution and scaling. */ @@ -1083,7 +1062,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse { struct input_dev *input_dev = psmouse->dev; - input_dev->dev.parent = &psmouse->ps2dev.serio->dev; + input_dev->private = psmouse; + input_dev->cdev.dev = &psmouse->ps2dev.serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); diff --git a/trunk/drivers/input/mouse/psmouse.h b/trunk/drivers/input/mouse/psmouse.h index 3964e8acbc54..cf1de95b6f27 100644 --- a/trunk/drivers/input/mouse/psmouse.h +++ b/trunk/drivers/input/mouse/psmouse.h @@ -87,7 +87,6 @@ enum psmouse_type { PSMOUSE_ALPS, PSMOUSE_LIFEBOOK, PSMOUSE_TRACKPOINT, - PSMOUSE_TOUCHKIT_PS2, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/trunk/drivers/input/mouse/sermouse.c b/trunk/drivers/input/mouse/sermouse.c index 77b8ee2b9651..a85d74710b44 100644 --- a/trunk/drivers/input/mouse/sermouse.c +++ b/trunk/drivers/input/mouse/sermouse.c @@ -69,8 +69,7 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data) switch (sermouse->count) { case 0: - if ((data & 0xf8) != 0x80) - return; + if ((data & 0xf8) != 0x80) return; input_report_key(dev, BTN_LEFT, !(data & 4)); input_report_key(dev, BTN_RIGHT, !(data & 1)); input_report_key(dev, BTN_MIDDLE, !(data & 2)); @@ -108,10 +107,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data) struct input_dev *dev = sermouse->dev; signed char *buf = sermouse->buf; - if (data & 0x40) - sermouse->count = 0; - else if (sermouse->count == 0) - return; + if (data & 0x40) sermouse->count = 0; switch (sermouse->count) { @@ -173,8 +169,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data) case 5: case 7: /* Ignore anything besides MZ++ */ - if (sermouse->type != SERIO_MZPP) - break; + if (sermouse->type != SERIO_MZPP) break; switch (buf[1]) { @@ -211,16 +206,13 @@ static irqreturn_t sermouse_interrupt(struct serio *serio, { struct sermouse *sermouse = serio_get_drvdata(serio); - if (time_after(jiffies, sermouse->last + HZ/10)) - sermouse->count = 0; - + if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0; sermouse->last = jiffies; if (sermouse->type > SERIO_SUN) sermouse_process_ms(sermouse, data); else sermouse_process_msc(sermouse, data); - return IRQ_HANDLED; } @@ -266,11 +258,12 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = sermouse->type; input_dev->id.product = c; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->private = sermouse; if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit); if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit); diff --git a/trunk/drivers/input/mouse/synaptics.c b/trunk/drivers/input/mouse/synaptics.c index c77788bf932d..f0f9413d762c 100644 --- a/trunk/drivers/input/mouse/synaptics.c +++ b/trunk/drivers/input/mouse/synaptics.c @@ -40,70 +40,33 @@ #define YMIN_NOMINAL 1408 #define YMAX_NOMINAL 4448 - /***************************************************************************** - * Stuff we need even when we do not want native Synaptics support + * Synaptics communications functions ****************************************************************************/ /* - * Set the synaptics touchpad mode byte by special commands + * Send a command to the synpatics touchpad by special commands */ -static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) +static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) { - unsigned char param[1]; - - if (psmouse_sliced_command(psmouse, mode)) + if (psmouse_sliced_command(psmouse, c)) return -1; - param[0] = SYN_PS_SET_MODE2; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) return -1; return 0; } -int synaptics_detect(struct psmouse *psmouse, int set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - param[0] = 0; - - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); - - if (param[1] != 0x47) - return -ENODEV; - - if (set_properties) { - psmouse->vendor = "Synaptics"; - psmouse->name = "TouchPad"; - } - - return 0; -} - -void synaptics_reset(struct psmouse *psmouse) -{ - /* reset touchpad back to relative mode, gestures enabled */ - synaptics_mode_cmd(psmouse, 0); -} - -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - -/***************************************************************************** - * Synaptics communications functions - ****************************************************************************/ - /* - * Send a command to the synpatics touchpad by special commands + * Set the synaptics touchpad mode byte by special commands */ -static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) +static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) { - if (psmouse_sliced_command(psmouse, c)) + unsigned char param[1]; + + if (psmouse_sliced_command(psmouse, mode)) return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) + param[0] = SYN_PS_SET_MODE2; + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) return -1; return 0; } @@ -566,6 +529,12 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) clear_bit(REL_Y, dev->relbit); } +void synaptics_reset(struct psmouse *psmouse) +{ + /* reset touchpad back to relative mode, gestures enabled */ + synaptics_mode_cmd(psmouse, 0); +} + static void synaptics_disconnect(struct psmouse *psmouse) { synaptics_reset(psmouse); @@ -600,6 +569,30 @@ static int synaptics_reconnect(struct psmouse *psmouse) return 0; } +int synaptics_detect(struct psmouse *psmouse, int set_properties) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[4]; + + param[0] = 0; + + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); + + if (param[1] != 0x47) + return -1; + + if (set_properties) { + psmouse->vendor = "Synaptics"; + psmouse->name = "TouchPad"; + } + + return 0; +} + #if defined(__i386__) #include static struct dmi_system_id toshiba_dmi_table[] = { @@ -655,16 +648,6 @@ int synaptics_init(struct psmouse *psmouse) set_input_params(psmouse->dev, priv); - /* - * Encode touchpad model so that it can be used to set - * input device->id.version and be visible to userspace. - * Because version is __u16 we have to drop something. - * Hardware info bits seem to be good candidates as they - * are documented to be for Synaptics corp. internal use. - */ - psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | - (priv->model_id & 0x000000ff); - psmouse->protocol_handler = synaptics_process_byte; psmouse->set_rate = synaptics_set_rate; psmouse->disconnect = synaptics_disconnect; @@ -697,12 +680,4 @@ int synaptics_init(struct psmouse *psmouse) return -1; } -#else /* CONFIG_MOUSE_PS2_SYNAPTICS */ - -int synaptics_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} - -#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ diff --git a/trunk/drivers/input/mouse/synaptics.h b/trunk/drivers/input/mouse/synaptics.h index 02aa4cf7bc77..68fff1dcd7de 100644 --- a/trunk/drivers/input/mouse/synaptics.h +++ b/trunk/drivers/input/mouse/synaptics.h @@ -9,6 +9,10 @@ #ifndef _SYNAPTICS_H #define _SYNAPTICS_H +extern int synaptics_detect(struct psmouse *psmouse, int set_properties); +extern int synaptics_init(struct psmouse *psmouse); +extern void synaptics_reset(struct psmouse *psmouse); + /* synaptics queries */ #define SYN_QUE_IDENTIFY 0x00 #define SYN_QUE_MODES 0x01 @@ -58,9 +62,9 @@ #define SYN_MODE_WMODE(m) ((m) & (1 << 0)) /* synaptics identify query bits */ -#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) -#define SYN_ID_MAJOR(i) ((i) & 0x0f) -#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) +#define SYN_ID_MAJOR(i) ((i) & 0x0f) +#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) #define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) /* synaptics special commands */ @@ -94,8 +98,8 @@ struct synaptics_hw_state { struct synaptics_data { /* Data read from the touchpad */ unsigned long int model_id; /* Model-ID */ - unsigned long int capabilities; /* Capabilities */ - unsigned long int ext_cap; /* Extended Capabilities */ + unsigned long int capabilities; /* Capabilities */ + unsigned long int ext_cap; /* Extended Capabilities */ unsigned long int identity; /* Identification */ unsigned char pkt_type; /* packet type - old, new, etc */ @@ -103,8 +107,4 @@ struct synaptics_data { int scroll; }; -int synaptics_detect(struct psmouse *psmouse, int set_properties); -int synaptics_init(struct psmouse *psmouse); -void synaptics_reset(struct psmouse *psmouse); - #endif /* _SYNAPTICS_H */ diff --git a/trunk/drivers/input/mouse/touchkit_ps2.c b/trunk/drivers/input/mouse/touchkit_ps2.c deleted file mode 100644 index 7b977fd23571..000000000000 --- a/trunk/drivers/input/mouse/touchkit_ps2.c +++ /dev/null @@ -1,100 +0,0 @@ -/* ---------------------------------------------------------------------------- - * touchkit_ps2.c -- Driver for eGalax TouchKit PS/2 Touchscreens - * - * Copyright (C) 2005 by Stefan Lucke - * Copyright (C) 2004 by Daniel Ritz - * Copyright (C) by Todd E. Johnson (mtouchusb.c) - * - * 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. - * - * Based upon touchkitusb.c - * - * Vendor documentation is available in support section of: - * http://www.egalax.com.tw/ - */ - -#include -#include - -#include -#include -#include - -#include "psmouse.h" -#include "touchkit_ps2.h" - -#define TOUCHKIT_MAX_XC 0x07ff -#define TOUCHKIT_MAX_YC 0x07ff - -#define TOUCHKIT_CMD 0x0a -#define TOUCHKIT_CMD_LENGTH 1 - -#define TOUCHKIT_CMD_ACTIVE 'A' -#define TOUCHKIT_CMD_FIRMWARE_VERSION 'D' -#define TOUCHKIT_CMD_CONTROLLER_TYPE 'E' - -#define TOUCHKIT_SEND_PARMS(s, r, c) ((s) << 12 | (r) << 8 | (c)) - -#define TOUCHKIT_GET_TOUCHED(packet) (((packet)[0]) & 0x01) -#define TOUCHKIT_GET_X(packet) (((packet)[1] << 7) | (packet)[2]) -#define TOUCHKIT_GET_Y(packet) (((packet)[3] << 7) | (packet)[4]) - -static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse) -{ - unsigned char *packet = psmouse->packet; - struct input_dev *dev = psmouse->dev; - - if (psmouse->pktcnt != 5) - return PSMOUSE_GOOD_DATA; - - input_report_abs(dev, ABS_X, TOUCHKIT_GET_X(packet)); - input_report_abs(dev, ABS_Y, TOUCHKIT_GET_Y(packet)); - input_report_key(dev, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(packet)); - input_sync(dev); - - return PSMOUSE_FULL_PACKET; -} - -int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties) -{ - struct input_dev *dev = psmouse->dev; - unsigned char param[3]; - int command; - - param[0] = TOUCHKIT_CMD_LENGTH; - param[1] = TOUCHKIT_CMD_ACTIVE; - command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD); - - if (ps2_command(&psmouse->ps2dev, param, command)) - return -ENODEV; - - if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 || - param[2] != TOUCHKIT_CMD_ACTIVE) - return -ENODEV; - - if (set_properties) { - dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - set_bit(BTN_TOUCH, dev->keybit); - input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0); - input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); - - psmouse->vendor = "eGalax"; - psmouse->name = "Touchscreen"; - psmouse->protocol_handler = touchkit_ps2_process_byte; - psmouse->pktsize = 5; - } - - return 0; -} diff --git a/trunk/drivers/input/mouse/touchkit_ps2.h b/trunk/drivers/input/mouse/touchkit_ps2.h deleted file mode 100644 index 61e9dfd8419f..000000000000 --- a/trunk/drivers/input/mouse/touchkit_ps2.h +++ /dev/null @@ -1,24 +0,0 @@ -/* ---------------------------------------------------------------------------- - * touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens - * - * Copyright (C) 2005 by Stefan Lucke - * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _TOUCHKIT_PS2_H -#define _TOUCHKIT_PS2_H - -#ifdef CONFIG_MOUSE_PS2_TOUCHKIT -int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties); -#else -inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */ - -#endif diff --git a/trunk/drivers/input/mouse/trackpoint.h b/trunk/drivers/input/mouse/trackpoint.h index c10a6e7d0101..050298b1a09d 100644 --- a/trunk/drivers/input/mouse/trackpoint.h +++ b/trunk/drivers/input/mouse/trackpoint.h @@ -142,13 +142,6 @@ struct trackpoint_data unsigned char ext_dev; }; -#ifdef CONFIG_MOUSE_PS2_TRACKPOINT -int trackpoint_detect(struct psmouse *psmouse, int set_properties); -#else -inline int trackpoint_detect(struct psmouse *psmouse, int set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */ +extern int trackpoint_detect(struct psmouse *psmouse, int set_properties); #endif /* _TRACKPOINT_H */ diff --git a/trunk/drivers/input/mouse/vsxxxaa.c b/trunk/drivers/input/mouse/vsxxxaa.c index 4a321576f345..c3d64fcc858d 100644 --- a/trunk/drivers/input/mouse/vsxxxaa.c +++ b/trunk/drivers/input/mouse/vsxxxaa.c @@ -508,7 +508,8 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) input_dev->name = mouse->name; input_dev->phys = mouse->phys; input_dev->id.bustype = BUS_RS232; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; + input_dev->private = mouse; set_bit (EV_KEY, input_dev->evbit); /* We have buttons */ set_bit (EV_REL, input_dev->evbit); diff --git a/trunk/drivers/input/mousedev.c b/trunk/drivers/input/mousedev.c index 7678e9876550..664bcc8116fc 100644 --- a/trunk/drivers/input/mousedev.c +++ b/trunk/drivers/input/mousedev.c @@ -63,12 +63,9 @@ struct mousedev { int minor; char name[16]; wait_queue_head_t wait; - struct list_head client_list; + struct list_head list; struct input_handle handle; - struct list_head mixdev_node; - int mixdev_open; - struct mousedev_hw_data packet; unsigned int pkt_count; int old_x[4], old_y[4]; @@ -88,7 +85,7 @@ struct mousedev_motion { }; #define PACKET_QUEUE_LEN 16 -struct mousedev_client { +struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; @@ -114,7 +111,6 @@ static struct input_handler mousedev_handler; static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev mousedev_mix; -static LIST_HEAD(mousedev_mix_list); #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) @@ -124,33 +120,32 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous int size, tmp; enum { FRACTION_DENOM = 128 }; - switch (code) { - case ABS_X: - fx(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) - size = 256 * 2; - tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; - tmp += mousedev->frac_dx; - mousedev->packet.dx = tmp / FRACTION_DENOM; - mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; - } - break; + if (mousedev->touch) { + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + if (size == 0) + size = 256 * 2; + + switch (code) { + case ABS_X: + fx(0) = value; + if (mousedev->pkt_count >= 2) { + tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; + tmp += mousedev->frac_dx; + mousedev->packet.dx = tmp / FRACTION_DENOM; + mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; + } + break; - case ABS_Y: - fy(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - /* use X size to keep the same scale */ - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) - size = 256 * 2; - tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; - tmp += mousedev->frac_dy; - mousedev->packet.dy = tmp / FRACTION_DENOM; - mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; - } - break; + case ABS_Y: + fy(0) = value; + if (mousedev->pkt_count >= 2) { + tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; + tmp += mousedev->frac_dy; + mousedev->packet.dy = tmp / FRACTION_DENOM; + mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; + } + break; + } } } @@ -228,47 +223,47 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) { - struct mousedev_client *client; + struct mousedev_list *list; struct mousedev_motion *p; unsigned long flags; int wake_readers = 0; - list_for_each_entry(client, &mousedev->client_list, node) { - spin_lock_irqsave(&client->packet_lock, flags); + list_for_each_entry(list, &mousedev->list, node) { + spin_lock_irqsave(&list->packet_lock, flags); - p = &client->packets[client->head]; - if (client->ready && p->buttons != mousedev->packet.buttons) { - unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN; - if (new_head != client->tail) { - p = &client->packets[client->head = new_head]; + p = &list->packets[list->head]; + if (list->ready && p->buttons != mousedev->packet.buttons) { + unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; + if (new_head != list->tail) { + p = &list->packets[list->head = new_head]; memset(p, 0, sizeof(struct mousedev_motion)); } } if (packet->abs_event) { - p->dx += packet->x - client->pos_x; - p->dy += packet->y - client->pos_y; - client->pos_x = packet->x; - client->pos_y = packet->y; + p->dx += packet->x - list->pos_x; + p->dy += packet->y - list->pos_y; + list->pos_x = packet->x; + list->pos_y = packet->y; } - client->pos_x += packet->dx; - client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x); - client->pos_y += packet->dy; - client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y); + list->pos_x += packet->dx; + list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); + list->pos_y += packet->dy; + list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); p->dx += packet->dx; p->dy += packet->dy; p->dz += packet->dz; p->buttons = mousedev->packet.buttons; - if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons) - client->ready = 1; + if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons) + list->ready = 1; - spin_unlock_irqrestore(&client->packet_lock, flags); + spin_unlock_irqrestore(&list->packet_lock, flags); - if (client->ready) { - kill_fasync(&client->fasync, SIGIO, POLL_IN); + if (list->ready) { + kill_fasync(&list->fasync, SIGIO, POLL_IN); wake_readers = 1; } } @@ -356,9 +351,9 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig static int mousedev_fasync(int fd, struct file *file, int on) { int retval; - struct mousedev_client *client = file->private_data; + struct mousedev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &client->fasync); + retval = fasync_helper(fd, file, on, &list->fasync); return retval < 0 ? retval : 0; } @@ -369,95 +364,50 @@ static void mousedev_free(struct mousedev *mousedev) kfree(mousedev); } -static int mixdev_add_device(struct mousedev *mousedev) -{ - int error; - - if (mousedev_mix.open) { - error = input_open_device(&mousedev->handle); - if (error) - return error; - - mousedev->open++; - mousedev->mixdev_open++; - } - - list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); - - return 0; -} - -static void mixdev_remove_device(struct mousedev *mousedev) -{ - if (mousedev->mixdev_open) { - mousedev->mixdev_open = 0; - if (!--mousedev->open && mousedev->exist) - input_close_device(&mousedev->handle); - } - - list_del_init(&mousedev->mixdev_node); -} - -static void mixdev_open_devices(void) +static void mixdev_release(void) { - struct mousedev *mousedev; - - list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { - if (mousedev->exist && !mousedev->open) { - if (input_open_device(&mousedev->handle)) - continue; + struct input_handle *handle; - mousedev->open++; - mousedev->mixdev_open++; - } - } -} + list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { + struct mousedev *mousedev = handle->private; -static void mixdev_close_devices(void) -{ - struct mousedev *mousedev, *next; - - list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) { - if (mousedev->mixdev_open) { - mousedev->mixdev_open = 0; - if (!--mousedev->open) { - if (mousedev->exist) - input_close_device(&mousedev->handle); - else - mousedev_free(mousedev); - } + if (!mousedev->open) { + if (mousedev->exist) + input_close_device(&mousedev->handle); + else + mousedev_free(mousedev); } } } -static int mousedev_release(struct inode *inode, struct file *file) +static int mousedev_release(struct inode * inode, struct file * file) { - struct mousedev_client *client = file->private_data; - struct mousedev *mousedev = client->mousedev; + struct mousedev_list *list = file->private_data; mousedev_fasync(-1, file, 0); - list_del(&client->node); - kfree(client); + list_del(&list->node); - if (!--mousedev->open) { - if (mousedev->minor == MOUSEDEV_MIX) - mixdev_close_devices(); - else if (mousedev->exist) - input_close_device(&mousedev->handle); - else - mousedev_free(mousedev); + if (!--list->mousedev->open) { + if (list->mousedev->minor == MOUSEDEV_MIX) + mixdev_release(); + else if (!mousedev_mix.open) { + if (list->mousedev->exist) + input_close_device(&list->mousedev->handle); + else + mousedev_free(list->mousedev); + } } + kfree(list); return 0; } - -static int mousedev_open(struct inode *inode, struct file *file) +static int mousedev_open(struct inode * inode, struct file * file) { - struct mousedev_client *client; + struct mousedev_list *list; + struct input_handle *handle; struct mousedev *mousedev; - int error; int i; #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX @@ -467,37 +417,31 @@ static int mousedev_open(struct inode *inode, struct file *file) #endif i = iminor(inode) - MOUSEDEV_MINOR_BASE; - if (i >= MOUSEDEV_MINORS) - return -ENODEV; - - mousedev = mousedev_table[i]; - if (!mousedev) + if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; - client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); - if (!client) + if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL))) return -ENOMEM; - spin_lock_init(&client->packet_lock); - client->pos_x = xres / 2; - client->pos_y = yres / 2; - client->mousedev = mousedev; - list_add_tail(&client->node, &mousedev->client_list); - - if (!mousedev->open++) { - if (mousedev->minor == MOUSEDEV_MIX) - mixdev_open_devices(); - else if (mousedev->exist) { - error = input_open_device(&mousedev->handle); - if (error) { - list_del(&client->node); - kfree(client); - return error; + spin_lock_init(&list->packet_lock); + list->pos_x = xres / 2; + list->pos_y = yres / 2; + list->mousedev = mousedev_table[i]; + list_add_tail(&list->node, &mousedev_table[i]->list); + file->private_data = list; + + if (!list->mousedev->open++) { + if (list->mousedev->minor == MOUSEDEV_MIX) { + list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { + mousedev = handle->private; + if (!mousedev->open && mousedev->exist) + input_open_device(handle); } - } + } else + if (!mousedev_mix.open && list->mousedev->exist) + input_open_device(&list->mousedev->handle); } - file->private_data = client; return 0; } @@ -506,13 +450,13 @@ static inline int mousedev_limit_delta(int delta, int limit) return delta > limit ? limit : (delta < -limit ? -limit : delta); } -static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data) +static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) { struct mousedev_motion *p; unsigned long flags; - spin_lock_irqsave(&client->packet_lock, flags); - p = &client->packets[client->tail]; + spin_lock_irqsave(&list->packet_lock, flags); + p = &list->packets[list->tail]; ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); ps2_data[1] = mousedev_limit_delta(p->dx, 127); @@ -520,44 +464,44 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat p->dx -= ps2_data[1]; p->dy -= ps2_data[2]; - switch (client->mode) { + switch (list->mode) { case MOUSEDEV_EMUL_EXPS: ps2_data[3] = mousedev_limit_delta(p->dz, 7); p->dz -= ps2_data[3]; ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); - client->bufsiz = 4; + list->bufsiz = 4; break; case MOUSEDEV_EMUL_IMPS: ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); ps2_data[3] = mousedev_limit_delta(p->dz, 127); p->dz -= ps2_data[3]; - client->bufsiz = 4; + list->bufsiz = 4; break; case MOUSEDEV_EMUL_PS2: default: ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); p->dz = 0; - client->bufsiz = 3; + list->bufsiz = 3; break; } if (!p->dx && !p->dy && !p->dz) { - if (client->tail == client->head) { - client->ready = 0; - client->last_buttons = p->buttons; + if (list->tail == list->head) { + list->ready = 0; + list->last_buttons = p->buttons; } else - client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; } - spin_unlock_irqrestore(&client->packet_lock, flags); + spin_unlock_irqrestore(&list->packet_lock, flags); } -static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { - struct mousedev_client *client = file->private_data; + struct mousedev_list *list = file->private_data; unsigned char c; unsigned int i; @@ -566,95 +510,95 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size if (get_user(c, buffer + i)) return -EFAULT; - if (c == mousedev_imex_seq[client->imexseq]) { - if (++client->imexseq == MOUSEDEV_SEQ_LEN) { - client->imexseq = 0; - client->mode = MOUSEDEV_EMUL_EXPS; + if (c == mousedev_imex_seq[list->imexseq]) { + if (++list->imexseq == MOUSEDEV_SEQ_LEN) { + list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_EXPS; } } else - client->imexseq = 0; + list->imexseq = 0; - if (c == mousedev_imps_seq[client->impsseq]) { - if (++client->impsseq == MOUSEDEV_SEQ_LEN) { - client->impsseq = 0; - client->mode = MOUSEDEV_EMUL_IMPS; + if (c == mousedev_imps_seq[list->impsseq]) { + if (++list->impsseq == MOUSEDEV_SEQ_LEN) { + list->impsseq = 0; + list->mode = MOUSEDEV_EMUL_IMPS; } } else - client->impsseq = 0; + list->impsseq = 0; - client->ps2[0] = 0xfa; + list->ps2[0] = 0xfa; switch (c) { case 0xeb: /* Poll */ - mousedev_packet(client, &client->ps2[1]); - client->bufsiz++; /* account for leading ACK */ + mousedev_packet(list, &list->ps2[1]); + list->bufsiz++; /* account for leading ACK */ break; case 0xf2: /* Get ID */ - switch (client->mode) { - case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break; - case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break; - case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break; + switch (list->mode) { + case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; + case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; + case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; } - client->bufsiz = 2; + list->bufsiz = 2; break; case 0xe9: /* Get info */ - client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; - client->bufsiz = 4; + list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; + list->bufsiz = 4; break; case 0xff: /* Reset */ - client->impsseq = client->imexseq = 0; - client->mode = MOUSEDEV_EMUL_PS2; - client->ps2[1] = 0xaa; client->ps2[2] = 0x00; - client->bufsiz = 3; + list->impsseq = list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_PS2; + list->ps2[1] = 0xaa; list->ps2[2] = 0x00; + list->bufsiz = 3; break; default: - client->bufsiz = 1; + list->bufsiz = 1; break; } - client->buffer = client->bufsiz; + list->buffer = list->bufsiz; } - kill_fasync(&client->fasync, SIGIO, POLL_IN); + kill_fasync(&list->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&client->mousedev->wait); + wake_up_interruptible(&list->mousedev->wait); return count; } -static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { - struct mousedev_client *client = file->private_data; + struct mousedev_list *list = file->private_data; int retval = 0; - if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK)) + if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(client->mousedev->wait, - !client->mousedev->exist || client->ready || client->buffer); + retval = wait_event_interruptible(list->mousedev->wait, + !list->mousedev->exist || list->ready || list->buffer); if (retval) return retval; - if (!client->mousedev->exist) + if (!list->mousedev->exist) return -ENODEV; - if (!client->buffer && client->ready) { - mousedev_packet(client, client->ps2); - client->buffer = client->bufsiz; + if (!list->buffer && list->ready) { + mousedev_packet(list, list->ps2); + list->buffer = list->bufsiz; } - if (count > client->buffer) - count = client->buffer; + if (count > list->buffer) + count = list->buffer; - client->buffer -= count; + list->buffer -= count; - if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count)) + if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count)) return -EFAULT; return count; @@ -663,12 +607,11 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun /* No kernel lock - fine */ static unsigned int mousedev_poll(struct file *file, poll_table *wait) { - struct mousedev_client *client = file->private_data; - struct mousedev *mousedev = client->mousedev; + struct mousedev_list *list = file->private_data; - poll_wait(file, &mousedev->wait, wait); - return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) | - (mousedev->exist ? 0 : (POLLHUP | POLLERR)); + poll_wait(file, &list->mousedev->wait, wait); + return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | + (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); } static const struct file_operations mousedev_fops = { @@ -681,27 +624,23 @@ static const struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; -static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct mousedev *mousedev; struct class_device *cdev; - dev_t devt; - int minor; - int error; + int minor = 0; for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); if (minor == MOUSEDEV_MINORS) { printk(KERN_ERR "mousedev: no more free mousedev devices\n"); - return -ENFILE; + return NULL; } - mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); - if (!mousedev) - return -ENOMEM; + if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) + return NULL; - INIT_LIST_HEAD(&mousedev->client_list); - INIT_LIST_HEAD(&mousedev->mixdev_node); + INIT_LIST_HEAD(&mousedev->list); init_waitqueue_head(&mousedev->wait); mousedev->minor = minor; @@ -712,66 +651,42 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev mousedev->handle.private = mousedev; sprintf(mousedev->name, "mouse%d", minor); - mousedev_table[minor] = mousedev; + if (mousedev_mix.open) + input_open_device(&mousedev->handle); - devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + mousedev_table[minor] = mousedev; - cdev = class_device_create(&input_class, &dev->cdev, devt, - dev->cdev.dev, mousedev->name); - if (IS_ERR(cdev)) { - error = PTR_ERR(cdev); - goto err_free_mousedev; - } + cdev = class_device_create(&input_class, &dev->cdev, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + dev->cdev.dev, mousedev->name); /* temporary symlink to keep userspace happy */ - error = sysfs_create_link(&input_class.subsys.kobj, - &cdev->kobj, mousedev->name); - if (error) - goto err_cdev_destroy; - - error = input_register_handle(&mousedev->handle); - if (error) - goto err_remove_link; - - error = mixdev_add_device(mousedev); - if (error) - goto err_unregister_handle; - - return 0; + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + mousedev->name); - err_unregister_handle: - input_unregister_handle(&mousedev->handle); - err_remove_link: - sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); - err_cdev_destroy: - class_device_destroy(&input_class, devt); - err_free_mousedev: - mousedev_table[minor] = NULL; - kfree(mousedev); - return error; + return &mousedev->handle; } static void mousedev_disconnect(struct input_handle *handle) { struct mousedev *mousedev = handle->private; - struct mousedev_client *client; + struct mousedev_list *list; - input_unregister_handle(handle); - - sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev->exist = 0; - mixdev_remove_device(mousedev); - if (mousedev->open) { input_close_device(handle); wake_up_interruptible(&mousedev->wait); - list_for_each_entry(client, &mousedev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - } else + list_for_each_entry(list, &mousedev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); + } else { + if (mousedev_mix.open) + input_close_device(handle); mousedev_free(mousedev); + } } static const struct input_device_id mousedev_ids[] = { @@ -799,7 +714,7 @@ static const struct input_device_id mousedev_ids[] = { .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, }, /* A touchpad */ - { }, /* Terminating entry */ + { }, /* Terminating entry */ }; MODULE_DEVICE_TABLE(input, mousedev_ids); @@ -831,7 +746,7 @@ static int __init mousedev_init(void) return error; memset(&mousedev_mix, 0, sizeof(struct mousedev)); - INIT_LIST_HEAD(&mousedev_mix.client_list); + INIT_LIST_HEAD(&mousedev_mix.list); init_waitqueue_head(&mousedev_mix.wait); mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; mousedev_mix.exist = 1; diff --git a/trunk/drivers/input/power.c b/trunk/drivers/input/power.c new file mode 100644 index 000000000000..ee82464a2fa7 --- /dev/null +++ b/trunk/drivers/input/power.c @@ -0,0 +1,166 @@ +/* + * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ + * + * Copyright (c) 2001 "Crazy" James Simmons + * + * Input driver Power Management. + * + * Sponsored by Transvirtual Technology. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to . + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct input_handler power_handler; + +/* + * Power management can't be done in a interrupt context. So we have to + * use keventd. + */ +static int suspend_button_pushed = 0; +static void suspend_button_task_handler(void *data) +{ + udelay(200); /* debounce */ + suspend_button_pushed = 0; +} + +static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); + +static void power_event(struct input_handle *handle, unsigned int type, + unsigned int code, int down) +{ + struct input_dev *dev = handle->dev; + + printk("Entering power_event\n"); + + if (type == EV_PWR) { + switch (code) { + case KEY_SUSPEND: + printk("Powering down entire device\n"); + + if (!suspend_button_pushed) { + suspend_button_pushed = 1; + schedule_work(&suspend_button_task); + } + break; + case KEY_POWER: + /* Hum power down the machine. */ + break; + default: + return; + } + } + + if (type == EV_KEY) { + switch (code) { + case KEY_SUSPEND: + printk("Powering down input device\n"); + /* This is risky. See pm.h for details. */ + if (dev->state != PM_RESUME) + dev->state = PM_RESUME; + else + dev->state = PM_SUSPEND; + pm_send(dev->pm_dev, dev->state, dev); + break; + case KEY_POWER: + /* Turn the input device off completely ? */ + break; + default: + return; + } + } + return; +} + +static struct input_handle *power_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + + if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_INFO "power.c: Adding power management to input layer\n"); + return handle; +} + +static void power_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + kfree(handle); +} + +static const struct input_device_id power_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT(EV_KEY) }, + .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT(EV_KEY) }, + .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) } + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT(EV_PWR) }, + }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, power_ids); + +static struct input_handler power_handler = { + .event = power_event, + .connect = power_connect, + .disconnect = power_disconnect, + .name = "power", + .id_table = power_ids, +}; + +static int __init power_init(void) +{ + return input_register_handler(&power_handler); +} + +static void __exit power_exit(void) +{ + input_unregister_handler(&power_handler); +} + +module_init(power_init); +module_exit(power_exit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Input Power Management driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/serio/hil_mlc.c b/trunk/drivers/input/serio/hil_mlc.c index 93a1a6ba216a..4fa93ff30919 100644 --- a/trunk/drivers/input/serio/hil_mlc.c +++ b/trunk/drivers/input/serio/hil_mlc.c @@ -32,11 +32,11 @@ * * Driver theory of operation: * - * Some access methods and an ISR is defined by the sub-driver - * (e.g. hp_sdc_mlc.c). These methods are expected to provide a - * few bits of logic in addition to raw access to the HIL MLC, - * specifically, the ISR, which is entirely registered by the - * sub-driver and invoked directly, must check for record + * Some access methods and an ISR is defined by the sub-driver + * (e.g. hp_sdc_mlc.c). These methods are expected to provide a + * few bits of logic in addition to raw access to the HIL MLC, + * specifically, the ISR, which is entirely registered by the + * sub-driver and invoked directly, must check for record * termination or packet match, at which point a semaphore must * be cleared and then the hil_mlcs_tasklet must be scheduled. * @@ -47,7 +47,7 @@ * itself if output is pending. (This rescheduling should be replaced * at some point with a sub-driver-specific mechanism.) * - * A timer task prods the tasklet once per second to prevent + * A timer task prods the tasklet once per second to prevent * hangups when attached devices do not return expected data * and to initiate probes of the loop for new devices. */ @@ -83,85 +83,69 @@ DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); /********************** Device info/instance management **********************/ -static void hil_mlc_clear_di_map(hil_mlc *mlc, int val) -{ +static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) { int j; - - for (j = val; j < 7 ; j++) + for (j = val; j < 7 ; j++) { mlc->di_map[j] = -1; + } } -static void hil_mlc_clear_di_scratch(hil_mlc *mlc) -{ - memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch)); +static void hil_mlc_clear_di_scratch (hil_mlc *mlc) { + memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch)); } -static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx) -{ - memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch)); +static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) { + memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch)); } -static int hil_mlc_match_di_scratch(hil_mlc *mlc) -{ +static int hil_mlc_match_di_scratch (hil_mlc *mlc) { int idx; for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { - int j, found = 0; + int j, found; /* In-use slots are not eligible. */ - for (j = 0; j < 7 ; j++) - if (mlc->di_map[j] == idx) - found++; - - if (found) - continue; - - if (!memcmp(mlc->di + idx, &mlc->di_scratch, - sizeof(mlc->di_scratch))) - break; + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (found) continue; + if (!memcmp(mlc->di + idx, + &(mlc->di_scratch), + sizeof(mlc->di_scratch))) break; } - return idx >= HIL_MLC_DEVMEM ? -1 : idx; + return((idx >= HIL_MLC_DEVMEM) ? -1 : idx); } -static int hil_mlc_find_free_di(hil_mlc *mlc) -{ +static int hil_mlc_find_free_di(hil_mlc *mlc) { int idx; - - /* TODO: Pick all-zero slots first, failing that, - * randomize the slot picked among those eligible. + /* TODO: Pick all-zero slots first, failing that, + * randomize the slot picked among those eligible. */ for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { - int j, found = 0; - - for (j = 0; j < 7 ; j++) - if (mlc->di_map[j] == idx) - found++; - - if (!found) - break; + int j, found; + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (!found) break; } - - return idx; /* Note: It is guaranteed at least one above will match */ + return(idx); /* Note: It is guaranteed at least one above will match */ } -static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) -{ +static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) { int idx; - for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { - int j, found = 0; - - for (j = 0; j < 7 ; j++) - if (mlc->di_map[j] == idx) - found++; - - if (!found) - mlc->serio_map[idx].di_revmap = -1; + int j, found; + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (!found) mlc->serio_map[idx].di_revmap = -1; } } -static void hil_mlc_send_polls(hil_mlc *mlc) -{ +static void hil_mlc_send_polls(hil_mlc *mlc) { int did, i, cnt; struct serio *serio; struct serio_driver *drv; @@ -173,31 +157,26 @@ static void hil_mlc_send_polls(hil_mlc *mlc) while (mlc->icount < 15 - i) { hil_packet p; - p = mlc->ipacket[i]; if (did != (p & HIL_PKT_ADDR_MASK) >> 8) { - if (drv && drv->interrupt) { - drv->interrupt(serio, 0, 0); - drv->interrupt(serio, HIL_ERR_INT >> 16, 0); - drv->interrupt(serio, HIL_PKT_CMD >> 8, 0); - drv->interrupt(serio, HIL_CMD_POL + cnt, 0); - } + if (drv == NULL || drv->interrupt == NULL) goto skip; + drv->interrupt(serio, 0, 0); + drv->interrupt(serio, HIL_ERR_INT >> 16, 0); + drv->interrupt(serio, HIL_PKT_CMD >> 8, 0); + drv->interrupt(serio, HIL_CMD_POL + cnt, 0); + skip: did = (p & HIL_PKT_ADDR_MASK) >> 8; serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL; drv = (serio != NULL) ? serio->drv : NULL; cnt = 0; } - - cnt++; - i++; - - if (drv && drv->interrupt) { - drv->interrupt(serio, (p >> 24), 0); - drv->interrupt(serio, (p >> 16) & 0xff, 0); - drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0); - drv->interrupt(serio, p & 0xff, 0); - } + cnt++; i++; + if (drv == NULL || drv->interrupt == NULL) continue; + drv->interrupt(serio, (p >> 24), 0); + drv->interrupt(serio, (p >> 16) & 0xff, 0); + drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0); + drv->interrupt(serio, p & 0xff, 0); } } @@ -236,16 +215,12 @@ static void hil_mlc_send_polls(hil_mlc *mlc) #define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK) #define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK) -static int hilse_match(hil_mlc *mlc, int unused) -{ +static int hilse_match(hil_mlc *mlc, int unused) { int rc; - rc = hil_mlc_match_di_scratch(mlc); if (rc == -1) { rc = hil_mlc_find_free_di(mlc); - if (rc == -1) - goto err; - + if (rc == -1) goto err; #ifdef HIL_MLC_DEBUG printk(KERN_DEBUG PREFIX "new in slot %i\n", rc); #endif @@ -256,7 +231,6 @@ static int hilse_match(hil_mlc *mlc, int unused) serio_rescan(mlc->serio[rc]); return -1; } - mlc->di_map[mlc->ddi] = rc; #ifdef HIL_MLC_DEBUG printk(KERN_DEBUG PREFIX "same in slot %i\n", rc); @@ -264,177 +238,152 @@ static int hilse_match(hil_mlc *mlc, int unused) mlc->serio_map[rc].di_revmap = mlc->ddi; hil_mlc_clean_serio_map(mlc); return 0; - err: printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n"); return 1; } /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ -static int hilse_init_lcv(hil_mlc *mlc, int unused) -{ +static int hilse_init_lcv(hil_mlc *mlc, int unused) { struct timeval tv; do_gettimeofday(&tv); - if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5) - return -1; - + if(mlc->lcv == 0) goto restart; /* First init, no need to dally */ + if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1; + restart: mlc->lcv_tv = tv; mlc->lcv = 0; - return 0; } -static int hilse_inc_lcv(hil_mlc *mlc, int lim) -{ - return mlc->lcv++ >= lim ? -1 : 0; +static int hilse_inc_lcv(hil_mlc *mlc, int lim) { + if (mlc->lcv++ >= lim) return -1; + return 0; } #if 0 -static int hilse_set_lcv(hil_mlc *mlc, int val) -{ +static int hilse_set_lcv(hil_mlc *mlc, int val) { mlc->lcv = val; - return 0; } #endif /* Management of the discovered device index (zero based, -1 means no devs) */ -static int hilse_set_ddi(hil_mlc *mlc, int val) -{ +static int hilse_set_ddi(hil_mlc *mlc, int val) { mlc->ddi = val; hil_mlc_clear_di_map(mlc, val + 1); - return 0; } -static int hilse_dec_ddi(hil_mlc *mlc, int unused) -{ +static int hilse_dec_ddi(hil_mlc *mlc, int unused) { mlc->ddi--; - if (mlc->ddi <= -1) { + if (mlc->ddi <= -1) { mlc->ddi = -1; hil_mlc_clear_di_map(mlc, 0); return -1; } hil_mlc_clear_di_map(mlc, mlc->ddi + 1); - return 0; } -static int hilse_inc_ddi(hil_mlc *mlc, int unused) -{ - BUG_ON(mlc->ddi >= 6); +static int hilse_inc_ddi(hil_mlc *mlc, int unused) { + if (mlc->ddi >= 6) { + BUG(); + return -1; + } mlc->ddi++; - return 0; } -static int hilse_take_idd(hil_mlc *mlc, int unused) -{ +static int hilse_take_idd(hil_mlc *mlc, int unused) { int i; - /* Help the state engine: - * Is this a real IDD response or just an echo? + /* Help the state engine: + * Is this a real IDD response or just an echo? * - * Real IDD response does not start with a command. + * Real IDD response does not start with a command. */ - if (mlc->ipacket[0] & HIL_PKT_CMD) - goto bail; - + if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail; /* Should have the command echoed further down. */ for (i = 1; i < 16; i++) { - if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == + if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) && - (mlc->ipacket[i] & HIL_PKT_CMD) && + (mlc->ipacket[i] & HIL_PKT_CMD) && ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD)) break; } - if (i > 15) - goto bail; - + if (i > 15) goto bail; /* And the rest of the packets should still be clear. */ - while (++i < 16) - if (mlc->ipacket[i]) - break; - - if (i < 16) - goto bail; - - for (i = 0; i < 16; i++) - mlc->di_scratch.idd[i] = + while (++i < 16) { + if (mlc->ipacket[i]) break; + } + if (i < 16) goto bail; + for (i = 0; i < 16; i++) { + mlc->di_scratch.idd[i] = mlc->ipacket[i] & HIL_PKT_DATA_MASK; - + } /* Next step is to see if RSC supported */ - if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) return HILSEN_NEXT; - - if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) return HILSEN_DOWN | 4; - return 0; - bail: mlc->ddi--; - return -1; /* This should send us off to ACF */ } -static int hilse_take_rsc(hil_mlc *mlc, int unused) -{ +static int hilse_take_rsc(hil_mlc *mlc, int unused) { int i; - for (i = 0; i < 16; i++) - mlc->di_scratch.rsc[i] = + for (i = 0; i < 16; i++) { + mlc->di_scratch.rsc[i] = mlc->ipacket[i] & HIL_PKT_DATA_MASK; - + } /* Next step is to see if EXD supported (IDD has already been read) */ - if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) return HILSEN_NEXT; - return 0; } -static int hilse_take_exd(hil_mlc *mlc, int unused) -{ +static int hilse_take_exd(hil_mlc *mlc, int unused) { int i; - for (i = 0; i < 16; i++) - mlc->di_scratch.exd[i] = + for (i = 0; i < 16; i++) { + mlc->di_scratch.exd[i] = mlc->ipacket[i] & HIL_PKT_DATA_MASK; - + } /* Next step is to see if RNM supported. */ - if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) + if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) return HILSEN_NEXT; - return 0; } -static int hilse_take_rnm(hil_mlc *mlc, int unused) -{ +static int hilse_take_rnm(hil_mlc *mlc, int unused) { int i; - for (i = 0; i < 16; i++) - mlc->di_scratch.rnm[i] = + for (i = 0; i < 16; i++) { + mlc->di_scratch.rnm[i] = mlc->ipacket[i] & HIL_PKT_DATA_MASK; - - printk(KERN_INFO PREFIX "Device name gotten: %16s\n", - mlc->di_scratch.rnm); - + } + do { + char nam[17]; + snprintf(nam, 16, "%s", mlc->di_scratch.rnm); + nam[16] = '\0'; + printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam); + } while (0); return 0; } -static int hilse_operate(hil_mlc *mlc, int repoll) -{ +static int hilse_operate(hil_mlc *mlc, int repoll) { - if (mlc->opercnt == 0) - hil_mlcs_probe = 0; + if (mlc->opercnt == 0) hil_mlcs_probe = 0; mlc->opercnt = 1; hil_mlc_send_polls(mlc); - if (!hil_mlcs_probe) - return 0; + if (!hil_mlcs_probe) return 0; hil_mlcs_probe = 0; mlc->opercnt = 0; return 1; @@ -459,7 +408,7 @@ static int hilse_operate(hil_mlc *mlc, int repoll) #define OUT_LAST(pack) \ { HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 }, -const struct hilse_node hil_mlc_se[HILSEN_END] = { +struct hilse_node hil_mlc_se[HILSEN_END] = { /* 0 HILSEN_START */ FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) @@ -479,7 +428,7 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { EXPECT(HIL_ERR_INT | TEST_PACKET(0xa), 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */ - + /* 9 HILSEN_DHR */ FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) @@ -490,7 +439,7 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT) /* 14 HILSEN_IFC */ - OUT(HIL_PKT_CMD | HIL_CMD_IFC) + OUT(HIL_PKT_CMD | HIL_CMD_IFC) EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, 20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT ) @@ -506,7 +455,7 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { /* 18 HILSEN_HEAL */ OUT_LAST(HIL_CMD_ELB) - EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, + EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, 20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT) FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0) @@ -554,7 +503,7 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { /* 44 HILSEN_PROBE */ OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT) - IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) + IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) @@ -565,7 +514,7 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { /* 52 HILSEN_DSR */ FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) OUT(HIL_PKT_CMD | HIL_CMD_DSR) - IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC) + IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC) /* 55 HILSEN_REPOLL */ OUT(HIL_PKT_CMD | HIL_CMD_RPL) @@ -574,15 +523,14 @@ const struct hilse_node hil_mlc_se[HILSEN_END] = { FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE) /* 58 HILSEN_IFCACF */ - OUT(HIL_PKT_CMD | HIL_CMD_IFC) + OUT(HIL_PKT_CMD | HIL_CMD_IFC) EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, 20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL) /* 60 HILSEN_END */ }; -static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node) -{ +static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) { switch (node->act) { case HILSE_EXPECT_DISC: @@ -607,27 +555,29 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node do_gettimeofday(&(mlc->instart)); mlc->icount = 15; memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); - BUG_ON(down_trylock(&mlc->isem)); + BUG_ON(down_trylock(&(mlc->isem))); + + return; } #ifdef HIL_MLC_DEBUG -static int doze; +static int doze = 0; static int seidx; /* For debug */ +static int kick = 1; #endif -static int hilse_donode(hil_mlc *mlc) -{ - const struct hilse_node *node; +static int hilse_donode (hil_mlc *mlc) { + struct hilse_node *node; int nextidx = 0; int sched_long = 0; unsigned long flags; #ifdef HIL_MLC_DEBUG - if (mlc->seidx && mlc->seidx != seidx && - mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) { - printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx); + if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) { + printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx); doze = 0; } + kick = 0; seidx = mlc->seidx; #endif @@ -638,61 +588,52 @@ static int hilse_donode(hil_mlc *mlc) hil_packet pack; case HILSE_FUNC: - BUG_ON(node->object.func == NULL); + if (node->object.func == NULL) break; rc = node->object.func(mlc, node->arg); - nextidx = (rc > 0) ? node->ugly : + nextidx = (rc > 0) ? node->ugly : ((rc < 0) ? node->bad : node->good); - if (nextidx == HILSEN_FOLLOW) - nextidx = rc; + if (nextidx == HILSEN_FOLLOW) nextidx = rc; break; - case HILSE_EXPECT_LAST: case HILSE_EXPECT_DISC: case HILSE_EXPECT: case HILSE_IN: /* Already set up from previous HILSE_OUT_* */ - write_lock_irqsave(&mlc->lock, flags); + write_lock_irqsave(&(mlc->lock), flags); rc = mlc->in(mlc, node->arg); if (rc == 2) { nextidx = HILSEN_DOZE; sched_long = 1; - write_unlock_irqrestore(&mlc->lock, flags); + write_unlock_irqrestore(&(mlc->lock), flags); break; } - if (rc == 1) - nextidx = node->ugly; - else if (rc == 0) - nextidx = node->good; - else - nextidx = node->bad; + if (rc == 1) nextidx = node->ugly; + else if (rc == 0) nextidx = node->good; + else nextidx = node->bad; mlc->istarted = 0; - write_unlock_irqrestore(&mlc->lock, flags); + write_unlock_irqrestore(&(mlc->lock), flags); break; - case HILSE_OUT_LAST: - write_lock_irqsave(&mlc->lock, flags); + write_lock_irqsave(&(mlc->lock), flags); pack = node->object.packet; pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); goto out; - case HILSE_OUT_DISC: - write_lock_irqsave(&mlc->lock, flags); + write_lock_irqsave(&(mlc->lock), flags); pack = node->object.packet; pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); goto out; - case HILSE_OUT: - write_lock_irqsave(&mlc->lock, flags); + write_lock_irqsave(&(mlc->lock), flags); pack = node->object.packet; out: - if (mlc->istarted) - goto out2; + if (mlc->istarted) goto out2; /* Prepare to receive input */ if ((node + 1)->act & HILSE_IN) hilse_setup_input(mlc, node + 1); out2: - write_unlock_irqrestore(&mlc->lock, flags); + write_unlock_irqrestore(&(mlc->lock), flags); if (down_trylock(&mlc->osem)) { nextidx = HILSEN_DOZE; @@ -700,71 +641,60 @@ static int hilse_donode(hil_mlc *mlc) } up(&mlc->osem); - write_lock_irqsave(&mlc->lock, flags); - if (!mlc->ostarted) { + write_lock_irqsave(&(mlc->lock), flags); + if (!(mlc->ostarted)) { mlc->ostarted = 1; mlc->opacket = pack; mlc->out(mlc); nextidx = HILSEN_DOZE; - write_unlock_irqrestore(&mlc->lock, flags); + write_unlock_irqrestore(&(mlc->lock), flags); break; } mlc->ostarted = 0; do_gettimeofday(&(mlc->instart)); - write_unlock_irqrestore(&mlc->lock, flags); + write_unlock_irqrestore(&(mlc->lock), flags); nextidx = HILSEN_NEXT; break; - case HILSE_CTS: - write_lock_irqsave(&mlc->lock, flags); nextidx = mlc->cts(mlc) ? node->bad : node->good; - write_unlock_irqrestore(&mlc->lock, flags); break; - default: BUG(); + nextidx = 0; + break; } #ifdef HIL_MLC_DEBUG - if (nextidx == HILSEN_DOZE) - doze++; + if (nextidx == HILSEN_DOZE) doze++; #endif while (nextidx & HILSEN_SCHED) { struct timeval tv; - if (!sched_long) - goto sched; + if (!sched_long) goto sched; do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); + tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); tv.tv_usec -= mlc->instart.tv_usec; if (tv.tv_usec >= mlc->intimeout) goto sched; - tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC; + tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000; if (!tv.tv_usec) goto sched; mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); break; sched: tasklet_schedule(&hil_mlcs_tasklet); break; - } - - if (nextidx & HILSEN_DOWN) - mlc->seidx += nextidx & HILSEN_MASK; - else if (nextidx & HILSEN_UP) - mlc->seidx -= nextidx & HILSEN_MASK; - else - mlc->seidx = nextidx & HILSEN_MASK; - - if (nextidx & HILSEN_BREAK) - return 1; + } + if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK; + else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK; + else mlc->seidx = nextidx & HILSEN_MASK; + if (nextidx & HILSEN_BREAK) return 1; return 0; } /******************** tasklet context functions **************************/ -static void hil_mlcs_process(unsigned long unused) -{ +static void hil_mlcs_process(unsigned long unused) { struct list_head *tmp; read_lock(&hil_mlcs_lock); @@ -772,20 +702,19 @@ static void hil_mlcs_process(unsigned long unused) struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list); while (hilse_donode(mlc) == 0) { #ifdef HIL_MLC_DEBUG - if (mlc->seidx != 41 && - mlc->seidx != 42 && - mlc->seidx != 43) - printk(KERN_DEBUG PREFIX " + "); + if (mlc->seidx != 41 && + mlc->seidx != 42 && + mlc->seidx != 43) + printk(KERN_DEBUG PREFIX " + "); #endif - } + }; } read_unlock(&hil_mlcs_lock); } /************************* Keepalive timer task *********************/ -void hil_mlcs_timer(unsigned long data) -{ +void hil_mlcs_timer (unsigned long data) { hil_mlcs_probe = 1; tasklet_schedule(&hil_mlcs_tasklet); /* Re-insert the periodic task. */ @@ -795,25 +724,28 @@ void hil_mlcs_timer(unsigned long data) /******************** user/kernel context functions **********************/ -static int hil_mlc_serio_write(struct serio *serio, unsigned char c) -{ +static int hil_mlc_serio_write(struct serio *serio, unsigned char c) { struct hil_mlc_serio_map *map; struct hil_mlc *mlc; struct serio_driver *drv; uint8_t *idx, *last; map = serio->port_data; - BUG_ON(map == NULL); - + if (map == NULL) { + BUG(); + return -EIO; + } mlc = map->mlc; - BUG_ON(mlc == NULL); - - mlc->serio_opacket[map->didx] |= + if (mlc == NULL) { + BUG(); + return -EIO; + } + mlc->serio_opacket[map->didx] |= ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx])); if (mlc->serio_oidx[map->didx] >= 3) { /* for now only commands */ - if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) + if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) return -EIO; switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) { case HIL_CMD_IDD: @@ -839,11 +771,12 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) return -EIO; emu: drv = serio->drv; - BUG_ON(drv == NULL); - + if (drv == NULL) { + BUG(); + return -EIO; + } last = idx + 15; - while ((last != idx) && (*last == 0)) - last--; + while ((last != idx) && (*last == 0)) last--; while (idx != last) { drv->interrupt(serio, 0, 0); @@ -856,15 +789,14 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) drv->interrupt(serio, HIL_ERR_INT >> 16, 0); drv->interrupt(serio, HIL_PKT_CMD >> 8, 0); drv->interrupt(serio, *idx, 0); - + mlc->serio_oidx[map->didx] = 0; mlc->serio_opacket[map->didx] = 0; return 0; } -static int hil_mlc_serio_open(struct serio *serio) -{ +static int hil_mlc_serio_open(struct serio *serio) { struct hil_mlc_serio_map *map; struct hil_mlc *mlc; @@ -872,57 +804,67 @@ static int hil_mlc_serio_open(struct serio *serio) return -EBUSY; map = serio->port_data; - BUG_ON(map == NULL); - + if (map == NULL) { + BUG(); + return -ENODEV; + } mlc = map->mlc; - BUG_ON(mlc == NULL); + if (mlc == NULL) { + BUG(); + return -ENODEV; + } return 0; } -static void hil_mlc_serio_close(struct serio *serio) -{ +static void hil_mlc_serio_close(struct serio *serio) { struct hil_mlc_serio_map *map; struct hil_mlc *mlc; map = serio->port_data; - BUG_ON(map == NULL); - + if (map == NULL) { + BUG(); + return; + } mlc = map->mlc; - BUG_ON(mlc == NULL); + if (mlc == NULL) { + BUG(); + return; + } serio_set_drvdata(serio, NULL); serio->drv = NULL; /* TODO wake up interruptable */ } -static const struct serio_device_id hil_mlc_serio_id = { +static struct serio_device_id hil_mlc_serio_id = { .type = SERIO_HIL_MLC, .proto = SERIO_HIL, .extra = SERIO_ANY, .id = SERIO_ANY, }; -int hil_mlc_register(hil_mlc *mlc) -{ +int hil_mlc_register(hil_mlc *mlc) { int i; - unsigned long flags; + unsigned long flags; - BUG_ON(mlc == NULL); + if (mlc == NULL) { + return -EINVAL; + } mlc->istarted = 0; - mlc->ostarted = 0; + mlc->ostarted = 0; - rwlock_init(&mlc->lock); - init_MUTEX(&mlc->osem); + rwlock_init(&mlc->lock); + init_MUTEX(&(mlc->osem)); - init_MUTEX(&mlc->isem); - mlc->icount = -1; - mlc->imatch = 0; + init_MUTEX(&(mlc->isem)); + mlc->icount = -1; + mlc->imatch = 0; mlc->opercnt = 0; - init_MUTEX_LOCKED(&(mlc->csem)); + init_MUTEX_LOCKED(&(mlc->csem)); hil_mlc_clear_di_scratch(mlc); hil_mlc_clear_di_map(mlc, 0); @@ -931,8 +873,6 @@ int hil_mlc_register(hil_mlc *mlc) hil_mlc_copy_di_scratch(mlc, i); mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc->serio[i] = mlc_serio; - snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i); - snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i); mlc_serio->id = hil_mlc_serio_id; mlc_serio->write = hil_mlc_serio_write; mlc_serio->open = hil_mlc_serio_open; @@ -957,18 +897,19 @@ int hil_mlc_register(hil_mlc *mlc) return 0; } -int hil_mlc_unregister(hil_mlc *mlc) -{ +int hil_mlc_unregister(hil_mlc *mlc) { struct list_head *tmp; - unsigned long flags; + unsigned long flags; int i; - BUG_ON(mlc == NULL); + if (mlc == NULL) + return -EINVAL; write_lock_irqsave(&hil_mlcs_lock, flags); - list_for_each(tmp, &hil_mlcs) + list_for_each(tmp, &hil_mlcs) { if (list_entry(tmp, hil_mlc, list) == mlc) goto found; + } /* not found in list */ write_unlock_irqrestore(&hil_mlcs_lock, flags); @@ -977,7 +918,7 @@ int hil_mlc_unregister(hil_mlc *mlc) found: list_del(tmp); - write_unlock_irqrestore(&hil_mlcs_lock, flags); + write_unlock_irqrestore(&hil_mlcs_lock, flags); for (i = 0; i < HIL_MLC_DEVMEM; i++) { serio_unregister_port(mlc->serio[i]); @@ -1001,7 +942,7 @@ static int __init hil_mlc_init(void) return 0; } - + static void __exit hil_mlc_exit(void) { del_timer(&hil_mlcs_kicker); @@ -1009,6 +950,6 @@ static void __exit hil_mlc_exit(void) tasklet_disable(&hil_mlcs_tasklet); tasklet_kill(&hil_mlcs_tasklet); } - + module_init(hil_mlc_init); module_exit(hil_mlc_exit); diff --git a/trunk/drivers/input/serio/hp_sdc.c b/trunk/drivers/input/serio/hp_sdc.c index 6af199805ffc..b57370dc4e3d 100644 --- a/trunk/drivers/input/serio/hp_sdc.c +++ b/trunk/drivers/input/serio/hp_sdc.c @@ -34,27 +34,27 @@ * * Driver theory of operation: * - * hp_sdc_put does all writing to the SDC. ISR can run on a different - * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time + * hp_sdc_put does all writing to the SDC. ISR can run on a different + * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time * (it cannot really benefit from SMP anyway.) A tasket fit this perfectly. * - * All data coming back from the SDC is sent via interrupt and can be read - * fully in the ISR, so there are no latency/throughput problems there. - * The problem is with output, due to the slow clock speed of the SDC - * compared to the CPU. This should not be too horrible most of the time, - * but if used with HIL devices that support the multibyte transfer command, - * keeping outbound throughput flowing at the 6500KBps that the HIL is + * All data coming back from the SDC is sent via interrupt and can be read + * fully in the ISR, so there are no latency/throughput problems there. + * The problem is with output, due to the slow clock speed of the SDC + * compared to the CPU. This should not be too horrible most of the time, + * but if used with HIL devices that support the multibyte transfer command, + * keeping outbound throughput flowing at the 6500KBps that the HIL is * capable of is more than can be done at HZ=100. * - * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf - * is set to 0 when the IBF flag in the status register has cleared. ISR - * may do this, and may also access the parts of queued transactions related - * to reading data back from the SDC, but otherwise will not touch the + * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf + * is set to 0 when the IBF flag in the status register has cleared. ISR + * may do this, and may also access the parts of queued transactions related + * to reading data back from the SDC, but otherwise will not touch the * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1. * * The i8042 write index and the values in the 4-byte input buffer * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively, - * to minimize the amount of IO needed to the SDC. However these values + * to minimize the amount of IO needed to the SDC. However these values * do not need to be locked since they are only ever accessed by hp_sdc_put. * * A timer task schedules the tasklet once per second just to make @@ -100,46 +100,39 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq); EXPORT_SYMBOL(hp_sdc_release_hil_irq); EXPORT_SYMBOL(hp_sdc_release_cooked_irq); -EXPORT_SYMBOL(__hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_dequeue_transaction); static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */ /*************** primitives for use in any context *********************/ -static inline uint8_t hp_sdc_status_in8(void) -{ +static inline uint8_t hp_sdc_status_in8 (void) { uint8_t status; unsigned long flags; write_lock_irqsave(&hp_sdc.ibf_lock, flags); status = sdc_readb(hp_sdc.status_io); - if (!(status & HP_SDC_STATUS_IBF)) - hp_sdc.ibf = 0; + if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0; write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); return status; } -static inline uint8_t hp_sdc_data_in8(void) -{ - return sdc_readb(hp_sdc.data_io); +static inline uint8_t hp_sdc_data_in8 (void) { + return sdc_readb(hp_sdc.data_io); } -static inline void hp_sdc_status_out8(uint8_t val) -{ +static inline void hp_sdc_status_out8 (uint8_t val) { unsigned long flags; write_lock_irqsave(&hp_sdc.ibf_lock, flags); hp_sdc.ibf = 1; - if ((val & 0xf0) == 0xe0) - hp_sdc.wi = 0xff; + if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff; sdc_writeb(val, hp_sdc.status_io); write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); } -static inline void hp_sdc_data_out8(uint8_t val) -{ +static inline void hp_sdc_data_out8 (uint8_t val) { unsigned long flags; write_lock_irqsave(&hp_sdc.ibf_lock, flags); @@ -148,12 +141,11 @@ static inline void hp_sdc_data_out8(uint8_t val) write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); } -/* Care must be taken to only invoke hp_sdc_spin_ibf when - * absolutely needed, or in rarely invoked subroutines. - * Not only does it waste CPU cycles, it also wastes bus cycles. +/* Care must be taken to only invoke hp_sdc_spin_ibf when + * absolutely needed, or in rarely invoked subroutines. + * Not only does it waste CPU cycles, it also wastes bus cycles. */ -static inline void hp_sdc_spin_ibf(void) -{ +static inline void hp_sdc_spin_ibf(void) { unsigned long flags; rwlock_t *lock; @@ -166,21 +158,19 @@ static inline void hp_sdc_spin_ibf(void) } read_unlock(lock); write_lock(lock); - while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) - { } + while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {}; hp_sdc.ibf = 0; write_unlock_irqrestore(lock, flags); } /************************ Interrupt context functions ************************/ -static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) -{ +static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) { hp_sdc_transaction *curr; read_lock(&hp_sdc.rtq_lock); if (hp_sdc.rcurr < 0) { - read_unlock(&hp_sdc.rtq_lock); + read_unlock(&hp_sdc.rtq_lock); return; } curr = hp_sdc.tq[hp_sdc.rcurr]; @@ -193,27 +183,25 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) if (hp_sdc.rqty <= 0) { /* All data has been gathered. */ - if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) - if (curr->act.semaphore) - up(curr->act.semaphore); - - if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) + if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) { + if (curr->act.semaphore) up(curr->act.semaphore); + } + if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) { if (curr->act.irqhook) curr->act.irqhook(irq, dev_id, status, data); - + } curr->actidx = curr->idx; curr->idx++; /* Return control of this transaction */ write_lock(&hp_sdc.rtq_lock); - hp_sdc.rcurr = -1; + hp_sdc.rcurr = -1; hp_sdc.rqty = 0; write_unlock(&hp_sdc.rtq_lock); tasklet_schedule(&hp_sdc.task); } } -static irqreturn_t hp_sdc_isr(int irq, void *dev_id) -{ +static irqreturn_t hp_sdc_isr(int irq, void *dev_id) { uint8_t status, data; status = hp_sdc_status_in8(); @@ -221,74 +209,67 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) data = hp_sdc_data_in8(); /* For now we are ignoring these until we get the SDC to behave. */ - if (((status & 0xf1) == 0x51) && data == 0x82) - return IRQ_HANDLED; + if (((status & 0xf1) == 0x51) && data == 0x82) { + return IRQ_HANDLED; + } - switch (status & HP_SDC_STATUS_IRQMASK) { - case 0: /* This case is not documented. */ + switch(status & HP_SDC_STATUS_IRQMASK) { + case 0: /* This case is not documented. */ break; - - case HP_SDC_STATUS_USERTIMER: - case HP_SDC_STATUS_PERIODIC: - case HP_SDC_STATUS_TIMER: + case HP_SDC_STATUS_USERTIMER: + case HP_SDC_STATUS_PERIODIC: + case HP_SDC_STATUS_TIMER: read_lock(&hp_sdc.hook_lock); - if (hp_sdc.timer != NULL) + if (hp_sdc.timer != NULL) hp_sdc.timer(irq, dev_id, status, data); read_unlock(&hp_sdc.hook_lock); break; - - case HP_SDC_STATUS_REG: + case HP_SDC_STATUS_REG: hp_sdc_take(irq, dev_id, status, data); break; - - case HP_SDC_STATUS_HILCMD: - case HP_SDC_STATUS_HILDATA: + case HP_SDC_STATUS_HILCMD: + case HP_SDC_STATUS_HILDATA: read_lock(&hp_sdc.hook_lock); if (hp_sdc.hil != NULL) hp_sdc.hil(irq, dev_id, status, data); read_unlock(&hp_sdc.hook_lock); break; - - case HP_SDC_STATUS_PUP: + case HP_SDC_STATUS_PUP: read_lock(&hp_sdc.hook_lock); if (hp_sdc.pup != NULL) hp_sdc.pup(irq, dev_id, status, data); - else - printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n"); + else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n"); read_unlock(&hp_sdc.hook_lock); break; - - default: + default: read_lock(&hp_sdc.hook_lock); if (hp_sdc.cooked != NULL) hp_sdc.cooked(irq, dev_id, status, data); read_unlock(&hp_sdc.hook_lock); break; } - return IRQ_HANDLED; } -static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) -{ +static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) { int status; - + status = hp_sdc_status_in8(); printk(KERN_WARNING PREFIX "NMI !\n"); -#if 0 +#if 0 if (status & HP_SDC_NMISTATUS_FHS) { read_lock(&hp_sdc.hook_lock); - if (hp_sdc.timer != NULL) + if (hp_sdc.timer != NULL) hp_sdc.timer(irq, dev_id, status, 0); read_unlock(&hp_sdc.hook_lock); - } else { + } + else { /* TODO: pass this on to the HIL handler, or do SAK here? */ printk(KERN_WARNING PREFIX "HIL NMI\n"); } #endif - return IRQ_HANDLED; } @@ -297,17 +278,13 @@ static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) unsigned long hp_sdc_put(void); -static void hp_sdc_tasklet(unsigned long foo) -{ - write_lock_irq(&hp_sdc.rtq_lock); +static void hp_sdc_tasklet(unsigned long foo) { + write_lock_irq(&hp_sdc.rtq_lock); if (hp_sdc.rcurr >= 0) { struct timeval tv; - do_gettimeofday(&tv); - if (tv.tv_sec > hp_sdc.rtv.tv_sec) - tv.tv_usec += USEC_PER_SEC; - + if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000; if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { hp_sdc_transaction *curr; uint8_t tmp; @@ -323,29 +300,27 @@ static void hp_sdc_tasklet(unsigned long foo) hp_sdc.rqty = 0; tmp = curr->seq[curr->actidx]; curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD; - if (tmp & HP_SDC_ACT_SEMAPHORE) - if (curr->act.semaphore) + if(tmp & HP_SDC_ACT_SEMAPHORE) { + if (curr->act.semaphore) up(curr->act.semaphore); - - if (tmp & HP_SDC_ACT_CALLBACK) { + } + if(tmp & HP_SDC_ACT_CALLBACK) { /* Note this means that irqhooks may be called * in tasklet/bh context. */ - if (curr->act.irqhook) + if (curr->act.irqhook) curr->act.irqhook(0, NULL, 0, 0); } - curr->actidx = curr->idx; curr->idx++; - hp_sdc.rcurr = -1; + hp_sdc.rcurr = -1; } } write_unlock_irq(&hp_sdc.rtq_lock); hp_sdc_put(); } -unsigned long hp_sdc_put(void) -{ +unsigned long hp_sdc_put(void) { hp_sdc_transaction *curr; uint8_t act; int idx, curridx; @@ -358,24 +333,19 @@ unsigned long hp_sdc_put(void) requires output, so we skip to the administrativa. */ if (hp_sdc.ibf) { hp_sdc_status_in8(); - if (hp_sdc.ibf) - goto finish; + if (hp_sdc.ibf) goto finish; } anew: /* See if we are in the middle of a sequence. */ - if (hp_sdc.wcurr < 0) - hp_sdc.wcurr = 0; + if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0; read_lock_irq(&hp_sdc.rtq_lock); - if (hp_sdc.rcurr == hp_sdc.wcurr) - hp_sdc.wcurr++; + if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++; read_unlock_irq(&hp_sdc.rtq_lock); - if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) - hp_sdc.wcurr = 0; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; curridx = hp_sdc.wcurr; - if (hp_sdc.tq[curridx] != NULL) - goto start; + if (hp_sdc.tq[curridx] != NULL) goto start; while (++curridx != hp_sdc.wcurr) { if (curridx >= HP_SDC_QUEUE_LEN) { @@ -388,8 +358,7 @@ unsigned long hp_sdc_put(void) continue; } read_unlock_irq(&hp_sdc.rtq_lock); - if (hp_sdc.tq[curridx] != NULL) - break; /* Found one. */ + if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */ } if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */ curridx = -1; @@ -405,8 +374,7 @@ unsigned long hp_sdc_put(void) goto finish; } - if (hp_sdc.wcurr == -1) - goto done; + if (hp_sdc.wcurr == -1) goto done; curr = hp_sdc.tq[curridx]; idx = curr->actidx; @@ -415,23 +383,20 @@ unsigned long hp_sdc_put(void) hp_sdc.tq[curridx] = NULL; /* Interleave outbound data between the transactions. */ hp_sdc.wcurr++; - if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) - hp_sdc.wcurr = 0; - goto finish; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + goto finish; } act = curr->seq[idx]; idx++; if (curr->idx >= curr->endidx) { - if (act & HP_SDC_ACT_DEALLOC) - kfree(curr); + if (act & HP_SDC_ACT_DEALLOC) kfree(curr); hp_sdc.tq[curridx] = NULL; /* Interleave outbound data between the transactions. */ hp_sdc.wcurr++; - if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) - hp_sdc.wcurr = 0; - goto finish; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + goto finish; } while (act & HP_SDC_ACT_PRECMD) { @@ -444,10 +409,9 @@ unsigned long hp_sdc_put(void) curr->idx++; /* act finished? */ if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD) - goto actdone; + goto actdone; /* skip quantity field if data-out sequence follows. */ - if (act & HP_SDC_ACT_DATAOUT) - curr->idx++; + if (act & HP_SDC_ACT_DATAOUT) curr->idx++; goto finish; } if (act & HP_SDC_ACT_DATAOUT) { @@ -459,15 +423,15 @@ unsigned long hp_sdc_put(void) hp_sdc_data_out8(curr->seq[curr->idx]); curr->idx++; /* act finished? */ - if (curr->idx - idx >= qty && - (act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT) + if ((curr->idx - idx >= qty) && + ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)) goto actdone; goto finish; } idx += qty; act &= ~HP_SDC_ACT_DATAOUT; - } else - while (act & HP_SDC_ACT_DATAREG) { + } + else while (act & HP_SDC_ACT_DATAREG) { int mask; uint8_t w7[4]; @@ -481,30 +445,26 @@ unsigned long hp_sdc_put(void) act &= ~HP_SDC_ACT_DATAREG; break; } - + w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0]; w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1]; w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2]; w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3]; - + if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 || - w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) { + w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) { int i = 0; - /* Need to point the write index register */ - while (i < 4 && w7[i] == hp_sdc.r7[i]) - i++; - + /* Need to point the write index register */ + while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; if (i < 4) { hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i); hp_sdc.wi = 0x70 + i; goto finish; } - idx++; if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG) goto actdone; - curr->idx = idx; act &= ~HP_SDC_ACT_DATAREG; break; @@ -516,13 +476,12 @@ unsigned long hp_sdc_put(void) { int i = 0; - while ((i < 4) && w7[i] == hp_sdc.r7[i]) - i++; + while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; if (i >= 4) { curr->idx = idx + 1; - if ((act & HP_SDC_ACT_DURING) == + if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG) - goto actdone; + goto actdone; } } goto finish; @@ -538,7 +497,7 @@ unsigned long hp_sdc_put(void) if (act & HP_SDC_ACT_POSTCMD) { - uint8_t postcmd; + uint8_t postcmd; /* curr->idx should == idx at this point. */ postcmd = curr->seq[idx]; @@ -546,12 +505,12 @@ unsigned long hp_sdc_put(void) if (act & HP_SDC_ACT_DATAIN) { /* Start a new read */ - hp_sdc.rqty = curr->seq[curr->idx]; + hp_sdc.rqty = curr->seq[curr->idx]; do_gettimeofday(&hp_sdc.rtv); curr->idx++; /* Still need to lock here in case of spurious irq. */ write_lock_irq(&hp_sdc.rtq_lock); - hp_sdc.rcurr = curridx; + hp_sdc.rcurr = curridx; write_unlock_irq(&hp_sdc.rtq_lock); hp_sdc_status_out8(postcmd); goto finish; @@ -560,86 +519,75 @@ unsigned long hp_sdc_put(void) goto actdone; } - actdone: - if (act & HP_SDC_ACT_SEMAPHORE) +actdone: + if (act & HP_SDC_ACT_SEMAPHORE) { up(curr->act.semaphore); - else if (act & HP_SDC_ACT_CALLBACK) + } + else if (act & HP_SDC_ACT_CALLBACK) { curr->act.irqhook(0,NULL,0,0); - + } if (curr->idx >= curr->endidx) { /* This transaction is over. */ - if (act & HP_SDC_ACT_DEALLOC) - kfree(curr); + if (act & HP_SDC_ACT_DEALLOC) kfree(curr); hp_sdc.tq[curridx] = NULL; - } else { + } + else { curr->actidx = idx + 1; curr->idx = idx + 2; } /* Interleave outbound data between the transactions. */ hp_sdc.wcurr++; - if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) - hp_sdc.wcurr = 0; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; finish: - /* If by some quirk IBF has cleared and our ISR has run to + /* If by some quirk IBF has cleared and our ISR has run to see that that has happened, do it all again. */ - if (!hp_sdc.ibf && limit++ < 20) - goto anew; + if (!hp_sdc.ibf && limit++ < 20) goto anew; done: - if (hp_sdc.wcurr >= 0) - tasklet_schedule(&hp_sdc.task); + if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task); write_unlock(&hp_sdc.lock); - return 0; } /******* Functions called in either user or kernel context ****/ -int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this) -{ +int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { + unsigned long flags; int i; if (this == NULL) { - BUG(); + tasklet_schedule(&hp_sdc.task); return -EINVAL; - } + }; + + write_lock_irqsave(&hp_sdc.lock, flags); /* Can't have same transaction on queue twice */ - for (i = 0; i < HP_SDC_QUEUE_LEN; i++) - if (hp_sdc.tq[i] == this) - goto fail; + for (i=0; i < HP_SDC_QUEUE_LEN; i++) + if (hp_sdc.tq[i] == this) goto fail; this->actidx = 0; this->idx = 1; /* Search for empty slot */ - for (i = 0; i < HP_SDC_QUEUE_LEN; i++) + for (i=0; i < HP_SDC_QUEUE_LEN; i++) { if (hp_sdc.tq[i] == NULL) { hp_sdc.tq[i] = this; + write_unlock_irqrestore(&hp_sdc.lock, flags); tasklet_schedule(&hp_sdc.task); return 0; } - + } + write_unlock_irqrestore(&hp_sdc.lock, flags); printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); return -EBUSY; fail: + write_unlock_irqrestore(&hp_sdc.lock,flags); printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); return -EINVAL; } -int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { - unsigned long flags; - int ret; - - write_lock_irqsave(&hp_sdc.lock, flags); - ret = __hp_sdc_enqueue_transaction(this); - write_unlock_irqrestore(&hp_sdc.lock,flags); - - return ret; -} - -int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) -{ +int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) { unsigned long flags; int i; @@ -647,9 +595,8 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) /* TODO: don't remove it if it's not done. */ - for (i = 0; i < HP_SDC_QUEUE_LEN; i++) - if (hp_sdc.tq[i] == this) - hp_sdc.tq[i] = NULL; + for (i=0; i < HP_SDC_QUEUE_LEN; i++) + if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL; write_unlock_irqrestore(&hp_sdc.lock, flags); return 0; @@ -658,11 +605,11 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) /********************** User context functions **************************/ -int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) -{ - if (callback == NULL || hp_sdc.dev == NULL) - return -EINVAL; +int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) { + if (callback == NULL || hp_sdc.dev == NULL) { + return -EINVAL; + } write_lock_irq(&hp_sdc.hook_lock); if (hp_sdc.timer != NULL) { write_unlock_irq(&hp_sdc.hook_lock); @@ -682,11 +629,11 @@ int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) return 0; } -int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) -{ - if (callback == NULL || hp_sdc.dev == NULL) - return -EINVAL; +int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) { + if (callback == NULL || hp_sdc.dev == NULL) { + return -EINVAL; + } write_lock_irq(&hp_sdc.hook_lock); if (hp_sdc.hil != NULL) { write_unlock_irq(&hp_sdc.hook_lock); @@ -703,11 +650,11 @@ int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) return 0; } -int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) -{ - if (callback == NULL || hp_sdc.dev == NULL) - return -EINVAL; +int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) { + if (callback == NULL || hp_sdc.dev == NULL) { + return -EINVAL; + } write_lock_irq(&hp_sdc.hook_lock); if (hp_sdc.cooked != NULL) { write_unlock_irq(&hp_sdc.hook_lock); @@ -725,8 +672,9 @@ int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) return 0; } -int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) -{ +int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) { + + write_lock_irq(&hp_sdc.hook_lock); if ((callback != hp_sdc.timer) || (hp_sdc.timer == NULL)) { @@ -746,8 +694,8 @@ int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) return 0; } -int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) -{ +int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) { + write_lock_irq(&hp_sdc.hook_lock); if ((callback != hp_sdc.hil) || (hp_sdc.hil == NULL)) { @@ -767,8 +715,8 @@ int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) return 0; } -int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) -{ +int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) { + write_lock_irq(&hp_sdc.hook_lock); if ((callback != hp_sdc.cooked) || (hp_sdc.cooked == NULL)) { @@ -790,8 +738,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) /************************* Keepalive timer task *********************/ -void hp_sdc_kicker (unsigned long data) -{ +void hp_sdc_kicker (unsigned long data) { tasklet_schedule(&hp_sdc.task); /* Re-insert the periodic task. */ mod_timer(&hp_sdc.kicker, jiffies + HZ); @@ -801,12 +748,12 @@ void hp_sdc_kicker (unsigned long data) #if defined(__hppa__) -static const struct parisc_device_id hp_sdc_tbl[] = { +static struct parisc_device_id hp_sdc_tbl[] = { { - .hw_type = HPHW_FIO, + .hw_type = HPHW_FIO, .hversion_rev = HVERSION_REV_ANY_ID, .hversion = HVERSION_ANY_ID, - .sversion = 0x73, + .sversion = 0x73, }, { 0, } }; @@ -825,15 +772,16 @@ static struct parisc_driver hp_sdc_driver = { static int __init hp_sdc_init(void) { + int i; char *errstr; hp_sdc_transaction t_sync; uint8_t ts_sync[6]; struct semaphore s_sync; - rwlock_init(&hp_sdc.lock); - rwlock_init(&hp_sdc.ibf_lock); - rwlock_init(&hp_sdc.rtq_lock); - rwlock_init(&hp_sdc.hook_lock); + rwlock_init(&hp_sdc.lock); + rwlock_init(&hp_sdc.ibf_lock); + rwlock_init(&hp_sdc.rtq_lock); + rwlock_init(&hp_sdc.hook_lock); hp_sdc.timer = NULL; hp_sdc.hil = NULL; @@ -848,8 +796,7 @@ static int __init hp_sdc_init(void) hp_sdc.r7[3] = 0xff; hp_sdc.ibf = 1; - memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq)); - + for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL; hp_sdc.wcurr = -1; hp_sdc.rcurr = -1; hp_sdc.rqty = 0; @@ -857,32 +804,27 @@ static int __init hp_sdc_init(void) hp_sdc.dev_err = -ENODEV; errstr = "IO not found for"; - if (!hp_sdc.base_io) - goto err0; + if (!hp_sdc.base_io) goto err0; errstr = "IRQ not found for"; - if (!hp_sdc.irq) - goto err0; + if (!hp_sdc.irq) goto err0; hp_sdc.dev_err = -EBUSY; #if defined(__hppa__) errstr = "IO not available for"; - if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) - goto err0; -#endif + if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0; +#endif errstr = "IRQ not available for"; - if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED|IRQF_SAMPLE_RANDOM, - "HP SDC", &hp_sdc)) - goto err1; + if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC", + (void *) hp_sdc.base_io)) goto err1; errstr = "NMI not available for"; - if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED, - "HP SDC NMI", &hp_sdc)) - goto err2; + if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", + (void *) hp_sdc.base_io)) goto err2; - printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", + printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); hp_sdc_status_in8(); @@ -912,14 +854,13 @@ static int __init hp_sdc_init(void) hp_sdc.dev_err = 0; return 0; err2: - free_irq(hp_sdc.irq, &hp_sdc); + free_irq(hp_sdc.irq, NULL); err1: release_region(hp_sdc.data_io, 2); err0: - printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", + printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); hp_sdc.dev = NULL; - return hp_sdc.dev_err; } @@ -927,10 +868,8 @@ static int __init hp_sdc_init(void) static int __init hp_sdc_init_hppa(struct parisc_device *d) { - if (!d) - return 1; - if (hp_sdc.dev != NULL) - return 1; /* We only expect one SDC */ + if (!d) return 1; + if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */ hp_sdc.dev = d; hp_sdc.irq = d->irq; @@ -959,16 +898,18 @@ static void hp_sdc_exit(void) /* Wait until we know this has been processed by the i8042 */ hp_sdc_spin_ibf(); - free_irq(hp_sdc.nmi, &hp_sdc); - free_irq(hp_sdc.irq, &hp_sdc); + free_irq(hp_sdc.nmi, NULL); + free_irq(hp_sdc.irq, NULL); write_unlock_irq(&hp_sdc.lock); del_timer(&hp_sdc.kicker); tasklet_kill(&hp_sdc.task); +/* release_region(hp_sdc.data_io, 2); */ + #if defined(__hppa__) - if (unregister_parisc_driver(&hp_sdc_driver)) + if (unregister_parisc_driver(&hp_sdc_driver)) printk(KERN_WARNING PREFIX "Error unregistering HP SDC"); #endif } @@ -982,7 +923,7 @@ static int __init hp_sdc_register(void) mm_segment_t fs; unsigned char i; #endif - + hp_sdc.dev = NULL; hp_sdc.dev_err = 0; #if defined(__hppa__) @@ -1019,8 +960,8 @@ static int __init hp_sdc_register(void) tq_init.seq = tq_init_seq; tq_init.act.semaphore = &tq_init_sem; - tq_init_seq[0] = - HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; + tq_init_seq[0] = + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; tq_init_seq[1] = HP_SDC_CMD_READ_KCC; tq_init_seq[2] = 1; tq_init_seq[3] = 0; @@ -1038,13 +979,13 @@ static int __init hp_sdc_register(void) } hp_sdc.r11 = tq_init_seq[4]; if (hp_sdc.r11 & HP_SDC_CFG_NEW) { - const char *str; + char *str; printk(KERN_INFO PREFIX "New style SDC\n"); tq_init_seq[1] = HP_SDC_CMD_READ_XTD; tq_init.actidx = 0; tq_init.idx = 1; down(&tq_init_sem); - hp_sdc_enqueue_transaction(&tq_init); + hp_sdc_enqueue_transaction(&tq_init); down(&tq_init_sem); up(&tq_init_sem); if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { @@ -1054,13 +995,15 @@ static int __init hp_sdc_register(void) hp_sdc.r7e = tq_init_seq[4]; HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str) printk(KERN_INFO PREFIX "Revision: %s\n", str); - if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) + if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) { printk(KERN_INFO PREFIX "TI SN76494 beeper present\n"); - if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) + } + if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) { printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n"); + } printk(KERN_INFO PREFIX "Spunking the self test register to force PUP " "on next firmware reset.\n"); - tq_init_seq[0] = HP_SDC_ACT_PRECMD | + tq_init_seq[0] = HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; tq_init_seq[1] = HP_SDC_CMD_SET_STR; tq_init_seq[2] = 1; @@ -1069,12 +1012,14 @@ static int __init hp_sdc_register(void) tq_init.idx = 1; tq_init.endidx = 4; down(&tq_init_sem); - hp_sdc_enqueue_transaction(&tq_init); + hp_sdc_enqueue_transaction(&tq_init); down(&tq_init_sem); up(&tq_init_sem); - } else - printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", + } + else { + printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087"); + } return 0; } @@ -1082,13 +1027,13 @@ static int __init hp_sdc_register(void) module_init(hp_sdc_register); module_exit(hp_sdc_exit); -/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64) +/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64) * cycles cycles-adj time * between two consecutive mfctl(16)'s: 4 n/a 63ns * hp_sdc_spin_ibf when idle: 119 115 1.7us * gsc_writeb status register: 83 79 1.2us * IBF to clear after sending SET_IM: 6204 6006 93us - * IBF to clear after sending LOAD_RT: 4467 4352 68us + * IBF to clear after sending LOAD_RT: 4467 4352 68us * IBF to clear after sending two LOAD_RTs: 18974 18859 295us * READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us * cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms diff --git a/trunk/drivers/input/serio/hp_sdc_mlc.c b/trunk/drivers/input/serio/hp_sdc_mlc.c index c45ea74d53e4..aa4a8a4ccfdb 100644 --- a/trunk/drivers/input/serio/hp_sdc_mlc.c +++ b/trunk/drivers/input/serio/hp_sdc_mlc.c @@ -58,13 +58,12 @@ struct hp_sdc_mlc_priv_s { } hp_sdc_mlc_priv; /************************* Interrupt context ******************************/ -static void hp_sdc_mlc_isr (int irq, void *dev_id, - uint8_t status, uint8_t data) -{ - int idx; +static void hp_sdc_mlc_isr (int irq, void *dev_id, + uint8_t status, uint8_t data) { + int idx; hil_mlc *mlc = &hp_sdc_mlc; - write_lock(&mlc->lock); + write_lock(&(mlc->lock)); if (mlc->icount < 0) { printk(KERN_WARNING PREFIX "HIL Overflow!\n"); up(&mlc->isem); @@ -74,232 +73,239 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id, if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { mlc->ipacket[idx] |= data | HIL_ERR_INT; mlc->icount--; - if (hp_sdc_mlc_priv.got5x || !idx) - goto check; - if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) != + if (hp_sdc_mlc_priv.got5x) goto check; + if (!idx) goto check; + if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) != (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; - mlc->ipacket[idx] |= (mlc->ipacket[idx - 1] - & HIL_PKT_ADDR_MASK); + mlc->ipacket[idx] |= (mlc->ipacket[idx-1] + & HIL_PKT_ADDR_MASK); } goto check; } /* We know status is 5X */ - if (data & HP_SDC_HIL_ISERR) - goto err; - mlc->ipacket[idx] = + if (data & HP_SDC_HIL_ISERR) goto err; + mlc->ipacket[idx] = (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; hp_sdc_mlc_priv.got5x = 1; goto out; check: hp_sdc_mlc_priv.got5x = 0; - if (mlc->imatch == 0) - goto done; - if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - && (mlc->ipacket[idx] == (mlc->imatch | idx))) - goto done; - if (mlc->ipacket[idx] == mlc->imatch) - goto done; + if (mlc->imatch == 0) goto done; + if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) + && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done; + if (mlc->ipacket[idx] == mlc->imatch) goto done; goto out; - err: + err: printk(KERN_DEBUG PREFIX "err code %x\n", data); - switch (data) { case HP_SDC_HIL_RC_DONE: printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); break; - case HP_SDC_HIL_ERR: - mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | - HIL_ERR_FERR | HIL_ERR_FOF; + mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | + HIL_ERR_FERR | HIL_ERR_FOF; break; - case HP_SDC_HIL_TO: mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; break; - case HP_SDC_HIL_RC: printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); break; - default: printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data); break; } - /* No more data will be coming due to an error. */ done: tasklet_schedule(mlc->tasklet); - up(&mlc->isem); + up(&(mlc->isem)); out: - write_unlock(&mlc->lock); + write_unlock(&(mlc->lock)); } /******************** Tasklet or userspace context functions ****************/ -static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) -{ +static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) { + unsigned long flags; struct hp_sdc_mlc_priv_s *priv; int rc = 2; priv = mlc->priv; + write_lock_irqsave(&(mlc->lock), flags); + /* Try to down the semaphore */ - if (down_trylock(&mlc->isem)) { + if (down_trylock(&(mlc->isem))) { struct timeval tv; if (priv->emtestmode) { - mlc->ipacket[0] = - HIL_ERR_INT | (mlc->opacket & - (HIL_PKT_CMD | - HIL_PKT_ADDR_MASK | + mlc->ipacket[0] = + HIL_ERR_INT | (mlc->opacket & + (HIL_PKT_CMD | + HIL_PKT_ADDR_MASK | HIL_PKT_DATA_MASK)); mlc->icount = 14; /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ goto wasup; } do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); + tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { - /* printk("!%i %i", - tv.tv_usec - mlc->instart.tv_usec, - mlc->intimeout); - */ + /* printk("!%i %i", + tv.tv_usec - mlc->instart.tv_usec, + mlc->intimeout); + */ rc = 1; - up(&mlc->isem); + up(&(mlc->isem)); } goto done; } wasup: - up(&mlc->isem); + up(&(mlc->isem)); rc = 0; + goto done; done: + write_unlock_irqrestore(&(mlc->lock), flags); return rc; } -static int hp_sdc_mlc_cts(hil_mlc *mlc) -{ +static int hp_sdc_mlc_cts (hil_mlc *mlc) { struct hp_sdc_mlc_priv_s *priv; + unsigned long flags; - priv = mlc->priv; - - /* Try to down the semaphores -- they should be up. */ - BUG_ON(down_trylock(&mlc->isem)); - BUG_ON(down_trylock(&mlc->osem)); + priv = mlc->priv; - up(&mlc->isem); - up(&mlc->osem); + write_lock_irqsave(&(mlc->lock), flags); - if (down_trylock(&mlc->csem)) { - if (priv->trans.act.semaphore != &mlc->csem) - goto poll; - else - goto busy; + /* Try to down the semaphores -- they should be up. */ + if (down_trylock(&(mlc->isem))) { + BUG(); + goto busy; + } + if (down_trylock(&(mlc->osem))) { + BUG(); + up(&(mlc->isem)); + goto busy; } + up(&(mlc->isem)); + up(&(mlc->osem)); - if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) - goto done; + if (down_trylock(&(mlc->csem))) { + if (priv->trans.act.semaphore != &(mlc->csem)) goto poll; + goto busy; + } + if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done; poll: - priv->trans.act.semaphore = &mlc->csem; + priv->trans.act.semaphore = &(mlc->csem); priv->trans.actidx = 0; priv->trans.idx = 1; priv->trans.endidx = 5; - priv->tseq[0] = + priv->tseq[0] = HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; priv->tseq[1] = HP_SDC_CMD_READ_USE; priv->tseq[2] = 1; priv->tseq[3] = 0; priv->tseq[4] = 0; - __hp_sdc_enqueue_transaction(&priv->trans); + hp_sdc_enqueue_transaction(&(priv->trans)); busy: + write_unlock_irqrestore(&(mlc->lock), flags); return 1; done: - priv->trans.act.semaphore = &mlc->osem; - up(&mlc->csem); + priv->trans.act.semaphore = &(mlc->osem); + up(&(mlc->csem)); + write_unlock_irqrestore(&(mlc->lock), flags); return 0; } -static void hp_sdc_mlc_out(hil_mlc *mlc) -{ +static void hp_sdc_mlc_out (hil_mlc *mlc) { struct hp_sdc_mlc_priv_s *priv; + unsigned long flags; priv = mlc->priv; + write_lock_irqsave(&(mlc->lock), flags); + /* Try to down the semaphore -- it should be up. */ - BUG_ON(down_trylock(&mlc->osem)); + if (down_trylock(&(mlc->osem))) { + BUG(); + goto done; + } - if (mlc->opacket & HIL_DO_ALTER_CTRL) - goto do_control; + if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control; do_data: if (priv->emtestmode) { - up(&mlc->osem); - return; + up(&(mlc->osem)); + goto done; } /* Shouldn't be sending commands when loop may be busy */ - BUG_ON(down_trylock(&mlc->csem)); - up(&mlc->csem); + if (down_trylock(&(mlc->csem))) { + BUG(); + goto done; + } + up(&(mlc->csem)); priv->trans.actidx = 0; priv->trans.idx = 1; - priv->trans.act.semaphore = &mlc->osem; + priv->trans.act.semaphore = &(mlc->osem); priv->trans.endidx = 6; - priv->tseq[0] = + priv->tseq[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; priv->tseq[1] = 0x7; - priv->tseq[2] = - (mlc->opacket & + priv->tseq[2] = + (mlc->opacket & (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) >> HIL_PKT_ADDR_SHIFT; - priv->tseq[3] = - (mlc->opacket & HIL_PKT_DATA_MASK) + priv->tseq[3] = + (mlc->opacket & HIL_PKT_DATA_MASK) >> HIL_PKT_DATA_SHIFT; priv->tseq[4] = 0; /* No timeout */ - if (priv->tseq[3] == HIL_CMD_DHR) - priv->tseq[4] = 1; + if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1; priv->tseq[5] = HP_SDC_CMD_DO_HIL; goto enqueue; do_control: priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; - + /* we cannot emulate this, it should not be used. */ BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE); - - if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) - goto control_only; - - /* Should not send command/data after engaging APE */ - BUG_ON(mlc->opacket & HIL_CTRL_APE); - - /* Disengaging APE this way would not be valid either since + + if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only; + if (mlc->opacket & HIL_CTRL_APE) { + BUG(); /* Should not send command/data after engaging APE */ + goto done; + } + /* Disengaging APE this way would not be valid either since * the loop must be allowed to idle. * - * So, it works out that we really never actually send control - * and data when using SDC, we just send the data. + * So, it works out that we really never actually send control + * and data when using SDC, we just send the data. */ goto do_data; control_only: priv->trans.actidx = 0; priv->trans.idx = 1; - priv->trans.act.semaphore = &mlc->osem; + priv->trans.act.semaphore = &(mlc->osem); priv->trans.endidx = 4; - priv->tseq[0] = + priv->tseq[0] = HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; priv->tseq[1] = HP_SDC_CMD_SET_LPC; priv->tseq[2] = 1; - /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */ + // priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; priv->tseq[3] = 0; if (mlc->opacket & HIL_CTRL_APE) { priv->tseq[3] |= HP_SDC_LPC_APE_IPF; - down_trylock(&mlc->csem); - } + down_trylock(&(mlc->csem)); + } enqueue: - hp_sdc_enqueue_transaction(&priv->trans); + hp_sdc_enqueue_transaction(&(priv->trans)); + done: + write_unlock_irqrestore(&(mlc->lock), flags); } static int __init hp_sdc_mlc_init(void) @@ -310,18 +316,18 @@ static int __init hp_sdc_mlc_init(void) hp_sdc_mlc_priv.emtestmode = 0; hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; - hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem; + hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem); hp_sdc_mlc_priv.got5x = 0; - mlc->cts = &hp_sdc_mlc_cts; - mlc->in = &hp_sdc_mlc_in; - mlc->out = &hp_sdc_mlc_out; - mlc->priv = &hp_sdc_mlc_priv; + mlc->cts = &hp_sdc_mlc_cts; + mlc->in = &hp_sdc_mlc_in; + mlc->out = &hp_sdc_mlc_out; if (hil_mlc_register(mlc)) { printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); goto err0; } + mlc->priv = &hp_sdc_mlc_priv; if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); @@ -329,9 +335,10 @@ static int __init hp_sdc_mlc_init(void) } return 0; err1: - if (hil_mlc_unregister(mlc)) + if (hil_mlc_unregister(mlc)) { printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" "This is bad. Could cause an oops.\n"); + } err0: return -EBUSY; } @@ -339,14 +346,14 @@ static int __init hp_sdc_mlc_init(void) static void __exit hp_sdc_mlc_exit(void) { hil_mlc *mlc = &hp_sdc_mlc; - - if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) + if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) { printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" "This is bad. Could cause an oops.\n"); - - if (hil_mlc_unregister(mlc)) + } + if (hil_mlc_unregister(mlc)) { printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" "This is bad. Could cause an oops.\n"); + } } module_init(hp_sdc_mlc_init); diff --git a/trunk/drivers/input/serio/i8042-x86ia64io.h b/trunk/drivers/input/serio/i8042-x86ia64io.h index 6858bc58f0fd..d36bd5475b6d 100644 --- a/trunk/drivers/input/serio/i8042-x86ia64io.h +++ b/trunk/drivers/input/serio/i8042-x86ia64io.h @@ -159,28 +159,6 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), }, }, - { - /* - * No data is coming from the touchscreen unless KBC - * is in legacy mode. - */ - .ident = "Panasonic CF-29", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), - DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), - }, - }, - { - /* - * Errors on MUX ports are reported without raising AUXDATA - * causing "spurious NAK" messages. - */ - .ident = "HP Pavilion DV4017EA", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), - }, - }, { .ident = "Toshiba P10", .matches = { @@ -302,8 +280,6 @@ static struct pnp_driver i8042_pnp_kbd_driver = { }; static struct pnp_device_id pnp_aux_devids[] = { - { .id = "FJC6000", .driver_data = 0 }, - { .id = "FJC6001", .driver_data = 0 }, { .id = "PNP0f03", .driver_data = 0 }, { .id = "PNP0f0b", .driver_data = 0 }, { .id = "PNP0f0e", .driver_data = 0 }, diff --git a/trunk/drivers/input/serio/i8042.c b/trunk/drivers/input/serio/i8042.c index 7c17377a65b9..db9cca3b65e0 100644 --- a/trunk/drivers/input/serio/i8042.c +++ b/trunk/drivers/input/serio/i8042.c @@ -767,13 +767,6 @@ static void i8042_controller_reset(void) { i8042_flush(); -/* - * Disable both KBD and AUX interfaces so they don't get in the way - */ - - i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; - i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); - /* * Disable MUX mode if present. */ diff --git a/trunk/drivers/input/serio/serio.c b/trunk/drivers/input/serio/serio.c index 5895202b972c..a15e531ec755 100644 --- a/trunk/drivers/input/serio/serio.c +++ b/trunk/drivers/input/serio/serio.c @@ -115,18 +115,18 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser * Basic serio -> driver core mappings */ -static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) +static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) { int error; - if (serio_match_port(drv->id_table, serio)) { + down_write(&serio_bus.subsys.rwsem); + if (serio_match_port(drv->id_table, serio)) { serio->dev.driver = &drv->driver; if (serio_connect_driver(serio, drv)) { serio->dev.driver = NULL; - return -ENODEV; + goto out; } - error = device_bind_driver(&serio->dev); if (error) { printk(KERN_WARNING @@ -136,21 +136,31 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) drv->description, error); serio_disconnect_driver(serio); serio->dev.driver = NULL; - return error; + goto out; } } - return 0; + out: + up_write(&serio_bus.subsys.rwsem); +} + +static void serio_release_driver(struct serio *serio) +{ + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); } static void serio_find_driver(struct serio *serio) { int error; + down_write(&serio_bus.subsys.rwsem); error = device_attach(&serio->dev); if (error < 0) printk(KERN_WARNING "serio: device_attach() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); + up_write(&serio_bus.subsys.rwsem); } @@ -460,12 +470,13 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * { struct serio *serio = to_serio_port(dev); struct device_driver *drv; - int error; + int retval; - error = mutex_lock_interruptible(&serio_mutex); - if (error) - return error; + retval = mutex_lock_interruptible(&serio_mutex); + if (retval) + return retval; + retval = count; if (!strncmp(buf, "none", count)) { serio_disconnect_port(serio); } else if (!strncmp(buf, "reconnect", count)) { @@ -475,15 +486,15 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * serio_find_driver(serio); } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { serio_disconnect_port(serio); - error = serio_bind_driver(serio, to_serio_driver(drv)); + serio_bind_driver(serio, to_serio_driver(drv)); put_driver(drv); } else { - error = -EINVAL; + retval = -EINVAL; } mutex_unlock(&serio_mutex); - return error ? error : count; + return retval; } static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) @@ -654,7 +665,7 @@ static void serio_disconnect_port(struct serio *serio) do { parent = s->parent; - device_release_driver(&s->dev); + serio_release_driver(s); serio_destroy_port(s); } while ((s = parent) != serio); } @@ -662,7 +673,7 @@ static void serio_disconnect_port(struct serio *serio) /* * Ok, no children left, now disconnect this port */ - device_release_driver(&serio->dev); + serio_release_driver(serio); } void serio_rescan(struct serio *serio) diff --git a/trunk/drivers/input/touchscreen/ads7846.c b/trunk/drivers/input/touchscreen/ads7846.c index 693e3b2a65a3..0a26e0663542 100644 --- a/trunk/drivers/input/touchscreen/ads7846.c +++ b/trunk/drivers/input/touchscreen/ads7846.c @@ -39,8 +39,7 @@ /* * This code has been heavily tested on a Nokia 770, and lightly * tested on other ads7846 devices (OSK/Mistral, Lubbock). - * Support for ads7843 tested on Atmel at91sam926x-EK. - * Support for ads7845 has only been stubbed in. + * Support for ads7843 and ads7845 has only been stubbed in. * * IRQ handling needs a workaround because of a shortcoming in handling * edge triggered IRQs on some platforms like the OMAP1/2. These @@ -247,16 +246,18 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) /* REVISIT: take a few more samples, and compare ... */ - /* converter in low power mode & enable PENIRQ */ - req->ref_off = PWRDOWN; - req->xfer[4].tx_buf = &req->ref_off; - req->xfer[4].len = 1; - spi_message_add_tail(&req->xfer[4], &req->msg); - - req->xfer[5].rx_buf = &req->scratch; - req->xfer[5].len = 2; - CS_CHANGE(req->xfer[5]); - spi_message_add_tail(&req->xfer[5], &req->msg); + /* maybe off internal vREF */ + if (use_internal) { + req->ref_off = REF_OFF; + req->xfer[4].tx_buf = &req->ref_off; + req->xfer[4].len = 1; + spi_message_add_tail(&req->xfer[4], &req->msg); + + req->xfer[5].rx_buf = &req->scratch; + req->xfer[5].len = 2; + CS_CHANGE(req->xfer[5]); + spi_message_add_tail(&req->xfer[5], &req->msg); + } ts->irq_disabled = 1; disable_irq(spi->irq); @@ -535,9 +536,6 @@ static void ads7846_rx(void *ads) } else Rt = 0; - if (ts->model == 7843) - Rt = ts->pressure_max / 2; - /* Sample found inconsistent by debouncing or pressure is beyond * the maximum. Don't report it to user space, repeat at least * once more the measurement @@ -899,7 +897,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) input_dev->name = "ADS784x Touchscreen"; input_dev->phys = ts->phys; - input_dev->dev.parent = &spi->dev; + input_dev->cdev.dev = &spi->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); diff --git a/trunk/drivers/input/touchscreen/corgi_ts.c b/trunk/drivers/input/touchscreen/corgi_ts.c index e6a31d118786..e2945582828e 100644 --- a/trunk/drivers/input/touchscreen/corgi_ts.c +++ b/trunk/drivers/input/touchscreen/corgi_ts.c @@ -300,7 +300,8 @@ static int __init corgits_probe(struct platform_device *pdev) input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0002; input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; + input_dev->cdev.dev = &pdev->dev; + input_dev->private = corgi_ts; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); diff --git a/trunk/drivers/input/touchscreen/elo.c b/trunk/drivers/input/touchscreen/elo.c index 557d781719f1..9d61cd133d01 100644 --- a/trunk/drivers/input/touchscreen/elo.c +++ b/trunk/drivers/input/touchscreen/elo.c @@ -312,13 +312,14 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) init_completion(&elo->cmd_done); snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); + input_dev->private = elo; input_dev->name = "Elo Serial TouchScreen"; input_dev->phys = elo->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_ELO; input_dev->id.product = elo->id; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); diff --git a/trunk/drivers/input/touchscreen/gunze.c b/trunk/drivers/input/touchscreen/gunze.c index 39d602600d7c..9157eb148e84 100644 --- a/trunk/drivers/input/touchscreen/gunze.c +++ b/trunk/drivers/input/touchscreen/gunze.c @@ -130,13 +130,13 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv) gunze->dev = input_dev; snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); + input_dev->private = gunze; input_dev->name = "Gunze AHL-51S TouchScreen"; input_dev->phys = gunze->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_GUNZE; input_dev->id.product = 0x0051; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0); diff --git a/trunk/drivers/input/touchscreen/h3600_ts_input.c b/trunk/drivers/input/touchscreen/h3600_ts_input.c index 09ed7803cb8f..c4116d4f64e7 100644 --- a/trunk/drivers/input/touchscreen/h3600_ts_input.c +++ b/trunk/drivers/input/touchscreen/h3600_ts_input.c @@ -147,7 +147,7 @@ enum flite_pwr { unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) { unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness; - struct h3600_dev *ts = input_get_drvdata(dev); + struct h3600_dev *ts = dev->private; /* Must be in this order */ ts->serio->write(ts->serio, 1); @@ -260,7 +260,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { #if 0 - struct h3600_dev *ts = input_get_drvdata(dev); + struct h3600_dev *ts = dev->private; switch (type) { case EV_LED: { @@ -367,9 +367,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) input_dev->id.vendor = SERIO_H3600; input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */ input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; - - input_set_drvdata(input_dev, ts); + input_dev->cdev.dev = &serio->dev; + input_dev->private = ts; input_dev->event = h3600ts_event; diff --git a/trunk/drivers/input/touchscreen/mtouch.c b/trunk/drivers/input/touchscreen/mtouch.c index 4ec3b1f940c8..c3c2d735d0ec 100644 --- a/trunk/drivers/input/touchscreen/mtouch.c +++ b/trunk/drivers/input/touchscreen/mtouch.c @@ -144,13 +144,13 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv) mtouch->dev = input_dev; snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys); + input_dev->private = mtouch; input_dev->name = "MicroTouch Serial TouchScreen"; input_dev->phys = mtouch->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_MICROTOUCH; input_dev->id.product = 0; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0); diff --git a/trunk/drivers/input/touchscreen/penmount.c b/trunk/drivers/input/touchscreen/penmount.c index f2c0d3c7149c..bd2767991ae9 100644 --- a/trunk/drivers/input/touchscreen/penmount.c +++ b/trunk/drivers/input/touchscreen/penmount.c @@ -105,13 +105,14 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) pm->dev = input_dev; snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); + input_dev->private = pm; input_dev->name = "Penmount Serial TouchScreen"; input_dev->phys = pm->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_PENMOUNT; input_dev->id.product = 0; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; + input_dev->cdev.dev = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); diff --git a/trunk/drivers/input/touchscreen/touchright.c b/trunk/drivers/input/touchscreen/touchright.c index 3def7bb1df44..35ba46c6ad2d 100644 --- a/trunk/drivers/input/touchscreen/touchright.c +++ b/trunk/drivers/input/touchscreen/touchright.c @@ -118,13 +118,13 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv) tr->dev = input_dev; snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); + input_dev->private = tr; input_dev->name = "Touchright Serial TouchScreen"; input_dev->phys = tr->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_TOUCHRIGHT; input_dev->id.product = 0; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); diff --git a/trunk/drivers/input/touchscreen/touchwin.c b/trunk/drivers/input/touchscreen/touchwin.c index ac4bdcf18666..4dc073dacabb 100644 --- a/trunk/drivers/input/touchscreen/touchwin.c +++ b/trunk/drivers/input/touchscreen/touchwin.c @@ -125,13 +125,13 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv) tw->dev = input_dev; snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); + input_dev->private = tw; input_dev->name = "Touchwindow Serial TouchScreen"; input_dev->phys = tw->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_TOUCHWIN; input_dev->id.product = 0; input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); diff --git a/trunk/drivers/input/touchscreen/ucb1400_ts.c b/trunk/drivers/input/touchscreen/ucb1400_ts.c index 6582816a0477..e8606c48c9c3 100644 --- a/trunk/drivers/input/touchscreen/ucb1400_ts.c +++ b/trunk/drivers/input/touchscreen/ucb1400_ts.c @@ -97,8 +97,6 @@ struct ucb1400 { }; static int adcsync; -static int ts_delay = 55; /* us */ -static int ts_delay_pressure; /* us */ static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg) { @@ -161,7 +159,6 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb) UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); - udelay(ts_delay_pressure); return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); } @@ -183,7 +180,7 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb) UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - udelay(ts_delay); + udelay(55); return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); } @@ -206,7 +203,7 @@ static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb) UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - udelay(ts_delay); + udelay(55); return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX); } @@ -372,7 +369,7 @@ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) static int ucb1400_ts_open(struct input_dev *idev) { - struct ucb1400 *ucb = input_get_drvdata(idev); + struct ucb1400 *ucb = idev->private; int ret = 0; BUG_ON(ucb->ts_task); @@ -388,7 +385,7 @@ static int ucb1400_ts_open(struct input_dev *idev) static void ucb1400_ts_close(struct input_dev *idev) { - struct ucb1400 *ucb = input_get_drvdata(idev); + struct ucb1400 *ucb = idev->private; if (ucb->ts_task) kthread_stop(ucb->ts_task); @@ -510,9 +507,8 @@ static int ucb1400_ts_probe(struct device *dev) } printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq); - input_set_drvdata(idev, ucb); - - idev->dev.parent = dev; + idev->private = ucb; + idev->cdev.dev = dev; idev->name = "UCB1400 touchscreen interface"; idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1); idev->id.product = id; @@ -575,15 +571,7 @@ static void __exit ucb1400_ts_exit(void) driver_unregister(&ucb1400_ts_driver); } -module_param(adcsync, bool, 0444); -MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin."); - -module_param(ts_delay, int, 0444); -MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us."); - -module_param(ts_delay_pressure, int, 0444); -MODULE_PARM_DESC(ts_delay_pressure, - "delay between panel setup and pressure read. Default = 0us."); +module_param(adcsync, int, 0444); module_init(ucb1400_ts_init); module_exit(ucb1400_ts_exit); diff --git a/trunk/drivers/input/tsdev.c b/trunk/drivers/input/tsdev.c index 5e5b5c91d75b..0300dca8591d 100644 --- a/trunk/drivers/input/tsdev.c +++ b/trunk/drivers/input/tsdev.c @@ -111,13 +111,13 @@ struct tsdev { int minor; char name[8]; wait_queue_head_t wait; - struct list_head client_list; + struct list_head list; struct input_handle handle; int x, y, pressure; struct ts_calibration cal; }; -struct tsdev_client { +struct tsdev_list { struct fasync_struct *fasync; struct list_head node; struct tsdev *tsdev; @@ -139,49 +139,38 @@ static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) { - struct tsdev_client *client = file->private_data; + struct tsdev_list *list = file->private_data; int retval; - retval = fasync_helper(fd, file, on, &client->fasync); + retval = fasync_helper(fd, file, on, &list->fasync); return retval < 0 ? retval : 0; } static int tsdev_open(struct inode *inode, struct file *file) { int i = iminor(inode) - TSDEV_MINOR_BASE; - struct tsdev_client *client; - struct tsdev *tsdev; - int error; + struct tsdev_list *list; printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " "for removal.\nSee Documentation/feature-removal-schedule.txt " "for details.\n"); - if (i >= TSDEV_MINORS) - return -ENODEV; - - tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; - if (!tsdev || !tsdev->exist) + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; - client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); - if (!client) + if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; - client->tsdev = tsdev; - client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; - list_add_tail(&client->node, &tsdev->client_list); + list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; - if (!tsdev->open++ && tsdev->exist) { - error = input_open_device(&tsdev->handle); - if (error) { - list_del(&client->node); - kfree(client); - return error; - } - } + i &= TSDEV_MINOR_MASK; + list->tsdev = tsdev_table[i]; + list_add_tail(&list->node, &tsdev_table[i]->list); + file->private_data = list; - file->private_data = client; + if (!list->tsdev->open++) + if (list->tsdev->exist) + input_open_device(&list->tsdev->handle); return 0; } @@ -193,48 +182,45 @@ static void tsdev_free(struct tsdev *tsdev) static int tsdev_release(struct inode *inode, struct file *file) { - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; + struct tsdev_list *list = file->private_data; tsdev_fasync(-1, file, 0); + list_del(&list->node); - list_del(&client->node); - kfree(client); - - if (!--tsdev->open) { - if (tsdev->exist) - input_close_device(&tsdev->handle); + if (!--list->tsdev->open) { + if (list->tsdev->exist) + input_close_device(&list->tsdev->handle); else - tsdev_free(tsdev); + tsdev_free(list->tsdev); } - + kfree(list); return 0; } static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, - loff_t *ppos) + loff_t * ppos) { - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; + struct tsdev_list *list = file->private_data; int retval = 0; - if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) + if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(tsdev->wait, - client->head != client->tail || !tsdev->exist); + retval = wait_event_interruptible(list->tsdev->wait, + list->head != list->tail || !list->tsdev->exist); + if (retval) return retval; - if (!tsdev->exist) + if (!list->tsdev->exist) return -ENODEV; - while (client->head != client->tail && + while (list->head != list->tail && retval + sizeof (struct ts_event) <= count) { - if (copy_to_user (buffer + retval, client->event + client->tail, + if (copy_to_user (buffer + retval, list->event + list->tail, sizeof (struct ts_event))) return -EFAULT; - client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1); + list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); retval += sizeof (struct ts_event); } @@ -242,33 +228,32 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, } /* No kernel lock - fine */ -static unsigned int tsdev_poll(struct file *file, poll_table *wait) +static unsigned int tsdev_poll(struct file *file, poll_table * wait) { - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; + struct tsdev_list *list = file->private_data; - poll_wait(file, &tsdev->wait, wait); - return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | - (tsdev->exist ? 0 : (POLLHUP | POLLERR)); + poll_wait(file, &list->tsdev->wait, wait); + return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | + (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); } static int tsdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct tsdev_client *client = file->private_data; - struct tsdev *tsdev = client->tsdev; + struct tsdev_list *list = file->private_data; + struct tsdev *tsdev = list->tsdev; int retval = 0; switch (cmd) { case TS_GET_CAL: - if (copy_to_user((void __user *)arg, &tsdev->cal, - sizeof (struct ts_calibration))) + if (copy_to_user ((void __user *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) retval = -EFAULT; break; case TS_SET_CAL: - if (copy_from_user(&tsdev->cal, (void __user *)arg, - sizeof (struct ts_calibration))) + if (copy_from_user (&tsdev->cal, (void __user *)arg, + sizeof (struct ts_calibration))) retval = -EFAULT; break; @@ -294,7 +279,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct tsdev *tsdev = handle->private; - struct tsdev_client *client; + struct tsdev_list *list; struct timeval time; switch (type) { @@ -358,18 +343,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, if (type != EV_SYN || code != SYN_REPORT) return; - list_for_each_entry(client, &tsdev->client_list, node) { + list_for_each_entry(list, &tsdev->list, node) { int x, y, tmp; do_gettimeofday(&time); - client->event[client->head].millisecs = time.tv_usec / 100; - client->event[client->head].pressure = tsdev->pressure; + list->event[list->head].millisecs = time.tv_usec / 100; + list->event[list->head].pressure = tsdev->pressure; x = tsdev->x; y = tsdev->y; /* Calibration */ - if (!client->raw) { + if (!list->raw) { x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; if (tsdev->cal.xyswap) { @@ -377,35 +362,33 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, } } - client->event[client->head].x = x; - client->event[client->head].y = y; - client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1); - kill_fasync(&client->fasync, SIGIO, POLL_IN); + list->event[list->head].x = x; + list->event[list->head].y = y; + list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&tsdev->wait); } -static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) +static struct input_handle *tsdev_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) { struct tsdev *tsdev; struct class_device *cdev; - dev_t devt; int minor, delta; - int error; for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); if (minor >= TSDEV_MINORS / 2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); - return -ENFILE; + return NULL; } - tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); - if (!tsdev) - return -ENOMEM; + if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) + return NULL; - INIT_LIST_HEAD(&tsdev->client_list); + INIT_LIST_HEAD(&tsdev->list); init_waitqueue_head(&tsdev->wait); sprintf(tsdev->name, "ts%d", minor); @@ -432,45 +415,23 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, tsdev_table[minor] = tsdev; - devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), - - cdev = class_device_create(&input_class, &dev->cdev, devt, - dev->cdev.dev, tsdev->name); - if (IS_ERR(cdev)) { - error = PTR_ERR(cdev); - goto err_free_tsdev; - } + cdev = class_device_create(&input_class, &dev->cdev, + MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), + dev->cdev.dev, tsdev->name); /* temporary symlink to keep userspace happy */ - error = sysfs_create_link(&input_class.subsys.kobj, - &cdev->kobj, tsdev->name); - if (error) - goto err_cdev_destroy; - - error = input_register_handle(&tsdev->handle); - if (error) - goto err_remove_link; + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + tsdev->name); - return 0; - - err_remove_link: - sysfs_remove_link(&input_class.subsys.kobj, tsdev->name); - err_cdev_destroy: - class_device_destroy(&input_class, devt); - err_free_tsdev: - tsdev_table[minor] = NULL; - kfree(tsdev); - return error; + return &tsdev->handle; } static void tsdev_disconnect(struct input_handle *handle) { struct tsdev *tsdev = handle->private; - struct tsdev_client *client; - - input_unregister_handle(handle); + struct tsdev_list *list; - sysfs_remove_link(&input_class.subsys.kobj, tsdev->name); + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); tsdev->exist = 0; @@ -478,8 +439,8 @@ static void tsdev_disconnect(struct input_handle *handle) if (tsdev->open) { input_close_device(handle); wake_up_interruptible(&tsdev->wait); - list_for_each_entry(client, &tsdev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); + list_for_each_entry(list, &tsdev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); } else tsdev_free(tsdev); } diff --git a/trunk/drivers/isdn/act2000/module.c b/trunk/drivers/isdn/act2000/module.c index ee2b0b9f8f46..e3e5c1399076 100644 --- a/trunk/drivers/isdn/act2000/module.c +++ b/trunk/drivers/isdn/act2000/module.c @@ -442,7 +442,7 @@ act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb) return 0; } skb_reserve(xmit_skb, 19); - skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len); + memcpy(skb_put(xmit_skb, len), skb->data, len); } else { xmit_skb = skb_clone(skb, GFP_ATOMIC); if (!xmit_skb) { diff --git a/trunk/drivers/isdn/gigaset/usb-gigaset.c b/trunk/drivers/isdn/gigaset/usb-gigaset.c index c8e1c357cec8..2baef349c12d 100644 --- a/trunk/drivers/isdn/gigaset/usb-gigaset.c +++ b/trunk/drivers/isdn/gigaset/usb-gigaset.c @@ -652,7 +652,7 @@ static int write_modem(struct cardstate *cs) * transmit data */ count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); - skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); + memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); atomic_set(&ucs->busy, 1); gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); diff --git a/trunk/drivers/isdn/hardware/avm/b1dma.c b/trunk/drivers/isdn/hardware/avm/b1dma.c index 428872b653e9..1e2d38e3d68c 100644 --- a/trunk/drivers/isdn/hardware/avm/b1dma.c +++ b/trunk/drivers/isdn/hardware/avm/b1dma.c @@ -404,8 +404,7 @@ static void b1dma_dispatch_tx(avmcard *card) printk(KERN_DEBUG "tx: put 0x%x len=%d\n", skb->data[2], txlen); #endif - skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, - skb->len - 2); + memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); } txlen = (txlen + 3) & ~3; diff --git a/trunk/drivers/isdn/hardware/avm/c4.c b/trunk/drivers/isdn/hardware/avm/c4.c index d58f927e766a..6f5efa8d78cb 100644 --- a/trunk/drivers/isdn/hardware/avm/c4.c +++ b/trunk/drivers/isdn/hardware/avm/c4.c @@ -457,8 +457,7 @@ static void c4_dispatch_tx(avmcard *card) printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", card->name, skb->data[2], txlen); #endif - skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, - skb->len - 2); + memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); } txlen = (txlen + 3) & ~3; diff --git a/trunk/drivers/isdn/hisax/elsa_ser.c b/trunk/drivers/isdn/hisax/elsa_ser.c index 1642dca988a1..ae377e812775 100644 --- a/trunk/drivers/isdn/hisax/elsa_ser.c +++ b/trunk/drivers/isdn/hisax/elsa_ser.c @@ -254,16 +254,14 @@ write_modem(struct BCState *bcs) { count = len; if (count > MAX_MODEM_BUF - fp) { count = MAX_MODEM_BUF - fp; - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); + memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); cs->hw.elsa.transcnt += count; ret = count; count = len - count; fp = 0; } - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); + memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); cs->hw.elsa.transcnt += count; ret += count; diff --git a/trunk/drivers/isdn/hisax/isdnl2.c b/trunk/drivers/isdn/hisax/isdnl2.c index 3446f249d675..cd3b5ad53491 100644 --- a/trunk/drivers/isdn/hisax/isdnl2.c +++ b/trunk/drivers/isdn/hisax/isdnl2.c @@ -1293,8 +1293,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) oskb = skb; skb = alloc_skb(oskb->len + i, GFP_ATOMIC); memcpy(skb_put(skb, i), header, i); - skb_copy_from_linear_data(oskb, - skb_put(skb, oskb->len), oskb->len); + memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len); dev_kfree_skb(oskb); } st->l2.l2l1(st, PH_PULL | INDICATION, skb); diff --git a/trunk/drivers/isdn/hisax/netjet.c b/trunk/drivers/isdn/hisax/netjet.c index 02c6fbaeccf8..38f648f9b0ed 100644 --- a/trunk/drivers/isdn/hisax/netjet.c +++ b/trunk/drivers/isdn/hisax/netjet.c @@ -19,6 +19,7 @@ #include "isac.h" #include "hscx.h" #include "isdnl1.h" +#include #include #include #include diff --git a/trunk/drivers/isdn/hysdn/hycapi.c b/trunk/drivers/isdn/hysdn/hycapi.c index f85450146bdc..b2ae4ec1e49e 100644 --- a/trunk/drivers/isdn/hysdn/hycapi.c +++ b/trunk/drivers/isdn/hysdn/hycapi.c @@ -398,9 +398,8 @@ static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) _len = CAPIMSG_LEN(skb->data); if (_len > 22) { _len2 = _len - 22; - skb_copy_from_linear_data(skb, msghead, 22); - skb_copy_to_linear_data_offset(skb, _len2, - msghead, 22); + memcpy(msghead, skb->data, 22); + memcpy(skb->data + _len2, msghead, 22); skb_pull(skb, _len2); CAPIMSG_SETLEN(skb->data, 22); retval = capilib_data_b3_req(&cinfo->ncci_head, diff --git a/trunk/drivers/isdn/hysdn/hysdn_net.c b/trunk/drivers/isdn/hysdn/hysdn_net.c index cfa8fa5e44ab..557d96c78a62 100644 --- a/trunk/drivers/isdn/hysdn/hysdn_net.c +++ b/trunk/drivers/isdn/hysdn/hysdn_net.c @@ -214,6 +214,8 @@ hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len) lp->stats.rx_dropped++; return; } + skb->dev = &lp->netdev; + /* copy the data */ memcpy(skb_put(skb, len), buf, len); diff --git a/trunk/drivers/isdn/hysdn/hysdn_proclog.c b/trunk/drivers/isdn/hysdn/hysdn_proclog.c index 4c7dedac0e51..f7e83a86f444 100644 --- a/trunk/drivers/isdn/hysdn/hysdn_proclog.c +++ b/trunk/drivers/isdn/hysdn/hysdn_proclog.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "hysdn_defs.h" diff --git a/trunk/drivers/isdn/hysdn/hysdn_sched.c b/trunk/drivers/isdn/hysdn/hysdn_sched.c index 81db4a190d41..b7b5aa4748a0 100644 --- a/trunk/drivers/isdn/hysdn/hysdn_sched.c +++ b/trunk/drivers/isdn/hysdn/hysdn_sched.c @@ -113,8 +113,7 @@ hysdn_sched_tx(hysdn_card *card, unsigned char *buf, (skb = hysdn_tx_netget(card)) != NULL) { if (skb->len <= maxlen) { - /* copy the packet to the buffer */ - skb_copy_from_linear_data(skb, buf, skb->len); + memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */ *len = skb->len; *chan = CHAN_NDIS_DATA; card->net_tx_busy = 1; /* we are busy sending network data */ @@ -127,7 +126,7 @@ hysdn_sched_tx(hysdn_card *card, unsigned char *buf, ((skb = hycapi_tx_capiget(card)) != NULL) ) { if (skb->len <= maxlen) { - skb_copy_from_linear_data(skb, buf, skb->len); + memcpy(buf, skb->data, skb->len); *len = skb->len; *chan = CHAN_CAPI; hycapi_tx_capiack(card); diff --git a/trunk/drivers/isdn/i4l/isdn_common.c b/trunk/drivers/isdn/i4l/isdn_common.c index c97330b19877..9c926e41b114 100644 --- a/trunk/drivers/isdn/i4l/isdn_common.c +++ b/trunk/drivers/isdn/i4l/isdn_common.c @@ -829,7 +829,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que dflag = 0; } count_put = count_pull; - skb_copy_from_linear_data(skb, cp, count_put); + memcpy(cp, skb->data, count_put); cp += count_put; len -= count_put; #ifdef CONFIG_ISDN_AUDIO diff --git a/trunk/drivers/isdn/i4l/isdn_net.c b/trunk/drivers/isdn/i4l/isdn_net.c index aa83277aba74..838b3734e2b6 100644 --- a/trunk/drivers/isdn/i4l/isdn_net.c +++ b/trunk/drivers/isdn/i4l/isdn_net.c @@ -872,8 +872,7 @@ typedef struct { static void isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) { - /* hopefully, this was set correctly */ - const u_char *p = skb_network_header(skb); + u_char *p = skb->nh.raw; /* hopefully, this was set correctly */ unsigned short proto = ntohs(skb->protocol); int data_ofs; ip_ports *ipp; @@ -881,7 +880,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) addinfo[0] = '\0'; /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ - if (p < skb->data || skb->network_header >= skb->tail) { + if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) { /* fall back to old isdn_net_log_packet method() */ char * buf = skb->data; @@ -1122,7 +1121,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) if (!skb) return; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - const int pullsize = skb_network_offset(skb) - ETH_HLEN; + int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; if (pullsize > 0) { printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); skb_pull(skb, pullsize); @@ -1367,7 +1366,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) struct ethhdr *eth; unsigned char *rawp; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); eth = eth_hdr(skb); @@ -1787,7 +1786,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) } skb->dev = ndev; skb->pkt_type = PACKET_HOST; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; #ifdef ISDN_DEBUG_NET_DUMP isdn_dumppkt("R:", skb->data, skb->len, 40); #endif diff --git a/trunk/drivers/isdn/i4l/isdn_ppp.c b/trunk/drivers/isdn/i4l/isdn_ppp.c index 387392cb3d68..1b2df80c3bce 100644 --- a/trunk/drivers/isdn/i4l/isdn_ppp.c +++ b/trunk/drivers/isdn/i4l/isdn_ppp.c @@ -1100,8 +1100,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff goto drop_packet; } skb_put(skb, skb_old->len + 128); - skb_copy_from_linear_data(skb_old, skb->data, - skb_old->len); + memcpy(skb->data, skb_old->data, skb_old->len); if (net_dev->local->ppp_slot < 0) { printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", __FUNCTION__, net_dev->local->ppp_slot); @@ -1168,7 +1167,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff mlp->huptimer = 0; #endif /* CONFIG_IPPP_FILTER */ skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; netif_rx(skb); /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ return; @@ -1903,9 +1902,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, while( from != to ) { unsigned int len = from->len - MP_HEADER_LEN; - skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, - skb_put(skb,len), - len); + memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len); frag = from->next; isdn_ppp_mp_free_skb(mp, from); from = frag; diff --git a/trunk/drivers/isdn/isdnloop/isdnloop.c b/trunk/drivers/isdn/isdnloop/isdnloop.c index e93ad59f60bf..e3add27dd0e1 100644 --- a/trunk/drivers/isdn/isdnloop/isdnloop.c +++ b/trunk/drivers/isdn/isdnloop/isdnloop.c @@ -415,8 +415,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card) spin_lock_irqsave(&card->isdnloop_lock, flags); nskb = dev_alloc_skb(skb->len); if (nskb) { - skb_copy_from_linear_data(skb, - skb_put(nskb, len), len); + memcpy(skb_put(nskb, len), skb->data, len); skb_queue_tail(&card->bqueue[channel], nskb); dev_kfree_skb(skb); } else diff --git a/trunk/drivers/isdn/pcbit/capi.c b/trunk/drivers/isdn/pcbit/capi.c index 7b55e151f1b0..47c59e95898d 100644 --- a/trunk/drivers/isdn/pcbit/capi.c +++ b/trunk/drivers/isdn/pcbit/capi.c @@ -429,9 +429,8 @@ int capi_decode_conn_ind(struct pcbit_chan * chan, if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC))) return -1; - skb_copy_from_linear_data_offset(skb, count + 1, - info->data.setup.CallingPN, - len - count); + memcpy(info->data.setup.CallingPN, skb->data + count + 1, + len - count); info->data.setup.CallingPN[len - count] = 0; } @@ -458,9 +457,8 @@ int capi_decode_conn_ind(struct pcbit_chan * chan, if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC))) return -1; - skb_copy_from_linear_data_offset(skb, count + 1, - info->data.setup.CalledPN, - len - count); + memcpy(info->data.setup.CalledPN, skb->data + count + 1, + len - count); info->data.setup.CalledPN[len - count] = 0; } @@ -541,7 +539,7 @@ int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb) #ifdef DEBUG if (len > 1 && len < 31) { - skb_copy_from_linear_data_offset(skb, 2, str, len - 1); + memcpy(str, skb->data + 2, len - 1); str[len] = 0; printk(KERN_DEBUG "Connected Party Number: %s\n", str); } diff --git a/trunk/drivers/macintosh/adb.c b/trunk/drivers/macintosh/adb.c index adfea3c7c62a..f729eebf771f 100644 --- a/trunk/drivers/macintosh/adb.c +++ b/trunk/drivers/macintosh/adb.c @@ -90,7 +90,7 @@ static int autopoll_devs; int __adb_probe_sync; #ifdef CONFIG_PM -static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when); +static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier adb_sleep_notifier = { adb_notify_sleep, SLEEP_LEVEL_ADB, @@ -340,9 +340,11 @@ __initcall(adb_init); /* * notify clients before sleep and reset bus afterwards */ -void +int adb_notify_sleep(struct pmu_sleep_notifier *self, int when) { + int ret; + switch (when) { case PBOOK_SLEEP_REQUEST: adb_got_sleep = 1; @@ -351,8 +353,22 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) /* Stop autopoll */ if (adb_controller->autopoll) adb_controller->autopoll(0); - blocking_notifier_call_chain(&adb_client_list, - ADB_MSG_POWERDOWN, NULL); + ret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POWERDOWN, NULL); + if (ret & NOTIFY_STOP_MASK) { + up(&adb_probe_mutex); + return PBOOK_SLEEP_REFUSE; + } + break; + case PBOOK_SLEEP_REJECT: + if (adb_got_sleep) { + adb_got_sleep = 0; + up(&adb_probe_mutex); + adb_reset_bus(); + } + break; + + case PBOOK_SLEEP_NOW: break; case PBOOK_WAKE: adb_got_sleep = 0; @@ -360,13 +376,14 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) adb_reset_bus(); break; } + return PBOOK_SLEEP_OK; } #endif /* CONFIG_PM */ static int do_adb_reset_bus(void) { - int ret; + int ret, nret; if (adb_controller == NULL) return -ENXIO; @@ -374,8 +391,13 @@ do_adb_reset_bus(void) if (adb_controller->autopoll) adb_controller->autopoll(0); - blocking_notifier_call_chain(&adb_client_list, - ADB_MSG_PRE_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_PRE_RESET, NULL); + if (nret & NOTIFY_STOP_MASK) { + if (adb_controller->autopoll) + adb_controller->autopoll(autopoll_devs); + return -EBUSY; + } if (sleepy_trackpad) { /* Let the trackpad settle down */ @@ -405,8 +427,10 @@ do_adb_reset_bus(void) } up(&adb_handler_sem); - blocking_notifier_call_chain(&adb_client_list, - ADB_MSG_POST_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POST_RESET, NULL); + if (nret & NOTIFY_STOP_MASK) + return -EBUSY; return ret; } diff --git a/trunk/drivers/macintosh/ans-lcd.c b/trunk/drivers/macintosh/ans-lcd.c index e54c4d9f6365..cdd5a0f72e3c 100644 --- a/trunk/drivers/macintosh/ans-lcd.c +++ b/trunk/drivers/macintosh/ans-lcd.c @@ -145,12 +145,11 @@ anslcd_init(void) int retval; struct device_node* node; - node = of_find_node_by_name(NULL, "lcd"); - if (!node || !node->parent || strcmp(node->parent->name, "gc")) { - of_node_put(node); + node = find_devices("lcd"); + if (!node || !node->parent) + return -ENODEV; + if (strcmp(node->parent->name, "gc")) return -ENODEV; - } - of_node_put(node); anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20); diff --git a/trunk/drivers/macintosh/apm_emu.c b/trunk/drivers/macintosh/apm_emu.c index cdb0bead9917..c5e4d43f97fc 100644 --- a/trunk/drivers/macintosh/apm_emu.c +++ b/trunk/drivers/macintosh/apm_emu.c @@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list; -static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when); +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when); static struct pmu_sleep_notifier apm_sleep_notifier = { apm_notify_sleep, SLEEP_LEVEL_USERLAND, @@ -352,7 +352,7 @@ static int do_open(struct inode * inode, struct file * filp) * doesn't provide a way to NAK, but this could be added * here. */ -static void wait_all_suspend(void) +static int wait_all_suspend(void) { DECLARE_WAITQUEUE(wait, current); @@ -366,19 +366,24 @@ static void wait_all_suspend(void) remove_wait_queue(&apm_suspend_waitqueue, &wait); DBG("apm_emu: wait_all_suspend() - complete !\n"); + + return 1; } -static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when) +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when) { switch(when) { case PBOOK_SLEEP_REQUEST: queue_event(APM_SYS_SUSPEND, NULL); - wait_all_suspend(); + if (!wait_all_suspend()) + return PBOOK_SLEEP_REFUSE; break; + case PBOOK_SLEEP_REJECT: case PBOOK_WAKE: queue_event(APM_NORMAL_RESUME, NULL); break; } + return PBOOK_SLEEP_OK; } #define APM_CRITICAL 10 diff --git a/trunk/drivers/macintosh/mac_hid.c b/trunk/drivers/macintosh/mac_hid.c index 1599dc34f15f..c1fd816e9f09 100644 --- a/trunk/drivers/macintosh/mac_hid.c +++ b/trunk/drivers/macintosh/mac_hid.c @@ -102,6 +102,8 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) return 0; } +EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons); + static int emumousebtn_input_register(void) { int ret; diff --git a/trunk/drivers/macintosh/macio-adb.c b/trunk/drivers/macintosh/macio-adb.c index 79119f56e82d..026b67f4f659 100644 --- a/trunk/drivers/macintosh/macio-adb.c +++ b/trunk/drivers/macintosh/macio-adb.c @@ -82,14 +82,7 @@ struct adb_driver macio_adb_driver = { int macio_probe(void) { - struct device_node *np; - - np = of_find_compatible_node(NULL, "adb", "chrp,adb0"); - if (np) { - of_node_put(np); - return 0; - } - return -ENODEV; + return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV; } int macio_init(void) @@ -98,14 +91,12 @@ int macio_init(void) struct resource r; unsigned int irq; - adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0"); + adbs = find_compatible_devices("adb", "chrp,adb0"); if (adbs == 0) return -ENXIO; - if (of_address_to_resource(adbs, 0, &r)) { - of_node_put(adbs); + if (of_address_to_resource(adbs, 0, &r)) return -ENXIO; - } adb = ioremap(r.start, sizeof(struct adb_regs)); out_8(&adb->ctrl.r, 0); @@ -116,7 +107,6 @@ int macio_init(void) out_8(&adb->autopoll.r, APE); irq = irq_of_parse_and_map(adbs, 0); - of_node_put(adbs); if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) { printk(KERN_ERR "ADB: can't get irq %d\n", irq); return -EAGAIN; diff --git a/trunk/drivers/macintosh/macio_asic.c b/trunk/drivers/macintosh/macio_asic.c index c96b7fe882a4..d56216067549 100644 --- a/trunk/drivers/macintosh/macio_asic.c +++ b/trunk/drivers/macintosh/macio_asic.c @@ -134,12 +134,108 @@ static int macio_device_resume(struct device * dev) return 0; } +static int macio_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct macio_dev * macio_dev; + struct of_device * of; + char *scratch; + const char *compat, *compat2; + + int i = 0; + int length, cplen, cplen2, seen = 0; + + if (!dev) + return -ENODEV; + + macio_dev = to_macio_device(dev); + if (!macio_dev) + return -ENODEV; + + of = &macio_dev->ofdev; + + /* stuff we want to pass to /sbin/hotplug */ + envp[i++] = scratch = buffer; + length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name); + ++length; + buffer_size -= length; + if ((buffer_size <= 0) || (i >= num_envp)) + return -ENOMEM; + scratch += length; + + envp[i++] = scratch; + length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type); + ++length; + buffer_size -= length; + if ((buffer_size <= 0) || (i >= num_envp)) + return -ENOMEM; + scratch += length; + + /* Since the compatible field can contain pretty much anything + * it's not really legal to split it out with commas. We split it + * up using a number of environment variables instead. */ + + compat = get_property(of->node, "compatible", &cplen); + compat2 = compat; + cplen2= cplen; + while (compat && cplen > 0) { + envp[i++] = scratch; + length = scnprintf (scratch, buffer_size, + "OF_COMPATIBLE_%d=%s", seen, compat); + ++length; + buffer_size -= length; + if ((buffer_size <= 0) || (i >= num_envp)) + return -ENOMEM; + scratch += length; + length = strlen (compat) + 1; + compat += length; + cplen -= length; + seen++; + } + + envp[i++] = scratch; + length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen); + ++length; + buffer_size -= length; + if ((buffer_size <= 0) || (i >= num_envp)) + return -ENOMEM; + scratch += length; + + envp[i++] = scratch; + length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s", + of->node->name, of->node->type); + /* overwrite '\0' */ + buffer_size -= length; + if ((buffer_size <= 0) || (i >= num_envp)) + return -ENOMEM; + scratch += length; + + if (!compat2) { + compat2 = ""; + cplen2 = 1; + } + while (cplen2 > 0) { + length = snprintf (scratch, buffer_size, "C%s", compat2); + buffer_size -= length; + if (buffer_size <= 0) + return -ENOMEM; + scratch += length; + length = strlen (compat2) + 1; + compat2 += length; + cplen2 -= length; + } + + envp[i] = NULL; + + return 0; +} + extern struct device_attribute macio_dev_attrs[]; struct bus_type macio_bus_type = { .name = "macio", .match = macio_bus_match, - .uevent = of_device_uevent, + .uevent = macio_uevent, .probe = macio_device_probe, .remove = macio_device_remove, .shutdown = macio_device_shutdown, @@ -395,7 +491,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, #endif MAX_NODE_NAME_SIZE, np->name); } else { - reg = of_get_property(np, "reg", NULL); + reg = get_property(np, "reg", NULL); sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index, reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name); diff --git a/trunk/drivers/macintosh/macio_sysfs.c b/trunk/drivers/macintosh/macio_sysfs.c index cc8267912656..8566bdfdd4b8 100644 --- a/trunk/drivers/macintosh/macio_sysfs.c +++ b/trunk/drivers/macintosh/macio_sysfs.c @@ -21,7 +21,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf) int length = 0; of = &to_macio_device (dev)->ofdev; - compat = of_get_property(of->node, "compatible", &cplen); + compat = get_property(of->node, "compatible", &cplen); if (!compat) { *buf = '\0'; return 0; @@ -47,20 +47,18 @@ static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, int length; of = &to_macio_device (dev)->ofdev; - compat = of_get_property(of->node, "compatible", &cplen); + compat = get_property(of->node, "compatible", &cplen); if (!compat) compat = "", cplen = 1; length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type); buf += length; while (cplen > 0) { int l; - l = sprintf (buf, "C%s", compat); - length += l; - buf += l; + length += sprintf (buf, "C%s", compat); + buf += length; l = strlen (compat) + 1; compat += l; cplen -= l; } - length += sprintf(buf, "\n"); return length; } diff --git a/trunk/drivers/macintosh/rack-meter.c b/trunk/drivers/macintosh/rack-meter.c index 4177ff004753..f83fad2a3ff4 100644 --- a/trunk/drivers/macintosh/rack-meter.c +++ b/trunk/drivers/macintosh/rack-meter.c @@ -387,7 +387,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev, if (strcmp(np->name, "lightshow") == 0) break; if ((strcmp(np->name, "sound") == 0) && - of_get_property(np, "virtual", NULL) != NULL) + get_property(np, "virtual", NULL) != NULL) break; } if (np == NULL) { diff --git a/trunk/drivers/macintosh/smu.c b/trunk/drivers/macintosh/smu.c index a98a328b1cfc..c9f3dc4fd3ee 100644 --- a/trunk/drivers/macintosh/smu.c +++ b/trunk/drivers/macintosh/smu.c @@ -491,7 +491,7 @@ int __init smu_init (void) printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n"); goto fail; } - data = of_get_property(smu->db_node, "reg", NULL); + data = get_property(smu->db_node, "reg", NULL); if (data == NULL) { of_node_put(smu->db_node); smu->db_node = NULL; @@ -512,7 +512,7 @@ int __init smu_init (void) smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt"); if (smu->msg_node == NULL) break; - data = of_get_property(smu->msg_node, "reg", NULL); + data = get_property(smu->msg_node, "reg", NULL); if (data == NULL) { of_node_put(smu->msg_node); smu->msg_node = NULL; @@ -952,7 +952,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id) prop->name = ((char *)prop) + tlen - 18; sprintf(prop->name, "sdb-partition-%02x", id); prop->length = len; - prop->value = hdr; + prop->value = (unsigned char *)hdr; prop->next = NULL; /* Read the datablock */ @@ -1004,7 +1004,7 @@ const struct smu_sdbp_header *__smu_get_sdb_partition(int id, } else mutex_lock(&smu_part_access); - part = of_get_property(smu->of_node, pname, size); + part = get_property(smu->of_node, pname, size); if (part == NULL) { DPRINTK("trying to extract from SMU ...\n"); part = smu_create_sdb_partition(id); diff --git a/trunk/drivers/macintosh/therm_adt746x.c b/trunk/drivers/macintosh/therm_adt746x.c index 228903403cfc..a7ce55926638 100644 --- a/trunk/drivers/macintosh/therm_adt746x.c +++ b/trunk/drivers/macintosh/therm_adt746x.c @@ -567,13 +567,13 @@ thermostat_init(void) else return -ENODEV; - prop = of_get_property(np, "hwsensor-params-version", NULL); + prop = get_property(np, "hwsensor-params-version", NULL); printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop, (*prop == 1)?"":"un"); if (*prop != 1) return -ENODEV; - prop = of_get_property(np, "reg", NULL); + prop = get_property(np, "reg", NULL); if (!prop) return -ENODEV; @@ -591,9 +591,9 @@ thermostat_init(void) "limit_adjust: %d, fan_speed: %d\n", therm_bus, therm_address, limit_adjust, fan_speed); - if (of_get_property(np, "hwsensor-location", NULL)) { + if (get_property(np, "hwsensor-location", NULL)) { for (i = 0; i < 3; i++) { - sensor_location[i] = of_get_property(np, + sensor_location[i] = get_property(np, "hwsensor-location", NULL) + offset; if (sensor_location[i] == NULL) diff --git a/trunk/drivers/macintosh/therm_pm72.c b/trunk/drivers/macintosh/therm_pm72.c index 78ff18617139..2e4ad44a8636 100644 --- a/trunk/drivers/macintosh/therm_pm72.c +++ b/trunk/drivers/macintosh/therm_pm72.c @@ -674,7 +674,7 @@ static int read_eeprom(int cpu, struct mpu_data *out) printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid node from device-tree\n"); return -ENODEV; } - data = of_get_property(np, "cpuid", &len); + data = get_property(np, "cpuid", &len); if (data == NULL) { printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid property from device-tree\n"); of_node_put(np); @@ -1337,7 +1337,7 @@ static int init_backside_state(struct backside_pid_state *state) */ u3 = of_find_node_by_path("/u3@0,f8000000"); if (u3 != NULL) { - const u32 *vers = of_get_property(u3, "device-rev", NULL); + const u32 *vers = get_property(u3, "device-rev", NULL); if (vers) if (((*vers) & 0x3f) < 0x34) u3h = 0; @@ -2129,8 +2129,8 @@ static void fcu_lookup_fans(struct device_node *fcu_node) continue; /* Lookup for a matching location */ - loc = of_get_property(np, "location", NULL); - reg = of_get_property(np, "reg", NULL); + loc = get_property(np, "location", NULL); + reg = get_property(np, "reg", NULL); if (loc == NULL || reg == NULL) continue; DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg); diff --git a/trunk/drivers/macintosh/therm_windtunnel.c b/trunk/drivers/macintosh/therm_windtunnel.c index 3d0354e96a97..a1d3a987cb3a 100644 --- a/trunk/drivers/macintosh/therm_windtunnel.c +++ b/trunk/drivers/macintosh/therm_windtunnel.c @@ -459,8 +459,7 @@ therm_of_probe( struct of_device *dev, const struct of_device_id *match ) static int therm_of_remove( struct of_device *dev ) { - i2c_del_driver( &g4fan_driver ); - return 0; + return i2c_del_driver( &g4fan_driver ); } static struct of_device_id therm_of_match[] = {{ @@ -493,7 +492,7 @@ g4fan_init( void ) if( !(np=of_find_node_by_name(NULL, "power-mgt")) ) return -ENODEV; - info = of_get_property(np, "thermal-info", NULL); + info = get_property(np, "thermal-info", NULL); of_node_put(np); if( !info || !machine_is_compatible("PowerMac3,6") ) diff --git a/trunk/drivers/macintosh/via-cuda.c b/trunk/drivers/macintosh/via-cuda.c index 741a93a3eb61..d58fcf6cca0a 100644 --- a/trunk/drivers/macintosh/via-cuda.c +++ b/trunk/drivers/macintosh/via-cuda.c @@ -82,7 +82,6 @@ static unsigned char cuda_rbuf[16]; static unsigned char *reply_ptr; static int reading_reply; static int data_index; -static int cuda_irq; #ifdef CONFIG_PPC static struct device_node *vias; #endif @@ -132,7 +131,7 @@ int __init find_via_cuda(void) if (vias == 0) return 0; - reg = of_get_property(vias, "reg", NULL); + reg = get_property(vias, "reg", NULL); if (reg == NULL) { printk(KERN_ERR "via-cuda: No \"reg\" property !\n"); goto fail; @@ -161,8 +160,10 @@ int __init find_via_cuda(void) /* Clear and enable interrupts, but only on PPC. On 68K it's done */ /* for us by the main VIA driver in arch/m68k/mac/via.c */ +#ifndef CONFIG_MAC out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ +#endif /* enable autopoll */ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); @@ -180,22 +181,24 @@ int __init find_via_cuda(void) static int __init via_cuda_start(void) { + unsigned int irq; + if (via == NULL) return -ENODEV; #ifdef CONFIG_MAC - cuda_irq = IRQ_MAC_ADB; + irq = IRQ_MAC_ADB; #else /* CONFIG_MAC */ - cuda_irq = irq_of_parse_and_map(vias, 0); - if (cuda_irq == NO_IRQ) { + irq = irq_of_parse_and_map(vias, 0); + if (irq == NO_IRQ) { printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", vias->full_name); return -ENODEV; } -#endif /* CONFIG_MAC */ +#endif /* CONFIG_MAP */ - if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { - printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq); + if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { + printk(KERN_ERR "via-cuda: can't request irq %d\n", irq); return -EAGAIN; } @@ -235,7 +238,6 @@ cuda_init(void) printk(KERN_ERR "cuda_init_via() failed\n"); return -ENODEV; } - out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ return via_cuda_start(); #endif @@ -261,17 +263,15 @@ cuda_init_via(void) out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ (void)in_8(&via[SR]); /* clear any left-over data */ -#ifdef CONFIG_PPC +#ifndef CONFIG_MAC out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ (void)in_8(&via[IER]); -#else - out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ #endif /* delay 4ms and then clear any pending interrupt */ mdelay(4); (void)in_8(&via[SR]); - out_8(&via[IFR], SR_INT); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); /* sync with the CUDA - assert TACK without TIP */ out_8(&via[B], in_8(&via[B]) & ~TACK); @@ -282,7 +282,7 @@ cuda_init_via(void) /* wait for the interrupt and then clear it */ WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); (void)in_8(&via[SR]); - out_8(&via[IFR], SR_INT); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); /* finish the sync by negating TACK */ out_8(&via[B], in_8(&via[B]) | TACK); @@ -291,7 +291,7 @@ cuda_init_via(void) WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); (void)in_8(&via[SR]); - out_8(&via[IFR], SR_INT); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ return 0; @@ -428,12 +428,16 @@ cuda_start(void) void cuda_poll(void) { + unsigned long flags; + /* cuda_interrupt only takes a normal lock, we disable * interrupts here to avoid re-entering and thus deadlocking. + * An option would be to disable only the IRQ source with + * disable_irq(), would that work on m68k ? --BenH */ - disable_irq(cuda_irq); + local_irq_save(flags); cuda_interrupt(0, NULL); - enable_irq(cuda_irq); + local_irq_restore(flags); } static irqreturn_t @@ -444,25 +448,15 @@ cuda_interrupt(int irq, void *arg) unsigned char ibuf[16]; int ibuf_len = 0; int complete = 0; + unsigned char virq; spin_lock(&cuda_lock); - /* On powermacs, this handler is registered for the VIA IRQ. But it uses - * just the shift register IRQ -- other VIA interrupt sources are disabled. - * On m68k macs, the VIA IRQ sources are dispatched individually. Unless - * we are polling, the shift register IRQ flag has already been cleared. - */ - -#ifdef CONFIG_MAC - if (!arg) -#endif - { - if ((in_8(&via[IFR]) & SR_INT) == 0) { - spin_unlock(&cuda_lock); - return IRQ_NONE; - } else { - out_8(&via[IFR], SR_INT); - } + virq = in_8(&via[IFR]) & 0x7f; + out_8(&via[IFR], virq); + if ((virq & SR_INT) == 0) { + spin_unlock(&cuda_lock); + return IRQ_NONE; } status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); diff --git a/trunk/drivers/macintosh/via-macii.c b/trunk/drivers/macintosh/via-macii.c index 01b8eca7ccd5..1b3bad62a1be 100644 --- a/trunk/drivers/macintosh/via-macii.c +++ b/trunk/drivers/macintosh/via-macii.c @@ -12,15 +12,6 @@ * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. * 2000-03-29 Tony Mantler * - Big overhaul, should actually work now. - * 2006-12-31 Finn Thain - Another overhaul. - * - * Suggested reading: - * Inside Macintosh, ch. 5 ADB Manager - * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus - * Rockwell R6522 VIA datasheet - * - * Apple's "ADB Analyzer" bus sniffer is invaluable: - * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/ */ #include @@ -35,6 +26,7 @@ #include #include #include +#include #include static volatile unsigned char *via; @@ -59,7 +51,9 @@ static volatile unsigned char *via; #define ANH (15*RS) /* A-side data, no handshake */ /* Bits in B data register: all active low */ -#define CTLR_IRQ 0x08 /* Controller rcv status (input) */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ #define ST_MASK 0x30 /* mask for selecting ADB state bits */ /* Bits in ACR */ @@ -71,6 +65,8 @@ static volatile unsigned char *via; #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA 0x08 /* Shift register data */ +#define SR_CLOCK 0x10 /* Shift register clock */ /* ADB transaction states according to GMHW */ #define ST_CMD 0x00 /* ADB state: command byte */ @@ -81,6 +77,7 @@ static volatile unsigned char *via; static int macii_init_via(void); static void macii_start(void); static irqreturn_t macii_interrupt(int irq, void *arg); +static void macii_retransmit(int); static void macii_queue_poll(void); static int macii_probe(void); @@ -106,37 +103,29 @@ static enum macii_state { sending, reading, read_done, + awaiting_reply } macii_state; -static struct adb_request *current_req; /* first request struct in the queue */ -static struct adb_request *last_req; /* last request struct in the queue */ -static unsigned char reply_buf[16]; /* storage for autopolled replies */ -static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */ -static int reading_reply; /* store reply in reply_buf else req->reply */ -static int data_index; /* index of the next byte to send from req->data */ -static int reply_len; /* number of bytes received in reply_buf or req->reply */ -static int status; /* VIA's ADB status bits captured upon interrupt */ -static int last_status; /* status bits as at previous interrupt */ -static int srq_asserted; /* have to poll for the device that asserted it */ -static int command_byte; /* the most recent command byte transmitted */ -static int autopoll_devs; /* bits set are device addresses to be polled */ - -/* Sanity check for request queue. Doesn't check for cycles. */ -static int request_is_queued(struct adb_request *req) { - struct adb_request *cur; - unsigned long flags; - local_irq_save(flags); - cur = current_req; - while (cur) { - if (cur == req) { - local_irq_restore(flags); - return 1; - } - cur = cur->next; - } - local_irq_restore(flags); - return 0; -} +static int need_poll; +static int command_byte; +static int last_reply; +static int last_active; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static struct adb_request *retry_req; +static unsigned char reply_buf[16]; +static unsigned char *reply_ptr; +static int reply_len; +static int reading_reply; +static int data_index; +static int first_byte; +static int prefix_len; +static int status = ST_IDLE|TREQ; +static int last_status; +static int driver_running; + +/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ /* Check for MacII style ADB */ static int macii_probe(void) @@ -158,16 +147,15 @@ int macii_init(void) local_irq_save(flags); err = macii_init_via(); - if (err) goto out; + if (err) return err; err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", macii_interrupt); - if (err) goto out; + if (err) return err; macii_state = idle; -out: local_irq_restore(flags); - return err; + return 0; } /* initialize the hardware */ @@ -175,12 +163,12 @@ static int macii_init_via(void) { unsigned char x; - /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */ - via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ; + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; /* Set up state: idle */ via[B] |= ST_IDLE; - last_status = via[B] & (ST_MASK|CTLR_IRQ); + last_status = via[B] & (ST_MASK|TREQ); /* Shift register on input */ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; @@ -191,72 +179,81 @@ static int macii_init_via(void) return 0; } -/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */ +/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */ static void macii_queue_poll(void) { - /* No point polling the active device as it will never assert SRQ, so - * poll the next device in the autopoll list. This could leave us - * stuck in a polling loop if an unprobed device is asserting SRQ. - * In theory, that could only happen if a device was plugged in after - * probing started. Unplugging it again will break the cycle. - * (Simply polling the next higher device often ends up polling almost - * every device (after wrapping around), which takes too long.) - */ - int device_mask; - int next_device; + static int device = 0; + static int in_poll=0; static struct adb_request req; + unsigned long flags; + + if (in_poll) printk("macii_queue_poll: double poll!\n"); - if (!autopoll_devs) return; - - device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1; - if (autopoll_devs & ~device_mask) - next_device = ffs(autopoll_devs & ~device_mask) - 1; - else - next_device = ffs(autopoll_devs) - 1; + in_poll++; + if (++device > 15) device = 1; - BUG_ON(request_is_queued(&req)); + adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, + ADB_READREG(device, 0)); - adb_request(&req, NULL, ADBREQ_NOSEND, 1, - ADB_READREG(next_device, 0)); + local_irq_save(flags); - req.sent = 0; - req.complete = 0; - req.reply_len = 0; req.next = current_req; + current_req = &req; + + local_irq_restore(flags); + macii_start(); + in_poll--; +} + +/* Send an ADB retransmit (Talk, appended to the request queue) */ +static void macii_retransmit(int device) +{ + static int in_retransmit = 0; + static struct adb_request rt; + unsigned long flags; + + if (in_retransmit) printk("macii_retransmit: double retransmit!\n"); + + in_retransmit++; + + adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, + ADB_READREG(device, 0)); + + local_irq_save(flags); if (current_req != NULL) { - current_req = &req; + last_req->next = &rt; + last_req = &rt; } else { - current_req = &req; - last_req = &req; + current_req = &rt; + last_req = &rt; } + + if (macii_state == idle) macii_start(); + + local_irq_restore(flags); + in_retransmit--; } /* Send an ADB request; if sync, poll out the reply 'till it's done */ static int macii_send_request(struct adb_request *req, int sync) { - int err; - unsigned long flags; + int i; - BUG_ON(request_is_queued(req)); + i = macii_write(req); + if (i) return i; - local_irq_save(flags); - err = macii_write(req); - local_irq_restore(flags); - - if (!err && sync) { - while (!req->complete) { - macii_poll(); - } - BUG_ON(request_is_queued(req)); + if (sync) { + while (!req->complete) macii_poll(); } - - return err; + return 0; } -/* Send an ADB request (append to request queue) */ +/* Send an ADB request */ static int macii_write(struct adb_request *req) { + unsigned long flags; + if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { req->complete = 1; return -EINVAL; @@ -267,6 +264,8 @@ static int macii_write(struct adb_request *req) req->complete = 0; req->reply_len = 0; + local_irq_save(flags); + if (current_req != NULL) { last_req->next = req; last_req = req; @@ -275,52 +274,28 @@ static int macii_write(struct adb_request *req) last_req = req; if (macii_state == idle) macii_start(); } + + local_irq_restore(flags); return 0; } /* Start auto-polling */ static int macii_autopoll(int devs) { - static struct adb_request req; - unsigned long flags; - int err = 0; - - /* bit 1 == device 1, and so on. */ - autopoll_devs = devs & 0xFFFE; - - if (!autopoll_devs) return 0; - - local_irq_save(flags); - - if (current_req == NULL) { - /* Send a Talk Reg 0. The controller will repeatedly transmit - * this as long as it is idle. - */ - adb_request(&req, NULL, ADBREQ_NOSEND, 1, - ADB_READREG(ffs(autopoll_devs) - 1, 0)); - err = macii_write(&req); - } - - local_irq_restore(flags); - return err; -} - -static inline int need_autopoll(void) { - /* Was the last command Talk Reg 0 - * and is the target on the autopoll list? - */ - if ((command_byte & 0x0F) == 0x0C && - ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs)) - return 0; - return 1; + /* Just ping a random default address */ + if (!(current_req || retry_req)) + macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); + return 0; } /* Prod the chip without interrupts */ static void macii_poll(void) { - disable_irq(IRQ_MAC_ADB); - macii_interrupt(0, NULL); - enable_irq(IRQ_MAC_ADB); + unsigned long flags; + + local_irq_save(flags); + if (via[IFR] & SR_INT) macii_interrupt(0, NULL); + local_irq_restore(flags); } /* Reset the bus */ @@ -328,34 +303,73 @@ static int macii_reset_bus(void) { static struct adb_request req; - if (request_is_queued(&req)) - return 0; - /* Command = 0, Address = ignored */ adb_request(&req, NULL, 0, 1, ADB_BUSRESET); - /* Don't want any more requests during the Global Reset low time. */ - udelay(3000); - return 0; } /* Start sending ADB packet */ static void macii_start(void) { + unsigned long flags; struct adb_request *req; req = current_req; + if (!req) return; + + /* assert macii_state == idle */ + if (macii_state != idle) { + printk("macii_start: called while driver busy (%p %x %x)!\n", + req, macii_state, (uint) via1[B] & (ST_MASK|TREQ)); + return; + } - BUG_ON(req == NULL); - - BUG_ON(macii_state != idle); - - /* Now send it. Be careful though, that first byte of the request - * is actually ADB_PACKET; the real data begins at index 1! - * And req->nbytes is the number of bytes of real data plus one. + local_irq_save(flags); + + /* + * IRQ signaled ?? (means ADB controller wants to send, or might + * be end of packet if we were reading) + */ +#if 0 /* FIXME: This is broke broke broke, for some reason */ + if ((via[B] & TREQ) == 0) { + printk("macii_start: weird poll stuff. huh?\n"); + /* + * FIXME - we need to restart this on a timer + * or a collision at boot hangs us. + * Never set macii_state to idle here, or macii_start + * won't be called again from send_request! + * (need to re-check other cases ...) + */ + /* + * if the interrupt handler set the need_poll + * flag, it's hopefully a SRQ poll or re-Talk + * so we try to send here anyway + */ + if (!need_poll) { + if (console_loglevel == 10) + printk("macii_start: device busy - retry %p state %d status %x!\n", + req, macii_state, + (uint) via[B] & (ST_MASK|TREQ)); + retry_req = req; + /* set ADB status here ? */ + local_irq_restore(flags); + return; + } else { + need_poll = 0; + } + } +#endif + /* + * Another retry pending? (sanity check) */ + if (retry_req) { + retry_req = NULL; + } + /* Now send it. Be careful though, that first byte of the request */ + /* is actually ADB_PACKET; the real data begins at index 1! */ + /* store command byte */ command_byte = req->data[1]; /* Output mode */ @@ -367,97 +381,115 @@ static void macii_start(void) macii_state = sending; data_index = 2; + + local_irq_restore(flags); } /* - * The notorious ADB interrupt handler - does all of the protocol handling. - * Relies on the ADB controller sending and receiving data, thereby - * generating shift register interrupts (SR_INT) for us. This means there has - * to be activity on the ADB bus. The chip will poll to achieve this. + * The notorious ADB interrupt handler - does all of the protocol handling, + * except for starting new send operations. Relies heavily on the ADB + * controller sending and receiving data, thereby generating SR interrupts + * for us. This means there has to be always activity on the ADB bus, otherwise + * the whole process dies and has to be re-kicked by sending TALK requests ... + * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type + * ADB the problem isn't solved yet (retransmit of the latest active TALK seems + * a good choice; either on timeout or on a timer interrupt). * * The basic ADB state machine was left unchanged from the original MacII code * by Alan Cox, which was based on the CUDA driver for PowerMac. - * The syntax of the ADB status lines is totally different on MacII, - * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle - * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. - * Start and end of a receive packet are signalled by asserting /IRQ on the - * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused - * with the VIA shift register interrupt. /IRQ never actually interrupts the - * processor, it's just an ordinary input.) + * The syntax of the ADB status lines seems to be totally different on MacII, + * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for + * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start + * and end of a receive packet are signaled by asserting /IRQ on the interrupt + * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on + * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the + * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB + * protocol with a logic analyzer!!) + * + * Note: As of 21/10/97, the MacII ADB part works including timeout detection + * and retransmit (Talk to the last active device). */ static irqreturn_t macii_interrupt(int irq, void *arg) { - int x; - static int entered; + int x, adbdir; + unsigned long flags; struct adb_request *req; - if (!arg) { - /* Clear the SR IRQ flag when polling. */ - if (via[IFR] & SR_INT) - via[IFR] = SR_INT; - else - return IRQ_NONE; - } + last_status = status; - BUG_ON(entered++); + /* prevent races due to SCSI enabling ints */ + local_irq_save(flags); - last_status = status; - status = via[B] & (ST_MASK|CTLR_IRQ); + if (driver_running) { + local_irq_restore(flags); + return IRQ_NONE; + } + + driver_running = 1; + + status = via[B] & (ST_MASK|TREQ); + adbdir = via[ACR] & SR_OUT; switch (macii_state) { case idle: - if (reading_reply) { - reply_ptr = current_req->reply; - } else { - BUG_ON(current_req != NULL); - reply_ptr = reply_buf; - } - x = via[SR]; + first_byte = x; + /* set ADB state = even for first data byte */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - if ((status & CTLR_IRQ) && (x == 0xFF)) { - /* Bus timeout without SRQ sequence: - * data is "FF" while CTLR_IRQ is "H" - */ - reply_len = 0; - srq_asserted = 0; - macii_state = read_done; - } else { - macii_state = reading; - *reply_ptr = x; - reply_len = 1; - } + reply_buf[0] = first_byte; /* was command_byte?? */ + reply_ptr = reply_buf + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 0; + + macii_state = reading; + break; + case awaiting_reply: + /* handshake etc. for II ?? */ + x = via[SR]; + first_byte = x; /* set ADB state = even for first data byte */ via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + + current_req->reply[0] = first_byte; + reply_ptr = current_req->reply + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 1; + + macii_state = reading; break; case sending: req = current_req; if (data_index >= req->nbytes) { + /* print an error message if a listen command has no data */ + if (((command_byte & 0x0C) == 0x08) + /* && (console_loglevel == 10) */ + && (data_index == 2)) + printk("MacII ADB: listen command with no data: %x!\n", + command_byte); + /* reset to shift in */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + /* set ADB state idle - might get SRQ */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + req->sent = 1; - macii_state = idle; if (req->reply_expected) { - reading_reply = 1; + macii_state = awaiting_reply; } else { req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); - - if (current_req) + macii_state = idle; + if (current_req || retry_req) macii_start(); else - if (need_autopoll()) - macii_autopoll(autopoll_devs); - } - - if (macii_state == idle) { - /* reset to shift in */ - via[ACR] &= ~SR_OUT; - x = via[SR]; - /* set ADB state idle - might get SRQ */ - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + macii_retransmit((command_byte & 0xF0) >> 4); } } else { via[SR] = req->data[data_index++]; @@ -473,79 +505,147 @@ static irqreturn_t macii_interrupt(int irq, void *arg) break; case reading: - x = via[SR]; - BUG_ON((status & ST_MASK) == ST_CMD || - (status & ST_MASK) == ST_IDLE); - - /* Bus timeout with SRQ sequence: - * data is "XX FF" while CTLR_IRQ is "L L" - * End of packet without SRQ sequence: - * data is "XX...YY 00" while CTLR_IRQ is "L...H L" - * End of packet SRQ sequence: - * data is "XX...YY 00" while CTLR_IRQ is "L...L L" - * (where XX is the first response byte and - * YY is the last byte of valid response data.) - */ - srq_asserted = 0; - if (!(status & CTLR_IRQ)) { - if (x == 0xFF) { - if (!(last_status & CTLR_IRQ)) { - macii_state = read_done; - reply_len = 0; - srq_asserted = 1; - } - } else if (x == 0x00) { - macii_state = read_done; - if (!(last_status & CTLR_IRQ)) - srq_asserted = 1; - } - } + /* timeout / SRQ handling for II hw */ + if( (first_byte == 0xFF && (reply_len-prefix_len)==2 + && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || + ((reply_len-prefix_len)==3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) + { + /* + * possible timeout (in fact, most probably a + * timeout, since SRQ can't be signaled without + * transfer on the bus). + * The last three bytes seen were FF, together + * with the starting byte (in case we started + * on 'idle' or 'awaiting_reply') this probably + * makes four. So this is mostl likely #5! + * The timeout signal is a pattern 1 0 1 0 0.. + * on /INT, meaning we missed it :-( + */ + x = via[SR]; + if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n"); - if (macii_state == reading) { - BUG_ON(reply_len > 15); - reply_ptr++; + if ((status & TREQ) == (last_status & TREQ)) { + /* Not a timeout. Unsolicited SRQ? weird. */ + /* Terminate the SRQ packet and poll */ + need_poll = 1; + } + /* There's no packet to get, so reply is blank */ + via[B] ^= ST_MASK; + reply_ptr -= (reply_len-prefix_len); + reply_len = prefix_len; + macii_state = read_done; + break; + } /* end timeout / SRQ handling for II hw. */ + + if((reply_len-prefix_len)>3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* SRQ tacked on data packet */ + /* Terminate the packet (SRQ never ends) */ + x = via[SR]; + macii_state = read_done; + reply_len -= 3; + reply_ptr -= 3; + need_poll = 1; + /* need to continue; next byte not seen else */ + } else { + /* Sanity check */ + if (reply_len > 15) reply_len = 0; + /* read byte */ + x = via[SR]; *reply_ptr = x; + reply_ptr++; reply_len++; } + /* The usual handshake ... */ + + /* + * NetBSD hints that the next to last byte + * is sent with IRQ !! + * Guido found out it's the last one (0x0), + * but IRQ should be asserted already. + * Problem with timeout detection: First + * transition to /IRQ might be second + * byte of timeout packet! + * Timeouts are signaled by 4x FF. + */ + if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */ + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; - /* invert state bits, toggle ODD/EVEN */ - via[B] ^= ST_MASK; + /* adjust packet length */ + reply_len--; + reply_ptr--; + macii_state = read_done; + } else { + /* not caught: ST_CMD */ + /* required for re-entry 'reading'! */ + if ((status & ST_MASK) == ST_IDLE) { + /* (in)sanity check - set even */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + } else { + /* invert state bits */ + via[B] ^= ST_MASK; + } + } break; case read_done: x = via[SR]; - if (reading_reply) { - reading_reply = 0; req = current_req; - req->reply_len = reply_len; + req->reply_len = reply_ptr - req->reply; req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); - } else if (reply_len && autopoll_devs) - adb_input(reply_buf, reply_len, 0); + } else { + adb_input(reply_buf, reply_ptr - reply_buf, 0); + } - macii_state = idle; + /* + * remember this device ID; it's the latest we got a + * reply from! + */ + last_reply = command_byte; + last_active = (command_byte & 0xF0) >> 4; /* SRQ seen before, initiate poll now */ - if (srq_asserted) + if (need_poll) { + macii_state = idle; macii_queue_poll(); + need_poll = 0; + break; + } + + /* set ADB state to idle */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + + /* /IRQ seen, so the ADB controller has data for us */ + if ((via[B] & TREQ) != 0) { + macii_state = reading; - if (current_req) - macii_start(); - else - if (need_autopoll()) - macii_autopoll(autopoll_devs); - - if (macii_state == idle) - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + reply_buf[0] = command_byte; + reply_ptr = reply_buf + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 0; + } else { + /* no IRQ, send next packet or wait */ + macii_state = idle; + if (current_req) + macii_start(); + else + macii_retransmit(last_active); + } break; default: break; } - - entered--; + /* reset mutex and interrupts */ + driver_running = 0; + local_irq_restore(flags); return IRQ_HANDLED; } diff --git a/trunk/drivers/macintosh/via-pmu-led.c b/trunk/drivers/macintosh/via-pmu-led.c index fc89a7047cd0..179af10105d9 100644 --- a/trunk/drivers/macintosh/via-pmu-led.c +++ b/trunk/drivers/macintosh/via-pmu-led.c @@ -81,7 +81,7 @@ static struct led_classdev pmu_led = { }; #ifdef CONFIG_PM -static void pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when) +static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when) { unsigned long flags; @@ -99,6 +99,8 @@ static void pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when) break; } spin_unlock_irqrestore(&pmu_blink_lock, flags); + + return PBOOK_SLEEP_OK; } static struct pmu_sleep_notifier via_pmu_led_sleep_notif = { @@ -118,13 +120,11 @@ static int __init via_pmu_led_init(void) dt = of_find_node_by_path("/"); if (dt == NULL) return -ENODEV; - model = of_get_property(dt, "model", NULL); + model = get_property(dt, "model", NULL); if (model == NULL) return -ENODEV; if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && - strncmp(model, "iBook", strlen("iBook")) != 0 && - strcmp(model, "PowerMac7,2") != 0 && - strcmp(model, "PowerMac7,3") != 0) { + strncmp(model, "iBook", strlen("iBook")) != 0) { of_node_put(dt); /* ignore */ return -ENODEV; diff --git a/trunk/drivers/macintosh/via-pmu.c b/trunk/drivers/macintosh/via-pmu.c index 1729d3fd7a11..b6073bdb50c3 100644 --- a/trunk/drivers/macintosh/via-pmu.c +++ b/trunk/drivers/macintosh/via-pmu.c @@ -289,7 +289,7 @@ int __init find_via_pmu(void) if (vias == NULL) return 0; - reg = of_get_property(vias, "reg", NULL); + reg = get_property(vias, "reg", NULL); if (reg == NULL) { printk(KERN_ERR "via-pmu: No \"reg\" property !\n"); goto fail; @@ -319,13 +319,10 @@ int __init find_via_pmu(void) else if (device_is_compatible(vias->parent, "Keylargo") || device_is_compatible(vias->parent, "K2-Keylargo")) { struct device_node *gpiop; - struct device_node *adbp; u64 gaddr = OF_BAD_ADDR; pmu_kind = PMU_KEYLARGO_BASED; - adbp = of_find_node_by_type(NULL, "adb"); - pmu_has_adb = (adbp != NULL); - of_node_put(adbp); + pmu_has_adb = (find_type_devices("adb") != NULL); pmu_intr_mask = PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | @@ -334,7 +331,7 @@ int __init find_via_pmu(void) gpiop = of_find_node_by_name(NULL, "gpio"); if (gpiop) { - reg = of_get_property(gpiop, "reg", NULL); + reg = get_property(gpiop, "reg", NULL); if (reg) gaddr = of_translate_address(gpiop, reg); if (gaddr != OF_BAD_ADDR) @@ -487,11 +484,10 @@ static int __init via_pmu_dev_init(void) pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } else { - struct device_node* prim = - of_find_node_by_name(NULL, "power-mgt"); + struct device_node* prim = find_devices("power-mgt"); const u32 *prim_info = NULL; if (prim) - prim_info = of_get_property(prim, "prim-info", NULL); + prim_info = get_property(prim, "prim-info", NULL); if (prim_info) { /* Other stuffs here yet unknown */ pmu_battery_count = (prim_info[6] >> 16) & 0xff; @@ -499,7 +495,6 @@ static int __init via_pmu_dev_init(void) if (pmu_battery_count > 1) pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } - of_node_put(prim); } #endif /* CONFIG_PPC32 */ @@ -1774,21 +1769,35 @@ EXPORT_SYMBOL(pmu_unregister_sleep_notifier); #if defined(CONFIG_PM) && defined(CONFIG_PPC32) /* Sleep is broadcast last-to-first */ -static void broadcast_sleep(int when) +static int +broadcast_sleep(int when, int fallback) { + int ret = PBOOK_SLEEP_OK; struct list_head *list; struct pmu_sleep_notifier *notifier; for (list = sleep_notifiers.prev; list != &sleep_notifiers; list = list->prev) { notifier = list_entry(list, struct pmu_sleep_notifier, list); - notifier->notifier_call(notifier, when); + ret = notifier->notifier_call(notifier, when); + if (ret != PBOOK_SLEEP_OK) { + printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n", + when, notifier, notifier->notifier_call); + for (; list != &sleep_notifiers; list = list->next) { + notifier = list_entry(list, struct pmu_sleep_notifier, list); + notifier->notifier_call(notifier, fallback); + } + return ret; + } } + return ret; } /* Wake is broadcast first-to-last */ -static void broadcast_wake(void) +static int +broadcast_wake(void) { + int ret = PBOOK_SLEEP_OK; struct list_head *list; struct pmu_sleep_notifier *notifier; @@ -1797,6 +1806,7 @@ static void broadcast_wake(void) notifier = list_entry(list, struct pmu_sleep_notifier, list); notifier->notifier_call(notifier, PBOOK_WAKE); } + return ret; } /* @@ -2003,8 +2013,12 @@ pmac_suspend_devices(void) pm_prepare_console(); - /* Notify old-style device drivers */ - broadcast_sleep(PBOOK_SLEEP_REQUEST); + /* Notify old-style device drivers & userland */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk(KERN_ERR "Sleep rejected by drivers\n"); + return -EBUSY; + } /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that @@ -2014,7 +2028,12 @@ pmac_suspend_devices(void) */ sys_sync(); - broadcast_sleep(PBOOK_SLEEP_NOW); + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); + if (ret != PBOOK_SLEEP_OK) { + printk(KERN_ERR "Driver sleep failed\n"); + return -EBUSY; + } /* Send suspend call to devices, hold the device core's dpm_sem */ ret = device_suspend(PMSG_SUSPEND); @@ -2135,7 +2154,7 @@ static int powerbook_sleep_grackle(void) int ret; struct pci_dev *grackle; - grackle = pci_get_bus_and_slot(0, 0); + grackle = pci_find_slot(0, 0); if (!grackle) return -ENODEV; @@ -2183,8 +2202,6 @@ static int powerbook_sleep_grackle(void) pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); pci_write_config_word(grackle, 0x70, pmcr1); - pci_dev_put(grackle); - /* Make sure the PMU is idle */ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); diff --git a/trunk/drivers/macintosh/via-pmu68k.c b/trunk/drivers/macintosh/via-pmu68k.c index dfdf11c1eec4..356c7216a179 100644 --- a/trunk/drivers/macintosh/via-pmu68k.c +++ b/trunk/drivers/macintosh/via-pmu68k.c @@ -111,6 +111,7 @@ static int pmu_send_request(struct adb_request *req, int sync); static int pmu_autopoll(int devs); void pmu_poll(void); static int pmu_reset_bus(void); +static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static void send_byte(int x); @@ -474,7 +475,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *), return pmu_queue_request(req); } -int +static int pmu_queue_request(struct adb_request *req) { unsigned long flags; diff --git a/trunk/drivers/macintosh/windfarm_lm75_sensor.c b/trunk/drivers/macintosh/windfarm_lm75_sensor.c index ab4d1b63f63e..3f7967feaf5b 100644 --- a/trunk/drivers/macintosh/windfarm_lm75_sensor.c +++ b/trunk/drivers/macintosh/windfarm_lm75_sensor.c @@ -176,7 +176,7 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) for (dev = NULL; (dev = of_get_next_child(busnode, dev)) != NULL;) { const char *loc = - of_get_property(dev, "hwsensor-location", NULL); + get_property(dev, "hwsensor-location", NULL); u8 addr; /* We must re-match the adapter in order to properly check diff --git a/trunk/drivers/macintosh/windfarm_max6690_sensor.c b/trunk/drivers/macintosh/windfarm_max6690_sensor.c index eaa74afa175b..eae1189d6c41 100644 --- a/trunk/drivers/macintosh/windfarm_max6690_sensor.c +++ b/trunk/drivers/macintosh/windfarm_max6690_sensor.c @@ -134,7 +134,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) if (!device_is_compatible(dev, "max6690")) continue; addr = pmac_i2c_get_dev_addr(dev); - loc = of_get_property(dev, "hwsensor-location", NULL); + loc = get_property(dev, "hwsensor-location", NULL); if (loc == NULL || addr == 0) continue; printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); diff --git a/trunk/drivers/macintosh/windfarm_smu_controls.c b/trunk/drivers/macintosh/windfarm_smu_controls.c index ff398adc0283..31b750d61206 100644 --- a/trunk/drivers/macintosh/windfarm_smu_controls.c +++ b/trunk/drivers/macintosh/windfarm_smu_controls.c @@ -167,7 +167,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, if (fct == NULL) return NULL; fct->ctrl.ops = &smu_fan_ops; - l = of_get_property(node, "location", NULL); + l = get_property(node, "location", NULL); if (l == NULL) goto fail; @@ -224,17 +224,17 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, goto fail; /* Get min & max values*/ - v = of_get_property(node, "min-value", NULL); + v = get_property(node, "min-value", NULL); if (v == NULL) goto fail; fct->min = *v; - v = of_get_property(node, "max-value", NULL); + v = get_property(node, "max-value", NULL); if (v == NULL) goto fail; fct->max = *v; /* Get "reg" value */ - reg = of_get_property(node, "reg", NULL); + reg = get_property(node, "reg", NULL); if (reg == NULL) goto fail; fct->reg = *reg; diff --git a/trunk/drivers/macintosh/windfarm_smu_sat.c b/trunk/drivers/macintosh/windfarm_smu_sat.c index 9a6c2cf8fd0e..83f79de7174b 100644 --- a/trunk/drivers/macintosh/windfarm_smu_sat.c +++ b/trunk/drivers/macintosh/windfarm_smu_sat.c @@ -241,7 +241,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) char *name; int vsens[2], isens[2]; - reg = of_get_property(dev, "reg", NULL); + reg = get_property(dev, "reg", NULL); if (reg == NULL) return; addr = *reg; @@ -268,9 +268,9 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) isens[0] = isens[1] = -1; child = NULL; while ((child = of_get_next_child(dev, child)) != NULL) { - reg = of_get_property(child, "reg", NULL); - type = of_get_property(child, "device_type", NULL); - loc = of_get_property(child, "location", NULL); + reg = get_property(child, "reg", NULL); + type = get_property(child, "device_type", NULL); + loc = get_property(child, "location", NULL); if (reg == NULL || loc == NULL) continue; diff --git a/trunk/drivers/macintosh/windfarm_smu_sensors.c b/trunk/drivers/macintosh/windfarm_smu_sensors.c index 9c567b93f417..01b4c50143dd 100644 --- a/trunk/drivers/macintosh/windfarm_smu_sensors.c +++ b/trunk/drivers/macintosh/windfarm_smu_sensors.c @@ -204,8 +204,8 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node) ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL); if (ads == NULL) return NULL; - c = of_get_property(node, "device_type", NULL); - l = of_get_property(node, "location", NULL); + c = get_property(node, "device_type", NULL); + l = get_property(node, "location", NULL); if (c == NULL || l == NULL) goto fail; @@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node) } else goto fail; - v = of_get_property(node, "reg", NULL); + v = get_property(node, "reg", NULL); if (v == NULL) goto fail; ads->reg = *v; diff --git a/trunk/drivers/md/dm-crypt.c b/trunk/drivers/md/dm-crypt.c index d8121234c347..4c2471ee054a 100644 --- a/trunk/drivers/md/dm-crypt.c +++ b/trunk/drivers/md/dm-crypt.c @@ -867,7 +867,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad4; } - cc->bs = bioset_create(MIN_IOS, MIN_IOS); + cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4); if (!cc->bs) { ti->error = "Cannot allocate crypt bioset"; goto bad_bs; diff --git a/trunk/drivers/md/dm-io.c b/trunk/drivers/md/dm-io.c index 8bdc8a87b249..4eb73d395213 100644 --- a/trunk/drivers/md/dm-io.c +++ b/trunk/drivers/md/dm-io.c @@ -60,7 +60,7 @@ static int resize_pool(unsigned int new_ios) if (!_io_pool) return -ENOMEM; - _bios = bioset_create(16, 16); + _bios = bioset_create(16, 16, 4); if (!_bios) { mempool_destroy(_io_pool); _io_pool = NULL; diff --git a/trunk/drivers/md/dm.c b/trunk/drivers/md/dm.c index 11a98df298ec..3668b170ea68 100644 --- a/trunk/drivers/md/dm.c +++ b/trunk/drivers/md/dm.c @@ -1012,7 +1012,7 @@ static struct mapped_device *alloc_dev(int minor) if (!md->tio_pool) goto bad3; - md->bs = bioset_create(16, 16); + md->bs = bioset_create(16, 16, 4); if (!md->bs) goto bad_no_bioset; diff --git a/trunk/drivers/media/common/ir-keymaps.c b/trunk/drivers/media/common/ir-keymaps.c index cbd1184b5219..03b47a262f27 100644 --- a/trunk/drivers/media/common/ir-keymaps.c +++ b/trunk/drivers/media/common/ir-keymaps.c @@ -667,7 +667,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { [ 0x1f ] = KEY_L, [ 0x2b ] = KEY_I, - [ 0x2d ] = KEY_SCREEN, + [ 0x2d ] = KEY_ZOOM, [ 0x1e ] = KEY_ZOOM, [ 0x1b ] = KEY_VOLUMEUP, [ 0x0f ] = KEY_VOLUMEDOWN, @@ -682,12 +682,12 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { [ 0x3f ] = KEY_UP, [ 0x3e ] = KEY_DOWN, - [ 0x1a ] = KEY_ENTER, + [ 0x1a ] = KEY_PAUSE, [ 0x1d ] = KEY_MENU, - [ 0x19 ] = KEY_AGAIN, - [ 0x16 ] = KEY_PREVIOUSSONG, - [ 0x13 ] = KEY_NEXTSONG, + [ 0x19 ] = KEY_PLAY, + [ 0x16 ] = KEY_REWIND, + [ 0x13 ] = KEY_FORWARD, [ 0x15 ] = KEY_PAUSE, [ 0x0e ] = KEY_REWIND, [ 0x0d ] = KEY_PLAY, @@ -1739,7 +1739,7 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_encore_enltv); -/* for the Technotrend 1500 bundled remotes (grey and black): */ +/* for the Technotrend 1500 bundled remote: */ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { [ 0x01 ] = KEY_POWER, [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */ @@ -1774,12 +1774,6 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { [ 0x25 ] = KEY_VOLUMEUP, [ 0x26 ] = KEY_VOLUMEDOWN, [ 0x27 ] = KEY_SETUP, - [ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */ - [ 0x3b ] = KEY_PLAY, - [ 0x3c ] = KEY_STOP, - [ 0x3d ] = KEY_REWIND, - [ 0x3e ] = KEY_PAUSE, - [ 0x3f ] = KEY_FORWARD, }; EXPORT_SYMBOL_GPL(ir_codes_tt_1500); diff --git a/trunk/drivers/media/common/saa7146_video.c b/trunk/drivers/media/common/saa7146_video.c index e3d04a4cef4d..7e0cedc557df 100644 --- a/trunk/drivers/media/common/saa7146_video.c +++ b/trunk/drivers/media/common/saa7146_video.c @@ -1428,7 +1428,6 @@ static void video_close(struct saa7146_dev *dev, struct file *file) { struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_vv *vv = dev->vv_data; - struct videobuf_queue *q = &fh->video_q; int err; if (IS_CAPTURE_ACTIVE(fh) != 0) { @@ -1437,11 +1436,6 @@ static void video_close(struct saa7146_dev *dev, struct file *file) err = saa7146_stop_preview(fh); } - // release all capture buffers - mutex_lock(&q->lock); - videobuf_read_stop(q); - mutex_unlock(&q->lock); - /* hmm, why is this function declared void? */ /* return err */ } diff --git a/trunk/drivers/media/dvb/b2c2/Kconfig b/trunk/drivers/media/dvb/b2c2/Kconfig index a0dcd59da76e..79875958930e 100644 --- a/trunk/drivers/media/dvb/b2c2/Kconfig +++ b/trunk/drivers/media/dvb/b2c2/Kconfig @@ -9,6 +9,7 @@ config DVB_B2C2_FLEXCOP select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_BCM3510 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/trunk/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/trunk/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index b02c2fd65baa..752cf79c532f 100644 --- a/trunk/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/trunk/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -14,6 +14,7 @@ #include "stv0297.h" #include "mt312.h" #include "lgdt330x.h" +#include "lgh06xf.h" #include "dvb-pll.h" /* lnb control */ @@ -506,7 +507,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) /* try the air atsc 3nd generation (lgdt3303) */ if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC3; - dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf); + dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap); info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); } else /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ diff --git a/trunk/drivers/media/dvb/b2c2/flexcop-i2c.c b/trunk/drivers/media/dvb/b2c2/flexcop-i2c.c index 02a0ea6e1c17..5347a406fff7 100644 --- a/trunk/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/trunk/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -183,8 +183,7 @@ int flexcop_i2c_init(struct flexcop_device *fc) mutex_init(&fc->i2c_mutex); memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); - strncpy(fc->i2c_adap.name, "B2C2 FlexCop device", - sizeof(fc->i2c_adap.name)); + strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE); i2c_set_adapdata(&fc->i2c_adap,fc); diff --git a/trunk/drivers/media/dvb/b2c2/flexcop-pci.c b/trunk/drivers/media/dvb/b2c2/flexcop-pci.c index 01af4d237eb1..6e166801505d 100644 --- a/trunk/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/trunk/drivers/media/dvb/b2c2/flexcop-pci.c @@ -127,11 +127,10 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) { struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; - unsigned long flags; flexcop_ibi_value v; irqreturn_t ret = IRQ_HANDLED; - spin_lock_irqsave(&fc_pci->irq_lock,flags); + spin_lock_irq(&fc_pci->irq_lock); v = fc->read_ibi_reg(fc,irq_20c); @@ -195,7 +194,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) ret = IRQ_NONE; } - spin_unlock_irqrestore(&fc_pci->irq_lock,flags); + spin_unlock_irq(&fc_pci->irq_lock); return ret; } @@ -294,12 +293,12 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) } pci_set_drvdata(fc_pci->pdev, fc_pci); - spin_lock_init(&fc_pci->irq_lock); + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; - + spin_lock_init(&fc_pci->irq_lock); fc_pci->init_state |= FC_PCI_INIT; return ret; diff --git a/trunk/drivers/media/dvb/bt8xx/Kconfig b/trunk/drivers/media/dvb/bt8xx/Kconfig index cfd6fb729a61..dd66b60fbc98 100644 --- a/trunk/drivers/media/dvb/bt8xx/Kconfig +++ b/trunk/drivers/media/dvb/bt8xx/Kconfig @@ -7,7 +7,7 @@ config DVB_BT8XX select DVB_CX24110 if !DVB_FE_CUSTOMISE select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_PLL + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select FW_LOADER help diff --git a/trunk/drivers/media/dvb/bt8xx/bt878.c b/trunk/drivers/media/dvb/bt8xx/bt878.c index df72b4b8ee10..83b090ef2445 100644 --- a/trunk/drivers/media/dvb/bt8xx/bt878.c +++ b/trunk/drivers/media/dvb/bt8xx/bt878.c @@ -393,7 +393,9 @@ static struct cards card_list[] __devinitdata = { { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, - { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" } + { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" }, + + { 0, -1, NULL } }; diff --git a/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 4f1c09bee538..58f69f6ae391 100644 --- a/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -610,8 +610,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) lgdt330x_reset(card); card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); if (card->fe != NULL) { - dvb_attach(dvb_pll_attach, card->fe, 0x61, - card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf); + dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter); dprintk ("dvb_bt8xx: lgdt330x detected\n"); } break; diff --git a/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 436880e68672..e75f4173c059 100644 --- a/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/trunk/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -37,8 +37,8 @@ #include "cx24110.h" #include "or51211.h" #include "lgdt330x.h" +#include "lgh06xf.h" #include "zl10353.h" -#include "dvb-pll.h" struct dvb_bt8xx_card { struct mutex lock; diff --git a/trunk/drivers/media/dvb/cinergyT2/cinergyT2.c b/trunk/drivers/media/dvb/cinergyT2/cinergyT2.c index 34d7abc900d7..a6cbbdd262d6 100644 --- a/trunk/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/trunk/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -26,11 +26,11 @@ #include #include #include +#include #include #include #include #include -#include #include "dmxdev.h" #include "dvb_demux.h" diff --git a/trunk/drivers/media/dvb/dvb-core/dmxdev.c b/trunk/drivers/media/dvb/dvb-core/dmxdev.c index 275df65fde99..a5c0e1a3e6d1 100644 --- a/trunk/drivers/media/dvb/dvb-core/dmxdev.c +++ b/trunk/drivers/media/dvb/dvb-core/dmxdev.c @@ -132,11 +132,6 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - if ((file->f_flags & O_ACCMODE) == O_RDWR) { if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { mutex_unlock(&dmxdev->mutex); @@ -176,7 +171,6 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->connect_frontend(dmxdev->demux, front); } - dvbdev->users++; mutex_unlock(&dmxdev->mutex); return 0; } @@ -204,16 +198,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) vfree(mem); } } - /* TODO */ - dvbdev->users--; - if(dvbdev->users==-1 && dmxdev->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - mutex_unlock(&dmxdev->mutex); - wake_up(&dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); - + mutex_unlock(&dmxdev->mutex); return 0; } @@ -230,11 +215,6 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, return -EINVAL; if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } ret = dmxdev->demux->write(dmxdev->demux, buf, count); mutex_unlock(&dmxdev->mutex); return ret; @@ -247,11 +227,6 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, struct dmxdev *dmxdev = dvbdev->priv; int ret; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - //mutex_lock(&dmxdev->mutex); ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, file->f_flags & O_NONBLOCK, @@ -690,8 +665,6 @@ static int dvb_demux_open(struct inode *inode, struct file *file) dmxdevfilter->feed.ts = NULL; init_timer(&dmxdevfilter->timer); - dvbdev->users++; - mutex_unlock(&dmxdev->mutex); return 0; } @@ -970,21 +943,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file) struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; - int ret; - - ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); - - mutex_lock(&dmxdev->mutex); - dmxdev->dvbdev->users--; - if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - mutex_unlock(&dmxdev->mutex); - wake_up(&dmxdev->dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); - - return ret; + return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); } static struct file_operations dvb_demux_fops = { @@ -1068,7 +1027,6 @@ static struct file_operations dvb_dvr_fops = { static struct dvb_device dvbdev_dvr = { .priv = NULL, .readers = 1, - .users = 1, .fops = &dvb_dvr_fops }; @@ -1106,16 +1064,6 @@ EXPORT_SYMBOL(dvb_dmxdev_init); void dvb_dmxdev_release(struct dmxdev *dmxdev) { - dmxdev->exit=1; - if (dmxdev->dvbdev->users > 1) { - wait_event(dmxdev->dvbdev->wait_queue, - dmxdev->dvbdev->users==1); - } - if (dmxdev->dvr_dvbdev->users > 1) { - wait_event(dmxdev->dvr_dvbdev->wait_queue, - dmxdev->dvr_dvbdev->users==1); - } - dvb_unregister_device(dmxdev->dvbdev); dvb_unregister_device(dmxdev->dvr_dvbdev); diff --git a/trunk/drivers/media/dvb/dvb-core/dmxdev.h b/trunk/drivers/media/dvb/dvb-core/dmxdev.h index 29746e70d325..d2bee9ffe43c 100644 --- a/trunk/drivers/media/dvb/dvb-core/dmxdev.h +++ b/trunk/drivers/media/dvb/dvb-core/dmxdev.h @@ -91,8 +91,6 @@ struct dmxdev { int filternum; int capabilities; - - unsigned int exit:1; #define DMXDEV_CAP_DUPLEX 1 struct dmx_frontend *dvr_orig_fe; diff --git a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c index f4e4ca2dcade..a21a894d3f98 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -606,7 +606,6 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) return; kthread_stop(fepriv->thread); - init_MUTEX (&fepriv->sem); fepriv->state = FESTATE_IDLE; @@ -1024,7 +1023,6 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int ret; dprintk ("%s\n", __FUNCTION__); @@ -1034,14 +1032,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if (fe->ops.ts_bus_ctrl) fe->ops.ts_bus_ctrl (fe, 0); - ret = dvb_generic_release (inode, file); - - if (dvbdev->users==-1 && fepriv->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); - } - return ret; + return dvb_generic_release (inode, file); } static struct file_operations dvb_frontend_fops = { @@ -1100,16 +1091,9 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); - mutex_lock(&frontend_mutex); - dvb_frontend_stop (fe); - mutex_unlock(&frontend_mutex); - - if (fepriv->dvbdev->users < -1) - wait_event(fepriv->dvbdev->wait_queue, - fepriv->dvbdev->users==-1); - mutex_lock(&frontend_mutex); dvb_unregister_device (fepriv->dvbdev); + dvb_frontend_stop (fe); /* fe is invalid now */ kfree(fepriv); diff --git a/trunk/drivers/media/dvb/dvb-core/dvb_net.c b/trunk/drivers/media/dvb/dvb-core/dvb_net.c index 4ebf33a5ffa2..76e9c36597eb 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvb_net.c +++ b/trunk/drivers/media/dvb/dvb-core/dvb_net.c @@ -174,7 +174,7 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, struct ethhdr *eth; unsigned char *rawp; - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); eth = eth_hdr(skb); @@ -600,7 +600,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Check CRC32, we've got it in our skb already. */ unsigned short ulen = htons(priv->ule_sndu_len); unsigned short utype = htons(priv->ule_sndu_type); - const u8 *tail; struct kvec iov[3] = { { &ulen, sizeof ulen }, { &utype, sizeof utype }, @@ -614,11 +613,10 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) } ule_crc = iov_crc32(ule_crc, iov, 3); - tail = skb_tail_pointer(priv->ule_skb); - expected_crc = *(tail - 4) << 24 | - *(tail - 3) << 16 | - *(tail - 2) << 8 | - *(tail - 1); + expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 | + *((u8 *)priv->ule_skb->tail - 3) << 16 | + *((u8 *)priv->ule_skb->tail - 2) << 8 | + *((u8 *)priv->ule_skb->tail - 1); if (ule_crc != expected_crc) { printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); @@ -697,9 +695,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) } else { - skb_copy_from_linear_data(priv->ule_skb, - dest_addr, - ETH_ALEN); + memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN); skb_pull(priv->ule_skb, ETH_ALEN); } } @@ -1439,36 +1435,11 @@ static int dvb_net_ioctl(struct inode *inode, struct file *file, return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl); } -static int dvb_net_close(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_net *dvbnet = dvbdev->priv; - - if (!dvbdev) - return -ENODEV; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; - - if(dvbdev->users == 1 && dvbnet->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); - } - return 0; -} - - static struct file_operations dvb_net_fops = { .owner = THIS_MODULE, .ioctl = dvb_net_ioctl, .open = dvb_generic_open, - .release = dvb_net_close, + .release = dvb_generic_release, }; static struct dvb_device dvbdev_net = { @@ -1483,11 +1454,6 @@ void dvb_net_release (struct dvb_net *dvbnet) { int i; - dvbnet->exit = 1; - if (dvbnet->dvbdev->users < 1) - wait_event(dvbnet->dvbdev->wait_queue, - dvbnet->dvbdev->users==1); - dvb_unregister_device(dvbnet->dvbdev); for (i=0; iadapter = adap; dvbdev->priv = priv; dvbdev->fops = dvbdevfops; - init_waitqueue_head (&dvbdev->wait_queue); memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations)); dvbdev->fops->owner = adap->module; diff --git a/trunk/drivers/media/dvb/dvb-core/dvbdev.h b/trunk/drivers/media/dvb/dvb-core/dvbdev.h index 6dff10ebf470..620e7887b3d3 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvbdev.h +++ b/trunk/drivers/media/dvb/dvb-core/dvbdev.h @@ -69,7 +69,6 @@ struct dvb_device { int writers; int users; - wait_queue_head_t wait_queue; /* don't really need those !? -- FIXME: use video_usercopy */ int (*kernel_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, void *arg); diff --git a/trunk/drivers/media/dvb/dvb-usb/Kconfig b/trunk/drivers/media/dvb/dvb-usb/Kconfig index 54488737a08f..80f67a51b908 100644 --- a/trunk/drivers/media/dvb/dvb-usb/Kconfig +++ b/trunk/drivers/media/dvb/dvb-usb/Kconfig @@ -33,7 +33,6 @@ config DVB_USB_A800 config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB - select DVB_PLL select DVB_DIB3000MB select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help @@ -89,7 +88,6 @@ config DVB_USB_DIB0700 config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help @@ -98,9 +96,9 @@ config DVB_USB_UMT_010 config DVB_USB_CXUSB tristate "Conexant USB2.0 hybrid reference design support" depends on DVB_USB - select DVB_PLL select DVB_CX22702 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE help @@ -142,7 +140,6 @@ config DVB_USB_AU6610 config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL select DVB_NXT6000 if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE help @@ -211,10 +208,3 @@ config DVB_USB_DTT200U The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). The WT-220U and its clones are pen-sized. - -config DVB_USB_OPERA1 - tristate "Opera1 DVB-S USB2.0 receiver" - depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE - help - Say Y here to support the Opera DVB-S USB2.0 receiver. diff --git a/trunk/drivers/media/dvb/dvb-usb/Makefile b/trunk/drivers/media/dvb/dvb-usb/Makefile index 976f840cc904..40f28f559b54 100644 --- a/trunk/drivers/media/dvb/dvb-usb/Makefile +++ b/trunk/drivers/media/dvb/dvb-usb/Makefile @@ -51,8 +51,4 @@ obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o -dvb-usb-opera-objs = opera1.o -obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o - - EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/trunk/drivers/media/dvb/dvb-usb/au6610.c b/trunk/drivers/media/dvb/dvb-usb/au6610.c index 18e0b16fb2a9..0dc66a8d2baf 100644 --- a/trunk/drivers/media/dvb/dvb-usb/au6610.c +++ b/trunk/drivers/media/dvb/dvb-usb/au6610.c @@ -40,7 +40,7 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, } ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, - USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf, + USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT); if (ret < 0) @@ -124,7 +124,7 @@ static int au6610_identify_state(struct usb_device *udev, } static struct zl10353_config au6610_zl10353_config = { - .demod_address = 0x0f, + .demod_address = 0x1e, .no_tuner = 1, .parallel_ts = 1, }; @@ -140,7 +140,7 @@ static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) } static struct qt1010_config au6610_qt1010_config = { - .i2c_address = 0x62 + .i2c_address = 0xc4 }; static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) diff --git a/trunk/drivers/media/dvb/dvb-usb/cxusb.c b/trunk/drivers/media/dvb/dvb-usb/cxusb.c index bac2ae3b4a1f..127a94b9a1b5 100644 --- a/trunk/drivers/media/dvb/dvb-usb/cxusb.c +++ b/trunk/drivers/media/dvb/dvb-usb/cxusb.c @@ -27,6 +27,7 @@ #include "cx22702.h" #include "lgdt330x.h" +#include "lgh06xf.h" #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" @@ -387,8 +388,7 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap); return 0; } diff --git a/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c b/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c index dddf164f269a..6a4d150784a6 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -56,6 +56,10 @@ static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u if (txlen > 3) index |= tx[3]; + /* think about swapping here */ + value = le16_to_cpu(value); + index = le16_to_cpu(index); + status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, USB_CTRL_GET_TIMEOUT); diff --git a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 088b6dee3a7f..70df31b0a8a9 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) return -EINVAL; } - strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); + strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE); #ifdef I2C_ADAP_CLASS_TV_DIGITAL d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, #else diff --git a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 97715f7514d6..148386aba275 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -13,7 +13,6 @@ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ANCHOR 0x0547 -#define USB_VID_ANUBIS_ELECTRONIC 0x10fd #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -32,7 +31,6 @@ #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 #define USB_VID_MSI 0x0db0 -#define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 @@ -129,7 +127,6 @@ #define USB_PID_KYE_DVB_T_WARM 0x701f #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 #define USB_PID_LITEON_DVB_T_COLD 0xf000 #define USB_PID_LITEON_DVB_T_WARM 0xf001 #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 @@ -142,9 +139,6 @@ #define USB_PID_GENPIX_8PSK_COLD 0x0200 #define USB_PID_GENPIX_8PSK_WARM 0x0201 #define USB_PID_SIGMATEK_DVB_110 0x6610 -#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 -#define USB_PID_OPERA1_COLD 0x2830 -#define USB_PID_OPERA1_WARM 0x3829 #endif diff --git a/trunk/drivers/media/dvb/dvb-usb/gl861.c b/trunk/drivers/media/dvb/dvb-usb/gl861.c index e0587e663591..c9f38a5e70d3 100644 --- a/trunk/drivers/media/dvb/dvb-usb/gl861.c +++ b/trunk/drivers/media/dvb/dvb-usb/gl861.c @@ -12,7 +12,7 @@ #include "qt1010.h" /* debug */ -static int dvb_usb_gl861_debug; +int dvb_usb_gl861_debug; module_param_named(debug,dvb_usb_gl861_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); @@ -20,7 +20,7 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { u16 index; - u16 value = addr << (8 + 1); + u16 value = addr << 8; int wo = (rbuf == NULL || rlen == 0); /* write-only */ u8 req, type; @@ -101,7 +101,7 @@ static int gl861_identify_state(struct usb_device *udev, } static struct zl10353_config gl861_zl10353_config = { - .demod_address = 0x0f, + .demod_address = 0x1e, .no_tuner = 1, .parallel_ts = 1, }; @@ -117,7 +117,7 @@ static int gl861_frontend_attach(struct dvb_usb_adapter *adap) } static struct qt1010_config gl861_qt1010_config = { - .i2c_address = 0x62 + .i2c_address = 0xc4 }; static int gl861_tuner_attach(struct dvb_usb_adapter *adap) diff --git a/trunk/drivers/media/dvb/dvb-usb/m920x.c b/trunk/drivers/media/dvb/dvb-usb/m920x.c index 45d7bc214c18..d48b24d9abf4 100644 --- a/trunk/drivers/media/dvb/dvb-usb/m920x.c +++ b/trunk/drivers/media/dvb/dvb-usb/m920x.c @@ -14,8 +14,6 @@ #include "mt352.h" #include "mt352_priv.h" #include "qt1010.h" -#include "tda1004x.h" -#include "tda827x.h" /* debug */ static int dvb_usb_m920x_debug; @@ -49,15 +47,11 @@ static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), request, USB_TYPE_VENDOR | USB_DIR_IN, value, index, data, size, 2000); - if (ret < 0) { - printk(KERN_INFO "m920x_read = error: %d\n", ret); + if (ret < 0) return ret; - } - if (ret != size) { - deb_rc("m920x_read = no data\n"); + if (ret != size) return -EIO; - } return 0; } @@ -70,22 +64,19 @@ static inline int m9206_write(struct usb_device *udev, u8 request, ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, USB_TYPE_VENDOR | USB_DIR_OUT, value, index, NULL, 0, 2000); - return ret; } -static int m9206_init(struct dvb_usb_device *d) +static int m9206_rc_init(struct usb_device *udev) { int ret = 0; /* Remote controller init. */ - if (d->props.rc_query) { - if ((ret = m9206_write(d->udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0) - return ret; + if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0) + return ret; - if ((ret = m9206_write(d->udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0) - return ret; - } + if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0) + return ret; return ret; } @@ -96,15 +87,16 @@ static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state) int i, ret = 0; u8 rc_state[2]; + if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) goto unlock; if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) goto unlock; - for (i = 0; i < d->props.rc_key_map_size; i++) - if (d->props.rc_key_map[i].data == rc_state[1]) { - *event = d->props.rc_key_map[i].event; + for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++) + if (megasky_rc_keys[i].data == rc_state[1]) { + *event = megasky_rc_keys[i].event; switch(rc_state[0]) { case 0x80: @@ -145,51 +137,53 @@ static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i, j; + struct m9206_state *m = d->priv; + int i; int ret = 0; - if (!num) - return -EINVAL; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (num > 2) + return -EINVAL; + for (i = 0; i < num; i++) { - if (msg[i].flags & (I2C_M_NO_RD_ACK|I2C_M_IGNORE_NAK|I2C_M_TEN) || - msg[i].len == 0) { - /* For a 0 byte message, I think sending the address to index 0x80|0x40 - * would be the correct thing to do. However, zero byte messages are - * only used for probing, and since we don't know how to get the slave's - * ack, we can't probe. */ - ret = -ENOTSUPP; + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0) goto unlock; - } - /* Send START & address/RW bit */ - if (!(msg[i].flags & I2C_M_NOSTART)) { - if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), 0x80)) != 0) + + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0) + goto unlock; + + if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) { + int i2c_i; + + for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++) + if (msg[i].addr == m->i2c_r[i2c_i].addr) + break; + + if (i2c_i >= M9206_I2C_MAX) { + deb_rc("No magic for i2c addr!\n"); + ret = -EINVAL; goto unlock; - /* Should check for ack here, if we knew how. */ - } - if (msg[i].flags & I2C_M_RD) { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? Send STOP, otherwise send ACK. */ - int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x01; - if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x20|stop, &msg[i].buf[j], 1)) != 0) - goto unlock; } + + if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0) + goto unlock; + + if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0) + goto unlock; + + i++; } else { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? Then send STOP. */ - int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x00; - if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) - goto unlock; - /* Should check for ack here too. */ - } + if (msg[i].len != 2) + return -EINVAL; + + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0) + goto unlock; } } - ret = num; - -unlock: + ret = i; + unlock: mutex_unlock(&d->i2c_mutex); return ret; @@ -330,7 +324,6 @@ static int m9206_firmware_download(struct usb_device *udev, i += size; } if (i != fw->size) { - deb_rc("bad firmware file!\n"); ret = -EINVAL; goto done; } @@ -349,10 +342,10 @@ static int m9206_firmware_download(struct usb_device *udev, } /* Callbacks for DVB USB */ -static int m920x_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) +static int megasky_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) { struct usb_host_interface *alt; @@ -388,15 +381,20 @@ static int megasky_mt352_demod_init(struct dvb_frontend *fe) } static struct mt352_config megasky_mt352_config = { - .demod_address = 0x0f, + .demod_address = 0x1e, .no_tuner = 1, .demod_init = megasky_mt352_demod_init, }; static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) { + struct m9206_state *m = adap->dev->priv; + deb_rc("megasky_frontend_attach!\n"); + m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address; + m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f; + if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -404,11 +402,16 @@ static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) } static struct qt1010_config megasky_qt1010_config = { - .i2c_address = 0x62 + .i2c_address = 0xc4 }; static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { + struct m9206_state *m = adap->dev->priv; + + m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address; + m->i2c_r[M9206_I2C_TUNER].magic = 0xc5; + if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &megasky_qt1010_config) == NULL) return -ENODEV; @@ -416,40 +419,8 @@ static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static struct tda1004x_config digivox_tda10046_config = { - .demod_address = 0x08, - .invert = 0, - .invert_oclk = 0, - .ts_mode = TDA10046_TS_SERIAL, - .xtal_freq = TDA10046_XTAL_16M, - .if_freq = TDA10046_FREQ_045, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GPTRI, - .request_firmware = NULL, -}; - -static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb_rc("digivox_tda10046_frontend_attach!\n"); - - if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - return 0; -} - -static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap) -{ - if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, - NULL) == NULL) - return -ENODEV; - return 0; -} - /* DVB USB Driver stuff */ static struct dvb_usb_device_properties megasky_properties; -static struct dvb_usb_device_properties digivox_mini_ii_properties; static int m920x_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -458,36 +429,30 @@ static int m920x_probe(struct usb_interface *intf, struct usb_host_interface *alt; int ret; - deb_rc("Probed!\n"); + if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) { + deb_rc("probed!\n"); - if (((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) || - ((ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, THIS_MODULE, &d)) == 0)) - goto found; - - return ret; - -found: - alt = usb_altnum_to_altsetting(intf, 1); - if (alt == NULL) { - deb_rc("No alt found!\n"); - return -ENODEV; - } + alt = usb_altnum_to_altsetting(intf, 1); + if (alt == NULL) { + deb_rc("not alt found!\n"); + return -ENODEV; + } - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (ret < 0) - return ret; + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret < 0) + return ret; - if ((ret = m9206_init(d)) != 0) - return ret; + deb_rc("Changed to alternate setting!\n"); + if ((ret = m9206_rc_init(d->udev)) != 0) + return ret; + } return ret; } static struct usb_device_id m920x_table [] = { { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_MSI_DIGI_VOX_MINI_II) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, m920x_table); @@ -506,7 +471,7 @@ static struct dvb_usb_device_properties megasky_properties = { .size_of_priv = sizeof(struct m9206_state), - .identify_state = m920x_identify_state, + .identify_state = megasky_identify_state, .num_adapters = 1, .adapter = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | @@ -537,50 +502,6 @@ static struct dvb_usb_device_properties megasky_properties = { { "MSI Mega Sky 580 DVB-T USB2.0", { &m920x_table[0], NULL }, { NULL }, - } - } -}; - -static struct dvb_usb_device_properties digivox_mini_ii_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-digivox-02.fw", - .download_firmware = m9206_firmware_download, - - .size_of_priv = sizeof(struct m9206_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m9206_pid_filter, - .pid_filter_ctrl = m9206_pid_filter_ctrl, - - .frontend_attach = digivox_tda10046_frontend_attach, - .tuner_attach = digivox_tda8275_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 0x4000, - } - } - }, - }}, - .i2c_algo = &m9206_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "MSI DIGI VOX mini II DVB-T USB2.0", - { &m920x_table[1], NULL }, - { NULL }, }, } }; diff --git a/trunk/drivers/media/dvb/dvb-usb/m920x.h b/trunk/drivers/media/dvb/dvb-usb/m920x.h index 7dd3db65c80e..c354196ffe5d 100644 --- a/trunk/drivers/media/dvb/dvb-usb/m920x.h +++ b/trunk/drivers/media/dvb/dvb-usb/m920x.h @@ -19,49 +19,17 @@ #define M9206_MAX_FILTERS 8 -/* -sequences found in logs: -[index value] -0x80 write addr -(0x00 out byte)* -0x40 out byte - -0x80 write addr -(0x00 out byte)* -0x80 read addr -(0x21 in byte)* -0x60 in byte - -this sequence works: -0x80 read addr -(0x21 in byte)* -0x60 in byte - -Guess at API of the I2C function: -I2C operation is done one byte at a time with USB control messages. The -index the messages is sent to is made up of a set of flags that control -the I2C bus state: -0x80: Send START condition. After a START condition, one would normally - always send the 7-bit slave I2C address as the 7 MSB, followed by - the read/write bit as the LSB. -0x40: Send STOP condition. This should be set on the last byte of an - I2C transaction. -0x20: Read a byte from the slave. As opposed to writing a byte to the - slave. The slave will normally not produce any data unless you - set the R/W bit to 1 when sending the slave's address after the - START condition. -0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, - the master should send an ACK, that is pull SDA low during the 9th - clock cycle, after every byte but the last. This flags only makes - sense when bit 0x20 is set, indicating a read. - -What any other bits might mean, or how to get the slave's ACK/NACK -response to a write, is unknown. -*/ +#define M9206_I2C_TUNER 0 +#define M9206_I2C_DEMOD 1 +#define M9206_I2C_MAX 2 struct m9206_state { u16 filters[M9206_MAX_FILTERS]; int filtering_enabled; int rep_count; + struct { + unsigned char addr; + unsigned char magic; + }i2c_r[M9206_I2C_MAX]; }; #endif diff --git a/trunk/drivers/media/dvb/dvb-usb/opera1.c b/trunk/drivers/media/dvb/dvb-usb/opera1.c deleted file mode 100644 index 518d7ad217df..000000000000 --- a/trunk/drivers/media/dvb/dvb-usb/opera1.c +++ /dev/null @@ -1,581 +0,0 @@ -/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card -* -* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) -* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the Free -* Software Foundation, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ - -#include "opera1.h" -#include "stv0299.h" - -#define OPERA_READ_MSG 0 -#define OPERA_WRITE_MSG 1 -#define OPERA_I2C_TUNER 0xd1 - -#define READ_FX2_REG_REQ 0xba -#define READ_MAC_ADDR 0x08 -#define OPERA_WRITE_FX2 0xbb -#define OPERA_TUNER_REQ 0xb1 -#define REG_1F_SYMBOLRATE_BYTE0 0x1f -#define REG_20_SYMBOLRATE_BYTE1 0x20 -#define REG_21_SYMBOLRATE_BYTE2 0x21 - -#define ADDR_B600_VOLTAGE_13V (0x02) -#define ADDR_B601_VOLTAGE_18V (0x03) -#define ADDR_B1A6_STREAM_CTRL (0x04) -#define ADDR_B880_READ_REMOTE (0x05) - -struct opera1_state { - u32 last_key_pressed; -}; -struct opera_rc_keys { - u32 keycode; - u32 event; -}; - -int dvb_usb_opera1_debug; -module_param_named(debug, dvb_usb_opera1_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." - DVB_USB_DEBUG_STATUS); - -static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, - u8 * data, u16 len, int flags) -{ - int ret; - u8 r; - u8 u8buf[len]; - - unsigned int pipe = (flags == OPERA_READ_MSG) ? - usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - - if (flags == OPERA_WRITE_MSG) - memcpy(u8buf, data, len); - ret = - usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, - value, 0x0, u8buf, len, 2000); - - if (request == OPERA_TUNER_REQ) { - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, - 0x01, 0x0, &r, 1, 2000)<1 || r!=0x08) - return 0; - } - if (flags == OPERA_READ_MSG) - memcpy(data, u8buf, len); - return ret; -} - -/* I2C */ - -static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, - u8 * buf, u16 len) -{ - int ret = 0; - u8 request; - u16 value; - - if (!dev) { - info("no usb_device"); - return -EINVAL; - } - if (mutex_lock_interruptible(&dev->usb_mutex) < 0) - return -EAGAIN; - - switch (addr>>1){ - case ADDR_B600_VOLTAGE_13V: - request=0xb6; - value=0x00; - break; - case ADDR_B601_VOLTAGE_18V: - request=0xb6; - value=0x01; - break; - case ADDR_B1A6_STREAM_CTRL: - request=0xb1; - value=0xa6; - break; - case ADDR_B880_READ_REMOTE: - request=0xb8; - value=0x80; - break; - default: - request=0xb1; - value=addr; - } - ret = opera1_xilinx_rw(dev->udev, request, - value, buf, len, - addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); - - mutex_unlock(&dev->usb_mutex); - return ret; -} - -static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, tmp = 0; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if ((tmp = opera1_usb_i2c_msgxfer(d, - (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), - msg[i].buf, - msg[i].len - )!= msg[i].len)) { - break; - } - if (dvb_usb_opera1_debug & 0x10) - info("sending i2c mesage %d %d", tmp, msg[i].len); - } - mutex_unlock(&d->i2c_mutex); - return num; -} - -static u32 opera1_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm opera1_i2c_algo = { - .master_xfer = opera1_i2c_xfer, - .functionality = opera1_i2c_func, -}; - -static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - static u8 command_13v[1]={0x00}; - static u8 command_18v[1]={0x01}; - struct i2c_msg msg[] = { - {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, - }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - if (voltage == SEC_VOLTAGE_18) { - msg[0].addr = ADDR_B601_VOLTAGE_18V; - msg[0].buf = command_18v; - } - i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, - u32 ratio) -{ - stv0299_writereg(fe, 0x13, 0x98); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); - stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); - stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); - return 0; - -} -static u8 opera1_inittab[] = { - 0x00, 0xa1, - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x05, - 0x06, 0x02, - 0x07, 0x00, - 0x0b, 0x00, - 0x0c, 0x01, - 0x0d, 0x81, - 0x0e, 0x44, - 0x0f, 0x19, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x98, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0xeb, - 0x17, 0x00, - 0x18, 0x19, - 0x19, 0x8b, - 0x1a, 0x00, - 0x1b, 0x82, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - REG_1F_SYMBOLRATE_BYTE0, 0x06, - REG_20_SYMBOLRATE_BYTE1, 0x50, - REG_21_SYMBOLRATE_BYTE2, 0x10, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x37, - 0x25, 0xbc, - 0x26, 0x00, - 0x27, 0x00, - 0x28, 0x00, - 0x29, 0x1e, - 0x2a, 0x14, - 0x2b, 0x1f, - 0x2c, 0x09, - 0x2d, 0x0a, - 0x2e, 0x00, - 0x2f, 0x00, - 0x30, 0x00, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13, - 0xff, 0xff, -}; - -static struct stv0299_config opera1_stv0299_config = { - .demod_address = 0xd0>>1, - .min_delay_ms = 100, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0229_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .inittab = opera1_inittab, - .set_symbol_rate = opera1_stv0299_set_symbol_rate, -}; - -static int opera1_frontend_attach(struct dvb_usb_adapter *d) -{ - if ((d->fe = - dvb_attach(stv0299_attach, &opera1_stv0299_config, - &d->dev->i2c_adap)) != NULL) { - d->fe->ops.set_voltage = opera1_set_voltage; - return 0; - } - info("not attached stv0299"); - return -EIO; -} - -static int opera1_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach( - dvb_pll_attach, adap->fe, 0xc0>>1, - &adap->dev->i2c_adap, &dvb_pll_opera1 - ); - return 0; -} - -static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 val = onoff ? 0x01 : 0x00; - - if (dvb_usb_opera1_debug) - info("power %s", onoff ? "on" : "off"); - return opera1_xilinx_rw(d->udev, 0xb7, val, - &val, 1, OPERA_WRITE_MSG); -} - -static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - static u8 buf_start[2] = { 0xff, 0x03 }; - static u8 buf_stop[2] = { 0xff, 0x00 }; - struct i2c_msg start_tuner[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, - }; - if (dvb_usb_opera1_debug) - info("streaming %s", onoff ? "on" : "off"); - i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); - return 0; -} - -static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("pidfilter index: %d pid: %d %s", index, pid, - onoff ? "on" : "off"); - b_pid[0] = (2 * index) + 4; - b_pid[1] = onoff ? (pid & 0xff) : (0x00); - b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) -{ - int u = 0x04; - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("%s hw-pidfilter", onoff ? "enable" : "disable"); - for (; u < 0x7e; u += 2) { - b_pid[0] = u; - b_pid[1] = 0; - b_pid[2] = 0x80; - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - } - return 0; -} - -static struct dvb_usb_rc_key opera1_rc_keys[] = { - {0x5f, 0xa0, KEY_1}, - {0x51, 0xaf, KEY_2}, - {0x5d, 0xa2, KEY_3}, - {0x41, 0xbe, KEY_4}, - {0x0b, 0xf5, KEY_5}, - {0x43, 0xbd, KEY_6}, - {0x47, 0xb8, KEY_7}, - {0x49, 0xb6, KEY_8}, - {0x05, 0xfa, KEY_9}, - {0x45, 0xba, KEY_0}, - {0x09, 0xf6, KEY_UP}, /*chanup */ - {0x1b, 0xe5, KEY_DOWN}, /*chandown */ - {0x5d, 0xa3, KEY_LEFT}, /*voldown */ - {0x5f, 0xa1, KEY_RIGHT}, /*volup */ - {0x07, 0xf8, KEY_SPACE}, /*tab */ - {0x1f, 0xe1, KEY_ENTER}, /*play ok */ - {0x1b, 0xe4, KEY_Z}, /*zoom */ - {0x59, 0xa6, KEY_M}, /*mute */ - {0x5b, 0xa5, KEY_F}, /*tv/f */ - {0x19, 0xe7, KEY_R}, /*rec */ - {0x01, 0xfe, KEY_S}, /*Stop */ - {0x03, 0xfd, KEY_P}, /*pause */ - {0x03, 0xfc, KEY_W}, /*<- -> */ - {0x07, 0xf9, KEY_C}, /*capture */ - {0x47, 0xb9, KEY_Q}, /*exit */ - {0x43, 0xbc, KEY_O}, /*power */ - -}; - -static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) -{ - struct opera1_state *opst = dev->priv; - u8 rcbuffer[32]; - const u16 startmarker1 = 0x10ed; - const u16 startmarker2 = 0x11ec; - struct i2c_msg read_remote[] = { - {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, - }; - int i = 0; - u32 send_key = 0; - - if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { - for (i = 0; i < 32; i++) { - if (rcbuffer[i]) - send_key |= 1; - if (i < 31) - send_key = send_key << 1; - } - if (send_key & 0x8000) - send_key = (send_key << 1) | (send_key >> 15 & 0x01); - - if (send_key == 0xffff && opst->last_key_pressed != 0) { - *state = REMOTE_KEY_REPEAT; - *event = opst->last_key_pressed; - return 0; - } - for (; send_key != 0;) { - if (send_key >> 16 == startmarker2) { - break; - } else if (send_key >> 16 == startmarker1) { - send_key = - (send_key & 0xfffeffff) | (startmarker1 << 16); - break; - } else - send_key >>= 1; - } - - if (send_key == 0) - return 0; - - send_key = (send_key & 0xffff) | 0x0100; - - for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) { - if ((opera1_rc_keys[i].custom * 256 + - opera1_rc_keys[i].data) == (send_key & 0xffff)) { - *state = REMOTE_KEY_PRESSED; - *event = opera1_rc_keys[i].event; - opst->last_key_pressed = - opera1_rc_keys[i].event; - break; - } - opst->last_key_pressed = 0; - } - } else - *state = REMOTE_NO_KEY_PRESSED; - return 0; -} - -static struct usb_device_id opera1_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, - {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, opera1_table); - -static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - u8 command[] = { READ_MAC_ADDR }; - opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); - opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); - return 0; -} -static int opera1_xilinx_load_firmware(struct usb_device *dev, - const char *filename) -{ - const struct firmware *fw = NULL; - u8 *b, *p; - int ret = 0, i; - u8 testval; - info("start downloading fpga firmware"); - - if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - filename); - return ret; - } else { - p = kmalloc(fw->size, GFP_KERNEL); - opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); - if (p != NULL && testval != 0x67) { - - u8 reset = 0, fpga_command = 0; - memcpy(p, fw->data, fw->size); - /* clear fpga ? */ - opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, - OPERA_WRITE_MSG); - for (i = 0; p[i] != 0 && i < fw->size;) { - b = (u8 *) p + i; - if (opera1_xilinx_rw - (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0], - OPERA_WRITE_MSG) != b[0] - ) { - err("error while transferring firmware"); - ret = -EINVAL; - break; - } - i = i + 1 + b[0]; - } - /* restart the CPU */ - if (ret || opera1_xilinx_rw - (dev, 0xa0, 0xe600, &reset, 1, - OPERA_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - kfree(p); - } - } - if (fw) { - release_firmware(fw); - } - return ret; -} - -static struct dvb_usb_device_properties opera1_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-opera-01.fw", - .size_of_priv = sizeof(struct opera1_state), - - .power_ctrl = opera1_power_ctrl, - .i2c_algo = &opera1_i2c_algo, - - .rc_key_map = opera1_rc_keys, - .rc_key_map_size = ARRAY_SIZE(opera1_rc_keys), - .rc_interval = 200, - .rc_query = opera1_rc_query, - .read_mac_address = opera1_read_mac_address, - .generic_bulk_ctrl_endpoint = 0x00, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .adapter = { - { - .frontend_attach = opera1_frontend_attach, - .streaming_ctrl = opera1_streaming_ctrl, - .tuner_attach = opera1_tuner_attach, - .caps = - DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter = opera1_pid_filter, - .pid_filter_ctrl = opera1_pid_filter_control, - .pid_filter_count = 252, - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 1, - .devices = { - {"Opera1 DVB-S USB2.0", - {&opera1_table[0], NULL}, - {&opera1_table[1], NULL}, - }, - } -}; - -static int opera1_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_device *udev = interface_to_usbdev(intf); - - if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && - udev->descriptor.idVendor == USB_VID_OPERA1 && - (d == NULL - || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0) - ) { - return -EINVAL; - } - - if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0) - return -EINVAL; - return 0; -} - -static struct usb_driver opera1_driver = { - .name = "opera1", - .probe = opera1_probe, - .disconnect = dvb_usb_device_exit, - .id_table = opera1_table, -}; - -static int __init opera1_module_init(void) -{ - int result = 0; - if ((result = usb_register(&opera1_driver))) { - err("usb_register failed. Error number %d", result); - } - return result; -} - -static void __exit opera1_module_exit(void) -{ - usb_deregister(&opera1_driver); -} - -module_init(opera1_module_init); -module_exit(opera1_module_exit); - -MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); -MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); -MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); -MODULE_VERSION("0.1"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/media/dvb/dvb-usb/opera1.h b/trunk/drivers/media/dvb/dvb-usb/opera1.h deleted file mode 100644 index 53174427902d..000000000000 --- a/trunk/drivers/media/dvb/dvb-usb/opera1.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _OPERA1_H_ -#define _OPERA1_H_ - -#define DVB_USB_LOG_PREFIX "opera" -#include "dvb-usb.h" - -extern int dvb_usb_opera1_debug; -#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) -#endif diff --git a/trunk/drivers/media/dvb/dvb-usb/ttusb2.c b/trunk/drivers/media/dvb/dvb-usb/ttusb2.c index 88dc4367a2e3..95d29976ed78 100644 --- a/trunk/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/trunk/drivers/media/dvb/dvb-usb/ttusb2.c @@ -184,7 +184,6 @@ static int ttusb2_probe(struct usb_interface *intf, static struct usb_device_id ttusb2_table [] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, ttusb2_table); @@ -228,16 +227,12 @@ static struct dvb_usb_device_properties ttusb2_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 2, + .num_device_descs = 1, .devices = { { "Pinnacle 400e DVB-S USB2.0", { &ttusb2_table[0], NULL }, { NULL }, }, - { "Pinnacle 450e DVB-S USB2.0", - { &ttusb2_table[1], NULL }, - { NULL }, - }, } }; diff --git a/trunk/drivers/media/dvb/frontends/Kconfig b/trunk/drivers/media/dvb/frontends/Kconfig index ff448761dcef..22c2cf2cea98 100644 --- a/trunk/drivers/media/dvb/frontends/Kconfig +++ b/trunk/drivers/media/dvb/frontends/Kconfig @@ -205,13 +205,6 @@ config DVB_TDA10021 help A DVB-C tuner module. Say Y when you want to support this frontend. -config DVB_TDA10023 - tristate "Philips TDA10023 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-C tuner module. Say Y when you want to support this frontend. - config DVB_STV0297 tristate "ST STV0297 based" depends on DVB_CORE && I2C @@ -287,12 +280,8 @@ comment "Tuners/PLL support" depends on DVB_CORE config DVB_PLL - tristate "Generic I2C PLL based tuners" + tristate depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - This module driver a number of tuners based on PLL chips with a - common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X tristate "Philips TDA826X silicon tuner" @@ -301,13 +290,6 @@ config DVB_TDA826X help A DVB-S silicon tuner module. Say Y when you want to support this tuner. -config DVB_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C @@ -322,6 +304,14 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config DVB_TUNER_LGH06XF + tristate "LG TDVS-H06xF ATSC tuner" + depends on DVB_CORE && I2C + select DVB_PLL + default m if DVB_FE_CUSTOMISE + help + A driver for the LG TDVS-H06xF ATSC tuner family. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/trunk/drivers/media/dvb/frontends/Makefile b/trunk/drivers/media/dvb/frontends/Makefile index 27f386585d43..a646d9969b71 100644 --- a/trunk/drivers/media/dvb/frontends/Makefile +++ b/trunk/drivers/media/dvb/frontends/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_DVB_MT352) += mt352.o obj-$(CONFIG_DVB_ZL10353) += zl10353.o obj-$(CONFIG_DVB_CX22702) += cx22702.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o -obj-$(CONFIG_DVB_TDA10023) += tda10023.o obj-$(CONFIG_DVB_STV0297) += stv0297.o obj-$(CONFIG_DVB_NXT200X) += nxt200x.o obj-$(CONFIG_DVB_OR51211) += or51211.o @@ -38,7 +37,7 @@ obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o -obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o diff --git a/trunk/drivers/media/dvb/frontends/dibx000_common.c b/trunk/drivers/media/dvb/frontends/dibx000_common.c index 315e09e95b0c..a18c8f45a2ee 100644 --- a/trunk/drivers/media/dvb/frontends/dibx000_common.c +++ b/trunk/drivers/media/dvb/frontends/dibx000_common.c @@ -105,9 +105,9 @@ struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enu } EXPORT_SYMBOL(dibx000_get_i2c_adapter); -static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) +static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst) { - strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); + strncpy(i2c_adap->name, name, I2C_NAME_SIZE); i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo; i2c_adap->algo_data = NULL; diff --git a/trunk/drivers/media/dvb/frontends/dvb-pll.c b/trunk/drivers/media/dvb/frontends/dvb-pll.c index 5f96ffda91ad..62de760c844f 100644 --- a/trunk/drivers/media/dvb/frontends/dvb-pll.c +++ b/trunk/drivers/media/dvb/frontends/dvb-pll.c @@ -27,29 +27,17 @@ /* ----------------------------------------------------------- */ /* descriptions */ -/* Set AGC TOP value to 103 dBuV: - 0x80 = Control Byte - 0x40 = 250 uA charge pump (irrelevant) - 0x18 = Aux Byte to follow - 0x06 = 64.5 kHz divider (irrelevant) - 0x01 = Disable Vt (aka sleep) - - 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) - 0x50 = AGC Take over point = 103 dBuV */ -static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; - struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { .name = "Thomson dtt7579", .min = 177000000, .max = 858000000, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0xb4, 0x03 }, - .count = 4, + .count = 5, .entries = { - { 443250000, 166667, 0xb4, 0x02 }, - { 542000000, 166667, 0xb4, 0x08 }, - { 771000000, 166667, 0xbc, 0x08 }, - { 999999999, 166667, 0xf4, 0x08 }, + { 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */ + { 443250000, 36166667, 166666, 0xb4, 0x02 }, + { 542000000, 36166667, 166666, 0xb4, 0x08 }, + { 771000000, 36166667, 166666, 0xbc, 0x08 }, + { 999999999, 36166667, 166666, 0xf4, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); @@ -58,12 +46,11 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { .name = "Thomson dtt7610", .min = 44000000, .max = 958000000, - .iffreq= 44000000, .count = 3, .entries = { - { 157250000, 62500, 0x8e, 0x39 }, - { 454000000, 62500, 0x8e, 0x3a }, - { 999999999, 62500, 0x8e, 0x3c }, + { 157250000, 44000000, 62500, 0x8e, 0x39 }, + { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 999999999, 44000000, 62500, 0x8e, 0x3c }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); @@ -79,15 +66,14 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = { .min = 177000000, .max = 896000000, .setbw = thomson_dtt759x_bw, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0x84, 0x03 }, - .count = 5, + .count = 6, .entries = { - { 264000000, 166667, 0xb4, 0x02 }, - { 470000000, 166667, 0xbc, 0x02 }, - { 735000000, 166667, 0xbc, 0x08 }, - { 835000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x08 }, + { 0, 36166667, 166666, 0x84, 0x03 }, + { 264000000, 36166667, 166666, 0xb4, 0x02 }, + { 470000000, 36166667, 166666, 0xbc, 0x02 }, + { 735000000, 36166667, 166666, 0xbc, 0x08 }, + { 835000000, 36166667, 166666, 0xf4, 0x08 }, + { 999999999, 36166667, 166666, 0xfc, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); @@ -96,15 +82,14 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { .name = "LG z201", .min = 174000000, .max = 862000000, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0xbc, 0x03 }, - .count = 5, + .count = 6, .entries = { - { 157500000, 166667, 0xbc, 0x01 }, - { 443250000, 166667, 0xbc, 0x02 }, - { 542000000, 166667, 0xbc, 0x04 }, - { 830000000, 166667, 0xf4, 0x04 }, - { 999999999, 166667, 0xfc, 0x04 }, + { 0, 36166667, 166666, 0xbc, 0x03 }, + { 157500000, 36166667, 166666, 0xbc, 0x01 }, + { 443250000, 36166667, 166666, 0xbc, 0x02 }, + { 542000000, 36166667, 166666, 0xbc, 0x04 }, + { 830000000, 36166667, 166666, 0xf4, 0x04 }, + { 999999999, 36166667, 166666, 0xfc, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_lg_z201); @@ -113,12 +98,11 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { .name = "Microtune 4042 FI5", .min = 57000000, .max = 858000000, - .iffreq= 44000000, .count = 3, .entries = { - { 162000000, 62500, 0x8e, 0xa1 }, - { 457000000, 62500, 0x8e, 0x91 }, - { 999999999, 62500, 0x8e, 0x31 }, + { 162000000, 44000000, 62500, 0x8e, 0xa1 }, + { 457000000, 44000000, 62500, 0x8e, 0x91 }, + { 999999999, 44000000, 62500, 0x8e, 0x31 }, }, }; EXPORT_SYMBOL(dvb_pll_microtune_4042); @@ -128,13 +112,11 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = { .name = "Thomson dtt761x", .min = 57000000, .max = 863000000, - .iffreq= 44000000, .count = 3, - .initdata = tua603x_agc103, .entries = { - { 147000000, 62500, 0x8e, 0x39 }, - { 417000000, 62500, 0x8e, 0x3a }, - { 999999999, 62500, 0x8e, 0x3c }, + { 147000000, 44000000, 62500, 0x8e, 0x39 }, + { 417000000, 44000000, 62500, 0x8e, 0x3a }, + { 999999999, 44000000, 62500, 0x8e, 0x3c }, }, }; EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); @@ -143,18 +125,17 @@ struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, .max = 862000000, - .iffreq= 36166667, .count = 9, .entries = { - { 150000000, 166667, 0xb4, 0x01 }, - { 173000000, 166667, 0xbc, 0x01 }, - { 250000000, 166667, 0xb4, 0x02 }, - { 400000000, 166667, 0xbc, 0x02 }, - { 420000000, 166667, 0xf4, 0x02 }, - { 470000000, 166667, 0xfc, 0x02 }, - { 600000000, 166667, 0xbc, 0x08 }, - { 730000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x08 }, + { 150000000, 36166667, 166666, 0xb4, 0x01 }, + { 173000000, 36166667, 166666, 0xbc, 0x01 }, + { 250000000, 36166667, 166666, 0xb4, 0x02 }, + { 400000000, 36166667, 166666, 0xbc, 0x02 }, + { 420000000, 36166667, 166666, 0xf4, 0x02 }, + { 470000000, 36166667, 166666, 0xfc, 0x02 }, + { 600000000, 36166667, 166666, 0xbc, 0x08 }, + { 730000000, 36166667, 166666, 0xf4, 0x08 }, + { 999999999, 36166667, 166666, 0xfc, 0x08 }, }, }; EXPORT_SYMBOL(dvb_pll_unknown_1); @@ -166,12 +147,11 @@ struct dvb_pll_desc dvb_pll_tua6010xs = { .name = "Infineon TUA6010XS", .min = 44250000, .max = 858000000, - .iffreq= 36125000, .count = 3, .entries = { - { 115750000, 62500, 0x8e, 0x03 }, - { 403250000, 62500, 0x8e, 0x06 }, - { 999999999, 62500, 0x8e, 0x85 }, + { 115750000, 36125000, 62500, 0x8e, 0x03 }, + { 403250000, 36125000, 62500, 0x8e, 0x06 }, + { 999999999, 36125000, 62500, 0x8e, 0x85 }, }, }; EXPORT_SYMBOL(dvb_pll_tua6010xs); @@ -181,13 +161,12 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = { .name = "Panasonic ENV57H1XD5", .min = 44250000, .max = 858000000, - .iffreq= 36125000, .count = 4, .entries = { - { 153000000, 166667, 0xc2, 0x41 }, - { 470000000, 166667, 0xc2, 0x42 }, - { 526000000, 166667, 0xc2, 0x84 }, - { 999999999, 166667, 0xc2, 0xa4 }, + { 153000000, 36291666, 166666, 0xc2, 0x41 }, + { 470000000, 36291666, 166666, 0xc2, 0x42 }, + { 526000000, 36291666, 166666, 0xc2, 0x84 }, + { 999999999, 36291666, 166666, 0xc2, 0xa4 }, }, }; EXPORT_SYMBOL(dvb_pll_env57h1xd5); @@ -206,21 +185,20 @@ struct dvb_pll_desc dvb_pll_tda665x = { .min = 44250000, .max = 858000000, .setbw = tda665x_bw, - .iffreq= 36166667, .count = 12, .entries = { - { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, - { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, - { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, - { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, - { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, - { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, + { 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, + { 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, + { 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, + { 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, + { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, + { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, } }; EXPORT_SYMBOL(dvb_pll_tda665x); @@ -238,13 +216,12 @@ struct dvb_pll_desc dvb_pll_tua6034 = { .name = "Infineon TUA6034", .min = 44250000, .max = 858000000, - .iffreq= 36166667, .count = 3, .setbw = tua6034_bw, .entries = { - { 174500000, 62500, 0xce, 0x01 }, - { 230000000, 62500, 0xce, 0x02 }, - { 999999999, 62500, 0xce, 0x04 }, + { 174500000, 36166667, 62500, 0xce, 0x01 }, + { 230000000, 36166667, 62500, 0xce, 0x02 }, + { 999999999, 36166667, 62500, 0xce, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_tua6034); @@ -256,13 +233,11 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { .name = "LG TDVS-H06xF", .min = 54000000, .max = 863000000, - .iffreq= 44000000, - .initdata = tua603x_agc103, .count = 3, .entries = { - { 165000000, 62500, 0xce, 0x01 }, - { 450000000, 62500, 0xce, 0x02 }, - { 999999999, 62500, 0xce, 0x04 }, + { 165000000, 44000000, 62500, 0xce, 0x01 }, + { 450000000, 44000000, 62500, 0xce, 0x02 }, + { 999999999, 44000000, 62500, 0xce, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); @@ -280,17 +255,16 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { .name = "Philips FMD1216ME", .min = 50870000, .max = 858000000, - .iffreq= 36125000, .setbw = fmd1216me_bw, .count = 7, .entries = { - { 143870000, 166667, 0xbc, 0x41 }, - { 158870000, 166667, 0xf4, 0x41 }, - { 329870000, 166667, 0xbc, 0x42 }, - { 441870000, 166667, 0xf4, 0x42 }, - { 625870000, 166667, 0xbc, 0x44 }, - { 803870000, 166667, 0xf4, 0x44 }, - { 999999999, 166667, 0xfc, 0x44 }, + { 143870000, 36213333, 166667, 0xbc, 0x41 }, + { 158870000, 36213333, 166667, 0xf4, 0x41 }, + { 329870000, 36213333, 166667, 0xbc, 0x42 }, + { 441870000, 36213333, 166667, 0xf4, 0x42 }, + { 625870000, 36213333, 166667, 0xbc, 0x44 }, + { 803870000, 36213333, 166667, 0xf4, 0x44 }, + { 999999999, 36213333, 166667, 0xfc, 0x44 }, } }; EXPORT_SYMBOL(dvb_pll_fmd1216me); @@ -308,14 +282,13 @@ struct dvb_pll_desc dvb_pll_tded4 = { .name = "ALPS TDED4", .min = 47000000, .max = 863000000, - .iffreq= 36166667, .setbw = tded4_bw, .count = 4, .entries = { - { 153000000, 166667, 0x85, 0x01 }, - { 470000000, 166667, 0x85, 0x02 }, - { 823000000, 166667, 0x85, 0x08 }, - { 999999999, 166667, 0x85, 0x88 }, + { 153000000, 36166667, 166667, 0x85, 0x01 }, + { 470000000, 36166667, 166667, 0x85, 0x02 }, + { 823000000, 36166667, 166667, 0x85, 0x08 }, + { 999999999, 36166667, 166667, 0x85, 0x88 }, } }; EXPORT_SYMBOL(dvb_pll_tded4); @@ -327,13 +300,12 @@ struct dvb_pll_desc dvb_pll_tdhu2 = { .name = "ALPS TDHU2", .min = 54000000, .max = 864000000, - .iffreq= 44000000, .count = 4, .entries = { - { 162000000, 62500, 0x85, 0x01 }, - { 426000000, 62500, 0x85, 0x02 }, - { 782000000, 62500, 0x85, 0x08 }, - { 999999999, 62500, 0x85, 0x88 }, + { 162000000, 44000000, 62500, 0x85, 0x01 }, + { 426000000, 44000000, 62500, 0x85, 0x02 }, + { 782000000, 44000000, 62500, 0x85, 0x08 }, + { 999999999, 44000000, 62500, 0x85, 0x88 }, } }; EXPORT_SYMBOL(dvb_pll_tdhu2); @@ -345,12 +317,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = { .name = "Philips TUV1236D", .min = 54000000, .max = 864000000, - .iffreq= 44000000, .count = 3, .entries = { - { 157250000, 62500, 0xc6, 0x41 }, - { 454000000, 62500, 0xc6, 0x42 }, - { 999999999, 62500, 0xc6, 0x44 }, + { 157250000, 44000000, 62500, 0xc6, 0x41 }, + { 454000000, 44000000, 62500, 0xc6, 0x42 }, + { 999999999, 44000000, 62500, 0xc6, 0x44 }, }, }; EXPORT_SYMBOL(dvb_pll_tuv1236d); @@ -362,15 +333,14 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = { .name = "Samsung TBMV30111IN / TBMV30712IN1", .min = 54000000, .max = 860000000, - .iffreq= 44000000, .count = 6, .entries = { - { 172000000, 166667, 0xb4, 0x01 }, - { 214000000, 166667, 0xb4, 0x02 }, - { 467000000, 166667, 0xbc, 0x02 }, - { 721000000, 166667, 0xbc, 0x08 }, - { 841000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x02 }, + { 172000000, 44000000, 166666, 0xb4, 0x01 }, + { 214000000, 44000000, 166666, 0xb4, 0x02 }, + { 467000000, 44000000, 166666, 0xbc, 0x02 }, + { 721000000, 44000000, 166666, 0xbc, 0x08 }, + { 841000000, 44000000, 166666, 0xf4, 0x08 }, + { 999999999, 44000000, 166666, 0xfc, 0x02 }, } }; EXPORT_SYMBOL(dvb_pll_samsung_tbmv); @@ -382,13 +352,12 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { .name = "Philips SD1878", .min = 950000, .max = 2150000, - .iffreq= 249, /* zero-IF, offset 249 is to round up */ .count = 4, .entries = { - { 1250000, 500, 0xc4, 0x00}, - { 1550000, 500, 0xc4, 0x40}, - { 2050000, 500, 0xc4, 0x80}, - { 2150000, 500, 0xc4, 0xc0}, + { 1250000, 499, 500, 0xc4, 0x00}, + { 1550000, 499, 500, 0xc4, 0x40}, + { 2050000, 499, 500, 0xc4, 0x80}, + { 2150000, 499, 500, 0xc4, 0xc0}, }, }; EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); @@ -419,19 +388,18 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = { .name = "Philips TD1316", .min = 87000000, .max = 895000000, - .iffreq= 36166667, .setbw = td1316_bw, .count = 9, .entries = { - { 93834000, 166667, 0xca, 0x60}, - { 123834000, 166667, 0xca, 0xa0}, - { 163834000, 166667, 0xca, 0xc0}, - { 253834000, 166667, 0xca, 0x60}, - { 383834000, 166667, 0xca, 0xa0}, - { 443834000, 166667, 0xca, 0xc0}, - { 583834000, 166667, 0xca, 0x60}, - { 793834000, 166667, 0xca, 0xa0}, - { 858834000, 166667, 0xca, 0xe0}, + { 93834000, 36166000, 166666, 0xca, 0x60}, + { 123834000, 36166000, 166666, 0xca, 0xa0}, + { 163834000, 36166000, 166666, 0xca, 0xc0}, + { 253834000, 36166000, 166666, 0xca, 0x60}, + { 383834000, 36166000, 166666, 0xca, 0xa0}, + { 443834000, 36166000, 166666, 0xca, 0xc0}, + { 583834000, 36166000, 166666, 0xca, 0x60}, + { 793834000, 36166000, 166666, 0xca, 0xa0}, + { 858834000, 36166000, 166666, 0xca, 0xe0}, }, }; EXPORT_SYMBOL(dvb_pll_philips_td1316); @@ -441,41 +409,15 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = { .name = "Thomson FE6600", .min = 44250000, .max = 858000000, - .iffreq= 36125000, .count = 4, .entries = { - { 250000000, 166667, 0xb4, 0x12 }, - { 455000000, 166667, 0xfe, 0x11 }, - { 775500000, 166667, 0xbc, 0x18 }, - { 999999999, 166667, 0xf4, 0x18 }, + { 250000000, 36213333, 166667, 0xb4, 0x12 }, + { 455000000, 36213333, 166667, 0xfe, 0x11 }, + { 775500000, 36213333, 166667, 0xbc, 0x18 }, + { 999999999, 36213333, 166667, 0xf4, 0x18 }, } }; EXPORT_SYMBOL(dvb_pll_thomson_fe6600); -static void opera1_bw(u8 *buf, u32 freq, int bandwidth) -{ - if (bandwidth == BANDWIDTH_8_MHZ) - buf[2] |= 0x08; -} - -struct dvb_pll_desc dvb_pll_opera1 = { - .name = "Opera Tuner", - .min = 900000, - .max = 2250000, - .iffreq= 0, - .setbw = opera1_bw, - .count = 8, - .entries = { - { 1064000, 500, 0xe5, 0xc6 }, - { 1169000, 500, 0xe5, 0xe6 }, - { 1299000, 500, 0xe5, 0x24 }, - { 1444000, 500, 0xe5, 0x44 }, - { 1606000, 500, 0xe5, 0x64 }, - { 1777000, 500, 0xe5, 0x84 }, - { 1941000, 500, 0xe5, 0xa4 }, - { 2250000, 500, 0xe5, 0xc4 }, - } -}; -EXPORT_SYMBOL(dvb_pll_opera1); struct dvb_pll_priv { /* i2c details */ @@ -517,8 +459,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, if (i == desc->count) return -EINVAL; - div = (freq + desc->iffreq + desc->entries[i].stepsize/2) / - desc->entries[i].stepsize; + div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; buf[0] = div >> 8; buf[1] = div & 0xff; buf[2] = desc->entries[i].config; @@ -532,7 +473,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, desc->name, div, buf[0], buf[1], buf[2], buf[3]); // calculate the frequency we set it to - return (div * desc->entries[i].stepsize) - desc->iffreq; + return (div * desc->entries[i].stepsize) - desc->entries[i].offset; } EXPORT_SYMBOL(dvb_pll_configure); @@ -546,27 +487,35 @@ static int dvb_pll_release(struct dvb_frontend *fe) static int dvb_pll_sleep(struct dvb_frontend *fe) { struct dvb_pll_priv *priv = fe->tuner_priv; + u8 buf[4]; + struct i2c_msg msg = + { .addr = priv->pll_i2c_address, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int i; + int result; if (priv->i2c == NULL) return -EINVAL; - if (priv->pll_desc->sleepdata) { - struct i2c_msg msg = { .flags = 0, - .addr = priv->pll_i2c_address, - .buf = priv->pll_desc->sleepdata + 1, - .len = priv->pll_desc->sleepdata[0] }; + for (i = 0; i < priv->pll_desc->count; i++) { + if (priv->pll_desc->entries[i].limit == 0) + break; + } + if (i == priv->pll_desc->count) + return 0; - int result; + buf[0] = 0; + buf[1] = 0; + buf[2] = priv->pll_desc->entries[i].config; + buf[3] = priv->pll_desc->entries[i].cb; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - return result; - } - return 0; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; } - /* Shouldn't be called when initdata is NULL, maybe BUG()? */ - return -EINVAL; + + return 0; } static int dvb_pll_set_params(struct dvb_frontend *fe, @@ -650,35 +599,9 @@ static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } -static int dvb_pll_init(struct dvb_frontend *fe) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - - if (priv->i2c == NULL) - return -EINVAL; - - if (priv->pll_desc->initdata) { - struct i2c_msg msg = { .flags = 0, - .addr = priv->pll_i2c_address, - .buf = priv->pll_desc->initdata + 1, - .len = priv->pll_desc->initdata[0] }; - - int result; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - return result; - } - return 0; - } - /* Shouldn't be called when initdata is NULL, maybe BUG()? */ - return -EINVAL; -} - static struct dvb_tuner_ops dvb_pll_tuner_ops = { .release = dvb_pll_release, .sleep = dvb_pll_sleep, - .init = dvb_pll_init, .set_params = dvb_pll_set_params, .calc_regs = dvb_pll_calc_regs, .get_frequency = dvb_pll_get_frequency, @@ -717,14 +640,9 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); - strncpy(fe->ops.tuner_ops.info.name, desc->name, - sizeof(fe->ops.tuner_ops.info.name)); + strncpy(fe->ops.tuner_ops.info.name, desc->name, 128); fe->ops.tuner_ops.info.frequency_min = desc->min; fe->ops.tuner_ops.info.frequency_min = desc->max; - if (!desc->initdata) - fe->ops.tuner_ops.init = NULL; - if (!desc->sleepdata) - fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; return fe; diff --git a/trunk/drivers/media/dvb/frontends/dvb-pll.h b/trunk/drivers/media/dvb/frontends/dvb-pll.h index 5209f46f0893..681186a5e5eb 100644 --- a/trunk/drivers/media/dvb/frontends/dvb-pll.h +++ b/trunk/drivers/media/dvb/frontends/dvb-pll.h @@ -12,13 +12,11 @@ struct dvb_pll_desc { char *name; u32 min; u32 max; - u32 iffreq; void (*setbw)(u8 *buf, u32 freq, int bandwidth); - u8 *initdata; - u8 *sleepdata; int count; struct { u32 limit; + u32 offset; u32 stepsize; u8 config; u8 cb; @@ -48,7 +46,6 @@ extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261; extern struct dvb_pll_desc dvb_pll_philips_td1316; extern struct dvb_pll_desc dvb_pll_thomson_fe6600; -extern struct dvb_pll_desc dvb_pll_opera1; extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); @@ -62,20 +59,9 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, * @param desc dvb_pll_desc to use. * @return Frontend pointer on success, NULL on failure */ -#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc); -#else -static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, - int pll_addr, - struct i2c_adapter *i2c, - struct dvb_pll_desc *desc) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif #endif diff --git a/trunk/drivers/media/dvb/frontends/lgdt330x.c b/trunk/drivers/media/dvb/frontends/lgdt330x.c index e25286e2d431..68aad0f6519f 100644 --- a/trunk/drivers/media/dvb/frontends/lgdt330x.c +++ b/trunk/drivers/media/dvb/frontends/lgdt330x.c @@ -475,7 +475,7 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) *status |= FE_HAS_CARRIER; break; default: - printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); } return 0; @@ -534,7 +534,7 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) } break; default: - printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); } return 0; } diff --git a/trunk/drivers/media/dvb/frontends/lgh06xf.c b/trunk/drivers/media/dvb/frontends/lgh06xf.c new file mode 100644 index 000000000000..2202d0cc878b --- /dev/null +++ b/trunk/drivers/media/dvb/frontends/lgh06xf.c @@ -0,0 +1,134 @@ +/* + * lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF + * + * 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. + */ + +#include "dvb-pll.h" +#include "lgh06xf.h" + +#define LG_H06XF_PLL_I2C_ADDR 0x61 + +struct lgh06xf_priv { + struct i2c_adapter *i2c; + u32 frequency; +}; + +static int lgh06xf_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int lgh06xf_set_params(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params) +{ + struct lgh06xf_priv *priv = fe->tuner_priv; + u8 buf[4]; + struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + u32 frequency; + int result; + + if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, + params->frequency, 0)) < 0) + return result; + else + frequency = result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgh06xf: %s error " + "(addr %02x <- %02x, result = %i)\n", + __FUNCTION__, buf[0], buf[1], result); + if (result < 0) + return result; + else + return -EREMOTEIO; + } + + /* Set the Auxiliary Byte. */ + buf[0] = buf[2]; + buf[0] &= ~0x20; + buf[0] |= 0x18; + buf[1] = 0x50; + msg.len = 2; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgh06xf: %s error " + "(addr %02x <- %02x, result = %i)\n", + __FUNCTION__, buf[0], buf[1], result); + if (result < 0) + return result; + else + return -EREMOTEIO; + } + + priv->frequency = frequency; + + return 0; +} + +static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct lgh06xf_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops lgh06xf_tuner_ops = { + .release = lgh06xf_release, + .set_params = lgh06xf_set_params, + .get_frequency = lgh06xf_get_frequency, +}; + +struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c) +{ + struct lgh06xf_priv *priv = NULL; + + priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c = i2c; + + memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name, + sizeof(fe->ops.tuner_ops.info.name)); + + fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min; + fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max; + + fe->tuner_priv = priv; + return fe; +} + +EXPORT_SYMBOL(lgh06xf_attach); + +MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support"); +MODULE_AUTHOR("Michael Krufky"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/trunk/drivers/media/dvb/frontends/lgh06xf.h b/trunk/drivers/media/dvb/frontends/lgh06xf.h new file mode 100644 index 000000000000..510b4bedfb24 --- /dev/null +++ b/trunk/drivers/media/dvb/frontends/lgh06xf.h @@ -0,0 +1,35 @@ +/* + * lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LGH06XF_H_ +#define _LGH06XF_H_ +#include "dvb_frontend.h" + +#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE)) +extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif /* CONFIG_DVB_TUNER_LGH06XF */ + +#endif /* _LGH06XF_H_ */ diff --git a/trunk/drivers/media/dvb/frontends/or51132.c b/trunk/drivers/media/dvb/frontends/or51132.c index 4e0aca7c67aa..5a3a6e53cda2 100644 --- a/trunk/drivers/media/dvb/frontends/or51132.c +++ b/trunk/drivers/media/dvb/frontends/or51132.c @@ -1,9 +1,6 @@ /* * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM * - * - * Copyright (C) 2007 Trent Piepho - * * Copyright (C) 2005 Kirk Lapray * * Based on code from Jack Kelliher (kelliher@xmission.com) @@ -72,70 +69,46 @@ struct or51132_state u32 current_frequency; }; - -/* Write buffer to demod */ -static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) +static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len) { int err; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = (u8*)buf, .len = len }; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = 0; + msg.len = len; + msg.buf = buf; - /* msleep(20); */ /* doesn't appear to be necessary */ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", - msg.addr, msg.len, err); + printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err); return -EREMOTEIO; } + return 0; } -/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); - Less code and more efficient that loading a buffer on the stack with - the bytes to send and then calling or51132_writebuf() on that. */ -#define or51132_writebytes(state, data...) \ - ({ const static u8 _data[] = {data}; \ - or51132_writebuf(state, _data, sizeof(_data)); }) - -/* Read data from demod into buffer. Returns 0 on success. */ -static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) +static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) { int err; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = I2C_M_RD, .buf = buf, .len = len }; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buf; - /* msleep(20); */ /* doesn't appear to be necessary */ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", - msg.addr, msg.len, err); + printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err); return -EREMOTEIO; } - return 0; -} -/* Reads a 16-bit demod register. Returns <0 on error. */ -static int or51132_readreg(struct or51132_state *state, u8 reg) -{ - u8 buf[2] = { 0x04, reg }; - struct i2c_msg msg[2] = { - {.addr = state->config->demod_address, .flags = 0, - .buf = buf, .len = 2 }, - {.addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = buf, .len = 2 }}; - int err; - - if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { - printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", - reg, err); - return -EREMOTEIO; - } - return le16_to_cpup((u16*)buf); + return 0; } static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) { struct or51132_state* state = fe->demodulator_priv; - const static u8 run_buf[] = {0x7F,0x01}; + static u8 run_buf[] = {0x7F,0x01}; u8 rec_buf[8]; + u8 cmd_buf[3]; u32 firmwareAsize, firmwareBsize; int i,ret; @@ -148,21 +121,30 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware dprintk("FirmwareB is %i bytes\n",firmwareBsize); /* Upload firmware */ - if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { + if ((ret = i2c_writebytes(state,state->config->demod_address, + &fw->data[8],firmwareAsize))) { printk(KERN_WARNING "or51132: load_firmware error 1\n"); return ret; } - if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], - firmwareBsize))) { + msleep(1); /* 1ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + &fw->data[8+firmwareAsize],firmwareBsize))) { printk(KERN_WARNING "or51132: load_firmware error 2\n"); return ret; } + msleep(1); /* 1ms */ - if ((ret = or51132_writebuf(state, run_buf, 2))) { + if ((ret = i2c_writebytes(state,state->config->demod_address, + run_buf,2))) { printk(KERN_WARNING "or51132: load_firmware error 3\n"); return ret; } - if ((ret = or51132_writebuf(state, run_buf, 2))) { + + /* Wait at least 5 msec */ + msleep(20); /* 10ms */ + + if ((ret = i2c_writebytes(state,state->config->demod_address, + run_buf,2))) { printk(KERN_WARNING "or51132: load_firmware error 4\n"); return ret; } @@ -172,25 +154,43 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware /* Read back ucode version to besure we loaded correctly and are really up and running */ /* Get uCode version */ - if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { + cmd_buf[0] = 0x10; + cmd_buf[1] = 0x10; + cmd_buf[2] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,3))) { printk(KERN_WARNING "or51132: load_firmware error a\n"); return ret; } - if ((ret = or51132_writebytes(state, 0x04, 0x17))) { + + cmd_buf[0] = 0x04; + cmd_buf[1] = 0x17; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,2))) { printk(KERN_WARNING "or51132: load_firmware error b\n"); return ret; } - if ((ret = or51132_writebytes(state, 0x00, 0x00))) { + + cmd_buf[0] = 0x00; + cmd_buf[1] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,2))) { printk(KERN_WARNING "or51132: load_firmware error c\n"); return ret; } - for (i=0;i<4;i++) { + + for(i=0;i<4;i++) { + msleep(20); /* 20ms */ /* Once upon a time, this command might have had something to do with getting the firmware version, but it's not used anymore: {0x04,0x00,0x30,0x00,i+1} */ /* Read 8 bytes, two bytes at a time */ - if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { + if ((ret = i2c_readbytes(state,state->config->demod_address, + &rec_buf[i*2],2))) { printk(KERN_WARNING "or51132: load_firmware error d - %d\n",i); return ret; @@ -204,7 +204,12 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); - if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { + cmd_buf[0] = 0x10; + cmd_buf[1] = 0x00; + cmd_buf[2] = 0x00; + msleep(20); /* 20ms */ + if ((ret = i2c_writebytes(state,state->config->demod_address, + cmd_buf,3))) { printk(KERN_WARNING "or51132: load_firmware error e\n"); return ret; } @@ -236,55 +241,70 @@ static int or51132_sleep(struct dvb_frontend* fe) static int or51132_setmode(struct dvb_frontend* fe) { struct or51132_state* state = fe->demodulator_priv; - u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; - u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; + unsigned char cmd_buf[3]; dprintk("setmode %d\n",(int)state->current_modulation); - + /* set operation mode in Receiver 1 register; */ + cmd_buf[0] = 0x04; + cmd_buf[1] = 0x01; switch (state->current_modulation) { + case QAM_256: + case QAM_64: + case QAM_AUTO: + /* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/ + cmd_buf[2] = 0x5F; + break; case VSB_8: - /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ - cmd_buf1[2] = 0x50; - /* REC MODE inv IF spectrum, Normal */ - cmd_buf2[1] = 0x03; - /* Channel MODE ATSC/VSB8 */ - cmd_buf2[2] = 0x06; + /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/ + cmd_buf[2] = 0x50; break; - /* All QAM modes are: - Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high - REC MODE Normal Carrier Lock */ + default: + printk("setmode:Modulation set to unsupported value\n"); + }; + if (i2c_writebytes(state,state->config->demod_address, + cmd_buf,3)) { + printk(KERN_WARNING "or51132: set_mode error 1\n"); + return -1; + } + dprintk("or51132: set #1 to %02x\n", cmd_buf[2]); + + /* Set operation mode in Receiver 6 register */ + cmd_buf[0] = 0x1C; + switch (state->current_modulation) { case QAM_AUTO: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; /* Channel MODE Auto QAM64/256 */ - cmd_buf2[2] = 0x4f; + cmd_buf[2] = 0x4f; break; case QAM_256: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; /* Channel MODE QAM256 */ - cmd_buf2[2] = 0x45; + cmd_buf[2] = 0x45; break; case QAM_64: + /* REC MODE Normal Carrier Lock */ + cmd_buf[1] = 0x00; /* Channel MODE QAM64 */ - cmd_buf2[2] = 0x43; + cmd_buf[2] = 0x43; + break; + case VSB_8: + /* REC MODE inv IF spectrum, Normal */ + cmd_buf[1] = 0x03; + /* Channel MODE ATSC/VSB8 */ + cmd_buf[2] = 0x06; break; default: - printk(KERN_WARNING - "or51132: setmode: Modulation set to unsupported value (%d)\n", - state->current_modulation); - return -EINVAL; - } - - /* Set Receiver 1 register */ - if (or51132_writebuf(state, cmd_buf1, 3)) { - printk(KERN_WARNING "or51132: set_mode error 1\n"); - return -EREMOTEIO; - } - dprintk("set #1 to %02x\n", cmd_buf1[2]); - - /* Set operation mode in Receiver 6 register */ - if (or51132_writebuf(state, cmd_buf2, 3)) { + printk("setmode: Modulation set to unsupported value\n"); + }; + msleep(20); /* 20ms */ + if (i2c_writebytes(state,state->config->demod_address, + cmd_buf,3)) { printk(KERN_WARNING "or51132: set_mode error 2\n"); - return -EREMOTEIO; + return -1; } - dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); + dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]); return 0; } @@ -381,23 +401,28 @@ static int or51132_get_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { struct or51132_state* state = fe->demodulator_priv; - int status; - int retry = 1; + u8 buf[2]; -start: /* Receiver Status */ - if ((status = or51132_readreg(state, 0x00)) < 0) { - printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); + buf[0]=0x04; + buf[1]=0x00; + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,buf,2)) { + printk(KERN_WARNING "or51132: get_parameters write error\n"); + return -EREMOTEIO; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,buf,2)) { + printk(KERN_WARNING "or51132: get_parameters read error\n"); return -EREMOTEIO; } - switch(status&0xff) { + switch(buf[0]) { case 0x06: param->u.vsb.modulation = VSB_8; break; case 0x43: param->u.vsb.modulation = QAM_64; break; case 0x45: param->u.vsb.modulation = QAM_256; break; default: - if (retry--) goto start; printk(KERN_WARNING "or51132: unknown status 0x%02x\n", - status&0xff); + buf[0]); return -EREMOTEIO; } @@ -413,21 +438,32 @@ static int or51132_get_parameters(struct dvb_frontend* fe, static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct or51132_state* state = fe->demodulator_priv; - int reg; + unsigned char rec_buf[2]; + unsigned char snd_buf[2]; + *status = 0; /* Receiver Status */ - if ((reg = or51132_readreg(state, 0x00)) < 0) { - printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); - *status = 0; - return -EREMOTEIO; + snd_buf[0]=0x04; + snd_buf[1]=0x00; + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: read_status write error\n"); + return -1; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_status read error\n"); + return -1; + } + dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); + + if (rec_buf[1] & 0x01) { /* Receiver Lock */ + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; } - dprintk("%s: read_status %04x\n", __FUNCTION__, reg); - - if (reg & 0x0100) /* Receiver Lock */ - *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| - FE_HAS_SYNC|FE_HAS_LOCK; - else - *status = 0; return 0; } @@ -470,30 +506,47 @@ static u32 calculate_snr(u32 mse, u32 c) static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) { struct or51132_state* state = fe->demodulator_priv; - int noise, reg; - u32 c, usK = 0; - int retry = 1; - -start: - /* SNR after Equalizer */ - noise = or51132_readreg(state, 0x02); - if (noise < 0) { - printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); + u8 rec_buf[2]; + u8 snd_buf[2]; + u32 noise; + u32 c; + u32 usK; + + /* Register is same for VSB or QAM firmware */ + snd_buf[0]=0x04; + snd_buf[1]=0x02; /* SNR after Equalizer */ + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: snr write error\n"); + return -EREMOTEIO; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: snr read error\n"); return -EREMOTEIO; } - dprintk("read_snr noise (%d)\n", noise); + noise = rec_buf[0] | (rec_buf[1] << 8); + dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise); /* Read status, contains modulation type for QAM_AUTO and NTSC filter for VSB */ - reg = or51132_readreg(state, 0x00); - if (reg < 0) { - printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); + snd_buf[0]=0x04; + snd_buf[1]=0x00; /* Status register */ + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { + printk(KERN_WARNING "or51132: status write error\n"); + return -EREMOTEIO; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: status read error\n"); return -EREMOTEIO; } - switch (reg&0xff) { + usK = 0; + switch (rec_buf[0]) { case 0x06: - if (reg & 0x1000) usK = 3 << 24; + usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0; /* Fall through to QAM64 case */ case 0x43: c = 150204167; @@ -502,12 +555,11 @@ static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) c = 150290396; break; default: - printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); - if (retry--) goto start; + printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]); return -EREMOTEIO; } dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__, - reg&0xff, reg&0x1000?"n":"ff"); + rec_buf[0], rec_buf[1]&0x10?"n":"ff"); /* Calculate SNR using noise, c, and NTSC rejection correction */ state->snr = calculate_snr(noise, c) - usK; @@ -619,7 +671,6 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); MODULE_AUTHOR("Kirk Lapray"); -MODULE_AUTHOR("Trent Piepho"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(or51132_attach); diff --git a/trunk/drivers/media/dvb/frontends/tda10021.c b/trunk/drivers/media/dvb/frontends/tda10021.c index 110536843e8e..5b9c5bb29b23 100644 --- a/trunk/drivers/media/dvb/frontends/tda10021.c +++ b/trunk/drivers/media/dvb/frontends/tda10021.c @@ -30,13 +30,13 @@ #include #include "dvb_frontend.h" -#include "tda1002x.h" +#include "tda10021.h" struct tda10021_state { struct i2c_adapter* i2c; /* configuration settings */ - const struct tda1002x_config* config; + const struct tda10021_config* config; struct dvb_frontend frontend; u8 pwm; @@ -53,6 +53,9 @@ struct tda10021_state { static int verbose; #define XIN 57840000UL +#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) +#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) +#define HAS_INVERSION(reg0) (!(reg0 & 0x20)) #define FIN (XIN >> 4) @@ -61,7 +64,7 @@ static u8 tda10021_inittab[0x40]= { 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, - 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, + 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff, 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, @@ -94,8 +97,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) int ret; ret = i2c_transfer (state->i2c, msg, 2); - // Don't print an error message if the id is read. - if (ret != 2 && reg != 0x1a) + if (ret != 2) printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", __FUNCTION__, ret); return b1[0]; @@ -134,10 +136,10 @@ static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, { reg0 |= state->reg0 & 0x63; - if ((INVERSION_ON == inversion) ^ (state->config->invert == 0)) - reg0 &= ~0x20; - else - reg0 |= 0x20; + if (INVERSION_ON == inversion) + ENABLE_INVERSION(reg0); + else if (INVERSION_OFF == inversion) + DISABLE_INVERSION(reg0); _tda10021_writereg (state, 0x00, reg0 & 0xfe); _tda10021_writereg (state, 0x00, reg0 | 0x01); @@ -199,6 +201,16 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate return 0; } +static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len) +{ + struct tda10021_state* state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return _tda10021_writereg(state, buf[0], buf[1]); +} + static int tda10021_init (struct dvb_frontend *fe) { struct tda10021_state* state = fe->demodulator_priv; @@ -246,9 +258,6 @@ static int tda10021_set_parameters (struct dvb_frontend *fe, if (qam < 0 || qam > 5) return -EINVAL; - if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) - return -EINVAL; - //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); if (fe->ops.tuner_ops.set_params) { @@ -357,7 +366,7 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa -((s32)p->u.qam.symbol_rate * afc) >> 10); } - p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; + p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; p->u.qam.fec_inner = FEC_NONE; @@ -399,12 +408,11 @@ static void tda10021_release(struct dvb_frontend* fe) static struct dvb_frontend_ops tda10021_ops; -struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, +struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm) { struct tda10021_state* state = NULL; - u8 id; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); @@ -417,11 +425,7 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, state->reg0 = tda10021_inittab[0]; /* check if the demod is there */ - id = tda10021_readreg(state, 0x1a); - if ((id & 0xf0) != 0x70) goto error; - - printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", - state->config->demod_address, id); + if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); @@ -443,7 +447,7 @@ static struct dvb_frontend_ops tda10021_ops = { .frequency_max = 858000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ - #if 0 +#if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ #endif @@ -457,6 +461,7 @@ static struct dvb_frontend_ops tda10021_ops = { .init = tda10021_init, .sleep = tda10021_sleep, + .write = tda10021_write, .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, .set_frontend = tda10021_set_parameters, diff --git a/trunk/drivers/media/dvb/frontends/tda1002x.h b/trunk/drivers/media/dvb/frontends/tda10021.h similarity index 66% rename from trunk/drivers/media/dvb/frontends/tda1002x.h rename to trunk/drivers/media/dvb/frontends/tda10021.h index e9094d8123f6..e3da780108f6 100644 --- a/trunk/drivers/media/dvb/frontends/tda1002x.h +++ b/trunk/drivers/media/dvb/frontends/tda10021.h @@ -1,6 +1,6 @@ /* - TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module - used on the the Siemens DVB-C cards + TDA10021 - Single Chip Cable Channel Receiver driver module + used on the the Siemens DVB-C cards Copyright (C) 1999 Convergence Integrated Media GmbH Copyright (C) 2004 Markus Schulz @@ -21,23 +21,22 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef TDA1002x_H -#define TDA1002x_H +#ifndef TDA10021_H +#define TDA10021_H #include -struct tda1002x_config +struct tda10021_config { /* the demodulator's i2c address */ u8 demod_address; - u8 invert; }; #if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, +extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm); #else -static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, +static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); @@ -45,16 +44,12 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* } #endif // CONFIG_DVB_TDA10021 -#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm); -#else -static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; +static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { + int r = 0; + u8 buf[] = {reg, val}; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; } -#endif // CONFIG_DVB_TDA10023 -#endif // TDA1002x_H +#endif // TDA10021_H diff --git a/trunk/drivers/media/dvb/frontends/tda10023.c b/trunk/drivers/media/dvb/frontends/tda10023.c deleted file mode 100644 index da796e784be3..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda10023.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - TDA10023 - DVB-C decoder - (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) - - Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) - Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) - - Remotely based on tda10021.c - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2004 Markus Schulz - Support for TDA10021 - - 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dvb_frontend.h" -#include "tda1002x.h" - - -struct tda10023_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct tda1002x_config* config; - struct dvb_frontend frontend; - - u8 pwm; - u8 reg0; -}; - - -#define dprintk(x...) - -static int verbose; - -#define XTAL 28920000UL -#define PLL_M 8UL -#define PLL_P 4UL -#define PLL_N 1UL -#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000 - -static u8 tda10023_inittab[]={ - // reg mask val - 0x2a,0xff,0x02, // PLL3, Bypass, Power Down - 0xff,0x64,0x00, // Sleep 100ms - 0x2a,0xff,0x03, // PLL3, Bypass, Power Down - 0xff,0x64,0x00, // Sleep 100ms - 0x28,0xff,PLL_M-1, // PLL1 M=8 - 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2 - 0x00,0xff,0x23, // GPR FSAMPLING=1 - 0x2a,0xff,0x08, // PLL3 PSACLK=1 - 0xff,0x64,0x00, // Sleep 100ms - 0x1f,0xff,0x00, // RESET - 0xff,0x64,0x00, // Sleep 100ms - 0xe6,0x0c,0x04, // RSCFG_IND - 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1 - - 0x0e,0xff,0x82, // GAIN1 - 0x03,0x08,0x08, // CLKCONF DYN=1 - 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0 - 0x01,0xff,0x30, // AGCREF - 0x1e,0x84,0x84, // CONTROL SACLK_ON=1 - 0x1b,0xff,0xc8, // ADC TWOS=1 - 0x3b,0xff,0xff, // IFMAX - 0x3c,0xff,0x00, // IFMIN - 0x34,0xff,0x00, // PWMREF - 0x35,0xff,0xff, // TUNMAX - 0x36,0xff,0x00, // TUNMIN - 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77 - 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1 - 0x37,0xff,0xf6, // DELTAF_LSB - 0x38,0xff,0xff, // DELTAF_MSB - 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 - 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 - 0x04,0x10,0x00, // SWRAMP=1 - 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0 - 0x2b,0x01,0xa1, // INTS1 - 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? - 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0 - 0xc4,0xff,0x00, - 0xc3,0x30,0x00, - 0xb5,0xff,0x19, // ERAGC_THD - 0x00,0x03,0x01, // GPR, CLBS soft reset - 0x00,0x03,0x03, // GPR, CLBS soft reset - 0xff,0x64,0x00, // Sleep 100ms - 0xff,0xff,0xff -}; - -static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) -{ - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - int ret; - - ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) - printk("DVB: TDA10023: %s: readreg error (ret == %i)\n", - __FUNCTION__, ret); - return b1[0]; -} - -static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - int ret; - - ret = i2c_transfer (state->i2c, &msg, 1); - if (ret != 1) - printk("DVB: TDA10023(%d): %s, writereg error " - "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", - state->frontend.dvb->num, __FUNCTION__, reg, data, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - - -static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) -{ - if (mask==0xff) - return tda10023_writereg(state, reg, data); - else { - u8 val; - val=tda10023_readreg(state,reg); - val&=~mask; - val|=(data&mask); - return tda10023_writereg(state, reg, val); - } -} - -static void tda10023_writetab(struct tda10023_state* state, u8* tab) -{ - u8 r,m,v; - while (1) { - r=*tab++; - m=*tab++; - v=*tab++; - if (r==0xff) { - if (m==0xff) - break; - else - msleep(m); - } - else - tda10023_writebit(state,r,m,v); - } -} - -//get access to tuner -static int lock_tuner(struct tda10023_state* state) -{ - u8 buf[2] = { 0x0f, 0xc0 }; - struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg, 1) != 1) - { - printk("tda10023: lock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -//release access from tuner -static int unlock_tuner(struct tda10023_state* state) -{ - u8 buf[2] = { 0x0f, 0x40 }; - struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg_post, 1) != 1) - { - printk("tda10023: unlock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) -{ - reg0 |= state->reg0 & 0x63; - - tda10023_writereg (state, 0x00, reg0 & 0xfe); - tda10023_writereg (state, 0x00, reg0 | 0x01); - - state->reg0 = reg0; - return 0; -} - -static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) -{ - s32 BDR; - s32 BDRI; - s16 SFIL=0; - u16 NDEC = 0; - - if (sr > (SYSCLK/(2*4))) - sr=SYSCLK/(2*4); - - if (sr<870000) - sr=870000; - - if (sr < (u32)(SYSCLK/98.40)) { - NDEC=3; - SFIL=1; - } else if (sr<(u32)(SYSCLK/64.0)) { - NDEC=3; - SFIL=0; - } else if (sr<(u32)(SYSCLK/49.2)) { - NDEC=2; - SFIL=1; - } else if (sr<(u32)(SYSCLK/32.0)) { - NDEC=2; - SFIL=0; - } else if (sr<(u32)(SYSCLK/24.6)) { - NDEC=1; - SFIL=1; - } else if (sr<(u32)(SYSCLK/16.0)) { - NDEC=1; - SFIL=0; - } else if (sr<(u32)(SYSCLK/12.3)) { - NDEC=0; - SFIL=1; - } - - BDRI=SYSCLK*16; - BDRI>>=NDEC; - BDRI +=sr/2; - BDRI /=sr; - - if (BDRI>255) - BDRI=255; - - { - u64 BDRX; - - BDRX=1<<(24+NDEC); - BDRX*=sr; - do_div(BDRX,SYSCLK); // BDRX/=SYSCLK; - - BDR=(s32)BDRX; - } -// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC); - tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); - tda10023_writereg (state, 0x0a, BDR&255); - tda10023_writereg (state, 0x0b, (BDR>>8)&255); - tda10023_writereg (state, 0x0c, (BDR>>16)&31); - tda10023_writereg (state, 0x0d, BDRI); - tda10023_writereg (state, 0x3d, (SFIL<<7)); - return 0; -} - -static int tda10023_init (struct dvb_frontend *fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - - dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num); - - tda10023_writetab(state, tda10023_inittab); - - return 0; -} - -static int tda10023_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct tda10023_state* state = fe->demodulator_priv; - - static int qamvals[6][6] = { - // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD - { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM - { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM - { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM - { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM - { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM - { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM - }; - - int qam = p->u.qam.modulation; - - if (qam < 0 || qam > 5) - return -EINVAL; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - tda10023_set_symbolrate (state, p->u.qam.symbol_rate); - tda10023_writereg (state, 0x05, qamvals[qam][1]); - tda10023_writereg (state, 0x08, qamvals[qam][2]); - tda10023_writereg (state, 0x09, qamvals[qam][3]); - tda10023_writereg (state, 0xb4, qamvals[qam][4]); - tda10023_writereg (state, 0xb6, qamvals[qam][5]); - -// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); -// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); - tda10023_writebit (state, 0x04, 0x40, 0x40); - tda10023_setup_reg0 (state, qamvals[qam][0]); - - return 0; -} - -static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct tda10023_state* state = fe->demodulator_priv; - int sync; - - *status = 0; - - //0x11[1] == CARLOCK -> Carrier locked - //0x11[2] == FSYNC -> Frame synchronisation - //0x11[3] == FEL -> Front End locked - //0x11[6] == NODVB -> DVB Mode Information - sync = tda10023_readreg (state, 0x11); - - if (sync & 2) - *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; - - if (sync & 4) - *status |= FE_HAS_SYNC|FE_HAS_VITERBI; - - if (sync & 8) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 a,b,c; - a=tda10023_readreg(state, 0x14); - b=tda10023_readreg(state, 0x15); - c=tda10023_readreg(state, 0x16)&0xf; - tda10023_writebit (state, 0x10, 0xc0, 0x00); - - *ber = a | (b<<8)| (c<<16); - return 0; -} - -static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 ifgain=tda10023_readreg(state, 0x2f); - - u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; - // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 - if (gain>0x90) - gain=gain+2*(gain-0x90); - if (gain>255) - gain=255; - - *strength = (gain<<8)|gain; - return 0; -} - -static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct tda10023_state* state = fe->demodulator_priv; - - u8 quality = ~tda10023_readreg(state, 0x18); - *snr = (quality << 8) | quality; - return 0; -} - -static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 a,b,c,d; - a= tda10023_readreg (state, 0x74); - b= tda10023_readreg (state, 0x75); - c= tda10023_readreg (state, 0x76); - d= tda10023_readreg (state, 0x77); - *ucblocks = a | (b<<8)|(c<<16)|(d<<24); - - tda10023_writebit (state, 0x10, 0x20,0x00); - tda10023_writebit (state, 0x10, 0x20,0x20); - tda10023_writebit (state, 0x13, 0x01, 0x00); - - return 0; -} - -static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct tda10023_state* state = fe->demodulator_priv; - int sync,inv; - s8 afc = 0; - - sync = tda10023_readreg(state, 0x11); - afc = tda10023_readreg(state, 0x19); - inv = tda10023_readreg(state, 0x04); - - if (verbose) { - /* AFC only valid when carrier has been recovered */ - printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : - "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", - state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); - } - - p->inversion = (inv&0x20?0:1); - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; - - p->u.qam.fec_inner = FEC_NONE; - p->frequency = ((p->frequency + 31250) / 62500) * 62500; - - if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; - - return 0; -} - -static int tda10023_sleep(struct dvb_frontend* fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - - tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ - tda10023_writereg (state, 0x00, 0x80); /* standby */ - - return 0; -} - -static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct tda10023_state* state = fe->demodulator_priv; - - if (enable) { - lock_tuner(state); - } else { - unlock_tuner(state); - } - return 0; -} - -static void tda10023_release(struct dvb_frontend* fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops tda10023_ops; - -struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, - u8 pwm) -{ - struct tda10023_state* state = NULL; - int i; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); - state->pwm = pwm; - for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) { - if (tda10023_inittab[i] == 0x00) { - state->reg0 = tda10023_inittab[i+2]; - break; - } - } - - // Wakeup if in standby - tda10023_writereg (state, 0x00, 0x33); - /* check if the demod is there */ - if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops tda10023_ops = { - - .info = { - .name = "Philips TDA10023 DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ - .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ - .caps = 0x400 | //FE_CAN_QAM_4 - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = tda10023_release, - - .init = tda10023_init, - .sleep = tda10023_sleep, - .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, - - .set_frontend = tda10023_set_parameters, - .get_frontend = tda10023_get_frontend, - - .read_status = tda10023_read_status, - .read_ber = tda10023_read_ber, - .read_signal_strength = tda10023_read_signal_strength, - .read_snr = tda10023_read_snr, - .read_ucblocks = tda10023_read_ucblocks, -}; - - -MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); -MODULE_AUTHOR("Georg Acher, Hartmut Birr"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda10023_attach); diff --git a/trunk/drivers/media/dvb/frontends/tda1004x.c b/trunk/drivers/media/dvb/frontends/tda1004x.c index 33a84372c9e6..f4a9cf9d26d0 100644 --- a/trunk/drivers/media/dvb/frontends/tda1004x.c +++ b/trunk/drivers/media/dvb/frontends/tda1004x.c @@ -40,6 +40,20 @@ #include "dvb_frontend.h" #include "tda1004x.h" +enum tda1004x_demod { + TDA1004X_DEMOD_TDA10045, + TDA1004X_DEMOD_TDA10046, +}; + +struct tda1004x_state { + struct i2c_adapter* i2c; + const struct tda1004x_config* config; + struct dvb_frontend frontend; + + /* private demod data */ + enum tda1004x_demod demod_type; +}; + static int debug; #define dprintk(args...) \ do { \ @@ -493,25 +507,12 @@ static int tda10046_fwupload(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80); } tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); - /* set GPIO 1 and 3 */ - if (state->config->gpio_config != TDA10046_GPTRI) { - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); - } /* let the clocks recover from sleep */ - msleep(10); + msleep(5); /* The PLLs need to be reprogrammed after sleep */ tda10046_init_plls(fe); - tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); - /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state) == 0) - return 0; - - printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); - tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); - msleep(300); /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; @@ -521,23 +522,20 @@ static int tda10046_fwupload(struct dvb_frontend* fe) printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); if (ret) { - /* remain compatible to old bug: try to load with tda10045 image name */ - ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); - if (ret) { - printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; - } else { - printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", - TDA10046_DEFAULT_FIRMWARE); - } + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; } + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + release_firmware(fw); + if (ret) + return ret; } else { - printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); - return -EIO; + /* boot from firmware eeprom */ + printk(KERN_INFO "tda1004x: booting from eeprom\n"); + tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); + msleep(300); } - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); - release_firmware(fw); return tda1004x_check_upload_ok(state); } @@ -640,33 +638,37 @@ static int tda10046_init(struct dvb_frontend* fe) switch (state->config->agc_config) { case TDA10046_AGC_DEFAULT: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_NEG: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities break; case TDA10046_AGC_IFO_AUTO_POS: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities break; - case TDA10046_AGC_TDA827X: + case TDA10046_AGC_TDA827X_GP11: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities + break; + case TDA10046_AGC_TDA827X_GP00: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; + case TDA10046_AGC_TDA827X_GP01: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities break; - } - if (state->config->ts_mode == 0) { - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); - tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - } else { - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, - state->config->invert_oclk << 4); } tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); - tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } @@ -676,6 +678,7 @@ static int tda10046_init(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes + tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); return 0; } @@ -702,8 +705,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set frequency if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } // Hardcoded to use auto as much as possible on the TDA10045 as it @@ -1163,7 +1165,6 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) static int tda1004x_sleep(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; - int gpio_conf; switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: @@ -1173,13 +1174,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe) case TDA1004X_DEMOD_TDA10046: /* set outputs to tristate */ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); - /* invert GPIO 1 and 3 if desired*/ - gpio_conf = state->config->gpio_config; - if (gpio_conf >= TDA10046_GP00_I) - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, - (gpio_conf & 0x0f) ^ 0x0a); - - tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0); tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } diff --git a/trunk/drivers/media/dvb/frontends/tda1004x.h b/trunk/drivers/media/dvb/frontends/tda1004x.h index abae84350142..ec502d71b83c 100644 --- a/trunk/drivers/media/dvb/frontends/tda1004x.h +++ b/trunk/drivers/media/dvb/frontends/tda1004x.h @@ -35,23 +35,9 @@ enum tda10046_agc { TDA10046_AGC_DEFAULT, /* original configuration */ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ - TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ -}; - -/* Many (hybrid) boards use GPIO 1 and 3 - GPIO1 analog - dvb switch - GPIO3 firmware eeprom address switch -*/ -enum tda10046_gpio { - TDA10046_GPTRI = 0x00, /* All GPIOs tristate */ - TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */ - TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */ - TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */ - TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */ - TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/ - TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */ - TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */ - TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */ + TDA10046_AGC_TDA827X_GP11, /* IF AGC only, special setup for tda827x */ + TDA10046_AGC_TDA827X_GP00, /* same as above, but GPIOs 0 */ + TDA10046_AGC_TDA827X_GP01, /* same as above, but GPIO3=0 GPIO1=1*/ }; enum tda10046_if { @@ -61,11 +47,6 @@ enum tda10046_if { TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ }; -enum tda10046_tsout { - TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */ - TDA10046_TS_SERIAL = 0x01, /* serial transport stream */ -}; - struct tda1004x_config { /* the demodulator's i2c address */ @@ -77,9 +58,6 @@ struct tda1004x_config /* Does the OCLK signal need inverted? */ u8 invert_oclk; - /* parallel or serial transport stream */ - enum tda10046_tsout ts_mode; - /* Xtal frequency, 4 or 16MHz*/ enum tda10046_xtal xtal_freq; @@ -89,35 +67,11 @@ struct tda1004x_config /* AGC configuration */ enum tda10046_agc agc_config; - /* setting of GPIO1 and 3 */ - enum tda10046_gpio gpio_config; - - /* slave address and configuration of the tuner */ - u8 tuner_address; - u8 tuner_config; - u8 antenna_switch; - - /* if the board uses another I2c Bridge (tda8290), its address */ - u8 i2c_gate; - /* request firmware for device */ + /* set this to NULL if the card has a firmware EEPROM */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -enum tda1004x_demod { - TDA1004X_DEMOD_TDA10045, - TDA1004X_DEMOD_TDA10046, -}; - -struct tda1004x_state { - struct i2c_adapter* i2c; - const struct tda1004x_config* config; - struct dvb_frontend frontend; - - /* private demod data */ - enum tda1004x_demod demod_type; -}; - #if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c); diff --git a/trunk/drivers/media/dvb/frontends/tda827x.c b/trunk/drivers/media/dvb/frontends/tda827x.c deleted file mode 100644 index 256fc4bf500b..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda827x.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * - * (c) 2005 Hartmut Hackmann - * (c) 2007 Michael Krufky - * - * 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. - */ - -#include -#include -#include - -#include "tda827x.h" - -static int debug = 0; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda827x: " args); \ - } while (0) - -struct tda827x_priv { - int i2c_addr; - struct i2c_adapter *i2c_adap; - struct tda827x_config *cfg; - u32 frequency; - u32 bandwidth; -}; - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - -static const struct tda827x_data tda827x_dvbt[] = { - { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} -}; - -static int tda827xo_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - u8 buf[14]; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - int i, tuner_freq, if_freq; - u32 N; - - dprintk("%s:\n", __FUNCTION__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: - if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ - if_freq = 5000000; - break; - } - tuner_freq = params->frequency + if_freq; - - i = 0; - while (tda827x_dvbt[i].lomax < tuner_freq) { - if(tda827x_dvbt[i + 1].lomax == 0) - break; - i++; - } - - N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); - buf[0] = 0; - buf[1] = (N>>8) | 0x40; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x52; - buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + - (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; - buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; - buf[7] = 0xbf; - buf[8] = 0x2a; - buf[9] = 0x05; - buf[10] = 0xff; - buf[11] = 0x00; - buf[12] = 0x00; - buf[13] = 0x40; - - msg.len = 14; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { - printk("%s: could not write to tuner at addr: 0x%02x\n", - __FUNCTION__, priv->i2c_addr << 1); - return -EIO; - } - msleep(500); - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x50 + tda827x_dvbt[i].cp; - msg.len = 2; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - priv->frequency = tuner_freq - if_freq; // FIXME - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - return 0; -} - -static int tda827xo_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0xd0 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __FUNCTION__); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; - -static const struct tda827xa_data tda827xa_dvbt[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static int tda827xa_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - u8 buf[11]; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - int i, tuner_freq, if_freq; - u32 N; - - dprintk("%s:\n", __FUNCTION__); - if (priv->cfg && priv->cfg->lna_gain) - priv->cfg->lna_gain(fe, 1); - msleep(20); - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: - if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ - if_freq = 5000000; - break; - } - tuner_freq = params->frequency + if_freq; - - i = 0; - while (tda827xa_dvbt[i].lomax < tuner_freq) { - if(tda827xa_dvbt[i + 1].lomax == 0) - break; - i++; - } - - N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; - buf[0] = 0; // subaddress - buf[1] = N >> 8; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x16; - buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + - tda827xa_dvbt[i].sbs; - buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); - buf[7] = 0x1c; - buf[8] = 0x06; - buf[9] = 0x24; - buf[10] = 0x00; - msg.len = 11; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { - printk("%s: could not write to tuner at addr: 0x%02x\n", - __FUNCTION__, priv->i2c_addr << 1); - return -EIO; - } - buf[0] = 0x90; - buf[1] = 0xff; - buf[2] = 0x60; - buf[3] = 0x00; - buf[4] = 0x59; // lpsel, for 6MHz + 2 - msg.len = 5; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - buf[0] = 0xa0; - buf[1] = 0x40; - msg.len = 2; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(11); - msg.flags = I2C_M_RD; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - msg.flags = 0; - - buf[1] >>= 4; - dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); - if ((buf[1]) < 2) { - if (priv->cfg && priv->cfg->lna_gain) - priv->cfg->lna_gain(fe, 0); - buf[0] = 0x60; - buf[1] = 0x0c; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - } - - buf[0] = 0xc0; - buf[1] = 0x99; // lpsel, for 6MHz + 2 - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - buf[0] = 0x60; - buf[1] = 0x3c; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x10 + tda827xa_dvbt[i].scr; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(163); - buf[0] = 0xc0; - buf[1] = 0x39; // lpsel, for 6MHz + 2 - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(3); - /* freeze AGC1 */ - buf[0] = 0x50; - buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - priv->frequency = tuner_freq - if_freq; // FIXME - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - return 0; -} - -static int tda827xa_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0x90 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __FUNCTION__); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - i2c_transfer(priv->i2c_adap, &msg, 1); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -static int tda827x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int tda827x_init(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - dprintk("%s:\n", __FUNCTION__); - if (priv->cfg && priv->cfg->init) - priv->cfg->init(fe); - - return 0; -} - -static int tda827x_probe_version(struct dvb_frontend *fe); - -static int tda827x_initial_init(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.init(fe); -} - -static int tda827x_initial_sleep(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.sleep(fe); -} - -static struct dvb_tuner_ops tda827xo_tuner_ops = { - .info = { - .name = "Philips TDA827X", - .frequency_min = 55000000, - .frequency_max = 860000000, - .frequency_step = 250000 - }, - .release = tda827x_release, - .init = tda827x_initial_init, - .sleep = tda827x_initial_sleep, - .set_params = tda827xo_set_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static struct dvb_tuner_ops tda827xa_tuner_ops = { - .info = { - .name = "Philips TDA827XA", - .frequency_min = 44000000, - .frequency_max = 906000000, - .frequency_step = 62500 - }, - .release = tda827x_release, - .init = tda827x_init, - .sleep = tda827xa_sleep, - .set_params = tda827xa_set_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static int tda827x_probe_version(struct dvb_frontend *fe) -{ u8 data; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = &data, .len = 1 }; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { - printk("%s: could not read from tuner at addr: 0x%02x\n", - __FUNCTION__, msg.addr << 1); - return -EIO; - } - if ((data & 0x3c) == 0) { - dprintk("tda827x tuner found\n"); - fe->ops.tuner_ops.init = tda827x_init; - fe->ops.tuner_ops.sleep = tda827xo_sleep; - } else { - dprintk("tda827xa tuner found\n"); - memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); - } - return 0; -} - -struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - struct tda827x_priv *priv = NULL; - - dprintk("%s:\n", __FUNCTION__); - priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->cfg = cfg; - memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - return fe; -} - -EXPORT_SYMBOL(tda827x_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("DVB TDA827x driver"); -MODULE_AUTHOR("Hartmut Hackmann "); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/dvb/frontends/tda827x.h b/trunk/drivers/media/dvb/frontends/tda827x.h deleted file mode 100644 index 69e8263d6d59..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda827x.h +++ /dev/null @@ -1,62 +0,0 @@ - /* - DVB Driver for Philips tda827x / tda827xa Silicon tuners - - (c) 2005 Hartmut Hackmann - (c) 2007 Michael Krufky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef __DVB_TDA827X_H__ -#define __DVB_TDA827X_H__ - -#include -#include "dvb_frontend.h" - -struct tda827x_config -{ - void (*lna_gain) (struct dvb_frontend *fe, int high); - int (*init) (struct dvb_frontend *fe); - int (*sleep) (struct dvb_frontend *fe); -}; - - -/** - * Attach a tda827x tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @param cfg optional callback function pointers. - * @return FE pointer on success, NULL on failure. - */ -#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg); -#else -static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, - int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif // CONFIG_DVB_TDA827X - -#endif // __DVB_TDA827X_H__ diff --git a/trunk/drivers/media/dvb/pluto2/Kconfig b/trunk/drivers/media/dvb/pluto2/Kconfig index 7d8e6e87bdbb..9b84b1bdc313 100644 --- a/trunk/drivers/media/dvb/pluto2/Kconfig +++ b/trunk/drivers/media/dvb/pluto2/Kconfig @@ -2,6 +2,7 @@ config DVB_PLUTO2 tristate "Pluto2 cards" depends on DVB_CORE && PCI && I2C select I2C_ALGOBIT + select DVB_PLL select DVB_TDA1004X help Support for PCI cards based on the Pluto2 FPGA like the Satelco diff --git a/trunk/drivers/media/dvb/ttpci/Kconfig b/trunk/drivers/media/dvb/ttpci/Kconfig index 7751628e1415..eec7ccf41f8b 100644 --- a/trunk/drivers/media/dvb/ttpci/Kconfig +++ b/trunk/drivers/media/dvb/ttpci/Kconfig @@ -3,6 +3,7 @@ config DVB_AV7110 depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select FW_LOADER if !DVB_AV7110_FIRMWARE select VIDEO_SAA7146_VV + select DVB_PLL select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -61,13 +62,13 @@ config DVB_BUDGET tristate "Budget cards" depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146 + select DVB_PLL select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_L64781 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE @@ -86,6 +87,7 @@ config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146 + select DVB_PLL select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -112,7 +114,6 @@ config DVB_BUDGET_AV select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_TUA6100 if !DVB_FE_CUSTOMISE select FW_LOADER help @@ -129,6 +130,7 @@ config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 select DVB_AV7110 + select DVB_PLL select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE diff --git a/trunk/drivers/media/dvb/ttpci/av7110.c b/trunk/drivers/media/dvb/ttpci/av7110.c index 67becdd4db60..29ed532ba966 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110.c +++ b/trunk/drivers/media/dvb/ttpci/av7110.c @@ -219,10 +219,7 @@ static void recover_arm(struct av7110 *av7110) av7110->recover(av7110); restart_feeds(av7110); - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, true); -#endif + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); } static void av7110_arm_sync(struct av7110 *av7110) @@ -253,10 +250,6 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, false); -#endif - if (mutex_lock_interruptible(&av7110->dcomlock)) break; newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); @@ -674,8 +667,8 @@ static void gpioirq(unsigned long data) return; case DATA_IRCOMMAND: - if (av7110->ir.ir_handler) - av7110->ir.ir_handler(av7110, + if (av7110->ir_handler) + av7110->ir_handler(av7110, swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; @@ -1914,10 +1907,8 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) if (av7110->fe_synced == synced) return 0; - if (av7110->playing) { - av7110->fe_synced = synced; + if (av7110->playing) return 0; - } if (mutex_lock_interruptible(&av7110->pid_mutex)) return -ERESTARTSYS; diff --git a/trunk/drivers/media/dvb/ttpci/av7110.h b/trunk/drivers/media/dvb/ttpci/av7110.h index 115002b0390c..b98bd453cade 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110.h +++ b/trunk/drivers/media/dvb/ttpci/av7110.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -67,27 +66,6 @@ struct dvb_video_events { }; -struct av7110; - -/* infrared remote control */ -struct infrared { - u16 key_map[256]; - struct input_dev *input_dev; - char input_phys[32]; - struct timer_list keyup_timer; - struct tasklet_struct ir_tasklet; - void (*ir_handler)(struct av7110 *av7110, u32 ircom); - u32 ir_command; - u32 ir_config; - u32 device_mask; - u8 protocol; - u8 inversion; - u16 last_key; - u16 last_toggle; - u8 delay_timer_finished; -}; - - /* place to store all the necessary device information */ struct av7110 { @@ -249,7 +227,10 @@ struct av7110 { u16 wssMode; u16 wssData; - struct infrared ir; + u32 ir_config; + u32 ir_command; + void (*ir_handler)(struct av7110 *av7110, u32 ircom); + struct tasklet_struct ir_tasklet; /* firmware stuff */ unsigned char *bin_fw; @@ -287,7 +268,6 @@ struct av7110 { extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); -extern int av7110_check_ir_config(struct av7110 *av7110, int force); extern int av7110_ir_init(struct av7110 *av7110); extern void av7110_ir_exit(struct av7110 *av7110); diff --git a/trunk/drivers/media/dvb/ttpci/av7110_av.c b/trunk/drivers/media/dvb/ttpci/av7110_av.c index 654c9e919e04..e719af807685 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_av.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_av.c @@ -1009,7 +1009,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) ret = av7110_av_stop(av7110, RP_VIDEO); else - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, + ret = vidcom(av7110, VIDEO_CMD_STOP, av7110->videostate.video_blank ? 0 : 1); if (!ret) av7110->trickmode = TRICK_NONE; @@ -1019,7 +1019,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, av7110->trickmode = TRICK_NONE; if (av7110->videostate.play_state == VIDEO_FREEZED) { av7110->videostate.play_state = VIDEO_PLAYING; - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); if (ret) break; } @@ -1034,7 +1034,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, ret = av7110_av_start_play(av7110, RP_VIDEO); } if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); if (!ret) av7110->videostate.play_state = VIDEO_PLAYING; break; @@ -1044,7 +1044,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->playing & RP_VIDEO) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); else - ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1); if (!ret) av7110->trickmode = TRICK_FREEZE; break; @@ -1053,7 +1053,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->playing & RP_VIDEO) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); if (!ret) { av7110->videostate.play_state = VIDEO_PLAYING; av7110->trickmode = TRICK_NONE; @@ -1136,7 +1136,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Scan_I, 2, AV_PES, 0); else - ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); + ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); if (!ret) { av7110->trickmode = TRICK_FAST; av7110->videostate.play_state = VIDEO_PLAYING; @@ -1147,13 +1147,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->playing&RP_VIDEO) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } else { - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); + ret = vidcom(av7110, VIDEO_CMD_STOP, 0); if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } if (!ret) { av7110->trickmode = TRICK_SLOW; @@ -1182,10 +1182,10 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } if (av7110->trickmode == TRICK_FREEZE) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); + ret = vidcom(av7110, VIDEO_CMD_STOP, 1); } break; diff --git a/trunk/drivers/media/dvb/ttpci/av7110_hw.h b/trunk/drivers/media/dvb/ttpci/av7110_hw.h index 673d9b3f064c..4e173c67fbb2 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_hw.h +++ b/trunk/drivers/media/dvb/ttpci/av7110_hw.h @@ -216,11 +216,11 @@ enum av7110_command_type { #define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ /* MPEG video decoder commands */ -#define AV_VIDEO_CMD_STOP 0x000e -#define AV_VIDEO_CMD_PLAY 0x000d -#define AV_VIDEO_CMD_FREEZE 0x0102 -#define AV_VIDEO_CMD_FFWD 0x0016 -#define AV_VIDEO_CMD_SLOW 0x0022 +#define VIDEO_CMD_STOP 0x000e +#define VIDEO_CMD_PLAY 0x000d +#define VIDEO_CMD_FREEZE 0x0102 +#define VIDEO_CMD_FFWD 0x0016 +#define VIDEO_CMD_SLOW 0x0022 /* MPEG audio decoder commands */ #define AUDIO_CMD_MUTE 0x0001 diff --git a/trunk/drivers/media/dvb/ttpci/av7110_ir.c b/trunk/drivers/media/dvb/ttpci/av7110_ir.c index a97f166bb523..f59465bb0af3 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_ir.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_ir.c @@ -1,31 +1,8 @@ -/* - * Driver for the remote control of SAA7146 based AV7110 cards - * - * Copyright (C) 1999-2003 Holger Waechtler - * Copyright (C) 2003-2007 Oliver Endriss - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - */ - - #include #include #include #include +#include #include #include #include @@ -33,37 +10,18 @@ #include "av7110.h" #include "av7110_hw.h" +#define UP_TIMEOUT (HZ*7/25) -#define AV_CNT 4 - -#define IR_RC5 0 -#define IR_RCMM 1 -#define IR_RC5_EXT 2 /* internal only */ - -#define IR_ALL 0xffffffff - -#define UP_TIMEOUT (HZ*7/25) - - -/* Note: enable ir debugging by or'ing debug with 16 */ - -static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; -module_param_array(ir_protocol, int, NULL, 0644); -MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); - -static int ir_inversion[AV_CNT]; -module_param_array(ir_inversion, int, NULL, 0644); -MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); - -static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; -module_param_array(ir_device_mask, uint, NULL, 0644); -MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); - +/* enable ir debugging by or'ing debug with 16 */ static int av_cnt; -static struct av7110 *av_list[AV_CNT]; +static struct av7110 *av_list[4]; +static struct input_dev *input_dev; +static char input_phys[32]; + +static u8 delay_timer_finished; -static u16 default_key_map [256] = { +static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -87,194 +45,141 @@ static u16 default_key_map [256] = { }; -/* key-up timer */ -static void av7110_emit_keyup(unsigned long parm) +static void av7110_emit_keyup(unsigned long data) { - struct infrared *ir = (struct infrared *) parm; - - if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) + if (!data || !test_bit(data, input_dev->key)) return; - input_report_key(ir->input_dev, ir->last_key, 0); - input_sync(ir->input_dev); + input_report_key(input_dev, data, 0); + input_sync(input_dev); } -/* tasklet */ +static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; + + static void av7110_emit_key(unsigned long parm) { - struct infrared *ir = (struct infrared *) parm; - u32 ircom = ir->ir_command; + struct av7110 *av7110 = (struct av7110 *) parm; + u32 ir_config = av7110->ir_config; + u32 ircom = av7110->ir_command; u8 data; u8 addr; - u16 toggle; + static u16 old_toggle = 0; + u16 new_toggle; u16 keycode; /* extract device address and data */ - switch (ir->protocol) { - case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ + switch (ir_config & 0x0003) { + case 0: /* RC5: 5 bits device address, 6 bits data */ data = ircom & 0x3f; addr = (ircom >> 6) & 0x1f; - toggle = ircom & 0x0800; break; - case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ + case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */ data = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - toggle = ircom & 0x8000; + addr = (ircom >> 8) & 0xff; break; - case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ + case 2: /* extended RC5: 5 bits device address, 7 bits data */ data = ircom & 0x3f; addr = (ircom >> 6) & 0x1f; /* invert 7th data bit for backward compatibility with RC5 keymaps */ if (!(ircom & 0x1000)) data |= 0x40; - toggle = ircom & 0x0800; break; default: - printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol); + printk("invalid ir_config %x\n", ir_config); return; } - input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); - input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); + keycode = key_map[data]; - keycode = ir->key_map[data]; + dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", + ircom, addr, data, keycode); - dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", - __FUNCTION__, ircom, addr, data, keycode); - - /* check device address */ - if (!(ir->device_mask & (1 << addr))) - return; + /* check device address (if selected) */ + if (ir_config & 0x4000) + if (addr != ((ir_config >> 16) & 0xff)) + return; if (!keycode) { - printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", - __FUNCTION__, ircom, addr, data); + printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data); return; } - if (timer_pending(&ir->keyup_timer)) { - del_timer(&ir->keyup_timer); - if (ir->last_key != keycode || toggle != ir->last_toggle) { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, ir->last_key, 0); - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - } else if (ir->delay_timer_finished) { - input_event(ir->input_dev, EV_KEY, keycode, 2); - input_sync(ir->input_dev); + if ((ir_config & 0x0003) == 1) + new_toggle = 0; /* RCMM */ + else + new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ + + if (timer_pending(&keyup_timer)) { + del_timer(&keyup_timer); + if (keyup_timer.data != keycode || new_toggle != old_toggle) { + delay_timer_finished = 0; + input_event(input_dev, EV_KEY, keyup_timer.data, 0); + input_event(input_dev, EV_KEY, keycode, 1); + input_sync(input_dev); + } else if (delay_timer_finished) { + input_event(input_dev, EV_KEY, keycode, 2); + input_sync(input_dev); } } else { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); + delay_timer_finished = 0; + input_event(input_dev, EV_KEY, keycode, 1); + input_sync(input_dev); } - ir->last_key = keycode; - ir->last_toggle = toggle; + keyup_timer.expires = jiffies + UP_TIMEOUT; + keyup_timer.data = keycode; - ir->keyup_timer.expires = jiffies + UP_TIMEOUT; - add_timer(&ir->keyup_timer); + add_timer(&keyup_timer); + old_toggle = new_toggle; } - -/* register with input layer */ -static void input_register_keys(struct infrared *ir) +static void input_register_keys(void) { int i; - set_bit(EV_KEY, ir->input_dev->evbit); - set_bit(EV_REP, ir->input_dev->evbit); - set_bit(EV_MSC, ir->input_dev->evbit); + memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - set_bit(MSC_RAW, ir->input_dev->mscbit); - set_bit(MSC_SCAN, ir->input_dev->mscbit); - - memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); - - for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { - if (ir->key_map[i] > KEY_MAX) - ir->key_map[i] = 0; - else if (ir->key_map[i] > KEY_RESERVED) - set_bit(ir->key_map[i], ir->input_dev->keybit); + for (i = 0; i < ARRAY_SIZE(key_map); i++) { + if (key_map[i] > KEY_MAX) + key_map[i] = 0; + else if (key_map[i] > KEY_RESERVED) + set_bit(key_map[i], input_dev->keybit); } - - ir->input_dev->keycode = ir->key_map; - ir->input_dev->keycodesize = sizeof(ir->key_map[0]); - ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); } -/* called by the input driver after rep[REP_DELAY] ms */ -static void input_repeat_key(unsigned long parm) +static void input_repeat_key(unsigned long data) { - struct infrared *ir = (struct infrared *) parm; - - ir->delay_timer_finished = 1; + /* called by the input driver after rep[REP_DELAY] ms */ + delay_timer_finished = 1; } -/* check for configuration changes */ -int av7110_check_ir_config(struct av7110 *av7110, int force) +static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) { - int i; - int modified = force; - int ret = -ENODEV; + int ret = 0; - for (i = 0; i < av_cnt; i++) - if (av7110 == av_list[i]) - break; - - if (i < av_cnt && av7110) { - if ((av7110->ir.protocol & 1) != ir_protocol[i] || - av7110->ir.inversion != ir_inversion[i]) - modified = true; - - if (modified) { - /* protocol */ - if (ir_protocol[i]) { - ir_protocol[i] = 1; - av7110->ir.protocol = IR_RCMM; - av7110->ir.ir_config = 0x0001; - } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { - av7110->ir.protocol = IR_RC5_EXT; - av7110->ir.ir_config = 0x0002; - } else { - av7110->ir.protocol = IR_RC5; - av7110->ir.ir_config = 0x0000; - } - /* inversion */ - if (ir_inversion[i]) { - ir_inversion[i] = 1; - av7110->ir.ir_config |= 0x8000; - } - av7110->ir.inversion = ir_inversion[i]; - /* update ARM */ - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, - av7110->ir.ir_config); - } else - ret = 0; - - /* address */ - if (av7110->ir.device_mask != ir_device_mask[i]) - av7110->ir.device_mask = ir_device_mask[i]; + dprintk(4, "%p\n", av7110); + if (av7110) { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); + av7110->ir_config = ir_config; } - return ret; } -/* /proc/av7110_ir interface */ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) { char *page; + int size = 4 + 256 * sizeof(u16); u32 ir_config; - int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; int i; if (count < size) @@ -289,86 +194,71 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, return -EFAULT; } - memcpy(&ir_config, page, sizeof ir_config); - - for (i = 0; i < av_cnt; i++) { - /* keymap */ - memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, - sizeof(av_list[i]->ir.key_map)); - /* protocol, inversion, address */ - ir_protocol[i] = ir_config & 0x0001; - ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; - if (ir_config & 0x4000) - ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); - else - ir_device_mask[i] = IR_ALL; - /* update configuration */ - av7110_check_ir_config(av_list[i], false); - input_register_keys(&av_list[i]->ir); - } + memcpy(&ir_config, page, 4); + memcpy(&key_map, page + 4, 256 * sizeof(u16)); vfree(page); + if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001)) + ir_config |= 0x0002; /* enable extended RC5 */ + for (i = 0; i < av_cnt; i++) + av7110_setup_irc_config(av_list[i], ir_config); + input_register_keys(); return count; } -/* interrupt handler */ static void ir_handler(struct av7110 *av7110, u32 ircom) { - dprintk(4, "ir command = %08x\n", ircom); - av7110->ir.ir_command = ircom; - tasklet_schedule(&av7110->ir.ir_tasklet); + dprintk(4, "ircommand = %08x\n", ircom); + av7110->ir_command = ircom; + tasklet_schedule(&av7110->ir_tasklet); } int __devinit av7110_ir_init(struct av7110 *av7110) { - struct input_dev *input_dev; static struct proc_dir_entry *e; int err; if (av_cnt >= ARRAY_SIZE(av_list)) return -ENOSPC; + av7110_setup_irc_config(av7110, 0x0001); av_list[av_cnt++] = av7110; - av7110_check_ir_config(av7110, true); - - init_timer(&av7110->ir.keyup_timer); - av7110->ir.keyup_timer.function = av7110_emit_keyup; - av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - av7110->ir.input_dev = input_dev; - snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), - "pci-%s/ir0", pci_name(av7110->dev->pci)); - - input_dev->name = "DVB on-card IR receiver"; - - input_dev->phys = av7110->ir.input_phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 2; - if (av7110->dev->pci->subsystem_vendor) { - input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; - input_dev->id.product = av7110->dev->pci->subsystem_device; - } else { - input_dev->id.vendor = av7110->dev->pci->vendor; - input_dev->id.product = av7110->dev->pci->device; - } - input_dev->cdev.dev = &av7110->dev->pci->dev; - /* initial keymap */ - memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); - input_register_keys(&av7110->ir); - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - input_dev->timer.function = input_repeat_key; - input_dev->timer.data = (unsigned long) &av7110->ir; if (av_cnt == 1) { + init_timer(&keyup_timer); + keyup_timer.data = 0; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + snprintf(input_phys, sizeof(input_phys), + "pci-%s/ir0", pci_name(av7110->dev->pci)); + + input_dev->name = "DVB on-card IR receiver"; + + input_dev->phys = input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; + if (av7110->dev->pci->subsystem_vendor) { + input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; + input_dev->id.product = av7110->dev->pci->subsystem_device; + } else { + input_dev->id.vendor = av7110->dev->pci->vendor; + input_dev->id.product = av7110->dev->pci->device; + } + input_dev->cdev.dev = &av7110->dev->pci->dev; + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_REP, input_dev->evbit); + input_register_keys(); + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + input_dev->timer.function = input_repeat_key; + e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); if (e) { e->write_proc = av7110_ir_write_proc; @@ -376,8 +266,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110) } } - tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); - av7110->ir.ir_handler = ir_handler; + tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); + av7110->ir_handler = ir_handler; return 0; } @@ -390,10 +280,8 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) if (av_cnt == 0) return; - del_timer_sync(&av7110->ir.keyup_timer); - av7110->ir.ir_handler = NULL; - tasklet_kill(&av7110->ir.ir_tasklet); - + av7110->ir_handler = NULL; + tasklet_kill(&av7110->ir_tasklet); for (i = 0; i < av_cnt; i++) if (av_list[i] == av7110) { av_list[i] = av_list[av_cnt-1]; @@ -401,13 +289,14 @@ void __devexit av7110_ir_exit(struct av7110 *av7110) break; } - if (av_cnt == 1) + if (av_cnt == 1) { + del_timer_sync(&keyup_timer); remove_proc_entry("av7110_ir", NULL); - - input_unregister_device(av7110->ir.input_dev); + input_unregister_device(input_dev); + } av_cnt--; } -//MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); +//MODULE_AUTHOR("Holger Waechtler "); //MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/media/dvb/ttpci/budget-av.c b/trunk/drivers/media/dvb/ttpci/budget-av.c index 0e817d6f1ce5..3035b224c7a3 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-av.c +++ b/trunk/drivers/media/dvb/ttpci/budget-av.c @@ -35,7 +35,7 @@ #include "budget.h" #include "stv0299.h" -#include "tda1002x.h" +#include "tda10021.h" #include "tda1004x.h" #include "tua6100.h" #include "dvb-pll.h" @@ -66,6 +66,9 @@ struct budget_av { int slot_status; struct dvb_ca_en50221 ca; u8 reinitialise_demod:1; + u8 tda10021_poclkp:1; + u8 tda10021_ts_enabled; + int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); }; static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); @@ -231,6 +234,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) if (budget_av->reinitialise_demod) dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + /* set tda10021 back to original clock configuration on reset */ + if (budget_av->tda10021_poclkp) { + tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); + budget_av->tda10021_ts_enabled = 0; + } + return 0; } @@ -247,6 +256,11 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); budget_av->slot_status = SLOTSTATUS_NONE; + /* set tda10021 back to original clock configuration when cam removed */ + if (budget_av->tda10021_poclkp) { + tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); + budget_av->tda10021_ts_enabled = 0; + } return 0; } @@ -262,6 +276,12 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + /* tda10021 seems to need a different TS clock config when data is routed to the CAM */ + if (budget_av->tda10021_poclkp) { + tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1); + budget_av->tda10021_ts_enabled = 1; + } + return 0; } @@ -611,62 +631,37 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = { static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct budget *budget = (struct budget *) fe->dvb->priv; - u8 buf[6]; + u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - int i; -#define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; - buf[2] = 0xce; + buf[2] = 0x86; buf[3] = (params->frequency < 150000000 ? 0x01 : params->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; } -static struct tda1002x_config philips_cu1216_config = { +static struct tda10021_config philips_cu1216_config = { .demod_address = 0x0c, - .invert = 1, }; -static struct tda1002x_config philips_cu1216_config_altaddress = { +static struct tda10021_config philips_cu1216_config_altaddress = { .demod_address = 0x0d, - .invert = 0, }; + + + static int philips_tu1216_tuner_init(struct dvb_frontend *fe) { struct budget *budget = (struct budget *) fe->dvb->priv; @@ -913,28 +908,41 @@ static u8 read_pwm(struct budget_av *budget_av) return pwm; } -#define SUBID_DVBS_KNC1 0x0010 -#define SUBID_DVBS_KNC1_PLUS 0x0011 -#define SUBID_DVBS_TYPHOON 0x4f56 -#define SUBID_DVBS_CINERGY1200 0x1154 -#define SUBID_DVBS_CYNERGY1200N 0x1155 -#define SUBID_DVBS_TV_STAR 0x0014 -#define SUBID_DVBS_TV_STAR_CI 0x0016 -#define SUBID_DVBS_EASYWATCH_1 0x001a -#define SUBID_DVBS_EASYWATCH 0x001e - -#define SUBID_DVBC_EASYWATCH 0x002a -#define SUBID_DVBC_EASYWATCH_MK3 0x002c -#define SUBID_DVBC_KNC1 0x0020 -#define SUBID_DVBC_KNC1_PLUS 0x0021 -#define SUBID_DVBC_KNC1_MK3 0x0022 -#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 -#define SUBID_DVBC_CINERGY1200 0x1156 -#define SUBID_DVBC_CINERGY1200_MK3 0x1176 - -#define SUBID_DVBT_KNC1_PLUS 0x0031 -#define SUBID_DVBT_KNC1 0x0030 -#define SUBID_DVBT_CINERGY1200 0x1157 +#define SUBID_DVBS_KNC1 0x0010 +#define SUBID_DVBS_KNC1_PLUS 0x0011 +#define SUBID_DVBS_TYPHOON 0x4f56 +#define SUBID_DVBS_CINERGY1200 0x1154 +#define SUBID_DVBS_CYNERGY1200N 0x1155 + +#define SUBID_DVBS_TV_STAR 0x0014 +#define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS_EASYWATCH_1 0x001a +#define SUBID_DVBS_EASYWATCH 0x001e +#define SUBID_DVBC_EASYWATCH 0x002a +#define SUBID_DVBC_KNC1 0x0020 +#define SUBID_DVBC_KNC1_PLUS 0x0021 +#define SUBID_DVBC_CINERGY1200 0x1156 + +#define SUBID_DVBT_KNC1_PLUS 0x0031 +#define SUBID_DVBT_KNC1 0x0030 +#define SUBID_DVBT_CINERGY1200 0x1157 + + +static int tda10021_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct budget_av* budget_av = fe->dvb->priv; + int result; + + result = budget_av->tda10021_set_frontend(fe, p); + if (budget_av->tda10021_ts_enabled) { + tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1); + } else { + tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0); + } + + return result; +} static void frontend_init(struct budget_av *budget_av) { @@ -953,7 +961,6 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_KNC1_PLUS: case SUBID_DVBT_KNC1_PLUS: case SUBID_DVBC_EASYWATCH: - case SUBID_DVBC_KNC1_PLUS_MK3: saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } @@ -1010,7 +1017,6 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_CINERGY1200: case SUBID_DVBC_EASYWATCH: budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; fe = dvb_attach(tda10021_attach, &philips_cu1216_config, &budget_av->budget.i2c_adap, read_pwm(budget_av)); @@ -1019,20 +1025,9 @@ static void frontend_init(struct budget_av *budget_av) &budget_av->budget.i2c_adap, read_pwm(budget_av)); if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBC_EASYWATCH_MK3: - case SUBID_DVBC_CINERGY1200_MK3: - case SUBID_DVBC_KNC1_MK3: - case SUBID_DVBC_KNC1_PLUS_MK3: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10023_attach, &philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { + budget_av->tda10021_poclkp = 1; + budget_av->tda10021_set_frontend = fe->ops.set_frontend; + fe->ops.set_frontend = tda10021_set_frontend; fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; } break; @@ -1265,16 +1260,12 @@ MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); -MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); static struct pci_device_id pci_tbl[] = { @@ -1288,17 +1279,13 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), - MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), - MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), - MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), - MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), { .vendor = 0, diff --git a/trunk/drivers/media/dvb/ttpci/budget-ci.c b/trunk/drivers/media/dvb/ttpci/budget-ci.c index 4ed4599ce816..464feaf1a9ad 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-ci.c +++ b/trunk/drivers/media/dvb/ttpci/budget-ci.c @@ -73,15 +73,21 @@ #define SLOTSTATUS_READY 8 #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) -/* - * Milliseconds during which a key is regarded as pressed. - * If an identical command arrives within this time, the timer will start over. +/* Milliseconds during which key presses are regarded as key repeat and during + * which the debounce logic is active */ -#define IR_KEYPRESS_TIMEOUT 250 +#define IR_REPEAT_TIMEOUT 350 /* RC5 device wildcard */ #define IR_DEVICE_ANY 255 +/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two), + * this setting allows the superflous sequences to be ignored + */ +static int debounce = 0; +module_param(debounce, int, 0644); +MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)"); + static int rc5_device = -1; module_param(rc5_device, int, 0644); MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); @@ -93,14 +99,10 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); struct budget_ci_ir { struct input_dev *dev; struct tasklet_struct msp430_irq_tasklet; - struct timer_list timer_keyup; char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ char phys[32]; struct ir_input_state state; int rc5_device; - u32 last_raw; - u32 ir_key; - bool have_command; }; struct budget_ci { @@ -123,8 +125,13 @@ static void msp430_ir_interrupt(unsigned long data) { struct budget_ci *budget_ci = (struct budget_ci *) data; struct input_dev *dev = budget_ci->ir.dev; + static int bounces = 0; + int device; + int toggle; + static int prev_toggle = -1; + static u32 ir_key; + static int state = 0; u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; - u32 raw; /* * The msp430 chip can generate two different bytes, command and device @@ -136,7 +143,7 @@ static void msp430_ir_interrupt(unsigned long data) * bytes and one or more device bytes. For the repeated bytes, the * highest bit (X) is set. The first command byte is always generated * before the first device byte. Other than that, no specific order - * seems to apply. To make life interesting, bytes can also be lost. + * seems to apply. * * Only when we have a command and device byte, a keypress is * generated. @@ -145,35 +152,53 @@ static void msp430_ir_interrupt(unsigned long data) if (ir_debug) printk("budget_ci: received byte 0x%02x\n", command); - /* Remove repeat bit, we use every command */ - command = command & 0x7f; + /* Is this a repeated byte? */ + if (command & 0x80) + return; /* Is this a RC5 command byte? */ if (command & 0x40) { - budget_ci->ir.have_command = true; - budget_ci->ir.ir_key = command & 0x3f; + state = 1; + ir_key = command & 0x3f; return; } /* It's a RC5 device byte */ - if (!budget_ci->ir.have_command) + if (!state) return; - budget_ci->ir.have_command = false; + state = 0; + device = command & 0x1f; + toggle = command & 0x20; - if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && - budget_ci->ir.rc5_device != (command & 0x1f)) + if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device) return; - /* Is this a repeated key sequence? (same device, command, toggle) */ - raw = budget_ci->ir.ir_key | (command << 8); - if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) { - ir_input_nokey(dev, &budget_ci->ir.state); - ir_input_keydown(dev, &budget_ci->ir.state, - budget_ci->ir.ir_key, raw); - budget_ci->ir.last_raw = raw; + /* Ignore repeated key sequences if requested */ + if (toggle == prev_toggle && ir_key == dev->repeat_key && + bounces > 0 && timer_pending(&dev->timer)) { + if (ir_debug) + printk("budget_ci: debounce logic ignored IR command\n"); + bounces--; + return; } + prev_toggle = toggle; + + /* Are we still waiting for a keyup event? */ + if (del_timer(&dev->timer)) + ir_input_nokey(dev, &budget_ci->ir.state); - mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT)); + /* Generate keypress */ + if (ir_debug) + printk("budget_ci: generating keypress 0x%02x\n", ir_key); + ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8))); + + /* Do we want to delay the keyup event? */ + if (debounce) { + bounces = debounce; + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT)); + } else { + ir_input_nokey(dev, &budget_ci->ir.state); + } } static int msp430_ir_init(struct budget_ci *budget_ci) @@ -246,21 +271,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci) break; } - /* initialise the key-up timeout handler */ - init_timer(&budget_ci->ir.timer_keyup); - budget_ci->ir.timer_keyup.function = msp430_ir_keyup; - budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; - budget_ci->ir.last_raw = 0xffff; /* An impossible value */ + /* initialise the key-up debounce timeout handler */ + input_dev->timer.function = msp430_ir_keyup; + input_dev->timer.data = (unsigned long) &budget_ci->ir; + error = input_register_device(input_dev); if (error) { printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); goto out2; } - /* note: these must be after input_register_device */ - input_dev->rep[REP_DELAY] = 400; - input_dev->rep[REP_PERIOD] = 250; - tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, (unsigned long) budget_ci); @@ -284,8 +304,10 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); - del_timer_sync(&dev->timer); - ir_input_nokey(dev, &budget_ci->ir.state); + if (del_timer(&dev->timer)) { + ir_input_nokey(dev, &budget_ci->ir.state); + input_sync(dev); + } input_unregister_device(dev); } diff --git a/trunk/drivers/media/dvb/ttpci/budget-core.c b/trunk/drivers/media/dvb/ttpci/budget-core.c index 6b97dc1e6b65..e15562f81664 100644 --- a/trunk/drivers/media/dvb/ttpci/budget-core.c +++ b/trunk/drivers/media/dvb/ttpci/budget-core.c @@ -41,14 +41,11 @@ #define TS_WIDTH (2 * TS_SIZE) #define TS_WIDTH_ACTIVY TS_SIZE -#define TS_WIDTH_DVBC TS_SIZE #define TS_HEIGHT_MASK 0xf00 #define TS_HEIGHT_MASK_ACTIVY 0xc00 -#define TS_HEIGHT_MASK_DVBC 0xe00 #define TS_MIN_BUFSIZE_K 188 #define TS_MAX_BUFSIZE_K 1410 #define TS_MAX_BUFSIZE_K_ACTIVY 564 -#define TS_MAX_BUFSIZE_K_DVBC 1316 #define BUFFER_WARNING_WAIT (30*HZ) int budget_debug; @@ -109,19 +106,6 @@ static int start_ts_capture(struct budget *budget) saa7146_write(dev, MC2, (MASK_10 | MASK_26)); saa7146_write(dev, BRS_CTRL, 0x60000000); break; - case BUDGET_CIN1200C_MK3: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1CP_MK3: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - break; default: if (budget->video_port == BUDGET_VIDEO_PORTA) { saa7146_write(dev, DD1_INIT, 0x06000200); @@ -138,13 +122,7 @@ static int start_ts_capture(struct budget *budget) mdelay(10); saa7146_write(dev, BASE_ODD3, 0); - if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { - // using odd/even buffers - saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); - } else { - // using a single buffer - saa7146_write(dev, BASE_EVEN3, 0); - } + saa7146_write(dev, BASE_EVEN3, 0); saa7146_write(dev, PROT_ADDR3, budget->buffer_size); saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); @@ -421,25 +399,11 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, budget->card = bi; budget->dev = (struct saa7146_dev *) dev; - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: + if (budget->card->type == BUDGET_FS_ACTIVY) { budget->buffer_width = TS_WIDTH_ACTIVY; max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; height_mask = TS_HEIGHT_MASK_ACTIVY; - break; - - case BUDGET_KNC1C: - case BUDGET_KNC1CP: - case BUDGET_CIN1200C: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1CP_MK3: - case BUDGET_CIN1200C_MK3: - budget->buffer_width = TS_WIDTH_DVBC; - max_bufsize = TS_MAX_BUFSIZE_K_DVBC; - height_mask = TS_HEIGHT_MASK_DVBC; - break; - - default: + } else { budget->buffer_width = TS_WIDTH; max_bufsize = TS_MAX_BUFSIZE_K; height_mask = TS_HEIGHT_MASK; @@ -451,22 +415,14 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, dma_buffer_size = max_bufsize; budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; - if (budget->buffer_height > 0xfff) { - budget->buffer_height /= 2; - budget->buffer_height &= height_mask; - budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; - } else { - budget->buffer_height &= height_mask; - budget->buffer_size = budget->buffer_height * budget->buffer_width; - } + budget->buffer_height &= height_mask; + budget->buffer_size = budget->buffer_height * budget->buffer_width; budget->buffer_warning_threshold = budget->buffer_size * 80/100; budget->buffer_warnings = 0; budget->buffer_warning_time = jiffies; - dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", - budget->dev->name, - budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", - budget->buffer_width, budget->buffer_height); + dprintk(2, "%s: width = %d, height = %d\n", + budget->dev->name, budget->buffer_width, budget->buffer_height); printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) { diff --git a/trunk/drivers/media/dvb/ttpci/budget.h b/trunk/drivers/media/dvb/ttpci/budget.h index d764ffa728b0..e8a5c79178e1 100644 --- a/trunk/drivers/media/dvb/ttpci/budget.h +++ b/trunk/drivers/media/dvb/ttpci/budget.h @@ -99,9 +99,6 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_KNC1CP 12 #define BUDGET_KNC1TP 13 #define BUDGET_TVSTAR 14 -#define BUDGET_CIN1200C_MK3 15 -#define BUDGET_KNC1C_MK3 16 -#define BUDGET_KNC1CP_MK3 17 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 diff --git a/trunk/drivers/media/dvb/ttusb-budget/Kconfig b/trunk/drivers/media/dvb/ttusb-budget/Kconfig index f546bccdb997..e78ea9227b0e 100644 --- a/trunk/drivers/media/dvb/ttusb-budget/Kconfig +++ b/trunk/drivers/media/dvb/ttusb-budget/Kconfig @@ -1,6 +1,7 @@ config DVB_TTUSB_BUDGET tristate "Technotrend/Hauppauge Nova-USB devices" depends on DVB_CORE && USB && I2C + select DVB_PLL select DVB_CX22700 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE diff --git a/trunk/drivers/media/radio/radio-aimslab.c b/trunk/drivers/media/radio/radio-aimslab.c index 5adc27c3ced9..b2e88ad28977 100644 --- a/trunk/drivers/media/radio/radio-aimslab.c +++ b/trunk/drivers/media/radio/radio-aimslab.c @@ -231,149 +231,129 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); - strlcpy(v->card, "RadioTrack", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int rt_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt=dev->priv; - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*rt_getsigstr(rt); - return 0; -} + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-aimslab", sizeof (v->driver)); + strlcpy(v->card, "RadioTrack", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + if (v->index > 0) + return -EINVAL; - rt->curfreq = f->frequency; - rt_setfreq(rt, rt->curfreq); - return 0; -} + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + v->rangelow=(87*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*rt_getsigstr(rt); - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + rt->curfreq = f->frequency; + rt_setfreq(rt, rt->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = rt->curvol * 6554; - return 0; - } - return -EINVAL; -} + f->type = V4L2_TUNER_RADIO; + f->frequency = rt->curfreq; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=rt->muted; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=rt->curvol * 6554; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + rt_mute(rt); + } else { + rt_setvol(rt,rt->curvol); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + rt_setvol(rt,ctrl->value); + return (0); + } + return -EINVAL; + } - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - rt_mute(rt); - else - rt_setvol(rt,rt->curvol); - return 0; - case V4L2_CID_AUDIO_VOLUME: - rt_setvol(rt,ctrl->value); - return 0; + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + rt_do_ioctl); } - return -EINVAL; -} - -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int rt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, rt_do_ioctl); } static struct rt_device rtrack_unit; @@ -382,7 +362,7 @@ static const struct file_operations rtrack_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = rt_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -394,18 +374,6 @@ static struct video_device rtrack_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &rtrack_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static int __init rtrack_init(void) diff --git a/trunk/drivers/media/radio/radio-gemtek-pci.c b/trunk/drivers/media/radio/radio-gemtek-pci.c index fdf5d6e46eac..74976cba869f 100644 --- a/trunk/drivers/media/radio/radio-gemtek-pci.c +++ b/trunk/drivers/media/radio/radio-gemtek-pci.c @@ -192,158 +192,131 @@ static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card ) return ( inb( card->iobase ) & 0x08 ) ? 0 : 1; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver)); - strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct gemtek_pci_card *card = dev->priv; - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = GEMTEK_PCI_RANGE_LOW; - v->rangehigh = GEMTEK_PCI_RANGE_HIGH; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff * gemtek_pci_getsignal(card); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} + switch ( cmd ) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver)); + strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; - if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || - (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) - return -EINVAL; - gemtek_pci_setfrequency(card, f->frequency); - card->current_frequency = f->frequency; - card->mute = false; - return 0; -} + if (v->index > 0) + return -EINVAL; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; - f->type = V4L2_TUNER_RADIO; - f->frequency = card->current_frequency; - return 0; -} + v->rangelow = GEMTEK_PCI_RANGE_LOW; + v->rangehigh = GEMTEK_PCI_RANGE_HIGH; + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*gemtek_pci_getsignal( card ); -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + if (v->index > 0) + return -EINVAL; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = card->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (card->mute) - ctrl->value = 0; - else - ctrl->value = 65535; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - gemtek_pci_mute(card); - else - gemtek_pci_unmute(card); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - gemtek_pci_unmute(card); - else - gemtek_pci_mute(card); - return 0; - } - return -EINVAL; -} + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; + if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || + (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) + return -EINVAL; - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; + gemtek_pci_setfrequency( card, f->frequency ); + card->current_frequency = f->frequency; + card->mute = false; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=card->mute; + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (card->mute) + ctrl->value=0; + else + ctrl->value=65535; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + gemtek_pci_mute(card); + } else { + gemtek_pci_unmute(card); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (ctrl->value) { + gemtek_pci_unmute(card); + } else { + gemtek_pci_mute(card); + } + return (0); + } + return -EINVAL; + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + gemtek_pci_do_ioctl); + } } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int gemtek_pci_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, gemtek_pci_do_ioctl); } enum { @@ -369,7 +342,7 @@ static const struct file_operations gemtek_pci_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = gemtek_pci_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -380,18 +353,6 @@ static struct video_device vdev_template = { .type = VID_TYPE_TUNER, .hardware = 0, .fops = &gemtek_pci_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) diff --git a/trunk/drivers/media/radio/radio-gemtek.c b/trunk/drivers/media/radio/radio-gemtek.c index b04b6a7fff7c..36c4be6622c7 100644 --- a/trunk/drivers/media/radio/radio-gemtek.c +++ b/trunk/drivers/media/radio/radio-gemtek.c @@ -161,157 +161,137 @@ static int gemtek_getsigstr(struct gemtek_device *dev) return 1; /* signal present */ } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); - strlcpy(v->card, "GemTek", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int gemtek_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; - - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*gemtek_getsigstr(rt); - return 0; -} + struct gemtek_device *rt=dev->priv; -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-gemtek", sizeof (v->driver)); + strlcpy(v->card, "GemTek", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; - rt->curfreq = f->frequency; - /* needs to be called twice in order for getsigstr to work */ - gemtek_setfreq(rt, rt->curfreq); - gemtek_setfreq(rt, rt->curfreq); - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + if (v->index > 0) + return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; - return 0; -} + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + v->rangelow=(87*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*gemtek_getsigstr(rt); - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + if (v->index > 0) + return -EINVAL; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (rt->muted) - ctrl->value = 0; - else - ctrl->value = 65535; - return 0; - } - return -EINVAL; -} + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + rt->curfreq = f->frequency; + /* needs to be called twice in order for getsigstr to work */ + gemtek_setfreq(rt, rt->curfreq); + gemtek_setfreq(rt, rt->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + f->type = V4L2_TUNER_RADIO; + f->frequency = rt->curfreq; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - gemtek_mute(rt); - else - gemtek_unmute(rt); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - gemtek_unmute(rt); - else - gemtek_mute(rt); - return 0; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=rt->muted; + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (rt->muted) + ctrl->value=0; + else + ctrl->value=65535; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + gemtek_mute(rt); + } else { + gemtek_unmute(rt); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (ctrl->value) { + gemtek_unmute(rt); + } else { + gemtek_mute(rt); + } + return (0); + } + return -EINVAL; + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + gemtek_do_ioctl); } - return -EINVAL; } -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) +static int gemtek_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, gemtek_do_ioctl); } static struct gemtek_device gemtek_unit; @@ -320,7 +300,7 @@ static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = gemtek_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -332,18 +312,6 @@ static struct video_device gemtek_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &gemtek_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static int __init gemtek_init(void) diff --git a/trunk/drivers/media/radio/radio-maestro.c b/trunk/drivers/media/radio/radio-maestro.c index 11f80cacd6ed..e67b7f258029 100644 --- a/trunk/drivers/media/radio/radio-maestro.c +++ b/trunk/drivers/media/radio/radio-maestro.c @@ -75,6 +75,8 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int radio_nr = -1; module_param(radio_nr, int, 0); +static int radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void maestro_remove(struct pci_dev *pdev); @@ -100,11 +102,18 @@ static const struct file_operations maestro_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = radio_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; +static struct video_device maestro_radio = { + .name = "Maestro radio", + .type = VID_TYPE_TUNER, + .hardware = 0, + .fops = &maestro_fops, +}; + struct radio_device { u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ muted, /* VIDEO_AUDIO_MUTE */ @@ -181,153 +190,142 @@ static void radio_bits_set(struct radio_device *dev, u32 data) msleep(125); } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-maestro", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static inline int radio_function(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct radio_device *card = video_get_drvdata(dev); - if (v->index > 0) - return -EINVAL; - - (void)radio_bits_get(card); - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_LO; - v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if(card->stereo) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = card->tuned; - return 0; -} + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-maestro", sizeof (v->driver)); + strlcpy(v->card, "Maestro Radio", sizeof (v->card)); + sprintf(v->bus_info,"PCI"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + if (v->index > 0) + return -EINVAL; - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) - return -EINVAL; - radio_bits_set(card, FREQ2BITS(f->frequency)); - return 0; -} + (void)radio_bits_get(card); -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; - f->type = V4L2_TUNER_RADIO; - f->frequency = BITS2FREQ(radio_bits_get(card)); - return 0; -} + v->rangelow = FREQ_LO; + v->rangehigh = FREQ_HI; + v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->capability=V4L2_TUNER_CAP_LOW; + if(card->stereo) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=card->tuned; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; + + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) + return -EINVAL; + radio_bits_set(card, FREQ2BITS(f->frequency)); + + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + f->type = V4L2_TUNER_RADIO; + f->frequency = BITS2FREQ(radio_bits_get(card)); - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = card->muted; - return 0; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=card->muted; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + { + register u16 io = card->io; + register u16 omask = inw(io + IO_MASK); + outw(~STR_WREN, io + IO_MASK); + outw((card->muted = ctrl->value ) ? + STR_WREN : 0, io); + udelay(4); + outw(omask, io + IO_MASK); + msleep(125); + + return (0); + } + } + return -EINVAL; + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + radio_function); } - return -EINVAL; } -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct video_device *dev = video_devdata(file); struct radio_device *card = video_get_drvdata(dev); - register u16 io = card->io; - register u16 omask = inw(io + IO_MASK); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - outw(~STR_WREN, io + IO_MASK); - outw((card->muted = ctrl->value ) ? - STR_WREN : 0, io); - udelay(4); - outw(omask, io + IO_MASK); - msleep(125); - return 0; - } - return -EINVAL; -} + int ret; -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; + mutex_lock(&card->lock); + ret = video_usercopy(inode, file, cmd, arg, radio_function); + mutex_unlock(&card->lock); - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return ret; } static u16 __devinit radio_power_on(struct radio_device *dev) @@ -354,24 +352,6 @@ static u16 __devinit radio_power_on(struct radio_device *dev) return (ofreq == radio_bits_get(dev)); } -static struct video_device maestro_radio = { - .name = "Maestro radio", - .type = VID_TYPE_TUNER, - .fops = &maestro_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - static int __devinit maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/trunk/drivers/media/radio/radio-rtrack2.c b/trunk/drivers/media/radio/radio-rtrack2.c index 9b493b3298cd..f6683872251e 100644 --- a/trunk/drivers/media/radio/radio-rtrack2.c +++ b/trunk/drivers/media/radio/radio-rtrack2.c @@ -122,26 +122,6 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq) return 0; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); - strlcpy(v->card, "RadioTrack II", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - return 0; -} - static int rt_getsigstr(struct rt_device *dev) { if (inb(io) & 2) /* bit set = no signal present */ @@ -149,136 +129,135 @@ static int rt_getsigstr(struct rt_device *dev) return 1; /* signal present */ } -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int rt_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt=dev->priv; - if (v->index > 0) - return -EINVAL; + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver)); + strlcpy(v->card, "RadioTrack II", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (88*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*rt_getsigstr(rt); - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + if (v->index > 0) + return -EINVAL; - rt->curfreq = f->frequency; - rt_setfreq(rt, rt->curfreq); - return 0; -} + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + v->rangelow=(88*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*rt_getsigstr(rt); - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (rt->muted) - ctrl->value = 0; - else - ctrl->value = 65535; - return 0; - } - return -EINVAL; -} + rt->curfreq = f->frequency; + rt_setfreq(rt, rt->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + f->type = V4L2_TUNER_RADIO; + f->frequency = rt->curfreq; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - rt_mute(rt); - else - rt_unmute(rt); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - rt_unmute(rt); - else - rt_mute(rt); - return 0; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=rt->muted; + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (rt->muted) + ctrl->value=0; + else + ctrl->value=65535; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + rt_mute(rt); + } else { + rt_unmute(rt); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + if (ctrl->value) { + rt_unmute(rt); + } else { + rt_mute(rt); + } + return (0); + } + return -EINVAL; + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + rt_do_ioctl); } - return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int rt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, rt_do_ioctl); } static struct rt_device rtrack2_unit; @@ -287,7 +266,7 @@ static const struct file_operations rtrack2_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = rt_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -299,18 +278,6 @@ static struct video_device rtrack2_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &rtrack2_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, }; static int __init rtrack2_init(void) diff --git a/trunk/drivers/media/radio/radio-sf16fmi.c b/trunk/drivers/media/radio/radio-sf16fmi.c index dc33f19c0e2c..f4619e4dda4f 100644 --- a/trunk/drivers/media/radio/radio-sf16fmi.c +++ b/trunk/drivers/media/radio/radio-sf16fmi.c @@ -130,155 +130,137 @@ static inline int fmi_getsigstr(struct fmi_device *dev) return (res & 2) ? 0 : 0xFFFF; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +static int fmi_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); - strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - int mult; struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; - - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ/mult; - v->rangehigh = RSF16_MAXFREQ/mult; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; - v->capability = fmi->flags&V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_STEREO; - v->signal = fmi_getsigstr(fmi); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} + struct fmi_device *fmi=dev->priv; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; - - if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) - f->frequency *= 1000; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ ) - return -EINVAL; - /*rounding in steps of 800 to match th freq - that will be used */ - fmi->curfreq = (f->frequency/800)*800; - fmi_setfreq(fmi); - return 0; -} + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver)); + strlcpy(v->card, "SF16-FMx radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; + int mult; + + if (v->index > 0) + return -EINVAL; + + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + + mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; + v->rangelow = RSF16_MINFREQ/mult; + v->rangehigh = RSF16_MAXFREQ/mult; + v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; + v->capability=fmi->flags&V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_STEREO; + v->signal = fmi_getsigstr(fmi); - f->type = V4L2_TUNER_RADIO; - f->frequency = fmi->curfreq; - if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) - f->frequency /= 1000; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) + f->frequency *= 1000; + if (f->frequency < RSF16_MINFREQ || + f->frequency > RSF16_MAXFREQ ) + return -EINVAL; + /*rounding in steps of 800 to match th freq + that will be used */ + fmi->curfreq = (f->frequency/800)*800; + fmi_setfreq(fmi); -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmi->curvol; - return 0; - } - return -EINVAL; -} + f->type = V4L2_TUNER_RADIO; + f->frequency = fmi->curfreq; + if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) + f->frequency /= 1000; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - fmi_mute(fmi->port); - else - fmi_unmute(fmi->port); - fmi->curvol = ctrl->value; - return 0; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=fmi->curvol; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + { + if (ctrl->value) + fmi_mute(fmi->port); + else + fmi_unmute(fmi->port); + + fmi->curvol=ctrl->value; + return (0); + } + } + return -EINVAL; + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + fmi_do_ioctl); } - return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int fmi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl); } static struct fmi_device fmi_unit; @@ -287,7 +269,7 @@ static const struct file_operations fmi_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = fmi_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -299,18 +281,6 @@ static struct video_device fmi_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &fmi_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; /* ladis: this is my card. does any other types exist? */ diff --git a/trunk/drivers/media/radio/radio-sf16fmr2.c b/trunk/drivers/media/radio/radio-sf16fmr2.c index e6c125def5cb..b96fafe1f9da 100644 --- a/trunk/drivers/media/radio/radio-sf16fmr2.c +++ b/trunk/drivers/media/radio/radio-sf16fmr2.c @@ -226,204 +226,186 @@ static int fmr2_setvolume(struct fmr2_device *dev) return 0; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); - strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - int mult; - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; - - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - - mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ/mult; - v->rangehigh = RSF16_MAXFREQ/mult; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; - v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; - v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: - V4L2_TUNER_MODE_MONO; - mutex_lock(&lock); - v->signal = fmr2_getsigstr(fmr2); - mutex_unlock(&lock); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) +static int fmr2_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct fmr2_device *fmr2 = dev->priv; + debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d " + "stereo %d type %d\n", + fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, + fmr2->stereo, fmr2->card_type)); - if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) - f->frequency *= 1000; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ ) - return -EINVAL; - /*rounding in steps of 200 to match th freq - that will be used */ - fmr2->curfreq = (f->frequency/200)*200; - - /* set card freq (if not muted) */ - if (fmr2->curvol && !fmr2->mute) { - mutex_lock(&lock); - fmr2_setfreq(fmr2); - mutex_unlock(&lock); - } - return 0; -} + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver)); + strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; + int mult; + + if (v->index > 0) + return -EINVAL; + + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + + mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; + v->rangelow = RSF16_MINFREQ/mult; + v->rangehigh = RSF16_MAXFREQ/mult; + v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; + v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW; + + v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: + V4L2_TUNER_MODE_MONO; + mutex_lock(&lock); + v->signal = fmr2_getsigstr(fmr2); + mutex_unlock(&lock); - f->type = V4L2_TUNER_RADIO; - f->frequency = fmr2->curfreq; - if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) - f->frequency /= 1000; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if ((fmr2->card_type != 11) - && V4L2_CID_AUDIO_VOLUME) - radio_qctrl[i].step = 65535; - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) + f->frequency *= 1000; + if (f->frequency < RSF16_MINFREQ || + f->frequency > RSF16_MAXFREQ ) + return -EINVAL; + /*rounding in steps of 200 to match th freq + that will be used */ + fmr2->curfreq = (f->frequency/200)*200; + + /* set card freq (if not muted) */ + if (fmr2->curvol && !fmr2->mute) + { + mutex_lock(&lock); + fmr2_setfreq(fmr2); + mutex_unlock(&lock); + } - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmr2->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = fmr2->curvol; - return 0; - } - return -EINVAL; -} + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + f->type = V4L2_TUNER_RADIO; + f->frequency = fmr2->curfreq; + if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) + f->frequency /= 1000; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - fmr2->mute = ctrl->value; - if (fmr2->card_type != 11) { - if (!fmr2->mute) - fmr2->curvol = 65535; - else - fmr2->curvol = 0; + return 0; } - break; - case V4L2_CID_AUDIO_VOLUME: - fmr2->curvol = ctrl->value; - if (fmr2->card_type != 11) { - if (fmr2->curvol) { - fmr2->curvol = 65535; - fmr2->mute = 0; - } else { - fmr2->curvol = 0; - fmr2->mute = 1; + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if ((fmr2->card_type != 11) + && V4L2_CID_AUDIO_VOLUME) + radio_qctrl[i].step=65535; + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } } + return -EINVAL; } - break; - default: - return -EINVAL; - } - + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=fmr2->mute; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=fmr2->curvol; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + fmr2->mute=ctrl->value; + if (fmr2->card_type != 11) { + if (!fmr2->mute) { + fmr2->curvol = 65535; + } else { + fmr2->curvol = 0; + } + } + break; + case V4L2_CID_AUDIO_VOLUME: + fmr2->curvol = ctrl->value; + if (fmr2->card_type != 11) { + if (fmr2->curvol) { + fmr2->curvol = 65535; + fmr2->mute = 0; + } else { + fmr2->curvol = 0; + fmr2->mute = 1; + } + } + break; + default: + return -EINVAL; + } #ifdef DEBUG - if (fmr2->curvol && !fmr2->mute) - printk(KERN_DEBUG "unmute\n"); - else - printk(KERN_DEBUG "mute\n"); + if (fmr2->curvol && !fmr2->mute) + printk(KERN_DEBUG "unmute\n"); + else + printk(KERN_DEBUG "mute\n"); #endif + mutex_lock(&lock); + if (fmr2->curvol && !fmr2->mute) { + fmr2_setvolume(fmr2); + fmr2_setfreq(fmr2); + } else + fmr2_mute(fmr2->port); + mutex_unlock(&lock); + return (0); + } + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + fmr2_do_ioctl); - mutex_lock(&lock); - if (fmr2->curvol && !fmr2->mute) { - fmr2_setvolume(fmr2); - fmr2_setfreq(fmr2); - } else - fmr2_mute(fmr2->port); - mutex_unlock(&lock); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; + } } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; +static int fmr2_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) + { + return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl); } static struct fmr2_device fmr2_unit; @@ -432,7 +414,7 @@ static const struct file_operations fmr2_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = fmr2_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -444,18 +426,6 @@ static struct video_device fmr2_radio= . type = VID_TYPE_TUNER, .hardware = 0, .fops = &fmr2_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static int __init fmr2_init(void) diff --git a/trunk/drivers/media/radio/radio-terratec.c b/trunk/drivers/media/radio/radio-terratec.c index e43acfd7e533..d59a27accb84 100644 --- a/trunk/drivers/media/radio/radio-terratec.c +++ b/trunk/drivers/media/radio/radio-terratec.c @@ -205,152 +205,135 @@ static int tt_getsigstr(struct tt_device *dev) /* TODO */ return 1; /* signal present */ } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); - strlcpy(v->card, "ActiveRadio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +/* implement the video4linux api */ + +static int tt_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt=dev->priv; - if (v->index > 0) - return -EINVAL; + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-terratec", sizeof (v->driver)); + strlcpy(v->card, "ActiveRadio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*tt_getsigstr(tt); - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} + if (v->index > 0) + return -EINVAL; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; - tt->curfreq = f->frequency; - tt_setfreq(tt, tt->curfreq); - return 0; -} + v->rangelow=(87*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*tt_getsigstr(tt); -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; - - f->type = V4L2_TUNER_RADIO; - f->frequency = tt->curfreq; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + tt->curfreq = f->frequency; + tt_setfreq(tt, tt->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (tt->muted) - ctrl->value = 1; - else - ctrl->value = 0; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = tt->curvol * 6554; - return 0; - } - return -EINVAL; -} + f->type = V4L2_TUNER_RADIO; + f->frequency = tt->curfreq; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (tt->muted) + ctrl->value=1; + else + ctrl->value=0; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=tt->curvol * 6554; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + tt_mute(tt); + } else { + tt_setvol(tt,tt->curvol); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + tt_setvol(tt,ctrl->value); + return (0); + } + return -EINVAL; + } - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - tt_mute(tt); - else - tt_setvol(tt,tt->curvol); - return 0; - case V4L2_CID_AUDIO_VOLUME: - tt_setvol(tt,ctrl->value); - return 0; + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + tt_do_ioctl); } - return -EINVAL; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; } -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +static int tt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, tt_do_ioctl); } static struct tt_device terratec_unit; @@ -359,7 +342,7 @@ static const struct file_operations terratec_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = tt_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -371,18 +354,6 @@ static struct video_device terratec_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &terratec_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, }; static int __init terratec_init(void) diff --git a/trunk/drivers/media/radio/radio-trust.c b/trunk/drivers/media/radio/radio-trust.c index c27c629d99df..6d7f1e7116ea 100644 --- a/trunk/drivers/media/radio/radio-trust.c +++ b/trunk/drivers/media/radio/radio-trust.c @@ -192,154 +192,144 @@ static void tr_setfreq(unsigned long f) write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +static int tr_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - strlcpy(v->driver, "radio-trust", sizeof(v->driver)); - strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; + switch(cmd) + { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-trust", sizeof (v->driver)); + strlcpy(v->card, "Trust FM Radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (87.5*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (tr_getstereo()) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = tr_getsigstr(); - return 0; -} + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; + + if (v->index > 0) + return -EINVAL; + + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + + v->rangelow=(87.5*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->capability=V4L2_TUNER_CAP_LOW; + if(tr_getstereo()) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=tr_getsigstr(); -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; - return 0; -} + if (v->index > 0) + return -EINVAL; -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - curfreq = f->frequency; - tr_setfreq(curfreq); - return 0; -} + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - f->type = V4L2_TUNER_RADIO; - f->frequency = curfreq; - return 0; -} + curfreq = f->frequency; + tr_setfreq(curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + f->type = V4L2_TUNER_RADIO; + f->frequency = curfreq; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = curmute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = curvol * 2048; - return 0; - case V4L2_CID_AUDIO_BASS: - ctrl->value = curbass * 4370; - return 0; - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = curtreble * 4370; - return 0; - } - return -EINVAL; -} + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=curmute; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value= curvol * 2048; + return (0); + case V4L2_CID_AUDIO_BASS: + ctrl->value= curbass * 4370; + return (0); + case V4L2_CID_AUDIO_TREBLE: + ctrl->value= curtreble * 4370; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + tr_setmute(ctrl->value); + return 0; + case V4L2_CID_AUDIO_VOLUME: + tr_setvol(ctrl->value); + return 0; + case V4L2_CID_AUDIO_BASS: + tr_setbass(ctrl->value); + return 0; + case V4L2_CID_AUDIO_TREBLE: + tr_settreble(ctrl->value); + return (0); + } + return -EINVAL; + } -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tr_setmute(ctrl->value); - return 0; - case V4L2_CID_AUDIO_VOLUME: - tr_setvol(ctrl->value); - return 0; - case V4L2_CID_AUDIO_BASS: - tr_setbass(ctrl->value); - return 0; - case V4L2_CID_AUDIO_TREBLE: - tr_settreble(ctrl->value); - return 0; + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + tr_do_ioctl); } - return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int tr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, tr_do_ioctl); } static const struct file_operations trust_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = tr_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -351,18 +341,6 @@ static struct video_device trust_radio= .type = VID_TYPE_TUNER, .hardware = 0, .fops = &trust_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, }; static int __init trust_init(void) diff --git a/trunk/drivers/media/radio/radio-typhoon.c b/trunk/drivers/media/radio/radio-typhoon.c index 8ff5a23a9f01..3031fef178cb 100644 --- a/trunk/drivers/media/radio/radio-typhoon.c +++ b/trunk/drivers/media/radio/radio-typhoon.c @@ -93,6 +93,8 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); static void typhoon_mute(struct typhoon_device *dev); static void typhoon_unmute(struct typhoon_device *dev); static int typhoon_setvol(struct typhoon_device *dev, int vol); +static int typhoon_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); #ifdef CONFIG_RADIO_TYPHOON_PROC_FS static int typhoon_get_info(char *buf, char **start, off_t offset, int len); #endif @@ -184,148 +186,129 @@ static int typhoon_setvol(struct typhoon_device *dev, int vol) return 0; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); - strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (87.5*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF; /* We can't get the signal strength */ - return 0; -} -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) +static int typhoon_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct typhoon_device *typhoon = dev->priv; - typhoon->curfreq = f->frequency; - typhoon_setfreq(typhoon, typhoon->curfreq); - return 0; -} + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-typhoon", sizeof (v->driver)); + strlcpy(v->card, "Typhoon Radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; - f->type = V4L2_TUNER_RADIO; - f->frequency = typhoon->curfreq; + if (v->index > 0) + return -EINVAL; - return 0; -} + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + v->rangelow=(87.5*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO; + v->capability=V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF; /* We can't get the signal strength */ - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + if (v->index > 0) + return -EINVAL; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = typhoon->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = typhoon->curvol; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - typhoon_mute(typhoon); - else - typhoon_unmute(typhoon); - return 0; - case V4L2_CID_AUDIO_VOLUME: - typhoon_setvol(typhoon, ctrl->value); - return 0; - } - return -EINVAL; -} + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; + typhoon->curfreq = f->frequency; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} + f->type = V4L2_TUNER_RADIO; + f->frequency = typhoon->curfreq; -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=typhoon->muted; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=typhoon->curvol; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + typhoon_mute(typhoon); + } else { + typhoon_unmute(typhoon); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + typhoon_setvol(typhoon, ctrl->value); + return (0); + } + return -EINVAL; + } -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + typhoon_do_ioctl); + } } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int typhoon_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, typhoon_do_ioctl); } static struct typhoon_device typhoon_unit = @@ -339,7 +322,7 @@ static const struct file_operations typhoon_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = typhoon_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -351,18 +334,6 @@ static struct video_device typhoon_radio = .type = VID_TYPE_TUNER, .hardware = 0, .fops = &typhoon_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; #ifdef CONFIG_RADIO_TYPHOON_PROC_FS diff --git a/trunk/drivers/media/radio/radio-zoltrix.c b/trunk/drivers/media/radio/radio-zoltrix.c index a4715901512d..ec08491fb7c5 100644 --- a/trunk/drivers/media/radio/radio-zoltrix.c +++ b/trunk/drivers/media/radio/radio-zoltrix.c @@ -230,123 +230,121 @@ static int zol_is_stereo (struct zol_device *dev) return 0; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); - strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int zol_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct zol_device *zol = dev->priv; - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = (88*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (zol_is_stereo(zol)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*zol_getsigstr(zol); - return 0; -} + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *v = arg; + memset(v,0,sizeof(*v)); + strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver)); + strlcpy(v->card, "Zoltrix Radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; - - zol->curfreq = f->frequency; - zol_setfreq(zol, zol->curfreq); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *v = arg; + + if (v->index > 0) + return -EINVAL; + + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + + v->rangelow=(88*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->capability=V4L2_TUNER_CAP_LOW; + if(zol_is_stereo(zol)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*zol_getsigstr(zol); - f->type = V4L2_TUNER_RADIO; - f->frequency = zol->curfreq; - return 0; -} + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *v = arg; -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if (v->index > 0) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); return 0; } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = zol->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = zol->curvol * 4096; - return 0; - } - return -EINVAL; -} + zol->curfreq = f->frequency; + zol_setfreq(zol, zol->curfreq); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + f->type = V4L2_TUNER_RADIO; + f->frequency = zol->curfreq; - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - zol_mute(zol); - else { - zol_unmute(zol); - zol_setvol(zol,zol->curvol); + return 0; } - return 0; - case V4L2_CID_AUDIO_VOLUME: - zol_setvol(zol,ctrl->value/4096); - return 0; - } - zol->stereo = 1; - zol_setfreq(zol, zol->curfreq); + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); + } + } + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=zol->muted; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=zol->curvol * 4096; + return (0); + } + return -EINVAL; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl= arg; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + zol_mute(zol); + } else { + zol_unmute(zol); + zol_setvol(zol,zol->curvol); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + zol_setvol(zol,ctrl->value/4096); + return (0); + } + zol->stereo = 1; + zol_setfreq(zol, zol->curfreq); #if 0 /* FIXME: Implement stereo/mono switch on V4L2 */ if (v->mode & VIDEO_SOUND_STEREO) { @@ -358,39 +356,19 @@ static int vidioc_s_ctrl(struct file *file, void *priv, zol_setfreq(zol, zol->curfreq); } #endif - return -EINVAL; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} + return -EINVAL; + } -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + zol_do_ioctl); + } } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int zol_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - if (a->index != 0) - return -EINVAL; - return 0; + return video_usercopy(inode, file, cmd, arg, zol_do_ioctl); } static struct zol_device zoltrix_unit; @@ -400,7 +378,7 @@ static const struct file_operations zoltrix_fops = .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = video_ioctl2, + .ioctl = zol_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -412,18 +390,6 @@ static struct video_device zoltrix_radio = .type = VID_TYPE_TUNER, .hardware = 0, .fops = &zoltrix_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static int __init zoltrix_init(void) diff --git a/trunk/drivers/media/video/Kconfig b/trunk/drivers/media/video/Kconfig index bc773781993a..7a6105153f23 100644 --- a/trunk/drivers/media/video/Kconfig +++ b/trunk/drivers/media/video/Kconfig @@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" - depends on PCI && SONY_LAPTOP && VIDEO_V4L1 + depends on PCI && SONYPI && VIDEO_V4L1 ---help--- This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in for more information. - If you say Y or M here, you need to say Y or M to "Sony Laptop - Extras" in the misc device section. + If you say Y or M here, you need to say Y or M to "Sony Programmable + I/O Control Device" in the character device section. To compile this driver as a module, choose M here: the module will be called meye. @@ -647,8 +647,6 @@ config VIDEO_HEXIUM_GEMINI source "drivers/media/video/cx88/Kconfig" -source "drivers/media/video/ivtv/Kconfig" - config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 @@ -763,18 +761,6 @@ source "drivers/media/video/zc0301/Kconfig" source "drivers/media/video/pwc/Kconfig" -config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. - See for more info - and list of supported cameras. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - endmenu # V4L USB devices endmenu diff --git a/trunk/drivers/media/video/Makefile b/trunk/drivers/media/video/Makefile index 9c2de501612f..44ccaed40b49 100644 --- a/trunk/drivers/media/video/Makefile +++ b/trunk/drivers/media/video/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o @@ -100,7 +99,6 @@ obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o -obj-$(CONFIG_USB_ZR364XX) += zr364xx.o obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_USB_ET61X251) += et61x251/ diff --git a/trunk/drivers/media/video/adv7170.c b/trunk/drivers/media/video/adv7170.c index 823cd6cc471e..2aa9ce920607 100644 --- a/trunk/drivers/media/video/adv7170.c +++ b/trunk/drivers/media/video/adv7170.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/adv7175.c b/trunk/drivers/media/video/adv7175.c index 05c7820fe53e..a3246a283aa4 100644 --- a/trunk/drivers/media/video/adv7175.c +++ b/trunk/drivers/media/video/adv7175.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/bt819.c b/trunk/drivers/media/video/bt819.c index 59a43603b5cb..68673863d5c9 100644 --- a/trunk/drivers/media/video/bt819.c +++ b/trunk/drivers/media/video/bt819.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/bt856.c b/trunk/drivers/media/video/bt856.c index 853b1a3d6a1d..42e2299dcb22 100644 --- a/trunk/drivers/media/video/bt856.c +++ b/trunk/drivers/media/video/bt856.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/bt866.c b/trunk/drivers/media/video/bt866.c index 2e4cf1efdd21..772fd52d551a 100644 --- a/trunk/drivers/media/video/bt866.c +++ b/trunk/drivers/media/video/bt866.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/bt8xx/bttv-cards.c b/trunk/drivers/media/video/bt8xx/bttv-cards.c index 6b31e50fb951..6addc42df045 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-cards.c +++ b/trunk/drivers/media/video/bt8xx/bttv-cards.c @@ -291,9 +291,6 @@ static struct CARD { { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, - { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, - { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, - /* likely broken, vendor id doesn't match the other magic views ... * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ @@ -2910,28 +2907,6 @@ struct tvcard bttv_tvcards[] = { .has_radio = 1, .has_remote = 1, }, - [BTTV_BOARD_SSAI_SECURITY] = { - .name = "SSAI Security Video Interface", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .muxsel = { 0, 1, 2, 3 }, - .tuner_type = -1, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - }, - [BTTV_BOARD_SSAI_ULTRASOUND] = { - .name = "SSAI Ultrasound Video Interface", - .video_inputs = 2, - .audio_inputs = 0, - .tuner = -1, - .svhs = 1, - .muxsel = { 2, 0, 1, 3 }, - .tuner_type = -1, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2995,20 +2970,20 @@ void __devinit bttv_idcard(struct bttv *btv) if (UNSET != audiomux[0]) { gpiobits = 0; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + for (i = 0; i < 4; i++) { bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; gpiobits |= audiomux[i]; } } else { gpiobits = audioall; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + for (i = 0; i < 4; i++) { bttv_tvcards[btv->c.type].gpiomux[i] = audioall; } } bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + for (i = 0; i < 5; i++) { printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); } printk("\n"); @@ -3663,7 +3638,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) for (n = 0; n < microlen; n++) { bits = micro[n]; - for (i = 0 ; i < 8 ; i++) { + for ( i = 0 ; i < 8 ; i++ ) { gpio_bits(BTTV_ALT_DCLK,0); if (bits & 0x01) gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); @@ -3716,7 +3691,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) /* this might be an antique... check for MMAC label in eeprom */ if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { unsigned char checksum = 0; - for (i = 0; i < 21; i++) + for (i =0; i<21; i++) checksum += ee[i]; if (checksum != ee[21]) return; @@ -3728,13 +3703,12 @@ static void __devinit osprey_eeprom(struct bttv *btv) unsigned short type; int offset = 4*16; - for (; offset < 8*16; offset += 16) { + for(; offset < 8*16; offset += 16) { unsigned short checksum = 0; /* verify the checksum */ - for (i = 0; i < 14; i++) - checksum += ee[i+offset]; - checksum = ~checksum; /* no idea why */ - if ((((checksum>>8)&0x0FF) == ee[offset+14]) && + for(i = 0; i<14; i++) checksum += ee[i+offset]; + checksum = ~checksum; /* no idea why */ + if ((((checksum>>8)&0x0FF) == ee[offset+14]) && ((checksum & 0x0FF) == ee[offset+15])) { break; } @@ -3747,6 +3721,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) type = (ee[offset+4]<<8) | (ee[offset+5]); switch(type) { + /* 848 based */ case 0x0004: btv->c.type = BTTV_BOARD_OSPREY1x0_848; @@ -4174,7 +4149,8 @@ static int tea5757_read(struct bttv *btv) } dprintk("bttv%d: tea5757:",btv->c.nr); - for (i = 0; i < 24; i++) { + for(i = 0; i < 24; i++) + { udelay(5); bus_high(btv,btv->mbox_clk); udelay(5); @@ -4206,7 +4182,8 @@ static int tea5757_write(struct bttv *btv, int value) dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); bus_low(btv,btv->mbox_clk); bus_high(btv,btv->mbox_we); - for (i = 0; i < 25; i++) { + for(i = 0; i < 25; i++) + { if (reg & 0x1000000) bus_high(btv,btv->mbox_data); else @@ -4778,7 +4755,7 @@ static void kodicom4400r_init(struct bttv *btv) gpio_write(1 << 9); /* reset MUX */ gpio_write(0); /* Preset camera 0 to the 4 controllers */ - for (ix = 0; ix < 4; ix++) { + for (ix=0; ix<4; ix++) { sw_status[ix] = ix; kodicom4400r_write(btv, ix, ix, 1); } diff --git a/trunk/drivers/media/video/bt8xx/bttv-driver.c b/trunk/drivers/media/video/bt8xx/bttv-driver.c index 1c38723d3169..5720b77ac9a7 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-driver.c +++ b/trunk/drivers/media/video/bt8xx/bttv-driver.c @@ -163,24 +163,6 @@ static ssize_t show_card(struct class_device *cd, char *buf) } static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); -/* ----------------------------------------------------------------------- */ -/* dvb auto-load setup */ -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - request_module("dvb-bt8xx"); -} - -static void request_modules(struct bttv *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#endif /* CONFIG_MODULES */ - - /* ----------------------------------------------------------------------- */ /* static data */ @@ -4787,11 +4769,9 @@ static int __devinit bttv_probe(struct pci_dev *dev, disclaim_video_lines(btv); } - /* add subdevices and autoload dvb-bt8xx if needed */ - if (bttv_tvcards[btv->c.type].has_dvb) { + /* add subdevices */ + if (bttv_tvcards[btv->c.type].has_dvb) bttv_sub_add_device(&btv->c, "dvb"); - request_modules(btv); - } bttv_input_init(btv); diff --git a/trunk/drivers/media/video/bt8xx/bttv-gpio.c b/trunk/drivers/media/video/bt8xx/bttv-gpio.c index 84154c26f9c5..ba081f6f8c82 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-gpio.c +++ b/trunk/drivers/media/video/bt8xx/bttv-gpio.c @@ -71,6 +71,7 @@ struct bus_type bttv_sub_bus_type = { .probe = bttv_sub_probe, .remove = bttv_sub_remove, }; +EXPORT_SYMBOL(bttv_sub_bus_type); static void release_sub_device(struct device *dev) { @@ -151,6 +152,7 @@ void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) btwrite(data,BT848_GPIO_OUT_EN); spin_unlock_irqrestore(&btv->gpio_lock,flags); } +EXPORT_SYMBOL(bttv_gpio_inout); u32 bttv_gpio_read(struct bttv_core *core) { @@ -160,6 +162,7 @@ u32 bttv_gpio_read(struct bttv_core *core) value = btread(BT848_GPIO_DATA); return value; } +EXPORT_SYMBOL(bttv_gpio_read); void bttv_gpio_write(struct bttv_core *core, u32 value) { @@ -167,6 +170,7 @@ void bttv_gpio_write(struct bttv_core *core, u32 value) btwrite(value,BT848_GPIO_DATA); } +EXPORT_SYMBOL(bttv_gpio_write); void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) { @@ -181,6 +185,7 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) btwrite(data,BT848_GPIO_DATA); spin_unlock_irqrestore(&btv->gpio_lock,flags); } +EXPORT_SYMBOL(bttv_gpio_bits); /* * Local variables: diff --git a/trunk/drivers/media/video/bt8xx/bttv-i2c.c b/trunk/drivers/media/video/bt8xx/bttv-i2c.c index 0dfa49b66418..62b873076e09 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-i2c.c +++ b/trunk/drivers/media/video/bt8xx/bttv-i2c.c @@ -412,7 +412,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + for (i = 0; i < 128; i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/trunk/drivers/media/video/bt8xx/bttv-if.c b/trunk/drivers/media/video/bt8xx/bttv-if.c index ecf07988cd33..19b564ab0e92 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-if.c +++ b/trunk/drivers/media/video/bt8xx/bttv-if.c @@ -33,16 +33,32 @@ #include "bttvp.h" +EXPORT_SYMBOL(bttv_get_cardinfo); EXPORT_SYMBOL(bttv_get_pcidev); +EXPORT_SYMBOL(bttv_get_id); EXPORT_SYMBOL(bttv_gpio_enable); EXPORT_SYMBOL(bttv_read_gpio); EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); +EXPORT_SYMBOL(bttv_i2c_call); /* ----------------------------------------------------------------------- */ /* Exported functions - for other modules which want to access the */ /* gpio ports (IR for example) */ /* see bttv.h for comments */ +int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid) +{ + printk("The bttv_* interface is obsolete and will go away,\n" + "please use the new, sysfs based interface instead.\n"); + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].c.type; + *cardid = bttvs[card].cardid; + return 0; +} + struct pci_dev* bttv_get_pcidev(unsigned int card) { if (card >= bttv_num) @@ -50,6 +66,16 @@ struct pci_dev* bttv_get_pcidev(unsigned int card) return bttvs[card].c.pci; } +int bttv_get_id(unsigned int card) +{ + printk("The bttv_* interface is obsolete and will go away,\n" + "please use the new, sysfs based interface instead.\n"); + if (card >= bttv_num) { + return -1; + } + return bttvs[card].c.type; +} + int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) { @@ -104,6 +130,28 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) return 0; } +wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + if (bttvs[card].shutdown) { + return NULL; + } + return &btv->gpioq; +} + +void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) +{ + if (card >= bttv_num) + return; + bttv_call_i2c_clients(&bttvs[card], cmd, arg); +} + /* * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/bt8xx/bttv.h b/trunk/drivers/media/video/bt8xx/bttv.h index f821ba69db99..5491acbdaf63 100644 --- a/trunk/drivers/media/video/bt8xx/bttv.h +++ b/trunk/drivers/media/video/bt8xx/bttv.h @@ -168,8 +168,6 @@ #define BTTV_BOARD_SABRENT_TVFM 0x8e #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f #define BTTV_BOARD_MACHTV_MAGICTV 0x90 -#define BTTV_BOARD_SSAI_SECURITY 0x91 -#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 @@ -262,8 +260,17 @@ extern int bttv_handle_chipset(struct bttv *btv); /* this obsolete -- please use the sysfs-based interface below for new code */ +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN + returns negative value if error occurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); extern struct pci_dev* bttv_get_pcidev(unsigned int card); +/* obsolete, use bttv_get_cardinfo instead */ +extern int bttv_get_id(unsigned int card); + /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: data | (current_GPOE_value & ~mask) returns negative value if error occurred @@ -283,6 +290,20 @@ extern int bttv_read_gpio(unsigned int card, unsigned long *data); extern int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data); +/* returns pointer to task queue which can be used as parameter to + interruptible_sleep_on + in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated + (wake_up_interruptible) and following call to the function bttv_read_gpio + should return new value of GPDATA, + returns NULL value if error occurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); diff --git a/trunk/drivers/media/video/bt8xx/bttvp.h b/trunk/drivers/media/video/bt8xx/bttvp.h index 8f44f02029be..ad79b8d53430 100644 --- a/trunk/drivers/media/video/bt8xx/bttvp.h +++ b/trunk/drivers/media/video/bt8xx/bttvp.h @@ -434,9 +434,6 @@ struct bttv { unsigned int users; struct bttv_fh init; - /* used to make dvb-bt8xx autoloadable */ - struct work_struct request_module_wk; - /* Default (0) and current (1) video capturing and overlay cropping parameters in bttv_tvnorm.cropcap units. Protected by bttv.lock. */ diff --git a/trunk/drivers/media/video/cafe_ccic.c b/trunk/drivers/media/video/cafe_ccic.c index 96254dbaf625..710c11a68296 100644 --- a/trunk/drivers/media/video/cafe_ccic.c +++ b/trunk/drivers/media/video/cafe_ccic.c @@ -4,7 +4,6 @@ * sensor. * * Copyright 2006 One Laptop Per Child Association, Inc. - * Copyright 2006-7 Jonathan Corbet * * Written by Jonathan Corbet, corbet@lwn.net. * @@ -23,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -38,7 +36,7 @@ #include "cafe_ccic-regs.h" -#define CAFE_VERSION 0x000002 +#define CAFE_VERSION 0x000001 /* @@ -166,7 +164,7 @@ struct cafe_camera struct tasklet_struct s_tasklet; /* Current operating parameters */ - u32 sensor_type; /* Currently ov7670 only */ + enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */ struct v4l2_pix_format pix_format; /* Locks */ @@ -706,13 +704,7 @@ static void cafe_ctlr_init(struct cafe_camera *cam) cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); - /* - * Here we must wait a bit for the controller to come around. - */ - spin_unlock_irqrestore(&cam->dev_lock, flags); mdelay(5); /* FIXME revisit this */ - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); /* @@ -780,9 +772,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) * Control 1 is power down, set to 0 to operate. */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ -// mdelay(1); /* Marvell says 1ms will do it */ + mdelay(1); /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); -// mdelay(1); /* Enough? */ + mdelay(1); /* Enough? */ spin_unlock_irqrestore(&cam->dev_lock, flags); } @@ -826,7 +818,6 @@ static int __cafe_cam_reset(struct cafe_camera *cam) */ static int cafe_cam_init(struct cafe_camera *cam) { - struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 }; int ret; mutex_lock(&cam->s_mutex); @@ -836,11 +827,9 @@ static int cafe_cam_init(struct cafe_camera *cam) ret = __cafe_cam_reset(cam); if (ret) goto out; - chip.match_chip = cam->sensor->addr; - ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip); + ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type); if (ret) goto out; - cam->sensor_type = chip.ident; // if (cam->sensor->addr != OV7xx0_SID) { if (cam->sensor_type != V4L2_IDENT_OV7670) { cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); @@ -1803,19 +1792,18 @@ static void cafe_frame_tasklet(unsigned long data) if (list_empty(&cam->sb_avail)) break; /* Leave it valid, hope for better later */ clear_bit(bufno, &cam->flags); - sbuf = list_entry(cam->sb_avail.next, - struct cafe_sio_buffer, list); /* - * Drop the lock during the big copy. This *should* be safe... + * We could perhaps drop the spinlock during this + * big copy. Something to consider. */ - spin_unlock_irqrestore(&cam->dev_lock, flags); + sbuf = list_entry(cam->sb_avail.next, + struct cafe_sio_buffer, list); memcpy(sbuf->buffer, cam->dma_bufs[bufno], cam->pix_format.sizeimage); sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&cam->dev_lock, flags); list_move_tail(&sbuf->list, &cam->sb_full); } if (! list_empty(&cam->sb_full)) @@ -2119,7 +2107,6 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam->v4ldev = cafe_v4l_template; cam->v4ldev.debug = 0; // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; - cam->v4ldev.dev = &pdev->dev; ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); if (ret) goto out_smbus; @@ -2189,52 +2176,10 @@ static void cafe_pci_remove(struct pci_dev *pdev) } -#ifdef CONFIG_PM -/* - * Basic power management. - */ -static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct cafe_camera *cam = cafe_find_by_pdev(pdev); - int ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - pci_disable_device(pdev); - return 0; -} - - -static int cafe_pci_resume(struct pci_dev *pdev) -{ - struct cafe_camera *cam = cafe_find_by_pdev(pdev); - int ret = 0; - - ret = pci_restore_state(pdev); - if (ret) - return ret; - ret = pci_enable_device(pdev); - if (ret) { - cam_warn(cam, "Unable to re-enable device on resume!\n"); - return ret; - } - cafe_ctlr_init(cam); - cafe_ctlr_power_up(cam); - set_bit(CF_CONFIG_NEEDED, &cam->flags); - if (cam->state == S_SPECREAD) - cam->state = S_IDLE; /* Don't bother restarting */ - else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) - ret = cafe_read_setup(cam, cam->state); - return ret; -} - -#endif /* CONFIG_PM */ static struct pci_device_id cafe_ids[] = { + { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ { 0, } @@ -2247,10 +2192,6 @@ static struct pci_driver cafe_pci_driver = { .id_table = cafe_ids, .probe = cafe_pci_probe, .remove = cafe_pci_remove, -#ifdef CONFIG_PM - .suspend = cafe_pci_suspend, - .resume = cafe_pci_resume, -#endif }; diff --git a/trunk/drivers/media/video/cpia_pp.c b/trunk/drivers/media/video/cpia_pp.c index 19711aaf9a3e..b12cec94f4cc 100644 --- a/trunk/drivers/media/video/cpia_pp.c +++ b/trunk/drivers/media/video/cpia_pp.c @@ -62,6 +62,7 @@ static int cpia_pp_close(void *privdata); #define PPCPIA_PARPORT_OFF -2 #define PPCPIA_PARPORT_NONE -1 +#ifdef MODULE static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; static char *parport[PARPORT_MAX] = {NULL,}; @@ -71,6 +72,11 @@ MODULE_LICENSE("GPL"); module_param_array(parport, charp, NULL, 0); MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); +#else +static int parport_nr[PARPORT_MAX] __initdata = + {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; +static int parport_ptr = 0; +#endif struct pp_cam_entry { struct pardevice *pdev; @@ -135,6 +141,7 @@ static void cpia_pp_run_callback(struct work_struct *work) cam = container_of(work, struct pp_cam_entry, cb_task); cb_func = cam->cb_func; cb_data = cam->cb_data; + work_release(work); cb_func(cb_data); } @@ -675,7 +682,7 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo if(cam->port->irq != PARPORT_IRQ_NONE) { cam->cb_func = cb; cam->cb_data = cbdata; - INIT_WORK(&cam->cb_task, cpia_pp_run_callback); + INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); } else { retval = -1; } @@ -813,7 +820,7 @@ static struct parport_driver cpia_pp_driver = { .detach = cpia_pp_detach, }; -static int __init cpia_pp_init(void) +static int cpia_pp_init(void) { printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); @@ -832,7 +839,8 @@ static int __init cpia_pp_init(void) return 0; } -static int __init cpia_init(void) +#ifdef MODULE +int init_module(void) { if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ @@ -859,11 +867,38 @@ static int __init cpia_init(void) return cpia_pp_init(); } -static void __exit cpia_cleanup(void) +void cleanup_module(void) { - parport_unregister_driver(&cpia_pp_driver); + parport_unregister_driver (&cpia_pp_driver); return; } -module_init(cpia_init); -module_exit(cpia_cleanup); +#else /* !MODULE */ + +static int __init cpia_pp_setup(char *str) +{ + int err; + + if (!strncmp(str, "parport", 7)) { + int n = simple_strtoul(str + 7, NULL, 10); + if (parport_ptr < PARPORT_MAX) { + parport_nr[parport_ptr++] = n; + } else { + LOG("too many ports, %s ignored.\n", str); + } + } else if (!strcmp(str, "auto")) { + parport_nr[0] = PPCPIA_PARPORT_AUTO; + } else if (!strcmp(str, "none")) { + parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; + } + + err=cpia_pp_init(); + if (err) + return err; + + return 1; +} + +__setup("cpia_pp=", cpia_pp_setup); + +#endif /* !MODULE */ diff --git a/trunk/drivers/media/video/cs53l32a.c b/trunk/drivers/media/video/cs53l32a.c index a73e285af730..de87247c74ee 100644 --- a/trunk/drivers/media/video/cs53l32a.c +++ b/trunk/drivers/media/video/cs53l32a.c @@ -28,7 +28,6 @@ #include #include #include -#include MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); @@ -104,9 +103,6 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, cs53l32a_write(client, 0x05, (u8) ctrl->value); break; - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); - case VIDIOC_LOG_STATUS: { u8 v = cs53l32a_read(client, 0x01); diff --git a/trunk/drivers/media/video/cx2341x.c b/trunk/drivers/media/video/cx2341x.c index d73c86aeeaac..d60cd5ecf821 100644 --- a/trunk/drivers/media/video/cx2341x.c +++ b/trunk/drivers/media/video/cx2341x.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -50,7 +51,6 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, V4L2_CID_MPEG_AUDIO_EMPHASIS, V4L2_CID_MPEG_AUDIO_CRC, - V4L2_CID_MPEG_AUDIO_MUTE, V4L2_CID_MPEG_VIDEO_ENCODING, V4L2_CID_MPEG_VIDEO_ASPECT, V4L2_CID_MPEG_VIDEO_B_FRAMES, @@ -60,8 +60,6 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_VIDEO_BITRATE, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, - V4L2_CID_MPEG_VIDEO_MUTE, - V4L2_CID_MPEG_VIDEO_MUTE_YUV, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, @@ -73,7 +71,6 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, - V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, 0 }; @@ -105,9 +102,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_AUDIO_CRC: ctrl->value = params->audio_crc; break; - case V4L2_CID_MPEG_AUDIO_MUTE: - ctrl->value = params->audio_mute; - break; case V4L2_CID_MPEG_VIDEO_ENCODING: ctrl->value = params->video_encoding; break; @@ -135,12 +129,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: ctrl->value = params->video_temporal_decimation; break; - case V4L2_CID_MPEG_VIDEO_MUTE: - ctrl->value = params->video_mute; - break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: - ctrl->value = params->video_mute_yuv; - break; case V4L2_CID_MPEG_STREAM_TYPE: ctrl->value = params->stream_type; break; @@ -180,9 +168,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: ctrl->value = params->video_chroma_median_filter_bottom; break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - ctrl->value = params->stream_insert_nav_packets; - break; default: return -EINVAL; } @@ -216,9 +201,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_AUDIO_CRC: params->audio_crc = ctrl->value; break; - case V4L2_CID_MPEG_AUDIO_MUTE: - params->audio_mute = ctrl->value; - break; case V4L2_CID_MPEG_VIDEO_ASPECT: params->video_aspect = ctrl->value; break; @@ -261,12 +243,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: params->video_temporal_decimation = ctrl->value; break; - case V4L2_CID_MPEG_VIDEO_MUTE: - params->video_mute = (ctrl->value != 0); - break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: - params->video_mute_yuv = ctrl->value; - break; case V4L2_CID_MPEG_STREAM_TYPE: params->stream_type = ctrl->value; params->video_encoding = @@ -314,9 +290,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: params->video_chroma_median_filter_bottom = ctrl->value; break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - params->stream_insert_nav_packets = ctrl->value; - break; default: return -EINVAL; } @@ -363,9 +336,6 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: name = "Median Chroma Filter Minimum"; break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - name = "Insert Navigation Packets"; - break; default: return v4l2_ctrl_query_fill(qctrl, min, max, step, def); @@ -380,12 +350,6 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma min = 0; step = 1; break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; - min = 0; - max = 1; - step = 1; - break; default: qctrl->type = V4L2_CTRL_TYPE_INTEGER; break; @@ -541,9 +505,6 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0); - default: return v4l2_ctrl_query_fill_std(qctrl); @@ -695,7 +656,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) /* stream */ .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, - .stream_insert_nav_packets = 0, /* audio */ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, @@ -705,7 +665,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, - .audio_mute = 0, /* video */ .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, @@ -717,8 +676,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .video_bitrate = 6000000, .video_bitrate_peak = 8000000, .video_temporal_decimation = 0, - .video_mute = 0, - .video_mute_yuv = 0x008080, /* YCbCr value for black */ /* encoding filters */ .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, @@ -822,10 +779,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); if (err) return err; } - if (old == NULL || old->audio_mute != new->audio_mute) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); - if (err) return err; - } if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || old->video_bitrate != new->video_bitrate || old->video_bitrate_peak != new->video_bitrate_peak) { @@ -873,15 +826,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, new->video_temporal_decimation); if (err) return err; } - if (old == NULL || old->video_mute != new->video_mute || - (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); - if (err) return err; - } - if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { - err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); - if (err) return err; - } return 0; } @@ -910,22 +854,18 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) int temporal = p->video_temporal_filter; /* Stream */ - printk(KERN_INFO "%s: Stream: %s", + printk(KERN_INFO "%s: Stream: %s\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); - if (p->stream_insert_nav_packets) - printk(" (with navigation packets)"); - printk("\n"); printk(KERN_INFO "%s: VBI Format: %s\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); /* Video */ - printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", + printk(KERN_INFO "%s: Video: %dx%d, %d fps\n", prefix, p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), - p->is_50hz ? 25 : 30, - (p->video_mute) ? " (muted)" : ""); + p->is_50hz ? 25 : 30); printk(KERN_INFO "%s: Video: %s, %s, %s, %d", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), @@ -946,13 +886,12 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) } /* Audio */ - printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", + printk(KERN_INFO "%s: Audio: %s, %s, %s, %s", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), - p->audio_mute ? " (muted)" : ""); + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE)); if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { printk(", %s", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); diff --git a/trunk/drivers/media/video/cx25840/cx25840-core.c b/trunk/drivers/media/video/cx25840/cx25840-core.c index 1757a588970f..774d2536555b 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-core.c +++ b/trunk/drivers/media/video/cx25840/cx25840-core.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "cx25840-core.h" @@ -828,8 +827,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, cx25840_initialize(client, 0); break; - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev); + case VIDIOC_INT_G_CHIP_IDENT: + *(enum v4l2_chip_ident *)arg = state->id; + break; default: return -EINVAL; @@ -847,7 +847,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, { struct i2c_client *client; struct cx25840_state *state; - u32 id; + enum v4l2_chip_ident id; u16 device_id; /* Check if the adapter supports the needed features @@ -902,7 +902,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audmode = V4L2_TUNER_MODE_LANG1; state->vbi_line_offset = 8; state->id = id; - state->rev = device_id; i2c_attach_client(client); diff --git a/trunk/drivers/media/video/cx25840/cx25840-core.h b/trunk/drivers/media/video/cx25840/cx25840-core.h index f4b56d2fd6b6..28049064dd7d 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-core.h +++ b/trunk/drivers/media/video/cx25840/cx25840-core.h @@ -43,8 +43,7 @@ struct cx25840_state { u32 audclk_freq; int audmode; int vbi_line_offset; - u32 id; - u32 rev; + enum v4l2_chip_ident id; int is_cx25836; }; diff --git a/trunk/drivers/media/video/cx25840/cx25840-firmware.c b/trunk/drivers/media/video/cx25840/cx25840-firmware.c index e852024a5ea3..0e86b9d033ac 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-firmware.c +++ b/trunk/drivers/media/video/cx25840/cx25840-firmware.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/cx88/Kconfig b/trunk/drivers/media/video/cx88/Kconfig index 0f9d96963618..b2a66ba625f9 100644 --- a/trunk/drivers/media/video/cx88/Kconfig +++ b/trunk/drivers/media/video/cx88/Kconfig @@ -53,6 +53,7 @@ config VIDEO_CX88_DVB select DVB_OR51132 if !DVB_FE_CUSTOMISE select DVB_CX22702 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE diff --git a/trunk/drivers/media/video/cx88/cx88-alsa.c b/trunk/drivers/media/video/cx88/cx88-alsa.c index 3956c257556c..e4355fdc3b6d 100644 --- a/trunk/drivers/media/video/cx88/cx88-alsa.c +++ b/trunk/drivers/media/video/cx88/cx88-alsa.c @@ -232,8 +232,7 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq aud", - cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), - status, mask); + cx88_aud_irqs, status, mask); /* risc op code error */ if (status & (1 << 16)) { printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); @@ -414,9 +413,11 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, dprintk(1,"Setting buffer\n"); - buf = kzalloc(sizeof(*buf),GFP_KERNEL); + buf = kmalloc(sizeof(*buf),GFP_KERNEL); if (NULL == buf) return -ENOMEM; + memset(buf,0,sizeof(*buf)); + buf->vb.memory = V4L2_MEMORY_MMAP; buf->vb.width = chip->period_size; @@ -681,7 +682,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, return err; } - if (!pci_dma_supported(pci,DMA_32BIT_MASK)) { + if (!pci_dma_supported(pci,0xffffffff)) { dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); err = -EIO; cx88_core_put(core,pci); diff --git a/trunk/drivers/media/video/cx88/cx88-cards.c b/trunk/drivers/media/video/cx88/cx88-cards.c index e61102dc8ad7..65e9d8096b74 100644 --- a/trunk/drivers/media/video/cx88/cx88-cards.c +++ b/trunk/drivers/media/video/cx88/cx88-cards.c @@ -885,12 +885,6 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, }}, .mpeg = CX88_MPEG_DVB, }, @@ -1543,10 +1537,10 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x17de, .subdevice = 0x0840, - .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ - .subvendor = 0x1421, - .subdevice = 0x0305, + .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, + },{ + .subvendor = 0x1421, + .subdevice = 0x0305, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, },{ .subvendor = 0x18ac, @@ -1637,10 +1631,6 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x1402, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ - .subvendor = 0x1421, - .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ - .card = CX88_BOARD_KWORLD_DVBS_100, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1796,7 +1786,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) { 0x03, 0x0C }, }; - for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { + for (i = 0; i < 13; i++) { msg.buf = init_bufs[i]; msg.len = (i != 12 ? 5 : 2); err = i2c_transfer(&core->i2c_adap, &msg, 1); @@ -1923,21 +1913,12 @@ void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) { /* enable tuner */ int i; - static const u8 buffer [][2] = { - {0x10,0x12}, - {0x13,0x04}, - {0x16,0x00}, - {0x14,0x04}, - {0x17,0x00} - }; + static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; core->i2c_client.addr = 0x0a; - for (i = 0; i < ARRAY_SIZE(buffer); i++) - if (2 != i2c_master_send(&core->i2c_client, - buffer[i],2)) - printk(KERN_WARNING - "%s: Unable to enable " - "tuner(%i).\n", + for (i = 0; i < 5; i++) + if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2)) + printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", core->name, i); } break; diff --git a/trunk/drivers/media/video/cx88/cx88-core.c b/trunk/drivers/media/video/cx88/cx88-core.c index f31ec96924b9..d86813be56de 100644 --- a/trunk/drivers/media/video/cx88/cx88-core.c +++ b/trunk/drivers/media/video/cx88/cx88-core.c @@ -489,12 +489,12 @@ static char *cx88_pci_irqs[32] = { }; void cx88_print_irqbits(char *name, char *tag, char **strings, - int len, u32 bits, u32 mask) + u32 bits, u32 mask) { unsigned int i; printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); - for (i = 0; i < len; i++) { + for (i = 0; i < 32; i++) { if (!(bits & (1 << i))) continue; if (strings[i]) @@ -520,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status) } if (!handled) cx88_print_irqbits(core->name, "irq pci", - cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), - status, core->pci_irqmask); + cx88_pci_irqs, status, + core->pci_irqmask); return handled; } diff --git a/trunk/drivers/media/video/cx88/cx88-dvb.c b/trunk/drivers/media/video/cx88/cx88-dvb.c index dbfe4dc9cf8c..4f5560285770 100644 --- a/trunk/drivers/media/video/cx88/cx88-dvb.c +++ b/trunk/drivers/media/video/cx88/cx88-dvb.c @@ -42,6 +42,7 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" +#include "lgh06xf.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -475,8 +476,6 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_WINFAST_DTV2000H: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: - case CX88_BOARD_HAUPPAUGE_HVR1300: - case CX88_BOARD_HAUPPAUGE_HVR3000: dev->dvb.frontend = dvb_attach(cx22702_attach, &hauppauge_hvr_config, &dev->core->i2c_adap); @@ -632,9 +631,8 @@ static int dvb_register(struct cx8802_dev *dev) &fusionhdtv_5_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + dvb_attach(lgh06xf_attach, dev->dvb.frontend, + &dev->core->i2c_adap); } } break; @@ -652,9 +650,8 @@ static int dvb_register(struct cx8802_dev *dev) &pchdtv_hd5500, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + dvb_attach(lgh06xf_attach, dev->dvb.frontend, + &dev->core->i2c_adap); } } break; @@ -695,6 +692,24 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, &dvb_pll_fmd1216me); + } + break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, &dvb_pll_fmd1216me); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); diff --git a/trunk/drivers/media/video/cx88/cx88-i2c.c b/trunk/drivers/media/video/cx88/cx88-i2c.c index 7919a1f9da06..9830d5c43921 100644 --- a/trunk/drivers/media/video/cx88/cx88-i2c.c +++ b/trunk/drivers/media/video/cx88/cx88-i2c.c @@ -1,4 +1,3 @@ - /* cx88-i2c.c -- all the i2c code is here @@ -196,7 +195,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + for (i = 0; i < 128; i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/trunk/drivers/media/video/cx88/cx88-mpeg.c b/trunk/drivers/media/video/cx88/cx88-mpeg.c index b2eb32e01aee..1fe1a833c7c7 100644 --- a/trunk/drivers/media/video/cx88/cx88-mpeg.c +++ b/trunk/drivers/media/video/cx88/cx88-mpeg.c @@ -49,27 +49,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); - - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) - request_module("cx88-dvb"); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) - request_module("cx88-blackbird"); -} - -static void request_modules(struct cx8802_dev *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#endif /* CONFIG_MODULES */ - - static LIST_HEAD(cx8802_devlist); /* ------------------------------------------------------------------ */ @@ -366,8 +345,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) if (debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq mpeg ", - cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), - status, mask); + cx88_mpeg_irqs, status, mask); /* risc op code error */ if (status & (1 << 16)) { @@ -449,7 +427,7 @@ int cx8802_init_common(struct cx8802_dev *dev) if (pci_enable_device(dev->pci)) return -EIO; pci_set_master(dev->pci); - if (!pci_dma_supported(dev->pci,DMA_32BIT_MASK)) { + if (!pci_dma_supported(dev->pci,0xffffffff)) { printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); return -EIO; } @@ -800,9 +778,6 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, /* Maintain a reference so cx88-video can query the 8802 device. */ core->dvbdev = dev; - - /* now autoload cx88-dvb or cx88-blackbird */ - request_modules(dev); return 0; fail_free: diff --git a/trunk/drivers/media/video/cx88/cx88-tvaudio.c b/trunk/drivers/media/video/cx88/cx88-tvaudio.c index e627062fde3a..97ef421dd093 100644 --- a/trunk/drivers/media/video/cx88/cx88-tvaudio.c +++ b/trunk/drivers/media/video/cx88/cx88-tvaudio.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/cx88/cx88-video.c b/trunk/drivers/media/video/cx88/cx88-video.c index fbce1d50578b..bdfe2af70124 100644 --- a/trunk/drivers/media/video/cx88/cx88-video.c +++ b/trunk/drivers/media/video/cx88/cx88-video.c @@ -1555,8 +1555,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) cx_write(MO_VID_INTSTAT, status); if (irq_debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq vid", - cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), - status, mask); + cx88_vid_irqs, status, mask); /* risc op code error */ if (status & (1 << 16)) { @@ -1779,7 +1778,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) { + if (!pci_dma_supported(pci_dev,0xffffffff)) { printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); err = -EIO; goto fail_core; diff --git a/trunk/drivers/media/video/cx88/cx88.h b/trunk/drivers/media/video/cx88/cx88.h index 738d4f20c580..a4f7befda5b0 100644 --- a/trunk/drivers/media/video/cx88/cx88.h +++ b/trunk/drivers/media/video/cx88/cx88.h @@ -481,8 +481,6 @@ struct cx8802_dev { /* List of attached drivers */ struct cx8802_driver drvlist; - struct work_struct request_module_wk; - }; /* ----------------------------------------------------------- */ @@ -512,7 +510,7 @@ struct cx8802_dev { /* cx88-core.c */ extern void cx88_print_irqbits(char *name, char *tag, char **strings, - int len, u32 bits, u32 mask); + u32 bits, u32 mask); extern int cx88_core_irq(struct cx88_core *core, u32 status); extern void cx88_wakeup(struct cx88_core *core, diff --git a/trunk/drivers/media/video/em28xx/em28xx-cards.c b/trunk/drivers/media/video/em28xx/em28xx-cards.c index 418ea8b7f85a..ed882ebc7b95 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-cards.c +++ b/trunk/drivers/media/video/em28xx/em28xx-cards.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/em28xx/em28xx-i2c.c b/trunk/drivers/media/video/em28xx/em28xx-i2c.c index 563a8319e608..d829d8f8c1f6 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-i2c.c +++ b/trunk/drivers/media/video/em28xx/em28xx-i2c.c @@ -523,7 +523,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i, rc; - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + for (i = 0; i < 128; i++) { c->addr = i; rc = i2c_master_recv(c, &buf, 0); if (rc < 0) diff --git a/trunk/drivers/media/video/ir-kbd-i2c.c b/trunk/drivers/media/video/ir-kbd-i2c.c index ed92b6f7187a..210582d420f8 100644 --- a/trunk/drivers/media/video/ir-kbd-i2c.c +++ b/trunk/drivers/media/video/ir-kbd-i2c.c @@ -173,7 +173,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, return -EIO; } - for (start = 0; start < ARRAY_SIZE(b); start++) { + for (start = 0; start<4; start++) { if (b[start] == marker) { code=b[(start+parity_offset+1)%4]; parity=b[(start+parity_offset)%4]; diff --git a/trunk/drivers/media/video/ivtv/Kconfig b/trunk/drivers/media/video/ivtv/Kconfig deleted file mode 100644 index e854f3f1b70f..000000000000 --- a/trunk/drivers/media/video/ivtv/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config VIDEO_IVTV - tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" - depends on VIDEO_V4L1 && VIDEO_V4L2 && USB && I2C && EXPERIMENTAL - select FW_LOADER - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_SAA711X - select VIDEO_SAA7127 - select VIDEO_TVAUDIO - select VIDEO_CS53L32A - select VIDEO_WM8775 - select VIDEO_WM8739 - select VIDEO_UPD64031A - select VIDEO_UPD64083 - ---help--- - This is a video4linux driver for Conexant cx23416 or cx23416 based - PCI personal video recorder devices. - - This is used in devices such as the Hauppauge PVR-150/250/350/500 - cards. - - To compile this driver as a module, choose M here: the - module will be called ivtv. diff --git a/trunk/drivers/media/video/ivtv/Makefile b/trunk/drivers/media/video/ivtv/Makefile deleted file mode 100644 index 7e95148fbf4f..000000000000 --- a/trunk/drivers/media/video/ivtv/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ - ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ - ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ - ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ - ivtv-vbi.o ivtv-video.o ivtv-yuv.o - -obj-$(CONFIG_VIDEO_IVTV) += ivtv.o diff --git a/trunk/drivers/media/video/ivtv/ivtv-audio.c b/trunk/drivers/media/video/ivtv/ivtv-audio.c deleted file mode 100644 index d702b8b539a1..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-audio.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-mailbox.h" -#include "ivtv-i2c.h" -#include "ivtv-gpio.h" -#include "ivtv-cards.h" -#include "ivtv-audio.h" -#include -#include - -/* Selects the audio input and output according to the current - settings. */ -int ivtv_audio_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - u32 audio_input; - int mux_input; - - /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } - - /* handle muxer chips */ - route.input = mux_input; - route.output = 0; - ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } - return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); -} - -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) -{ - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); -} - -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) -{ - static u32 freqs[3] = { 44100, 48000, 32000 }; - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (freq > 2) - return; - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); -} - diff --git a/trunk/drivers/media/video/ivtv/ivtv-audio.h b/trunk/drivers/media/video/ivtv/ivtv-audio.h deleted file mode 100644 index 9c42846d8124..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-audio.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -int ivtv_audio_set_io(struct ivtv *itv); -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); diff --git a/trunk/drivers/media/video/ivtv/ivtv-cards.c b/trunk/drivers/media/video/ivtv/ivtv-cards.c deleted file mode 100644 index 8eab02083887..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-cards.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - Functions to query card hardware - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-i2c.h" - -#include -#include -#include -#include -#include - -#define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ - MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) -#define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) - -/********************** card configuration *******************************/ - -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii - This keeps the PCI ID database up to date. Note that the entries - must be added under vendor 0x4444 (Conexant) as subsystem IDs. - New vendor IDs should still be added to the vendor ID list. */ - -/* Hauppauge PVR-250 cards */ - -/* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */ -static const struct ivtv_card ivtv_card_pvr250 = { - .type = IVTV_CARD_PVR_250, - .name = "Hauppauge WinTV PVR-250", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, -}; - -/* ------------------------------------------------------------------------- */ - -/* Hauppauge PVR-350 cards */ - -/* Outputs for Hauppauge PVR350 cards */ -static struct ivtv_card_output ivtv_pvr350_outputs[] = { - { - .name = "S-Video + Composite", - .video_output = 0, - }, { - .name = "Composite", - .video_output = 1, - }, { - .name = "S-Video", - .video_output = 2, - }, { - .name = "RGB", - .video_output = 3, - }, { - .name = "YUV C", - .video_output = 4, - }, { - .name = "YUV V", - .video_output = 5, - } -}; - -static const struct ivtv_card ivtv_card_pvr350 = { - .type = IVTV_CARD_PVR_350, - .name = "Hauppauge WinTV PVR-350", - .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, - .video_outputs = ivtv_pvr350_outputs, - .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, -}; - -/* PVR-350 V1 boards have a different audio tuner input and use a - saa7114 instead of a saa7115. - Note that the info below comes from a pre-production model so it may - not be correct. Especially the audio behaves strangely (mono only it seems) */ -static const struct ivtv_card ivtv_card_pvr350_v1 = { - .type = IVTV_CARD_PVR_350_V1, - .name = "Hauppauge WinTV PVR-350 (V1)", - .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, - .video_outputs = ivtv_pvr350_outputs, - .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 | - IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_MONO }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, -}; - -/* ------------------------------------------------------------------------- */ - -/* Hauppauge PVR-150/PVR-500 cards */ - -static const struct ivtv_card ivtv_card_pvr150 = { - .type = IVTV_CARD_PVR_150, - .name = "Hauppauge WinTV PVR-150", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_WM8775, - .hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 | - IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE7 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, CX25840_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, - CX25840_AUDIO8, WM8775_AIN2 }, - { IVTV_CARD_INPUT_LINE_IN1, - CX25840_AUDIO_SERIAL, WM8775_AIN2 }, - { IVTV_CARD_INPUT_LINE_IN2, - CX25840_AUDIO_SERIAL, WM8775_AIN3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, - CX25840_AUDIO_SERIAL, WM8775_AIN4 }, - /* apparently needed for the IR blaster */ - .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia M179 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_m179[] = { - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf }, - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_m179 = { - .type = IVTV_CARD_M179, - .name = "AVerMedia M179", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xe380, .initial_value = 0x8290 }, - .gpio_audio_input = { .mask = 0x8040, .tuner = 0x8000, .linein = 0x0000 }, - .gpio_audio_mute = { .mask = 0x2000, .mute = 0x2000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0200, .lang2 = 0x0100, .both = 0x0000 }, - .gpio_audio_freq = { .mask = 0x0018, .f32000 = 0x0000, - .f44100 = 0x0008, .f48000 = 0x0010 }, - .gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 }, - .tuners = { - /* As far as we know all M179 cards use this tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, - }, - .pci_list = ivtv_pci_m179, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_mpg600 = { - .type = IVTV_CARD_MPG600, - .name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0x3080, .initial_value = 0x0004 }, - .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, - .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, - .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, - .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, - .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, - .tuners = { - /* The PAL tuner is confirmed */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_mpg600, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = { - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 }, - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_mpg160 = { - .type = IVTV_CARD_MPG160, - .name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0x7080, .initial_value = 0x400c }, - .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, - .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, - .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, - .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, - .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, - .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_mpg160, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan PG600/Diamond PVR-550 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_pg600[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_pg600 = { - .type = IVTV_CARD_PG600, - .name = "Yuan PG600, Diamond PVR-550", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_pg600, -}; - -/* ------------------------------------------------------------------------- */ - -/* Adaptec VideOh! AVC-2410 card */ - -static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_avc2410 = { - .type = IVTV_CARD_AVC2410, - .name = "Adaptec VideOh! AVC-2410", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_muxer = IVTV_HW_CS53L32A, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A | - IVTV_HW_SAA7115 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, - MSP_TUNER, CS53L32A_IN0 }, - { IVTV_CARD_INPUT_LINE_IN1, - MSP_SCART1, CS53L32A_IN2 }, - }, - /* This card has no eeprom and in fact the Windows driver relies - on the country/region setting of the user to decide which tuner - is available. */ - .tuners = { - /* This tuner has been verified for the AVC2410 */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - /* This is a good guess, but I'm not totally sure this is - the correct tuner for NTSC. */ - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .pci_list = ivtv_pci_avc2410, -}; - -/* ------------------------------------------------------------------------- */ - -/* Adaptec VideOh! AVC-2010 card */ - -static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_avc2010 = { - .type = IVTV_CARD_AVC2010, - .name = "Adaptec VideOh! AVC-2010", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_CS53L32A, - .hw_audio_ctrl = IVTV_HW_CS53L32A, - .hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CS53L32A_IN2 }, - }, - /* Does not have a tuner */ - .pci_list = ivtv_pci_avc2010, -}; - -/* ------------------------------------------------------------------------- */ - -/* Nagase Transgear 5000TV card */ - -static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_tg5000tv = { - .type = IVTV_CARD_TG5000TV, - .name = "Nagase Transgear 5000TV", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | - IVTV_HW_GPIO, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gr_config = UPD64031A_VERTICAL_EXTERNAL, - .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, - .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, - .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, - .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, - .composite = 0x0010, .svideo = 0x0020 }, - .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_tg5000tv, -}; - -/* ------------------------------------------------------------------------- */ - -/* AOpen VA2000MAX-SNT6 card */ - -static const struct ivtv_card_pci_info ivtv_pci_va2000[] = { - { PCI_DEVICE_ID_IVTV16, 0, 0xff5f }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_va2000 = { - .type = IVTV_CARD_VA2000MAX_SNT6, - .name = "AOpen VA2000MAX-SNT6", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_UPD6408X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - }, - .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_va2000, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_cx23416gyc = { - .type = IVTV_CARD_CX23416GYC, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO3 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gr_config = UPD64031A_VERTICAL_EXTERNAL, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .pci_list = ivtv_pci_cx23416gyc, -}; - -static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { - .type = IVTV_CARD_CX23416GYC_NOGR, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | - IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, -}; - -static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { - .type = IVTV_CARD_CX23416GYC_NOGRYCS, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, -}; - -/* ------------------------------------------------------------------------- */ - -/* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */ - -static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */ - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */ - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gv_mvprx = { - .type = IVTV_CARD_GV_MVPRX, - .name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | - IVTV_HW_TUNER | IVTV_HW_WM8739 | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, - .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, - .tuners = { - /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, - }, - .pci_list = ivtv_pci_gv_mvprx, -}; - -/* ------------------------------------------------------------------------- */ - -/* I/O Data GV-MVP/RX2E card */ - -static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 }, - {0, 0, 0} -}; - -static const struct ivtv_card ivtv_card_gv_mvprx2e = { - .type = IVTV_CARD_GV_MVPRX2E, - .name = "I/O Data GV-MVP/RX2E", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_TVAUDIO | IVTV_HW_WM8739, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, - .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, - .tuners = { - /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, - }, - .pci_list = ivtv_pci_gv_mvprx2e, -}; - -/* ------------------------------------------------------------------------- */ - -/* GotVIEW PCI DVD card */ - -static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gotview_pci_dvd = { - .type = IVTV_CARD_GOTVIEW_PCI_DVD, - .name = "GotView PCI DVD", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, /* pin 116 */ - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, /* pin 114/109 */ - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, /* pin 118 */ - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN0 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN2 }, - }, - .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, - .tuners = { - /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .pci_list = ivtv_pci_gotview_pci_dvd, -}; - -/* ------------------------------------------------------------------------- */ - -/* GotVIEW PCI DVD2 Deluxe card */ - -static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { - .type = IVTV_CARD_GOTVIEW_PCI_DVD2, - .name = "GotView PCI DVD2 Deluxe", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_GPIO, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - .gpio_init = { .direction = 0x0800, .initial_value = 0 }, - .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, - .tuners = { - /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .pci_list = ivtv_pci_gotview_pci_dvd2, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPC622 miniPCI card */ - -static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_yuan_mpc622 = { - .type = IVTV_CARD_YUAN_MPC622, - .name = "Yuan MPC622", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 }, - .tuners = { - /* This card has the TDA8290/TDA8275 tuner chips */ - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, - }, - .pci_list = ivtv_pci_yuan_mpc622, -}; - -/* ------------------------------------------------------------------------- */ - -/* DIGITAL COWBOY DCT-MTVP1 card */ - -static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_dctmvtvp1 = { - .type = IVTV_CARD_DCTMTVP1, - .name = "Digital Cowboy DCT-MTVP1", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | - IVTV_HW_GPIO, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, - .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, - .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, - .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, - .composite = 0x0010, .svideo = 0x0020}, - .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_dctmvtvp1, -}; - -/* ------------------------------------------------------------------------- */ - -#ifdef HAVE_XC3028 - -/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_pg600v2 = { - .type = IVTV_CARD_PG600V2, - .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, - }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ - .pci_list = ivtv_pci_pg600v2, -}; -#endif - -static const struct ivtv_card *ivtv_card_list[] = { - &ivtv_card_pvr250, - &ivtv_card_pvr350, - &ivtv_card_pvr150, - &ivtv_card_m179, - &ivtv_card_mpg600, - &ivtv_card_mpg160, - &ivtv_card_pg600, - &ivtv_card_avc2410, - &ivtv_card_avc2010, - &ivtv_card_tg5000tv, - &ivtv_card_va2000, - &ivtv_card_cx23416gyc, - &ivtv_card_gv_mvprx, - &ivtv_card_gv_mvprx2e, - &ivtv_card_gotview_pci_dvd, - &ivtv_card_gotview_pci_dvd2, - &ivtv_card_yuan_mpc622, - &ivtv_card_dctmvtvp1, -#ifdef HAVE_XC3028 - &ivtv_card_pg600v2, -#endif - - /* Variations of standard cards but with the same PCI IDs. - These cards must come last in this list. */ - &ivtv_card_pvr350_v1, - &ivtv_card_cx23416gyc_nogr, - &ivtv_card_cx23416gyc_nogrycs, -}; - -const struct ivtv_card *ivtv_get_card(u16 index) -{ - if (index >= ARRAY_SIZE(ivtv_card_list)) - return NULL; - return ivtv_card_list[index]; -} - -int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) -{ - const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "S-Video 1", - "S-Video 2", - "Composite 1", - "Composite 2", - "Composite 3" - }; - - memset(input, 0, sizeof(*input)); - if (index >= itv->nof_inputs) - return -EINVAL; - input->index = index; - strcpy(input->name, input_strs[card_input->video_type - 1]); - input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? - V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); - input->audioset = (1 << itv->nof_audio_inputs) - 1; - input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? - itv->tuner_std : V4L2_STD_ALL; - return 0; -} - -int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) -{ - const struct ivtv_card_output *card_output = itv->card->video_outputs + index; - - memset(output, 0, sizeof(*output)); - if (index >= itv->card->nof_outputs) - return -EINVAL; - output->index = index; - strcpy(output->name, card_output->name); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->audioset = 1; - output->std = V4L2_STD_ALL; - return 0; -} - -int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) -{ - const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "Line In 1", - "Line In 2" - }; - - memset(audio, 0, sizeof(*audio)); - if (index >= itv->nof_audio_inputs) - return -EINVAL; - strcpy(audio->name, input_strs[aud_input->audio_type - 1]); - audio->index = index; - audio->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output) -{ - memset(aud_output, 0, sizeof(*aud_output)); - if (itv->card->video_outputs == NULL || index != 0) - return -EINVAL; - strcpy(aud_output->name, "A/V Audio Out"); - return 0; -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-cards.h b/trunk/drivers/media/video/ivtv/ivtv-cards.h deleted file mode 100644 index 15012f88b802..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-cards.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - Functions to query card hardware - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -/* hardware flags */ -#define IVTV_HW_CX25840 (1 << 0) -#define IVTV_HW_SAA7115 (1 << 1) -#define IVTV_HW_SAA7127 (1 << 2) -#define IVTV_HW_MSP34XX (1 << 3) -#define IVTV_HW_TUNER (1 << 4) -#define IVTV_HW_WM8775 (1 << 5) -#define IVTV_HW_CS53L32A (1 << 6) -#define IVTV_HW_TVEEPROM (1 << 7) -#define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_TVAUDIO (1 << 9) -#define IVTV_HW_UPD64031A (1 << 10) -#define IVTV_HW_UPD6408X (1 << 11) -#define IVTV_HW_SAA717X (1 << 12) -#define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_GPIO (1 << 14) - -#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) - -/* video inputs */ -#define IVTV_CARD_INPUT_VID_TUNER 1 -#define IVTV_CARD_INPUT_SVIDEO1 2 -#define IVTV_CARD_INPUT_SVIDEO2 3 -#define IVTV_CARD_INPUT_COMPOSITE1 4 -#define IVTV_CARD_INPUT_COMPOSITE2 5 -#define IVTV_CARD_INPUT_COMPOSITE3 6 - -/* audio inputs */ -#define IVTV_CARD_INPUT_AUD_TUNER 1 -#define IVTV_CARD_INPUT_LINE_IN1 2 -#define IVTV_CARD_INPUT_LINE_IN2 3 - -#define IVTV_CARD_MAX_VIDEO_INPUTS 6 -#define IVTV_CARD_MAX_AUDIO_INPUTS 3 -#define IVTV_CARD_MAX_TUNERS 2 - -/* SAA71XX HW inputs */ -#define IVTV_SAA71XX_COMPOSITE0 0 -#define IVTV_SAA71XX_COMPOSITE1 1 -#define IVTV_SAA71XX_COMPOSITE2 2 -#define IVTV_SAA71XX_COMPOSITE3 3 -#define IVTV_SAA71XX_COMPOSITE4 4 -#define IVTV_SAA71XX_COMPOSITE5 5 -#define IVTV_SAA71XX_SVIDEO0 6 -#define IVTV_SAA71XX_SVIDEO1 7 -#define IVTV_SAA71XX_SVIDEO2 8 -#define IVTV_SAA71XX_SVIDEO3 9 - -/* SAA717X needs to mark the tuner input by ORing with this flag */ -#define IVTV_SAA717X_TUNER_FLAG 0x80 - -/* Dummy HW input */ -#define IVTV_DUMMY_AUDIO 0 - -/* GPIO HW inputs */ -#define IVTV_GPIO_TUNER 0 -#define IVTV_GPIO_LINE_IN 1 - -/* SAA717X HW inputs */ -#define IVTV_SAA717X_IN0 0 -#define IVTV_SAA717X_IN1 1 -#define IVTV_SAA717X_IN2 2 - -/* V4L2 capability aliases */ -#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ - V4L2_CAP_SLICED_VBI_CAPTURE) -#define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \ - V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_POS) - -struct ivtv_card_video_input { - u8 video_type; /* video input type */ - u8 audio_index; /* index in ivtv_card_audio_input array */ - u16 video_input; /* hardware video input */ -}; - -struct ivtv_card_audio_input { - u8 audio_type; /* audio input type */ - u32 audio_input; /* hardware audio input */ - u16 muxer_input; /* hardware muxer input for boards with a - multiplexer chip */ -}; - -struct ivtv_card_output { - u8 name[32]; - u16 video_output; /* hardware video output */ -}; - -struct ivtv_card_pci_info { - u16 device; - u16 subsystem_vendor; - u16 subsystem_device; -}; - -/* GPIO definitions */ - -/* The mask is the set of bits used by the operation */ - -struct ivtv_gpio_init { /* set initial GPIO DIR and OUT values */ - u16 direction; /* DIR setting. Leave to 0 if no init is needed */ - u16 initial_value; -}; - -struct ivtv_gpio_video_input { /* select tuner/line in input */ - u16 mask; /* leave to 0 if not supported */ - u16 tuner; - u16 composite; - u16 svideo; -}; - -struct ivtv_gpio_audio_input { /* select tuner/line in input */ - u16 mask; /* leave to 0 if not supported */ - u16 tuner; - u16 linein; - u16 radio; -}; - -struct ivtv_gpio_audio_mute { - u16 mask; /* leave to 0 if not supported */ - u16 mute; /* set this value to mute, 0 to unmute */ -}; - -struct ivtv_gpio_audio_mode { - u16 mask; /* leave to 0 if not supported */ - u16 mono; /* set audio to mono */ - u16 stereo; /* set audio to stereo */ - u16 lang1; /* set audio to the first language */ - u16 lang2; /* set audio to the second language */ - u16 both; /* both languages are output */ -}; - -struct ivtv_gpio_audio_freq { - u16 mask; /* leave to 0 if not supported */ - u16 f32000; - u16 f44100; - u16 f48000; -}; - -struct ivtv_gpio_audio_detect { - u16 mask; /* leave to 0 if not supported */ - u16 stereo; /* if the input matches this value then - stereo is detected */ -}; - -struct ivtv_card_tuner { - v4l2_std_id std; /* standard for which the tuner is suitable */ - int tuner; /* tuner ID (from tuner.h) */ -}; - -/* for card information/parameters */ -struct ivtv_card { - int type; - char *name; - u32 v4l2_capabilities; - u32 hw_video; /* hardware used to process video */ - u32 hw_audio; /* hardware used to process audio */ - u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only 1 dev allowed) */ - u32 hw_muxer; /* hardware used to multiplex audio input */ - u32 hw_all; /* all hardware used by the board */ - struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS]; - struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS]; - struct ivtv_card_audio_input radio_input; - int nof_outputs; - const struct ivtv_card_output *video_outputs; - u8 gr_config; /* config byte for the ghost reduction device */ - - /* GPIO card-specific settings */ - struct ivtv_gpio_init gpio_init; - struct ivtv_gpio_video_input gpio_video_input; - struct ivtv_gpio_audio_input gpio_audio_input; - struct ivtv_gpio_audio_mute gpio_audio_mute; - struct ivtv_gpio_audio_mode gpio_audio_mode; - struct ivtv_gpio_audio_freq gpio_audio_freq; - struct ivtv_gpio_audio_detect gpio_audio_detect; - - struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; - - /* list of device and subsystem vendor/devices that - correspond to this card type. */ - const struct ivtv_card_pci_info *pci_list; -}; - -int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input); -int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); -int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); -int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); -const struct ivtv_card *ivtv_get_card(u16 index); diff --git a/trunk/drivers/media/video/ivtv/ivtv-controls.c b/trunk/drivers/media/video/ivtv/ivtv-controls.c deleted file mode 100644 index 7a876c3e5b19..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-controls.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - ioctl control functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-ioctl.h" -#include "ivtv-audio.h" -#include "ivtv-i2c.h" -#include "ivtv-mailbox.h" -#include "ivtv-controls.h" - -static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_BALANCE, - V4L2_CID_AUDIO_BASS, - V4L2_CID_AUDIO_TREBLE, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_AUDIO_LOUDNESS, - 0 -}; - -static const u32 *ctrl_classes[] = { - user_ctrls, - cx2341x_mpeg_ctrls, - NULL -}; - -static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) -{ - const char *name; - - IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - switch (qctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - - default: - if (cx2341x_ctrl_query(&itv->params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - } - strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); - qctrl->name[sizeof(qctrl->name) - 1] = 0; - return 0; -} - -static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - ivtv_queryctrl(itv, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); -} - -static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) -{ - s32 v = vctrl->value; - - IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); - - switch (vctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl); - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); - - default: - IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); - return -EINVAL; - } - return 0; -} - -static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) -{ - IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); - - switch (vctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl); - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); - default: - IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); - return -EINVAL; - } - return 0; -} - -static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) -{ - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) - return -EINVAL; - if (atomic_read(&itv->capturing) > 0) - return -EBUSY; - - /* First try to allocate sliced VBI buffers if needed. */ - if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { - int i; - - for (i = 0; i < IVTV_VBI_FRAMES; i++) { - /* Yuck, hardcoded. Needs to be a define */ - itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); - if (itv->vbi.sliced_mpeg_data[i] == NULL) { - while (--i >= 0) { - kfree(itv->vbi.sliced_mpeg_data[i]); - itv->vbi.sliced_mpeg_data[i] = NULL; - } - return -ENOMEM; - } - } - } - - itv->vbi.insert_mpeg = fmt; - - if (itv->vbi.insert_mpeg == 0) { - return 0; - } - /* Need sliced data for mpeg insertion */ - if (get_service_set(itv->vbi.sliced_in) == 0) { - if (itv->is_60hz) - itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; - else - itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; - expand_service_set(itv->vbi.sliced_in, itv->is_50hz); - } - return 0; -} - -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) -{ - struct v4l2_control ctrl; - - switch (cmd) { - case VIDIOC_QUERYMENU: - IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); - return ivtv_querymenu(itv, arg); - - case VIDIOC_QUERYCTRL: - return ivtv_queryctrl(itv, arg); - - case VIDIOC_S_CTRL: - return ivtv_s_ctrl(itv, arg); - - case VIDIOC_G_CTRL: - return ivtv_g_ctrl(itv, arg); - - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = ivtv_s_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, arg, cmd); - - if (err) - return err; - - if (p.video_encoding != itv->params.video_encoding) { - int is_mpeg1 = p.video_encoding == - V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; - - /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = itv->params.height; - itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); - } - err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); - if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { - err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); - } - itv->params = p; - itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); - return err; - } - return -EINVAL; - } - - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = ivtv_g_ctrl(itv, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); - return -EINVAL; - } - - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *c = arg; - - IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); - return -EINVAL; - } - - default: - return -EINVAL; - } - return 0; -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-controls.h b/trunk/drivers/media/video/ivtv/ivtv-controls.h deleted file mode 100644 index 5a11149725ad..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-controls.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - ioctl control functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); diff --git a/trunk/drivers/media/video/ivtv/ivtv-driver.c b/trunk/drivers/media/video/ivtv/ivtv-driver.c deleted file mode 100644 index 45b9328a538f..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-driver.c +++ /dev/null @@ -1,1374 +0,0 @@ -/* - ivtv driver initialization and card probing - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -/* Main Driver file for the ivtv project: - * Driver for the Conexant CX23415/CX23416 chip. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - * License: GPL - * http://www.ivtvdriver.org - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - * - * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta - * using information from T.Adachi,Takeru KOMORIYA and others :-) - * - * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX - * version by T.Adachi. Special thanks Mr.Suzuki - */ - -#include "ivtv-driver.h" -#include "ivtv-version.h" -#include "ivtv-fileops.h" -#include "ivtv-i2c.h" -#include "ivtv-firmware.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-mailbox.h" -#include "ivtv-streams.h" -#include "ivtv-ioctl.h" -#include "ivtv-cards.h" -#include "ivtv-vbi.h" -#include "ivtv-audio.h" -#include "ivtv-gpio.h" -#include "ivtv-yuv.h" - -#include -#include -#include - -/* var to keep track of the number of array elements in use */ -int ivtv_cards_active = 0; - -/* If you have already X v4l cards, then set this to X. This way - the device numbers stay matched. Example: you have a WinTV card - without radio and a PVR-350 with. Normally this would give a - video1 device together with a radio0 device for the PVR. By - setting this to 1 you ensure that radio0 is now also radio1. */ -int ivtv_first_minor = 0; - -/* Master variable for all ivtv info */ -struct ivtv *ivtv_cards[IVTV_MAX_CARDS]; - -/* Protects ivtv_cards_active */ -spinlock_t ivtv_cards_lock = SPIN_LOCK_UNLOCKED; - -/* add your revision and whatnot here */ -static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); - -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 -}; - -/* Parameter declarations */ -static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - -static int cardtype_c = 1; -static int tuner_c = 1; -static int radio_c = 1; -static char pal[] = "--"; -static char secam[] = "--"; -static char ntsc[] = "-"; - -/* Buffers */ -static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; -static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; -static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; -static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS; -static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; -static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; -static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS; - -static int ivtv_yuv_mode = 0; -static int ivtv_yuv_threshold=-1; -static int ivtv_pci_latency = 1; - -int ivtv_debug = 0; - -static int newi2c = -1; - -module_param_array(tuner, int, &tuner_c, 0644); -module_param_array(radio, bool, &radio_c, 0644); -module_param_array(cardtype, int, &cardtype_c, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); -module_param_named(debug,ivtv_debug, int, 0644); -module_param(ivtv_pci_latency, int, 0644); -module_param(ivtv_yuv_mode, int, 0644); -module_param(ivtv_yuv_threshold, int, 0644); -module_param(ivtv_first_minor, int, 0644); - -module_param(enc_mpg_buffers, int, 0644); -module_param(enc_yuv_buffers, int, 0644); -module_param(enc_vbi_buffers, int, 0644); -module_param(enc_pcm_buffers, int, 0644); -module_param(dec_mpg_buffers, int, 0644); -module_param(dec_yuv_buffers, int, 0644); -module_param(dec_vbi_buffers, int, 0644); - -module_param(newi2c, int, 0644); - -MODULE_PARM_DESC(tuner, "Tuner type selection,\n" - "\t\t\tsee tuner.h for values"); -MODULE_PARM_DESC(radio, - "Enable or disable the radio. Use only if autodetection\n" - "\t\t\tfails. 0 = disable, 1 = enable"); -MODULE_PARM_DESC(cardtype, - "Only use this option if your card is not detected properly.\n" - "\t\tSpecify card type:\n" - "\t\t\t 1 = WinTV PVR 250\n" - "\t\t\t 2 = WinTV PVR 350\n" - "\t\t\t 3 = WinTV PVR-150 or PVR-500\n" - "\t\t\t 4 = AVerMedia M179\n" - "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n" - "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n" - "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n" - "\t\t\t 8 = Adaptec AVC-2410\n" - "\t\t\t 9 = Adaptec AVC-2010\n" - "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n" - "\t\t\t11 = AOpen VA2000MAX-STN6\n" - "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n" - "\t\t\t13 = I/O Data GV-MVP/RX\n" - "\t\t\t14 = I/O Data GV-MVP/RX2E\n" - "\t\t\t15 = GOTVIEW PCI DVD\n" - "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" - "\t\t\t17 = Yuan MPC622\n" - "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" -#ifdef HAVE_XC3028 - "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" -#endif - "\t\t\t 0 = Autodetect (default)\n" - "\t\t\t-1 = Ignore this card\n\t\t"); -MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); -MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); -MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 511 gives full debugging)"); -MODULE_PARM_DESC(ivtv_pci_latency, - "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" - "\t\t\tDefault: Yes"); -MODULE_PARM_DESC(ivtv_yuv_mode, - "Specify the yuv playback mode:\n" - "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n" - "\t\t\tDefault: 0 (interlaced)"); -MODULE_PARM_DESC(ivtv_yuv_threshold, - "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n" - "\t\t\tDefault: 480");; -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS)); -MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS)); -MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); -MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); -MODULE_PARM_DESC(dec_mpg_buffers, - "Decoder MPG buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS)); -MODULE_PARM_DESC(dec_yuv_buffers, - "Decoder YUV buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); -MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); -MODULE_PARM_DESC(newi2c, - "Use new I2C implementation\n" - "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" - "\t\t\tDefault is autodetect"); - -MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card"); - -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); -MODULE_DESCRIPTION("CX23415/CX23416 driver"); -MODULE_SUPPORTED_DEVICE - ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n" - "\t\t\tYuan MPG series and similar)"); -MODULE_LICENSE("GPL"); - -MODULE_VERSION(IVTV_VERSION); - -void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask) -{ - itv->irqmask &= ~mask; - write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); -} - -void ivtv_set_irq_mask(struct ivtv *itv, u32 mask) -{ - itv->irqmask |= mask; - write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); -} - -int ivtv_set_output_mode(struct ivtv *itv, int mode) -{ - int old_mode; - - spin_lock(&itv->lock); - old_mode = itv->output_mode; - if (old_mode == 0) - itv->output_mode = old_mode = mode; - spin_unlock(&itv->lock); - return old_mode; -} - -struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv) -{ - switch (itv->output_mode) { - case OUT_MPG: - return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - case OUT_YUV: - return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - default: - return NULL; - } -} - -int ivtv_waitq(wait_queue_head_t *waitq) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(waitq, &wait); - return signal_pending(current) ? -EINTR : 0; -} - -/* Generic utility functions */ -int ivtv_sleep_timeout(int timeout, int intr) -{ - int ret; - - do { - set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - timeout = schedule_timeout(timeout); - if (intr && (ret = signal_pending(current))) - return ret; - } while (timeout); - return 0; -} - -/* Release ioremapped memory */ -static void ivtv_iounmap(struct ivtv *itv) -{ - if (itv == NULL) - return; - - /* Release registers memory */ - if (itv->reg_mem != NULL) { - IVTV_DEBUG_INFO("releasing reg_mem\n"); - iounmap(itv->reg_mem); - itv->reg_mem = NULL; - } - /* Release io memory */ - if (itv->has_cx23415 && itv->dec_mem != NULL) { - IVTV_DEBUG_INFO("releasing dec_mem\n"); - iounmap(itv->dec_mem); - } - itv->dec_mem = NULL; - - /* Release io memory */ - if (itv->enc_mem != NULL) { - IVTV_DEBUG_INFO("releasing enc_mem\n"); - iounmap(itv->enc_mem); - itv->enc_mem = NULL; - } -} - -/* Hauppauge card? get values from tveeprom */ -void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) -{ - u8 eedata[256]; - - itv->i2c_client.addr = 0xA0 >> 1; - tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); - tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); -} - -static void ivtv_process_eeprom(struct ivtv *itv) -{ - struct tveeprom tv; - int pci_slot = PCI_SLOT(itv->dev->devfn); - - ivtv_read_eeprom(itv, &tv); - - /* Many thanks to Steven Toth from Hauppauge for providing the - model numbers */ - switch (tv.model) { - /* In a few cases the PCI subsystem IDs do not correctly - identify the card. A better method is to check the - model number from the eeprom instead. */ - case 32000 ... 32999: - case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ - case 48400 ... 48599: - itv->card = ivtv_get_card(IVTV_CARD_PVR_250); - break; - case 48100 ... 48399: - case 48600 ... 48999: - itv->card = ivtv_get_card(IVTV_CARD_PVR_350); - break; - case 23000 ... 23999: /* PVR500 */ - case 25000 ... 25999: /* Low profile PVR150 */ - case 26000 ... 26999: /* Regular PVR150 */ - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - break; - case 0: - IVTV_ERR("Invalid EEPROM\n"); - return; - default: - IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model); - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - break; - } - - switch (tv.model) { - /* Old style PVR350 (with an saa7114) uses this input for - the tuner. */ - case 48254: - itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1); - break; - default: - break; - } - - itv->v4l2_cap = itv->card->v4l2_capabilities; - itv->card_name = itv->card->name; - - /* If this is a PVR500 then it should be possible to detect whether it is the - first or second unit by looking at the subsystem device ID: is bit 4 is - set, then it is the second unit (according to info from Hauppauge). - - However, while this works for most cards, I have seen a few PVR500 cards - where both units have the same subsystem ID. - - So instead I look at the reported 'PCI slot' (which is the slot on the PVR500 - PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise - it is the second unit. It is possible that it is a different slot when ivtv is - used in Xen, in that case I ignore this card here. The worst that can happen - is that the card presents itself with a non-working radio device. - - This detection is needed since the eeprom reports incorrectly that a radio is - present on the second unit. */ - if (tv.model / 1000 == 23) { - itv->card_name = "WinTV PVR 500"; - if (pci_slot == 8 || pci_slot == 9) { - int is_first = (pci_slot & 1) == 0; - - itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" : - "WinTV PVR 500 (unit #2)"; - if (!is_first) { - IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n"); - tv.has_radio = 0; - } - } - } - IVTV_INFO("Autodetected %s\n", itv->card_name); - - switch (tv.tuner_hauppauge_model) { - case 85: - case 99: - case 112: - itv->pvr150_workaround = 1; - break; - default: - break; - } - if (tv.tuner_type == TUNER_ABSENT) - IVTV_ERR("tveeprom cannot autodetect tuner!"); - - if (itv->options.tuner == -1) - itv->options.tuner = tv.tuner_type; - if (itv->options.radio == -1) - itv->options.radio = (tv.has_radio != 0); - /* only enable newi2c if an IR blaster is present */ - /* FIXME: for 2.6.20 the test against 2 should be removed */ - if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) { - itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0; - if (itv->options.newi2c) { - IVTV_INFO("reopen i2c bus for IR-blaster support\n"); - exit_ivtv_i2c(itv); - init_ivtv_i2c(itv); - } - } - - if (itv->std != 0) - /* user specified tuner standard */ - return; - - /* autodetect tuner standard */ - if (tv.tuner_formats & V4L2_STD_PAL) { - IVTV_DEBUG_INFO("PAL tuner detected\n"); - itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - } else if (tv.tuner_formats & V4L2_STD_NTSC) { - IVTV_DEBUG_INFO("NTSC tuner detected\n"); - itv->std |= V4L2_STD_NTSC_M; - } else if (tv.tuner_formats & V4L2_STD_SECAM) { - IVTV_DEBUG_INFO("SECAM tuner detected\n"); - itv->std |= V4L2_STD_SECAM_L; - } else { - IVTV_INFO("No tuner detected, default to NTSC-M\n"); - itv->std |= V4L2_STD_NTSC_M; - } -} - -static v4l2_std_id ivtv_parse_std(struct ivtv *itv) -{ - switch (pal[0]) { - case '6': - return V4L2_STD_PAL_60; - case 'b': - case 'B': - case 'g': - case 'G': - return V4L2_STD_PAL_BG; - case 'h': - case 'H': - return V4L2_STD_PAL_H; - case 'n': - case 'N': - if (pal[1] == 'c' || pal[1] == 'C') - return V4L2_STD_PAL_Nc; - return V4L2_STD_PAL_N; - case 'i': - case 'I': - return V4L2_STD_PAL_I; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_PAL_DK; - case 'M': - case 'm': - return V4L2_STD_PAL_M; - case '-': - break; - default: - IVTV_WARN("pal= argument not recognised\n"); - return 0; - } - - switch (secam[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_SECAM_DK; - case 'l': - case 'L': - if (secam[1] == 'C' || secam[1] == 'c') - return V4L2_STD_SECAM_LC; - return V4L2_STD_SECAM_L; - case '-': - break; - default: - IVTV_WARN("secam= argument not recognised\n"); - return 0; - } - - switch (ntsc[0]) { - case 'm': - case 'M': - return V4L2_STD_NTSC_M; - case 'j': - case 'J': - return V4L2_STD_NTSC_M_JP; - case 'k': - case 'K': - return V4L2_STD_NTSC_M_KR; - case '-': - break; - default: - IVTV_WARN("ntsc= argument not recognised\n"); - return 0; - } - - /* no match found */ - return 0; -} - -static void ivtv_process_options(struct ivtv *itv) -{ - const char *chipname; - int i, j; - - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; - itv->options.cardtype = cardtype[itv->num]; - itv->options.tuner = tuner[itv->num]; - itv->options.radio = radio[itv->num]; - itv->options.newi2c = newi2c; - - itv->std = ivtv_parse_std(itv); - itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15); - chipname = itv->has_cx23415 ? "cx23415" : "cx23416"; - if (itv->options.cardtype == -1) { - IVTV_INFO("Ignore card (detected %s based chip)\n", chipname); - return; - } - if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) { - IVTV_INFO("User specified %s card (detected %s based chip)\n", - itv->card->name, chipname); - } else if (itv->options.cardtype != 0) { - IVTV_ERR("Unknown user specified type, trying to autodetect card\n"); - } - if (itv->card == NULL) { - if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE || - itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 || - itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) { - itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150); - IVTV_INFO("Autodetected Hauppauge card (%s based)\n", - chipname); - } - } - if (itv->card == NULL) { - for (i = 0; (itv->card = ivtv_get_card(i)); i++) { - if (itv->card->pci_list == NULL) - continue; - for (j = 0; itv->card->pci_list[j].device; j++) { - if (itv->dev->device != - itv->card->pci_list[j].device) - continue; - if (itv->dev->subsystem_vendor != - itv->card->pci_list[j].subsystem_vendor) - continue; - if (itv->dev->subsystem_device != - itv->card->pci_list[j].subsystem_device) - continue; - IVTV_INFO("Autodetected %s card (%s based)\n", - itv->card->name, chipname); - goto done; - } - } - } -done: - - if (itv->card == NULL) { - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n", - itv->dev->vendor, itv->dev->device); - IVTV_ERR(" subsystem vendor/device: %04x/%04x\n", - itv->dev->subsystem_vendor, itv->dev->subsystem_device); - IVTV_ERR(" %s based\n", chipname); - IVTV_ERR("Defaulting to %s card\n", itv->card->name); - IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); - IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); - } - itv->v4l2_cap = itv->card->v4l2_capabilities; - itv->card_name = itv->card->name; -} - -/* Precondition: the ivtv structure has been memset to 0. Only - the dev and num fields have been filled in. - No assumptions on the card type may be made here (see ivtv_init_struct2 - for that). - */ -static int __devinit ivtv_init_struct1(struct ivtv *itv) -{ - itv->base_addr = pci_resource_start(itv->dev, 0); - itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ - itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ - - mutex_init(&itv->i2c_bus_lock); - mutex_init(&itv->udma.lock); - - spin_lock_init(&itv->lock); - spin_lock_init(&itv->dma_reg_lock); - - itv->irq_work_queues = create_workqueue(itv->name); - if (itv->irq_work_queues == NULL) { - IVTV_ERR("Could not create ivtv workqueue\n"); - return -1; - } - - INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); - - /* start counting open_id at 1 */ - itv->open_id = 1; - - /* Initial settings */ - cx2341x_fill_defaults(&itv->params); - itv->params.port = CX2341X_PORT_MEMORY; - itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; - init_waitqueue_head(&itv->cap_w); - init_waitqueue_head(&itv->event_waitq); - init_waitqueue_head(&itv->vsync_waitq); - init_waitqueue_head(&itv->dma_waitq); - init_timer(&itv->dma_timer); - itv->dma_timer.function = ivtv_unfinished_dma; - itv->dma_timer.data = (unsigned long)itv; - - itv->cur_dma_stream = -1; - itv->audio_stereo_mode = AUDIO_STEREO; - itv->audio_bilingual_mode = AUDIO_MONO_LEFT; - - /* Ctrls */ - itv->speed = 1000; - - /* VBI */ - itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; - - /* OSD */ - itv->osd_global_alpha_state = 1; - itv->osd_global_alpha = 255; - - /* YUV */ - atomic_set(&itv->yuv_info.next_dma_frame, -1); - itv->yuv_info.lace_mode = ivtv_yuv_mode; - itv->yuv_info.lace_threshold = ivtv_yuv_threshold; - return 0; -} - -/* Second initialization part. Here the card type has been - autodetected. */ -static void __devinit ivtv_init_struct2(struct ivtv *itv) -{ - int i; - - for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) - if (itv->card->video_inputs[i].video_type == 0) - break; - itv->nof_inputs = i; - for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) - if (itv->card->audio_inputs[i].audio_type == 0) - break; - itv->nof_audio_inputs = i; - - /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ - if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) - itv->digitizer = 0xF1; - else if (itv->card->hw_all & IVTV_HW_SAA7114) - itv->digitizer = 0xEF; - else /* cx25840 */ - itv->digitizer = 0x140; - - if (itv->card->hw_all & IVTV_HW_CX25840) { - itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ - } else { - itv->vbi.sliced_size = 64; /* multiple of 16, real size = 52 */ - } - - /* Find tuner input */ - for (i = 0; i < itv->nof_inputs; i++) { - if (itv->card->video_inputs[i].video_type == - IVTV_CARD_INPUT_VID_TUNER) - break; - } - if (i == itv->nof_inputs) - i = 0; - itv->active_input = i; - itv->audio_input = itv->card->video_inputs[i].audio_index; - if (itv->card->hw_all & IVTV_HW_CX25840) - itv->video_dec_func = ivtv_cx25840; - else if (itv->card->hw_all & IVTV_HW_SAA717X) - itv->video_dec_func = ivtv_saa717x; - else - itv->video_dec_func = ivtv_saa7115; -} - -static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - u16 cmd; - unsigned char pci_latency; - - IVTV_DEBUG_INFO("Enabling pci device\n"); - - if (pci_enable_device(dev)) { - IVTV_ERR("Can't enable device %d!\n", itv->num); - return -EIO; - } - if (pci_set_dma_mask(dev, 0xffffffff)) { - IVTV_ERR("No suitable DMA available on card %d.\n", itv->num); - return -EIO; - } - if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { - IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num); - return -EIO; - } - - if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, - IVTV_REG_SIZE, "ivtv registers")) { - IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num); - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - return -EIO; - } - - if (itv->has_cx23415 && - !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, - IVTV_DECODER_SIZE, "ivtv decoder")) { - IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num); - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - return -EIO; - } - - /* Check for bus mastering */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) { - IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n"); - pci_set_master(dev); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) { - IVTV_ERR("Bus Mastering is not enabled\n"); - return -ENXIO; - } - } - IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 64 && ivtv_pci_latency) { - IVTV_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); - } - /* This config space value relates to DMA latencies. The - default value 0x8080 is too low however and will lead - to DMA errors. 0xffff is the max value which solves - these problems. */ - pci_write_config_dword(dev, 0x40, 0xffff); - - IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%lx\n", - itv->dev->device, itv->card_rev, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); - - return 0; -} - -static void ivtv_request_module(struct ivtv *itv, const char *name) -{ - if (request_module(name) != 0) { - IVTV_ERR("Failed to load module %s\n", name); - } else { - IVTV_DEBUG_INFO("Loaded module %s\n", name); - } -} - -static void ivtv_load_and_init_modules(struct ivtv *itv) -{ - struct v4l2_control ctrl; - u32 hw = itv->card->hw_all; - int i; - - /* load modules */ -#ifndef CONFIG_VIDEO_TUNER - if (hw & IVTV_HW_TUNER) { - ivtv_request_module(itv, "tuner"); -#ifdef HAVE_XC3028 - if (itv->options.tuner == TUNER_XCEIVE_XC3028) - ivtv_request_module(itv, "xc3028-tuner"); -#endif - } -#endif -#ifndef CONFIG_VIDEO_CX25840 - if (hw & IVTV_HW_CX25840) - ivtv_request_module(itv, "cx25840"); -#endif -#ifndef CONFIG_VIDEO_SAA711X - if (hw & IVTV_HW_SAA711X) - ivtv_request_module(itv, "saa7115"); -#endif -#ifndef CONFIG_VIDEO_SAA7127 - if (hw & IVTV_HW_SAA7127) - ivtv_request_module(itv, "saa7127"); -#endif - if (hw & IVTV_HW_SAA717X) - ivtv_request_module(itv, "saa717x"); -#ifndef CONFIG_VIDEO_UPD64031A - if (hw & IVTV_HW_UPD64031A) - ivtv_request_module(itv, "upd64031a"); -#endif -#ifndef CONFIG_VIDEO_UPD64083 - if (hw & IVTV_HW_UPD6408X) - ivtv_request_module(itv, "upd64083"); -#endif -#ifndef CONFIG_VIDEO_MSP3400 - if (hw & IVTV_HW_MSP34XX) - ivtv_request_module(itv, "msp3400"); -#endif - if (hw & IVTV_HW_TVAUDIO) - ivtv_request_module(itv, "tvaudio"); -#ifndef CONFIG_VIDEO_WM8775 - if (hw & IVTV_HW_WM8775) - ivtv_request_module(itv, "wm8775"); -#endif -#ifndef CONFIG_VIDEO_WM8739 - if (hw & IVTV_HW_WM8739) - ivtv_request_module(itv, "wm8739"); -#endif -#ifndef CONFIG_VIDEO_CS53L32A - if (hw & IVTV_HW_CS53L32A) - ivtv_request_module(itv, "cs53l32a"); -#endif - - /* check which i2c devices are actually found */ - for (i = 0; i < 32; i++) { - u32 device = 1 << i; - - if (!(device & hw)) - continue; - if (device == IVTV_HW_GPIO) { - /* GPIO is always available */ - itv->hw_flags |= IVTV_HW_GPIO; - continue; - } - if (ivtv_i2c_hw_addr(itv, device) > 0) - itv->hw_flags |= device; - } - - hw = itv->hw_flags; - - if (itv->card->type == IVTV_CARD_CX23416GYC) { - /* Several variations of this card exist, detect which card - type should be used. */ - if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0) - itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS); - else if ((hw & IVTV_HW_UPD64031A) == 0) - itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); - } - - if (hw & IVTV_HW_CX25840) { - /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ - ctrl.id = V4L2_CID_PRIVATE_BASE; - ctrl.value = itv->pvr150_workaround; - itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); - - itv->vbi.raw_decoder_line_size = 1444; - itv->vbi.raw_decoder_sav_odd_field = 0x20; - itv->vbi.raw_decoder_sav_even_field = 0x60; - itv->vbi.sliced_decoder_line_size = 272; - itv->vbi.sliced_decoder_sav_odd_field = 0xB0; - itv->vbi.sliced_decoder_sav_even_field = 0xF0; - } - - if (hw & IVTV_HW_SAA711X) { - struct v4l2_chip_ident v = { V4L2_CHIP_MATCH_I2C_DRIVER, I2C_DRIVERID_SAA711X }; - - /* determine the exact saa711x model */ - itv->hw_flags &= ~IVTV_HW_SAA711X; - - ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v); - if (v.ident == V4L2_IDENT_SAA7114) { - itv->hw_flags |= IVTV_HW_SAA7114; - /* VBI is not yet supported by the saa7114 driver. */ - itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE); - } - else { - itv->hw_flags |= IVTV_HW_SAA7115; - } - itv->vbi.raw_decoder_line_size = 1443; - itv->vbi.raw_decoder_sav_odd_field = 0x25; - itv->vbi.raw_decoder_sav_even_field = 0x62; - itv->vbi.sliced_decoder_line_size = 51; - itv->vbi.sliced_decoder_sav_odd_field = 0xAB; - itv->vbi.sliced_decoder_sav_even_field = 0xEC; - } - - if (hw & IVTV_HW_SAA717X) { - itv->vbi.raw_decoder_line_size = 1443; - itv->vbi.raw_decoder_sav_odd_field = 0x25; - itv->vbi.raw_decoder_sav_even_field = 0x62; - itv->vbi.sliced_decoder_line_size = 51; - itv->vbi.sliced_decoder_sav_odd_field = 0xAB; - itv->vbi.sliced_decoder_sav_even_field = 0xEC; - } -} - -static int __devinit ivtv_probe(struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - int retval = 0; - int video_input; - int yuv_buf_size; - int vbi_buf_size; - int fw_retry_count = 3; - struct ivtv *itv; - struct v4l2_frequency vf; - - spin_lock(&ivtv_cards_lock); - - /* Make sure we've got a place for this card */ - if (ivtv_cards_active == IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n", - ivtv_cards_active); - spin_unlock(&ivtv_cards_lock); - return -ENOMEM; - } - - itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); - if (itv == 0) { - spin_unlock(&ivtv_cards_lock); - return -ENOMEM; - } - ivtv_cards[ivtv_cards_active] = itv; - itv->dev = dev; - itv->num = ivtv_cards_active++; - snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num); - if (itv->num) { - printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n"); - } - - spin_unlock(&ivtv_cards_lock); - - ivtv_process_options(itv); - if (itv->options.cardtype == -1) { - retval = -ENODEV; - goto err; - } - if (ivtv_init_struct1(itv)) { - retval = -ENOMEM; - goto err; - } - - IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); - - /* PCI Device Setup */ - if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { - if (retval == -EIO) - goto free_workqueue; - else if (retval == -ENXIO) - goto free_mem; - } - /* save itv in the pci struct for later use */ - pci_set_drvdata(dev, itv); - - /* map io memory */ - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); - itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, - IVTV_ENCODER_SIZE); - if (!itv->enc_mem) { - IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); - retval = -ENOMEM; - goto free_mem; - } - - if (itv->has_cx23415) { - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, - IVTV_DECODER_SIZE); - if (!itv->dec_mem) { - IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); - retval = -ENOMEM; - goto free_mem; - } - } - else { - itv->dec_mem = itv->enc_mem; - } - - /* map registers memory */ - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - itv->reg_mem = - ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (!itv->reg_mem) { - IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); - retval = -ENOMEM; - goto free_io; - } - - while (--fw_retry_count > 0) { - /* load firmware */ - if (ivtv_firmware_init(itv) == 0) - break; - if (fw_retry_count > 1) - IVTV_WARN("Retry loading firmware\n"); - } - if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - goto free_i2c; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - - /* Check yuv output filter table */ - if (itv->has_cx23415) ivtv_yuv_filter_check(itv); - - ivtv_gpio_init(itv); - - /* active i2c */ - IVTV_DEBUG_INFO("activating i2c...\n"); - if (init_ivtv_i2c(itv)) { - IVTV_ERR("Could not initialize i2c\n"); - goto free_irq; - } - - IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); - - if (itv->card->hw_all & IVTV_HW_TVEEPROM) { -#ifdef CONFIG_VIDEO_TVEEPROM_MODULE - ivtv_request_module(itv, "tveeprom"); -#endif - /* Based on the model number the cardtype may be changed. - The PCI IDs are not always reliable. */ - ivtv_process_eeprom(itv); - } - - if (itv->std == 0) { - itv->std = V4L2_STD_NTSC_M; - } - - if (itv->options.tuner == -1) { - int i; - - for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { - if ((itv->std & itv->card->tuners[i].std) == 0) - continue; - itv->options.tuner = itv->card->tuners[i].tuner; - break; - } - } - /* if no tuner was found, then pick the first tuner in the card list */ - if (itv->options.tuner == -1 && itv->card->tuners[0].std) { - itv->std = itv->card->tuners[0].std; - itv->options.tuner = itv->card->tuners[0].tuner; - } - if (itv->options.radio == -1) - itv->options.radio = (itv->card->radio_input.audio_type != 0); - - /* The card is now fully identified, continue with card-specific - initialization. */ - ivtv_init_struct2(itv); - - ivtv_load_and_init_modules(itv); - - if (itv->std & V4L2_STD_525_60) { - itv->is_60hz = 1; - itv->is_out_60hz = 1; - } else { - itv->is_50hz = 1; - itv->is_out_50hz = 1; - } - itv->params.video_gop_size = itv->is_60hz ? 15 : 12; - - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; - - /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ - yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; - - /* Setup VBI Raw Size. Should be big enough to hold PAL. - It is possible to switch between PAL and NTSC, so we need to - take the largest size here. */ - /* 1456 is multiple of 16, real size = 1444 */ - itv->vbi.raw_size = 1456; - /* We use a buffer size of 1/2 of the total size needed for a - frame. This is actually very useful, since we now receive - a field at a time and that makes 'compressing' the raw data - down to size by stripping off the SAV codes a lot easier. - Note: having two different buffer sizes prevents standard - switching on the fly. We need to find a better solution... */ - vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; - - if (itv->options.radio > 0) - itv->v4l2_cap |= V4L2_CAP_RADIO; - - if (itv->options.tuner > -1) { - struct tuner_setup setup; - - setup.addr = ADDR_UNSET; - setup.type = itv->options.tuner; - setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ -#ifdef HAVE_XC3028 - setup.initmode = V4L2_TUNER_ANALOG_TV; - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { - setup.gpio_write = ivtv_reset_tuner_gpio; - setup.gpio_priv = itv; - } -#endif - ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); - } - - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - if (itv->std & V4L2_STD_NTSC_M) { - /* Why on earth? */ - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - } - - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) - are not. */ - itv->tuner_std = itv->std; - - video_input = itv->active_input; - itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - itv->std++; /* Force full standard initialization */ - itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); - - retval = ivtv_streams_setup(itv); - if (retval) { - IVTV_ERR("Error %d setting up streams\n", retval); - goto free_i2c; - } - - if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_init_mpeg_decoder(itv); - } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); - - IVTV_DEBUG_IRQ("Masking interrupts\n"); - /* clear interrupt mask, effectively disabling interrupts */ - ivtv_set_irq_mask(itv, 0xffffffff); - - /* Register IRQ */ - retval = request_irq(itv->dev->irq, ivtv_irq_handler, - IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); - if (retval) { - IVTV_ERR("Failed to register irq %d\n", retval); - goto free_streams; - } - - /* On a cx23416 this seems to be able to enable DMA to the chip? */ - if (!itv->has_cx23415) - write_reg_sync(0x03, IVTV_REG_DMACONTROL); - - /* Default interrupts enabled. For the PVR350 this includes the - decoder VSYNC interrupt, which is always on. It is not only used - during decoding but also by the OSD. - Some old PVR250 cards had a cx23415, so testing for that is too - general. Instead test if the card has video output capability. */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - if (itv->has_cx23415) - ivtv_set_osd_alpha(itv); - - IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num); - - return 0; - - free_irq: - free_irq(itv->dev->irq, (void *)itv); - free_streams: - ivtv_streams_cleanup(itv); - free_i2c: - exit_ivtv_i2c(itv); - free_io: - ivtv_iounmap(itv); - free_mem: - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - free_workqueue: - destroy_workqueue(itv->irq_work_queues); - err: - if (retval == 0) - retval = -ENODEV; - IVTV_ERR("Error %d on initialization\n", retval); - - kfree(ivtv_cards[ivtv_cards_active]); - ivtv_cards[ivtv_cards_active] = NULL; - return retval; -} - -static void ivtv_remove(struct pci_dev *pci_dev) -{ - struct ivtv *itv = pci_get_drvdata(pci_dev); - - IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num); - - /* Stop all captures */ - IVTV_DEBUG_INFO(" Stopping all streams.\n"); - if (atomic_read(&itv->capturing) > 0) - ivtv_stop_all_captures(itv); - - /* Stop all decoding */ - IVTV_DEBUG_INFO(" Stopping decoding.\n"); - if (atomic_read(&itv->decoding) > 0) { - int type; - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - type = IVTV_DEC_STREAM_TYPE_YUV; - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], - VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); - } - - /* Interrupts */ - IVTV_DEBUG_INFO(" Disabling interrupts.\n"); - ivtv_set_irq_mask(itv, 0xffffffff); - del_timer_sync(&itv->dma_timer); - - /* Stop all Work Queues */ - IVTV_DEBUG_INFO(" Stop Work Queues.\n"); - flush_workqueue(itv->irq_work_queues); - destroy_workqueue(itv->irq_work_queues); - - IVTV_DEBUG_INFO(" Stopping Firmware.\n"); - ivtv_halt_firmware(itv); - - IVTV_DEBUG_INFO(" Unregistering v4l devices.\n"); - ivtv_streams_cleanup(itv); - IVTV_DEBUG_INFO(" Freeing dma resources.\n"); - ivtv_udma_free(itv); - - exit_ivtv_i2c(itv); - - IVTV_DEBUG_INFO(" Releasing irq.\n"); - free_irq(itv->dev->irq, (void *)itv); - - if (itv->dev) { - ivtv_iounmap(itv); - } - - IVTV_DEBUG_INFO(" Releasing mem.\n"); - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - - pci_disable_device(itv->dev); - - IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num); -} - -/* define a pci_driver for card detection */ -static struct pci_driver ivtv_pci_driver = { - .name = "ivtv", - .id_table = ivtv_pci_tbl, - .probe = ivtv_probe, - .remove = ivtv_remove, -}; - -static int module_start(void) -{ - printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n"); - printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION); - - memset(ivtv_cards, 0, sizeof(ivtv_cards)); - - /* Validate parameters */ - if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n", - IVTV_MAX_CARDS - 1); - return -1; - } - - if (ivtv_debug < 0 || ivtv_debug > 511) { - ivtv_debug = 0; - printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n"); - } - - if (pci_register_driver(&ivtv_pci_driver)) { - printk(KERN_ERR "ivtv: Error detecting PCI card\n"); - return -ENODEV; - } - printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n"); - return 0; -} - -static void module_cleanup(void) -{ - int i, j; - - pci_unregister_driver(&ivtv_pci_driver); - - for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_cards[i] == NULL) - continue; - for (j = 0; j < IVTV_VBI_FRAMES; j++) { - kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]); - } - kfree(ivtv_cards[i]); - } -} - -/* Note: These symbols are exported because they are used by the ivtv-fb - framebuffer module and an infrared module for the IR-blaster. */ -EXPORT_SYMBOL(ivtv_set_irq_mask); -EXPORT_SYMBOL(ivtv_cards_active); -EXPORT_SYMBOL(ivtv_cards); -EXPORT_SYMBOL(ivtv_api); -EXPORT_SYMBOL(ivtv_vapi); -EXPORT_SYMBOL(ivtv_vapi_result); -EXPORT_SYMBOL(ivtv_clear_irq_mask); -EXPORT_SYMBOL(ivtv_debug); -EXPORT_SYMBOL(ivtv_reset_ir_gpio); -EXPORT_SYMBOL(ivtv_udma_setup); -EXPORT_SYMBOL(ivtv_udma_unmap); -EXPORT_SYMBOL(ivtv_udma_alloc); -EXPORT_SYMBOL(ivtv_udma_prepare); - -module_init(module_start); -module_exit(module_cleanup); diff --git a/trunk/drivers/media/video/ivtv/ivtv-driver.h b/trunk/drivers/media/video/ivtv/ivtv-driver.h deleted file mode 100644 index 9a412d6c6d06..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-driver.h +++ /dev/null @@ -1,868 +0,0 @@ -/* - ivtv driver internal defines and structures - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef IVTV_DRIVER_H -#define IVTV_DRIVER_H - -/* Internal header for ivtv project: - * Driver for the cx23415/6 chip. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - * License: GPL - * http://www.ivtvdriver.org - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* #define HAVE_XC3028 1 */ - -#include - -#ifdef CONFIG_LIRC_I2C -# error "This driver is not compatible with the LIRC I2C kernel configuration option." -#endif /* CONFIG_LIRC_I2C */ - -#ifndef CONFIG_PCI -# error "This driver requires kernel PCI support." -#endif /* CONFIG_PCI */ - -#define IVTV_ENCODER_OFFSET 0x00000000 -#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - -#define IVTV_DECODER_OFFSET 0x01000000 -#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - -#define IVTV_REG_OFFSET 0x02000000 -#define IVTV_REG_SIZE 0x00010000 - -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ -#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ - -/* Offset to filter table in firmware */ -#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 -#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 - -extern const u32 yuv_offset[4]; - -/* Maximum ivtv driver instances. - Based on 6 PVR500s each with two PVR15s... - TODO: make this dynamic. I believe it is only a global in order to support - ivtv-fb. There must be a better way to do that. */ -#define IVTV_MAX_CARDS 12 - -/* Supported cards */ -#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ -#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ -#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two - PVR150s on one PCI board) */ -#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ -#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ -#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 - cx23415 based, but does not have tv-out */ -#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ -#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ -#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ -#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ -#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ -#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ -#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ -#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ -#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ -#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ -#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#ifdef HAVE_XC3028 -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ -#define IVTV_CARD_LAST 18 -#else -#define IVTV_CARD_LAST 17 -#endif - -/* Variants of existing cards but with the same PCI IDs. The driver - detects these based on other device information. - These cards must always come last. - New cards must be inserted above, and the indices of the cards below - must be adjusted accordingly. */ - -/* PVR-350 V1 (uses saa7114) */ -#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) -/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) -#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) - -#define IVTV_ENC_STREAM_TYPE_MPG 0 -#define IVTV_ENC_STREAM_TYPE_YUV 1 -#define IVTV_ENC_STREAM_TYPE_VBI 2 -#define IVTV_ENC_STREAM_TYPE_PCM 3 -#define IVTV_ENC_STREAM_TYPE_RAD 4 -#define IVTV_DEC_STREAM_TYPE_MPG 5 -#define IVTV_DEC_STREAM_TYPE_VBI 6 -#define IVTV_DEC_STREAM_TYPE_VOUT 7 -#define IVTV_DEC_STREAM_TYPE_YUV 8 -#define IVTV_MAX_STREAMS 9 - -#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ -#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ -#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ -#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ - -#define IVTV_ENC_MEM_START 0x00000000 -#define IVTV_DEC_MEM_START 0x01000000 - -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_ICOMP 0x4444 -#define PCI_DEVICE_ID_IVTV15 0x0803 -#define PCI_DEVICE_ID_IVTV16 0x0016 - -/* subsystem vendor ID */ -#define IVTV_PCI_ID_HAUPPAUGE 0x0070 -#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 -#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 -#define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_AVERMEDIA 0x1461 -#define IVTV_PCI_ID_YUAN1 0x12ab -#define IVTV_PCI_ID_YUAN2 0xff01 -#define IVTV_PCI_ID_YUAN3 0xffab -#define IVTV_PCI_ID_YUAN4 0xfbab -#define IVTV_PCI_ID_DIAMONDMM 0xff92 -#define IVTV_PCI_ID_IODATA 0x10fc -#define IVTV_PCI_ID_MELCO 0x1154 -#define IVTV_PCI_ID_GOTVIEW1 0xffac -#define IVTV_PCI_ID_GOTVIEW2 0xffad - -/* Decoder Buffer hardware size on Chip */ -#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ -#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - -#define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ - -/* DMA Buffers, Default size in MB allocated */ -#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 -#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 -#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 -#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 -#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 - -/* ======================================================================== */ -/* ========================== END USER SETTABLE DMA VARIABLES ============= */ -/* ======================================================================== */ - -/* Decoder Status Register */ -#define IVTV_DMA_ERR_LIST 0x00000010 -#define IVTV_DMA_ERR_WRITE 0x00000008 -#define IVTV_DMA_ERR_READ 0x00000004 -#define IVTV_DMA_SUCCESS_WRITE 0x00000002 -#define IVTV_DMA_SUCCESS_READ 0x00000001 -#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) -#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) -#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) - -/* DMA Registers */ -#define IVTV_REG_DMAXFER (0x0000) -#define IVTV_REG_DMASTATUS (0x0004) -#define IVTV_REG_DECDMAADDR (0x0008) -#define IVTV_REG_ENCDMAADDR (0x000c) -#define IVTV_REG_DMACONTROL (0x0010) -#define IVTV_REG_IRQSTATUS (0x0040) -#define IVTV_REG_IRQMASK (0x0048) - -/* Setup Registers */ -#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) -#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) -#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8) -#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC) -#define IVTV_REG_VDM (0x2800) -#define IVTV_REG_AO (0x2D00) -#define IVTV_REG_BYTEFLUSH (0x2D24) -#define IVTV_REG_SPU (0x9050) -#define IVTV_REG_HW_BLOCKS (0x9054) -#define IVTV_REG_VPU (0x9058) -#define IVTV_REG_APU (0xA064) - -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) - -/* IRQ Masks */ -#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|IVTV_IRQ_DMA_READ) - -#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) -#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) - -/* i2c stuff */ -#define I2C_CLIENTS_MAX 16 - -/* debugging */ - -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_API (1 << 2) -#define IVTV_DBGFLG_DMA (1 << 3) -#define IVTV_DBGFLG_IOCTL (1 << 4) -#define IVTV_DBGFLG_I2C (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) - -/* NOTE: extra space before comma in 'itv->num , ## args' is required for - gcc-2.95, otherwise it won't compile. */ -#define IVTV_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - -/* Standard kernel messages */ -#define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) - -/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ -#define MPEG_FRAME_TYPE_IFRAME 1 -#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 -#define MPEG_FRAME_TYPE_ALL 7 - -/* output modes (cx23415 only) */ -#define OUT_NONE 0 -#define OUT_MPG 1 -#define OUT_YUV 2 -#define OUT_UDMA_YUV 3 -#define OUT_PASSTHROUGH 4 - -#define IVTV_MAX_PGM_INDEX (400) - -extern int ivtv_debug; - - -struct ivtv_options { - int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ - int newi2c; /* New I2C algorithm */ -}; - -#define IVTV_MBOX_DMA_START 6 -#define IVTV_MBOX_DMA_END 8 -#define IVTV_MBOX_DMA 9 -#define IVTV_MBOX_FIELD_DISPLAYED 8 - -/* ivtv-specific mailbox template */ -struct ivtv_mailbox { - u32 flags; - u32 cmd; - u32 retval; - u32 timeout; - u32 data[CX2341X_MBOX_MAX_DATA]; -}; - -struct ivtv_api_cache { - unsigned long last_jiffies; /* when last command was issued */ - u32 data[CX2341X_MBOX_MAX_DATA]; /* last sent api data */ -}; - -struct ivtv_mailbox_data { - volatile struct ivtv_mailbox __iomem *mbox; - /* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes. - If the bit is set, then the corresponding mailbox is in use by the driver. */ - unsigned long busy; - u8 max_mbox; -}; - -/* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ - -/* per-stream, s_flags */ -#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ -#define IVTV_F_S_DMA_HAS_VBI 1 /* the current DMA request also requests VBI data */ -#define IVTV_F_S_NEEDS_DATA 2 /* this decoding stream needs more data */ - -#define IVTV_F_S_CLAIMED 3 /* this stream is claimed */ -#define IVTV_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ -#define IVTV_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ -#define IVTV_F_S_PASSTHROUGH 6 /* this stream is in passthrough mode */ -#define IVTV_F_S_STREAMOFF 7 /* signal end of stream EOS */ -#define IVTV_F_S_APPL_IO 8 /* this stream is used read/written by an application */ - -/* per-ivtv, i_flags */ -#define IVTV_F_I_DMA 0 /* DMA in progress */ -#define IVTV_F_I_UDMA 1 /* UDMA in progress */ -#define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ -#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ -#define IVTV_F_I_EOS 4 /* End of encoder stream reached */ -#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ -#define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ -#define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ -#define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ -#define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ -#define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ -#define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ -#define IVTV_F_I_WORK_HANDLER_VBI 15 /* there is work to be done for VBI */ -#define IVTV_F_I_WORK_HANDLER_YUV 16 /* there is work to be done for YUV */ - -/* Event notifications */ -#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ -#define IVTV_F_I_EV_VSYNC 29 /* VSYNC event */ -#define IVTV_F_I_EV_VSYNC_FIELD 30 /* VSYNC event field (0 = first, 1 = second field) */ -#define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ - -/* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_SG_element { - u32 src; - u32 dst; - u32 size; -}; - -struct ivtv_user_dma { - struct mutex lock; - int page_count; - struct page *map[IVTV_DMA_SG_OSD_ENT]; - - /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; - dma_addr_t SG_handle; - int SG_length; - - /* SG List of Buffers */ - struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT]; -}; - -struct ivtv_dma_page_info { - unsigned long uaddr; - unsigned long first; - unsigned long last; - unsigned int offset; - unsigned int tail; - int page_count; -}; - -struct ivtv_buffer { - struct list_head list; - dma_addr_t dma_handle; - unsigned long b_flags; - char *buf; - - u32 bytesused; - u32 readpos; -}; - -struct ivtv_queue { - struct list_head list; - u32 buffers; - u32 length; - u32 bytesused; -}; - -struct ivtv; /* forward reference */ - -struct ivtv_stream { - /* These first four fields are always set, even if the stream - is not actually created. */ - struct video_device *v4l2dev; /* NULL when stream not created */ - struct ivtv *itv; /* for ease of use */ - const char *name; /* name of the stream */ - int type; /* stream type */ - - u32 id; - spinlock_t qlock; /* locks access to the queues */ - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ - u32 dma_offset; - u32 dma_backup; - u64 dma_pts; - - int subtype; - wait_queue_head_t waitq; - u32 dma_last_offset; - - /* Buffer Stats */ - u32 buffers; - u32 buf_size; - u32 buffers_stolen; - - /* Buffer Queues */ - struct ivtv_queue q_free; /* free buffers */ - struct ivtv_queue q_full; /* full buffers */ - struct ivtv_queue q_io; /* waiting for I/O */ - struct ivtv_queue q_dma; /* waiting for DMA */ - struct ivtv_queue q_predma; /* waiting for DMA */ - - /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element *SGarray; - dma_addr_t SG_handle; - int SG_length; - - /* SG List of Buffers */ - struct scatterlist *SGlist; -}; - -struct ivtv_open_id { - u32 open_id; - int type; - enum v4l2_priority prio; - struct ivtv *itv; -}; - -#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 -#define IVTV_YUV_UPDATE_VERTICAL 0x02 - -struct yuv_frame_info -{ - u32 update; - int src_x; - int src_y; - unsigned int src_w; - unsigned int src_h; - int dst_x; - int dst_y; - unsigned int dst_w; - unsigned int dst_h; - int pan_x; - int pan_y; - u32 vis_w; - u32 vis_h; - u32 interlaced_y; - u32 interlaced_uv; - int tru_x; - u32 tru_w; - u32 tru_h; - u32 offset_y; -}; - -#define IVTV_YUV_MODE_INTERLACED 0x00 -#define IVTV_YUV_MODE_PROGRESSIVE 0x01 -#define IVTV_YUV_MODE_AUTO 0x02 -#define IVTV_YUV_MODE_MASK 0x03 - -#define IVTV_YUV_SYNC_EVEN 0x00 -#define IVTV_YUV_SYNC_ODD 0x04 -#define IVTV_YUV_SYNC_MASK 0x04 - -struct yuv_playback_info -{ - u32 reg_2834; - u32 reg_2838; - u32 reg_283c; - u32 reg_2840; - u32 reg_2844; - u32 reg_2848; - u32 reg_2854; - u32 reg_285c; - u32 reg_2864; - - u32 reg_2870; - u32 reg_2874; - u32 reg_2890; - u32 reg_2898; - u32 reg_289c; - - u32 reg_2918; - u32 reg_291c; - u32 reg_2920; - u32 reg_2924; - u32 reg_2928; - u32 reg_292c; - u32 reg_2930; - - u32 reg_2934; - - u32 reg_2938; - u32 reg_293c; - u32 reg_2940; - u32 reg_2944; - u32 reg_2948; - u32 reg_294c; - u32 reg_2950; - u32 reg_2954; - u32 reg_2958; - u32 reg_295c; - u32 reg_2960; - u32 reg_2964; - u32 reg_2968; - u32 reg_296c; - - u32 reg_2970; - - int v_filter_1; - int v_filter_2; - int h_filter; - - u32 osd_x_offset; - u32 osd_y_offset; - - u32 osd_x_pan; - u32 osd_y_pan; - - u32 osd_vis_w; - u32 osd_vis_h; - - int decode_height; - - int frame_interlaced; - int frame_interlaced_last; - - int lace_mode; - int lace_threshold; - int lace_sync_field; - - atomic_t next_dma_frame; - atomic_t next_fill_frame; - - u32 yuv_forced_update; - int update_frame; - struct yuv_frame_info new_frame_info[4]; - struct yuv_frame_info old_frame_info; - struct yuv_frame_info old_frame_info_args; - - void *blanking_ptr; - dma_addr_t blanking_dmaptr; -}; - -#define IVTV_VBI_FRAMES 32 - -/* VBI data */ -struct vbi_info { - u32 dec_start; - u32 enc_start, enc_size; - int fpi; - u32 frame; - u32 dma_offset; - u8 cc_data_odd[256]; - u8 cc_data_even[256]; - int cc_pos; - u8 cc_no_update; - u8 vps[5]; - u8 vps_found; - int wss; - u8 wss_found; - u8 wss_no_update; - u32 raw_decoder_line_size; - u8 raw_decoder_sav_odd_field; - u8 raw_decoder_sav_even_field; - u32 sliced_decoder_line_size; - u8 sliced_decoder_sav_odd_field; - u8 sliced_decoder_sav_even_field; - struct v4l2_format in; - /* convenience pointer to sliced struct in vbi_in union */ - struct v4l2_sliced_vbi_format *sliced_in; - u32 service_set_in; - u32 service_set_out; - int insert_mpeg; - - /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - One for /dev/vbi0 and one for /dev/vbi8 */ - struct v4l2_sliced_vbi_data sliced_data[36]; - struct v4l2_sliced_vbi_data sliced_dec_data[36]; - - /* Buffer for VBI data inserted into MPEG stream. - The first byte is a dummy byte that's never used. - The next 16 bytes contain the MPEG header for the VBI data, - the remainder is the actual VBI data. - The max size accepted by the MPEG VBI reinsertion turns out - to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, - where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is - a single line header byte and 2 * 18 is the number of VBI lines per frame. - - However, it seems that the data must be 1K aligned, so we have to - pad the data until the 1 or 2 K boundary. - - This pointer array will allocate 2049 bytes to store each VBI frame. */ - u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; - u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; - struct ivtv_buffer sliced_mpeg_buf; - u32 inserted_frame; - - u32 start[2], count; - u32 raw_size; - u32 sliced_size; -}; - -/* forward declaration of struct defined in ivtv-cards.h */ -struct ivtv_card; - -/* Struct to hold info about ivtv cards */ -struct ivtv { - int num; /* board number, -1 during init! */ - char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ - struct pci_dev *dev; /* PCI device */ - const struct ivtv_card *card; /* card information */ - const char *card_name; /* full name of the card */ - u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ - u8 is_50hz; - u8 is_60hz; - u8 is_out_50hz; - u8 is_out_60hz; - u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - - /* controlling Video decoder function */ - int (*video_dec_func)(struct ivtv *, unsigned int, void *); - - struct ivtv_options options; /* User options */ - int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ - struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ - int speed; - u8 speed_mute_audio; - unsigned long i_flags; /* global ivtv flags */ - atomic_t capturing; /* count number of active capture streams */ - atomic_t decoding; /* count number of active decoding streams */ - u32 irq_rr_idx; /* Round-robin stream index */ - int cur_dma_stream; /* index of stream doing DMA */ - u32 dma_data_req_offset; - u32 dma_data_req_size; - int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ - spinlock_t lock; /* lock access to this struct */ - int search_pack_header; - - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - - /* User based DMA for OSD */ - struct ivtv_user_dma udma; - - int open_id; /* incremented each time an open occurs, used as unique ID. - starts at 1, so 0 can be used as uninitialized value - in the stream->id. */ - - u32 base_addr; - u32 irqmask; - - struct v4l2_prio_state prio; - struct workqueue_struct *irq_work_queues; - struct work_struct irq_work_queue; - struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ - - struct vbi_info vbi; - - struct ivtv_mailbox_data enc_mbox; - struct ivtv_mailbox_data dec_mbox; - struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ - - u8 card_rev; - volatile void __iomem *enc_mem, *dec_mem, *reg_mem; - - u32 pgm_info_offset; - u32 pgm_info_num; - u32 pgm_info_write_idx; - u32 pgm_info_read_idx; - struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; - - u64 mpg_data_received; - u64 vbi_data_inserted; - - wait_queue_head_t cap_w; - /* when the next decoder event arrives this queue is woken up */ - wait_queue_head_t event_waitq; - /* when the next decoder vsync arrives this queue is woken up */ - wait_queue_head_t vsync_waitq; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; - - /* OSD support */ - unsigned long osd_video_pbase; - int osd_global_alpha_state; /* 0=off : 1=on */ - int osd_local_alpha_state; /* 0=off : 1=on */ - int osd_color_key_state; /* 0=off : 1=on */ - u8 osd_global_alpha; /* Current global alpha */ - u32 osd_color_key; /* Current color key */ - u32 osd_pixelformat; /* Current pixel format */ - struct v4l2_rect osd_rect; /* Current OSD position and size */ - struct v4l2_rect main_rect; /* Current Main window position and size */ - - u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ - - /* i2c */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - struct mutex i2c_bus_lock; - int i2c_state; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; - - /* v4l2 and User settings */ - - /* codec settings */ - struct cx2341x_mpeg_params params; - u32 audio_input; - u32 active_input; - u32 active_output; - v4l2_std_id std; - v4l2_std_id std_out; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - u8 audio_stereo_mode; - u8 audio_bilingual_mode; - - /* dualwatch */ - unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; - - /* Digitizer type */ - int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ - - u32 lastVsyncFrame; - - struct yuv_playback_info yuv_info; - struct osd_info *osd_info; -}; - -/* Globals */ -extern struct ivtv *ivtv_cards[]; -extern int ivtv_cards_active; -extern int ivtv_first_minor; -extern spinlock_t ivtv_cards_lock; - -/*==============Prototypes==================*/ - -/* Hardware/IRQ */ -void ivtv_set_irq_mask(struct ivtv *itv, u32 mask); -void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask); - -/* try to set output mode, return current mode. */ -int ivtv_set_output_mode(struct ivtv *itv, int mode); - -/* return current output stream based on current mode */ -struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv); - -/* Return non-zero if a signal is pending */ -int ivtv_sleep_timeout(int timeout, int intr); - -/* Wait on queue, returns -EINTR if interrupted */ -int ivtv_waitq(wait_queue_head_t *waitq); - -/* Read Hauppauge eeprom */ -struct tveeprom; /* forward reference */ -void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); - -/* This is a PCI post thing, where if the pci register is not read, then - the write doesn't always take effect right away. By reading back the - register any pending PCI writes will be performed (in order), and so - you can be sure that the writes are guaranteed to be done. - - Rarely needed, only in some timing sensitive cases. - Apparently if this is not done some motherboards seem - to kill the firmware and get into the broken state until computer is - rebooted. */ -#define write_sync(val, reg) \ - do { writel(val, reg); readl(reg); } while (0) - -#define read_reg(reg) readl(itv->reg_mem + (reg)) -#define write_reg(val, reg) writel(val, itv->reg_mem + (reg)) -#define write_reg_sync(val, reg) \ - do { write_reg(val, reg); read_reg(reg); } while (0) - -#define read_enc(addr) readl(itv->enc_mem + (u32)(addr)) -#define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr)) -#define write_enc_sync(val, addr) \ - do { write_enc(val, addr); read_enc(addr); } while (0) - -#define read_dec(addr) readl(itv->dec_mem + (u32)(addr)) -#define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr)) -#define write_dec_sync(val, addr) \ - do { write_dec(val, addr); read_dec(addr); } while (0) - -#endif /* IVTV_DRIVER_H */ diff --git a/trunk/drivers/media/video/ivtv/ivtv-fileops.c b/trunk/drivers/media/video/ivtv/ivtv-fileops.c deleted file mode 100644 index 1637097ddec7..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-fileops.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - file operation functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-fileops.h" -#include "ivtv-i2c.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-vbi.h" -#include "ivtv-mailbox.h" -#include "ivtv-audio.h" -#include "ivtv-streams.h" -#include "ivtv-yuv.h" -#include "ivtv-controls.h" -#include "ivtv-ioctl.h" - -/* This function tries to claim the stream for a specific file descriptor. - If no one else is using this stream then the stream is claimed and - associated VBI streams are also automatically claimed. - Possible error returns: -EBUSY if someone else has claimed - the stream or 0 on success. */ -int ivtv_claim_stream(struct ivtv_open_id *id, int type) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[type]; - struct ivtv_stream *s_vbi; - int vbi_type; - - if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - /* someone already claimed this stream */ - if (s->id == id->open_id) { - /* yes, this file descriptor did. So that's OK. */ - return 0; - } - if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || - type == IVTV_ENC_STREAM_TYPE_VBI)) { - /* VBI is handled already internally, now also assign - the file descriptor to this stream for external - reading of the stream. */ - s->id = id->open_id; - IVTV_DEBUG_INFO("Start Read VBI\n"); - return 0; - } - /* someone else is using this stream already */ - IVTV_DEBUG_INFO("Stream %d is busy\n", type); - return -EBUSY; - } - s->id = id->open_id; - if (type == IVTV_DEC_STREAM_TYPE_VBI) { - /* Enable reinsertion interrupt */ - ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - } - - /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, - IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI - (provided VBI insertion is on and sliced VBI is selected), for all - other streams we're done */ - if (type == IVTV_DEC_STREAM_TYPE_MPG) { - vbi_type = IVTV_DEC_STREAM_TYPE_VBI; - } else if (type == IVTV_ENC_STREAM_TYPE_MPG && - itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) { - vbi_type = IVTV_ENC_STREAM_TYPE_VBI; - } else { - return 0; - } - s_vbi = &itv->streams[vbi_type]; - - if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { - /* Enable reinsertion interrupt */ - if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - } - /* mark that it is used internally */ - set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); - return 0; -} - -/* This function releases a previously claimed stream. It will take into - account associated VBI streams. */ -void ivtv_release_stream(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi; - - s->id = -1; - if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && - test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { - /* this stream is still in use internally */ - return; - } - if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); - return; - } - - ivtv_flush_queues(s); - - /* disable reinsertion interrupt */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - - /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, - IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, - for all other streams we're done */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - else - return; - - /* clear internal use flag */ - if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { - /* was already cleared */ - return; - } - if (s_vbi->id != -1) { - /* VBI stream still claimed by a file descriptor */ - return; - } - /* disable reinsertion interrupt */ - if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); - ivtv_flush_queues(s_vbi); -} - -static void ivtv_dualwatch(struct ivtv *itv) -{ - struct v4l2_tuner vt; - u16 new_bitmap; - u16 new_stereo_mode; - const u16 stereo_mask = 0x0300; - const u16 dual = 0x0200; - - new_stereo_mode = itv->params.audio_properties & stereo_mask; - memset(&vt, 0, sizeof(vt)); - ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt); - if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) - new_stereo_mode = dual; - - if (new_stereo_mode == itv->dualwatch_stereo_mode) - return; - - new_bitmap = new_stereo_mode | (itv->params.audio_properties & ~stereo_mask); - - IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", - itv->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); - - if (ivtv_vapi(itv, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new_bitmap) == 0) { - itv->dualwatch_stereo_mode = new_stereo_mode; - return; - } - IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); -} - -static void ivtv_update_pgm_info(struct ivtv *itv) -{ - u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; - int cnt; - int i = 0; - - if (wr_idx >= itv->pgm_info_num) { - IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); - return; - } - cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; - while (i < cnt) { - int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; - struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; - u32 addr = itv->pgm_info_offset + 4 + idx * 24; - const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 }; - - e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); - if (e->offset > itv->mpg_data_received) { - break; - } - e->offset += itv->vbi_data_inserted; - e->length = read_enc(addr); - e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); - e->flags = mapping[read_enc(addr + 12) & 3]; - i++; - } - itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; -} - -static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - struct ivtv_buffer *buf; - DEFINE_WAIT(wait); - - *err = 0; - while (1) { - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { - /* Process pending program info updates and pending VBI data */ - ivtv_update_pgm_info(itv); - - if (jiffies - itv->dualwatch_jiffies > HZ) { - itv->dualwatch_jiffies = jiffies; - ivtv_dualwatch(itv); - } - - if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { - while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { - /* byteswap and process VBI data */ - ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); - ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); - } - } - buf = &itv->vbi.sliced_mpeg_buf; - if (buf->readpos != buf->bytesused) { - return buf; - } - } - - /* do we have leftover data? */ - buf = ivtv_dequeue(s, &s->q_io); - if (buf) - return buf; - - /* do we have new data? */ - buf = ivtv_dequeue(s, &s->q_full); - if (buf) { - if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) - return buf; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - /* byteswap MPG data */ - ivtv_buf_swap(buf); - else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { - /* byteswap and process VBI data */ - ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); - } - return buf; - } - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } - - /* return if end of stream */ - if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - IVTV_DEBUG_INFO("EOS %s\n", s->name); - return NULL; - } - - /* wait for more data to arrive */ - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become available before we were added to the waitqueue */ - if (!s->q_full.buffers) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - /* return if a signal was received */ - IVTV_DEBUG_INFO("User stopped %s\n", s->name); - *err = -EINTR; - return NULL; - } - } -} - -static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) -{ - int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; - - itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; - itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; - itv->vbi.sliced_mpeg_buf.readpos = 0; -} - -static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, - char __user *ubuf, size_t ucount) -{ - struct ivtv *itv = s->itv; - size_t len = buf->bytesused - buf->readpos; - - if (len > ucount) len = ucount; - if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && - itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) { - const char *start = buf->buf + buf->readpos; - const char *p = start + 1; - const u8 *q; - u8 ch = itv->search_pack_header ? 0xba : 0xe0; - int stuffing, i; - - while (start + len > p && (q = memchr(p, 0, start + len - p))) { - p = q + 1; - if ((char *)q + 15 >= buf->buf + buf->bytesused || - q[1] != 0 || q[2] != 1 || q[3] != ch) { - continue; - } - if (!itv->search_pack_header) { - if ((q[6] & 0xc0) != 0x80) - continue; - if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || - ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { - ch = 0xba; - itv->search_pack_header = 1; - p = q + 9; - } - continue; - } - stuffing = q[13] & 7; - /* all stuffing bytes must be 0xff */ - for (i = 0; i < stuffing; i++) - if (q[14 + i] != 0xff) - break; - if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && - q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && - q[16 + stuffing] == 1) { - itv->search_pack_header = 0; - len = (char *)q - start; - ivtv_setup_sliced_vbi_buf(itv); - break; - } - } - } - if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { - IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); - return -EFAULT; - } - /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, - buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, - buf == &itv->vbi.sliced_mpeg_buf); */ - buf->readpos += len; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) - itv->mpg_data_received += len; - return len; -} - -static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) -{ - struct ivtv *itv = s->itv; - size_t tot_written = 0; - int single_frame = 0; - - if (atomic_read(&itv->capturing) == 0 && s->id == -1) { - /* shouldn't happen */ - IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); - return -EIO; - } - - /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should - arrive one-by-one, so make sure we never output more than one VBI frame at a time */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI || - (s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set)) - single_frame = 1; - - for (;;) { - struct ivtv_buffer *buf; - int rc; - - buf = ivtv_get_buffer(s, non_block, &rc); - if (buf == NULL && rc == -EAGAIN && tot_written) - break; - if (buf == NULL) - return rc; - rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); - if (buf != &itv->vbi.sliced_mpeg_buf) { - ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); - } - else if (buf->readpos == buf->bytesused) { - int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; - itv->vbi.sliced_mpeg_size[idx] = 0; - itv->vbi.inserted_frame++; - itv->vbi_data_inserted += buf->bytesused; - } - if (rc < 0) - return rc; - tot_written += rc; - - if (tot_written == tot_count || single_frame) - break; - } - return tot_written; -} - -static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, - loff_t *pos, int non_block) -{ - ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; - struct ivtv *itv = s->itv; - - IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc); - if (rc > 0) - pos += rc; - return rc; -} - -int ivtv_start_capture(struct ivtv_open_id *id) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - struct ivtv_stream *s_vbi; - - if (s->type == IVTV_ENC_STREAM_TYPE_RAD || - s->type == IVTV_DEC_STREAM_TYPE_MPG || - s->type == IVTV_DEC_STREAM_TYPE_YUV || - s->type == IVTV_DEC_STREAM_TYPE_VOUT) { - /* you cannot read from these stream types. */ - return -EPERM; - } - - /* Try to claim this stream. */ - if (ivtv_claim_stream(id, s->type)) - return -EBUSY; - - /* This stream does not need to start capturing */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* If capture is already in progress, then we also have to - do nothing extra. */ - if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* Start VBI capture if required */ - s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { - /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed - automatically when the MPG stream is claimed. - We only need to start the VBI capturing. */ - if (ivtv_start_v4l2_encode_stream(s_vbi)) { - IVTV_DEBUG_WARN("VBI capture start failed\n"); - - /* Failure, clean up and return an error */ - clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* also releases the associated VBI stream */ - ivtv_release_stream(s); - return -EIO; - } - IVTV_DEBUG_INFO("VBI insertion started\n"); - } - - /* Tell the card to start capturing */ - if (!ivtv_start_v4l2_encode_stream(s)) { - /* We're done */ - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - /* Resume a possibly paused encoder */ - if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - return 0; - } - - /* failure, clean up */ - IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); - - /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released - automatically when the MPG stream is released. - We only need to stop the VBI capturing. */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { - ivtv_stop_v4l2_encode_stream(s_vbi, 0); - clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); - } - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - ivtv_release_stream(s); - return -EIO; -} - -ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) -{ - struct ivtv_open_id *id = filp->private_data; - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int rc; - - IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name); - - rc = ivtv_start_capture(id); - if (rc) - return rc; - return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); -} - -int ivtv_start_decoding(struct ivtv_open_id *id, int speed) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - if (atomic_read(&itv->decoding) == 0) { - if (ivtv_claim_stream(id, s->type)) { - /* someone else is using this stream already */ - IVTV_DEBUG_WARN("start decode, stream already claimed\n"); - return -EBUSY; - } - ivtv_start_v4l2_decode_stream(s, 0); - } - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - return ivtv_set_speed(itv, speed); - return 0; -} - -ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) -{ - struct ivtv_open_id *id = filp->private_data; - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - struct ivtv_buffer *buf; - struct ivtv_queue q; - int bytes_written = 0; - int mode; - int rc; - DEFINE_WAIT(wait); - - IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name); - - if (s->type != IVTV_DEC_STREAM_TYPE_MPG && - s->type != IVTV_DEC_STREAM_TYPE_YUV && - s->type != IVTV_DEC_STREAM_TYPE_VOUT) - /* not decoder streams */ - return -EPERM; - - /* Try to claim this stream */ - if (ivtv_claim_stream(id, s->type)) - return -EBUSY; - - /* This stream does not need to start any decoding */ - if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return ivtv_write_vbi(itv, user_buf, count); - } - - mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; - - if (ivtv_set_output_mode(itv, mode) != mode) { - ivtv_release_stream(s); - return -EBUSY; - } - ivtv_queue_init(&q); - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - -retry: - for (;;) { - /* Gather buffers */ - while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) - ivtv_enqueue(s, buf, &q); - while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { - ivtv_enqueue(s, buf, &q); - } - if (q.buffers) - break; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become free before we were added to the waitqueue */ - if (!s->q_free.buffers) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - IVTV_DEBUG_INFO("User stopped %s\n", s->name); - return -EINTR; - } - } - - /* copy user data into buffers */ - while ((buf = ivtv_dequeue(s, &q))) { - /* Make sure we really got all the user data */ - rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); - - if (rc < 0) { - ivtv_queue_move(s, &q, NULL, &s->q_free, 0); - return rc; - } - user_buf += rc; - count -= rc; - bytes_written += rc; - - if (buf->bytesused != s->buf_size) { - /* incomplete, leave in q_io for next time */ - ivtv_enqueue(s, buf, &s->q_io); - break; - } - /* Byteswap MPEG buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - ivtv_buf_swap(buf); - ivtv_enqueue(s, buf, &s->q_full); - } - - /* Start decoder (returns 0 if already started) */ - rc = ivtv_start_decoding(id, itv->speed); - if (rc) { - IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); - - /* failure, clean up */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return rc; - } - if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { - if (s->q_full.length >= itv->dma_data_req_size) { - int got_sig; - - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - while (!(got_sig = signal_pending(current)) && - test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - if (got_sig) { - IVTV_DEBUG_INFO("User interrupted %s\n", s->name); - return -EINTR; - } - - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); - ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); - } - } - /* more user data is available, wait until buffers become free - to transfer the rest. */ - if (count && !(filp->f_flags & O_NONBLOCK)) - goto retry; - IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); - return bytes_written; -} - -unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) -{ - struct ivtv_open_id *id = filp->private_data; - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int res = 0; - - /* add stream's waitq to the poll list */ - poll_wait(filp, &s->waitq, wait); - - set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); - if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || - test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) - res = POLLPRI; - - /* Allow write if buffers are available for writing */ - if (s->q_free.buffers) - res |= POLLOUT | POLLWRNORM; - return res; -} - -unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) -{ - struct ivtv_open_id *id = filp->private_data; - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - /* Start a capture if there is none */ - if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc = ivtv_start_capture(id); - - if (rc) { - IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", - s->name, rc); - return POLLERR; - } - } - - /* add stream's waitq to the poll list */ - poll_wait(filp, &s->waitq, wait); - - if (eof || s->q_full.length) - return POLLIN | POLLRDNORM; - return 0; -} - -void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); - - /* 'Unclaim' this stream */ - - /* Stop capturing */ - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - - IVTV_DEBUG_INFO("close stopping capture\n"); - /* Special case: a running VBI capture for VBI insertion - in the mpeg stream. Need to stop that too. */ - if (id->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { - IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); - ivtv_stop_v4l2_encode_stream(s_vbi, 0); - } - if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || - id->type == IVTV_ENC_STREAM_TYPE_VBI) && - test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { - /* Also used internally, don't stop capturing */ - s->id = -1; - } - else { - ivtv_stop_v4l2_encode_stream(s, gop_end); - } - } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - ivtv_release_stream(s); -} - -static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); - - /* Stop decoding */ - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - IVTV_DEBUG_INFO("close stopping decode\n"); - - ivtv_stop_v4l2_decode_stream(s, flags, pts); - } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { - /* Restore registers we've changed & clean up any mess we've made */ - ivtv_yuv_close(itv); - } - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) - itv->output_mode = OUT_NONE; - - itv->speed = 0; - ivtv_release_stream(s); -} - -int ivtv_v4l2_close(struct inode *inode, struct file *filp) -{ - struct ivtv_open_id *id = filp->private_data; - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); - - v4l2_prio_close(&itv->prio, &id->prio); - - /* Easy case first: this stream was never claimed by us */ - if (s->id != id->open_id) { - kfree(id); - return 0; - } - - /* 'Unclaim' this stream */ - - /* Stop radio */ - if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { - /* Closing radio device, return to TV mode */ - ivtv_mute(itv); - /* Mark that the radio is no longer in use */ - clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); - /* Switch tuner to TV */ - ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); - /* Select correct audio input (i.e. TV tuner or Line in) */ - ivtv_audio_set_io(itv); - /* Done! Unmute and continue. */ - ivtv_unmute(itv); - ivtv_release_stream(s); - } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { - ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); - } else { - ivtv_stop_capture(id, 0); - } - kfree(id); - return 0; -} - -int ivtv_v4l2_open(struct inode *inode, struct file *filp) -{ - int x, y = 0; - struct ivtv_open_id *item; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - int minor = MINOR(inode->i_rdev); - - /* Find which card this open was on */ - spin_lock(&ivtv_cards_lock); - for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { - /* find out which stream this open was on */ - for (y = 0; y < IVTV_MAX_STREAMS; y++) { - s = &ivtv_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { - itv = ivtv_cards[x]; - break; - } - } - } - spin_unlock(&ivtv_cards_lock); - - if (itv == NULL) { - /* Couldn't find a device registered - on that minor, shouldn't happen! */ - printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor); - return -ENXIO; - } - - if (y == IVTV_DEC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) - return -EBUSY; - - if (y == IVTV_DEC_STREAM_TYPE_YUV && - test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) - return -EBUSY; - - if (y == IVTV_DEC_STREAM_TYPE_YUV) { - if (read_reg(0x82c) == 0) { - IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); - /* return -ENODEV; */ - } - ivtv_udma_alloc(itv); - } - - /* Allocate memory */ - item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); - if (NULL == item) { - IVTV_DEBUG_WARN("nomem on v4l2 open\n"); - return -ENOMEM; - } - item->itv = itv; - item->type = y; - v4l2_prio_open(&itv->prio, &item->prio); - - item->open_id = itv->open_id++; - filp->private_data = item; - - if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { - /* Try to claim this stream */ - if (ivtv_claim_stream(item, item->type)) { - /* No, it's already in use */ - kfree(item); - return -EBUSY; - } - - /* We have the radio */ - ivtv_mute(itv); - /* Switch tuner to radio */ - ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); - /* Select the correct audio input (i.e. radio tuner) */ - ivtv_audio_set_io(itv); - /* Done! Unmute and continue. */ - ivtv_unmute(itv); - } - - /* YUV or MPG Decoding Mode? */ - if (y == IVTV_DEC_STREAM_TYPE_MPG) - clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (y == IVTV_DEC_STREAM_TYPE_YUV) - { - set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - } - - return 0; -} - -void ivtv_mute(struct ivtv *itv) -{ - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; - - /* Mute sound to avoid pop */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); - - if (atomic_read(&itv->capturing)) - ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); - - IVTV_DEBUG_INFO("Mute\n"); -} - -void ivtv_unmute(struct ivtv *itv) -{ - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; - - /* initialize or refresh input */ - if (atomic_read(&itv->capturing) == 0) - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_sleep_timeout(HZ / 10, 0); - - if (atomic_read(&itv->capturing)) { - ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); - ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); - } - - /* Unmute */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); - IVTV_DEBUG_INFO("Unmute\n"); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-fileops.h b/trunk/drivers/media/video/ivtv/ivtv-fileops.h deleted file mode 100644 index 74a1745fabbc..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-fileops.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - file operation functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -/* Testing/Debugging */ -int ivtv_v4l2_open(struct inode *inode, struct file *filp); -ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t * pos); -ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count, - loff_t * pos); -int ivtv_v4l2_close(struct inode *inode, struct file *filp); -unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait); -unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait); -int ivtv_start_capture(struct ivtv_open_id *id); -void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end); -int ivtv_start_decoding(struct ivtv_open_id *id, int speed); -void ivtv_mute(struct ivtv *itv); -void ivtv_unmute(struct ivtv *itv); - -/* Utilities */ - -/* Try to claim a stream for the filehandle. Return 0 on success, - -EBUSY if stream already claimed. Once a stream is claimed, it - remains claimed until the associated filehandle is closed. */ -int ivtv_claim_stream(struct ivtv_open_id *id, int type); - -/* Release a previously claimed stream. */ -void ivtv_release_stream(struct ivtv_stream *s); diff --git a/trunk/drivers/media/video/ivtv/ivtv-firmware.c b/trunk/drivers/media/video/ivtv/ivtv-firmware.c deleted file mode 100644 index d4c910b782af..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-firmware.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - ivtv firmware functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-mailbox.h" -#include "ivtv-firmware.h" -#include - -#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE -#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 -#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB -#define IVTV_CMD_VDM_STOP 0x00000000 -#define IVTV_CMD_AO_STOP 0x00000005 -#define IVTV_CMD_APU_PING 0x00000000 -#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE -#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE -#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF -#define IVTV_CMD_SPU_STOP 0x00000001 -#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A -#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 -#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */ - -#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg" -#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024) - -/* Encoder/decoder firmware sizes */ -#define IVTV_FW_ENC_SIZE (376836) -#define IVTV_FW_DEC_SIZE (256*1024) - -static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size) -{ - const struct firmware *fw = NULL; - int retries = 3; - -retry: - if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) { - int i; - volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; - const u32 *src = (const u32 *)fw->data; - - /* temporarily allow 256 KB encoding firmwares as well for - compatibility with blackbird cards */ - if (fw->size != size && fw->size != 256 * 1024) { - /* Due to race conditions in firmware loading (esp. with udev <0.95) - the wrong file was sometimes loaded. So we check filesizes to - see if at least the right-sized file was loaded. If not, then we - retry. */ - IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); - release_firmware(fw); - retries--; - goto retry; - } - for (i = 0; i < fw->size; i += 4) { - /* no need for endianness conversion on the ppc */ - __raw_writel(*src, dst); - dst++; - src++; - } - release_firmware(fw); - IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); - return size; - } - IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size); - IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n"); - return -ENOMEM; -} - -void ivtv_halt_firmware(struct ivtv *itv) -{ - IVTV_DEBUG_INFO("Preparing for firmware halt.\n"); - if (itv->has_cx23415 && itv->dec_mbox.mbox) - ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0); - if (itv->enc_mbox.mbox) - ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0); - - ivtv_sleep_timeout(HZ / 100, 0); - itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL; - - IVTV_DEBUG_INFO("Stopping VDM\n"); - write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM); - - IVTV_DEBUG_INFO("Stopping AO\n"); - write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO); - - IVTV_DEBUG_INFO("pinging (?) APU\n"); - write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU); - - IVTV_DEBUG_INFO("Stopping VPU\n"); - if (!itv->has_cx23415) - write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU); - else - write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU); - - IVTV_DEBUG_INFO("Resetting Hw Blocks\n"); - write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS); - - IVTV_DEBUG_INFO("Stopping SPU\n"); - write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU); - - ivtv_sleep_timeout(HZ / 100, 0); - - IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n"); - write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE); - - IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n"); - write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH); - - if (itv->has_cx23415) { - IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n"); - write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE); - - IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n"); - write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH); - } - - IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n", - (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ)); - ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0); -} - -void ivtv_firmware_versions(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - - /* Encoder */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0); - IVTV_INFO("Encoder revision: 0x%08x\n", data[0]); - - if (data[0] != 0x02060039) - IVTV_WARN("Recommended firmware version is 0x02060039.\n"); - - if (itv->has_cx23415) { - /* Decoder */ - ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0); - IVTV_INFO("Decoder revision: 0x%08x\n", data[0]); - } -} - -static int ivtv_firmware_copy(struct ivtv *itv) -{ - IVTV_DEBUG_INFO("Loading encoder image\n"); - if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME, - itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) { - IVTV_DEBUG_WARN("failed loading encoder firmware\n"); - return -3; - } - if (!itv->has_cx23415) - return 0; - - IVTV_DEBUG_INFO("Loading decoder image\n"); - if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME, - itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) { - IVTV_DEBUG_WARN("failed loading decoder firmware\n"); - return -1; - } - return 0; -} - -static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size) -{ - int i; - - /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte - address boundary */ - for (i = 0; i < size; i += 0x100) { - if (readl(mem + i) == 0x12345678 && - readl(mem + i + 4) == 0x34567812 && - readl(mem + i + 8) == 0x56781234 && - readl(mem + i + 12) == 0x78123456) { - return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16); - } - } - return NULL; -} - -int ivtv_firmware_init(struct ivtv *itv) -{ - int err; - - ivtv_halt_firmware(itv); - - /* load firmware */ - err = ivtv_firmware_copy(itv); - if (err) { - IVTV_DEBUG_WARN("Error %d loading firmware\n", err); - return err; - } - - /* start firmware */ - write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU); - ivtv_sleep_timeout(HZ / 10, 0); - if (itv->has_cx23415) - write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU); - else - write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU); - ivtv_sleep_timeout(HZ / 10, 0); - - /* find mailboxes and ping firmware */ - itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE); - if (itv->enc_mbox.mbox == NULL) - IVTV_ERR("Encoder mailbox not found\n"); - else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) { - IVTV_ERR("Encoder firmware dead!\n"); - itv->enc_mbox.mbox = NULL; - } - if (itv->enc_mbox.mbox == NULL) - return -ENODEV; - - if (!itv->has_cx23415) - return 0; - - itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); - if (itv->dec_mbox.mbox == NULL) - IVTV_ERR("Decoder mailbox not found\n"); - else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { - IVTV_ERR("Decoder firmware dead!\n"); - itv->dec_mbox.mbox = NULL; - } - return itv->dec_mbox.mbox ? 0 : -ENODEV; -} - -void ivtv_init_mpeg_decoder(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - long readbytes; - volatile u8 __iomem *mem_offset; - - data[0] = 0; - data[1] = itv->params.width; /* YUV source width */ - data[2] = itv->params.height; - data[3] = itv->params.audio_properties; /* Audio settings to use, - bitmap. see docs. */ - if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { - IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); - return; - } - - if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { - IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); - return; - } - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); - mem_offset = itv->dec_mem + data[1]; - - if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, - mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { - IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", - IVTV_DECODE_INIT_MPEG_FILENAME); - } else { - ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); - ivtv_sleep_timeout(HZ / 10, 0); - } - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-firmware.h b/trunk/drivers/media/video/ivtv/ivtv-firmware.h deleted file mode 100644 index 8b2ffe658905..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-firmware.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - ivtv firmware functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -int ivtv_firmware_init(struct ivtv *itv); -void ivtv_firmware_versions(struct ivtv *itv); -void ivtv_halt_firmware(struct ivtv *itv); -void ivtv_init_mpeg_decoder(struct ivtv *itv); diff --git a/trunk/drivers/media/video/ivtv/ivtv-gpio.c b/trunk/drivers/media/video/ivtv/ivtv-gpio.c deleted file mode 100644 index bc8f8ca2961f..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-gpio.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - gpio functions. - Merging GPIO support into driver: - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-gpio.h" -#include - -/* - * GPIO assignment of Yuan MPG600/MPG160 - * - * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 - * OUTPUT IN1 IN0 AM3 AM2 AM1 AM0 - * INPUT DM1 DM0 - * - * IN* : Input selection - * IN1 IN0 - * 1 1 N/A - * 1 0 Line - * 0 1 N/A - * 0 0 Tuner - * - * AM* : Audio Mode - * AM3 0: Normal 1: Mixed(Sub+Main channel) - * AM2 0: Subchannel 1: Main channel - * AM1 0: Stereo 1: Mono - * AM0 0: Normal 1: Mute - * - * DM* : Detected tuner audio Mode - * DM1 0: Stereo 1: Mono - * DM0 0: Multiplex 1: Normal - * - * GPIO Initial Settings - * MPG600 MPG160 - * DIR 0x3080 0x7080 - * OUTPUT 0x000C 0x400C - * - * Special thanks to Makoto Iguchi and Mr. Anonymous - * for analyzing GPIO of MPG160. - * - ***************************************************************************** - * - * GPIO assignment of Avermedia M179 (per information direct from AVerMedia) - * - * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 - * OUTPUT IN0 AM0 IN1 AM1 AM2 IN2 BR0 BR1 - * INPUT - * - * IN* : Input selection - * IN0 IN1 IN2 - * * 1 * Mute - * 0 0 0 Line-In - * 1 0 0 TV Tuner Audio - * 0 0 1 FM Audio - * 1 0 1 Mute - * - * AM* : Audio Mode - * AM0 AM1 AM2 - * 0 0 0 TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP - * 0 0 1 TV Tuner Audio: L_OUT=R_OUT=SAP (SAP) - * 0 1 0 TV Tuner Audio: L_OUT=L, R_OUT=R (stereo) - * 0 1 1 TV Tuner Audio: mute - * 1 * * TV Tuner Audio: L_OUT=R_OUT=(L+R)/2 (mono) - * - * BR* : Audio Sample Rate (BR stands for bitrate for some reason) - * BR0 BR1 - * 0 0 32 kHz - * 0 1 44.1 kHz - * 1 0 48 kHz - * - * DM* : Detected tuner audio Mode - * Unknown currently - * - * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at - * AVerMedia for providing the GPIO information used to add support - * for the M179 cards. - */ - -/********************* GPIO stuffs *********************/ - -/* GPIO registers */ -#define IVTV_REG_GPIO_IN 0x9008 -#define IVTV_REG_GPIO_OUT 0x900c -#define IVTV_REG_GPIO_DIR 0x9020 - -void ivtv_reset_ir_gpio(struct ivtv *itv) -{ - int curdir, curout; - - if (itv->card->type != IVTV_CARD_PVR_150) - return; - IVTV_DEBUG_INFO("Resetting PVR150 IR\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= 0x80; - write_reg(curdir, IVTV_REG_GPIO_DIR); - curout = (curout & ~0xF) | 1; - write_reg(curout, IVTV_REG_GPIO_OUT); - /* We could use something else for smaller time */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - curout |= 2; - write_reg(curout, IVTV_REG_GPIO_OUT); - curdir &= ~0x80; - write_reg(curdir, IVTV_REG_GPIO_DIR); -} - -#ifdef HAVE_XC3028 -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) -{ - int curdir, curout; - struct ivtv *itv = (struct ivtv *) priv; - - if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) - return -EINVAL; - IVTV_INFO("Resetting tuner.\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - - curout |= (1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - - return 0; -} -#endif - -void ivtv_gpio_init(struct ivtv *itv) -{ - if (itv->card->gpio_init.direction == 0) - return; - - IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", - read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); - - /* init output data then direction */ - write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT); - write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR); -} - -static struct v4l2_queryctrl gpio_ctrl_mute = { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0, -}; - -int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg) -{ - struct v4l2_tuner *tuner = arg; - struct v4l2_control *ctrl = arg; - struct v4l2_routing *route = arg; - u16 mask, data; - - switch (command) { - case VIDIOC_INT_AUDIO_CLOCK_FREQ: - mask = itv->card->gpio_audio_freq.mask; - switch (*(u32 *)arg) { - case 32000: - data = itv->card->gpio_audio_freq.f32000; - break; - case 44100: - data = itv->card->gpio_audio_freq.f44100; - break; - case 48000: - default: - data = itv->card->gpio_audio_freq.f48000; - break; - } - break; - - case VIDIOC_G_TUNER: - mask = itv->card->gpio_audio_detect.mask; - if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) - tuner->rxsubchans = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - else - tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - return 0; - - case VIDIOC_S_TUNER: - mask = itv->card->gpio_audio_mode.mask; - switch (tuner->audmode) { - case V4L2_TUNER_MODE_LANG1: - data = itv->card->gpio_audio_mode.lang1; - break; - case V4L2_TUNER_MODE_LANG2: - data = itv->card->gpio_audio_mode.lang2; - break; - case V4L2_TUNER_MODE_MONO: - data = itv->card->gpio_audio_mode.mono; - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - default: - data = itv->card->gpio_audio_mode.stereo; - break; - } - break; - - case AUDC_SET_RADIO: - mask = itv->card->gpio_audio_input.mask; - data = itv->card->gpio_audio_input.radio; - break; - - case VIDIOC_S_STD: - mask = itv->card->gpio_audio_input.mask; - data = itv->card->gpio_audio_input.tuner; - break; - - case VIDIOC_INT_S_AUDIO_ROUTING: - if (route->input > 2) - return -EINVAL; - mask = itv->card->gpio_audio_input.mask; - switch (route->input) { - case 0: - data = itv->card->gpio_audio_input.tuner; - break; - case 1: - data = itv->card->gpio_audio_input.linein; - break; - case 2: - default: - data = itv->card->gpio_audio_input.radio; - break; - } - break; - - case VIDIOC_G_CTRL: - if (ctrl->id != V4L2_CID_AUDIO_MUTE) - return -EINVAL; - mask = itv->card->gpio_audio_mute.mask; - data = itv->card->gpio_audio_mute.mute; - ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data; - return 0; - - case VIDIOC_S_CTRL: - if (ctrl->id != V4L2_CID_AUDIO_MUTE) - return -EINVAL; - mask = itv->card->gpio_audio_mute.mask; - data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0; - break; - - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - - if (qc->id != V4L2_CID_AUDIO_MUTE) - return -EINVAL; - *qc = gpio_ctrl_mute; - return 0; - } - - case VIDIOC_LOG_STATUS: - IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", - read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), - read_reg(IVTV_REG_GPIO_IN)); - return 0; - - case VIDIOC_INT_S_VIDEO_ROUTING: - if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */ - return -EINVAL; - mask = itv->card->gpio_video_input.mask; - if (route->input == 0) - data = itv->card->gpio_video_input.tuner; - else if (route->input == 1) - data = itv->card->gpio_video_input.composite; - else - data = itv->card->gpio_video_input.svideo; - break; - - default: - return -EINVAL; - } - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-gpio.h b/trunk/drivers/media/video/ivtv/ivtv-gpio.h deleted file mode 100644 index c301d2a39346..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-gpio.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - gpio functions. - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -/* GPIO stuff */ -void ivtv_gpio_init(struct ivtv *itv); -void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); -int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); diff --git a/trunk/drivers/media/video/ivtv/ivtv-i2c.c b/trunk/drivers/media/video/ivtv/ivtv-i2c.c deleted file mode 100644 index 50624c6a62a5..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-i2c.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - I2C functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - This file includes an i2c implementation that was reverse engineered - from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, - which whilst fine under most circumstances, had trouble with the Zilog - CPU on the PVR-150 which handles IR functions (occasional inability to - communicate with the chip until it was reset) and also with the i2c - bus being completely unreachable when multiple PVR cards were present. - - The implementation is very similar to i2c-algo-bit, but there are enough - subtle differences that the two are hard to merge. The general strategy - employed by i2c-algo-bit is to use udelay() to implement the timing - when putting out bits on the scl/sda lines. The general strategy taken - here is to poll the lines for state changes (see ivtv_waitscl and - ivtv_waitsda). In addition there are small delays at various locations - which poll the SCL line 5 times (ivtv_scldelay). I would guess that - since this is memory mapped I/O that the length of those delays is tied - to the PCI bus clock. There is some extra code to do with recovery - and retries. Since it is not known what causes the actual i2c problems - in the first place, the only goal if one was to attempt to use - i2c-algo-bit would be to try to make it follow the same code path. - This would be a lot of work, and I'm also not convinced that it would - provide a generic benefit to i2c-algo-bit. Therefore consider this - an engineering solution -- not pretty, but it works. - - Some more general comments about what we are doing: - - The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) - lines. To communicate on the bus (as a master, we don't act as a slave), - we first initiate a start condition (ivtv_start). We then write the - address of the device that we want to communicate with, along with a flag - that indicates whether this is a read or a write. The slave then issues - an ACK signal (ivtv_ack), which tells us that it is ready for reading / - writing. We then proceed with reading or writing (ivtv_read/ivtv_write), - and finally issue a stop condition (ivtv_stop) to make the bus available - to other masters. - - There is an additional form of transaction where a write may be - immediately followed by a read. In this case, there is no intervening - stop condition. (Only the msp3400 chip uses this method of data transfer). - */ - -#include "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-gpio.h" -#include "ivtv-i2c.h" - -#include - -/* i2c implementation for cx23415/6 chip, ivtv project. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - */ -/* i2c stuff */ -#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 -#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 -#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 -#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c - -#ifndef I2C_ADAP_CLASS_TV_ANALOG -#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG -#endif /* I2C_ADAP_CLASS_TV_ANALOG */ - -#define IVTV_CS53L32A_I2C_ADDR 0x11 -#define IVTV_CX25840_I2C_ADDR 0x44 -#define IVTV_SAA7115_I2C_ADDR 0x21 -#define IVTV_SAA7127_I2C_ADDR 0x44 -#define IVTV_SAA717x_I2C_ADDR 0x21 -#define IVTV_MSP3400_I2C_ADDR 0x40 -#define IVTV_HAUPPAUGE_I2C_ADDR 0x50 -#define IVTV_WM8739_I2C_ADDR 0x1a -#define IVTV_WM8775_I2C_ADDR 0x1b -#define IVTV_TEA5767_I2C_ADDR 0x60 -#define IVTV_UPD64031A_I2C_ADDR 0x12 -#define IVTV_UPD64083_I2C_ADDR 0x5c -#define IVTV_TDA985X_I2C_ADDR 0x5b - -/* This array should match the IVTV_HW_ defines */ -static const u8 hw_driverids[] = { - I2C_DRIVERID_CX25840, - I2C_DRIVERID_SAA711X, - I2C_DRIVERID_SAA7127, - I2C_DRIVERID_MSP3400, - I2C_DRIVERID_TUNER, - I2C_DRIVERID_WM8775, - I2C_DRIVERID_CS53L32A, - I2C_DRIVERID_TVEEPROM, - I2C_DRIVERID_SAA711X, - I2C_DRIVERID_TVAUDIO, - I2C_DRIVERID_UPD64031A, - I2C_DRIVERID_UPD64083, - I2C_DRIVERID_SAA717X, - I2C_DRIVERID_WM8739, - 0 /* IVTV_HW_GPIO dummy driver ID */ -}; - -/* This array should match the IVTV_HW_ defines */ -static const char * const hw_drivernames[] = { - "cx2584x", - "saa7115", - "saa7127", - "msp3400", - "tuner", - "wm8775", - "cs53l32a", - "tveeprom", - "saa7114", - "tvaudio", - "upd64031a", - "upd64083", - "saa717x", - "wm8739", - "gpio", -}; - -static int attach_inform(struct i2c_client *client) -{ - struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); - int i; - - IVTV_DEBUG_I2C("i2c client attach\n"); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (itv->i2c_clients[i] == NULL) { - itv->i2c_clients[i] = client; - break; - } - } - if (i == I2C_CLIENTS_MAX) { - IVTV_ERR("insufficient room for new I2C client!\n"); - } - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - int i; - struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); - - IVTV_DEBUG_I2C("i2c client detach\n"); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (itv->i2c_clients[i] == client) { - itv->i2c_clients[i] = NULL; - break; - } - } - IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n", - client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); - - return 0; -} - -/* Set the serial clock line to the desired state */ -static void ivtv_setscl(struct ivtv *itv, int state) -{ - /* write them out */ - /* write bits are inverted */ - write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); -} - -/* Set the serial data line to the desired state */ -static void ivtv_setsda(struct ivtv *itv, int state) -{ - /* write them out */ - /* write bits are inverted */ - write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); -} - -/* Read the serial clock line */ -static int ivtv_getscl(struct ivtv *itv) -{ - return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; -} - -/* Read the serial data line */ -static int ivtv_getsda(struct ivtv *itv) -{ - return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; -} - -/* Implement a short delay by polling the serial clock line */ -static void ivtv_scldelay(struct ivtv *itv) -{ - int i; - - for (i = 0; i < 5; ++i) - ivtv_getscl(itv); -} - -/* Wait for the serial clock line to become set to a specific value */ -static int ivtv_waitscl(struct ivtv *itv, int val) -{ - int i; - - ivtv_scldelay(itv); - for (i = 0; i < 1000; ++i) { - if (ivtv_getscl(itv) == val) - return 1; - } - return 0; -} - -/* Wait for the serial data line to become set to a specific value */ -static int ivtv_waitsda(struct ivtv *itv, int val) -{ - int i; - - ivtv_scldelay(itv); - for (i = 0; i < 1000; ++i) { - if (ivtv_getsda(itv) == val) - return 1; - } - return 0; -} - -/* Wait for the slave to issue an ACK */ -static int ivtv_ack(struct ivtv *itv) -{ - int ret = 0; - - if (ivtv_getscl(itv) == 1) { - IVTV_DEBUG_I2C("SCL was high starting an ack\n"); - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); - return -EREMOTEIO; - } - } - ivtv_setsda(itv, 1); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitsda(itv, 0)) { - IVTV_DEBUG_I2C("Slave did not ack\n"); - ret = -EREMOTEIO; - } - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); - ret = -EREMOTEIO; - } - return ret; -} - -/* Write a single byte to the i2c bus and wait for the slave to ACK */ -static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) -{ - int i, bit; - - IVTV_DEBUG_I2C("write %x\n",byte); - for (i = 0; i < 8; ++i, byte<<=1) { - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Error setting SCL low\n"); - return -EREMOTEIO; - } - bit = (byte>>7)&1; - ivtv_setsda(itv, bit); - if (!ivtv_waitsda(itv, bit)) { - IVTV_DEBUG_I2C("Error setting SDA\n"); - return -EREMOTEIO; - } - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("Slave not ready for bit\n"); - return -EREMOTEIO; - } - } - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Error setting SCL low\n"); - return -EREMOTEIO; - } - return ivtv_ack(itv); -} - -/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the - final byte) */ -static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) -{ - int i; - - *byte = 0; - - ivtv_setsda(itv, 1); - ivtv_scldelay(itv); - for (i = 0; i < 8; ++i) { - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("Error setting SCL high\n"); - return -EREMOTEIO; - } - *byte = ((*byte)<<1)|ivtv_getsda(itv); - } - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setsda(itv, nack); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - ivtv_scldelay(itv); - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - IVTV_DEBUG_I2C("read %x\n",*byte); - return 0; -} - -/* Issue a start condition on the i2c bus to alert slaves to prepare for - an address write */ -static int ivtv_start(struct ivtv *itv) -{ - int sda; - - sda = ivtv_getsda(itv); - if (sda != 1) { - IVTV_DEBUG_I2C("SDA was low at start\n"); - ivtv_setsda(itv, 1); - if (!ivtv_waitsda(itv, 1)) { - IVTV_DEBUG_I2C("SDA stuck low\n"); - return -EREMOTEIO; - } - } - if (ivtv_getscl(itv) != 1) { - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("SCL stuck low at start\n"); - return -EREMOTEIO; - } - } - ivtv_setsda(itv, 0); - ivtv_scldelay(itv); - return 0; -} - -/* Issue a stop condition on the i2c bus to release it */ -static int ivtv_stop(struct ivtv *itv) -{ - int i; - - if (ivtv_getscl(itv) != 0) { - IVTV_DEBUG_I2C("SCL not low when stopping\n"); - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("SCL could not be set low\n"); - } - } - ivtv_setsda(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("SCL could not be set high\n"); - return -EREMOTEIO; - } - ivtv_scldelay(itv); - ivtv_setsda(itv, 1); - if (!ivtv_waitsda(itv, 1)) { - IVTV_DEBUG_I2C("resetting I2C\n"); - for (i = 0; i < 16; ++i) { - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - ivtv_scldelay(itv); - ivtv_setsda(itv, 1); - } - ivtv_waitsda(itv, 1); - return -EREMOTEIO; - } - return 0; -} - -/* Write a message to the given i2c slave. do_stop may be 0 to prevent - issuing the i2c stop condition (when following with a read) */ -static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) -{ - int retry, ret = -EREMOTEIO; - u32 i; - - for (retry = 0; ret != 0 && retry < 8; ++retry) { - ret = ivtv_start(itv); - - if (ret == 0) { - ret = ivtv_sendbyte(itv, addr<<1); - for (i = 0; ret == 0 && i < len; ++i) - ret = ivtv_sendbyte(itv, data[i]); - } - if (ret != 0 || do_stop) { - ivtv_stop(itv); - } - } - if (ret) - IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); - return ret; -} - -/* Read data from the given i2c slave. A stop condition is always issued. */ -static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) -{ - int retry, ret = -EREMOTEIO; - u32 i; - - for (retry = 0; ret != 0 && retry < 8; ++retry) { - ret = ivtv_start(itv); - if (ret == 0) - ret = ivtv_sendbyte(itv, (addr << 1) | 1); - for (i = 0; ret == 0 && i < len; ++i) { - ret = ivtv_readbyte(itv, &data[i], i == len - 1); - } - ivtv_stop(itv); - } - if (ret) - IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); - return ret; -} - -/* Kernel i2c transfer implementation. Takes a number of messages to be read - or written. If a read follows a write, this will occur without an - intervening stop condition */ -static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct ivtv *itv = i2c_get_adapdata(i2c_adap); - int retval; - int i; - - mutex_lock(&itv->i2c_bus_lock); - for (i = retval = 0; retval == 0 && i < num; i++) { - if (msgs[i].flags & I2C_M_RD) - retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); - else { - /* if followed by a read, don't stop */ - int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); - - retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); - } - } - mutex_unlock(&itv->i2c_bus_lock); - return retval ? retval : num; -} - -/* Kernel i2c capabilities */ -static u32 ivtv_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ivtv_algo = { - .master_xfer = ivtv_xfer, - .functionality = ivtv_functionality, -}; - -/* template for our-bit banger */ -static struct i2c_adapter ivtv_i2c_adap_hw_template = { - .name = "ivtv i2c driver", - .id = I2C_HW_B_CX2341X, - .algo = &ivtv_algo, - .algo_data = NULL, /* filled from template */ - .client_register = attach_inform, - .client_unregister = detach_inform, - .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif -}; - -static void ivtv_setscl_old(void *data, int state) -{ - struct ivtv *itv = (struct ivtv *)data; - - if (state) - itv->i2c_state |= 0x01; - else - itv->i2c_state &= ~0x01; - - /* write them out */ - /* write bits are inverted */ - write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); -} - -static void ivtv_setsda_old(void *data, int state) -{ - struct ivtv *itv = (struct ivtv *)data; - - if (state) - itv->i2c_state |= 0x01; - else - itv->i2c_state &= ~0x01; - - /* write them out */ - /* write bits are inverted */ - write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); -} - -static int ivtv_getscl_old(void *data) -{ - struct ivtv *itv = (struct ivtv *)data; - - return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; -} - -static int ivtv_getsda_old(void *data) -{ - struct ivtv *itv = (struct ivtv *)data; - - return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; -} - -/* template for i2c-bit-algo */ -static struct i2c_adapter ivtv_i2c_adap_template = { - .name = "ivtv i2c driver", - .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ - .algo = NULL, /* set by i2c-algo-bit */ - .algo_data = NULL, /* filled from template */ - .client_register = attach_inform, - .client_unregister = detach_inform, - .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif -}; - -static struct i2c_algo_bit_data ivtv_i2c_algo_template = { - NULL, /* ?? */ - ivtv_setsda_old, /* setsda function */ - ivtv_setscl_old, /* " */ - ivtv_getsda_old, /* " */ - ivtv_getscl_old, /* " */ - 10, /* udelay */ - 200 /* timeout */ -}; - -static struct i2c_client ivtv_i2c_client_template = { - .name = "ivtv internal", -}; - -int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg) -{ - struct i2c_client *client; - int retval; - int i; - - IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - client = itv->i2c_clients[i]; - if (client == NULL) { - continue; - } - if (client->driver->command == NULL) { - continue; - } - if (addr == client->addr) { - retval = client->driver->command(client, cmd, arg); - return retval; - } - } - if (cmd != VIDIOC_G_CHIP_IDENT) - IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd); - return -ENODEV; -} - -/* Find the i2c device based on the driver ID and return - its i2c address or -ENODEV if no matching device was found. */ -static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) -{ - struct i2c_client *client; - int retval = -ENODEV; - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - client = itv->i2c_clients[i]; - if (client == NULL) - continue; - if (id == client->driver->id) { - retval = client->addr; - break; - } - } - return retval; -} - -/* Find the i2c device name matching the DRIVERID */ -static const char *ivtv_i2c_id_name(u32 id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) - if (hw_driverids[i] == id) - return hw_drivernames[i]; - return "unknown device"; -} - -/* Find the i2c device name matching the IVTV_HW_ flag */ -static const char *ivtv_i2c_hw_name(u32 hw) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) - if (1 << i == hw) - return hw_drivernames[i]; - return "unknown device"; -} - -/* Find the i2c device matching the IVTV_HW_ flag and return - its i2c address or -ENODEV if no matching device was found. */ -int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) - if (1 << i == hw) - return ivtv_i2c_id_addr(itv, hw_driverids[i]); - return -ENODEV; -} - -/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing. - If hw == IVTV_HW_GPIO then call the gpio handler. */ -int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg) -{ - int addr; - - if (hw == IVTV_HW_GPIO) - return ivtv_gpio(itv, cmd, arg); - if (hw == 0) - return 0; - - addr = ivtv_i2c_hw_addr(itv, hw); - if (addr < 0) { - IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n", - hw, ivtv_i2c_hw_name(hw), cmd); - return addr; - } - return ivtv_call_i2c_client(itv, addr, cmd, arg); -} - -/* Calls i2c device based on I2C driver ID. */ -int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg) -{ - int addr; - - addr = ivtv_i2c_id_addr(itv, id); - if (addr < 0) { - if (cmd != VIDIOC_G_CHIP_IDENT) - IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n", - id, ivtv_i2c_id_name(id), cmd); - return addr; - } - return ivtv_call_i2c_client(itv, addr, cmd, arg); -} - -int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg); -} - -int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg); -} - -int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg); -} - -int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg); -} - -int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg); -} - -int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg) -{ - return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg); -} - -/* broadcast cmd for all I2C clients and for the gpio subsystem */ -void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg) -{ - if (itv->i2c_adap.algo == NULL) { - IVTV_ERR("adapter is not set"); - return; - } - i2c_clients_command(&itv->i2c_adap, cmd, arg); - if (itv->hw_flags & IVTV_HW_GPIO) - ivtv_gpio(itv, cmd, arg); -} - -/* init + register i2c algo-bit adapter */ -int __devinit init_ivtv_i2c(struct ivtv *itv) -{ - IVTV_DEBUG_I2C("i2c init\n"); - - if (itv->options.newi2c > 0) { - memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, - sizeof(struct i2c_adapter)); - } else { - memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, - sizeof(struct i2c_adapter)); - memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, - sizeof(struct i2c_algo_bit_data)); - itv->i2c_algo.data = itv; - itv->i2c_adap.algo_data = &itv->i2c_algo; - } - - sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", - itv->num); - i2c_set_adapdata(&itv->i2c_adap, itv); - - memcpy(&itv->i2c_client, &ivtv_i2c_client_template, - sizeof(struct i2c_client)); - itv->i2c_client.adapter = &itv->i2c_adap; - itv->i2c_adap.dev.parent = &itv->dev->dev; - - IVTV_DEBUG_I2C("setting scl and sda to 1\n"); - ivtv_setscl(itv, 1); - ivtv_setsda(itv, 1); - - if (itv->options.newi2c > 0) - return i2c_add_adapter(&itv->i2c_adap); - else - return i2c_bit_add_bus(&itv->i2c_adap); -} - -void __devexit exit_ivtv_i2c(struct ivtv *itv) -{ - IVTV_DEBUG_I2C("i2c exit\n"); - - i2c_del_adapter(&itv->i2c_adap); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-i2c.h b/trunk/drivers/media/video/ivtv/ivtv-i2c.h deleted file mode 100644 index 5d210adb5c52..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-i2c.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - I2C functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg); - -int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw); -int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); -int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); -int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); -void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); - -/* init + register i2c algo-bit adapter */ -int __devinit init_ivtv_i2c(struct ivtv *itv); -void __devexit exit_ivtv_i2c(struct ivtv *itv); diff --git a/trunk/drivers/media/video/ivtv/ivtv-ioctl.c b/trunk/drivers/media/video/ivtv/ivtv-ioctl.c deleted file mode 100644 index 794a6a02f82f..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-ioctl.c +++ /dev/null @@ -1,1567 +0,0 @@ -/* - ioctl system call - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-version.h" -#include "ivtv-mailbox.h" -#include "ivtv-i2c.h" -#include "ivtv-queue.h" -#include "ivtv-fileops.h" -#include "ivtv-vbi.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" -#include "ivtv-streams.h" -#include "ivtv-yuv.h" -#include "ivtv-ioctl.h" -#include "ivtv-gpio.h" -#include "ivtv-controls.h" -#include "ivtv-cards.h" -#include -#include -#include -#include -#include - -u16 service2vbi(int type) -{ - switch (type) { - case V4L2_SLICED_TELETEXT_B: - return IVTV_SLICED_TYPE_TELETEXT_B; - case V4L2_SLICED_CAPTION_525: - return IVTV_SLICED_TYPE_CAPTION_525; - case V4L2_SLICED_WSS_625: - return IVTV_SLICED_TYPE_WSS_625; - case V4L2_SLICED_VPS: - return IVTV_SLICED_TYPE_VPS; - default: - return 0; - } -} - -static int valid_service_line(int field, int line, int is_pal) -{ - return (is_pal && line >= 6 && (line != 23 || field == 0)) || - (!is_pal && line >= 10 && line < 22); -} - -static u16 select_service_from_set(int field, int line, u16 set, int is_pal) -{ - u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); - int i; - - set = set & valid_set; - if (set == 0 || !valid_service_line(field, line, is_pal)) { - return 0; - } - if (!is_pal) { - if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) - return V4L2_SLICED_CAPTION_525; - } - else { - if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) - return V4L2_SLICED_VPS; - if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) - return V4L2_SLICED_WSS_625; - if (line == 23) - return 0; - } - for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; - } - return 0; -} - -void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - u16 set = fmt->service_set; - int f, l; - - fmt->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); - } - } -} - -static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); - set |= fmt->service_lines[f][l]; - } - } - return set != 0; -} - -u16 get_service_set(struct v4l2_sliced_vbi_format *fmt) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - set |= fmt->service_lines[f][l]; - } - } - return set; -} - -static const struct { - v4l2_std_id std; - char *name; -} enum_stds[] = { - { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, - { V4L2_STD_PAL_DK, "PAL-DK" }, - { V4L2_STD_PAL_I, "PAL-I" }, - { V4L2_STD_PAL_M, "PAL-M" }, - { V4L2_STD_PAL_N, "PAL-N" }, - { V4L2_STD_PAL_Nc, "PAL-Nc" }, - { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, - { V4L2_STD_SECAM_DK, "SECAM-DK" }, - { V4L2_STD_SECAM_L, "SECAM-L" }, - { V4L2_STD_SECAM_LC, "SECAM-L'" }, - { V4L2_STD_NTSC_M, "NTSC-M" }, - { V4L2_STD_NTSC_M_JP, "NTSC-J" }, - { V4L2_STD_NTSC_M_KR, "NTSC-K" }, -}; - -static const struct v4l2_standard ivtv_std_60hz = -{ - .frameperiod = {.numerator = 1001, .denominator = 30000}, - .framelines = 525, -}; - -static const struct v4l2_standard ivtv_std_50hz = -{ - .frameperiod = {.numerator = 1, .denominator = 25}, - .framelines = 625, -}; - -void ivtv_set_osd_alpha(struct ivtv *itv) -{ - ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, - itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); - ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); -} - -int ivtv_set_speed(struct ivtv *itv, int speed) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - int single_step = (speed == 1 || speed == -1); - DEFINE_WAIT(wait); - - if (speed == 0) speed = 1000; - - /* No change? */ - if (speed == itv->speed && !single_step) - return 0; - - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - - if (single_step && (speed < 0) == (itv->speed < 0)) { - /* Single step video and no need to change direction */ - ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); - itv->speed = speed; - return 0; - } - if (single_step) - /* Need to change direction */ - speed = speed < 0 ? -1000 : 1000; - - data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; - data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; - data[1] = (speed < 0); - data[2] = speed < 0 ? 3 : 7; - data[3] = itv->params.video_b_frames; - data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; - data[5] = 0; - data[6] = 0; - - if (speed == 1500 || speed == -1500) data[0] |= 1; - else if (speed == 2000 || speed == -2000) data[0] |= 2; - else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); - else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); - - /* If not decoding, just change speed setting */ - if (atomic_read(&itv->decoding) > 0) { - int got_sig = 0; - - /* Stop all DMA and decoding activity */ - ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); - - /* Wait for any DMA to finish */ - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - while (itv->i_flags & IVTV_F_I_DMA) { - got_sig = signal_pending(current); - if (got_sig) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - if (got_sig) - return -EINTR; - - /* Change Speed safely */ - ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); - IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", - data[0], data[1], data[2], data[3], data[4], data[5], data[6]); - } - if (single_step) { - speed = (speed < 0) ? -1 : 1; - ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); - } - itv->speed = speed; - return 0; -} - -static int ivtv_validate_speed(int cur_speed, int new_speed) -{ - int fact = new_speed < 0 ? -1 : 1; - int s; - - if (new_speed < 0) new_speed = -new_speed; - if (cur_speed < 0) cur_speed = -cur_speed; - - if (cur_speed <= new_speed) { - if (new_speed > 1500) return fact * 2000; - if (new_speed > 1000) return fact * 1500; - } - else { - if (new_speed >= 2000) return fact * 2000; - if (new_speed >= 1500) return fact * 1500; - if (new_speed >= 1000) return fact * 1000; - } - if (new_speed == 0) return 1000; - if (new_speed == 1 || new_speed == 1000) return fact * new_speed; - - s = new_speed; - new_speed = 1000 / new_speed; - if (1000 / cur_speed == new_speed) - new_speed += (cur_speed < s) ? -1 : 1; - if (new_speed > 60) return 1000 / (fact * 60); - return 1000 / (fact * new_speed); -} - -static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, - struct video_command *vc, int try) -{ - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - switch (vc->cmd) { - case VIDEO_CMD_PLAY: { - vc->flags = 0; - vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); - if (vc->play.speed < 0) - vc->play.format = VIDEO_PLAY_FMT_GOP; - if (try) break; - - if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) - return -EBUSY; - return ivtv_start_decoding(id, vc->play.speed); - } - - case VIDEO_CMD_STOP: - vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; - if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) - vc->stop.pts = 0; - if (try) break; - if (atomic_read(&itv->decoding) == 0) - return 0; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - - itv->output_mode = OUT_NONE; - return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); - - case VIDEO_CMD_FREEZE: - vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - if (atomic_read(&itv->decoding) > 0) { - ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, - (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); - } - break; - - case VIDEO_CMD_CONTINUE: - vc->flags = 0; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - if (atomic_read(&itv->decoding) > 0) { - ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0); - } - break; - - default: - return -EINVAL; - } - return 0; -} - -static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) -{ - struct v4l2_register *regs = arg; - unsigned long flags; - volatile u8 __iomem *reg_start; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) - reg_start = itv->reg_mem - IVTV_REG_OFFSET; - else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && - regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) - reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; - else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) - reg_start = itv->enc_mem; - else - return -EINVAL; - - spin_lock_irqsave(&ivtv_cards_lock, flags); - if (cmd == VIDIOC_DBG_G_REGISTER) { - regs->val = readl(regs->reg + reg_start); - } else { - writel(regs->val, regs->reg + reg_start); - } - spin_unlock_irqrestore(&ivtv_cards_lock, flags); - return 0; -} - -static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.pix.left = itv->main_rect.left; - fmt->fmt.pix.top = itv->main_rect.top; - fmt->fmt.pix.width = itv->main_rect.width; - fmt->fmt.pix.height = itv->main_rect.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (itv->output_mode == OUT_UDMA_YUV) { - switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { - case IVTV_YUV_MODE_INTERLACED: - fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? - V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; - break; - case IVTV_YUV_MODE_PROGRESSIVE: - fmt->fmt.pix.field = V4L2_FIELD_NONE; - break; - default: - fmt->fmt.pix.field = V4L2_FIELD_ANY; - break; - } - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } - else if (itv->output_mode == OUT_YUV || - streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } else { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.sizeimage = 128 * 1024; - } - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - fmt->fmt.pix.left = 0; - fmt->fmt.pix.top = 0; - fmt->fmt.pix.width = itv->params.width; - fmt->fmt.pix.height = itv->params.height; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } else { - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.sizeimage = 128 * 1024; - } - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_color_key; - fmt->fmt.win.global_alpha = itv->osd_global_alpha; - break; - - case V4L2_BUF_TYPE_VBI_CAPTURE: - fmt->fmt.vbi.sampling_rate = 27000000; - fmt->fmt.vbi.offset = 248; - fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4; - fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - fmt->fmt.vbi.start[0] = itv->vbi.start[0]; - fmt->fmt.vbi.start[1] = itv->vbi.start[1]; - fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count; - break; - - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); - if (itv->is_60hz) { - vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; - vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; - } - vbifmt->service_set = get_service_set(vbifmt); - break; - } - - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); - - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { - vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : - V4L2_SLICED_VBI_525; - expand_service_set(vbifmt, itv->is_50hz); - break; - } - - itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); - vbifmt->service_set = get_service_set(vbifmt); - break; - } - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - return 0; -} - -static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, - struct v4l2_format *fmt, int set_fmt) -{ - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - u16 set; - - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - struct v4l2_rect r; - int field; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - field = fmt->fmt.pix.field; - r.top = fmt->fmt.pix.top; - r.left = fmt->fmt.pix.left; - r.width = fmt->fmt.pix.width; - r.height = fmt->fmt.pix.height; - ivtv_get_fmt(itv, streamtype, fmt); - if (itv->output_mode != OUT_UDMA_YUV) { - /* TODO: would setting the rect also be valid for this mode? */ - fmt->fmt.pix.top = r.top; - fmt->fmt.pix.left = r.left; - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - } - if (itv->output_mode == OUT_UDMA_YUV) { - /* TODO: add checks for validity */ - fmt->fmt.pix.field = field; - } - if (set_fmt) { - if (itv->output_mode == OUT_UDMA_YUV) { - switch (field) { - case V4L2_FIELD_NONE: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - itv->yuv_info.lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; - - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - return 0; - } - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - r.width, r.height, r.left, r.top)) - itv->main_rect = r; - else - return -EINVAL; - } - return 0; - } - - if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - if (set_fmt) { - itv->osd_color_key = fmt->fmt.win.chromakey; - itv->osd_global_alpha = fmt->fmt.win.global_alpha; - ivtv_set_osd_alpha(itv); - } - return 0; - } - - /* set window size */ - if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - - if (w > 720) w = 720; - else if (w < 1) w = 1; - if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480); - else if (h < 2) h = 2; - ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - - if (!set_fmt || (itv->params.width == w && itv->params.height == h)) - return 0; - if (atomic_read(&itv->capturing) > 0) - return -EBUSY; - - itv->params.width = w; - itv->params.height = h; - if (w != 720 || h != (itv->is_50hz ? 576 : 480)) - itv->params.video_temporal_filter = 0; - else - itv->params.video_temporal_filter = 8; - itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); - return ivtv_get_fmt(itv, streamtype, fmt); - } - - /* set raw VBI format */ - if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && - itv->vbi.sliced_in->service_set && - atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - if (set_fmt) { - itv->vbi.sliced_in->service_set = 0; - itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); - } - return ivtv_get_fmt(itv, streamtype, fmt); - } - - /* set sliced VBI output - In principle the user could request that only certain - VBI types are output and that the others are ignored. - I.e., suppress CC in the even fields or only output - WSS and no VPS. Currently though there is no choice. */ - if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return ivtv_get_fmt(itv, streamtype, fmt); - - /* any else but sliced VBI capture is an error */ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) - return ivtv_get_fmt(itv, streamtype, fmt); - - /* set sliced VBI capture format */ - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); - - if (vbifmt->service_set) - expand_service_set(vbifmt, itv->is_50hz); - set = check_service_set(vbifmt, itv->is_50hz); - vbifmt->service_set = get_service_set(vbifmt); - - if (!set_fmt) - return 0; - if (set == 0) - return -EINVAL; - if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { - return -EBUSY; - } - itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); - memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); - return 0; -} - -static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) -{ - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - struct v4l2_register *reg = arg; - - switch (cmd) { - /* ioctls to allow direct access to the encoder registers for testing */ - case VIDIOC_DBG_G_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - - case VIDIOC_DBG_S_REGISTER: - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return ivtv_itvc(itv, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - - case VIDIOC_G_CHIP_IDENT: { - struct v4l2_chip_ident *chip = arg; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { - struct v4l2_chip_ident *chip = arg; - - chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - } - return 0; - } - if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) - return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); - if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) - return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); - return -EINVAL; - } - - case VIDIOC_INT_S_AUDIO_ROUTING: { - struct v4l2_routing *route = arg; - - ivtv_audio_set_route(itv, route); - break; - } - - case VIDIOC_INT_RESET: - ivtv_reset_ir_gpio(itv); - break; - - default: - return -EINVAL; - } - return 0; -} - -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) -{ - struct ivtv_open_id *id = NULL; - - if (filp) id = (struct ivtv_open_id *)filp->private_data; - - switch (cmd) { - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - - *p = v4l2_prio_max(&itv->prio); - break; - } - - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; - - return v4l2_prio_change(&itv->prio, &id->prio, *prio); - } - - case VIDIOC_QUERYCAP:{ - struct v4l2_capability *vcap = arg; - - memset(vcap, 0, sizeof(*vcap)); - strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ - strcpy(vcap->card, itv->card_name); /* card type */ - strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ - vcap->version = IVTV_DRIVER_VERSION; /* version */ - vcap->capabilities = itv->v4l2_cap; /* capabilities */ - - /* reserved.. must set to 0! */ - vcap->reserved[0] = vcap->reserved[1] = - vcap->reserved[2] = vcap->reserved[3] = 0; - break; - } - - case VIDIOC_ENUMAUDIO:{ - struct v4l2_audio *vin = arg; - - return ivtv_get_audio_input(itv, vin->index, vin); - } - - case VIDIOC_G_AUDIO:{ - struct v4l2_audio *vin = arg; - - vin->index = itv->audio_input; - return ivtv_get_audio_input(itv, vin->index, vin); - } - - case VIDIOC_S_AUDIO:{ - struct v4l2_audio *vout = arg; - - if (vout->index >= itv->nof_audio_inputs) - return -EINVAL; - itv->audio_input = vout->index; - ivtv_audio_set_io(itv); - break; - } - - case VIDIOC_ENUMAUDOUT:{ - struct v4l2_audioout *vin = arg; - - /* set it to defaults from our table */ - return ivtv_get_audio_output(itv, vin->index, vin); - } - - case VIDIOC_G_AUDOUT:{ - struct v4l2_audioout *vin = arg; - - vin->index = 0; - return ivtv_get_audio_output(itv, vin->index, vin); - } - - case VIDIOC_S_AUDOUT:{ - struct v4l2_audioout *vout = arg; - - return ivtv_get_audio_output(itv, vout->index, vout); - } - - case VIDIOC_ENUMINPUT:{ - struct v4l2_input *vin = arg; - - /* set it to defaults from our table */ - return ivtv_get_input(itv, vin->index, vin); - } - - case VIDIOC_ENUMOUTPUT:{ - struct v4l2_output *vout = arg; - - return ivtv_get_output(itv, vout->index, vout); - } - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format *fmt = arg; - - return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT); - } - - case VIDIOC_G_FMT: { - struct v4l2_format *fmt = arg; - int type = fmt->type; - - memset(fmt, 0, sizeof(*fmt)); - fmt->type = type; - return ivtv_get_fmt(itv, id->type, fmt); - } - - case VIDIOC_S_CROP: { - struct v4l2_crop *crop = arg; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return itv->video_dec_func(itv, VIDIOC_S_CROP, arg); - } - - case VIDIOC_G_CROP: { - struct v4l2_crop *crop = arg; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return itv->video_dec_func(itv, VIDIOC_G_CROP, arg); - } - - case VIDIOC_ENUM_FMT: { - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, - { 0, 0, 0, 0 } - }, - { 1, 0, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, - { 0, 0, 0, 0 } - } - }; - struct v4l2_fmtdesc *fmt = arg; - enum v4l2_buf_type type = fmt->type; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - break; - default: - return -EINVAL; - } - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; - } - - case VIDIOC_G_INPUT:{ - *(int *)arg = itv->active_input; - break; - } - - case VIDIOC_S_INPUT:{ - int inp = *(int *)arg; - - if (inp < 0 || inp >= itv->nof_inputs) - return -EINVAL; - - if (inp == itv->active_input) { - IVTV_DEBUG_INFO("Input unchanged\n"); - break; - } - IVTV_DEBUG_INFO("Changing input from %d to %d\n", - itv->active_input, inp); - - itv->active_input = inp; - /* Set the audio input to whatever is appropriate for the - input type. */ - itv->audio_input = itv->card->video_inputs[inp].audio_index; - - /* prevent others from messing with the streams until - we're finished changing inputs. */ - ivtv_mute(itv); - ivtv_video_set_io(itv); - ivtv_audio_set_io(itv); - ivtv_unmute(itv); - break; - } - - case VIDIOC_G_OUTPUT:{ - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - *(int *)arg = itv->active_output; - break; - } - - case VIDIOC_S_OUTPUT:{ - int outp = *(int *)arg; - struct v4l2_routing route; - - if (outp >= itv->card->nof_outputs) - return -EINVAL; - - if (outp == itv->active_output) { - IVTV_DEBUG_INFO("Output unchanged\n"); - break; - } - IVTV_DEBUG_INFO("Changing output from %d to %d\n", - itv->active_output, outp); - - itv->active_output = outp; - route.input = SAA7127_INPUT_TYPE_NORMAL; - route.output = itv->card->video_outputs[outp].video_output; - ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - break; - } - - case VIDIOC_G_FREQUENCY:{ - struct v4l2_frequency *vf = arg; - - if (vf->tuner != 0) - return -EINVAL; - ivtv_call_i2c_clients(itv, cmd, arg); - break; - } - - case VIDIOC_S_FREQUENCY:{ - struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; - - if (vf.tuner != 0) - return -EINVAL; - - ivtv_mute(itv); - IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); - ivtv_call_i2c_clients(itv, cmd, &vf); - ivtv_unmute(itv); - break; - } - - case VIDIOC_ENUMSTD:{ - struct v4l2_standard *vs = arg; - int idx = vs->index; - - if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) - return -EINVAL; - - *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? - ivtv_std_60hz : ivtv_std_50hz; - vs->index = idx; - vs->id = enum_stds[idx].std; - strcpy(vs->name, enum_stds[idx].name); - break; - } - - case VIDIOC_G_STD:{ - *(v4l2_std_id *) arg = itv->std; - break; - } - - case VIDIOC_S_STD: { - v4l2_std_id std = *(v4l2_std_id *) arg; - - if ((std & V4L2_STD_ALL) == 0) - return -EINVAL; - - if (std == itv->std) - break; - - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || - atomic_read(&itv->capturing) > 0 || - atomic_read(&itv->decoding) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } - - itv->std = std; - itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; - itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; - itv->params.width = 720; - itv->params.height = itv->is_50hz ? 576 : 480; - itv->vbi.count = itv->is_50hz ? 18 : 12; - itv->vbi.start[0] = itv->is_50hz ? 6 : 10; - itv->vbi.start[1] = itv->is_50hz ? 318 : 273; - if (itv->hw_flags & IVTV_HW_CX25840) { - itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; - } - IVTV_DEBUG_INFO("Switching standard to %llx.\n", itv->std); - - /* Tuner */ - ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - /* set display standard */ - itv->std_out = std; - itv->is_out_60hz = itv->is_60hz; - itv->is_out_50hz = itv->is_50hz; - ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); - ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); - itv->main_rect.left = itv->main_rect.top = 0; - itv->main_rect.width = 720; - itv->main_rect.height = itv->params.height; - ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - 720, itv->main_rect.height, 0, 0); - } - break; - } - - case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ - struct v4l2_tuner *vt = arg; - - if (vt->index != 0) - return -EINVAL; - - ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); - break; - } - - case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; - - if (vt->index != 0) - return -EINVAL; - - memset(vt, 0, sizeof(*vt)); - ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); - - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strcpy(vt->name, "ivtv Radio Tuner"); - vt->type = V4L2_TUNER_RADIO; - } else { - strcpy(vt->name, "ivtv TV Tuner"); - vt->type = V4L2_TUNER_ANALOG_TV; - } - break; - } - - case VIDIOC_G_SLICED_VBI_CAP: { - struct v4l2_sliced_vbi_cap *cap = arg; - int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - enum v4l2_buf_type type = cap->type; - - memset(cap, 0, sizeof(*cap)); - cap->type = type; - if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, itv->is_50hz)) { - cap->service_lines[f][l] = set; - } - } - } - return 0; - } - if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - if (itv->is_60hz) { - cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - cap->service_lines[0][16] = V4L2_SLICED_VPS; - } - return 0; - } - return -EINVAL; - } - - case VIDIOC_G_ENC_INDEX: { - struct v4l2_enc_idx *idx = arg; - int i; - - idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % - IVTV_MAX_PGM_INDEX; - if (idx->entries > V4L2_ENC_IDX_ENTRIES) - idx->entries = V4L2_ENC_IDX_ENTRIES; - for (i = 0; i < idx->entries; i++) { - idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; - } - itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; - break; - } - - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: { - struct v4l2_encoder_cmd *enc = arg; - int try = cmd == VIDIOC_TRY_ENCODER_CMD; - - memset(&enc->raw, 0, sizeof(enc->raw)); - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - enc->flags = 0; - if (try) - return 0; - return ivtv_start_capture(id); - - case V4L2_ENC_CMD_STOP: - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - if (try) - return 0; - ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); - return 0; - - case V4L2_ENC_CMD_PAUSE: - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_mute(itv); - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); - break; - - case V4L2_ENC_CMD_RESUME: - enc->flags = 0; - if (try) - return 0; - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - ivtv_unmute(itv); - break; - default: - return -EINVAL; - } - break; - } - - case VIDIOC_G_FBUF: { - struct v4l2_framebuffer *fb = arg; - - memset(fb, 0, sizeof(*fb)); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - break; - fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; - fb->fmt.pixelformat = itv->osd_pixelformat; - fb->fmt.width = itv->osd_rect.width; - fb->fmt.height = itv->osd_rect.height; - fb->fmt.left = itv->osd_rect.left; - fb->fmt.top = itv->osd_rect.top; - fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - if (itv->osd_local_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - if (itv->osd_color_key_state) - fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - break; - } - - case VIDIOC_S_FBUF: { - struct v4l2_framebuffer *fb = arg; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - break; - itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; - itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; - break; - } - - case VIDIOC_LOG_STATUS: - { - int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; - - IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); - if (itv->hw_flags & IVTV_HW_TVEEPROM) { - struct tveeprom tv; - - ivtv_read_eeprom(itv, &tv); - } - ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); - ivtv_get_input(itv, itv->active_input, &vidin); - ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s\n", audin.name); - if (has_output) { - struct v4l2_output vidout; - struct v4l2_audioout audout; - int mode = itv->output_mode; - static const char * const output_modes[] = { - "None", - "MPEG Streaming", - "YUV Streaming", - "YUV Frames", - "Passthrough", - }; - - ivtv_get_output(itv, itv->active_output, &vidout); - ivtv_get_audio_output(itv, 0, &audout); - IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s\n", audout.name); - if (mode < 0 || mode > OUT_PASSTHROUGH) - mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); - } - IVTV_INFO("Tuner: %s\n", - test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); - cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->v4l2dev == NULL || s->buffers == 0) - continue; - IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, - (s->buffers - s->q_free.buffers) * 100 / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", itv->mpg_data_received, itv->vbi_data_inserted); - IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); - break; - } - - default: - return -EINVAL; - } - return 0; -} - -static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) -{ - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - int nonblocking = filp->f_flags & O_NONBLOCK; - struct ivtv_stream *s = &itv->streams[id->type]; - - switch (cmd) { - case IVTV_IOC_DMA_FRAME: { - struct ivtv_dma_frame *args = arg; - - IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) - return 0; - if (ivtv_claim_stream(id, id->type)) { - return -EBUSY; - } - if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { - ivtv_release_stream(s); - return -EBUSY; - } - if (args->y_source == NULL) - return 0; - return ivtv_yuv_prep_frame(itv, args); - } - - case VIDEO_GET_PTS: { - u32 data[CX2341X_MBOX_MAX_DATA]; - u64 *pts = arg; - - IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { - *pts = s->dma_pts; - break; - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { - *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | - (u64)itv->last_dec_timing[1]; - break; - } - *pts = 0; - if (atomic_read(&itv->decoding)) { - if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { - IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); - return -EIO; - } - memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); - set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; - /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ - } - break; - } - - case VIDEO_GET_FRAME_COUNT: { - u32 data[CX2341X_MBOX_MAX_DATA]; - u64 *frame = arg; - - IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { - *frame = 0; - break; - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { - *frame = itv->last_dec_timing[0]; - break; - } - *frame = 0; - if (atomic_read(&itv->decoding)) { - if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { - IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); - return -EIO; - } - memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); - set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - *frame = data[0]; - } - break; - } - - case VIDEO_PLAY: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_PLAY; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_STOP: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_STOP; - vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_FREEZE: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_FREEZE; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_CONTINUE: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_CONTINUE; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: { - struct video_command *vc = arg; - int try = (cmd == VIDEO_TRY_COMMAND); - - if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); - else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); - return ivtv_video_command(itv, id, vc, try); - } - - case VIDEO_GET_EVENT: { - struct video_event *ev = arg; - DEFINE_WAIT(wait); - - IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - memset(ev, 0, sizeof(*ev)); - set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); - - while (1) { - if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) - ev->type = VIDEO_EVENT_DECODER_STOPPED; - else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { - ev->type = VIDEO_EVENT_VSYNC; - ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? - VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; - if (itv->output_mode == OUT_UDMA_YUV && - (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == - IVTV_YUV_MODE_PROGRESSIVE) { - ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; - } - } - if (ev->type) - return 0; - if (nonblocking) - return -EAGAIN; - /* wait for event */ - prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); - if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) - schedule(); - finish_wait(&itv->event_waitq, &wait); - if (signal_pending(current)) { - /* return if a signal was received */ - IVTV_DEBUG_INFO("User stopped wait for event\n"); - return -EINTR; - } - } - break; - } - - default: - return -EINVAL; - } - return 0; -} - -static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) -{ - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - int ret; - - /* check priority */ - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - ret = v4l2_prio_check(&itv->prio, &id->prio); - if (ret) - return ret; - } - - switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_G_CHIP_IDENT: - case VIDIOC_INT_S_AUDIO_ROUTING: - case VIDIOC_INT_RESET: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - } - return ivtv_debug_ioctls(filp, cmd, arg); - - case VIDIOC_G_PRIORITY: - case VIDIOC_S_PRIORITY: - case VIDIOC_QUERYCAP: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_ENUMOUTPUT: - case VIDIOC_G_OUTPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_G_FMT: - case VIDIOC_S_FMT: - case VIDIOC_TRY_FMT: - case VIDIOC_ENUM_FMT: - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_S_TUNER: - case VIDIOC_G_TUNER: - case VIDIOC_ENUMAUDIO: - case VIDIOC_S_AUDIO: - case VIDIOC_G_AUDIO: - case VIDIOC_ENUMAUDOUT: - case VIDIOC_S_AUDOUT: - case VIDIOC_G_AUDOUT: - case VIDIOC_G_SLICED_VBI_CAP: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: - case VIDIOC_G_FBUF: - case VIDIOC_S_FBUF: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - } - return ivtv_v4l2_ioctls(itv, filp, cmd, arg); - - case VIDIOC_QUERYMENU: - case VIDIOC_QUERYCTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - if (ivtv_debug & IVTV_DBGFLG_IOCTL) { - printk(KERN_INFO "ivtv%d ioctl: ", itv->num); - v4l_printk_ioctl(cmd); - } - return ivtv_control_ioctls(itv, cmd, arg); - - case IVTV_IOC_DMA_FRAME: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: - return ivtv_decoder_ioctls(filp, cmd, arg); - - case 0x00005401: /* Handle isatty() calls */ - return -EINVAL; - default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - ivtv_v4l2_do_ioctl); - } - return 0; -} - -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - - /* Filter dvb ioctls that cannot be handled by video_usercopy */ - switch (cmd) { - case VIDEO_SELECT_SOURCE: - IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - return ivtv_passthrough_mode(itv, arg == VIDEO_SOURCE_DEMUX); - - case AUDIO_SET_MUTE: - IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n"); - itv->speed_mute_audio = arg; - return 0; - - case AUDIO_CHANNEL_SELECT: - IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); - if (arg > AUDIO_STEREO_SWAPPED) - return -EINVAL; - itv->audio_stereo_mode = arg; - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - return 0; - - case AUDIO_BILINGUAL_CHANNEL_SELECT: - IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); - if (arg > AUDIO_STEREO_SWAPPED) - return -EINVAL; - itv->audio_bilingual_mode = arg; - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - return 0; - - default: - break; - } - return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-ioctl.h b/trunk/drivers/media/video/ivtv/ivtv-ioctl.h deleted file mode 100644 index cbccf7a9f65c..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-ioctl.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - ioctl system call - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -u16 service2vbi(int type); -void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); -u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); -void ivtv_set_osd_alpha(struct ivtv *itv); -int ivtv_set_speed(struct ivtv *itv, int speed); diff --git a/trunk/drivers/media/video/ivtv/ivtv-irq.c b/trunk/drivers/media/video/ivtv/ivtv-irq.c deleted file mode 100644 index c3a047b381b3..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-irq.c +++ /dev/null @@ -1,838 +0,0 @@ -/* interrupt handling - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-firmware.h" -#include "ivtv-fileops.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-ioctl.h" -#include "ivtv-mailbox.h" -#include "ivtv-vbi.h" -#include "ivtv-yuv.h" - -#define DMA_MAGIC_COOKIE 0x000001fe - -#define SLICED_VBI_PIO 1 - -static void ivtv_dma_dec_start(struct ivtv_stream *s); - -static const int ivtv_stream_map[] = { - IVTV_ENC_STREAM_TYPE_MPG, - IVTV_ENC_STREAM_TYPE_YUV, - IVTV_ENC_STREAM_TYPE_PCM, - IVTV_ENC_STREAM_TYPE_VBI, -}; - -static inline int ivtv_use_pio(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - return s->dma == PCI_DMA_NONE || - (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set); -} - -void ivtv_irq_work_handler(struct work_struct *work) -{ - struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); - - DEFINE_WAIT(wait); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) - vbi_work_handler(itv); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) - ivtv_yuv_work_handler(itv); -} - -/* Determine the required DMA size, setup enough buffers in the predma queue and - actually copy the data from the card to the buffers in case a PIO transfer is - required for this stream. - */ -static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf; - struct list_head *p; - u32 bytes_needed = 0; - u32 offset, size; - u32 UVoffset = 0, UVsize = 0; - int skip_bufs = s->q_predma.buffers; - int idx = s->SG_length; - int rc; - - /* sanity checks */ - if (s->v4l2dev == NULL) { - IVTV_DEBUG_WARN("Stream %s not started\n", s->name); - return -1; - } - if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - IVTV_DEBUG_WARN("Stream %s not open\n", s->name); - return -1; - } - - /* determine offset, size and PTS for the various streams */ - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_MPG: - offset = data[1]; - size = data[2]; - s->dma_pts = 0; - break; - - case IVTV_ENC_STREAM_TYPE_YUV: - offset = data[1]; - size = data[2]; - UVoffset = data[3]; - UVsize = data[4]; - s->dma_pts = ((u64) data[5] << 32) | data[6]; - break; - - case IVTV_ENC_STREAM_TYPE_PCM: - offset = data[1] + 12; - size = data[2] - 12; - s->dma_pts = read_dec(offset - 8) | - ((u64)(read_dec(offset - 12)) << 32); - if (itv->has_cx23415) - offset += IVTV_DECODER_OFFSET; - break; - - case IVTV_ENC_STREAM_TYPE_VBI: - size = itv->vbi.enc_size * itv->vbi.fpi; - offset = read_enc(itv->vbi.enc_start - 4) + 12; - if (offset == 12) { - IVTV_DEBUG_INFO("VBI offset == 0\n"); - return -1; - } - s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); - break; - - case IVTV_DEC_STREAM_TYPE_VBI: - size = read_dec(itv->vbi.dec_start + 4) + 8; - offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->dma_pts = 0; - offset += IVTV_DECODER_OFFSET; - break; - default: - /* shouldn't happen */ - return -1; - } - - /* if this is the start of the DMA then fill in the magic cookie */ - if (s->SG_length == 0) { - if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || - s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); - write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); - } - else { - s->dma_backup = read_enc(offset); - write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); - } - s->dma_offset = offset; - } - - bytes_needed = size; - if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { - /* The size for the Y samples needs to be rounded upwards to a - multiple of the buf_size. The UV samples then start in the - next buffer. */ - bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); - bytes_needed += UVsize; - } - - IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n", - ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); - - rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); - if (rc < 0) { /* Insufficient buffers */ - IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", - bytes_needed, s->name); - return -1; - } - if (rc && !s->buffers_stolen && (s->s_flags & IVTV_F_S_APPL_IO)) { - IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); - IVTV_WARN("Cause: the application is not reading fast enough.\n"); - } - s->buffers_stolen = rc; - - /* got the buffers, now fill in SGarray (DMA) or copy the data from the card - to the buffers (PIO). */ - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - memset(buf->buf, 0, 128); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - - if (skip_bufs-- > 0) - continue; - if (!ivtv_use_pio(s)) { - s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].src = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(s->buf_size); - } - buf->bytesused = (size < s->buf_size) ? size : s->buf_size; - - /* If PIO, then copy the data from the card to the buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + offset - IVTV_DECODER_OFFSET, buf->bytesused); - } - else if (ivtv_use_pio(s)) { - memcpy_fromio(buf->buf, itv->enc_mem + offset, buf->bytesused); - } - - s->q_predma.bytesused += buf->bytesused; - size -= buf->bytesused; - offset += s->buf_size; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - - if (size == 0) { /* YUV */ - /* process the UV section */ - offset = UVoffset; - size = UVsize; - } - idx++; - } - s->SG_length = idx; - return 0; -} - -static void dma_post(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf = NULL; - struct list_head *p; - u32 offset; - u32 *u32buf; - int x = 0; - - if (ivtv_use_pio(s)) { - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - s->SG_length = 0; - } - IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", - s->name, s->dma_offset); - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - u32buf = (u32 *)buf->buf; - - /* Sync Buffer */ - ivtv_buf_sync_for_cpu(s, buf); - - if (x == 0) { - offset = s->dma_last_offset; - if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) - { - for (offset = 0; offset < 64; offset++) { - if (u32buf[offset] == DMA_MAGIC_COOKIE) { - break; - } - } - offset *= 4; - if (offset == 256) { - IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); - offset = s->dma_last_offset; - } - if (s->dma_last_offset != offset) - IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); - s->dma_last_offset = offset; - } - if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || - s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); - } - else { - write_enc_sync(0, s->dma_offset); - } - if (offset) { - buf->bytesused -= offset; - memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); - } - *u32buf = cpu_to_le32(s->dma_backup); - } - x++; - /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG || - s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); - } - if (buf) - buf->bytesused += s->dma_last_offset; - if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - /* Parse and Groom VBI Data */ - s->q_dma.bytesused -= buf->bytesused; - ivtv_process_vbi_data(itv, buf, 0, s->type); - s->q_dma.bytesused += buf->bytesused; - if (s->id == -1) { - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); - return; - } - } - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); - if (s->id != -1) - wake_up(&s->waitq); -} - -void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf; - struct list_head *p; - u32 y_size = itv->params.height * itv->params.width; - u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; - int y_done = 0; - int bytes_written = 0; - unsigned long flags = 0; - int idx = 0; - - IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - - /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { - offset = uv_offset; - y_done = 1; - } - s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].dst = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(buf->bytesused); - - offset += buf->bytesused; - bytes_written += buf->bytesused; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - idx++; - } - s->SG_length = idx; - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); - - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - if (lock) - spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - ivtv_dma_dec_start(s); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - if (lock) - spin_unlock_irqrestore(&itv->dma_reg_lock, flags); -} - -/* start the encoder DMA */ -static void ivtv_dma_enc_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - int i; - - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - IVTV_DEBUG_DMA("start DMA for %s\n", s->name); - s->SGarray[s->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); - - /* If this is an MPEG stream, and VBI data is also pending, then append the - VBI DMA to the MPEG DMA and transfer both sets of data at once. - - VBI DMA is a second class citizen compared to MPEG and mixing them together - will confuse the firmware (the end of a VBI DMA is seen as the end of a - MPEG DMA, thus effectively dropping an MPEG frame). So instead we make - sure we only use the MPEG DMA to transfer the VBI DMA if both are in - use. This way no conflicts occur. */ - clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && - s->SG_length + s_vbi->SG_length <= s->buffers) { - ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); - s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); - for (i = 0; i < s_vbi->SG_length; i++) { - s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; - } - itv->vbi.dma_offset = s_vbi->dma_offset; - s_vbi->SG_length = 0; - set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_DMA("include DMA for %s\n", s->name); - } - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); - - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = s->type; - itv->dma_timer.expires = jiffies + HZ / 10; - add_timer(&itv->dma_timer); -} - -static void ivtv_dma_dec_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - IVTV_DEBUG_DMA("start DMA for %s\n", s->name); - /* put SG Handle into register 0x0c */ - write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = s->type; - itv->dma_timer.expires = jiffies + HZ / 10; - add_timer(&itv->dma_timer); -} - -static void ivtv_irq_dma_read(struct ivtv *itv) -{ - struct ivtv_stream *s = NULL; - struct ivtv_buffer *buf; - int hw_stream_type; - - IVTV_DEBUG_IRQ("DEC DMA READ\n"); - del_timer(&itv->dma_timer); - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - } - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - hw_stream_type = 2; - } - else { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - hw_stream_type = 0; - } - IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); - - ivtv_stream_sync_for_cpu(s); - - /* For some reason must kick the firmware, like PIO mode, - I think this tells the firmware we are done and the size - of the xfer so it can calculate what we need next. - I think we can do this part ourselves but would have to - fully calculate xfer info ourselves and not use interrupts - */ - ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, - hw_stream_type); - - /* Free last DMA call */ - while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { - ivtv_buf_sync_for_cpu(s, buf); - ivtv_enqueue(s, buf, &s->q_free); - } - wake_up(&s->waitq); - } - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_dma_complete(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - del_timer(&itv->dma_timer); - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); - if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) - data[1] = 3; - else if (data[1] > 2) - return; - s = &itv->streams[ivtv_stream_map[data[1]]]; - if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); - } - s->SG_length = 0; - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - dma_post(s); - ivtv_stream_sync_for_cpu(s); - if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; - dma_post(s); - s->dma_offset = tmp; - } - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_dma_err(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - - del_timer(&itv->dma_timer); - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && - itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { - struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; - - /* retry */ - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_dec_start(s); - else - ivtv_dma_enc_start(s); - return; - } - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_start_cap(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* Get DMA destination and size arguments from card */ - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data); - IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); - - if (data[0] > 2 || data[1] == 0 || data[2] == 0) { - IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", - data[0], data[1], data[2]); - return; - } - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - s = &itv->streams[ivtv_stream_map[data[0]]]; - if (!stream_enc_dma_append(s, data)) { - if (ivtv_use_pio(s)) { - dma_post(s); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[0]); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - } -} - -static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) -{ - struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - IVTV_DEBUG_IRQ("ENC START VBI CAP\n"); - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - - if (ivtv_use_pio(s)) { - if (stream_enc_dma_append(s, data)) - return; - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - s->SG_length = 0; - dma_post(s); - return; - } - /* If more than two VBI buffers are pending, then - clear the old ones and start with this new one. - This can happen during transition stages when MPEG capturing is - started, but the first interrupts haven't arrived yet. During - that period VBI requests can accumulate without being able to - DMA the data. Since at most four VBI DMA buffers are available, - we just drop the old requests when there are already three - requests queued. */ - if (s->SG_length > 2) { - struct list_head *p; - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - ivtv_buf_sync_for_cpu(s, buf); - } - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->SG_length = 0; - } - /* if we can append the data, and the MPEG stream isn't capturing, - then start a DMA request for just the VBI data. */ - if (!stream_enc_dma_append(s, data) && - !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { - set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } -} - -static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - - IVTV_DEBUG_IRQ("DEC VBI REINSERT\n"); - if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && - !stream_enc_dma_append(s, data)) { - dma_post(s); - } -} - -static void ivtv_irq_dec_data_req(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* YUV or MPG */ - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; - itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - } - else { - itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; - itv->dma_data_req_offset = data[1]; - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - } - IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, - itv->dma_data_req_offset, itv->dma_data_req_size); - if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { - set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - } - else { - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); - ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); - } -} - -static void ivtv_irq_vsync(struct ivtv *itv) -{ - /* The vsync interrupt is unusual in that it won't clear until - * the end of the first line for the current field, at which - * point it clears itself. This can result in repeated vsync - * interrupts, or a missed vsync. Read some of the registers - * to determine the line being displayed and ensure we handle - * one vsync per frame. - */ - unsigned int frame = read_reg(0x28c0) & 1; - int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); - - if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - - if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || - (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { - int next_dma_frame = last_dma_frame; - - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); - } - } - if (frame != (itv->lastVsyncFrame & 1)) { - struct ivtv_stream *s = ivtv_get_output_stream(itv); - int work = 0; - - itv->lastVsyncFrame += 1; - if (frame == 0) { - clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - else { - set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { - set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); - wake_up(&itv->event_waitq); - } - wake_up(&itv->vsync_waitq); - if (s) - wake_up(&s->waitq); - - /* Send VBI to saa7127 */ - if (frame) { - set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); - work = 1; - } - - /* Check if we need to update the yuv registers */ - if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { - if (!itv->yuv_info.new_frame_info[last_dma_frame].update) - last_dma_frame = (last_dma_frame - 1) & 3; - - if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { - itv->yuv_info.update_frame = last_dma_frame; - itv->yuv_info.new_frame_info[last_dma_frame].update = 0; - itv->yuv_info.yuv_forced_update = 0; - set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); - work = 1; - } - } - if (work) - queue_work(itv->irq_work_queues, &itv->irq_work_queue); - } -} - -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) - -irqreturn_t ivtv_irq_handler(int irq, void *dev_id) -{ - struct ivtv *itv = (struct ivtv *)dev_id; - u32 combo; - u32 stat; - int i; - u8 vsync_force = 0; - - spin_lock(&itv->dma_reg_lock); - /* get contents of irq status register */ - stat = read_reg(IVTV_REG_IRQSTATUS); - - combo = ~itv->irqmask & stat; - - /* Clear out IRQ */ - if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); - - if (0 == combo) { - /* The vsync interrupt is unusual and clears itself. If we - * took too long, we may have missed it. Do some checks - */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - /* vsync is enabled, see if we're in a new field */ - if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { - /* New field, looks like we missed it */ - IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); - vsync_force = 1; - } - } - - if (!vsync_force) { - /* No Vsync expected, wasn't for us */ - spin_unlock(&itv->dma_reg_lock); - return IRQ_NONE; - } - } - - /* Exclude interrupts noted below from the output, otherwise the log is flooded with - these messages */ - if (combo & ~0xff6d0400) - IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); - - if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { - IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n"); - } - - if (combo & IVTV_IRQ_DMA_READ) { - ivtv_irq_dma_read(itv); - } - - if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { - ivtv_irq_enc_dma_complete(itv); - } - - if (combo & IVTV_IRQ_DMA_ERR) { - ivtv_irq_dma_err(itv); - } - - if (combo & IVTV_IRQ_ENC_START_CAP) { - ivtv_irq_enc_start_cap(itv); - } - - if (combo & IVTV_IRQ_ENC_VBI_CAP) { - ivtv_irq_enc_vbi_cap(itv); - } - - if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { - ivtv_irq_dev_vbi_reinsert(itv); - } - - if (combo & IVTV_IRQ_ENC_EOS) { - IVTV_DEBUG_IRQ("ENC EOS\n"); - set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->cap_w); - } - - if (combo & IVTV_IRQ_DEC_DATA_REQ) { - ivtv_irq_dec_data_req(itv); - } - - /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - ivtv_irq_vsync(itv); - } - - if (combo & IVTV_IRQ_ENC_VIM_RST) { - IVTV_DEBUG_IRQ("VIM RST\n"); - /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ - } - - if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { - IVTV_DEBUG_INFO("Stereo mode changed\n"); - } - - if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; - struct ivtv_stream *s = &itv->streams[idx]; - - if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) - continue; - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_dec_start(s); - else - ivtv_dma_enc_start(s); - break; - } - if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) { - ivtv_udma_start(itv); - } - } - - spin_unlock(&itv->dma_reg_lock); - - /* If we've just handled a 'forced' vsync, it's safest to say it - * wasn't ours. Another device may have triggered it at just - * the right time. - */ - return vsync_force ? IRQ_NONE : IRQ_HANDLED; -} - -void ivtv_unfinished_dma(unsigned long arg) -{ - struct ivtv *itv = (struct ivtv *)arg; - - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) - return; - IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); - - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-irq.h b/trunk/drivers/media/video/ivtv/ivtv-irq.h deleted file mode 100644 index a43348a30309..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-irq.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - interrupt handling - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -irqreturn_t ivtv_irq_handler(int irq, void *dev_id); - -void ivtv_irq_work_handler(struct work_struct *work); -void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); -void ivtv_unfinished_dma(unsigned long arg); diff --git a/trunk/drivers/media/video/ivtv/ivtv-mailbox.c b/trunk/drivers/media/video/ivtv/ivtv-mailbox.c deleted file mode 100644 index 6ae42a3b03cc..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-mailbox.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - mailbox functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-mailbox.h" - -/* Firmware mailbox flags*/ -#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 -#define IVTV_MBOX_DRIVER_DONE 0x00000002 -#define IVTV_MBOX_DRIVER_BUSY 0x00000001 -#define IVTV_MBOX_FREE 0x00000000 - -/* Firmware mailbox standard timeout */ -#define IVTV_API_STD_TIMEOUT 0x02000000 - -#define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */ -#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */ -#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */ -#define API_DMA (1 << 3) /* DMA mailbox, has special handling */ -#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */ -#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */ - -struct ivtv_api_info { - int flags; /* Flags, see above */ - const char *name; /* The name of the command */ -}; - -#define API_ENTRY(x, f) [x] = { (f), #x } - -static const struct ivtv_api_info api_info[256] = { - /* MPEG encoder API */ - API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT), - API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE), - API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE), - API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE), - API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA), - API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT), - API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB), - API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE), - API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT), - API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT), - /* Obsolete PULLDOWN API command */ - API_ENTRY(0xb1, API_CACHE), - - /* MPEG decoder API */ - API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT), - API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT), - API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA), - API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT), - API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT /*| API_NO_WAIT_RES*/), - API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE), - API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE), - API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE), - - /* OSD API */ - API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE), - API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE), - API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT), - API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT), - API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT), - API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE), - API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE) -}; - -static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb) -{ - u32 flags = readl(&mbdata->mbox[mb].flags); - int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE); - - /* if the mailbox is free, then try to claim it */ - if (is_free && !test_and_set_bit(mb, &mbdata->busy)) { - write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags); - return 1; - } - return 0; -} - -/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not - attempted here. */ -static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags) -{ - unsigned long then = jiffies; - int i, mb; - int max_mbox = mbdata->max_mbox; - int retries = 100; - - /* All slow commands use the same mailbox, serializing them and also - leaving the other mailbox free for simple fast commands. */ - if ((flags & API_FAST_RESULT) == API_RESULT) - max_mbox = 1; - - /* find free non-DMA mailbox */ - for (i = 0; i < retries; i++) { - for (mb = 1; mb <= max_mbox; mb++) - if (try_mailbox(itv, mbdata, mb)) - return mb; - - /* Sleep before a retry, if not atomic */ - if (!(flags & API_NO_WAIT_MB)) { - if (jiffies - then > retries * HZ / 100) - break; - ivtv_sleep_timeout(HZ / 100, 0); - } - } - return -ENODEV; -} - -static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[]) -{ - int i; - - write_sync(cmd, &mbox->cmd); - write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout); - - for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) - write_sync(data[i], &mbox->data[i]); - - write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags); -} - -static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata) -{ - int i; - - for (i = 0; i <= mbdata->max_mbox; i++) { - IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n", - i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags)); - write_sync(0, &mbdata->mbox[i].flags); - clear_bit(i, &mbdata->busy); - } -} - -static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) -{ - struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox; - volatile struct ivtv_mailbox __iomem *mbox; - int api_timeout = HZ; - int flags, mb, i; - unsigned long then; - - /* sanity checks */ - if (NULL == mbdata) { - IVTV_ERR("No mailbox allocated\n"); - return -ENODEV; - } - if (args < 0 || args > CX2341X_MBOX_MAX_DATA || - cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); - return -EINVAL; - } - - IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); - - /* clear possibly uninitialized part of data array */ - for (i = args; i < CX2341X_MBOX_MAX_DATA; i++) - data[i] = 0; - - /* If this command was issued within the last 30 minutes and with identical - data, then just return 0 as there is no need to issue this command again. - Just an optimization to prevent unnecessary use of mailboxes. */ - if (itv->api_cache[cmd].last_jiffies && - jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 && - !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { - itv->api_cache[cmd].last_jiffies = jiffies; - return 0; - } - - flags = api_info[cmd].flags; - - if (flags & API_DMA) { - for (i = 0; i < 100; i++) { - mb = i % (mbdata->max_mbox + 1); - if (try_mailbox(itv, mbdata, mb)) { - write_mailbox(&mbdata->mbox[mb], cmd, args, data); - clear_bit(mb, &mbdata->busy); - return 0; - } - IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n", - api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags)); - } - IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name); - clear_all_mailboxes(itv, mbdata); - return -EBUSY; - } - - if ((flags & API_FAST_RESULT) == API_FAST_RESULT) - api_timeout = HZ / 10; - - mb = get_mailbox(itv, mbdata, flags); - if (mb < 0) { - IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name); - clear_all_mailboxes(itv, mbdata); - return -EBUSY; - } - mbox = &mbdata->mbox[mb]; - write_mailbox(mbox, cmd, args, data); - if (flags & API_CACHE) { - memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data)); - itv->api_cache[cmd].last_jiffies = jiffies; - } - if ((flags & API_RESULT) == 0) { - clear_bit(mb, &mbdata->busy); - return 0; - } - - /* Get results */ - then = jiffies; - - while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { - if (jiffies - then > api_timeout) { - IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); - /* reset the mailbox, but it is likely too late already */ - write_sync(0, &mbox->flags); - clear_bit(mb, &mbdata->busy); - return -EIO; - } - if (flags & API_NO_WAIT_RES) - mdelay(1); - else - ivtv_sleep_timeout(HZ / 100, 0); - } - if (jiffies - then > HZ / 10) - IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n", - api_info[cmd].name, jiffies - then, HZ); - - for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) - data[i] = readl(&mbox->data[i]); - write_sync(0, &mbox->flags); - clear_bit(mb, &mbdata->busy); - return 0; -} - -int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) -{ - int res = ivtv_api_call(itv, cmd, args, data); - - /* Allow a single retry, probably already too late though. - If there is no free mailbox then that is usually an indication - of a more serious problem. */ - return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; -} - -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - return ivtv_api(priv, cmd, in, data); -} - -int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) -{ - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) { - data[i] = va_arg(ap, u32); - } - va_end(ap); - return ivtv_api(itv, cmd, args, data); -} - -int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) { - data[i] = va_arg(ap, u32); - } - va_end(ap); - return ivtv_api(itv, cmd, args, data); -} - -/* This one is for stuff that can't sleep.. irq handlers, etc.. */ -void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, u32 data[]) -{ - int i; - - for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) - data[i] = readl(&mbdata->mbox[mb].data[i]); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-mailbox.h b/trunk/drivers/media/video/ivtv/ivtv-mailbox.h deleted file mode 100644 index 79b8aec14370..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-mailbox.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - mailbox functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); -int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); -int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); -int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); diff --git a/trunk/drivers/media/video/ivtv/ivtv-queue.c b/trunk/drivers/media/video/ivtv/ivtv-queue.c deleted file mode 100644 index ccfcef1ad91a..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-queue.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - buffer queues. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-streams.h" -#include "ivtv-queue.h" -#include "ivtv-mailbox.h" - -int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) -{ - if (s->buf_size - buf->bytesused < copybytes) - copybytes = s->buf_size - buf->bytesused; - if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { - return -EFAULT; - } - buf->bytesused += copybytes; - return copybytes; -} - -void ivtv_buf_swap(struct ivtv_buffer *buf) -{ - int i; - - for (i = 0; i < buf->bytesused; i += 4) - swab32s((u32 *)(buf->buf + i)); -} - -void ivtv_queue_init(struct ivtv_queue *q) -{ - INIT_LIST_HEAD(&q->list); - q->buffers = 0; - q->length = 0; - q->bytesused = 0; -} - -void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) -{ - unsigned long flags = 0; - - /* clear the buffer if it is going to be enqueued to the free queue */ - if (q == &s->q_free) { - buf->bytesused = 0; - buf->readpos = 0; - buf->b_flags = 0; - } - spin_lock_irqsave(&s->qlock, flags); - list_add_tail(&buf->list, &q->list); - q->buffers++; - q->length += s->buf_size; - q->bytesused += buf->bytesused - buf->readpos; - spin_unlock_irqrestore(&s->qlock, flags); -} - -struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) -{ - struct ivtv_buffer *buf = NULL; - unsigned long flags = 0; - - spin_lock_irqsave(&s->qlock, flags); - if (!list_empty(&q->list)) { - buf = list_entry(q->list.next, struct ivtv_buffer, list); - list_del_init(q->list.next); - q->buffers--; - q->length -= s->buf_size; - q->bytesused -= buf->bytesused - buf->readpos; - } - spin_unlock_irqrestore(&s->qlock, flags); - return buf; -} - -static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear, int full) -{ - struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); - - list_move_tail(from->list.next, &to->list); - from->buffers--; - from->length -= s->buf_size; - from->bytesused -= buf->bytesused - buf->readpos; - /* special handling for q_free */ - if (clear) - buf->bytesused = buf->readpos = buf->b_flags = 0; - else if (full) { - /* special handling for stolen buffers, assume - all bytes are used. */ - buf->bytesused = s->buf_size; - buf->readpos = buf->b_flags = 0; - } - to->buffers++; - to->length += s->buf_size; - to->bytesused += buf->bytesused - buf->readpos; -} - -/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. - If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. - If 'steal' != NULL, then buffers may also taken from that queue if - needed. - - The buffer is automatically cleared if it goes to the free queue. It is - also cleared if buffers need to be taken from the 'steal' queue and - the 'from' queue is the free queue. - - When 'from' is q_free, then needed_bytes is compared to the total - available buffer length, otherwise needed_bytes is compared to the - bytesused value. For the 'steal' queue the total available buffer - length is always used. - - -ENOMEM is returned if the buffers could not be obtained, 0 if all - buffers where obtained from the 'from' list and if non-zero then - the number of stolen buffers is returned. */ -int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, - struct ivtv_queue *to, int needed_bytes) -{ - unsigned long flags; - int rc = 0; - int from_free = from == &s->q_free; - int to_free = to == &s->q_free; - int bytes_available; - - spin_lock_irqsave(&s->qlock, flags); - if (needed_bytes == 0) { - from_free = 1; - needed_bytes = from->length; - } - - bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; - - if (bytes_available < needed_bytes) { - spin_unlock_irqrestore(&s->qlock, flags); - return -ENOMEM; - } - if (from_free) { - u32 old_length = to->length; - - while (to->length - old_length < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, 1, 0); - } - } - else { - u32 old_bytesused = to->bytesused; - - while (to->bytesused - old_bytesused < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, to_free, rc); - } - } - spin_unlock_irqrestore(&s->qlock, flags); - return rc; -} - -void ivtv_flush_queues(struct ivtv_stream *s) -{ - ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); -} - -int ivtv_stream_alloc(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; - int i; - - if (s->buffers == 0) - return 0; - - IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", - s->dma != PCI_DMA_NONE ? "DMA " : "", - s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - - /* Allocate DMA SG Arrays */ - if (s->dma != PCI_DMA_NONE) { - s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->SGarray == NULL) { - IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); - return -ENOMEM; - } - s->SG_length = 0; - s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); - ivtv_stream_sync_for_cpu(s); - } - - /* allocate stream buffers. Initially all buffers are in q_free. */ - for (i = 0; i < s->buffers; i++) { - struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL); - - if (buf == NULL) - break; - buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL); - if (buf->buf == NULL) { - kfree(buf); - break; - } - INIT_LIST_HEAD(&buf->list); - if (s->dma != PCI_DMA_NONE) { - buf->dma_handle = pci_map_single(s->itv->dev, - buf->buf, s->buf_size + 256, s->dma); - ivtv_buf_sync_for_cpu(s, buf); - } - ivtv_enqueue(s, buf, &s->q_free); - } - if (i == s->buffers) - return 0; - IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); - ivtv_stream_free(s); - return -ENOMEM; -} - -void ivtv_stream_free(struct ivtv_stream *s) -{ - struct ivtv_buffer *buf; - - /* move all buffers to q_free */ - ivtv_flush_queues(s); - - /* empty q_free */ - while ((buf = ivtv_dequeue(s, &s->q_free))) { - if (s->dma != PCI_DMA_NONE) - pci_unmap_single(s->itv->dev, buf->dma_handle, - s->buf_size + 256, s->dma); - kfree(buf->buf); - kfree(buf); - } - - /* Free SG Array/Lists */ - if (s->SGarray != NULL) { - if (s->SG_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); - s->SG_handle = IVTV_DMA_UNMAPPED; - } - s->SGarray = NULL; - s->SG_length = 0; - } -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-queue.h b/trunk/drivers/media/video/ivtv/ivtv-queue.h deleted file mode 100644 index 903edd4b4381..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-queue.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - buffer queues. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -#define IVTV_DMA_UNMAPPED ((u32) -1) - -/* ivtv_buffer utility functions */ -static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf) -{ - if (s->dma != PCI_DMA_NONE) - pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle, - s->buf_size + 256, s->dma); -} - -static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf) -{ - if (s->dma != PCI_DMA_NONE) - pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle, - s->buf_size + 256, s->dma); -} - -int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes); -void ivtv_buf_swap(struct ivtv_buffer *buf); - -/* ivtv_queue utility functions */ -void ivtv_queue_init(struct ivtv_queue *q); -void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q); -struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q); -int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, - struct ivtv_queue *to, int needed_bytes); -void ivtv_flush_queues(struct ivtv_stream *s); - -/* ivtv_stream utility functions */ -int ivtv_stream_alloc(struct ivtv_stream *s); -void ivtv_stream_free(struct ivtv_stream *s); - -static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) -{ - pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); -} - -static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) -{ - pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-streams.c b/trunk/drivers/media/video/ivtv/ivtv-streams.c deleted file mode 100644 index 01a41a844a30..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-streams.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - init/start/stop/exit stream functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -/* License: GPL - * Author: Kevin Thayer - * - * This file will hold API related functions, both internal (firmware api) - * and external (v4l2, etc) - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - */ - -#include "ivtv-driver.h" -#include "ivtv-fileops.h" -#include "ivtv-i2c.h" -#include "ivtv-queue.h" -#include "ivtv-mailbox.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" -#include "ivtv-ioctl.h" -#include "ivtv-irq.h" -#include "ivtv-streams.h" -#include "ivtv-cards.h" - -static struct file_operations ivtv_v4l2_enc_fops = { - .owner = THIS_MODULE, - .read = ivtv_v4l2_read, - .write = ivtv_v4l2_write, - .open = ivtv_v4l2_open, - .ioctl = ivtv_v4l2_ioctl, - .release = ivtv_v4l2_close, - .poll = ivtv_v4l2_enc_poll, -}; - -static struct file_operations ivtv_v4l2_dec_fops = { - .owner = THIS_MODULE, - .read = ivtv_v4l2_read, - .write = ivtv_v4l2_write, - .open = ivtv_v4l2_open, - .ioctl = ivtv_v4l2_ioctl, - .release = ivtv_v4l2_close, - .poll = ivtv_v4l2_dec_poll, -}; - -static struct { - const char *name; - int vfl_type; - int minor_offset; - int dma, pio; - enum v4l2_buf_type buf_type; - struct file_operations *fops; -} ivtv_stream_info[] = { - { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", - VFL_TYPE_GRABBER, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_YUV */ - "encoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_VBI */ - "encoder VBI", - VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_RAD */ - "encoder radio", - VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPEG", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VBI */ - "decoder VBI", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VOUT */ - "decoder VOUT", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_YUV */ - "decoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, - &ivtv_v4l2_dec_fops - } -}; - -static void ivtv_stream_init(struct ivtv *itv, int type) -{ - struct ivtv_stream *s = &itv->streams[type]; - struct video_device *dev = s->v4l2dev; - - /* we need to keep v4l2dev, so restore it afterwards */ - memset(s, 0, sizeof(*s)); - s->v4l2dev = dev; - - /* initialize ivtv_stream fields */ - s->itv = itv; - s->type = type; - s->name = ivtv_stream_info[type].name; - - if (ivtv_stream_info[type].pio) - s->dma = PCI_DMA_NONE; - else - s->dma = ivtv_stream_info[type].dma; - s->buf_size = itv->stream_buf_size[type]; - if (s->buf_size) - s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; - spin_lock_init(&s->qlock); - init_waitqueue_head(&s->waitq); - s->id = -1; - s->SG_handle = IVTV_DMA_UNMAPPED; - ivtv_queue_init(&s->q_free); - ivtv_queue_init(&s->q_full); - ivtv_queue_init(&s->q_dma); - ivtv_queue_init(&s->q_predma); - ivtv_queue_init(&s->q_io); -} - -static int ivtv_reg_dev(struct ivtv *itv, int type) -{ - struct ivtv_stream *s = &itv->streams[type]; - int vfl_type = ivtv_stream_info[type].vfl_type; - int minor_offset = ivtv_stream_info[type].minor_offset; - int minor; - - /* These four fields are always initialized. If v4l2dev == NULL, then - this stream is not in use. In that case no other fields but these - four can be used. */ - s->v4l2dev = NULL; - s->itv = itv; - s->type = type; - s->name = ivtv_stream_info[type].name; - - /* Check whether the radio is supported */ - if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) - return 0; - if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return 0; - - if (minor_offset >= 0) - /* card number + user defined offset + device offset */ - minor = itv->num + ivtv_first_minor + minor_offset; - else - minor = -1; - - /* User explicitly selected 0 buffers for these streams, so don't - create them. */ - if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.megabytes[type] == 0) { - IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); - return 0; - } - - ivtv_stream_init(itv, type); - - /* allocate and initialize the v4l2 video device structure */ - s->v4l2dev = video_device_alloc(); - if (s->v4l2dev == NULL) { - IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); - return -ENOMEM; - } - - s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | - VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; - } - snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", - itv->num, s->name); - - s->v4l2dev->minor = minor; - s->v4l2dev->dev = &itv->dev->dev; - s->v4l2dev->fops = ivtv_stream_info[type].fops; - s->v4l2dev->release = video_device_release; - - if (minor >= 0) { - /* Register device. First try the desired minor, then any free one. */ - if (video_register_device(s->v4l2dev, vfl_type, minor) && - video_register_device(s->v4l2dev, vfl_type, -1)) { - IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", - s->name, minor); - video_device_release(s->v4l2dev); - s->v4l2dev = NULL; - return -ENOMEM; - } - } - else { - /* Don't register a 'hidden' stream (OSD) */ - IVTV_INFO("Created framebuffer stream for %s\n", s->name); - return 0; - } - - switch (vfl_type) { - case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d MB)\n", - s->v4l2dev->minor, s->name, itv->options.megabytes[type]); - break; - case VFL_TYPE_RADIO: - IVTV_INFO("Registered device radio%d for %s\n", - s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); - break; - case VFL_TYPE_VBI: - if (itv->options.megabytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", - s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, - s->name, itv->options.megabytes[type]); - else - IVTV_INFO("Registered device vbi%d for %s\n", - s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); - break; - } - return 0; -} - -/* Initialize v4l2 variables and register v4l2 devices */ -int ivtv_streams_setup(struct ivtv *itv) -{ - int type; - - /* Setup V4L2 Devices */ - for (type = 0; type < IVTV_MAX_STREAMS; type++) { - /* Register Device */ - if (ivtv_reg_dev(itv, type)) - break; - - if (itv->streams[type].v4l2dev == NULL) - continue; - - /* Allocate Stream */ - if (ivtv_stream_alloc(&itv->streams[type])) - break; - } - if (type == IVTV_MAX_STREAMS) { - return 0; - } - - /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv); - return -ENOMEM; -} - -/* Unregister v4l2 devices */ -void ivtv_streams_cleanup(struct ivtv *itv) -{ - int type; - - /* Teardown all streams */ - for (type = 0; type < IVTV_MAX_STREAMS; type++) { - struct video_device *vdev = itv->streams[type].v4l2dev; - - itv->streams[type].v4l2dev = NULL; - if (vdev == NULL) - continue; - - ivtv_stream_free(&itv->streams[type]); - /* Free Device */ - if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */ - video_device_release(vdev); - else /* All others, just unregister. */ - video_unregister_device(vdev); - } -} - -static void ivtv_vbi_setup(struct ivtv *itv) -{ - int raw = itv->vbi.sliced_in->service_set == 0; - u32 data[CX2341X_MBOX_MAX_DATA]; - int lines; - int i; - - /* If Embed then streamtype must be Program */ - /* TODO: should we really do this? */ - if (0 && !raw && itv->vbi.insert_mpeg) { - itv->params.stream_type = 0; - - /* assign stream type */ - ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); - } - - /* Reset VBI */ - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); - - if (itv->is_60hz) { - itv->vbi.count = 12; - itv->vbi.start[0] = 10; - itv->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - itv->vbi.count = 18; - itv->vbi.start[0] = 6; - itv->vbi.start[1] = 318; - } - - /* setup VBI registers */ - itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); - - /* determine number of lines and total number of VBI bytes. - A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 - The '- 1' byte is probably an unused U or V byte. Or something... - A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal - header, 42 data bytes + checksum (to be confirmed) */ - if (raw) { - lines = itv->vbi.count * 2; - } else { - lines = itv->is_60hz ? 24 : 38; - if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) - lines += 2; - } - - itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); - - /* Note: sliced vs raw flag doesn't seem to have any effect - TODO: check mode (0x02) value with older ivtv versions. */ - data[0] = raw | 0x02 | (0xbd << 8); - - /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ - data[1] = 1; - /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ - data[2] = raw ? 4 : 8; - /* The start/stop codes determine which VBI lines end up in the raw VBI data area. - The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line - is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) - code. These values for raw VBI are obtained from a driver disassembly. The sliced - start/stop codes was deduced from this, but they do not appear in the driver. - Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. - However, I have no idea what these values are for. */ - if (itv->hw_flags & IVTV_HW_CX25840) { - /* Setup VBI for the cx25840 digitizer */ - if (raw) { - data[3] = 0x20602060; - data[4] = 0x30703070; - } else { - data[3] = 0xB0F0B0F0; - data[4] = 0xA0E0A0E0; - } - /* Lines per frame */ - data[5] = lines; - /* bytes per line */ - data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); - } else { - /* Setup VBI for the saa7115 digitizer */ - if (raw) { - data[3] = 0x25256262; - data[4] = 0x387F7F7F; - } else { - data[3] = 0xABABECEC; - data[4] = 0xB6F1F1F1; - } - /* Lines per frame */ - data[5] = lines; - /* bytes per line */ - data[6] = itv->vbi.enc_size / lines; - } - - IVTV_DEBUG_INFO( - "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", - data[0], data[1], data[2], data[5], data[6]); - - ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); - - /* returns the VBI encoder memory area. */ - itv->vbi.enc_start = data[2]; - itv->vbi.fpi = data[0]; - if (!itv->vbi.fpi) - itv->vbi.fpi = 1; - - IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", - itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); - - /* select VBI lines. - Note that the sliced argument seems to have no effect. */ - for (i = 2; i <= 24; i++) { - int valid; - - if (itv->is_60hz) { - valid = i >= 10 && i < 22; - } else { - valid = i >= 6 && i < 24; - } - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, - valid, 0 , 0, 0); - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, - valid, 0, 0, 0); - } - - /* Remaining VBI questions: - - Is it possible to select particular VBI lines only for inclusion in the MPEG - stream? Currently you can only get the first X lines. - - Is mixed raw and sliced VBI possible? - - What's the meaning of the raw/sliced flag? - - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ -} - -int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv *itv = s->itv; - int captype = 0, subtype = 0; - int enable_passthrough = 0; - - if (s->v4l2dev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); - - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_MPG: - captype = 0; - subtype = 3; - - /* Stop Passthrough */ - if (itv->output_mode == OUT_PASSTHROUGH) { - ivtv_passthrough_mode(itv, 0); - enable_passthrough = 1; - } - itv->mpg_data_received = itv->vbi_data_inserted = 0; - itv->dualwatch_jiffies = jiffies; - itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300; - itv->search_pack_header = 0; - break; - - case IVTV_ENC_STREAM_TYPE_YUV: - if (itv->output_mode == OUT_PASSTHROUGH) { - captype = 2; - subtype = 11; /* video+audio+decoder */ - break; - } - captype = 1; - subtype = 1; - break; - case IVTV_ENC_STREAM_TYPE_PCM: - captype = 1; - subtype = 2; - break; - case IVTV_ENC_STREAM_TYPE_VBI: - captype = 1; - subtype = 4; - - itv->vbi.frame = 0; - itv->vbi.inserted_frame = 0; - memset(itv->vbi.sliced_mpeg_size, - 0, sizeof(itv->vbi.sliced_mpeg_size)); - break; - default: - return -EINVAL; - } - s->subtype = subtype; - s->buffers_stolen = 0; - - /* mute/unmute video */ - ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0); - - /* Clear Streamoff flags in case left from last capture */ - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - if (atomic_read(&itv->capturing) == 0) { - /* Always use frame based mode. Experiments have demonstrated that byte - stream based mode results in dropped frames and corruption. Not often, - but occasionally. Many thanks go to Leonard Orb who spent a lot of - effort and time trying to trace the cause of the drop outs. */ - /* 1 frame per DMA */ - /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */ - ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1); - - /* Stuff from Windows, we don't know what it is */ - ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); - /* According to the docs, this should be correct. However, this is - untested. I don't dare enable this without having tested it. - Only very few old cards actually have this hardware combination. - ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, - ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0); - */ - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415); - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0); - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1); - ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); - - /* assign placeholder */ - ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); - - /* Setup VBI */ - if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { - ivtv_vbi_setup(itv); - } - - /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */ - ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400); - itv->pgm_info_offset = data[0]; - itv->pgm_info_num = data[1]; - itv->pgm_info_write_idx = 0; - itv->pgm_info_read_idx = 0; - - IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n", - itv->pgm_info_offset, itv->pgm_info_num); - - /* Setup API for Stream */ - cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); - } - - /* Vsync Setup */ - if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { - /* event notification (on) */ - ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1); - ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); - } - - if (atomic_read(&itv->capturing) == 0) { - /* Clear all Pending Interrupts */ - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - - clear_bit(IVTV_F_I_EOS, &itv->i_flags); - - /* Initialize Digitizer for Capture */ - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_sleep_timeout(HZ / 10, 0); - } - - /* begin_capture */ - if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) - { - IVTV_DEBUG_WARN( "Error starting capture!\n"); - return -EINVAL; - } - - /* Start Passthrough */ - if (enable_passthrough) { - ivtv_passthrough_mode(itv, 1); - } - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - - /* you're live! sit back and await interrupts :) */ - atomic_inc(&itv->capturing); - return 0; -} - -static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv *itv = s->itv; - int datatype; - - if (s->v4l2dev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); - - /* disable VBI signals, if the MPEG stream contains VBI data, - then that data will be processed automatically for you. */ - ivtv_disable_vbi(itv); - - /* set audio mode to left/stereo for dual/stereo mode. */ - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - - /* set number of internal decoder buffers */ - ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0); - - /* prebuffering */ - ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1); - - /* extract from user packets */ - ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1); - itv->vbi.dec_start = data[0]; - - IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n", - itv->vbi.dec_start, data[1]); - - /* set decoder source settings */ - /* Data type: 0 = mpeg from host, - 1 = yuv from encoder, - 2 = yuv_from_host */ - switch (s->type) { - case IVTV_DEC_STREAM_TYPE_YUV: - datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2; - IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); - break; - case IVTV_DEC_STREAM_TYPE_MPG: - default: - datatype = 0; - break; - } - if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, - itv->params.width, itv->params.height, itv->params.audio_properties)) { - IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n"); - } - return 0; -} - -int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) -{ - struct ivtv *itv = s->itv; - - if (s->v4l2dev == NULL) - return -EINVAL; - - if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) - return 0; /* already started */ - - IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); - - /* Clear Streamoff */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - /* Initialize Decoder */ - /* Reprogram Decoder YUV Buffers for YUV */ - write_reg(yuv_offset[0] >> 4, 0x82c); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[0] >> 4, 0x834); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - - write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); - - write_reg_sync(0x00108080, 0x2898); - /* Enable YUV decoder output */ - write_reg_sync(0x01, IVTV_REG_VDM); - } - - ivtv_setup_v4l2_decode_stream(s); - - /* set dma size to 65536 bytes */ - ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); - - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - /* Zero out decoder counters */ - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]); - - /* turn on notification of dual/stereo mode change */ - ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); - - /* start playback */ - ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); - - /* Clear the following Interrupt mask bits for decoding */ - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); - IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); - - /* you're live! sit back and await interrupts :) */ - atomic_inc(&itv->decoding); - return 0; -} - -void ivtv_stop_all_captures(struct ivtv *itv) -{ - int i; - - for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->v4l2dev == NULL) - continue; - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - ivtv_stop_v4l2_encode_stream(s, 0); - } - } -} - -int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) -{ - struct ivtv *itv = s->itv; - DECLARE_WAITQUEUE(wait, current); - int cap_type; - unsigned long then; - int stopmode; - u32 data[CX2341X_MBOX_MAX_DATA]; - - if (s->v4l2dev == NULL) - return -EINVAL; - - /* This function assumes that you are allowed to stop the capture - and that we are actually capturing */ - - IVTV_DEBUG_INFO("Stop Capture\n"); - - if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) - return 0; - if (atomic_read(&itv->capturing) == 0) - return 0; - - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_YUV: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_PCM: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_VBI: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_MPG: - default: - cap_type = 0; - break; - } - - /* Stop Capture Mode */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { - stopmode = 0; - } else { - stopmode = 1; - } - - /* end_capture */ - /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ - ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - - /* only run these if we're shutting down the last cap */ - if (atomic_read(&itv->capturing) - 1 == 0) { - /* event notification (off) */ - if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { - /* type: 0 = refresh */ - /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ - ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); - ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); - } - } - - then = jiffies; - - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { - /* only run these if we're shutting down the last cap */ - unsigned long duration; - - then = jiffies; - add_wait_queue(&itv->cap_w, &wait); - - set_current_state(TASK_INTERRUPTIBLE); - - /* wait 2s for EOS interrupt */ - while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) { - schedule_timeout(HZ / 100); - } - - /* To convert jiffies to ms, we must multiply by 1000 - * and divide by HZ. To avoid runtime division, we - * convert this to multiplication by 1000/HZ. - * Since integer division truncates, we get the best - * accuracy if we do a rounding calculation of the constant. - * Think of the case where HZ is 1024. - */ - duration = ((1000 + HZ / 2) / HZ) * (jiffies - then); - - if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { - IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); - IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); - } else { - IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&itv->cap_w, &wait); - } - - then = jiffies; - /* Make sure DMA is complete */ - add_wait_queue(&s->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - do { - /* check if DMA is pending */ - if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ - (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { - /* Check for last DMA */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); - - if (data[0] == 1) { - IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); - break; - } - } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { - break; - } - - ivtv_sleep_timeout(HZ / 100, 1); - } while (then + HZ * 2 > jiffies); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&s->waitq, &wait); - } - - atomic_dec(&itv->capturing); - - /* Clear capture and no-read bits */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); - - if (atomic_read(&itv->capturing) > 0) { - return 0; - } - - /* Set the following Interrupt mask bits for capture */ - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - - wake_up(&s->waitq); - - return 0; -} - -int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) -{ - struct ivtv *itv = s->itv; - - if (s->v4l2dev == NULL) - return -EINVAL; - - if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) - return -EINVAL; - - if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags)) - return 0; - - IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", pts, flags); - - /* Stop Decoder */ - if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { - u32 tmp = 0; - - /* Wait until the decoder is no longer running */ - if (pts) { - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, - 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32)); - } - while (1) { - u32 data[CX2341X_MBOX_MAX_DATA]; - ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0); - if (s->q_full.buffers + s->q_dma.buffers == 0) { - if (tmp == data[3]) - break; - tmp = data[3]; - } - if (ivtv_sleep_timeout(HZ/10, 1)) - break; - } - } - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); - - /* turn off notification of dual/stereo mode change */ - ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); - - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); - - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - ivtv_flush_queues(s); - - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { - /* disable VBI on TV-out */ - ivtv_disable_vbi(itv); - } - - /* decrement decoding */ - atomic_dec(&itv->decoding); - - set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); - wake_up(&itv->event_waitq); - - /* wake up wait queues */ - wake_up(&s->waitq); - - return 0; -} - -int ivtv_passthrough_mode(struct ivtv *itv, int enable) -{ - struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; - struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - - if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); - - /* Prevent others from starting/stopping streams while we - initiate/terminate passthrough mode */ - if (enable) { - if (itv->output_mode == OUT_PASSTHROUGH) { - return 0; - } - if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) - return -EBUSY; - - /* Fully initialize stream, and then unflag init */ - set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); - set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); - - /* Setup YUV Decoder */ - ivtv_setup_v4l2_decode_stream(dec_stream); - - /* Start Decoder */ - ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1); - atomic_inc(&itv->decoding); - - /* Setup capture if not already done */ - if (atomic_read(&itv->capturing) == 0) { - cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); - } - - /* Start Passthrough Mode */ - ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11); - atomic_inc(&itv->capturing); - return 0; - } - - if (itv->output_mode != OUT_PASSTHROUGH) - return 0; - - /* Stop Passthrough Mode */ - ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11); - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0); - - atomic_dec(&itv->capturing); - atomic_dec(&itv->decoding); - clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); - clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); - itv->output_mode = OUT_NONE; - - return 0; -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-streams.h b/trunk/drivers/media/video/ivtv/ivtv-streams.h deleted file mode 100644 index 8597b75384a7..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-streams.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - init/start/stop/exit stream functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -int ivtv_streams_setup(struct ivtv *itv); -void ivtv_streams_cleanup(struct ivtv *itv); - -/* Capture related */ -int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); -int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end); -int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset); -int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); - -void ivtv_stop_all_captures(struct ivtv *itv); -int ivtv_passthrough_mode(struct ivtv *itv, int enable); diff --git a/trunk/drivers/media/video/ivtv/ivtv-udma.c b/trunk/drivers/media/video/ivtv/ivtv-udma.c deleted file mode 100644 index bd642e1aafc3..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-udma.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - User DMA - - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-streams.h" -#include "ivtv-udma.h" - -void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) -{ - dma_page->uaddr = first & PAGE_MASK; - dma_page->offset = first & ~PAGE_MASK; - dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK); - dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT; - dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma_page->page_count = dma_page->last - dma_page->first + 1; - if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset; -} - -int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) -{ - int i, offset; - - offset = dma_page->offset; - - /* Fill SG Array with new values */ - for (i = 0; i < dma_page->page_count; i++) { - if (i == dma_page->page_count - 1) { - dma->SGlist[map_offset].length = dma_page->tail; - } - else { - dma->SGlist[map_offset].length = PAGE_SIZE - offset; - } - dma->SGlist[map_offset].offset = offset; - dma->SGlist[map_offset].page = dma->map[map_offset]; - offset = 0; - map_offset++; - } - return map_offset; -} - -void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { - int i; - struct scatterlist *sg; - - for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) { - dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); - dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); - dma->SGarray[i].dst = cpu_to_le32(buffer_offset); - buffer_offset += sg_dma_len(sg); - - split -= sg_dma_len(sg); - if (split == 0) - buffer_offset = buffer_offset_2; - } -} - -/* User DMA Buffers */ -void ivtv_udma_alloc(struct ivtv *itv) -{ - if (itv->udma.SG_handle == 0) { - /* Map DMA Page Array Buffer */ - itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); - ivtv_udma_sync_for_cpu(itv); - } -} - -int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, - void __user *userbuf, int size_in_bytes) -{ - struct ivtv_dma_page_info user_dma; - struct ivtv_user_dma *dma = &itv->udma; - int err; - - IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); - - /* Still in USE */ - if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); - return -EBUSY; - } - - ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes); - - if (user_dma.page_count <= 0) { - IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n", - user_dma.page_count, size_in_bytes, user_dma.offset); - return -EINVAL; - } - - /* Get user pages for DMA Xfer */ - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current, current->mm, - user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); - up_read(¤t->mm->mmap_sem); - - if (user_dma.page_count != err) { - IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", - err, user_dma.page_count); - return -EINVAL; - } - - dma->page_count = user_dma.page_count; - - /* Fill SG List with new values */ - ivtv_udma_fill_sg_list(dma, &user_dma, 0); - - /* Map SG List */ - dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - - /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); - - /* Tag SG Array with Interrupt Bit */ - dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); - - ivtv_udma_sync_for_device(itv); - return dma->page_count; -} - -void ivtv_udma_unmap(struct ivtv *itv) -{ - struct ivtv_user_dma *dma = &itv->udma; - int i; - - IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n"); - - /* Nothing to free */ - if (dma->page_count == 0) - return; - - /* Unmap Scatterlist */ - if (dma->SG_length) { - pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - dma->SG_length = 0; - } - /* sync DMA */ - ivtv_udma_sync_for_cpu(itv); - - /* Release User Pages */ - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); - } - dma->page_count = 0; -} - -void ivtv_udma_free(struct ivtv *itv) -{ - /* Unmap SG Array */ - if (itv->udma.SG_handle) { - pci_unmap_single(itv->dev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); - } - - /* Unmap Scatterlist */ - if (itv->udma.SG_length) { - pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); - } -} - -void ivtv_udma_start(struct ivtv *itv) -{ - IVTV_DEBUG_DMA("start UDMA\n"); - write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - set_bit(IVTV_F_I_UDMA, &itv->i_flags); -} - -void ivtv_udma_prepare(struct ivtv *itv) -{ - unsigned long flags; - - spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) - ivtv_udma_start(itv); - else - set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); - spin_unlock_irqrestore(&itv->dma_reg_lock, flags); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-udma.h b/trunk/drivers/media/video/ivtv/ivtv-udma.h deleted file mode 100644 index e131bccedec0..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-udma.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2006-2007 Hans Verkuil - - 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 - */ - -/* User DMA functions */ -void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); -int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); -void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split); -int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, - void __user *userbuf, int size_in_bytes); -void ivtv_udma_unmap(struct ivtv *itv); -void ivtv_udma_free(struct ivtv *itv); -void ivtv_udma_alloc(struct ivtv *itv); -void ivtv_udma_prepare(struct ivtv *itv); -void ivtv_udma_start(struct ivtv *itv); - -static inline void ivtv_udma_sync_for_device(struct ivtv *itv) -{ - pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); -} - -static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) -{ - pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-vbi.c b/trunk/drivers/media/video/ivtv/ivtv-vbi.c deleted file mode 100644 index 5efa5a867818..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-vbi.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" -#include "ivtv-ioctl.h" -#include "ivtv-queue.h" - -static int odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static void passthrough_vbi_data(struct ivtv *itv, int cnt) -{ - int wss = 0; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - u8 vps[13]; - int found_cc = 0; - int found_wss = 0; - int found_vps = 0; - int cc_pos = itv->vbi.cc_pos; - int i; - - for (i = 0; i < cnt; i++) { - struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; - - if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { - found_cc = 1; - if (d->field) { - cc[2] = d->data[0]; - cc[3] = d->data[1]; - } else { - cc[0] = d->data[0]; - cc[1] = d->data[1]; - } - } - else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { - memcpy(vps, d->data, sizeof(vps)); - found_vps = 1; - } - else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { - wss = d->data[0] | d->data[1] << 8; - found_wss = 1; - } - } - - if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { - itv->vbi.wss = wss; - itv->vbi.wss_found = found_wss; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - - if (found_vps || itv->vbi.vps_found) { - itv->vbi.vps[0] = vps[2]; - itv->vbi.vps[1] = vps[8]; - itv->vbi.vps[2] = vps[9]; - itv->vbi.vps[3] = vps[10]; - itv->vbi.vps[4] = vps[11]; - itv->vbi.vps_found = found_vps; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } -} - -static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) -{ - int line = 0; - int i; - u32 linemask[2] = { 0, 0 }; - unsigned short size; - static const u8 mpeg_hdr_data[] = { - 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, - 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, - 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, - 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff - }; - const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ - int idx = itv->vbi.frame % IVTV_VBI_FRAMES; - u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; - - for (i = 0; i < lines; i++) { - int f, l; - - if (itv->vbi.sliced_data[i].id == 0) - continue; - - l = itv->vbi.sliced_data[i].line - 6; - f = itv->vbi.sliced_data[i].field; - if (f) - l += 18; - if (l < 32) - linemask[0] |= (1 << l); - else - linemask[1] |= (1 << (l - 32)); - dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id); - memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); - line++; - } - memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); - if (line == 36) { - /* All lines are used, so there is no space for the linemask - (the max size of the VBI data is 36 * 43 + 4 bytes). - So in this case we use the magic number 'ITV0'. */ - memcpy(dst + sd, "ITV0", 4); - memcpy(dst + sd + 4, dst + sd + 12, line * 43); - size = 4 + ((43 * line + 3) & ~3); - } else { - memcpy(dst + sd, "itv0", 4); - memcpy(dst + sd + 4, &linemask[0], 8); - size = 12 + ((43 * line + 3) & ~3); - } - dst[4+16] = (size + 10) >> 8; - dst[5+16] = (size + 10) & 0xff; - dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); - dst[10+16] = (pts_stamp >> 22) & 0xff; - dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); - dst[12+16] = (pts_stamp >> 7) & 0xff; - dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); - itv->vbi.sliced_mpeg_size[idx] = sd + size; -} - -static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) -{ - u32 linemask[2]; - int i, l, id2; - int line = 0; - - if (!memcmp(p, "itv0", 4)) { - memcpy(linemask, p + 4, 8); - p += 12; - } else if (!memcmp(p, "ITV0", 4)) { - linemask[0] = 0xffffffff; - linemask[1] = 0xf; - p += 4; - } else { - /* unknown VBI data stream */ - return 0; - } - for (i = 0; i < 36; i++) { - int err = 0; - - if (i < 32 && !(linemask[0] & (1 << i))) - continue; - if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) - continue; - id2 = *p & 0xf; - switch (id2) { - case IVTV_SLICED_TYPE_TELETEXT_B: - id2 = V4L2_SLICED_TELETEXT_B; - break; - case IVTV_SLICED_TYPE_CAPTION_525: - id2 = V4L2_SLICED_CAPTION_525; - err = !odd_parity(p[1]) || !odd_parity(p[2]); - break; - case IVTV_SLICED_TYPE_VPS: - id2 = V4L2_SLICED_VPS; - break; - case IVTV_SLICED_TYPE_WSS_625: - id2 = V4L2_SLICED_WSS_625; - break; - default: - id2 = 0; - break; - } - if (err == 0) { - l = (i < 18) ? i + 6 : i - 18 + 6; - itv->vbi.sliced_dec_data[line].line = l; - itv->vbi.sliced_dec_data[line].field = i >= 18; - itv->vbi.sliced_dec_data[line].id = id2; - memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); - line++; - } - p += 43; - } - while (line < 36) { - itv->vbi.sliced_dec_data[line].id = 0; - itv->vbi.sliced_dec_data[line].line = 0; - itv->vbi.sliced_dec_data[line].field = 0; - line++; - } - return line * sizeof(itv->vbi.sliced_dec_data[0]); -} - -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) -{ - /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ - const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - int found_cc = 0; - int cc_pos = itv->vbi.cc_pos; - - if (itv->vbi.service_set_out == 0) - return -EPERM; - - while (count >= sizeof(struct v4l2_sliced_vbi_data)) { - switch (p->id) { - case V4L2_SLICED_CAPTION_525: - if (p->id == V4L2_SLICED_CAPTION_525 && - p->line == 21 && - (itv->vbi.service_set_out & - V4L2_SLICED_CAPTION_525) == 0) { - break; - } - found_cc = 1; - if (p->field) { - cc[2] = p->data[0]; - cc[3] = p->data[1]; - } else { - cc[0] = p->data[0]; - cc[1] = p->data[1]; - } - break; - - case V4L2_SLICED_VPS: - if (p->line == 16 && p->field == 0 && - (itv->vbi.service_set_out & V4L2_SLICED_VPS)) { - itv->vbi.vps[0] = p->data[2]; - itv->vbi.vps[1] = p->data[8]; - itv->vbi.vps[2] = p->data[9]; - itv->vbi.vps[3] = p->data[10]; - itv->vbi.vps[4] = p->data[11]; - itv->vbi.vps_found = 1; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - break; - - case V4L2_SLICED_WSS_625: - if (p->line == 23 && p->field == 0 && - (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) { - /* No lock needed for WSS */ - itv->vbi.wss = p->data[0] | (p->data[1] << 8); - itv->vbi.wss_found = 1; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - break; - - default: - break; - } - count -= sizeof(*p); - p++; - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } - - return (const char __user *)p - ubuf; -} - -/* Compress raw VBI format, removes leading SAV codes and surplus space after the - field. - Returns new compressed size. */ -static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) -{ - u32 line_size = itv->vbi.raw_decoder_line_size; - u32 lines = itv->vbi.count; - u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; - u8 sav2 = itv->vbi.raw_decoder_sav_even_field; - u8 *q = buf; - u8 *p; - int i; - - for (i = 0; i < lines; i++) { - p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { - break; - } - memcpy(q, p + 4, line_size - 4); - q += line_size - 4; - } - return lines * (line_size - 4); -} - - -/* Compressed VBI format, all found sliced blocks put next to one another - Returns new compressed size */ -static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) -{ - u32 line_size = itv->vbi.sliced_decoder_line_size; - struct v4l2_decode_vbi_line vbi; - int i; - - /* find the first valid line */ - for (i = 0; i < size; i++, buf++) { - if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) - break; - } - - size -= i; - if (size < line_size) { - return line; - } - for (i = 0; i < size / line_size; i++) { - u8 *p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { - continue; - } - vbi.p = p + 4; - itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); - if (vbi.type) { - itv->vbi.sliced_data[line].id = vbi.type; - itv->vbi.sliced_data[line].field = vbi.is_second_field; - itv->vbi.sliced_data[line].line = vbi.line; - memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); - line++; - } - } - return line; -} - -void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, - u64 pts_stamp, int streamtype) -{ - u8 *p = (u8 *) buf->buf; - u32 size = buf->bytesused; - int y; - - /* Raw VBI data */ - if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) { - u8 type; - - ivtv_buf_swap(buf); - - type = p[3]; - - size = buf->bytesused = compress_raw_buf(itv, p, size); - - /* second field of the frame? */ - if (type == itv->vbi.raw_decoder_sav_even_field) { - /* Dirty hack needed for backwards - compatibility of old VBI software. */ - p += size - 4; - memcpy(p, &itv->vbi.frame, 4); - itv->vbi.frame++; - } - return; - } - - /* Sliced VBI data with data insertion */ - if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { - int lines; - - ivtv_buf_swap(buf); - - /* first field */ - lines = compress_sliced_buf(itv, 0, p, size / 2, - itv->vbi.sliced_decoder_sav_odd_field); - /* second field */ - /* experimentation shows that the second half does not always begin - at the exact address. So start a bit earlier (hence 32). */ - lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, - itv->vbi.sliced_decoder_sav_even_field); - /* always return at least one empty line */ - if (lines == 0) { - itv->vbi.sliced_data[0].id = 0; - itv->vbi.sliced_data[0].line = 0; - itv->vbi.sliced_data[0].field = 0; - lines = 1; - } - buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); - memcpy(p, &itv->vbi.sliced_data[0], size); - - if (itv->vbi.insert_mpeg) { - copy_vbi_data(itv, lines, pts_stamp); - } - itv->vbi.frame++; - return; - } - - /* Sliced VBI re-inserted from an MPEG stream */ - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { - /* If the size is not 4-byte aligned, then the starting address - for the swapping is also shifted. After swapping the data the - real start address of the VBI data is exactly 4 bytes after the - original start. It's a bit fiddly but it works like a charm. - Non-4-byte alignment happens when an lseek is done on the input - mpeg file to a non-4-byte aligned position. So on arrival here - the VBI data is also non-4-byte aligned. */ - int offset = size & 3; - int cnt; - - if (offset) { - p += 4 - offset; - } - /* Swap Buffer */ - for (y = 0; y < size; y += 4) { - swab32s((u32 *)(p + y)); - } - - cnt = ivtv_convert_ivtv_vbi(itv, p + offset); - memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); - buf->bytesused = cnt; - - passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); - return; - } -} - -void ivtv_disable_vbi(struct ivtv *itv) -{ - clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_wss(itv, 0, 0); - ivtv_set_cc(itv, 0, 0, 0, 0, 0); - ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); - itv->vbi.vps_found = itv->vbi.wss_found = 0; - itv->vbi.wss = 0; - itv->vbi.cc_pos = 0; -} - - -void vbi_work_handler(struct ivtv *itv) -{ - struct v4l2_sliced_vbi_data data; - - /* Lock */ - if (itv->output_mode == OUT_PASSTHROUGH) { - /* Note: currently only the saa7115 is used in a PVR350, - so these commands are for now saa7115 specific. */ - if (itv->is_50hz) { - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - - if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { - ivtv_set_wss(itv, 1, data.data[0] & 0xf); - itv->vbi.wss_no_update = 0; - } else if (itv->vbi.wss_no_update == 4) { - ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ - } else { - itv->vbi.wss_no_update++; - } - } - else { - u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; - int mode = 0; - - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { - mode |= 1; - c1 = data.data[0]; - c2 = data.data[1]; - } - data.field = 1; - if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { - mode |= 2; - c3 = data.data[0]; - c4 = data.data[1]; - } - if (mode) { - itv->vbi.cc_no_update = 0; - ivtv_set_cc(itv, mode, c1, c2, c3, c4); - } else if (itv->vbi.cc_no_update == 4) { - ivtv_set_cc(itv, 0, 0, 0, 0, 0); - } else { - itv->vbi.cc_no_update++; - } - } - return; - } - - if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { - /* Lock */ - ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); - } - - if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { - if (itv->vbi.cc_pos == 0) { - ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); - } - while (itv->vbi.cc_pos) { - u8 cc_odd0 = itv->vbi.cc_data_odd[0]; - u8 cc_odd1 = itv->vbi.cc_data_odd[1]; - u8 cc_even0 = itv->vbi.cc_data_even[0]; - u8 cc_even1 = itv->vbi.cc_data_even[1]; - - memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); - memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); - itv->vbi.cc_pos -= 2; - if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) - continue; - - /* Send to Saa7127 */ - ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); - if (itv->vbi.cc_pos == 0) - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - break; - } - } - - if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { - /* Lock */ - ivtv_set_vps(itv, itv->vbi.vps_found, - itv->vbi.vps[0], itv->vbi.vps[1], - itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); - } -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-vbi.h b/trunk/drivers/media/video/ivtv/ivtv-vbi.h deleted file mode 100644 index cdaea697b3ec..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-vbi.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil - - 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 - */ - -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); -void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, - u64 pts_stamp, int streamtype); -int ivtv_used_line(struct ivtv *itv, int line, int field); -void ivtv_disable_vbi(struct ivtv *itv); -void ivtv_set_vbi(unsigned long arg); -void vbi_work_handler(struct ivtv *itv); diff --git a/trunk/drivers/media/video/ivtv/ivtv-version.h b/trunk/drivers/media/video/ivtv/ivtv-version.h deleted file mode 100644 index 85530a3cd369..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-version.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - ivtv driver version information - Copyright (C) 2005-2007 Hans Verkuil - - 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 - */ - -#define IVTV_DRIVER_NAME "ivtv" -#define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 0 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 0 - -#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/trunk/drivers/media/video/ivtv/ivtv-video.c b/trunk/drivers/media/video/ivtv/ivtv-video.c deleted file mode 100644 index 5858b197d510..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-video.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - 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 "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-i2c.h" -#include "ivtv-gpio.h" -#include "ivtv-cards.h" -#include -#include - -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_VPS; - data.field = 0; - data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); - data.field = 1; - data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - /* When using a 50 Hz system, always turn on the - wide screen signal with 4x3 ratio as the default. - Turning this signal on and off can confuse certain - TVs. As far as I can tell there is no reason not to - transmit this signal. */ - if ((itv->std & V4L2_STD_625_50) && !enabled) { - enabled = 1; - mode = 0x08; /* 4x3 full format */ - } - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - data.line = enabled ? 23 : 0; - data.data[0] = mode & 0xff; - data.data[1] = (mode >> 8) & 0xff; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_video_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - int inp = itv->active_input; - u32 type; - - route.input = itv->card->video_inputs[inp].video_input; - route.output = 0; - itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - - type = itv->card->video_inputs[inp].video_type; - - if (type == IVTV_CARD_INPUT_VID_TUNER) { - route.input = 0; /* Tuner */ - } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { - route.input = 2; /* S-Video */ - } else { - route.input = 1; /* Composite */ - } - - if (itv->card->hw_video & IVTV_HW_GPIO) - ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - - if (itv->card->hw_video & IVTV_HW_UPD64031A) { - if (type == IVTV_CARD_INPUT_VID_TUNER || - type >= IVTV_CARD_INPUT_COMPOSITE1) { - /* Composite: GR on, connect to 3DYCS */ - route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; - } else { - /* S-Video: GR bypassed, turn it off */ - route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; - } - route.input |= itv->card->gr_config; - - ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - } - - if (itv->card->hw_video & IVTV_HW_UPD6408X) { - route.input = UPD64083_YCS_MODE; - if (type > IVTV_CARD_INPUT_VID_TUNER && - type < IVTV_CARD_INPUT_COMPOSITE1) { - /* S-Video uses YCNR mode and internal Y-ADC, the upd64031a - is not used. */ - route.input |= UPD64083_YCNR_MODE; - } - else if (itv->card->hw_video & IVTV_HW_UPD64031A) { - /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */ - if ((type == IVTV_CARD_INPUT_VID_TUNER)|| - (itv->card->type == IVTV_CARD_CX23416GYC)) { - route.input |= UPD64083_EXT_Y_ADC; - } - } - ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - } -} diff --git a/trunk/drivers/media/video/ivtv/ivtv-video.h b/trunk/drivers/media/video/ivtv/ivtv-video.h deleted file mode 100644 index c8ade5d3c413..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-video.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - 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 - */ - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5); -void ivtv_video_set_io(struct ivtv *itv); diff --git a/trunk/drivers/media/video/ivtv/ivtv-yuv.c b/trunk/drivers/media/video/ivtv/ivtv-yuv.c deleted file mode 100644 index bcea09542e5a..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-yuv.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - yuv support - - Copyright (C) 2007 Ian Armstrong - - 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 "ivtv-driver.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-yuv.h" - -static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, - struct ivtv_dma_frame *args) -{ - struct ivtv_dma_page_info y_dma; - struct ivtv_dma_page_info uv_dma; - - int i; - int y_pages, uv_pages; - - unsigned long y_buffer_offset, uv_buffer_offset; - int y_decode_height, uv_decode_height, y_size; - int frame = atomic_read(&itv->yuv_info.next_fill_frame); - - y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; - uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - - y_decode_height = uv_decode_height = args->src.height + args->src.top; - - if (y_decode_height < 512-16) - y_buffer_offset += 720 * 16; - - if (y_decode_height & 15) - y_decode_height = (y_decode_height + 16) & ~15; - - if (uv_decode_height & 31) - uv_decode_height = (uv_decode_height + 32) & ~31; - - y_size = 720 * y_decode_height; - - /* Still in USE */ - if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); - return -EBUSY; - } - - ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); - ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); - - /* Get user pages for DMA Xfer */ - down_read(¤t->mm->mmap_sem); - y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); - uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL); - up_read(¤t->mm->mmap_sem); - - dma->page_count = y_dma.page_count + uv_dma.page_count; - - if (y_pages + uv_pages != dma->page_count) { - IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", - y_pages + uv_pages, dma->page_count); - - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); - } - dma->page_count = 0; - return -EINVAL; - } - - /* Fill & map SG List */ - ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); - dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - - /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); - - /* If we've offset the y plane, ensure top area is blanked */ - if (args->src.height + args->src.top < 512-16) { - if (itv->yuv_info.blanking_dmaptr) { - dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); - dma->SG_length++; - } - } - - /* Tag SG Array with Interrupt Bit */ - dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); - - ivtv_udma_sync_for_device(itv); - return 0; -} - -/* We rely on a table held in the firmware - Quick check. */ -int ivtv_yuv_filter_check(struct ivtv *itv) -{ - int i, offset_y, offset_uv; - - for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { - if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || - (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { - IVTV_WARN ("YUV filter table not found in firmware.\n"); - return -1; - } - } - return 0; -} - -static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) -{ - int filter_index, filter_line; - - /* If any filter is -1, then don't update it */ - if (h_filter > -1) { - if (h_filter > 4) h_filter = 4; - filter_index = h_filter * 384; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); - filter_index += 8; - write_reg(0, 0x02818); - write_reg(0, 0x02830); - filter_line ++; - } - IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); - } - - if (v_filter_1 > -1) { - if (v_filter_1 > 4) v_filter_1 = 4; - filter_index = v_filter_1 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); - filter_index += 8; - write_reg(0, 0x02908); - filter_line ++; - } - IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); - } - - if (v_filter_2 > -1) { - if (v_filter_2 > 4) v_filter_2 = 4; - filter_index = v_filter_2 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); - filter_index += 8; - write_reg(0, 0x02914); - filter_line ++; - } - IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); - } -} - -static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) -{ - u32 reg_2834, reg_2838, reg_283c; - u32 reg_2844, reg_2854, reg_285c; - u32 reg_2864, reg_2874, reg_2890; - u32 reg_2870, reg_2870_base, reg_2870_offset; - int x_cutoff; - int h_filter; - u32 master_width; - - IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", - window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); - - /* How wide is the src image */ - x_cutoff = window->src_w + window->src_x; - - /* Set the display width */ - reg_2834 = window->dst_w; - reg_2838 = reg_2834; - - /* Set the display position */ - reg_2890 = window->dst_x; - - /* Index into the image horizontally */ - reg_2870 = 0; - - /* 2870 is normally fudged to align video coords with osd coords. - If running full screen, it causes an unwanted left shift - Remove the fudge if we almost fill the screen. - Gradually adjust the offset to avoid the video 'snapping' - left/right if it gets dragged through this region. - Only do this if osd is full width. */ - if (window->vis_w == 720) { - if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ - reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; - } - else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { - reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); - } - - if (window->dst_w >= window->src_w) - reg_2870 = reg_2870 << 16 | reg_2870; - else - reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); - } - - if (window->dst_w < window->src_w) - reg_2870 = 0x000d000e - reg_2870; - else - reg_2870 = 0x0012000e - reg_2870; - - /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ - reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; - - if (window->dst_w >= window->src_w) { - x_cutoff &= ~1; - master_width = (window->src_w * 0x00200000) / (window->dst_w); - if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 2; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - - /* We also need to factor in the scaling - (src_w - dst_w) / (src_w / 4) */ - if (window->dst_w > window->src_w) - reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); - else - reg_2870_base = 0; - - reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); - reg_2874 = 0; - } - else if (window->dst_w < window->src_w / 2) { - master_width = (window->src_w * 0x00080000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 1; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); - reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; - reg_2874 = 0x00000012; - } - else { - master_width = (window->src_w * 0x00100000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 1; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); - reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; - reg_2874 = 0x00000001; - } - - /* Select the horizontal filter */ - if (window->src_w == window->dst_w) { - /* An exact size match uses filter 0 */ - h_filter = 0; - } - else { - /* Figure out which filter to use */ - h_filter = ((window->src_w << 16) / window->dst_w) >> 15; - h_filter = (h_filter >> 1) + (h_filter & 1); - /* Only an exact size match can use filter 0 */ - if (h_filter == 0) h_filter = 1; - } - - write_reg(reg_2834, 0x02834); - write_reg(reg_2838, 0x02838); - IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); - - write_reg(reg_283c, 0x0283c); - write_reg(reg_2844, 0x02844); - - IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); - - write_reg(0x00080514, 0x02840); - write_reg(0x00100514, 0x02848); - IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); - - write_reg(reg_2854, 0x02854); - IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); - - write_reg(reg_285c, 0x0285c); - write_reg(reg_2864, 0x02864); - IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); - - write_reg(reg_2874, 0x02874); - IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); - - write_reg(reg_2870, 0x02870); - IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); - - write_reg( reg_2890,0x02890); - IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); - - /* Only update the filter if we really need to */ - if (h_filter != itv->yuv_info.h_filter) { - ivtv_yuv_filter (itv,h_filter,-1,-1); - itv->yuv_info.h_filter = h_filter; - } -} - -static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) -{ - u32 master_height; - u32 reg_2918, reg_291c, reg_2920, reg_2928; - u32 reg_2930, reg_2934, reg_293c; - u32 reg_2940, reg_2944, reg_294c; - u32 reg_2950, reg_2954, reg_2958, reg_295c; - u32 reg_2960, reg_2964, reg_2968, reg_296c; - u32 reg_289c; - u32 src_y_major_y, src_y_minor_y; - u32 src_y_major_uv, src_y_minor_uv; - u32 reg_2964_base, reg_2968_base; - int v_filter_1, v_filter_2; - - IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", - window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); - - /* What scaling mode is being used... */ - if (window->interlaced_y) { - IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); - } - - if (window->interlaced_uv) { - IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); - } - - /* What is the source video being treated as... */ - if (itv->yuv_info.frame_interlaced) { - IVTV_DEBUG_WARN("Source video: Interlaced\n"); - } - else { - IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); - } - - /* We offset into the image using two different index methods, so split - the y source coord into two parts. */ - if (window->src_y < 8) { - src_y_minor_uv = window->src_y; - src_y_major_uv = 0; - } - else { - src_y_minor_uv = 8; - src_y_major_uv = window->src_y - 8; - } - - src_y_minor_y = src_y_minor_uv; - src_y_major_y = src_y_major_uv; - - if (window->offset_y) src_y_minor_y += 16; - - if (window->interlaced_y) - reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); - else - reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); - - if (window->interlaced_uv) - reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); - else - reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); - - reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; - reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; - - if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { - master_height = (window->src_h * 0x00400000) / window->dst_h; - if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 3; - reg_2930 = master_height; - reg_2940 = master_height >> 1; - reg_2964_base >>= 3; - reg_2968_base >>= 3; - reg_296c = 0x00000000; - } - else if (window->dst_h >= window->src_h) { - master_height = (window->src_h * 0x00400000) / window->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height >> 1; - reg_296c = 0x00000000; - if (window->interlaced_y) { - reg_2964_base >>= 3; - } - else { - reg_296c ++; - reg_2964_base >>= 2; - } - if (window->interlaced_uv) reg_2928 >>= 1; - reg_2968_base >>= 3; - } - else if (window->dst_h >= window->src_h / 2) { - master_height = (window->src_h * 0x00200000) / window->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height; - reg_296c = 0x00000101; - if (window->interlaced_y) { - reg_2964_base >>= 2; - } - else { - reg_296c ++; - reg_2964_base >>= 1; - } - if (window->interlaced_uv) reg_2928 >>= 1; - reg_2968_base >>= 2; - } - else { - master_height = (window->src_h * 0x00100000) / window->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height; - reg_2964_base >>= 1; - reg_2968_base >>= 2; - reg_296c = 0x00000102; - } - - /* FIXME These registers change depending on scaled / unscaled output - We really need to work out what they should be */ - if (window->src_h == window->dst_h){ - reg_2934 = 0x00020000; - reg_293c = 0x00100000; - reg_2944 = 0x00040000; - reg_294c = 0x000b0000; - } - else { - reg_2934 = 0x00000FF0; - reg_293c = 0x00000FF0; - reg_2944 = 0x00000FF0; - reg_294c = 0x00000FF0; - } - - /* The first line to be displayed */ - reg_2950 = 0x00010000 + src_y_major_y; - if (window->interlaced_y) reg_2950 += 0x00010000; - reg_2954 = reg_2950 + 1; - - reg_2958 = 0x00010000 + (src_y_major_y >> 1); - if (window->interlaced_uv) reg_2958 += 0x00010000; - reg_295c = reg_2958 + 1; - - if (itv->yuv_info.decode_height == 480) - reg_289c = 0x011e0017; - else - reg_289c = 0x01500017; - - if (window->dst_y < 0) - reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); - else - reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); - - /* How much of the source to decode. - Take into account the source offset */ - reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | - ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); - - /* Calculate correct value for register 2964 */ - if (window->src_h == window->dst_h) - reg_2964 = 1; - else { - reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); - reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); - } - reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); - reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); - - /* Okay, we've wasted time working out the correct value, - but if we use it, it fouls the the window alignment. - Fudge it to what we want... */ - reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); - reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); - - /* Deviate further from what it should be. I find the flicker headache - inducing so try to reduce it slightly. Leave 2968 as-is otherwise - colours foul. */ - if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) - reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); - - if (!window->interlaced_y) reg_2964 -= 0x00010001; - if (!window->interlaced_uv) reg_2968 -= 0x00010001; - - reg_2964 += ((reg_2964_base << 16) | reg_2964_base); - reg_2968 += ((reg_2968_base << 16) | reg_2968_base); - - /* Select the vertical filter */ - if (window->src_h == window->dst_h) { - /* An exact size match uses filter 0/1 */ - v_filter_1 = 0; - v_filter_2 = 1; - } - else { - /* Figure out which filter to use */ - v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; - v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); - /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; - v_filter_2 = v_filter_1; - } - - write_reg(reg_2934, 0x02934); - write_reg(reg_293c, 0x0293c); - IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); - write_reg(reg_2944, 0x02944); - write_reg(reg_294c, 0x0294c); - IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); - - /* Ensure 2970 is 0 (does it ever change ?) */ -/* write_reg(0,0x02970); */ -/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ - - write_reg(reg_2930, 0x02938); - write_reg(reg_2930, 0x02930); - IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); - - write_reg(reg_2928, 0x02928); - write_reg(reg_2928+0x514, 0x0292C); - IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); - - write_reg(reg_2920, 0x02920); - write_reg(reg_2920+0x514, 0x02924); - IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); - - write_reg (reg_2918,0x02918); - write_reg (reg_291c,0x0291C); - IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); - - write_reg(reg_296c, 0x0296c); - IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); - - write_reg(reg_2940, 0x02948); - write_reg(reg_2940, 0x02940); - IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); - - write_reg(reg_2950, 0x02950); - write_reg(reg_2954, 0x02954); - IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); - - write_reg(reg_2958, 0x02958); - write_reg(reg_295c, 0x0295C); - IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); - - write_reg(reg_2960, 0x02960); - IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); - - write_reg(reg_2964, 0x02964); - write_reg(reg_2968, 0x02968); - IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); - - write_reg( reg_289c,0x0289c); - IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); - - /* Only update filter 1 if we really need to */ - if (v_filter_1 != itv->yuv_info.v_filter_1) { - ivtv_yuv_filter (itv,-1,v_filter_1,-1); - itv->yuv_info.v_filter_1 = v_filter_1; - } - - /* Only update filter 2 if we really need to */ - if (v_filter_2 != itv->yuv_info.v_filter_2) { - ivtv_yuv_filter (itv,-1,-1,v_filter_2); - itv->yuv_info.v_filter_2 = v_filter_2; - } - - itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; -} - -/* Modify the supplied coordinate information to fit the visible osd area */ -static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) -{ - int osd_crop, lace_threshold; - u32 osd_scale; - u32 yuv_update = 0; - - lace_threshold = itv->yuv_info.lace_threshold; - if (lace_threshold < 0) - lace_threshold = itv->yuv_info.decode_height - 1; - - /* Work out the lace settings */ - switch (itv->yuv_info.lace_mode) { - case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ - itv->yuv_info.frame_interlaced = 0; - if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - break; - - case IVTV_YUV_MODE_AUTO: - if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ - itv->yuv_info.frame_interlaced = 0; - if ((window->tru_h < 512) || - (window->tru_h > 576 && window->tru_h < 1021) || - (window->tru_w > 720 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - } - else { - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - } - break; - - case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ - default: - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - break; - } - - /* Sorry, but no negative coords for src */ - if (window->src_x < 0) window->src_x = 0; - if (window->src_y < 0) window->src_y = 0; - - /* Can only reduce width down to 1/4 original size */ - if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { - window->src_x += osd_crop / 2; - window->src_w = (window->src_w - osd_crop) & ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; - } - - /* Can only reduce height down to 1/4 original size */ - if (window->src_h / window->dst_h >= 2) { - /* Overflow may be because we're running progressive, so force mode switch */ - window->interlaced_y = 1; - /* Make sure we're still within limits for interlace */ - if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { - /* If we reach here we'll have to force the height. */ - window->src_y += osd_crop / 2; - window->src_h = (window->src_h - osd_crop) & ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; - } - } - - /* If there's nothing to safe to display, we may as well stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { - return 0; - } - - /* Ensure video remains inside OSD area */ - osd_scale = (window->src_h << 16) / window->dst_h; - - if ((osd_crop = window->pan_y - window->dst_y) > 0) { - /* Falls off the upper edge - crop */ - window->src_y += (osd_scale * osd_crop) >> 16; - window->src_h -= (osd_scale * osd_crop) >> 16; - window->dst_h -= osd_crop; - window->dst_y = 0; - } - else { - window->dst_y -= window->pan_y; - } - - if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { - /* Falls off the lower edge - crop */ - window->dst_h -= osd_crop; - window->src_h -= (osd_scale * osd_crop) >> 16; - } - - osd_scale = (window->src_w << 16) / window->dst_w; - - if ((osd_crop = window->pan_x - window->dst_x) > 0) { - /* Fall off the left edge - crop */ - window->src_x += (osd_scale * osd_crop) >> 16; - window->src_w -= (osd_scale * osd_crop) >> 16; - window->dst_w -= osd_crop; - window->dst_x = 0; - } - else { - window->dst_x -= window->pan_x; - } - - if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { - /* Falls off the right edge - crop */ - window->dst_w -= osd_crop; - window->src_w -= (osd_scale * osd_crop) >> 16; - } - - /* The OSD can be moved. Track to it */ - window->dst_x += itv->yuv_info.osd_x_offset; - window->dst_y += itv->yuv_info.osd_y_offset; - - /* Width & height for both src & dst must be even. - Same for coordinates. */ - window->dst_w &= ~1; - window->dst_x &= ~1; - - window->src_w += window->src_x & 1; - window->src_x &= ~1; - - window->src_w &= ~1; - window->dst_w &= ~1; - - window->dst_h &= ~1; - window->dst_y &= ~1; - - window->src_h += window->src_y & 1; - window->src_y &= ~1; - - window->src_h &= ~1; - window->dst_h &= ~1; - - /* Due to rounding, we may have reduced the output size to <1/4 of the source - Check again, but this time just resize. Don't change source coordinates */ - if (window->dst_w < window->src_w / 4) { - window->src_w &= ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; - } - if (window->dst_h < window->src_h / 4) { - window->src_h &= ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; - } - - /* Check again. If there's nothing to safe to display, stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { - return 0; - } - - /* Both x offset & width are linked, so they have to be done together */ - if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || - (itv->yuv_info.old_frame_info.src_w != window->src_w) || - (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || - (itv->yuv_info.old_frame_info.src_x != window->src_x) || - (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || - (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { - yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; - } - - if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || - (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || - (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || - (itv->yuv_info.old_frame_info.src_y != window->src_y) || - (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || - (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || - (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || - (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { - yuv_update |= IVTV_YUV_UPDATE_VERTICAL; - } - - return yuv_update; -} - -/* Update the scaling register to the requested value */ -void ivtv_yuv_work_handler (struct ivtv *itv) -{ - struct yuv_frame_info window; - u32 yuv_update; - - int frame = itv->yuv_info.update_frame; - -/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ - memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); - - /* Update the osd pan info */ - window.pan_x = itv->yuv_info.osd_x_pan; - window.pan_y = itv->yuv_info.osd_y_pan; - window.vis_w = itv->yuv_info.osd_vis_w; - window.vis_h = itv->yuv_info.osd_vis_h; - - /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) - return; - - /* Update horizontal settings */ - if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) - ivtv_yuv_handle_horizontal(itv, &window); - - if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) - ivtv_yuv_handle_vertical(itv, &window); - - memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); -} - -static void ivtv_yuv_init (struct ivtv *itv) -{ - IVTV_DEBUG_YUV("ivtv_yuv_init\n"); - - /* Take a snapshot of the current register settings */ - itv->yuv_info.reg_2834 = read_reg(0x02834); - itv->yuv_info.reg_2838 = read_reg(0x02838); - itv->yuv_info.reg_283c = read_reg(0x0283c); - itv->yuv_info.reg_2840 = read_reg(0x02840); - itv->yuv_info.reg_2844 = read_reg(0x02844); - itv->yuv_info.reg_2848 = read_reg(0x02848); - itv->yuv_info.reg_2854 = read_reg(0x02854); - itv->yuv_info.reg_285c = read_reg(0x0285c); - itv->yuv_info.reg_2864 = read_reg(0x02864); - itv->yuv_info.reg_2870 = read_reg(0x02870); - itv->yuv_info.reg_2874 = read_reg(0x02874); - itv->yuv_info.reg_2898 = read_reg(0x02898); - itv->yuv_info.reg_2890 = read_reg(0x02890); - - itv->yuv_info.reg_289c = read_reg(0x0289c); - itv->yuv_info.reg_2918 = read_reg(0x02918); - itv->yuv_info.reg_291c = read_reg(0x0291c); - itv->yuv_info.reg_2920 = read_reg(0x02920); - itv->yuv_info.reg_2924 = read_reg(0x02924); - itv->yuv_info.reg_2928 = read_reg(0x02928); - itv->yuv_info.reg_292c = read_reg(0x0292c); - itv->yuv_info.reg_2930 = read_reg(0x02930); - itv->yuv_info.reg_2934 = read_reg(0x02934); - itv->yuv_info.reg_2938 = read_reg(0x02938); - itv->yuv_info.reg_293c = read_reg(0x0293c); - itv->yuv_info.reg_2940 = read_reg(0x02940); - itv->yuv_info.reg_2944 = read_reg(0x02944); - itv->yuv_info.reg_2948 = read_reg(0x02948); - itv->yuv_info.reg_294c = read_reg(0x0294c); - itv->yuv_info.reg_2950 = read_reg(0x02950); - itv->yuv_info.reg_2954 = read_reg(0x02954); - itv->yuv_info.reg_2958 = read_reg(0x02958); - itv->yuv_info.reg_295c = read_reg(0x0295c); - itv->yuv_info.reg_2960 = read_reg(0x02960); - itv->yuv_info.reg_2964 = read_reg(0x02964); - itv->yuv_info.reg_2968 = read_reg(0x02968); - itv->yuv_info.reg_296c = read_reg(0x0296c); - itv->yuv_info.reg_2970 = read_reg(0x02970); - - itv->yuv_info.v_filter_1 = -1; - itv->yuv_info.v_filter_2 = -1; - itv->yuv_info.h_filter = -1; - - /* Set some valid size info */ - itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF; - itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; - - /* Bit 2 of reg 2878 indicates current decoder output format - 0 : NTSC 1 : PAL */ - if (read_reg(0x2878) & 4) - itv->yuv_info.decode_height = 576; - else - itv->yuv_info.decode_height = 480; - - /* If no visible size set, assume full size */ - if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; - if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; - - /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); - if (itv->yuv_info.blanking_ptr) { - itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE); - } - else { - itv->yuv_info.blanking_dmaptr = 0; - IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n"); - } - - IVTV_DEBUG_WARN("Enable video output\n"); - write_reg_sync(0x00108080, 0x2898); - - /* Enable YUV decoder output */ - write_reg_sync(0x01, IVTV_REG_VDM); - - set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); - atomic_set(&itv->yuv_info.next_dma_frame,0); -} - -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ - DEFINE_WAIT(wait); - int rc = 0; - int got_sig = 0; - int frame, next_fill_frame, last_fill_frame; - - IVTV_DEBUG_INFO("yuv_prep_frame\n"); - - if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); - - frame = atomic_read(&itv->yuv_info.next_fill_frame); - next_fill_frame = (frame + 1) & 0x3; - last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; - - if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { - /* Buffers are full - Overwrite the last frame */ - next_fill_frame = frame; - frame = (frame - 1) & 3; - } - - /* Take a snapshot of the yuv coordinate information */ - itv->yuv_info.new_frame_info[frame].src_x = args->src.left; - itv->yuv_info.new_frame_info[frame].src_y = args->src.top; - itv->yuv_info.new_frame_info[frame].src_w = args->src.width; - itv->yuv_info.new_frame_info[frame].src_h = args->src.height; - itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; - itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; - itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; - itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; - itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; - - /* Are we going to offset the Y plane */ - if (args->src.height + args->src.top < 512-16) - itv->yuv_info.new_frame_info[frame].offset_y = 1; - else - itv->yuv_info.new_frame_info[frame].offset_y = 0; - - /* Snapshot the osd pan info */ - itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; - itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; - itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; - itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; - - itv->yuv_info.new_frame_info[frame].update = 0; - itv->yuv_info.new_frame_info[frame].interlaced_y = 0; - itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; - - if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], - sizeof (itv->yuv_info.new_frame_info[frame]))) { - memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); - itv->yuv_info.new_frame_info[frame].update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ - } - - /* DMA the frame */ - mutex_lock(&itv->udma.lock); - - if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { - mutex_unlock(&itv->udma.lock); - return rc; - } - - ivtv_udma_prepare(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ - while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { - /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ - got_sig = signal_pending(current); - if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - - /* Unmap Last DMA Xfer */ - ivtv_udma_unmap(itv); - - if (got_sig) { - IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); - mutex_unlock(&itv->udma.lock); - return -EINTR; - } - - atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); - - mutex_unlock(&itv->udma.lock); - return rc; -} - -void ivtv_yuv_close(struct ivtv *itv) -{ - int h_filter, v_filter_1, v_filter_2; - - IVTV_DEBUG_YUV("ivtv_yuv_close\n"); - ivtv_waitq(&itv->vsync_waitq); - - atomic_set(&itv->yuv_info.next_dma_frame, -1); - atomic_set(&itv->yuv_info.next_fill_frame, 0); - - /* Reset registers we have changed so mpeg playback works */ - - /* If we fully restore this register, the display may remain active. - Restore, but set one bit to blank the video. Firmware will always - clear this bit when needed, so not a problem. */ - write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); - - write_reg(itv->yuv_info.reg_2834, 0x02834); - write_reg(itv->yuv_info.reg_2838, 0x02838); - write_reg(itv->yuv_info.reg_283c, 0x0283c); - write_reg(itv->yuv_info.reg_2840, 0x02840); - write_reg(itv->yuv_info.reg_2844, 0x02844); - write_reg(itv->yuv_info.reg_2848, 0x02848); - write_reg(itv->yuv_info.reg_2854, 0x02854); - write_reg(itv->yuv_info.reg_285c, 0x0285c); - write_reg(itv->yuv_info.reg_2864, 0x02864); - write_reg(itv->yuv_info.reg_2870, 0x02870); - write_reg(itv->yuv_info.reg_2874, 0x02874); - write_reg(itv->yuv_info.reg_2890, 0x02890); - write_reg(itv->yuv_info.reg_289c, 0x0289c); - - write_reg(itv->yuv_info.reg_2918, 0x02918); - write_reg(itv->yuv_info.reg_291c, 0x0291c); - write_reg(itv->yuv_info.reg_2920, 0x02920); - write_reg(itv->yuv_info.reg_2924, 0x02924); - write_reg(itv->yuv_info.reg_2928, 0x02928); - write_reg(itv->yuv_info.reg_292c, 0x0292c); - write_reg(itv->yuv_info.reg_2930, 0x02930); - write_reg(itv->yuv_info.reg_2934, 0x02934); - write_reg(itv->yuv_info.reg_2938, 0x02938); - write_reg(itv->yuv_info.reg_293c, 0x0293c); - write_reg(itv->yuv_info.reg_2940, 0x02940); - write_reg(itv->yuv_info.reg_2944, 0x02944); - write_reg(itv->yuv_info.reg_2948, 0x02948); - write_reg(itv->yuv_info.reg_294c, 0x0294c); - write_reg(itv->yuv_info.reg_2950, 0x02950); - write_reg(itv->yuv_info.reg_2954, 0x02954); - write_reg(itv->yuv_info.reg_2958, 0x02958); - write_reg(itv->yuv_info.reg_295c, 0x0295c); - write_reg(itv->yuv_info.reg_2960, 0x02960); - write_reg(itv->yuv_info.reg_2964, 0x02964); - write_reg(itv->yuv_info.reg_2968, 0x02968); - write_reg(itv->yuv_info.reg_296c, 0x0296c); - write_reg(itv->yuv_info.reg_2970, 0x02970); - - /* Prepare to restore filters */ - - /* First the horizontal filter */ - if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { - /* An exact size match uses filter 0 */ - h_filter = 0; - } - else { - /* Figure out which filter to use */ - h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; - h_filter = (h_filter >> 1) + (h_filter & 1); - /* Only an exact size match can use filter 0. */ - if (h_filter < 1) h_filter = 1; - } - - /* Now the vertical filter */ - if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { - /* An exact size match uses filter 0/1 */ - v_filter_1 = 0; - v_filter_2 = 1; - } - else { - /* Figure out which filter to use */ - v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; - v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); - /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; - v_filter_2 = v_filter_1; - } - - /* Now restore the filters */ - ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); - - /* and clear a few registers */ - write_reg(0, 0x02814); - write_reg(0, 0x0282c); - write_reg(0, 0x02904); - write_reg(0, 0x02910); - - /* Release the blanking buffer */ - if (itv->yuv_info.blanking_ptr) { - kfree (itv->yuv_info.blanking_ptr); - itv->yuv_info.blanking_ptr = NULL; - pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); - } - - /* Invalidate the old dimension information */ - itv->yuv_info.old_frame_info.src_w = 0; - itv->yuv_info.old_frame_info.src_h = 0; - itv->yuv_info.old_frame_info_args.src_w = 0; - itv->yuv_info.old_frame_info_args.src_h = 0; - - /* All done. */ - clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); -} - diff --git a/trunk/drivers/media/video/ivtv/ivtv-yuv.h b/trunk/drivers/media/video/ivtv/ivtv-yuv.h deleted file mode 100644 index 88972d3f77c4..000000000000 --- a/trunk/drivers/media/video/ivtv/ivtv-yuv.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - yuv support - - Copyright (C) 2007 Ian Armstrong - - 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 - */ - -int ivtv_yuv_filter_check(struct ivtv *itv); -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); -void ivtv_yuv_close(struct ivtv *itv); -void ivtv_yuv_work_handler (struct ivtv *itv); diff --git a/trunk/drivers/media/video/meye.c b/trunk/drivers/media/video/meye.c index 664aba8b4d85..98681da5e3b9 100644 --- a/trunk/drivers/media/video/meye.c +++ b/trunk/drivers/media/video/meye.c @@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV) return -EINVAL; mutex_lock(&meye.lock); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, p->brightness >> 10); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, p->hue >> 10); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, p->colour >> 10); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, p->contrast >> 10); meye.picture = *p; mutex_unlock(&meye.lock); @@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ meye.params = *jp; - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, meye.params.sharpness); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, meye.params.agc); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, meye.params.picture); mutex_unlock(&meye.lock); break; @@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value); meye.picture.brightness = c->value << 10; break; case V4L2_CID_HUE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAHUE, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERAHUE, c->value); meye.picture.hue = c->value << 10; break; case V4L2_CID_CONTRAST: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERACONTRAST, c->value); meye.picture.contrast = c->value << 10; break; case V4L2_CID_SATURATION: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACOLOR, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERACOLOR, c->value); meye.picture.colour = c->value << 10; break; case V4L2_CID_AGC: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAAGC, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERAAGC, c->value); meye.params.agc = c->value; break; case V4L2_CID_SHARPNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERASHARPNESS, c->value); meye.params.sharpness = c->value; break; case V4L2_CID_PICTURE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value); + sonypi_camera_command( + SONYPI_COMMAND_SETCAMERAPICTURE, c->value); meye.params.picture = c->value; break; case V4L2_CID_JPEGQUAL: @@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, memcpy(meye.video_dev, &meye_template, sizeof(meye_template)); meye.video_dev->dev = &meye.mchip_dev->dev; - if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { + if ((ret = sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1))) { printk(KERN_ERR "meye: unable to power on the camera\n"); printk(KERN_ERR "meye: did you enable the camera in " "sonypi using the module options ?\n"); @@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev, meye.params.picture = 0; meye.params.framerate = 0; - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48); printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n", MEYE_DRIVER_VERSION); @@ -1953,7 +1953,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, outregions: pci_disable_device(meye.mchip_dev); outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0); outsonypienable: kfifo_free(meye.doneq); outkfifoalloc2: @@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev) pci_disable_device(meye.mchip_dev); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0); kfifo_free(meye.doneq); kfifo_free(meye.grabq); diff --git a/trunk/drivers/media/video/meye.h b/trunk/drivers/media/video/meye.h index 323d0074120d..ea107cb5c845 100644 --- a/trunk/drivers/media/video/meye.h +++ b/trunk/drivers/media/video/meye.h @@ -255,7 +255,7 @@ /****************************************************************************/ /* Sony Programmable I/O Controller for accessing the camera commands */ -#include +#include /* private API definitions */ #include diff --git a/trunk/drivers/media/video/msp3400-driver.c b/trunk/drivers/media/video/msp3400-driver.c index 3bb7d6634862..ba1af3c8525e 100644 --- a/trunk/drivers/media/video/msp3400-driver.c +++ b/trunk/drivers/media/video/msp3400-driver.c @@ -773,9 +773,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); - default: /* unknown */ return -EINVAL; @@ -875,8 +872,6 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", msp_family, msp_product, msp_revision, msp_hard, msp_rom); - /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; diff --git a/trunk/drivers/media/video/msp3400-driver.h b/trunk/drivers/media/video/msp3400-driver.h index ab69a290e5dc..7531efa1615e 100644 --- a/trunk/drivers/media/video/msp3400-driver.h +++ b/trunk/drivers/media/video/msp3400-driver.h @@ -50,7 +50,6 @@ extern int msp_stereo_thresh; struct msp_state { int rev1, rev2; - int ident; u8 has_nicam; u8 has_radio; u8 has_headphones; diff --git a/trunk/drivers/media/video/ov7670.c b/trunk/drivers/media/video/ov7670.c index 03bc369a9e49..5ed0adc4ca26 100644 --- a/trunk/drivers/media/video/ov7670.c +++ b/trunk/drivers/media/video/ov7670.c @@ -5,8 +5,6 @@ * by Jonathan Corbet with substantial inspiration from Mark * McClelland's ovcamchip code. * - * Copyright 2006-7 Jonathan Corbet - * * This file may be distributed under the terms of the GNU General * Public License, version 2. */ @@ -17,7 +15,6 @@ #include #include #include -#include #include @@ -165,10 +162,6 @@ MODULE_LICENSE("GPL"); #define REG_GFIX 0x69 /* Fix gain control */ -#define REG_REG76 0x76 /* OV's name */ -#define R76_BLKPCOR 0x80 /* Black pixel correction enable */ -#define R76_WHTPCOR 0x40 /* White pixel correction enable */ - #define REG_RGB444 0x8c /* RGB 444 control */ #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ #define R444_RGBX 0x01 /* Empty nibble at end */ @@ -262,7 +255,7 @@ static struct regval_list ov7670_default_regs[] = { /* Almost all of these are magic "reserved" values. */ { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, - { 0x16, 0x02 }, { REG_MVFP, 0x07 }, + { 0x16, 0x02 }, { REG_MVFP, 0x07|MVFP_MIRROR }, { 0x21, 0x02 }, { 0x22, 0x91 }, { 0x29, 0x07 }, { 0x33, 0x0b }, { 0x35, 0x0b }, { 0x37, 0x1d }, @@ -387,13 +380,6 @@ static struct regval_list ov7670_fmt_rgb444[] = { { 0xff, 0xff }, }; -static struct regval_list ov7670_fmt_raw[] = { - { REG_COM7, COM7_BAYER }, - { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ - { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ - { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ - { 0xff, 0xff }, -}; @@ -497,39 +483,32 @@ static struct ov7670_format_struct { __u32 pixelformat; struct regval_list *regs; int cmatrix[CMATRIX_LEN]; - int bpp; /* Bytes per pixel */ } ov7670_formats[] = { { .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .regs = ov7670_fmt_yuv422, .cmatrix = { 128, -128, 0, -34, -94, 128 }, - .bpp = 2, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, .regs = ov7670_fmt_rgb444, .cmatrix = { 179, -179, 0, -61, -176, 228 }, - .bpp = 2, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .regs = ov7670_fmt_rgb565, .cmatrix = { 179, -179, 0, -61, -176, 228 }, - .bpp = 2, - }, - { - .desc = "Raw RGB Bayer", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .regs = ov7670_fmt_raw, - .cmatrix = { 0, 0, 0, 0, 0, 0 }, - .bpp = 1 }, }; -#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) +#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) +/* + * All formats we support are 2 bytes/pixel. + */ +#define BYTES_PER_PIXEL 2 /* * Then there is the issue of window sizes. Try to capture the info here. @@ -706,7 +685,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, */ pix->width = wsize->width; pix->height = wsize->height; - pix->bytesperline = pix->width*ov7670_formats[index].bpp; + pix->bytesperline = pix->width*BYTES_PER_PIXEL; pix->sizeimage = pix->height*pix->bytesperline; return 0; } @@ -1291,8 +1270,9 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd, void *arg) { switch (cmd) { - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); + case VIDIOC_INT_G_CHIP_IDENT: + * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670; + return 0; case VIDIOC_INT_RESET: ov7670_reset(client); diff --git a/trunk/drivers/media/video/ovcamchip/ovcamchip_priv.h b/trunk/drivers/media/video/ovcamchip/ovcamchip_priv.h index 50c7763d44b3..1231335a9f4a 100644 --- a/trunk/drivers/media/video/ovcamchip/ovcamchip_priv.h +++ b/trunk/drivers/media/video/ovcamchip/ovcamchip_priv.h @@ -15,7 +15,6 @@ #ifndef __LINUX_OVCAMCHIP_PRIV_H #define __LINUX_OVCAMCHIP_PRIV_H -#include #include #ifdef DEBUG diff --git a/trunk/drivers/media/video/planb.c b/trunk/drivers/media/video/planb.c index 1455a8f4e930..86d2884e16c6 100644 --- a/trunk/drivers/media/video/planb.c +++ b/trunk/drivers/media/video/planb.c @@ -2160,7 +2160,7 @@ static int find_planb(void) if (!machine_is(powermac)) return 0; - planb_devices = of_find_node_by_name(NULL, "planb"); + planb_devices = find_devices("planb"); if (planb_devices == 0) { planb_num=0; printk(KERN_WARNING "PlanB: no device found!\n"); @@ -2175,14 +2175,12 @@ static int find_planb(void) if (planb_devices->n_addrs != 1) { printk (KERN_WARNING "PlanB: expecting 1 address for planb " "(got %d)", planb_devices->n_addrs); - of_node_put(planb_devices); return 0; } if (planb_devices->n_intrs == 0) { printk(KERN_WARNING "PlanB: no intrs for device %s\n", planb_devices->full_name); - of_node_put(planb_devices); return 0; } else { irq = planb_devices->intrs[0].line; @@ -2204,13 +2202,12 @@ static int find_planb(void) confreg = planb_devices->addrs[0].space & 0xff; old_base = planb_devices->addrs[0].address; new_base = 0xf1000000; - of_node_put(planb_devices); DEBUG("PlanB: Found on bus %d, dev %d, func %d, " "membase 0x%x (base reg. 0x%x)\n", bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); - pdev = pci_get_bus_and_slot(bus, dev_fn); + pdev = pci_find_slot (bus, dev_fn); if (!pdev) { printk(KERN_ERR "planb: cannot find slot\n"); goto err_out; @@ -2240,7 +2237,6 @@ static int find_planb(void) pb->planb_base = planb_regs; pb->planb_base_phys = (struct planb_registers *)new_base; pb->irq = irq; - pb->dev = pdev; return planb_num; @@ -2248,7 +2244,6 @@ static int find_planb(void) pci_disable_device(pdev); err_out: /* FIXME handle error */ /* comment moved from pci_find_slot, above */ - pci_dev_put(pdev); return 0; } @@ -2276,8 +2271,6 @@ static void release_planb(void) printk(KERN_INFO "PlanB: unregistering with v4l\n"); video_unregister_device(&pb->video_dev); - pci_dev_put(pb->dev); - /* note that iounmap() does nothing on the PPC right now */ iounmap ((void *)pb->planb_base); } diff --git a/trunk/drivers/media/video/planb.h b/trunk/drivers/media/video/planb.h index e21b5735c103..92823211d0c5 100644 --- a/trunk/drivers/media/video/planb.h +++ b/trunk/drivers/media/video/planb.h @@ -177,7 +177,6 @@ struct planb { struct mutex lock; unsigned int irq; /* interrupt number */ volatile unsigned int intr_mask; - struct pci_dev *dev; /* Our PCI device */ int overlay; /* overlay running? */ struct planb_window win; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 5669c8ca9ca3..5786faf9b3b8 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -324,7 +324,7 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, /* This implements some extra setup for the encoder that seems to be specific to the PVR USB2 hardware. */ -static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) +int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) { int ret = 0; int encMisc3Arg = 0; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index ce66ab8ff2d8..16bd74199601 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -283,8 +283,6 @@ struct pvr2_hdw { int unit_number; /* ID for driver instance */ unsigned long serial_number; /* ID for hardware itself */ - char bus_info[32]; /* Bus location info */ - /* Minor numbers used by v4l logic (yes, this is a hack, as there should be no v4l junk here). Probably a better way to do this. */ int v4l_minor_number_video; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c index acf651e01f94..9916cf32494d 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1008,13 +1008,6 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) return hdw->serial_number; } - -const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) -{ - return hdw->bus_info; -} - - unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) { return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; @@ -2112,11 +2105,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->usb_intf = intf; hdw->usb_dev = interface_to_usbdev(intf); - scnprintf(hdw->bus_info,sizeof(hdw->bus_info), - "usb %s address %d", - hdw->usb_dev->dev.bus_id, - hdw->usb_dev->devnum); - ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; usb_set_interface(hdw->usb_dev,ifnum,0); @@ -3287,9 +3275,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, mutex_lock(&hdw->i2c_list_lock); do { list_for_each(item,&hdw->i2c_clients) { cp = list_entry(item,struct pvr2_i2c_client,list); - if (!v4l2_chip_match_i2c_client( - cp->client, - req.match_type, req.match_chip)) { + if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) { continue; } stat = pvr2_i2c_client_cmd( diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 4dba8d006324..0c9cca43ff85 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -124,9 +124,6 @@ struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *); /* Retrieve serial number of device */ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); -/* Retrieve bus location info of device */ -const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *); - /* Called when hardware has been unplugged */ void pvr2_hdw_disconnect(struct pvr2_hdw *); diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index a741c556a39a..91396fd573e4 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -42,11 +42,9 @@ struct pvr2_sysfs { struct class_device_attribute attr_v4l_minor_number; struct class_device_attribute attr_v4l_radio_minor_number; struct class_device_attribute attr_unit_number; - struct class_device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; - int bus_info_created_ok; }; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC @@ -707,10 +705,6 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) pvr2_sysfs_tear_down_debugifc(sfp); #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); - if (sfp->bus_info_created_ok) { - class_device_remove_file(sfp->class_dev, - &sfp->attr_bus_info); - } if (sfp->v4l_minor_number_created_ok) { class_device_remove_file(sfp->class_dev, &sfp->attr_v4l_minor_number); @@ -741,16 +735,6 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) } -static ssize_t bus_info_show(struct class_device *class_dev,char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_bus_info(sfp->channel.hdw)); -} - - static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, char *buf) { @@ -852,20 +836,6 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->unit_number_created_ok = !0; } - sfp->attr_bus_info.attr.owner = THIS_MODULE; - sfp->attr_bus_info.attr.name = "bus_info_str"; - sfp->attr_bus_info.attr.mode = S_IRUGO; - sfp->attr_bus_info.show = bus_info_show; - sfp->attr_bus_info.store = NULL; - ret = class_device_create_file(sfp->class_dev, - &sfp->attr_bus_info); - if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", - __FUNCTION__, ret); - } else { - sfp->bus_info_created_ok = !0; - } - pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_add_debugifc(sfp); diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 4563b3df8a0d..25d3830b482a 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -203,8 +203,6 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, struct v4l2_capability *cap = arg; memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); - strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), - sizeof(cap->bus_info)); ret = 0; break; diff --git a/trunk/drivers/media/video/pwc/pwc-ctrl.c b/trunk/drivers/media/video/pwc/pwc-ctrl.c index 338ced7188f2..0bd115588f31 100644 --- a/trunk/drivers/media/video/pwc/pwc-ctrl.c +++ b/trunk/drivers/media/video/pwc/pwc-ctrl.c @@ -140,8 +140,6 @@ static const char *size2name[PSZ_MAX] = An alternate value of 0 means this mode is not available at all. */ -#define PWC_FPS_MAX_NALA 8 - struct Nala_table_entry { char alternate; /* USB alternate setting */ int compressed; /* Compressed yes/no */ @@ -149,9 +147,7 @@ struct Nala_table_entry { unsigned char mode[3]; /* precomputed mode table */ }; -static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; - -static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = +static struct Nala_table_entry Nala_table[PSZ_MAX][8] = { #include "pwc-nala.h" }; @@ -427,59 +423,6 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame return 0; } -static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < PWC_FPS_MAX_NALA; i++) { - if (Nala_table[size][i].alternate) { - if (index--==0) return Nala_fps_vector[i]; - } - } - return 0; -} - -static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { - if (Kiara_table[size][i][3].alternate) { - if (index--==0) return Kiara_fps_vector[i]; - } - } - return 0; -} - -static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i=0; i < PWC_FPS_MAX_TIMON; i++) { - if (Timon_table[size][i][3].alternate) { - if (index--==0) return Timon_fps_vector[i]; - } - } - return 0; -} - -unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int ret; - - if (DEVICE_USE_CODEC1(pdev->type)) { - ret = pwc_get_fps_Nala(pdev, index, size); - - } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = pwc_get_fps_Kiara(pdev, index, size); - - } else { - ret = pwc_get_fps_Timon(pdev, index, size); - } - - return ret; -} - #define BLACK_Y 0 #define BLACK_U 128 #define BLACK_V 128 @@ -1400,7 +1343,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); if (ret < 0) break; - ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); + ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); if (ret < 0) break; } diff --git a/trunk/drivers/media/video/pwc/pwc-if.c b/trunk/drivers/media/video/pwc/pwc-if.c index 085332a503de..27ed76986ca2 100644 --- a/trunk/drivers/media/video/pwc/pwc-if.c +++ b/trunk/drivers/media/video/pwc/pwc-if.c @@ -95,8 +95,8 @@ static const struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ - { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */ - { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */ + { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ + { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ @@ -1493,7 +1493,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id case 0x0329: PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); name = "Philips SPC 900NC webcam"; - type_id = 740; + type_id = 720; break; default: return -ENODEV; @@ -1547,16 +1547,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id features |= FEATURE_MOTOR_PANTILT; break; case 0x08b6: - PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n"); - name = "Cisco VT Camera"; - type_id = 740; /* CCD sensor */ - break; case 0x08b7: - PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n"); - name = "Logitech ViewPort AV 100"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b8: /* Where this released? */ + case 0x08b8: PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); name = "Logitech QuickCam (res.)"; type_id = 730; /* Assuming CMOS */ diff --git a/trunk/drivers/media/video/pwc/pwc-ioctl.h b/trunk/drivers/media/video/pwc/pwc-ioctl.h index cec660299768..784bc72521fa 100644 --- a/trunk/drivers/media/video/pwc/pwc-ioctl.h +++ b/trunk/drivers/media/video/pwc/pwc-ioctl.h @@ -2,7 +2,7 @@ #define PWC_IOCTL_H /* (C) 2001-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) + (C) 2004 Luc Saillard (luc@saillard.org) NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx driver and thus may have bugs that are not present in the original version. @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This is pwc-ioctl.h belonging to PWC 10.0.10 +/* This is pwc-ioctl.h belonging to PWC 8.12.1 It contains structures and defines to communicate from user space directly to the driver. */ @@ -51,9 +51,6 @@ ... the function */ -#include -#include - /* Enumeration of image sizes */ #define PSZ_SQCIF 0x00 @@ -68,8 +65,6 @@ /* The frame rate is encoded in the video_window.flags parameter using the upper 16 bits, since some flags are defined nowadays. The following defines provide a mask and shift to filter out this value. - This value can also be passing using the private flag when using v4l2 and - VIDIOC_S_FMT ioctl. In 'Snapshot' mode the camera freezes its automatic exposure and colour balance controls. @@ -78,8 +73,6 @@ #define PWC_FPS_MASK 0x00FF0000 #define PWC_FPS_FRMASK 0x003F0000 #define PWC_FPS_SNAPSHOT 0x00400000 -#define PWC_QLT_MASK 0x03000000 -#define PWC_QLT_SHIFT 24 /* structure for transferring x & y coordinates */ @@ -296,29 +289,4 @@ struct pwc_table_init_buffer { }; #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) -/* - * This is private command used when communicating with v4l2. - * In the future all private ioctl will be remove/replace to - * use interface offer by v4l2. - */ - -#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) - -struct pwc_raw_frame { - __le16 type; /* type of the webcam */ - __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ - __u8 cmd[4]; /* the four byte of the command (in case of nala, - only the first 3 bytes is filled) */ - __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ -} __attribute__ ((packed)); - - #endif diff --git a/trunk/drivers/media/video/pwc/pwc-kiara.c b/trunk/drivers/media/video/pwc/pwc-kiara.c index f4ae83c0cf2b..fec39cc5a9f1 100644 --- a/trunk/drivers/media/video/pwc/pwc-kiara.c +++ b/trunk/drivers/media/video/pwc/pwc-kiara.c @@ -42,8 +42,6 @@ #include "pwc-kiara.h" #include "pwc-uncompress.h" -const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; - const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = { /* SQCIF */ diff --git a/trunk/drivers/media/video/pwc/pwc-kiara.h b/trunk/drivers/media/video/pwc/pwc-kiara.h index 047dad8c15f7..0bdb22547d86 100644 --- a/trunk/drivers/media/video/pwc/pwc-kiara.h +++ b/trunk/drivers/media/video/pwc/pwc-kiara.h @@ -29,8 +29,6 @@ #include -#define PWC_FPS_MAX_KIARA 6 - struct Kiara_table_entry { char alternate; /* USB alternate interface */ @@ -39,9 +37,8 @@ struct Kiara_table_entry unsigned char mode[12]; /* precomputed mode settings for cam */ }; -extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4]; +extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; extern const unsigned int KiaraRomTable[8][2][16][8]; -extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA]; #endif diff --git a/trunk/drivers/media/video/pwc/pwc-timon.c b/trunk/drivers/media/video/pwc/pwc-timon.c index c56c174b161c..be65bdcd195b 100644 --- a/trunk/drivers/media/video/pwc/pwc-timon.c +++ b/trunk/drivers/media/video/pwc/pwc-timon.c @@ -40,9 +40,7 @@ #include "pwc-timon.h" -const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 }; - -const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] = +const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = { /* SQCIF */ { diff --git a/trunk/drivers/media/video/pwc/pwc-timon.h b/trunk/drivers/media/video/pwc/pwc-timon.h index a6e22224c95f..eef9e2cd4320 100644 --- a/trunk/drivers/media/video/pwc/pwc-timon.h +++ b/trunk/drivers/media/video/pwc/pwc-timon.h @@ -44,8 +44,6 @@ #include -#define PWC_FPS_MAX_TIMON 6 - struct Timon_table_entry { char alternate; /* USB alternate interface */ @@ -54,9 +52,9 @@ struct Timon_table_entry unsigned char mode[13]; /* precomputed mode settings for cam */ }; -extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4]; +extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; extern const unsigned int TimonRomTable [16][2][16][8]; -extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON]; + #endif diff --git a/trunk/drivers/media/video/pwc/pwc-v4l.c b/trunk/drivers/media/video/pwc/pwc-v4l.c index 32fbe1ae6251..d5e6bc850643 100644 --- a/trunk/drivers/media/video/pwc/pwc-v4l.c +++ b/trunk/drivers/media/video/pwc/pwc-v4l.c @@ -1168,7 +1168,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, buf->sequence = 0; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = pdev->fill_image * pdev->len_per_image; - buf->length = pdev->len_per_image; + buf->length = buf->bytesused; pwc_next_image(pdev); PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); @@ -1193,64 +1193,6 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, return 0; } - case VIDIOC_ENUM_FRAMESIZES: - { - struct v4l2_frmsizeenum *fsize = arg; - unsigned int i = 0, index = fsize->index; - - if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1UL << i)) { - if (!index--) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pwc_image_sizes[i].x; - fsize->discrete.height = pwc_image_sizes[i].y; - return 0; - } - } - } - } else if (fsize->index == 0 && - ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || - (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pdev->abs_max.x; - fsize->discrete.height = pdev->abs_max.y; - return 0; - } - return -EINVAL; - } - - case VIDIOC_ENUM_FRAMEINTERVALS: - { - struct v4l2_frmivalenum *fival = arg; - int size = -1; - unsigned int i; - - for (i = 0; i < PSZ_MAX; i++) { - if (pwc_image_sizes[i].x == fival->width && - pwc_image_sizes[i].y == fival->height) { - size = i; - break; - } - } - - /* TODO: Support raw format */ - if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { - return -EINVAL; - } - - i = pwc_get_fps(pdev, fival->index, size); - if (!i) - return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = 1; - fival->discrete.denominator = i; - - return 0; - } - default: return pwc_ioctl(pdev, cmd, arg); } /* ..switch */ diff --git a/trunk/drivers/media/video/pwc/pwc.h b/trunk/drivers/media/video/pwc/pwc.h index acbb9312960a..e778a2b8c280 100644 --- a/trunk/drivers/media/video/pwc/pwc.h +++ b/trunk/drivers/media/video/pwc/pwc.h @@ -44,7 +44,7 @@ #define PWC_MINOR 0 #define PWC_EXTRAMINOR 12 #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) -#define PWC_VERSION "10.0.13" +#define PWC_VERSION "10.0.12" #define PWC_NAME "pwc" #define PFX PWC_NAME ": " @@ -85,7 +85,7 @@ #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) -#else /* if ! CONFIG_USB_PWC_DEBUG */ +#else /* if ! CONFIG_PWC_DEBUG */ #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) @@ -287,7 +287,6 @@ void pwc_construct(struct pwc_device *pdev); /** Functions in pwc-ctrl.c */ /* Request a certain video mode. Returns < 0 if not possible */ extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); -extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); /* Calculate the number of bytes per image (not frame) */ extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); diff --git a/trunk/drivers/media/video/saa7111.c b/trunk/drivers/media/video/saa7111.c index 74839f98b7c4..44dc7479119c 100644 --- a/trunk/drivers/media/video/saa7111.c +++ b/trunk/drivers/media/video/saa7111.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/saa7114.c b/trunk/drivers/media/video/saa7114.c index 87c3144ec7fc..2ce3321ab995 100644 --- a/trunk/drivers/media/video/saa7114.c +++ b/trunk/drivers/media/video/saa7114.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/saa7115.c b/trunk/drivers/media/video/saa7115.c index 2d18f0069821..4d5bbd859de1 100644 --- a/trunk/drivers/media/video/saa7115.c +++ b/trunk/drivers/media/video/saa7115.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -81,7 +80,7 @@ struct saa711x_state { int sat; int width; int height; - u32 ident; + enum v4l2_chip_ident ident; u32 audclk_freq; u32 crystal_freq; u8 ucgc; @@ -1233,6 +1232,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa711x_state *state = i2c_get_clientdata(client); + int *iarg = arg; /* ioctls to allow direct access to the saa7115 registers for testing */ switch (cmd) { @@ -1437,8 +1437,9 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar } #endif - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); + case VIDIOC_INT_G_CHIP_IDENT: + *iarg = state->ident; + break; default: return -EINVAL; @@ -1486,7 +1487,6 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", address << 1, name); - kfree(client); return 0; } diff --git a/trunk/drivers/media/video/saa711x.c b/trunk/drivers/media/video/saa711x.c index 80bf91187856..269d7114a93a 100644 --- a/trunk/drivers/media/video/saa711x.c +++ b/trunk/drivers/media/video/saa711x.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/saa7127.c b/trunk/drivers/media/video/saa7127.c index 9f986930490f..654863db1591 100644 --- a/trunk/drivers/media/video/saa7127.c +++ b/trunk/drivers/media/video/saa7127.c @@ -54,7 +54,6 @@ #include #include #include -#include #include static int debug = 0; @@ -235,7 +234,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = { struct saa7127_state { v4l2_std_id std; - u32 ident; + enum v4l2_chip_ident ident; enum saa7127_input_type input_type; enum saa7127_output_type output_type; int video_enable; @@ -551,12 +550,12 @@ static int saa7127_command(struct i2c_client *client, struct v4l2_routing *route = arg; switch (cmd) { - case VIDIOC_INT_S_STD_OUTPUT: + case VIDIOC_S_STD: if (state->std == *(v4l2_std_id *)arg) break; return saa7127_set_std(client, *(v4l2_std_id *)arg); - case VIDIOC_INT_G_STD_OUTPUT: + case VIDIOC_G_STD: *(v4l2_std_id *)arg = state->std; break; @@ -651,8 +650,9 @@ static int saa7127_command(struct i2c_client *client, break; } - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); + case VIDIOC_INT_G_CHIP_IDENT: + *(enum v4l2_chip_ident *)arg = state->ident; + break; default: return -EINVAL; diff --git a/trunk/drivers/media/video/saa7134/Kconfig b/trunk/drivers/media/video/saa7134/Kconfig index 309dca368f4a..59da79ce2efd 100644 --- a/trunk/drivers/media/video/saa7134/Kconfig +++ b/trunk/drivers/media/video/saa7134/Kconfig @@ -46,7 +46,6 @@ config VIDEO_SAA7134_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_TDA827X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB cards based on the diff --git a/trunk/drivers/media/video/saa7134/saa7134-cards.c b/trunk/drivers/media/video/saa7134/saa7134-cards.c index 4ea479baee74..89f32107f46b 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-cards.c +++ b/trunk/drivers/media/video/saa7134/saa7134-cards.c @@ -1543,12 +1543,12 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_comp1, .vmux = 0, - .amux = LINE1, + .amux = LINE2, .gpio = 0x02, },{ .name = name_svideo, .vmux = 6, - .amux = LINE1, + .amux = LINE2, .gpio = 0x02, }}, .radio = { @@ -1778,19 +1778,17 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_FLYDVBTDUO] = { /* LifeView FlyDVB-T DUO */ /* "Nico Sabbi Hartmut Hackmann hartmut.hackmann@t-online.de*/ - .name = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo", + .name = "LifeView FlyDVB-T DUO", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .gpiomask = 0x00200000, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, - .gpio = 0x200000, /* GPIO21=High for TV input */ .tv = 1, },{ .name = name_comp1, /* Composite signal on S-Video input */ @@ -1805,11 +1803,6 @@ struct saa7134_board saa7134_boards[] = { .vmux = 8, .amux = LINE2, }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ - }, }, [SAA7134_BOARD_PHILIPS_TOUGH] = { .name = "Philips TOUGH DVB-T reference design", @@ -2553,9 +2546,8 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, + .gpiomask = 1 << 21, .inputs = {{ .name = name_tv, .vmux = 1, @@ -2632,7 +2624,7 @@ struct saa7134_board saa7134_boards[] = { }}, .radio = { .name = name_radio, - .amux = TV, + .amux = LINE1, .gpio = 0x0200000, }, }, @@ -3051,7 +3043,6 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 1, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x000200000, .inputs = {{ @@ -3298,115 +3289,6 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }}, }, - [SAA7134_BOARD_PHILIPS_TIGER_S] = { - .name = "Philips Tiger - S Reference design", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_M102] = { - .name = "Avermedia M102", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1<<21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_ASUS_P7131_4871] = { - .name = "ASUS P7131 4871", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0200000, - }}, - }, - [SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = { - .name = "ASUSTeK P7131 Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .gpiomask = 1 << 21, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x0200000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4032,7 +3914,7 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1043, .subdevice = 0x4876, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -4075,30 +3957,6 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x153b, .subdevice = 0x1175, .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31e, - .driver_data = SAA7134_BOARD_AVERMEDIA_M102, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4E42, /* MSI */ - .subdevice = 0x0306, /* TV@nywhere DUO */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4871, - .driver_data = SAA7134_BOARD_ASUS_P7131_4871, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4857, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4113,6 +3971,7 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0, .driver_data = SAA7134_BOARD_NOAUTO, },{ + /* --- default catch --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -4204,7 +4063,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: case SAA7134_BOARD_FLYDVBT_LR301: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_PROTEUS_2309: case SAA7134_BOARD_AVERMEDIA_A16AR: @@ -4245,8 +4103,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); + saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); + saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS: /* power-up tuner chip */ @@ -4279,11 +4137,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) "%s: Dual decoder functionality is disabled for now, use the other chip.\n", dev->name,card(dev).name,dev->name,dev->name); break; - case SAA7134_BOARD_AVERMEDIA_M102: - /* enable tuner */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); - break; } return 0; } @@ -4293,9 +4146,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) { unsigned char buf; int board; - struct tuner_setup tun_setup; - tun_setup.config = 0; - tun_setup.tuner_callback = saa7134_tuner_callback; switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: @@ -4312,6 +4162,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->tuner_type = saa7134_boards[dev->board].tuner_type; if (TUNER_ABSENT != dev->tuner_type) { + struct tuner_setup tun_setup; + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; tun_setup.type = dev->tuner_type; tun_setup.addr = ADDR_UNSET; @@ -4321,6 +4173,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_MD7134: { + struct tuner_setup tun_setup; u8 subaddr; u8 data[3]; int ret, tuner_t; @@ -4392,6 +4245,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) * the channel decoder. We have to make it transparent to find it */ { + struct tuner_setup tun_setup; u8 data[] = { 0x07, 0x02}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); @@ -4404,38 +4258,16 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_PHILIPS_TIGER: - case SAA7134_BOARD_PHILIPS_TIGER_S: - { - u8 data[] = { 0x3c, 0x33, 0x60}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { - dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; - printk(KERN_INFO "%s: Reconfigured board as %s\n", - dev->name, saa7134_boards[dev->board].name); - } - if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = TUNER_PHILIPS_TDA8290; - tun_setup.addr = 0x4b; - tun_setup.config = 2; - - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); - data[2] = 0x68; - } - i2c_transfer(&dev->i2c_adap, &msg, 1); - } - break; case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: case SAA7134_BOARD_HAUPPAUGE_HVR1110: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ { - u8 data[] = { 0x3c, 0x33, 0x60}; + u8 data[] = { 0x3c, 0x33, 0x68}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); } @@ -4449,18 +4281,18 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: - /* initialize analog mode */ + /* make the tda10046 find its eeprom */ { - u8 data[] = { 0x3c, 0x33, 0x6a}; + u8 data[] = { 0x3c, 0x33, 0x62}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); } break; case SAA7134_BOARD_CINERGY_HT_PCMCIA: case SAA7134_BOARD_CINERGY_HT_PCI: - /* initialize analog mode */ + /* make the tda10046 find its eeprom */ { - u8 data[] = { 0x3c, 0x33, 0x68}; + u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); } diff --git a/trunk/drivers/media/video/saa7134/saa7134-core.c b/trunk/drivers/media/video/saa7134/saa7134-core.c index 25f84701a8e8..ed038fff3b4f 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-core.c +++ b/trunk/drivers/media/video/saa7134/saa7134-core.c @@ -117,64 +117,6 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) dev->name, mode, (~mode) & status, mode & status, msg); } -void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) -{ - u32 index, bitval; - - index = 1 << bit_no; - switch (value) { - case 0: /* static value */ - case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); - /* turn sync mode off if necessary */ - if (index & 0x00c00000) - saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); - if (value) - bitval = index; - else - bitval = 0; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); - break; - case 3: /* tristate */ - dprintk("setting GPIO%d to tristate\n", bit_no); - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); - break; - } -} - -int saa7134_tuner_callback(void *ptr, int command, int arg) -{ - u8 sync_control; - struct saa7134_dev *dev = ptr; - - switch (dev->tuner_type) { - case TUNER_PHILIPS_TDA8290: - switch (command) { - case 0: /* switch LNA gain through GPIO 22*/ - saa7134_set_gpio(dev, 22, arg) ; - break; - case 1: /* vsync output at GPIO22. 50 / 60Hz */ - dprintk("setting GPIO22 to vsync %d\n", arg); - saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80); - saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03); - if (arg == 1) - sync_control = 11; - else - sync_control = 17; - saa_writeb(SAA7134_VGATE_START, sync_control); - saa_writeb(SAA7134_VGATE_STOP, sync_control + 1); - saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00); - break; - default: - return -EINVAL; - } - break; - default: - return -ENODEV; - } - return 0; -} - /* ------------------------------------------------------------------ */ @@ -182,28 +124,55 @@ int saa7134_tuner_callback(void *ptr, int command, int arg) /* delayed request_module */ #if defined(CONFIG_MODULES) && defined(MODULE) +static int need_empress; +static int need_dvb; +static int need_alsa; +static int need_oss; +static int pending_call(struct notifier_block *self, unsigned long state, + void *module) +{ + if (module != THIS_MODULE || state != MODULE_STATE_LIVE) + return NOTIFY_DONE; -static void request_module_async(struct work_struct *work){ - struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk); - if (card_is_empress(dev)) + if (need_empress) request_module("saa7134-empress"); - if (card_is_dvb(dev)) + if (need_dvb) request_module("saa7134-dvb"); - if (alsa) + if (need_alsa) request_module("saa7134-alsa"); - if (oss) + if (need_oss) request_module("saa7134-oss"); + return NOTIFY_DONE; } -static void request_submodules(struct saa7134_dev *dev) +static int pending_registered; +static struct notifier_block pending_notifier = { + .notifier_call = pending_call, +}; + +static void request_module_depend(char *name, int *flag) { - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); + int err; + switch (THIS_MODULE->state) { + case MODULE_STATE_COMING: + if (!pending_registered) { + err = register_module_notifier(&pending_notifier); + pending_registered = 1; + } + *flag = 1; + break; + case MODULE_STATE_LIVE: + request_module(name); + break; + default: + /* nothing */; + break; + } } #else -#define request_submodules(dev) +#define request_module_depend(name,flag) #endif /* CONFIG_MODULES */ /* ------------------------------------------------------------------ */ @@ -734,6 +703,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev) saa7134_ts_fini(dev); saa7134_input_fini(dev); saa7134_vbi_fini(dev); + saa7134_video_fini(dev); saa7134_tvaudio_fini(dev); return 0; } @@ -974,9 +944,18 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (card_is_empress(dev)) { request_module("saa6752hs"); + request_module_depend("saa7134-empress",&need_empress); } - request_submodules(dev); + if (card_is_dvb(dev)) + request_module_depend("saa7134-dvb",&need_dvb); + + + if (alsa) + request_module_depend("saa7134-alsa",&need_alsa); + + if (oss) + request_module_depend("saa7134-oss",&need_oss); v4l2_prio_init(&dev->prio); @@ -1034,9 +1013,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_dmasound_init(dev); } - if (TUNER_ABSENT != dev->tuner_type) - saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); - return 0; fail4: @@ -1176,6 +1152,10 @@ static int saa7134_init(void) static void saa7134_fini(void) { +#if defined(CONFIG_MODULES) && defined(MODULE) + if (pending_registered) + unregister_module_notifier(&pending_notifier); +#endif /* CONFIG_MODULES */ pci_unregister_driver(&saa7134_pci_driver); } @@ -1184,7 +1164,6 @@ module_exit(saa7134_fini); /* ----------------------------------------------------------- */ -EXPORT_SYMBOL(saa7134_set_gpio); EXPORT_SYMBOL(saa7134_i2c_call_clients); EXPORT_SYMBOL(saa7134_devlist); EXPORT_SYMBOL(saa7134_boards); diff --git a/trunk/drivers/media/video/saa7134/saa7134-dvb.c b/trunk/drivers/media/video/saa7134/saa7134-dvb.c index 65aec881bbde..e3059fd33951 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-dvb.c +++ b/trunk/drivers/media/video/saa7134/saa7134-dvb.c @@ -41,9 +41,7 @@ #include "tda10086.h" #include "tda826x.h" -#include "tda827x.h" #include "isl6421.h" - MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -56,21 +54,7 @@ static int use_frontend = 0; module_param(use_frontend, int, 0644); MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); - -#define dprintk(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) - -/* Print a warning */ -#define wprintk(fmt, arg...) \ - printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) - -/* ------------------------------------------------------------------ - * mt352 based DVB-T cards - */ - +/* ------------------------------------------------------------------ */ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) { u32 ok; @@ -91,7 +75,8 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); udelay(10); ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); - dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off"); + printk("%s: %s %s\n", dev->name, __FUNCTION__, + ok ? "on" : "off"); if (!ok) saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); @@ -111,7 +96,7 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; struct saa7134_dev *dev= fe->dvb->priv; - dprintk("%s called\n", __FUNCTION__); + printk("%s: %s called\n",dev->name,__FUNCTION__); mt352_write(fe, clock_config, sizeof(clock_config)); udelay(200); @@ -200,26 +185,10 @@ static struct mt352_config avermedia_777 = { .demod_init = mt352_aver777_init, }; -/* ================================================================== - * tda1004x based DVB-T cards, helper functions - */ - -static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct saa7134_dev *dev = fe->dvb->priv; - return request_firmware(fw, name, &dev->pci->dev); -} - -/* ------------------------------------------------------------------ - * these tuners are tu1216, td1316(a) - */ - -static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +/* ------------------------------------------------------------------ */ +static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; @@ -294,20 +263,15 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", - addr << 1); + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) return -EIO; - } msleep(1); return 0; } -static int philips_tu1216_init(struct dvb_frontend *fe) +static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; @@ -323,17 +287,46 @@ static int philips_tu1216_init(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ +static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe) +{ + return philips_tda6651_pll_init(0x60, fe); +} + +static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + return philips_tda6651_pll_set(0x60, fe, params); +} + +static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct saa7134_dev *dev = fe->dvb->priv; + return request_firmware(fw, name, &dev->pci->dev); +} + static struct tda1004x_config philips_tu1216_60_config = { + .demod_address = 0x8, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = philips_tda1004x_request_firmware, }; +/* ------------------------------------------------------------------ */ + +static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe) +{ + return philips_tda6651_pll_init(0x61, fe); +} + +static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + return philips_tda6651_pll_set(0x61, fe, params); +} + static struct tda1004x_config philips_tu1216_61_config = { .demod_address = 0x8, @@ -342,8 +335,7 @@ static struct tda1004x_config philips_tu1216_61_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = philips_tda1004x_request_firmware, }; /* ------------------------------------------------------------------ */ @@ -351,42 +343,24 @@ static struct tda1004x_config philips_tu1216_61_config = { static int philips_td1316_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; - struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; + struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; /* setup PLL configuration */ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) return -EIO; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); return 0; } static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { - return philips_tda6651_pll_set(fe, params); + return philips_tda6651_pll_set(0x61, fe, params); } -static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; - struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - /* switch the tuner to analog mode */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1) - return -EIO; - return 0; -} - -/* ------------------------------------------------------------------ */ - static int philips_europa_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; @@ -406,14 +380,18 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe) static int philips_europa_tuner_sleep(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; + /* this message actually turns the tuner back to analog mode */ + static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; + struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; - static u8 msg[] = { 0x00, 0x14 }; - struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - if (philips_td1316_tuner_sleep(fe)) - return -EIO; + i2c_transfer(&dev->i2c_adap, &analog_msg, 1); + msleep(1); /* switch the board to analog mode */ + analog_msg.addr = 0x43; + analog_msg.len = 0x02; + msg[0] = 0x00; + msg[1] = 0x14; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &analog_msg, 1); @@ -438,8 +416,7 @@ static struct tda1004x_config philips_europa_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_IFO_AUTO_POS, .if_freq = TDA10046_FREQ_052, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; /* ------------------------------------------------------------------ */ @@ -447,11 +424,9 @@ static struct tda1004x_config philips_europa_config = { static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; /* this message is to set up ATC and ALC */ static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -465,11 +440,9 @@ static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; /* this message actually turns the tuner back to analog mode */ - u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -487,10 +460,8 @@ static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; int tuner_frequency = 0; int divider = 0; @@ -565,11 +536,8 @@ static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", - addr << 1); + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) return -EIO; - } return 0; } @@ -580,365 +548,582 @@ static struct tda1004x_config medion_cardbus = { .xtal_freq = TDA10046_XTAL_16M, .agc_config = TDA10046_AGC_IFO_AUTO_NEG, .if_freq = TDA10046_FREQ_3613, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; -/* ------------------------------------------------------------------ - * tda 1004x based cards with philips silicon tuner - */ +/* ------------------------------------------------------------------ */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; -static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high) +static struct tda827x_data tda827x_dvbt[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int philips_tda827x_tuner_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->i2c_gate; - u8 config = state->config->tuner_config; - u8 GP00_CF[] = {0x20, 0x01}; - u8 GP00_LEV[] = {0x22, 0x00}; - - struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2}; - if (config) { - if (high) { - dprintk("setting LNA to high gain\n"); - } else { - dprintk("setting LNA to low gain\n"); - } + u8 tuner_buf[14]; + + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int i, tuner_freq, if_freq; + u32 N; + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; } - switch (config) { - case 0: /* no LNA */ + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827x_dvbt[i].lomax < tuner_freq) { + if(tda827x_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + tuner_buf[0] = 0; + tuner_buf[1] = (N>>8) | 0x40; + tuner_buf[2] = N & 0xff; + tuner_buf[3] = 0; + tuner_buf[4] = 0x52; + tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + + (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; + tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + tuner_buf[7] = 0xbf; + tuner_buf[8] = 0x2a; + tuner_buf[9] = 0x05; + tuner_buf[10] = 0xff; + tuner_buf[11] = 0x00; + tuner_buf[12] = 0x00; + tuner_buf[13] = 0x40; + + tuner_msg.len = 14; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(500); + /* correct CP value */ + tuner_buf[0] = 0x30; + tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp; + tuner_msg.len = 2; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + + return 0; +} + +static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda827x_sleep[] = { 0x30, 0xd0}; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, + .len = sizeof(tda827x_sleep) }; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + return 0; +} + +static struct tda1004x_config tda827x_lifeview_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X_GP11, + .if_freq = TDA10046_FREQ_045, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static struct tda827xa_data tda827xa_dvbt[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}}; + + +static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[14]; + unsigned char reg2[2]; + + struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf}; + int i, tuner_freq, if_freq; + u32 N; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync off */ - saa7134_set_gpio(dev, 22, 0); - GP00_LEV[1] = high ? 0 : 1; - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access tda8290 at addr: 0x%02x\n", - addr << 1); - return; - } - msg.buf = GP00_LEV; - if (config == 2) - GP00_LEV[1] = high ? 1 : 0; - i2c_transfer(&dev->i2c_adap, &msg, 1); + case BANDWIDTH_7_MHZ: + if_freq = 4500000; break; - case 3: /* switch with GPIO of saa713x */ - saa7134_set_gpio(dev, 22, high); + default: /* 8 MHz or Auto */ + if_freq = 5000000; break; } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827xa_dvbt[i].lomax < tuner_freq) { + if(tda827xa_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; + tuner_buf[0] = 0; // subaddress + tuner_buf[1] = N >> 8; + tuner_buf[2] = N & 0xff; + tuner_buf[3] = 0; + tuner_buf[4] = 0x16; + tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + + tda827xa_dvbt[i].sbs; + tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); + tuner_buf[7] = 0x0c; + tuner_buf[8] = 0x06; + tuner_buf[9] = 0x24; + tuner_buf[10] = 0xff; + tuner_buf[11] = 0x60; + tuner_buf[12] = 0x00; + tuner_buf[13] = 0x39; // lpsel + msg.len = 14; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + + msg.buf= reg2; + msg.len = 2; + reg2[0] = 0x60; + reg2[1] = 0x3c; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &msg, 1); + + reg2[0] = 0xa0; + reg2[1] = 0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &msg, 1); + + msleep(2); + /* correct CP value */ + reg2[0] = 0x30; + reg2[1] = 0x10 + tda827xa_dvbt[i].scr; + msg.len = 2; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &msg, 1); + + msleep(550); + reg2[0] = 0x50; + reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &msg, 1); + + return 0; + } -static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) +static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe) { - struct tda1004x_state *state = fe->demodulator_priv; + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda827xa_sleep[] = { 0x30, 0x90}; + struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep, + .len = sizeof(tda827xa_sleep) }; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; +} - u8 addr = state->config->i2c_gate; +/* ------------------------------------------------------------------ */ + +static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct saa7134_dev *dev = fe->dvb->priv; static u8 tda8290_close[] = { 0x21, 0xc0}; static u8 tda8290_open[] = { 0x21, 0x80}; - struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2}; + struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; if (enable) { tda8290_msg.buf = tda8290_close; } else { tda8290_msg.buf = tda8290_open; } - if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("could not access tda8290 I2C gate\n"); + if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1) return -EIO; - } msleep(20); return 0; } /* ------------------------------------------------------------------ */ -static int philips_tda827x_tuner_init(struct dvb_frontend *fe) +static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; + int ret; - switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); - saa7134_set_gpio(dev, 21, 0); - break; - case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); - saa7134_set_gpio(dev, 21, 1); - break; - } + ret = philips_tda827xa_pll_set(0x61, fe, params); + if (ret != 0) + return ret; return 0; } -static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) +static int philips_tiger_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; + static u8 data[] = { 0x3c, 0x33, 0x6a}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); - saa7134_set_gpio(dev, 21, 1); - break; - case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); - saa7134_set_gpio(dev, 21, 0); - break; - } + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; return 0; } -static struct tda827x_config tda827x_cfg = { - .lna_gain = philips_tda827x_lna_gain, - .init = philips_tda827x_tuner_init, - .sleep = philips_tda827x_tuner_sleep -}; - -static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf) +static int philips_tiger_tuner_sleep(struct dvb_frontend *fe) { - dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap); - if (dev->dvb.frontend) { - if (tda_conf->i2c_gate) - dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; - if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address, - &dev->i2c_adap,&tda827x_cfg) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", - tda_conf->tuner_address); - } - } -} + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; -/* ------------------------------------------------------------------ */ -static struct tda1004x_config tda827x_lifeview_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); + return 0; +} static struct tda1004x_config philips_tiger_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 0, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; +/* ------------------------------------------------------------------ */ -static struct tda1004x_config cinergy_ht_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 0, - .request_firmware = philips_tda1004x_request_firmware -}; +static int cinergy_ht_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x62}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; -static struct tda1004x_config cinergy_ht_pci_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x60, - .tuner_config = 0, - .request_firmware = philips_tda1004x_request_firmware -}; + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x60}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); + return 0; +} -static struct tda1004x_config philips_tiger_s_config = { +static struct tda1004x_config cinergy_ht_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, + .agc_config = TDA10046_AGC_TDA827X_GP01, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 2, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; +/* ------------------------------------------------------------------ */ + static struct tda1004x_config pinnacle_pctv_310i_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 1, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = philips_tda1004x_request_firmware, }; +/* ------------------------------------------------------------------ */ + static struct tda1004x_config hauppauge_hvr_1110_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = philips_tda1004x_request_firmware, }; +/* ------------------------------------------------------------------ */ + static struct tda1004x_config asus_p7131_dual_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 0, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = philips_tda1004x_request_firmware, }; +static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x6a}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + /* make sure the DVB-T antenna input is set */ + saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); + return 0; +} + +static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); + /* reset antenna inputs for analog usage */ + saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + + ret = philips_tda827xa_pll_set(0x60, fe, params); + return ret; +} + +static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe) +{ + philips_tda827xa_tuner_sleep(0x60, fe); + return 0; +} + static struct tda1004x_config lifeview_trio_config = { .demod_address = 0x09, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP00_I, + .agc_config = TDA10046_AGC_TDA827X_GP00, .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; -static struct tda1004x_config tevion_dvbt220rf_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; +/* ------------------------------------------------------------------ */ -static struct tda1004x_config md8800_dvbt_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x60, - .tuner_config = 0, - .request_firmware = philips_tda1004x_request_firmware -}; +static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; -static struct tda1004x_config asus_p7131_4871_config = { + ret = philips_tda827xa_pll_set(0x61, fe, params); + return ret; +} + +static int ads_duo_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* route TDA8275a AGC input to the channel decoder */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60); + return 0; +} + +static int ads_duo_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* route TDA8275a AGC input to the analog IF chip*/ + saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20); + philips_tda827xa_tuner_sleep( 0x61, fe); + return 0; +} + +static struct tda1004x_config ads_tech_duo_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, + .agc_config = TDA10046_AGC_TDA827X_GP00, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 2, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; -static struct tda1004x_config asus_p7131_hybrid_lna_config = { +/* ------------------------------------------------------------------ */ + +static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + ret = philips_tda827xa_pll_set(0x60, fe, params); + return ret; +} + +static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe) +{ + philips_tda827xa_tuner_sleep( 0x61, fe); + return 0; +} + +static struct tda1004x_config tevion_dvbt220rf_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .tuner_config = 2, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; -/* ------------------------------------------------------------------ - * special case: this card uses saa713x GPIO22 for the mode switch - */ -static int ads_duo_tuner_init(struct dvb_frontend *fe) +/* ------------------------------------------------------------------ */ + +static int md8800_dvbt_analog_mode(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; - philips_tda827x_tuner_init(fe); - /* route TDA8275a AGC input to the channel decoder */ - saa7134_set_gpio(dev, 22, 1); + static u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); return 0; } -static int ads_duo_tuner_sleep(struct dvb_frontend *fe) +static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { + int ret; struct saa7134_dev *dev = fe->dvb->priv; - /* route TDA8275a AGC input to the analog IF chip*/ - saa7134_set_gpio(dev, 22, 0); - philips_tda827x_tuner_sleep(fe); - return 0; + static u8 tda8290_close[] = { 0x21, 0xc0}; + static u8 tda8290_open[] = { 0x21, 0x80}; + struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; + /* close tda8290 i2c bridge */ + tda8290_msg.buf = tda8290_close; + ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); + if (ret != 1) + return -EIO; + msleep(20); + ret = philips_tda827xa_pll_set(0x60, fe, params); + if (ret != 0) + return ret; + /* open tda8290 i2c bridge */ + tda8290_msg.buf = tda8290_open; + i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); + return ret; } -static struct tda827x_config ads_duo_cfg = { - .lna_gain = philips_tda827x_lna_gain, - .init = ads_duo_tuner_init, - .sleep = ads_duo_tuner_sleep -}; - -static struct tda1004x_config ads_tech_duo_config = { +static struct tda1004x_config md8800_dvbt_config = { .demod_address = 0x08, .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP00_I, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware + .request_firmware = NULL, }; -/* ================================================================== - * tda10086 based DVB-S cards, helper functions - */ - static struct tda10086_config flydvbs = { .demod_address = 0x0e, .invert = 0, }; -/* ================================================================== - * nxt200x based ATSC cards, helper functions - */ +/* ------------------------------------------------------------------ */ static struct nxt200x_config avertvhda180 = { .demod_address = 0x0a, @@ -958,13 +1143,10 @@ static struct nxt200x_config kworldatsc110 = { .set_pll_input = nxt200x_set_pll_input, }; -/* ================================================================== - * Core code - */ +/* ------------------------------------------------------------------ */ static int dvb_init(struct saa7134_dev *dev) { - int ret; /* init struct videobuf_dvb */ dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; @@ -978,7 +1160,7 @@ static int dvb_init(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: - dprintk("pinnacle 300i dvb setup\n"); + printk("%s: pinnacle 300i dvb setup\n",dev->name); dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, &dev->i2c_adap); if (dev->dvb.frontend) { @@ -987,7 +1169,7 @@ static int dvb_init(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_777: case SAA7134_BOARD_AVERMEDIA_A16AR: - dprintk("avertv 777 dvb setup\n"); + printk("%s: avertv 777 dvb setup\n",dev->name); dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, &dev->i2c_adap); if (dev->dvb.frontend) { @@ -1009,15 +1191,42 @@ static int dvb_init(struct saa7134_dev *dev) &philips_tu1216_60_config, &dev->i2c_adap); if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; - dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; + dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params; } break; case SAA7134_BOARD_FLYDVBTDUO: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &tda827x_lifeview_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; + } + break; case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: - configure_tda827x_fe(dev, &tda827x_lifeview_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &tda827x_lifeview_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; + } break; case SAA7134_BOARD_PHILIPS_EUROPA: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &philips_europa_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; + dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; + dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; + } + break; case SAA7134_BOARD_VIDEOMATE_DVBT_300: dev->dvb.frontend = dvb_attach(tda10046_attach, &philips_europa_config, @@ -1035,61 +1244,125 @@ static int dvb_init(struct saa7134_dev *dev) &philips_tu1216_61_config, &dev->i2c_adap); if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; - dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; + dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params; } break; case SAA7134_BOARD_PHILIPS_TIGER: - configure_tda827x_fe(dev, &philips_tiger_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &philips_tiger_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } break; case SAA7134_BOARD_PINNACLE_PCTV_310i: - configure_tda827x_fe(dev, &pinnacle_pctv_310i_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &pinnacle_pctv_310i_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: - configure_tda827x_fe(dev, &hauppauge_hvr_1110_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &hauppauge_hvr_1110_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - configure_tda827x_fe(dev, &asus_p7131_dual_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &asus_p7131_dual_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } break; case SAA7134_BOARD_FLYDVBT_LR301: - configure_tda827x_fe(dev, &tda827x_lifeview_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &tda827x_lifeview_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; + } break; case SAA7134_BOARD_FLYDVB_TRIO: if(! use_frontend) { //terrestrial - configure_tda827x_fe(dev, &lifeview_trio_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &lifeview_trio_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = + lifeview_trio_tuner_set_params; + } } else { //satellite dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); if (dev->dvb.frontend) { if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); + printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); } if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); + printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); } } } break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: - case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: dev->dvb.frontend = dvb_attach(tda10046_attach, &ads_tech_duo_config, &dev->i2c_adap); if (dev->dvb.frontend) { - if (dvb_attach(tda827x_attach,dev->dvb.frontend, - ads_tech_duo_config.tuner_address, - &dev->i2c_adap,&ads_duo_cfg) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", - ads_tech_duo_config.tuner_address); - } + dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; } break; case SAA7134_BOARD_TEVION_DVBT_220RF: - configure_tda827x_fe(dev, &tevion_dvbt220rf_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &tevion_dvbt220rf_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params; + } + break; + case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &ads_tech_duo_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; + } break; case SAA7134_BOARD_MEDION_MD8800_QUADRO: - configure_tda827x_fe(dev, &md8800_dvbt_config); + dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode; + dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; + } break; case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, @@ -1113,11 +1386,11 @@ static int dvb_init(struct saa7134_dev *dev) if (dev->dvb.frontend) { if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __FUNCTION__); + printk("%s: No tda826x found!\n", __FUNCTION__); } if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: No ISL6421 found!\n", __FUNCTION__); + printk("%s: No ISL6421 found!\n", __FUNCTION__); } } break; @@ -1142,45 +1415,41 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_CINERGY_HT_PCMCIA: - configure_tda827x_fe(dev, &cinergy_ht_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &cinergy_ht_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + + } break; case SAA7134_BOARD_CINERGY_HT_PCI: - configure_tda827x_fe(dev, &cinergy_ht_pci_config); - break; - case SAA7134_BOARD_PHILIPS_TIGER_S: - configure_tda827x_fe(dev, &philips_tiger_s_config); - break; - case SAA7134_BOARD_ASUS_P7131_4871: - configure_tda827x_fe(dev, &asus_p7131_4871_config); - break; - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &cinergy_ht_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; + + } break; default: - wprintk("Huh? unknown DVB card?\n"); + printk("%s: Huh? unknown DVB card?\n",dev->name); break; } if (NULL == dev->dvb.frontend) { - printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); + printk("%s: frontend initialization failed\n",dev->name); return -1; } /* register everything else */ - ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); - - /* this sequence is necessary to make the tda1004x load its firmware - * and to enter analog mode of hybrid boards - */ - if (!ret) { - if (dev->dvb.frontend->ops.init) - dev->dvb.frontend->ops.init(dev->dvb.frontend); - if (dev->dvb.frontend->ops.sleep) - dev->dvb.frontend->ops.sleep(dev->dvb.frontend); - if (dev->dvb.frontend->ops.tuner_ops.sleep) - dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend); - } - return ret; + return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); } static int dvb_fini(struct saa7134_dev *dev) diff --git a/trunk/drivers/media/video/saa7134/saa7134-i2c.c b/trunk/drivers/media/video/saa7134/saa7134-i2c.c index 1cb8c709ca90..cce8da6a4f94 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-i2c.c +++ b/trunk/drivers/media/video/saa7134/saa7134-i2c.c @@ -370,8 +370,6 @@ static int attach_inform(struct i2c_client *client) tun_setup.type = tuner; tun_setup.addr = saa7134_boards[dev->board].tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; - tun_setup.tuner_callback = saa7134_tuner_callback; if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { @@ -447,7 +445,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) unsigned char buf; int i,rc; - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + for (i = 0; i < 128; i++) { c->addr = i; rc = i2c_master_recv(c,&buf,0); if (rc < 0) diff --git a/trunk/drivers/media/video/saa7134/saa7134-input.c b/trunk/drivers/media/video/saa7134/saa7134-input.c index c0de37e3f5c6..46c583f1e788 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-input.c +++ b/trunk/drivers/media/video/saa7134/saa7134-input.c @@ -321,7 +321,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keydown = 0x0040000; break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: ir_codes = ir_codes_asus_pc39; mask_keydown = 0x0040000; rc5_gpio = 1; diff --git a/trunk/drivers/media/video/saa7134/saa7134-video.c b/trunk/drivers/media/video/saa7134/saa7134-video.c index 9985ded20950..f2cb63053041 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-video.c +++ b/trunk/drivers/media/video/saa7134/saa7134-video.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "saa7134-reg.h" #include "saa7134.h" @@ -517,12 +516,14 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int return 1; } -static int res_check(struct saa7134_fh *fh, unsigned int bit) +static +int res_check(struct saa7134_fh *fh, unsigned int bit) { return (fh->resources & bit); } -static int res_locked(struct saa7134_dev *dev, unsigned int bit) +static +int res_locked(struct saa7134_dev *dev, unsigned int bit) { return (dev->resources & bit); } @@ -602,14 +603,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); - /* only tell the tuner if this is a tv input */ - if (card_in(dev,dev->ctl_input).tv) { - if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) - && ((card(dev).tuner_config == 1) - || (card(dev).tuner_config == 2))) - saa7134_set_gpio(dev, 22, 5); - saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); - } + saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); } static void video_mux(struct saa7134_dev *dev, int input) @@ -738,6 +732,25 @@ struct cliplist { __u8 disable; }; +static void sort_cliplist(struct cliplist *cl, int entries) +{ + struct cliplist swap; + int i,j,n; + + for (i = entries-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (cl[j].position > cl[j+1].position) { + swap = cl[j]; + cl[j] = cl[j+1]; + cl[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + static void set_cliplist(struct saa7134_dev *dev, int reg, struct cliplist *cl, int entries, char *name) { @@ -771,27 +784,15 @@ static int clip_range(int val) return val; } -/* Sort into smallest position first order */ -static int cliplist_cmp(const void *a, const void *b) -{ - const struct cliplist *cla = a; - const struct cliplist *clb = b; - if (cla->position < clb->position) - return -1; - if (cla->position > clb->position) - return 1; - return 0; -} - static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, int nclips, int interlace) { struct cliplist col[16], row[16]; - int cols = 0, rows = 0, i; + int cols, rows, i; int div = interlace ? 2 : 1; - memset(col, 0, sizeof(col)); - memset(row, 0, sizeof(row)); + memset(col,0,sizeof(col)); cols = 0; + memset(row,0,sizeof(row)); rows = 0; for (i = 0; i < nclips && i < 8; i++) { col[cols].position = clip_range(clips[i].c.left); col[cols].enable = (1 << i); @@ -807,8 +808,8 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, row[rows].disable = (1 << i); rows++; } - sort(col, cols, sizeof col[0], cliplist_cmp, NULL); - sort(row, rows, sizeof row[0], cliplist_cmp, NULL); + sort_cliplist(col,cols); + sort_cliplist(row,rows); set_cliplist(dev,0x380,col,cols,"cols"); set_cliplist(dev,0x384,row,rows,"rows"); return 0; @@ -1260,14 +1261,19 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) static int saa7134_resource(struct saa7134_fh *fh) { - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return RESOURCE_VIDEO; + int res = 0; - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return RESOURCE_VBI; - - BUG(); - return 0; + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + res = RESOURCE_VIDEO; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + res = RESOURCE_VBI; + break; + default: + BUG(); + } + return res; } static int video_open(struct inode *inode, struct file *file) @@ -1455,7 +1461,8 @@ static int video_release(struct inode *inode, struct file *file) return 0; } -static int video_mmap(struct file *file, struct vm_area_struct * vma) +static int +video_mmap(struct file *file, struct vm_area_struct * vma) { struct saa7134_fh *fh = file->private_data; @@ -2454,6 +2461,12 @@ int saa7134_video_init2(struct saa7134_dev *dev) return 0; } +int saa7134_video_fini(struct saa7134_dev *dev) +{ + /* nothing */ + return 0; +} + void saa7134_irq_video_intl(struct saa7134_dev *dev) { static const char *st[] = { diff --git a/trunk/drivers/media/video/saa7134/saa7134.h b/trunk/drivers/media/video/saa7134/saa7134.h index 62224cc958f1..b3e3957c89b5 100644 --- a/trunk/drivers/media/video/saa7134/saa7134.h +++ b/trunk/drivers/media/video/saa7134/saa7134.h @@ -231,10 +231,6 @@ struct saa7134_format { #define SAA7134_BOARD_ENCORE_ENLTV 106 #define SAA7134_BOARD_ENCORE_ENLTV_FM 107 #define SAA7134_BOARD_CINERGY_HT_PCI 108 -#define SAA7134_BOARD_PHILIPS_TIGER_S 109 -#define SAA7134_BOARD_AVERMEDIA_M102 110 -#define SAA7134_BOARD_ASUS_P7131_4871 111 -#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -284,7 +280,6 @@ struct saa7134_board { unsigned char radio_addr; unsigned int tda9887_conf; - unsigned int tuner_config; /* peripheral I/O */ enum saa7134_video_out video_out; @@ -440,8 +435,6 @@ struct saa7134_dev { #ifdef VIDIOC_G_PRIORITY struct v4l2_prio_state prio; #endif - /* workstruct for loading modules */ - struct work_struct request_module_wk; /* insmod option/autodetected */ int autodetected; @@ -569,8 +562,6 @@ extern struct list_head saa7134_devlist; extern int saa7134_no_overlay; void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); -void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value); -int saa7134_tuner_callback(void *ptr, int command, int arg); #define SAA7134_PGTABLE_SIZE 4096 @@ -629,6 +620,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); +int saa7134_video_fini(struct saa7134_dev *dev); void saa7134_irq_video_intl(struct saa7134_dev *dev); void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); diff --git a/trunk/drivers/media/video/saa7185.c b/trunk/drivers/media/video/saa7185.c index 339592e7722d..e0fdb1ab7580 100644 --- a/trunk/drivers/media/video/saa7185.c +++ b/trunk/drivers/media/video/saa7185.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/se401.c b/trunk/drivers/media/video/se401.c index 93fb04ed99a0..038448f5a978 100644 --- a/trunk/drivers/media/video/se401.c +++ b/trunk/drivers/media/video/se401.c @@ -450,13 +450,6 @@ static int se401_start_stream(struct usb_se401 *se401) } for (i=0; isbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - if (!se401->sbuf[i].data) { - for(i = i - 1; i >= 0; i--) { - kfree(se401->sbuf[i].data); - se401->sbuf[i].data = NULL; - } - return -ENOMEM; - } } se401->bayeroffset=0; @@ -465,26 +458,13 @@ static int se401_start_stream(struct usb_se401 *se401) se401->scratch_overflow=0; for (i=0; iscratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - if (!se401->scratch[i].data) { - for(i = i - 1; i >= 0; i--) { - kfree(se401->scratch[i].data); - se401->scratch[i].data = NULL; - } - goto nomem_sbuf; - } se401->scratch[i].state=BUFFER_UNUSED; } for (i=0; i= 0; i--) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - } - goto nomem_scratch; - } + if(!urb) + return -ENOMEM; usb_fill_bulk_urb(urb, se401->dev, usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), @@ -502,18 +482,6 @@ static int se401_start_stream(struct usb_se401 *se401) se401->framecount=0; return 0; - - nomem_scratch: - for (i=0; iscratch[i].data); - se401->scratch[i].data = NULL; - } - nomem_sbuf: - for (i=0; isbuf[i].data); - se401->sbuf[i].data = NULL; - } - return -ENOMEM; } static int se401_stop_stream(struct usb_se401 *se401) diff --git a/trunk/drivers/media/video/sn9c102/Kconfig b/trunk/drivers/media/video/sn9c102/Kconfig index 19204f5686e1..1a7ccb666ab0 100644 --- a/trunk/drivers/media/video/sn9c102/Kconfig +++ b/trunk/drivers/media/video/sn9c102/Kconfig @@ -1,6 +1,6 @@ config USB_SN9C102 tristate "USB SN9C1xx PC Camera Controller support" - depends on USB && VIDEO_V4L2 + depends on USB && VIDEO_V4L1 ---help--- Say Y here if you want support for cameras based on SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. diff --git a/trunk/drivers/media/video/sn9c102/Makefile b/trunk/drivers/media/video/sn9c102/Makefile index a56d16f69c71..30e3dfe537fe 100644 --- a/trunk/drivers/media/video/sn9c102/Makefile +++ b/trunk/drivers/media/video/sn9c102/Makefile @@ -1,14 +1,7 @@ -sn9c102-objs := sn9c102_core.o \ - sn9c102_hv7131d.o \ - sn9c102_hv7131r.o \ - sn9c102_mi0343.o \ - sn9c102_mi0360.o \ - sn9c102_ov7630.o \ - sn9c102_ov7660.o \ - sn9c102_pas106b.o \ - sn9c102_pas202bcb.o \ - sn9c102_tas5110c1b.o \ - sn9c102_tas5110d.o \ - sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ + sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \ + sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ + sn9c102_tas5130d1b.o obj-$(CONFIG_USB_SN9C102) += sn9c102.o + diff --git a/trunk/drivers/media/video/sn9c102/sn9c102.h b/trunk/drivers/media/video/sn9c102/sn9c102.h index 680e74634527..5428f34e7c5b 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102.h +++ b/trunk/drivers/media/video/sn9c102/sn9c102.h @@ -78,13 +78,8 @@ enum sn9c102_stream_state { typedef char sn9c102_sof_header_t[62]; -struct sn9c102_sof_t { - sn9c102_sof_header_t header; - u16 bytesread; -}; - struct sn9c102_sysfs_attr { - u16 reg, i2c_reg; + u8 reg, i2c_reg; sn9c102_sof_header_t frame_header; }; @@ -117,7 +112,7 @@ struct sn9c102_device { struct v4l2_jpegcompression compression; struct sn9c102_sysfs_attr sysfs; - struct sn9c102_sof_t sof; + sn9c102_sof_header_t sof_header; u16 reg[384]; struct sn9c102_module_param module_param; @@ -187,8 +182,8 @@ do { \ if ((level) == 1 || (level) == 2) \ pr_info("sn9c102: " fmt "\n", ## args); \ else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ + pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ + __LINE__ , ## args); \ } \ } while (0) #else @@ -199,8 +194,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ - __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_core.c b/trunk/drivers/media/video/sn9c102/sn9c102_core.c index 89f83354de3b..d0e2b40a7725 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_core.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_core.c @@ -44,12 +44,11 @@ /*****************************************************************************/ #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" -#define SN9C102_MODULE_ALIAS "sn9c1xx" -#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" +#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.39" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39) +#define SN9C102_MODULE_VERSION "1:1.34" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34) /*****************************************************************************/ @@ -57,7 +56,6 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table); MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); MODULE_DESCRIPTION(SN9C102_MODULE_NAME); -MODULE_ALIAS(SN9C102_MODULE_ALIAS); MODULE_VERSION(SN9C102_MODULE_VERSION); MODULE_LICENSE(SN9C102_MODULE_LICENSE); @@ -108,7 +106,8 @@ MODULE_PARM_DESC(debug, "\n1 = critical errors" "\n2 = significant informations" "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only." + "\nLevel 3 is useful for testing only, when only " + "one device is used." "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." "\n"); #endif @@ -122,8 +121,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, struct v4l2_pix_format* p = &(cam->sensor.pix_format); struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; + (p->width * p->height * p->priv) / 8 : + (r->width * r->height * p->priv) / 8; void* buff = NULL; u32 i; @@ -209,40 +208,27 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) } /*****************************************************************************/ -/* - * Write a sequence of count value/register pairs. Returns -1 after the - * first failed write, or 0 for no errors. - */ -int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], - int count) + +int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) { struct usb_device* udev = cam->usbdev; - u8* value = cam->control_buffer; /* Needed for DMA'able memory */ int i, res; - for (i = 0; i < count; i++) { - u8 index = valreg[i][1]; - - /* - * index is a u8, so it must be <256 and can't be out of range. - * If we put in a check anyway, gcc annoys us with a warning - * that our check is useless. People get all uppity when they - * see warnings in the kernel compile. - */ - - *value = valreg[i][0]; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x08, 0x41, index, 0, - value, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, " - "index 0x%02X, error %d)", *value, index, res); - return -1; - } + if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) + return -1; - cam->reg[index] = *value; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, + index, 0, buff, sizeof(buff), + SN9C102_CTRL_TIMEOUT*sizeof(buff)); + if (res < 0) { + DBG(3, "Failed to write registers (index 0x%02X, error %d)", + index, res); + return -1; } + for (i = 0; i < sizeof(buff); i++) + cam->reg[index+i] = buff[i]; + return 0; } @@ -499,43 +485,18 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam) static void* sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) { - static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; - const char *m = mem; - size_t soflen = 0, i, j; + char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; + size_t soflen = 0, i; soflen = sn9c102_sof_length(cam); - for (i = 0; i < len; i++) { - size_t b; - - /* Read the variable part of the header */ - if (unlikely(cam->sof.bytesread >= sizeof(marker))) { - cam->sof.header[cam->sof.bytesread] = *(m+i); - if (++cam->sof.bytesread == soflen) { - cam->sof.bytesread = 0; - return mem + i; - } - continue; - } - - /* Search for the SOF marker (fixed part) in the header */ - for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { - if (unlikely(i+j) == len) - return NULL; - if (*(m+i+j) == marker[cam->sof.bytesread]) { - cam->sof.header[cam->sof.bytesread] = *(m+i+j); - if (++cam->sof.bytesread == sizeof(marker)) { - PDBGG("Bytes to analyze: %zd. SOF " - "starts at byte #%zd", len, i); - i += j+1; - break; - } - } else { - cam->sof.bytesread = 0; - break; + for (i = 0; (len >= soflen) && (i <= len - soflen); i++) + if (!memcmp(mem + i, sof_header, sizeof(sof_header))) { + memcpy(cam->sof_header, mem + i, + sizeof(sn9c102_sof_header_t)); + /* Skip the header */ + return mem + i + soflen; } - } - } return NULL; } @@ -544,7 +505,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) static void* sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) { - static const u8 eof_header[4][4] = { + char eof_header[4][4] = { {0x00, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x00}, {0x80, 0x00, 0x00, 0x00}, @@ -552,16 +513,10 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) }; size_t i, j; - /* The EOF header does not exist in compressed data */ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - return NULL; + return NULL; /* EOF header does not exist in compressed data */ - /* - The EOF header might cross the packet boundary, but this is not a - problem, since the end of a frame is determined by checking its size - in the first place. - */ for (i = 0; (len >= 4) && (i <= len - 4); i++) for (j = 0; j < ARRAY_SIZE(eof_header); j++) if (!memcmp(mem + i, eof_header[j], 4)) @@ -574,7 +529,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) static void sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) { - static const u8 jpeg_header[589] = { + static u8 jpeg_header[589] = { 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, @@ -684,7 +639,6 @@ static void sn9c102_urb_complete(struct urb *urb) cam->stream = STREAM_OFF; if ((*f)) (*f)->state = F_QUEUED; - cam->sof.bytesread = 0; DBG(3, "Stream interrupted by application"); wake_up(&cam->wait_stream); } @@ -722,7 +676,6 @@ static void sn9c102_urb_complete(struct urb *urb) if (status) { DBG(3, "Error in isochronous frame"); (*f)->state = F_ERROR; - cam->sof.bytesread = 0; continue; } @@ -739,13 +692,13 @@ static void sn9c102_urb_complete(struct urb *urb) if (eof) img = (eof > pos) ? eof - pos - 1 : 0; - if ((*f)->buf.bytesused + img > imagesize) { + if ((*f)->buf.bytesused+img > imagesize) { u32 b; b = (*f)->buf.bytesused + img - imagesize; img = imagesize - (*f)->buf.bytesused; - PDBGG("Expected EOF not found: video " - "frame cut"); + DBG(3, "Expected EOF not found: " + "video frame cut"); if (eof) DBG(3, "Exceeded limit: +%u " "bytes", (unsigned)(b)); @@ -766,6 +719,11 @@ static void sn9c102_urb_complete(struct urb *urb) V4L2_PIX_FMT_JPEG) && eof)) { u32 b; + if (cam->sensor.pix_format.pixelformat + == V4L2_PIX_FMT_JPEG) + sn9c102_write_eoimarker(cam, + (*f)); + b = (*f)->buf.bytesused; (*f)->state = F_DONE; (*f)->buf.sequence= ++cam->frame_count; @@ -783,7 +741,7 @@ static void sn9c102_urb_complete(struct urb *urb) spin_unlock(&cam->queue_lock); memcpy(cam->sysfs.frame_header, - cam->sof.header, soflen); + cam->sof_header, soflen); DBG(3, "Video frame captured: %lu " "bytes", (unsigned long)(b)); @@ -833,13 +791,7 @@ static void sn9c102_urb_complete(struct urb *urb) V4L2_PIX_FMT_SN9C10X || cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) { - if (sof - pos >= soflen) { - eof = sof - soflen; - } else { /* remove header */ - eof = pos; - (*f)->buf.bytesused -= - (soflen - (sof - pos)); - } + eof = sof - soflen; goto end_of_frame; } else { DBG(3, "SOF before expected EOF after " @@ -926,7 +878,6 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) } cam->frame_current = NULL; - cam->sof.bytesread = 0; for (i = 0; i < SN9C102_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); @@ -1008,9 +959,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) if (len < 6) { strncpy(str, buff, len); - str[len] = '\0'; + str[len+1] = '\0'; } else { - strncpy(str, buff, 6); + strncpy(str, buff, 4); str[6] = '\0'; } @@ -1111,7 +1062,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) count = sprintf(buf, "%d\n", val); - DBG(3, "Read bytes: %zd, value: %d", count, val); + DBG(3, "Read bytes: %zd", count); mutex_unlock(&sn9c102_sysfs_lock); @@ -1246,7 +1197,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) count = sprintf(buf, "%d\n", val); - DBG(3, "Read bytes: %zd, value: %d", count, val); + DBG(3, "Read bytes: %zd", count); mutex_unlock(&sn9c102_sysfs_lock); @@ -1420,35 +1371,35 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct video_device *v4ldev = cam->v4ldev; int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = video_device_create_file(v4ldev, &class_device_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = video_device_create_file(v4ldev, &class_device_attr_val))) goto err_reg; - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_i2c_reg))) goto err_frame_header; - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_green))) goto err_i2c_val; } else { - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_blue))) goto err_i2c_val; - if ((err = class_device_create_file(classdev, + if ((err = video_device_create_file(v4ldev, &class_device_attr_red))) goto err_blue; } @@ -1456,19 +1407,19 @@ static int sn9c102_create_sysfs(struct sn9c102_device* cam) return 0; err_blue: - class_device_remove_file(classdev, &class_device_attr_blue); + video_device_remove_file(v4ldev, &class_device_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_val); + video_device_remove_file(v4ldev, &class_device_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); err_frame_header: - class_device_remove_file(classdev, &class_device_attr_frame_header); + video_device_remove_file(v4ldev, &class_device_attr_frame_header); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + video_device_remove_file(v4ldev, &class_device_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + video_device_remove_file(v4ldev, &class_device_attr_reg); err_out: return err; } @@ -1526,10 +1477,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - if (compression->quality == 0) + if (compression->quality == 0) err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); - else if (compression->quality == 1) + else if (compression->quality == 1) err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); break; @@ -1538,10 +1489,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, if (compression->quality == 0) { for (i = 0; i <= 63; i++) { err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE1[i], + SN9C102_Y_QTABLE0[i], 0x100 + i); err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE1[i], + SN9C102_UV_QTABLE0[i], 0x140 + i); } err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, @@ -1646,13 +1597,9 @@ static int sn9c102_init(struct sn9c102_device* cam) if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102 || cam->bridge == BRIDGE_SN9C103) { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; } else { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) - s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; cam->compression.quality = cam->reg[0x18] & 0x40 ? 0 : 1; err += sn9c102_set_compression(cam, &cam->compression); @@ -1858,7 +1805,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) DBG(3, "Close and open the device again to choose " "the read method"); mutex_unlock(&cam->fileop_mutex); - return -EBUSY; + return -EINVAL; } if (cam->io == IO_NONE) { @@ -1898,16 +1845,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) return err; } } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; } else if (timeout == 0 && !(cam->state & DEV_DISCONNECTED)) { DBG(1, "Video frame timeout elapsed"); @@ -2054,12 +2001,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) return -EIO; } - if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { - mutex_unlock(&cam->fileop_mutex); - return -EACCES; - } - - if (cam->io != IO_MMAP || + if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(cam->frame[0].buf.length)) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; @@ -2325,7 +2267,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_CROP failed. " "Unmap the buffers first."); - return -EBUSY; + return -EINVAL; } /* Preserve R,G or B origin */ @@ -2468,8 +2410,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; + strcpy(fmtd.description, "compressed"); + fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; break; case BRIDGE_SN9C105: case BRIDGE_SN9C120: @@ -2503,10 +2445,8 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; - pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || - pfmt->pixelformat == V4L2_PIX_FMT_JPEG) + pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X || + pfmt->pixelformat==V4L2_PIX_FMT_JPEG) ? 0 : (pfmt->width * pfmt->priv) / 8; pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); pfmt->field = V4L2_FIELD_NONE; @@ -2581,9 +2521,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, case BRIDGE_SN9C101: case BRIDGE_SN9C102: case BRIDGE_SN9C103: - if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; + if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && + pix->pixelformat != V4L2_PIX_FMT_SBGGR8) + pix->pixelformat = pfmt->pixelformat; break; case BRIDGE_SN9C105: case BRIDGE_SN9C120: @@ -2593,8 +2533,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, break; } pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; + pix->colorspace = pfmt->colorspace; pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || pix->pixelformat == V4L2_PIX_FMT_JPEG) ? 0 : (pix->width * pix->priv) / 8; @@ -2612,7 +2551,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. Unmap the " "buffers first."); - return -EBUSY; + return -EINVAL; } if (cam->stream == STREAM_ON) @@ -2727,14 +2666,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose the mmap " "I/O method"); - return -EBUSY; + return -EINVAL; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " "still mapped."); - return -EBUSY; + return -EINVAL; } if (cam->stream == STREAM_ON) @@ -2846,15 +2785,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, if (err) return err; } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; else if (timeout == 0 && !(cam->state & DEV_DISCONNECTED)) { DBG(1, "Video frame timeout elapsed"); @@ -2898,6 +2837,9 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; + if (list_empty(&cam->inqueue)) + return -EINVAL; + cam->stream = STREAM_ON; DBG(3, "Stream on"); @@ -3224,8 +3166,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) r = sn9c102_read_reg(cam, 0x00); if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { - DBG(1, "Sorry, this is not a SN9C1xx-based camera " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + DBG(1, "Sorry, this is not a SN9C1xx based camera " + "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); err = -ENODEV; goto fail; } @@ -3235,19 +3177,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) case BRIDGE_SN9C101: case BRIDGE_SN9C102: DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C103: DBG(2, "SN9C103 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C105: DBG(2, "SN9C105 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; case BRIDGE_SN9C120: DBG(2, "SN9C120 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); break; } @@ -3318,8 +3260,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) "device controlling. Error #%d", err); #else DBG(2, "Optional device control through 'sysfs' interface disabled"); - DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " - "configuration option to enable it."); #endif usb_set_intfdata(intf, cam); diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h b/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h index f49bd8c5b86e..3a682eca6c65 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -89,22 +89,16 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, /* SN9C120 */ - { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, @@ -120,15 +114,12 @@ static const struct usb_device_id sn9c102_id_table[] = { Functions must return 0 on success, the appropriate error otherwise. */ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); -extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); /* @@ -137,16 +128,13 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); the order of the list below, from top to bottom. */ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ - &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ + &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ NULL, }; diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/trunk/drivers/media/video/sn9c102/sn9c102_hv7131d.c index 28a861aed044..7ae368f60d89 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_hv7131d.c @@ -22,13 +22,19 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor hv7131d; + + static int hv7131d_init(struct sn9c102_device* cam) { - int err; + int err = 0; - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x60, 0x17}, - {0x0e, 0x18}, {0xf2, 0x19}); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0e, 0x18); + err += sn9c102_write_reg(cam, 0xf2, 0x19); err += sn9c102_i2c_write(cam, 0x01, 0x04); err += sn9c102_i2c_write(cam, 0x02, 0x00); @@ -147,7 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor hv7131d = { .name = "HV7131D", .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, @@ -244,10 +250,11 @@ static struct sn9c102_sensor hv7131d = { int sn9c102_probe_hv7131d(struct sn9c102_device* cam) { - int r0 = 0, r1 = 0, err; + int r0 = 0, r1 = 0, err = 0; - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); if (err) return -EIO; @@ -256,7 +263,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam) if (r0 < 0 || r1 < 0) return -EIO; - if (r0 != 0x00 || r1 != 0x04) + if (r0 != 0x00 && r1 != 0x04) return -ENODEV; sn9c102_attach_sensor(cam, &hv7131d); diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/trunk/drivers/media/video/sn9c102/sn9c102_hv7131r.c deleted file mode 100644 index 5a495baa5f95..000000000000 --- a/trunk/drivers/media/video/sn9c102/sn9c102_hv7131r.c +++ /dev/null @@ -1,366 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static int hv7131r_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, - {0x20, 0x05}, {0x20, 0x06}, - {0x03, 0x10}, {0x00, 0x14}, - {0x60, 0x17}, {0x0a, 0x18}, - {0xf0, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x44, 0x05}, {0x3e, 0x06}, - {0x1a, 0x07}, {0x03, 0x10}, - {0x08, 0x14}, {0xa3, 0x17}, - {0x4b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); - break; - default: - break; - } - - err += sn9c102_i2c_write(cam, 0x20, 0x00); - err += sn9c102_i2c_write(cam, 0x21, 0xd6); - err += sn9c102_i2c_write(cam, 0x25, 0x06); - - return err; -} - - -static int hv7131r_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLACK_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x08) ? 1 : 0; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131r_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, ctrl->value); - break; - case V4L2_CID_BLACK_LEVEL: - { - int r = sn9c102_i2c_read(cam, 0x01); - if (r < 0) - return -EIO; - err += sn9c102_i2c_write(cam, 0x01, - (ctrl->value<<3) | (r&0xf7)); - } - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131r_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131r_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa0, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } else { - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa5, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x24); - } else { - err += sn9c102_write_reg(cam, 0xa3, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - default: - break; - } - - return err; -} - - -static struct sn9c102_sensor hv7131r = { - .name = "HV7131R", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131r_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x08, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1a, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x2f, - .flags = 0, - }, - { - .id = V4L2_CID_BLACK_LEVEL, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto black level compensation", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &hv7131r_get_ctrl, - .set_ctrl = &hv7131r_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131r_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131r_set_pix_format -}; - - -int sn9c102_probe_hv7131r(struct sn9c102_device* cam) -{ - int devid, err; - - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, - {0x34, 0x01}, {0x20, 0x17}, - {0x34, 0x01}, {0x46, 0x01}); - - if (err) - return -EIO; - - devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); - if (devid < 0) - return -EIO; - - if (devid != 0x02) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131r); - - return 0; -} diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_mi0343.c b/trunk/drivers/media/video/sn9c102/sn9c102_mi0343.c index 9200845d011b..a33d1bc10f90 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_mi0343.c @@ -22,30 +22,36 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor mi0343; +static u8 mi0343_i2c_data[5+1]; + + static int mi0343_init(struct sn9c102_device* cam) { - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); int err = 0; - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x0a, 0x14); + err += sn9c102_write_reg(cam, 0x40, 0x01); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x07, 0x18); + err += sn9c102_write_reg(cam, 0xa0, 0x19); + + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x0d, 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x0d, 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x03, 0x01, 0xe1, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x04, 0x02, 0x81, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x05, 0x00, 0x17, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x06, 0x00, 0x11, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, + 0x62, 0x04, 0x9a, 0, 0); return err; } @@ -54,46 +60,43 @@ static int mi0343_init(struct sn9c102_device* cam) static int mi0343_get_ctrl(struct sn9c102_device* cam, struct v4l2_control* ctrl) { - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[5+1]; - switch (ctrl->id) { case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x09, 2+1, mi0343_i2c_data) < 0) return -EIO; - ctrl->value = data[2]; + ctrl->value = mi0343_i2c_data[2]; return 0; case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x35, 2+1, mi0343_i2c_data) < 0) return -EIO; break; case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x20, 2+1, mi0343_i2c_data) < 0) return -EIO; - ctrl->value = data[3] & 0x20 ? 1 : 0; + ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; return 0; case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x20, 2+1, mi0343_i2c_data) < 0) return -EIO; - ctrl->value = data[3] & 0x80 ? 1 : 0; + ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; return 0; case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x2d, 2+1, mi0343_i2c_data) < 0) return -EIO; break; case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x2c, 2+1, mi0343_i2c_data) < 0) return -EIO; break; case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, - 2+1, data) < 0) + if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, + 0x2e, 2+1, mi0343_i2c_data) < 0) return -EIO; break; default: @@ -105,7 +108,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, case V4L2_CID_RED_BALANCE: case V4L2_CID_BLUE_BALANCE: case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = data[3] | (data[2] << 8); + ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) ctrl->value -= 0x10; else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) @@ -121,7 +124,6 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, static int mi0343_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); u16 reg = 0; int err = 0; @@ -141,42 +143,50 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x09, ctrl->value, 0x00, 0, 0); break; case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x35, reg >> 8, reg & 0xff, 0, 0); break; case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x20, ctrl->value ? 0x40:0x00, ctrl->value ? 0x20:0x00, 0, 0); break; case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x20, ctrl->value ? 0x80:0x00, ctrl->value ? 0x80:0x00, 0, 0); break; case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x2d, reg >> 8, reg & 0xff, 0, 0); break; case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x2c, reg >> 8, reg & 0xff, 0, 0); break; case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x2b, reg >> 8, reg & 0xff, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x2e, reg >> 8, reg & 0xff, 0, 0); break; @@ -206,15 +216,16 @@ static int mi0343_set_crop(struct sn9c102_device* cam, static int mi0343_set_pix_format(struct sn9c102_device* cam, const struct v4l2_pix_format* pix) { - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); int err = 0; if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x0a, 0x00, 0x03, 0, 0); err += sn9c102_write_reg(cam, 0x20, 0x19); } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, + mi0343.i2c_slave_id, 0x0a, 0x00, 0x05, 0, 0); err += sn9c102_write_reg(cam, 0xa0, 0x19); } @@ -226,7 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor mi0343 = { .name = "MI-0343", .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, .i2c_slave_id = 0x5d, @@ -332,20 +343,19 @@ static struct sn9c102_sensor mi0343 = { int sn9c102_probe_mi0343(struct sn9c102_device* cam) { - u8 data[5+1]; int err = 0; - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); if (err) return -EIO; if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, - 2, data) < 0) + 2, mi0343_i2c_data) < 0) return -EIO; - if (data[4] != 0x32 || data[3] != 0xe3) + if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) return -ENODEV; sn9c102_attach_sensor(cam, &mi0343); diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_mi0360.c b/trunk/drivers/media/video/sn9c102/sn9c102_mi0360.c deleted file mode 100644 index 64698acb0b15..000000000000 --- a/trunk/drivers/media/video/sn9c102/sn9c102_mi0360.c +++ /dev/null @@ -1,338 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static int mi0360_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0360_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[5+1]; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[2]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3]; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3]; - return 0; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3]; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3]; - return 0; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, - 2+1, data) < 0) - return -EIO; - ctrl->value = data[3] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return 0; -} - - -static int mi0360_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x35, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2c, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2d, 0x03, ctrl->value, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2b, 0x03, ctrl->value, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2e, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0360_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0360_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x02, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0x60, 0x19); - } - - return err; -} - - -static struct sn9c102_sensor mi0360 = { - .name = "MI-0360", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C103, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0360_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x0f, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x32, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - }, - .get_ctrl = &mi0360_get_ctrl, - .set_ctrl = &mi0360_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0360_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0360_set_pix_format -}; - - -int sn9c102_probe_mi0360(struct sn9c102_device* cam) -{ - u8 data[5+1]; - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - if (err) - return -EIO; - - if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, - 2+1, data) < 0) - return -EIO; - - if (data[2] != 0x82 || data[3] != 0x43) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0360); - - return 0; -} diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_ov7630.c b/trunk/drivers/media/video/sn9c102/sn9c102_ov7630.c index 31b6080b0615..7df09ff38e63 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_ov7630.c @@ -22,6 +22,9 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor ov7630; + + static int ov7630_init(struct sn9c102_device* cam) { int err = 0; @@ -29,20 +32,21 @@ static int ov7630_init(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x14}, - {0x60, 0x17}, {0x0f, 0x18}, - {0x50, 0x19}); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); err += sn9c102_i2c_write(cam, 0x12, 0x8d); err += sn9c102_i2c_write(cam, 0x12, 0x0d); err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x15, 0x35); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1c); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x06); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x15, 0x34); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1c); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x06); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); err += sn9c102_i2c_write(cam, 0x20, 0x44); err += sn9c102_i2c_write(cam, 0x23, 0xee); err += sn9c102_i2c_write(cam, 0x26, 0xa0); @@ -61,26 +65,42 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x71, 0x00); err += sn9c102_i2c_write(cam, 0x74, 0x21); err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - break; case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x20, 0x05}, - {0x20, 0x06}, {0x20, 0x07}, - {0x03, 0x10}, {0x0a, 0x14}, - {0x60, 0x17}, {0x0f, 0x18}, - {0x50, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); + err += sn9c102_write_reg(cam, 0x00, 0x02); + err += sn9c102_write_reg(cam, 0x00, 0x03); + err += sn9c102_write_reg(cam, 0x1a, 0x04); + err += sn9c102_write_reg(cam, 0x20, 0x05); + err += sn9c102_write_reg(cam, 0x20, 0x06); + err += sn9c102_write_reg(cam, 0x20, 0x07); + err += sn9c102_write_reg(cam, 0x03, 0x10); + err += sn9c102_write_reg(cam, 0x0a, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x10, 0x21); + err += sn9c102_write_reg(cam, 0x20, 0x22); + err += sn9c102_write_reg(cam, 0x30, 0x23); + err += sn9c102_write_reg(cam, 0x40, 0x24); + err += sn9c102_write_reg(cam, 0x50, 0x25); + err += sn9c102_write_reg(cam, 0x60, 0x26); + err += sn9c102_write_reg(cam, 0x70, 0x27); + err += sn9c102_write_reg(cam, 0x80, 0x28); + err += sn9c102_write_reg(cam, 0x90, 0x29); + err += sn9c102_write_reg(cam, 0xa0, 0x2a); + err += sn9c102_write_reg(cam, 0xb0, 0x2b); + err += sn9c102_write_reg(cam, 0xc0, 0x2c); + err += sn9c102_write_reg(cam, 0xd0, 0x2d); + err += sn9c102_write_reg(cam, 0xe0, 0x2e); + err += sn9c102_write_reg(cam, 0xf0, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); err += sn9c102_i2c_write(cam, 0x12, 0x8d); err += sn9c102_i2c_write(cam, 0x12, 0x0d); @@ -88,23 +108,23 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x11, 0x01); err += sn9c102_i2c_write(cam, 0x1b, 0x04); err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); + err += sn9c102_i2c_write(cam, 0x23, 0xee); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0x9a); err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); + err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2f, 0x3d); + err += sn9c102_i2c_write(cam, 0x30, 0x24); + err += sn9c102_i2c_write(cam, 0x32, 0x86); + err += sn9c102_i2c_write(cam, 0x60, 0xa9); + err += sn9c102_i2c_write(cam, 0x61, 0x42); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x88); + err += sn9c102_i2c_write(cam, 0x70, 0x0b); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x74, 0x21); + err += sn9c102_i2c_write(cam, 0x7d, 0xf7); break; default: break; @@ -408,14 +428,15 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, - {0x00, 0x01}, {0x28, 0x17}); - + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); break; case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, - {0x42, 0x01}, {0x28, 0x17}, - {0x44, 0x02}); + err += sn9c102_write_reg(cam, 0x09, 0x01); + err += sn9c102_write_reg(cam, 0x42, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + err += sn9c102_write_reg(cam, 0x44, 0x02); pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); if (err || pid < 0) { /* try a different initialization */ err = sn9c102_write_reg(cam, 0x01, 0x01); diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_ov7660.c b/trunk/drivers/media/video/sn9c102/sn9c102_ov7660.c index c898e948fe8d..d670c24d4435 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_ov7660.c @@ -22,84 +22,160 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor ov7660; + + static int ov7660_init(struct sn9c102_device* cam) { int err = 0; - err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x03, 0x10}, - {0x08, 0x14}, {0x20, 0x17}, - {0x8b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); + err += sn9c102_write_reg(cam, 0x40, 0x02); + err += sn9c102_write_reg(cam, 0x00, 0x03); + err += sn9c102_write_reg(cam, 0x1a, 0x04); + err += sn9c102_write_reg(cam, 0x03, 0x10); + err += sn9c102_write_reg(cam, 0x08, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x8b, 0x18); + err += sn9c102_write_reg(cam, 0x00, 0x19); + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x29, 0x21); + err += sn9c102_write_reg(cam, 0x40, 0x22); + err += sn9c102_write_reg(cam, 0x54, 0x23); + err += sn9c102_write_reg(cam, 0x66, 0x24); + err += sn9c102_write_reg(cam, 0x76, 0x25); + err += sn9c102_write_reg(cam, 0x85, 0x26); + err += sn9c102_write_reg(cam, 0x94, 0x27); + err += sn9c102_write_reg(cam, 0xa1, 0x28); + err += sn9c102_write_reg(cam, 0xae, 0x29); + err += sn9c102_write_reg(cam, 0xbb, 0x2a); + err += sn9c102_write_reg(cam, 0xc7, 0x2b); + err += sn9c102_write_reg(cam, 0xd3, 0x2c); + err += sn9c102_write_reg(cam, 0xde, 0x2d); + err += sn9c102_write_reg(cam, 0xea, 0x2e); + err += sn9c102_write_reg(cam, 0xf4, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); + err += sn9c102_write_reg(cam, 0x00, 0x3F); + err += sn9c102_write_reg(cam, 0xC7, 0x40); + err += sn9c102_write_reg(cam, 0x01, 0x41); + err += sn9c102_write_reg(cam, 0x44, 0x42); + err += sn9c102_write_reg(cam, 0x00, 0x43); + err += sn9c102_write_reg(cam, 0x44, 0x44); + err += sn9c102_write_reg(cam, 0x00, 0x45); + err += sn9c102_write_reg(cam, 0x44, 0x46); + err += sn9c102_write_reg(cam, 0x00, 0x47); + err += sn9c102_write_reg(cam, 0xC7, 0x48); + err += sn9c102_write_reg(cam, 0x01, 0x49); + err += sn9c102_write_reg(cam, 0xC7, 0x4A); + err += sn9c102_write_reg(cam, 0x01, 0x4B); + err += sn9c102_write_reg(cam, 0xC7, 0x4C); + err += sn9c102_write_reg(cam, 0x01, 0x4D); + err += sn9c102_write_reg(cam, 0x44, 0x4E); + err += sn9c102_write_reg(cam, 0x00, 0x4F); + err += sn9c102_write_reg(cam, 0x44, 0x50); + err += sn9c102_write_reg(cam, 0x00, 0x51); + err += sn9c102_write_reg(cam, 0x44, 0x52); + err += sn9c102_write_reg(cam, 0x00, 0x53); + err += sn9c102_write_reg(cam, 0xC7, 0x54); + err += sn9c102_write_reg(cam, 0x01, 0x55); + err += sn9c102_write_reg(cam, 0xC7, 0x56); + err += sn9c102_write_reg(cam, 0x01, 0x57); + err += sn9c102_write_reg(cam, 0xC7, 0x58); + err += sn9c102_write_reg(cam, 0x01, 0x59); + err += sn9c102_write_reg(cam, 0x44, 0x5A); + err += sn9c102_write_reg(cam, 0x00, 0x5B); + err += sn9c102_write_reg(cam, 0x44, 0x5C); + err += sn9c102_write_reg(cam, 0x00, 0x5D); + err += sn9c102_write_reg(cam, 0x44, 0x5E); + err += sn9c102_write_reg(cam, 0x00, 0x5F); + err += sn9c102_write_reg(cam, 0xC7, 0x60); + err += sn9c102_write_reg(cam, 0x01, 0x61); + err += sn9c102_write_reg(cam, 0xC7, 0x62); + err += sn9c102_write_reg(cam, 0x01, 0x63); + err += sn9c102_write_reg(cam, 0xC7, 0x64); + err += sn9c102_write_reg(cam, 0x01, 0x65); + err += sn9c102_write_reg(cam, 0x44, 0x66); + err += sn9c102_write_reg(cam, 0x00, 0x67); + err += sn9c102_write_reg(cam, 0x44, 0x68); + err += sn9c102_write_reg(cam, 0x00, 0x69); + err += sn9c102_write_reg(cam, 0x44, 0x6A); + err += sn9c102_write_reg(cam, 0x00, 0x6B); + err += sn9c102_write_reg(cam, 0xC7, 0x6C); + err += sn9c102_write_reg(cam, 0x01, 0x6D); + err += sn9c102_write_reg(cam, 0xC7, 0x6E); + err += sn9c102_write_reg(cam, 0x01, 0x6F); + err += sn9c102_write_reg(cam, 0xC7, 0x70); + err += sn9c102_write_reg(cam, 0x01, 0x71); + err += sn9c102_write_reg(cam, 0x44, 0x72); + err += sn9c102_write_reg(cam, 0x00, 0x73); + err += sn9c102_write_reg(cam, 0x44, 0x74); + err += sn9c102_write_reg(cam, 0x00, 0x75); + err += sn9c102_write_reg(cam, 0x44, 0x76); + err += sn9c102_write_reg(cam, 0x00, 0x77); + err += sn9c102_write_reg(cam, 0xC7, 0x78); + err += sn9c102_write_reg(cam, 0x01, 0x79); + err += sn9c102_write_reg(cam, 0xC7, 0x7A); + err += sn9c102_write_reg(cam, 0x01, 0x7B); + err += sn9c102_write_reg(cam, 0xC7, 0x7C); + err += sn9c102_write_reg(cam, 0x01, 0x7D); + err += sn9c102_write_reg(cam, 0x44, 0x7E); + err += sn9c102_write_reg(cam, 0x00, 0x7F); + err += sn9c102_write_reg(cam, 0x14, 0x84); + err += sn9c102_write_reg(cam, 0x00, 0x85); + err += sn9c102_write_reg(cam, 0x27, 0x86); + err += sn9c102_write_reg(cam, 0x00, 0x87); + err += sn9c102_write_reg(cam, 0x07, 0x88); + err += sn9c102_write_reg(cam, 0x00, 0x89); + err += sn9c102_write_reg(cam, 0xEC, 0x8A); + err += sn9c102_write_reg(cam, 0x0f, 0x8B); + err += sn9c102_write_reg(cam, 0xD8, 0x8C); + err += sn9c102_write_reg(cam, 0x0f, 0x8D); + err += sn9c102_write_reg(cam, 0x3D, 0x8E); + err += sn9c102_write_reg(cam, 0x00, 0x8F); + err += sn9c102_write_reg(cam, 0x3D, 0x90); + err += sn9c102_write_reg(cam, 0x00, 0x91); + err += sn9c102_write_reg(cam, 0xCD, 0x92); + err += sn9c102_write_reg(cam, 0x0f, 0x93); + err += sn9c102_write_reg(cam, 0xf7, 0x94); + err += sn9c102_write_reg(cam, 0x0f, 0x95); + err += sn9c102_write_reg(cam, 0x0C, 0x96); + err += sn9c102_write_reg(cam, 0x00, 0x97); + err += sn9c102_write_reg(cam, 0x00, 0x98); + err += sn9c102_write_reg(cam, 0x66, 0x99); + err += sn9c102_write_reg(cam, 0x05, 0x9A); + err += sn9c102_write_reg(cam, 0x00, 0x9B); + err += sn9c102_write_reg(cam, 0x04, 0x9C); + err += sn9c102_write_reg(cam, 0x00, 0x9D); + err += sn9c102_write_reg(cam, 0x08, 0x9E); + err += sn9c102_write_reg(cam, 0x00, 0x9F); + err += sn9c102_write_reg(cam, 0x2D, 0xC0); + err += sn9c102_write_reg(cam, 0x2D, 0xC1); + err += sn9c102_write_reg(cam, 0x3A, 0xC2); + err += sn9c102_write_reg(cam, 0x05, 0xC3); + err += sn9c102_write_reg(cam, 0x04, 0xC4); + err += sn9c102_write_reg(cam, 0x3F, 0xC5); + err += sn9c102_write_reg(cam, 0x00, 0xC6); + err += sn9c102_write_reg(cam, 0x00, 0xC7); + err += sn9c102_write_reg(cam, 0x50, 0xC8); + err += sn9c102_write_reg(cam, 0x3C, 0xC9); + err += sn9c102_write_reg(cam, 0x28, 0xCA); + err += sn9c102_write_reg(cam, 0xD8, 0xCB); + err += sn9c102_write_reg(cam, 0x14, 0xCC); + err += sn9c102_write_reg(cam, 0xEC, 0xCD); + err += sn9c102_write_reg(cam, 0x32, 0xCE); + err += sn9c102_write_reg(cam, 0xDD, 0xCF); + err += sn9c102_write_reg(cam, 0x32, 0xD0); + err += sn9c102_write_reg(cam, 0xDD, 0xD1); + err += sn9c102_write_reg(cam, 0x6A, 0xD2); + err += sn9c102_write_reg(cam, 0x50, 0xD3); + err += sn9c102_write_reg(cam, 0x00, 0xD4); + err += sn9c102_write_reg(cam, 0x00, 0xD5); + err += sn9c102_write_reg(cam, 0x00, 0xD6); err += sn9c102_i2c_write(cam, 0x12, 0x80); err += sn9c102_i2c_write(cam, 0x11, 0x09); @@ -496,11 +572,13 @@ static struct sn9c102_sensor ov7660 = { int sn9c102_probe_ov7660(struct sn9c102_device* cam) { - int pid, ver, err; + int pid, ver, err = 0; - err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); + err += sn9c102_write_reg(cam, 0x01, 0xf1); + err += sn9c102_write_reg(cam, 0x00, 0xf1); + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_pas106b.c b/trunk/drivers/media/video/sn9c102/sn9c102_pas106b.c index 67151964801f..8d79a5fae5de 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_pas106b.c @@ -23,13 +23,19 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor pas106b; + + static int pas106b_init(struct sn9c102_device* cam) { int err = 0; - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x20, 0x19}, {0x09, 0x18}); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); err += sn9c102_i2c_write(cam, 0x02, 0x0c); err += sn9c102_i2c_write(cam, 0x05, 0x5a); @@ -166,7 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor pas106b = { .name = "PAS106B", .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, @@ -273,17 +279,16 @@ static struct sn9c102_sensor pas106b = { int sn9c102_probe_pas106b(struct sn9c102_device* cam) { - int r0 = 0, r1 = 0, err; + int r0 = 0, r1 = 0, err = 0; unsigned int pid = 0; /* Minimal initialization to enable the I2C communication NOTE: do NOT change the values! */ - err = sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* sensor power down */ - {0x00, 0x01}, /* sensor power on */ - {0x28, 0x17});/* sensor clock 24 MHz */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ + err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ if (err) return -EIO; diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index c1b8d6b63b47..7894f01b56e8 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_pas202bcb.c @@ -28,6 +28,9 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor pas202bcb; + + static int pas202bcb_init(struct sn9c102_device* cam) { int err = 0; @@ -35,29 +38,47 @@ static int pas202bcb_init(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, - {0x00, 0x11}, {0x00, 0x14}, - {0x20, 0x17}, {0x30, 0x19}, - {0x09, 0x18}); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x30, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); break; case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x20, 0x05}, {0x20, 0x06}, - {0x20, 0x07}, {0x00, 0x10}, - {0x00, 0x11}, {0x00, 0x14}, - {0x20, 0x17}, {0x30, 0x19}, - {0x09, 0x18}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); + err += sn9c102_write_reg(cam, 0x00, 0x02); + err += sn9c102_write_reg(cam, 0x00, 0x03); + err += sn9c102_write_reg(cam, 0x1a, 0x04); + err += sn9c102_write_reg(cam, 0x20, 0x05); + err += sn9c102_write_reg(cam, 0x20, 0x06); + err += sn9c102_write_reg(cam, 0x20, 0x07); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x30, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + err += sn9c102_write_reg(cam, 0x02, 0x1c); + err += sn9c102_write_reg(cam, 0x03, 0x1d); + err += sn9c102_write_reg(cam, 0x0f, 0x1e); + err += sn9c102_write_reg(cam, 0x0c, 0x1f); + err += sn9c102_write_reg(cam, 0x00, 0x20); + err += sn9c102_write_reg(cam, 0x10, 0x21); + err += sn9c102_write_reg(cam, 0x20, 0x22); + err += sn9c102_write_reg(cam, 0x30, 0x23); + err += sn9c102_write_reg(cam, 0x40, 0x24); + err += sn9c102_write_reg(cam, 0x50, 0x25); + err += sn9c102_write_reg(cam, 0x60, 0x26); + err += sn9c102_write_reg(cam, 0x70, 0x27); + err += sn9c102_write_reg(cam, 0x80, 0x28); + err += sn9c102_write_reg(cam, 0x90, 0x29); + err += sn9c102_write_reg(cam, 0xa0, 0x2a); + err += sn9c102_write_reg(cam, 0xb0, 0x2b); + err += sn9c102_write_reg(cam, 0xc0, 0x2c); + err += sn9c102_write_reg(cam, 0xd0, 0x2d); + err += sn9c102_write_reg(cam, 0xe0, 0x2e); + err += sn9c102_write_reg(cam, 0xf0, 0x2f); + err += sn9c102_write_reg(cam, 0xff, 0x30); break; default: break; @@ -307,15 +328,15 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) switch (sn9c102_get_bridge(cam)) { case BRIDGE_SN9C101: case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* power down */ - {0x40, 0x01}, /* power on */ - {0x28, 0x17});/* clock 24 MHz */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */ + err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */ break; case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, - {0x44, 0x01}, {0x44, 0x02}, - {0x29, 0x17}); + err += sn9c102_write_reg(cam, 0x09, 0x01); + err += sn9c102_write_reg(cam, 0x44, 0x01); + err += sn9c102_write_reg(cam, 0x44, 0x02); + err += sn9c102_write_reg(cam, 0x29, 0x17); break; default: break; diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_sensor.h b/trunk/drivers/media/video/sn9c102/sn9c102_sensor.h index 1bbf64c897a2..05f2942639c3 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/trunk/drivers/media/video/sn9c102/sn9c102_sensor.h @@ -114,17 +114,9 @@ extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); /* I/O on registers in the bridge. Could be used by the sensor methods too */ -extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); +extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); -extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], - int count); -/* - * Write multiple registers with constant values. For example: - * sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); - */ -#define sn9c102_write_const_regs(device, data...) \ - ({ const static u8 _data[][2] = {data}; \ - sn9c102_write_regs(device, _data, ARRAY_SIZE(_data)); }) +extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); /*****************************************************************************/ diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/trunk/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index 0e7ec8662c70..90023ad63adc 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c @@ -22,14 +22,21 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor tas5110c1b; + + static int tas5110c1b_init(struct sn9c102_device* cam) { int err = 0; - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, - {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x44, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x0a, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x06, 0x18); + err += sn9c102_write_reg(cam, 0xfb, 0x19); err += sn9c102_i2c_write(cam, 0xc0, 0x80); @@ -91,7 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor tas5110c1b = { .name = "TAS5110C1B", .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, .sysfs_ops = SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, @@ -139,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) const struct usb_device_id tas5110c1b_id_table[] = { { USB_DEVICE(0x0c45, 0x6001), }, { USB_DEVICE(0x0c45, 0x6005), }, + { USB_DEVICE(0x0c45, 0x6007), }, { USB_DEVICE(0x0c45, 0x60ab), }, { } }; diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/trunk/drivers/media/video/sn9c102/sn9c102_tas5110d.c deleted file mode 100644 index 83a39e8b5e71..000000000000 --- a/trunk/drivers/media/video/sn9c102/sn9c102_tas5110d.c +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static int tas5110d_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); - - err += sn9c102_i2c_write(cam, 0x9a, 0xca); - - return err; -} - - -static int tas5110d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - - return err; -} - - -static int tas5110d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x3b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static struct sn9c102_sensor tas5110d = { - .name = "TAS5110D", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x61, - .init = &tas5110d_init, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110d_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110d_set_pix_format -}; - - -int sn9c102_probe_tas5110d(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110d_id_table[] = { - { USB_DEVICE(0x0c45, 0x6007), }, - { } - }; - - if (!sn9c102_match_id(cam, tas5110d_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110d); - - return 0; -} diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/trunk/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index 50406503fc40..cb1b318bc1ff 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c @@ -22,14 +22,21 @@ #include "sn9c102_sensor.h" +static struct sn9c102_sensor tas5130d1b; + + static int tas5130d1b_init(struct sn9c102_device* cam) { - int err; + int err = 0; - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, - {0x04, 0x01}, {0x01, 0x10}, - {0x00, 0x11}, {0x00, 0x14}, - {0x60, 0x17}, {0x07, 0x18}); + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x04, 0x01); + err += sn9c102_write_reg(cam, 0x01, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x07, 0x18); return err; } @@ -92,7 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, static struct sn9c102_sensor tas5130d1b = { .name = "TAS5130D1B", .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, .sysfs_ops = SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, diff --git a/trunk/drivers/media/video/tda7432.c b/trunk/drivers/media/video/tda7432.c index 43225802a551..d1ccc064206f 100644 --- a/trunk/drivers/media/video/tda7432.c +++ b/trunk/drivers/media/video/tda7432.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/media/video/tda8290.c b/trunk/drivers/media/video/tda8290.c index 1a1bef0e9c3d..027c8a074dfe 100644 --- a/trunk/drivers/media/video/tda8290.c +++ b/trunk/drivers/media/video/tda8290.c @@ -192,52 +192,14 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct i2c_client *c, int high) -{ - struct tuner *t = i2c_get_clientdata(c); - unsigned char buf[] = {0x22, 0x01}; - int arg; - struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - if (t->config) { - if (high) - tuner_dbg("setting LNA to high gain\n"); - else - tuner_dbg("setting LNA to low gain\n"); - } - switch (t->config) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync on */ - if (t->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 1, arg); - buf[1] = high ? 0 : 1; - if (t->config == 2) - buf[1] = high ? 1 : 0; - i2c_transfer(c->adapter, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 0, high); - break; - } -} - static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) { - unsigned char tuner_reg[11]; + unsigned char tuner_reg[14]; + unsigned char reg2[2]; u32 N; int i; struct tuner *t = i2c_get_clientdata(c); - struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg}; - - tda827xa_lna_gain( c, 1); - msleep(10); + struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0}; if (t->mode == V4L2_TUNER_RADIO) freq = freq / 1000; @@ -260,58 +222,48 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + tda827xa_analog[i].sbs; tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; + tuner_reg[7] = 0x0c; tuner_reg[8] = 4; tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - i2c_transfer(c->adapter, &msg, 1); + tuner_reg[10] = 0xff; + tuner_reg[11] = 0xe0; + tuner_reg[12] = 0; + tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1); - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1); - msg.len = 5; + msg.buf = tuner_reg; + msg.len = 14; i2c_transfer(c->adapter, &msg, 1); - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; + msg.buf= reg2; msg.len = 2; + reg2[0] = 0x60; + reg2[1] = 0x3c; i2c_transfer(c->adapter, &msg, 1); - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + reg2[0] = 0xa0; + reg2[1] = 0xc0; i2c_transfer(c->adapter, &msg, 1); - msg.flags = I2C_M_RD; - i2c_transfer(c->adapter, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain( c, 0); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; + msleep(2); + reg2[0] = 0x30; + reg2[1] = 0x10 + tda827xa_analog[i].scr; i2c_transfer(c->adapter, &msg, 1); - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + msleep(550); + reg2[0] = 0x50; + reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); i2c_transfer(c->adapter, &msg, 1); - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; + reg2[0] = 0x80; + reg2[1] = 0x28; i2c_transfer(c->adapter, &msg, 1); - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; + reg2[0] = 0xb0; + reg2[1] = 0x01; i2c_transfer(c->adapter, &msg, 1); - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1); + reg2[0] = 0xc0; + reg2[1] = 0x19 + (t->tda827x_lpsel << 1); i2c_transfer(c->adapter, &msg, 1); } @@ -367,9 +319,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) unsigned char addr_pll_stat = 0x1b; unsigned char adc_sat, agc_stat, pll_stat; - int i; - tuner_dbg("tda827xa config is 0x%02x\n", t->config); i2c_master_send(c, easy_mode, 2); i2c_master_send(c, agc_out_on, 2); i2c_master_send(c, soft_reset, 2); @@ -390,22 +340,17 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tda827xa_tune(c, ifc, freq); else tda827x_tune(c, ifc, freq); - for (i = 0; i < 3; i++) { - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); - if (pll_stat & 0x80) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); - break; - } else { - tuner_dbg("tda8290 not locked, no signal?\n"); - msleep(100); - } - } /* adjust headroom resp. gain */ + i2c_master_send(c, &addr_adc_sat, 1); + i2c_master_recv(c, &adc_sat, 1); + i2c_master_send(c, &addr_agc_stat, 1); + i2c_master_recv(c, &agc_stat, 1); + i2c_master_send(c, &addr_pll_stat, 1); + i2c_master_recv(c, &pll_stat, 1); + if (pll_stat & 0x80) + tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); + else + tuner_dbg("tda8290 not locked, no signal?\n"); if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", agc_stat, adc_sat, pll_stat & 0x80); @@ -462,6 +407,7 @@ static void set_audio(struct tuner *t) char* mode; t->tda827x_lpsel = 0; + mode = "xx"; if (t->std & V4L2_STD_MN) { t->sgIF = 92; t->tda8290_easy_mode = 0x01; @@ -491,12 +437,8 @@ static void set_audio(struct tuner *t) t->sgIF = 20; t->tda8290_easy_mode = 0x40; mode = "LC"; - } else { - t->sgIF = 124; - t->tda8290_easy_mode = 0x10; - mode = "xx"; } - tuner_dbg("setting tda8290 to system %s\n", mode); + tuner_dbg("setting tda8290 to system %s\n", mode); } static void set_tv_freq(struct i2c_client *c, unsigned int freq) @@ -545,16 +487,11 @@ static void standby(struct i2c_client *c) static void tda8290_init_if(struct i2c_client *c) { - struct tuner *t = i2c_get_clientdata(c); unsigned char set_VS[] = { 0x30, 0x6F }; - unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((t->config == 1) || (t->config == 2)) - i2c_master_send(c, set_GP00_CF, 2); - else - i2c_master_send(c, set_GP01_CF, 2); i2c_master_send(c, set_VS, 2); + i2c_master_send(c, set_GP01_CF, 2); } static void tda8290_init_tuner(struct i2c_client *c) @@ -639,7 +576,6 @@ int tda8290_init(struct i2c_client *c) t->has_signal = has_signal; t->standby = standby; t->tda827x_lpsel = 0; - t->mode = V4L2_TUNER_ANALOG_TV; tda8290_init_tuner(c); tda8290_init_if(c); diff --git a/trunk/drivers/media/video/tda9875.c b/trunk/drivers/media/video/tda9875.c index d11044170872..00f0e8b6e03b 100644 --- a/trunk/drivers/media/video/tda9875.c +++ b/trunk/drivers/media/video/tda9875.c @@ -27,6 +27,7 @@ #include #include #include +#include #include diff --git a/trunk/drivers/media/video/tuner-core.c b/trunk/drivers/media/video/tuner-core.c index 505591a7abe9..15dbc6bf42a7 100644 --- a/trunk/drivers/media/video/tuner-core.c +++ b/trunk/drivers/media/video/tuner-core.c @@ -144,8 +144,7 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } static void set_type(struct i2c_client *c, unsigned int type, - unsigned int new_mode_mask, unsigned int new_config, - int (*tuner_callback) (void *dev, int command,int arg)) + unsigned int new_mode_mask) { struct tuner *t = i2c_get_clientdata(c); unsigned char buffer[4]; @@ -160,20 +159,15 @@ static void set_type(struct i2c_client *c, unsigned int type, return; } - t->type = type; - t->config = new_config; - if (tuner_callback != NULL) { - tuner_dbg("defining GPIO callback\n"); - t->tuner_callback = tuner_callback; - } - /* This code detects calls by card attach_inform */ if (NULL == t->i2c.dev.driver) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); + t->type=type; return; } + t->type = type; switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -240,11 +234,10 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) tuner_dbg("set addr for type %i\n", t->type); - if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && - (t->mode_mask & tun_setup->mode_mask))) || - (tun_setup->addr == c->addr)) { - set_type(c, tun_setup->type, tun_setup->mode_mask, - tun_setup->config, tun_setup->tuner_callback); + if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET && + (t->mode_mask & tun_setup->mode_mask)) || + tun_setup->addr == c->addr)) { + set_type(c, tun_setup->type, tun_setup->mode_mask); } } @@ -503,7 +496,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) register_client: tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); i2c_attach_client (&t->i2c); - set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); + set_type (&t->i2c,t->type, t->mode_mask); return 0; } @@ -583,11 +576,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { /* --- configuration --- */ case TUNER_SET_TYPE_ADDR: - tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", + tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", ((struct tuner_setup *)arg)->type, ((struct tuner_setup *)arg)->addr, - ((struct tuner_setup *)arg)->mode_mask, - ((struct tuner_setup *)arg)->config); + ((struct tuner_setup *)arg)->mode_mask); set_addr(client, (struct tuner_setup *)arg); break; diff --git a/trunk/drivers/media/video/tvaudio.c b/trunk/drivers/media/video/tvaudio.c index a2da5d2affff..d506dfaa45a9 100644 --- a/trunk/drivers/media/video/tvaudio.c +++ b/trunk/drivers/media/video/tvaudio.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include #include -#include #include @@ -1775,9 +1775,6 @@ static int chip_command(struct i2c_client *client, /* the thread will call checkmode() later */ } break; - - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0); } return 0; } diff --git a/trunk/drivers/media/video/tveeprom.c b/trunk/drivers/media/video/tveeprom.c index a1136da74ba8..4e7c1fa668d3 100644 --- a/trunk/drivers/media/video/tveeprom.c +++ b/trunk/drivers/media/video/tveeprom.c @@ -163,7 +163,7 @@ hauppauge_tuner[] = /* 60-69 */ { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, { TUNER_ABSENT, "LG M001D MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, + { TUNER_ABSENT, "LG S701D MK3"}, { TUNER_ABSENT, "LG M701D MK3"}, { TUNER_ABSENT, "Temic 4146FM5"}, { TUNER_ABSENT, "Temic 4136FY5"}, @@ -229,36 +229,6 @@ hauppauge_tuner[] = /* 120-129 */ { TUNER_ABSENT, "Xceive XC3028"}, { TUNER_ABSENT, "Philips FQ1216LME MK5"}, - { TUNER_ABSENT, "Philips FQD1216LME"}, - { TUNER_ABSENT, "Conexant CX24118A"}, - { TUNER_ABSENT, "TCL DMF11WIP"}, - { TUNER_ABSENT, "TCL MFNM05_4H_E"}, - { TUNER_ABSENT, "TCL MNM05_4H_E"}, - { TUNER_ABSENT, "TCL MPE05_2H_E"}, - { TUNER_ABSENT, "TCL MQNM05_4_U"}, - { TUNER_ABSENT, "TCL M2523_5NH_E"}, - /* 130-139 */ - { TUNER_ABSENT, "TCL M2523_3DBH_E"}, - { TUNER_ABSENT, "TCL M2523_3DIH_E"}, - { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_ABSENT, "Philips FMD1216MEX"}, - { TUNER_ABSENT, "Philips FRH2036B"}, - { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, - { TUNER_ABSENT, "MaxLinear MXL5005"}, - { TUNER_ABSENT, "MaxLinear MXL5003"}, - { TUNER_ABSENT, "Xceive XC2028"}, - { TUNER_ABSENT, "Microtune MT2131"}, - /* 140-149 */ - { TUNER_ABSENT, "Philips 8275A_8295"}, - { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, - { TUNER_ABSENT, "Microtune MT2266"}, - { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, - { TUNER_ABSENT, "LG TAPQ_H702F"}, - { TUNER_ABSENT, "TCL M09WPP_4N_E"}, - { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_ABSENT, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC @@ -310,16 +280,11 @@ audioIC[] = {AUDIO_CHIP_INTERNAL, "CX883"}, {AUDIO_CHIP_INTERNAL, "CX882"}, {AUDIO_CHIP_INTERNAL, "CX25840"}, - /* 35-39 */ + /* 35-38 */ {AUDIO_CHIP_INTERNAL, "CX25841"}, {AUDIO_CHIP_INTERNAL, "CX25842"}, {AUDIO_CHIP_INTERNAL, "CX25843"}, {AUDIO_CHIP_INTERNAL, "CX23418"}, - {AUDIO_CHIP_INTERNAL, "CX23885"}, - /* 40-42 */ - {AUDIO_CHIP_INTERNAL, "CX23888"}, - {AUDIO_CHIP_INTERNAL, "SAA7131"}, - {AUDIO_CHIP_INTERNAL, "CX23887"}, }; /* This list is supplied by Hauppauge. Thanks! */ @@ -336,10 +301,8 @@ static const char *decoderIC[] = { "CX880", "CX881", "CX883", "SAA7111", "SAA7113", /* 25-29 */ "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", - /* 30-34 */ - "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", - /* 35-37 */ - "SAA7131", "CX25837", "CX23887" + /* 30-31 */ + "CX25843", "CX23418", }; static int hasRadioTuner(int tunerType) diff --git a/trunk/drivers/media/video/upd64031a.c b/trunk/drivers/media/video/upd64031a.c index 0b2a961efd22..28d1133a3b7a 100644 --- a/trunk/drivers/media/video/upd64031a.c +++ b/trunk/drivers/media/video/upd64031a.c @@ -27,7 +27,6 @@ #include #include #include -#include #include // --------------------- read registers functions define ----------------------- @@ -180,9 +179,6 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * } #endif - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); - default: break; } diff --git a/trunk/drivers/media/video/upd64083.c b/trunk/drivers/media/video/upd64083.c index 401bd21f46eb..fe38224150d8 100644 --- a/trunk/drivers/media/video/upd64083.c +++ b/trunk/drivers/media/video/upd64083.c @@ -26,7 +26,6 @@ #include #include #include -#include #include MODULE_DESCRIPTION("uPD64083 driver"); @@ -156,10 +155,6 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a break; } #endif - - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); - default: break; } diff --git a/trunk/drivers/media/video/usbvideo/usbvideo.c b/trunk/drivers/media/video/usbvideo/usbvideo.c index 687f026753b2..d34d8c8b7376 100644 --- a/trunk/drivers/media/video/usbvideo/usbvideo.c +++ b/trunk/drivers/media/video/usbvideo/usbvideo.c @@ -628,21 +628,24 @@ EXPORT_SYMBOL(usbvideo_HexDump); /* ******************************************************************** */ /* XXX: this piece of crap really wants some error handling.. */ -static int usbvideo_ClientIncModCount(struct uvd *uvd) +static void usbvideo_ClientIncModCount(struct uvd *uvd) { if (uvd == NULL) { err("%s: uvd == NULL", __FUNCTION__); - return -EINVAL; + return; } if (uvd->handle == NULL) { err("%s: uvd->handle == NULL", __FUNCTION__); - return -EINVAL; + return; + } + if (uvd->handle->md_module == NULL) { + err("%s: uvd->handle->md_module == NULL", __FUNCTION__); + return; } if (!try_module_get(uvd->handle->md_module)) { err("%s: try_module_get() == 0", __FUNCTION__); - return -ENODEV; + return; } - return 0; } static void usbvideo_ClientDecModCount(struct uvd *uvd) @@ -709,6 +712,8 @@ int usbvideo_register( cams->num_cameras = num_cams; cams->cam = (struct uvd *) &cams[1]; cams->md_module = md; + if (cams->md_module == NULL) + warn("%s: module == NULL!", __FUNCTION__); mutex_init(&cams->lock); /* to 1 == available */ for (i = 0; i < num_cams; i++) { @@ -1114,8 +1119,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) if (uvd->debug > 1) info("%s($%p)", __FUNCTION__, dev); - if (0 < usbvideo_ClientIncModCount(uvd)) - return -ENODEV; + usbvideo_ClientIncModCount(uvd); mutex_lock(&uvd->lock); if (uvd->user) { diff --git a/trunk/drivers/media/video/usbvision/usbvision-cards.c b/trunk/drivers/media/video/usbvision/usbvision-cards.c index 51ab265d566a..a40e5838515b 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-cards.c +++ b/trunk/drivers/media/video/usbvision/usbvision-cards.c @@ -1,6 +1,6 @@ /* - * usbvision-cards.c - * usbvision cards definition file + * USBVISION.H + * usbvision header file * * Copyright (c) 1999-2005 Joerg Heckenbach * @@ -24,1063 +24,133 @@ #include +#include #include #include #include "usbvision.h" -#include "usbvision-cards.h" /* Supported Devices: A table for usbvision.c*/ struct usbvision_device_data_st usbvision_device_data[] = { - [XANBOO] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 4, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Xanboo", - }, - [BELKIN_VIDEOBUS_II] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Belkin USB VideoBus II Adapter", - }, - [BELKIN_VIDEOBUS] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Belkin Components USB VideoBus", - }, - [BELKIN_USB_VIDEOBUS_II] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Belkin USB VideoBus II", - }, - [ECHOFX_INTERVIEW_LITE] = { - .Interface = 0, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = -1, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "echoFX InterView Lite", - }, - [USBGEAR_USBG_V1] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "USBGear USBG-V1 resp. HAMA USB", - }, - [D_LINK_V100] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 4, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "D-Link V100", - }, - [X10_USB_CAMERA] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "X10 USB Camera", - }, - [HPG_WINTV_LIVE_PAL_BG] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = -1, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Live (PAL B/G)", - }, - [HPG_WINTV_LIVE_PRO_NTSC_MN] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Live Pro (NTSC M/N)", - }, - [ZORAN_PMD_NOGATECH] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 2, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan", - }, - [NOGATECH_USB_TV_NTSC_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = 20, - .ModelString = "Nogatech USB-TV (NTSC) FM", - }, - [PNY_USB_TV_NTSC_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = 20, - .ModelString = "PNY USB-TV (NTSC) FM", - }, - [PV_PLAYTV_USB_PRO_PAL_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "PixelView PlayTv-USB PRO (PAL) FM", - }, - [ZT_721] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "ZTV ZT-721 2.4GHz USB A/V Receiver", - }, - [HPG_WINTV_NTSC_MN] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = 20, - .ModelString = "Hauppauge WinTV USB (NTSC M/N)", - }, - [HPG_WINTV_PAL_BG] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL B/G)", - }, - [HPG_WINTV_PAL_I] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL I)", - }, - [HPG_WINTV_PAL_SECAM_L] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)", - }, - [HPG_WINTV_PAL_D_K] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL D/K)", - }, - [HPG_WINTV_NTSC_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (NTSC FM)", - }, - [HPG_WINTV_PAL_BG_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL B/G FM)", - }, - [HPG_WINTV_PAL_I_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL I FM)", - }, - [HPG_WINTV_PAL_D_K_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTV USB (PAL D/K FM)", - }, - [HPG_WINTV_PRO_NTSC_MN] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_MICROTUNE_4049FM5, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N)", - }, - [HPG_WINTV_PRO_NTSC_MN_V2] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_MICROTUNE_4049FM5, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V2", - }, - [HPG_WINTV_PRO_PAL] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_FM1216ME_MK3, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)", - }, - [HPG_WINTV_PRO_NTSC_MN_V3] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V3", - }, - [HPG_WINTV_PRO_PAL_BG] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL B/G)", - }, - [HPG_WINTV_PRO_PAL_I] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL I)", - }, - [HPG_WINTV_PRO_PAL_SECAM_L] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM L)", - }, - [HPG_WINTV_PRO_PAL_D_K] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL D/K)", - }, - [HPG_WINTV_PRO_PAL_SECAM] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)", - }, - [HPG_WINTV_PRO_PAL_SECAM_V2] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2", - }, - [HPG_WINTV_PRO_PAL_BG_V2] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_ALPS_TSBE1_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL B/G) V2", - }, - [HPG_WINTV_PRO_PAL_BG_D_K] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_ALPS_TSBE1_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL B/G,D/K)", - }, - [HPG_WINTV_PRO_PAL_I_D_K] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL I,D/K)", - }, - [HPG_WINTV_PRO_NTSC_MN_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM)", - }, - [HPG_WINTV_PRO_PAL_BG_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL B/G FM)", - }, - [HPG_WINTV_PRO_PAL_I_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL I FM)", - }, - [HPG_WINTV_PRO_PAL_D_K_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL D/K FM)", - }, - [HPG_WINTV_PRO_TEMIC_PAL_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_MICROTUNE_4049FM5, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)", - }, - [HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_MICROTUNE_4049FM5, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)", - }, - [HPG_WINTV_PRO_PAL_FM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_FM1216ME_MK3, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)", - }, - [HPG_WINTV_PRO_NTSC_MN_FM_V2] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2", - }, - [CAMTEL_TVB330] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = 5, - .Y_Offset = 5, - .ModelString = "Camtel Technology USB TV Genie Pro FM Model TVB330", - }, - [DIGITAL_VIDEO_CREATOR_I] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Digital Video Creator I", - }, - [GLOBAL_VILLAGE_GV_007_NTSC] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 82, - .Y_Offset = 20, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Global Village GV-007 (NTSC)", - }, - [DAZZLE_DVC_50_REV_1_NTSC] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)", - }, - [DAZZLE_DVC_80_REV_1_PAL] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)", - }, - [DAZZLE_DVC_90_REV_1_SECAM] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 0, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)", - }, - [ESKAPE_LABS_MYTV2GO] = { - .Interface = 0, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_FM1216ME_MK3, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Eskape Labs MyTV2Go", - }, - [PINNA_PCTV_USB_PAL] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 0, - .Tuner = 1, - .TunerType = TUNER_TEMIC_4066FY5_PAL_I, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Pinnacle Studio PCTV USB (PAL)", - }, - [PINNA_PCTV_USB_SECAM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_SECAM, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Pinnacle Studio PCTV USB (SECAM)", - }, - [PINNA_PCTV_USB_PAL_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = 128, - .Y_Offset = 23, - .ModelString = "Pinnacle Studio PCTV USB (PAL) FM", - }, - [MIRO_PCTV_USB] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Miro PCTV USB", - }, - [PINNA_PCTV_USB_NTSC_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", - }, - [PINNA_PCTV_USB_PAL_FM_V2] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_TEMIC_4009FR5_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V2", - }, - [PINNA_PCTV_USB_NTSC_FM_V2] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_TEMIC_4039FR5_NTSC, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V2", - }, - [PINNA_PCTV_USB_PAL_FM_V3] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_TEMIC_4009FR5_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V3", - }, - [PINNA_LINX_VD_IN_CAB_NTSC] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle Studio Linx Video input cable (NTSC)", - }, - [PINNA_LINX_VD_IN_CAB_PAL] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 0, - .TunerType = 0, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle Studio Linx Video input cable (PAL)", - }, - [PINNA_PCTV_BUNGEE_PAL_FM] = { - .Interface = -1, - .Codec = CODEC_SAA7113, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_PAL, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_TEMIC_4009FR5_PAL, - .X_Offset = 0, - .Y_Offset = 3, - .Dvi_yuv_override = 1, - .Dvi_yuv = 7, - .ModelString = "Pinnacle PCTV Bungee USB (PAL) FM", - }, - [HPG_WINTV] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 0, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Hauppauge WinTv-USB", - }, + {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, + {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, + {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, + {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, + {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, + {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, + {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, + {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, + {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, + {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, + {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, + {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, + {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, + {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, + {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, + {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, + {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, + {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, + {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, + {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, + {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, + {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, + {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, + {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, + {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, + {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, + {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, + {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, + {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, + {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, + {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, + {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, + {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, + {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, + {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, + {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, + {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, + {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, + {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, + {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, + {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, + {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, + {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, + {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, + {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, + {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, + {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, + {0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {} /* Terminating entry */ }; -const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data); /* Supported Devices */ struct usb_device_id usbvision_table [] = { - { USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO }, - { USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II }, - { USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS }, - { USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II }, - { USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE }, - { USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 }, - { USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 }, - { USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA }, - { USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG }, - { USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN }, - { USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH }, - { USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM }, - { USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 }, - { USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN }, - { USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG }, - { USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I }, - { USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L }, - { USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K }, - { USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM }, - { USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM }, - { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, - { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, - { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, - { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, - { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, - { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, - { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, - { USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K }, - { USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM }, - { USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 }, - { USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 }, - { USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K }, - { USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K }, - { USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM }, - { USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM }, - { USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM }, - { USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM }, - { USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM }, - { USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 }, - { USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 }, - { USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I }, - { USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC }, - { USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC }, - { USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL }, - { USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM }, - { USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO }, - { USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL }, - { USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM }, - { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, - { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, - { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, - { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, - { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, - { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, - { USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC }, - { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL }, - { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM }, - { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV }, + { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ + { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ + { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ + { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ + { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ + { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ + { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ + { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ + { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ + { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ + { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ + { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ + { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ + { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ + { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ + { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ + { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ + { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ + { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ + { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ + { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ + { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ + { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ + { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ + { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ + { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ + { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ + { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ + { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ + { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ + { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ + { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ + { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ + { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ + { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ + { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ + { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ + { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ + { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ + { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ + { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ + { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ + { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ + { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ + { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ + { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ + { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ + { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ + + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usbvision_table); diff --git a/trunk/drivers/media/video/usbvision/usbvision-cards.h b/trunk/drivers/media/video/usbvision/usbvision-cards.h deleted file mode 100644 index 512c5cee4145..000000000000 --- a/trunk/drivers/media/video/usbvision/usbvision-cards.h +++ /dev/null @@ -1,66 +0,0 @@ -#define XANBOO 0 -#define BELKIN_VIDEOBUS_II 1 -#define BELKIN_VIDEOBUS 2 -#define BELKIN_USB_VIDEOBUS_II 3 -#define ECHOFX_INTERVIEW_LITE 4 -#define USBGEAR_USBG_V1 5 -#define D_LINK_V100 6 -#define X10_USB_CAMERA 7 -#define HPG_WINTV_LIVE_PAL_BG 8 -#define HPG_WINTV_LIVE_PRO_NTSC_MN 9 -#define ZORAN_PMD_NOGATECH 10 -#define NOGATECH_USB_TV_NTSC_FM 11 -#define PNY_USB_TV_NTSC_FM 12 -#define PV_PLAYTV_USB_PRO_PAL_FM 13 -#define ZT_721 14 -#define HPG_WINTV_NTSC_MN 15 -#define HPG_WINTV_PAL_BG 16 -#define HPG_WINTV_PAL_I 17 -#define HPG_WINTV_PAL_SECAM_L 18 -#define HPG_WINTV_PAL_D_K 19 -#define HPG_WINTV_NTSC_FM 20 -#define HPG_WINTV_PAL_BG_FM 21 -#define HPG_WINTV_PAL_I_FM 22 -#define HPG_WINTV_PAL_D_K_FM 23 -#define HPG_WINTV_PRO_NTSC_MN 24 -#define HPG_WINTV_PRO_NTSC_MN_V2 25 -#define HPG_WINTV_PRO_PAL 26 -#define HPG_WINTV_PRO_NTSC_MN_V3 27 -#define HPG_WINTV_PRO_PAL_BG 28 -#define HPG_WINTV_PRO_PAL_I 29 -#define HPG_WINTV_PRO_PAL_SECAM_L 30 -#define HPG_WINTV_PRO_PAL_D_K 31 -#define HPG_WINTV_PRO_PAL_SECAM 32 -#define HPG_WINTV_PRO_PAL_SECAM_V2 33 -#define HPG_WINTV_PRO_PAL_BG_V2 34 -#define HPG_WINTV_PRO_PAL_BG_D_K 35 -#define HPG_WINTV_PRO_PAL_I_D_K 36 -#define HPG_WINTV_PRO_NTSC_MN_FM 37 -#define HPG_WINTV_PRO_PAL_BG_FM 38 -#define HPG_WINTV_PRO_PAL_I_FM 39 -#define HPG_WINTV_PRO_PAL_D_K_FM 40 -#define HPG_WINTV_PRO_TEMIC_PAL_FM 41 -#define HPG_WINTV_PRO_TEMIC_PAL_BG_FM 42 -#define HPG_WINTV_PRO_PAL_FM 43 -#define HPG_WINTV_PRO_NTSC_MN_FM_V2 44 -#define CAMTEL_TVB330 45 -#define DIGITAL_VIDEO_CREATOR_I 46 -#define GLOBAL_VILLAGE_GV_007_NTSC 47 -#define DAZZLE_DVC_50_REV_1_NTSC 48 -#define DAZZLE_DVC_80_REV_1_PAL 49 -#define DAZZLE_DVC_90_REV_1_SECAM 50 -#define ESKAPE_LABS_MYTV2GO 51 -#define PINNA_PCTV_USB_PAL 52 -#define PINNA_PCTV_USB_SECAM 53 -#define PINNA_PCTV_USB_PAL_FM 54 -#define MIRO_PCTV_USB 55 -#define PINNA_PCTV_USB_NTSC_FM 56 -#define PINNA_PCTV_USB_PAL_FM_V2 57 -#define PINNA_PCTV_USB_NTSC_FM_V2 58 -#define PINNA_PCTV_USB_PAL_FM_V3 59 -#define PINNA_LINX_VD_IN_CAB_NTSC 60 -#define PINNA_LINX_VD_IN_CAB_PAL 61 -#define PINNA_PCTV_BUNGEE_PAL_FM 62 -#define HPG_WINTV 63 - -extern const int usbvision_device_data_size; diff --git a/trunk/drivers/media/video/usbvision/usbvision-core.c b/trunk/drivers/media/video/usbvision/usbvision-core.c index bcb551adb7e6..f2154dc072e2 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-core.c +++ b/trunk/drivers/media/video/usbvision/usbvision-core.c @@ -2040,8 +2040,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) return 0; /* Set input format expected from decoder*/ - if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) { - value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1; + if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) { + value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff; } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { /* SAA7113 uses 8 bit output */ value[0] = USBVISION_8_422_SYNC; @@ -2112,8 +2112,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ - if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){ - dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv; + if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){ + dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff; } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { /* This changes as the fine sync control changes. Further investigation necessary */ @@ -2238,7 +2238,7 @@ static void call_usbvision_power_off(struct work_struct *work) PDEBUG(DBG_FUNC, ""); down_interruptible(&usbvision->lock); if(usbvision->user == 0) { - usbvision_i2c_unregister(usbvision); + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); usbvision_power_off(usbvision); usbvision->initialized = 0; diff --git a/trunk/drivers/media/video/usbvision/usbvision-i2c.c b/trunk/drivers/media/video/usbvision/usbvision-i2c.c index 025be555194f..609e1fd9c784 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-i2c.c +++ b/trunk/drivers/media/video/usbvision/usbvision-i2c.c @@ -1,8 +1,8 @@ /* - * usbvision_i2c.c + * I2C_ALGO_USB.C * i2c algorithm for USB-I2C Bridges * - * Copyright (c) 1999-2007 Joerg Heckenbach + * Copyright (c) 1999-2005 Joerg Heckenbach * Dwaine Garden * * This module is part of usbvision driver project. @@ -39,6 +39,7 @@ #include "usbvision.h" #define DBG_I2C 1<<0 +#define DBG_ALGO 1<<1 static int i2c_debug = 0; @@ -48,22 +49,22 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); #define PDEBUG(level, fmt, args...) \ if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) -static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len); -static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len); static inline int try_write_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { - struct usb_usbvision *usbvision; + void *data; int i, ret = -1; char buf[4]; - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); + data = i2c_get_adapdata(i2c_adap); buf[0] = 0x00; for (i = 0; i <= retries; i++) { - ret = (usbvision_i2c_write(usbvision, addr, buf, 1)); + ret = (usbvision_i2c_write(data, addr, buf, 1)); if (ret == 1) break; /* success! */ udelay(5); @@ -72,8 +73,8 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, udelay(10); } if (i) { - PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); - PDEBUG(DBG_I2C,"Maybe there's no device at this address"); + PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); + PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); } return ret; } @@ -81,13 +82,13 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, static inline int try_read_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { - struct usb_usbvision *usbvision; + void *data; int i, ret = -1; char buf[4]; - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); + data = i2c_get_adapdata(i2c_adap); for (i = 0; i <= retries; i++) { - ret = (usbvision_i2c_read(usbvision, addr, buf, 1)); + ret = (usbvision_i2c_read(data, addr, buf, 1)); if (ret == 1) break; /* success! */ udelay(5); @@ -96,8 +97,8 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, udelay(10); } if (i) { - PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); - PDEBUG(DBG_I2C,"Maybe there's no device at this address"); + PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); + PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); } return ret; } @@ -151,32 +152,32 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, } static int -usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct i2c_msg *pmsg; - struct usb_usbvision *usbvision; + void *data; int i, ret; unsigned char addr; - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); + data = i2c_get_adapdata(i2c_adap); for (i = 0; i < num; i++) { pmsg = &msgs[i]; ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); if (ret != 0) { - PDEBUG(DBG_I2C,"got NAK from device, message #%d", i); + PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i); return (ret < 0) ? ret : -EREMOTEIO; } if (pmsg->flags & I2C_M_RD) { /* read bytes into buffer */ - ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len)); + ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len)); if (ret < pmsg->len) { return (ret < 0) ? ret : -EREMOTEIO; } } else { /* write bytes from buffer */ - ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len)); + ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len)); if (ret < pmsg->len) { return (ret < 0) ? ret : -EREMOTEIO; } @@ -190,7 +191,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned return 0; } -static u32 functionality(struct i2c_adapter *adap) +static u32 usb_func(struct i2c_adapter *adap) { return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } @@ -198,11 +199,11 @@ static u32 functionality(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ -static struct i2c_algorithm usbvision_algo = { - .master_xfer = usbvision_i2c_xfer, +static struct i2c_algorithm i2c_usb_algo = { + .master_xfer = usb_xfer, .smbus_xfer = NULL, .algo_control = algo_control, - .functionality = functionality, + .functionality = usb_func, }; @@ -212,29 +213,41 @@ static struct i2c_algorithm usbvision_algo = { static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) { PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); - PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); + PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]"); /* register new adapter to i2c module... */ - adap->algo = &usbvision_algo; + adap->algo = &i2c_usb_algo; adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ i2c_add_adapter(adap); - PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name); + PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name); + + return 0; +} + + +int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) +{ + + i2c_del_adapter(adap); + + PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name); return 0; } + /* ----------------------------------------------------------------------- */ /* usbvision specific I2C functions */ /* ----------------------------------------------------------------------- */ static struct i2c_adapter i2c_adap_template; static struct i2c_client i2c_client_template; -int usbvision_i2c_register(struct usb_usbvision *usbvision) +int usbvision_init_i2c(struct usb_usbvision *usbvision) { memcpy(&usbvision->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); @@ -252,7 +265,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) usbvision->i2c_client.adapter = &usbvision->i2c_adap; if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { - printk(KERN_ERR "usbvision_register: can't write reg\n"); + printk(KERN_ERR "usbvision_init_i2c: can't write reg\n"); return -EBUSY; } @@ -274,16 +287,6 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); } -int usbvision_i2c_unregister(struct usb_usbvision *usbvision) -{ - - i2c_del_adapter(&(usbvision->i2c_adap)); - - PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name); - - return 0; -} - void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg) { @@ -297,12 +300,19 @@ static int attach_inform(struct i2c_client *client) usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); switch (client->addr << 1) { - case 0x42 << 1: - case 0x43 << 1: - case 0x4a << 1: - case 0x4b << 1: - PDEBUG(DBG_I2C,"attach_inform: tda9887 detected."); + case 0x43: + case 0x4b: + { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = TUNER_TDA9887; + tun_setup.addr = client->addr; + + call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); + break; + } case 0x42: PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); break; @@ -470,7 +480,7 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, return len; } -static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len) { char *bufPtr = buf; @@ -478,6 +488,7 @@ static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char ad int wrcount = 0; int count; int maxLen = 4; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; while (len > 0) { count = (len > maxLen) ? maxLen : len; @@ -492,13 +503,14 @@ static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char ad return wrcount; } -static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len) { char temp[4]; int retval, i; int rdcount = 0; int count; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; while (len > 0) { count = (len > 3) ? 4 : len; diff --git a/trunk/drivers/media/video/usbvision/usbvision-video.c b/trunk/drivers/media/video/usbvision/usbvision-video.c index 216704170a4c..6fc14557d623 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-video.c +++ b/trunk/drivers/media/video/usbvision/usbvision-video.c @@ -76,7 +76,6 @@ #endif #include "usbvision.h" -#include "usbvision-cards.h" #define DRIVER_AUTHOR "Joerg Heckenbach , Dwaine Garden " #define DRIVER_NAME "usbvision" @@ -151,6 +150,7 @@ static int PowerOnAtOpen = 1; // Set the default device to power on at startu static int video_nr = -1; // Sequential Number of Video Device static int radio_nr = -1; // Sequential Number of Radio Device static int vbi_nr = -1; // Sequential Number of VBI Device +static char *CustomDevice=NULL; // Set as nothing.... // Grab parameters for the device driver @@ -161,6 +161,7 @@ module_param(PowerOnAtOpen, int, 0444); module_param(video_nr, int, 0444); module_param(radio_nr, int, 0444); module_param(vbi_nr, int, 0444); +module_param(CustomDevice, charp, 0444); #else // Old Style MODULE_PARAM(isocMode, "i"); MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver @@ -170,6 +171,7 @@ MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White ou MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) +MODULE_PARM(CustomDevice, "s"); // .... CustomDevice #endif MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); @@ -178,6 +180,7 @@ MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); // Misc stuff @@ -406,7 +409,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) down(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); + usbvision_init_i2c(usbvision); } /* Send init sequence only once, it's large! */ @@ -428,7 +431,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) } else { if (PowerOnAtOpen) { - usbvision_i2c_unregister(usbvision); + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); usbvision_power_off(usbvision); usbvision->initialized = 0; } @@ -1236,7 +1239,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision_reset_powerOffTimer(usbvision); if (usbvision->power == 0) { usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); + usbvision_init_i2c(usbvision); } } @@ -1258,7 +1261,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) if (errCode) { if (PowerOnAtOpen) { - usbvision_i2c_unregister(usbvision); + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); usbvision_power_off(usbvision); usbvision->initialized = 0; } @@ -1741,8 +1744,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) model = usbvision->DevModel; usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; - if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) { - usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2; + if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { + usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; } else { usbvision->Vin_Reg2_Preset = 0; } @@ -1761,7 +1764,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) usbvision_audio_off(usbvision); //first switch off audio if (!PowerOnAtOpen) { usbvision_power_on(usbvision); //and then power up the noisy tuner - usbvision_i2c_register(usbvision); + usbvision_init_i2c(usbvision); } } @@ -1772,8 +1775,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) * if it looks like USBVISION video device * */ -static int __devinit usbvision_probe(struct usb_interface *intf, - const struct usb_device_id *devid) +static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) { struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); struct usb_interface *uif; @@ -1784,17 +1786,25 @@ static int __devinit usbvision_probe(struct usb_interface *intf, int model,i; PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", - dev->descriptor.idVendor, - dev->descriptor.idProduct, ifnum); + dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); - model = devid->driver_info; - if ( (model<0) || (model>=usbvision_device_data_size) ) { - PDEBUG(DBG_PROBE, "model out of bounds %d",model); - return -ENODEV; + /* Is it an USBVISION video dev? */ + model = 0; + for(model = 0; usbvision_device_data[model].idVendor; model++) { + if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { + continue; + } + if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { + continue; + } + + printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString); + break; } - printk(KERN_INFO "%s: %s found\n", __FUNCTION__, - usbvision_device_data[model].ModelString); + if (usbvision_device_data[model].idVendor == 0) { + return -ENODEV; //no matching device + } if (usbvision_device_data[model].Interface >= 0) { interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; } @@ -1812,15 +1822,16 @@ static int __devinit usbvision_probe(struct usb_interface *intf, return -ENODEV; } + usb_get_dev(dev); + if ((usbvision = usbvision_alloc(dev)) == NULL) { err("%s: couldn't allocate USBVision struct", __FUNCTION__); return -ENOMEM; } - if (dev->descriptor.bNumConfigurations > 1) { usbvision->bridgeType = BRIDGE_NT1004; } - else if (model == DAZZLE_DVC_90_REV_1_SECAM) { + else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { usbvision->bridgeType = BRIDGE_NT1005; } else { @@ -1909,7 +1920,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usbvision_stop_isoc(usbvision); if (usbvision->power) { - usbvision_i2c_unregister(usbvision); + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); usbvision_power_off(usbvision); } usbvision->remove_pending = 1; // Now all ISO data will be ignored @@ -1939,6 +1950,124 @@ static struct usb_driver usbvision_driver = { .disconnect = usbvision_disconnect }; +/* + * customdevice_process() + * + * This procedure preprocesses CustomDevice parameter if any + * + */ +static void customdevice_process(void) +{ + usbvision_device_data[0]=usbvision_device_data[1]; + usbvision_table[0]=usbvision_table[1]; + + if(CustomDevice) + { + char *parse=CustomDevice; + + PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); + + /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" + usbvision_device_data[0].idVendor; + usbvision_device_data[0].idProduct; + usbvision_device_data[0].Interface; + usbvision_device_data[0].Codec; + usbvision_device_data[0].VideoChannels; + usbvision_device_data[0].VideoNorm; + usbvision_device_data[0].AudioChannels; + usbvision_device_data[0].Radio; + usbvision_device_data[0].Tuner; + usbvision_device_data[0].TunerType; + usbvision_device_data[0].Vin_Reg1; + usbvision_device_data[0].Vin_Reg2; + usbvision_device_data[0].X_Offset; + usbvision_device_data[0].Y_Offset; + usbvision_device_data[0].Dvi_yuv; + usbvision_device_data[0].ModelString; + */ + + rmspace(parse); + usbvision_device_data[0].ModelString="USBVISION Custom Device"; + + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idVendor); + goto2next(parse); + PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idProduct); + goto2next(parse); + PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); + sscanf(parse,"%d",&usbvision_device_data[0].Interface); + goto2next(parse); + PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); + sscanf(parse,"%d",&usbvision_device_data[0].Codec); + goto2next(parse); + PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); + sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); + + switch(*parse) + { + case 'P': + PDEBUG(DBG_PROBE, "VideoNorm=PAL"); + usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; + break; + + case 'S': + PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); + usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM; + break; + + case 'N': + PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); + usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC; + break; + + default: + PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); + usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; + break; + } + goto2next(parse); + + sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); + sscanf(parse,"%d",&usbvision_device_data[0].Radio); + goto2next(parse); + PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); + sscanf(parse,"%d",&usbvision_device_data[0].Tuner); + goto2next(parse); + PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); + sscanf(parse,"%d",&usbvision_device_data[0].TunerType); + goto2next(parse); + PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); + sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); + PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); + + //add to usbvision_table also + usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; + usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; + usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; + + } +} + + + /* * usbvision_init() * @@ -1963,6 +2092,8 @@ static int __init usbvision_init(void) usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P } + customdevice_process(); + errCode = usb_register(&usbvision_driver); if (errCode == 0) { diff --git a/trunk/drivers/media/video/usbvision/usbvision.h b/trunk/drivers/media/video/usbvision/usbvision.h index bd6f6422ed54..ad6afd3e42a4 100644 --- a/trunk/drivers/media/video/usbvision/usbvision.h +++ b/trunk/drivers/media/video/usbvision/usbvision.h @@ -342,24 +342,23 @@ struct usbvision_frame { #define BRIDGE_NT1005 1005 struct usbvision_device_data_st { - __u64 VideoNorm; - const char *ModelString; + int idVendor; + int idProduct; int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ - __u16 Codec; - unsigned VideoChannels:3; - unsigned AudioChannels:2; - unsigned Radio:1; - unsigned vbi:1; - unsigned Tuner:1; - unsigned Vin_Reg1_override:1; /* Override default value with */ - unsigned Vin_Reg2_override:1; /* Vin_Reg1, Vin_Reg2, etc. */ - unsigned Dvi_yuv_override:1; - __u8 Vin_Reg1; - __u8 Vin_Reg2; - __u8 Dvi_yuv; - __u8 TunerType; - __s16 X_Offset; - __s16 Y_Offset; + int Codec; + int VideoChannels; + __u64 VideoNorm; + int AudioChannels; + int Radio; + int vbi; + int Tuner; + int TunerType; + int Vin_Reg1; + int Vin_Reg2; + int X_Offset; + int Y_Offset; + int Dvi_yuv; + char *ModelString; }; /* Declared on usbvision-cards.c */ @@ -482,11 +481,13 @@ struct usb_usbvision { /* i2c-algo-usb declaration */ /* --------------------------------------------------------------- */ +int usbvision_i2c_usb_del_bus(struct i2c_adapter *); + + /* ----------------------------------------------------------------------- */ /* usbvision specific I2C functions */ /* ----------------------------------------------------------------------- */ -int usbvision_i2c_register(struct usb_usbvision *usbvision); -int usbvision_i2c_unregister(struct usb_usbvision *usbvision); +int usbvision_init_i2c(struct usb_usbvision *usbvision); void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); /* defined in usbvision-core.c */ diff --git a/trunk/drivers/media/video/v4l2-common.c b/trunk/drivers/media/video/v4l2-common.c index 49f1df74aa21..54747606eae1 100644 --- a/trunk/drivers/media/video/v4l2-common.c +++ b/trunk/drivers/media/video/v4l2-common.c @@ -60,7 +60,6 @@ #include #define __OLD_VIDIOC_ /* To allow fixing old calls*/ #include -#include #ifdef CONFIG_KMOD #include @@ -261,8 +260,6 @@ char *v4l2_field_names[] = { [V4L2_FIELD_SEQ_TB] = "seq-tb", [V4L2_FIELD_SEQ_BT] = "seq-bt", [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", }; char *v4l2_type_names[] = { @@ -272,8 +269,7 @@ char *v4l2_type_names[] = { [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", - [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", + [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out", }; @@ -384,8 +380,6 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - - [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", #endif }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -416,16 +410,14 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", + [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT", [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", - [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", - [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", - [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", - [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", + [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ" }; #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) @@ -688,7 +680,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; - case V4L2_CID_MPEG_AUDIO_MUTE: name = "Audio Mute"; break; case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; @@ -699,8 +690,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; - case V4L2_CID_MPEG_VIDEO_MUTE: name = "Video Mute"; break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: name = "Video Mute YUV"; break; case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; @@ -716,7 +705,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste switch (qctrl->id) { case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_MPEG_AUDIO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; @@ -850,8 +838,6 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) V4L2_MPEG_AUDIO_CRC_NONE, V4L2_MPEG_AUDIO_CRC_CRC16, 1, V4L2_MPEG_AUDIO_CRC_NONE); - case V4L2_CID_MPEG_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); case V4L2_CID_MPEG_VIDEO_ENCODING: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_VIDEO_ENCODING_MPEG_1, @@ -881,10 +867,6 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - case V4L2_CID_MPEG_VIDEO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ - return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); case V4L2_CID_MPEG_STREAM_TYPE: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_STREAM_TYPE_MPEG2_PS, @@ -983,22 +965,6 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c } } -int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip, - u32 ident, u32 revision) -{ - if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip)) - return 0; - if (chip->ident == V4L2_IDENT_NONE) { - chip->ident = ident; - chip->revision = revision; - } - else { - chip->ident = V4L2_IDENT_AMBIGUOUS; - chip->revision = 0; - } - return 0; -} - int v4l2_chip_match_host(u32 match_type, u32 match_chip) { switch (match_type) { @@ -1033,7 +999,6 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill); EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); EXPORT_SYMBOL(v4l2_chip_match_i2c_client); -EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); EXPORT_SYMBOL(v4l2_chip_match_host); /* diff --git a/trunk/drivers/media/video/videocodec.c b/trunk/drivers/media/video/videocodec.c index f2bbd7a4d562..290e64135650 100644 --- a/trunk/drivers/media/video/videocodec.c +++ b/trunk/drivers/media/video/videocodec.c @@ -348,9 +348,6 @@ videocodec_build_table (void) kfree(videocodec_buf); videocodec_buf = kmalloc(size, GFP_KERNEL); - if (!videocodec_buf) - return 0; - i = 0; i += scnprintf(videocodec_buf + i, size - 1, "lave or attached aster name type flags magic "); diff --git a/trunk/drivers/media/video/videodev.c b/trunk/drivers/media/video/videodev.c index 80ac5f86d9e5..011938fb7e0e 100644 --- a/trunk/drivers/media/video/videodev.c +++ b/trunk/drivers/media/video/videodev.c @@ -318,7 +318,6 @@ static char *v4l2_type_names_FIXME[] = { [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", [V4L2_BUF_TYPE_PRIVATE] = "private", }; @@ -331,8 +330,6 @@ static char *v4l2_field_names_FIXME[] = { [V4L2_FIELD_SEQ_TB] = "seq-tb", [V4L2_FIELD_SEQ_BT] = "seq-bt", [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", }; #define prt_names(a,arr) (((a)>=0)&&((a)vidioc_try_fmt_vbi_output) return (0); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_output_overlay) - return (0); - break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_try_fmt_type_private) return (0); @@ -532,10 +525,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_enum_fmt_vbi_output(file, fh, f); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_enum_fmt_output_overlay) - ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f); - break; case V4L2_BUF_TYPE_PRIVATE: if (vfd->vidioc_enum_fmt_type_private) ret=vfd->vidioc_enum_fmt_type_private(file, @@ -593,10 +582,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_g_fmt_video_output(file, fh, f); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_g_fmt_output_overlay) - ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f); - break; case V4L2_BUF_TYPE_VBI_OUTPUT: if (vfd->vidioc_g_fmt_vbi_output) ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); @@ -645,10 +630,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_s_fmt_video_output(file, fh, f); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_s_fmt_output_overlay) - ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f); - break; case V4L2_BUF_TYPE_VBI_OUTPUT: if (vfd->vidioc_s_fmt_vbi_output) ret=vfd->vidioc_s_fmt_vbi_output(file, @@ -699,10 +680,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_try_fmt_video_output(file, fh, f); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_output_overlay) - ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f); - break; case V4L2_BUF_TYPE_VBI_OUTPUT: if (vfd->vidioc_try_fmt_vbi_output) ret=vfd->vidioc_try_fmt_vbi_output(file, @@ -1404,11 +1381,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_PARM: { struct v4l2_streamparm *p=arg; - __u32 type=p->type; - - memset(p,0,sizeof(*p)); - p->type=type; - if (vfd->vidioc_g_parm) { ret=vfd->vidioc_g_parm(file, fh, p); } else { @@ -1420,6 +1392,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l2_video_std_construct(&s, vfd->current_norm, v4l2_norm_to_name(vfd->current_norm)); + memset(p,0,sizeof(*p)); + p->parm.capture.timeperframe = s.frameperiod; ret=0; } @@ -1535,16 +1509,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; } #endif - case VIDIOC_G_CHIP_IDENT: - { - struct v4l2_chip_ident *p=arg; - if (!vfd->vidioc_g_chip_ident) - break; - ret=vfd->vidioc_g_chip_ident(file, fh, p); - if (!ret) - dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); - break; - } } /* switch */ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { diff --git a/trunk/drivers/media/video/wm8739.c b/trunk/drivers/media/video/wm8739.c index 8f6741a28a47..a9b59c35cd67 100644 --- a/trunk/drivers/media/video/wm8739.c +++ b/trunk/drivers/media/video/wm8739.c @@ -29,7 +29,6 @@ #include #include #include -#include MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); @@ -237,9 +236,6 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg return -EINVAL; } - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); - case VIDIOC_LOG_STATUS: v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, diff --git a/trunk/drivers/media/video/wm8775.c b/trunk/drivers/media/video/wm8775.c index 4df5d30d4d09..d81a88bbe43d 100644 --- a/trunk/drivers/media/video/wm8775.c +++ b/trunk/drivers/media/video/wm8775.c @@ -33,7 +33,6 @@ #include #include #include -#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -125,9 +124,6 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, wm8775_write(client, R21, 0x100 + state->input); break; - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); - case VIDIOC_LOG_STATUS: v4l_info(client, "Input: %d%s\n", state->input, state->muted ? " (muted)" : ""); diff --git a/trunk/drivers/media/video/zr364xx.c b/trunk/drivers/media/video/zr364xx.c deleted file mode 100644 index b5d3364c94c7..000000000000 --- a/trunk/drivers/media/video/zr364xx.c +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Zoran 364xx based USB webcam module version 0.72 - * - * Allows you to use your USB webcam with V4L2 applications - * This is still in heavy developpement ! - * - * Copyright (C) 2004 Antoine Jacquet - * http://royale.zerezo.com/zr364xx/ - * - * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers - * V4L2 version inspired by meye.c driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 - - -/* Version Information */ -#define DRIVER_VERSION "v0.72" -#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" -#define DRIVER_DESC "Zoran 364xx" - - -/* Camera */ -#define FRAMES 2 -#define MAX_FRAME_SIZE 100000 -#define BUFFER_SIZE 0x1000 -#define CTRL_TIMEOUT 500 - - -/* Debug macro */ -#define DBG(x...) if (debug) info(x) - - -/* Init methods, need to find nicer names for these - * the exact names of the chipsets would be the best if someone finds it */ -#define METHOD0 0 -#define METHOD1 1 -#define METHOD2 2 - - -/* Module parameters */ -static int debug = 0; -static int mode = 0; - - -/* Module parameters interface */ -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level"); -module_param(mode, int, 0644); -MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); - - -/* Devices supported by this driver - * .driver_info contains the init method used by the camera */ -static struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, - {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, - {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, - {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, - {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, - {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, - {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, - {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, - {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, - {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, - {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, - {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, device_table); - - -/* Camera stuff */ -struct zr364xx_camera { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface;/* the interface for this device */ - struct video_device *vdev; /* v4l video device */ - u8 *framebuf; - int nb; - unsigned char *buffer; - int skip; - int brightness; - int width; - int height; - int method; - struct mutex lock; -}; - - -/* function used to send initialisation commands to the camera */ -static int send_control_msg(struct usb_device *udev, u8 request, u16 value, - u16 index, unsigned char *cp, u16 size) -{ - int status; - - unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); - if (!transfer_buffer) { - info("kmalloc(%d) failed", size); - return -ENOMEM; - } - - memcpy(transfer_buffer, cp, size); - - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, value, index, - transfer_buffer, size, CTRL_TIMEOUT); - - kfree(transfer_buffer); - - if (status < 0) - info("Failed sending control message, error %d.", status); - - return status; -} - - -/* Control messages sent to the camera to initialize it - * and launch the capture */ -typedef struct { - unsigned int value; - unsigned int size; - unsigned char *bytes; -} message; - -/* method 0 */ -static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d3[] = { 0, 0 }; -static message m0[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0x3370, sizeof(m0d1), m0d1}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2610, sizeof(m0d2), m0d2}, - {0xe107, 0, NULL}, - {0x2502, 0, NULL}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m0d3), m0d3}, - {-1, -1, NULL} -}; - -/* method 1 */ -static unsigned char m1d1[] = { 0xff, 0xff }; -static unsigned char m1d2[] = { 0x00, 0x00 }; -static message m1[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m1d1), m1d1}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m1d2), m1d2}, - {-1, -1, NULL} -}; - -/* method 2 */ -static unsigned char m2d1[] = { 0xff, 0xff }; -static message m2[] = { - {0x1f30, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m2d1), m2d1}, - {0x1f70, 0, NULL}, - {-1, -1, NULL} -}; - -/* init table */ -static message *init[3] = { m0, m1, m2 }; - - -/* JPEG static data in header (Huffman table, etc) */ -static unsigned char header1[] = { - 0xFF, 0xD8, - /* - 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', - 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, - */ - 0xFF, 0xDB, 0x00, 0x84 -}; -static unsigned char header2[] = { - 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, - 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, - 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, - 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, - 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, - 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, - 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, - 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, - 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, - 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, - 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, - 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, - 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, - 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, - 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, - 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, - 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, - 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, - 0x00, 0x3F, 0x00 -}; -static unsigned char header3; - - - -/********************/ -/* V4L2 integration */ -/********************/ - -/* this function reads a full JPEG picture synchronously - * TODO: do it asynchronously... */ -static int read_frame(struct zr364xx_camera *cam, int framenum) -{ - int i, n, temp, head, size, actual_length; - unsigned char *ptr = NULL, *jpeg; - - redo: - /* hardware brightness */ - n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); - temp = (0x60 << 8) + 127 - cam->brightness; - n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0); - - /* during the first loop we are going to insert JPEG header */ - head = 0; - /* this is the place in memory where we are going to build - * the JPEG image */ - jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE; - /* read data... */ - do { - n = usb_bulk_msg(cam->udev, - usb_rcvbulkpipe(cam->udev, 0x81), - cam->buffer, BUFFER_SIZE, &actual_length, - CTRL_TIMEOUT); - DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]); - DBG("bulk : n=%d size=%d", n, actual_length); - if (n < 0) { - info("error reading bulk msg"); - return 0; - } - if (actual_length < 0 || actual_length > BUFFER_SIZE) { - info("wrong number of bytes"); - return 0; - } - - /* swap bytes if camera needs it */ - if (cam->method == METHOD0) { - u16 *buf = (u16*)cam->buffer; - for (i = 0; i < BUFFER_SIZE/2; i++) - swab16s(buf + i); - } - - /* write the JPEG header */ - if (!head) { - DBG("jpeg header"); - ptr = jpeg; - memcpy(ptr, header1, sizeof(header1)); - ptr += sizeof(header1); - header3 = 0; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, cam->buffer, 64); - ptr += 64; - header3 = 1; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, cam->buffer + 64, 64); - ptr += 64; - memcpy(ptr, header2, sizeof(header2)); - ptr += sizeof(header2); - memcpy(ptr, cam->buffer + 128, - actual_length - 128); - ptr += actual_length - 128; - head = 1; - DBG("header : %d %d %d %d %d %d %d %d %d", - cam->buffer[0], cam->buffer[1], cam->buffer[2], - cam->buffer[3], cam->buffer[4], cam->buffer[5], - cam->buffer[6], cam->buffer[7], cam->buffer[8]); - } else { - memcpy(ptr, cam->buffer, actual_length); - ptr += actual_length; - } - } - /* ... until there is no more */ - while (actual_length == BUFFER_SIZE); - - /* we skip the 2 first frames which are usually buggy */ - if (cam->skip) { - cam->skip--; - goto redo; - } - - /* go back to find the JPEG EOI marker */ - size = ptr - jpeg; - ptr -= 2; - while (ptr > jpeg) { - if (*ptr == 0xFF && *(ptr + 1) == 0xD9 - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr == jpeg) - DBG("No EOI marker"); - - /* Sometimes there is junk data in the middle of the picture, - * we want to skip this bogus frames */ - while (ptr > jpeg) { - if (*ptr == 0xFF && *(ptr + 1) == 0xFF - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr != jpeg) { - DBG("Bogus frame ? %d", cam->nb); - goto redo; - } - - DBG("jpeg : %d %d %d %d %d %d %d %d", - jpeg[0], jpeg[1], jpeg[2], jpeg[3], - jpeg[4], jpeg[5], jpeg[6], jpeg[7]); - - return size; -} - - -static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt, - loff_t * ppos) -{ - unsigned long count = cnt; - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - DBG("zr364xx_read: read %d bytes.", (int) count); - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - if (!buf) - return -EINVAL; - - if (!count) - return -EINVAL; - - /* NoMan Sux ! */ - count = read_frame(cam, 0); - - if (copy_to_user(buf, cam->framebuf, count)) - return -EFAULT; - - return count; -} - - -static int zr364xx_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - memset(cap, 0, sizeof(*cap)); - strcpy(cap->driver, DRIVER_DESC); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int zr364xx_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = 0; - strcpy(i->name, DRIVER_DESC " Camera"); - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int zr364xx_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - *i = 0; - return 0; -} - -static int zr364xx_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int zr364xx_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Brightness"); - c->minimum = 0; - c->maximum = 127; - c->step = 1; - c->default_value = cam->brightness; - c->flags = 0; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - cam->brightness = c->value; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = cam->brightness; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_enum_fmt_cap(struct file *file, - void *priv, struct v4l2_fmtdesc *f) -{ - if (f->index > 0) - return -EINVAL; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = 0; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strcpy(f->description, "JPEG"); - f->pixelformat = V4L2_PIX_FMT_JPEG; - return 0; -} - -static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) - return -EINVAL; - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - return 0; -} - -static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - return 0; -} - -static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) - return -EINVAL; - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - DBG("ok!"); - return 0; -} - -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - return 0; -} - -static int zr364xx_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - return 0; -} - - -/* open the camera */ -static int zr364xx_open(struct inode *inode, struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam = video_get_drvdata(vdev); - struct usb_device *udev = cam->udev; - int i, err; - - DBG("zr364xx_open"); - - cam->skip = 2; - - err = video_exclusive_open(inode, file); - if (err < 0) - return err; - - if (!cam->framebuf) { - cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES); - if (!cam->framebuf) { - info("vmalloc_32 failed!"); - return -ENOMEM; - } - } - - mutex_lock(&cam->lock); - for (i = 0; init[cam->method][i].size != -1; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (err < 0) { - info("error during open sequence: %d", i); - mutex_unlock(&cam->lock); - return err; - } - } - - file->private_data = vdev; - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - - mutex_unlock(&cam->lock); - return 0; -} - - -/* release the camera */ -static int zr364xx_release(struct inode *inode, struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - struct usb_device *udev; - int i, err; - - DBG("zr364xx_release"); - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - udev = cam->udev; - - mutex_lock(&cam->lock); - for (i = 0; i < 2; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[i][cam->method].bytes, - init[cam->method][i].size); - if (err < 0) { - info("error during release sequence"); - mutex_unlock(&cam->lock); - return err; - } - } - - file->private_data = NULL; - video_exclusive_release(inode, file); - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - - mutex_unlock(&cam->lock); - return 0; -} - - -static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) -{ - void *pos; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam; - - DBG("zr364xx_mmap: %ld\n", size); - - if (vdev == NULL) - return -ENODEV; - cam = video_get_drvdata(vdev); - - pos = cam->framebuf; - while (size > 0) { - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - - -static struct file_operations zr364xx_fops = { - .owner = THIS_MODULE, - .open = zr364xx_open, - .release = zr364xx_release, - .read = zr364xx_read, - .mmap = zr364xx_mmap, - .ioctl = video_ioctl2, - .llseek = no_llseek, -}; - -static struct video_device zr364xx_template = { - .owner = THIS_MODULE, - .name = DRIVER_DESC, - .type = VID_TYPE_CAPTURE, - .fops = &zr364xx_fops, - .release = video_device_release, - .minor = -1, - - .vidioc_querycap = zr364xx_vidioc_querycap, - .vidioc_enum_fmt_cap = zr364xx_vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = zr364xx_vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = zr364xx_vidioc_s_fmt_cap, - .vidioc_g_fmt_cap = zr364xx_vidioc_g_fmt_cap, - .vidioc_enum_input = zr364xx_vidioc_enum_input, - .vidioc_g_input = zr364xx_vidioc_g_input, - .vidioc_s_input = zr364xx_vidioc_s_input, - .vidioc_streamon = zr364xx_vidioc_streamon, - .vidioc_streamoff = zr364xx_vidioc_streamoff, - .vidioc_queryctrl = zr364xx_vidioc_queryctrl, - .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl, - .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, -}; - - - -/*******************/ -/* USB integration */ -/*******************/ - -static int zr364xx_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct zr364xx_camera *cam = NULL; - - DBG("probing..."); - - info(DRIVER_DESC " compatible webcam plugged"); - info("model %04x:%04x detected", udev->descriptor.idVendor, - udev->descriptor.idProduct); - - if ((cam = - kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) { - info("cam: out of memory !"); - return -ENODEV; - } - memset(cam, 0x00, sizeof(struct zr364xx_camera)); - /* save the init method used by this camera */ - cam->method = id->driver_info; - - cam->vdev = video_device_alloc(); - if (cam->vdev == NULL) { - info("cam->vdev: out of memory !"); - kfree(cam); - return -ENODEV; - } - memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); - video_set_drvdata(cam->vdev, cam); - if (debug) - cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - - cam->udev = udev; - - if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) { - info("cam->buffer: out of memory !"); - video_device_release(cam->vdev); - kfree(cam); - return -ENODEV; - } - - switch (mode) { - case 1: - info("160x120 mode selected"); - cam->width = 160; - cam->height = 120; - break; - case 2: - info("640x480 mode selected"); - cam->width = 640; - cam->height = 480; - break; - default: - info("320x240 mode selected"); - cam->width = 320; - cam->height = 240; - break; - } - - m0d1[0] = mode; - m1[2].value = 0xf000 + mode; - m2[1].value = 0xf000 + mode; - header2[437] = cam->height / 256; - header2[438] = cam->height % 256; - header2[439] = cam->width / 256; - header2[440] = cam->width % 256; - - cam->nb = 0; - cam->brightness = 64; - mutex_init(&cam->lock); - - if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { - info("video_register_device failed"); - video_device_release(cam->vdev); - kfree(cam->buffer); - kfree(cam); - return -ENODEV; - } - - usb_set_intfdata(intf, cam); - - info(DRIVER_DESC " controlling video device %d", cam->vdev->minor); - return 0; -} - - -static void zr364xx_disconnect(struct usb_interface *intf) -{ - struct zr364xx_camera *cam = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - dev_set_drvdata(&intf->dev, NULL); - info(DRIVER_DESC " webcam unplugged"); - if (cam->vdev) - video_unregister_device(cam->vdev); - cam->vdev = NULL; - kfree(cam->buffer); - if (cam->framebuf) - vfree(cam->framebuf); - kfree(cam); -} - - - -/**********************/ -/* Module integration */ -/**********************/ - -static struct usb_driver zr364xx_driver = { - .name = "zr364xx", - .probe = zr364xx_probe, - .disconnect = zr364xx_disconnect, - .id_table = device_table -}; - - -static int __init zr364xx_init(void) -{ - int retval; - retval = usb_register(&zr364xx_driver) < 0; - if (retval) - info("usb_register failed!"); - else - info(DRIVER_DESC " module loaded"); - return retval; -} - - -static void __exit zr364xx_exit(void) -{ - info(DRIVER_DESC " module unloaded"); - usb_deregister(&zr364xx_driver); -} - - -module_init(zr364xx_init); -module_exit(zr364xx_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/message/fusion/mptbase.c b/trunk/drivers/message/fusion/mptbase.c index 97471af4309c..083acfd91d8b 100644 --- a/trunk/drivers/message/fusion/mptbase.c +++ b/trunk/drivers/message/fusion/mptbase.c @@ -1531,7 +1531,6 @@ mpt_resume(struct pci_dev *pdev) MPT_ADAPTER *ioc = pci_get_drvdata(pdev); u32 device_state = pdev->current_state; int recovery_state; - int err; printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", @@ -1539,9 +1538,7 @@ mpt_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); - err = pci_enable_device(pdev); - if (err) - return err; + pci_enable_device(pdev); /* enable interrupts */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); @@ -4742,8 +4739,12 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) } /** - * mpt_inactive_raid_list_free - This clears this link list. - * @ioc : pointer to per adapter structure + * mpt_inactive_raid_list_free + * + * This clears this link list. + * + * @ioc - pointer to per adapter structure + * **/ static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) @@ -4763,11 +4764,15 @@ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) } /** - * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume + * mpt_inactive_raid_volumes + * + * This sets up link list of phy_disk_nums for devices belonging in an inactive volume + * + * @ioc - pointer to per adapter structure + * @channel - volume channel + * @id - volume target id + * * - * @ioc : pointer to per adapter structure - * @channel : volume channel - * @id : volume target id **/ static void mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) @@ -6658,7 +6663,7 @@ union loginfo_type { /** * mpt_iocstatus_info_config - IOCSTATUS information for config pages * @ioc: Pointer to MPT_ADAPTER structure - * @ioc_status: U32 IOCStatus word from IOC + * ioc_status: U32 IOCStatus word from IOC * @mf: Pointer to MPT request frame * * Refer to lsi/mpi.h. diff --git a/trunk/drivers/message/fusion/mptbase.h b/trunk/drivers/message/fusion/mptbase.h index d25d3be8fcd2..e3a39272aad6 100644 --- a/trunk/drivers/message/fusion/mptbase.h +++ b/trunk/drivers/message/fusion/mptbase.h @@ -994,7 +994,6 @@ typedef struct _MPT_SCSI_HOST { int scandv_wait_done; long last_queue_full; u16 tm_iocstatus; - u16 spi_pending; struct list_head target_reset_list; } MPT_SCSI_HOST; diff --git a/trunk/drivers/message/fusion/mptlan.c b/trunk/drivers/message/fusion/mptlan.c index 7dd34bd28efc..b691292ff599 100644 --- a/trunk/drivers/message/fusion/mptlan.c +++ b/trunk/drivers/message/fusion/mptlan.c @@ -714,7 +714,6 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) LANSendRequest_t *pSendReq; SGETransaction32_t *pTrans; SGESimple64_t *pSimple; - const unsigned char *mac; dma_addr_t dma; unsigned long flags; int ctx; @@ -754,7 +753,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) /* Set the mac.raw pointer, since this apparently isn't getting * done before we get the skb. Pull the data pointer past the mac data. */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, 12); dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, @@ -785,7 +784,6 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) // IOC_AND_NETDEV_NAMES_s_s(dev), // ctx, skb, skb->data)); - mac = skb_mac_header(skb); #ifdef QLOGIC_NAA_WORKAROUND { struct NAA_Hosed *nh; @@ -795,12 +793,12 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) drops. */ read_lock_irq(&bad_naa_lock); for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) { - if ((nh->ieee[0] == mac[0]) && - (nh->ieee[1] == mac[1]) && - (nh->ieee[2] == mac[2]) && - (nh->ieee[3] == mac[3]) && - (nh->ieee[4] == mac[4]) && - (nh->ieee[5] == mac[5])) { + if ((nh->ieee[0] == skb->mac.raw[0]) && + (nh->ieee[1] == skb->mac.raw[1]) && + (nh->ieee[2] == skb->mac.raw[2]) && + (nh->ieee[3] == skb->mac.raw[3]) && + (nh->ieee[4] == skb->mac.raw[4]) && + (nh->ieee[5] == skb->mac.raw[5])) { cur_naa = nh->NAA; dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " "= %04x.\n", cur_naa)); @@ -812,12 +810,12 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) #endif pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | - (mac[0] << 8) | - (mac[1] << 0)); - pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) | - (mac[3] << 16) | - (mac[4] << 8) | - (mac[5] << 0)); + (skb->mac.raw[0] << 8) | + (skb->mac.raw[1] << 0)); + pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) | + (skb->mac.raw[3] << 16) | + (skb->mac.raw[4] << 8) | + (skb->mac.raw[5] << 0)); pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; @@ -932,7 +930,7 @@ mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); + memcpy(skb_put(skb, len), old_skb->data, len); pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); @@ -1093,7 +1091,7 @@ mpt_lan_receive_post_reply(struct net_device *dev, priv->RcvCtl[ctx].dma, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(old_skb, skb_put(skb, l), l); + memcpy(skb_put(skb, l), old_skb->data, l); pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, @@ -1122,7 +1120,7 @@ mpt_lan_receive_post_reply(struct net_device *dev, priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); + memcpy(skb_put(skb, len), old_skb->data, len); pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, @@ -1551,7 +1549,7 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; struct fcllc *fcllc; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, sizeof(struct mpt_lan_ohdr)); if (fch->dtype == htons(0xffff)) { diff --git a/trunk/drivers/message/fusion/mptscsih.c b/trunk/drivers/message/fusion/mptscsih.c index fa0f7761652a..2a3e9e66d4ef 100644 --- a/trunk/drivers/message/fusion/mptscsih.c +++ b/trunk/drivers/message/fusion/mptscsih.c @@ -819,7 +819,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) sc->resid=0; case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - sc->result = (DID_OK << 16) | scsi_status; + if (scsi_status == MPI_SCSI_STATUS_BUSY) + sc->result = (DID_BUS_BUSY << 16) | scsi_status; + else + sc->result = (DID_OK << 16) | scsi_status; if (scsi_state == 0) { ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { @@ -1185,7 +1188,20 @@ mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) int mptscsih_resume(struct pci_dev *pdev) { - return mpt_resume(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct Scsi_Host *host = ioc->sh; + MPT_SCSI_HOST *hd; + + mpt_resume(pdev); + + if(!host) + return 0; + + hd = (MPT_SCSI_HOST *)host->hostdata; + if(!hd) + return 0; + + return 0; } #endif @@ -1521,23 +1537,21 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_TMHandler - Generic handler for SCSI Task Management. - * @hd: Pointer to MPT SCSI HOST structure + * Fall through to mpt_HardResetHandler if: not operational, too many + * failed TM requests or handshake failure. + * + * @ioc: Pointer to MPT_ADAPTER structure * @type: Task Management type - * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) - * @timeout: timeout for task management control - * - * Fall through to mpt_HardResetHandler if: not operational, too many - * failed TM requests or handshake failure. * * Remark: Currently invoked from a non-interrupt thread (_bh). * * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC * will be active. * - * Returns 0 for SUCCESS, or %FAILED. + * Returns 0 for SUCCESS, or FAILED. **/ int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) @@ -1636,11 +1650,9 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type - * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) - * @timeout: timeout for task management control * * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) * or a non-interrupt thread. In the former, must not call schedule(). @@ -2010,7 +2022,6 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) /** * mptscsih_tm_wait_for_completion - wait for completion of TM task * @hd: Pointer to MPT host structure. - * @timeout: timeout value * * Returns {SUCCESS,FAILED}. */ diff --git a/trunk/drivers/message/fusion/mptspi.c b/trunk/drivers/message/fusion/mptspi.c index d75f7ffbb02e..85f21b54cb7d 100644 --- a/trunk/drivers/message/fusion/mptspi.c +++ b/trunk/drivers/message/fusion/mptspi.c @@ -96,13 +96,14 @@ static int mptspiTaskCtx = -1; static int mptspiInternalCtx = -1; /* Used only for internal commands */ /** - * mptspi_setTargetNegoParms - Update the target negotiation parameters + * mptspi_setTargetNegoParms - Update the target negotiation + * parameters based on the the Inquiry data, adapter capabilities, + * and NVRAM settings + * * @hd: Pointer to a SCSI Host Structure - * @target: per target private data + * @vtarget: per target private data * @sdev: SCSI device * - * Update the target negotiation parameters based on the the Inquiry - * data, adapter capabilities, and NVRAM settings. **/ static void mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, @@ -233,7 +234,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, /** * mptspi_writeIOCPage4 - write IOC Page 4 * @hd: Pointer to a SCSI Host Structure - * @channel: channel number + * @channel: * @id: write IOC Page4 for this ID & Bus * * Return: -EAGAIN if unable to obtain a Message Frame @@ -445,7 +446,7 @@ static int mptspi_target_alloc(struct scsi_target *starget) return 0; } -static void +void mptspi_target_destroy(struct scsi_target *starget) { if (starget->hostdata) @@ -676,9 +677,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, return; } - hd->spi_pending |= (1 << sdev->id); spi_dv_device(sdev); - hd->spi_pending &= ~(1 << sdev->id); if (sdev->channel == 1 && mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) @@ -1204,27 +1203,11 @@ mptspi_dv_renegotiate_work(struct work_struct *work) container_of(work, struct work_queue_wrapper, work); struct _MPT_SCSI_HOST *hd = wqw->hd; struct scsi_device *sdev; - struct scsi_target *starget; - struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; - u32 nego; kfree(wqw); - if (hd->spi_pending) { - shost_for_each_device(sdev, hd->ioc->sh) { - if (hd->spi_pending & (1 << sdev->id)) - continue; - starget = scsi_target(sdev); - nego = mptspi_getRP(starget); - pg1.RequestedParameters = cpu_to_le32(nego); - pg1.Reserved = 0; - pg1.Configuration = 0; - mptspi_write_spi_device_pg1(starget, &pg1); - } - } else { - shost_for_each_device(sdev, hd->ioc->sh) - mptspi_dv_device(hd, sdev); - } + shost_for_each_device(sdev, hd->ioc->sh) + mptspi_dv_device(hd, sdev); } static void @@ -1470,7 +1453,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) init_waitqueue_head(&hd->scandv_waitq); hd->scandv_wait_done = 0; hd->last_queue_full = 0; - hd->spi_pending = 0; /* Some versions of the firmware don't support page 0; without * that we can't get the parameters */ diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index a3c525b2616a..80b199fa0aa9 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -112,70 +112,14 @@ config SONY_LAPTOP depends on X86 && ACPI select BACKLIGHT_CLASS_DEVICE ---help--- - This mini-driver drives the SNC and SPIC devices present in the ACPI - BIOS of the Sony Vaio laptops. + This mini-driver drives the SNC device present in the ACPI BIOS of + the Sony Vaio laptops. - It gives access to some extra laptop functionalities like Bluetooth, - screen brightness control, Fn keys and allows powering on/off some + It gives access to some extra laptop functionalities. In its current + form, this driver let the user set or query the screen brightness + through the backlight subsystem and remove/apply power to some devices. Read for more information. -config SONY_LAPTOP_OLD - bool "Sonypi compatibility" - depends on SONY_LAPTOP - ---help--- - Build the sonypi driver compatibility code into the sony-laptop driver. - -config THINKPAD_ACPI - tristate "ThinkPad ACPI Laptop Extras" - depends on X86 && ACPI - select BACKLIGHT_CLASS_DEVICE - select HWMON - ---help--- - This is a driver for the IBM and Lenovo ThinkPad laptops. It adds - support for Fn-Fx key combinations, Bluetooth control, video - output switching, ThinkLight control, UltraBay eject and more. - For more information about this driver see - and . - - This driver was formely known as ibm-acpi. - - If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. - -config THINKPAD_ACPI_DEBUG - bool "Verbose debug mode" - depends on THINKPAD_ACPI - default n - ---help--- - Enables extra debugging information, at the expense of a slightly - increase in driver size. - - If you are not sure, say N here. - -config THINKPAD_ACPI_DOCK - bool "Legacy Docking Station Support" - depends on THINKPAD_ACPI - depends on ACPI_DOCK=n - default n - ---help--- - Allows the thinkpad_acpi driver to handle docking station events. - This support was made obsolete by the generic ACPI docking station - support (CONFIG_ACPI_DOCK). It will allow locking and removing the - laptop from the docking station, but will not properly connect PCI - devices. - - If you are not sure, say N here. - -config THINKPAD_ACPI_BAY - bool "Legacy Removable Bay Support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to handle removable bays. It will - eletrically disable the device in the bay, and also generate - notifications when the bay lever is ejected or inserted. - - If you are not sure, say Y here. - endmenu diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile index e32516459138..7793ccd79049 100644 --- a/trunk/drivers/misc/Makefile +++ b/trunk/drivers/misc/Makefile @@ -12,4 +12,3 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o -obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o diff --git a/trunk/drivers/misc/asus-laptop.c b/trunk/drivers/misc/asus-laptop.c index 65c32a95e121..4b232124a1ab 100644 --- a/trunk/drivers/misc/asus-laptop.c +++ b/trunk/drivers/misc/asus-laptop.c @@ -3,7 +3,7 @@ * * * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor - * Copyright (C) 2006-2007 Corentin Chary + * Copyright (C) 2006 Corentin Chary * * 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 @@ -48,7 +48,7 @@ #include #include -#define ASUS_LAPTOP_VERSION "0.41" +#define ASUS_LAPTOP_VERSION "0.40" #define ASUS_HOTK_NAME "Asus Laptop Support" #define ASUS_HOTK_CLASS "hotkey" @@ -81,8 +81,7 @@ #define TLED_ON 0x08 //touchpad LED #define RLED_ON 0x10 //Record LED #define PLED_ON 0x20 //Phone LED -#define GLED_ON 0x40 //Gaming LED -#define LCD_ON 0x80 //LCD backlight +#define LCD_ON 0x40 //LCD backlight #define ASUS_LOG ASUS_HOTK_FILE ": " #define ASUS_ERR KERN_ERR ASUS_LOG @@ -95,19 +94,6 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); MODULE_DESCRIPTION(ASUS_HOTK_NAME); MODULE_LICENSE("GPL"); -/* WAPF defines the behavior of the Fn+Fx wlan key - * The significance of values is yet to be found, but - * most of the time: - * 0x0 will do nothing - * 0x1 will allow to control the device with Fn+Fx key. - * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key - * 0x5 like 0x1 or 0x4 - * So, if something doesn't work as you want, just try other values =) - */ -static uint wapf = 1; -module_param(wapf, uint, 0644); -MODULE_PARM_DESC(wapf, "WAPF value"); - #define ASUS_HANDLE(object, paths...) \ static acpi_handle object##_handle = NULL; \ static char *object##_paths[] = { paths } @@ -117,7 +103,6 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ -ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ /* LEDD */ ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); @@ -236,7 +221,6 @@ ASUS_LED(mled, "mail"); ASUS_LED(tled, "touchpad"); ASUS_LED(rled, "record"); ASUS_LED(pled, "phone"); -ASUS_LED(gled, "gaming"); /* * This function evaluates an ACPI method, given an int as parameter, the @@ -261,19 +245,32 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val, return (status == AE_OK); } +static int read_acpi_int(acpi_handle handle, const char *method, int *val, + struct acpi_object_list *params) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char *)method, params, &output); + *val = out_obj.integer.value; + return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); +} + static int read_wireless_status(int mask) { - ulong status; - acpi_status rv = AE_OK; + int status; if (!wireless_status_handle) return (hotk->status & mask) ? 1 : 0; - rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); - if (ACPI_FAILURE(rv)) - printk(ASUS_WARNING "Error reading Wireless status\n"); - else + if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) { return (status & mask) ? 1 : 0; + } else + printk(ASUS_WARNING "Error reading Wireless status\n"); return (hotk->status & mask) ? 1 : 0; } @@ -288,28 +285,19 @@ static int read_status(int mask) return (hotk->status & mask) ? 1 : 0; } -static void write_status(acpi_handle handle, int out, int mask) +static void write_status(acpi_handle handle, int out, int mask, int invert) { hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); - switch (mask) { - case MLED_ON: + if (invert) /* invert target value */ out = !out & 0x1; - break; - case GLED_ON: - out = (out & 0x1) + 1; - break; - default: - out &= 0x1; - break; - } if (handle && !write_acpi_int(handle, NULL, out, NULL)) - printk(ASUS_WARNING " write failed %x\n", mask); + printk(ASUS_WARNING " write failed\n"); } /* /sys/class/led handlers */ -#define ASUS_LED_HANDLER(object, mask) \ +#define ASUS_LED_HANDLER(object, mask, invert) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value) \ { \ @@ -319,14 +307,13 @@ static void write_status(acpi_handle handle, int out, int mask) static void object##_led_update(struct work_struct *ignored) \ { \ int value = object##_led_wk; \ - write_status(object##_set_handle, value, (mask)); \ + write_status(object##_set_handle, value, (mask), (invert)); \ } -ASUS_LED_HANDLER(mled, MLED_ON); -ASUS_LED_HANDLER(pled, PLED_ON); -ASUS_LED_HANDLER(rled, RLED_ON); -ASUS_LED_HANDLER(tled, TLED_ON); -ASUS_LED_HANDLER(gled, GLED_ON); +ASUS_LED_HANDLER(mled, MLED_ON, 1); +ASUS_LED_HANDLER(pled, PLED_ON, 0); +ASUS_LED_HANDLER(rled, RLED_ON, 0); +ASUS_LED_HANDLER(tled, TLED_ON, 0); static int get_lcd_state(void) { @@ -351,7 +338,7 @@ static int set_lcd_state(int value) printk(ASUS_WARNING "Error switching LCD\n"); } - write_status(NULL, lcd, LCD_ON); + write_status(NULL, lcd, LCD_ON, 0); return 0; } @@ -367,11 +354,9 @@ static void lcd_blank(int blank) static int read_brightness(struct backlight_device *bd) { - ulong value; - acpi_status rv = AE_OK; + int value; - rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); - if (ACPI_FAILURE(rv)) + if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL)) printk(ASUS_WARNING "Error reading brightness\n"); return value; @@ -418,10 +403,8 @@ static ssize_t show_infos(struct device *dev, struct device_attribute *attr, char *page) { int len = 0; - ulong temp; + int temp; char buf[16]; //enough for all info - acpi_status rv = AE_OK; - /* * We use the easy way, we don't care of off and count, so we don't set eof * to 1 @@ -435,10 +418,9 @@ static ssize_t show_infos(struct device *dev, * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. * The significance of others is yet to be found. */ - rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); - if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "SFUN value : 0x%04x\n", - (uint) temp); + if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL)) + len += + sprintf(page + len, "SFUN value : 0x%04x\n", temp); /* * Another value for userspace: the ASYM method returns 0x02 for * battery low and 0x04 for battery critical, its readings tend to be @@ -446,10 +428,9 @@ static ssize_t show_infos(struct device *dev, * Note: since not all the laptops provide this method, errors are * silently ignored. */ - rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); - if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "ASYM value : 0x%04x\n", - (uint) temp); + if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL)) + len += + sprintf(page + len, "ASYM value : 0x%04x\n", temp); if (asus_info) { snprintf(buf, 16, "%d", asus_info->length); len += sprintf(page + len, "DSDT length : %s\n", buf); @@ -484,7 +465,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val) } static ssize_t store_status(const char *buf, size_t count, - acpi_handle handle, int mask) + acpi_handle handle, int mask, int invert) { int rv, value; int out = 0; @@ -493,7 +474,7 @@ static ssize_t store_status(const char *buf, size_t count, if (rv > 0) out = value ? 1 : 0; - write_status(handle, out, mask); + write_status(handle, out, mask, invert); return rv; } @@ -534,7 +515,7 @@ static ssize_t show_wlan(struct device *dev, static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return store_status(buf, count, wl_switch_handle, WL_ON); + return store_status(buf, count, wl_switch_handle, WL_ON, 0); } /* @@ -550,7 +531,7 @@ static ssize_t store_bluetooth(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return store_status(buf, count, bt_switch_handle, BT_ON); + return store_status(buf, count, bt_switch_handle, BT_ON, 0); } /* @@ -566,15 +547,12 @@ static void set_display(int value) static int read_display(void) { - ulong value = 0; - acpi_status rv = AE_OK; + int value = 0; /* In most of the case, we know how to set the display, but sometime we can't read it */ if (display_get_handle) { - rv = acpi_evaluate_integer(display_get_handle, NULL, - NULL, &value); - if (ACPI_FAILURE(rv)) + if (!read_acpi_int(display_get_handle, NULL, &value, NULL)) printk(ASUS_WARNING "Error reading display status\n"); } @@ -678,10 +656,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) * switched */ if (event == ATKD_LCD_ON) { - write_status(NULL, 1, LCD_ON); + write_status(NULL, 1, LCD_ON, 0); lcd_blank(FB_BLANK_UNBLANK); } else if (event == ATKD_LCD_OFF) { - write_status(NULL, 0, LCD_ON); + write_status(NULL, 0, LCD_ON, 0); lcd_blank(FB_BLANK_POWERDOWN); } @@ -793,7 +771,7 @@ static int asus_hotk_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; - ulong bsts_result, hwrs_result; + int bsts_result, hwrs_result; char *string = NULL; acpi_status status; @@ -816,16 +794,11 @@ static int asus_hotk_get_info(void) } /* This needs to be called for some laptops to init properly */ - status = - acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); - if (ACPI_FAILURE(status)) + if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL)) printk(ASUS_WARNING "Error calling BSTS\n"); else if (bsts_result) printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", - (uint) bsts_result); - - /* This too ... */ - write_acpi_int(hotk->handle, "CWAP", wapf, NULL); + bsts_result); /* * Try to match the object returned by INIT to the specific model. @@ -858,7 +831,6 @@ static int asus_hotk_get_info(void) ASUS_HANDLE_INIT(tled_set); ASUS_HANDLE_INIT(rled_set); ASUS_HANDLE_INIT(pled_set); - ASUS_HANDLE_INIT(gled_set); ASUS_HANDLE_INIT(ledd_set); @@ -868,9 +840,7 @@ static int asus_hotk_get_info(void) * The significance of others is yet to be found. * If we don't find the method, we assume the device are present. */ - status = - acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); - if (ACPI_FAILURE(status)) + if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL)) hwrs_result = WL_HWRS | BT_HWRS; if (hwrs_result & WL_HWRS) @@ -958,15 +928,11 @@ static int asus_hotk_add(struct acpi_device *device) asus_hotk_found = 1; /* WLED and BLED are on by default */ - write_status(bt_switch_handle, 1, BT_ON); - write_status(wl_switch_handle, 1, WL_ON); - - /* If the h/w switch is off, we need to check the real status */ - write_status(NULL, read_status(BT_ON), BT_ON); - write_status(NULL, read_status(WL_ON), WL_ON); + write_status(bt_switch_handle, 1, BT_ON, 0); + write_status(wl_switch_handle, 1, WL_ON, 0); /* LCD Backlight is on by default */ - write_status(NULL, 1, LCD_ON); + write_status(NULL, 1, LCD_ON, 0); /* LED display is off by default */ hotk->ledd_status = 0xFFF; @@ -1025,7 +991,6 @@ static void asus_led_exit(void) ASUS_LED_UNREGISTER(tled); ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); - ASUS_LED_UNREGISTER(gled); destroy_workqueue(led_workqueue); } @@ -1097,10 +1062,6 @@ static int asus_led_init(struct device *dev) if (rv) return rv; - rv = ASUS_LED_REGISTER(gled, dev); - if (rv) - return rv; - led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) return -ENOMEM; diff --git a/trunk/drivers/misc/hdpuftrs/hdpu_cpustate.c b/trunk/drivers/misc/hdpuftrs/hdpu_cpustate.c index 276ba3c5143f..ca86f113f36a 100644 --- a/trunk/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/trunk/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/misc/hdpuftrs/hdpu_nexus.c b/trunk/drivers/misc/hdpuftrs/hdpu_nexus.c index 60c8b26f0678..6a51e99a8079 100644 --- a/trunk/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/trunk/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/trunk/drivers/misc/sony-laptop.c b/trunk/drivers/misc/sony-laptop.c index c15c1f61bd1b..ac708bc2f9f3 100644 --- a/trunk/drivers/misc/sony-laptop.c +++ b/trunk/drivers/misc/sony-laptop.c @@ -1,5 +1,5 @@ /* - * ACPI Sony Notebook Control Driver (SNC and SPIC) + * ACPI Sony Notebook Control Driver (SNC) * * Copyright (C) 2004-2005 Stelian Pop * Copyright (C) 2007 Mattia Dongili @@ -7,25 +7,6 @@ * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c * which are copyrighted by their respective authors. * - * The SNY6001 driver part is based on the sonypi driver which includes - * material from: - * - * Copyright (C) 2001-2005 Stelian Pop - * - * Copyright (C) 2005 Narayanan R S - * - * Copyright (C) 2001-2002 Alcôve - * - * Copyright (C) 2001 Michael Ashley - * - * Copyright (C) 2001 Junichi Morita - * - * Copyright (C) 2000 Takaya Kinjo - * - * Copyright (C) 2000 Andrew Tridgell - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * * 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 @@ -50,404 +31,40 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include -#ifdef CONFIG_SONY_LAPTOP_OLD -#include -#include -#endif - -#define DRV_PFX "sony-laptop: " -#define dprintk(msg...) do { \ - if (debug) printk(KERN_WARNING DRV_PFX msg); \ -} while (0) -#define SONY_LAPTOP_DRIVER_VERSION "0.5" +#define ACPI_SNC_CLASS "sony" +#define ACPI_SNC_HID "SNY5001" +#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4" -#define SONY_NC_CLASS "sony-nc" -#define SONY_NC_HID "SNY5001" -#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver" +/* the device uses 1-based values, while the backlight subsystem uses + 0-based values */ +#define SONY_MAX_BRIGHTNESS 8 -#define SONY_PIC_CLASS "sony-pic" -#define SONY_PIC_HID "SNY6001" -#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver" +#define LOG_PFX KERN_WARNING "sony-laptop: " MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); -MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)"); +MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME); MODULE_LICENSE("GPL"); -MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION); static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " "the development of this driver"); -static int no_spic; /* = 0 */ -module_param(no_spic, int, 0444); -MODULE_PARM_DESC(no_spic, - "set this if you don't want to enable the SPIC device"); - -static int compat; /* = 0 */ -module_param(compat, int, 0444); -MODULE_PARM_DESC(compat, - "set this if you want to enable backward compatibility mode"); - -static unsigned long mask = 0xffffffff; -module_param(mask, ulong, 0644); -MODULE_PARM_DESC(mask, - "set this to the mask of event you want to enable (see doc)"); - -static int camera; /* = 0 */ -module_param(camera, int, 0444); -MODULE_PARM_DESC(camera, - "set this to 1 to enable Motion Eye camera controls " - "(only use it if you have a C1VE or C1VN model)"); - -#ifdef CONFIG_SONY_LAPTOP_OLD -static int minor = -1; -module_param(minor, int, 0); -MODULE_PARM_DESC(minor, - "minor number of the misc device for the SPIC compatibility code, " - "default is -1 (automatic)"); -#endif - -/*********** Input Devices ***********/ - -#define SONY_LAPTOP_BUF_SIZE 128 -struct sony_laptop_input_s { - atomic_t users; - struct input_dev *jog_dev; - struct input_dev *key_dev; - struct kfifo *fifo; - spinlock_t fifo_lock; - struct workqueue_struct *wq; -}; -static struct sony_laptop_input_s sony_laptop_input = { - .users = ATOMIC_INIT(0), -}; - -struct sony_laptop_keypress { - struct input_dev *dev; - int key; -}; - -/* Correspondance table between sonypi events and input layer events */ -static struct { - int sonypiev; - int inputev; -} sony_laptop_inputkeys[] = { - { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, - { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, - { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, - { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, - { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, - { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, - { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, - { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, - { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, - { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, - { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, - { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, - { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, - { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, - { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, - { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, - { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, - { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, - { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, - { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, - { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, - { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, - { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, - { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, - { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, - { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, - { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, - { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, - { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, - { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, - { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, - { 0, 0 }, -}; - -/* release buttons after a short delay if pressed */ -static void do_sony_laptop_release_key(struct work_struct *work) -{ - struct sony_laptop_keypress kp; - - while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, - sizeof(kp)) == sizeof(kp)) { - msleep(10); - input_report_key(kp.dev, kp.key, 0); - input_sync(kp.dev); - } -} -static DECLARE_WORK(sony_laptop_release_key_work, - do_sony_laptop_release_key); - -/* forward event to the input subsytem */ -static void sony_laptop_report_input_event(u8 event) -{ - struct input_dev *jog_dev = sony_laptop_input.jog_dev; - struct input_dev *key_dev = sony_laptop_input.key_dev; - struct sony_laptop_keypress kp = { NULL }; - int i; - - if (event == SONYPI_EVENT_FNKEY_RELEASED) { - /* Nothing, not all VAIOs generate this event */ - return; - } - - /* report events */ - switch (event) { - /* jog_dev events */ - case SONYPI_EVENT_JOGDIAL_UP: - case SONYPI_EVENT_JOGDIAL_UP_PRESSED: - input_report_rel(jog_dev, REL_WHEEL, 1); - input_sync(jog_dev); - return; - - case SONYPI_EVENT_JOGDIAL_DOWN: - case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: - input_report_rel(jog_dev, REL_WHEEL, -1); - input_sync(jog_dev); - return; - - /* key_dev events */ - case SONYPI_EVENT_JOGDIAL_PRESSED: - kp.key = BTN_MIDDLE; - kp.dev = jog_dev; - break; - - default: - for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) - if (event == sony_laptop_inputkeys[i].sonypiev) { - kp.dev = key_dev; - kp.key = sony_laptop_inputkeys[i].inputev; - break; - } - break; - } - - if (kp.dev) { - input_report_key(kp.dev, kp.key, 1); - input_sync(kp.dev); - kfifo_put(sony_laptop_input.fifo, - (unsigned char *)&kp, sizeof(kp)); - - if (!work_pending(&sony_laptop_release_key_work)) - queue_work(sony_laptop_input.wq, - &sony_laptop_release_key_work); - } else - dprintk("unknown input event %.2x\n", event); -} - -static int sony_laptop_setup_input(void) -{ - struct input_dev *jog_dev; - struct input_dev *key_dev; - int i; - int error; - - /* don't run again if already initialized */ - if (atomic_add_return(1, &sony_laptop_input.users) > 1) - return 0; - - /* kfifo */ - spin_lock_init(&sony_laptop_input.fifo_lock); - sony_laptop_input.fifo = - kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, - &sony_laptop_input.fifo_lock); - if (IS_ERR(sony_laptop_input.fifo)) { - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); - error = PTR_ERR(sony_laptop_input.fifo); - goto err_dec_users; - } - - /* init workqueue */ - sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop"); - if (!sony_laptop_input.wq) { - printk(KERN_ERR DRV_PFX - "Unabe to create workqueue.\n"); - error = -ENXIO; - goto err_free_kfifo; - } - - /* input keys */ - key_dev = input_allocate_device(); - if (!key_dev) { - error = -ENOMEM; - goto err_destroy_wq; - } - - key_dev->name = "Sony Vaio Keys"; - key_dev->id.bustype = BUS_ISA; - key_dev->id.vendor = PCI_VENDOR_ID_SONY; - - /* Initialize the Input Drivers: special keys */ - key_dev->evbit[0] = BIT(EV_KEY); - for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) - if (sony_laptop_inputkeys[i].inputev) - set_bit(sony_laptop_inputkeys[i].inputev, - key_dev->keybit); - - error = input_register_device(key_dev); - if (error) - goto err_free_keydev; - - sony_laptop_input.key_dev = key_dev; - - /* jogdial */ - jog_dev = input_allocate_device(); - if (!jog_dev) { - error = -ENOMEM; - goto err_unregister_keydev; - } - - jog_dev->name = "Sony Vaio Jogdial"; - jog_dev->id.bustype = BUS_ISA; - jog_dev->id.vendor = PCI_VENDOR_ID_SONY; - - jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE); - jog_dev->relbit[0] = BIT(REL_WHEEL); - - error = input_register_device(jog_dev); - if (error) - goto err_free_jogdev; - - sony_laptop_input.jog_dev = jog_dev; - - return 0; - -err_free_jogdev: - input_free_device(jog_dev); - -err_unregister_keydev: - input_unregister_device(key_dev); - /* to avoid kref underflow below at input_free_device */ - key_dev = NULL; - -err_free_keydev: - input_free_device(key_dev); - -err_destroy_wq: - destroy_workqueue(sony_laptop_input.wq); - -err_free_kfifo: - kfifo_free(sony_laptop_input.fifo); - -err_dec_users: - atomic_dec(&sony_laptop_input.users); - return error; -} - -static void sony_laptop_remove_input(void) -{ - /* cleanup only after the last user has gone */ - if (!atomic_dec_and_test(&sony_laptop_input.users)) - return; - - /* flush workqueue first */ - flush_workqueue(sony_laptop_input.wq); - - /* destroy input devs */ - input_unregister_device(sony_laptop_input.key_dev); - sony_laptop_input.key_dev = NULL; - - if (sony_laptop_input.jog_dev) { - input_unregister_device(sony_laptop_input.jog_dev); - sony_laptop_input.jog_dev = NULL; - } - - destroy_workqueue(sony_laptop_input.wq); - kfifo_free(sony_laptop_input.fifo); -} - -/*********** Platform Device ***********/ - -static atomic_t sony_pf_users = ATOMIC_INIT(0); -static struct platform_driver sony_pf_driver = { - .driver = { - .name = "sony-laptop", - .owner = THIS_MODULE, - } -}; -static struct platform_device *sony_pf_device; - -static int sony_pf_add(void) -{ - int ret = 0; - - /* don't run again if already initialized */ - if (atomic_add_return(1, &sony_pf_users) > 1) - return 0; - - ret = platform_driver_register(&sony_pf_driver); - if (ret) - goto out; - - sony_pf_device = platform_device_alloc("sony-laptop", -1); - if (!sony_pf_device) { - ret = -ENOMEM; - goto out_platform_registered; - } - - ret = platform_device_add(sony_pf_device); - if (ret) - goto out_platform_alloced; - - return 0; - - out_platform_alloced: - platform_device_put(sony_pf_device); - sony_pf_device = NULL; - out_platform_registered: - platform_driver_unregister(&sony_pf_driver); - out: - atomic_dec(&sony_pf_users); - return ret; -} - -static void sony_pf_remove(void) -{ - /* deregister only after the last user has gone */ - if (!atomic_dec_and_test(&sony_pf_users)) - return; - - platform_device_del(sony_pf_device); - platform_device_put(sony_pf_device); - platform_driver_unregister(&sony_pf_driver); -} - -/*********** SNC (SNY5001) Device ***********/ - -/* the device uses 1-based values, while the backlight subsystem uses - 0-based values */ -#define SONY_MAX_BRIGHTNESS 8 - -#define SNC_VALIDATE_IN 0 -#define SNC_VALIDATE_OUT 1 - -static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, +static ssize_t sony_acpi_show(struct device *, struct device_attribute *, char *); -static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, +static ssize_t sony_acpi_store(struct device *, struct device_attribute *, const char *, size_t); static int boolean_validate(const int, const int); static int brightness_default_validate(const int, const int); -struct sony_nc_value { +#define SNC_VALIDATE_IN 0 +#define SNC_VALIDATE_OUT 1 + +struct sony_acpi_value { char *name; /* name of the entry */ char **acpiget; /* names of the ACPI get function */ char **acpiset; /* names of the ACPI set function */ @@ -458,65 +75,65 @@ struct sony_nc_value { struct device_attribute devattr; /* sysfs atribute */ }; -#define SNC_HANDLE_NAMES(_name, _values...) \ +#define HANDLE_NAMES(_name, _values...) \ static char *snc_##_name[] = { _values, NULL } -#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \ +#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ { \ .name = __stringify(_name), \ .acpiget = _getters, \ .acpiset = _setters, \ .validate = _validate, \ .debug = _debug, \ - .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \ + .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ } -#define SNC_HANDLE_NULL { .name = NULL } +#define SONY_ACPI_VALUE_NULL { .name = NULL } -SNC_HANDLE_NAMES(fnkey_get, "GHKE"); +HANDLE_NAMES(fnkey_get, "GHKE"); -SNC_HANDLE_NAMES(brightness_def_get, "GPBR"); -SNC_HANDLE_NAMES(brightness_def_set, "SPBR"); +HANDLE_NAMES(brightness_def_get, "GPBR"); +HANDLE_NAMES(brightness_def_set, "SPBR"); -SNC_HANDLE_NAMES(cdpower_get, "GCDP"); -SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); +HANDLE_NAMES(cdpower_get, "GCDP"); +HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); -SNC_HANDLE_NAMES(audiopower_get, "GAZP"); -SNC_HANDLE_NAMES(audiopower_set, "AZPW"); +HANDLE_NAMES(audiopower_get, "GAZP"); +HANDLE_NAMES(audiopower_set, "AZPW"); -SNC_HANDLE_NAMES(lanpower_get, "GLNP"); -SNC_HANDLE_NAMES(lanpower_set, "LNPW"); +HANDLE_NAMES(lanpower_get, "GLNP"); +HANDLE_NAMES(lanpower_set, "LNPW"); -SNC_HANDLE_NAMES(PID_get, "GPID"); +HANDLE_NAMES(PID_get, "GPID"); -SNC_HANDLE_NAMES(CTR_get, "GCTR"); -SNC_HANDLE_NAMES(CTR_set, "SCTR"); +HANDLE_NAMES(CTR_get, "GCTR"); +HANDLE_NAMES(CTR_set, "SCTR"); -SNC_HANDLE_NAMES(PCR_get, "GPCR"); -SNC_HANDLE_NAMES(PCR_set, "SPCR"); +HANDLE_NAMES(PCR_get, "GPCR"); +HANDLE_NAMES(PCR_set, "SPCR"); -SNC_HANDLE_NAMES(CMI_get, "GCMI"); -SNC_HANDLE_NAMES(CMI_set, "SCMI"); +HANDLE_NAMES(CMI_get, "GCMI"); +HANDLE_NAMES(CMI_set, "SCMI"); -static struct sony_nc_value sony_nc_values[] = { - SNC_HANDLE(brightness_default, snc_brightness_def_get, +static struct sony_acpi_value sony_acpi_values[] = { + SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, snc_brightness_def_set, brightness_default_validate, 0), - SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0), - SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), - SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set, + SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), + SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), + SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, boolean_validate, 0), - SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, + SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, boolean_validate, 1), /* unknown methods */ - SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), - SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), - SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), - SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), - SNC_HANDLE_NULL + SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), + SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), + SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), + SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), + SONY_ACPI_VALUE_NULL }; -static acpi_handle sony_nc_acpi_handle; -static struct acpi_device *sony_nc_acpi_device = NULL; +static acpi_handle sony_acpi_handle; +static struct acpi_device *sony_acpi_acpi_device = NULL; /* * acpi_evaluate_object wrappers @@ -536,7 +153,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) return 0; } - printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); + printk(LOG_PFX "acpi_callreadfunc failed\n"); return -1; } @@ -562,7 +179,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, if (status == AE_OK) { if (result != NULL) { if (out_obj.type != ACPI_TYPE_INTEGER) { - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " + printk(LOG_PFX "acpi_evaluate_object bad " "return type\n"); return -1; } @@ -571,13 +188,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, return 0; } - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); + printk(LOG_PFX "acpi_evaluate_object failed\n"); return -1; } /* - * sony_nc_values input/output validate functions + * sony_acpi_values input/output validate functions */ /* brightness_default_validate: @@ -612,19 +229,19 @@ static int boolean_validate(const int direction, const int value) } /* - * Sysfs show/store common to all sony_nc_values + * Sysfs show/store common to all sony_acpi_values */ -static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, +static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, char *buffer) { int value; - struct sony_nc_value *item = - container_of(attr, struct sony_nc_value, devattr); + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); if (!*item->acpiget) return -EIO; - if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) + if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) return -EIO; if (item->validate) @@ -633,13 +250,13 @@ static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *a return snprintf(buffer, PAGE_SIZE, "%d\n", value); } -static ssize_t sony_nc_sysfs_store(struct device *dev, +static ssize_t sony_acpi_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { int value; - struct sony_nc_value *item = - container_of(attr, struct sony_nc_value, devattr); + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); if (!item->acpiset) return -EIO; @@ -655,20 +272,118 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, if (value < 0) return value; - if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) + if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) return -EIO; item->value = value; item->valid = 1; return count; } +/* + * Platform device + */ +static struct platform_driver sncpf_driver = { + .driver = { + .name = "sony-laptop", + .owner = THIS_MODULE, + } +}; +static struct platform_device *sncpf_device; + +static int sony_snc_pf_add(void) +{ + acpi_handle handle; + struct sony_acpi_value *item; + int ret = 0; + + ret = platform_driver_register(&sncpf_driver); + if (ret) + goto out; + + sncpf_device = platform_device_alloc("sony-laptop", -1); + if (!sncpf_device) { + ret = -ENOMEM; + goto out_platform_registered; + } + + ret = platform_device_add(sncpf_device); + if (ret) + goto out_platform_alloced; + + for (item = sony_acpi_values; item->name; ++item) { + + if (!debug && item->debug) + continue; + + /* find the available acpiget as described in the DSDT */ + for (; item->acpiget && *item->acpiget; ++item->acpiget) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiget, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s getter: %s\n", + item->name, *item->acpiget); + item->devattr.attr.mode |= S_IRUGO; + break; + } + } + + /* find the available acpiset as described in the DSDT */ + for (; item->acpiset && *item->acpiset; ++item->acpiset) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiset, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s setter: %s\n", + item->name, *item->acpiset); + item->devattr.attr.mode |= S_IWUSR; + break; + } + } + + if (item->devattr.attr.mode != 0) { + ret = + device_create_file(&sncpf_device->dev, + &item->devattr); + if (ret) + goto out_sysfs; + } + } + + return 0; + + out_sysfs: + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + platform_device_del(sncpf_device); + out_platform_alloced: + platform_device_put(sncpf_device); + out_platform_registered: + platform_driver_unregister(&sncpf_driver); + out: + return ret; +} + +static void sony_snc_pf_remove(void) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + + platform_device_del(sncpf_device); + platform_device_put(sncpf_device); + platform_driver_unregister(&sncpf_driver); +} /* * Backlight device */ static int sony_backlight_update_status(struct backlight_device *bd) { - return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", + return acpi_callsetfunc(sony_acpi_handle, "SBRT", bd->props.brightness + 1, NULL); } @@ -676,7 +391,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) { int value; - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) + if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value)) return 0; /* brightness levels are 1-based, while backlight ones are 0-based */ return value - 1; @@ -693,9 +408,9 @@ static struct backlight_ops sony_backlight_ops = { */ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) { - dprintk("sony_acpi_notify, event: %d\n", event); - sony_laptop_report_input_event(event); - acpi_bus_generate_event(sony_nc_acpi_device, 1, event); + if (debug) + printk(LOG_PFX "sony_acpi_notify, event: %d\n", event); + acpi_bus_generate_event(sony_acpi_acpi_device, 1, event); } static acpi_status sony_walk_callback(acpi_handle handle, u32 level, @@ -707,7 +422,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, node = (struct acpi_namespace_node *)handle; operand = (union acpi_operand_object *)node->object; - printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, + printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii, (u32) operand->method.param_count); return AE_OK; @@ -716,16 +431,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, /* * ACPI device */ -static int sony_nc_resume(struct acpi_device *device) +static int sony_acpi_resume(struct acpi_device *device) { - struct sony_nc_value *item; + struct sony_acpi_value *item; - for (item = sony_nc_values; item->name; item++) { + for (item = sony_acpi_values; item->name; item++) { int ret; if (!item->valid) continue; - ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, + ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { printk("%s: %d\n", __FUNCTION__, ret); @@ -735,55 +450,42 @@ static int sony_nc_resume(struct acpi_device *device) return 0; } -static int sony_nc_add(struct acpi_device *device) +static int sony_acpi_add(struct acpi_device *device) { acpi_status status; int result = 0; acpi_handle handle; - struct sony_nc_value *item; - - printk(KERN_INFO DRV_PFX "%s v%s.\n", - SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); - sony_nc_acpi_device = device; - strcpy(acpi_device_class(device), "sony/hotkey"); + sony_acpi_acpi_device = device; - sony_nc_acpi_handle = device->handle; + sony_acpi_handle = device->handle; if (debug) { - status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, + status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle, 1, sony_walk_callback, NULL, NULL); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); + printk(LOG_PFX "unable to walk acpi resources\n"); result = -ENODEV; goto outwalk; } } - /* setup input devices and helper fifo */ - result = sony_laptop_setup_input(); - if (result) { - printk(KERN_ERR DRV_PFX - "Unabe to create input devices.\n"); - goto outwalk; - } - - status = acpi_install_notify_handler(sony_nc_acpi_handle, + status = acpi_install_notify_handler(sony_acpi_handle, ACPI_DEVICE_NOTIFY, sony_acpi_notify, NULL); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING DRV_PFX "unable to install notify handler\n"); + printk(LOG_PFX "unable to install notify handler\n"); result = -ENODEV; - goto outinput; + goto outwalk; } - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) { sony_backlight_device = backlight_device_register("sony", NULL, NULL, &sony_backlight_ops); if (IS_ERR(sony_backlight_device)) { - printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); + printk(LOG_PFX "unable to register backlight device\n"); sony_backlight_device = NULL; } else { sony_backlight_device->props.brightness = @@ -795,1497 +497,68 @@ static int sony_nc_add(struct acpi_device *device) } - result = sony_pf_add(); - if (result) + if (sony_snc_pf_add()) goto outbacklight; - /* create sony_pf sysfs attributes related to the SNC device */ - for (item = sony_nc_values; item->name; ++item) { - - if (!debug && item->debug) - continue; - - /* find the available acpiget as described in the DSDT */ - for (; item->acpiget && *item->acpiget; ++item->acpiget) { - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, - *item->acpiget, - &handle))) { - dprintk("Found %s getter: %s\n", - item->name, *item->acpiget); - item->devattr.attr.mode |= S_IRUGO; - break; - } - } - - /* find the available acpiset as described in the DSDT */ - for (; item->acpiset && *item->acpiset; ++item->acpiset) { - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, - *item->acpiset, - &handle))) { - dprintk("Found %s setter: %s\n", - item->name, *item->acpiset); - item->devattr.attr.mode |= S_IWUSR; - break; - } - } - - if (item->devattr.attr.mode != 0) { - result = - device_create_file(&sony_pf_device->dev, - &item->devattr); - if (result) - goto out_sysfs; - } - } + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n"); return 0; - out_sysfs: - for (item = sony_nc_values; item->name; ++item) { - device_remove_file(&sony_pf_device->dev, &item->devattr); - } - sony_pf_remove(); - outbacklight: if (sony_backlight_device) backlight_device_unregister(sony_backlight_device); - status = acpi_remove_notify_handler(sony_nc_acpi_handle, + status = acpi_remove_notify_handler(sony_acpi_handle, ACPI_DEVICE_NOTIFY, sony_acpi_notify); if (ACPI_FAILURE(status)) - printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); - - outinput: - sony_laptop_remove_input(); - + printk(LOG_PFX "unable to remove notify handler\n"); outwalk: return result; } -static int sony_nc_remove(struct acpi_device *device, int type) +static int sony_acpi_remove(struct acpi_device *device, int type) { acpi_status status; - struct sony_nc_value *item; if (sony_backlight_device) backlight_device_unregister(sony_backlight_device); - sony_nc_acpi_device = NULL; + sony_acpi_acpi_device = NULL; - status = acpi_remove_notify_handler(sony_nc_acpi_handle, + status = acpi_remove_notify_handler(sony_acpi_handle, ACPI_DEVICE_NOTIFY, sony_acpi_notify); if (ACPI_FAILURE(status)) - printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n"); + printk(LOG_PFX "unable to remove notify handler\n"); - for (item = sony_nc_values; item->name; ++item) { - device_remove_file(&sony_pf_device->dev, &item->devattr); - } + sony_snc_pf_remove(); - sony_pf_remove(); - sony_laptop_remove_input(); - dprintk(SONY_NC_DRIVER_NAME " removed.\n"); + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n"); return 0; } -static struct acpi_driver sony_nc_driver = { - .name = SONY_NC_DRIVER_NAME, - .class = SONY_NC_CLASS, - .ids = SONY_NC_HID, - .owner = THIS_MODULE, +static struct acpi_driver sony_acpi_driver = { + .name = ACPI_SNC_DRIVER_NAME, + .class = ACPI_SNC_CLASS, + .ids = ACPI_SNC_HID, .ops = { - .add = sony_nc_add, - .remove = sony_nc_remove, - .resume = sony_nc_resume, + .add = sony_acpi_add, + .remove = sony_acpi_remove, + .resume = sony_acpi_resume, }, }; -/*********** SPIC (SNY6001) Device ***********/ - -#define SONYPI_DEVICE_TYPE1 0x00000001 -#define SONYPI_DEVICE_TYPE2 0x00000002 -#define SONYPI_DEVICE_TYPE3 0x00000004 - -#define SONY_PIC_EV_MASK 0xff - -struct sony_pic_ioport { - struct acpi_resource_io io; - struct list_head list; -}; - -struct sony_pic_irq { - struct acpi_resource_irq irq; - struct list_head list; -}; - -struct sony_pic_dev { - int model; - u8 camera_power; - u8 bluetooth_power; - u8 wwan_power; - struct acpi_device *acpi_dev; - struct sony_pic_irq *cur_irq; - struct sony_pic_ioport *cur_ioport; - struct list_head interrupts; - struct list_head ioports; - struct mutex lock; -}; - -static struct sony_pic_dev spic_dev = { - .interrupts = LIST_HEAD_INIT(spic_dev.interrupts), - .ioports = LIST_HEAD_INIT(spic_dev.ioports), -}; - -/* Event masks */ -#define SONYPI_JOGGER_MASK 0x00000001 -#define SONYPI_CAPTURE_MASK 0x00000002 -#define SONYPI_FNKEY_MASK 0x00000004 -#define SONYPI_BLUETOOTH_MASK 0x00000008 -#define SONYPI_PKEY_MASK 0x00000010 -#define SONYPI_BACK_MASK 0x00000020 -#define SONYPI_HELP_MASK 0x00000040 -#define SONYPI_LID_MASK 0x00000080 -#define SONYPI_ZOOM_MASK 0x00000100 -#define SONYPI_THUMBPHRASE_MASK 0x00000200 -#define SONYPI_MEYE_MASK 0x00000400 -#define SONYPI_MEMORYSTICK_MASK 0x00000800 -#define SONYPI_BATTERY_MASK 0x00001000 -#define SONYPI_WIRELESS_MASK 0x00002000 - -struct sonypi_event { - u8 data; - u8 event; -}; - -/* The set of possible button release events */ -static struct sonypi_event sonypi_releaseev[] = { - { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED }, - { 0, 0 } -}; - -/* The set of possible jogger events */ -static struct sonypi_event sonypi_joggerev[] = { - { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, - { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, - { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, - { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, - { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP }, - { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN }, - { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED }, - { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED }, - { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP }, - { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN }, - { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED }, - { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED }, - { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, - { 0, 0 } -}; - -/* The set of possible capture button events */ -static struct sonypi_event sonypi_captureev[] = { - { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, - { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, - { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, - { 0, 0 } -}; - -/* The set of possible fnkeys events */ -static struct sonypi_event sonypi_fnkeyev[] = { - { 0x10, SONYPI_EVENT_FNKEY_ESC }, - { 0x11, SONYPI_EVENT_FNKEY_F1 }, - { 0x12, SONYPI_EVENT_FNKEY_F2 }, - { 0x13, SONYPI_EVENT_FNKEY_F3 }, - { 0x14, SONYPI_EVENT_FNKEY_F4 }, - { 0x15, SONYPI_EVENT_FNKEY_F5 }, - { 0x16, SONYPI_EVENT_FNKEY_F6 }, - { 0x17, SONYPI_EVENT_FNKEY_F7 }, - { 0x18, SONYPI_EVENT_FNKEY_F8 }, - { 0x19, SONYPI_EVENT_FNKEY_F9 }, - { 0x1a, SONYPI_EVENT_FNKEY_F10 }, - { 0x1b, SONYPI_EVENT_FNKEY_F11 }, - { 0x1c, SONYPI_EVENT_FNKEY_F12 }, - { 0x1f, SONYPI_EVENT_FNKEY_RELEASED }, - { 0x21, SONYPI_EVENT_FNKEY_1 }, - { 0x22, SONYPI_EVENT_FNKEY_2 }, - { 0x31, SONYPI_EVENT_FNKEY_D }, - { 0x32, SONYPI_EVENT_FNKEY_E }, - { 0x33, SONYPI_EVENT_FNKEY_F }, - { 0x34, SONYPI_EVENT_FNKEY_S }, - { 0x35, SONYPI_EVENT_FNKEY_B }, - { 0x36, SONYPI_EVENT_FNKEY_ONLY }, - { 0, 0 } -}; - -/* The set of possible program key events */ -static struct sonypi_event sonypi_pkeyev[] = { - { 0x01, SONYPI_EVENT_PKEY_P1 }, - { 0x02, SONYPI_EVENT_PKEY_P2 }, - { 0x04, SONYPI_EVENT_PKEY_P3 }, - { 0x5c, SONYPI_EVENT_PKEY_P1 }, - { 0, 0 } -}; - -/* The set of possible bluetooth events */ -static struct sonypi_event sonypi_blueev[] = { - { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, - { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, - { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, - { 0, 0 } -}; - -/* The set of possible wireless events */ -static struct sonypi_event sonypi_wlessev[] = { - { 0x59, SONYPI_EVENT_WIRELESS_ON }, - { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, - { 0, 0 } -}; - -/* The set of possible back button events */ -static struct sonypi_event sonypi_backev[] = { - { 0x20, SONYPI_EVENT_BACK_PRESSED }, - { 0, 0 } -}; - -/* The set of possible help button events */ -static struct sonypi_event sonypi_helpev[] = { - { 0x3b, SONYPI_EVENT_HELP_PRESSED }, - { 0, 0 } -}; - - -/* The set of possible lid events */ -static struct sonypi_event sonypi_lidev[] = { - { 0x51, SONYPI_EVENT_LID_CLOSED }, - { 0x50, SONYPI_EVENT_LID_OPENED }, - { 0, 0 } -}; - -/* The set of possible zoom events */ -static struct sonypi_event sonypi_zoomev[] = { - { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, - { 0, 0 } -}; - -/* The set of possible thumbphrase events */ -static struct sonypi_event sonypi_thumbphraseev[] = { - { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED }, - { 0, 0 } -}; - -/* The set of possible motioneye camera events */ -static struct sonypi_event sonypi_meyeev[] = { - { 0x00, SONYPI_EVENT_MEYE_FACE }, - { 0x01, SONYPI_EVENT_MEYE_OPPOSITE }, - { 0, 0 } -}; - -/* The set of possible memorystick events */ -static struct sonypi_event sonypi_memorystickev[] = { - { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT }, - { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT }, - { 0, 0 } -}; - -/* The set of possible battery events */ -static struct sonypi_event sonypi_batteryev[] = { - { 0x20, SONYPI_EVENT_BATTERY_INSERT }, - { 0x30, SONYPI_EVENT_BATTERY_REMOVE }, - { 0, 0 } -}; - -static struct sonypi_eventtypes { - int model; - u8 data; - unsigned long mask; - struct sonypi_event * events; -} sony_pic_eventtypes[] = { - { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, - { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, - { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, - { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, - { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, - - { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, - { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, - { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, - { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, - { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, - { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, - { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, - - { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev }, - { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, - { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, - { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, - { 0 } -}; - -static int sony_pic_detect_device_type(void) -{ - struct pci_dev *pcidev; - int model = 0; - - if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) - model = SONYPI_DEVICE_TYPE1; - - else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) - model = SONYPI_DEVICE_TYPE3; - - else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) - model = SONYPI_DEVICE_TYPE3; - - else - model = SONYPI_DEVICE_TYPE2; - - if (pcidev) - pci_dev_put(pcidev); - - printk(KERN_INFO DRV_PFX "detected Type%d model\n", - model == SONYPI_DEVICE_TYPE1 ? 1 : - model == SONYPI_DEVICE_TYPE2 ? 2 : 3); - return model; -} - -#define ITERATIONS_LONG 10000 -#define ITERATIONS_SHORT 10 -#define wait_on_command(command, iterations) { \ - unsigned int n = iterations; \ - while (--n && (command)) \ - udelay(1); \ - if (!n) \ - dprintk("command failed at %s : %s (line %d)\n", \ - __FILE__, __FUNCTION__, __LINE__); \ -} - -static u8 sony_pic_call1(u8 dev) -{ - u8 v1, v2; - - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, - ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4); - v2 = inb_p(spic_dev.cur_ioport->io.minimum); - dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); - return v2; -} - -static u8 sony_pic_call2(u8 dev, u8 fn) -{ - u8 v1; - - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, - ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, - ITERATIONS_LONG); - outb(fn, spic_dev.cur_ioport->io.minimum); - v1 = inb_p(spic_dev.cur_ioport->io.minimum); - dprintk("sony_pic_call2: 0x%.4x\n", v1); - return v1; -} - -static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) -{ - u8 v1; - - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(dev, spic_dev.cur_ioport->io.minimum + 4); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(fn, spic_dev.cur_ioport->io.minimum); - wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); - outb(v, spic_dev.cur_ioport->io.minimum); - v1 = inb_p(spic_dev.cur_ioport->io.minimum); - dprintk("sony_pic_call3: 0x%.4x\n", v1); - return v1; -} - -/* camera tests and poweron/poweroff */ -#define SONYPI_CAMERA_PICTURE 5 -#define SONYPI_CAMERA_CONTROL 0x10 - -#define SONYPI_CAMERA_BRIGHTNESS 0 -#define SONYPI_CAMERA_CONTRAST 1 -#define SONYPI_CAMERA_HUE 2 -#define SONYPI_CAMERA_COLOR 3 -#define SONYPI_CAMERA_SHARPNESS 4 - -#define SONYPI_CAMERA_EXPOSURE_MASK 0xC -#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 -#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 -#define SONYPI_CAMERA_MUTE_MASK 0x40 - -/* the rest don't need a loop until not 0xff */ -#define SONYPI_CAMERA_AGC 6 -#define SONYPI_CAMERA_AGC_MASK 0x30 -#define SONYPI_CAMERA_SHUTTER_MASK 0x7 - -#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 -#define SONYPI_CAMERA_CONTROL 0x10 - -#define SONYPI_CAMERA_STATUS 7 -#define SONYPI_CAMERA_STATUS_READY 0x2 -#define SONYPI_CAMERA_STATUS_POSITION 0x4 - -#define SONYPI_DIRECTION_BACKWARDS 0x4 - -#define SONYPI_CAMERA_REVISION 8 -#define SONYPI_CAMERA_ROMVERSION 9 - -static int __sony_pic_camera_ready(void) -{ - u8 v; - - v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); - return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); -} - -static int __sony_pic_camera_off(void) -{ - if (!camera) { - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); - return -ENODEV; - } - - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, - SONYPI_CAMERA_MUTE_MASK), - ITERATIONS_SHORT); - - if (spic_dev.camera_power) { - sony_pic_call2(0x91, 0); - spic_dev.camera_power = 0; - } - return 0; -} - -static int __sony_pic_camera_on(void) -{ - int i, j, x; - - if (!camera) { - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); - return -ENODEV; - } - - if (spic_dev.camera_power) - return 0; - - for (j = 5; j > 0; j--) { - - for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++) - msleep(10); - sony_pic_call1(0x93); - - for (i = 400; i > 0; i--) { - if (__sony_pic_camera_ready()) - break; - msleep(10); - } - if (i) - break; - } - - if (j == 0) { - printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); - return -ENODEV; - } - - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, - 0x5a), - ITERATIONS_SHORT); - - spic_dev.camera_power = 1; - return 0; -} - -/* External camera command (exported to the motion eye v4l driver) */ -int sony_pic_camera_command(int command, u8 value) -{ - if (!camera) - return -EIO; - - mutex_lock(&spic_dev.lock); - - switch (command) { - case SONY_PIC_COMMAND_SETCAMERA: - if (value) - __sony_pic_camera_on(); - else - __sony_pic_camera_off(); - break; - case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERACONTRAST: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERAHUE: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERACOLOR: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERASHARPNESS: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERAPICTURE: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value), - ITERATIONS_SHORT); - break; - case SONY_PIC_COMMAND_SETCAMERAAGC: - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value), - ITERATIONS_SHORT); - break; - default: - printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", - command); - break; - } - mutex_unlock(&spic_dev.lock); - return 0; -} -EXPORT_SYMBOL(sony_pic_camera_command); - -/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */ -static void sony_pic_set_wwanpower(u8 state) -{ - state = !!state; - mutex_lock(&spic_dev.lock); - if (spic_dev.wwan_power == state) { - mutex_unlock(&spic_dev.lock); - return; - } - sony_pic_call2(0xB0, state); - spic_dev.wwan_power = state; - mutex_unlock(&spic_dev.lock); -} - -static ssize_t sony_pic_wwanpower_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned long value; - if (count > 31) - return -EINVAL; - - value = simple_strtoul(buffer, NULL, 10); - sony_pic_set_wwanpower(value); - - return count; -} - -static ssize_t sony_pic_wwanpower_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - ssize_t count; - mutex_lock(&spic_dev.lock); - count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power); - mutex_unlock(&spic_dev.lock); - return count; -} - -/* bluetooth subsystem power state */ -static void __sony_pic_set_bluetoothpower(u8 state) -{ - state = !!state; - if (spic_dev.bluetooth_power == state) - return; - sony_pic_call2(0x96, state); - sony_pic_call1(0x82); - spic_dev.bluetooth_power = state; -} - -static ssize_t sony_pic_bluetoothpower_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned long value; - if (count > 31) - return -EINVAL; - - value = simple_strtoul(buffer, NULL, 10); - mutex_lock(&spic_dev.lock); - __sony_pic_set_bluetoothpower(value); - mutex_unlock(&spic_dev.lock); - - return count; -} - -static ssize_t sony_pic_bluetoothpower_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - ssize_t count = 0; - mutex_lock(&spic_dev.lock); - count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); - mutex_unlock(&spic_dev.lock); - return count; -} - -/* fan speed */ -/* FAN0 information (reverse engineered from ACPI tables) */ -#define SONY_PIC_FAN0_STATUS 0x93 -static int sony_pic_set_fanspeed(unsigned long value) -{ - return ec_write(SONY_PIC_FAN0_STATUS, value); -} - -static int sony_pic_get_fanspeed(u8 *value) -{ - return ec_read(SONY_PIC_FAN0_STATUS, value); -} - -static ssize_t sony_pic_fanspeed_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned long value; - if (count > 31) - return -EINVAL; - - value = simple_strtoul(buffer, NULL, 10); - if (sony_pic_set_fanspeed(value)) - return -EIO; - - return count; -} - -static ssize_t sony_pic_fanspeed_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - u8 value = 0; - if (sony_pic_get_fanspeed(&value)) - return -EIO; - - return snprintf(buffer, PAGE_SIZE, "%d\n", value); -} - -#define SPIC_ATTR(_name, _mode) \ -struct device_attribute spic_attr_##_name = __ATTR(_name, \ - _mode, sony_pic_## _name ##_show, \ - sony_pic_## _name ##_store) - -static SPIC_ATTR(bluetoothpower, 0644); -static SPIC_ATTR(wwanpower, 0644); -static SPIC_ATTR(fanspeed, 0644); - -static struct attribute *spic_attributes[] = { - &spic_attr_bluetoothpower.attr, - &spic_attr_wwanpower.attr, - &spic_attr_fanspeed.attr, - NULL -}; - -static struct attribute_group spic_attribute_group = { - .attrs = spic_attributes -}; - -/******** SONYPI compatibility **********/ -#ifdef CONFIG_SONY_LAPTOP_OLD - -/* battery / brightness / temperature addresses */ -#define SONYPI_BAT_FLAGS 0x81 -#define SONYPI_LCD_LIGHT 0x96 -#define SONYPI_BAT1_PCTRM 0xa0 -#define SONYPI_BAT1_LEFT 0xa2 -#define SONYPI_BAT1_MAXRT 0xa4 -#define SONYPI_BAT2_PCTRM 0xa8 -#define SONYPI_BAT2_LEFT 0xaa -#define SONYPI_BAT2_MAXRT 0xac -#define SONYPI_BAT1_MAXTK 0xb0 -#define SONYPI_BAT1_FULL 0xb2 -#define SONYPI_BAT2_MAXTK 0xb8 -#define SONYPI_BAT2_FULL 0xba -#define SONYPI_TEMP_STATUS 0xC1 - -struct sonypi_compat_s { - struct fasync_struct *fifo_async; - struct kfifo *fifo; - spinlock_t fifo_lock; - wait_queue_head_t fifo_proc_list; - atomic_t open_count; -}; -static struct sonypi_compat_s sonypi_compat = { - .open_count = ATOMIC_INIT(0), -}; - -static int sonypi_misc_fasync(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async); - if (retval < 0) - return retval; - return 0; -} - -static int sonypi_misc_release(struct inode *inode, struct file *file) +static int __init sony_acpi_init(void) { - sonypi_misc_fasync(-1, file, 0); - atomic_dec(&sonypi_compat.open_count); - return 0; -} - -static int sonypi_misc_open(struct inode *inode, struct file *file) -{ - /* Flush input queue on first open */ - if (atomic_inc_return(&sonypi_compat.open_count) == 1) - kfifo_reset(sonypi_compat.fifo); - return 0; -} - -static ssize_t sonypi_misc_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - ssize_t ret; - unsigned char c; - - if ((kfifo_len(sonypi_compat.fifo) == 0) && - (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - - ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, - kfifo_len(sonypi_compat.fifo) != 0); - if (ret) - return ret; - - while (ret < count && - (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { - if (put_user(c, buf++)) - return -EFAULT; - ret++; - } - - if (ret > 0) { - struct inode *inode = file->f_path.dentry->d_inode; - inode->i_atime = current_fs_time(inode->i_sb); - } - - return ret; -} - -static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &sonypi_compat.fifo_proc_list, wait); - if (kfifo_len(sonypi_compat.fifo)) - return POLLIN | POLLRDNORM; - return 0; -} - -static int ec_read16(u8 addr, u16 *value) -{ - u8 val_lb, val_hb; - if (ec_read(addr, &val_lb)) - return -1; - if (ec_read(addr + 1, &val_hb)) - return -1; - *value = val_lb | (val_hb << 8); - return 0; -} - -static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - void __user *argp = (void __user *)arg; - u8 val8; - u16 val16; - int value; - - mutex_lock(&spic_dev.lock); - switch (cmd) { - case SONYPI_IOCGBRT: - if (sony_backlight_device == NULL) { - ret = -EIO; - break; - } - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { - ret = -EIO; - break; - } - val8 = ((value & 0xff) - 1) << 5; - if (copy_to_user(argp, &val8, sizeof(val8))) - ret = -EFAULT; - break; - case SONYPI_IOCSBRT: - if (sony_backlight_device == NULL) { - ret = -EIO; - break; - } - if (copy_from_user(&val8, argp, sizeof(val8))) { - ret = -EFAULT; - break; - } - if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", - (val8 >> 5) + 1, NULL)) { - ret = -EIO; - break; - } - /* sync the backlight device status */ - sony_backlight_device->props.brightness = - sony_backlight_get_brightness(sony_backlight_device); - break; - case SONYPI_IOCGBAT1CAP: - if (ec_read16(SONYPI_BAT1_FULL, &val16)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val16, sizeof(val16))) - ret = -EFAULT; - break; - case SONYPI_IOCGBAT1REM: - if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val16, sizeof(val16))) - ret = -EFAULT; - break; - case SONYPI_IOCGBAT2CAP: - if (ec_read16(SONYPI_BAT2_FULL, &val16)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val16, sizeof(val16))) - ret = -EFAULT; - break; - case SONYPI_IOCGBAT2REM: - if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val16, sizeof(val16))) - ret = -EFAULT; - break; - case SONYPI_IOCGBATFLAGS: - if (ec_read(SONYPI_BAT_FLAGS, &val8)) { - ret = -EIO; - break; - } - val8 &= 0x07; - if (copy_to_user(argp, &val8, sizeof(val8))) - ret = -EFAULT; - break; - case SONYPI_IOCGBLUE: - val8 = spic_dev.bluetooth_power; - if (copy_to_user(argp, &val8, sizeof(val8))) - ret = -EFAULT; - break; - case SONYPI_IOCSBLUE: - if (copy_from_user(&val8, argp, sizeof(val8))) { - ret = -EFAULT; - break; - } - __sony_pic_set_bluetoothpower(val8); - break; - /* FAN Controls */ - case SONYPI_IOCGFAN: - if (sony_pic_get_fanspeed(&val8)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val8, sizeof(val8))) - ret = -EFAULT; - break; - case SONYPI_IOCSFAN: - if (copy_from_user(&val8, argp, sizeof(val8))) { - ret = -EFAULT; - break; - } - if (sony_pic_set_fanspeed(val8)) - ret = -EIO; - break; - /* GET Temperature (useful under APM) */ - case SONYPI_IOCGTEMP: - if (ec_read(SONYPI_TEMP_STATUS, &val8)) { - ret = -EIO; - break; - } - if (copy_to_user(argp, &val8, sizeof(val8))) - ret = -EFAULT; - break; - default: - ret = -EINVAL; - } - mutex_unlock(&spic_dev.lock); - return ret; -} - -static const struct file_operations sonypi_misc_fops = { - .owner = THIS_MODULE, - .read = sonypi_misc_read, - .poll = sonypi_misc_poll, - .open = sonypi_misc_open, - .release = sonypi_misc_release, - .fasync = sonypi_misc_fasync, - .ioctl = sonypi_misc_ioctl, -}; - -static struct miscdevice sonypi_misc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "sonypi", - .fops = &sonypi_misc_fops, -}; - -static void sonypi_compat_report_event(u8 event) -{ - kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); - kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); - wake_up_interruptible(&sonypi_compat.fifo_proc_list); -} - -static int sonypi_compat_init(void) -{ - int error; - - spin_lock_init(&sonypi_compat.fifo_lock); - sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, - &sonypi_compat.fifo_lock); - if (IS_ERR(sonypi_compat.fifo)) { - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); - return PTR_ERR(sonypi_compat.fifo); - } - - init_waitqueue_head(&sonypi_compat.fifo_proc_list); - - if (minor != -1) - sonypi_misc_device.minor = minor; - error = misc_register(&sonypi_misc_device); - if (error) { - printk(KERN_ERR DRV_PFX "misc_register failed\n"); - goto err_free_kfifo; - } - if (minor == -1) - printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", - sonypi_misc_device.minor); - - return 0; - -err_free_kfifo: - kfifo_free(sonypi_compat.fifo); - return error; -} - -static void sonypi_compat_exit(void) -{ - misc_deregister(&sonypi_misc_device); - kfifo_free(sonypi_compat.fifo); -} -#else -static int sonypi_compat_init(void) { return 0; } -static void sonypi_compat_exit(void) { } -static void sonypi_compat_report_event(u8 event) { } -#endif /* CONFIG_SONY_LAPTOP_OLD */ - -/* - * ACPI callbacks - */ -static acpi_status -sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) -{ - u32 i; - struct sony_pic_dev *dev = (struct sony_pic_dev *)context; - - switch (resource->type) { - case ACPI_RESOURCE_TYPE_START_DEPENDENT: - case ACPI_RESOURCE_TYPE_END_DEPENDENT: - return AE_OK; - - case ACPI_RESOURCE_TYPE_IRQ: - { - struct acpi_resource_irq *p = &resource->data.irq; - struct sony_pic_irq *interrupt = NULL; - if (!p || !p->interrupt_count) { - /* - * IRQ descriptors may have no IRQ# bits set, - * particularly those those w/ _STA disabled - */ - dprintk("Blank IRQ resource\n"); - return AE_OK; - } - for (i = 0; i < p->interrupt_count; i++) { - if (!p->interrupts[i]) { - printk(KERN_WARNING DRV_PFX - "Invalid IRQ %d\n", - p->interrupts[i]); - continue; - } - interrupt = kzalloc(sizeof(*interrupt), - GFP_KERNEL); - if (!interrupt) - return AE_ERROR; - - list_add_tail(&interrupt->list, &dev->interrupts); - interrupt->irq.triggering = p->triggering; - interrupt->irq.polarity = p->polarity; - interrupt->irq.sharable = p->sharable; - interrupt->irq.interrupt_count = 1; - interrupt->irq.interrupts[0] = p->interrupts[i]; - } - return AE_OK; - } - case ACPI_RESOURCE_TYPE_IO: - { - struct acpi_resource_io *io = &resource->data.io; - struct sony_pic_ioport *ioport = NULL; - if (!io) { - dprintk("Blank IO resource\n"); - return AE_OK; - } - - ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); - if (!ioport) - return AE_ERROR; - - list_add_tail(&ioport->list, &dev->ioports); - memcpy(&ioport->io, io, sizeof(*io)); - return AE_OK; - } - default: - dprintk("Resource %d isn't an IRQ nor an IO port\n", - resource->type); - - case ACPI_RESOURCE_TYPE_END_TAG: - return AE_OK; - } - return AE_CTRL_TERMINATE; -} - -static int sony_pic_possible_resources(struct acpi_device *device) -{ - int result = 0; - acpi_status status = AE_OK; - - if (!device) - return -EINVAL; - - /* get device status */ - /* see acpi_pci_link_get_current acpi_pci_link_get_possible */ - dprintk("Evaluating _STA\n"); - result = acpi_bus_get_status(device); - if (result) { - printk(KERN_WARNING DRV_PFX "Unable to read status\n"); - goto end; - } - - if (!device->status.enabled) - dprintk("Device disabled\n"); - else - dprintk("Device enabled\n"); - - /* - * Query and parse 'method' - */ - dprintk("Evaluating %s\n", METHOD_NAME__PRS); - status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, - sony_pic_read_possible_resource, &spic_dev); - if (ACPI_FAILURE(status)) { - printk(KERN_WARNING DRV_PFX - "Failure evaluating %s\n", - METHOD_NAME__PRS); - result = -ENODEV; - } -end: - return result; -} - -/* - * Disable the spic device by calling its _DIS method - */ -static int sony_pic_disable(struct acpi_device *device) -{ - if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL))) - return -ENXIO; - - dprintk("Device disabled\n"); - return 0; -} - - -/* - * Based on drivers/acpi/pci_link.c:acpi_pci_link_set - * - * Call _SRS to set current resources - */ -static int sony_pic_enable(struct acpi_device *device, - struct sony_pic_ioport *ioport, struct sony_pic_irq *irq) -{ - acpi_status status; - int result = 0; - struct { - struct acpi_resource io_res; - struct acpi_resource irq_res; - struct acpi_resource end; - } *resource; - struct acpi_buffer buffer = { 0, NULL }; - - if (!ioport || !irq) - return -EINVAL; - - /* init acpi_buffer */ - resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL); - if (!resource) - return -ENOMEM; - - buffer.length = sizeof(*resource) + 1; - buffer.pointer = resource; - - /* setup io resource */ - resource->io_res.type = ACPI_RESOURCE_TYPE_IO; - resource->io_res.length = sizeof(struct acpi_resource); - memcpy(&resource->io_res.data.io, &ioport->io, - sizeof(struct acpi_resource_io)); - - /* setup irq resource */ - resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ; - resource->irq_res.length = sizeof(struct acpi_resource); - memcpy(&resource->irq_res.data.irq, &irq->irq, - sizeof(struct acpi_resource_irq)); - /* we requested a shared irq */ - resource->irq_res.data.irq.sharable = ACPI_SHARED; - - resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; - - /* Attempt to set the resource */ - dprintk("Evaluating _SRS\n"); - status = acpi_set_current_resources(device->handle, &buffer); - - /* check for total failure */ - if (ACPI_FAILURE(status)) { - printk(KERN_ERR DRV_PFX "Error evaluating _SRS"); - result = -ENODEV; - goto end; - } - - /* Necessary device initializations calls (from sonypi) */ - sony_pic_call1(0x82); - sony_pic_call2(0x81, 0xff); - sony_pic_call1(compat ? 0x92 : 0x82); - -end: - kfree(resource); - return result; -} - -/***************** - * - * ISR: some event is available - * - *****************/ -static irqreturn_t sony_pic_irq(int irq, void *dev_id) -{ - int i, j; - u32 port_val = 0; - u8 ev = 0; - u8 data_mask = 0; - u8 device_event = 0; - - struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; - - acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val, - dev->cur_ioport->io.address_length); - ev = port_val & SONY_PIC_EV_MASK; - data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8)); - - dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n", - port_val, ev, data_mask, dev->cur_ioport->io.minimum); - - if (ev == 0x00 || ev == 0xff) - return IRQ_HANDLED; - - for (i = 0; sony_pic_eventtypes[i].model; i++) { - - if (spic_dev.model != sony_pic_eventtypes[i].model) - continue; - - if ((data_mask & sony_pic_eventtypes[i].data) != - sony_pic_eventtypes[i].data) - continue; - - if (!(mask & sony_pic_eventtypes[i].mask)) - continue; - - for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) { - if (ev == sony_pic_eventtypes[i].events[j].data) { - device_event = - sony_pic_eventtypes[i].events[j].event; - goto found; - } - } - } - return IRQ_HANDLED; - -found: - sony_laptop_report_input_event(device_event); - acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event); - sonypi_compat_report_event(device_event); - - return IRQ_HANDLED; -} - -/***************** - * - * ACPI driver - * - *****************/ -static int sony_pic_remove(struct acpi_device *device, int type) -{ - struct sony_pic_ioport *io, *tmp_io; - struct sony_pic_irq *irq, *tmp_irq; - - sonypi_compat_exit(); - - if (sony_pic_disable(device)) { - printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); - return -ENXIO; - } - - free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); - release_region(spic_dev.cur_ioport->io.minimum, - spic_dev.cur_ioport->io.address_length); - - sony_laptop_remove_input(); - - /* pf attrs */ - sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); - sony_pf_remove(); - - list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { - list_del(&io->list); - kfree(io); - } - list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { - list_del(&irq->list); - kfree(irq); - } - spic_dev.cur_ioport = NULL; - spic_dev.cur_irq = NULL; - - dprintk(SONY_PIC_DRIVER_NAME " removed.\n"); - return 0; -} - -static int sony_pic_add(struct acpi_device *device) -{ - int result; - struct sony_pic_ioport *io, *tmp_io; - struct sony_pic_irq *irq, *tmp_irq; - - printk(KERN_INFO DRV_PFX "%s v%s.\n", - SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); - - spic_dev.acpi_dev = device; - strcpy(acpi_device_class(device), "sony/hotkey"); - spic_dev.model = sony_pic_detect_device_type(); - mutex_init(&spic_dev.lock); - - /* read _PRS resources */ - result = sony_pic_possible_resources(device); - if (result) { - printk(KERN_ERR DRV_PFX - "Unabe to read possible resources.\n"); - goto err_free_resources; - } - - /* setup input devices and helper fifo */ - result = sony_laptop_setup_input(); - if (result) { - printk(KERN_ERR DRV_PFX - "Unabe to create input devices.\n"); - goto err_free_resources; - } - - /* request io port */ - list_for_each_entry(io, &spic_dev.ioports, list) { - if (request_region(io->io.minimum, io->io.address_length, - "Sony Programable I/O Device")) { - dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n", - io->io.minimum, io->io.maximum, - io->io.address_length); - spic_dev.cur_ioport = io; - break; - } - } - if (!spic_dev.cur_ioport) { - printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); - result = -ENODEV; - goto err_remove_input; - } - - /* request IRQ */ - list_for_each_entry(irq, &spic_dev.interrupts, list) { - if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, - IRQF_SHARED, "sony-laptop", &spic_dev)) { - dprintk("IRQ: %d - triggering: %d - " - "polarity: %d - shr: %d\n", - irq->irq.interrupts[0], - irq->irq.triggering, - irq->irq.polarity, - irq->irq.sharable); - spic_dev.cur_irq = irq; - break; - } - } - if (!spic_dev.cur_irq) { - printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); - result = -ENODEV; - goto err_release_region; - } - - /* set resource status _SRS */ - result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); - if (result) { - printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); - goto err_free_irq; - } - - spic_dev.bluetooth_power = -1; - /* create device attributes */ - result = sony_pf_add(); - if (result) - goto err_disable_device; - - result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); - if (result) - goto err_remove_pf; - - if (sonypi_compat_init()) - goto err_remove_pf; - - return 0; - -err_remove_pf: - sony_pf_remove(); - -err_disable_device: - sony_pic_disable(device); - -err_free_irq: - free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); - -err_release_region: - release_region(spic_dev.cur_ioport->io.minimum, - spic_dev.cur_ioport->io.address_length); - -err_remove_input: - sony_laptop_remove_input(); - -err_free_resources: - list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { - list_del(&io->list); - kfree(io); - } - list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) { - list_del(&irq->list); - kfree(irq); - } - spic_dev.cur_ioport = NULL; - spic_dev.cur_irq = NULL; - - return result; -} - -static int sony_pic_suspend(struct acpi_device *device, pm_message_t state) -{ - if (sony_pic_disable(device)) - return -ENXIO; - return 0; -} - -static int sony_pic_resume(struct acpi_device *device) -{ - sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); - return 0; -} - -static struct acpi_driver sony_pic_driver = { - .name = SONY_PIC_DRIVER_NAME, - .class = SONY_PIC_CLASS, - .ids = SONY_PIC_HID, - .owner = THIS_MODULE, - .ops = { - .add = sony_pic_add, - .remove = sony_pic_remove, - .suspend = sony_pic_suspend, - .resume = sony_pic_resume, - }, -}; - -static struct dmi_system_id __initdata sonypi_dmi_table[] = { - { - .ident = "Sony Vaio", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), - }, - }, - { - .ident = "Sony Vaio", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), - }, - }, - { } -}; - -static int __init sony_laptop_init(void) -{ - int result; - - if (!no_spic && dmi_check_system(sonypi_dmi_table)) { - result = acpi_bus_register_driver(&sony_pic_driver); - if (result) { - printk(KERN_ERR DRV_PFX - "Unable to register SPIC driver."); - goto out; - } - } - - result = acpi_bus_register_driver(&sony_nc_driver); - if (result) { - printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); - goto out_unregister_pic; - } - - return 0; - -out_unregister_pic: - if (!no_spic) - acpi_bus_unregister_driver(&sony_pic_driver); -out: - return result; + return acpi_bus_register_driver(&sony_acpi_driver); } -static void __exit sony_laptop_exit(void) +static void __exit sony_acpi_exit(void) { - acpi_bus_unregister_driver(&sony_nc_driver); - if (!no_spic) - acpi_bus_unregister_driver(&sony_pic_driver); + acpi_bus_unregister_driver(&sony_acpi_driver); } -module_init(sony_laptop_init); -module_exit(sony_laptop_exit); +module_init(sony_acpi_init); +module_exit(sony_acpi_exit); diff --git a/trunk/drivers/misc/thinkpad_acpi.c b/trunk/drivers/misc/thinkpad_acpi.c deleted file mode 100644 index 6c36a55cb3d1..000000000000 --- a/trunk/drivers/misc/thinkpad_acpi.c +++ /dev/null @@ -1,4312 +0,0 @@ -/* - * thinkpad_acpi.c - ThinkPad ACPI Extras - * - * - * Copyright (C) 2004-2005 Borislav Deianov - * Copyright (C) 2006-2007 Henrique de Moraes Holschuh - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#define IBM_VERSION "0.14" -#define TPACPI_SYSFS_VERSION 0x000100 - -/* - * Changelog: - * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to - * drivers/misc. - * - * 2006-11-22 0.13 new maintainer - * changelog now lives in git commit history, and will - * not be updated further in-file. - * - * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels - * 2005-03-17 0.11 support for 600e, 770x - * thanks to Jamie Lentin - * support for 770e, G41 - * G40 and G41 don't have a thinklight - * temperatures no longer experimental - * experimental brightness control - * experimental volume control - * experimental fan enable/disable - * 2005-01-16 0.10 fix module loading on R30, R31 - * 2005-01-16 0.9 support for 570, R30, R31 - * ultrabay support on A22p, A3x - * limit arg for cmos, led, beep, drop experimental status - * more capable led control on A21e, A22p, T20-22, X20 - * experimental temperatures and fan speed - * experimental embedded controller register dump - * mark more functions as __init, drop incorrect __exit - * use MODULE_VERSION - * thanks to Henrik Brix Andersen - * fix parameter passing on module loading - * thanks to Rusty Russell - * thanks to Jim Radford - * 2004-11-08 0.8 fix init error case, don't return from a macro - * thanks to Chris Wright - * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 - * fix led control on A21e - * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device - * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 - * proc file format changed - * video_switch command - * experimental cmos control - * experimental led control - * experimental acpi sounds - * 2004-09-16 0.4 support for module parameters - * hotkey mask can be prefixed by 0x - * video output switching - * video expansion control - * ultrabay eject support - * removed lcd brightness/on/off control, didn't work - * 2004-08-17 0.3 support for R40 - * lcd off, brightness control - * thinklight on/off - * 2004-08-14 0.2 support for T series, X20 - * bluetooth enable/disable - * hotkey events disabled by default - * removed fan control, currently useless - * 2004-08-09 0.1 initial release, support for X series - */ - -#include "thinkpad_acpi.h" - -MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); -MODULE_DESCRIPTION(IBM_DESC); -MODULE_VERSION(IBM_VERSION); -MODULE_LICENSE("GPL"); - -/* Please remove this in year 2009 */ -MODULE_ALIAS("ibm_acpi"); - -#define __unused __attribute__ ((unused)) - -/**************************************************************************** - **************************************************************************** - * - * ACPI Helpers and device model - * - **************************************************************************** - ****************************************************************************/ - -/************************************************************************* - * ACPI basic handles - */ - -static acpi_handle root_handle = NULL; - -#define IBM_HANDLE(object, parent, paths...) \ - static acpi_handle object##_handle; \ - static acpi_handle *object##_parent = &parent##_handle; \ - static char *object##_path; \ - static char *object##_paths[] = { paths } - -IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ - "\\_SB.PCI.ISA.EC", /* 570 */ - "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ - "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ - "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ - "\\_SB.PCI0.ICH3.EC0", /* R31 */ - "\\_SB.PCI0.LPC.EC", /* all others */ - ); - -IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ -IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ - - -/************************************************************************* - * Misc ACPI handles - */ - -IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ - "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ - "\\CMS", /* R40, R40e */ - ); /* all others */ - -IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ - "^HKEY", /* R30, R31 */ - "HKEY", /* all others */ - ); /* 570 */ - - -/************************************************************************* - * ACPI helpers - */ - -static int acpi_evalf(acpi_handle handle, - void *res, char *method, char *fmt, ...) -{ - char *fmt0 = fmt; - struct acpi_object_list params; - union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; - struct acpi_buffer result, *resultp; - union acpi_object out_obj; - acpi_status status; - va_list ap; - char res_type; - int success; - int quiet; - - if (!*fmt) { - printk(IBM_ERR "acpi_evalf() called with empty format\n"); - return 0; - } - - if (*fmt == 'q') { - quiet = 1; - fmt++; - } else - quiet = 0; - - res_type = *(fmt++); - - params.count = 0; - params.pointer = &in_objs[0]; - - va_start(ap, fmt); - while (*fmt) { - char c = *(fmt++); - switch (c) { - case 'd': /* int */ - in_objs[params.count].integer.value = va_arg(ap, int); - in_objs[params.count++].type = ACPI_TYPE_INTEGER; - break; - /* add more types as needed */ - default: - printk(IBM_ERR "acpi_evalf() called " - "with invalid format character '%c'\n", c); - return 0; - } - } - va_end(ap); - - if (res_type != 'v') { - result.length = sizeof(out_obj); - result.pointer = &out_obj; - resultp = &result; - } else - resultp = NULL; - - status = acpi_evaluate_object(handle, method, ¶ms, resultp); - - switch (res_type) { - case 'd': /* int */ - if (res) - *(int *)res = out_obj.integer.value; - success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; - break; - case 'v': /* void */ - success = status == AE_OK; - break; - /* add more types as needed */ - default: - printk(IBM_ERR "acpi_evalf() called " - "with invalid format character '%c'\n", res_type); - return 0; - } - - if (!success && !quiet) - printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", - method, fmt0, status); - - return success; -} - -static void __unused acpi_print_int(acpi_handle handle, char *method) -{ - int i; - - if (acpi_evalf(handle, &i, method, "d")) - printk(IBM_INFO "%s = 0x%x\n", method, i); - else - printk(IBM_ERR "error calling %s\n", method); -} - -static int acpi_ec_read(int i, u8 * p) -{ - int v; - - if (ecrd_handle) { - if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) - return 0; - *p = v; - } else { - if (ec_read(i, p) < 0) - return 0; - } - - return 1; -} - -static int acpi_ec_write(int i, u8 v) -{ - if (ecwr_handle) { - if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) - return 0; - } else { - if (ec_write(i, v) < 0) - return 0; - } - - return 1; -} - -static int _sta(acpi_handle handle) -{ - int status; - - if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) - status = 0; - - return status; -} - -static int issue_thinkpad_cmos_command(int cmos_cmd) -{ - if (!cmos_handle) - return -ENXIO; - - if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) - return -EIO; - - return 0; -} - -/************************************************************************* - * ACPI device model - */ - -static void drv_acpi_handle_init(char *name, - acpi_handle *handle, acpi_handle parent, - char **paths, int num_paths, char **path) -{ - int i; - acpi_status status; - - vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n", - name); - - for (i = 0; i < num_paths; i++) { - status = acpi_get_handle(parent, paths[i], handle); - if (ACPI_SUCCESS(status)) { - *path = paths[i]; - dbg_printk(TPACPI_DBG_INIT, - "Found ACPI handle %s for %s\n", - *path, name); - return; - } - } - - vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", - name); - *handle = NULL; -} - -static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) -{ - struct ibm_struct *ibm = data; - - if (!ibm || !ibm->acpi || !ibm->acpi->notify) - return; - - ibm->acpi->notify(ibm, event); -} - -static int __init setup_acpi_notify(struct ibm_struct *ibm) -{ - acpi_status status; - int rc; - - BUG_ON(!ibm->acpi); - - if (!*ibm->acpi->handle) - return 0; - - vdbg_printk(TPACPI_DBG_INIT, - "setting up ACPI notify for %s\n", ibm->name); - - rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); - if (rc < 0) { - printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", - ibm->name, rc); - return -ENODEV; - } - - acpi_driver_data(ibm->acpi->device) = ibm; - sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", - IBM_ACPI_EVENT_PREFIX, - ibm->name); - - status = acpi_install_notify_handler(*ibm->acpi->handle, - ibm->acpi->type, dispatch_acpi_notify, ibm); - if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - printk(IBM_NOTICE "another device driver is already handling %s events\n", - ibm->name); - } else { - printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", - ibm->name, status); - } - return -ENODEV; - } - ibm->flags.acpi_notify_installed = 1; - return 0; -} - -static int __init tpacpi_device_add(struct acpi_device *device) -{ - return 0; -} - -static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) -{ - int rc; - - dbg_printk(TPACPI_DBG_INIT, - "registering %s as an ACPI driver\n", ibm->name); - - BUG_ON(!ibm->acpi); - - ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); - if (!ibm->acpi->driver) { - printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); - return -ENOMEM; - } - - sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); - ibm->acpi->driver->ids = ibm->acpi->hid; - ibm->acpi->driver->ops.add = &tpacpi_device_add; - - rc = acpi_bus_register_driver(ibm->acpi->driver); - if (rc < 0) { - printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", - ibm->acpi->hid, rc); - kfree(ibm->acpi->driver); - ibm->acpi->driver = NULL; - } else if (!rc) - ibm->flags.acpi_driver_registered = 1; - - return rc; -} - - -/**************************************************************************** - **************************************************************************** - * - * Procfs Helpers - * - **************************************************************************** - ****************************************************************************/ - -static int dispatch_procfs_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct ibm_struct *ibm = data; - int len; - - if (!ibm || !ibm->read) - return -EINVAL; - - len = ibm->read(page); - if (len < 0) - return len; - - if (len <= off + count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - - return len; -} - -static int dispatch_procfs_write(struct file *file, - const char __user * userbuf, - unsigned long count, void *data) -{ - struct ibm_struct *ibm = data; - char *kernbuf; - int ret; - - if (!ibm || !ibm->write) - return -EINVAL; - - kernbuf = kmalloc(count + 2, GFP_KERNEL); - if (!kernbuf) - return -ENOMEM; - - if (copy_from_user(kernbuf, userbuf, count)) { - kfree(kernbuf); - return -EFAULT; - } - - kernbuf[count] = 0; - strcat(kernbuf, ","); - ret = ibm->write(kernbuf); - if (ret == 0) - ret = count; - - kfree(kernbuf); - - return ret; -} - -static char *next_cmd(char **cmds) -{ - char *start = *cmds; - char *end; - - while ((end = strchr(start, ',')) && end == start) - start = end + 1; - - if (!end) - return NULL; - - *end = 0; - *cmds = end + 1; - return start; -} - - -/**************************************************************************** - **************************************************************************** - * - * Device model: hwmon and platform - * - **************************************************************************** - ****************************************************************************/ - -static struct platform_device *tpacpi_pdev = NULL; -static struct class_device *tpacpi_hwmon = NULL; - -static struct platform_driver tpacpi_pdriver = { - .driver = { - .name = IBM_DRVR_NAME, - .owner = THIS_MODULE, - }, -}; - - -/************************************************************************* - * thinkpad-acpi driver attributes - */ - -/* interface_version --------------------------------------------------- */ -static ssize_t tpacpi_driver_interface_version_show( - struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); -} - -static DRIVER_ATTR(interface_version, S_IRUGO, - tpacpi_driver_interface_version_show, NULL); - -/* debug_level --------------------------------------------------------- */ -static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); -} - -static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, - const char *buf, size_t count) -{ - unsigned long t; - - if (parse_strtoul(buf, 0xffff, &t)) - return -EINVAL; - - dbg_level = t; - - return count; -} - -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, - tpacpi_driver_debug_show, tpacpi_driver_debug_store); - -/* version ------------------------------------------------------------- */ -static ssize_t tpacpi_driver_version_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); -} - -static DRIVER_ATTR(version, S_IRUGO, - tpacpi_driver_version_show, NULL); - -/* --------------------------------------------------------------------- */ - -static struct driver_attribute* tpacpi_driver_attributes[] = { - &driver_attr_debug_level, &driver_attr_version, - &driver_attr_interface_version, -}; - -static int __init tpacpi_create_driver_attributes(struct device_driver *drv) -{ - int i, res; - - i = 0; - res = 0; - while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { - res = driver_create_file(drv, tpacpi_driver_attributes[i]); - i++; - } - - return res; -} - -static void tpacpi_remove_driver_attributes(struct device_driver *drv) -{ - int i; - - for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) - driver_remove_file(drv, tpacpi_driver_attributes[i]); -} - -/************************************************************************* - * sysfs support helpers - */ - -struct attribute_set_obj { - struct attribute_set s; - struct attribute *a; -} __attribute__((packed)); - -static struct attribute_set *create_attr_set(unsigned int max_members, - const char* name) -{ - struct attribute_set_obj *sobj; - - if (max_members == 0) - return NULL; - - /* Allocates space for implicit NULL at the end too */ - sobj = kzalloc(sizeof(struct attribute_set_obj) + - max_members * sizeof(struct attribute *), - GFP_KERNEL); - if (!sobj) - return NULL; - sobj->s.max_members = max_members; - sobj->s.group.attrs = &sobj->a; - sobj->s.group.name = name; - - return &sobj->s; -} - -/* not multi-threaded safe, use it in a single thread per set */ -static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) -{ - if (!s || !attr) - return -EINVAL; - - if (s->members >= s->max_members) - return -ENOMEM; - - s->group.attrs[s->members] = attr; - s->members++; - - return 0; -} - -static int add_many_to_attr_set(struct attribute_set* s, - struct attribute **attr, - unsigned int count) -{ - int i, res; - - for (i = 0; i < count; i++) { - res = add_to_attr_set(s, attr[i]); - if (res) - return res; - } - - return 0; -} - -static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) -{ - sysfs_remove_group(kobj, &s->group); - destroy_attr_set(s); -} - -static int parse_strtoul(const char *buf, - unsigned long max, unsigned long *value) -{ - char *endp; - - *value = simple_strtoul(buf, &endp, 0); - while (*endp && isspace(*endp)) - endp++; - if (*endp || *value > max) - return -EINVAL; - - return 0; -} - -/**************************************************************************** - **************************************************************************** - * - * Subdrivers - * - **************************************************************************** - ****************************************************************************/ - -/************************************************************************* - * thinkpad-acpi init subdriver - */ - -static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) -{ - printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); - printk(IBM_INFO "%s\n", IBM_URL); - - if (ibm_thinkpad_ec_found) - printk(IBM_INFO "ThinkPad EC firmware %s\n", - ibm_thinkpad_ec_found); - - return 0; -} - -static int thinkpad_acpi_driver_read(char *p) -{ - int len = 0; - - len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); - len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); - - return len; -} - -static struct ibm_struct thinkpad_acpi_driver_data = { - .name = "driver", - .read = thinkpad_acpi_driver_read, -}; - -/************************************************************************* - * Hotkey subdriver - */ - -static int hotkey_orig_status; -static int hotkey_orig_mask; - -static struct attribute_set *hotkey_dev_attributes = NULL; - -/* sysfs hotkey enable ------------------------------------------------- */ -static ssize_t hotkey_enable_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int res, status, mask; - - res = hotkey_get(&status, &mask); - if (res) - return res; - - return snprintf(buf, PAGE_SIZE, "%d\n", status); -} - -static ssize_t hotkey_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res, status, mask; - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - res = hotkey_get(&status, &mask); - if (!res) - res = hotkey_set(t, mask); - - return (res) ? res : count; -} - -static struct device_attribute dev_attr_hotkey_enable = - __ATTR(enable, S_IWUSR | S_IRUGO, - hotkey_enable_show, hotkey_enable_store); - -/* sysfs hotkey mask --------------------------------------------------- */ -static ssize_t hotkey_mask_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int res, status, mask; - - res = hotkey_get(&status, &mask); - if (res) - return res; - - return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); -} - -static ssize_t hotkey_mask_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res, status, mask; - - if (parse_strtoul(buf, 0xffff, &t)) - return -EINVAL; - - res = hotkey_get(&status, &mask); - if (!res) - hotkey_set(status, t); - - return (res) ? res : count; -} - -static struct device_attribute dev_attr_hotkey_mask = - __ATTR(mask, S_IWUSR | S_IRUGO, - hotkey_mask_show, hotkey_mask_store); - -/* sysfs hotkey bios_enabled ------------------------------------------- */ -static ssize_t hotkey_bios_enabled_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); -} - -static struct device_attribute dev_attr_hotkey_bios_enabled = - __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); - -/* sysfs hotkey bios_mask ---------------------------------------------- */ -static ssize_t hotkey_bios_mask_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); -} - -static struct device_attribute dev_attr_hotkey_bios_mask = - __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); - -/* --------------------------------------------------------------------- */ - -static struct attribute *hotkey_mask_attributes[] = { - &dev_attr_hotkey_mask.attr, - &dev_attr_hotkey_bios_enabled.attr, - &dev_attr_hotkey_bios_mask.attr, -}; - -static int __init hotkey_init(struct ibm_init_struct *iibm) -{ - int res; - - vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); - - IBM_ACPIHANDLE_INIT(hkey); - mutex_init(&hotkey_mutex); - - /* hotkey not supported on 570 */ - tp_features.hotkey = hkey_handle != NULL; - - vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", - str_supported(tp_features.hotkey)); - - if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(4, - TPACPI_HOTKEY_SYSFS_GROUP); - if (!hotkey_dev_attributes) - return -ENOMEM; - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_enable.attr); - if (res) - return res; - - /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, - A30, R30, R31, T20-22, X20-21, X22-24 */ - tp_features.hotkey_mask = - acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); - - vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", - str_supported(tp_features.hotkey_mask)); - - res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); - if (!res && tp_features.hotkey_mask) { - res = add_many_to_attr_set(hotkey_dev_attributes, - hotkey_mask_attributes, - ARRAY_SIZE(hotkey_mask_attributes)); - } - if (!res) - res = register_attr_set_with_sysfs( - hotkey_dev_attributes, - &tpacpi_pdev->dev.kobj); - - if (res) - return res; - } - - return (tp_features.hotkey)? 0 : 1; -} - -static void hotkey_exit(void) -{ - int res; - - if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); - res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); - if (res) - printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); - } - - if (hotkey_dev_attributes) { - delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); - hotkey_dev_attributes = NULL; - } -} - -static void hotkey_notify(struct ibm_struct *ibm, u32 event) -{ - int hkey; - - if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) - acpi_bus_generate_event(ibm->acpi->device, event, hkey); - else { - printk(IBM_ERR "unknown hotkey event %d\n", event); - acpi_bus_generate_event(ibm->acpi->device, event, 0); - } -} - -/* - * Call with hotkey_mutex held - */ -static int hotkey_get(int *status, int *mask) -{ - if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) - return -EIO; - - if (tp_features.hotkey_mask) - if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) - return -EIO; - - return 0; -} - -/* - * Call with hotkey_mutex held - */ -static int hotkey_set(int status, int mask) -{ - int i; - - if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) - return -EIO; - - if (tp_features.hotkey_mask) - for (i = 0; i < 32; i++) { - int bit = ((1 << i) & mask) != 0; - if (!acpi_evalf(hkey_handle, - NULL, "MHKM", "vdd", i + 1, bit)) - return -EIO; - } - - return 0; -} - -/* procfs -------------------------------------------------------------- */ -static int hotkey_read(char *p) -{ - int res, status, mask; - int len = 0; - - if (!tp_features.hotkey) { - len += sprintf(p + len, "status:\t\tnot supported\n"); - return len; - } - - res = mutex_lock_interruptible(&hotkey_mutex); - if (res < 0) - return res; - res = hotkey_get(&status, &mask); - mutex_unlock(&hotkey_mutex); - if (res) - return res; - - len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); - if (tp_features.hotkey_mask) { - len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); - len += sprintf(p + len, - "commands:\tenable, disable, reset, \n"); - } else { - len += sprintf(p + len, "mask:\t\tnot supported\n"); - len += sprintf(p + len, "commands:\tenable, disable, reset\n"); - } - - return len; -} - -static int hotkey_write(char *buf) -{ - int res, status, mask; - char *cmd; - int do_cmd = 0; - - if (!tp_features.hotkey) - return -ENODEV; - - res = mutex_lock_interruptible(&hotkey_mutex); - if (res < 0) - return res; - - res = hotkey_get(&status, &mask); - if (res) - goto errexit; - - res = 0; - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - status = 1; - } else if (strlencmp(cmd, "disable") == 0) { - status = 0; - } else if (strlencmp(cmd, "reset") == 0) { - status = hotkey_orig_status; - mask = hotkey_orig_mask; - } else if (sscanf(cmd, "0x%x", &mask) == 1) { - /* mask set */ - } else if (sscanf(cmd, "%x", &mask) == 1) { - /* mask set */ - } else { - res = -EINVAL; - goto errexit; - } - do_cmd = 1; - } - - if (do_cmd) - res = hotkey_set(status, mask); - -errexit: - mutex_unlock(&hotkey_mutex); - return res; -} - -static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { - .hid = IBM_HKEY_HID, - .notify = hotkey_notify, - .handle = &hkey_handle, - .type = ACPI_DEVICE_NOTIFY, -}; - -static struct ibm_struct hotkey_driver_data = { - .name = "hotkey", - .read = hotkey_read, - .write = hotkey_write, - .exit = hotkey_exit, - .acpi = &ibm_hotkey_acpidriver, -}; - -/************************************************************************* - * Bluetooth subdriver - */ - -/* sysfs bluetooth enable ---------------------------------------------- */ -static ssize_t bluetooth_enable_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int status; - - status = bluetooth_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); -} - -static ssize_t bluetooth_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res; - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - res = bluetooth_set_radiosw(t); - - return (res) ? res : count; -} - -static struct device_attribute dev_attr_bluetooth_enable = - __ATTR(enable, S_IWUSR | S_IRUGO, - bluetooth_enable_show, bluetooth_enable_store); - -/* --------------------------------------------------------------------- */ - -static struct attribute *bluetooth_attributes[] = { - &dev_attr_bluetooth_enable.attr, - NULL -}; - -static const struct attribute_group bluetooth_attr_group = { - .name = TPACPI_BLUETH_SYSFS_GROUP, - .attrs = bluetooth_attributes, -}; - -static int __init bluetooth_init(struct ibm_init_struct *iibm) -{ - int res; - int status = 0; - - vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); - - IBM_ACPIHANDLE_INIT(hkey); - - /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, - G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ - tp_features.bluetooth = hkey_handle && - acpi_evalf(hkey_handle, &status, "GBDC", "qd"); - - vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", - str_supported(tp_features.bluetooth), - status); - - if (tp_features.bluetooth) { - if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { - /* no bluetooth hardware present in system */ - tp_features.bluetooth = 0; - dbg_printk(TPACPI_DBG_INIT, - "bluetooth hardware not installed\n"); - } else { - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); - if (res) - return res; - } - } - - return (tp_features.bluetooth)? 0 : 1; -} - -static void bluetooth_exit(void) -{ - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); -} - -static int bluetooth_get_radiosw(void) -{ - int status; - - if (!tp_features.bluetooth) - return -ENODEV; - - if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) - return -EIO; - - return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0); -} - -static int bluetooth_set_radiosw(int radio_on) -{ - int status; - - if (!tp_features.bluetooth) - return -ENODEV; - - if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) - return -EIO; - if (radio_on) - status |= TP_ACPI_BLUETOOTH_RADIOSSW; - else - status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; - if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) - return -EIO; - - return 0; -} - -/* procfs -------------------------------------------------------------- */ -static int bluetooth_read(char *p) -{ - int len = 0; - int status = bluetooth_get_radiosw(); - - if (!tp_features.bluetooth) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status)? "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; -} - -static int bluetooth_write(char *buf) -{ - char *cmd; - - if (!tp_features.bluetooth) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - bluetooth_set_radiosw(1); - } else if (strlencmp(cmd, "disable") == 0) { - bluetooth_set_radiosw(0); - } else - return -EINVAL; - } - - return 0; -} - -static struct ibm_struct bluetooth_driver_data = { - .name = "bluetooth", - .read = bluetooth_read, - .write = bluetooth_write, - .exit = bluetooth_exit, -}; - -/************************************************************************* - * Wan subdriver - */ - -/* sysfs wan enable ---------------------------------------------------- */ -static ssize_t wan_enable_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int status; - - status = wan_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); -} - -static ssize_t wan_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res; - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - res = wan_set_radiosw(t); - - return (res) ? res : count; -} - -static struct device_attribute dev_attr_wan_enable = - __ATTR(enable, S_IWUSR | S_IRUGO, - wan_enable_show, wan_enable_store); - -/* --------------------------------------------------------------------- */ - -static struct attribute *wan_attributes[] = { - &dev_attr_wan_enable.attr, - NULL -}; - -static const struct attribute_group wan_attr_group = { - .name = TPACPI_WAN_SYSFS_GROUP, - .attrs = wan_attributes, -}; - -static int __init wan_init(struct ibm_init_struct *iibm) -{ - int res; - int status = 0; - - vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); - - IBM_ACPIHANDLE_INIT(hkey); - - tp_features.wan = hkey_handle && - acpi_evalf(hkey_handle, &status, "GWAN", "qd"); - - vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", - str_supported(tp_features.wan), - status); - - if (tp_features.wan) { - if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { - /* no wan hardware present in system */ - tp_features.wan = 0; - dbg_printk(TPACPI_DBG_INIT, - "wan hardware not installed\n"); - } else { - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); - if (res) - return res; - } - } - - return (tp_features.wan)? 0 : 1; -} - -static void wan_exit(void) -{ - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); -} - -static int wan_get_radiosw(void) -{ - int status; - - if (!tp_features.wan) - return -ENODEV; - - if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) - return -EIO; - - return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0); -} - -static int wan_set_radiosw(int radio_on) -{ - int status; - - if (!tp_features.wan) - return -ENODEV; - - if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) - return -EIO; - if (radio_on) - status |= TP_ACPI_WANCARD_RADIOSSW; - else - status &= ~TP_ACPI_WANCARD_RADIOSSW; - if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) - return -EIO; - - return 0; -} - -/* procfs -------------------------------------------------------------- */ -static int wan_read(char *p) -{ - int len = 0; - int status = wan_get_radiosw(); - - if (!tp_features.wan) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status)? "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; -} - -static int wan_write(char *buf) -{ - char *cmd; - - if (!tp_features.wan) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - wan_set_radiosw(1); - } else if (strlencmp(cmd, "disable") == 0) { - wan_set_radiosw(0); - } else - return -EINVAL; - } - - return 0; -} - -static struct ibm_struct wan_driver_data = { - .name = "wan", - .read = wan_read, - .write = wan_write, - .exit = wan_exit, - .flags.experimental = 1, -}; - -/************************************************************************* - * Video subdriver - */ - -static enum video_access_mode video_supported; -static int video_orig_autosw; - -IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ - "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ - "\\_SB.PCI0.VID0", /* 770e */ - "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ - "\\_SB.PCI0.AGP.VID", /* all others */ - ); /* R30, R31 */ - -IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ - -static int __init video_init(struct ibm_init_struct *iibm) -{ - int ivga; - - vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); - - IBM_ACPIHANDLE_INIT(vid); - IBM_ACPIHANDLE_INIT(vid2); - - if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) - /* G41, assume IVGA doesn't change */ - vid_handle = vid2_handle; - - if (!vid_handle) - /* video switching not supported on R30, R31 */ - video_supported = TPACPI_VIDEO_NONE; - else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) - /* 570 */ - video_supported = TPACPI_VIDEO_570; - else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) - /* 600e/x, 770e, 770x */ - video_supported = TPACPI_VIDEO_770; - else - /* all others */ - video_supported = TPACPI_VIDEO_NEW; - - vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n", - str_supported(video_supported != TPACPI_VIDEO_NONE), - video_supported); - - return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; -} - -static void video_exit(void) -{ - dbg_printk(TPACPI_DBG_EXIT, - "restoring original video autoswitch mode\n"); - if (video_autosw_set(video_orig_autosw)) - printk(IBM_ERR "error while trying to restore original " - "video autoswitch mode\n"); -} - -static int video_outputsw_get(void) -{ - int status = 0; - int i; - - switch (video_supported) { - case TPACPI_VIDEO_570: - if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", - TP_ACPI_VIDEO_570_PHSCMD)) - return -EIO; - status = i & TP_ACPI_VIDEO_570_PHSMASK; - break; - case TPACPI_VIDEO_770: - if (!acpi_evalf(NULL, &i, "\\VCDL", "d")) - return -EIO; - if (i) - status |= TP_ACPI_VIDEO_S_LCD; - if (!acpi_evalf(NULL, &i, "\\VCDC", "d")) - return -EIO; - if (i) - status |= TP_ACPI_VIDEO_S_CRT; - break; - case TPACPI_VIDEO_NEW: - if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) || - !acpi_evalf(NULL, &i, "\\VCDC", "d")) - return -EIO; - if (i) - status |= TP_ACPI_VIDEO_S_CRT; - - if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) || - !acpi_evalf(NULL, &i, "\\VCDL", "d")) - return -EIO; - if (i) - status |= TP_ACPI_VIDEO_S_LCD; - if (!acpi_evalf(NULL, &i, "\\VCDD", "d")) - return -EIO; - if (i) - status |= TP_ACPI_VIDEO_S_DVI; - break; - default: - return -ENOSYS; - } - - return status; -} - -static int video_outputsw_set(int status) -{ - int autosw; - int res = 0; - - switch (video_supported) { - case TPACPI_VIDEO_570: - res = acpi_evalf(NULL, NULL, - "\\_SB.PHS2", "vdd", - TP_ACPI_VIDEO_570_PHS2CMD, - status | TP_ACPI_VIDEO_570_PHS2SET); - break; - case TPACPI_VIDEO_770: - autosw = video_autosw_get(); - if (autosw < 0) - return autosw; - - res = video_autosw_set(1); - if (res) - return res; - res = acpi_evalf(vid_handle, NULL, - "ASWT", "vdd", status * 0x100, 0); - if (!autosw && video_autosw_set(autosw)) { - printk(IBM_ERR "video auto-switch left enabled due to error\n"); - return -EIO; - } - break; - case TPACPI_VIDEO_NEW: - res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && - acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); - break; - default: - return -ENOSYS; - } - - return (res)? 0 : -EIO; -} - -static int video_autosw_get(void) -{ - int autosw = 0; - - switch (video_supported) { - case TPACPI_VIDEO_570: - if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d")) - return -EIO; - break; - case TPACPI_VIDEO_770: - case TPACPI_VIDEO_NEW: - if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d")) - return -EIO; - break; - default: - return -ENOSYS; - } - - return autosw & 1; -} - -static int video_autosw_set(int enable) -{ - if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0)) - return -EIO; - return 0; -} - -static int video_outputsw_cycle(void) -{ - int autosw = video_autosw_get(); - int res; - - if (autosw < 0) - return autosw; - - switch (video_supported) { - case TPACPI_VIDEO_570: - res = video_autosw_set(1); - if (res) - return res; - res = acpi_evalf(ec_handle, NULL, "_Q16", "v"); - break; - case TPACPI_VIDEO_770: - case TPACPI_VIDEO_NEW: - res = video_autosw_set(1); - if (res) - return res; - res = acpi_evalf(vid_handle, NULL, "VSWT", "v"); - break; - default: - return -ENOSYS; - } - if (!autosw && video_autosw_set(autosw)) { - printk(IBM_ERR "video auto-switch left enabled due to error\n"); - return -EIO; - } - - return (res)? 0 : -EIO; -} - -static int video_expand_toggle(void) -{ - switch (video_supported) { - case TPACPI_VIDEO_570: - return acpi_evalf(ec_handle, NULL, "_Q17", "v")? - 0 : -EIO; - case TPACPI_VIDEO_770: - return acpi_evalf(vid_handle, NULL, "VEXP", "v")? - 0 : -EIO; - case TPACPI_VIDEO_NEW: - return acpi_evalf(NULL, NULL, "\\VEXP", "v")? - 0 : -EIO; - default: - return -ENOSYS; - } - /* not reached */ -} - -static int video_read(char *p) -{ - int status, autosw; - int len = 0; - - if (video_supported == TPACPI_VIDEO_NONE) { - len += sprintf(p + len, "status:\t\tnot supported\n"); - return len; - } - - status = video_outputsw_get(); - if (status < 0) - return status; - - autosw = video_autosw_get(); - if (autosw < 0) - return autosw; - - len += sprintf(p + len, "status:\t\tsupported\n"); - len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); - len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); - if (video_supported == TPACPI_VIDEO_NEW) - len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); - len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); - len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); - len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); - if (video_supported == TPACPI_VIDEO_NEW) - len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); - len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); - len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); - - return len; -} - -static int video_write(char *buf) -{ - char *cmd; - int enable, disable, status; - int res; - - if (video_supported == TPACPI_VIDEO_NONE) - return -ENODEV; - - enable = 0; - disable = 0; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "lcd_enable") == 0) { - enable |= TP_ACPI_VIDEO_S_LCD; - } else if (strlencmp(cmd, "lcd_disable") == 0) { - disable |= TP_ACPI_VIDEO_S_LCD; - } else if (strlencmp(cmd, "crt_enable") == 0) { - enable |= TP_ACPI_VIDEO_S_CRT; - } else if (strlencmp(cmd, "crt_disable") == 0) { - disable |= TP_ACPI_VIDEO_S_CRT; - } else if (video_supported == TPACPI_VIDEO_NEW && - strlencmp(cmd, "dvi_enable") == 0) { - enable |= TP_ACPI_VIDEO_S_DVI; - } else if (video_supported == TPACPI_VIDEO_NEW && - strlencmp(cmd, "dvi_disable") == 0) { - disable |= TP_ACPI_VIDEO_S_DVI; - } else if (strlencmp(cmd, "auto_enable") == 0) { - res = video_autosw_set(1); - if (res) - return res; - } else if (strlencmp(cmd, "auto_disable") == 0) { - res = video_autosw_set(0); - if (res) - return res; - } else if (strlencmp(cmd, "video_switch") == 0) { - res = video_outputsw_cycle(); - if (res) - return res; - } else if (strlencmp(cmd, "expand_toggle") == 0) { - res = video_expand_toggle(); - if (res) - return res; - } else - return -EINVAL; - } - - if (enable || disable) { - status = video_outputsw_get(); - if (status < 0) - return status; - res = video_outputsw_set((status & ~disable) | enable); - if (res) - return res; - } - - return 0; -} - -static struct ibm_struct video_driver_data = { - .name = "video", - .read = video_read, - .write = video_write, - .exit = video_exit, -}; - -/************************************************************************* - * Light (thinklight) subdriver - */ - -IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ -IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ - -static int __init light_init(struct ibm_init_struct *iibm) -{ - vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); - - IBM_ACPIHANDLE_INIT(ledb); - IBM_ACPIHANDLE_INIT(lght); - IBM_ACPIHANDLE_INIT(cmos); - - /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ - tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; - - if (tp_features.light) - /* light status not supported on - 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ - tp_features.light_status = - acpi_evalf(ec_handle, NULL, "KBLT", "qv"); - - vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", - str_supported(tp_features.light)); - - return (tp_features.light)? 0 : 1; -} - -static int light_read(char *p) -{ - int len = 0; - int status = 0; - - if (!tp_features.light) { - len += sprintf(p + len, "status:\t\tnot supported\n"); - } else if (!tp_features.light_status) { - len += sprintf(p + len, "status:\t\tunknown\n"); - len += sprintf(p + len, "commands:\ton, off\n"); - } else { - if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) - return -EIO; - len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); - len += sprintf(p + len, "commands:\ton, off\n"); - } - - return len; -} - -static int light_write(char *buf) -{ - int cmos_cmd, lght_cmd; - char *cmd; - int success; - - if (!tp_features.light) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "on") == 0) { - cmos_cmd = 0x0c; - lght_cmd = 1; - } else if (strlencmp(cmd, "off") == 0) { - cmos_cmd = 0x0d; - lght_cmd = 0; - } else - return -EINVAL; - - success = cmos_handle ? - acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) : - acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd); - if (!success) - return -EIO; - } - - return 0; -} - -static struct ibm_struct light_driver_data = { - .name = "light", - .read = light_read, - .write = light_write, -}; - -/************************************************************************* - * Dock subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_DOCK - -IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ - "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ - "\\_SB.PCI0.PCI1.DOCK", /* all others */ - "\\_SB.PCI.ISA.SLCE", /* 570 */ - ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ - -/* don't list other alternatives as we install a notify handler on the 570 */ -IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ - -static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { - { - .notify = dock_notify, - .handle = &dock_handle, - .type = ACPI_SYSTEM_NOTIFY, - }, - { - .hid = IBM_PCI_HID, - .notify = dock_notify, - .handle = &pci_handle, - .type = ACPI_SYSTEM_NOTIFY, - }, -}; - -static struct ibm_struct dock_driver_data[2] = { - { - .name = "dock", - .read = dock_read, - .write = dock_write, - .acpi = &ibm_dock_acpidriver[0], - }, - { - .name = "dock", - .acpi = &ibm_dock_acpidriver[1], - }, -}; - -#define dock_docked() (_sta(dock_handle) & 1) - -static int __init dock_init(struct ibm_init_struct *iibm) -{ - vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); - - IBM_ACPIHANDLE_INIT(dock); - - vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", - str_supported(dock_handle != NULL)); - - return (dock_handle)? 0 : 1; -} - -static int __init dock_init2(struct ibm_init_struct *iibm) -{ - int dock2_needed; - - vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n"); - - if (dock_driver_data[0].flags.acpi_driver_registered && - dock_driver_data[0].flags.acpi_notify_installed) { - IBM_ACPIHANDLE_INIT(pci); - dock2_needed = (pci_handle != NULL); - vdbg_printk(TPACPI_DBG_INIT, - "dock PCI handler for the TP 570 is %s\n", - str_supported(dock2_needed)); - } else { - vdbg_printk(TPACPI_DBG_INIT, - "dock subdriver part 2 not required\n"); - dock2_needed = 0; - } - - return (dock2_needed)? 0 : 1; -} - -static void dock_notify(struct ibm_struct *ibm, u32 event) -{ - int docked = dock_docked(); - int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); - - if (event == 1 && !pci) /* 570 */ - acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ - else if (event == 1 && pci) /* 570 */ - acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ - else if (event == 3 && docked) - acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ - else if (event == 3 && !docked) - acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */ - else if (event == 0 && docked) - acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ - else { - printk(IBM_ERR "unknown dock event %d, status %d\n", - event, _sta(dock_handle)); - acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */ - } -} - -static int dock_read(char *p) -{ - int len = 0; - int docked = dock_docked(); - - if (!dock_handle) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else if (!docked) - len += sprintf(p + len, "status:\t\tundocked\n"); - else { - len += sprintf(p + len, "status:\t\tdocked\n"); - len += sprintf(p + len, "commands:\tdock, undock\n"); - } - - return len; -} - -static int dock_write(char *buf) -{ - char *cmd; - - if (!dock_docked()) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "undock") == 0) { - if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || - !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) - return -EIO; - } else if (strlencmp(cmd, "dock") == 0) { - if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) - return -EIO; - } else - return -EINVAL; - } - - return 0; -} - -#endif /* CONFIG_THINKPAD_ACPI_DOCK */ - -/************************************************************************* - * Bay subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_BAY -IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ - "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ - "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ - "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ - ); /* A21e, R30, R31 */ -IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ - "_EJ0", /* all others */ - ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ -IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ - "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ - ); /* all others */ -IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ - "_EJ0", /* 770x */ - ); /* all others */ - -static int __init bay_init(struct ibm_init_struct *iibm) -{ - vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); - - IBM_ACPIHANDLE_INIT(bay); - if (bay_handle) - IBM_ACPIHANDLE_INIT(bay_ej); - IBM_ACPIHANDLE_INIT(bay2); - if (bay2_handle) - IBM_ACPIHANDLE_INIT(bay2_ej); - - tp_features.bay_status = bay_handle && - acpi_evalf(bay_handle, NULL, "_STA", "qv"); - tp_features.bay_status2 = bay2_handle && - acpi_evalf(bay2_handle, NULL, "_STA", "qv"); - - tp_features.bay_eject = bay_handle && bay_ej_handle && - (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); - tp_features.bay_eject2 = bay2_handle && bay2_ej_handle && - (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); - - vdbg_printk(TPACPI_DBG_INIT, - "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", - str_supported(tp_features.bay_status), - str_supported(tp_features.bay_eject), - str_supported(tp_features.bay_status2), - str_supported(tp_features.bay_eject2)); - - return (tp_features.bay_status || tp_features.bay_eject || - tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1; -} - -static void bay_notify(struct ibm_struct *ibm, u32 event) -{ - acpi_bus_generate_event(ibm->acpi->device, event, 0); -} - -#define bay_occupied(b) (_sta(b##_handle) & 1) - -static int bay_read(char *p) -{ - int len = 0; - int occupied = bay_occupied(bay); - int occupied2 = bay_occupied(bay2); - int eject, eject2; - - len += sprintf(p + len, "status:\t\t%s\n", - tp_features.bay_status ? - (occupied ? "occupied" : "unoccupied") : - "not supported"); - if (tp_features.bay_status2) - len += sprintf(p + len, "status2:\t%s\n", occupied2 ? - "occupied" : "unoccupied"); - - eject = tp_features.bay_eject && occupied; - eject2 = tp_features.bay_eject2 && occupied2; - - if (eject && eject2) - len += sprintf(p + len, "commands:\teject, eject2\n"); - else if (eject) - len += sprintf(p + len, "commands:\teject\n"); - else if (eject2) - len += sprintf(p + len, "commands:\teject2\n"); - - return len; -} - -static int bay_write(char *buf) -{ - char *cmd; - - if (!tp_features.bay_eject && !tp_features.bay_eject2) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) { - if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) - return -EIO; - } else if (tp_features.bay_eject2 && - strlencmp(cmd, "eject2") == 0) { - if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) - return -EIO; - } else - return -EINVAL; - } - - return 0; -} - -static struct tp_acpi_drv_struct ibm_bay_acpidriver = { - .notify = bay_notify, - .handle = &bay_handle, - .type = ACPI_SYSTEM_NOTIFY, -}; - -static struct ibm_struct bay_driver_data = { - .name = "bay", - .read = bay_read, - .write = bay_write, - .acpi = &ibm_bay_acpidriver, -}; - -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - -/************************************************************************* - * CMOS subdriver - */ - -/* sysfs cmos_command -------------------------------------------------- */ -static ssize_t cmos_command_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long cmos_cmd; - int res; - - if (parse_strtoul(buf, 21, &cmos_cmd)) - return -EINVAL; - - res = issue_thinkpad_cmos_command(cmos_cmd); - return (res)? res : count; -} - -static struct device_attribute dev_attr_cmos_command = - __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store); - -/* --------------------------------------------------------------------- */ - -static int __init cmos_init(struct ibm_init_struct *iibm) -{ - int res; - - vdbg_printk(TPACPI_DBG_INIT, - "initializing cmos commands subdriver\n"); - - IBM_ACPIHANDLE_INIT(cmos); - - vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", - str_supported(cmos_handle != NULL)); - - res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); - if (res) - return res; - - return (cmos_handle)? 0 : 1; -} - -static void cmos_exit(void) -{ - device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); -} - -static int cmos_read(char *p) -{ - int len = 0; - - /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, - R30, R31, T20-22, X20-21 */ - if (!cmos_handle) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\tsupported\n"); - len += sprintf(p + len, "commands:\t ( is 0-21)\n"); - } - - return len; -} - -static int cmos_write(char *buf) -{ - char *cmd; - int cmos_cmd, res; - - while ((cmd = next_cmd(&buf))) { - if (sscanf(cmd, "%u", &cmos_cmd) == 1 && - cmos_cmd >= 0 && cmos_cmd <= 21) { - /* cmos_cmd set */ - } else - return -EINVAL; - - res = issue_thinkpad_cmos_command(cmos_cmd); - if (res) - return res; - } - - return 0; -} - -static struct ibm_struct cmos_driver_data = { - .name = "cmos", - .read = cmos_read, - .write = cmos_write, - .exit = cmos_exit, -}; - -/************************************************************************* - * LED subdriver - */ - -static enum led_access_mode led_supported; - -IBM_HANDLE(led, ec, "SLED", /* 570 */ - "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - "LED", /* all others */ - ); /* R30, R31 */ - -static int __init led_init(struct ibm_init_struct *iibm) -{ - vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); - - IBM_ACPIHANDLE_INIT(led); - - if (!led_handle) - /* led not supported on R30, R31 */ - led_supported = TPACPI_LED_NONE; - else if (strlencmp(led_path, "SLED") == 0) - /* 570 */ - led_supported = TPACPI_LED_570; - else if (strlencmp(led_path, "SYSL") == 0) - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - led_supported = TPACPI_LED_OLD; - else - /* all others */ - led_supported = TPACPI_LED_NEW; - - vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", - str_supported(led_supported), led_supported); - - return (led_supported != TPACPI_LED_NONE)? 0 : 1; -} - -#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) - -static int led_read(char *p) -{ - int len = 0; - - if (!led_supported) { - len += sprintf(p + len, "status:\t\tnot supported\n"); - return len; - } - len += sprintf(p + len, "status:\t\tsupported\n"); - - if (led_supported == TPACPI_LED_570) { - /* 570 */ - int i, status; - for (i = 0; i < 8; i++) { - if (!acpi_evalf(ec_handle, - &status, "GLED", "dd", 1 << i)) - return -EIO; - len += sprintf(p + len, "%d:\t\t%s\n", - i, led_status(status)); - } - } - - len += sprintf(p + len, "commands:\t" - " on, off, blink ( is 0-7)\n"); - - return len; -} - -/* off, on, blink */ -static const int led_sled_arg1[] = { 0, 1, 3 }; -static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ -static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ -static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; - -static int led_write(char *buf) -{ - char *cmd; - int led, ind, ret; - - if (!led_supported) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) - return -EINVAL; - - if (strstr(cmd, "off")) { - ind = 0; - } else if (strstr(cmd, "on")) { - ind = 1; - } else if (strstr(cmd, "blink")) { - ind = 2; - } else - return -EINVAL; - - if (led_supported == TPACPI_LED_570) { - /* 570 */ - led = 1 << led; - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_sled_arg1[ind])) - return -EIO; - } else if (led_supported == TPACPI_LED_OLD) { - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ - led = 1 << led; - ret = ec_write(TPACPI_LED_EC_HLMS, led); - if (ret >= 0) - ret = - ec_write(TPACPI_LED_EC_HLBL, - led * led_exp_hlbl[ind]); - if (ret >= 0) - ret = - ec_write(TPACPI_LED_EC_HLCL, - led * led_exp_hlcl[ind]); - if (ret < 0) - return ret; - } else { - /* all others */ - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_led_arg1[ind])) - return -EIO; - } - } - - return 0; -} - -static struct ibm_struct led_driver_data = { - .name = "led", - .read = led_read, - .write = led_write, -}; - -/************************************************************************* - * Beep subdriver - */ - -IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ - -static int __init beep_init(struct ibm_init_struct *iibm) -{ - vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); - - IBM_ACPIHANDLE_INIT(beep); - - vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", - str_supported(beep_handle != NULL)); - - return (beep_handle)? 0 : 1; -} - -static int beep_read(char *p) -{ - int len = 0; - - if (!beep_handle) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\tsupported\n"); - len += sprintf(p + len, "commands:\t ( is 0-17)\n"); - } - - return len; -} - -static int beep_write(char *buf) -{ - char *cmd; - int beep_cmd; - - if (!beep_handle) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (sscanf(cmd, "%u", &beep_cmd) == 1 && - beep_cmd >= 0 && beep_cmd <= 17) { - /* beep_cmd set */ - } else - return -EINVAL; - if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) - return -EIO; - } - - return 0; -} - -static struct ibm_struct beep_driver_data = { - .name = "beep", - .read = beep_read, - .write = beep_write, -}; - -/************************************************************************* - * Thermal subdriver - */ - -static enum thermal_access_mode thermal_read_mode; - -/* sysfs temp##_input -------------------------------------------------- */ - -static ssize_t thermal_temp_input_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = - to_sensor_dev_attr(attr); - int idx = sensor_attr->index; - s32 value; - int res; - - res = thermal_get_sensor(idx, &value); - if (res) - return res; - if (value == TP_EC_THERMAL_TMP_NA * 1000) - return -ENXIO; - - return snprintf(buf, PAGE_SIZE, "%d\n", value); -} - -#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ - SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) - -static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { - THERMAL_SENSOR_ATTR_TEMP(1, 0), - THERMAL_SENSOR_ATTR_TEMP(2, 1), - THERMAL_SENSOR_ATTR_TEMP(3, 2), - THERMAL_SENSOR_ATTR_TEMP(4, 3), - THERMAL_SENSOR_ATTR_TEMP(5, 4), - THERMAL_SENSOR_ATTR_TEMP(6, 5), - THERMAL_SENSOR_ATTR_TEMP(7, 6), - THERMAL_SENSOR_ATTR_TEMP(8, 7), - THERMAL_SENSOR_ATTR_TEMP(9, 8), - THERMAL_SENSOR_ATTR_TEMP(10, 9), - THERMAL_SENSOR_ATTR_TEMP(11, 10), - THERMAL_SENSOR_ATTR_TEMP(12, 11), - THERMAL_SENSOR_ATTR_TEMP(13, 12), - THERMAL_SENSOR_ATTR_TEMP(14, 13), - THERMAL_SENSOR_ATTR_TEMP(15, 14), - THERMAL_SENSOR_ATTR_TEMP(16, 15), -}; - -#define THERMAL_ATTRS(X) \ - &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr - -static struct attribute *thermal_temp_input_attr[] = { - THERMAL_ATTRS(8), - THERMAL_ATTRS(9), - THERMAL_ATTRS(10), - THERMAL_ATTRS(11), - THERMAL_ATTRS(12), - THERMAL_ATTRS(13), - THERMAL_ATTRS(14), - THERMAL_ATTRS(15), - THERMAL_ATTRS(0), - THERMAL_ATTRS(1), - THERMAL_ATTRS(2), - THERMAL_ATTRS(3), - THERMAL_ATTRS(4), - THERMAL_ATTRS(5), - THERMAL_ATTRS(6), - THERMAL_ATTRS(7), - NULL -}; - -static const struct attribute_group thermal_temp_input16_group = { - .attrs = thermal_temp_input_attr -}; - -static const struct attribute_group thermal_temp_input8_group = { - .attrs = &thermal_temp_input_attr[8] -}; - -#undef THERMAL_SENSOR_ATTR_TEMP -#undef THERMAL_ATTRS - -/* --------------------------------------------------------------------- */ - -static int __init thermal_init(struct ibm_init_struct *iibm) -{ - u8 t, ta1, ta2; - int i; - int acpi_tmp7; - int res; - - vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); - - acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); - - if (ibm_thinkpad_ec_found && experimental) { - /* - * Direct EC access mode: sensors at registers - * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for - * non-implemented, thermal sensors return 0x80 when - * not available - */ - - ta1 = ta2 = 0; - for (i = 0; i < 8; i++) { - if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { - ta1 |= t; - } else { - ta1 = 0; - break; - } - if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { - ta2 |= t; - } else { - ta1 = 0; - break; - } - } - if (ta1 == 0) { - /* This is sheer paranoia, but we handle it anyway */ - if (acpi_tmp7) { - printk(IBM_ERR - "ThinkPad ACPI EC access misbehaving, " - "falling back to ACPI TMPx access mode\n"); - thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; - } else { - printk(IBM_ERR - "ThinkPad ACPI EC access misbehaving, " - "disabling thermal sensors access\n"); - thermal_read_mode = TPACPI_THERMAL_NONE; - } - } else { - thermal_read_mode = - (ta2 != 0) ? - TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; - } - } else if (acpi_tmp7) { - if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { - /* 600e/x, 770e, 770x */ - thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; - } else { - /* Standard ACPI TMPx access, max 8 sensors */ - thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; - } - } else { - /* temperatures not supported on 570, G4x, R30, R31, R32 */ - thermal_read_mode = TPACPI_THERMAL_NONE; - } - - vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n", - str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), - thermal_read_mode); - - switch(thermal_read_mode) { - case TPACPI_THERMAL_TPEC_16: - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &thermal_temp_input16_group); - if (res) - return res; - break; - case TPACPI_THERMAL_TPEC_8: - case TPACPI_THERMAL_ACPI_TMP07: - case TPACPI_THERMAL_ACPI_UPDT: - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &thermal_temp_input8_group); - if (res) - return res; - break; - case TPACPI_THERMAL_NONE: - default: - return 1; - } - - return 0; -} - -static void thermal_exit(void) -{ - switch(thermal_read_mode) { - case TPACPI_THERMAL_TPEC_16: - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &thermal_temp_input16_group); - break; - case TPACPI_THERMAL_TPEC_8: - case TPACPI_THERMAL_ACPI_TMP07: - case TPACPI_THERMAL_ACPI_UPDT: - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &thermal_temp_input16_group); - break; - case TPACPI_THERMAL_NONE: - default: - break; - } -} - -/* idx is zero-based */ -static int thermal_get_sensor(int idx, s32 *value) -{ - int t; - s8 tmp; - char tmpi[5]; - - t = TP_EC_THERMAL_TMP0; - - switch (thermal_read_mode) { -#if TPACPI_MAX_THERMAL_SENSORS >= 16 - case TPACPI_THERMAL_TPEC_16: - if (idx >= 8 && idx <= 15) { - t = TP_EC_THERMAL_TMP8; - idx -= 8; - } - /* fallthrough */ -#endif - case TPACPI_THERMAL_TPEC_8: - if (idx <= 7) { - if (!acpi_ec_read(t + idx, &tmp)) - return -EIO; - *value = tmp * 1000; - return 0; - } - break; - - case TPACPI_THERMAL_ACPI_UPDT: - if (idx <= 7) { - snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); - if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) - return -EIO; - if (!acpi_evalf(ec_handle, &t, tmpi, "d")) - return -EIO; - *value = (t - 2732) * 100; - return 0; - } - break; - - case TPACPI_THERMAL_ACPI_TMP07: - if (idx <= 7) { - snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); - if (!acpi_evalf(ec_handle, &t, tmpi, "d")) - return -EIO; - *value = t * 1000; - return 0; - } - break; - - case TPACPI_THERMAL_NONE: - default: - return -ENOSYS; - } - - return -EINVAL; -} - -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) -{ - int res, i; - int n; - - n = 8; - i = 0; - - if (!s) - return -EINVAL; - - if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) - n = 16; - - for(i = 0 ; i < n; i++) { - res = thermal_get_sensor(i, &s->temp[i]); - if (res) - return res; - } - - return n; -} - -static int thermal_read(char *p) -{ - int len = 0; - int n, i; - struct ibm_thermal_sensors_struct t; - - n = thermal_get_sensors(&t); - if (unlikely(n < 0)) - return n; - - len += sprintf(p + len, "temperatures:\t"); - - if (n > 0) { - for (i = 0; i < (n - 1); i++) - len += sprintf(p + len, "%d ", t.temp[i] / 1000); - len += sprintf(p + len, "%d\n", t.temp[i] / 1000); - } else - len += sprintf(p + len, "not supported\n"); - - return len; -} - -static struct ibm_struct thermal_driver_data = { - .name = "thermal", - .read = thermal_read, - .exit = thermal_exit, -}; - -/************************************************************************* - * EC Dump subdriver - */ - -static u8 ecdump_regs[256]; - -static int ecdump_read(char *p) -{ - int len = 0; - int i, j; - u8 v; - - len += sprintf(p + len, "EC " - " +00 +01 +02 +03 +04 +05 +06 +07" - " +08 +09 +0a +0b +0c +0d +0e +0f\n"); - for (i = 0; i < 256; i += 16) { - len += sprintf(p + len, "EC 0x%02x:", i); - for (j = 0; j < 16; j++) { - if (!acpi_ec_read(i + j, &v)) - break; - if (v != ecdump_regs[i + j]) - len += sprintf(p + len, " *%02x", v); - else - len += sprintf(p + len, " %02x", v); - ecdump_regs[i + j] = v; - } - len += sprintf(p + len, "\n"); - if (j != 16) - break; - } - - /* These are way too dangerous to advertise openly... */ -#if 0 - len += sprintf(p + len, "commands:\t0x 0x" - " ( is 00-ff, is 00-ff)\n"); - len += sprintf(p + len, "commands:\t0x " - " ( is 00-ff, is 0-255)\n"); -#endif - return len; -} - -static int ecdump_write(char *buf) -{ - char *cmd; - int i, v; - - while ((cmd = next_cmd(&buf))) { - if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { - /* i and v set */ - } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { - /* i and v set */ - } else - return -EINVAL; - if (i >= 0 && i < 256 && v >= 0 && v < 256) { - if (!acpi_ec_write(i, v)) - return -EIO; - } else - return -EINVAL; - } - - return 0; -} - -static struct ibm_struct ecdump_driver_data = { - .name = "ecdump", - .read = ecdump_read, - .write = ecdump_write, - .flags.experimental = 1, -}; - -/************************************************************************* - * Backlight/brightness subdriver - */ - -static struct backlight_device *ibm_backlight_device = NULL; - -static struct backlight_ops ibm_backlight_data = { - .get_brightness = brightness_get, - .update_status = brightness_update_status, -}; - -static int __init brightness_init(struct ibm_init_struct *iibm) -{ - int b; - - vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); - - b = brightness_get(NULL); - if (b < 0) - return b; - - ibm_backlight_device = backlight_device_register( - TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, - &ibm_backlight_data); - if (IS_ERR(ibm_backlight_device)) { - printk(IBM_ERR "Could not register backlight device\n"); - return PTR_ERR(ibm_backlight_device); - } - vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); - - ibm_backlight_device->props.max_brightness = 7; - ibm_backlight_device->props.brightness = b; - backlight_update_status(ibm_backlight_device); - - return 0; -} - -static void brightness_exit(void) -{ - if (ibm_backlight_device) { - vdbg_printk(TPACPI_DBG_EXIT, - "calling backlight_device_unregister()\n"); - backlight_device_unregister(ibm_backlight_device); - ibm_backlight_device = NULL; - } -} - -static int brightness_update_status(struct backlight_device *bd) -{ - return brightness_set( - (bd->props.fb_blank == FB_BLANK_UNBLANK && - bd->props.power == FB_BLANK_UNBLANK) ? - bd->props.brightness : 0); -} - -static int brightness_get(struct backlight_device *bd) -{ - u8 level; - if (!acpi_ec_read(brightness_offset, &level)) - return -EIO; - - level &= 0x7; - - return level; -} - -static int brightness_set(int value) -{ - int cmos_cmd, inc, i; - int current_value = brightness_get(NULL); - - value &= 7; - - cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; - inc = value > current_value ? 1 : -1; - for (i = current_value; i != value; i += inc) { - if (issue_thinkpad_cmos_command(cmos_cmd)) - return -EIO; - if (!acpi_ec_write(brightness_offset, i + inc)) - return -EIO; - } - - return 0; -} - -static int brightness_read(char *p) -{ - int len = 0; - int level; - - if ((level = brightness_get(NULL)) < 0) { - len += sprintf(p + len, "level:\t\tunreadable\n"); - } else { - len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); - len += sprintf(p + len, "commands:\tup, down\n"); - len += sprintf(p + len, "commands:\tlevel " - " ( is 0-7)\n"); - } - - return len; -} - -static int brightness_write(char *buf) -{ - int level; - int new_level; - char *cmd; - - while ((cmd = next_cmd(&buf))) { - if ((level = brightness_get(NULL)) < 0) - return level; - level &= 7; - - if (strlencmp(cmd, "up") == 0) { - new_level = level == 7 ? 7 : level + 1; - } else if (strlencmp(cmd, "down") == 0) { - new_level = level == 0 ? 0 : level - 1; - } else if (sscanf(cmd, "level %d", &new_level) == 1 && - new_level >= 0 && new_level <= 7) { - /* new_level set */ - } else - return -EINVAL; - - brightness_set(new_level); - } - - return 0; -} - -static struct ibm_struct brightness_driver_data = { - .name = "brightness", - .read = brightness_read, - .write = brightness_write, - .exit = brightness_exit, -}; - -/************************************************************************* - * Volume subdriver - */ - -static int volume_read(char *p) -{ - int len = 0; - u8 level; - - if (!acpi_ec_read(volume_offset, &level)) { - len += sprintf(p + len, "level:\t\tunreadable\n"); - } else { - len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); - len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); - len += sprintf(p + len, "commands:\tup, down, mute\n"); - len += sprintf(p + len, "commands:\tlevel " - " ( is 0-15)\n"); - } - - return len; -} - -static int volume_write(char *buf) -{ - int cmos_cmd, inc, i; - u8 level, mute; - int new_level, new_mute; - char *cmd; - - while ((cmd = next_cmd(&buf))) { - if (!acpi_ec_read(volume_offset, &level)) - return -EIO; - new_mute = mute = level & 0x40; - new_level = level = level & 0xf; - - if (strlencmp(cmd, "up") == 0) { - if (mute) - new_mute = 0; - else - new_level = level == 15 ? 15 : level + 1; - } else if (strlencmp(cmd, "down") == 0) { - if (mute) - new_mute = 0; - else - new_level = level == 0 ? 0 : level - 1; - } else if (sscanf(cmd, "level %d", &new_level) == 1 && - new_level >= 0 && new_level <= 15) { - /* new_level set */ - } else if (strlencmp(cmd, "mute") == 0) { - new_mute = 0x40; - } else - return -EINVAL; - - if (new_level != level) { /* mute doesn't change */ - cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; - inc = new_level > level ? 1 : -1; - - if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || - !acpi_ec_write(volume_offset, level))) - return -EIO; - - for (i = level; i != new_level; i += inc) - if (issue_thinkpad_cmos_command(cmos_cmd) || - !acpi_ec_write(volume_offset, i + inc)) - return -EIO; - - if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || - !acpi_ec_write(volume_offset, - new_level + mute))) - return -EIO; - } - - if (new_mute != mute) { /* level doesn't change */ - cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; - - if (issue_thinkpad_cmos_command(cmos_cmd) || - !acpi_ec_write(volume_offset, level + new_mute)) - return -EIO; - } - } - - return 0; -} - -static struct ibm_struct volume_driver_data = { - .name = "volume", - .read = volume_read, - .write = volume_write, -}; - -/************************************************************************* - * Fan subdriver - */ - -/* - * FAN ACCESS MODES - * - * TPACPI_FAN_RD_ACPI_GFAN: - * ACPI GFAN method: returns fan level - * - * see TPACPI_FAN_WR_ACPI_SFAN - * EC 0x2f (HFSP) not available if GFAN exists - * - * TPACPI_FAN_WR_ACPI_SFAN: - * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) - * - * EC 0x2f (HFSP) might be available *for reading*, but do not use - * it for writing. - * - * TPACPI_FAN_WR_TPEC: - * ThinkPad EC register 0x2f (HFSP): fan control loop mode - * Supported on almost all ThinkPads - * - * Fan speed changes of any sort (including those caused by the - * disengaged mode) are usually done slowly by the firmware as the - * maximum ammount of fan duty cycle change per second seems to be - * limited. - * - * Reading is not available if GFAN exists. - * Writing is not available if SFAN exists. - * - * Bits - * 7 automatic mode engaged; - * (default operation mode of the ThinkPad) - * fan level is ignored in this mode. - * 6 full speed mode (takes precedence over bit 7); - * not available on all thinkpads. May disable - * the tachometer while the fan controller ramps up - * the speed (which can take up to a few *minutes*). - * Speeds up fan to 100% duty-cycle, which is far above - * the standard RPM levels. It is not impossible that - * it could cause hardware damage. - * 5-3 unused in some models. Extra bits for fan level - * in others, but still useless as all values above - * 7 map to the same speed as level 7 in these models. - * 2-0 fan level (0..7 usually) - * 0x00 = stop - * 0x07 = max (set when temperatures critical) - * Some ThinkPads may have other levels, see - * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) - * - * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at - * boot. Apparently the EC does not intialize it, so unless ACPI DSDT - * does so, its initial value is meaningless (0x07). - * - * For firmware bugs, refer to: - * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues - * - * ---- - * - * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): - * Main fan tachometer reading (in RPM) - * - * This register is present on all ThinkPads with a new-style EC, and - * it is known not to be present on the A21m/e, and T22, as there is - * something else in offset 0x84 according to the ACPI DSDT. Other - * ThinkPads from this same time period (and earlier) probably lack the - * tachometer as well. - * - * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare - * was never fixed by IBM to report the EC firmware version string - * probably support the tachometer (like the early X models), so - * detecting it is quite hard. We need more data to know for sure. - * - * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings - * might result. - * - * FIRMWARE BUG: may go stale while the EC is switching to full speed - * mode. - * - * For firmware bugs, refer to: - * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues - * - * TPACPI_FAN_WR_ACPI_FANS: - * ThinkPad X31, X40, X41. Not available in the X60. - * - * FANS ACPI handle: takes three arguments: low speed, medium speed, - * high speed. ACPI DSDT seems to map these three speeds to levels - * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH - * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") - * - * The speeds are stored on handles - * (FANA:FAN9), (FANC:FANB), (FANE:FAND). - * - * There are three default speed sets, acessible as handles: - * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H - * - * ACPI DSDT switches which set is in use depending on various - * factors. - * - * TPACPI_FAN_WR_TPEC is also available and should be used to - * command the fan. The X31/X40/X41 seems to have 8 fan levels, - * but the ACPI tables just mention level 7. - */ - -static enum fan_status_access_mode fan_status_access_mode; -static enum fan_control_access_mode fan_control_access_mode; -static enum fan_control_commands fan_control_commands; - -static u8 fan_control_initial_status; -static u8 fan_control_desired_level; - -static void fan_watchdog_fire(struct work_struct *ignored); -static int fan_watchdog_maxinterval; -static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); - -IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ -IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ - "\\FSPD", /* 600e/x, 770e, 770x */ - ); /* all others */ -IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ - "JFNS", /* 770x-JL */ - ); /* all others */ - -/* - * SYSFS fan layout: hwmon compatible (device) - * - * pwm*_enable: - * 0: "disengaged" mode - * 1: manual mode - * 2: native EC "auto" mode (recommended, hardware default) - * - * pwm*: set speed in manual mode, ignored otherwise. - * 0 is level 0; 255 is level 7. Intermediate points done with linear - * interpolation. - * - * fan*_input: tachometer reading, RPM - * - * - * SYSFS fan layout: extensions - * - * fan_watchdog (driver): - * fan watchdog interval in seconds, 0 disables (default), max 120 - */ - -/* sysfs fan pwm1_enable ----------------------------------------------- */ -static ssize_t fan_pwm1_enable_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int res, mode; - u8 status; - - res = fan_get_status_safe(&status); - if (res) - return res; - - if (unlikely(tp_features.fan_ctrl_status_undef)) { - if (status != fan_control_initial_status) { - tp_features.fan_ctrl_status_undef = 0; - } else { - /* Return most likely status. In fact, it - * might be the only possible status */ - status = TP_EC_FAN_AUTO; - } - } - - if (status & TP_EC_FAN_FULLSPEED) { - mode = 0; - } else if (status & TP_EC_FAN_AUTO) { - mode = 2; - } else - mode = 1; - - return snprintf(buf, PAGE_SIZE, "%d\n", mode); -} - -static ssize_t fan_pwm1_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long t; - int res, level; - - if (parse_strtoul(buf, 2, &t)) - return -EINVAL; - - switch (t) { - case 0: - level = TP_EC_FAN_FULLSPEED; - break; - case 1: - level = TPACPI_FAN_LAST_LEVEL; - break; - case 2: - level = TP_EC_FAN_AUTO; - break; - case 3: - /* reserved for software-controlled auto mode */ - return -ENOSYS; - default: - return -EINVAL; - } - - res = fan_set_level_safe(level); - if (res == -ENXIO) - return -EINVAL; - else if (res < 0) - return res; - - fan_watchdog_reset(); - - return count; -} - -static struct device_attribute dev_attr_fan_pwm1_enable = - __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, - fan_pwm1_enable_show, fan_pwm1_enable_store); - -/* sysfs fan pwm1 ------------------------------------------------------ */ -static ssize_t fan_pwm1_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int res; - u8 status; - - res = fan_get_status_safe(&status); - if (res) - return res; - - if (unlikely(tp_features.fan_ctrl_status_undef)) { - if (status != fan_control_initial_status) { - tp_features.fan_ctrl_status_undef = 0; - } else { - status = TP_EC_FAN_AUTO; - } - } - - if ((status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) - status = fan_control_desired_level; - - if (status > 7) - status = 7; - - return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); -} - -static ssize_t fan_pwm1_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long s; - int rc; - u8 status, newlevel; - - if (parse_strtoul(buf, 255, &s)) - return -EINVAL; - - /* scale down from 0-255 to 0-7 */ - newlevel = (s >> 5) & 0x07; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - - rc = fan_get_status(&status); - if (!rc && (status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { - rc = fan_set_level(newlevel); - if (rc == -ENXIO) - rc = -EINVAL; - else if (!rc) { - fan_update_desired_level(newlevel); - fan_watchdog_reset(); - } - } - - mutex_unlock(&fan_mutex); - return (rc)? rc : count; -} - -static struct device_attribute dev_attr_fan_pwm1 = - __ATTR(pwm1, S_IWUSR | S_IRUGO, - fan_pwm1_show, fan_pwm1_store); - -/* sysfs fan fan1_input ------------------------------------------------ */ -static ssize_t fan_fan1_input_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int res; - unsigned int speed; - - res = fan_get_speed(&speed); - if (res < 0) - return res; - - return snprintf(buf, PAGE_SIZE, "%u\n", speed); -} - -static struct device_attribute dev_attr_fan_fan1_input = - __ATTR(fan1_input, S_IRUGO, - fan_fan1_input_show, NULL); - -/* sysfs fan fan_watchdog (driver) ------------------------------------- */ -static ssize_t fan_fan_watchdog_show(struct device_driver *drv, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); -} - -static ssize_t fan_fan_watchdog_store(struct device_driver *drv, - const char *buf, size_t count) -{ - unsigned long t; - - if (parse_strtoul(buf, 120, &t)) - return -EINVAL; - - if (!fan_control_allowed) - return -EPERM; - - fan_watchdog_maxinterval = t; - fan_watchdog_reset(); - - return count; -} - -static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, - fan_fan_watchdog_show, fan_fan_watchdog_store); - -/* --------------------------------------------------------------------- */ -static struct attribute *fan_attributes[] = { - &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, - &dev_attr_fan_fan1_input.attr, - NULL -}; - -static const struct attribute_group fan_attr_group = { - .attrs = fan_attributes, -}; - -static int __init fan_init(struct ibm_init_struct *iibm) -{ - int rc; - - vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); - - mutex_init(&fan_mutex); - fan_status_access_mode = TPACPI_FAN_NONE; - fan_control_access_mode = TPACPI_FAN_WR_NONE; - fan_control_commands = 0; - fan_watchdog_maxinterval = 0; - tp_features.fan_ctrl_status_undef = 0; - fan_control_desired_level = 7; - - IBM_ACPIHANDLE_INIT(fans); - IBM_ACPIHANDLE_INIT(gfan); - IBM_ACPIHANDLE_INIT(sfan); - - if (gfan_handle) { - /* 570, 600e/x, 770e, 770x */ - fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; - } else { - /* all other ThinkPads: note that even old-style - * ThinkPad ECs supports the fan control register */ - if (likely(acpi_ec_read(fan_status_offset, - &fan_control_initial_status))) { - fan_status_access_mode = TPACPI_FAN_RD_TPEC; - - /* In some ThinkPads, neither the EC nor the ACPI - * DSDT initialize the fan status, and it ends up - * being set to 0x07 when it *could* be either - * 0x07 or 0x80. - * - * Enable for TP-1Y (T43), TP-78 (R51e), - * TP-76 (R52), TP-70 (T43, R52), which are known - * to be buggy. */ - if (fan_control_initial_status == 0x07 && - ibm_thinkpad_ec_found && - ((ibm_thinkpad_ec_found[0] == '1' && - ibm_thinkpad_ec_found[1] == 'Y') || - (ibm_thinkpad_ec_found[0] == '7' && - (ibm_thinkpad_ec_found[1] == '6' || - ibm_thinkpad_ec_found[1] == '8' || - ibm_thinkpad_ec_found[1] == '0')) - )) { - printk(IBM_NOTICE - "fan_init: initial fan status is " - "unknown, assuming it is in auto " - "mode\n"); - tp_features.fan_ctrl_status_undef = 1; - } - } else { - printk(IBM_ERR - "ThinkPad ACPI EC access misbehaving, " - "fan status and control unavailable\n"); - return 1; - } - } - - if (sfan_handle) { - /* 570, 770x-JL */ - fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; - fan_control_commands |= - TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; - } else { - if (!gfan_handle) { - /* gfan without sfan means no fan control */ - /* all other models implement TP EC 0x2f control */ - - if (fans_handle) { - /* X31, X40, X41 */ - fan_control_access_mode = - TPACPI_FAN_WR_ACPI_FANS; - fan_control_commands |= - TPACPI_FAN_CMD_SPEED | - TPACPI_FAN_CMD_LEVEL | - TPACPI_FAN_CMD_ENABLE; - } else { - fan_control_access_mode = TPACPI_FAN_WR_TPEC; - fan_control_commands |= - TPACPI_FAN_CMD_LEVEL | - TPACPI_FAN_CMD_ENABLE; - } - } - } - - vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", - str_supported(fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE), - fan_status_access_mode, fan_control_access_mode); - - /* fan control master switch */ - if (!fan_control_allowed) { - fan_control_access_mode = TPACPI_FAN_WR_NONE; - fan_control_commands = 0; - dbg_printk(TPACPI_DBG_INIT, - "fan control features disabled by parameter\n"); - } - - /* update fan_control_desired_level */ - if (fan_status_access_mode != TPACPI_FAN_NONE) - fan_get_status_safe(NULL); - - if (fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE) { - rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &fan_attr_group); - if (!(rc < 0)) - rc = driver_create_file(&tpacpi_pdriver.driver, - &driver_attr_fan_watchdog); - if (rc < 0) - return rc; - return 0; - } else - return 1; -} - -/* - * Call with fan_mutex held - */ -static void fan_update_desired_level(u8 status) -{ - if ((status & - (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { - if (status > 7) - fan_control_desired_level = 7; - else - fan_control_desired_level = status; - } -} - -static int fan_get_status(u8 *status) -{ - u8 s; - - /* TODO: - * Add TPACPI_FAN_RD_ACPI_FANS ? */ - - switch (fan_status_access_mode) { - case TPACPI_FAN_RD_ACPI_GFAN: - /* 570, 600e/x, 770e, 770x */ - - if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) - return -EIO; - - if (likely(status)) - *status = s & 0x07; - - break; - - case TPACPI_FAN_RD_TPEC: - /* all except 570, 600e/x, 770e, 770x */ - if (unlikely(!acpi_ec_read(fan_status_offset, &s))) - return -EIO; - - if (likely(status)) - *status = s; - - break; - - default: - return -ENXIO; - } - - return 0; -} - -static int fan_get_status_safe(u8 *status) -{ - int rc; - u8 s; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - rc = fan_get_status(&s); - if (!rc) - fan_update_desired_level(s); - mutex_unlock(&fan_mutex); - - if (status) - *status = s; - - return rc; -} - -static void fan_exit(void) -{ - vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); - - /* FIXME: can we really do this unconditionally? */ - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); - driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); - - cancel_delayed_work(&fan_watchdog_task); - flush_scheduled_work(); -} - -static int fan_get_speed(unsigned int *speed) -{ - u8 hi, lo; - - switch (fan_status_access_mode) { - case TPACPI_FAN_RD_TPEC: - /* all except 570, 600e/x, 770e, 770x */ - if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || - !acpi_ec_read(fan_rpm_offset + 1, &hi))) - return -EIO; - - if (likely(speed)) - *speed = (hi << 8) | lo; - - break; - - default: - return -ENXIO; - } - - return 0; -} - -static void fan_watchdog_fire(struct work_struct *ignored) -{ - int rc; - - printk(IBM_NOTICE "fan watchdog: enabling fan\n"); - rc = fan_set_enable(); - if (rc < 0) { - printk(IBM_ERR "fan watchdog: error %d while enabling fan, " - "will try again later...\n", -rc); - /* reschedule for later */ - fan_watchdog_reset(); - } -} - -static void fan_watchdog_reset(void) -{ - static int fan_watchdog_active = 0; - - if (fan_control_access_mode == TPACPI_FAN_WR_NONE) - return; - - if (fan_watchdog_active) - cancel_delayed_work(&fan_watchdog_task); - - if (fan_watchdog_maxinterval > 0) { - fan_watchdog_active = 1; - if (!schedule_delayed_work(&fan_watchdog_task, - msecs_to_jiffies(fan_watchdog_maxinterval - * 1000))) { - printk(IBM_ERR "failed to schedule the fan watchdog, " - "watchdog will not trigger\n"); - } - } else - fan_watchdog_active = 0; -} - -static int fan_set_level(int level) -{ - if (!fan_control_allowed) - return -EPERM; - - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_SFAN: - if (level >= 0 && level <= 7) { - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) - return -EIO; - } else - return -EINVAL; - break; - - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - if ((level != TP_EC_FAN_AUTO) && - (level != TP_EC_FAN_FULLSPEED) && - ((level < 0) || (level > 7))) - return -EINVAL; - - /* safety net should the EC not support AUTO - * or FULLSPEED mode bits and just ignore them */ - if (level & TP_EC_FAN_FULLSPEED) - level |= 7; /* safety min speed 7 */ - else if (level & TP_EC_FAN_FULLSPEED) - level |= 4; /* safety min speed 4 */ - - if (!acpi_ec_write(fan_status_offset, level)) - return -EIO; - else - tp_features.fan_ctrl_status_undef = 0; - break; - - default: - return -ENXIO; - } - return 0; -} - -static int fan_set_level_safe(int level) -{ - int rc; - - if (!fan_control_allowed) - return -EPERM; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - - if (level == TPACPI_FAN_LAST_LEVEL) - level = fan_control_desired_level; - - rc = fan_set_level(level); - if (!rc) - fan_update_desired_level(level); - - mutex_unlock(&fan_mutex); - return rc; -} - -static int fan_set_enable(void) -{ - u8 s; - int rc; - - if (!fan_control_allowed) - return -EPERM; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - rc = fan_get_status(&s); - if (rc < 0) - break; - - /* Don't go out of emergency fan mode */ - if (s != 7) { - s &= 0x07; - s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ - } - - if (!acpi_ec_write(fan_status_offset, s)) - rc = -EIO; - else { - tp_features.fan_ctrl_status_undef = 0; - rc = 0; - } - break; - - case TPACPI_FAN_WR_ACPI_SFAN: - rc = fan_get_status(&s); - if (rc < 0) - break; - - s &= 0x07; - - /* Set fan to at least level 4 */ - s |= 4; - - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) - rc= -EIO; - else - rc = 0; - break; - - default: - rc = -ENXIO; - } - - mutex_unlock(&fan_mutex); - return rc; -} - -static int fan_set_disable(void) -{ - int rc; - - if (!fan_control_allowed) - return -EPERM; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - - rc = 0; - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - case TPACPI_FAN_WR_TPEC: - if (!acpi_ec_write(fan_status_offset, 0x00)) - rc = -EIO; - else { - fan_control_desired_level = 0; - tp_features.fan_ctrl_status_undef = 0; - } - break; - - case TPACPI_FAN_WR_ACPI_SFAN: - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) - rc = -EIO; - else - fan_control_desired_level = 0; - break; - - default: - rc = -ENXIO; - } - - - mutex_unlock(&fan_mutex); - return rc; -} - -static int fan_set_speed(int speed) -{ - int rc; - - if (!fan_control_allowed) - return -EPERM; - - rc = mutex_lock_interruptible(&fan_mutex); - if (rc < 0) - return rc; - - rc = 0; - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_FANS: - if (speed >= 0 && speed <= 65535) { - if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", - speed, speed, speed)) - rc = -EIO; - } else - rc = -EINVAL; - break; - - default: - rc = -ENXIO; - } - - mutex_unlock(&fan_mutex); - return rc; -} - -static int fan_read(char *p) -{ - int len = 0; - int rc; - u8 status; - unsigned int speed = 0; - - switch (fan_status_access_mode) { - case TPACPI_FAN_RD_ACPI_GFAN: - /* 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status_safe(&status)) < 0) - return rc; - - len += sprintf(p + len, "status:\t\t%s\n" - "level:\t\t%d\n", - (status != 0) ? "enabled" : "disabled", status); - break; - - case TPACPI_FAN_RD_TPEC: - /* all except 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status_safe(&status)) < 0) - return rc; - - if (unlikely(tp_features.fan_ctrl_status_undef)) { - if (status != fan_control_initial_status) - tp_features.fan_ctrl_status_undef = 0; - else - /* Return most likely status. In fact, it - * might be the only possible status */ - status = TP_EC_FAN_AUTO; - } - - len += sprintf(p + len, "status:\t\t%s\n", - (status != 0) ? "enabled" : "disabled"); - - if ((rc = fan_get_speed(&speed)) < 0) - return rc; - - len += sprintf(p + len, "speed:\t\t%d\n", speed); - - if (status & TP_EC_FAN_FULLSPEED) - /* Disengaged mode takes precedence */ - len += sprintf(p + len, "level:\t\tdisengaged\n"); - else if (status & TP_EC_FAN_AUTO) - len += sprintf(p + len, "level:\t\tauto\n"); - else - len += sprintf(p + len, "level:\t\t%d\n", status); - break; - - case TPACPI_FAN_NONE: - default: - len += sprintf(p + len, "status:\t\tnot supported\n"); - } - - if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { - len += sprintf(p + len, "commands:\tlevel "); - - switch (fan_control_access_mode) { - case TPACPI_FAN_WR_ACPI_SFAN: - len += sprintf(p + len, " ( is 0-7)\n"); - break; - - default: - len += sprintf(p + len, " ( is 0-7, " - "auto, disengaged, full-speed)\n"); - break; - } - } - - if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) - len += sprintf(p + len, "commands:\tenable, disable\n" - "commands:\twatchdog ( is 0 (off), " - "1-120 (seconds))\n"); - - if (fan_control_commands & TPACPI_FAN_CMD_SPEED) - len += sprintf(p + len, "commands:\tspeed " - " ( is 0-65535)\n"); - - return len; -} - -static int fan_write_cmd_level(const char *cmd, int *rc) -{ - int level; - - if (strlencmp(cmd, "level auto") == 0) - level = TP_EC_FAN_AUTO; - else if ((strlencmp(cmd, "level disengaged") == 0) | - (strlencmp(cmd, "level full-speed") == 0)) - level = TP_EC_FAN_FULLSPEED; - else if (sscanf(cmd, "level %d", &level) != 1) - return 0; - - if ((*rc = fan_set_level_safe(level)) == -ENXIO) - printk(IBM_ERR "level command accepted for unsupported " - "access mode %d", fan_control_access_mode); - - return 1; -} - -static int fan_write_cmd_enable(const char *cmd, int *rc) -{ - if (strlencmp(cmd, "enable") != 0) - return 0; - - if ((*rc = fan_set_enable()) == -ENXIO) - printk(IBM_ERR "enable command accepted for unsupported " - "access mode %d", fan_control_access_mode); - - return 1; -} - -static int fan_write_cmd_disable(const char *cmd, int *rc) -{ - if (strlencmp(cmd, "disable") != 0) - return 0; - - if ((*rc = fan_set_disable()) == -ENXIO) - printk(IBM_ERR "disable command accepted for unsupported " - "access mode %d", fan_control_access_mode); - - return 1; -} - -static int fan_write_cmd_speed(const char *cmd, int *rc) -{ - int speed; - - /* TODO: - * Support speed ? */ - - if (sscanf(cmd, "speed %d", &speed) != 1) - return 0; - - if ((*rc = fan_set_speed(speed)) == -ENXIO) - printk(IBM_ERR "speed command accepted for unsupported " - "access mode %d", fan_control_access_mode); - - return 1; -} - -static int fan_write_cmd_watchdog(const char *cmd, int *rc) -{ - int interval; - - if (sscanf(cmd, "watchdog %d", &interval) != 1) - return 0; - - if (interval < 0 || interval > 120) - *rc = -EINVAL; - else - fan_watchdog_maxinterval = interval; - - return 1; -} - -static int fan_write(char *buf) -{ - char *cmd; - int rc = 0; - - while (!rc && (cmd = next_cmd(&buf))) { - if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) && - fan_write_cmd_level(cmd, &rc)) && - !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) && - (fan_write_cmd_enable(cmd, &rc) || - fan_write_cmd_disable(cmd, &rc) || - fan_write_cmd_watchdog(cmd, &rc))) && - !((fan_control_commands & TPACPI_FAN_CMD_SPEED) && - fan_write_cmd_speed(cmd, &rc)) - ) - rc = -EINVAL; - else if (!rc) - fan_watchdog_reset(); - } - - return rc; -} - -static struct ibm_struct fan_driver_data = { - .name = "fan", - .read = fan_read, - .write = fan_write, - .exit = fan_exit, -}; - -/**************************************************************************** - **************************************************************************** - * - * Infrastructure - * - **************************************************************************** - ****************************************************************************/ - -/* /proc support */ -static struct proc_dir_entry *proc_dir = NULL; - -/* Subdriver registry */ -static LIST_HEAD(tpacpi_all_drivers); - - -/* - * Module and infrastructure proble, init and exit handling - */ - -#ifdef CONFIG_THINKPAD_ACPI_DEBUG -static const char * __init str_supported(int is_supported) -{ - static char text_unsupported[] __initdata = "not supported"; - - return (is_supported)? &text_unsupported[4] : &text_unsupported[0]; -} -#endif /* CONFIG_THINKPAD_ACPI_DEBUG */ - -static int __init ibm_init(struct ibm_init_struct *iibm) -{ - int ret; - struct ibm_struct *ibm = iibm->data; - struct proc_dir_entry *entry; - - BUG_ON(ibm == NULL); - - INIT_LIST_HEAD(&ibm->all_drivers); - - if (ibm->flags.experimental && !experimental) - return 0; - - dbg_printk(TPACPI_DBG_INIT, - "probing for %s\n", ibm->name); - - if (iibm->init) { - ret = iibm->init(iibm); - if (ret > 0) - return 0; /* probe failed */ - if (ret) - return ret; - - ibm->flags.init_called = 1; - } - - if (ibm->acpi) { - if (ibm->acpi->hid) { - ret = register_tpacpi_subdriver(ibm); - if (ret) - goto err_out; - } - - if (ibm->acpi->notify) { - ret = setup_acpi_notify(ibm); - if (ret == -ENODEV) { - printk(IBM_NOTICE "disabling subdriver %s\n", - ibm->name); - ret = 0; - goto err_out; - } - if (ret < 0) - goto err_out; - } - } - - dbg_printk(TPACPI_DBG_INIT, - "%s installed\n", ibm->name); - - if (ibm->read) { - entry = create_proc_entry(ibm->name, - S_IFREG | S_IRUGO | S_IWUSR, - proc_dir); - if (!entry) { - printk(IBM_ERR "unable to create proc entry %s\n", - ibm->name); - ret = -ENODEV; - goto err_out; - } - entry->owner = THIS_MODULE; - entry->data = ibm; - entry->read_proc = &dispatch_procfs_read; - if (ibm->write) - entry->write_proc = &dispatch_procfs_write; - ibm->flags.proc_created = 1; - } - - list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); - - return 0; - -err_out: - dbg_printk(TPACPI_DBG_INIT, - "%s: at error exit path with result %d\n", - ibm->name, ret); - - ibm_exit(ibm); - return (ret < 0)? ret : 0; -} - -static void ibm_exit(struct ibm_struct *ibm) -{ - dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); - - list_del_init(&ibm->all_drivers); - - if (ibm->flags.acpi_notify_installed) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: acpi_remove_notify_handler\n", ibm->name); - BUG_ON(!ibm->acpi); - acpi_remove_notify_handler(*ibm->acpi->handle, - ibm->acpi->type, - dispatch_acpi_notify); - ibm->flags.acpi_notify_installed = 0; - ibm->flags.acpi_notify_installed = 0; - } - - if (ibm->flags.proc_created) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: remove_proc_entry\n", ibm->name); - remove_proc_entry(ibm->name, proc_dir); - ibm->flags.proc_created = 0; - } - - if (ibm->flags.acpi_driver_registered) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: acpi_bus_unregister_driver\n", ibm->name); - BUG_ON(!ibm->acpi); - acpi_bus_unregister_driver(ibm->acpi->driver); - kfree(ibm->acpi->driver); - ibm->acpi->driver = NULL; - ibm->flags.acpi_driver_registered = 0; - } - - if (ibm->flags.init_called && ibm->exit) { - ibm->exit(); - ibm->flags.init_called = 0; - } - - dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); -} - -/* Probing */ - -static char *ibm_thinkpad_ec_found = NULL; - -static char* __init check_dmi_for_ec(void) -{ - struct dmi_device *dev = NULL; - char ec_fw_string[18]; - - /* - * ThinkPad T23 or newer, A31 or newer, R50e or newer, - * X32 or newer, all Z series; Some models must have an - * up-to-date BIOS or they will not be detected. - * - * See http://thinkwiki.org/wiki/List_of_DMI_IDs - */ - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { - if (sscanf(dev->name, - "IBM ThinkPad Embedded Controller -[%17c", - ec_fw_string) == 1) { - ec_fw_string[sizeof(ec_fw_string) - 1] = 0; - ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; - return kstrdup(ec_fw_string, GFP_KERNEL); - } - } - return NULL; -} - -static int __init probe_for_thinkpad(void) -{ - int is_thinkpad; - - if (acpi_disabled) - return -ENODEV; - - /* - * Non-ancient models have better DMI tagging, but very old models - * don't. - */ - is_thinkpad = dmi_name_in_vendors("ThinkPad"); - - /* ec is required because many other handles are relative to it */ - IBM_ACPIHANDLE_INIT(ec); - if (!ec_handle) { - if (is_thinkpad) - printk(IBM_ERR - "Not yet supported ThinkPad detected!\n"); - return -ENODEV; - } - - /* - * Risks a regression on very old machines, but reduces potential - * false positives a damn great deal - */ - if (!is_thinkpad) - is_thinkpad = dmi_name_in_vendors("IBM"); - - if (!is_thinkpad && !force_load) - return -ENODEV; - - return 0; -} - - -/* Module init, exit, parameters */ - -static struct ibm_init_struct ibms_init[] __initdata = { - { - .init = thinkpad_acpi_driver_init, - .data = &thinkpad_acpi_driver_data, - }, - { - .init = hotkey_init, - .data = &hotkey_driver_data, - }, - { - .init = bluetooth_init, - .data = &bluetooth_driver_data, - }, - { - .init = wan_init, - .data = &wan_driver_data, - }, - { - .init = video_init, - .data = &video_driver_data, - }, - { - .init = light_init, - .data = &light_driver_data, - }, -#ifdef CONFIG_THINKPAD_ACPI_DOCK - { - .init = dock_init, - .data = &dock_driver_data[0], - }, - { - .init = dock_init2, - .data = &dock_driver_data[1], - }, -#endif -#ifdef CONFIG_THINKPAD_ACPI_BAY - { - .init = bay_init, - .data = &bay_driver_data, - }, -#endif - { - .init = cmos_init, - .data = &cmos_driver_data, - }, - { - .init = led_init, - .data = &led_driver_data, - }, - { - .init = beep_init, - .data = &beep_driver_data, - }, - { - .init = thermal_init, - .data = &thermal_driver_data, - }, - { - .data = &ecdump_driver_data, - }, - { - .init = brightness_init, - .data = &brightness_driver_data, - }, - { - .data = &volume_driver_data, - }, - { - .init = fan_init, - .data = &fan_driver_data, - }, -}; - -static int __init set_ibm_param(const char *val, struct kernel_param *kp) -{ - unsigned int i; - struct ibm_struct *ibm; - - for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { - ibm = ibms_init[i].data; - BUG_ON(ibm == NULL); - - if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { - if (strlen(val) > sizeof(ibms_init[i].param) - 2) - return -ENOSPC; - strcpy(ibms_init[i].param, val); - strcat(ibms_init[i].param, ","); - return 0; - } - } - - return -EINVAL; -} - -static int experimental; -module_param(experimental, int, 0); - -static u32 dbg_level; -module_param_named(debug, dbg_level, uint, 0); - -static int force_load; -module_param(force_load, int, 0); - -static int fan_control_allowed; -module_param_named(fan_control, fan_control_allowed, int, 0); - -#define IBM_PARAM(feature) \ - module_param_call(feature, set_ibm_param, NULL, NULL, 0) - -IBM_PARAM(hotkey); -IBM_PARAM(bluetooth); -IBM_PARAM(video); -IBM_PARAM(light); -#ifdef CONFIG_THINKPAD_ACPI_DOCK -IBM_PARAM(dock); -#endif -#ifdef CONFIG_THINKPAD_ACPI_BAY -IBM_PARAM(bay); -#endif /* CONFIG_THINKPAD_ACPI_BAY */ -IBM_PARAM(cmos); -IBM_PARAM(led); -IBM_PARAM(beep); -IBM_PARAM(ecdump); -IBM_PARAM(brightness); -IBM_PARAM(volume); -IBM_PARAM(fan); - -static int __init thinkpad_acpi_module_init(void) -{ - int ret, i; - - /* Driver-level probe */ - ret = probe_for_thinkpad(); - if (ret) - return ret; - - /* Driver initialization */ - ibm_thinkpad_ec_found = check_dmi_for_ec(); - IBM_ACPIHANDLE_INIT(ecrd); - IBM_ACPIHANDLE_INIT(ecwr); - - proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); - if (!proc_dir) { - printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); - thinkpad_acpi_module_exit(); - return -ENODEV; - } - proc_dir->owner = THIS_MODULE; - - ret = platform_driver_register(&tpacpi_pdriver); - if (ret) { - printk(IBM_ERR "unable to register platform driver\n"); - thinkpad_acpi_module_exit(); - return ret; - } - ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); - if (ret) { - printk(IBM_ERR "unable to create sysfs driver attributes\n"); - thinkpad_acpi_module_exit(); - return ret; - } - - - /* Device initialization */ - tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, - NULL, 0); - if (IS_ERR(tpacpi_pdev)) { - ret = PTR_ERR(tpacpi_pdev); - tpacpi_pdev = NULL; - printk(IBM_ERR "unable to register platform device\n"); - thinkpad_acpi_module_exit(); - return ret; - } - tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); - if (IS_ERR(tpacpi_hwmon)) { - ret = PTR_ERR(tpacpi_hwmon); - tpacpi_hwmon = NULL; - printk(IBM_ERR "unable to register hwmon device\n"); - thinkpad_acpi_module_exit(); - return ret; - } - for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { - ret = ibm_init(&ibms_init[i]); - if (ret >= 0 && *ibms_init[i].param) - ret = ibms_init[i].data->write(ibms_init[i].param); - if (ret < 0) { - thinkpad_acpi_module_exit(); - return ret; - } - } - - return 0; -} - -static void thinkpad_acpi_module_exit(void) -{ - struct ibm_struct *ibm, *itmp; - - list_for_each_entry_safe_reverse(ibm, itmp, - &tpacpi_all_drivers, - all_drivers) { - ibm_exit(ibm); - } - - dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); - - if (tpacpi_hwmon) - hwmon_device_unregister(tpacpi_hwmon); - - if (tpacpi_pdev) - platform_device_unregister(tpacpi_pdev); - - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); - platform_driver_unregister(&tpacpi_pdriver); - - if (proc_dir) - remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); - - kfree(ibm_thinkpad_ec_found); -} - -module_init(thinkpad_acpi_module_init); -module_exit(thinkpad_acpi_module_exit); diff --git a/trunk/drivers/misc/thinkpad_acpi.h b/trunk/drivers/misc/thinkpad_acpi.h deleted file mode 100644 index 440145a02617..000000000000 --- a/trunk/drivers/misc/thinkpad_acpi.h +++ /dev/null @@ -1,572 +0,0 @@ -/* - * thinkpad_acpi.h - ThinkPad ACPI Extras - * - * - * Copyright (C) 2004-2005 Borislav Deianov - * Copyright (C) 2006-2007 Henrique de Moraes Holschuh - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __THINKPAD_ACPI_H__ -#define __THINKPAD_ACPI_H__ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - - -/**************************************************************************** - * Main driver - */ - -#define IBM_NAME "thinkpad" -#define IBM_DESC "ThinkPad ACPI Extras" -#define IBM_FILE "thinkpad_acpi" -#define IBM_URL "http://ibm-acpi.sf.net/" -#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" - -#define IBM_PROC_DIR "ibm" -#define IBM_ACPI_EVENT_PREFIX "ibm" -#define IBM_DRVR_NAME IBM_FILE - -#define IBM_LOG IBM_FILE ": " -#define IBM_ERR KERN_ERR IBM_LOG -#define IBM_NOTICE KERN_NOTICE IBM_LOG -#define IBM_INFO KERN_INFO IBM_LOG -#define IBM_DEBUG KERN_DEBUG IBM_LOG - -#define IBM_MAX_ACPI_ARGS 3 - -/* ThinkPad CMOS commands */ -#define TP_CMOS_VOLUME_DOWN 0 -#define TP_CMOS_VOLUME_UP 1 -#define TP_CMOS_VOLUME_MUTE 2 -#define TP_CMOS_BRIGHTNESS_UP 4 -#define TP_CMOS_BRIGHTNESS_DOWN 5 - -#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") -#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") -#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) - -/* Debugging */ -#define TPACPI_DBG_ALL 0xffff -#define TPACPI_DBG_ALL 0xffff -#define TPACPI_DBG_INIT 0x0001 -#define TPACPI_DBG_EXIT 0x0002 -#define dbg_printk(a_dbg_level, format, arg...) \ - do { if (dbg_level & a_dbg_level) \ - printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) -#ifdef CONFIG_THINKPAD_ACPI_DEBUG -#define vdbg_printk(a_dbg_level, format, arg...) \ - dbg_printk(a_dbg_level, format, ## arg) -static const char *str_supported(int is_supported); -#else -#define vdbg_printk(a_dbg_level, format, arg...) -#endif - -/* ACPI HIDs */ -#define IBM_HKEY_HID "IBM0068" -#define IBM_PCI_HID "PNP0A03" - -/* ACPI helpers */ -static int __must_check acpi_evalf(acpi_handle handle, - void *res, char *method, char *fmt, ...); -static int __must_check acpi_ec_read(int i, u8 * p); -static int __must_check acpi_ec_write(int i, u8 v); -static int __must_check _sta(acpi_handle handle); - -/* ACPI handles */ -static acpi_handle root_handle; /* root namespace */ -static acpi_handle ec_handle; /* EC */ -static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ -static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ - -static void drv_acpi_handle_init(char *name, - acpi_handle *handle, acpi_handle parent, - char **paths, int num_paths, char **path); -#define IBM_ACPIHANDLE_INIT(object) \ - drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ - object##_paths, ARRAY_SIZE(object##_paths), &object##_path) - -/* ThinkPad ACPI helpers */ -static int issue_thinkpad_cmos_command(int cmos_cmd); - -/* procfs support */ -static struct proc_dir_entry *proc_dir; - -/* procfs helpers */ -static int dispatch_procfs_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int dispatch_procfs_write(struct file *file, - const char __user * userbuf, - unsigned long count, void *data); -static char *next_cmd(char **cmds); - -/* sysfs support */ -struct attribute_set { - unsigned int members, max_members; - struct attribute_group group; -}; - -static struct attribute_set *create_attr_set(unsigned int max_members, - const char* name); -#define destroy_attr_set(_set) \ - kfree(_set); -static int add_to_attr_set(struct attribute_set* s, struct attribute *attr); -static int add_many_to_attr_set(struct attribute_set* s, - struct attribute **attr, - unsigned int count); -#define register_attr_set_with_sysfs(_attr_set, _kobj) \ - sysfs_create_group(_kobj, &_attr_set->group) -static void delete_attr_set(struct attribute_set* s, struct kobject *kobj); - -static int parse_strtoul(const char *buf, unsigned long max, - unsigned long *value); - -/* Device model */ -static struct platform_device *tpacpi_pdev; -static struct class_device *tpacpi_hwmon; -static struct platform_driver tpacpi_pdriver; -static int tpacpi_create_driver_attributes(struct device_driver *drv); -static void tpacpi_remove_driver_attributes(struct device_driver *drv); - -/* Module */ -static int experimental; -static u32 dbg_level; -static int force_load; -static char *ibm_thinkpad_ec_found; - -static char* check_dmi_for_ec(void); -static int thinkpad_acpi_module_init(void); -static void thinkpad_acpi_module_exit(void); - - -/**************************************************************************** - * Subdrivers - */ - -struct ibm_struct; - -struct tp_acpi_drv_struct { - char *hid; - struct acpi_driver *driver; - - void (*notify) (struct ibm_struct *, u32); - acpi_handle *handle; - u32 type; - struct acpi_device *device; -}; - -struct ibm_struct { - char *name; - - int (*read) (char *); - int (*write) (char *); - void (*exit) (void); - - struct list_head all_drivers; - - struct tp_acpi_drv_struct *acpi; - - struct { - u8 acpi_driver_registered:1; - u8 acpi_notify_installed:1; - u8 proc_created:1; - u8 init_called:1; - u8 experimental:1; - } flags; -}; - -struct ibm_init_struct { - char param[32]; - - int (*init) (struct ibm_init_struct *); - struct ibm_struct *data; -}; - -static struct { -#ifdef CONFIG_THINKPAD_ACPI_BAY - u16 bay_status:1; - u16 bay_eject:1; - u16 bay_status2:1; - u16 bay_eject2:1; -#endif - u16 bluetooth:1; - u16 hotkey:1; - u16 hotkey_mask:1; - u16 light:1; - u16 light_status:1; - u16 wan:1; - u16 fan_ctrl_status_undef:1; -} tp_features; - -static struct list_head tpacpi_all_drivers; - -static struct ibm_init_struct ibms_init[]; -static int set_ibm_param(const char *val, struct kernel_param *kp); -static int ibm_init(struct ibm_init_struct *iibm); -static void ibm_exit(struct ibm_struct *ibm); - - -/* - * procfs master subdriver - */ -static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm); -static int thinkpad_acpi_driver_read(char *p); - - -/* - * Bay subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_BAY -static acpi_handle bay_handle, bay_ej_handle; -static acpi_handle bay2_handle, bay2_ej_handle; - -static int bay_init(struct ibm_init_struct *iibm); -static void bay_notify(struct ibm_struct *ibm, u32 event); -static int bay_read(char *p); -static int bay_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - - -/* - * Beep subdriver - */ - -static acpi_handle beep_handle; - -static int beep_read(char *p); -static int beep_write(char *buf); - - -/* - * Bluetooth subdriver - */ - -#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth" - -enum { - /* ACPI GBDC/SBDC bits */ - TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ - TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ - TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ -}; - -static int bluetooth_init(struct ibm_init_struct *iibm); -static int bluetooth_get_radiosw(void); -static int bluetooth_set_radiosw(int radio_on); -static int bluetooth_read(char *p); -static int bluetooth_write(char *buf); - - -/* - * Brightness (backlight) subdriver - */ - -#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" - -static struct backlight_device *ibm_backlight_device; -static int brightness_offset = 0x31; - -static int brightness_init(struct ibm_init_struct *iibm); -static void brightness_exit(void); -static int brightness_get(struct backlight_device *bd); -static int brightness_set(int value); -static int brightness_update_status(struct backlight_device *bd); -static int brightness_read(char *p); -static int brightness_write(char *buf); - - -/* - * CMOS subdriver - */ - -static int cmos_read(char *p); -static int cmos_write(char *buf); - - -/* - * Dock subdriver - */ - -#ifdef CONFIG_THINKPAD_ACPI_DOCK -static acpi_handle pci_handle; -static acpi_handle dock_handle; - -static void dock_notify(struct ibm_struct *ibm, u32 event); -static int dock_read(char *p); -static int dock_write(char *buf); -#endif /* CONFIG_THINKPAD_ACPI_DOCK */ - - -/* - * EC dump subdriver - */ - -static int ecdump_read(char *p) ; -static int ecdump_write(char *buf); - - -/* - * Fan subdriver - */ - -enum { /* Fan control constants */ - fan_status_offset = 0x2f, /* EC register 0x2f */ - fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) - * 0x84 must be read before 0x85 */ - - TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ - TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ - - TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ -}; - -enum fan_status_access_mode { - TPACPI_FAN_NONE = 0, /* No fan status or control */ - TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ - TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ -}; - -enum fan_control_access_mode { - TPACPI_FAN_WR_NONE = 0, /* No fan control */ - TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ - TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ - TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ -}; - -enum fan_control_commands { - TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ - TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ - TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, - * and also watchdog cmd */ -}; - -static int fan_control_allowed; - -static enum fan_status_access_mode fan_status_access_mode; -static enum fan_control_access_mode fan_control_access_mode; -static enum fan_control_commands fan_control_commands; -static u8 fan_control_initial_status; -static u8 fan_control_desired_level; -static int fan_watchdog_maxinterval; - -static struct mutex fan_mutex; - -static acpi_handle fans_handle, gfan_handle, sfan_handle; - -static int fan_init(struct ibm_init_struct *iibm); -static void fan_exit(void); -static int fan_get_status(u8 *status); -static int fan_get_status_safe(u8 *status); -static int fan_get_speed(unsigned int *speed); -static void fan_update_desired_level(u8 status); -static void fan_watchdog_fire(struct work_struct *ignored); -static void fan_watchdog_reset(void); -static int fan_set_level(int level); -static int fan_set_level_safe(int level); -static int fan_set_enable(void); -static int fan_set_disable(void); -static int fan_set_speed(int speed); -static int fan_read(char *p); -static int fan_write(char *buf); -static int fan_write_cmd_level(const char *cmd, int *rc); -static int fan_write_cmd_enable(const char *cmd, int *rc); -static int fan_write_cmd_disable(const char *cmd, int *rc); -static int fan_write_cmd_speed(const char *cmd, int *rc); -static int fan_write_cmd_watchdog(const char *cmd, int *rc); - - -/* - * Hotkey subdriver - */ - -#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey" - -static int hotkey_orig_status; -static int hotkey_orig_mask; - -static struct mutex hotkey_mutex; - -static int hotkey_init(struct ibm_init_struct *iibm); -static void hotkey_exit(void); -static int hotkey_get(int *status, int *mask); -static int hotkey_set(int status, int mask); -static void hotkey_notify(struct ibm_struct *ibm, u32 event); -static int hotkey_read(char *p); -static int hotkey_write(char *buf); - - -/* - * LED subdriver - */ - -enum led_access_mode { - TPACPI_LED_NONE = 0, - TPACPI_LED_570, /* 570 */ - TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - TPACPI_LED_NEW, /* all others */ -}; - -enum { /* For TPACPI_LED_OLD */ - TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ - TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ - TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ -}; - -static enum led_access_mode led_supported; -static acpi_handle led_handle; - -static int led_init(struct ibm_init_struct *iibm); -static int led_read(char *p); -static int led_write(char *buf); - -/* - * Light (thinklight) subdriver - */ - -static acpi_handle lght_handle, ledb_handle; - -static int light_init(struct ibm_init_struct *iibm); -static int light_read(char *p); -static int light_write(char *buf); - - -/* - * Thermal subdriver - */ - -enum thermal_access_mode { - TPACPI_THERMAL_NONE = 0, /* No thermal support */ - TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ - TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ - TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ - TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ -}; - -enum { /* TPACPI_THERMAL_TPEC_* */ - TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ - TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ - TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ -}; - -#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ -struct ibm_thermal_sensors_struct { - s32 temp[TPACPI_MAX_THERMAL_SENSORS]; -}; - -static enum thermal_access_mode thermal_read_mode; - -static int thermal_init(struct ibm_init_struct *iibm); -static int thermal_get_sensor(int idx, s32 *value); -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); -static int thermal_read(char *p); - - -/* - * Video subdriver - */ - -enum video_access_mode { - TPACPI_VIDEO_NONE = 0, - TPACPI_VIDEO_570, /* 570 */ - TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ - TPACPI_VIDEO_NEW, /* all others */ -}; - -enum { /* video status flags, based on VIDEO_570 */ - TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ - TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ - TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ -}; - -enum { /* TPACPI_VIDEO_570 constants */ - TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to - * video_status_flags */ - TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ - TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ -}; - -static enum video_access_mode video_supported; -static int video_orig_autosw; -static acpi_handle vid_handle, vid2_handle; - -static int video_init(struct ibm_init_struct *iibm); -static void video_exit(void); -static int video_outputsw_get(void); -static int video_outputsw_set(int status); -static int video_autosw_get(void); -static int video_autosw_set(int enable); -static int video_outputsw_cycle(void); -static int video_expand_toggle(void); -static int video_read(char *p); -static int video_write(char *buf); - - -/* - * Volume subdriver - */ - -static int volume_offset = 0x30; - -static int volume_read(char *p); -static int volume_write(char *buf); - - -/* - * Wan subdriver - */ - -#define TPACPI_WAN_SYSFS_GROUP "wwan" - -enum { - /* ACPI GWAN/SWAN bits */ - TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ - TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ - TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ -}; - -static int wan_init(struct ibm_init_struct *iibm); -static int wan_get_radiosw(void); -static int wan_set_radiosw(int radio_on); -static int wan_read(char *p); -static int wan_write(char *buf); - - -#endif /* __THINKPAD_ACPI_H */ diff --git a/trunk/drivers/misc/tifm_7xx1.c b/trunk/drivers/misc/tifm_7xx1.c index 1ba6c085419a..bc60e2fc3c2c 100644 --- a/trunk/drivers/misc/tifm_7xx1.c +++ b/trunk/drivers/misc/tifm_7xx1.c @@ -11,20 +11,10 @@ #include #include +#include #define DRIVER_NAME "tifm_7xx1" -#define DRIVER_VERSION "0.8" - -#define TIFM_IRQ_ENABLE 0x80000000 -#define TIFM_IRQ_SOCKMASK(x) (x) -#define TIFM_IRQ_CARDMASK(x) ((x) << 8) -#define TIFM_IRQ_FIFOMASK(x) ((x) << 16) -#define TIFM_IRQ_SETALL 0xffffffff - -static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm, - struct tifm_dev *sock) -{ -} +#define DRIVER_VERSION "0.7" static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) { @@ -32,7 +22,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) spin_lock_irqsave(&fm->lock, flags); fm->socket_change_set |= 1 << sock->socket_id; - tifm_queue_work(&fm->media_switcher); + wake_up_all(&fm->change_set_notify); spin_unlock_irqrestore(&fm->lock, flags); } @@ -40,7 +30,8 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; struct tifm_dev *sock; - unsigned int irq_status, cnt; + unsigned int irq_status; + unsigned int sock_irq_status, cnt; spin_lock(&fm->lock); irq_status = readl(fm->addr + FM_INTERRUPT_STATUS); @@ -54,12 +45,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) for (cnt = 0; cnt < fm->num_sockets; cnt++) { sock = fm->sockets[cnt]; - if (sock) { - if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1)) - sock->data_event(sock); - if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1)) - sock->card_event(sock); - } + sock_irq_status = (irq_status >> cnt) + & (TIFM_IRQ_FIFOMASK(1) + | TIFM_IRQ_CARDMASK(1)); + + if (sock && sock_irq_status) + sock->signal_irq(sock, sock_irq_status); } fm->socket_change_set |= irq_status @@ -67,57 +58,57 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); - if (fm->finish_me) - complete_all(fm->finish_me); - else if (!fm->socket_change_set) + if (!fm->socket_change_set) writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); else - tifm_queue_work(&fm->media_switcher); + wake_up_all(&fm->change_set_notify); spin_unlock(&fm->lock); return IRQ_HANDLED; } -static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr) +static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, + int is_x2) { unsigned int s_state; int cnt; writel(0x0e00, sock_addr + SOCK_CONTROL); - for (cnt = 16; cnt <= 256; cnt <<= 1) { + for (cnt = 0; cnt < 100; cnt++) { if (!(TIFM_SOCK_STATE_POWERED & readl(sock_addr + SOCK_PRESENT_STATE))) break; - - msleep(cnt); + msleep(10); } s_state = readl(sock_addr + SOCK_PRESENT_STATE); if (!(TIFM_SOCK_STATE_OCCUPIED & s_state)) - return 0; - - writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED, - sock_addr + SOCK_CONTROL); - - /* xd needs some extra time before power on */ - if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) - == TIFM_TYPE_XD) - msleep(40); + return FM_NULL; + + if (is_x2) { + writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); + } else { + // SmartMedia cards need extra 40 msec + if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1) + msleep(40); + writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED, + sock_addr + SOCK_CONTROL); + msleep(10); + writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED, + sock_addr + SOCK_CONTROL); + } - writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); - /* wait for power to stabilize */ - msleep(20); - for (cnt = 16; cnt <= 256; cnt <<= 1) { + for (cnt = 0; cnt < 100; cnt++) { if ((TIFM_SOCK_STATE_POWERED & readl(sock_addr + SOCK_PRESENT_STATE))) break; - - msleep(cnt); + msleep(10); } - writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), - sock_addr + SOCK_CONTROL); + if (!is_x2) + writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), + sock_addr + SOCK_CONTROL); return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; } @@ -128,77 +119,127 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_switch_media(struct work_struct *work) +static int tifm_7xx1_switch_media(void *data) { - struct tifm_adapter *fm = container_of(work, struct tifm_adapter, - media_switcher); - struct tifm_dev *sock; + struct tifm_adapter *fm = data; unsigned long flags; - unsigned char media_id; - unsigned int socket_change_set, cnt; - - spin_lock_irqsave(&fm->lock, flags); - socket_change_set = fm->socket_change_set; - fm->socket_change_set = 0; + tifm_media_id media_id; + char *card_name = "xx"; + int cnt, rc; + struct tifm_dev *sock; + unsigned int socket_change_set; - dev_dbg(fm->cdev.dev, "checking media set %x\n", - socket_change_set); + while (1) { + rc = wait_event_interruptible(fm->change_set_notify, + fm->socket_change_set); + if (rc == -ERESTARTSYS) + try_to_freeze(); - if (!socket_change_set) { - spin_unlock_irqrestore(&fm->lock, flags); - return; - } + spin_lock_irqsave(&fm->lock, flags); + socket_change_set = fm->socket_change_set; + fm->socket_change_set = 0; - for (cnt = 0; cnt < fm->num_sockets; cnt++) { - if (!(socket_change_set & (1 << cnt))) - continue; - sock = fm->sockets[cnt]; - if (sock) { - printk(KERN_INFO - "%s : demand removing card from socket %u:%u\n", - fm->cdev.class_id, fm->id, cnt); - fm->sockets[cnt] = NULL; - spin_unlock_irqrestore(&fm->lock, flags); - device_unregister(&sock->dev); - spin_lock_irqsave(&fm->lock, flags); - writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt) - + SOCK_CONTROL); - } + dev_dbg(fm->dev, "checking media set %x\n", + socket_change_set); + if (kthread_should_stop()) + socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - media_id = tifm_7xx1_toggle_sock_power( - tifm_7xx1_sock_addr(fm->addr, cnt)); - - // tifm_alloc_device will check if media_id is valid - sock = tifm_alloc_device(fm, cnt, media_id); - if (sock) { - sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt); + if (!socket_change_set) + continue; - if (!device_register(&sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (!(socket_change_set & (1 << cnt))) + continue; + sock = fm->sockets[cnt]; + if (sock) { + printk(KERN_INFO DRIVER_NAME + ": demand removing card from socket %d\n", + cnt); + fm->sockets[cnt] = NULL; + spin_unlock_irqrestore(&fm->lock, flags); + device_unregister(&sock->dev); spin_lock_irqsave(&fm->lock, flags); - if (!fm->sockets[cnt]) { - fm->sockets[cnt] = sock; - sock = NULL; + writel(0x0e00, + tifm_7xx1_sock_addr(fm->addr, cnt) + + SOCK_CONTROL); + } + if (kthread_should_stop()) + continue; + + spin_unlock_irqrestore(&fm->lock, flags); + media_id = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); + if (media_id) { + sock = tifm_alloc_device(fm); + if (sock) { + sock->addr = tifm_7xx1_sock_addr(fm->addr, + cnt); + sock->media_id = media_id; + sock->socket_id = cnt; + switch (media_id) { + case 1: + card_name = "xd"; + break; + case 2: + card_name = "ms"; + break; + case 3: + card_name = "sd"; + break; + default: + tifm_free_device(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + continue; + } + snprintf(sock->dev.bus_id, BUS_ID_SIZE, + "tifm_%s%u:%u", card_name, + fm->id, cnt); + printk(KERN_INFO DRIVER_NAME + ": %s card detected in socket %d\n", + card_name, cnt); + if (!device_register(&sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + if (!fm->sockets[cnt]) { + fm->sockets[cnt] = sock; + sock = NULL; + } + spin_unlock_irqrestore(&fm->lock, flags); + } + if (sock) + tifm_free_device(&sock->dev); } + spin_lock_irqsave(&fm->lock, flags); + } + } + + if (!kthread_should_stop()) { + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + } else { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) + fm->socket_change_set |= 1 << cnt; + } + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { spin_unlock_irqrestore(&fm->lock, flags); } - if (sock) - tifm_free_device(&sock->dev); } - spin_lock_irqsave(&fm->lock, flags); } - - writel(TIFM_IRQ_FIFOMASK(socket_change_set) - | TIFM_IRQ_CARDMASK(socket_change_set), - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - - writel(TIFM_IRQ_FIFOMASK(socket_change_set) - | TIFM_IRQ_CARDMASK(socket_change_set), - fm->addr + FM_SET_INTERRUPT_ENABLE); - - writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&fm->lock, flags); + return 0; } #ifdef CONFIG_PM @@ -217,11 +258,9 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) static int tifm_7xx1_resume(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); - int rc; - unsigned int good_sockets = 0, bad_sockets = 0; + int cnt, rc; unsigned long flags; - unsigned char new_ids[fm->num_sockets]; - DECLARE_COMPLETION_ONSTACK(finish_resume); + tifm_media_id new_ids[fm->num_sockets]; pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -232,49 +271,45 @@ static int tifm_7xx1_resume(struct pci_dev *dev) dev_dbg(&dev->dev, "resuming host\n"); - for (rc = 0; rc < fm->num_sockets; rc++) - new_ids[rc] = tifm_7xx1_toggle_sock_power( - tifm_7xx1_sock_addr(fm->addr, rc)); + for (cnt = 0; cnt < fm->num_sockets; cnt++) + new_ids[cnt] = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); spin_lock_irqsave(&fm->lock, flags); - for (rc = 0; rc < fm->num_sockets; rc++) { - if (fm->sockets[rc]) { - if (fm->sockets[rc]->type == new_ids[rc]) - good_sockets |= 1 << rc; - else - bad_sockets |= 1 << rc; + fm->socket_change_set = 0; + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) { + if (fm->sockets[cnt]->media_id == new_ids[cnt]) + fm->socket_change_set |= 1 << cnt; + + fm->sockets[cnt]->media_id = new_ids[cnt]; } } writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n", - good_sockets, bad_sockets); - - fm->socket_change_set = 0; - if (good_sockets) { - fm->finish_me = &finish_resume; + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { + fm->socket_change_set = 0; spin_unlock_irqrestore(&fm->lock, flags); - rc = wait_for_completion_timeout(&finish_resume, HZ); - dev_dbg(&dev->dev, "wait returned %d\n", rc); - writel(TIFM_IRQ_FIFOMASK(good_sockets) - | TIFM_IRQ_CARDMASK(good_sockets), - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_FIFOMASK(good_sockets) - | TIFM_IRQ_CARDMASK(good_sockets), - fm->addr + FM_SET_INTERRUPT_ENABLE); - spin_lock_irqsave(&fm->lock, flags); - fm->finish_me = NULL; - fm->socket_change_set ^= good_sockets & fm->socket_change_set; } - fm->socket_change_set |= bad_sockets; - if (fm->socket_change_set) - tifm_queue_work(&fm->media_switcher); + wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); - spin_unlock_irqrestore(&fm->lock, flags); + spin_lock_irqsave(&fm->lock, flags); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); return 0; } @@ -310,14 +345,20 @@ static int tifm_7xx1_probe(struct pci_dev *dev, pci_intx(dev, 1); - fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM - ? 4 : 2, &dev->dev); + fm = tifm_alloc_adapter(); if (!fm) { rc = -ENOMEM; goto err_out_int; } - INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); + fm->dev = &dev->dev; + fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) + ? 4 : 2; + fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, + GFP_KERNEL); + if (!fm->sockets) + goto err_out_free; + fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -326,16 +367,19 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (!fm->addr) goto err_out_free; - rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm); + rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); if (rc) goto err_out_unmap; - rc = tifm_add_adapter(fm); + init_waitqueue_head(&fm->change_set_notify); + rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); if (rc) goto err_out_irq; + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); + wake_up_process(fm->media_switcher); return 0; err_out_irq: @@ -357,12 +401,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev, static void tifm_7xx1_remove(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); + unsigned long flags; - fm->eject = tifm_7xx1_dummy_eject; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); mmiowb(); free_irq(dev->irq, fm); + spin_lock_irqsave(&fm->lock, flags); + fm->socket_change_set = (1 << fm->num_sockets) - 1; + spin_unlock_irqrestore(&fm->lock, flags); + + kthread_stop(fm->media_switcher); + tifm_remove_adapter(fm); pci_set_drvdata(dev, NULL); diff --git a/trunk/drivers/misc/tifm_core.c b/trunk/drivers/misc/tifm_core.c index d195fb088f4a..6b10ebe9d936 100644 --- a/trunk/drivers/misc/tifm_core.c +++ b/trunk/drivers/misc/tifm_core.c @@ -14,124 +14,71 @@ #include #define DRIVER_NAME "tifm_core" -#define DRIVER_VERSION "0.8" +#define DRIVER_VERSION "0.7" -static struct workqueue_struct *workqueue; static DEFINE_IDR(tifm_adapter_idr); static DEFINE_SPINLOCK(tifm_adapter_lock); -static const char *tifm_media_type_name(unsigned char type, unsigned char nt) +static tifm_media_id *tifm_device_match(tifm_media_id *ids, + struct tifm_dev *dev) { - const char *card_type_name[3][3] = { - { "SmartMedia/xD", "MemoryStick", "MMC/SD" }, - { "XD", "MS", "SD"}, - { "xd", "ms", "sd"} - }; - - if (nt > 2 || type < 1 || type > 3) - return NULL; - return card_type_name[nt][type - 1]; + while (*ids) { + if (dev->media_id == *ids) + return ids; + ids++; + } + return NULL; } -static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id) +static int tifm_match(struct device *dev, struct device_driver *drv) { - if (sock->type == id->type) - return 1; - return 0; -} + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *fm_drv; -static int tifm_bus_match(struct device *dev, struct device_driver *drv) -{ - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver, - driver); - struct tifm_device_id *ids = fm_drv->id_table; - - if (ids) { - while (ids->type) { - if (tifm_dev_match(sock, ids)) - return 1; - ++ids; - } - } - return 0; + fm_drv = container_of(drv, struct tifm_driver, driver); + if (!fm_drv->id_table) + return -EINVAL; + if (tifm_device_match(fm_drv->id_table, fm_dev)) + return 1; + return -ENODEV; } static int tifm_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); + struct tifm_dev *fm_dev; int i = 0; int length = 0; + const char *card_type_name[] = {"INV", "SM", "MS", "SD"}; + if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev))) + return -ENODEV; if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id])) return -ENOMEM; return 0; } -static int tifm_device_probe(struct device *dev) -{ - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver, - driver); - int rc = -ENODEV; - - get_device(dev); - if (dev->driver && drv->probe) { - rc = drv->probe(sock); - if (!rc) - return 0; - } - put_device(dev); - return rc; -} - -static void tifm_dummy_event(struct tifm_dev *sock) -{ - return; -} - -static int tifm_device_remove(struct device *dev) -{ - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver, - driver); - - if (dev->driver && drv->remove) { - sock->card_event = tifm_dummy_event; - sock->data_event = tifm_dummy_event; - drv->remove(sock); - sock->dev.driver = NULL; - } - - put_device(dev); - return 0; -} - #ifdef CONFIG_PM static int tifm_device_suspend(struct device *dev, pm_message_t state) { - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver, - driver); + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; - if (dev->driver && drv->suspend) - return drv->suspend(sock, state); + if (drv && drv->suspend) + return drv->suspend(fm_dev, state); return 0; } static int tifm_device_resume(struct device *dev) { - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver, - driver); + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; - if (dev->driver && drv->resume) - return drv->resume(sock); + if (drv && drv->resume) + return drv->resume(fm_dev); return 0; } @@ -142,33 +89,19 @@ static int tifm_device_resume(struct device *dev) #endif /* CONFIG_PM */ -static ssize_t type_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - return sprintf(buf, "%x", sock->type); -} - -static struct device_attribute tifm_dev_attrs[] = { - __ATTR(type, S_IRUGO, type_show, NULL), - __ATTR_NULL -}; - static struct bus_type tifm_bus_type = { - .name = "tifm", - .dev_attrs = tifm_dev_attrs, - .match = tifm_bus_match, - .uevent = tifm_uevent, - .probe = tifm_device_probe, - .remove = tifm_device_remove, - .suspend = tifm_device_suspend, - .resume = tifm_device_resume + .name = "tifm", + .match = tifm_match, + .uevent = tifm_uevent, + .suspend = tifm_device_suspend, + .resume = tifm_device_resume }; static void tifm_free(struct class_device *cdev) { struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); + kfree(fm->sockets); kfree(fm); } @@ -177,25 +110,28 @@ static struct class tifm_adapter_class = { .release = tifm_free }; -struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets, - struct device *dev) +struct tifm_adapter *tifm_alloc_adapter(void) { struct tifm_adapter *fm; - fm = kzalloc(sizeof(struct tifm_adapter) - + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL); + fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL); if (fm) { fm->cdev.class = &tifm_adapter_class; - fm->cdev.dev = dev; - class_device_initialize(&fm->cdev); spin_lock_init(&fm->lock); - fm->num_sockets = num_sockets; + class_device_initialize(&fm->cdev); } return fm; } EXPORT_SYMBOL(tifm_alloc_adapter); -int tifm_add_adapter(struct tifm_adapter *fm) +void tifm_free_adapter(struct tifm_adapter *fm) +{ + class_device_put(&fm->cdev); +} +EXPORT_SYMBOL(tifm_free_adapter); + +int tifm_add_adapter(struct tifm_adapter *fm, + int (*mediathreadfn)(void *data)) { int rc; @@ -205,80 +141,59 @@ int tifm_add_adapter(struct tifm_adapter *fm) spin_lock(&tifm_adapter_lock); rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id); spin_unlock(&tifm_adapter_lock); - if (rc) - return rc; + if (!rc) { + snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); + fm->media_switcher = kthread_create(mediathreadfn, + fm, "tifm/%u", fm->id); + + if (!IS_ERR(fm->media_switcher)) + return class_device_add(&fm->cdev); - snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); - rc = class_device_add(&fm->cdev); - if (rc) { spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); spin_unlock(&tifm_adapter_lock); + rc = -ENOMEM; } - return rc; } EXPORT_SYMBOL(tifm_add_adapter); void tifm_remove_adapter(struct tifm_adapter *fm) { - unsigned int cnt; - - flush_workqueue(workqueue); - for (cnt = 0; cnt < fm->num_sockets; ++cnt) { - if (fm->sockets[cnt]) - device_unregister(&fm->sockets[cnt]->dev); - } + class_device_del(&fm->cdev); spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); spin_unlock(&tifm_adapter_lock); - class_device_del(&fm->cdev); } EXPORT_SYMBOL(tifm_remove_adapter); -void tifm_free_adapter(struct tifm_adapter *fm) +void tifm_free_device(struct device *dev) { - class_device_put(&fm->cdev); + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + kfree(fm_dev); } -EXPORT_SYMBOL(tifm_free_adapter); +EXPORT_SYMBOL(tifm_free_device); -void tifm_free_device(struct device *dev) +static void tifm_dummy_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) { - struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - kfree(sock); + return; } -EXPORT_SYMBOL(tifm_free_device); -struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id, - unsigned char type) +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm) { - struct tifm_dev *sock = NULL; - - if (!tifm_media_type_name(type, 0)) - return sock; - - sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); - if (sock) { - spin_lock_init(&sock->lock); - sock->type = type; - sock->socket_id = id; - sock->card_event = tifm_dummy_event; - sock->data_event = tifm_dummy_event; - - sock->dev.parent = fm->cdev.dev; - sock->dev.bus = &tifm_bus_type; - sock->dev.dma_mask = fm->cdev.dev->dma_mask; - sock->dev.release = tifm_free_device; - - snprintf(sock->dev.bus_id, BUS_ID_SIZE, - "tifm_%s%u:%u", tifm_media_type_name(type, 2), - fm->id, id); - printk(KERN_INFO DRIVER_NAME - ": %s card detected in socket %u:%u\n", - tifm_media_type_name(type, 0), fm->id, id); + struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); + + if (dev) { + spin_lock_init(&dev->lock); + + dev->dev.parent = fm->dev; + dev->dev.bus = &tifm_bus_type; + dev->dev.release = tifm_free_device; + dev->signal_irq = tifm_dummy_signal_irq; } - return sock; + return dev; } EXPORT_SYMBOL(tifm_alloc_device); @@ -303,15 +218,54 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents, } EXPORT_SYMBOL(tifm_unmap_sg); -void tifm_queue_work(struct work_struct *work) +static int tifm_device_probe(struct device *dev) +{ + struct tifm_driver *drv; + struct tifm_dev *fm_dev; + int rc = 0; + const tifm_media_id *id; + + drv = container_of(dev->driver, struct tifm_driver, driver); + fm_dev = container_of(dev, struct tifm_dev, dev); + get_device(dev); + if (!fm_dev->drv && drv->probe && drv->id_table) { + rc = -ENODEV; + id = tifm_device_match(drv->id_table, fm_dev); + if (id) + rc = drv->probe(fm_dev); + if (rc >= 0) { + rc = 0; + fm_dev->drv = drv; + } + } + if (rc) + put_device(dev); + return rc; +} + +static int tifm_device_remove(struct device *dev) { - queue_work(workqueue, work); + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv) { + fm_dev->signal_irq = tifm_dummy_signal_irq; + if (drv->remove) + drv->remove(fm_dev); + fm_dev->drv = NULL; + } + + put_device(dev); + return 0; } -EXPORT_SYMBOL(tifm_queue_work); int tifm_register_driver(struct tifm_driver *drv) { drv->driver.bus = &tifm_bus_type; + drv->driver.probe = tifm_device_probe; + drv->driver.remove = tifm_device_remove; + drv->driver.suspend = tifm_device_suspend; + drv->driver.resume = tifm_device_resume; return driver_register(&drv->driver); } @@ -325,25 +279,13 @@ EXPORT_SYMBOL(tifm_unregister_driver); static int __init tifm_init(void) { - int rc; - - workqueue = create_freezeable_workqueue("tifm"); - if (!workqueue) - return -ENOMEM; - - rc = bus_register(&tifm_bus_type); - - if (rc) - goto err_out_wq; - - rc = class_register(&tifm_adapter_class); - if (!rc) - return 0; + int rc = bus_register(&tifm_bus_type); - bus_unregister(&tifm_bus_type); - -err_out_wq: - destroy_workqueue(workqueue); + if (!rc) { + rc = class_register(&tifm_adapter_class); + if (rc) + bus_unregister(&tifm_bus_type); + } return rc; } @@ -352,7 +294,6 @@ static void __exit tifm_exit(void) { class_unregister(&tifm_adapter_class); bus_unregister(&tifm_bus_type); - destroy_workqueue(workqueue); } subsys_initcall(tifm_init); diff --git a/trunk/drivers/mmc/Kconfig b/trunk/drivers/mmc/Kconfig index 6c97491543db..12af9c718764 100644 --- a/trunk/drivers/mmc/Kconfig +++ b/trunk/drivers/mmc/Kconfig @@ -19,10 +19,110 @@ config MMC_DEBUG This is an option for use by developers; most people should say N here. This enables MMC core and driver debugging. -source "drivers/mmc/core/Kconfig" +config MMC_BLOCK + tristate "MMC block device driver" + depends on MMC && BLOCK + default y + help + Say Y here to enable the MMC block device driver support. + This provides a block device driver, which you can use to + mount the filesystem. Almost everyone wishing MMC support + should say Y or M here. + +config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA && MMC + help + This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card + Interface (PL180 and PL181) support. If you have an ARM(R) + platform with a Multimedia Card slot, say Y or M here. + + If unsure, say N. + +config MMC_PXA + tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" + depends on ARCH_PXA && MMC + help + This selects the Intel(R) PXA(R) Multimedia card Interface. + If you have a PXA(R) platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + +config MMC_SDHCI + tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)" + depends on PCI && MMC && EXPERIMENTAL + help + This select the generic Secure Digital Host Controller Interface. + It is used by manufacturers such as Texas Instruments(R), Ricoh(R) + and Toshiba(R). Most controllers found in laptops are of this type. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +config MMC_OMAP + tristate "TI OMAP Multimedia Card Interface support" + depends on ARCH_OMAP && MMC + select TPS65010 if MACH_OMAP_H2 + help + This selects the TI OMAP Multimedia card Interface. + If you have an OMAP board with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. -source "drivers/mmc/card/Kconfig" +config MMC_WBSD + tristate "Winbond W83L51xD SD/MMC Card Interface support" + depends on MMC && ISA_DMA_API + help + This selects the Winbond(R) W83L51xD Secure digital and + Multimedia card Interface. + If you have a machine with a integrated W83L518D or W83L519D + SD/MMC card reader, say Y or M here. + + If unsure, say N. + +config MMC_AU1X + tristate "Alchemy AU1XX0 MMC Card Interface support" + depends on MMC && SOC_AU1200 + help + This selects the AMD Alchemy(R) Multimedia card interface. + If you have a Alchemy platform with a MMC slot, say Y or M here. + + If unsure, say N. + +config MMC_AT91 + tristate "AT91 SD/MMC Card Interface support" + depends on ARCH_AT91 && MMC + help + This selects the AT91 MCI controller. + + If unsure, say N. + +config MMC_IMX + tristate "Motorola i.MX Multimedia Card Interface support" + depends on ARCH_IMX && MMC + help + This selects the Motorola i.MX Multimedia card Interface. + If you have a i.MX platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + +config MMC_TIFM_SD + tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" + depends on MMC && EXPERIMENTAL && PCI + select TIFM_CORE + help + Say Y here if you want to be able to access MMC/SD cards with + the Texas Instruments(R) Flash Media card reader, found in many + laptops. + This option 'selects' (turns on, enables) 'TIFM_CORE', but you + probably also need appropriate card reader host adapter, such as + 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support + (TIFM_7XX1)'. -source "drivers/mmc/host/Kconfig" + To compile this driver as a module, choose M here: the + module will be called tifm_sd. endmenu diff --git a/trunk/drivers/mmc/Makefile b/trunk/drivers/mmc/Makefile index 9979f5e9765b..83ffb9326a54 100644 --- a/trunk/drivers/mmc/Makefile +++ b/trunk/drivers/mmc/Makefile @@ -2,11 +2,32 @@ # Makefile for the kernel mmc device drivers. # -ifeq ($(CONFIG_MMC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif +# +# Core +# +obj-$(CONFIG_MMC) += mmc_core.o + +# +# Media drivers +# +obj-$(CONFIG_MMC_BLOCK) += mmc_block.o + +# +# Host drivers +# +obj-$(CONFIG_MMC_ARMMMCI) += mmci.o +obj-$(CONFIG_MMC_PXA) += pxamci.o +obj-$(CONFIG_MMC_IMX) += imxmmc.o +obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_WBSD) += wbsd.o +obj-$(CONFIG_MMC_AU1X) += au1xmmc.o +obj-$(CONFIG_MMC_OMAP) += omap.o +obj-$(CONFIG_MMC_AT91) += at91_mci.o +obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o -obj-$(CONFIG_MMC) += core/ -obj-$(CONFIG_MMC) += card/ -obj-$(CONFIG_MMC) += host/ +mmc_core-y := mmc.o mmc_sysfs.o +mmc_core-$(CONFIG_BLOCK) += mmc_queue.o +ifeq ($(CONFIG_MMC_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/trunk/drivers/mmc/host/at91_mci.c b/trunk/drivers/mmc/at91_mci.c similarity index 99% rename from trunk/drivers/mmc/host/at91_mci.c rename to trunk/drivers/mmc/at91_mci.c index e37943c314cb..459f4b4feded 100644 --- a/trunk/drivers/mmc/host/at91_mci.c +++ b/trunk/drivers/mmc/at91_mci.c @@ -67,6 +67,7 @@ #include #include +#include #include #include diff --git a/trunk/drivers/mmc/host/au1xmmc.c b/trunk/drivers/mmc/au1xmmc.c similarity index 99% rename from trunk/drivers/mmc/host/au1xmmc.c rename to trunk/drivers/mmc/au1xmmc.c index b7156a4555b5..b834be261ab7 100644 --- a/trunk/drivers/mmc/host/au1xmmc.c +++ b/trunk/drivers/mmc/au1xmmc.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/mmc/host/au1xmmc.h b/trunk/drivers/mmc/au1xmmc.h similarity index 100% rename from trunk/drivers/mmc/host/au1xmmc.h rename to trunk/drivers/mmc/au1xmmc.h diff --git a/trunk/drivers/mmc/card/Kconfig b/trunk/drivers/mmc/card/Kconfig deleted file mode 100644 index 01a9fd376a1f..000000000000 --- a/trunk/drivers/mmc/card/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# MMC/SD card drivers -# - -comment "MMC/SD Card Drivers" - depends MMC - -config MMC_BLOCK - tristate "MMC block device driver" - depends on MMC && BLOCK - default y - help - Say Y here to enable the MMC block device driver support. - This provides a block device driver, which you can use to - mount the filesystem. Almost everyone wishing MMC support - should say Y or M here. - diff --git a/trunk/drivers/mmc/card/Makefile b/trunk/drivers/mmc/card/Makefile deleted file mode 100644 index cf8c939867f5..000000000000 --- a/trunk/drivers/mmc/card/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for MMC/SD card drivers -# - -ifeq ($(CONFIG_MMC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif - -obj-$(CONFIG_MMC_BLOCK) += mmc_block.o -mmc_block-objs := block.o queue.o - diff --git a/trunk/drivers/mmc/core/Kconfig b/trunk/drivers/mmc/core/Kconfig deleted file mode 100644 index 94222b9a15ea..000000000000 --- a/trunk/drivers/mmc/core/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# MMC core configuration -# - -config MMC_UNSAFE_RESUME - bool "Allow unsafe resume (DANGEROUS)" - depends on MMC != n - help - If you say Y here, the MMC layer will assume that all cards - stayed in their respective slots during the suspend. The - normal behaviour is to remove them at suspend and - redetecting them at resume. Breaking this assumption will - in most cases result in data corruption. - - This option is usually just for embedded systems which use - a MMC/SD card for rootfs. Most people should say N here. - diff --git a/trunk/drivers/mmc/core/Makefile b/trunk/drivers/mmc/core/Makefile deleted file mode 100644 index 1075b02ae754..000000000000 --- a/trunk/drivers/mmc/core/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the kernel mmc core. -# - -ifeq ($(CONFIG_MMC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif - -obj-$(CONFIG_MMC) += mmc_core.o -mmc_core-y := core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o - diff --git a/trunk/drivers/mmc/core/core.c b/trunk/drivers/mmc/core/core.c deleted file mode 100644 index 72c7cf4a9f9d..000000000000 --- a/trunk/drivers/mmc/core/core.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * linux/drivers/mmc/core/core.c - * - * Copyright (C) 2003-2004 Russell King, All Rights Reserved. - * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. - * MMCv4 support Copyright (C) 2006 Philip Langdale, 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "core.h" -#include "sysfs.h" - -#include "mmc_ops.h" -#include "sd_ops.h" - -extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); -extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); - -/** - * mmc_request_done - finish processing an MMC request - * @host: MMC host which completed request - * @mrq: MMC request which request - * - * MMC drivers should call this function when they have completed - * their processing of a request. - */ -void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) -{ - struct mmc_command *cmd = mrq->cmd; - int err = cmd->error; - - pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", - mmc_hostname(host), cmd->opcode, err, - mrq->data ? mrq->data->error : 0, - mrq->stop ? mrq->stop->error : 0, - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); - - if (err && cmd->retries) { - cmd->retries--; - cmd->error = 0; - host->ops->request(host, mrq); - } else if (mrq->done) { - mrq->done(mrq); - } -} - -EXPORT_SYMBOL(mmc_request_done); - -/** - * mmc_start_request - start a command on a host - * @host: MMC host to start command on - * @mrq: MMC request to start - * - * Queue a command on the specified host. We expect the - * caller to be holding the host lock with interrupts disabled. - */ -void -mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) -{ -#ifdef CONFIG_MMC_DEBUG - unsigned int i, sz; -#endif - - pr_debug("%s: starting CMD%u arg %08x flags %08x\n", - mmc_hostname(host), mrq->cmd->opcode, - mrq->cmd->arg, mrq->cmd->flags); - - WARN_ON(!host->claimed); - - mrq->cmd->error = 0; - mrq->cmd->mrq = mrq; - if (mrq->data) { - BUG_ON(mrq->data->blksz > host->max_blk_size); - BUG_ON(mrq->data->blocks > host->max_blk_count); - BUG_ON(mrq->data->blocks * mrq->data->blksz > - host->max_req_size); - -#ifdef CONFIG_MMC_DEBUG - sz = 0; - for (i = 0;i < mrq->data->sg_len;i++) - sz += mrq->data->sg[i].length; - BUG_ON(sz != mrq->data->blocks * mrq->data->blksz); -#endif - - mrq->cmd->data = mrq->data; - mrq->data->error = 0; - mrq->data->mrq = mrq; - if (mrq->stop) { - mrq->data->stop = mrq->stop; - mrq->stop->error = 0; - mrq->stop->mrq = mrq; - } - } - host->ops->request(host, mrq); -} - -EXPORT_SYMBOL(mmc_start_request); - -static void mmc_wait_done(struct mmc_request *mrq) -{ - complete(mrq->done_data); -} - -int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) -{ - DECLARE_COMPLETION_ONSTACK(complete); - - mrq->done_data = &complete; - mrq->done = mmc_wait_done; - - mmc_start_request(host, mrq); - - wait_for_completion(&complete); - - return 0; -} - -EXPORT_SYMBOL(mmc_wait_for_req); - -/** - * mmc_wait_for_cmd - start a command and wait for completion - * @host: MMC host to start command - * @cmd: MMC command to start - * @retries: maximum number of retries - * - * Start a new MMC command for a host, and wait for the command - * to complete. Return any error that occurred while the command - * was executing. Do not attempt to parse the response. - */ -int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) -{ - struct mmc_request mrq; - - BUG_ON(!host->claimed); - - memset(&mrq, 0, sizeof(struct mmc_request)); - - memset(cmd->resp, 0, sizeof(cmd->resp)); - cmd->retries = retries; - - mrq.cmd = cmd; - cmd->data = NULL; - - mmc_wait_for_req(host, &mrq); - - return cmd->error; -} - -EXPORT_SYMBOL(mmc_wait_for_cmd); - -/** - * mmc_set_data_timeout - set the timeout for a data command - * @data: data phase for command - * @card: the MMC card associated with the data transfer - * @write: flag to differentiate reads from writes - */ -void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, - int write) -{ - unsigned int mult; - - /* - * SD cards use a 100 multiplier rather than 10 - */ - mult = mmc_card_sd(card) ? 100 : 10; - - /* - * Scale up the multiplier (and therefore the timeout) by - * the r2w factor for writes. - */ - if (write) - mult <<= card->csd.r2w_factor; - - data->timeout_ns = card->csd.tacc_ns * mult; - data->timeout_clks = card->csd.tacc_clks * mult; - - /* - * SD cards also have an upper limit on the timeout. - */ - if (mmc_card_sd(card)) { - unsigned int timeout_us, limit_us; - - timeout_us = data->timeout_ns / 1000; - timeout_us += data->timeout_clks * 1000 / - (card->host->ios.clock / 1000); - - if (write) - limit_us = 250000; - else - limit_us = 100000; - - /* - * SDHC cards always use these fixed values. - */ - if (timeout_us > limit_us || mmc_card_blockaddr(card)) { - data->timeout_ns = limit_us * 1000; - data->timeout_clks = 0; - } - } -} -EXPORT_SYMBOL(mmc_set_data_timeout); - -/** - * __mmc_claim_host - exclusively claim a host - * @host: mmc host to claim - * @card: mmc card to claim host for - * - * Claim a host for a set of operations. If a valid card - * is passed and this wasn't the last card selected, select - * the card before returning. - * - * Note: you should use mmc_card_claim_host or mmc_claim_host. - */ -void mmc_claim_host(struct mmc_host *host) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - - add_wait_queue(&host->wq, &wait); - spin_lock_irqsave(&host->lock, flags); - while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (!host->claimed) - break; - spin_unlock_irqrestore(&host->lock, flags); - schedule(); - spin_lock_irqsave(&host->lock, flags); - } - set_current_state(TASK_RUNNING); - host->claimed = 1; - spin_unlock_irqrestore(&host->lock, flags); - remove_wait_queue(&host->wq, &wait); -} - -EXPORT_SYMBOL(mmc_claim_host); - -/** - * mmc_release_host - release a host - * @host: mmc host to release - * - * Release a MMC host, allowing others to claim the host - * for their operations. - */ -void mmc_release_host(struct mmc_host *host) -{ - unsigned long flags; - - BUG_ON(!host->claimed); - - spin_lock_irqsave(&host->lock, flags); - host->claimed = 0; - spin_unlock_irqrestore(&host->lock, flags); - - wake_up(&host->wq); -} - -EXPORT_SYMBOL(mmc_release_host); - -/* - * Internal function that does the actual ios call to the host driver, - * optionally printing some debug output. - */ -static inline void mmc_set_ios(struct mmc_host *host) -{ - struct mmc_ios *ios = &host->ios; - - pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " - "width %u timing %u\n", - mmc_hostname(host), ios->clock, ios->bus_mode, - ios->power_mode, ios->chip_select, ios->vdd, - ios->bus_width, ios->timing); - - host->ops->set_ios(host, ios); -} - -/* - * Control chip select pin on a host. - */ -void mmc_set_chip_select(struct mmc_host *host, int mode) -{ - host->ios.chip_select = mode; - mmc_set_ios(host); -} - -/* - * Sets the host clock to the highest possible frequency that - * is below "hz". - */ -void mmc_set_clock(struct mmc_host *host, unsigned int hz) -{ - WARN_ON(hz < host->f_min); - - if (hz > host->f_max) - hz = host->f_max; - - host->ios.clock = hz; - mmc_set_ios(host); -} - -/* - * Change the bus mode (open drain/push-pull) of a host. - */ -void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) -{ - host->ios.bus_mode = mode; - mmc_set_ios(host); -} - -/* - * Change data bus width of a host. - */ -void mmc_set_bus_width(struct mmc_host *host, unsigned int width) -{ - host->ios.bus_width = width; - mmc_set_ios(host); -} - -/* - * Mask off any voltages we don't support and select - * the lowest voltage - */ -u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) -{ - int bit; - - ocr &= host->ocr_avail; - - bit = ffs(ocr); - if (bit) { - bit -= 1; - - ocr &= 3 << bit; - - host->ios.vdd = bit; - mmc_set_ios(host); - } else { - ocr = 0; - } - - return ocr; -} - -/* - * Select timing parameters for host. - */ -void mmc_set_timing(struct mmc_host *host, unsigned int timing) -{ - host->ios.timing = timing; - mmc_set_ios(host); -} - -/* - * Allocate a new MMC card - */ -struct mmc_card *mmc_alloc_card(struct mmc_host *host) -{ - struct mmc_card *card; - - card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); - if (!card) - return ERR_PTR(-ENOMEM); - - mmc_init_card(card, host); - - return card; -} - -/* - * Apply power to the MMC stack. This is a two-stage process. - * First, we enable power to the card without the clock running. - * We then wait a bit for the power to stabilise. Finally, - * enable the bus drivers and clock to the card. - * - * We must _NOT_ enable the clock prior to power stablising. - * - * If a host does all the power sequencing itself, ignore the - * initial MMC_POWER_UP stage. - */ -static void mmc_power_up(struct mmc_host *host) -{ - int bit = fls(host->ocr_avail) - 1; - - host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.power_mode = MMC_POWER_UP; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); - - mmc_delay(1); - - host->ios.clock = host->f_min; - host->ios.power_mode = MMC_POWER_ON; - mmc_set_ios(host); - - mmc_delay(2); -} - -static void mmc_power_off(struct mmc_host *host) -{ - host->ios.clock = 0; - host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.power_mode = MMC_POWER_OFF; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); -} - -/* - * Assign a mmc bus handler to a host. Only one bus handler may control a - * host at any given time. - */ -void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) -{ - unsigned long flags; - - BUG_ON(!host); - BUG_ON(!ops); - - BUG_ON(!host->claimed); - - spin_lock_irqsave(&host->lock, flags); - - BUG_ON(host->bus_ops); - BUG_ON(host->bus_refs); - - host->bus_ops = ops; - host->bus_refs = 1; - host->bus_dead = 0; - - spin_unlock_irqrestore(&host->lock, flags); -} - -/* - * Remove the current bus handler from a host. Assumes that there are - * no interesting cards left, so the bus is powered down. - */ -void mmc_detach_bus(struct mmc_host *host) -{ - unsigned long flags; - - BUG_ON(!host); - - BUG_ON(!host->claimed); - BUG_ON(!host->bus_ops); - - spin_lock_irqsave(&host->lock, flags); - - host->bus_dead = 1; - - spin_unlock_irqrestore(&host->lock, flags); - - mmc_power_off(host); - - mmc_bus_put(host); -} - -/* - * Cleanup when the last reference to the bus operator is dropped. - */ -void __mmc_release_bus(struct mmc_host *host) -{ - BUG_ON(!host); - BUG_ON(host->bus_refs); - BUG_ON(!host->bus_dead); - - host->bus_ops = NULL; -} - -/** - * mmc_detect_change - process change of state on a MMC socket - * @host: host which changed state. - * @delay: optional delay to wait before detection (jiffies) - * - * All we know is that card(s) have been inserted or removed - * from the socket(s). We don't know which socket or cards. - */ -void mmc_detect_change(struct mmc_host *host, unsigned long delay) -{ -#ifdef CONFIG_MMC_DEBUG - mmc_claim_host(host); - BUG_ON(host->removed); - mmc_release_host(host); -#endif - - mmc_schedule_delayed_work(&host->detect, delay); -} - -EXPORT_SYMBOL(mmc_detect_change); - - -static void mmc_rescan(struct work_struct *work) -{ - struct mmc_host *host = - container_of(work, struct mmc_host, detect.work); - u32 ocr; - int err; - - mmc_bus_get(host); - - if (host->bus_ops == NULL) { - /* - * Only we can add a new handler, so it's safe to - * release the lock here. - */ - mmc_bus_put(host); - - mmc_claim_host(host); - - mmc_power_up(host); - mmc_go_idle(host); - - mmc_send_if_cond(host, host->ocr_avail); - - err = mmc_send_app_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { - if (mmc_attach_sd(host, ocr)) - mmc_power_off(host); - } else { - /* - * If we fail to detect any SD cards then try - * searching for MMC cards. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - } else { - mmc_power_off(host); - mmc_release_host(host); - } - } - } else { - if (host->bus_ops->detect && !host->bus_dead) - host->bus_ops->detect(host); - - mmc_bus_put(host); - } -} - - -/** - * mmc_alloc_host - initialise the per-host structure. - * @extra: sizeof private data structure - * @dev: pointer to host device model structure - * - * Initialise the per-host structure. - */ -struct mmc_host *mmc_alloc_host(int extra, struct device *dev) -{ - struct mmc_host *host; - - host = mmc_alloc_host_sysfs(extra, dev); - if (host) { - spin_lock_init(&host->lock); - init_waitqueue_head(&host->wq); - INIT_DELAYED_WORK(&host->detect, mmc_rescan); - - /* - * By default, hosts do not support SGIO or large requests. - * They have to set these according to their abilities. - */ - host->max_hw_segs = 1; - host->max_phys_segs = 1; - host->max_seg_size = PAGE_CACHE_SIZE; - - host->max_req_size = PAGE_CACHE_SIZE; - host->max_blk_size = 512; - host->max_blk_count = PAGE_CACHE_SIZE / 512; - } - - return host; -} - -EXPORT_SYMBOL(mmc_alloc_host); - -/** - * mmc_add_host - initialise host hardware - * @host: mmc host - */ -int mmc_add_host(struct mmc_host *host) -{ - int ret; - - ret = mmc_add_host_sysfs(host); - if (ret == 0) { - mmc_power_off(host); - mmc_detect_change(host, 0); - } - - return ret; -} - -EXPORT_SYMBOL(mmc_add_host); - -/** - * mmc_remove_host - remove host hardware - * @host: mmc host - * - * Unregister and remove all cards associated with this host, - * and power down the MMC bus. - */ -void mmc_remove_host(struct mmc_host *host) -{ -#ifdef CONFIG_MMC_DEBUG - mmc_claim_host(host); - host->removed = 1; - mmc_release_host(host); -#endif - - mmc_flush_scheduled_work(); - - mmc_bus_get(host); - if (host->bus_ops && !host->bus_dead) { - if (host->bus_ops->remove) - host->bus_ops->remove(host); - - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - } - mmc_bus_put(host); - - BUG_ON(host->card); - - mmc_power_off(host); - mmc_remove_host_sysfs(host); -} - -EXPORT_SYMBOL(mmc_remove_host); - -/** - * mmc_free_host - free the host structure - * @host: mmc host - * - * Free the host once all references to it have been dropped. - */ -void mmc_free_host(struct mmc_host *host) -{ - mmc_free_host_sysfs(host); -} - -EXPORT_SYMBOL(mmc_free_host); - -#ifdef CONFIG_PM - -/** - * mmc_suspend_host - suspend a host - * @host: mmc host - * @state: suspend mode (PM_SUSPEND_xxx) - */ -int mmc_suspend_host(struct mmc_host *host, pm_message_t state) -{ - mmc_flush_scheduled_work(); - - mmc_bus_get(host); - if (host->bus_ops && !host->bus_dead) { - if (host->bus_ops->suspend) - host->bus_ops->suspend(host); - if (!host->bus_ops->resume) { - if (host->bus_ops->remove) - host->bus_ops->remove(host); - - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - } - } - mmc_bus_put(host); - - mmc_power_off(host); - - return 0; -} - -EXPORT_SYMBOL(mmc_suspend_host); - -/** - * mmc_resume_host - resume a previously suspended host - * @host: mmc host - */ -int mmc_resume_host(struct mmc_host *host) -{ - mmc_bus_get(host); - if (host->bus_ops && !host->bus_dead) { - mmc_power_up(host); - BUG_ON(!host->bus_ops->resume); - host->bus_ops->resume(host); - } - mmc_bus_put(host); - - /* - * We add a slight delay here so that resume can progress - * in parallel. - */ - mmc_detect_change(host, 1); - - return 0; -} - -EXPORT_SYMBOL(mmc_resume_host); - -#endif - -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mmc/core/core.h b/trunk/drivers/mmc/core/core.h deleted file mode 100644 index 177264d090ac..000000000000 --- a/trunk/drivers/mmc/core/core.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * linux/drivers/mmc/core/core.h - * - * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright 2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef _MMC_CORE_CORE_H -#define _MMC_CORE_CORE_H - -#include - -#define MMC_CMD_RETRIES 3 - -struct mmc_bus_ops { - void (*remove)(struct mmc_host *); - void (*detect)(struct mmc_host *); - void (*suspend)(struct mmc_host *); - void (*resume)(struct mmc_host *); -}; - -void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); -void mmc_detach_bus(struct mmc_host *host); - -void __mmc_release_bus(struct mmc_host *host); - -static inline void mmc_bus_get(struct mmc_host *host) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->bus_refs++; - spin_unlock_irqrestore(&host->lock, flags); -} - -static inline void mmc_bus_put(struct mmc_host *host) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->bus_refs--; - if ((host->bus_refs == 0) && host->bus_ops) - __mmc_release_bus(host); - spin_unlock_irqrestore(&host->lock, flags); -} - -void mmc_set_chip_select(struct mmc_host *host, int mode); -void mmc_set_clock(struct mmc_host *host, unsigned int hz); -void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); -void mmc_set_bus_width(struct mmc_host *host, unsigned int width); -u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); -void mmc_set_timing(struct mmc_host *host, unsigned int timing); - -struct mmc_card *mmc_alloc_card(struct mmc_host *host); - -static inline void mmc_delay(unsigned int ms) -{ - if (ms < 1000 / HZ) { - cond_resched(); - mdelay(ms); - } else { - msleep(ms); - } -} - -#endif - diff --git a/trunk/drivers/mmc/core/mmc.c b/trunk/drivers/mmc/core/mmc.c deleted file mode 100644 index 42cc2867ed7d..000000000000 --- a/trunk/drivers/mmc/core/mmc.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * linux/drivers/mmc/mmc.c - * - * Copyright (C) 2003-2004 Russell King, All Rights Reserved. - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. - * MMCv4 support Copyright (C) 2006 Philip Langdale, 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. - */ - -#include - -#include -#include -#include - -#include "core.h" -#include "sysfs.h" -#include "mmc_ops.h" - -static const unsigned int tran_exp[] = { - 10000, 100000, 1000000, 10000000, - 0, 0, 0, 0 -}; - -static const unsigned char tran_mant[] = { - 0, 10, 12, 13, 15, 20, 25, 30, - 35, 40, 45, 50, 55, 60, 70, 80, -}; - -static const unsigned int tacc_exp[] = { - 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, -}; - -static const unsigned int tacc_mant[] = { - 0, 10, 12, 13, 15, 20, 25, 30, - 35, 40, 45, 50, 55, 60, 70, 80, -}; - -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int __off = 3 - ((start) / 32); \ - const int __shft = (start) & 31; \ - u32 __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - -/* - * Given the decoded CSD structure, decode the raw CID to our CID structure. - */ -static int mmc_decode_cid(struct mmc_card *card) -{ - u32 *resp = card->raw_cid; - - /* - * The selection of the format here is based upon published - * specs from sandisk and from what people have reported. - */ - switch (card->csd.mmca_vsn) { - case 0: /* MMC v1.0 - v1.2 */ - case 1: /* MMC v1.4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); - card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); - card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); - card->cid.serial = UNSTUFF_BITS(resp, 16, 24); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; - break; - - case 2: /* MMC v2.0 - v2.2 */ - case 3: /* MMC v3.1 - v3.3 */ - case 4: /* MMC v4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); - card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.serial = UNSTUFF_BITS(resp, 16, 32); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; - break; - - default: - printk("%s: card has unknown MMCA version %d\n", - mmc_hostname(card->host), card->csd.mmca_vsn); - return -EINVAL; - } - - return 0; -} - -/* - * Given a 128-bit response, decode to our card CSD structure. - */ -static int mmc_decode_csd(struct mmc_card *card) -{ - struct mmc_csd *csd = &card->csd; - unsigned int e, m, csd_struct; - u32 *resp = card->raw_csd; - - /* - * We only understand CSD structure v1.1 and v1.2. - * v1.2 has extra information in bits 15, 11 and 10. - */ - csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 1 && csd_struct != 2) { - printk("%s: unrecognised CSD structure version %d\n", - mmc_hostname(card->host), csd_struct); - return -EINVAL; - } - - csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); - - return 0; -} - -/* - * Read and decode extended CSD. - */ -static int mmc_read_ext_csd(struct mmc_card *card) -{ - int err; - u8 *ext_csd; - - BUG_ON(!card); - - err = MMC_ERR_FAILED; - - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return MMC_ERR_NONE; - - /* - * As the ext_csd is so large and mostly unused, we don't store the - * raw block in mmc_card. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - printk(KERN_ERR "%s: could not allocate a buffer to " - "receive the ext_csd. mmc v4 cards will be " - "treated as v3.\n", mmc_hostname(card->host)); - return MMC_ERR_FAILED; - } - - err = mmc_send_ext_csd(card, ext_csd); - if (err != MMC_ERR_NONE) { - /* - * High capacity cards should have this "magic" size - * stored in their CSD. - */ - if (card->csd.capacity == (4096 * 512)) { - printk(KERN_ERR "%s: unable to read EXT_CSD " - "on a possible high capacity card. " - "Card will be ignored.\n", - mmc_hostname(card->host)); - } else { - printk(KERN_WARNING "%s: unable to read " - "EXT_CSD, performance might " - "suffer.\n", - mmc_hostname(card->host)); - err = MMC_ERR_NONE; - } - goto out; - } - - card->ext_csd.sectors = - ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | - ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | - ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | - ext_csd[EXT_CSD_SEC_CNT + 3] << 24; - if (card->ext_csd.sectors) - mmc_card_set_blockaddr(card); - - switch (ext_csd[EXT_CSD_CARD_TYPE]) { - case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - break; - case EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 26000000; - break; - default: - /* MMC v4 spec says this cannot happen */ - printk(KERN_WARNING "%s: card is mmc v4 but doesn't " - "support any high-speed modes.\n", - mmc_hostname(card->host)); - goto out; - } - -out: - kfree(ext_csd); - - return err; -} - -/* - * Handle the detection and initialisation of a card. - * - * In the case of a resume, "curcard" will contain the card - * we're trying to reinitialise. - */ -static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, - struct mmc_card *oldcard) -{ - struct mmc_card *card; - int err; - u32 cid[4]; - unsigned int max_dtr; - - BUG_ON(!host); - BUG_ON(!host->claimed); - - /* - * Since we're changing the OCR value, we seem to - * need to tell some cards to go back to the idle - * state. We wait 1ms to give cards time to - * respond. - */ - mmc_go_idle(host); - - /* The extra bit indicates that we support high capacity */ - err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); - if (err != MMC_ERR_NONE) - goto err; - - /* - * Fetch CID from card. - */ - err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) - goto err; - - if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) - goto err; - - card = oldcard; - } else { - /* - * Allocate card structure. - */ - card = mmc_alloc_card(host); - if (IS_ERR(card)) - goto err; - - card->type = MMC_TYPE_MMC; - card->rca = 1; - memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); - } - - /* - * Set card RCA. - */ - err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) - goto free_card; - - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); - - if (!oldcard) { - /* - * Fetch CSD from card. - */ - err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) - goto free_card; - - err = mmc_decode_csd(card); - if (err < 0) - goto free_card; - err = mmc_decode_cid(card); - if (err < 0) - goto free_card; - } - - /* - * Select card, as all following commands rely on that. - */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; - - if (!oldcard) { - /* - * Fetch and process extened CSD. - */ - err = mmc_read_ext_csd(card); - if (err != MMC_ERR_NONE) - goto free_card; - } - - /* - * Activate high speed (if supported) - */ - if ((card->ext_csd.hs_max_dtr != 0) && - (host->caps & MMC_CAP_MMC_HIGHSPEED)) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1); - if (err != MMC_ERR_NONE) - goto free_card; - - mmc_card_set_highspeed(card); - - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); - } - - /* - * Compute bus speed. - */ - max_dtr = (unsigned int)-1; - - if (mmc_card_highspeed(card)) { - if (max_dtr > card->ext_csd.hs_max_dtr) - max_dtr = card->ext_csd.hs_max_dtr; - } else if (max_dtr > card->csd.max_dtr) { - max_dtr = card->csd.max_dtr; - } - - mmc_set_clock(host, max_dtr); - - /* - * Activate wide bus (if supported). - */ - if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && - (host->caps & MMC_CAP_4_BIT_DATA)) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) - goto free_card; - - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - } - - if (!oldcard) - host->card = card; - - return MMC_ERR_NONE; - -free_card: - if (!oldcard) - mmc_remove_card(card); -err: - - return MMC_ERR_FAILED; -} - -/* - * Host is being removed. Free up the current card. - */ -static void mmc_remove(struct mmc_host *host) -{ - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_remove_card(host->card); - host->card = NULL; -} - -/* - * Card detection callback from host. - */ -static void mmc_detect(struct mmc_host *host) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - - /* - * Just check if our card has been removed. - */ - err = mmc_send_status(host->card, NULL); - - mmc_release_host(host); - - if (err != MMC_ERR_NONE) { - mmc_remove_card(host->card); - host->card = NULL; - - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - } -} - -#ifdef CONFIG_MMC_UNSAFE_RESUME - -/* - * Suspend callback from host. - */ -static void mmc_suspend(struct mmc_host *host) -{ - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - mmc_deselect_cards(host); - host->card->state &= ~MMC_STATE_HIGHSPEED; - mmc_release_host(host); -} - -/* - * Resume callback from host. - * - * This function tries to determine if the same card is still present - * and, if so, restore all state to it. - */ -static void mmc_resume(struct mmc_host *host) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - - err = mmc_sd_init_card(host, host->ocr, host->card); - if (err != MMC_ERR_NONE) { - mmc_remove_card(host->card); - host->card = NULL; - - mmc_detach_bus(host); - } - - mmc_release_host(host); -} - -#else - -#define mmc_suspend NULL -#define mmc_resume NULL - -#endif - -static const struct mmc_bus_ops mmc_ops = { - .remove = mmc_remove, - .detect = mmc_detect, - .suspend = mmc_suspend, - .resume = mmc_resume, -}; - -/* - * Starting point for MMC card init. - */ -int mmc_attach_mmc(struct mmc_host *host, u32 ocr) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->claimed); - - mmc_attach_bus(host, &mmc_ops); - - /* - * Sanity check the voltages that the card claims to - * support. - */ - if (ocr & 0x7F) { - printk(KERN_WARNING "%s: card claims to support voltages " - "below the defined range. These will be ignored.\n", - mmc_hostname(host)); - ocr &= ~0x7F; - } - - host->ocr = mmc_select_voltage(host, ocr); - - /* - * Can we support the voltage of the card? - */ - if (!host->ocr) - goto err; - - /* - * Detect and init the card. - */ - err = mmc_sd_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) - goto err; - - mmc_release_host(host); - - err = mmc_register_card(host->card); - if (err) - goto reclaim_host; - - return 0; - -reclaim_host: - mmc_claim_host(host); - mmc_remove_card(host->card); - host->card = NULL; -err: - mmc_detach_bus(host); - mmc_release_host(host); - - return 0; -} - diff --git a/trunk/drivers/mmc/core/mmc_ops.c b/trunk/drivers/mmc/core/mmc_ops.c deleted file mode 100644 index 7dd720fa5895..000000000000 --- a/trunk/drivers/mmc/core/mmc_ops.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * linux/drivers/mmc/mmc_ops.h - * - * Copyright 2006-2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include - -#include -#include -#include - -#include "core.h" -#include "mmc_ops.h" - -static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SELECT_CARD; - - if (card) { - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - } else { - cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; - } - - err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - return MMC_ERR_NONE; -} - -int mmc_select_card(struct mmc_card *card) -{ - BUG_ON(!card); - - return _mmc_select_card(card->host, card); -} - -int mmc_deselect_cards(struct mmc_host *host) -{ - return _mmc_select_card(host, NULL); -} - -int mmc_go_idle(struct mmc_host *host) -{ - int err; - struct mmc_command cmd; - - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_GO_IDLE_STATE; - cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; - - err = mmc_wait_for_cmd(host, &cmd, 0); - - mmc_delay(1); - - mmc_set_chip_select(host, MMC_CS_DONTCARE); - - mmc_delay(1); - - return err; -} - -int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) -{ - struct mmc_command cmd; - int i, err = 0; - - BUG_ON(!host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; - - for (i = 100; i; i--) { - err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) - break; - - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) - break; - - err = MMC_ERR_TIMEOUT; - - mmc_delay(10); - } - - if (rocr) - *rocr = cmd.resp[0]; - - return err; -} - -int mmc_all_send_cid(struct mmc_host *host, u32 *cid) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!host); - BUG_ON(!cid); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_ALL_SEND_CID; - cmd.arg = 0; - cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; - - err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - memcpy(cid, cmd.resp, sizeof(u32) * 4); - - return MMC_ERR_NONE; -} - -int mmc_set_relative_addr(struct mmc_card *card) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!card); - BUG_ON(!card->host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SET_RELATIVE_ADDR; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - return MMC_ERR_NONE; -} - -int mmc_send_csd(struct mmc_card *card, u32 *csd) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - memcpy(csd, cmd.resp, sizeof(u32) * 4); - - return MMC_ERR_NONE; -} - -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) -{ - struct mmc_request mrq; - struct mmc_command cmd; - struct mmc_data data; - struct scatterlist sg; - - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); - - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(&cmd, 0, sizeof(struct mmc_command)); - memset(&data, 0, sizeof(struct mmc_data)); - - mrq.cmd = &cmd; - mrq.data = &data; - - cmd.opcode = MMC_SEND_EXT_CSD; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = 512; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, ext_csd, 512); - - mmc_set_data_timeout(&data, card, 0); - - mmc_wait_for_req(card->host, &mrq); - - if (cmd.error != MMC_ERR_NONE) - return cmd.error; - if (data.error != MMC_ERR_NONE) - return data.error; - - return MMC_ERR_NONE; -} - -int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!card); - BUG_ON(!card->host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SWITCH; - cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | - (index << 16) | - (value << 8) | - set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - return MMC_ERR_NONE; -} - -int mmc_send_status(struct mmc_card *card, u32 *status) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!card); - BUG_ON(!card->host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - if (status) - *status = cmd.resp[0]; - - return MMC_ERR_NONE; -} - diff --git a/trunk/drivers/mmc/core/mmc_ops.h b/trunk/drivers/mmc/core/mmc_ops.h deleted file mode 100644 index 7a481e8ca5ea..000000000000 --- a/trunk/drivers/mmc/core/mmc_ops.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/drivers/mmc/mmc_ops.h - * - * Copyright 2006-2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#ifndef _MMC_MMC_OPS_H -#define _MMC_MMC_OPS_H - -int mmc_select_card(struct mmc_card *card); -int mmc_deselect_cards(struct mmc_host *host); -int mmc_go_idle(struct mmc_host *host); -int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); -int mmc_all_send_cid(struct mmc_host *host, u32 *cid); -int mmc_set_relative_addr(struct mmc_card *card); -int mmc_send_csd(struct mmc_card *card, u32 *csd); -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); -int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); -int mmc_send_status(struct mmc_card *card, u32 *status); - -#endif - diff --git a/trunk/drivers/mmc/core/sd.c b/trunk/drivers/mmc/core/sd.c deleted file mode 100644 index c1dfd03d559a..000000000000 --- a/trunk/drivers/mmc/core/sd.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * linux/drivers/mmc/sd.c - * - * Copyright (C) 2003-2004 Russell King, All Rights Reserved. - * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. - * Copyright (C) 2005-2007 Pierre Ossman, 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. - */ - -#include - -#include -#include -#include - -#include "core.h" -#include "sysfs.h" -#include "mmc_ops.h" -#include "sd_ops.h" - -#include "core.h" - -static const unsigned int tran_exp[] = { - 10000, 100000, 1000000, 10000000, - 0, 0, 0, 0 -}; - -static const unsigned char tran_mant[] = { - 0, 10, 12, 13, 15, 20, 25, 30, - 35, 40, 45, 50, 55, 60, 70, 80, -}; - -static const unsigned int tacc_exp[] = { - 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, -}; - -static const unsigned int tacc_mant[] = { - 0, 10, 12, 13, 15, 20, 25, 30, - 35, 40, 45, 50, 55, 60, 70, 80, -}; - -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int __off = 3 - ((start) / 32); \ - const int __shft = (start) & 31; \ - u32 __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - -/* - * Given the decoded CSD structure, decode the raw CID to our CID structure. - */ -static void mmc_decode_cid(struct mmc_card *card) -{ - u32 *resp = card->raw_cid; - - memset(&card->cid, 0, sizeof(struct mmc_cid)); - - /* - * SD doesn't currently have a version field so we will - * have to assume we can parse this. - */ - card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); - card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4); - card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4); - card->cid.serial = UNSTUFF_BITS(resp, 24, 32); - card->cid.year = UNSTUFF_BITS(resp, 12, 8); - card->cid.month = UNSTUFF_BITS(resp, 8, 4); - - card->cid.year += 2000; /* SD cards year offset */ -} - -/* - * Given a 128-bit response, decode to our card CSD structure. - */ -static int mmc_decode_csd(struct mmc_card *card) -{ - struct mmc_csd *csd = &card->csd; - unsigned int e, m, csd_struct; - u32 *resp = card->raw_csd; - - csd_struct = UNSTUFF_BITS(resp, 126, 2); - - switch (csd_struct) { - case 0: - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); - break; - case 1: - /* - * This is a block-addressed SDHC card. Most - * interesting fields are unused and have fixed - * values. To avoid getting tripped by buggy cards, - * we assume those fixed values ourselves. - */ - mmc_card_set_blockaddr(card); - - csd->tacc_ns = 0; /* Unused */ - csd->tacc_clks = 0; /* Unused */ - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - m = UNSTUFF_BITS(resp, 48, 22); - csd->capacity = (1 + m) << 10; - - csd->read_blkbits = 9; - csd->read_partial = 0; - csd->write_misalign = 0; - csd->read_misalign = 0; - csd->r2w_factor = 4; /* Unused */ - csd->write_blkbits = 9; - csd->write_partial = 0; - break; - default: - printk("%s: unrecognised CSD structure version %d\n", - mmc_hostname(card->host), csd_struct); - return -EINVAL; - } - - return 0; -} - -/* - * Given a 64-bit response, decode to our card SCR structure. - */ -static int mmc_decode_scr(struct mmc_card *card) -{ - struct sd_scr *scr = &card->scr; - unsigned int scr_struct; - u32 resp[4]; - - BUG_ON(!mmc_card_sd(card)); - - resp[3] = card->raw_scr[1]; - resp[2] = card->raw_scr[0]; - - scr_struct = UNSTUFF_BITS(resp, 60, 4); - if (scr_struct != 0) { - printk("%s: unrecognised SCR structure version %d\n", - mmc_hostname(card->host), scr_struct); - return -EINVAL; - } - - scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); - scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); - - return 0; -} - -/* - * Fetches and decodes switch information - */ -static int mmc_read_switch(struct mmc_card *card) -{ - int err; - u8 *status; - - err = MMC_ERR_FAILED; - - status = kmalloc(64, GFP_KERNEL); - if (!status) { - printk("%s: could not allocate a buffer for switch " - "capabilities.\n", - mmc_hostname(card->host)); - return err; - } - - err = mmc_sd_switch(card, 0, 0, 1, status); - if (err != MMC_ERR_NONE) { - /* - * Card not supporting high-speed will ignore the - * command. - */ - err = MMC_ERR_NONE; - goto out; - } - - if (status[13] & 0x02) - card->sw_caps.hs_max_dtr = 50000000; - -out: - kfree(status); - - return err; -} - -/* - * Test if the card supports high-speed mode and, if so, switch to it. - */ -static int mmc_switch_hs(struct mmc_card *card) -{ - int err; - u8 *status; - - if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) - return MMC_ERR_NONE; - - if (card->sw_caps.hs_max_dtr == 0) - return MMC_ERR_NONE; - - err = MMC_ERR_FAILED; - - status = kmalloc(64, GFP_KERNEL); - if (!status) { - printk("%s: could not allocate a buffer for switch " - "capabilities.\n", - mmc_hostname(card->host)); - return err; - } - - err = mmc_sd_switch(card, 1, 0, 1, status); - if (err != MMC_ERR_NONE) - goto out; - - if ((status[16] & 0xF) != 1) { - printk(KERN_WARNING "%s: Problem switching card " - "into high-speed mode!\n", - mmc_hostname(card->host)); - } else { - mmc_card_set_highspeed(card); - mmc_set_timing(card->host, MMC_TIMING_SD_HS); - } - -out: - kfree(status); - - return err; -} - -/* - * Handle the detection and initialisation of a card. - * - * In the case of a resume, "curcard" will contain the card - * we're trying to reinitialise. - */ -static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, - struct mmc_card *oldcard) -{ - struct mmc_card *card; - int err; - u32 cid[4]; - unsigned int max_dtr; - - BUG_ON(!host); - BUG_ON(!host->claimed); - - /* - * Since we're changing the OCR value, we seem to - * need to tell some cards to go back to the idle - * state. We wait 1ms to give cards time to - * respond. - */ - mmc_go_idle(host); - - /* - * If SD_SEND_IF_COND indicates an SD 2.0 - * compliant card and we should set bit 30 - * of the ocr to indicate that we can handle - * block-addressed SDHC cards. - */ - err = mmc_send_if_cond(host, ocr); - if (err == MMC_ERR_NONE) - ocr |= 1 << 30; - - err = mmc_send_app_op_cond(host, ocr, NULL); - if (err != MMC_ERR_NONE) - goto err; - - /* - * Fetch CID from card. - */ - err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) - goto err; - - if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) - goto err; - - card = oldcard; - } else { - /* - * Allocate card structure. - */ - card = mmc_alloc_card(host); - if (IS_ERR(card)) - goto err; - - card->type = MMC_TYPE_SD; - memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); - } - - /* - * Set card RCA. - */ - err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) - goto free_card; - - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); - - if (!oldcard) { - /* - * Fetch CSD from card. - */ - err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) - goto free_card; - - err = mmc_decode_csd(card); - if (err < 0) - goto free_card; - - mmc_decode_cid(card); - } - - /* - * Select card, as all following commands rely on that. - */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; - - if (!oldcard) { - /* - * Fetch SCR from card. - */ - err = mmc_app_send_scr(card, card->raw_scr); - if (err != MMC_ERR_NONE) - goto free_card; - - err = mmc_decode_scr(card); - if (err < 0) - goto free_card; - - /* - * Fetch switch information from card. - */ - err = mmc_read_switch(card); - if (err != MMC_ERR_NONE) - goto free_card; - } - - /* - * Attempt to change to high-speed (if supported) - */ - err = mmc_switch_hs(card); - if (err != MMC_ERR_NONE) - goto free_card; - - /* - * Compute bus speed. - */ - max_dtr = (unsigned int)-1; - - if (mmc_card_highspeed(card)) { - if (max_dtr > card->sw_caps.hs_max_dtr) - max_dtr = card->sw_caps.hs_max_dtr; - } else if (max_dtr > card->csd.max_dtr) { - max_dtr = card->csd.max_dtr; - } - - mmc_set_clock(host, max_dtr); - - /* - * Switch to wider bus (if supported). - */ - if ((host->caps && MMC_CAP_4_BIT_DATA) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { - err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) - goto free_card; - - mmc_set_bus_width(host, MMC_BUS_WIDTH_4); - } - - if (!oldcard) - host->card = card; - - return MMC_ERR_NONE; - -free_card: - if (!oldcard) - mmc_remove_card(card); -err: - - return MMC_ERR_FAILED; -} - -/* - * Host is being removed. Free up the current card. - */ -static void mmc_sd_remove(struct mmc_host *host) -{ - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_remove_card(host->card); - host->card = NULL; -} - -/* - * Card detection callback from host. - */ -static void mmc_sd_detect(struct mmc_host *host) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - - /* - * Just check if our card has been removed. - */ - err = mmc_send_status(host->card, NULL); - - mmc_release_host(host); - - if (err != MMC_ERR_NONE) { - mmc_remove_card(host->card); - host->card = NULL; - - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - } -} - -#ifdef CONFIG_MMC_UNSAFE_RESUME - -/* - * Suspend callback from host. - */ -static void mmc_sd_suspend(struct mmc_host *host) -{ - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - mmc_deselect_cards(host); - host->card->state &= ~MMC_STATE_HIGHSPEED; - mmc_release_host(host); -} - -/* - * Resume callback from host. - * - * This function tries to determine if the same card is still present - * and, if so, restore all state to it. - */ -static void mmc_sd_resume(struct mmc_host *host) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); - - err = mmc_sd_init_card(host, host->ocr, host->card); - if (err != MMC_ERR_NONE) { - mmc_remove_card(host->card); - host->card = NULL; - - mmc_detach_bus(host); - } - - mmc_release_host(host); -} - -#else - -#define mmc_sd_suspend NULL -#define mmc_sd_resume NULL - -#endif - -static const struct mmc_bus_ops mmc_sd_ops = { - .remove = mmc_sd_remove, - .detect = mmc_sd_detect, - .suspend = mmc_sd_suspend, - .resume = mmc_sd_resume, -}; - -/* - * Starting point for SD card init. - */ -int mmc_attach_sd(struct mmc_host *host, u32 ocr) -{ - int err; - - BUG_ON(!host); - BUG_ON(!host->claimed); - - mmc_attach_bus(host, &mmc_sd_ops); - - /* - * Sanity check the voltages that the card claims to - * support. - */ - if (ocr & 0x7F) { - printk(KERN_WARNING "%s: card claims to support voltages " - "below the defined range. These will be ignored.\n", - mmc_hostname(host)); - ocr &= ~0x7F; - } - - if (ocr & MMC_VDD_165_195) { - printk(KERN_WARNING "%s: SD card claims to support the " - "incompletely defined 'low voltage range'. This " - "will be ignored.\n", mmc_hostname(host)); - ocr &= ~MMC_VDD_165_195; - } - - host->ocr = mmc_select_voltage(host, ocr); - - /* - * Can we support the voltage(s) of the card(s)? - */ - if (!host->ocr) - goto err; - - /* - * Detect and init the card. - */ - err = mmc_sd_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) - goto err; - - mmc_release_host(host); - - err = mmc_register_card(host->card); - if (err) - goto reclaim_host; - - return 0; - -reclaim_host: - mmc_claim_host(host); - mmc_remove_card(host->card); - host->card = NULL; -err: - mmc_detach_bus(host); - mmc_release_host(host); - - return 0; -} - diff --git a/trunk/drivers/mmc/core/sd_ops.c b/trunk/drivers/mmc/core/sd_ops.c deleted file mode 100644 index 9697ce581101..000000000000 --- a/trunk/drivers/mmc/core/sd_ops.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * linux/drivers/mmc/sd_ops.h - * - * Copyright 2006-2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "core.h" -#include "sd_ops.h" - -/** - * mmc_wait_for_app_cmd - start an application command and wait for - completion - * @host: MMC host to start command - * @rca: RCA to send MMC_APP_CMD to - * @cmd: MMC command to start - * @retries: maximum number of retries - * - * Sends a MMC_APP_CMD, checks the card response, sends the command - * in the parameter and waits for it to complete. Return any error - * that occurred while the command was executing. Do not attempt to - * parse the response. - */ -int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, - struct mmc_command *cmd, int retries) -{ - struct mmc_request mrq; - - int i, err; - - BUG_ON(!cmd); - BUG_ON(retries < 0); - - err = MMC_ERR_INVALID; - - /* - * We have to resend MMC_APP_CMD for each attempt so - * we cannot use the retries field in mmc_command. - */ - for (i = 0;i <= retries;i++) { - memset(&mrq, 0, sizeof(struct mmc_request)); - - err = mmc_app_cmd(host, card); - if (err != MMC_ERR_NONE) - continue; - - memset(&mrq, 0, sizeof(struct mmc_request)); - - memset(cmd->resp, 0, sizeof(cmd->resp)); - cmd->retries = 0; - - mrq.cmd = cmd; - cmd->data = NULL; - - mmc_wait_for_req(host, &mrq); - - err = cmd->error; - if (cmd->error == MMC_ERR_NONE) - break; - } - - return err; -} - -EXPORT_SYMBOL(mmc_wait_for_app_cmd); - -int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!host); - BUG_ON(card && (card->host != host)); - - cmd.opcode = MMC_APP_CMD; - - if (card) { - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - } else { - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; - } - - err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) - return err; - - /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; - - return MMC_ERR_NONE; -} - -int mmc_app_set_bus_width(struct mmc_card *card, int width) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!card); - BUG_ON(!card->host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = SD_APP_SET_BUS_WIDTH; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - - switch (width) { - case MMC_BUS_WIDTH_1: - cmd.arg = SD_BUS_WIDTH_1; - break; - case MMC_BUS_WIDTH_4: - cmd.arg = SD_BUS_WIDTH_4; - break; - default: - return MMC_ERR_INVALID; - } - - err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - return MMC_ERR_NONE; -} - -int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) -{ - struct mmc_command cmd; - int i, err = 0; - - BUG_ON(!host); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = SD_APP_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; - - for (i = 100; i; i--) { - err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - break; - - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) - break; - - err = MMC_ERR_TIMEOUT; - - mmc_delay(10); - } - - if (rocr) - *rocr = cmd.resp[0]; - - return err; -} - -int mmc_send_if_cond(struct mmc_host *host, u32 ocr) -{ - struct mmc_command cmd; - int err; - static const u8 test_pattern = 0xAA; - - /* - * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND - * before SD_APP_OP_COND. This command will harmlessly fail for - * SD 1.0 cards. - */ - cmd.opcode = SD_SEND_IF_COND; - cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; - - err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) - return err; - - if ((cmd.resp[0] & 0xFF) != test_pattern) - return MMC_ERR_FAILED; - - return MMC_ERR_NONE; -} - -int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) -{ - int err; - struct mmc_command cmd; - - BUG_ON(!host); - BUG_ON(!rca); - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = SD_SEND_RELATIVE_ADDR; - cmd.arg = 0; - cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; - - err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) - return err; - - *rca = cmd.resp[0] >> 16; - - return MMC_ERR_NONE; -} - -int mmc_app_send_scr(struct mmc_card *card, u32 *scr) -{ - int err; - struct mmc_request mrq; - struct mmc_command cmd; - struct mmc_data data; - struct scatterlist sg; - - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!scr); - - err = mmc_app_cmd(card->host, card); - if (err != MMC_ERR_NONE) - return err; - - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(&cmd, 0, sizeof(struct mmc_command)); - memset(&data, 0, sizeof(struct mmc_data)); - - mrq.cmd = &cmd; - mrq.data = &data; - - cmd.opcode = SD_APP_SEND_SCR; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = 8; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, scr, 8); - - mmc_set_data_timeout(&data, card, 0); - - mmc_wait_for_req(card->host, &mrq); - - if (cmd.error != MMC_ERR_NONE) - return cmd.error; - if (data.error != MMC_ERR_NONE) - return data.error; - - scr[0] = ntohl(scr[0]); - scr[1] = ntohl(scr[1]); - - return MMC_ERR_NONE; -} - -int mmc_sd_switch(struct mmc_card *card, int mode, int group, - u8 value, u8 *resp) -{ - struct mmc_request mrq; - struct mmc_command cmd; - struct mmc_data data; - struct scatterlist sg; - - BUG_ON(!card); - BUG_ON(!card->host); - - mode = !!mode; - value &= 0xF; - - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(&cmd, 0, sizeof(struct mmc_command)); - memset(&data, 0, sizeof(struct mmc_data)); - - mrq.cmd = &cmd; - mrq.data = &data; - - cmd.opcode = SD_SWITCH; - cmd.arg = mode << 31 | 0x00FFFFFF; - cmd.arg &= ~(0xF << (group * 4)); - cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = 64; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, resp, 64); - - mmc_set_data_timeout(&data, card, 0); - - mmc_wait_for_req(card->host, &mrq); - - if (cmd.error != MMC_ERR_NONE) - return cmd.error; - if (data.error != MMC_ERR_NONE) - return data.error; - - return MMC_ERR_NONE; -} - diff --git a/trunk/drivers/mmc/core/sd_ops.h b/trunk/drivers/mmc/core/sd_ops.h deleted file mode 100644 index 1240fddba5e3..000000000000 --- a/trunk/drivers/mmc/core/sd_ops.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * linux/drivers/mmc/sd_ops.h - * - * Copyright 2006-2007 Pierre Ossman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#ifndef _MMC_SD_OPS_H -#define _MMC_SD_OPS_H - -int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); -int mmc_app_set_bus_width(struct mmc_card *card, int width); -int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); -int mmc_send_if_cond(struct mmc_host *host, u32 ocr); -int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca); -int mmc_app_send_scr(struct mmc_card *card, u32 *scr); -int mmc_sd_switch(struct mmc_card *card, int mode, int group, - u8 value, u8 *resp); - -#endif - diff --git a/trunk/drivers/mmc/host/Kconfig b/trunk/drivers/mmc/host/Kconfig deleted file mode 100644 index ed4deab2203d..000000000000 --- a/trunk/drivers/mmc/host/Kconfig +++ /dev/null @@ -1,103 +0,0 @@ -# -# MMC/SD host controller drivers -# - -comment "MMC/SD Host Controller Drivers" - depends on MMC - -config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA && MMC - help - This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card - Interface (PL180 and PL181) support. If you have an ARM(R) - platform with a Multimedia Card slot, say Y or M here. - - If unsure, say N. - -config MMC_PXA - tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" - depends on ARCH_PXA && MMC - help - This selects the Intel(R) PXA(R) Multimedia card Interface. - If you have a PXA(R) platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_SDHCI - tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)" - depends on PCI && MMC && EXPERIMENTAL - help - This select the generic Secure Digital Host Controller Interface. - It is used by manufacturers such as Texas Instruments(R), Ricoh(R) - and Toshiba(R). Most controllers found in laptops are of this type. - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_OMAP - tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP && MMC - select TPS65010 if MACH_OMAP_H2 - help - This selects the TI OMAP Multimedia card Interface. - If you have an OMAP board with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_WBSD - tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on MMC && ISA_DMA_API - help - This selects the Winbond(R) W83L51xD Secure digital and - Multimedia card Interface. - If you have a machine with a integrated W83L518D or W83L519D - SD/MMC card reader, say Y or M here. - - If unsure, say N. - -config MMC_AU1X - tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on MMC && SOC_AU1200 - help - This selects the AMD Alchemy(R) Multimedia card interface. - If you have a Alchemy platform with a MMC slot, say Y or M here. - - If unsure, say N. - -config MMC_AT91 - tristate "AT91 SD/MMC Card Interface support" - depends on ARCH_AT91 && MMC - help - This selects the AT91 MCI controller. - - If unsure, say N. - -config MMC_IMX - tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_IMX && MMC - help - This selects the Motorola i.MX Multimedia card Interface. - If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_TIFM_SD - tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL && PCI - select TIFM_CORE - help - Say Y here if you want to be able to access MMC/SD cards with - the Texas Instruments(R) Flash Media card reader, found in many - laptops. - This option 'selects' (turns on, enables) 'TIFM_CORE', but you - probably also need appropriate card reader host adapter, such as - 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support - (TIFM_7XX1)'. - - To compile this driver as a module, choose M here: the - module will be called tifm_sd. - diff --git a/trunk/drivers/mmc/host/Makefile b/trunk/drivers/mmc/host/Makefile deleted file mode 100644 index 6685f64345b4..000000000000 --- a/trunk/drivers/mmc/host/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for MMC/SD host controller drivers -# - -ifeq ($(CONFIG_MMC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif - -obj-$(CONFIG_MMC_ARMMMCI) += mmci.o -obj-$(CONFIG_MMC_PXA) += pxamci.o -obj-$(CONFIG_MMC_IMX) += imxmmc.o -obj-$(CONFIG_MMC_SDHCI) += sdhci.o -obj-$(CONFIG_MMC_WBSD) += wbsd.o -obj-$(CONFIG_MMC_AU1X) += au1xmmc.o -obj-$(CONFIG_MMC_OMAP) += omap.o -obj-$(CONFIG_MMC_AT91) += at91_mci.o -obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o - diff --git a/trunk/drivers/mmc/host/tifm_sd.c b/trunk/drivers/mmc/host/tifm_sd.c deleted file mode 100644 index 7511f961c67b..000000000000 --- a/trunk/drivers/mmc/host/tifm_sd.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * tifm_sd.c - TI FlashMedia driver - * - * Copyright (C) 2006 Alex Dubov - * - * 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. - * - * Special thanks to Brad Campbell for extensive testing of this driver. - * - */ - - -#include -#include -#include -#include -#include - -#define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.8" - -static int no_dma = 0; -static int fixed_timeout = 0; -module_param(no_dma, bool, 0644); -module_param(fixed_timeout, bool, 0644); - -/* Constants here are mostly from OMAP5912 datasheet */ -#define TIFM_MMCSD_RESET 0x0002 -#define TIFM_MMCSD_CLKMASK 0x03ff -#define TIFM_MMCSD_POWER 0x0800 -#define TIFM_MMCSD_4BBUS 0x8000 -#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */ -#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */ -#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */ -#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */ -#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ -#define TIFM_MMCSD_READ 0x8000 - -#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */ -#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ -#define TIFM_MMCSD_CD 0x0002 /* card detect */ -#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ -#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ -#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */ -#define TIFM_MMCSD_DTO 0x0020 /* data time-out */ -#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */ -#define TIFM_MMCSD_CTO 0x0080 /* command time-out */ -#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */ -#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */ -#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */ -#define TIFM_MMCSD_OCRB 0x1000 /* OCR busy */ -#define TIFM_MMCSD_CIRQ 0x2000 /* card irq (cmd40/sdio) */ -#define TIFM_MMCSD_CERR 0x4000 /* card status error */ - -#define TIFM_MMCSD_ODTO 0x0040 /* open drain / extended timeout */ -#define TIFM_MMCSD_CARD_RO 0x0200 /* card is read-only */ - -#define TIFM_MMCSD_FIFO_SIZE 0x0020 - -#define TIFM_MMCSD_RSP_R0 0x0000 -#define TIFM_MMCSD_RSP_R1 0x0100 -#define TIFM_MMCSD_RSP_R2 0x0200 -#define TIFM_MMCSD_RSP_R3 0x0300 -#define TIFM_MMCSD_RSP_R4 0x0400 -#define TIFM_MMCSD_RSP_R5 0x0500 -#define TIFM_MMCSD_RSP_R6 0x0600 - -#define TIFM_MMCSD_RSP_BUSY 0x0800 - -#define TIFM_MMCSD_CMD_BC 0x0000 -#define TIFM_MMCSD_CMD_BCR 0x1000 -#define TIFM_MMCSD_CMD_AC 0x2000 -#define TIFM_MMCSD_CMD_ADTC 0x3000 - -#define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL - -enum { - CMD_READY = 0x0001, - FIFO_READY = 0x0002, - BRS_READY = 0x0004, - SCMD_ACTIVE = 0x0008, - SCMD_READY = 0x0010, - CARD_BUSY = 0x0020, - DATA_CARRY = 0x0040 -}; - -struct tifm_sd { - struct tifm_dev *dev; - - unsigned short eject:1, - open_drain:1, - no_dma:1; - unsigned short cmd_flags; - - unsigned int clk_freq; - unsigned int clk_div; - unsigned long timeout_jiffies; - - struct tasklet_struct finish_tasklet; - struct timer_list timer; - struct mmc_request *req; - - int sg_len; - int sg_pos; - unsigned int block_pos; - struct scatterlist bounce_buf; - unsigned char bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE]; -}; - -/* for some reason, host won't respond correctly to readw/writew */ -static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, - unsigned int off, unsigned int cnt) -{ - struct tifm_dev *sock = host->dev; - unsigned char *buf; - unsigned int pos = 0, val; - - buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off; - if (host->cmd_flags & DATA_CARRY) { - buf[pos++] = host->bounce_buf_data[0]; - host->cmd_flags &= ~DATA_CARRY; - } - - while (pos < cnt) { - val = readl(sock->addr + SOCK_MMCSD_DATA); - buf[pos++] = val & 0xff; - if (pos == cnt) { - host->bounce_buf_data[0] = (val >> 8) & 0xff; - host->cmd_flags |= DATA_CARRY; - break; - } - buf[pos++] = (val >> 8) & 0xff; - } - kunmap_atomic(buf - off, KM_BIO_DST_IRQ); -} - -static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, - unsigned int off, unsigned int cnt) -{ - struct tifm_dev *sock = host->dev; - unsigned char *buf; - unsigned int pos = 0, val; - - buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off; - if (host->cmd_flags & DATA_CARRY) { - val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); - writel(val, sock->addr + SOCK_MMCSD_DATA); - host->cmd_flags &= ~DATA_CARRY; - } - - while (pos < cnt) { - val = buf[pos++]; - if (pos == cnt) { - host->bounce_buf_data[0] = val & 0xff; - host->cmd_flags |= DATA_CARRY; - break; - } - val |= (buf[pos++] << 8) & 0xff00; - writel(val, sock->addr + SOCK_MMCSD_DATA); - } - kunmap_atomic(buf - off, KM_BIO_SRC_IRQ); -} - -static void tifm_sd_transfer_data(struct tifm_sd *host) -{ - struct mmc_data *r_data = host->req->cmd->data; - struct scatterlist *sg = r_data->sg; - unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2; - unsigned int p_off, p_cnt; - struct page *pg; - - if (host->sg_pos == host->sg_len) - return; - while (t_size) { - cnt = sg[host->sg_pos].length - host->block_pos; - if (!cnt) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) { - if ((r_data->flags & MMC_DATA_WRITE) - && DATA_CARRY) - writel(host->bounce_buf_data[0], - host->dev->addr - + SOCK_MMCSD_DATA); - - return; - } - cnt = sg[host->sg_pos].length; - } - off = sg[host->sg_pos].offset + host->block_pos; - - pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT); - p_off = offset_in_page(off); - p_cnt = PAGE_SIZE - p_off; - p_cnt = min(p_cnt, cnt); - p_cnt = min(p_cnt, t_size); - - if (r_data->flags & MMC_DATA_READ) - tifm_sd_read_fifo(host, pg, p_off, p_cnt); - else if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_write_fifo(host, pg, p_off, p_cnt); - - t_size -= p_cnt; - host->block_pos += p_cnt; - } -} - -static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, - struct page *src, unsigned int src_off, - unsigned int count) -{ - unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off; - unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; - - memcpy(dst_buf, src_buf, count); - - kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); - kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); -} - -static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) -{ - struct scatterlist *sg = r_data->sg; - unsigned int t_size = r_data->blksz; - unsigned int off, cnt; - unsigned int p_off, p_cnt; - struct page *pg; - - dev_dbg(&host->dev->dev, "bouncing block\n"); - while (t_size) { - cnt = sg[host->sg_pos].length - host->block_pos; - if (!cnt) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) - return; - cnt = sg[host->sg_pos].length; - } - off = sg[host->sg_pos].offset + host->block_pos; - - pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT); - p_off = offset_in_page(off); - p_cnt = PAGE_SIZE - p_off; - p_cnt = min(p_cnt, cnt); - p_cnt = min(p_cnt, t_size); - - if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_copy_page(host->bounce_buf.page, - r_data->blksz - t_size, - pg, p_off, p_cnt); - else if (r_data->flags & MMC_DATA_READ) - tifm_sd_copy_page(pg, p_off, host->bounce_buf.page, - r_data->blksz - t_size, p_cnt); - - t_size -= p_cnt; - host->block_pos += p_cnt; - } -} - -static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data) -{ - struct tifm_dev *sock = host->dev; - unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz; - unsigned int dma_len, dma_blk_cnt, dma_off; - struct scatterlist *sg = NULL; - unsigned long flags; - - if (host->sg_pos == host->sg_len) - return 1; - - if (host->cmd_flags & DATA_CARRY) { - host->cmd_flags &= ~DATA_CARRY; - local_irq_save(flags); - tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); - if (host->sg_pos == host->sg_len) - return 1; - } - - dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos; - if (!dma_len) { - host->block_pos = 0; - host->sg_pos++; - if (host->sg_pos == host->sg_len) - return 1; - dma_len = sg_dma_len(&r_data->sg[host->sg_pos]); - } - - if (dma_len < t_size) { - dma_blk_cnt = dma_len / r_data->blksz; - dma_off = host->block_pos; - host->block_pos += dma_blk_cnt * r_data->blksz; - } else { - dma_blk_cnt = TIFM_DMA_TSIZE; - dma_off = host->block_pos; - host->block_pos += t_size; - } - - if (dma_blk_cnt) - sg = &r_data->sg[host->sg_pos]; - else if (dma_len) { - if (r_data->flags & MMC_DATA_WRITE) { - local_irq_save(flags); - tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); - } else - host->cmd_flags |= DATA_CARRY; - - sg = &host->bounce_buf; - dma_off = 0; - dma_blk_cnt = 1; - } else - return 1; - - dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt); - writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS); - if (r_data->flags & MMC_DATA_WRITE) - writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - else - writel((dma_blk_cnt << 8) | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); - - return 0; -} - -static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) -{ - unsigned int rc = 0; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - rc |= TIFM_MMCSD_RSP_R0; - break; - case MMC_RSP_R1B: - rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through - case MMC_RSP_R1: - rc |= TIFM_MMCSD_RSP_R1; - break; - case MMC_RSP_R2: - rc |= TIFM_MMCSD_RSP_R2; - break; - case MMC_RSP_R3: - rc |= TIFM_MMCSD_RSP_R3; - break; - default: - BUG(); - } - - switch (mmc_cmd_type(cmd)) { - case MMC_CMD_BC: - rc |= TIFM_MMCSD_CMD_BC; - break; - case MMC_CMD_BCR: - rc |= TIFM_MMCSD_CMD_BCR; - break; - case MMC_CMD_AC: - rc |= TIFM_MMCSD_CMD_AC; - break; - case MMC_CMD_ADTC: - rc |= TIFM_MMCSD_CMD_ADTC; - break; - default: - BUG(); - } - return rc; -} - -static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) -{ - struct tifm_dev *sock = host->dev; - unsigned int cmd_mask = tifm_sd_op_flags(cmd); - - if (host->open_drain) - cmd_mask |= TIFM_MMCSD_ODTO; - - if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) - cmd_mask |= TIFM_MMCSD_READ; - - dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", - cmd->opcode, cmd->arg, cmd_mask); - - writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); - writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); - writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND); -} - -static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock) -{ - cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18); - cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10); - cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08); - cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16) - | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00); -} - -static void tifm_sd_check_status(struct tifm_sd *host) -{ - struct tifm_dev *sock = host->dev; - struct mmc_command *cmd = host->req->cmd; - - if (cmd->error != MMC_ERR_NONE) - goto finish_request; - - if (!(host->cmd_flags & CMD_READY)) - return; - - if (cmd->data) { - if (cmd->data->error != MMC_ERR_NONE) { - if ((host->cmd_flags & SCMD_ACTIVE) - && !(host->cmd_flags & SCMD_READY)) - return; - - goto finish_request; - } - - if (!(host->cmd_flags & BRS_READY)) - return; - - if (!(host->no_dma || (host->cmd_flags & FIFO_READY))) - return; - - if (cmd->data->flags & MMC_DATA_WRITE) { - if (host->req->stop) { - if (!(host->cmd_flags & SCMD_ACTIVE)) { - host->cmd_flags |= SCMD_ACTIVE; - writel(TIFM_MMCSD_EOFB - | readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr - + SOCK_MMCSD_INT_ENABLE); - tifm_sd_exec(host, host->req->stop); - return; - } else { - if (!(host->cmd_flags & SCMD_READY) - || (host->cmd_flags & CARD_BUSY)) - return; - writel((~TIFM_MMCSD_EOFB) - & readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr - + SOCK_MMCSD_INT_ENABLE); - } - } else { - if (host->cmd_flags & CARD_BUSY) - return; - writel((~TIFM_MMCSD_EOFB) - & readl(sock->addr - + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - } - } else { - if (host->req->stop) { - if (!(host->cmd_flags & SCMD_ACTIVE)) { - host->cmd_flags |= SCMD_ACTIVE; - tifm_sd_exec(host, host->req->stop); - return; - } else { - if (!(host->cmd_flags & SCMD_READY)) - return; - } - } - } - } -finish_request: - tasklet_schedule(&host->finish_tasklet); -} - -/* Called from interrupt handler */ -static void tifm_sd_data_event(struct tifm_dev *sock) -{ - struct tifm_sd *host; - unsigned int fifo_status = 0; - struct mmc_data *r_data = NULL; - - spin_lock(&sock->lock); - host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); - dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n", - fifo_status, host->cmd_flags); - - if (host->req) { - r_data = host->req->cmd->data; - - if (r_data && (fifo_status & TIFM_FIFO_READY)) { - if (tifm_sd_set_dma_data(host, r_data)) { - host->cmd_flags |= FIFO_READY; - tifm_sd_check_status(host); - } - } - } - - writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); - spin_unlock(&sock->lock); -} - -/* Called from interrupt handler */ -static void tifm_sd_card_event(struct tifm_dev *sock) -{ - struct tifm_sd *host; - unsigned int host_status = 0; - int cmd_error = MMC_ERR_NONE; - struct mmc_command *cmd = NULL; - unsigned long flags; - - spin_lock(&sock->lock); - host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - host_status = readl(sock->addr + SOCK_MMCSD_STATUS); - dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n", - host_status, host->cmd_flags); - - if (host->req) { - cmd = host->req->cmd; - - if (host_status & TIFM_MMCSD_ERRMASK) { - writel(host_status & TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_STATUS); - if (host_status & TIFM_MMCSD_CTO) - cmd_error = MMC_ERR_TIMEOUT; - else if (host_status & TIFM_MMCSD_CCRC) - cmd_error = MMC_ERR_BADCRC; - - if (cmd->data) { - if (host_status & TIFM_MMCSD_DTO) - cmd->data->error = MMC_ERR_TIMEOUT; - else if (host_status & TIFM_MMCSD_DCRC) - cmd->data->error = MMC_ERR_BADCRC; - } - - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); - - if (host->req->stop) { - if (host->cmd_flags & SCMD_ACTIVE) { - host->req->stop->error = cmd_error; - host->cmd_flags |= SCMD_READY; - } else { - cmd->error = cmd_error; - host->cmd_flags |= SCMD_ACTIVE; - tifm_sd_exec(host, host->req->stop); - goto done; - } - } else - cmd->error = cmd_error; - } else { - if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { - if (!(host->cmd_flags & CMD_READY)) { - host->cmd_flags |= CMD_READY; - tifm_sd_fetch_resp(cmd, sock); - } else if (host->cmd_flags & SCMD_ACTIVE) { - host->cmd_flags |= SCMD_READY; - tifm_sd_fetch_resp(host->req->stop, - sock); - } - } - if (host_status & TIFM_MMCSD_BRS) - host->cmd_flags |= BRS_READY; - } - - if (host->no_dma && cmd->data) { - if (host_status & TIFM_MMCSD_AE) - writel(host_status & TIFM_MMCSD_AE, - sock->addr + SOCK_MMCSD_STATUS); - - if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF - | TIFM_MMCSD_BRS)) { - local_irq_save(flags); - tifm_sd_transfer_data(host); - local_irq_restore(flags); - host_status &= ~TIFM_MMCSD_AE; - } - } - - if (host_status & TIFM_MMCSD_EOFB) - host->cmd_flags &= ~CARD_BUSY; - else if (host_status & TIFM_MMCSD_CB) - host->cmd_flags |= CARD_BUSY; - - tifm_sd_check_status(host); - } -done: - writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - spin_unlock(&sock->lock); -} - -static void tifm_sd_set_data_timeout(struct tifm_sd *host, - struct mmc_data *data) -{ - struct tifm_dev *sock = host->dev; - unsigned int data_timeout = data->timeout_clks; - - if (fixed_timeout) - return; - - data_timeout += data->timeout_ns / - ((1000000000UL / host->clk_freq) * host->clk_div); - - if (data_timeout < 0xffff) { - writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); - writel((~TIFM_MMCSD_DPE) - & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); - } else { - data_timeout = (data_timeout >> 10) + 1; - if (data_timeout > 0xffff) - data_timeout = 0; /* set to unlimited */ - writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); - writel(TIFM_MMCSD_DPE - | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); - } -} - -static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned long flags; - struct mmc_data *r_data = mrq->cmd->data; - - spin_lock_irqsave(&sock->lock, flags); - if (host->eject) { - spin_unlock_irqrestore(&sock->lock, flags); - goto err_out; - } - - if (host->req) { - printk(KERN_ERR "%s : unfinished request detected\n", - sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); - goto err_out; - } - - host->cmd_flags = 0; - host->block_pos = 0; - host->sg_pos = 0; - - if (r_data) { - tifm_sd_set_data_timeout(host, r_data); - - if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop) - writel(TIFM_MMCSD_EOFB - | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - - if (host->no_dma) { - writel(TIFM_MMCSD_BUFINT - | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) - | (TIFM_MMCSD_FIFO_SIZE - 1), - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - host->sg_len = r_data->sg_len; - } else { - sg_init_one(&host->bounce_buf, host->bounce_buf_data, - r_data->blksz); - - if(1 != tifm_map_sg(sock, &host->bounce_buf, 1, - r_data->flags & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE)) { - printk(KERN_ERR "%s : scatterlist map failed\n", - sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); - goto err_out; - } - host->sg_len = tifm_map_sg(sock, r_data->sg, - r_data->sg_len, - r_data->flags - & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); - if (host->sg_len < 1) { - printk(KERN_ERR "%s : scatterlist map failed\n", - sock->dev.bus_id); - tifm_unmap_sg(sock, &host->bounce_buf, 1, - r_data->flags & MMC_DATA_WRITE - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); - spin_unlock_irqrestore(&sock->lock, flags); - goto err_out; - } - - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(ilog2(r_data->blksz) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); - writel(TIFM_FIFO_ENABLE, - sock->addr + SOCK_FIFO_CONTROL); - writel(TIFM_FIFO_INTMASK, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - - if (r_data->flags & MMC_DATA_WRITE) - writel(TIFM_MMCSD_TXDE, - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - else - writel(TIFM_MMCSD_RXDE, - sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - tifm_sd_set_dma_data(host, r_data); - } - - writel(r_data->blocks - 1, - sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(r_data->blksz - 1, - sock->addr + SOCK_MMCSD_BLOCK_LEN); - } - - host->req = mrq; - mod_timer(&host->timer, jiffies + host->timeout_jiffies); - writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - tifm_sd_exec(host, mrq->cmd); - spin_unlock_irqrestore(&sock->lock, flags); - return; - -err_out: - mrq->cmd->error = MMC_ERR_TIMEOUT; - mmc_request_done(mmc, mrq); -} - -static void tifm_sd_end_cmd(unsigned long data) -{ - struct tifm_sd *host = (struct tifm_sd*)data; - struct tifm_dev *sock = host->dev; - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct mmc_request *mrq; - struct mmc_data *r_data = NULL; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - - del_timer(&host->timer); - mrq = host->req; - host->req = NULL; - - if (!mrq) { - printk(KERN_ERR " %s : no request to complete?\n", - sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); - return; - } - - r_data = mrq->cmd->data; - if (r_data) { - if (host->no_dma) { - writel((~TIFM_MMCSD_BUFINT) - & readl(sock->addr + SOCK_MMCSD_INT_ENABLE), - sock->addr + SOCK_MMCSD_INT_ENABLE); - } else { - tifm_unmap_sg(sock, &host->bounce_buf, 1, - (r_data->flags & MMC_DATA_WRITE) - ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, - (r_data->flags & MMC_DATA_WRITE) - ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - } - - r_data->bytes_xfered = r_data->blocks - - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; - r_data->bytes_xfered *= r_data->blksz; - r_data->bytes_xfered += r_data->blksz - - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; - } - - writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - - spin_unlock_irqrestore(&sock->lock, flags); - mmc_request_done(mmc, mrq); -} - -static void tifm_sd_abort(unsigned long data) -{ - struct tifm_sd *host = (struct tifm_sd*)data; - - printk(KERN_ERR - "%s : card failed to respond for a long period of time " - "(%x, %x)\n", - host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags); - - tifm_eject(host->dev); -} - -static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned int clk_div1, clk_div2; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - - dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, " - "chip_select = %x, power_mode = %x, bus_width = %x\n", - ios->clock, ios->vdd, ios->bus_mode, ios->chip_select, - ios->power_mode, ios->bus_width); - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); - } else { - writel((~TIFM_MMCSD_4BBUS) - & readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); - } - - if (ios->clock) { - clk_div1 = 20000000 / ios->clock; - if (!clk_div1) - clk_div1 = 1; - - clk_div2 = 24000000 / ios->clock; - if (!clk_div2) - clk_div2 = 1; - - if ((20000000 / clk_div1) > ios->clock) - clk_div1++; - if ((24000000 / clk_div2) > ios->clock) - clk_div2++; - if ((20000000 / clk_div1) > (24000000 / clk_div2)) { - host->clk_freq = 20000000; - host->clk_div = clk_div1; - writel((~TIFM_CTRL_FAST_CLK) - & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - } else { - host->clk_freq = 24000000; - host->clk_div = clk_div2; - writel(TIFM_CTRL_FAST_CLK - | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - } - } else { - host->clk_div = 0; - } - host->clk_div &= TIFM_MMCSD_CLKMASK; - writel(host->clk_div - | ((~TIFM_MMCSD_CLKMASK) - & readl(sock->addr + SOCK_MMCSD_CONFIG)), - sock->addr + SOCK_MMCSD_CONFIG); - - host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN); - - /* chip_select : maybe later */ - //vdd - //power is set before probe / after remove - - spin_unlock_irqrestore(&sock->lock, flags); -} - -static int tifm_sd_ro(struct mmc_host *mmc) -{ - int rc = 0; - struct tifm_sd *host = mmc_priv(mmc); - struct tifm_dev *sock = host->dev; - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE)) - rc = 1; - spin_unlock_irqrestore(&sock->lock, flags); - return rc; -} - -static const struct mmc_host_ops tifm_sd_ops = { - .request = tifm_sd_request, - .set_ios = tifm_sd_ios, - .get_ro = tifm_sd_ro -}; - -static int tifm_sd_initialize_host(struct tifm_sd *host) -{ - int rc; - unsigned int host_status = 0; - struct tifm_dev *sock = host->dev; - - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - host->clk_div = 61; - host->clk_freq = 20000000; - writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - - /* wait up to 0.51 sec for reset */ - for (rc = 32; rc <= 256; rc <<= 1) { - if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { - rc = 0; - break; - } - msleep(rc); - } - - if (rc) { - printk(KERN_ERR "%s : controller failed to reset\n", - sock->dev.bus_id); - return -ENODEV; - } - - writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - - // command timeout fixed to 64 clocks for now - writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); - writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); - - for (rc = 16; rc <= 64; rc <<= 1) { - host_status = readl(sock->addr + SOCK_MMCSD_STATUS); - writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - if (!(host_status & TIFM_MMCSD_ERRMASK) - && (host_status & TIFM_MMCSD_EOC)) { - rc = 0; - break; - } - msleep(rc); - } - - if (rc) { - printk(KERN_ERR - "%s : card not ready - probe failed on initialization\n", - sock->dev.bus_id); - return -ENODEV; - } - - writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC - | TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - - return 0; -} - -static int tifm_sd_probe(struct tifm_dev *sock) -{ - struct mmc_host *mmc; - struct tifm_sd *host; - int rc = -EIO; - - if (!(TIFM_SOCK_STATE_OCCUPIED - & readl(sock->addr + SOCK_PRESENT_STATE))) { - printk(KERN_WARNING "%s : card gone, unexpectedly\n", - sock->dev.bus_id); - return rc; - } - - mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->no_dma = no_dma; - tifm_set_drvdata(sock, mmc); - host->dev = sock; - host->timeout_jiffies = msecs_to_jiffies(1000); - - tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd, - (unsigned long)host); - setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); - - mmc->ops = &tifm_sd_ops; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; - mmc->f_min = 20000000 / 60; - mmc->f_max = 24000000; - - mmc->max_blk_count = 2048; - mmc->max_hw_segs = mmc->max_blk_count; - mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE); - mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size; - mmc->max_req_size = mmc->max_seg_size; - mmc->max_phys_segs = mmc->max_hw_segs; - - sock->card_event = tifm_sd_card_event; - sock->data_event = tifm_sd_data_event; - rc = tifm_sd_initialize_host(host); - - if (!rc) - rc = mmc_add_host(mmc); - if (!rc) - return 0; - - mmc_free_host(mmc); - return rc; -} - -static void tifm_sd_remove(struct tifm_dev *sock) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; - - spin_lock_irqsave(&sock->lock, flags); - host->eject = 1; - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - spin_unlock_irqrestore(&sock->lock, flags); - - tasklet_kill(&host->finish_tasklet); - - spin_lock_irqsave(&sock->lock, flags); - if (host->req) { - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - host->req->cmd->error = MMC_ERR_TIMEOUT; - if (host->req->stop) - host->req->stop->error = MMC_ERR_TIMEOUT; - tasklet_schedule(&host->finish_tasklet); - } - spin_unlock_irqrestore(&sock->lock, flags); - mmc_remove_host(mmc); - dev_dbg(&sock->dev, "after remove\n"); - - /* The meaning of the bit majority in this constant is unknown. */ - writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - - mmc_free_host(mmc); -} - -#ifdef CONFIG_PM - -static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - int rc; - - rc = mmc_suspend_host(mmc, state); - /* The meaning of the bit majority in this constant is unknown. */ - writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - return rc; -} - -static int tifm_sd_resume(struct tifm_dev *sock) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - int rc; - - rc = tifm_sd_initialize_host(host); - dev_dbg(&sock->dev, "resume initialize %d\n", rc); - - if (rc) - host->eject = 1; - else - rc = mmc_resume_host(mmc); - - return rc; -} - -#else - -#define tifm_sd_suspend NULL -#define tifm_sd_resume NULL - -#endif /* CONFIG_PM */ - -static struct tifm_device_id tifm_sd_id_tbl[] = { - { TIFM_TYPE_SD }, { } -}; - -static struct tifm_driver tifm_sd_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE - }, - .id_table = tifm_sd_id_tbl, - .probe = tifm_sd_probe, - .remove = tifm_sd_remove, - .suspend = tifm_sd_suspend, - .resume = tifm_sd_resume -}; - -static int __init tifm_sd_init(void) -{ - return tifm_register_driver(&tifm_sd_driver); -} - -static void __exit tifm_sd_exit(void) -{ - tifm_unregister_driver(&tifm_sd_driver); -} - -MODULE_AUTHOR("Alex Dubov"); -MODULE_DESCRIPTION("TI FlashMedia SD driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); -MODULE_VERSION(DRIVER_VERSION); - -module_init(tifm_sd_init); -module_exit(tifm_sd_exit); diff --git a/trunk/drivers/mmc/host/imxmmc.c b/trunk/drivers/mmc/imxmmc.c similarity index 99% rename from trunk/drivers/mmc/host/imxmmc.c rename to trunk/drivers/mmc/imxmmc.c index 7ee2045acbef..0de5c9e94e74 100644 --- a/trunk/drivers/mmc/host/imxmmc.c +++ b/trunk/drivers/mmc/imxmmc.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/mmc/host/imxmmc.h b/trunk/drivers/mmc/imxmmc.h similarity index 100% rename from trunk/drivers/mmc/host/imxmmc.h rename to trunk/drivers/mmc/imxmmc.h diff --git a/trunk/drivers/mmc/mmc.c b/trunk/drivers/mmc/mmc.c new file mode 100644 index 000000000000..4a73e8b2428d --- /dev/null +++ b/trunk/drivers/mmc/mmc.c @@ -0,0 +1,1724 @@ +/* + * linux/drivers/mmc/mmc.c + * + * Copyright (C) 2003-2004 Russell King, All Rights Reserved. + * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. + * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + * MMCv4 support Copyright (C) 2006 Philip Langdale, 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mmc.h" + +#define CMD_RETRIES 3 + +/* + * OCR Bit positions to 10s of Vdd mV. + */ +static const unsigned short mmc_ocr_bit_to_vdd[] = { + 150, 155, 160, 165, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, + 290, 300, 310, 320, 330, 340, 350, 360 +}; + +static const unsigned int tran_exp[] = { + 10000, 100000, 1000000, 10000000, + 0, 0, 0, 0 +}; + +static const unsigned char tran_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + +static const unsigned int tacc_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, +}; + +static const unsigned int tacc_mant[] = { + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + + +/** + * mmc_request_done - finish processing an MMC request + * @host: MMC host which completed request + * @mrq: MMC request which request + * + * MMC drivers should call this function when they have completed + * their processing of a request. + */ +void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + int err = cmd->error; + + pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", + mmc_hostname(host), cmd->opcode, err, + mrq->data ? mrq->data->error : 0, + mrq->stop ? mrq->stop->error : 0, + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + + if (err && cmd->retries) { + cmd->retries--; + cmd->error = 0; + host->ops->request(host, mrq); + } else if (mrq->done) { + mrq->done(mrq); + } +} + +EXPORT_SYMBOL(mmc_request_done); + +/** + * mmc_start_request - start a command on a host + * @host: MMC host to start command on + * @mrq: MMC request to start + * + * Queue a command on the specified host. We expect the + * caller to be holding the host lock with interrupts disabled. + */ +void +mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +{ + pr_debug("%s: starting CMD%u arg %08x flags %08x\n", + mmc_hostname(host), mrq->cmd->opcode, + mrq->cmd->arg, mrq->cmd->flags); + + WARN_ON(!host->claimed); + + mrq->cmd->error = 0; + mrq->cmd->mrq = mrq; + if (mrq->data) { + BUG_ON(mrq->data->blksz > host->max_blk_size); + BUG_ON(mrq->data->blocks > host->max_blk_count); + BUG_ON(mrq->data->blocks * mrq->data->blksz > + host->max_req_size); + + mrq->cmd->data = mrq->data; + mrq->data->error = 0; + mrq->data->mrq = mrq; + if (mrq->stop) { + mrq->data->stop = mrq->stop; + mrq->stop->error = 0; + mrq->stop->mrq = mrq; + } + } + host->ops->request(host, mrq); +} + +EXPORT_SYMBOL(mmc_start_request); + +static void mmc_wait_done(struct mmc_request *mrq) +{ + complete(mrq->done_data); +} + +int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) +{ + DECLARE_COMPLETION_ONSTACK(complete); + + mrq->done_data = &complete; + mrq->done = mmc_wait_done; + + mmc_start_request(host, mrq); + + wait_for_completion(&complete); + + return 0; +} + +EXPORT_SYMBOL(mmc_wait_for_req); + +/** + * mmc_wait_for_cmd - start a command and wait for completion + * @host: MMC host to start command + * @cmd: MMC command to start + * @retries: maximum number of retries + * + * Start a new MMC command for a host, and wait for the command + * to complete. Return any error that occurred while the command + * was executing. Do not attempt to parse the response. + */ +int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) +{ + struct mmc_request mrq; + + BUG_ON(!host->claimed); + + memset(&mrq, 0, sizeof(struct mmc_request)); + + memset(cmd->resp, 0, sizeof(cmd->resp)); + cmd->retries = retries; + + mrq.cmd = cmd; + cmd->data = NULL; + + mmc_wait_for_req(host, &mrq); + + return cmd->error; +} + +EXPORT_SYMBOL(mmc_wait_for_cmd); + +/** + * mmc_wait_for_app_cmd - start an application command and wait for + completion + * @host: MMC host to start command + * @rca: RCA to send MMC_APP_CMD to + * @cmd: MMC command to start + * @retries: maximum number of retries + * + * Sends a MMC_APP_CMD, checks the card response, sends the command + * in the parameter and waits for it to complete. Return any error + * that occurred while the command was executing. Do not attempt to + * parse the response. + */ +int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, + struct mmc_command *cmd, int retries) +{ + struct mmc_request mrq; + struct mmc_command appcmd; + + int i, err; + + BUG_ON(!host->claimed); + BUG_ON(retries < 0); + + err = MMC_ERR_INVALID; + + /* + * We have to resend MMC_APP_CMD for each attempt so + * we cannot use the retries field in mmc_command. + */ + for (i = 0;i <= retries;i++) { + memset(&mrq, 0, sizeof(struct mmc_request)); + + appcmd.opcode = MMC_APP_CMD; + appcmd.arg = rca << 16; + appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + appcmd.retries = 0; + memset(appcmd.resp, 0, sizeof(appcmd.resp)); + appcmd.data = NULL; + + mrq.cmd = &appcmd; + appcmd.data = NULL; + + mmc_wait_for_req(host, &mrq); + + if (appcmd.error) { + err = appcmd.error; + continue; + } + + /* Check that card supported application commands */ + if (!(appcmd.resp[0] & R1_APP_CMD)) + return MMC_ERR_FAILED; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + memset(cmd->resp, 0, sizeof(cmd->resp)); + cmd->retries = 0; + + mrq.cmd = cmd; + cmd->data = NULL; + + mmc_wait_for_req(host, &mrq); + + err = cmd->error; + if (cmd->error == MMC_ERR_NONE) + break; + } + + return err; +} + +EXPORT_SYMBOL(mmc_wait_for_app_cmd); + +/** + * mmc_set_data_timeout - set the timeout for a data command + * @data: data phase for command + * @card: the MMC card associated with the data transfer + * @write: flag to differentiate reads from writes + */ +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, + int write) +{ + unsigned int mult; + + /* + * SD cards use a 100 multiplier rather than 10 + */ + mult = mmc_card_sd(card) ? 100 : 10; + + /* + * Scale up the multiplier (and therefore the timeout) by + * the r2w factor for writes. + */ + if (write) + mult <<= card->csd.r2w_factor; + + data->timeout_ns = card->csd.tacc_ns * mult; + data->timeout_clks = card->csd.tacc_clks * mult; + + /* + * SD cards also have an upper limit on the timeout. + */ + if (mmc_card_sd(card)) { + unsigned int timeout_us, limit_us; + + timeout_us = data->timeout_ns / 1000; + timeout_us += data->timeout_clks * 1000 / + (card->host->ios.clock / 1000); + + if (write) + limit_us = 250000; + else + limit_us = 100000; + + /* + * SDHC cards always use these fixed values. + */ + if (timeout_us > limit_us || mmc_card_blockaddr(card)) { + data->timeout_ns = limit_us * 1000; + data->timeout_clks = 0; + } + } +} +EXPORT_SYMBOL(mmc_set_data_timeout); + +static int mmc_select_card(struct mmc_host *host, struct mmc_card *card); + +/** + * __mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * @card: mmc card to claim host for + * + * Claim a host for a set of operations. If a valid card + * is passed and this wasn't the last card selected, select + * the card before returning. + * + * Note: you should use mmc_card_claim_host or mmc_claim_host. + */ +int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int err = 0; + + add_wait_queue(&host->wq, &wait); + spin_lock_irqsave(&host->lock, flags); + while (1) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!host->claimed) + break; + spin_unlock_irqrestore(&host->lock, flags); + schedule(); + spin_lock_irqsave(&host->lock, flags); + } + set_current_state(TASK_RUNNING); + host->claimed = 1; + spin_unlock_irqrestore(&host->lock, flags); + remove_wait_queue(&host->wq, &wait); + + if (card != (void *)-1) { + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) + return err; + } + + return err; +} + +EXPORT_SYMBOL(__mmc_claim_host); + +/** + * mmc_release_host - release a host + * @host: mmc host to release + * + * Release a MMC host, allowing others to claim the host + * for their operations. + */ +void mmc_release_host(struct mmc_host *host) +{ + unsigned long flags; + + BUG_ON(!host->claimed); + + spin_lock_irqsave(&host->lock, flags); + host->claimed = 0; + spin_unlock_irqrestore(&host->lock, flags); + + wake_up(&host->wq); +} + +EXPORT_SYMBOL(mmc_release_host); + +static inline void mmc_set_ios(struct mmc_host *host) +{ + struct mmc_ios *ios = &host->ios; + + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " + "width %u timing %u\n", + mmc_hostname(host), ios->clock, ios->bus_mode, + ios->power_mode, ios->chip_select, ios->vdd, + ios->bus_width, ios->timing); + + host->ops->set_ios(host, ios); +} + +static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) +{ + int err; + struct mmc_command cmd; + + BUG_ON(!host->claimed); + + if (host->card_selected == card) + return MMC_ERR_NONE; + + host->card_selected = card; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + return err; + + /* + * We can only change the bus width of SD cards when + * they are selected so we have to put the handling + * here. + * + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. + */ + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + + /* + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + if (host->caps & MMC_CAP_4_BIT_DATA) { + struct mmc_command cmd; + cmd.opcode = SD_APP_SET_BUS_WIDTH; + cmd.arg = SD_BUS_WIDTH_4; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_app_cmd(host, card->rca, &cmd, + CMD_RETRIES); + if (err != MMC_ERR_NONE) + return err; + + host->ios.bus_width = MMC_BUS_WIDTH_4; + } + } + + mmc_set_ios(host); + + return MMC_ERR_NONE; +} + +/* + * Ensure that no card is selected. + */ +static void mmc_deselect_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + if (host->card_selected) { + host->card_selected = NULL; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; + + mmc_wait_for_cmd(host, &cmd, 0); + } +} + + +static inline void mmc_delay(unsigned int ms) +{ + if (ms < 1000 / HZ) { + cond_resched(); + mdelay(ms); + } else { + msleep(ms); + } +} + +/* + * Mask off any voltages we don't support and select + * the lowest voltage + */ +static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) +{ + int bit; + + ocr &= host->ocr_avail; + + bit = ffs(ocr); + if (bit) { + bit -= 1; + + ocr &= 3 << bit; + + host->ios.vdd = bit; + mmc_set_ios(host); + } else { + ocr = 0; + } + + return ocr; +} + +#define UNSTUFF_BITS(resp,start,size) \ + ({ \ + const int __size = size; \ + const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ + const int __off = 3 - ((start) / 32); \ + const int __shft = (start) & 31; \ + u32 __res; \ + \ + __res = resp[__off] >> __shft; \ + if (__size + __shft > 32) \ + __res |= resp[__off-1] << ((32 - __shft) % 32); \ + __res & __mask; \ + }) + +/* + * Given the decoded CSD structure, decode the raw CID to our CID structure. + */ +static void mmc_decode_cid(struct mmc_card *card) +{ + u32 *resp = card->raw_cid; + + memset(&card->cid, 0, sizeof(struct mmc_cid)); + + if (mmc_card_sd(card)) { + /* + * SD doesn't currently have a version field so we will + * have to assume we can parse this. + */ + card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); + card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4); + card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4); + card->cid.serial = UNSTUFF_BITS(resp, 24, 32); + card->cid.year = UNSTUFF_BITS(resp, 12, 8); + card->cid.month = UNSTUFF_BITS(resp, 8, 4); + + card->cid.year += 2000; /* SD cards year offset */ + } else { + /* + * The selection of the format here is based upon published + * specs from sandisk and from what people have reported. + */ + switch (card->csd.mmca_vsn) { + case 0: /* MMC v1.0 - v1.2 */ + case 1: /* MMC v1.4 */ + card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); + card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); + card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); + card->cid.serial = UNSTUFF_BITS(resp, 16, 24); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + case 2: /* MMC v2.0 - v2.2 */ + case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4 */ + card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); + card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); + card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); + card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); + card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); + card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); + card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); + card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.serial = UNSTUFF_BITS(resp, 16, 32); + card->cid.month = UNSTUFF_BITS(resp, 12, 4); + card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + break; + + default: + printk("%s: card has unknown MMCA version %d\n", + mmc_hostname(card->host), card->csd.mmca_vsn); + mmc_card_set_bad(card); + break; + } + } +} + +/* + * Given a 128-bit response, decode to our card CSD structure. + */ +static void mmc_decode_csd(struct mmc_card *card) +{ + struct mmc_csd *csd = &card->csd; + unsigned int e, m, csd_struct; + u32 *resp = card->raw_csd; + + if (mmc_card_sd(card)) { + csd_struct = UNSTUFF_BITS(resp, 126, 2); + + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + break; + case 1: + /* + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_card_set_blockaddr(card); + + csd->tacc_ns = 0; /* Unused */ + csd->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); + csd->capacity = (1 + m) << 10; + + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; + csd->read_misalign = 0; + csd->r2w_factor = 4; /* Unused */ + csd->write_blkbits = 9; + csd->write_partial = 0; + break; + default: + printk("%s: unrecognised CSD structure version %d\n", + mmc_hostname(card->host), csd_struct); + mmc_card_set_bad(card); + return; + } + } else { + /* + * We only understand CSD structure v1.1 and v1.2. + * v1.2 has extra information in bits 15, 11 and 10. + */ + csd_struct = UNSTUFF_BITS(resp, 126, 2); + if (csd_struct != 1 && csd_struct != 2) { + printk("%s: unrecognised CSD structure version %d\n", + mmc_hostname(card->host), csd_struct); + mmc_card_set_bad(card); + return; + } + + csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + } +} + +/* + * Given a 64-bit response, decode to our card SCR structure. + */ +static void mmc_decode_scr(struct mmc_card *card) +{ + struct sd_scr *scr = &card->scr; + unsigned int scr_struct; + u32 resp[4]; + + BUG_ON(!mmc_card_sd(card)); + + resp[3] = card->raw_scr[1]; + resp[2] = card->raw_scr[0]; + + scr_struct = UNSTUFF_BITS(resp, 60, 4); + if (scr_struct != 0) { + printk("%s: unrecognised SCR structure version %d\n", + mmc_hostname(card->host), scr_struct); + mmc_card_set_bad(card); + return; + } + + scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); + scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); +} + +/* + * Locate a MMC card on this MMC host given a raw CID. + */ +static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0) + return card; + } + return NULL; +} + +/* + * Allocate a new MMC card, and assign a unique RCA. + */ +static struct mmc_card * +mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca) +{ + struct mmc_card *card, *c; + unsigned int rca = *frca; + + card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + mmc_init_card(card, host); + memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid)); + + again: + list_for_each_entry(c, &host->cards, node) + if (c->rca == rca) { + rca++; + goto again; + } + + card->rca = rca; + + *frca = rca; + + return card; +} + +/* + * Tell attached cards to go to IDLE state + */ +static void mmc_idle_cards(struct mmc_host *host) +{ + struct mmc_command cmd; + + host->ios.chip_select = MMC_CS_HIGH; + mmc_set_ios(host); + + mmc_delay(1); + + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + + mmc_wait_for_cmd(host, &cmd, 0); + + mmc_delay(1); + + host->ios.chip_select = MMC_CS_DONTCARE; + mmc_set_ios(host); + + mmc_delay(1); +} + +/* + * Apply power to the MMC stack. This is a two-stage process. + * First, we enable power to the card without the clock running. + * We then wait a bit for the power to stabilise. Finally, + * enable the bus drivers and clock to the card. + * + * We must _NOT_ enable the clock prior to power stablising. + * + * If a host does all the power sequencing itself, ignore the + * initial MMC_POWER_UP stage. + */ +static void mmc_power_up(struct mmc_host *host) +{ + int bit = fls(host->ocr_avail) - 1; + + host->ios.vdd = bit; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.power_mode = MMC_POWER_UP; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + mmc_set_ios(host); + + mmc_delay(1); + + host->ios.clock = host->f_min; + host->ios.power_mode = MMC_POWER_ON; + mmc_set_ios(host); + + mmc_delay(2); +} + +static void mmc_power_off(struct mmc_host *host) +{ + host->ios.clock = 0; + host->ios.vdd = 0; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.power_mode = MMC_POWER_OFF; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + mmc_set_ios(host); +} + +static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = MMC_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = SD_APP_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + + for (i = 100; i; i--) { + err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) +{ + struct mmc_command cmd; + int err, sd2; + static const u8 test_pattern = 0xAA; + + /* + * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND + * before SD_APP_OP_COND. This command will harmlessly fail for + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; + cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) { + if ((cmd.resp[0] & 0xFF) == test_pattern) { + sd2 = 1; + } else { + sd2 = 0; + err = MMC_ERR_FAILED; + } + } else { + /* + * Treat errors as SD 1.0 card. + */ + sd2 = 0; + err = MMC_ERR_NONE; + } + if (rsd2) + *rsd2 = sd2; + return err; +} + +/* + * Discover cards by requesting their CID. If this command + * times out, it is not an error; there are no further cards + * to be discovered. Add new cards to the list. + * + * Create a mmc_card entry for each discovered card, assigning + * it an RCA, and save the raw CID for decoding later. + */ +static void mmc_discover_cards(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int first_rca = 1, err; + + while (1) { + struct mmc_command cmd; + + cmd.opcode = MMC_ALL_SEND_CID; + cmd.arg = 0; + cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_TIMEOUT) { + err = MMC_ERR_NONE; + break; + } + if (err != MMC_ERR_NONE) { + printk(KERN_ERR "%s: error requesting CID: %d\n", + mmc_hostname(host), err); + break; + } + + card = mmc_find_card(host, cmd.resp); + if (!card) { + card = mmc_alloc_card(host, cmd.resp, &first_rca); + if (IS_ERR(card)) { + err = PTR_ERR(card); + break; + } + list_add(&card->node, &host->cards); + } + + card->state &= ~MMC_STATE_DEAD; + + if (host->mode == MMC_MODE_SD) { + mmc_card_set_sd(card); + + cmd.opcode = SD_SEND_RELATIVE_ADDR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + mmc_card_set_dead(card); + else { + card->rca = cmd.resp[0] >> 16; + + if (!host->ops->get_ro) { + printk(KERN_WARNING "%s: host does not " + "support reading read-only " + "switch. assuming write-enable.\n", + mmc_hostname(host)); + } else { + if (host->ops->get_ro(host)) + mmc_card_set_readonly(card); + } + } + } else { + cmd.opcode = MMC_SET_RELATIVE_ADDR; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + mmc_card_set_dead(card); + } + } +} + +static void mmc_read_csds(struct mmc_host *host) +{ + struct mmc_card *card; + + list_for_each_entry(card, &host->cards, node) { + struct mmc_command cmd; + int err; + + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + + cmd.opcode = MMC_SEND_CSD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd)); + + mmc_decode_csd(card); + mmc_decode_cid(card); + } +} + +static void mmc_process_ext_csds(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + u8 *ext_csd; + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk("%s: could not allocate a buffer to receive the ext_csd." + "mmc v4 cards will be treated as v3.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (mmc_card_sd(card)) + continue; + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 512; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, ext_csd, 512); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + printk("%s: unable to read EXT_CSD, performance " + "might suffer.\n", mmc_hostname(card->host)); + continue; + } + + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; + case EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 26000000; + break; + default: + /* MMC v4 spec says this cannot happen */ + printk("%s: card is mmc v4 but doesn't support " + "any high-speed modes.\n", + mmc_hostname(card->host)); + continue; + } + + if (host->caps & MMC_CAP_MMC_HIGHSPEED) { + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } + + mmc_card_set_highspeed(card); + + host->ios.timing = MMC_TIMING_SD_HS; + mmc_set_ios(host); + } + + /* Check for host support for wide-bus modes. */ + if (host->caps & MMC_CAP_4_BIT_DATA) { + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } + + host->ios.bus_width = MMC_BUS_WIDTH_4; + mmc_set_ios(host); + } + } + + kfree(ext_csd); + + mmc_deselect_cards(host); +} + +static void mmc_read_scrs(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_APP_CMD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_APP_SEND_SCR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 1 << 3; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, (u8*)card->raw_scr, 8); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + card->raw_scr[0] = ntohl(card->raw_scr[0]); + card->raw_scr[1] = ntohl(card->raw_scr[1]); + + mmc_decode_scr(card); + } + + mmc_deselect_cards(host); +} + +static void mmc_read_switch_caps(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + unsigned char *status; + struct scatterlist sg; + + if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) + return; + + status = kmalloc(64, GFP_KERNEL); + if (!status) { + printk(KERN_WARNING "%s: Unable to allocate buffer for " + "reading switch capabilities.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + if (card->scr.sda_vsn < SCR_SPEC_VER_1) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x00FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + printk("%s: unable to read switch capabilities, " + "performance might suffer.\n", + mmc_hostname(card->host)); + continue; + } + + if (status[13] & 0x02) + card->sw_caps.hs_max_dtr = 50000000; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x80FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || + (status[16] & 0xF) != 1) { + printk(KERN_WARNING "%s: Problem switching card " + "into high-speed mode!\n", + mmc_hostname(host)); + continue; + } + + mmc_card_set_highspeed(card); + + host->ios.timing = MMC_TIMING_SD_HS; + mmc_set_ios(host); + } + + kfree(status); + + mmc_deselect_cards(host); +} + +static unsigned int mmc_calculate_clock(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int max_dtr = host->f_max; + + list_for_each_entry(card, &host->cards, node) + if (!mmc_card_dead(card)) { + if (mmc_card_highspeed(card) && mmc_card_sd(card)) { + if (max_dtr > card->sw_caps.hs_max_dtr) + max_dtr = card->sw_caps.hs_max_dtr; + } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { + if (max_dtr > card->ext_csd.hs_max_dtr) + max_dtr = card->ext_csd.hs_max_dtr; + } else if (max_dtr > card->csd.max_dtr) { + max_dtr = card->csd.max_dtr; + } + } + + pr_debug("%s: selected %d.%03dMHz transfer rate\n", + mmc_hostname(host), + max_dtr / 1000000, (max_dtr / 1000) % 1000); + + return max_dtr; +} + +/* + * Check whether cards we already know about are still present. + * We do this by requesting status, and checking whether a card + * responds. + * + * A request for status does not cause a state change in data + * transfer mode. + */ +static void mmc_check_cards(struct mmc_host *host) +{ + struct list_head *l, *n; + + mmc_deselect_cards(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + struct mmc_command cmd; + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err == MMC_ERR_NONE) + continue; + + mmc_card_set_dead(card); + } +} + +static void mmc_setup(struct mmc_host *host) +{ + if (host->ios.power_mode != MMC_POWER_ON) { + int err; + u32 ocr; + + host->mode = MMC_MODE_SD; + + mmc_power_up(host); + mmc_idle_cards(host); + + err = mmc_send_if_cond(host, host->ocr_avail, NULL); + if (err != MMC_ERR_NONE) { + return; + } + err = mmc_send_app_op_cond(host, 0, &ocr); + + /* + * If we fail to detect any SD cards then try + * searching for MMC cards. + */ + if (err != MMC_ERR_NONE) { + host->mode = MMC_MODE_MMC; + + err = mmc_send_op_cond(host, 0, &ocr); + if (err != MMC_ERR_NONE) + return; + } + + host->ocr = mmc_select_voltage(host, ocr); + + /* + * Since we're changing the OCR value, we seem to + * need to tell some cards to go back to the idle + * state. We wait 1ms to give cards time to + * respond. + */ + if (host->ocr) + mmc_idle_cards(host); + } else { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.clock = host->f_min; + mmc_set_ios(host); + + /* + * We should remember the OCR mask from the existing + * cards, and detect the new cards OCR mask, combine + * the two and re-select the VDD. However, if we do + * change VDD, we should do an idle, and then do a + * full re-initialisation. We would need to notify + * drivers so that they can re-setup the cards as + * well, while keeping their queues at bay. + * + * For the moment, we take the easy way out - if the + * new cards don't like our currently selected VDD, + * they drop off the bus. + */ + } + + if (host->ocr == 0) + return; + + /* + * Send the selected OCR multiple times... until the cards + * all get the idea that they should be ready for CMD2. + * (My SanDisk card seems to need this.) + */ + if (host->mode == MMC_MODE_SD) { + int err, sd2; + err = mmc_send_if_cond(host, host->ocr, &sd2); + if (err == MMC_ERR_NONE) { + /* + * If SD_SEND_IF_COND indicates an SD 2.0 + * compliant card and we should set bit 30 + * of the ocr to indicate that we can handle + * block-addressed SDHC cards. + */ + mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); + } + } else { + mmc_send_op_cond(host, host->ocr, NULL); + } + + mmc_discover_cards(host); + + /* + * Ok, now switch to push-pull mode. + */ + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + mmc_set_ios(host); + + mmc_read_csds(host); + + if (host->mode == MMC_MODE_SD) { + mmc_read_scrs(host); + mmc_read_switch_caps(host); + } else + mmc_process_ext_csds(host); +} + + +/** + * mmc_detect_change - process change of state on a MMC socket + * @host: host which changed state. + * @delay: optional delay to wait before detection (jiffies) + * + * All we know is that card(s) have been inserted or removed + * from the socket(s). We don't know which socket or cards. + */ +void mmc_detect_change(struct mmc_host *host, unsigned long delay) +{ + mmc_schedule_delayed_work(&host->detect, delay); +} + +EXPORT_SYMBOL(mmc_detect_change); + + +static void mmc_rescan(struct work_struct *work) +{ + struct mmc_host *host = + container_of(work, struct mmc_host, detect.work); + struct list_head *l, *n; + unsigned char power_mode; + + mmc_claim_host(host); + + /* + * Check for removed cards and newly inserted ones. We check for + * removed cards first so we can intelligently re-select the VDD. + */ + power_mode = host->ios.power_mode; + if (power_mode == MMC_POWER_ON) + mmc_check_cards(host); + + mmc_setup(host); + + /* + * Some broken cards process CMD1 even in stand-by state. There is + * no reply, but an ILLEGAL_COMMAND error is cached and returned + * after next command. We poll for card status here to clear any + * possibly pending error. + */ + if (power_mode == MMC_POWER_ON) + mmc_check_cards(host); + + if (!list_empty(&host->cards)) { + /* + * (Re-)calculate the fastest clock rate which the + * attached cards and the host support. + */ + host->ios.clock = mmc_calculate_clock(host); + mmc_set_ios(host); + } + + mmc_release_host(host); + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + /* + * If this is a new and good card, register it. + */ + if (!mmc_card_present(card) && !mmc_card_dead(card)) { + if (mmc_register_card(card)) + mmc_card_set_dead(card); + else + mmc_card_set_present(card); + } + + /* + * If this card is dead, destroy it. + */ + if (mmc_card_dead(card)) { + list_del(&card->node); + mmc_remove_card(card); + } + } + + /* + * If we discover that there are no cards on the + * bus, turn off the clock and power down. + */ + if (list_empty(&host->cards)) + mmc_power_off(host); +} + + +/** + * mmc_alloc_host - initialise the per-host structure. + * @extra: sizeof private data structure + * @dev: pointer to host device model structure + * + * Initialise the per-host structure. + */ +struct mmc_host *mmc_alloc_host(int extra, struct device *dev) +{ + struct mmc_host *host; + + host = mmc_alloc_host_sysfs(extra, dev); + if (host) { + spin_lock_init(&host->lock); + init_waitqueue_head(&host->wq); + INIT_LIST_HEAD(&host->cards); + INIT_DELAYED_WORK(&host->detect, mmc_rescan); + + /* + * By default, hosts do not support SGIO or large requests. + * They have to set these according to their abilities. + */ + host->max_hw_segs = 1; + host->max_phys_segs = 1; + host->max_seg_size = PAGE_CACHE_SIZE; + + host->max_req_size = PAGE_CACHE_SIZE; + host->max_blk_size = 512; + host->max_blk_count = PAGE_CACHE_SIZE / 512; + } + + return host; +} + +EXPORT_SYMBOL(mmc_alloc_host); + +/** + * mmc_add_host - initialise host hardware + * @host: mmc host + */ +int mmc_add_host(struct mmc_host *host) +{ + int ret; + + ret = mmc_add_host_sysfs(host); + if (ret == 0) { + mmc_power_off(host); + mmc_detect_change(host, 0); + } + + return ret; +} + +EXPORT_SYMBOL(mmc_add_host); + +/** + * mmc_remove_host - remove host hardware + * @host: mmc host + * + * Unregister and remove all cards associated with this host, + * and power down the MMC bus. + */ +void mmc_remove_host(struct mmc_host *host) +{ + struct list_head *l, *n; + + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + + mmc_remove_card(card); + } + + mmc_power_off(host); + mmc_remove_host_sysfs(host); +} + +EXPORT_SYMBOL(mmc_remove_host); + +/** + * mmc_free_host - free the host structure + * @host: mmc host + * + * Free the host once all references to it have been dropped. + */ +void mmc_free_host(struct mmc_host *host) +{ + mmc_flush_scheduled_work(); + mmc_free_host_sysfs(host); +} + +EXPORT_SYMBOL(mmc_free_host); + +#ifdef CONFIG_PM + +/** + * mmc_suspend_host - suspend a host + * @host: mmc host + * @state: suspend mode (PM_SUSPEND_xxx) + */ +int mmc_suspend_host(struct mmc_host *host, pm_message_t state) +{ + mmc_claim_host(host); + mmc_deselect_cards(host); + mmc_power_off(host); + mmc_release_host(host); + + return 0; +} + +EXPORT_SYMBOL(mmc_suspend_host); + +/** + * mmc_resume_host - resume a previously suspended host + * @host: mmc host + */ +int mmc_resume_host(struct mmc_host *host) +{ + mmc_rescan(&host->detect.work); + + return 0; +} + +EXPORT_SYMBOL(mmc_resume_host); + +#endif + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mmc/core/sysfs.h b/trunk/drivers/mmc/mmc.h similarity index 86% rename from trunk/drivers/mmc/core/sysfs.h rename to trunk/drivers/mmc/mmc.h index 80e29b358282..149affe0b686 100644 --- a/trunk/drivers/mmc/core/sysfs.h +++ b/trunk/drivers/mmc/mmc.h @@ -1,16 +1,15 @@ /* - * linux/drivers/mmc/core/sysfs.h + * linux/drivers/mmc/mmc.h * * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright 2007 Pierre Ossman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _MMC_CORE_SYSFS_H -#define _MMC_CORE_SYSFS_H - +#ifndef _MMC_H +#define _MMC_H +/* core-internal functions */ void mmc_init_card(struct mmc_card *card, struct mmc_host *host); int mmc_register_card(struct mmc_card *card); void mmc_remove_card(struct mmc_card *card); @@ -23,5 +22,4 @@ void mmc_free_host_sysfs(struct mmc_host *host); int mmc_schedule_work(struct work_struct *work); int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); void mmc_flush_scheduled_work(void); - #endif diff --git a/trunk/drivers/mmc/card/block.c b/trunk/drivers/mmc/mmc_block.c similarity index 93% rename from trunk/drivers/mmc/card/block.c rename to trunk/drivers/mmc/mmc_block.c index d24ab234394c..86439a0bb271 100644 --- a/trunk/drivers/mmc/card/block.c +++ b/trunk/drivers/mmc/mmc_block.c @@ -2,7 +2,6 @@ * Block driver for media (i.e., flash cards) * * Copyright 2002 Hewlett-Packard Company - * Copyright 2005-2007 Pierre Ossman * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is @@ -32,13 +31,13 @@ #include #include -#include -#include +#include +#include #include #include -#include "queue.h" +#include "mmc_queue.h" /* * max 8 partitions per card @@ -224,9 +223,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; struct mmc_blk_request brq; - int ret = 1, sg_pos, data_size; + int ret = 1; - mmc_claim_host(card->host); + if (mmc_card_claim_host(card)) + goto flush_queue; do { struct mmc_command cmd; @@ -283,20 +283,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.sg = mq->sg; brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); - if (brq.data.blocks != - (req->nr_sectors >> (md->block_bits - 9))) { - data_size = brq.data.blocks * brq.data.blksz; - for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) { - data_size -= mq->sg[sg_pos].length; - if (data_size <= 0) { - mq->sg[sg_pos].length += data_size; - sg_pos++; - break; - } - } - brq.data.sg_len = sg_pos; - } - mmc_wait_for_req(card->host, &brq.mrq); if (brq.cmd.error) { printk(KERN_ERR "%s: error %d sending read/write command\n", @@ -356,7 +342,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) spin_unlock_irq(&md->lock); } while (ret); - mmc_release_host(card->host); + mmc_card_release_host(card); return 1; @@ -392,7 +378,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) spin_unlock_irq(&md->lock); } - mmc_release_host(card->host); +flush_queue: + + mmc_card_release_host(card); spin_lock_irq(&md->lock); while (ret) { @@ -489,20 +477,11 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); - if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { - /* - * The EXT_CSD sector count is in number or 512 byte - * sectors. - */ - set_capacity(md->disk, card->ext_csd.sectors); - } else { - /* - * The CSD capacity field is in units of read_blkbits. - * set_capacity takes units of 512 bytes. - */ - set_capacity(md->disk, - card->csd.capacity << (card->csd.read_blkbits - 9)); - } + /* + * The CSD capacity field is in units of read_blkbits. + * set_capacity takes units of 512 bytes. + */ + set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); return md; err_putdisk: @@ -523,12 +502,12 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) if (mmc_card_blockaddr(card)) return 0; - mmc_claim_host(card->host); + mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); - mmc_release_host(card->host); + mmc_card_release_host(card); if (err) { printk(KERN_ERR "%s: unable to set block size to %d: %d\n", diff --git a/trunk/drivers/mmc/card/queue.c b/trunk/drivers/mmc/mmc_queue.c similarity index 96% rename from trunk/drivers/mmc/card/queue.c rename to trunk/drivers/mmc/mmc_queue.c index 2e77963db334..c27e42645cdb 100644 --- a/trunk/drivers/mmc/card/queue.c +++ b/trunk/drivers/mmc/mmc_queue.c @@ -1,8 +1,7 @@ /* - * linux/drivers/mmc/queue.c + * linux/drivers/mmc/mmc_queue.c * * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright 2006-2007 Pierre Ossman * * 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 @@ -15,7 +14,7 @@ #include #include -#include "queue.h" +#include "mmc_queue.h" #define MMC_QUEUE_SUSPENDED (1 << 0) @@ -180,6 +179,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock blk_cleanup_queue(mq->queue); return ret; } +EXPORT_SYMBOL(mmc_init_queue); void mmc_cleanup_queue(struct mmc_queue *mq) { @@ -191,9 +191,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq) q->queuedata = NULL; spin_unlock_irqrestore(q->queue_lock, flags); - /* Make sure the queue isn't suspended, as that will deadlock */ - mmc_queue_resume(mq); - /* Then terminate our worker thread */ kthread_stop(mq->thread); @@ -229,6 +226,7 @@ void mmc_queue_suspend(struct mmc_queue *mq) down(&mq->thread_sem); } } +EXPORT_SYMBOL(mmc_queue_suspend); /** * mmc_queue_resume - resume a previously suspended MMC request queue @@ -249,4 +247,4 @@ void mmc_queue_resume(struct mmc_queue *mq) spin_unlock_irqrestore(q->queue_lock, flags); } } - +EXPORT_SYMBOL(mmc_queue_resume); diff --git a/trunk/drivers/mmc/card/queue.h b/trunk/drivers/mmc/mmc_queue.h similarity index 100% rename from trunk/drivers/mmc/card/queue.h rename to trunk/drivers/mmc/mmc_queue.h diff --git a/trunk/drivers/mmc/core/sysfs.c b/trunk/drivers/mmc/mmc_sysfs.c similarity index 93% rename from trunk/drivers/mmc/core/sysfs.c rename to trunk/drivers/mmc/mmc_sysfs.c index 843b1fbba557..d32698b02d7f 100644 --- a/trunk/drivers/mmc/core/sysfs.c +++ b/trunk/drivers/mmc/mmc_sysfs.c @@ -1,5 +1,5 @@ /* - * linux/drivers/mmc/core/sysfs.c + * linux/drivers/mmc/mmc_sysfs.c * * Copyright (C) 2003 Russell King, All Rights Reserved. * @@ -18,7 +18,7 @@ #include #include -#include "sysfs.h" +#include "mmc.h" #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) @@ -72,11 +72,12 @@ static void mmc_release_card(struct device *dev) /* * This currently matches any MMC driver to any MMC card - drivers * themselves make the decision whether to drive this card in their - * probe method. + * probe method. However, we force "bad" cards to fail. */ static int mmc_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + struct mmc_card *card = dev_to_mmc_card(dev); + return !mmc_card_bad(card); } static int @@ -85,26 +86,31 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, { struct mmc_card *card = dev_to_mmc_card(dev); char ccc[13]; - int retval = 0, i = 0, length = 0; - -#define add_env(fmt,val) do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buf, buf_size, &length, \ - fmt, val); \ - if (retval) \ - return retval; \ -} while (0); + int i = 0; + +#define add_env(fmt,val) \ + ({ \ + int len, ret = -ENOMEM; \ + if (i < num_envp) { \ + envp[i++] = buf; \ + len = snprintf(buf, buf_size, fmt, val) + 1; \ + buf_size -= len; \ + buf += len; \ + if (buf_size >= 0) \ + ret = 0; \ + } \ + ret; \ + }) for (i = 0; i < 12; i++) ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; ccc[12] = '\0'; + i = 0; add_env("MMC_CCC=%s", ccc); add_env("MMC_MANFID=%06x", card->cid.manfid); add_env("MMC_NAME=%s", mmc_card_name(card)); add_env("MMC_OEMID=%04x", card->cid.oemid); -#undef add_env - envp[i] = NULL; return 0; } @@ -216,8 +222,6 @@ int mmc_register_card(struct mmc_card *card) device_del(&card->dev); } } - if (ret == 0) - mmc_card_set_present(card); return ret; } diff --git a/trunk/drivers/mmc/host/mmci.c b/trunk/drivers/mmc/mmci.c similarity index 99% rename from trunk/drivers/mmc/host/mmci.c rename to trunk/drivers/mmc/mmci.c index d11c2d23ceea..5941dd951e82 100644 --- a/trunk/drivers/mmc/host/mmci.c +++ b/trunk/drivers/mmc/mmci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/mmc/host/mmci.h b/trunk/drivers/mmc/mmci.h similarity index 100% rename from trunk/drivers/mmc/host/mmci.h rename to trunk/drivers/mmc/mmci.h diff --git a/trunk/drivers/mmc/host/omap.c b/trunk/drivers/mmc/omap.c similarity index 98% rename from trunk/drivers/mmc/host/omap.c rename to trunk/drivers/mmc/omap.c index 1914e65d4db1..1e96a2f65022 100644 --- a/trunk/drivers/mmc/host/omap.c +++ b/trunk/drivers/mmc/omap.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -604,7 +605,7 @@ static void mmc_omap_switch_handler(struct work_struct *work) } if (mmc_omap_cover_is_open(host)) { if (!complained) { - dev_info(mmc_dev(host->mmc), "cover is open\n"); + dev_info(mmc_dev(host->mmc), "cover is open"); complained = 1; } if (mmc_omap_enable_poll) @@ -936,55 +937,48 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on) } } -static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios) +static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_omap_host *host = mmc_priv(mmc); - int func_clk_rate = clk_get_rate(host->fclk); int dsor; + int realclock, i; - if (ios->clock == 0) - return 0; - - dsor = func_clk_rate / ios->clock; - if (dsor < 1) - dsor = 1; - - if (func_clk_rate / dsor > ios->clock) - dsor++; + realclock = ios->clock; - if (dsor > 250) - dsor = 250; - dsor++; + if (ios->clock == 0) + dsor = 0; + else { + int func_clk_rate = clk_get_rate(host->fclk); - if (ios->bus_width == MMC_BUS_WIDTH_4) - dsor |= 1 << 15; + dsor = func_clk_rate / realclock; + if (dsor < 1) + dsor = 1; - return dsor; -} + if (func_clk_rate / dsor > realclock) + dsor++; -static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct mmc_omap_host *host = mmc_priv(mmc); - int dsor; - int i; + if (dsor > 250) + dsor = 250; + dsor++; - dsor = mmc_omap_calc_divisor(mmc, ios); - host->bus_mode = ios->bus_mode; - host->hw_bus_mode = host->bus_mode; + if (ios->bus_width == MMC_BUS_WIDTH_4) + dsor |= 1 << 15; + } switch (ios->power_mode) { case MMC_POWER_OFF: mmc_omap_power(host, 0); break; case MMC_POWER_UP: - /* Cannot touch dsor yet, just power up MMC */ - mmc_omap_power(host, 1); - return; case MMC_POWER_ON: + mmc_omap_power(host, 1); dsor |= 1 << 11; break; } + host->bus_mode = ios->bus_mode; + host->hw_bus_mode = host->bus_mode; + clk_enable(host->fclk); /* On insanely high arm_per frequencies something sometimes @@ -993,7 +987,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * Writing to the CON register twice seems to do the trick. */ for (i = 0; i < 2; i++) OMAP_MMC_WRITE(host, CON, dsor); - if (ios->power_mode == MMC_POWER_ON) { + if (ios->power_mode == MMC_POWER_UP) { /* Send clock cycles, poll completion */ OMAP_MMC_WRITE(host, IE, 0); OMAP_MMC_WRITE(host, STAT, 0xffff); diff --git a/trunk/drivers/mmc/host/pxamci.c b/trunk/drivers/mmc/pxamci.c similarity index 99% rename from trunk/drivers/mmc/host/pxamci.c rename to trunk/drivers/mmc/pxamci.c index a98ff98fa567..9774fc68b61a 100644 --- a/trunk/drivers/mmc/host/pxamci.c +++ b/trunk/drivers/mmc/pxamci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/mmc/host/pxamci.h b/trunk/drivers/mmc/pxamci.h similarity index 100% rename from trunk/drivers/mmc/host/pxamci.h rename to trunk/drivers/mmc/pxamci.h diff --git a/trunk/drivers/mmc/host/sdhci.c b/trunk/drivers/mmc/sdhci.c similarity index 97% rename from trunk/drivers/mmc/host/sdhci.c rename to trunk/drivers/mmc/sdhci.c index ff5bf73cdd25..d749f08601b8 100644 --- a/trunk/drivers/mmc/host/sdhci.c +++ b/trunk/drivers/mmc/sdhci.c @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ #include #include +#include #include @@ -246,13 +247,14 @@ static void sdhci_read_block_pio(struct sdhci_host *host) chunk_remain = min(blksize, 4); } - size = min(host->remain, chunk_remain); + size = min(host->size, host->remain); + size = min(size, chunk_remain); chunk_remain -= size; blksize -= size; host->offset += size; host->remain -= size; - + host->size -= size; while (size) { *buffer = data & 0xFF; buffer++; @@ -287,13 +289,14 @@ static void sdhci_write_block_pio(struct sdhci_host *host) buffer = sdhci_sg_to_buffer(host) + host->offset; while (blksize) { - size = min(host->remain, chunk_remain); + size = min(host->size, host->remain); + size = min(size, chunk_remain); chunk_remain -= size; blksize -= size; host->offset += size; host->remain -= size; - + host->size -= size; while (size) { data >>= 8; data |= (u32)*buffer << 24; @@ -322,7 +325,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) BUG_ON(!host->data); - if (host->num_sg == 0) + if (host->size == 0) return; if (host->data->flags & MMC_DATA_READ) @@ -336,8 +339,10 @@ static void sdhci_transfer_pio(struct sdhci_host *host) else sdhci_write_block_pio(host); - if (host->num_sg == 0) + if (host->size == 0) break; + + BUG_ON(host->num_sg == 0); } DBG("PIO transfer complete.\n"); @@ -403,6 +408,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); } else { + host->size = data->blksz * data->blocks; + host->cur_sg = data->sg; host->num_sg = data->sg_len; @@ -466,6 +473,10 @@ static void sdhci_finish_data(struct sdhci_host *host) "though there were blocks left.\n", mmc_hostname(host->mmc)); data->error = MMC_ERR_FAILED; + } else if (host->size != 0) { + printk(KERN_ERR "%s: %d bytes were left untransferred.\n", + mmc_hostname(host->mmc), host->size); + data->error = MMC_ERR_FAILED; } DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered); @@ -658,16 +669,20 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) pwr = SDHCI_POWER_ON; - switch (1 << power) { - case MMC_VDD_165_195: + switch (power) { + case MMC_VDD_170: + case MMC_VDD_180: + case MMC_VDD_190: pwr |= SDHCI_POWER_180; break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: + case MMC_VDD_290: + case MMC_VDD_300: + case MMC_VDD_310: pwr |= SDHCI_POWER_300; break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: + case MMC_VDD_320: + case MMC_VDD_330: + case MMC_VDD_340: pwr |= SDHCI_POWER_330; break; default: @@ -1279,7 +1294,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) if (caps & SDHCI_CAN_VDD_300) mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; if (caps & SDHCI_CAN_VDD_180) - mmc->ocr_avail |= MMC_VDD_165_195; + mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; if (mmc->ocr_avail == 0) { printk(KERN_ERR "%s: Hardware doesn't report any " diff --git a/trunk/drivers/mmc/host/sdhci.h b/trunk/drivers/mmc/sdhci.h similarity index 98% rename from trunk/drivers/mmc/host/sdhci.h rename to trunk/drivers/mmc/sdhci.h index 7400f4bc114f..e324f0a623dc 100644 --- a/trunk/drivers/mmc/host/sdhci.h +++ b/trunk/drivers/mmc/sdhci.h @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2005 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -187,6 +187,8 @@ struct sdhci_host { int offset; /* Offset into current sg */ int remain; /* Bytes left in current */ + int size; /* Remaining bytes in transfer */ + char slot_descr[20]; /* Name for reservations */ int irq; /* Device IRQ */ diff --git a/trunk/drivers/mmc/tifm_sd.c b/trunk/drivers/mmc/tifm_sd.c new file mode 100644 index 000000000000..0581d09c58fc --- /dev/null +++ b/trunk/drivers/mmc/tifm_sd.c @@ -0,0 +1,987 @@ +/* + * tifm_sd.c - TI FlashMedia driver + * + * Copyright (C) 2006 Alex Dubov + * + * 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 + +#define DRIVER_NAME "tifm_sd" +#define DRIVER_VERSION "0.7" + +static int no_dma = 0; +static int fixed_timeout = 0; +module_param(no_dma, bool, 0644); +module_param(fixed_timeout, bool, 0644); + +/* Constants here are mostly from OMAP5912 datasheet */ +#define TIFM_MMCSD_RESET 0x0002 +#define TIFM_MMCSD_CLKMASK 0x03ff +#define TIFM_MMCSD_POWER 0x0800 +#define TIFM_MMCSD_4BBUS 0x8000 +#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */ +#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */ +#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */ +#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */ +#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ +#define TIFM_MMCSD_READ 0x8000 + +#define TIFM_MMCSD_DATAMASK 0x401d /* set bits: CERR, EOFB, BRS, CB, EOC */ +#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */ +#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ +#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ +#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ +#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */ +#define TIFM_MMCSD_DTO 0x0020 /* data time-out */ +#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */ +#define TIFM_MMCSD_CTO 0x0080 /* command time-out */ +#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */ +#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */ +#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */ +#define TIFM_MMCSD_CERR 0x4000 /* card status error */ + +#define TIFM_MMCSD_FIFO_SIZE 0x0020 + +#define TIFM_MMCSD_RSP_R0 0x0000 +#define TIFM_MMCSD_RSP_R1 0x0100 +#define TIFM_MMCSD_RSP_R2 0x0200 +#define TIFM_MMCSD_RSP_R3 0x0300 +#define TIFM_MMCSD_RSP_R4 0x0400 +#define TIFM_MMCSD_RSP_R5 0x0500 +#define TIFM_MMCSD_RSP_R6 0x0600 + +#define TIFM_MMCSD_RSP_BUSY 0x0800 + +#define TIFM_MMCSD_CMD_BC 0x0000 +#define TIFM_MMCSD_CMD_BCR 0x1000 +#define TIFM_MMCSD_CMD_AC 0x2000 +#define TIFM_MMCSD_CMD_ADTC 0x3000 + +typedef enum { + IDLE = 0, + CMD, /* main command ended */ + BRS, /* block transfer finished */ + SCMD, /* stop command ended */ + CARD, /* card left busy state */ + FIFO, /* FIFO operation completed (uncertain) */ + READY +} card_state_t; + +enum { + FIFO_RDY = 0x0001, /* hardware dependent value */ + EJECT = 0x0004, + EJECT_DONE = 0x0008, + CARD_BUSY = 0x0010, + OPENDRAIN = 0x0040, /* hardware dependent value */ + CARD_EVENT = 0x0100, /* hardware dependent value */ + CARD_RO = 0x0200, /* hardware dependent value */ + FIFO_EVENT = 0x10000 }; /* hardware dependent value */ + +struct tifm_sd { + struct tifm_dev *dev; + + unsigned int flags; + card_state_t state; + unsigned int clk_freq; + unsigned int clk_div; + unsigned long timeout_jiffies; + + struct tasklet_struct finish_tasklet; + struct timer_list timer; + struct mmc_request *req; + wait_queue_head_t notify; + + size_t written_blocks; + size_t buffer_size; + size_t buffer_pos; + +}; + +static char* tifm_sd_data_buffer(struct mmc_data *data) +{ + return page_address(data->sg->page) + data->sg->offset; +} + +static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, + unsigned int host_status) +{ + struct mmc_command *cmd = host->req->cmd; + unsigned int t_val = 0, cnt = 0; + char *buffer; + + if (host_status & TIFM_MMCSD_BRS) { + /* in non-dma rx mode BRS fires when fifo is still not empty */ + if (no_dma && (cmd->data->flags & MMC_DATA_READ)) { + buffer = tifm_sd_data_buffer(host->req->data); + while (host->buffer_size > host->buffer_pos) { + t_val = readl(sock->addr + SOCK_MMCSD_DATA); + buffer[host->buffer_pos++] = t_val & 0xff; + buffer[host->buffer_pos++] = + (t_val >> 8) & 0xff; + } + } + return 1; + } else if (no_dma) { + buffer = tifm_sd_data_buffer(host->req->data); + if ((cmd->data->flags & MMC_DATA_READ) && + (host_status & TIFM_MMCSD_AF)) { + for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { + t_val = readl(sock->addr + SOCK_MMCSD_DATA); + if (host->buffer_size > host->buffer_pos) { + buffer[host->buffer_pos++] = + t_val & 0xff; + buffer[host->buffer_pos++] = + (t_val >> 8) & 0xff; + } + } + } else if ((cmd->data->flags & MMC_DATA_WRITE) + && (host_status & TIFM_MMCSD_AE)) { + for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { + if (host->buffer_size > host->buffer_pos) { + t_val = buffer[host->buffer_pos++] + & 0x00ff; + t_val |= ((buffer[host->buffer_pos++]) + << 8) & 0xff00; + writel(t_val, + sock->addr + SOCK_MMCSD_DATA); + } + } + } + } + return 0; +} + +static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) +{ + unsigned int rc = 0; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rc |= TIFM_MMCSD_RSP_R0; + break; + case MMC_RSP_R1B: + rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through + case MMC_RSP_R1: + rc |= TIFM_MMCSD_RSP_R1; + break; + case MMC_RSP_R2: + rc |= TIFM_MMCSD_RSP_R2; + break; + case MMC_RSP_R3: + rc |= TIFM_MMCSD_RSP_R3; + break; + default: + BUG(); + } + + switch (mmc_cmd_type(cmd)) { + case MMC_CMD_BC: + rc |= TIFM_MMCSD_CMD_BC; + break; + case MMC_CMD_BCR: + rc |= TIFM_MMCSD_CMD_BCR; + break; + case MMC_CMD_AC: + rc |= TIFM_MMCSD_CMD_AC; + break; + case MMC_CMD_ADTC: + rc |= TIFM_MMCSD_CMD_ADTC; + break; + default: + BUG(); + } + return rc; +} + +static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) +{ + struct tifm_dev *sock = host->dev; + unsigned int cmd_mask = tifm_sd_op_flags(cmd) | + (host->flags & OPENDRAIN); + + if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) + cmd_mask |= TIFM_MMCSD_READ; + + dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", + cmd->opcode, cmd->arg, cmd_mask); + + writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); + writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); + writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND); +} + +static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock) +{ + cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18); + cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10); + cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08); + cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16) + | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00); +} + +static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host, + unsigned int host_status) +{ + struct mmc_command *cmd = host->req->cmd; + +change_state: + switch (host->state) { + case IDLE: + return; + case CMD: + if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { + tifm_sd_fetch_resp(cmd, sock); + if (cmd->data) { + host->state = BRS; + } else { + host->state = READY; + } + goto change_state; + } + break; + case BRS: + if (tifm_sd_transfer_data(sock, host, host_status)) { + if (cmd->data->flags & MMC_DATA_WRITE) { + host->state = CARD; + } else { + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } + } else { + host->state = FIFO; + } + } + goto change_state; + } + break; + case SCMD: + if (host_status & TIFM_MMCSD_EOC) { + tifm_sd_fetch_resp(host->req->stop, sock); + host->state = READY; + goto change_state; + } + break; + case CARD: + dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n", + host->written_blocks); + if (!(host->flags & CARD_BUSY) + && (host->written_blocks == cmd->data->blocks)) { + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } + } else { + host->state = FIFO; + } + goto change_state; + } + break; + case FIFO: + if (host->flags & FIFO_RDY) { + host->flags &= ~FIFO_RDY; + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } + goto change_state; + } + break; + case READY: + tasklet_schedule(&host->finish_tasklet); + return; + } + +} + +/* Called from interrupt handler */ +static void tifm_sd_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) +{ + struct tifm_sd *host; + unsigned int host_status = 0, fifo_status = 0; + int error_code = 0; + + spin_lock(&sock->lock); + host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); + + if (sock_irq_status & FIFO_EVENT) { + fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); + writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); + + host->flags |= fifo_status & FIFO_RDY; + } + + if (sock_irq_status & CARD_EVENT) { + host_status = readl(sock->addr + SOCK_MMCSD_STATUS); + writel(host_status, sock->addr + SOCK_MMCSD_STATUS); + + if (!host->req) + goto done; + + if (host_status & TIFM_MMCSD_ERRMASK) { + if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) + error_code = MMC_ERR_TIMEOUT; + else if (host_status + & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) + error_code = MMC_ERR_BADCRC; + + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); + + if (host->req->stop) { + if (host->state == SCMD) { + host->req->stop->error = error_code; + } else if (host->state == BRS + || host->state == CARD + || host->state == FIFO) { + host->req->cmd->error = error_code; + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + goto done; + } else { + host->req->cmd->error = error_code; + } + } else { + host->req->cmd->error = error_code; + } + host->state = READY; + } + + if (host_status & TIFM_MMCSD_CB) + host->flags |= CARD_BUSY; + if ((host_status & TIFM_MMCSD_EOFB) + && (host->flags & CARD_BUSY)) { + host->written_blocks++; + host->flags &= ~CARD_BUSY; + } + } + + if (host->req) + tifm_sd_process_cmd(sock, host, host_status); +done: + dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", + host_status, fifo_status); + spin_unlock(&sock->lock); +} + +static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) +{ + struct tifm_dev *sock = host->dev; + unsigned int dest_cnt; + + /* DMA style IO */ + dev_dbg(&sock->dev, "setting dma for %d blocks\n", + cmd->data->blocks); + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(ilog2(cmd->data->blksz) - 2, + sock->addr + SOCK_FIFO_PAGE_SIZE); + writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); + writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + + dest_cnt = (cmd->data->blocks) << 8; + + writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS); + + writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); + + if (cmd->data->flags & MMC_DATA_WRITE) { + writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, + sock->addr + SOCK_DMA_CONTROL); + } else { + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); + } +} + +static void tifm_sd_set_data_timeout(struct tifm_sd *host, + struct mmc_data *data) +{ + struct tifm_dev *sock = host->dev; + unsigned int data_timeout = data->timeout_clks; + + if (fixed_timeout) + return; + + data_timeout += data->timeout_ns / + ((1000000000UL / host->clk_freq) * host->clk_div); + + if (data_timeout < 0xffff) { + writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel((~TIFM_MMCSD_DPE) + & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); + } else { + data_timeout = (data_timeout >> 10) + 1; + if (data_timeout > 0xffff) + data_timeout = 0; /* set to unlimited */ + writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel(TIFM_MMCSD_DPE + | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); + } +} + +static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + int sg_count = 0; + struct mmc_data *r_data = mrq->cmd->data; + + spin_lock_irqsave(&sock->lock, flags); + if (host->flags & EJECT) { + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (host->req) { + printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (r_data) { + tifm_sd_set_data_timeout(host, r_data); + + sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len, + mrq->cmd->flags & MMC_DATA_WRITE + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + if (sg_count != 1) { + printk(KERN_ERR DRIVER_NAME + ": scatterlist map failed\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + host->written_blocks = 0; + host->flags &= ~CARD_BUSY; + tifm_sd_prepare_data(host, mrq->cmd); + } + + host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); + host->state = CMD; + writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + tifm_sd_exec(host, mrq->cmd); + spin_unlock_irqrestore(&sock->lock, flags); + return; + +err_out: + if (sg_count > 0) + tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, + (r_data->flags & MMC_DATA_WRITE) + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + + mrq->cmd->error = MMC_ERR_TIMEOUT; + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_end_cmd(unsigned long data) +{ + struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_dev *sock = host->dev; + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct mmc_request *mrq; + struct mmc_data *r_data = NULL; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + del_timer(&host->timer); + mrq = host->req; + host->req = NULL; + host->state = IDLE; + + if (!mrq) { + printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); + spin_unlock_irqrestore(&sock->lock, flags); + return; + } + + r_data = mrq->cmd->data; + if (r_data) { + if (r_data->flags & MMC_DATA_WRITE) { + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; + } else { + r_data->bytes_xfered = r_data->blocks - + readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; + r_data->bytes_xfered *= r_data->blksz; + r_data->bytes_xfered += r_data->blksz - + readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; + } + tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, + (r_data->flags & MMC_DATA_WRITE) + ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + } + + writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + + spin_unlock_irqrestore(&sock->lock, flags); + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + struct mmc_data *r_data = mrq->cmd->data; + + spin_lock_irqsave(&sock->lock, flags); + if (host->flags & EJECT) { + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (host->req) { + printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); + spin_unlock_irqrestore(&sock->lock, flags); + goto err_out; + } + + if (r_data) { + tifm_sd_set_data_timeout(host, r_data); + + host->buffer_size = mrq->cmd->data->blocks + * mrq->cmd->data->blksz; + + writel(TIFM_MMCSD_BUFINT + | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + sock->addr + SOCK_MMCSD_INT_ENABLE); + writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) + | (TIFM_MMCSD_FIFO_SIZE - 1), + sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + + host->written_blocks = 0; + host->flags &= ~CARD_BUSY; + host->buffer_pos = 0; + writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); + } + + host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); + host->state = CMD; + writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + tifm_sd_exec(host, mrq->cmd); + spin_unlock_irqrestore(&sock->lock, flags); + return; + +err_out: + mrq->cmd->error = MMC_ERR_TIMEOUT; + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_end_cmd_nodma(unsigned long data) +{ + struct tifm_sd *host = (struct tifm_sd*)data; + struct tifm_dev *sock = host->dev; + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct mmc_request *mrq; + struct mmc_data *r_data = NULL; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + del_timer(&host->timer); + mrq = host->req; + host->req = NULL; + host->state = IDLE; + + if (!mrq) { + printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); + spin_unlock_irqrestore(&sock->lock, flags); + return; + } + + r_data = mrq->cmd->data; + if (r_data) { + writel((~TIFM_MMCSD_BUFINT) & + readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + sock->addr + SOCK_MMCSD_INT_ENABLE); + + if (r_data->flags & MMC_DATA_WRITE) { + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; + } else { + r_data->bytes_xfered = r_data->blocks - + readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; + r_data->bytes_xfered *= r_data->blksz; + r_data->bytes_xfered += r_data->blksz - + readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; + } + host->buffer_pos = 0; + host->buffer_size = 0; + } + + writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + + spin_unlock_irqrestore(&sock->lock, flags); + + mmc_request_done(mmc, mrq); +} + +static void tifm_sd_terminate(struct tifm_sd *host) +{ + struct tifm_dev *sock = host->dev; + unsigned long flags; + + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + spin_lock_irqsave(&sock->lock, flags); + host->flags |= EJECT; + if (host->req) { + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + tasklet_schedule(&host->finish_tasklet); + } + spin_unlock_irqrestore(&sock->lock, flags); +} + +static void tifm_sd_abort(unsigned long data) +{ + struct tifm_sd *host = (struct tifm_sd*)data; + + printk(KERN_ERR DRIVER_NAME + ": card failed to respond for a long period of time"); + + tifm_sd_terminate(host); + tifm_eject(host->dev); +} + +static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned int clk_div1, clk_div2; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width, + ios->power_mode); + if (ios->bus_width == MMC_BUS_WIDTH_4) { + writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); + } else { + writel((~TIFM_MMCSD_4BBUS) + & readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); + } + + if (ios->clock) { + clk_div1 = 20000000 / ios->clock; + if (!clk_div1) + clk_div1 = 1; + + clk_div2 = 24000000 / ios->clock; + if (!clk_div2) + clk_div2 = 1; + + if ((20000000 / clk_div1) > ios->clock) + clk_div1++; + if ((24000000 / clk_div2) > ios->clock) + clk_div2++; + if ((20000000 / clk_div1) > (24000000 / clk_div2)) { + host->clk_freq = 20000000; + host->clk_div = clk_div1; + writel((~TIFM_CTRL_FAST_CLK) + & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + } else { + host->clk_freq = 24000000; + host->clk_div = clk_div2; + writel(TIFM_CTRL_FAST_CLK + | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + } + } else { + host->clk_div = 0; + } + host->clk_div &= TIFM_MMCSD_CLKMASK; + writel(host->clk_div + | ((~TIFM_MMCSD_CLKMASK) + & readl(sock->addr + SOCK_MMCSD_CONFIG)), + sock->addr + SOCK_MMCSD_CONFIG); + + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + host->flags |= OPENDRAIN; + else + host->flags &= ~OPENDRAIN; + + /* chip_select : maybe later */ + //vdd + //power is set before probe / after remove + //I believe, power_off when already marked for eject is sufficient to + // allow removal. + if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { + host->flags |= EJECT_DONE; + wake_up_all(&host->notify); + } + + spin_unlock_irqrestore(&sock->lock, flags); +} + +static int tifm_sd_ro(struct mmc_host *mmc) +{ + int rc; + struct tifm_sd *host = mmc_priv(mmc); + struct tifm_dev *sock = host->dev; + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + + host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE)); + rc = (host->flags & CARD_RO) ? 1 : 0; + + spin_unlock_irqrestore(&sock->lock, flags); + return rc; +} + +static struct mmc_host_ops tifm_sd_ops = { + .request = tifm_sd_request, + .set_ios = tifm_sd_ios, + .get_ro = tifm_sd_ro +}; + +static int tifm_sd_initialize_host(struct tifm_sd *host) +{ + int rc; + unsigned int host_status = 0; + struct tifm_dev *sock = host->dev; + + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + host->clk_div = 61; + host->clk_freq = 20000000; + writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + + /* wait up to 0.51 sec for reset */ + for (rc = 2; rc <= 256; rc <<= 1) { + if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": controller failed to reset\n"); + return -ENODEV; + } + + writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + + // command timeout fixed to 64 clocks for now + writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); + writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); + + /* INAB should take much less than reset */ + for (rc = 1; rc <= 16; rc <<= 1) { + host_status = readl(sock->addr + SOCK_MMCSD_STATUS); + writel(host_status, sock->addr + SOCK_MMCSD_STATUS); + if (!(host_status & TIFM_MMCSD_ERRMASK) + && (host_status & TIFM_MMCSD_EOC)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": card not ready - probe failed on initialization\n"); + return -ENODEV; + } + + writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, + sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + + return 0; +} + +static int tifm_sd_probe(struct tifm_dev *sock) +{ + struct mmc_host *mmc; + struct tifm_sd *host; + int rc = -EIO; + + if (!(TIFM_SOCK_STATE_OCCUPIED + & readl(sock->addr + SOCK_PRESENT_STATE))) { + printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); + return rc; + } + + mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + tifm_set_drvdata(sock, mmc); + host->dev = sock; + host->timeout_jiffies = msecs_to_jiffies(1000); + + init_waitqueue_head(&host->notify); + tasklet_init(&host->finish_tasklet, + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, + (unsigned long)host); + setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); + + tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; + mmc->ops = &tifm_sd_ops; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->f_min = 20000000 / 60; + mmc->f_max = 24000000; + mmc->max_hw_segs = 1; + mmc->max_phys_segs = 1; + // limited by DMA counter - it's safer to stick with + // block counter has 11 bits though + mmc->max_blk_count = 256; + // 2k maximum hw block length + mmc->max_blk_size = 2048; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + sock->signal_irq = tifm_sd_signal_irq; + rc = tifm_sd_initialize_host(host); + + if (!rc) + rc = mmc_add_host(mmc); + if (rc) + goto out_free_mmc; + + return 0; +out_free_mmc: + mmc_free_host(mmc); + return rc; +} + +static void tifm_sd_remove(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + + del_timer_sync(&host->timer); + tifm_sd_terminate(host); + wait_event_timeout(host->notify, host->flags & EJECT_DONE, + host->timeout_jiffies); + tasklet_kill(&host->finish_tasklet); + mmc_remove_host(mmc); + + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + + tifm_set_drvdata(sock, NULL); + mmc_free_host(mmc); +} + +#ifdef CONFIG_PM + +static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + int rc; + + rc = mmc_suspend_host(mmc, state); + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + return rc; +} + +static int tifm_sd_resume(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + + if (sock->media_id != FM_SD + || tifm_sd_initialize_host(host)) { + tifm_eject(sock); + return 0; + } else { + return mmc_resume_host(mmc); + } +} + +#else + +#define tifm_sd_suspend NULL +#define tifm_sd_resume NULL + +#endif /* CONFIG_PM */ + +static tifm_media_id tifm_sd_id_tbl[] = { + FM_SD, 0 +}; + +static struct tifm_driver tifm_sd_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE + }, + .id_table = tifm_sd_id_tbl, + .probe = tifm_sd_probe, + .remove = tifm_sd_remove, + .suspend = tifm_sd_suspend, + .resume = tifm_sd_resume +}; + +static int __init tifm_sd_init(void) +{ + return tifm_register_driver(&tifm_sd_driver); +} + +static void __exit tifm_sd_exit(void) +{ + tifm_unregister_driver(&tifm_sd_driver); +} + +MODULE_AUTHOR("Alex Dubov"); +MODULE_DESCRIPTION("TI FlashMedia SD driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl); +MODULE_VERSION(DRIVER_VERSION); + +module_init(tifm_sd_init); +module_exit(tifm_sd_exit); diff --git a/trunk/drivers/mmc/host/wbsd.c b/trunk/drivers/mmc/wbsd.c similarity index 93% rename from trunk/drivers/mmc/host/wbsd.c rename to trunk/drivers/mmc/wbsd.c index 867ca6a69298..05ccfc43168f 100644 --- a/trunk/drivers/mmc/host/wbsd.c +++ b/trunk/drivers/mmc/wbsd.c @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver * - * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -177,8 +178,9 @@ static void wbsd_init_device(struct wbsd_host *host) ier = 0; ier |= WBSD_EINT_CARD; ier |= WBSD_EINT_FIFO_THRE; - ier |= WBSD_EINT_CRC; + ier |= WBSD_EINT_CCRC; ier |= WBSD_EINT_TIMEOUT; + ier |= WBSD_EINT_CRC; ier |= WBSD_EINT_TC; outb(ier, host->base + WBSD_EIR); @@ -276,36 +278,90 @@ static inline char *wbsd_sg_to_buffer(struct wbsd_host *host) static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) { - unsigned int len, i; + unsigned int len, i, size; struct scatterlist *sg; char *dmabuf = host->dma_buffer; char *sgbuf; + size = host->size; + sg = data->sg; len = data->sg_len; + /* + * Just loop through all entries. Size might not + * be the entire list though so make sure that + * we do not transfer too much. + */ for (i = 0; i < len; i++) { sgbuf = page_address(sg[i].page) + sg[i].offset; - memcpy(dmabuf, sgbuf, sg[i].length); + if (size < sg[i].length) + memcpy(dmabuf, sgbuf, size); + else + memcpy(dmabuf, sgbuf, sg[i].length); dmabuf += sg[i].length; + + if (size < sg[i].length) + size = 0; + else + size -= sg[i].length; + + if (size == 0) + break; } + + /* + * Check that we didn't get a request to transfer + * more data than can fit into the SG list. + */ + + BUG_ON(size != 0); + + host->size -= size; } static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) { - unsigned int len, i; + unsigned int len, i, size; struct scatterlist *sg; char *dmabuf = host->dma_buffer; char *sgbuf; + size = host->size; + sg = data->sg; len = data->sg_len; + /* + * Just loop through all entries. Size might not + * be the entire list though so make sure that + * we do not transfer too much. + */ for (i = 0; i < len; i++) { sgbuf = page_address(sg[i].page) + sg[i].offset; - memcpy(sgbuf, dmabuf, sg[i].length); + if (size < sg[i].length) + memcpy(sgbuf, dmabuf, size); + else + memcpy(sgbuf, dmabuf, sg[i].length); dmabuf += sg[i].length; + + if (size < sg[i].length) + size = 0; + else + size -= sg[i].length; + + if (size == 0) + break; } + + /* + * Check that we didn't get a request to transfer + * more data than can fit into the SG list. + */ + + BUG_ON(size != 0); + + host->size -= size; } /* @@ -428,7 +484,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) /* * Handle excessive data. */ - if (host->num_sg == 0) + if (data->bytes_xfered == host->size) return; buffer = wbsd_sg_to_buffer(host) + host->offset; @@ -457,6 +513,12 @@ static void wbsd_empty_fifo(struct wbsd_host *host) data->bytes_xfered++; + /* + * Transfer done? + */ + if (data->bytes_xfered == host->size) + return; + /* * End of scatter list entry? */ @@ -464,8 +526,19 @@ static void wbsd_empty_fifo(struct wbsd_host *host) /* * Get next entry. Check if last. */ - if (!wbsd_next_sg(host)) + if (!wbsd_next_sg(host)) { + /* + * We should never reach this point. + * It means that we're trying to + * transfer more blocks than can fit + * into the scatter list. + */ + BUG_ON(1); + + host->size = data->bytes_xfered; + return; + } buffer = wbsd_sg_to_buffer(host); } @@ -477,7 +550,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) * hardware problem. The chip doesn't trigger * FIFO threshold interrupts properly. */ - if ((data->blocks * data->blksz - data->bytes_xfered) < 16) + if ((host->size - data->bytes_xfered) < 16) tasklet_schedule(&host->fifo_tasklet); } @@ -491,7 +564,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) * Check that we aren't being called after the * entire buffer has been transfered. */ - if (host->num_sg == 0) + if (data->bytes_xfered == host->size) return; buffer = wbsd_sg_to_buffer(host) + host->offset; @@ -520,6 +593,12 @@ static void wbsd_fill_fifo(struct wbsd_host *host) data->bytes_xfered++; + /* + * Transfer done? + */ + if (data->bytes_xfered == host->size) + return; + /* * End of scatter list entry? */ @@ -527,8 +606,19 @@ static void wbsd_fill_fifo(struct wbsd_host *host) /* * Get next entry. Check if last. */ - if (!wbsd_next_sg(host)) + if (!wbsd_next_sg(host)) { + /* + * We should never reach this point. + * It means that we're trying to + * transfer more blocks than can fit + * into the scatter list. + */ + BUG_ON(1); + + host->size = data->bytes_xfered; + return; + } buffer = wbsd_sg_to_buffer(host); } @@ -548,7 +638,6 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) u16 blksize; u8 setup; unsigned long dmaflags; - unsigned int size; DBGF("blksz %04x blks %04x flags %08x\n", data->blksz, data->blocks, data->flags); @@ -558,7 +647,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) /* * Calculate size. */ - size = data->blocks * data->blksz; + host->size = data->blocks * data->blksz; /* * Check timeout values for overflow. @@ -616,8 +705,8 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) /* * The buffer for DMA is only 64 kB. */ - BUG_ON(size > 0x10000); - if (size > 0x10000) { + BUG_ON(host->size > 0x10000); + if (host->size > 0x10000) { data->error = MMC_ERR_INVALID; return; } @@ -640,7 +729,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) else set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40); set_dma_addr(host->dma, host->dma_addr); - set_dma_count(host->dma, size); + set_dma_count(host->dma, host->size); enable_dma(host->dma); release_dma_lock(dmaflags); @@ -723,10 +812,6 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) count = get_dma_residue(host->dma); release_dma_lock(dmaflags); - data->bytes_xfered = host->mrq->data->blocks * - host->mrq->data->blksz - count; - data->bytes_xfered -= data->bytes_xfered % data->blksz; - /* * Any leftover data? */ @@ -735,8 +820,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) "%d bytes left.\n", mmc_hostname(host->mmc), count); - if (data->error == MMC_ERR_NONE) - data->error = MMC_ERR_FAILED; + data->error = MMC_ERR_FAILED; } else { /* * Transfer data from DMA buffer to @@ -744,11 +828,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) */ if (data->flags & MMC_DATA_READ) wbsd_dma_to_sg(host, data); - } - if (data->error != MMC_ERR_NONE) { - if (data->bytes_xfered) - data->bytes_xfered -= data->blksz; + data->bytes_xfered = host->size; } } @@ -788,7 +869,24 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) goto done; } + /* + * Does the request include data? + */ if (cmd->data) { + wbsd_prepare_data(host, cmd->data); + + if (cmd->data->error != MMC_ERR_NONE) + goto done; + } + + wbsd_send_command(host, cmd); + + /* + * If this is a data transfer the request + * will be finished after the data has + * transfered. + */ + if (cmd->data && (cmd->error == MMC_ERR_NONE)) { /* * The hardware is so delightfully stupid that it has a list * of "data" commands. If a command isn't on this list, it'll @@ -820,30 +918,14 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) "supported by this controller.\n", mmc_hostname(host->mmc), cmd->opcode); #endif - cmd->error = MMC_ERR_INVALID; - - goto done; - }; - } + cmd->data->error = MMC_ERR_INVALID; - /* - * Does the request include data? - */ - if (cmd->data) { - wbsd_prepare_data(host, cmd->data); + if (cmd->data->stop) + wbsd_send_command(host, cmd->data->stop); - if (cmd->data->error != MMC_ERR_NONE) goto done; - } - - wbsd_send_command(host, cmd); + }; - /* - * If this is a data transfer the request - * will be finished after the data has - * transfered. - */ - if (cmd->data && (cmd->error == MMC_ERR_NONE)) { /* * Dirty fix for hardware bug. */ @@ -1085,7 +1167,7 @@ static void wbsd_tasklet_fifo(unsigned long param) /* * Done? */ - if (host->num_sg == 0) { + if (host->size == data->bytes_xfered) { wbsd_write_index(host, WBSD_IDX_FIFOEN, 0); tasklet_schedule(&host->finish_tasklet); } @@ -1163,6 +1245,30 @@ static void wbsd_tasklet_finish(unsigned long param) spin_unlock(&host->lock); } +static void wbsd_tasklet_block(unsigned long param) +{ + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; + + spin_lock(&host->lock); + + if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) != + WBSD_CRC_OK) { + data = wbsd_get_data(host); + if (!data) + goto end; + + DBGF("CRC error\n"); + + data->error = MMC_ERR_BADCRC; + + tasklet_schedule(&host->finish_tasklet); + } + +end: + spin_unlock(&host->lock); +} + /* * Interrupt handling */ @@ -1193,6 +1299,8 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id) tasklet_hi_schedule(&host->crc_tasklet); if (isr & WBSD_INT_TIMEOUT) tasklet_hi_schedule(&host->timeout_tasklet); + if (isr & WBSD_INT_BUSYEND) + tasklet_hi_schedule(&host->block_tasklet); if (isr & WBSD_INT_TC) tasklet_schedule(&host->finish_tasklet); @@ -1493,6 +1601,8 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) (unsigned long)host); tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); + tasklet_init(&host->block_tasklet, wbsd_tasklet_block, + (unsigned long)host); return 0; } @@ -1511,6 +1621,7 @@ static void __devexit wbsd_release_irq(struct wbsd_host *host) tasklet_kill(&host->crc_tasklet); tasklet_kill(&host->timeout_tasklet); tasklet_kill(&host->finish_tasklet); + tasklet_kill(&host->block_tasklet); } /* diff --git a/trunk/drivers/mmc/host/wbsd.h b/trunk/drivers/mmc/wbsd.h similarity index 95% rename from trunk/drivers/mmc/host/wbsd.h rename to trunk/drivers/mmc/wbsd.h index 873bda1e59b4..d06718b0e2ab 100644 --- a/trunk/drivers/mmc/host/wbsd.h +++ b/trunk/drivers/mmc/wbsd.h @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver * - * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,10 +46,10 @@ #define WBSD_EINT_CARD 0x40 #define WBSD_EINT_FIFO_THRE 0x20 -#define WBSD_EINT_CRC 0x10 +#define WBSD_EINT_CCRC 0x10 #define WBSD_EINT_TIMEOUT 0x08 #define WBSD_EINT_PROGEND 0x04 -#define WBSD_EINT_BUSYEND 0x02 +#define WBSD_EINT_CRC 0x02 #define WBSD_EINT_TC 0x01 #define WBSD_INT_PENDING 0x80 @@ -158,6 +158,8 @@ struct wbsd_host unsigned int offset; /* Offset into current entry */ unsigned int remain; /* Data left in curren entry */ + int size; /* Total size of transfer */ + char* dma_buffer; /* ISA DMA buffer */ dma_addr_t dma_addr; /* Physical address for same */ @@ -180,6 +182,7 @@ struct wbsd_host struct tasklet_struct crc_tasklet; struct tasklet_struct timeout_tasklet; struct tasklet_struct finish_tasklet; + struct tasklet_struct block_tasklet; struct timer_list ignore_timer; /* Ignore detection timer */ }; diff --git a/trunk/drivers/mtd/Kconfig b/trunk/drivers/mtd/Kconfig index c1b47db29bd2..26f75c299440 100644 --- a/trunk/drivers/mtd/Kconfig +++ b/trunk/drivers/mtd/Kconfig @@ -1,6 +1,8 @@ # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ -menuconfig MTD +menu "Memory Technology Devices (MTD)" + +config MTD tristate "Memory Technology Device (MTD) support" help Memory Technology Devices are flash, RAM and similar chips, often @@ -11,10 +13,9 @@ menuconfig MTD them. It will also allow you to select individual drivers for particular hardware and users of MTD devices. If unsure, say N. -if MTD - config MTD_DEBUG bool "Debugging" + depends on MTD help This turns on low-level debugging for the entire MTD sub-system. Normally, you should say 'N'. @@ -28,6 +29,7 @@ config MTD_DEBUG_VERBOSE config MTD_CONCAT tristate "MTD concatenating support" + depends on MTD help Support for concatenating several MTD devices into a single (virtual) one. This allows you to have -for example- a JFFS(2) @@ -36,6 +38,7 @@ config MTD_CONCAT config MTD_PARTITIONS bool "MTD partitioning support" + depends on MTD help If you have a device which needs to divide its flash chip(s) up into multiple 'partitions', each of which appears to the user as @@ -150,9 +153,11 @@ config MTD_AFS_PARTS 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. comment "User Modules And Translation Layers" + depends on MTD config MTD_CHAR tristate "Direct char device access to MTD devices" + depends on MTD help This provides a character device for each MTD device present in the system, allowing the user to read and write directly to the @@ -161,12 +166,12 @@ config MTD_CHAR config MTD_BLKDEVS tristate "Common interface to block layer for MTD 'translation layers'" - depends on BLOCK + depends on MTD && BLOCK default n config MTD_BLOCK tristate "Caching block device access to MTD devices" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS ---help--- Although most flash chips have an erase size too large to be useful @@ -189,7 +194,7 @@ config MTD_BLOCK config MTD_BLOCK_RO tristate "Readonly block device access to MTD devices" - depends on MTD_BLOCK!=y && BLOCK + depends on MTD_BLOCK!=y && MTD && BLOCK select MTD_BLKDEVS help This allows you to mount read-only file systems (such as cramfs) @@ -201,7 +206,7 @@ config MTD_BLOCK_RO config FTL tristate "FTL (Flash Translation Layer) support" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS ---help--- This provides support for the original Flash Translation Layer which @@ -218,7 +223,7 @@ config FTL config NFTL tristate "NFTL (NAND Flash Translation Layer) support" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS ---help--- This provides support for the NAND Flash Translation Layer which is @@ -242,7 +247,7 @@ config NFTL_RW config INFTL tristate "INFTL (Inverse NAND Flash Translation Layer) support" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS ---help--- This provides support for the Inverse NAND Flash Translation @@ -260,7 +265,7 @@ config INFTL config RFD_FTL tristate "Resident Flash Disk (Flash Translation Layer) support" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS ---help--- This provides support for the flash translation layer known @@ -271,7 +276,7 @@ config RFD_FTL config SSFDC tristate "NAND SSFDC (SmartMedia) read only translation layer" - depends on BLOCK + depends on MTD && BLOCK select MTD_BLKDEVS help This enables read only access to SmartMedia formatted NAND @@ -287,6 +292,5 @@ source "drivers/mtd/nand/Kconfig" source "drivers/mtd/onenand/Kconfig" -source "drivers/mtd/ubi/Kconfig" +endmenu -endif # MTD diff --git a/trunk/drivers/mtd/Makefile b/trunk/drivers/mtd/Makefile index 92055405cb30..c130e6261adf 100644 --- a/trunk/drivers/mtd/Makefile +++ b/trunk/drivers/mtd/Makefile @@ -28,5 +28,3 @@ nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o obj-y += chips/ maps/ devices/ nand/ onenand/ - -obj-$(CONFIG_MTD_UBI) += ubi/ diff --git a/trunk/drivers/mtd/chips/Kconfig b/trunk/drivers/mtd/chips/Kconfig index d28e0fc85e12..72e6d73beb40 100644 --- a/trunk/drivers/mtd/chips/Kconfig +++ b/trunk/drivers/mtd/chips/Kconfig @@ -6,6 +6,7 @@ menu "RAM/ROM/Flash chip drivers" config MTD_CFI tristate "Detect flash chips by Common Flash Interface (CFI) probe" + depends on MTD select MTD_GEN_PROBE help The Common Flash Interface specification was developed by Intel, @@ -17,6 +18,7 @@ config MTD_CFI config MTD_JEDECPROBE tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" + depends on MTD select MTD_GEN_PROBE help This option enables JEDEC-style probing of flash chips which are not @@ -211,18 +213,21 @@ config MTD_CFI_UTIL config MTD_RAM tristate "Support for RAM chips in bus mapping" + depends on MTD help This option enables basic support for RAM chips accessed through a bus mapping driver. config MTD_ROM tristate "Support for ROM chips in bus mapping" + depends on MTD help This option enables basic support for ROM chips accessed through a bus mapping driver. config MTD_ABSENT tristate "Support for absent chips in bus mapping" + depends on MTD help This option enables support for a dummy probing driver used to allocated placeholder MTD devices on systems that have socketed @@ -232,6 +237,7 @@ config MTD_ABSENT with this driver will return -ENODEV upon access. config MTD_OBSOLETE_CHIPS + depends on MTD bool "Older (theoretically obsoleted now) drivers for non-CFI chips" help This option does not enable any code directly, but will allow you to @@ -244,7 +250,7 @@ config MTD_OBSOLETE_CHIPS config MTD_AMDSTD tristate "AMD compatible flash chip support (non-CFI)" - depends on MTD_OBSOLETE_CHIPS && BROKEN + depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN help This option enables support for flash chips using AMD-compatible commands, including some which are not CFI-compatible and hence @@ -254,7 +260,7 @@ config MTD_AMDSTD config MTD_SHARP tristate "pre-CFI Sharp chip support" - depends on MTD_OBSOLETE_CHIPS + depends on MTD && MTD_OBSOLETE_CHIPS help This option enables support for flash chips using Sharp-compatible commands, including some which are not CFI-compatible and hence @@ -262,7 +268,7 @@ config MTD_SHARP config MTD_JEDEC tristate "JEDEC device support" - depends on MTD_OBSOLETE_CHIPS && BROKEN + depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN help Enable older JEDEC flash interface devices for self programming flash. It is commonly used in older AMD chips. It is diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c index 2f19fa78d24a..f334959a335b 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c @@ -15,8 +15,6 @@ * - optimized write buffer method * 02/05/2002 Christopher Hoover / * - reworked lock/unlock/erase support for var size flash - * 21/03/2007 Rodolfo Giometti - * - auto unlock sectors on resume for auto locking flash on power up */ #include @@ -32,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -223,15 +220,6 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) } } -/* - * Some chips power-up with all sectors locked by default. - */ -static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param) -{ - printk(KERN_INFO "Using auto-unlock on power-up/resume\n" ); - mtd->flags |= MTD_STUPID_LOCK; -} - static struct cfi_fixup cfi_fixup_table[] = { #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, @@ -244,7 +232,6 @@ static struct cfi_fixup cfi_fixup_table[] = { #endif { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, - { MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, }, { 0, 0, NULL, NULL } }; @@ -473,7 +460,6 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; - mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL); } offset += (ersize * ernum); } @@ -1839,7 +1825,8 @@ static void cfi_intelext_sync (struct mtd_info *mtd) } } -static int __xipram do_getlockstatus_oneblock(struct map_info *map, +#ifdef DEBUG_LOCK_BITS +static int __xipram do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) @@ -1853,17 +1840,8 @@ static int __xipram do_getlockstatus_oneblock(struct map_info *map, chip->state = FL_JEDEC_QUERY; status = cfi_read_query(map, adr+(2*ofs_factor)); xip_enable(map, chip, 0); - return status; -} - -#ifdef DEBUG_LOCK_BITS -static int __xipram do_printlockstatus_oneblock(struct map_info *map, - struct flchip *chip, - unsigned long adr, - int len, void *thunk) -{ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", - adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk)); + adr, status); return 0; } #endif @@ -2238,45 +2216,14 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, #endif -static void cfi_intelext_save_locks(struct mtd_info *mtd) -{ - struct mtd_erase_region_info *region; - int block, status, i; - unsigned long adr; - size_t len; - - for (i = 0; i < mtd->numeraseregions; i++) { - region = &mtd->eraseregions[i]; - if (!region->lockmap) - continue; - - for (block = 0; block < region->numblocks; block++){ - len = region->erasesize; - adr = region->offset + block * len; - - status = cfi_varsize_frob(mtd, - do_getlockstatus_oneblock, adr, len, 0); - if (status) - set_bit(block, region->lockmap); - else - clear_bit(block, region->lockmap); - } - } -} - static int cfi_intelext_suspend(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; int i; struct flchip *chip; int ret = 0; - if ((mtd->flags & MTD_STUPID_LOCK) - && extp && (extp->FeatureSupport & (1 << 5))) - cfi_intelext_save_locks(mtd); - for (i=0; !ret && inumchips; i++) { chip = &cfi->chips[i]; @@ -2338,33 +2285,10 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) return ret; } -static void cfi_intelext_restore_locks(struct mtd_info *mtd) -{ - struct mtd_erase_region_info *region; - int block, i; - unsigned long adr; - size_t len; - - for (i = 0; i < mtd->numeraseregions; i++) { - region = &mtd->eraseregions[i]; - if (!region->lockmap) - continue; - - for (block = 0; block < region->numblocks; block++) { - len = region->erasesize; - adr = region->offset + block * len; - - if (!test_bit(block, region->lockmap)) - cfi_intelext_unlock(mtd, adr, len); - } - } -} - static void cfi_intelext_resume(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; int i; struct flchip *chip; @@ -2383,10 +2307,6 @@ static void cfi_intelext_resume(struct mtd_info *mtd) spin_unlock(chip->mutex); } - - if ((mtd->flags & MTD_STUPID_LOCK) - && extp && (extp->FeatureSupport & (1 << 5))) - cfi_intelext_restore_locks(mtd); } static int cfi_intelext_reset(struct mtd_info *mtd) @@ -2427,19 +2347,12 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct mtd_erase_region_info *region; - int i; cfi_intelext_reset(mtd); unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi->chips[0].priv); kfree(cfi); - for (i = 0; i < mtd->numeraseregions; i++) { - region = &mtd->eraseregions[i]; - if (region->lockmap) - kfree(region->lockmap); - } kfree(mtd->eraseregions); } diff --git a/trunk/drivers/mtd/chips/fwh_lock.h b/trunk/drivers/mtd/chips/fwh_lock.h index ab44f2b996f8..77303ce5dcf1 100644 --- a/trunk/drivers/mtd/chips/fwh_lock.h +++ b/trunk/drivers/mtd/chips/fwh_lock.h @@ -65,12 +65,11 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, return ret; } - chip->oldstate = chip->state; chip->state = xxlt->state; map_write(map, CMD(xxlt->val), adr); /* Done and happy. */ - chip->state = chip->oldstate; + chip->state = FL_READY; put_chip(map, chip, adr); spin_unlock(chip->mutex); return 0; diff --git a/trunk/drivers/mtd/devices/Kconfig b/trunk/drivers/mtd/devices/Kconfig index 690c94236d7f..440f6851da69 100644 --- a/trunk/drivers/mtd/devices/Kconfig +++ b/trunk/drivers/mtd/devices/Kconfig @@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers" config MTD_PMC551 tristate "Ramix PMC551 PCI Mezzanine RAM card support" - depends on PCI + depends on MTD && PCI ---help--- This provides a MTD device driver for the Ramix PMC551 RAM PCI card from Ramix Inc. . @@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG config MTD_MS02NV tristate "DEC MS02-NV NVRAM module support" - depends on MACH_DECSTATION + depends on MTD && MACH_DECSTATION help This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery backed-up NVRAM module. The module was originally meant as an NFS @@ -54,23 +54,15 @@ config MTD_MS02NV config MTD_DATAFLASH tristate "Support for AT45xxx DataFlash" - depends on SPI_MASTER && EXPERIMENTAL + depends on MTD && SPI_MASTER && EXPERIMENTAL help This enables access to AT45xxx DataFlash chips, using SPI. Sometimes DataFlash chips are packaged inside MMC-format cards; at this writing, the MMC stack won't handle those. -config MTD_DATAFLASH26 - tristate "AT91RM9200 DataFlash AT26xxx" - depends on MTD && ARCH_AT91RM9200 && AT91_SPI - help - This enables access to the DataFlash chip (AT26xxx) on an - AT91RM9200-based board. - If you have such a board and such a DataFlash, say 'Y'. - config MTD_M25P80 tristate "Support for M25 SPI Flash" - depends on SPI_MASTER && EXPERIMENTAL + depends on MTD && SPI_MASTER && EXPERIMENTAL help This enables access to ST M25P80 and similar SPI flash chips, used for program and data storage. Set up your spi devices @@ -78,6 +70,7 @@ config MTD_M25P80 config MTD_SLRAM tristate "Uncached system RAM" + depends on MTD help If your CPU cannot cache all of the physical memory in your machine, you can still use it for storage or swap by using this driver to @@ -85,6 +78,7 @@ config MTD_SLRAM config MTD_PHRAM tristate "Physical system RAM" + depends on MTD help This is a re-implementation of the slram driver above. @@ -94,7 +88,7 @@ config MTD_PHRAM config MTD_LART tristate "28F160xx flash driver for LART" - depends on SA1100_LART + depends on SA1100_LART && MTD help This enables the flash driver for LART. Please note that you do not need any mapping/chip driver for LART. This one does it all @@ -102,6 +96,7 @@ config MTD_LART config MTD_MTDRAM tristate "Test driver using RAM" + depends on MTD help This enables a test MTD device driver which uses vmalloc() to provide storage. You probably want to say 'N' unless you're @@ -141,7 +136,7 @@ config MTDRAM_ABS_POS config MTD_BLOCK2MTD tristate "MTD using block device" - depends on BLOCK + depends on MTD && BLOCK help This driver allows a block device to appear as an MTD. It would generally be used in the following cases: @@ -155,6 +150,7 @@ comment "Disk-On-Chip Device Drivers" config MTD_DOC2000 tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" + depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- @@ -177,6 +173,7 @@ config MTD_DOC2000 config MTD_DOC2001 tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" + depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- @@ -198,6 +195,7 @@ config MTD_DOC2001 config MTD_DOC2001PLUS tristate "M-Systems Disk-On-Chip Millennium Plus" + depends on MTD select MTD_DOCPROBE select MTD_NAND_IDS ---help--- diff --git a/trunk/drivers/mtd/devices/Makefile b/trunk/drivers/mtd/devices/Makefile index 8ab568b3f533..0f788d5c4bf8 100644 --- a/trunk/drivers/mtd/devices/Makefile +++ b/trunk/drivers/mtd/devices/Makefile @@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o -obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o obj-$(CONFIG_MTD_M25P80) += m25p80.o diff --git a/trunk/drivers/mtd/devices/at91_dataflash26.c b/trunk/drivers/mtd/devices/at91_dataflash26.c deleted file mode 100644 index 64ce37f986fc..000000000000 --- a/trunk/drivers/mtd/devices/at91_dataflash26.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) - * This is a largely modified version of at91_dataflash.c that - * supports AT26xxx dataflash chips. The original driver supports - * AT45xxx chips. - * - * Note: This driver was only tested with an AT26F004. It should be - * easy to make it work with other AT26xxx dataflash devices, though. - * - * Copyright (C) 2007 Hans J. Koch - * original Copyright (C) SAN People (Pty) Ltd - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. -*/ - -#include -#include -#include -#include - -#include - -#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ - -#define MANUFACTURER_ID_ATMEL 0x1F - -/* command codes */ - -#define AT26_OP_READ_STATUS 0x05 -#define AT26_OP_READ_DEV_ID 0x9F -#define AT26_OP_ERASE_PAGE_4K 0x20 -#define AT26_OP_READ_ARRAY_FAST 0x0B -#define AT26_OP_SEQUENTIAL_WRITE 0xAF -#define AT26_OP_WRITE_ENABLE 0x06 -#define AT26_OP_WRITE_DISABLE 0x04 -#define AT26_OP_SECTOR_PROTECT 0x36 -#define AT26_OP_SECTOR_UNPROTECT 0x39 - -/* status register bits */ - -#define AT26_STATUS_BUSY 0x01 -#define AT26_STATUS_WRITE_ENABLE 0x02 - -struct dataflash_local -{ - int spi; /* SPI chip-select number */ - unsigned int page_size; /* number of bytes per page */ -}; - - -/* Detected DataFlash devices */ -static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; -static int nr_devices = 0; - -/* Allocate a single SPI transfer descriptor. We're assuming that if multiple - SPI transfers occur at the same time, spi_access_bus() will serialize them. - If this is not valid, then either (i) each dataflash 'priv' structure - needs it's own transfer descriptor, (ii) we lock this one, or (iii) use - another mechanism. */ -static struct spi_transfer_list* spi_transfer_desc; - -/* - * Perform a SPI transfer to access the DataFlash device. - */ -static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, - char* txnext, int txnext_len, char* rxnext, int rxnext_len) -{ - struct spi_transfer_list* list = spi_transfer_desc; - - list->tx[0] = tx; list->txlen[0] = tx_len; - list->rx[0] = rx; list->rxlen[0] = rx_len; - - list->tx[1] = txnext; list->txlen[1] = txnext_len; - list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; - - list->nr_transfers = nr; - /* Note: spi_transfer() always returns 0, there are no error checks */ - return spi_transfer(list); -} - -/* - * Return the status of the DataFlash device. - */ -static unsigned char at91_dataflash26_status(void) -{ - unsigned char command[2]; - - command[0] = AT26_OP_READ_STATUS; - command[1] = 0; - - do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); - - return command[1]; -} - -/* - * Poll the DataFlash device until it is READY. - */ -static unsigned char at91_dataflash26_waitready(void) -{ - unsigned char status; - - while (1) { - status = at91_dataflash26_status(); - if (!(status & AT26_STATUS_BUSY)) - return status; - } -} - -/* - * Enable/disable write access - */ - static void at91_dataflash26_write_enable(int enable) -{ - unsigned char cmd[2]; - - DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable); - - if (enable) - cmd[0] = AT26_OP_WRITE_ENABLE; - else - cmd[0] = AT26_OP_WRITE_DISABLE; - cmd[1] = 0; - - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); -} - -/* - * Protect/unprotect sector - */ - static void at91_dataflash26_sector_protect(loff_t addr, int protect) -{ - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n", - addr, protect); - - if (protect) - cmd[0] = AT26_OP_SECTOR_PROTECT; - else - cmd[0] = AT26_OP_SECTOR_UNPROTECT; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); -} - -/* - * Erase blocks of flash. - */ -static int at91_dataflash26_erase(struct mtd_info *mtd, - struct erase_info *instr) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[4]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n", - instr->addr, instr->len); - - /* Sanity checks */ - if (priv->page_size != 4096) - return -EINVAL; /* Can't handle other sizes at the moment */ - - if ( ((instr->len % mtd->erasesize) != 0) - || ((instr->len % priv->page_size) != 0) - || ((instr->addr % priv->page_size) != 0) - || ((instr->addr + instr->len) > mtd->size)) - return -EINVAL; - - spi_access_bus(priv->spi); - - while (instr->len > 0) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(instr->addr, 0); - at91_dataflash26_write_enable(1); - cmd[0] = AT26_OP_ERASE_PAGE_4K; - cmd[1] = (instr->addr & 0x00FF0000) >> 16; - cmd[2] = (instr->addr & 0x0000FF00) >> 8; - cmd[3] = (instr->addr & 0x000000FF); - - DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x" - "0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); - at91_dataflash26_waitready(); - - instr->addr += priv->page_size; /* next page */ - instr->len -= priv->page_size; - } - - at91_dataflash26_write_enable(0); - spi_release_bus(priv->spi); - - /* Inform MTD subsystem that erase is complete */ - instr->state = MTD_ERASE_DONE; - if (instr->callback) - instr->callback(instr); - - return 0; -} - -/* - * Read from the DataFlash device. - * from : Start offset in flash device - * len : Number of bytes to read - * retlen : Number of bytes actually read - * buf : Buffer that will receive data - */ -static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned char cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n", - from, from+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (from + len > mtd->size) - return -EINVAL; - - cmd[0] = AT26_OP_READ_ARRAY_FAST; - cmd[1] = (from & 0x00FF0000) >> 16; - cmd[2] = (from & 0x0000FF00) >> 8; - cmd[3] = (from & 0x000000FF); - /* cmd[4] is a "Don't care" byte */ - - DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3]); - - spi_access_bus(priv->spi); - do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len); - spi_release_bus(priv->spi); - - *retlen = len; - return 0; -} - -/* - * Write to the DataFlash device. - * to : Start offset in flash device - * len : Number of bytes to write - * retlen : Number of bytes actually written - * buf : Buffer containing the data - */ -static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; - unsigned int addr, buf_index = 0; - int ret = -EIO, sector, last_sector; - unsigned char status, cmd[5]; - - DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len); - - *retlen = 0; - - /* Sanity checks */ - if (!len) - return 0; - if (to + len > mtd->size) - return -EINVAL; - - spi_access_bus(priv->spi); - - addr = to; - last_sector = -1; - - while (buf_index < len) { - sector = addr / priv->page_size; - /* Write first byte if a new sector begins */ - if (sector != last_sector) { - at91_dataflash26_write_enable(1); - at91_dataflash26_sector_protect(addr, 0); - at91_dataflash26_write_enable(1); - - /* Program first byte of a new sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = (addr & 0x00FF0000) >> 16; - cmd[2] = (addr & 0x0000FF00) >> 8; - cmd[3] = (addr & 0x000000FF); - cmd[4] = buf[buf_index++]; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - /* On write errors, the chip resets the write enable - flag. This also happens after the last byte of a - sector is successfully programmed. */ - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, - "write error1: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - (*retlen)++; - last_sector = sector; - } - - /* Write subsequent bytes in the same sector */ - cmd[0] = AT26_OP_SEQUENTIAL_WRITE; - cmd[1] = buf[buf_index++]; - do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); - status = at91_dataflash26_waitready(); - addr++; - - if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) - && ((addr % priv->page_size) != 0) ) { - DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, " - "status=0x%02x\n", addr, status); - goto write_err; - } - - (*retlen)++; - } - - ret = 0; - at91_dataflash26_write_enable(0); -write_err: - spi_release_bus(priv->spi); - return ret; -} - -/* - * Initialize and register DataFlash device with MTD subsystem. - */ -static int __init add_dataflash(int channel, char *name, int nr_pages, - int pagesize) -{ - struct mtd_info *device; - struct dataflash_local *priv; - - if (nr_devices >= DATAFLASH_MAX_DEVICES) { - printk(KERN_ERR "at91_dataflash26: Too many devices " - "detected\n"); - return 0; - } - - device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8, - GFP_KERNEL); - if (!device) - return -ENOMEM; - - device->name = (char *)&device[1]; - sprintf(device->name, "%s.spi%d", name, channel); - device->size = nr_pages * pagesize; - device->erasesize = pagesize; - device->owner = THIS_MODULE; - device->type = MTD_DATAFLASH; - device->flags = MTD_CAP_NORFLASH; - device->erase = at91_dataflash26_erase; - device->read = at91_dataflash26_read; - device->write = at91_dataflash26_write; - - priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local), - GFP_KERNEL); - if (!priv) { - kfree(device); - return -ENOMEM; - } - - priv->spi = channel; - priv->page_size = pagesize; - device->priv = priv; - - mtd_devices[nr_devices] = device; - nr_devices++; - printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n", - name, channel, device->size); - - return add_mtd_device(device); -} - -/* - * Detect and initialize DataFlash device connected to specified SPI channel. - * - */ - -struct dataflash26_types { - unsigned char id0; - unsigned char id1; - char *name; - int pagesize; - int nr_pages; -}; - -struct dataflash26_types df26_types[] = { - { - .id0 = 0x04, - .id1 = 0x00, - .name = "AT26F004", - .pagesize = 4096, - .nr_pages = 128, - }, - { - .id0 = 0x45, - .id1 = 0x01, - .name = "AT26DF081A", /* Not tested ! */ - .pagesize = 4096, - .nr_pages = 256, - }, -}; - -static int __init at91_dataflash26_detect(int channel) -{ - unsigned char status, cmd[5]; - int i; - - spi_access_bus(channel); - status = at91_dataflash26_status(); - - if (status == 0 || status == 0xff) { - printk(KERN_ERR "at91_dataflash26_detect: status error %d\n", - status); - spi_release_bus(channel); - return -ENODEV; - } - - cmd[0] = AT26_OP_READ_DEV_ID; - do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); - spi_release_bus(channel); - - if (cmd[1] != MANUFACTURER_ID_ATMEL) - return -ENODEV; - - for (i = 0; i < ARRAY_SIZE(df26_types); i++) { - if ( cmd[2] == df26_types[i].id0 - && cmd[3] == df26_types[i].id1) - return add_dataflash(channel, - df26_types[i].name, - df26_types[i].nr_pages, - df26_types[i].pagesize); - } - - printk(KERN_ERR "at91_dataflash26_detect: Unsupported device " - "(0x%02x/0x%02x)\n", cmd[2], cmd[3]); - return -ENODEV; -} - -static int __init at91_dataflash26_init(void) -{ - spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), - GFP_KERNEL); - if (!spi_transfer_desc) - return -ENOMEM; - - /* DataFlash (SPI chip select 0) */ - at91_dataflash26_detect(0); - -#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD - /* DataFlash card (SPI chip select 3) */ - at91_dataflash26_detect(3); -#endif - return 0; -} - -static void __exit at91_dataflash26_exit(void) -{ - int i; - - for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { - if (mtd_devices[i]) { - del_mtd_device(mtd_devices[i]); - kfree(mtd_devices[i]->priv); - kfree(mtd_devices[i]); - } - } - nr_devices = 0; - kfree(spi_transfer_desc); -} - -module_init(at91_dataflash26_init); -module_exit(at91_dataflash26_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Hans J. Koch"); -MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200"); diff --git a/trunk/drivers/mtd/devices/block2mtd.c b/trunk/drivers/mtd/devices/block2mtd.c index ce47544dc120..f9f2ce7806b0 100644 --- a/trunk/drivers/mtd/devices/block2mtd.c +++ b/trunk/drivers/mtd/devices/block2mtd.c @@ -40,9 +40,56 @@ struct block2mtd_dev { static LIST_HEAD(blkmtd_device_list); -static struct page* page_read(struct address_space *mapping, int index) +#define PAGE_READAHEAD 64 +static void cache_readahead(struct address_space *mapping, int index) { filler_t *filler = (filler_t*)mapping->a_ops->readpage; + int i, pagei; + unsigned ret = 0; + unsigned long end_index; + struct page *page; + LIST_HEAD(page_pool); + struct inode *inode = mapping->host; + loff_t isize = i_size_read(inode); + + if (!isize) { + INFO("iSize=0 in cache_readahead\n"); + return; + } + + end_index = ((isize - 1) >> PAGE_CACHE_SHIFT); + + read_lock_irq(&mapping->tree_lock); + for (i = 0; i < PAGE_READAHEAD; i++) { + pagei = index + i; + if (pagei > end_index) { + INFO("Overrun end of disk in cache readahead\n"); + break; + } + page = radix_tree_lookup(&mapping->page_tree, pagei); + if (page && (!i)) + break; + if (page) + continue; + read_unlock_irq(&mapping->tree_lock); + page = page_cache_alloc_cold(mapping); + read_lock_irq(&mapping->tree_lock); + if (!page) + break; + page->index = pagei; + list_add(&page->lru, &page_pool); + ret++; + } + read_unlock_irq(&mapping->tree_lock); + if (ret) + read_cache_pages(mapping, &page_pool, filler, NULL); +} + + +static struct page* page_readahead(struct address_space *mapping, int index) +{ + filler_t *filler = (filler_t*)mapping->a_ops->readpage; + cache_readahead(mapping, index); return read_cache_page(mapping, index, filler, NULL); } @@ -58,14 +105,14 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) u_long *max; while (pages) { - page = page_read(mapping, index); + page = page_readahead(mapping, index); if (!page) return -ENOMEM; if (IS_ERR(page)) return PTR_ERR(page); - max = page_address(page) + PAGE_SIZE; - for (p=page_address(page); pblkdev->bd_inode->i_mapping, index); + // Get page + page = page_readahead(dev->blkdev->bd_inode->i_mapping, index); if (!page) return -ENOMEM; if (IS_ERR(page)) @@ -165,7 +213,8 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, cpylen = len; // this page len = len - cpylen; - page = page_read(mapping, index); + // Get page + page = page_readahead(mapping, index); if (!page) return -ENOMEM; if (IS_ERR(page)) @@ -259,9 +308,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* We might not have rootfs mounted at this point. Try to resolve the device name by other means. */ - dev_t devt = name_to_dev_t(devname); - if (devt) { - bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); + dev_t dev = name_to_dev_t(devname); + if (dev != 0) { + bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ); } } #endif diff --git a/trunk/drivers/mtd/devices/doc2000.c b/trunk/drivers/mtd/devices/doc2000.c index c73e96bfafc6..8a0c4dec6351 100644 --- a/trunk/drivers/mtd/devices/doc2000.c +++ b/trunk/drivers/mtd/devices/doc2000.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/devices/doc2001.c b/trunk/drivers/mtd/devices/doc2001.c index 6413efc045e0..6f368aec5d5d 100644 --- a/trunk/drivers/mtd/devices/doc2001.c +++ b/trunk/drivers/mtd/devices/doc2001.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/devices/doc2001plus.c b/trunk/drivers/mtd/devices/doc2001plus.c index 2b30b587c6e8..88ba82df0fbb 100644 --- a/trunk/drivers/mtd/devices/doc2001plus.c +++ b/trunk/drivers/mtd/devices/doc2001plus.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/devices/docecc.c b/trunk/drivers/mtd/devices/docecc.c index fd8a8daba3a8..52b5d638077f 100644 --- a/trunk/drivers/mtd/devices/docecc.c +++ b/trunk/drivers/mtd/devices/docecc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/inftlmount.c b/trunk/drivers/mtd/inftlmount.c index ecac0e438f49..acf3ba223298 100644 --- a/trunk/drivers/mtd/inftlmount.c +++ b/trunk/drivers/mtd/inftlmount.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/maps/Kconfig b/trunk/drivers/mtd/maps/Kconfig index d990d8141ef5..bbf0553bdb2e 100644 --- a/trunk/drivers/mtd/maps/Kconfig +++ b/trunk/drivers/mtd/maps/Kconfig @@ -6,6 +6,7 @@ menu "Mapping drivers for chip access" config MTD_COMPLEX_MAPPINGS bool "Support non-linear mappings of flash chips" + depends on MTD help This causes the chip drivers to allow for complicated paged mappings of flash chips. @@ -68,39 +69,6 @@ config MTD_PHYSMAP_OF physically into the CPU's memory. The mapping description here is taken from OF device tree. -config MTD_PMC_MSP_EVM - tristate "CFI Flash device mapped on PMC-Sierra MSP" - depends on PMC_MSP && MTD_CFI - select MTD_PARTITIONS - help - This provides a 'mapping' driver which support the way - in which user-programmable flash chips are connected on the - PMC-Sierra MSP eval/demo boards - -choice - prompt "Maximum mappable memory avialable for flash IO" - depends on MTD_PMC_MSP_EVM - default MSP_FLASH_MAP_LIMIT_32M - -config MSP_FLASH_MAP_LIMIT_32M - bool "32M" - -endchoice - -config MSP_FLASH_MAP_LIMIT - hex - default "0x02000000" - depends on MSP_FLASH_MAP_LIMIT_32M - -config MTD_PMC_MSP_RAMROOT - tristate "Embedded RAM block device for root on PMC-Sierra MSP" - depends on PMC_MSP_EMBEDDED_ROOTFS && \ - (MTD_BLOCK || MTD_BLOCK_RO) && \ - MTD_RAM - help - This provides support for the embedded root file system - on PMC MSP devices. This memory is mapped as a MTD block device. - config MTD_SUN_UFLASH tristate "Sun Microsystems userflash support" depends on SPARC && MTD_CFI @@ -272,13 +240,13 @@ config MTD_NETtel config MTD_ALCHEMY tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support" - depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI + depends on SOC_AU1X00 help Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards config MTD_MTX1 tristate "4G Systems MTX-1 Flash device" - depends on MIPS_MTX1 && MTD_CFI + depends on MIPS && MIPS_MTX1 help Flash memory access on 4G Systems MTX-1 Board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. @@ -416,7 +384,7 @@ config MTD_TQM834x config MTD_OCELOT tristate "Momenco Ocelot boot flash device" - depends on MOMENCO_OCELOT + depends on MIPS && MOMENCO_OCELOT help 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 @@ -549,7 +517,7 @@ config MTD_OMAP_NOR # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" - depends on PCI && MTD_COMPLEX_MAPPINGS + depends on MTD && PCI && MTD_COMPLEX_MAPPINGS help 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 @@ -559,7 +527,7 @@ config MTD_PCI config MTD_PCMCIA tristate "PCMCIA MTD driver" - depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN + depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN help Map driver for accessing PCMCIA linear flash memory cards. These cards are usually around 4-16MiB in size. This does not include @@ -623,12 +591,13 @@ config MTD_BAST_MAXSIZE config MTD_SHARP_SL bool "ROM mapped on Sharp SL Series" - depends on ARCH_PXA + depends on MTD && ARCH_PXA help This enables access to the flash chip on the Sharp SL Series of PDAs. config MTD_PLATRAM tristate "Map driver for platform device RAM (mtd-ram)" + depends on MTD select MTD_RAM help Map driver for RAM areas described via the platform device diff --git a/trunk/drivers/mtd/maps/Makefile b/trunk/drivers/mtd/maps/Makefile index de036c5e6139..071d0bf922b6 100644 --- a/trunk/drivers/mtd/maps/Makefile +++ b/trunk/drivers/mtd/maps/Makefile @@ -27,8 +27,6 @@ obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o -obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o -obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o obj-$(CONFIG_MTD_PNC2000) += pnc2000.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o diff --git a/trunk/drivers/mtd/maps/alchemy-flash.c b/trunk/drivers/mtd/maps/alchemy-flash.c index 84fbe0e8c47e..7fc8097e41d2 100644 --- a/trunk/drivers/mtd/maps/alchemy-flash.c +++ b/trunk/drivers/mtd/maps/alchemy-flash.c @@ -1,7 +1,10 @@ /* * Flash memory access on AMD Alchemy evaluation boards * + * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $ + * * (C) 2003, 2004 Pete Popov + * */ #include @@ -15,6 +18,12 @@ #include +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + #ifdef CONFIG_MIPS_PB1000 #define BOARD_MAP_NAME "Pb1000 Flash" #define BOARD_FLASH_SIZE 0x00800000 /* 8MB */ diff --git a/trunk/drivers/mtd/maps/ck804xrom.c b/trunk/drivers/mtd/maps/ck804xrom.c index 688ef495888a..3d4a4d8ac789 100644 --- a/trunk/drivers/mtd/maps/ck804xrom.c +++ b/trunk/drivers/mtd/maps/ck804xrom.c @@ -338,7 +338,7 @@ static int __init init_ck804xrom(void) } return -ENXIO; #if 0 - return pci_register_driver(&ck804xrom_driver); + return pci_module_init(&ck804xrom_driver); #endif } diff --git a/trunk/drivers/mtd/maps/plat-ram.c b/trunk/drivers/mtd/maps/plat-ram.c index 894c0b271289..2b6504ecbbd1 100644 --- a/trunk/drivers/mtd/maps/plat-ram.c +++ b/trunk/drivers/mtd/maps/plat-ram.c @@ -169,8 +169,7 @@ static int platram_probe(struct platform_device *pdev) goto exit_free; } - dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res, - (unsigned long long)res->start); + dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start); /* setup map parameters */ diff --git a/trunk/drivers/mtd/maps/pmcmsp-flash.c b/trunk/drivers/mtd/maps/pmcmsp-flash.c deleted file mode 100644 index 7e0377ec1c40..000000000000 --- a/trunk/drivers/mtd/maps/pmcmsp-flash.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. - * Config with both CFI and JEDEC device support. - * - * Basically physmap.c with the addition of partitions and - * an array of mapping info to accomodate more than one flash type per board. - * - * Copyright 2005-2007 PMC-Sierra, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - - -static struct mtd_info **msp_flash; -static struct mtd_partition **msp_parts; -static struct map_info *msp_maps; -static int fcnt; - -#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__) - -int __init init_msp_flash(void) -{ - int i, j; - int offset, coff; - char *env; - int pcnt; - char flash_name[] = "flash0"; - char part_name[] = "flash0_0"; - unsigned addr, size; - - /* If ELB is disabled by "ful-mux" mode, we can't get at flash */ - if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) && - (*ELB_1PC_EN_REG & SINGLE_PCCARD)) { - printk(KERN_NOTICE "Single PC Card mode: no flash access\n"); - return -ENXIO; - } - - /* examine the prom environment for flash devices */ - for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++) - flash_name[5] = '0' + fcnt + 1; - - if (fcnt < 1) - return -ENXIO; - - printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); - msp_flash = (struct mtd_info **)kmalloc( - fcnt * sizeof(struct map_info *), GFP_KERNEL); - msp_parts = (struct mtd_partition **)kmalloc( - fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); - msp_maps = (struct map_info *)kmalloc( - fcnt * sizeof(struct mtd_info), GFP_KERNEL); - memset(msp_maps, 0, fcnt * sizeof(struct mtd_info)); - - /* loop over the flash devices, initializing each */ - for (i = 0; i < fcnt; i++) { - /* examine the prom environment for flash partititions */ - part_name[5] = '0' + i; - part_name[7] = '0'; - for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++) - part_name[7] = '0' + pcnt + 1; - - if (pcnt == 0) { - printk(KERN_NOTICE "Skipping flash device %d " - "(no partitions defined)\n", i); - continue; - } - - msp_parts[i] = (struct mtd_partition *)kmalloc( - pcnt * sizeof(struct mtd_partition), GFP_KERNEL); - memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition)); - - /* now initialize the devices proper */ - flash_name[5] = '0' + i; - env = prom_getenv(flash_name); - - if (sscanf(env, "%x:%x", &addr, &size) < 2) - return -ENXIO; - addr = CPHYSADDR(addr); - - printk(KERN_NOTICE - "MSP flash device \"%s\": 0x%08x at 0x%08x\n", - flash_name, size, addr); - /* This must matchs the actual size of the flash chip */ - msp_maps[i].size = size; - msp_maps[i].phys = addr; - - /* - * Platforms have a specific limit of the size of memory - * which may be mapped for flash: - */ - if (size > CONFIG_MSP_FLASH_MAP_LIMIT) - size = CONFIG_MSP_FLASH_MAP_LIMIT; - msp_maps[i].virt = ioremap(addr, size); - msp_maps[i].bankwidth = 1; - msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL), - flash_name, 7); - - if (msp_maps[i].virt == NULL) - return -ENXIO; - - for (j = 0; j < pcnt; j++) { - part_name[5] = '0' + i; - part_name[7] = '0' + j; - - env = prom_getenv(part_name); - - if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2) - return -ENXIO; - - msp_parts[i][j].size = size; - msp_parts[i][j].offset = offset; - msp_parts[i][j].name = env + coff; - } - - /* now probe and add the device */ - simple_map_init(&msp_maps[i]); - msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]); - if (msp_flash[i]) { - msp_flash[i]->owner = THIS_MODULE; - add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt); - } else { - printk(KERN_ERR "map probe failed for flash\n"); - return -ENXIO; - } - } - - return 0; -} - -static void __exit cleanup_msp_flash(void) -{ - int i; - - for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) { - del_mtd_partitions(msp_flash[i]); - map_destroy(msp_flash[i]); - iounmap((void *)msp_maps[i].virt); - - /* free the memory */ - kfree(msp_maps[i].name); - kfree(msp_parts[i]); - } - - kfree(msp_flash); - kfree(msp_parts); - kfree(msp_maps); -} - -MODULE_AUTHOR("PMC-Sierra, Inc"); -MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards"); -MODULE_LICENSE("GPL"); - -module_init(init_msp_flash); -module_exit(cleanup_msp_flash); diff --git a/trunk/drivers/mtd/maps/pmcmsp-ramroot.c b/trunk/drivers/mtd/maps/pmcmsp-ramroot.c deleted file mode 100644 index 18049bceba8d..000000000000 --- a/trunk/drivers/mtd/maps/pmcmsp-ramroot.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Mapping of the rootfs in a physical region of memory - * - * Copyright (C) 2005-2007 PMC-Sierra Inc. - * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -static struct mtd_info *rr_mtd; - -struct map_info rr_map = { - .name = "ramroot", - .bankwidth = 4, -}; - -static int __init init_rrmap(void) -{ - void *ramroot_start; - unsigned long ramroot_size; - - /* Check for supported rootfs types */ - if (get_ramroot(&ramroot_start, &ramroot_size)) { - rr_map.phys = CPHYSADDR(ramroot_start); - rr_map.size = ramroot_size; - - printk(KERN_NOTICE - "PMC embedded root device: 0x%08lx @ 0x%08lx\n", - rr_map.size, (unsigned long)rr_map.phys); - } else { - printk(KERN_ERR - "init_rrmap: no supported embedded rootfs detected!\n"); - return -ENXIO; - } - - /* Map rootfs to I/O space for block device driver */ - rr_map.virt = ioremap(rr_map.phys, rr_map.size); - if (!rr_map.virt) { - printk(KERN_ERR "Failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&rr_map); - - rr_mtd = do_map_probe("map_ram", &rr_map); - if (rr_mtd) { - rr_mtd->owner = THIS_MODULE; - - add_mtd_device(rr_mtd); - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index); - - return 0; - } - - iounmap(rr_map.virt); - return -ENXIO; -} - -static void __exit cleanup_rrmap(void) -{ - del_mtd_device(rr_mtd); - map_destroy(rr_mtd); - - iounmap(rr_map.virt); - rr_map.virt = NULL; -} - -MODULE_AUTHOR("PMC-Sierra, Inc"); -MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem"); -MODULE_LICENSE("GPL"); - -module_init(init_rrmap); -module_exit(cleanup_rrmap); diff --git a/trunk/drivers/mtd/maps/sun_uflash.c b/trunk/drivers/mtd/maps/sun_uflash.c index 001af7f7ddda..4db2055cee31 100644 --- a/trunk/drivers/mtd/maps/sun_uflash.c +++ b/trunk/drivers/mtd/maps/sun_uflash.c @@ -39,7 +39,7 @@ MODULE_VERSION("2.0"); static LIST_HEAD(device_list); struct uflash_dev { - const char *name; /* device name */ + char *name; /* device name */ struct map_info map; /* mtd map info */ struct mtd_info *mtd; /* mtd info */ }; @@ -80,7 +80,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) - up->map.name = (char *)up->name; + up->map.name = up->name; up->map.phys = res->start; diff --git a/trunk/drivers/mtd/mtd_blkdevs.c b/trunk/drivers/mtd/mtd_blkdevs.c index 524b83b5ebf5..b879a66daa9e 100644 --- a/trunk/drivers/mtd/mtd_blkdevs.c +++ b/trunk/drivers/mtd/mtd_blkdevs.c @@ -20,7 +20,6 @@ #include #include #include -#include #include static LIST_HEAD(blktrans_majors); @@ -29,7 +28,9 @@ extern struct mutex mtd_table_mutex; extern struct mtd_info *mtd_table[]; struct mtd_blkcore_priv { - struct task_struct *thread; + struct completion thread_dead; + int exiting; + wait_queue_head_t thread_wq; struct request_queue *rq; spinlock_t queue_lock; }; @@ -82,19 +83,38 @@ static int mtd_blktrans_thread(void *arg) /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC | PF_NOFREEZE; + daemonize("%sd", tr->name); + + /* daemonize() doesn't do this for us since some kernel threads + actually want to deal with signals. We can't just call + exit_sighand() since that'll cause an oops when we finally + do exit. */ + spin_lock_irq(¤t->sighand->siglock); + sigfillset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + spin_lock_irq(rq->queue_lock); - while (!kthread_should_stop()) { + + while (!tr->blkcore_priv->exiting) { struct request *req; struct mtd_blktrans_dev *dev; int res = 0; + DECLARE_WAITQUEUE(wait, current); req = elv_next_request(rq); if (!req) { + add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(rq->queue_lock); + schedule(); + remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); + spin_lock_irq(rq->queue_lock); + continue; } @@ -113,13 +133,13 @@ static int mtd_blktrans_thread(void *arg) } spin_unlock_irq(rq->queue_lock); - return 0; + complete_and_exit(&tr->blkcore_priv->thread_dead, 0); } static void mtd_blktrans_request(struct request_queue *rq) { struct mtd_blktrans_ops *tr = rq->queuedata; - wake_up_process(tr->blkcore_priv->thread); + wake_up(&tr->blkcore_priv->thread_wq); } @@ -368,6 +388,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) return ret; } spin_lock_init(&tr->blkcore_priv->queue_lock); + init_completion(&tr->blkcore_priv->thread_dead); + init_waitqueue_head(&tr->blkcore_priv->thread_wq); tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); if (!tr->blkcore_priv->rq) { @@ -381,14 +403,13 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); tr->blkshift = ffs(tr->blksize) - 1; - tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, - "%sd", tr->name); - if (IS_ERR(tr->blkcore_priv->thread)) { + ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL); + if (ret < 0) { blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); kfree(tr->blkcore_priv); mutex_unlock(&mtd_table_mutex); - return PTR_ERR(tr->blkcore_priv->thread); + return ret; } INIT_LIST_HEAD(&tr->devs); @@ -411,7 +432,9 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) mutex_lock(&mtd_table_mutex); /* Clean up the kernel thread */ - kthread_stop(tr->blkcore_priv->thread); + tr->blkcore_priv->exiting = 1; + wake_up(&tr->blkcore_priv->thread_wq); + wait_for_completion(&tr->blkcore_priv->thread_dead); /* Remove it from the list of active majors */ list_del(&tr->list); diff --git a/trunk/drivers/mtd/mtdchar.c b/trunk/drivers/mtd/mtdchar.c index 8c86b802f212..1592eac64e57 100644 --- a/trunk/drivers/mtd/mtdchar.c +++ b/trunk/drivers/mtd/mtdchar.c @@ -553,7 +553,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, ops.datbuf = NULL; ops.mode = MTD_OOB_PLACE; - if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) + if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs)) return -EINVAL; ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index d05873b8c155..2d12dcdd740c 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -1,7 +1,10 @@ # drivers/mtd/nand/Kconfig # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ -menuconfig MTD_NAND +menu "NAND Flash Device Drivers" + depends on MTD!=n + +config MTD_NAND tristate "NAND Device Support" depends on MTD select MTD_NAND_IDS @@ -10,10 +13,9 @@ menuconfig MTD_NAND devices. For further information see . -if MTD_NAND - config MTD_NAND_VERIFY_WRITE bool "Verify NAND page writes" + depends on MTD_NAND help This adds an extra check when data is written to the flash. The NAND flash device internally checks only bits transitioning @@ -23,61 +25,53 @@ config MTD_NAND_VERIFY_WRITE config MTD_NAND_ECC_SMC bool "NAND ECC Smart Media byte order" + depends on MTD_NAND default n help Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. -config MTD_NAND_MUSEUM_IDS - bool "Enable chip ids for obsolete ancient NAND devices" - depends on MTD_NAND - default n - help - Enable this option only when your board has first generation - NAND chips (page size 256 byte, erase size 4-8KiB). The IDs - of these chips were reused by later, larger chips. - config MTD_NAND_AUTCPU12 tristate "SmartMediaCard on autronix autcpu12 board" - depends on ARCH_AUTCPU12 + depends on MTD_NAND && ARCH_AUTCPU12 help This enables the driver for the autronix autcpu12 board to access the SmartMediaCard. config MTD_NAND_EDB7312 tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARCH_EDB7312 + depends on MTD_NAND && ARCH_EDB7312 help This enables the driver for the Cirrus Logic EBD7312 evaluation board to access the onboard NAND Flash. config MTD_NAND_H1900 tristate "iPAQ H1900 flash" - depends on ARCH_PXA && MTD_PARTITIONS + depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS help This enables the driver for the iPAQ h1900 flash. config MTD_NAND_SPIA tristate "NAND Flash device on SPIA board" - depends on ARCH_P720T + depends on ARCH_P720T && MTD_NAND help If you had to ask, you don't have one. Say 'N'. config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" - depends on MACH_AMS_DELTA + depends on MACH_AMS_DELTA && MTD_NAND help Support for NAND flash on Amstrad E3 (Delta). config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" - depends on ARCH_OMAP && BROKEN + depends on ARCH_OMAP && MTD_NAND && BROKEN help Support for NAND flash on Texas Instruments Toto platform. config MTD_NAND_TS7250 tristate "NAND Flash device on TS-7250 board" - depends on MACH_TS72XX + depends on MACH_TS72XX && MTD_NAND help Support for NAND flash on Technologic Systems TS-7250 platform. @@ -86,14 +80,14 @@ config MTD_NAND_IDS config MTD_NAND_AU1550 tristate "Au1550/1200 NAND support" - depends on SOC_AU1200 || SOC_AU1550 + depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND help This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" - depends on SH_SOLUTION_ENGINE + depends on MTD_NAND && SH_SOLUTION_ENGINE select REED_SOLOMON select REED_SOLOMON_DEC8 select BITREVERSE @@ -103,13 +97,13 @@ config MTD_NAND_RTC_FROM4 config MTD_NAND_PPCHAMELEONEVB tristate "NAND Flash device on PPChameleonEVB board" - depends on PPCHAMELEONEVB && BROKEN + depends on PPCHAMELEONEVB && MTD_NAND && BROKEN help This enables the NAND flash driver on the PPChameleon EVB Board. config MTD_NAND_S3C2410 tristate "NAND Flash support for S3C2410/S3C2440 SoC" - depends on ARCH_S3C2410 + depends on ARCH_S3C2410 && MTD_NAND help This enables the NAND flash controller on the S3C2410 and S3C2440 SoCs @@ -134,7 +128,7 @@ config MTD_NAND_S3C2410_HWECC config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" - depends on 44x + depends on MTD_NAND && 44x select MTD_NAND_ECC_SMC help NDFC Nand Flash Controllers are integrated in EP44x SoCs @@ -151,7 +145,7 @@ config MTD_NAND_S3C2410_CLKSTOP config MTD_NAND_DISKONCHIP tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on MTD_NAND && EXPERIMENTAL select REED_SOLOMON select REED_SOLOMON_DEC16 help @@ -221,11 +215,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE config MTD_NAND_SHARPSL tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on ARCH_PXA + depends on MTD_NAND && ARCH_PXA config MTD_NAND_BASLER_EXCITE tristate "Support for NAND Flash on Basler eXcite" - depends on BASLER_EXCITE + depends on MTD_NAND && BASLER_EXCITE help This enables the driver for the NAND flash device found on the Basler eXcite Smart Camera. If built as a module, the driver @@ -233,14 +227,14 @@ config MTD_NAND_BASLER_EXCITE config MTD_NAND_CAFE tristate "NAND support for OLPC CAFÉ chip" - depends on PCI + depends on MTD_NAND && PCI help Use NAND flash attached to the CAFÉ chip designed for the $100 laptop. config MTD_NAND_CS553X tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" - depends on X86_32 && (X86_PC || X86_GENERICARCH) + depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH) help The CS553x companion chips for the AMD Geode processor include NAND flash controllers with built-in hardware ECC @@ -253,21 +247,16 @@ config MTD_NAND_CS553X config MTD_NAND_AT91 bool "Support for NAND Flash / SmartMedia on AT91" - depends on ARCH_AT91 + depends on MTD_NAND && ARCH_AT91 help Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 processors. -config MTD_NAND_CM_X270 - tristate "Support for NAND Flash on CM-X270 modules" - depends on MTD_NAND && MACH_ARMCORE - - config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" - depends on MTD_PARTITIONS + depends on MTD_NAND && MTD_PARTITIONS help The simulator may simulate various NAND flash chips for the MTD nand layer. -endif # MTD_NAND +endmenu diff --git a/trunk/drivers/mtd/nand/Makefile b/trunk/drivers/mtd/nand/Makefile index 6872031a3fb2..80f1dfc77949 100644 --- a/trunk/drivers/mtd/nand/Makefile +++ b/trunk/drivers/mtd/nand/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o -obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o nand-objs := nand_base.o nand_bbt.o diff --git a/trunk/drivers/mtd/nand/cafe.c b/trunk/drivers/mtd/nand/cafe.c index c328a7514510..fd6bb3ed40df 100644 --- a/trunk/drivers/mtd/nand/cafe.c +++ b/trunk/drivers/mtd/nand/cafe.c @@ -530,6 +530,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, { struct mtd_info *mtd; struct cafe_priv *cafe; + uint32_t timing1, timing2, timing3; uint32_t ctrl; int err = 0; @@ -586,19 +587,21 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, } if (numtimings == 3) { + timing1 = timing[0]; + timing2 = timing[1]; + timing3 = timing[2]; cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n", - timing[0], timing[1], timing[2]); + timing1, timing2, timing3); } else { - timing[0] = cafe_readl(cafe, NAND_TIMING1); - timing[1] = cafe_readl(cafe, NAND_TIMING2); - timing[2] = cafe_readl(cafe, NAND_TIMING3); + timing1 = cafe_readl(cafe, NAND_TIMING1); + timing2 = cafe_readl(cafe, NAND_TIMING2); + timing3 = cafe_readl(cafe, NAND_TIMING3); - if (timing[0] | timing[1] | timing[2]) { - cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", - timing[0], timing[1], timing[2]); + if (timing1 | timing2 | timing3) { + cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3); } else { dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n"); - timing[0] = timing[1] = timing[2] = 0xffffffff; + timing1 = timing2 = timing3 = 0xffffffff; } } @@ -606,9 +609,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe_writel(cafe, 1, NAND_RESET); cafe_writel(cafe, 0, NAND_RESET); - cafe_writel(cafe, timing[0], NAND_TIMING1); - cafe_writel(cafe, timing[1], NAND_TIMING2); - cafe_writel(cafe, timing[2], NAND_TIMING3); + cafe_writel(cafe, timing1, NAND_TIMING1); + cafe_writel(cafe, timing2, NAND_TIMING2); + cafe_writel(cafe, timing3, NAND_TIMING3); cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, diff --git a/trunk/drivers/mtd/nand/cmx270_nand.c b/trunk/drivers/mtd/nand/cmx270_nand.c deleted file mode 100644 index cb663ef245d5..000000000000 --- a/trunk/drivers/mtd/nand/cmx270_nand.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * linux/drivers/mtd/nand/cmx270-nand.c - * - * Copyright (C) 2006 Compulab, Ltd. - * Mike Rapoport - * - * Derived from drivers/mtd/nand/h1910.c - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Overview: - * This is a device driver for the NAND flash device found on the - * CM-X270 board. - */ - -#include -#include - -#include -#include - -#include -#include - -#define GPIO_NAND_CS (11) -#define GPIO_NAND_RB (89) - -/* This macro needed to ensure in-order operation of GPIO and local - * bus. Without both asm command and dummy uncached read there're - * states when NAND access is broken. I've looked for such macro(s) in - * include/asm-arm but found nothing approptiate. - * dmac_clean_range is close, but is makes cache invalidation - * unnecessary here and it cannot be used in module - */ -#define DRAIN_WB() \ - do { \ - unsigned char dummy; \ - asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \ - dummy=*((unsigned char*)UNCACHED_ADDR); \ - } while(0) - -/* MTD structure for CM-X270 board */ -static struct mtd_info *cmx270_nand_mtd; - -/* remaped IO address of the device */ -static void __iomem *cmx270_nand_io; - -/* - * Define static partitions for flash device - */ -static struct mtd_partition partition_info[] = { - [0] = { - .name = "cmx270-0", - .offset = 0, - .size = MTDPART_SIZ_FULL - } -}; -#define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) - -const char *part_probes[] = { "cmdlinepart", NULL }; - -static u_char cmx270_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - - return (readl(this->IO_ADDR_R) >> 16); -} - -static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_W); -} - -static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R) >> 16; -} - -static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R) >> 16)) - return -EFAULT; - - return 0; -} - -static inline void nand_cs_on(void) -{ - GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); -} - -static void nand_cs_off(void) -{ - DRAIN_WB(); - - GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); -} - -/* - * hardware specific access to control-lines - */ -static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, - unsigned int ctrl) -{ - struct nand_chip* this = mtd->priv; - unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; - - DRAIN_WB(); - - if (ctrl & NAND_CTRL_CHANGE) { - if ( ctrl & NAND_ALE ) - nandaddr |= (1 << 3); - else - nandaddr &= ~(1 << 3); - if ( ctrl & NAND_CLE ) - nandaddr |= (1 << 2); - else - nandaddr &= ~(1 << 2); - if ( ctrl & NAND_NCE ) - nand_cs_on(); - else - nand_cs_off(); - } - - DRAIN_WB(); - this->IO_ADDR_W = (void __iomem*)nandaddr; - if (dat != NAND_CMD_NONE) - writel((dat << 16), this->IO_ADDR_W); - - DRAIN_WB(); -} - -/* - * read device ready pin - */ -static int cmx270_device_ready(struct mtd_info *mtd) -{ - DRAIN_WB(); - - return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB)); -} - -/* - * Main initialization routine - */ -static int cmx270_init(void) -{ - struct nand_chip *this; - const char *part_type; - struct mtd_partition *mtd_parts; - int mtd_parts_nb = 0; - int ret; - - /* Allocate memory for MTD device structure and private data */ - cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), - GFP_KERNEL); - if (!cmx270_nand_mtd) { - printk("Unable to allocate CM-X270 NAND MTD device structure.\n"); - return -ENOMEM; - } - - cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12); - if (!cmx270_nand_io) { - printk("Unable to ioremap NAND device\n"); - ret = -EINVAL; - goto err1; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&cmx270_nand_mtd[1]); - - /* Link the private data with the MTD structure */ - cmx270_nand_mtd->owner = THIS_MODULE; - cmx270_nand_mtd->priv = this; - - /* insert callbacks */ - this->IO_ADDR_R = cmx270_nand_io; - this->IO_ADDR_W = cmx270_nand_io; - this->cmd_ctrl = cmx270_hwcontrol; - this->dev_ready = cmx270_device_ready; - - /* 15 us command delay time */ - this->chip_delay = 20; - this->ecc.mode = NAND_ECC_SOFT; - - /* read/write functions */ - this->read_byte = cmx270_read_byte; - this->read_buf = cmx270_read_buf; - this->write_buf = cmx270_write_buf; - this->verify_buf = cmx270_verify_buf; - - /* Scan to find existence of the device */ - if (nand_scan (cmx270_nand_mtd, 1)) { - printk(KERN_NOTICE "No NAND device\n"); - ret = -ENXIO; - goto err2; - } - -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, - &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (!mtd_parts_nb) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - - /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); - if (ret) - goto err2; - - /* Return happy */ - return 0; - -err2: - iounmap(cmx270_nand_io); -err1: - kfree(cmx270_nand_mtd); - - return ret; - -} -module_init(cmx270_init); - -/* - * Clean up routine - */ -static void cmx270_cleanup(void) -{ - /* Release resources, unregister device */ - nand_release(cmx270_nand_mtd); - - iounmap(cmx270_nand_io); - - /* Free the MTD device structure */ - kfree (cmx270_nand_mtd); -} -module_exit(cmx270_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mike Rapoport "); -MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module"); diff --git a/trunk/drivers/mtd/nand/cs553x_nand.c b/trunk/drivers/mtd/nand/cs553x_nand.c index 89deff007116..8296305c8297 100644 --- a/trunk/drivers/mtd/nand/cs553x_nand.c +++ b/trunk/drivers/mtd/nand/cs553x_nand.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index 04de315e4937..6af37b8cff65 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -312,7 +312,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ chip->select_chip(mtd, chipnr); } else - page = (int)(ofs >> chip->page_shift); + page = (int)ofs; if (chip->options & NAND_BUSWIDTH_16) { chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, @@ -350,7 +350,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) int block, ret; /* Get block number */ - block = (int)(ofs >> chip->bbt_erase_shift); + block = ((int)ofs) >> chip->bbt_erase_shift; if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); @@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->buffers->ecccode; int *eccpos = chip->ecc.layout->eccpos; - chip->ecc.read_page_raw(mtd, chip, buf); + nand_read_page_raw(mtd, chip, buf); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf); + nand_write_page_raw(mtd, chip, buf); } /** diff --git a/trunk/drivers/mtd/nand/nand_ids.c b/trunk/drivers/mtd/nand/nand_ids.c index 2fc674a190cf..2e2cdf2fc91d 100644 --- a/trunk/drivers/mtd/nand/nand_ids.c +++ b/trunk/drivers/mtd/nand/nand_ids.c @@ -24,8 +24,6 @@ * 512 512 Byte page size */ struct nand_flash_dev nand_flash_ids[] = { - -#ifdef CONFIG_MTD_NAND_MUSEUM_IDS {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, @@ -41,7 +39,6 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, -#endif {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, @@ -140,7 +137,6 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, - {NAND_MFR_MICRON, "Micron"}, {0x0, "Unknown"} }; diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index 205df0f771fe..c3bca9590ad2 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -92,15 +90,6 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; static uint log = CONFIG_NANDSIM_LOG; static uint dbg = CONFIG_NANDSIM_DBG; -static unsigned long parts[MAX_MTD_DEVICES]; -static unsigned int parts_num; -static char *badblocks = NULL; -static char *weakblocks = NULL; -static char *weakpages = NULL; -static unsigned int bitflips = 0; -static char *gravepages = NULL; -static unsigned int rptwear = 0; -static unsigned int overridesize = 0; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -115,16 +104,8 @@ module_param(bus_width, uint, 0400); module_param(do_delays, uint, 0400); module_param(log, uint, 0400); module_param(dbg, uint, 0400); -module_param_array(parts, ulong, &parts_num, 0400); -module_param(badblocks, charp, 0400); -module_param(weakblocks, charp, 0400); -module_param(weakpages, charp, 0400); -module_param(bitflips, uint, 0400); -module_param(gravepages, charp, 0400); -module_param(rptwear, uint, 0400); -module_param(overridesize, uint, 0400); - -MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); + +MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); @@ -137,23 +118,6 @@ MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)"); MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); MODULE_PARM_DESC(log, "Perform logging if not zero"); MODULE_PARM_DESC(dbg, "Output debug information if not zero"); -MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); -/* Page and erase block positions for the following parameters are independent of any partitions */ -MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas"); -MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]" - " separated by commas e.g. 113:2 means eb 113" - " can be erased only twice before failing"); -MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]" - " separated by commas e.g. 1401:2 means page 1401" - " can be written only twice before failing"); -MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)"); -MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" - " separated by commas e.g. 1401:2 means page 1401" - " can be read only twice before failing"); -MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); -MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " - "The size is specified in erase blocks and as the exponent of a power of two" - " e.g. 5 means a size of 32 erase blocks"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -167,11 +131,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I #define NS_DBG(args...) \ do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) #define NS_WARN(args...) \ - do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) + do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0) #define NS_ERR(args...) \ - do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) -#define NS_INFO(args...) \ - do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0) + do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0) /* Busy-wait delay macros (microseconds, milliseconds) */ #define NS_UDELAY(us) \ @@ -276,8 +238,7 @@ union ns_mem { * The structure which describes all the internal simulator data. */ struct nandsim { - struct mtd_partition partitions[MAX_MTD_DEVICES]; - unsigned int nbparts; + struct mtd_partition part; uint busw; /* flash chip bus width (8 or 16) */ u_char ids[4]; /* chip's ID bytes */ @@ -377,38 +338,6 @@ static struct nandsim_operations { STATE_DATAOUT, STATE_READY}} }; -struct weak_block { - struct list_head list; - unsigned int erase_block_no; - unsigned int max_erases; - unsigned int erases_done; -}; - -static LIST_HEAD(weak_blocks); - -struct weak_page { - struct list_head list; - unsigned int page_no; - unsigned int max_writes; - unsigned int writes_done; -}; - -static LIST_HEAD(weak_pages); - -struct grave_page { - struct list_head list; - unsigned int page_no; - unsigned int max_reads; - unsigned int reads_done; -}; - -static LIST_HEAD(grave_pages); - -static unsigned long *erase_block_wear = NULL; -static unsigned int wear_eb_count = 0; -static unsigned long total_wear = 0; -static unsigned int rptwear_cnt = 0; - /* MTD structure for NAND controller */ static struct mtd_info *nsmtd; @@ -452,13 +381,6 @@ static void free_device(struct nandsim *ns) } } -static char *get_partition_name(int i) -{ - char buf[64]; - sprintf(buf, "NAND simulator partition %d", i); - return kstrdup(buf, GFP_KERNEL); -} - /* * Initialize the nandsim structure. * @@ -468,9 +390,7 @@ static int init_nandsim(struct mtd_info *mtd) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); - int i, ret = 0; - u_int32_t remains; - u_int32_t next_offset; + int i; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -528,40 +448,6 @@ static int init_nandsim(struct mtd_info *mtd) } } - /* Fill the partition_info structure */ - if (parts_num > ARRAY_SIZE(ns->partitions)) { - NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; - } - remains = ns->geom.totsz; - next_offset = 0; - for (i = 0; i < parts_num; ++i) { - unsigned long part = parts[i]; - if (!part || part > remains / ns->geom.secsz) { - NS_ERR("bad partition size.\n"); - ret = -EINVAL; - goto error; - } - ns->partitions[i].name = get_partition_name(i); - ns->partitions[i].offset = next_offset; - ns->partitions[i].size = part * ns->geom.secsz; - next_offset += ns->partitions[i].size; - remains -= ns->partitions[i].size; - } - ns->nbparts = parts_num; - if (remains) { - if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { - NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; - } - ns->partitions[i].name = get_partition_name(i); - ns->partitions[i].offset = next_offset; - ns->partitions[i].size = remains; - ns->nbparts += 1; - } - /* Detect how many ID bytes the NAND chip outputs */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (second_id_byte != nand_flash_ids[i].id) @@ -588,7 +474,7 @@ static int init_nandsim(struct mtd_info *mtd) printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); - if ((ret = alloc_device(ns)) != 0) + if (alloc_device(ns) != 0) goto error; /* Allocate / initialize the internal buffer */ @@ -596,17 +482,21 @@ static int init_nandsim(struct mtd_info *mtd) if (!ns->buf.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", ns->geom.pgszoob); - ret = -ENOMEM; goto error; } memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); + /* Fill the partition_info structure */ + ns->part.name = "NAND simulator partition"; + ns->part.offset = 0; + ns->part.size = ns->geom.totsz; + return 0; error: free_device(ns); - return ret; + return -ENOMEM; } /* @@ -620,287 +510,6 @@ static void free_nandsim(struct nandsim *ns) return; } -static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) -{ - char *w; - int zero_ok; - unsigned int erase_block_no; - loff_t offset; - - if (!badblocks) - return 0; - w = badblocks; - do { - zero_ok = (*w == '0' ? 1 : 0); - erase_block_no = simple_strtoul(w, &w, 0); - if (!zero_ok && !erase_block_no) { - NS_ERR("invalid badblocks.\n"); - return -EINVAL; - } - offset = erase_block_no * ns->geom.secsz; - if (mtd->block_markbad(mtd, offset)) { - NS_ERR("invalid badblocks.\n"); - return -EINVAL; - } - if (*w == ',') - w += 1; - } while (*w); - return 0; -} - -static int parse_weakblocks(void) -{ - char *w; - int zero_ok; - unsigned int erase_block_no; - unsigned int max_erases; - struct weak_block *wb; - - if (!weakblocks) - return 0; - w = weakblocks; - do { - zero_ok = (*w == '0' ? 1 : 0); - erase_block_no = simple_strtoul(w, &w, 0); - if (!zero_ok && !erase_block_no) { - NS_ERR("invalid weakblocks.\n"); - return -EINVAL; - } - max_erases = 3; - if (*w == ':') { - w += 1; - max_erases = simple_strtoul(w, &w, 0); - } - if (*w == ',') - w += 1; - wb = kzalloc(sizeof(*wb), GFP_KERNEL); - if (!wb) { - NS_ERR("unable to allocate memory.\n"); - return -ENOMEM; - } - wb->erase_block_no = erase_block_no; - wb->max_erases = max_erases; - list_add(&wb->list, &weak_blocks); - } while (*w); - return 0; -} - -static int erase_error(unsigned int erase_block_no) -{ - struct weak_block *wb; - - list_for_each_entry(wb, &weak_blocks, list) - if (wb->erase_block_no == erase_block_no) { - if (wb->erases_done >= wb->max_erases) - return 1; - wb->erases_done += 1; - return 0; - } - return 0; -} - -static int parse_weakpages(void) -{ - char *w; - int zero_ok; - unsigned int page_no; - unsigned int max_writes; - struct weak_page *wp; - - if (!weakpages) - return 0; - w = weakpages; - do { - zero_ok = (*w == '0' ? 1 : 0); - page_no = simple_strtoul(w, &w, 0); - if (!zero_ok && !page_no) { - NS_ERR("invalid weakpagess.\n"); - return -EINVAL; - } - max_writes = 3; - if (*w == ':') { - w += 1; - max_writes = simple_strtoul(w, &w, 0); - } - if (*w == ',') - w += 1; - wp = kzalloc(sizeof(*wp), GFP_KERNEL); - if (!wp) { - NS_ERR("unable to allocate memory.\n"); - return -ENOMEM; - } - wp->page_no = page_no; - wp->max_writes = max_writes; - list_add(&wp->list, &weak_pages); - } while (*w); - return 0; -} - -static int write_error(unsigned int page_no) -{ - struct weak_page *wp; - - list_for_each_entry(wp, &weak_pages, list) - if (wp->page_no == page_no) { - if (wp->writes_done >= wp->max_writes) - return 1; - wp->writes_done += 1; - return 0; - } - return 0; -} - -static int parse_gravepages(void) -{ - char *g; - int zero_ok; - unsigned int page_no; - unsigned int max_reads; - struct grave_page *gp; - - if (!gravepages) - return 0; - g = gravepages; - do { - zero_ok = (*g == '0' ? 1 : 0); - page_no = simple_strtoul(g, &g, 0); - if (!zero_ok && !page_no) { - NS_ERR("invalid gravepagess.\n"); - return -EINVAL; - } - max_reads = 3; - if (*g == ':') { - g += 1; - max_reads = simple_strtoul(g, &g, 0); - } - if (*g == ',') - g += 1; - gp = kzalloc(sizeof(*gp), GFP_KERNEL); - if (!gp) { - NS_ERR("unable to allocate memory.\n"); - return -ENOMEM; - } - gp->page_no = page_no; - gp->max_reads = max_reads; - list_add(&gp->list, &grave_pages); - } while (*g); - return 0; -} - -static int read_error(unsigned int page_no) -{ - struct grave_page *gp; - - list_for_each_entry(gp, &grave_pages, list) - if (gp->page_no == page_no) { - if (gp->reads_done >= gp->max_reads) - return 1; - gp->reads_done += 1; - return 0; - } - return 0; -} - -static void free_lists(void) -{ - struct list_head *pos, *n; - list_for_each_safe(pos, n, &weak_blocks) { - list_del(pos); - kfree(list_entry(pos, struct weak_block, list)); - } - list_for_each_safe(pos, n, &weak_pages) { - list_del(pos); - kfree(list_entry(pos, struct weak_page, list)); - } - list_for_each_safe(pos, n, &grave_pages) { - list_del(pos); - kfree(list_entry(pos, struct grave_page, list)); - } - kfree(erase_block_wear); -} - -static int setup_wear_reporting(struct mtd_info *mtd) -{ - size_t mem; - - if (!rptwear) - return 0; - wear_eb_count = mtd->size / mtd->erasesize; - mem = wear_eb_count * sizeof(unsigned long); - if (mem / sizeof(unsigned long) != wear_eb_count) { - NS_ERR("Too many erase blocks for wear reporting\n"); - return -ENOMEM; - } - erase_block_wear = kzalloc(mem, GFP_KERNEL); - if (!erase_block_wear) { - NS_ERR("Too many erase blocks for wear reporting\n"); - return -ENOMEM; - } - return 0; -} - -static void update_wear(unsigned int erase_block_no) -{ - unsigned long wmin = -1, wmax = 0, avg; - unsigned long deciles[10], decile_max[10], tot = 0; - unsigned int i; - - if (!erase_block_wear) - return; - total_wear += 1; - if (total_wear == 0) - NS_ERR("Erase counter total overflow\n"); - erase_block_wear[erase_block_no] += 1; - if (erase_block_wear[erase_block_no] == 0) - NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); - rptwear_cnt += 1; - if (rptwear_cnt < rptwear) - return; - rptwear_cnt = 0; - /* Calc wear stats */ - for (i = 0; i < wear_eb_count; ++i) { - unsigned long wear = erase_block_wear[i]; - if (wear < wmin) - wmin = wear; - if (wear > wmax) - wmax = wear; - tot += wear; - } - for (i = 0; i < 9; ++i) { - deciles[i] = 0; - decile_max[i] = (wmax * (i + 1) + 5) / 10; - } - deciles[9] = 0; - decile_max[9] = wmax; - for (i = 0; i < wear_eb_count; ++i) { - int d; - unsigned long wear = erase_block_wear[i]; - for (d = 0; d < 10; ++d) - if (wear <= decile_max[d]) { - deciles[d] += 1; - break; - } - } - avg = tot / wear_eb_count; - /* Output wear report */ - NS_INFO("*** Wear Report ***\n"); - NS_INFO("Total numbers of erases: %lu\n", tot); - NS_INFO("Number of erase blocks: %u\n", wear_eb_count); - NS_INFO("Average number of erases: %lu\n", avg); - NS_INFO("Maximum number of erases: %lu\n", wmax); - NS_INFO("Minimum number of erases: %lu\n", wmin); - for (i = 0; i < 10; ++i) { - unsigned long from = (i ? decile_max[i - 1] + 1 : 0); - if (from > decile_max[i]) - continue; - NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", - from, - decile_max[i], - deciles[i]); - } - NS_INFO("*** End of Wear Report ***\n"); -} - /* * Returns the string representation of 'state' state. */ @@ -1213,31 +822,9 @@ static void read_page(struct nandsim *ns, int num) NS_DBG("read_page: page %d not allocated\n", ns->regs.row); memset(ns->buf.byte, 0xFF, num); } else { - unsigned int page_no = ns->regs.row; NS_DBG("read_page: page %d allocated, reading from %d\n", ns->regs.row, ns->regs.column + ns->regs.off); - if (read_error(page_no)) { - int i; - memset(ns->buf.byte, 0xFF, num); - for (i = 0; i < num; ++i) - ns->buf.byte[i] = random32(); - NS_WARN("simulating read error in page %u\n", page_no); - return; - } memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); - if (bitflips && random32() < (1 << 22)) { - int flips = 1; - if (bitflips > 1) - flips = (random32() % (int) bitflips) + 1; - while (flips--) { - int pos = random32() % (num * 8); - ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); - NS_WARN("read_page: flipping bit %d in page %d " - "reading from %d ecc: corrected=%u failed=%u\n", - pos, ns->regs.row, ns->regs.column + ns->regs.off, - nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); - } - } } } @@ -1296,7 +883,6 @@ static int do_state_action(struct nandsim *ns, uint32_t action) { int num; int busdiv = ns->busw == 8 ? 1 : 2; - unsigned int erase_block_no, page_no; action &= ACTION_MASK; @@ -1356,24 +942,14 @@ static int do_state_action(struct nandsim *ns, uint32_t action) 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; ns->regs.column = 0; - erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift); - NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", ns->regs.row, NS_RAW_OFFSET(ns)); - NS_LOG("erase sector %u\n", erase_block_no); + NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); erase_sector(ns); NS_MDELAY(erase_delay); - if (erase_block_wear) - update_wear(erase_block_no); - - if (erase_error(erase_block_no)) { - NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); - return -1; - } - break; case ACTION_PRGPAGE: @@ -1396,8 +972,6 @@ static int do_state_action(struct nandsim *ns, uint32_t action) if (prog_page(ns, num) == -1) return -1; - page_no = ns->regs.row; - NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); NS_LOG("programm page %d\n", ns->regs.row); @@ -1405,11 +979,6 @@ static int do_state_action(struct nandsim *ns, uint32_t action) NS_UDELAY(programm_delay); NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); - if (write_error(page_no)) { - NS_WARN("simulating write failure in page %u\n", page_no); - return -1; - } - break; case ACTION_ZEROOFF: @@ -1934,7 +1503,7 @@ static int __init ns_init_module(void) { struct nand_chip *chip; struct nandsim *nand; - int retval = -ENOMEM, i; + int retval = -ENOMEM; if (bus_width != 8 && bus_width != 16) { NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); @@ -1964,8 +1533,6 @@ static int __init ns_init_module(void) chip->verify_buf = ns_nand_verify_buf; chip->read_word = ns_nand_read_word; chip->ecc.mode = NAND_ECC_SOFT; - /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ - /* and 'badblocks' parameters to work */ chip->options |= NAND_SKIP_BBTSCAN; /* @@ -1990,15 +1557,6 @@ static int __init ns_init_module(void) nsmtd->owner = THIS_MODULE; - if ((retval = parse_weakblocks()) != 0) - goto error; - - if ((retval = parse_weakpages()) != 0) - goto error; - - if ((retval = parse_gravepages()) != 0) - goto error; - if ((retval = nand_scan(nsmtd, 1)) != 0) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) @@ -2006,44 +1564,23 @@ static int __init ns_init_module(void) goto error; } - if (overridesize) { - u_int32_t new_size = nsmtd->erasesize << overridesize; - if (new_size >> overridesize != nsmtd->erasesize) { - NS_ERR("overridesize is too big\n"); - goto err_exit; - } - /* N.B. This relies on nand_scan not doing anything with the size before we change it */ - nsmtd->size = new_size; - chip->chipsize = new_size; - chip->chip_shift = ffs(new_size) - 1; + if ((retval = init_nandsim(nsmtd)) != 0) { + NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); + goto error; } - if ((retval = setup_wear_reporting(nsmtd)) != 0) - goto err_exit; - - if ((retval = init_nandsim(nsmtd)) != 0) - goto err_exit; - - if ((retval = parse_badblocks(nand, nsmtd)) != 0) - goto err_exit; - - if ((retval = nand_default_bbt(nsmtd)) != 0) - goto err_exit; + if ((retval = nand_default_bbt(nsmtd)) != 0) { + free_nandsim(nand); + goto error; + } - /* Register NAND partitions */ - if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) - goto err_exit; + /* Register NAND as one big partition */ + add_mtd_partitions(nsmtd, &nand->part, 1); return 0; -err_exit: - free_nandsim(nand); - nand_release(nsmtd); - for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) - kfree(nand->partitions[i].name); error: kfree(nsmtd); - free_lists(); return retval; } @@ -2056,14 +1593,10 @@ module_init(ns_init_module); static void __exit ns_cleanup_module(void) { struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); - int i; free_nandsim(ns); /* Free nandsim private resources */ - nand_release(nsmtd); /* Unregister driver */ - for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) - kfree(ns->partitions[i].name); + nand_release(nsmtd); /* Unregisterd drived */ kfree(nsmtd); /* Free other structures */ - free_lists(); } module_exit(ns_cleanup_module); @@ -2071,3 +1604,4 @@ module_exit(ns_cleanup_module); MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("Artem B. Bityuckiy"); MODULE_DESCRIPTION ("The NAND flash simulator"); + diff --git a/trunk/drivers/mtd/nftlcore.c b/trunk/drivers/mtd/nftlcore.c index 0c9ce19ea27a..e6ef7d7f9f14 100644 --- a/trunk/drivers/mtd/nftlcore.c +++ b/trunk/drivers/mtd/nftlcore.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/mtd/onenand/Kconfig b/trunk/drivers/mtd/onenand/Kconfig index c257d397d08a..373bddce8f1c 100644 --- a/trunk/drivers/mtd/onenand/Kconfig +++ b/trunk/drivers/mtd/onenand/Kconfig @@ -2,18 +2,20 @@ # linux/drivers/mtd/onenand/Kconfig # -menuconfig MTD_ONENAND +menu "OneNAND Flash Device Drivers" + depends on MTD != n + +config MTD_ONENAND tristate "OneNAND Device Support" depends on MTD help This enables support for accessing all type of OneNAND flash devices. For further information see - - -if MTD_ONENAND + . config MTD_ONENAND_VERIFY_WRITE bool "Verify OneNAND page writes" + depends on MTD_ONENAND help This adds an extra check when data is written to the flash. The OneNAND flash device internally checks only bits transitioning @@ -23,12 +25,13 @@ config MTD_ONENAND_VERIFY_WRITE config MTD_ONENAND_GENERIC tristate "OneNAND Flash device via platform device driver" - depends on ARM + depends on MTD_ONENAND && ARM help Support for OneNAND flash via platform device driver. config MTD_ONENAND_OTP bool "OneNAND OTP Support" + depends on MTD_ONENAND help One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. @@ -40,4 +43,4 @@ config MTD_ONENAND_OTP OTP block is fully-guaranteed to be a valid block. -endif # MTD_ONENAND +endmenu diff --git a/trunk/drivers/mtd/onenand/onenand_base.c b/trunk/drivers/mtd/onenand/onenand_base.c index 000794c6caf5..9e14a26ca4e8 100644 --- a/trunk/drivers/mtd/onenand/onenand_base.c +++ b/trunk/drivers/mtd/onenand/onenand_base.c @@ -836,11 +836,9 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col int readcol = column; int readend = column + thislen; int lastgap = 0; - unsigned int i; uint8_t *oob_buf = this->oob_buf; - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (free = this->ecclayout->oobfree; free->length; ++free) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) @@ -848,8 +846,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col lastgap = free->offset + free->length; } this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (free = this->ecclayout->oobfree; free->length; ++free) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); @@ -857,7 +854,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; - } else if (column == 0) + } else break; } return 0; @@ -1283,18 +1280,15 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, int writecol = column; int writeend = column + thislen; int lastgap = 0; - unsigned int i; - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (free = this->ecclayout->oobfree; free->length; ++free) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) writeend += free->offset - lastgap; lastgap = free->offset + free->length; } - free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (free = this->ecclayout->oobfree; free->length; ++free) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); @@ -1302,7 +1296,7 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; - } else if (column == 0) + } else break; } return 0; @@ -2392,8 +2386,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) * the out of band area */ this->ecclayout->oobavail = 0; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && - this->ecclayout->oobfree[i].length; i++) + for (i = 0; this->ecclayout->oobfree[i].length; i++) this->ecclayout->oobavail += this->ecclayout->oobfree[i].length; mtd->oobavail = this->ecclayout->oobavail; diff --git a/trunk/drivers/mtd/ubi/Kconfig b/trunk/drivers/mtd/ubi/Kconfig deleted file mode 100644 index b9daf159a4a7..000000000000 --- a/trunk/drivers/mtd/ubi/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -# drivers/mtd/ubi/Kconfig - -menu "UBI - Unsorted block images" - depends on MTD - -config MTD_UBI - tristate "Enable UBI" - depends on MTD - select CRC32 - help - UBI is a software layer above MTD layer which admits of LVM-like - logical volumes on top of MTD devices, hides some complexities of - flash chips like wear and bad blocks and provides some other useful - capabilities. Please, consult the MTD web site for more details - (www.linux-mtd.infradead.org). - -config MTD_UBI_WL_THRESHOLD - int "UBI wear-leveling threshold" - default 4096 - range 2 65536 - depends on MTD_UBI - help - This parameter defines the maximum difference between the highest - erase counter value and the lowest erase counter value of eraseblocks - of UBI devices. When this threshold is exceeded, UBI starts performing - wear leveling by means of moving data from eraseblock with low erase - counter to eraseblocks with high erase counter. Leave the default - value if unsure. - -config MTD_UBI_BEB_RESERVE - int "Percentage of reserved eraseblocks for bad eraseblocks handling" - default 1 - range 0 25 - depends on MTD_UBI - help - If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI - reserves some amount of physical eraseblocks to handle new bad - eraseblocks. For example, if a flash physical eraseblock becomes bad, - UBI uses these reserved physical eraseblocks to relocate the bad one. - This option specifies how many physical eraseblocks will be reserved - for bad eraseblock handling (percents of total number of good flash - eraseblocks). If the underlying flash does not admit of bad - eraseblocks (e.g. NOR flash), this value is ignored and nothing is - reserved. Leave the default value if unsure. - -config MTD_UBI_GLUEBI - bool "Emulate MTD devices" - default n - depends on MTD_UBI - help - This option enables MTD devices emulation on top of UBI volumes: for - each UBI volumes an MTD device is created, and all I/O to this MTD - device is redirected to the UBI volume. This is handy to make - MTD-oriented software (like JFFS2) work on top of UBI. Do not enable - this if no legacy software will be used. - -source "drivers/mtd/ubi/Kconfig.debug" -endmenu diff --git a/trunk/drivers/mtd/ubi/Kconfig.debug b/trunk/drivers/mtd/ubi/Kconfig.debug deleted file mode 100644 index 1e2ee22edeff..000000000000 --- a/trunk/drivers/mtd/ubi/Kconfig.debug +++ /dev/null @@ -1,104 +0,0 @@ -comment "UBI debugging options" - depends on MTD_UBI - -config MTD_UBI_DEBUG - bool "UBI debugging" - depends on SYSFS - depends on MTD_UBI - select DEBUG_FS - select KALLSYMS_ALL - help - This option enables UBI debugging. - -config MTD_UBI_DEBUG_MSG - bool "UBI debugging messages" - depends on MTD_UBI_DEBUG - default n - help - This option enables UBI debugging messages. - -config MTD_UBI_DEBUG_PARANOID - bool "Extra self-checks" - default n - depends on MTD_UBI_DEBUG - help - This option enables extra checks in UBI code. Note this slows UBI down - significantly. - -config MTD_UBI_DEBUG_DISABLE_BGT - bool "Do not enable the UBI background thread" - depends on MTD_UBI_DEBUG - default n - help - This option switches the background thread off by default. The thread - may be also be enabled/disabled via UBI sysfs. - -config MTD_UBI_DEBUG_USERSPACE_IO - bool "Direct user-space write/erase support" - default n - depends on MTD_UBI_DEBUG - help - By default, users cannot directly write and erase individual - eraseblocks of dynamic volumes, and have to use update operation - instead. This option enables this capability - it is very useful for - debugging and testing. - -config MTD_UBI_DEBUG_EMULATE_BITFLIPS - bool "Emulate flash bit-flips" - depends on MTD_UBI_DEBUG - default n - help - This option emulates bit-flips with probability 1/50, which in turn - causes scrubbing. Useful for debugging and stressing UBI. - -config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES - bool "Emulate flash write failures" - depends on MTD_UBI_DEBUG - default n - help - This option emulates write failures with probability 1/100. Useful for - debugging and testing how UBI handlines errors. - -config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES - bool "Emulate flash erase failures" - depends on MTD_UBI_DEBUG - default n - help - This option emulates erase failures with probability 1/100. Useful for - debugging and testing how UBI handlines errors. - -menu "Additional UBI debugging messages" - depends on MTD_UBI_DEBUG - -config MTD_UBI_DEBUG_MSG_BLD - bool "Additional UBI initialization and build messages" - default n - depends on MTD_UBI_DEBUG - help - This option enables detailed UBI initialization and device build - debugging messages. - -config MTD_UBI_DEBUG_MSG_EBA - bool "Eraseblock association unit messages" - default n - depends on MTD_UBI_DEBUG - help - This option enables debugging messages from the UBI eraseblock - association unit. - -config MTD_UBI_DEBUG_MSG_WL - bool "Wear-leveling unit messages" - default n - depends on MTD_UBI_DEBUG - help - This option enables debugging messages from the UBI wear-leveling - unit. - -config MTD_UBI_DEBUG_MSG_IO - bool "Input/output unit messages" - default n - depends on MTD_UBI_DEBUG - help - This option enables debugging messages from the UBI input/output unit. - -endmenu # UBI debugging messages diff --git a/trunk/drivers/mtd/ubi/Makefile b/trunk/drivers/mtd/ubi/Makefile deleted file mode 100644 index dd834e04151b..000000000000 --- a/trunk/drivers/mtd/ubi/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-$(CONFIG_MTD_UBI) += ubi.o - -ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o -ubi-y += misc.o - -ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o -ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o diff --git a/trunk/drivers/mtd/ubi/build.c b/trunk/drivers/mtd/ubi/build.c deleted file mode 100644 index 555d594d1811..000000000000 --- a/trunk/drivers/mtd/ubi/build.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (c) Nokia Corporation, 2007 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём), - * Frank Haverkamp - */ - -/* - * This file includes UBI initialization and building of UBI devices. At the - * moment UBI devices may only be added while UBI is initialized, but dynamic - * device add/remove functionality is planned. Also, at the moment we only - * attach UBI devices by scanning, which will become a bottleneck when flashes - * reach certain large size. Then one may improve UBI and add other methods. - */ - -#include -#include -#include -#include -#include -#include "ubi.h" - -/* Maximum length of the 'mtd=' parameter */ -#define MTD_PARAM_LEN_MAX 64 - -/** - * struct mtd_dev_param - MTD device parameter description data structure. - * @name: MTD device name or number string - * @vid_hdr_offs: VID header offset - * @data_offs: data offset - */ -struct mtd_dev_param -{ - char name[MTD_PARAM_LEN_MAX]; - int vid_hdr_offs; - int data_offs; -}; - -/* Numbers of elements set in the @mtd_dev_param array */ -static int mtd_devs = 0; - -/* MTD devices specification parameters */ -static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; - -/* Number of UBI devices in system */ -int ubi_devices_cnt; - -/* All UBI devices in system */ -struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; - -/* Root UBI "class" object (corresponds to '//class/ubi/') */ -struct class *ubi_class; - -/* "Show" method for files in '//class/ubi/' */ -static ssize_t ubi_version_show(struct class *class, char *buf) -{ - return sprintf(buf, "%d\n", UBI_VERSION); -} - -/* UBI version attribute ('//class/ubi/version') */ -static struct class_attribute ubi_version = - __ATTR(version, S_IRUGO, ubi_version_show, NULL); - -static ssize_t dev_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf); - -/* UBI device attributes (correspond to files in '//class/ubi/ubiX') */ -static struct device_attribute dev_eraseblock_size = - __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_avail_eraseblocks = - __ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_total_eraseblocks = - __ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_volumes_count = - __ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_max_ec = - __ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_reserved_for_bad = - __ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_bad_peb_count = - __ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_max_vol_count = - __ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_min_io_size = - __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); -static struct device_attribute dev_bgt_enabled = - __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); - -/* "Show" method for files in '//class/ubi/ubiX/' */ -static ssize_t dev_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct ubi_device *ubi; - - ubi = container_of(dev, struct ubi_device, dev); - if (attr == &dev_eraseblock_size) - return sprintf(buf, "%d\n", ubi->leb_size); - else if (attr == &dev_avail_eraseblocks) - return sprintf(buf, "%d\n", ubi->avail_pebs); - else if (attr == &dev_total_eraseblocks) - return sprintf(buf, "%d\n", ubi->good_peb_count); - else if (attr == &dev_volumes_count) - return sprintf(buf, "%d\n", ubi->vol_count); - else if (attr == &dev_max_ec) - return sprintf(buf, "%d\n", ubi->max_ec); - else if (attr == &dev_reserved_for_bad) - return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); - else if (attr == &dev_bad_peb_count) - return sprintf(buf, "%d\n", ubi->bad_peb_count); - else if (attr == &dev_max_vol_count) - return sprintf(buf, "%d\n", ubi->vtbl_slots); - else if (attr == &dev_min_io_size) - return sprintf(buf, "%d\n", ubi->min_io_size); - else if (attr == &dev_bgt_enabled) - return sprintf(buf, "%d\n", ubi->thread_enabled); - else - BUG(); - - return 0; -} - -/* Fake "release" method for UBI devices */ -static void dev_release(struct device *dev) { } - -/** - * ubi_sysfs_init - initialize sysfs for an UBI device. - * @ubi: UBI device description object - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int ubi_sysfs_init(struct ubi_device *ubi) -{ - int err; - - ubi->dev.release = dev_release; - ubi->dev.devt = MKDEV(ubi->major, 0); - ubi->dev.class = ubi_class; - sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); - err = device_register(&ubi->dev); - if (err) - goto out; - - err = device_create_file(&ubi->dev, &dev_eraseblock_size); - if (err) - goto out_unregister; - err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); - if (err) - goto out_eraseblock_size; - err = device_create_file(&ubi->dev, &dev_total_eraseblocks); - if (err) - goto out_avail_eraseblocks; - err = device_create_file(&ubi->dev, &dev_volumes_count); - if (err) - goto out_total_eraseblocks; - err = device_create_file(&ubi->dev, &dev_max_ec); - if (err) - goto out_volumes_count; - err = device_create_file(&ubi->dev, &dev_reserved_for_bad); - if (err) - goto out_volumes_max_ec; - err = device_create_file(&ubi->dev, &dev_bad_peb_count); - if (err) - goto out_reserved_for_bad; - err = device_create_file(&ubi->dev, &dev_max_vol_count); - if (err) - goto out_bad_peb_count; - err = device_create_file(&ubi->dev, &dev_min_io_size); - if (err) - goto out_max_vol_count; - err = device_create_file(&ubi->dev, &dev_bgt_enabled); - if (err) - goto out_min_io_size; - - return 0; - -out_min_io_size: - device_remove_file(&ubi->dev, &dev_min_io_size); -out_max_vol_count: - device_remove_file(&ubi->dev, &dev_max_vol_count); -out_bad_peb_count: - device_remove_file(&ubi->dev, &dev_bad_peb_count); -out_reserved_for_bad: - device_remove_file(&ubi->dev, &dev_reserved_for_bad); -out_volumes_max_ec: - device_remove_file(&ubi->dev, &dev_max_ec); -out_volumes_count: - device_remove_file(&ubi->dev, &dev_volumes_count); -out_total_eraseblocks: - device_remove_file(&ubi->dev, &dev_total_eraseblocks); -out_avail_eraseblocks: - device_remove_file(&ubi->dev, &dev_avail_eraseblocks); -out_eraseblock_size: - device_remove_file(&ubi->dev, &dev_eraseblock_size); -out_unregister: - device_unregister(&ubi->dev); -out: - ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); - return err; -} - -/** - * ubi_sysfs_close - close sysfs for an UBI device. - * @ubi: UBI device description object - */ -static void ubi_sysfs_close(struct ubi_device *ubi) -{ - device_remove_file(&ubi->dev, &dev_bgt_enabled); - device_remove_file(&ubi->dev, &dev_min_io_size); - device_remove_file(&ubi->dev, &dev_max_vol_count); - device_remove_file(&ubi->dev, &dev_bad_peb_count); - device_remove_file(&ubi->dev, &dev_reserved_for_bad); - device_remove_file(&ubi->dev, &dev_max_ec); - device_remove_file(&ubi->dev, &dev_volumes_count); - device_remove_file(&ubi->dev, &dev_total_eraseblocks); - device_remove_file(&ubi->dev, &dev_avail_eraseblocks); - device_remove_file(&ubi->dev, &dev_eraseblock_size); - device_unregister(&ubi->dev); -} - -/** - * kill_volumes - destroy all volumes. - * @ubi: UBI device description object - */ -static void kill_volumes(struct ubi_device *ubi) -{ - int i; - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) - ubi_free_volume(ubi, i); -} - -/** - * uif_init - initialize user interfaces for an UBI device. - * @ubi: UBI device description object - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int uif_init(struct ubi_device *ubi) -{ - int i, err; - dev_t dev; - - mutex_init(&ubi->vtbl_mutex); - spin_lock_init(&ubi->volumes_lock); - - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); - - /* - * Major numbers for the UBI character devices are allocated - * dynamically. Major numbers of volume character devices are - * equivalent to ones of the corresponding UBI character device. Minor - * numbers of UBI character devices are 0, while minor numbers of - * volume character devices start from 1. Thus, we allocate one major - * number and ubi->vtbl_slots + 1 minor numbers. - */ - err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); - if (err) { - ubi_err("cannot register UBI character devices"); - return err; - } - - cdev_init(&ubi->cdev, &ubi_cdev_operations); - ubi->major = MAJOR(dev); - dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); - ubi->cdev.owner = THIS_MODULE; - - dev = MKDEV(ubi->major, 0); - err = cdev_add(&ubi->cdev, dev, 1); - if (err) { - ubi_err("cannot add character device %s", ubi->ubi_name); - goto out_unreg; - } - - err = ubi_sysfs_init(ubi); - if (err) - goto out_cdev; - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) { - err = ubi_add_volume(ubi, i); - if (err) - goto out_volumes; - } - - return 0; - -out_volumes: - kill_volumes(ubi); - ubi_sysfs_close(ubi); -out_cdev: - cdev_del(&ubi->cdev); -out_unreg: - unregister_chrdev_region(MKDEV(ubi->major, 0), - ubi->vtbl_slots + 1); - return err; -} - -/** - * uif_close - close user interfaces for an UBI device. - * @ubi: UBI device description object - */ -static void uif_close(struct ubi_device *ubi) -{ - kill_volumes(ubi); - ubi_sysfs_close(ubi); - cdev_del(&ubi->cdev); - unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); -} - -/** - * attach_by_scanning - attach an MTD device using scanning method. - * @ubi: UBI device descriptor - * - * This function returns zero in case of success and a negative error code in - * case of failure. - * - * Note, currently this is the only method to attach UBI devices. Hopefully in - * the future we'll have more scalable attaching methods and avoid full media - * scanning. But even in this case scanning will be needed as a fall-back - * attaching method if there are some on-flash table corruptions. - */ -static int attach_by_scanning(struct ubi_device *ubi) -{ - int err; - struct ubi_scan_info *si; - - si = ubi_scan(ubi); - if (IS_ERR(si)) - return PTR_ERR(si); - - ubi->bad_peb_count = si->bad_peb_count; - ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count; - ubi->max_ec = si->max_ec; - ubi->mean_ec = si->mean_ec; - - err = ubi_read_volume_table(ubi, si); - if (err) - goto out_si; - - err = ubi_wl_init_scan(ubi, si); - if (err) - goto out_vtbl; - - err = ubi_eba_init_scan(ubi, si); - if (err) - goto out_wl; - - ubi_scan_destroy_si(si); - return 0; - -out_wl: - ubi_wl_close(ubi); -out_vtbl: - kfree(ubi->vtbl); -out_si: - ubi_scan_destroy_si(si); - return err; -} - -/** - * io_init - initialize I/O unit for a given UBI device. - * @ubi: UBI device description object - * - * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are - * assumed: - * o EC header is always at offset zero - this cannot be changed; - * o VID header starts just after the EC header at the closest address - * aligned to @io->@hdrs_min_io_size; - * o data starts just after the VID header at the closest address aligned to - * @io->@min_io_size - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int io_init(struct ubi_device *ubi) -{ - if (ubi->mtd->numeraseregions != 0) { - /* - * Some flashes have several erase regions. Different regions - * may have different eraseblock size and other - * characteristics. It looks like mostly multi-region flashes - * have one "main" region and one or more small regions to - * store boot loader code or boot parameters or whatever. I - * guess we should just pick the largest region. But this is - * not implemented. - */ - ubi_err("multiple regions, not implemented"); - return -EINVAL; - } - - /* - * Note, in this implementation we support MTD devices with 0x7FFFFFFF - * physical eraseblocks maximum. - */ - - ubi->peb_size = ubi->mtd->erasesize; - ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; - ubi->flash_size = ubi->mtd->size; - - if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) - ubi->bad_allowed = 1; - - ubi->min_io_size = ubi->mtd->writesize; - ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; - - /* Make sure minimal I/O unit is power of 2 */ - if (ubi->min_io_size == 0 || - (ubi->min_io_size & (ubi->min_io_size - 1))) { - ubi_err("bad min. I/O unit"); - return -EINVAL; - } - - ubi_assert(ubi->hdrs_min_io_size > 0); - ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size); - ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0); - - /* Calculate default aligned sizes of EC and VID headers */ - ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); - ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); - - dbg_msg("min_io_size %d", ubi->min_io_size); - dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size); - dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize); - dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize); - - if (ubi->vid_hdr_offset == 0) - /* Default offset */ - ubi->vid_hdr_offset = ubi->vid_hdr_aloffset = - ubi->ec_hdr_alsize; - else { - ubi->vid_hdr_aloffset = ubi->vid_hdr_offset & - ~(ubi->hdrs_min_io_size - 1); - ubi->vid_hdr_shift = ubi->vid_hdr_offset - - ubi->vid_hdr_aloffset; - } - - /* Similar for the data offset */ - if (ubi->leb_start == 0) { - ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; - ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); - } - - dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); - dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); - dbg_msg("vid_hdr_shift %d", ubi->vid_hdr_shift); - dbg_msg("leb_start %d", ubi->leb_start); - - /* The shift must be aligned to 32-bit boundary */ - if (ubi->vid_hdr_shift % 4) { - ubi_err("unaligned VID header shift %d", - ubi->vid_hdr_shift); - return -EINVAL; - } - - /* Check sanity */ - if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE || - ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || - ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || - ubi->leb_start % ubi->min_io_size) { - ubi_err("bad VID header (%d) or data offsets (%d)", - ubi->vid_hdr_offset, ubi->leb_start); - return -EINVAL; - } - - /* - * It may happen that EC and VID headers are situated in one minimal - * I/O unit. In this case we can only accept this UBI image in - * read-only mode. - */ - if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { - ubi_warn("EC and VID headers are in the same minimal I/O unit, " - "switch to read-only mode"); - ubi->ro_mode = 1; - } - - ubi->leb_size = ubi->peb_size - ubi->leb_start; - - if (!(ubi->mtd->flags & MTD_WRITEABLE)) { - ubi_msg("MTD device %d is write-protected, attach in " - "read-only mode", ubi->mtd->index); - ubi->ro_mode = 1; - } - - dbg_msg("leb_size %d", ubi->leb_size); - dbg_msg("ro_mode %d", ubi->ro_mode); - - /* - * Note, ideally, we have to initialize ubi->bad_peb_count here. But - * unfortunately, MTD does not provide this information. We should loop - * over all physical eraseblocks and invoke mtd->block_is_bad() for - * each physical eraseblock. So, we skip ubi->bad_peb_count - * uninitialized and initialize it after scanning. - */ - - return 0; -} - -/** - * attach_mtd_dev - attach an MTD device. - * @mtd_dev: MTD device name or number string - * @vid_hdr_offset: VID header offset - * @data_offset: data offset - * - * This function attaches an MTD device to UBI. It first treats @mtd_dev as the - * MTD device name, and tries to open it by this name. If it is unable to open, - * it tries to convert @mtd_dev to an integer and open the MTD device by its - * number. Returns zero in case of success and a negative error code in case of - * failure. - */ -static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, - int data_offset) -{ - struct ubi_device *ubi; - struct mtd_info *mtd; - int i, err; - - mtd = get_mtd_device_nm(mtd_dev); - if (IS_ERR(mtd)) { - int mtd_num; - char *endp; - - if (PTR_ERR(mtd) != -ENODEV) - return PTR_ERR(mtd); - - /* - * Probably this is not MTD device name but MTD device number - - * check this out. - */ - mtd_num = simple_strtoul(mtd_dev, &endp, 0); - if (*endp != '\0' || mtd_dev == endp) { - ubi_err("incorrect MTD device: \"%s\"", mtd_dev); - return -ENODEV; - } - - mtd = get_mtd_device(NULL, mtd_num); - if (IS_ERR(mtd)) - return PTR_ERR(mtd); - } - - /* Check if we already have the same MTD device attached */ - for (i = 0; i < ubi_devices_cnt; i++) - if (ubi_devices[i]->mtd->index == mtd->index) { - ubi_err("mtd%d is already attached to ubi%d", - mtd->index, i); - err = -EINVAL; - goto out_mtd; - } - - ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), - GFP_KERNEL); - if (!ubi) { - err = -ENOMEM; - goto out_mtd; - } - - ubi->ubi_num = ubi_devices_cnt; - ubi->mtd = mtd; - - dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", - ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset); - - ubi->vid_hdr_offset = vid_hdr_offset; - ubi->leb_start = data_offset; - err = io_init(ubi); - if (err) - goto out_free; - - err = attach_by_scanning(ubi); - if (err) { - dbg_err("failed to attach by scanning, error %d", err); - goto out_free; - } - - err = uif_init(ubi); - if (err) - goto out_detach; - - ubi_devices_cnt += 1; - - ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); - ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); - ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); - ubi_msg("physical eraseblock size: %d bytes (%d KiB)", - ubi->peb_size, ubi->peb_size >> 10); - ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); - ubi_msg("number of good PEBs: %d", ubi->good_peb_count); - ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); - ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); - ubi_msg("VID header offset: %d (aligned %d)", - ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); - ubi_msg("data offset: %d", ubi->leb_start); - ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); - ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); - ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); - ubi_msg("number of user volumes: %d", - ubi->vol_count - UBI_INT_VOL_COUNT); - ubi_msg("available PEBs: %d", ubi->avail_pebs); - ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs); - ubi_msg("number of PEBs reserved for bad PEB handling: %d", - ubi->beb_rsvd_pebs); - ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); - - /* Enable the background thread */ - if (!DBG_DISABLE_BGT) { - ubi->thread_enabled = 1; - wake_up_process(ubi->bgt_thread); - } - - return 0; - -out_detach: - ubi_eba_close(ubi); - ubi_wl_close(ubi); - kfree(ubi->vtbl); -out_free: - kfree(ubi); -out_mtd: - put_mtd_device(mtd); - ubi_devices[ubi_devices_cnt] = NULL; - return err; -} - -/** - * detach_mtd_dev - detach an MTD device. - * @ubi: UBI device description object - */ -static void detach_mtd_dev(struct ubi_device *ubi) -{ - int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; - - dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); - uif_close(ubi); - ubi_eba_close(ubi); - ubi_wl_close(ubi); - kfree(ubi->vtbl); - put_mtd_device(ubi->mtd); - kfree(ubi_devices[ubi_num]); - ubi_devices[ubi_num] = NULL; - ubi_devices_cnt -= 1; - ubi_assert(ubi_devices_cnt >= 0); - ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); -} - -static int __init ubi_init(void) -{ - int err, i, k; - - /* Ensure that EC and VID headers have correct size */ - BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64); - BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); - - if (mtd_devs > UBI_MAX_DEVICES) { - printk("UBI error: too many MTD devices, maximum is %d\n", - UBI_MAX_DEVICES); - return -EINVAL; - } - - ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); - if (IS_ERR(ubi_class)) - return PTR_ERR(ubi_class); - - err = class_create_file(ubi_class, &ubi_version); - if (err) - goto out_class; - - /* Attach MTD devices */ - for (i = 0; i < mtd_devs; i++) { - struct mtd_dev_param *p = &mtd_dev_param[i]; - - cond_resched(); - - if (!p->name) { - dbg_err("empty name"); - err = -EINVAL; - goto out_detach; - } - - err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); - if (err) - goto out_detach; - } - - return 0; - -out_detach: - for (k = 0; k < i; k++) - detach_mtd_dev(ubi_devices[k]); - class_remove_file(ubi_class, &ubi_version); -out_class: - class_destroy(ubi_class); - return err; -} -module_init(ubi_init); - -static void __exit ubi_exit(void) -{ - int i, n = ubi_devices_cnt; - - for (i = 0; i < n; i++) - detach_mtd_dev(ubi_devices[i]); - class_remove_file(ubi_class, &ubi_version); - class_destroy(ubi_class); -} -module_exit(ubi_exit); - -/** - * bytes_str_to_int - convert a string representing number of bytes to an - * integer. - * @str: the string to convert - * - * This function returns positive resulting integer in case of success and a - * negative error code in case of failure. - */ -static int __init bytes_str_to_int(const char *str) -{ - char *endp; - unsigned long result; - - result = simple_strtoul(str, &endp, 0); - if (str == endp || result < 0) { - printk("UBI error: incorrect bytes count: \"%s\"\n", str); - return -EINVAL; - } - - switch (*endp) { - case 'G': - result *= 1024; - case 'M': - result *= 1024; - case 'K': - case 'k': - result *= 1024; - if (endp[1] == 'i' && (endp[2] == '\0' || - endp[2] == 'B' || endp[2] == 'b')) - endp += 2; - case '\0': - break; - default: - printk("UBI error: incorrect bytes count: \"%s\"\n", str); - return -EINVAL; - } - - return result; -} - -/** - * ubi_mtd_param_parse - parse the 'mtd=' UBI parameter. - * @val: the parameter value to parse - * @kp: not used - * - * This function returns zero in case of success and a negative error code in - * case of error. - */ -static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) -{ - int i, len; - struct mtd_dev_param *p; - char buf[MTD_PARAM_LEN_MAX]; - char *pbuf = &buf[0]; - char *tokens[3] = {NULL, NULL, NULL}; - - if (mtd_devs == UBI_MAX_DEVICES) { - printk("UBI error: too many parameters, max. is %d\n", - UBI_MAX_DEVICES); - return -EINVAL; - } - - len = strnlen(val, MTD_PARAM_LEN_MAX); - if (len == MTD_PARAM_LEN_MAX) { - printk("UBI error: parameter \"%s\" is too long, max. is %d\n", - val, MTD_PARAM_LEN_MAX); - return -EINVAL; - } - - if (len == 0) { - printk("UBI warning: empty 'mtd=' parameter - ignored\n"); - return 0; - } - - strcpy(buf, val); - - /* Get rid of the final newline */ - if (buf[len - 1] == '\n') - buf[len - 1] = 0; - - for (i = 0; i < 3; i++) - tokens[i] = strsep(&pbuf, ","); - - if (pbuf) { - printk("UBI error: too many arguments at \"%s\"\n", val); - return -EINVAL; - } - - if (tokens[0] == '\0') - return -EINVAL; - - p = &mtd_dev_param[mtd_devs]; - strcpy(&p->name[0], tokens[0]); - - if (tokens[1]) - p->vid_hdr_offs = bytes_str_to_int(tokens[1]); - if (tokens[2]) - p->data_offs = bytes_str_to_int(tokens[2]); - - if (p->vid_hdr_offs < 0) - return p->vid_hdr_offs; - if (p->data_offs < 0) - return p->data_offs; - - mtd_devs += 1; - return 0; -} - -module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); -MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " - "mtd=[,,]. " - "Multiple \"mtd\" parameters may be specified.\n" - "MTD devices may be specified by their number or name. " - "Optional \"vid_hdr_offs\" and \"data_offs\" parameters " - "specify UBI VID header position and data starting " - "position to be used by UBI.\n" - "Example: mtd=content,1984,2048 mtd=4 - attach MTD device" - "with name content using VID header offset 1984 and data " - "start 2048, and MTD device number 4 using default " - "offsets"); - -MODULE_VERSION(__stringify(UBI_VERSION)); -MODULE_DESCRIPTION("UBI - Unsorted Block Images"); -MODULE_AUTHOR("Artem Bityutskiy"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/ubi/cdev.c b/trunk/drivers/mtd/ubi/cdev.c deleted file mode 100644 index 6612eb79bf17..000000000000 --- a/trunk/drivers/mtd/ubi/cdev.c +++ /dev/null @@ -1,722 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * This file includes implementation of UBI character device operations. - * - * There are two kinds of character devices in UBI: UBI character devices and - * UBI volume character devices. UBI character devices allow users to - * manipulate whole volumes: create, remove, and re-size them. Volume character - * devices provide volume I/O capabilities. - * - * Major and minor numbers are assigned dynamically to both UBI and volume - * character devices. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ubi.h" - -/* - * Maximum sequence numbers of UBI and volume character device IOCTLs (direct - * logical eraseblock erase is a debug-only feature). - */ -#define UBI_CDEV_IOC_MAX_SEQ 2 -#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO -#define VOL_CDEV_IOC_MAX_SEQ 1 -#else -#define VOL_CDEV_IOC_MAX_SEQ 2 -#endif - -/** - * major_to_device - get UBI device object by character device major number. - * @major: major number - * - * This function returns a pointer to the UBI device object. - */ -static struct ubi_device *major_to_device(int major) -{ - int i; - - for (i = 0; i < ubi_devices_cnt; i++) - if (ubi_devices[i] && ubi_devices[i]->major == major) - return ubi_devices[i]; - BUG(); -} - -/** - * get_exclusive - get exclusive access to an UBI volume. - * @desc: volume descriptor - * - * This function changes UBI volume open mode to "exclusive". Returns previous - * mode value (positive integer) in case of success and a negative error code - * in case of failure. - */ -static int get_exclusive(struct ubi_volume_desc *desc) -{ - int users, err; - struct ubi_volume *vol = desc->vol; - - spin_lock(&vol->ubi->volumes_lock); - users = vol->readers + vol->writers + vol->exclusive; - ubi_assert(users > 0); - if (users > 1) { - dbg_err("%d users for volume %d", users, vol->vol_id); - err = -EBUSY; - } else { - vol->readers = vol->writers = 0; - vol->exclusive = 1; - err = desc->mode; - desc->mode = UBI_EXCLUSIVE; - } - spin_unlock(&vol->ubi->volumes_lock); - - return err; -} - -/** - * revoke_exclusive - revoke exclusive mode. - * @desc: volume descriptor - * @mode: new mode to switch to - */ -static void revoke_exclusive(struct ubi_volume_desc *desc, int mode) -{ - struct ubi_volume *vol = desc->vol; - - spin_lock(&vol->ubi->volumes_lock); - ubi_assert(vol->readers == 0 && vol->writers == 0); - ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE); - vol->exclusive = 0; - if (mode == UBI_READONLY) - vol->readers = 1; - else if (mode == UBI_READWRITE) - vol->writers = 1; - else - vol->exclusive = 1; - spin_unlock(&vol->ubi->volumes_lock); - - desc->mode = mode; -} - -static int vol_cdev_open(struct inode *inode, struct file *file) -{ - struct ubi_volume_desc *desc; - const struct ubi_device *ubi = major_to_device(imajor(inode)); - int vol_id = iminor(inode) - 1; - int mode; - - if (file->f_mode & FMODE_WRITE) - mode = UBI_READWRITE; - else - mode = UBI_READONLY; - - dbg_msg("open volume %d, mode %d", vol_id, mode); - - desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - file->private_data = desc; - return 0; -} - -static int vol_cdev_release(struct inode *inode, struct file *file) -{ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - - dbg_msg("release volume %d, mode %d", vol->vol_id, desc->mode); - - if (vol->updating) { - ubi_warn("update of volume %d not finished, volume is damaged", - vol->vol_id); - vol->updating = 0; - kfree(vol->upd_buf); - } - - ubi_close_volume(desc); - return 0; -} - -static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) -{ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - loff_t new_offset; - - if (vol->updating) { - /* Update is in progress, seeking is prohibited */ - dbg_err("updating"); - return -EBUSY; - } - - switch (origin) { - case 0: /* SEEK_SET */ - new_offset = offset; - break; - case 1: /* SEEK_CUR */ - new_offset = file->f_pos + offset; - break; - case 2: /* SEEK_END */ - new_offset = vol->used_bytes + offset; - break; - default: - return -EINVAL; - } - - if (new_offset < 0 || new_offset > vol->used_bytes) { - dbg_err("bad seek %lld", new_offset); - return -EINVAL; - } - - dbg_msg("seek volume %d, offset %lld, origin %d, new offset %lld", - vol->vol_id, offset, origin, new_offset); - - file->f_pos = new_offset; - return new_offset; -} - -static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, - loff_t *offp) -{ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; - size_t count_save = count; - void *tbuf; - uint64_t tmp; - - dbg_msg("read %zd bytes from offset %lld of volume %d", - count, *offp, vol_id); - - if (vol->updating) { - dbg_err("updating"); - return -EBUSY; - } - if (vol->upd_marker) { - dbg_err("damaged volume, update marker is set"); - return -EBADF; - } - if (*offp == vol->used_bytes || count == 0) - return 0; - - if (vol->corrupted) - dbg_msg("read from corrupted volume %d", vol_id); - - if (*offp + count > vol->used_bytes) - count_save = count = vol->used_bytes - *offp; - - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); - tbuf = kmalloc(tbuf_size, GFP_KERNEL); - if (!tbuf) - return -ENOMEM; - - len = count > tbuf_size ? tbuf_size : count; - - tmp = *offp; - off = do_div(tmp, vol->usable_leb_size); - lnum = tmp; - - do { - cond_resched(); - - if (off + len >= vol->usable_leb_size) - len = vol->usable_leb_size - off; - - err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0); - if (err) - break; - - off += len; - if (off == vol->usable_leb_size) { - lnum += 1; - off -= vol->usable_leb_size; - } - - count -= len; - *offp += len; - - err = copy_to_user(buf, tbuf, len); - if (err) { - err = -EFAULT; - break; - } - - buf += len; - len = count > tbuf_size ? tbuf_size : count; - } while (count); - - kfree(tbuf); - return err ? err : count_save - count; -} - -#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO - -/* - * This function allows to directly write to dynamic UBI volumes, without - * issuing the volume update operation. Available only as a debugging feature. - * Very useful for testing UBI. - */ -static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, - size_t count, loff_t *offp) -{ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0; - size_t count_save = count; - char *tbuf; - uint64_t tmp; - - dbg_msg("requested: write %zd bytes to offset %lld of volume %u", - count, *offp, desc->vol->vol_id); - - if (vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; - - tmp = *offp; - off = do_div(tmp, vol->usable_leb_size); - lnum = tmp; - - if (off % ubi->min_io_size) { - dbg_err("unaligned position"); - return -EINVAL; - } - - if (*offp + count > vol->used_bytes) - count_save = count = vol->used_bytes - *offp; - - /* We can write only in fractions of the minimum I/O unit */ - if (count % ubi->min_io_size) { - dbg_err("unaligned write length"); - return -EINVAL; - } - - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); - tbuf = kmalloc(tbuf_size, GFP_KERNEL); - if (!tbuf) - return -ENOMEM; - - len = count > tbuf_size ? tbuf_size : count; - - while (count) { - cond_resched(); - - if (off + len >= vol->usable_leb_size) - len = vol->usable_leb_size - off; - - err = copy_from_user(tbuf, buf, len); - if (err) { - err = -EFAULT; - break; - } - - err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len, - UBI_UNKNOWN); - if (err) - break; - - off += len; - if (off == vol->usable_leb_size) { - lnum += 1; - off -= vol->usable_leb_size; - } - - count -= len; - *offp += len; - buf += len; - len = count > tbuf_size ? tbuf_size : count; - } - - kfree(tbuf); - return err ? err : count_save - count; -} - -#else -#define vol_cdev_direct_write(file, buf, count, offp) -EPERM -#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */ - -static ssize_t vol_cdev_write(struct file *file, const char __user *buf, - size_t count, loff_t *offp) -{ - int err = 0; - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - - if (!vol->updating) - return vol_cdev_direct_write(file, buf, count, offp); - - err = ubi_more_update_data(ubi, vol->vol_id, buf, count); - if (err < 0) { - ubi_err("cannot write %zd bytes of update data", count); - return err; - } - - if (err) { - /* - * Update is finished, @err contains number of actually written - * bytes now. - */ - count = err; - - err = ubi_check_volume(ubi, vol->vol_id); - if (err < 0) - return err; - - if (err) { - ubi_warn("volume %d on UBI device %d is corrupted", - vol->vol_id, ubi->ubi_num); - vol->corrupted = 1; - } - vol->checked = 1; - revoke_exclusive(desc, UBI_READWRITE); - } - - *offp += count; - return count; -} - -static int vol_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err = 0; - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - void __user *argp = (void __user *)arg; - - if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ || - _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC) - return -ENOTTY; - - if (_IOC_DIR(cmd) && _IOC_READ) - err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) && _IOC_WRITE) - err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - - switch (cmd) { - - /* Volume update command */ - case UBI_IOCVOLUP: - { - int64_t bytes, rsvd_bytes; - - if (!capable(CAP_SYS_RESOURCE)) { - err = -EPERM; - break; - } - - err = copy_from_user(&bytes, argp, sizeof(int64_t)); - if (err) { - err = -EFAULT; - break; - } - - if (desc->mode == UBI_READONLY) { - err = -EROFS; - break; - } - - rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad); - if (bytes < 0 || bytes > rsvd_bytes) { - err = -EINVAL; - break; - } - - err = get_exclusive(desc); - if (err < 0) - break; - - err = ubi_start_update(ubi, vol->vol_id, bytes); - if (bytes == 0) - revoke_exclusive(desc, UBI_READWRITE); - - file->f_pos = 0; - break; - } - -#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO - /* Logical eraseblock erasure command */ - case UBI_IOCEBER: - { - int32_t lnum; - - err = __get_user(lnum, (__user int32_t *)argp); - if (err) { - err = -EFAULT; - break; - } - - if (desc->mode == UBI_READONLY) { - err = -EROFS; - break; - } - - if (lnum < 0 || lnum >= vol->reserved_pebs) { - err = -EINVAL; - break; - } - - if (vol->vol_type != UBI_DYNAMIC_VOLUME) { - err = -EROFS; - break; - } - - dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); - err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum); - if (err) - break; - - err = ubi_wl_flush(ubi); - break; - } -#endif - - default: - err = -ENOTTY; - break; - } - - return err; -} - -/** - * verify_mkvol_req - verify volume creation request. - * @ubi: UBI device description object - * @req: the request to check - * - * This function zero if the request is correct, and %-EINVAL if not. - */ -static int verify_mkvol_req(const struct ubi_device *ubi, - const struct ubi_mkvol_req *req) -{ - int n, err = -EINVAL; - - if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 || - req->name_len < 0) - goto bad; - - if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) && - req->vol_id != UBI_VOL_NUM_AUTO) - goto bad; - - if (req->alignment == 0) - goto bad; - - if (req->bytes == 0) - goto bad; - - if (req->vol_type != UBI_DYNAMIC_VOLUME && - req->vol_type != UBI_STATIC_VOLUME) - goto bad; - - if (req->alignment > ubi->leb_size) - goto bad; - - n = req->alignment % ubi->min_io_size; - if (req->alignment != 1 && n) - goto bad; - - if (req->name_len > UBI_VOL_NAME_MAX) { - err = -ENAMETOOLONG; - goto bad; - } - - return 0; - -bad: - dbg_err("bad volume creation request"); - ubi_dbg_dump_mkvol_req(req); - return err; -} - -/** - * verify_rsvol_req - verify volume re-size request. - * @ubi: UBI device description object - * @req: the request to check - * - * This function returns zero if the request is correct, and %-EINVAL if not. - */ -static int verify_rsvol_req(const struct ubi_device *ubi, - const struct ubi_rsvol_req *req) -{ - if (req->bytes <= 0) - return -EINVAL; - - if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) - return -EINVAL; - - return 0; -} - -static int ubi_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err = 0; - struct ubi_device *ubi; - struct ubi_volume_desc *desc; - void __user *argp = (void __user *)arg; - - if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ || - _IOC_TYPE(cmd) != UBI_IOC_MAGIC) - return -ENOTTY; - - if (_IOC_DIR(cmd) && _IOC_READ) - err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) && _IOC_WRITE) - err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - ubi = major_to_device(imajor(inode)); - if (IS_ERR(ubi)) - return PTR_ERR(ubi); - - switch (cmd) { - /* Create volume command */ - case UBI_IOCMKVOL: - { - struct ubi_mkvol_req req; - - dbg_msg("create volume"); - err = __copy_from_user(&req, argp, - sizeof(struct ubi_mkvol_req)); - if (err) { - err = -EFAULT; - break; - } - - err = verify_mkvol_req(ubi, &req); - if (err) - break; - - req.name[req.name_len] = '\0'; - - err = ubi_create_volume(ubi, &req); - if (err) - break; - - err = __put_user(req.vol_id, (__user int32_t *)argp); - if (err) - err = -EFAULT; - - break; - } - - /* Remove volume command */ - case UBI_IOCRMVOL: - { - int vol_id; - - dbg_msg("remove volume"); - err = __get_user(vol_id, (__user int32_t *)argp); - if (err) { - err = -EFAULT; - break; - } - - desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE); - if (IS_ERR(desc)) { - err = PTR_ERR(desc); - break; - } - - err = ubi_remove_volume(desc); - if (err) - ubi_close_volume(desc); - - break; - } - - /* Re-size volume command */ - case UBI_IOCRSVOL: - { - int pebs; - uint64_t tmp; - struct ubi_rsvol_req req; - - dbg_msg("re-size volume"); - err = __copy_from_user(&req, argp, - sizeof(struct ubi_rsvol_req)); - if (err) { - err = -EFAULT; - break; - } - - err = verify_rsvol_req(ubi, &req); - if (err) - break; - - desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE); - if (IS_ERR(desc)) { - err = PTR_ERR(desc); - break; - } - - tmp = req.bytes; - pebs = !!do_div(tmp, desc->vol->usable_leb_size); - pebs += tmp; - - err = ubi_resize_volume(desc, pebs); - ubi_close_volume(desc); - break; - } - - default: - err = -ENOTTY; - break; - } - - return err; -} - -/* UBI character device operations */ -struct file_operations ubi_cdev_operations = { - .owner = THIS_MODULE, - .ioctl = ubi_cdev_ioctl, - .llseek = no_llseek -}; - -/* UBI volume character device operations */ -struct file_operations ubi_vol_cdev_operations = { - .owner = THIS_MODULE, - .open = vol_cdev_open, - .release = vol_cdev_release, - .llseek = vol_cdev_llseek, - .read = vol_cdev_read, - .write = vol_cdev_write, - .ioctl = vol_cdev_ioctl -}; diff --git a/trunk/drivers/mtd/ubi/debug.c b/trunk/drivers/mtd/ubi/debug.c deleted file mode 100644 index 86364221fafe..000000000000 --- a/trunk/drivers/mtd/ubi/debug.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * Here we keep all the UBI debugging stuff which should normally be disabled - * and compiled-out, but it is extremely helpful when hunting bugs or doing big - * changes. - */ - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG - -#include "ubi.h" - -/** - * ubi_dbg_dump_ec_hdr - dump an erase counter header. - * @ec_hdr: the erase counter header to dump - */ -void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) -{ - dbg_msg("erase counter header dump:"); - dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic)); - dbg_msg("version %d", (int)ec_hdr->version); - dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec)); - dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset)); - dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset)); - dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc)); - dbg_msg("erase counter header hexdump:"); - ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE); -} - -/** - * ubi_dbg_dump_vid_hdr - dump a volume identifier header. - * @vid_hdr: the volume identifier header to dump - */ -void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) -{ - dbg_msg("volume identifier header dump:"); - dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic)); - dbg_msg("version %d", (int)vid_hdr->version); - dbg_msg("vol_type %d", (int)vid_hdr->vol_type); - dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag); - dbg_msg("compat %d", (int)vid_hdr->compat); - dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id)); - dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum)); - dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver)); - dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size)); - dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs)); - dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad)); - dbg_msg("sqnum %llu", - (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum)); - dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc)); - dbg_msg("volume identifier header hexdump:"); -} - -/** - * ubi_dbg_dump_vol_info- dump volume information. - * @vol: UBI volume description object - */ -void ubi_dbg_dump_vol_info(const struct ubi_volume *vol) -{ - dbg_msg("volume information dump:"); - dbg_msg("vol_id %d", vol->vol_id); - dbg_msg("reserved_pebs %d", vol->reserved_pebs); - dbg_msg("alignment %d", vol->alignment); - dbg_msg("data_pad %d", vol->data_pad); - dbg_msg("vol_type %d", vol->vol_type); - dbg_msg("name_len %d", vol->name_len); - dbg_msg("usable_leb_size %d", vol->usable_leb_size); - dbg_msg("used_ebs %d", vol->used_ebs); - dbg_msg("used_bytes %lld", vol->used_bytes); - dbg_msg("last_eb_bytes %d", vol->last_eb_bytes); - dbg_msg("corrupted %d", vol->corrupted); - dbg_msg("upd_marker %d", vol->upd_marker); - - if (vol->name_len <= UBI_VOL_NAME_MAX && - strnlen(vol->name, vol->name_len + 1) == vol->name_len) { - dbg_msg("name %s", vol->name); - } else { - dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c", - vol->name[0], vol->name[1], vol->name[2], - vol->name[3], vol->name[4]); - } -} - -/** - * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object. - * @r: the object to dump - * @idx: volume table index - */ -void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) -{ - int name_len = ubi16_to_cpu(r->name_len); - - dbg_msg("volume table record %d dump:", idx); - dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs)); - dbg_msg("alignment %d", ubi32_to_cpu(r->alignment)); - dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad)); - dbg_msg("vol_type %d", (int)r->vol_type); - dbg_msg("upd_marker %d", (int)r->upd_marker); - dbg_msg("name_len %d", name_len); - - if (r->name[0] == '\0') { - dbg_msg("name NULL"); - return; - } - - if (name_len <= UBI_VOL_NAME_MAX && - strnlen(&r->name[0], name_len + 1) == name_len) { - dbg_msg("name %s", &r->name[0]); - } else { - dbg_msg("1st 5 characters of the name: %c%c%c%c%c", - r->name[0], r->name[1], r->name[2], r->name[3], - r->name[4]); - } - dbg_msg("crc %#08x", ubi32_to_cpu(r->crc)); -} - -/** - * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object. - * @sv: the object to dump - */ -void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) -{ - dbg_msg("volume scanning information dump:"); - dbg_msg("vol_id %d", sv->vol_id); - dbg_msg("highest_lnum %d", sv->highest_lnum); - dbg_msg("leb_count %d", sv->leb_count); - dbg_msg("compat %d", sv->compat); - dbg_msg("vol_type %d", sv->vol_type); - dbg_msg("used_ebs %d", sv->used_ebs); - dbg_msg("last_data_size %d", sv->last_data_size); - dbg_msg("data_pad %d", sv->data_pad); -} - -/** - * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object. - * @seb: the object to dump - * @type: object type: 0 - not corrupted, 1 - corrupted - */ -void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type) -{ - dbg_msg("eraseblock scanning information dump:"); - dbg_msg("ec %d", seb->ec); - dbg_msg("pnum %d", seb->pnum); - if (type == 0) { - dbg_msg("lnum %d", seb->lnum); - dbg_msg("scrub %d", seb->scrub); - dbg_msg("sqnum %llu", seb->sqnum); - dbg_msg("leb_ver %u", seb->leb_ver); - } -} - -/** - * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object. - * @req: the object to dump - */ -void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) -{ - char nm[17]; - - dbg_msg("volume creation request dump:"); - dbg_msg("vol_id %d", req->vol_id); - dbg_msg("alignment %d", req->alignment); - dbg_msg("bytes %lld", (long long)req->bytes); - dbg_msg("vol_type %d", req->vol_type); - dbg_msg("name_len %d", req->name_len); - - memcpy(nm, req->name, 16); - nm[16] = 0; - dbg_msg("the 1st 16 characters of the name: %s", nm); -} - -#define BYTES_PER_LINE 32 - -/** - * ubi_dbg_hexdump - dump a buffer. - * @ptr: the buffer to dump - * @size: buffer size which must be multiple of 4 bytes - */ -void ubi_dbg_hexdump(const void *ptr, int size) -{ - int i, k = 0, rows, columns; - const uint8_t *p = ptr; - - size = ALIGN(size, 4); - rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE; - for (i = 0; i < rows; i++) { - int j; - - cond_resched(); - columns = min(size - k, BYTES_PER_LINE) / 4; - if (columns == 0) - break; - printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE); - for (j = 0; j < columns; j++) { - int n, N; - - N = size - k > 4 ? 4 : size - k; - for (n = 0; n < N; n++) - printk("%02x", p[k++]); - printk(" "); - } - printk("\n"); - } -} - -#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/trunk/drivers/mtd/ubi/debug.h b/trunk/drivers/mtd/ubi/debug.h deleted file mode 100644 index f816ad9a36c0..000000000000 --- a/trunk/drivers/mtd/ubi/debug.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -#ifndef __UBI_DEBUG_H__ -#define __UBI_DEBUG_H__ - -#ifdef CONFIG_MTD_UBI_DEBUG -#include - -#define ubi_assert(expr) BUG_ON(!(expr)) -#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__) -#else -#define ubi_assert(expr) ({}) -#define dbg_err(fmt, ...) ({}) -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT -#define DBG_DISABLE_BGT 1 -#else -#define DBG_DISABLE_BGT 0 -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG -/* Generic debugging message */ -#define dbg_msg(fmt, ...) \ - printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) - -#define ubi_dbg_dump_stack() dump_stack() - -struct ubi_ec_hdr; -struct ubi_vid_hdr; -struct ubi_volume; -struct ubi_vtbl_record; -struct ubi_scan_volume; -struct ubi_scan_leb; -struct ubi_mkvol_req; - -void ubi_dbg_print(int type, const char *func, const char *fmt, ...); -void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr); -void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); -void ubi_dbg_dump_vol_info(const struct ubi_volume *vol); -void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx); -void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); -void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); -void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); -void ubi_dbg_hexdump(const void *buf, int size); - -#else - -#define dbg_msg(fmt, ...) ({}) -#define ubi_dbg_dump_stack() ({}) -#define ubi_dbg_print(func, fmt, ...) ({}) -#define ubi_dbg_dump_ec_hdr(ec_hdr) ({}) -#define ubi_dbg_dump_vid_hdr(vid_hdr) ({}) -#define ubi_dbg_dump_vol_info(vol) ({}) -#define ubi_dbg_dump_vtbl_record(r, idx) ({}) -#define ubi_dbg_dump_sv(sv) ({}) -#define ubi_dbg_dump_seb(seb, type) ({}) -#define ubi_dbg_dump_mkvol_req(req) ({}) -#define ubi_dbg_hexdump(buf, size) ({}) - -#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA -/* Messages from the eraseblock association unit */ -#define dbg_eba(fmt, ...) \ - printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \ - ##__VA_ARGS__) -#else -#define dbg_eba(fmt, ...) ({}) -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL -/* Messages from the wear-leveling unit */ -#define dbg_wl(fmt, ...) \ - printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \ - ##__VA_ARGS__) -#else -#define dbg_wl(fmt, ...) ({}) -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO -/* Messages from the input/output unit */ -#define dbg_io(fmt, ...) \ - printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \ - ##__VA_ARGS__) -#else -#define dbg_io(fmt, ...) ({}) -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD -/* Initialization and build messages */ -#define dbg_bld(fmt, ...) \ - printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \ - ##__VA_ARGS__) -#else -#define dbg_bld(fmt, ...) ({}) -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS -/** - * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip. - * - * Returns non-zero if a bit-flip should be emulated, otherwise returns zero. - */ -static inline int ubi_dbg_is_bitflip(void) -{ - return !(random32() % 200); -} -#else -#define ubi_dbg_is_bitflip() 0 -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES -/** - * ubi_dbg_is_write_failure - if it is time to emulate a write failure. - * - * Returns non-zero if a write failure should be emulated, otherwise returns - * zero. - */ -static inline int ubi_dbg_is_write_failure(void) -{ - return !(random32() % 500); -} -#else -#define ubi_dbg_is_write_failure() 0 -#endif - -#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES -/** - * ubi_dbg_is_erase_failure - if its time to emulate an erase failure. - * - * Returns non-zero if an erase failure should be emulated, otherwise returns - * zero. - */ -static inline int ubi_dbg_is_erase_failure(void) -{ - return !(random32() % 400); -} -#else -#define ubi_dbg_is_erase_failure() 0 -#endif - -#endif /* !__UBI_DEBUG_H__ */ diff --git a/trunk/drivers/mtd/ubi/eba.c b/trunk/drivers/mtd/ubi/eba.c deleted file mode 100644 index d847ee1da3d9..000000000000 --- a/trunk/drivers/mtd/ubi/eba.c +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * The UBI Eraseblock Association (EBA) unit. - * - * This unit is responsible for I/O to/from logical eraseblock. - * - * Although in this implementation the EBA table is fully kept and managed in - * RAM, which assumes poor scalability, it might be (partially) maintained on - * flash in future implementations. - * - * The EBA unit implements per-logical eraseblock locking. Before accessing a - * logical eraseblock it is locked for reading or writing. The per-logical - * eraseblock locking is implemented by means of the lock tree. The lock tree - * is an RB-tree which refers all the currently locked logical eraseblocks. The - * lock tree elements are &struct ltree_entry objects. They are indexed by - * (@vol_id, @lnum) pairs. - * - * EBA also maintains the global sequence counter which is incremented each - * time a logical eraseblock is mapped to a physical eraseblock and it is - * stored in the volume identifier header. This means that each VID header has - * a unique sequence number. The sequence number is only increased an we assume - * 64 bits is enough to never overflow. - */ - -#include -#include -#include -#include "ubi.h" - -/** - * struct ltree_entry - an entry in the lock tree. - * @rb: links RB-tree nodes - * @vol_id: volume ID of the locked logical eraseblock - * @lnum: locked logical eraseblock number - * @users: how many tasks are using this logical eraseblock or wait for it - * @mutex: read/write mutex to implement read/write access serialization to - * the (@vol_id, @lnum) logical eraseblock - * - * When a logical eraseblock is being locked - corresponding &struct ltree_entry - * object is inserted to the lock tree (@ubi->ltree). - */ -struct ltree_entry { - struct rb_node rb; - int vol_id; - int lnum; - int users; - struct rw_semaphore mutex; -}; - -/* Slab cache for lock-tree entries */ -static struct kmem_cache *ltree_slab; - -/** - * next_sqnum - get next sequence number. - * @ubi: UBI device description object - * - * This function returns next sequence number to use, which is just the current - * global sequence counter value. It also increases the global sequence - * counter. - */ -static unsigned long long next_sqnum(struct ubi_device *ubi) -{ - unsigned long long sqnum; - - spin_lock(&ubi->ltree_lock); - sqnum = ubi->global_sqnum++; - spin_unlock(&ubi->ltree_lock); - - return sqnum; -} - -/** - * ubi_get_compat - get compatibility flags of a volume. - * @ubi: UBI device description object - * @vol_id: volume ID - * - * This function returns compatibility flags for an internal volume. User - * volumes have no compatibility flags, so %0 is returned. - */ -static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) -{ - if (vol_id == UBI_LAYOUT_VOL_ID) - return UBI_LAYOUT_VOLUME_COMPAT; - return 0; -} - -/** - * ltree_lookup - look up the lock tree. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * - * This function returns a pointer to the corresponding &struct ltree_entry - * object if the logical eraseblock is locked and %NULL if it is not. - * @ubi->ltree_lock has to be locked. - */ -static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, - int lnum) -{ - struct rb_node *p; - - p = ubi->ltree.rb_node; - while (p) { - struct ltree_entry *le; - - le = rb_entry(p, struct ltree_entry, rb); - - if (vol_id < le->vol_id) - p = p->rb_left; - else if (vol_id > le->vol_id) - p = p->rb_right; - else { - if (lnum < le->lnum) - p = p->rb_left; - else if (lnum > le->lnum) - p = p->rb_right; - else - return le; - } - } - - return NULL; -} - -/** - * ltree_add_entry - add new entry to the lock tree. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * - * This function adds new entry for logical eraseblock (@vol_id, @lnum) to the - * lock tree. If such entry is already there, its usage counter is increased. - * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation - * failed. - */ -static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, - int lnum) -{ - struct ltree_entry *le, *le1, *le_free; - - le = kmem_cache_alloc(ltree_slab, GFP_KERNEL); - if (!le) - return ERR_PTR(-ENOMEM); - - le->vol_id = vol_id; - le->lnum = lnum; - - spin_lock(&ubi->ltree_lock); - le1 = ltree_lookup(ubi, vol_id, lnum); - - if (le1) { - /* - * This logical eraseblock is already locked. The newly - * allocated lock entry is not needed. - */ - le_free = le; - le = le1; - } else { - struct rb_node **p, *parent = NULL; - - /* - * No lock entry, add the newly allocated one to the - * @ubi->ltree RB-tree. - */ - le_free = NULL; - - p = &ubi->ltree.rb_node; - while (*p) { - parent = *p; - le1 = rb_entry(parent, struct ltree_entry, rb); - - if (vol_id < le1->vol_id) - p = &(*p)->rb_left; - else if (vol_id > le1->vol_id) - p = &(*p)->rb_right; - else { - ubi_assert(lnum != le1->lnum); - if (lnum < le1->lnum) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - } - - rb_link_node(&le->rb, parent, p); - rb_insert_color(&le->rb, &ubi->ltree); - } - le->users += 1; - spin_unlock(&ubi->ltree_lock); - - if (le_free) - kmem_cache_free(ltree_slab, le_free); - - return le; -} - -/** - * leb_read_lock - lock logical eraseblock for reading. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * - * This function locks a logical eraseblock for reading. Returns zero in case - * of success and a negative error code in case of failure. - */ -static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) -{ - struct ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) - return PTR_ERR(le); - down_read(&le->mutex); - return 0; -} - -/** - * leb_read_unlock - unlock logical eraseblock. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - */ -static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) -{ - int free = 0; - struct ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); - le->users -= 1; - ubi_assert(le->users >= 0); - if (le->users == 0) { - rb_erase(&le->rb, &ubi->ltree); - free = 1; - } - spin_unlock(&ubi->ltree_lock); - - up_read(&le->mutex); - if (free) - kmem_cache_free(ltree_slab, le); -} - -/** - * leb_write_lock - lock logical eraseblock for writing. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * - * This function locks a logical eraseblock for writing. Returns zero in case - * of success and a negative error code in case of failure. - */ -static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) -{ - struct ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) - return PTR_ERR(le); - down_write(&le->mutex); - return 0; -} - -/** - * leb_write_unlock - unlock logical eraseblock. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - */ -static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) -{ - int free; - struct ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); - le->users -= 1; - ubi_assert(le->users >= 0); - if (le->users == 0) { - rb_erase(&le->rb, &ubi->ltree); - free = 1; - } else - free = 0; - spin_unlock(&ubi->ltree_lock); - - up_write(&le->mutex); - if (free) - kmem_cache_free(ltree_slab, le); -} - -/** - * ubi_eba_unmap_leb - un-map logical eraseblock. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * - * This function un-maps logical eraseblock @lnum and schedules corresponding - * physical eraseblock for erasure. Returns zero in case of success and a - * negative error code in case of failure. - */ -int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum) -{ - int idx = vol_id2idx(ubi, vol_id), err, pnum; - struct ubi_volume *vol = ubi->volumes[idx]; - - if (ubi->ro_mode) - return -EROFS; - - err = leb_write_lock(ubi, vol_id, lnum); - if (err) - return err; - - pnum = vol->eba_tbl[lnum]; - if (pnum < 0) - /* This logical eraseblock is already unmapped */ - goto out_unlock; - - dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); - - vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; - err = ubi_wl_put_peb(ubi, pnum, 0); - -out_unlock: - leb_write_unlock(ubi, vol_id, lnum); - return err; -} - -/** - * ubi_eba_read_leb - read data. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: buffer to store the read data - * @offset: offset from where to read - * @len: how many bytes to read - * @check: data CRC check flag - * - * If the logical eraseblock @lnum is unmapped, @buf is filled with 0xFF - * bytes. The @check flag only makes sense for static volumes and forces - * eraseblock data CRC checking. - * - * In case of success this function returns zero. In case of a static volume, - * if data CRC mismatches - %-EBADMSG is returned. %-EBADMSG may also be - * returned for any volume type if an ECC error was detected by the MTD device - * driver. Other negative error cored may be returned in case of other errors. - */ -int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, - int offset, int len, int check) -{ - int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id); - struct ubi_vid_hdr *vid_hdr; - struct ubi_volume *vol = ubi->volumes[idx]; - uint32_t crc, crc1; - - err = leb_read_lock(ubi, vol_id, lnum); - if (err) - return err; - - pnum = vol->eba_tbl[lnum]; - if (pnum < 0) { - /* - * The logical eraseblock is not mapped, fill the whole buffer - * with 0xFF bytes. The exception is static volumes for which - * it is an error to read unmapped logical eraseblocks. - */ - dbg_eba("read %d bytes from offset %d of LEB %d:%d (unmapped)", - len, offset, vol_id, lnum); - leb_read_unlock(ubi, vol_id, lnum); - ubi_assert(vol->vol_type != UBI_STATIC_VOLUME); - memset(buf, 0xFF, len); - return 0; - } - - dbg_eba("read %d bytes from offset %d of LEB %d:%d, PEB %d", - len, offset, vol_id, lnum, pnum); - - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - check = 0; - -retry: - if (check) { - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) { - err = -ENOMEM; - goto out_unlock; - } - - err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); - if (err && err != UBI_IO_BITFLIPS) { - if (err > 0) { - /* - * The header is either absent or corrupted. - * The former case means there is a bug - - * switch to read-only mode just in case. - * The latter case means a real corruption - we - * may try to recover data. FIXME: but this is - * not implemented. - */ - if (err == UBI_IO_BAD_VID_HDR) { - ubi_warn("bad VID header at PEB %d, LEB" - "%d:%d", pnum, vol_id, lnum); - err = -EBADMSG; - } else - ubi_ro_mode(ubi); - } - goto out_free; - } else if (err == UBI_IO_BITFLIPS) - scrub = 1; - - ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs)); - ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size)); - - crc = ubi32_to_cpu(vid_hdr->data_crc); - ubi_free_vid_hdr(ubi, vid_hdr); - } - - err = ubi_io_read_data(ubi, buf, pnum, offset, len); - if (err) { - if (err == UBI_IO_BITFLIPS) { - scrub = 1; - err = 0; - } else if (err == -EBADMSG) { - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - goto out_unlock; - scrub = 1; - if (!check) { - ubi_msg("force data checking"); - check = 1; - goto retry; - } - } else - goto out_unlock; - } - - if (check) { - crc1 = crc32(UBI_CRC32_INIT, buf, len); - if (crc1 != crc) { - ubi_warn("CRC error: calculated %#08x, must be %#08x", - crc1, crc); - err = -EBADMSG; - goto out_unlock; - } - } - - if (scrub) - err = ubi_wl_scrub_peb(ubi, pnum); - - leb_read_unlock(ubi, vol_id, lnum); - return err; - -out_free: - ubi_free_vid_hdr(ubi, vid_hdr); -out_unlock: - leb_read_unlock(ubi, vol_id, lnum); - return err; -} - -/** - * recover_peb - recover from write failure. - * @ubi: UBI device description object - * @pnum: the physical eraseblock to recover - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: data which was not written because of the write failure - * @offset: offset of the failed write - * @len: how many bytes should have been written - * - * This function is called in case of a write failure and moves all good data - * from the potentially bad physical eraseblock to a good physical eraseblock. - * This function also writes the data which was not written due to the failure. - * Returns new physical eraseblock number in case of success, and a negative - * error code in case of failure. - */ -static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, - const void *buf, int offset, int len) -{ - int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; - struct ubi_volume *vol = ubi->volumes[idx]; - struct ubi_vid_hdr *vid_hdr; - unsigned char *new_buf; - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) { - return -ENOMEM; - } - -retry: - new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); - if (new_pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - return new_pnum; - } - - ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); - - err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); - if (err && err != UBI_IO_BITFLIPS) { - if (err > 0) - err = -EIO; - goto out_put; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); - if (err) - goto write_error; - - data_size = offset + len; - new_buf = kmalloc(data_size, GFP_KERNEL); - if (!new_buf) { - err = -ENOMEM; - goto out_put; - } - memset(new_buf + offset, 0xFF, len); - - /* Read everything before the area where the write failure happened */ - if (offset > 0) { - err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); - if (err && err != UBI_IO_BITFLIPS) { - kfree(new_buf); - goto out_put; - } - } - - memcpy(new_buf + offset, buf, len); - - err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); - if (err) { - kfree(new_buf); - goto write_error; - } - - kfree(new_buf); - ubi_free_vid_hdr(ubi, vid_hdr); - - vol->eba_tbl[lnum] = new_pnum; - ubi_wl_put_peb(ubi, pnum, 1); - - ubi_msg("data was successfully recovered"); - return 0; - -out_put: - ubi_wl_put_peb(ubi, new_pnum, 1); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - -write_error: - /* - * Bad luck? This physical eraseblock is bad too? Crud. Let's try to - * get another one. - */ - ubi_warn("failed to write to PEB %d", new_pnum); - ubi_wl_put_peb(ubi, new_pnum, 1); - if (++tries > UBI_IO_RETRIES) { - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - ubi_msg("try again"); - goto retry; -} - -/** - * ubi_eba_write_leb - write data to dynamic volume. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: the data to write - * @offset: offset within the logical eraseblock where to write - * @len: how many bytes to write - * @dtype: data type - * - * This function writes data to logical eraseblock @lnum of a dynamic volume - * @vol_id. Returns zero in case of success and a negative error code in case - * of failure. In case of error, it is possible that something was still - * written to the flash media, but may be some garbage. - */ -int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int offset, int len, int dtype) -{ - int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0; - struct ubi_volume *vol = ubi->volumes[idx]; - struct ubi_vid_hdr *vid_hdr; - - if (ubi->ro_mode) - return -EROFS; - - err = leb_write_lock(ubi, vol_id, lnum); - if (err) - return err; - - pnum = vol->eba_tbl[lnum]; - if (pnum >= 0) { - dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", - len, offset, vol_id, lnum, pnum); - - err = ubi_io_write_data(ubi, buf, pnum, offset, len); - if (err) { - ubi_warn("failed to write data to PEB %d", pnum); - if (err == -EIO && ubi->bad_allowed) - err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); - if (err) - ubi_ro_mode(ubi); - } - leb_write_unlock(ubi, vol_id, lnum); - return err; - } - - /* - * The logical eraseblock is not mapped. We have to get a free physical - * eraseblock and write the volume identifier header there first. - */ - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) { - leb_write_unlock(ubi, vol_id, lnum); - return -ENOMEM; - } - - vid_hdr->vol_type = UBI_VID_DYNAMIC; - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); - vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); - -retry: - pnum = ubi_wl_get_peb(ubi, dtype); - if (pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return pnum; - } - - dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d", - len, offset, vol_id, lnum, pnum); - - err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); - if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", - vol_id, lnum, pnum); - goto write_error; - } - - err = ubi_io_write_data(ubi, buf, pnum, offset, len); - if (err) { - ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, " - "PEB %d", len, offset, vol_id, lnum, pnum); - goto write_error; - } - - vol->eba_tbl[lnum] = pnum; - - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return 0; - -write_error: - if (err != -EIO || !ubi->bad_allowed) { - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - /* - * Fortunately, this is the first write operation to this physical - * eraseblock, so just put it and request a new one. We assume that if - * this physical eraseblock went bad, the erase code will handle that. - */ - err = ubi_wl_put_peb(ubi, pnum, 1); - if (err || ++tries > UBI_IO_RETRIES) { - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - ubi_msg("try another PEB"); - goto retry; -} - -/** - * ubi_eba_write_leb_st - write data to static volume. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write - * @dtype: data type - * @used_ebs: how many logical eraseblocks will this volume contain - * - * This function writes data to logical eraseblock @lnum of static volume - * @vol_id. The @used_ebs argument should contain total number of logical - * eraseblock in this static volume. - * - * When writing to the last logical eraseblock, the @len argument doesn't have - * to be aligned to the minimal I/O unit size. Instead, it has to be equivalent - * to the real data size, although the @buf buffer has to contain the - * alignment. In all other cases, @len has to be aligned. - * - * It is prohibited to write more then once to logical eraseblocks of static - * volumes. This function returns zero in case of success and a negative error - * code in case of failure. - */ -int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int len, int dtype, int used_ebs) -{ - int err, pnum, tries = 0, data_size = len; - int idx = vol_id2idx(ubi, vol_id); - struct ubi_volume *vol = ubi->volumes[idx]; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - - if (ubi->ro_mode) - return -EROFS; - - if (lnum == used_ebs - 1) - /* If this is the last LEB @len may be unaligned */ - len = ALIGN(data_size, ubi->min_io_size); - else - ubi_assert(len % ubi->min_io_size == 0); - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) - return -ENOMEM; - - err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); - vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); - - crc = crc32(UBI_CRC32_INIT, buf, data_size); - vid_hdr->vol_type = UBI_VID_STATIC; - vid_hdr->data_size = cpu_to_ubi32(data_size); - vid_hdr->used_ebs = cpu_to_ubi32(used_ebs); - vid_hdr->data_crc = cpu_to_ubi32(crc); - -retry: - pnum = ubi_wl_get_peb(ubi, dtype); - if (pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return pnum; - } - - dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d", - len, vol_id, lnum, pnum, used_ebs); - - err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); - if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", - vol_id, lnum, pnum); - goto write_error; - } - - err = ubi_io_write_data(ubi, buf, pnum, 0, len); - if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", - len, pnum); - goto write_error; - } - - ubi_assert(vol->eba_tbl[lnum] < 0); - vol->eba_tbl[lnum] = pnum; - - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return 0; - -write_error: - if (err != -EIO || !ubi->bad_allowed) { - /* - * This flash device does not admit of bad eraseblocks or - * something nasty and unexpected happened. Switch to read-only - * mode just in case. - */ - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - err = ubi_wl_put_peb(ubi, pnum, 1); - if (err || ++tries > UBI_IO_RETRIES) { - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - ubi_msg("try another PEB"); - goto retry; -} - -/* - * ubi_eba_atomic_leb_change - change logical eraseblock atomically. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write - * @dtype: data type - * - * This function changes the contents of a logical eraseblock atomically. @buf - * has to contain new logical eraseblock data, and @len - the length of the - * data, which has to be aligned. This function guarantees that in case of an - * unclean reboot the old contents is preserved. Returns zero in case of - * success and a negative error code in case of failure. - */ -int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int len, int dtype) -{ - int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id); - struct ubi_volume *vol = ubi->volumes[idx]; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - - if (ubi->ro_mode) - return -EROFS; - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) - return -ENOMEM; - - err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); - vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); - - crc = crc32(UBI_CRC32_INIT, buf, len); - vid_hdr->vol_type = UBI_VID_STATIC; - vid_hdr->data_size = cpu_to_ubi32(len); - vid_hdr->copy_flag = 1; - vid_hdr->data_crc = cpu_to_ubi32(crc); - -retry: - pnum = ubi_wl_get_peb(ubi, dtype); - if (pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return pnum; - } - - dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", - vol_id, lnum, vol->eba_tbl[lnum], pnum); - - err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); - if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", - vol_id, lnum, pnum); - goto write_error; - } - - err = ubi_io_write_data(ubi, buf, pnum, 0, len); - if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", - len, pnum); - goto write_error; - } - - err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return err; - } - - vol->eba_tbl[lnum] = pnum; - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return 0; - -write_error: - if (err != -EIO || !ubi->bad_allowed) { - /* - * This flash device does not admit of bad eraseblocks or - * something nasty and unexpected happened. Switch to read-only - * mode just in case. - */ - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - err = ubi_wl_put_peb(ubi, pnum, 1); - if (err || ++tries > UBI_IO_RETRIES) { - ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } - - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - ubi_msg("try another PEB"); - goto retry; -} - -/** - * ltree_entry_ctor - lock tree entries slab cache constructor. - * @obj: the lock-tree entry to construct - * @cache: the lock tree entry slab cache - * @flags: constructor flags - */ -static void ltree_entry_ctor(void *obj, struct kmem_cache *cache, - unsigned long flags) -{ - struct ltree_entry *le = obj; - - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) != - SLAB_CTOR_CONSTRUCTOR) - return; - - le->users = 0; - init_rwsem(&le->mutex); -} - -/** - * ubi_eba_copy_leb - copy logical eraseblock. - * @ubi: UBI device description object - * @from: physical eraseblock number from where to copy - * @to: physical eraseblock number where to copy - * @vid_hdr: VID header of the @from physical eraseblock - * - * This function copies logical eraseblock from physical eraseblock @from to - * physical eraseblock @to. The @vid_hdr buffer may be changed by this - * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation - * was canceled because bit-flips were detected at the target PEB, and a - * negative error code in case of failure. - */ -int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr) -{ - int err, vol_id, lnum, data_size, aldata_size, pnum, idx; - struct ubi_volume *vol; - uint32_t crc; - void *buf, *buf1 = NULL; - - vol_id = ubi32_to_cpu(vid_hdr->vol_id); - lnum = ubi32_to_cpu(vid_hdr->lnum); - - dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); - - if (vid_hdr->vol_type == UBI_VID_STATIC) { - data_size = ubi32_to_cpu(vid_hdr->data_size); - aldata_size = ALIGN(data_size, ubi->min_io_size); - } else - data_size = aldata_size = - ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad); - - buf = kmalloc(aldata_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* - * We do not want anybody to write to this logical eraseblock while we - * are moving it, so we lock it. - */ - err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - kfree(buf); - return err; - } - - /* - * But the logical eraseblock might have been put by this time. - * Cancel if it is true. - */ - idx = vol_id2idx(ubi, vol_id); - - /* - * We may race with volume deletion/re-size, so we have to hold - * @ubi->volumes_lock. - */ - spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[idx]; - if (!vol) { - dbg_eba("volume %d was removed meanwhile", vol_id); - spin_unlock(&ubi->volumes_lock); - goto out_unlock; - } - - pnum = vol->eba_tbl[lnum]; - if (pnum != from) { - dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " - "PEB %d, cancel", vol_id, lnum, from, pnum); - spin_unlock(&ubi->volumes_lock); - goto out_unlock; - } - spin_unlock(&ubi->volumes_lock); - - /* OK, now the LEB is locked and we can safely start moving it */ - - dbg_eba("read %d bytes of data", aldata_size); - err = ubi_io_read_data(ubi, buf, from, 0, aldata_size); - if (err && err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data from PEB %d", - err, from); - goto out_unlock; - } - - /* - * Now we have got to calculate how much data we have to to copy. In - * case of a static volume it is fairly easy - the VID header contains - * the data size. In case of a dynamic volume it is more difficult - we - * have to read the contents, cut 0xFF bytes from the end and copy only - * the first part. We must do this to avoid writing 0xFF bytes as it - * may have some side-effects. And not only this. It is important not - * to include those 0xFFs to CRC because later the they may be filled - * by data. - */ - if (vid_hdr->vol_type == UBI_VID_DYNAMIC) - aldata_size = data_size = - ubi_calc_data_len(ubi, buf, data_size); - - cond_resched(); - crc = crc32(UBI_CRC32_INIT, buf, data_size); - cond_resched(); - - /* - * It may turn out to me that the whole @from physical eraseblock - * contains only 0xFF bytes. Then we have to only write the VID header - * and do not write any data. This also means we should not set - * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc. - */ - if (data_size > 0) { - vid_hdr->copy_flag = 1; - vid_hdr->data_size = cpu_to_ubi32(data_size); - vid_hdr->data_crc = cpu_to_ubi32(crc); - } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - - err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); - if (err) - goto out_unlock; - - cond_resched(); - - /* Read the VID header back and check if it was written correctly */ - err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); - if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read VID header back from PEB %d", to); - goto out_unlock; - } - - if (data_size > 0) { - err = ubi_io_write_data(ubi, buf, to, 0, aldata_size); - if (err) - goto out_unlock; - - /* - * We've written the data and are going to read it back to make - * sure it was written correctly. - */ - buf1 = kmalloc(aldata_size, GFP_KERNEL); - if (!buf1) { - err = -ENOMEM; - goto out_unlock; - } - - cond_resched(); - - err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size); - if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read data back from PEB %d", - to); - goto out_unlock; - } - - cond_resched(); - - if (memcmp(buf, buf1, aldata_size)) { - ubi_warn("read data back from PEB %d - it is different", - to); - goto out_unlock; - } - } - - ubi_assert(vol->eba_tbl[lnum] == from); - vol->eba_tbl[lnum] = to; - - leb_write_unlock(ubi, vol_id, lnum); - kfree(buf); - kfree(buf1); - - return 0; - -out_unlock: - leb_write_unlock(ubi, vol_id, lnum); - kfree(buf); - kfree(buf1); - return err; -} - -/** - * ubi_eba_init_scan - initialize the EBA unit using scanning information. - * @ubi: UBI device description object - * @si: scanning information - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) -{ - int i, j, err, num_volumes; - struct ubi_scan_volume *sv; - struct ubi_volume *vol; - struct ubi_scan_leb *seb; - struct rb_node *rb; - - dbg_eba("initialize EBA unit"); - - spin_lock_init(&ubi->ltree_lock); - ubi->ltree = RB_ROOT; - - if (ubi_devices_cnt == 0) { - ltree_slab = kmem_cache_create("ubi_ltree_slab", - sizeof(struct ltree_entry), 0, - 0, <ree_entry_ctor, NULL); - if (!ltree_slab) - return -ENOMEM; - } - - ubi->global_sqnum = si->max_sqnum + 1; - num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; - - for (i = 0; i < num_volumes; i++) { - vol = ubi->volumes[i]; - if (!vol) - continue; - - cond_resched(); - - vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), - GFP_KERNEL); - if (!vol->eba_tbl) { - err = -ENOMEM; - goto out_free; - } - - for (j = 0; j < vol->reserved_pebs; j++) - vol->eba_tbl[j] = UBI_LEB_UNMAPPED; - - sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i)); - if (!sv) - continue; - - ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { - if (seb->lnum >= vol->reserved_pebs) - /* - * This may happen in case of an unclean reboot - * during re-size. - */ - ubi_scan_move_to_list(sv, seb, &si->erase); - vol->eba_tbl[seb->lnum] = seb->pnum; - } - } - - if (ubi->bad_allowed) { - ubi_calculate_reserved(ubi); - - if (ubi->avail_pebs < ubi->beb_rsvd_level) { - /* No enough free physical eraseblocks */ - ubi->beb_rsvd_pebs = ubi->avail_pebs; - ubi_warn("cannot reserve enough PEBs for bad PEB " - "handling, reserved %d, need %d", - ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); - } else - ubi->beb_rsvd_pebs = ubi->beb_rsvd_level; - - ubi->avail_pebs -= ubi->beb_rsvd_pebs; - ubi->rsvd_pebs += ubi->beb_rsvd_pebs; - } - - dbg_eba("EBA unit is initialized"); - return 0; - -out_free: - for (i = 0; i < num_volumes; i++) { - if (!ubi->volumes[i]) - continue; - kfree(ubi->volumes[i]->eba_tbl); - } - if (ubi_devices_cnt == 0) - kmem_cache_destroy(ltree_slab); - return err; -} - -/** - * ubi_eba_close - close EBA unit. - * @ubi: UBI device description object - */ -void ubi_eba_close(const struct ubi_device *ubi) -{ - int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; - - dbg_eba("close EBA unit"); - - for (i = 0; i < num_volumes; i++) { - if (!ubi->volumes[i]) - continue; - kfree(ubi->volumes[i]->eba_tbl); - } - if (ubi_devices_cnt == 1) - kmem_cache_destroy(ltree_slab); -} diff --git a/trunk/drivers/mtd/ubi/gluebi.c b/trunk/drivers/mtd/ubi/gluebi.c deleted file mode 100644 index fc9478d605ff..000000000000 --- a/trunk/drivers/mtd/ubi/gluebi.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём), Joern Engel - */ - -/* - * This file includes implementation of fake MTD devices for each UBI volume. - * This sounds strange, but it is in fact quite useful to make MTD-oriented - * software (including all the legacy software) to work on top of UBI. - * - * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit - * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The - * eraseblock size is equivalent to the logical eraseblock size of the volume. - */ - -#include -#include "ubi.h" - -/** - * gluebi_get_device - get MTD device reference. - * @mtd: the MTD device description object - * - * This function is called every time the MTD device is being opened and - * implements the MTD get_device() operation. Returns zero in case of success - * and a negative error code in case of failure. - */ -static int gluebi_get_device(struct mtd_info *mtd) -{ - struct ubi_volume *vol; - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - - /* - * We do not introduce locks for gluebi reference count because the - * get_device()/put_device() calls are already serialized at MTD. - */ - if (vol->gluebi_refcount > 0) { - /* - * The MTD device is already referenced and this is just one - * more reference. MTD allows many users to open the same - * volume simultaneously and do not distinguish between - * readers/writers/exclusive openers as UBI does. So we do not - * open the UBI volume again - just increase the reference - * counter and return. - */ - vol->gluebi_refcount += 1; - return 0; - } - - /* - * This is the first reference to this UBI volume via the MTD device - * interface. Open the corresponding volume in read-write mode. - */ - vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id, - UBI_READWRITE); - if (IS_ERR(vol->gluebi_desc)) - return PTR_ERR(vol->gluebi_desc); - vol->gluebi_refcount += 1; - return 0; -} - -/** - * gluebi_put_device - put MTD device reference. - * @mtd: the MTD device description object - * - * This function is called every time the MTD device is being put. Returns - * zero in case of success and a negative error code in case of failure. - */ -static void gluebi_put_device(struct mtd_info *mtd) -{ - struct ubi_volume *vol; - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - vol->gluebi_refcount -= 1; - ubi_assert(vol->gluebi_refcount >= 0); - if (vol->gluebi_refcount == 0) - ubi_close_volume(vol->gluebi_desc); -} - -/** - * gluebi_read - read operation of emulated MTD devices. - * @mtd: MTD device description object - * @from: absolute offset from where to read - * @len: how many bytes to read - * @retlen: count of read bytes is returned here - * @buf: buffer to store the read data - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, unsigned char *buf) -{ - int err = 0, lnum, offs, total_read; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = from; - - dbg_msg("read %zd bytes from offset %lld", len, from); - - if (len < 0 || from < 0 || from + len > mtd->size) - return -EINVAL; - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; - - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; - - total_read = len; - while (total_read) { - size_t to_read = mtd->erasesize - offs; - - if (to_read > total_read) - to_read = total_read; - - err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs, - to_read, 0); - if (err) - break; - - lnum += 1; - offs = 0; - total_read -= to_read; - buf += to_read; - } - - *retlen = len - total_read; - return err; -} - -/** - * gluebi_write - write operation of emulated MTD devices. - * @mtd: MTD device description object - * @to: absolute offset where to write - * @len: how many bytes to write - * @retlen: count of written bytes is returned here - * @buf: buffer with data to write - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - int err = 0, lnum, offs, total_written; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = to; - - dbg_msg("write %zd bytes to offset %lld", len, to); - - if (len < 0 || to < 0 || len + to > mtd->size) - return -EINVAL; - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; - - if (ubi->ro_mode) - return -EROFS; - - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; - - if (len % mtd->writesize || offs % mtd->writesize) - return -EINVAL; - - total_written = len; - while (total_written) { - size_t to_write = mtd->erasesize - offs; - - if (to_write > total_written) - to_write = total_written; - - err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs, - to_write, UBI_UNKNOWN); - if (err) - break; - - lnum += 1; - offs = 0; - total_written -= to_write; - buf += to_write; - } - - *retlen = len - total_written; - return err; -} - -/** - * gluebi_erase - erase operation of emulated MTD devices. - * @mtd: the MTD device description object - * @instr: the erase operation description - * - * This function calls the erase callback when finishes. Returns zero in case - * of success and a negative error code in case of failure. - */ -static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - int err, i, lnum, count; - struct ubi_volume *vol; - struct ubi_device *ubi; - - dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr); - - if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) - return -EINVAL; - - if (instr->len < 0 || instr->addr + instr->len > mtd->size) - return -EINVAL; - - if (instr->addr % mtd->writesize || instr->len % mtd->writesize) - return -EINVAL; - - lnum = instr->addr / mtd->erasesize; - count = instr->len / mtd->erasesize; - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; - - if (ubi->ro_mode) - return -EROFS; - - for (i = 0; i < count; i++) { - err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i); - if (err) - goto out_err; - } - - /* - * MTD erase operations are synchronous, so we have to make sure the - * physical eraseblock is wiped out. - */ - err = ubi_wl_flush(ubi); - if (err) - goto out_err; - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - return 0; - -out_err: - instr->state = MTD_ERASE_FAILED; - instr->fail_addr = lnum * mtd->erasesize; - return err; -} - -/** - * ubi_create_gluebi - initialize gluebi for an UBI volume. - * @ubi: UBI device description object - * @vol: volume description object - * - * This function is called when an UBI volume is created in order to create - * corresponding fake MTD device. Returns zero in case of success and a - * negative error code in case of failure. - */ -int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) -{ - struct mtd_info *mtd = &vol->gluebi_mtd; - - mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL); - if (!mtd->name) - return -ENOMEM; - - mtd->type = MTD_UBIVOLUME; - if (!ubi->ro_mode) - mtd->flags = MTD_WRITEABLE; - mtd->writesize = ubi->min_io_size; - mtd->owner = THIS_MODULE; - mtd->size = vol->usable_leb_size * vol->reserved_pebs; - mtd->erasesize = vol->usable_leb_size; - mtd->read = gluebi_read; - mtd->write = gluebi_write; - mtd->erase = gluebi_erase; - mtd->get_device = gluebi_get_device; - mtd->put_device = gluebi_put_device; - - if (add_mtd_device(mtd)) { - ubi_err("cannot not add MTD device\n"); - kfree(mtd->name); - return -ENFILE; - } - - dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u", - mtd->index, mtd->name, mtd->size, mtd->erasesize); - return 0; -} - -/** - * ubi_destroy_gluebi - close gluebi for an UBI volume. - * @vol: volume description object - * - * This function is called when an UBI volume is removed in order to remove - * corresponding fake MTD device. Returns zero in case of success and a - * negative error code in case of failure. - */ -int ubi_destroy_gluebi(struct ubi_volume *vol) -{ - int err; - struct mtd_info *mtd = &vol->gluebi_mtd; - - dbg_msg("remove mtd%d", mtd->index); - err = del_mtd_device(mtd); - if (err) - return err; - kfree(mtd->name); - return 0; -} diff --git a/trunk/drivers/mtd/ubi/io.c b/trunk/drivers/mtd/ubi/io.c deleted file mode 100644 index 438914d05151..000000000000 --- a/trunk/drivers/mtd/ubi/io.c +++ /dev/null @@ -1,1259 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (c) Nokia Corporation, 2006, 2007 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * UBI input/output unit. - * - * This unit provides a uniform way to work with all kinds of the underlying - * MTD devices. It also implements handy functions for reading and writing UBI - * headers. - * - * We are trying to have a paranoid mindset and not to trust to what we read - * from the flash media in order to be more secure and robust. So this unit - * validates every single header it reads from the flash media. - * - * Some words about how the eraseblock headers are stored. - * - * The erase counter header is always stored at offset zero. By default, the - * VID header is stored after the EC header at the closest aligned offset - * (i.e. aligned to the minimum I/O unit size). Data starts next to the VID - * header at the closest aligned offset. But this default layout may be - * changed. For example, for different reasons (e.g., optimization) UBI may be - * asked to put the VID header at further offset, and even at an unaligned - * offset. Of course, if the offset of the VID header is unaligned, UBI adds - * proper padding in front of it. Data offset may also be changed but it has to - * be aligned. - * - * About minimal I/O units. In general, UBI assumes flash device model where - * there is only one minimal I/O unit size. E.g., in case of NOR flash it is 1, - * in case of NAND flash it is a NAND page, etc. This is reported by MTD in the - * @ubi->mtd->writesize field. But as an exception, UBI admits of using another - * (smaller) minimal I/O unit size for EC and VID headers to make it possible - * to do different optimizations. - * - * This is extremely useful in case of NAND flashes which admit of several - * write operations to one NAND page. In this case UBI can fit EC and VID - * headers at one NAND page. Thus, UBI may use "sub-page" size as the minimal - * I/O unit for the headers (the @ubi->hdrs_min_io_size field). But it still - * reports NAND page size (@ubi->min_io_size) as a minimal I/O unit for the UBI - * users. - * - * Example: some Samsung NANDs with 2KiB pages allow 4x 512-byte writes, so - * although the minimal I/O unit is 2K, UBI uses 512 bytes for EC and VID - * headers. - * - * Q: why not just to treat sub-page as a minimal I/O unit of this flash - * device, e.g., make @ubi->min_io_size = 512 in the example above? - * - * A: because when writing a sub-page, MTD still writes a full 2K page but the - * bytes which are no relevant to the sub-page are 0xFF. So, basically, writing - * 4x512 sub-pages is 4 times slower then writing one 2KiB NAND page. Thus, we - * prefer to use sub-pages only for EV and VID headers. - * - * As it was noted above, the VID header may start at a non-aligned offset. - * For example, in case of a 2KiB page NAND flash with a 512 bytes sub-page, - * the VID header may reside at offset 1984 which is the last 64 bytes of the - * last sub-page (EC header is always at offset zero). This causes some - * difficulties when reading and writing VID headers. - * - * Suppose we have a 64-byte buffer and we read a VID header at it. We change - * the data and want to write this VID header out. As we can only write in - * 512-byte chunks, we have to allocate one more buffer and copy our VID header - * to offset 448 of this buffer. - * - * The I/O unit does the following trick in order to avoid this extra copy. - * It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header - * and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the - * VID header is being written out, it shifts the VID header pointer back and - * writes the whole sub-page. - */ - -#include -#include -#include "ubi.h" - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum); -static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum); -static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, - const struct ubi_ec_hdr *ec_hdr); -static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); -static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, - const struct ubi_vid_hdr *vid_hdr); -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len); -#else -#define paranoid_check_not_bad(ubi, pnum) 0 -#define paranoid_check_peb_ec_hdr(ubi, pnum) 0 -#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0 -#define paranoid_check_peb_vid_hdr(ubi, pnum) 0 -#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0 -#define paranoid_check_all_ff(ubi, pnum, offset, len) 0 -#endif - -/** - * ubi_io_read - read data from a physical eraseblock. - * @ubi: UBI device description object - * @buf: buffer where to store the read data - * @pnum: physical eraseblock number to read from - * @offset: offset within the physical eraseblock from where to read - * @len: how many bytes to read - * - * This function reads data from offset @offset of physical eraseblock @pnum - * and stores the read data in the @buf buffer. The following return codes are - * possible: - * - * o %0 if all the requested data were successfully read; - * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but - * correctable bit-flips were detected; this is harmless but may indicate - * that this eraseblock may become bad soon (but do not have to); - * o %-EBADMSG if the MTD subsystem reported about data data integrity - * problems, for example it can me an ECC error in case of NAND; this most - * probably means that the data is corrupted; - * o %-EIO if some I/O error occurred; - * o other negative error codes in case of other errors. - */ -int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, - int len) -{ - int err, retries = 0; - size_t read; - loff_t addr; - - dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset); - - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - ubi_assert(offset >= 0 && offset + len <= ubi->peb_size); - ubi_assert(len > 0); - - err = paranoid_check_not_bad(ubi, pnum); - if (err) - return err > 0 ? -EINVAL : err; - - addr = (loff_t)pnum * ubi->peb_size + offset; -retry: - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err) { - if (err == -EUCLEAN) { - /* - * -EUCLEAN is reported if there was a bit-flip which - * was corrected, so this is harmless. - */ - ubi_msg("fixable bit-flip detected at PEB %d", pnum); - ubi_assert(len == read); - return UBI_IO_BITFLIPS; - } - - if (read != len && retries++ < UBI_IO_RETRIES) { - dbg_io("error %d while reading %d bytes from PEB %d:%d, " - "read only %zd bytes, retry", - err, len, pnum, offset, read); - yield(); - goto retry; - } - - ubi_err("error %d while reading %d bytes from PEB %d:%d, " - "read %zd bytes", err, len, pnum, offset, read); - ubi_dbg_dump_stack(); - } else { - ubi_assert(len == read); - - if (ubi_dbg_is_bitflip()) { - dbg_msg("bit-flip (emulated)"); - err = UBI_IO_BITFLIPS; - } - } - - return err; -} - -/** - * ubi_io_write - write data to a physical eraseblock. - * @ubi: UBI device description object - * @buf: buffer with the data to write - * @pnum: physical eraseblock number to write to - * @offset: offset within the physical eraseblock where to write - * @len: how many bytes to write - * - * This function writes @len bytes of data from buffer @buf to offset @offset - * of physical eraseblock @pnum. If all the data were successfully written, - * zero is returned. If an error occurred, this function returns a negative - * error code. If %-EIO is returned, the physical eraseblock most probably went - * bad. - * - * Note, in case of an error, it is possible that something was still written - * to the flash media, but may be some garbage. - */ -int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, - int offset, int len) -{ - int err; - size_t written; - loff_t addr; - - dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset); - - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - ubi_assert(offset >= 0 && offset + len <= ubi->peb_size); - ubi_assert(offset % ubi->hdrs_min_io_size == 0); - ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0); - - if (ubi->ro_mode) { - ubi_err("read-only mode"); - return -EROFS; - } - - /* The below has to be compiled out if paranoid checks are disabled */ - - err = paranoid_check_not_bad(ubi, pnum); - if (err) - return err > 0 ? -EINVAL : err; - - /* The area we are writing to has to contain all 0xFF bytes */ - err = paranoid_check_all_ff(ubi, pnum, offset, len); - if (err) - return err > 0 ? -EINVAL : err; - - if (offset >= ubi->leb_start) { - /* - * We write to the data area of the physical eraseblock. Make - * sure it has valid EC and VID headers. - */ - err = paranoid_check_peb_ec_hdr(ubi, pnum); - if (err) - return err > 0 ? -EINVAL : err; - err = paranoid_check_peb_vid_hdr(ubi, pnum); - if (err) - return err > 0 ? -EINVAL : err; - } - - if (ubi_dbg_is_write_failure()) { - dbg_err("cannot write %d bytes to PEB %d:%d " - "(emulated)", len, pnum, offset); - ubi_dbg_dump_stack(); - return -EIO; - } - - addr = (loff_t)pnum * ubi->peb_size + offset; - err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); - if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written" - " %zd bytes", err, len, pnum, offset, written); - ubi_dbg_dump_stack(); - } else - ubi_assert(written == len); - - return err; -} - -/** - * erase_callback - MTD erasure call-back. - * @ei: MTD erase information object. - * - * Note, even though MTD erase interface is asynchronous, all the current - * implementations are synchronous anyway. - */ -static void erase_callback(struct erase_info *ei) -{ - wake_up_interruptible((wait_queue_head_t *)ei->priv); -} - -/** - * do_sync_erase - synchronously erase a physical eraseblock. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to erase - * - * This function synchronously erases physical eraseblock @pnum and returns - * zero in case of success and a negative error code in case of failure. If - * %-EIO is returned, the physical eraseblock most probably went bad. - */ -static int do_sync_erase(const struct ubi_device *ubi, int pnum) -{ - int err, retries = 0; - struct erase_info ei; - wait_queue_head_t wq; - - dbg_io("erase PEB %d", pnum); - -retry: - init_waitqueue_head(&wq); - memset(&ei, 0, sizeof(struct erase_info)); - - ei.mtd = ubi->mtd; - ei.addr = pnum * ubi->peb_size; - ei.len = ubi->peb_size; - ei.callback = erase_callback; - ei.priv = (unsigned long)&wq; - - err = ubi->mtd->erase(ubi->mtd, &ei); - if (err) { - if (retries++ < UBI_IO_RETRIES) { - dbg_io("error %d while erasing PEB %d, retry", - err, pnum); - yield(); - goto retry; - } - ubi_err("cannot erase PEB %d, error %d", pnum, err); - ubi_dbg_dump_stack(); - return err; - } - - err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || - ei.state == MTD_ERASE_FAILED); - if (err) { - ubi_err("interrupted PEB %d erasure", pnum); - return -EINTR; - } - - if (ei.state == MTD_ERASE_FAILED) { - if (retries++ < UBI_IO_RETRIES) { - dbg_io("error while erasing PEB %d, retry", pnum); - yield(); - goto retry; - } - ubi_err("cannot erase PEB %d", pnum); - ubi_dbg_dump_stack(); - return -EIO; - } - - err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size); - if (err) - return err > 0 ? -EINVAL : err; - - if (ubi_dbg_is_erase_failure() && !err) { - dbg_err("cannot erase PEB %d (emulated)", pnum); - return -EIO; - } - - return 0; -} - -/** - * check_pattern - check if buffer contains only a certain byte pattern. - * @buf: buffer to check - * @patt: the pattern to check - * @size: buffer size in bytes - * - * This function returns %1 in there are only @patt bytes in @buf, and %0 if - * something else was also found. - */ -static int check_pattern(const void *buf, uint8_t patt, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (((const uint8_t *)buf)[i] != patt) - return 0; - return 1; -} - -/* Patterns to write to a physical eraseblock when torturing it */ -static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; - -/** - * torture_peb - test a supposedly bad physical eraseblock. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to test - * - * This function returns %-EIO if the physical eraseblock did not pass the - * test, a positive number of erase operations done if the test was - * successfully passed, and other negative error codes in case of other errors. - */ -static int torture_peb(const struct ubi_device *ubi, int pnum) -{ - void *buf; - int err, i, patt_count; - - buf = kmalloc(ubi->peb_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - patt_count = ARRAY_SIZE(patterns); - ubi_assert(patt_count > 0); - - for (i = 0; i < patt_count; i++) { - err = do_sync_erase(ubi, pnum); - if (err) - goto out; - - /* Make sure the PEB contains only 0xFF bytes */ - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); - if (err) - goto out; - - err = check_pattern(buf, 0xFF, ubi->peb_size); - if (err == 0) { - ubi_err("erased PEB %d, but a non-0xFF byte found", - pnum); - err = -EIO; - goto out; - } - - /* Write a pattern and check it */ - memset(buf, patterns[i], ubi->peb_size); - err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size); - if (err) - goto out; - - memset(buf, ~patterns[i], ubi->peb_size); - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); - if (err) - goto out; - - err = check_pattern(buf, patterns[i], ubi->peb_size); - if (err == 0) { - ubi_err("pattern %x checking failed for PEB %d", - patterns[i], pnum); - err = -EIO; - goto out; - } - } - - err = patt_count; - -out: - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) - /* - * If a bit-flip or data integrity error was detected, the test - * has not passed because it happened on a freshly erased - * physical eraseblock which means something is wrong with it. - */ - err = -EIO; - kfree(buf); - return err; -} - -/** - * ubi_io_sync_erase - synchronously erase a physical eraseblock. - * @ubi: UBI device description object - * @pnum: physical eraseblock number to erase - * @torture: if this physical eraseblock has to be tortured - * - * This function synchronously erases physical eraseblock @pnum. If @torture - * flag is not zero, the physical eraseblock is checked by means of writing - * different patterns to it and reading them back. If the torturing is enabled, - * the physical eraseblock is erased more then once. - * - * This function returns the number of erasures made in case of success, %-EIO - * if the erasure failed or the torturing test failed, and other negative error - * codes in case of other errors. Note, %-EIO means that the physical - * eraseblock is bad. - */ -int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture) -{ - int err, ret = 0; - - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - err = paranoid_check_not_bad(ubi, pnum); - if (err != 0) - return err > 0 ? -EINVAL : err; - - if (ubi->ro_mode) { - ubi_err("read-only mode"); - return -EROFS; - } - - if (torture) { - ret = torture_peb(ubi, pnum); - if (ret < 0) - return ret; - } - - err = do_sync_erase(ubi, pnum); - if (err) - return err; - - return ret + 1; -} - -/** - * ubi_io_is_bad - check if a physical eraseblock is bad. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * - * This function returns a positive number if the physical eraseblock is bad, - * zero if not, and a negative error code if an error occurred. - */ -int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) -{ - struct mtd_info *mtd = ubi->mtd; - - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - if (ubi->bad_allowed) { - int ret; - - ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); - if (ret < 0) - ubi_err("error %d while checking if PEB %d is bad", - ret, pnum); - else if (ret) - dbg_io("PEB %d is bad", pnum); - return ret; - } - - return 0; -} - -/** - * ubi_io_mark_bad - mark a physical eraseblock as bad. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to mark - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) -{ - int err; - struct mtd_info *mtd = ubi->mtd; - - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - if (ubi->ro_mode) { - ubi_err("read-only mode"); - return -EROFS; - } - - if (!ubi->bad_allowed) - return 0; - - err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); - if (err) - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); - return err; -} - -/** - * validate_ec_hdr - validate an erase counter header. - * @ubi: UBI device description object - * @ec_hdr: the erase counter header to check - * - * This function returns zero if the erase counter header is OK, and %1 if - * not. - */ -static int validate_ec_hdr(const struct ubi_device *ubi, - const struct ubi_ec_hdr *ec_hdr) -{ - long long ec; - int vid_hdr_offset, leb_start; - - ec = ubi64_to_cpu(ec_hdr->ec); - vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset); - leb_start = ubi32_to_cpu(ec_hdr->data_offset); - - if (ec_hdr->version != UBI_VERSION) { - ubi_err("node with incompatible UBI version found: " - "this UBI version is %d, image version is %d", - UBI_VERSION, (int)ec_hdr->version); - goto bad; - } - - if (vid_hdr_offset != ubi->vid_hdr_offset) { - ubi_err("bad VID header offset %d, expected %d", - vid_hdr_offset, ubi->vid_hdr_offset); - goto bad; - } - - if (leb_start != ubi->leb_start) { - ubi_err("bad data offset %d, expected %d", - leb_start, ubi->leb_start); - goto bad; - } - - if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) { - ubi_err("bad erase counter %lld", ec); - goto bad; - } - - return 0; - -bad: - ubi_err("bad EC header"); - ubi_dbg_dump_ec_hdr(ec_hdr); - ubi_dbg_dump_stack(); - return 1; -} - -/** - * ubi_io_read_ec_hdr - read and check an erase counter header. - * @ubi: UBI device description object - * @pnum: physical eraseblock to read from - * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter - * header - * @verbose: be verbose if the header is corrupted or was not found - * - * This function reads erase counter header from physical eraseblock @pnum and - * stores it in @ec_hdr. This function also checks CRC checksum of the read - * erase counter header. The following codes may be returned: - * - * o %0 if the CRC checksum is correct and the header was successfully read; - * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected - * and corrected by the flash driver; this is harmless but may indicate that - * this eraseblock may become bad soon (but may be not); - * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error); - * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; - * o a negative error code in case of failure. - */ -int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_ec_hdr *ec_hdr, int verbose) -{ - int err, read_err = 0; - uint32_t crc, magic, hdr_crc; - - dbg_io("read EC header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err) { - if (err != UBI_IO_BITFLIPS && err != -EBADMSG) - return err; - - /* - * We read all the data, but either a correctable bit-flip - * occurred, or MTD reported about some data integrity error, - * like an ECC error in case of NAND. The former is harmless, - * the later may mean that the read data is corrupted. But we - * have a CRC check-sum and we will detect this. If the EC - * header is still OK, we just report this as there was a - * bit-flip. - */ - read_err = err; - } - - magic = ubi32_to_cpu(ec_hdr->magic); - if (magic != UBI_EC_HDR_MAGIC) { - /* - * The magic field is wrong. Let's check if we have read all - * 0xFF. If yes, this physical eraseblock is assumed to be - * empty. - * - * But if there was a read error, we do not test it for all - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and we anyway cannot treat it as empty. - */ - if (read_err != -EBADMSG && - check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { - /* The physical eraseblock is supposedly empty */ - - /* - * The below is just a paranoid check, it has to be - * compiled out if paranoid checks are disabled. - */ - err = paranoid_check_all_ff(ubi, pnum, 0, - ubi->peb_size); - if (err) - return err > 0 ? UBI_IO_BAD_EC_HDR : err; - - if (verbose) - ubi_warn("no EC header found at PEB %d, " - "only 0xFF bytes", pnum); - return UBI_IO_PEB_EMPTY; - } - - /* - * This is not a valid erase counter header, and these are not - * 0xFF bytes. Report that the header is corrupted. - */ - if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of " - "%08x", pnum, magic, UBI_EC_HDR_MAGIC); - ubi_dbg_dump_ec_hdr(ec_hdr); - } - return UBI_IO_BAD_EC_HDR; - } - - crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); - - if (hdr_crc != crc) { - if (verbose) { - ubi_warn("bad EC header CRC at PEB %d, calculated %#08x," - " read %#08x", pnum, crc, hdr_crc); - ubi_dbg_dump_ec_hdr(ec_hdr); - } - return UBI_IO_BAD_EC_HDR; - } - - /* And of course validate what has just been read from the media */ - err = validate_ec_hdr(ubi, ec_hdr); - if (err) { - ubi_err("validation failed for PEB %d", pnum); - return -EINVAL; - } - - return read_err ? UBI_IO_BITFLIPS : 0; -} - -/** - * ubi_io_write_ec_hdr - write an erase counter header. - * @ubi: UBI device description object - * @pnum: physical eraseblock to write to - * @ec_hdr: the erase counter header to write - * - * This function writes erase counter header described by @ec_hdr to physical - * eraseblock @pnum. It also fills most fields of @ec_hdr before writing, so - * the caller do not have to fill them. Callers must only fill the @ec_hdr->ec - * field. - * - * This function returns zero in case of success and a negative error code in - * case of failure. If %-EIO is returned, the physical eraseblock most probably - * went bad. - */ -int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_ec_hdr *ec_hdr) -{ - int err; - uint32_t crc; - - dbg_io("write EC header to PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC); - ec_hdr->version = UBI_VERSION; - ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset); - ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start); - crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - ec_hdr->hdr_crc = cpu_to_ubi32(crc); - - err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); - if (err) - return -EINVAL; - - err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); - return err; -} - -/** - * validate_vid_hdr - validate a volume identifier header. - * @ubi: UBI device description object - * @vid_hdr: the volume identifier header to check - * - * This function checks that data stored in the volume identifier header - * @vid_hdr. Returns zero if the VID header is OK and %1 if not. - */ -static int validate_vid_hdr(const struct ubi_device *ubi, - const struct ubi_vid_hdr *vid_hdr) -{ - int vol_type = vid_hdr->vol_type; - int copy_flag = vid_hdr->copy_flag; - int vol_id = ubi32_to_cpu(vid_hdr->vol_id); - int lnum = ubi32_to_cpu(vid_hdr->lnum); - int compat = vid_hdr->compat; - int data_size = ubi32_to_cpu(vid_hdr->data_size); - int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - int data_pad = ubi32_to_cpu(vid_hdr->data_pad); - int data_crc = ubi32_to_cpu(vid_hdr->data_crc); - int usable_leb_size = ubi->leb_size - data_pad; - - if (copy_flag != 0 && copy_flag != 1) { - dbg_err("bad copy_flag"); - goto bad; - } - - if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 || - data_pad < 0) { - dbg_err("negative values"); - goto bad; - } - - if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) { - dbg_err("bad vol_id"); - goto bad; - } - - if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) { - dbg_err("bad compat"); - goto bad; - } - - if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE && - compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE && - compat != UBI_COMPAT_REJECT) { - dbg_err("bad compat"); - goto bad; - } - - if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { - dbg_err("bad vol_type"); - goto bad; - } - - if (data_pad >= ubi->leb_size / 2) { - dbg_err("bad data_pad"); - goto bad; - } - - if (vol_type == UBI_VID_STATIC) { - /* - * Although from high-level point of view static volumes may - * contain zero bytes of data, but no VID headers can contain - * zero at these fields, because they empty volumes do not have - * mapped logical eraseblocks. - */ - if (used_ebs == 0) { - dbg_err("zero used_ebs"); - goto bad; - } - if (data_size == 0) { - dbg_err("zero data_size"); - goto bad; - } - if (lnum < used_ebs - 1) { - if (data_size != usable_leb_size) { - dbg_err("bad data_size"); - goto bad; - } - } else if (lnum == used_ebs - 1) { - if (data_size == 0) { - dbg_err("bad data_size at last LEB"); - goto bad; - } - } else { - dbg_err("too high lnum"); - goto bad; - } - } else { - if (copy_flag == 0) { - if (data_crc != 0) { - dbg_err("non-zero data CRC"); - goto bad; - } - if (data_size != 0) { - dbg_err("non-zero data_size"); - goto bad; - } - } else { - if (data_size == 0) { - dbg_err("zero data_size of copy"); - goto bad; - } - } - if (used_ebs != 0) { - dbg_err("bad used_ebs"); - goto bad; - } - } - - return 0; - -bad: - ubi_err("bad VID header"); - ubi_dbg_dump_vid_hdr(vid_hdr); - ubi_dbg_dump_stack(); - return 1; -} - -/** - * ubi_io_read_vid_hdr - read and check a volume identifier header. - * @ubi: UBI device description object - * @pnum: physical eraseblock number to read from - * @vid_hdr: &struct ubi_vid_hdr object where to store the read volume - * identifier header - * @verbose: be verbose if the header is corrupted or wasn't found - * - * This function reads the volume identifier header from physical eraseblock - * @pnum and stores it in @vid_hdr. It also checks CRC checksum of the read - * volume identifier header. The following codes may be returned: - * - * o %0 if the CRC checksum is correct and the header was successfully read; - * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected - * and corrected by the flash driver; this is harmless but may indicate that - * this eraseblock may become bad soon; - * o %UBI_IO_BAD_VID_HRD if the volume identifier header is corrupted (a CRC - * error detected); - * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID - * header there); - * o a negative error code in case of failure. - */ -int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr, int verbose) -{ - int err, read_err = 0; - uint32_t crc, magic, hdr_crc; - void *p; - - dbg_io("read VID header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, - ubi->vid_hdr_alsize); - if (err) { - if (err != UBI_IO_BITFLIPS && err != -EBADMSG) - return err; - - /* - * We read all the data, but either a correctable bit-flip - * occurred, or MTD reported about some data integrity error, - * like an ECC error in case of NAND. The former is harmless, - * the later may mean the read data is corrupted. But we have a - * CRC check-sum and we will identify this. If the VID header is - * still OK, we just report this as there was a bit-flip. - */ - read_err = err; - } - - magic = ubi32_to_cpu(vid_hdr->magic); - if (magic != UBI_VID_HDR_MAGIC) { - /* - * If we have read all 0xFF bytes, the VID header probably does - * not exist and the physical eraseblock is assumed to be free. - * - * But if there was a read error, we do not test the data for - * 0xFFs. Even if it does contain all 0xFFs, this error - * indicates that something is still wrong with this physical - * eraseblock and it cannot be regarded as free. - */ - if (read_err != -EBADMSG && - check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { - /* The physical eraseblock is supposedly free */ - - /* - * The below is just a paranoid check, it has to be - * compiled out if paranoid checks are disabled. - */ - err = paranoid_check_all_ff(ubi, pnum, ubi->leb_start, - ubi->leb_size); - if (err) - return err > 0 ? UBI_IO_BAD_VID_HDR : err; - - if (verbose) - ubi_warn("no VID header found at PEB %d, " - "only 0xFF bytes", pnum); - return UBI_IO_PEB_FREE; - } - - /* - * This is not a valid VID header, and these are not 0xFF - * bytes. Report that the header is corrupted. - */ - if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of " - "%08x", pnum, magic, UBI_VID_HDR_MAGIC); - ubi_dbg_dump_vid_hdr(vid_hdr); - } - return UBI_IO_BAD_VID_HDR; - } - - crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); - - if (hdr_crc != crc) { - if (verbose) { - ubi_warn("bad CRC at PEB %d, calculated %#08x, " - "read %#08x", pnum, crc, hdr_crc); - ubi_dbg_dump_vid_hdr(vid_hdr); - } - return UBI_IO_BAD_VID_HDR; - } - - /* Validate the VID header that we have just read */ - err = validate_vid_hdr(ubi, vid_hdr); - if (err) { - ubi_err("validation failed for PEB %d", pnum); - return -EINVAL; - } - - return read_err ? UBI_IO_BITFLIPS : 0; -} - -/** - * ubi_io_write_vid_hdr - write a volume identifier header. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to write to - * @vid_hdr: the volume identifier header to write - * - * This function writes the volume identifier header described by @vid_hdr to - * physical eraseblock @pnum. This function automatically fills the - * @vid_hdr->magic and the @vid_hdr->version fields, as well as calculates - * header CRC checksum and stores it at vid_hdr->hdr_crc. - * - * This function returns zero in case of success and a negative error code in - * case of failure. If %-EIO is returned, the physical eraseblock probably went - * bad. - */ -int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr) -{ - int err; - uint32_t crc; - void *p; - - dbg_io("write VID header to PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - - err = paranoid_check_peb_ec_hdr(ubi, pnum); - if (err) - return err > 0 ? -EINVAL: err; - - vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC); - vid_hdr->version = UBI_VERSION; - crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); - vid_hdr->hdr_crc = cpu_to_ubi32(crc); - - err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); - if (err) - return -EINVAL; - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, - ubi->vid_hdr_alsize); - return err; -} - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID - -/** - * paranoid_check_not_bad - ensure that a physical eraseblock is not bad. - * @ubi: UBI device description object - * @pnum: physical eraseblock number to check - * - * This function returns zero if the physical eraseblock is good, a positive - * number if it is bad and a negative error code if an error occurred. - */ -static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum) -{ - int err; - - err = ubi_io_is_bad(ubi, pnum); - if (!err) - return err; - - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_dbg_dump_stack(); - return err; -} - -/** - * paranoid_check_ec_hdr - check if an erase counter header is all right. - * @ubi: UBI device description object - * @pnum: physical eraseblock number the erase counter header belongs to - * @ec_hdr: the erase counter header to check - * - * This function returns zero if the erase counter header contains valid - * values, and %1 if not. - */ -static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, - const struct ubi_ec_hdr *ec_hdr) -{ - int err; - uint32_t magic; - - magic = ubi32_to_cpu(ec_hdr->magic); - if (magic != UBI_EC_HDR_MAGIC) { - ubi_err("bad magic %#08x, must be %#08x", - magic, UBI_EC_HDR_MAGIC); - goto fail; - } - - err = validate_ec_hdr(ubi, ec_hdr); - if (err) { - ubi_err("paranoid check failed for PEB %d", pnum); - goto fail; - } - - return 0; - -fail: - ubi_dbg_dump_ec_hdr(ec_hdr); - ubi_dbg_dump_stack(); - return 1; -} - -/** - * paranoid_check_peb_ec_hdr - check that the erase counter header of a - * physical eraseblock is in-place and is all right. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * - * This function returns zero if the erase counter header is all right, %1 if - * not, and a negative error code if an error occurred. - */ -static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) -{ - int err; - uint32_t crc, hdr_crc; - struct ubi_ec_hdr *ec_hdr; - - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - - err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) - goto exit; - - crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); - if (hdr_crc != crc) { - ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_dbg_dump_ec_hdr(ec_hdr); - ubi_dbg_dump_stack(); - err = 1; - goto exit; - } - - err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); - -exit: - kfree(ec_hdr); - return err; -} - -/** - * paranoid_check_vid_hdr - check that a volume identifier header is all right. - * @ubi: UBI device description object - * @pnum: physical eraseblock number the volume identifier header belongs to - * @vid_hdr: the volume identifier header to check - * - * This function returns zero if the volume identifier header is all right, and - * %1 if not. - */ -static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, - const struct ubi_vid_hdr *vid_hdr) -{ - int err; - uint32_t magic; - - magic = ubi32_to_cpu(vid_hdr->magic); - if (magic != UBI_VID_HDR_MAGIC) { - ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", - magic, pnum, UBI_VID_HDR_MAGIC); - goto fail; - } - - err = validate_vid_hdr(ubi, vid_hdr); - if (err) { - ubi_err("paranoid check failed for PEB %d", pnum); - goto fail; - } - - return err; - -fail: - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_dbg_dump_vid_hdr(vid_hdr); - ubi_dbg_dump_stack(); - return 1; - -} - -/** - * paranoid_check_peb_vid_hdr - check that the volume identifier header of a - * physical eraseblock is in-place and is all right. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * - * This function returns zero if the volume identifier header is all right, - * %1 if not, and a negative error code if an error occurred. - */ -static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) -{ - int err; - uint32_t crc, hdr_crc; - struct ubi_vid_hdr *vid_hdr; - void *p; - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) - return -ENOMEM; - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, - ubi->vid_hdr_alsize); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) - goto exit; - - crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); - if (hdr_crc != crc) { - ubi_err("bad VID header CRC at PEB %d, calculated %#08x, " - "read %#08x", pnum, crc, hdr_crc); - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_dbg_dump_vid_hdr(vid_hdr); - ubi_dbg_dump_stack(); - err = 1; - goto exit; - } - - err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); - -exit: - ubi_free_vid_hdr(ubi, vid_hdr); - return err; -} - -/** - * paranoid_check_all_ff - check that a region of flash is empty. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * @offset: the starting offset within the physical eraseblock to check - * @len: the length of the region to check - * - * This function returns zero if only 0xFF bytes are present at offset - * @offset of the physical eraseblock @pnum, %1 if not, and a negative error - * code if an error occurred. - */ -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len) -{ - size_t read; - int err; - void *buf; - loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, " - "read %zd bytes", err, len, pnum, offset, read); - goto error; - } - - err = check_pattern(buf, 0xFF, len); - if (err == 0) { - ubi_err("flash region at PEB %d:%d, length %d does not " - "contain all 0xFF bytes", pnum, offset, len); - goto fail; - } - - kfree(buf); - return 0; - -fail: - ubi_err("paranoid check failed for PEB %d", pnum); - dbg_msg("hex dump of the %d-%d region", offset, offset + len); - ubi_dbg_hexdump(buf, len); - err = 1; -error: - ubi_dbg_dump_stack(); - kfree(buf); - return err; -} - -#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/trunk/drivers/mtd/ubi/kapi.c b/trunk/drivers/mtd/ubi/kapi.c deleted file mode 100644 index d352c4575c3d..000000000000 --- a/trunk/drivers/mtd/ubi/kapi.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* This file mostly implements UBI kernel API functions */ - -#include -#include -#include -#include "ubi.h" - -/** - * ubi_get_device_info - get information about UBI device. - * @ubi_num: UBI device number - * @di: the information is stored here - * - * This function returns %0 in case of success and a %-ENODEV if there is no - * such UBI device. - */ -int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) -{ - const struct ubi_device *ubi; - - if (!try_module_get(THIS_MODULE)) - return -ENODEV; - - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || - !ubi_devices[ubi_num]) { - module_put(THIS_MODULE); - return -ENODEV; - } - - ubi = ubi_devices[ubi_num]; - di->ubi_num = ubi->ubi_num; - di->leb_size = ubi->leb_size; - di->min_io_size = ubi->min_io_size; - di->ro_mode = ubi->ro_mode; - di->cdev = MKDEV(ubi->major, 0); - module_put(THIS_MODULE); - return 0; -} -EXPORT_SYMBOL_GPL(ubi_get_device_info); - -/** - * ubi_get_volume_info - get information about UBI volume. - * @desc: volume descriptor - * @vi: the information is stored here - */ -void ubi_get_volume_info(struct ubi_volume_desc *desc, - struct ubi_volume_info *vi) -{ - const struct ubi_volume *vol = desc->vol; - const struct ubi_device *ubi = vol->ubi; - - vi->vol_id = vol->vol_id; - vi->ubi_num = ubi->ubi_num; - vi->size = vol->reserved_pebs; - vi->used_bytes = vol->used_bytes; - vi->vol_type = vol->vol_type; - vi->corrupted = vol->corrupted; - vi->upd_marker = vol->upd_marker; - vi->alignment = vol->alignment; - vi->usable_leb_size = vol->usable_leb_size; - vi->name_len = vol->name_len; - vi->name = vol->name; - vi->cdev = MKDEV(ubi->major, vi->vol_id + 1); -} -EXPORT_SYMBOL_GPL(ubi_get_volume_info); - -/** - * ubi_open_volume - open UBI volume. - * @ubi_num: UBI device number - * @vol_id: volume ID - * @mode: open mode - * - * The @mode parameter specifies if the volume should be opened in read-only - * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that - * nobody else will be able to open this volume. UBI allows to have many volume - * readers and one writer at a time. - * - * If a static volume is being opened for the first time since boot, it will be - * checked by this function, which means it will be fully read and the CRC - * checksum of each logical eraseblock will be checked. - * - * This function returns volume descriptor in case of success and a negative - * error code in case of failure. - */ -struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) -{ - int err; - struct ubi_volume_desc *desc; - struct ubi_device *ubi = ubi_devices[ubi_num]; - struct ubi_volume *vol; - - dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); - - err = -ENODEV; - if (!try_module_get(THIS_MODULE)) - return ERR_PTR(err); - - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi) - goto out_put; - - err = -EINVAL; - if (vol_id < 0 || vol_id >= ubi->vtbl_slots) - goto out_put; - if (mode != UBI_READONLY && mode != UBI_READWRITE && - mode != UBI_EXCLUSIVE) - goto out_put; - - desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); - if (!desc) { - err = -ENOMEM; - goto out_put; - } - - spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[vol_id]; - if (!vol) { - err = -ENODEV; - goto out_unlock; - } - - err = -EBUSY; - switch (mode) { - case UBI_READONLY: - if (vol->exclusive) - goto out_unlock; - vol->readers += 1; - break; - - case UBI_READWRITE: - if (vol->exclusive || vol->writers > 0) - goto out_unlock; - vol->writers += 1; - break; - - case UBI_EXCLUSIVE: - if (vol->exclusive || vol->writers || vol->readers) - goto out_unlock; - vol->exclusive = 1; - break; - } - spin_unlock(&ubi->volumes_lock); - - desc->vol = vol; - desc->mode = mode; - - /* - * To prevent simultaneous checks of the same volume we use @vtbl_mutex, - * although it is not the purpose it was introduced for. - */ - mutex_lock(&ubi->vtbl_mutex); - if (!vol->checked) { - /* This is the first open - check the volume */ - err = ubi_check_volume(ubi, vol_id); - if (err < 0) { - mutex_unlock(&ubi->vtbl_mutex); - ubi_close_volume(desc); - return ERR_PTR(err); - } - if (err == 1) { - ubi_warn("volume %d on UBI device %d is corrupted", - vol_id, ubi->ubi_num); - vol->corrupted = 1; - } - vol->checked = 1; - } - mutex_unlock(&ubi->vtbl_mutex); - return desc; - -out_unlock: - spin_unlock(&ubi->volumes_lock); - kfree(desc); -out_put: - module_put(THIS_MODULE); - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(ubi_open_volume); - -/** - * ubi_open_volume_nm - open UBI volume by name. - * @ubi_num: UBI device number - * @name: volume name - * @mode: open mode - * - * This function is similar to 'ubi_open_volume()', but opens a volume by name. - */ -struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, - int mode) -{ - int i, vol_id = -1, len; - struct ubi_volume_desc *ret; - struct ubi_device *ubi; - - dbg_msg("open volume %s, mode %d", name, mode); - - if (!name) - return ERR_PTR(-EINVAL); - - len = strnlen(name, UBI_VOL_NAME_MAX + 1); - if (len > UBI_VOL_NAME_MAX) - return ERR_PTR(-EINVAL); - - ret = ERR_PTR(-ENODEV); - if (!try_module_get(THIS_MODULE)) - return ret; - - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num]) - goto out_put; - - ubi = ubi_devices[ubi_num]; - - spin_lock(&ubi->volumes_lock); - /* Walk all volumes of this UBI device */ - for (i = 0; i < ubi->vtbl_slots; i++) { - struct ubi_volume *vol = ubi->volumes[i]; - - if (vol && len == vol->name_len && !strcmp(name, vol->name)) { - vol_id = i; - break; - } - } - spin_unlock(&ubi->volumes_lock); - - if (vol_id < 0) - goto out_put; - - ret = ubi_open_volume(ubi_num, vol_id, mode); - -out_put: - module_put(THIS_MODULE); - return ret; -} -EXPORT_SYMBOL_GPL(ubi_open_volume_nm); - -/** - * ubi_close_volume - close UBI volume. - * @desc: volume descriptor - */ -void ubi_close_volume(struct ubi_volume_desc *desc) -{ - struct ubi_volume *vol = desc->vol; - - dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); - - spin_lock(&vol->ubi->volumes_lock); - switch (desc->mode) { - case UBI_READONLY: - vol->readers -= 1; - break; - case UBI_READWRITE: - vol->writers -= 1; - break; - case UBI_EXCLUSIVE: - vol->exclusive = 0; - } - spin_unlock(&vol->ubi->volumes_lock); - - kfree(desc); - module_put(THIS_MODULE); -} -EXPORT_SYMBOL_GPL(ubi_close_volume); - -/** - * ubi_leb_read - read data. - * @desc: volume descriptor - * @lnum: logical eraseblock number to read from - * @buf: buffer where to store the read data - * @offset: offset within the logical eraseblock to read from - * @len: how many bytes to read - * @check: whether UBI has to check the read data's CRC or not. - * - * This function reads data from offset @offset of logical eraseblock @lnum and - * stores the data at @buf. When reading from static volumes, @check specifies - * whether the data has to be checked or not. If yes, the whole logical - * eraseblock will be read and its CRC checksum will be checked (i.e., the CRC - * checksum is per-eraseblock). So checking may substantially slow down the - * read speed. The @check argument is ignored for dynamic volumes. - * - * In case of success, this function returns zero. In case of failure, this - * function returns a negative error code. - * - * %-EBADMSG error code is returned: - * o for both static and dynamic volumes if MTD driver has detected a data - * integrity problem (unrecoverable ECC checksum mismatch in case of NAND); - * o for static volumes in case of data CRC mismatch. - * - * If the volume is damaged because of an interrupted update this function just - * returns immediately with %-EBADF error code. - */ -int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, - int len, int check) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int err, vol_id = vol->vol_id; - - dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); - - if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 || - lnum >= vol->used_ebs || offset < 0 || len < 0 || - offset + len > vol->usable_leb_size) - return -EINVAL; - - if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 && - offset + len > vol->last_eb_bytes) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - if (len == 0) - return 0; - - err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { - ubi_warn("mark volume %d as corrupted", vol_id); - vol->corrupted = 1; - } - - return err; -} -EXPORT_SYMBOL_GPL(ubi_leb_read); - -/** - * ubi_leb_write - write data. - * @desc: volume descriptor - * @lnum: logical eraseblock number to write to - * @buf: data to write - * @offset: offset within the logical eraseblock where to write - * @len: how many bytes to write - * @dtype: expected data type - * - * This function writes @len bytes of data from @buf to offset @offset of - * logical eraseblock @lnum. The @dtype argument describes expected lifetime of - * the data. - * - * This function takes care of physical eraseblock write failures. If write to - * the physical eraseblock write operation fails, the logical eraseblock is - * re-mapped to another physical eraseblock, the data is recovered, and the - * write finishes. UBI has a pool of reserved physical eraseblocks for this. - * - * If all the data were successfully written, zero is returned. If an error - * occurred and UBI has not been able to recover from it, this function returns - * a negative error code. Note, in case of an error, it is possible that - * something was still written to the flash media, but that may be some - * garbage. - * - * If the volume is damaged because of an interrupted update this function just - * returns immediately with %-EBADF code. - */ -int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, - int offset, int len, int dtype) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int vol_id = vol->vol_id; - - dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset); - - if (vol_id < 0 || vol_id >= ubi->vtbl_slots) - return -EINVAL; - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; - - if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 || - offset + len > vol->usable_leb_size || offset % ubi->min_io_size || - len % ubi->min_io_size) - return -EINVAL; - - if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && - dtype != UBI_UNKNOWN) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - - if (len == 0) - return 0; - - return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype); -} -EXPORT_SYMBOL_GPL(ubi_leb_write); - -/* - * ubi_leb_change - change logical eraseblock atomically. - * @desc: volume descriptor - * @lnum: logical eraseblock number to change - * @buf: data to write - * @len: how many bytes to write - * @dtype: expected data type - * - * This function changes the contents of a logical eraseblock atomically. @buf - * has to contain new logical eraseblock data, and @len - the length of the - * data, which has to be aligned. The length may be shorter then the logical - * eraseblock size, ant the logical eraseblock may be appended to more times - * later on. This function guarantees that in case of an unclean reboot the old - * contents is preserved. Returns zero in case of success and a negative error - * code in case of failure. - */ -int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, - int len, int dtype) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int vol_id = vol->vol_id; - - dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum); - - if (vol_id < 0 || vol_id >= ubi->vtbl_slots) - return -EINVAL; - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; - - if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || - len > vol->usable_leb_size || len % ubi->min_io_size) - return -EINVAL; - - if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && - dtype != UBI_UNKNOWN) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - - if (len == 0) - return 0; - - return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype); -} -EXPORT_SYMBOL_GPL(ubi_leb_change); - -/** - * ubi_leb_erase - erase logical eraseblock. - * @desc: volume descriptor - * @lnum: logical eraseblock number - * - * This function un-maps logical eraseblock @lnum and synchronously erases the - * correspondent physical eraseblock. Returns zero in case of success and a - * negative error code in case of failure. - * - * If the volume is damaged because of an interrupted update this function just - * returns immediately with %-EBADF code. - */ -int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int err, vol_id = vol->vol_id; - - dbg_msg("erase LEB %d:%d", vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; - - if (lnum < 0 || lnum >= vol->reserved_pebs) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - - err = ubi_eba_unmap_leb(ubi, vol_id, lnum); - if (err) - return err; - - return ubi_wl_flush(ubi); -} -EXPORT_SYMBOL_GPL(ubi_leb_erase); - -/** - * ubi_leb_unmap - un-map logical eraseblock. - * @desc: volume descriptor - * @lnum: logical eraseblock number - * - * This function un-maps logical eraseblock @lnum and schedules the - * corresponding physical eraseblock for erasure, so that it will eventually be - * physically erased in background. This operation is much faster then the - * erase operation. - * - * Unlike erase, the un-map operation does not guarantee that the logical - * eraseblock will contain all 0xFF bytes when UBI is initialized again. For - * example, if several logical eraseblocks are un-mapped, and an unclean reboot - * happens after this, the logical eraseblocks will not necessarily be - * un-mapped again when this MTD device is attached. They may actually be - * mapped to the same physical eraseblocks again. So, this function has to be - * used with care. - * - * In other words, when un-mapping a logical eraseblock, UBI does not store - * any information about this on the flash media, it just marks the logical - * eraseblock as "un-mapped" in RAM. If UBI is detached before the physical - * eraseblock is physically erased, it will be mapped again to the same logical - * eraseblock when the MTD device is attached again. - * - * The main and obvious use-case of this function is when the contents of a - * logical eraseblock has to be re-written. Then it is much more efficient to - * first un-map it, then write new data, rather then first erase it, then write - * new data. Note, once new data has been written to the logical eraseblock, - * UBI guarantees that the old contents has gone forever. In other words, if an - * unclean reboot happens after the logical eraseblock has been un-mapped and - * then written to, it will contain the last written data. - * - * This function returns zero in case of success and a negative error code in - * case of failure. If the volume is damaged because of an interrupted update - * this function just returns immediately with %-EBADF code. - */ -int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int vol_id = vol->vol_id; - - dbg_msg("unmap LEB %d:%d", vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; - - if (lnum < 0 || lnum >= vol->reserved_pebs) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - - return ubi_eba_unmap_leb(ubi, vol_id, lnum); -} -EXPORT_SYMBOL_GPL(ubi_leb_unmap); - -/** - * ubi_is_mapped - check if logical eraseblock is mapped. - * @desc: volume descriptor - * @lnum: logical eraseblock number - * - * This function checks if logical eraseblock @lnum is mapped to a physical - * eraseblock. If a logical eraseblock is un-mapped, this does not necessarily - * mean it will still be un-mapped after the UBI device is re-attached. The - * logical eraseblock may become mapped to the physical eraseblock it was last - * mapped to. - * - * This function returns %1 if the LEB is mapped, %0 if not, and a negative - * error code in case of failure. If the volume is damaged because of an - * interrupted update this function just returns immediately with %-EBADF error - * code. - */ -int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum) -{ - struct ubi_volume *vol = desc->vol; - - dbg_msg("test LEB %d:%d", vol->vol_id, lnum); - - if (lnum < 0 || lnum >= vol->reserved_pebs) - return -EINVAL; - - if (vol->upd_marker) - return -EBADF; - - return vol->eba_tbl[lnum] >= 0; -} -EXPORT_SYMBOL_GPL(ubi_is_mapped); diff --git a/trunk/drivers/mtd/ubi/misc.c b/trunk/drivers/mtd/ubi/misc.c deleted file mode 100644 index 38d4e6757dc7..000000000000 --- a/trunk/drivers/mtd/ubi/misc.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* Here we keep miscellaneous functions which are used all over the UBI code */ - -#include "ubi.h" - -/** - * calc_data_len - calculate how much real data is stored in a buffer. - * @ubi: UBI device description object - * @buf: a buffer with the contents of the physical eraseblock - * @length: the buffer length - * - * This function calculates how much "real data" is stored in @buf and returnes - * the length. Continuous 0xFF bytes at the end of the buffer are not - * considered as "real data". - */ -int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, - int length) -{ - int i; - - ubi_assert(length % ubi->min_io_size == 0); - - for (i = length - 1; i >= 0; i--) - if (((const uint8_t *)buf)[i] != 0xFF) - break; - - /* The resulting length must be aligned to the minimum flash I/O size */ - length = ALIGN(i + 1, ubi->min_io_size); - return length; -} - -/** - * ubi_check_volume - check the contents of a static volume. - * @ubi: UBI device description object - * @vol_id: ID of the volume to check - * - * This function checks if static volume @vol_id is corrupted by fully reading - * it and checking data CRC. This function returns %0 if the volume is not - * corrupted, %1 if it is corrupted and a negative error code in case of - * failure. Dynamic volumes are not checked and zero is returned immediately. - */ -int ubi_check_volume(struct ubi_device *ubi, int vol_id) -{ - void *buf; - int err = 0, i; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - if (vol->vol_type != UBI_STATIC_VOLUME) - return 0; - - buf = kmalloc(vol->usable_leb_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < vol->used_ebs; i++) { - int size; - - if (i == vol->used_ebs - 1) - size = vol->last_eb_bytes; - else - size = vol->usable_leb_size; - - err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1); - if (err) { - if (err == -EBADMSG) - err = 1; - break; - } - } - - kfree(buf); - return err; -} - -/** - * ubi_calculate_rsvd_pool - calculate how many PEBs must be reserved for bad - * eraseblock handling. - * @ubi: UBI device description object - */ -void ubi_calculate_reserved(struct ubi_device *ubi) -{ - ubi->beb_rsvd_level = ubi->good_peb_count/100; - ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE; - if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS) - ubi->beb_rsvd_level = MIN_RESEVED_PEBS; -} diff --git a/trunk/drivers/mtd/ubi/scan.c b/trunk/drivers/mtd/ubi/scan.c deleted file mode 100644 index 473f3200b868..000000000000 --- a/trunk/drivers/mtd/ubi/scan.c +++ /dev/null @@ -1,1368 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * UBI scanning unit. - * - * This unit is responsible for scanning the flash media, checking UBI - * headers and providing complete information about the UBI flash image. - * - * The scanning information is reoresented by a &struct ubi_scan_info' object. - * Information about found volumes is represented by &struct ubi_scan_volume - * objects which are kept in volume RB-tree with root at the @volumes field. - * The RB-tree is indexed by the volume ID. - * - * Found logical eraseblocks are represented by &struct ubi_scan_leb objects. - * These objects are kept in per-volume RB-trees with the root at the - * corresponding &struct ubi_scan_volume object. To put it differently, we keep - * an RB-tree of per-volume objects and each of these objects is the root of - * RB-tree of per-eraseblock objects. - * - * Corrupted physical eraseblocks are put to the @corr list, free physical - * eraseblocks are put to the @free list and the physical eraseblock to be - * erased are put to the @erase list. - */ - -#include -#include -#include "ubi.h" - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_si(const struct ubi_device *ubi, - struct ubi_scan_info *si); -#else -#define paranoid_check_si(ubi, si) 0 -#endif - -/* Temporary variables used during scanning */ -static struct ubi_ec_hdr *ech; -static struct ubi_vid_hdr *vidh; - -int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, - struct list_head *list) -{ - struct ubi_scan_leb *seb; - - if (list == &si->free) - dbg_bld("add to free: PEB %d, EC %d", pnum, ec); - else if (list == &si->erase) - dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); - else if (list == &si->corr) - dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); - else if (list == &si->alien) - dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); - else - BUG(); - - seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); - if (!seb) - return -ENOMEM; - - seb->pnum = pnum; - seb->ec = ec; - list_add_tail(&seb->u.list, list); - return 0; -} - -/** - * commit_to_mean_value - commit intermediate results to the final mean erase - * counter value. - * @si: scanning information - * - * This is a helper function which calculates partial mean erase counter mean - * value and adds it to the resulting mean value. As we can work only in - * integer arithmetic and we want to calculate the mean value of erase counter - * accurately, we first sum erase counter values in @si->ec_sum variable and - * count these components in @si->ec_count. If this temporary @si->ec_sum is - * going to overflow, we calculate the partial mean value - * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec. - */ -static void commit_to_mean_value(struct ubi_scan_info *si) -{ - si->ec_sum /= si->ec_count; - if (si->ec_sum % si->ec_count >= si->ec_count / 2) - si->mean_ec += 1; - si->mean_ec += si->ec_sum; -} - -/** - * validate_vid_hdr - check that volume identifier header is correct and - * consistent. - * @vid_hdr: the volume identifier header to check - * @sv: information about the volume this logical eraseblock belongs to - * @pnum: physical eraseblock number the VID header came from - * - * This function checks that data stored in @vid_hdr is consistent. Returns - * non-zero if an inconsistency was found and zero if not. - * - * Note, UBI does sanity check of everything it reads from the flash media. - * Most of the checks are done in the I/O unit. Here we check that the - * information in the VID header is consistent to the information in other VID - * headers of the same volume. - */ -static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, - const struct ubi_scan_volume *sv, int pnum) -{ - int vol_type = vid_hdr->vol_type; - int vol_id = ubi32_to_cpu(vid_hdr->vol_id); - int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - int data_pad = ubi32_to_cpu(vid_hdr->data_pad); - - if (sv->leb_count != 0) { - int sv_vol_type; - - /* - * This is not the first logical eraseblock belonging to this - * volume. Ensure that the data in its VID header is consistent - * to the data in previous logical eraseblock headers. - */ - - if (vol_id != sv->vol_id) { - dbg_err("inconsistent vol_id"); - goto bad; - } - - if (sv->vol_type == UBI_STATIC_VOLUME) - sv_vol_type = UBI_VID_STATIC; - else - sv_vol_type = UBI_VID_DYNAMIC; - - if (vol_type != sv_vol_type) { - dbg_err("inconsistent vol_type"); - goto bad; - } - - if (used_ebs != sv->used_ebs) { - dbg_err("inconsistent used_ebs"); - goto bad; - } - - if (data_pad != sv->data_pad) { - dbg_err("inconsistent data_pad"); - goto bad; - } - } - - return 0; - -bad: - ubi_err("inconsistent VID header at PEB %d", pnum); - ubi_dbg_dump_vid_hdr(vid_hdr); - ubi_dbg_dump_sv(sv); - return -EINVAL; -} - -/** - * add_volume - add volume to the scanning information. - * @si: scanning information - * @vol_id: ID of the volume to add - * @pnum: physical eraseblock number - * @vid_hdr: volume identifier header - * - * If the volume corresponding to the @vid_hdr logical eraseblock is already - * present in the scanning information, this function does nothing. Otherwise - * it adds corresponding volume to the scanning information. Returns a pointer - * to the scanning volume object in case of success and a negative error code - * in case of failure. - */ -static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, - int pnum, - const struct ubi_vid_hdr *vid_hdr) -{ - struct ubi_scan_volume *sv; - struct rb_node **p = &si->volumes.rb_node, *parent = NULL; - - ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id)); - - /* Walk the volume RB-tree to look if this volume is already present */ - while (*p) { - parent = *p; - sv = rb_entry(parent, struct ubi_scan_volume, rb); - - if (vol_id == sv->vol_id) - return sv; - - if (vol_id > sv->vol_id) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - /* The volume is absent - add it */ - sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL); - if (!sv) - return ERR_PTR(-ENOMEM); - - sv->highest_lnum = sv->leb_count = 0; - si->max_sqnum = 0; - sv->vol_id = vol_id; - sv->root = RB_ROOT; - sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad); - sv->compat = vid_hdr->compat; - sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME - : UBI_STATIC_VOLUME; - if (vol_id > si->highest_vol_id) - si->highest_vol_id = vol_id; - - rb_link_node(&sv->rb, parent, p); - rb_insert_color(&sv->rb, &si->volumes); - si->vols_found += 1; - dbg_bld("added volume %d", vol_id); - return sv; -} - -/** - * compare_lebs - find out which logical eraseblock is newer. - * @ubi: UBI device description object - * @seb: first logical eraseblock to compare - * @pnum: physical eraseblock number of the second logical eraseblock to - * compare - * @vid_hdr: volume identifier header of the second logical eraseblock - * - * This function compares 2 copies of a LEB and informs which one is newer. In - * case of success this function returns a positive value, in case of failure, a - * negative error code is returned. The success return codes use the following - * bits: - * o bit 0 is cleared: the first PEB (described by @seb) is newer then the - * second PEB (described by @pnum and @vid_hdr); - * o bit 0 is set: the second PEB is newer; - * o bit 1 is cleared: no bit-flips were detected in the newer LEB; - * o bit 1 is set: bit-flips were detected in the newer LEB; - * o bit 2 is cleared: the older LEB is not corrupted; - * o bit 2 is set: the older LEB is corrupted. - */ -static int compare_lebs(const struct ubi_device *ubi, - const struct ubi_scan_leb *seb, int pnum, - const struct ubi_vid_hdr *vid_hdr) -{ - void *buf; - int len, err, second_is_newer, bitflips = 0, corrupted = 0; - uint32_t data_crc, crc; - struct ubi_vid_hdr *vidh = NULL; - unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum); - - if (seb->sqnum == 0 && sqnum2 == 0) { - long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver); - - /* - * UBI constantly increases the logical eraseblock version - * number and it can overflow. Thus, we have to bear in mind - * that versions that are close to %0xFFFFFFFF are less then - * versions that are close to %0. - * - * The UBI WL unit guarantees that the number of pending tasks - * is not greater then %0x7FFFFFFF. So, if the difference - * between any two versions is greater or equivalent to - * %0x7FFFFFFF, there was an overflow and the logical - * eraseblock with lower version is actually newer then the one - * with higher version. - * - * FIXME: but this is anyway obsolete and will be removed at - * some point. - */ - - dbg_bld("using old crappy leb_ver stuff"); - - abs = v1 - v2; - if (abs < 0) - abs = -abs; - - if (abs < 0x7FFFFFFF) - /* Non-overflow situation */ - second_is_newer = (v2 > v1); - else - second_is_newer = (v2 < v1); - } else - /* Obviously the LEB with lower sequence counter is older */ - second_is_newer = sqnum2 > seb->sqnum; - - /* - * Now we know which copy is newer. If the copy flag of the PEB with - * newer version is not set, then we just return, otherwise we have to - * check data CRC. For the second PEB we already have the VID header, - * for the first one - we'll need to re-read it from flash. - * - * FIXME: this may be optimized so that we wouldn't read twice. - */ - - if (second_is_newer) { - if (!vid_hdr->copy_flag) { - /* It is not a copy, so it is newer */ - dbg_bld("second PEB %d is newer, copy_flag is unset", - pnum); - return 1; - } - } else { - pnum = seb->pnum; - - vidh = ubi_zalloc_vid_hdr(ubi); - if (!vidh) - return -ENOMEM; - - err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); - if (err) { - if (err == UBI_IO_BITFLIPS) - bitflips = 1; - else { - dbg_err("VID of PEB %d header is bad, but it " - "was OK earlier", pnum); - if (err > 0) - err = -EIO; - - goto out_free_vidh; - } - } - - if (!vidh->copy_flag) { - /* It is not a copy, so it is newer */ - dbg_bld("first PEB %d is newer, copy_flag is unset", - pnum); - err = bitflips << 1; - goto out_free_vidh; - } - - vid_hdr = vidh; - } - - /* Read the data of the copy and check the CRC */ - - len = ubi32_to_cpu(vid_hdr->data_size); - buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - err = -ENOMEM; - goto out_free_vidh; - } - - err = ubi_io_read_data(ubi, buf, pnum, 0, len); - if (err && err != UBI_IO_BITFLIPS) - goto out_free_buf; - - data_crc = ubi32_to_cpu(vid_hdr->data_crc); - crc = crc32(UBI_CRC32_INIT, buf, len); - if (crc != data_crc) { - dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x", - pnum, crc, data_crc); - corrupted = 1; - bitflips = 0; - second_is_newer = !second_is_newer; - } else { - dbg_bld("PEB %d CRC is OK", pnum); - bitflips = !!err; - } - - kfree(buf); - ubi_free_vid_hdr(ubi, vidh); - - if (second_is_newer) - dbg_bld("second PEB %d is newer, copy_flag is set", pnum); - else - dbg_bld("first PEB %d is newer, copy_flag is set", pnum); - - return second_is_newer | (bitflips << 1) | (corrupted << 2); - -out_free_buf: - kfree(buf); -out_free_vidh: - ubi_free_vid_hdr(ubi, vidh); - ubi_assert(err < 0); - return err; -} - -/** - * ubi_scan_add_used - add information about a physical eraseblock to the - * scanning information. - * @ubi: UBI device description object - * @si: scanning information - * @pnum: the physical eraseblock number - * @ec: erase counter - * @vid_hdr: the volume identifier header - * @bitflips: if bit-flips were detected when this physical eraseblock was read - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, - int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, - int bitflips) -{ - int err, vol_id, lnum; - uint32_t leb_ver; - unsigned long long sqnum; - struct ubi_scan_volume *sv; - struct ubi_scan_leb *seb; - struct rb_node **p, *parent = NULL; - - vol_id = ubi32_to_cpu(vid_hdr->vol_id); - lnum = ubi32_to_cpu(vid_hdr->lnum); - sqnum = ubi64_to_cpu(vid_hdr->sqnum); - leb_ver = ubi32_to_cpu(vid_hdr->leb_ver); - - dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", - pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); - - sv = add_volume(si, vol_id, pnum, vid_hdr); - if (IS_ERR(sv) < 0) - return PTR_ERR(sv); - - /* - * Walk the RB-tree of logical eraseblocks of volume @vol_id to look - * if this is the first instance of this logical eraseblock or not. - */ - p = &sv->root.rb_node; - while (*p) { - int cmp_res; - - parent = *p; - seb = rb_entry(parent, struct ubi_scan_leb, u.rb); - if (lnum != seb->lnum) { - if (lnum < seb->lnum) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - continue; - } - - /* - * There is already a physical eraseblock describing the same - * logical eraseblock present. - */ - - dbg_bld("this LEB already exists: PEB %d, sqnum %llu, " - "LEB ver %u, EC %d", seb->pnum, seb->sqnum, - seb->leb_ver, seb->ec); - - /* - * Make sure that the logical eraseblocks have different - * versions. Otherwise the image is bad. - */ - if (seb->leb_ver == leb_ver && leb_ver != 0) { - ubi_err("two LEBs with same version %u", leb_ver); - ubi_dbg_dump_seb(seb, 0); - ubi_dbg_dump_vid_hdr(vid_hdr); - return -EINVAL; - } - - /* - * Make sure that the logical eraseblocks have different - * sequence numbers. Otherwise the image is bad. - * - * FIXME: remove 'sqnum != 0' check when leb_ver is removed. - */ - if (seb->sqnum == sqnum && sqnum != 0) { - ubi_err("two LEBs with same sequence number %llu", - sqnum); - ubi_dbg_dump_seb(seb, 0); - ubi_dbg_dump_vid_hdr(vid_hdr); - return -EINVAL; - } - - /* - * Now we have to drop the older one and preserve the newer - * one. - */ - cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr); - if (cmp_res < 0) - return cmp_res; - - if (cmp_res & 1) { - /* - * This logical eraseblock is newer then the one - * found earlier. - */ - err = validate_vid_hdr(vid_hdr, sv, pnum); - if (err) - return err; - - if (cmp_res & 4) - err = ubi_scan_add_to_list(si, seb->pnum, - seb->ec, &si->corr); - else - err = ubi_scan_add_to_list(si, seb->pnum, - seb->ec, &si->erase); - if (err) - return err; - - seb->ec = ec; - seb->pnum = pnum; - seb->scrub = ((cmp_res & 2) || bitflips); - seb->sqnum = sqnum; - seb->leb_ver = leb_ver; - - if (sv->highest_lnum == lnum) - sv->last_data_size = - ubi32_to_cpu(vid_hdr->data_size); - - return 0; - } else { - /* - * This logical eraseblock is older then the one found - * previously. - */ - if (cmp_res & 4) - return ubi_scan_add_to_list(si, pnum, ec, - &si->corr); - else - return ubi_scan_add_to_list(si, pnum, ec, - &si->erase); - } - } - - /* - * We've met this logical eraseblock for the first time, add it to the - * scanning information. - */ - - err = validate_vid_hdr(vid_hdr, sv, pnum); - if (err) - return err; - - seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); - if (!seb) - return -ENOMEM; - - seb->ec = ec; - seb->pnum = pnum; - seb->lnum = lnum; - seb->sqnum = sqnum; - seb->scrub = bitflips; - seb->leb_ver = leb_ver; - - if (sv->highest_lnum <= lnum) { - sv->highest_lnum = lnum; - sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size); - } - - if (si->max_sqnum < sqnum) - si->max_sqnum = sqnum; - - sv->leb_count += 1; - rb_link_node(&seb->u.rb, parent, p); - rb_insert_color(&seb->u.rb, &sv->root); - return 0; -} - -/** - * ubi_scan_find_sv - find information about a particular volume in the - * scanning information. - * @si: scanning information - * @vol_id: the requested volume ID - * - * This function returns a pointer to the volume description or %NULL if there - * are no data about this volume in the scanning information. - */ -struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, - int vol_id) -{ - struct ubi_scan_volume *sv; - struct rb_node *p = si->volumes.rb_node; - - while (p) { - sv = rb_entry(p, struct ubi_scan_volume, rb); - - if (vol_id == sv->vol_id) - return sv; - - if (vol_id > sv->vol_id) - p = p->rb_left; - else - p = p->rb_right; - } - - return NULL; -} - -/** - * ubi_scan_find_seb - find information about a particular logical - * eraseblock in the volume scanning information. - * @sv: a pointer to the volume scanning information - * @lnum: the requested logical eraseblock - * - * This function returns a pointer to the scanning logical eraseblock or %NULL - * if there are no data about it in the scanning volume information. - */ -struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, - int lnum) -{ - struct ubi_scan_leb *seb; - struct rb_node *p = sv->root.rb_node; - - while (p) { - seb = rb_entry(p, struct ubi_scan_leb, u.rb); - - if (lnum == seb->lnum) - return seb; - - if (lnum > seb->lnum) - p = p->rb_left; - else - p = p->rb_right; - } - - return NULL; -} - -/** - * ubi_scan_rm_volume - delete scanning information about a volume. - * @si: scanning information - * @sv: the volume scanning information to delete - */ -void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) -{ - struct rb_node *rb; - struct ubi_scan_leb *seb; - - dbg_bld("remove scanning information about volume %d", sv->vol_id); - - while ((rb = rb_first(&sv->root))) { - seb = rb_entry(rb, struct ubi_scan_leb, u.rb); - rb_erase(&seb->u.rb, &sv->root); - list_add_tail(&seb->u.list, &si->erase); - } - - rb_erase(&sv->rb, &si->volumes); - kfree(sv); - si->vols_found -= 1; -} - -/** - * ubi_scan_erase_peb - erase a physical eraseblock. - * @ubi: UBI device description object - * @si: scanning information - * @pnum: physical eraseblock number to erase; - * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown) - * - * This function erases physical eraseblock 'pnum', and writes the erase - * counter header to it. This function should only be used on UBI device - * initialization stages, when the EBA unit had not been yet initialized. This - * function returns zero in case of success and a negative error code in case - * of failure. - */ -int ubi_scan_erase_peb(const struct ubi_device *ubi, - const struct ubi_scan_info *si, int pnum, int ec) -{ - int err; - struct ubi_ec_hdr *ec_hdr; - - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - - if ((long long)ec >= UBI_MAX_ERASECOUNTER) { - /* - * Erase counter overflow. Upgrade UBI and use 64-bit - * erase counters internally. - */ - ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); - return -EINVAL; - } - - ec_hdr->ec = cpu_to_ubi64(ec); - - err = ubi_io_sync_erase(ubi, pnum, 0); - if (err < 0) - goto out_free; - - err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr); - -out_free: - kfree(ec_hdr); - return err; -} - -/** - * ubi_scan_get_free_peb - get a free physical eraseblock. - * @ubi: UBI device description object - * @si: scanning information - * - * This function returns a free physical eraseblock. It is supposed to be - * called on the UBI initialization stages when the wear-leveling unit is not - * initialized yet. This function picks a physical eraseblocks from one of the - * lists, writes the EC header if it is needed, and removes it from the list. - * - * This function returns scanning physical eraseblock information in case of - * success and an error code in case of failure. - */ -struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, - struct ubi_scan_info *si) -{ - int err = 0, i; - struct ubi_scan_leb *seb; - - if (!list_empty(&si->free)) { - seb = list_entry(si->free.next, struct ubi_scan_leb, u.list); - list_del(&seb->u.list); - dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec); - return seb; - } - - for (i = 0; i < 2; i++) { - struct list_head *head; - struct ubi_scan_leb *tmp_seb; - - if (i == 0) - head = &si->erase; - else - head = &si->corr; - - /* - * We try to erase the first physical eraseblock from the @head - * list and pick it if we succeed, or try to erase the - * next one if not. And so forth. We don't want to take care - * about bad eraseblocks here - they'll be handled later. - */ - list_for_each_entry_safe(seb, tmp_seb, head, u.list) { - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; - - err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1); - if (err) - continue; - - seb->ec += 1; - list_del(&seb->u.list); - dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec); - return seb; - } - } - - ubi_err("no eraseblocks found"); - return ERR_PTR(-ENOSPC); -} - -/** - * process_eb - read UBI headers, check them and add corresponding data - * to the scanning information. - * @ubi: UBI device description object - * @si: scanning information - * @pnum: the physical eraseblock number - * - * This function returns a zero if the physical eraseblock was succesfully - * handled and a negative error code in case of failure. - */ -static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) -{ - long long ec; - int err, bitflips = 0, vol_id, ec_corr = 0; - - dbg_bld("scan PEB %d", pnum); - - /* Skip bad physical eraseblocks */ - err = ubi_io_is_bad(ubi, pnum); - if (err < 0) - return err; - else if (err) { - /* - * FIXME: this is actually duty of the I/O unit to initialize - * this, but MTD does not provide enough information. - */ - si->bad_peb_count += 1; - return 0; - } - - err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); - if (err < 0) - return err; - else if (err == UBI_IO_BITFLIPS) - bitflips = 1; - else if (err == UBI_IO_PEB_EMPTY) - return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, - &si->erase); - else if (err == UBI_IO_BAD_EC_HDR) { - /* - * We have to also look at the VID header, possibly it is not - * corrupted. Set %bitflips flag in order to make this PEB be - * moved and EC be re-created. - */ - ec_corr = 1; - ec = UBI_SCAN_UNKNOWN_EC; - bitflips = 1; - } - - si->is_empty = 0; - - if (!ec_corr) { - /* Make sure UBI version is OK */ - if (ech->version != UBI_VERSION) { - ubi_err("this UBI version is %d, image version is %d", - UBI_VERSION, (int)ech->version); - return -EINVAL; - } - - ec = ubi64_to_cpu(ech->ec); - if (ec > UBI_MAX_ERASECOUNTER) { - /* - * Erase counter overflow. The EC headers have 64 bits - * reserved, but we anyway make use of only 31 bit - * values, as this seems to be enough for any existing - * flash. Upgrade UBI and use 64-bit erase counters - * internally. - */ - ubi_err("erase counter overflow, max is %d", - UBI_MAX_ERASECOUNTER); - ubi_dbg_dump_ec_hdr(ech); - return -EINVAL; - } - } - - /* OK, we've done with the EC header, let's look at the VID header */ - - err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); - if (err < 0) - return err; - else if (err == UBI_IO_BITFLIPS) - bitflips = 1; - else if (err == UBI_IO_BAD_VID_HDR || - (err == UBI_IO_PEB_FREE && ec_corr)) { - /* VID header is corrupted */ - err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); - if (err) - return err; - goto adjust_mean_ec; - } else if (err == UBI_IO_PEB_FREE) { - /* No VID header - the physical eraseblock is free */ - err = ubi_scan_add_to_list(si, pnum, ec, &si->free); - if (err) - return err; - goto adjust_mean_ec; - } - - vol_id = ubi32_to_cpu(vidh->vol_id); - if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { - int lnum = ubi32_to_cpu(vidh->lnum); - - /* Unsupported internal volume */ - switch (vidh->compat) { - case UBI_COMPAT_DELETE: - ubi_msg("\"delete\" compatible internal volume %d:%d" - " found, remove it", vol_id, lnum); - err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); - if (err) - return err; - break; - - case UBI_COMPAT_RO: - ubi_msg("read-only compatible internal volume %d:%d" - " found, switch to read-only mode", - vol_id, lnum); - ubi->ro_mode = 1; - break; - - case UBI_COMPAT_PRESERVE: - ubi_msg("\"preserve\" compatible internal volume %d:%d" - " found", vol_id, lnum); - err = ubi_scan_add_to_list(si, pnum, ec, &si->alien); - if (err) - return err; - si->alien_peb_count += 1; - return 0; - - case UBI_COMPAT_REJECT: - ubi_err("incompatible internal volume %d:%d found", - vol_id, lnum); - return -EINVAL; - } - } - - /* Both UBI headers seem to be fine */ - err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips); - if (err) - return err; - -adjust_mean_ec: - if (!ec_corr) { - if (si->ec_sum + ec < ec) { - commit_to_mean_value(si); - si->ec_sum = 0; - si->ec_count = 0; - } else { - si->ec_sum += ec; - si->ec_count += 1; - } - - if (ec > si->max_ec) - si->max_ec = ec; - if (ec < si->min_ec) - si->min_ec = ec; - } - - return 0; -} - -/** - * ubi_scan - scan an MTD device. - * @ubi: UBI device description object - * - * This function does full scanning of an MTD device and returns complete - * information about it. In case of failure, an error code is returned. - */ -struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) -{ - int err, pnum; - struct rb_node *rb1, *rb2; - struct ubi_scan_volume *sv; - struct ubi_scan_leb *seb; - struct ubi_scan_info *si; - - si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL); - if (!si) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&si->corr); - INIT_LIST_HEAD(&si->free); - INIT_LIST_HEAD(&si->erase); - INIT_LIST_HEAD(&si->alien); - si->volumes = RB_ROOT; - si->is_empty = 1; - - err = -ENOMEM; - ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ech) - goto out_si; - - vidh = ubi_zalloc_vid_hdr(ubi); - if (!vidh) - goto out_ech; - - for (pnum = 0; pnum < ubi->peb_count; pnum++) { - cond_resched(); - - dbg_msg("process PEB %d", pnum); - err = process_eb(ubi, si, pnum); - if (err < 0) - goto out_vidh; - } - - dbg_msg("scanning is finished"); - - /* Finish mean erase counter calculations */ - if (si->ec_count) - commit_to_mean_value(si); - - if (si->is_empty) - ubi_msg("empty MTD device detected"); - - /* - * In case of unknown erase counter we use the mean erase counter - * value. - */ - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; - } - - list_for_each_entry(seb, &si->free, u.list) { - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; - } - - list_for_each_entry(seb, &si->corr, u.list) - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; - - list_for_each_entry(seb, &si->erase, u.list) - if (seb->ec == UBI_SCAN_UNKNOWN_EC) - seb->ec = si->mean_ec; - - err = paranoid_check_si(ubi, si); - if (err) { - if (err > 0) - err = -EINVAL; - goto out_vidh; - } - - ubi_free_vid_hdr(ubi, vidh); - kfree(ech); - - return si; - -out_vidh: - ubi_free_vid_hdr(ubi, vidh); -out_ech: - kfree(ech); -out_si: - ubi_scan_destroy_si(si); - return ERR_PTR(err); -} - -/** - * destroy_sv - free the scanning volume information - * @sv: scanning volume information - * - * This function destroys the volume RB-tree (@sv->root) and the scanning - * volume information. - */ -static void destroy_sv(struct ubi_scan_volume *sv) -{ - struct ubi_scan_leb *seb; - struct rb_node *this = sv->root.rb_node; - - while (this) { - if (this->rb_left) - this = this->rb_left; - else if (this->rb_right) - this = this->rb_right; - else { - seb = rb_entry(this, struct ubi_scan_leb, u.rb); - this = rb_parent(this); - if (this) { - if (this->rb_left == &seb->u.rb) - this->rb_left = NULL; - else - this->rb_right = NULL; - } - - kfree(seb); - } - } - kfree(sv); -} - -/** - * ubi_scan_destroy_si - destroy scanning information. - * @si: scanning information - */ -void ubi_scan_destroy_si(struct ubi_scan_info *si) -{ - struct ubi_scan_leb *seb, *seb_tmp; - struct ubi_scan_volume *sv; - struct rb_node *rb; - - list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) { - list_del(&seb->u.list); - kfree(seb); - } - list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) { - list_del(&seb->u.list); - kfree(seb); - } - list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) { - list_del(&seb->u.list); - kfree(seb); - } - list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) { - list_del(&seb->u.list); - kfree(seb); - } - - /* Destroy the volume RB-tree */ - rb = si->volumes.rb_node; - while (rb) { - if (rb->rb_left) - rb = rb->rb_left; - else if (rb->rb_right) - rb = rb->rb_right; - else { - sv = rb_entry(rb, struct ubi_scan_volume, rb); - - rb = rb_parent(rb); - if (rb) { - if (rb->rb_left == &sv->rb) - rb->rb_left = NULL; - else - rb->rb_right = NULL; - } - - destroy_sv(sv); - } - } - - kfree(si); -} - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID - -/** - * paranoid_check_si - check if the scanning information is correct and - * consistent. - * @ubi: UBI device description object - * @si: scanning information - * - * This function returns zero if the scanning information is all right, %1 if - * not and a negative error code if an error occurred. - */ -static int paranoid_check_si(const struct ubi_device *ubi, - struct ubi_scan_info *si) -{ - int pnum, err, vols_found = 0; - struct rb_node *rb1, *rb2; - struct ubi_scan_volume *sv; - struct ubi_scan_leb *seb, *last_seb; - uint8_t *buf; - - /* - * At first, check that scanning information is ok. - */ - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { - int leb_count = 0; - - cond_resched(); - - vols_found += 1; - - if (si->is_empty) { - ubi_err("bad is_empty flag"); - goto bad_sv; - } - - if (sv->vol_id < 0 || sv->highest_lnum < 0 || - sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 || - sv->data_pad < 0 || sv->last_data_size < 0) { - ubi_err("negative values"); - goto bad_sv; - } - - if (sv->vol_id >= UBI_MAX_VOLUMES && - sv->vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("bad vol_id"); - goto bad_sv; - } - - if (sv->vol_id > si->highest_vol_id) { - ubi_err("highest_vol_id is %d, but vol_id %d is there", - si->highest_vol_id, sv->vol_id); - goto out; - } - - if (sv->vol_type != UBI_DYNAMIC_VOLUME && - sv->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); - goto bad_sv; - } - - if (sv->data_pad > ubi->leb_size / 2) { - ubi_err("bad data_pad"); - goto bad_sv; - } - - last_seb = NULL; - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { - cond_resched(); - - last_seb = seb; - leb_count += 1; - - if (seb->pnum < 0 || seb->ec < 0) { - ubi_err("negative values"); - goto bad_seb; - } - - if (seb->ec < si->min_ec) { - ubi_err("bad si->min_ec (%d), %d found", - si->min_ec, seb->ec); - goto bad_seb; - } - - if (seb->ec > si->max_ec) { - ubi_err("bad si->max_ec (%d), %d found", - si->max_ec, seb->ec); - goto bad_seb; - } - - if (seb->pnum >= ubi->peb_count) { - ubi_err("too high PEB number %d, total PEBs %d", - seb->pnum, ubi->peb_count); - goto bad_seb; - } - - if (sv->vol_type == UBI_STATIC_VOLUME) { - if (seb->lnum >= sv->used_ebs) { - ubi_err("bad lnum or used_ebs"); - goto bad_seb; - } - } else { - if (sv->used_ebs != 0) { - ubi_err("non-zero used_ebs"); - goto bad_seb; - } - } - - if (seb->lnum > sv->highest_lnum) { - ubi_err("incorrect highest_lnum or lnum"); - goto bad_seb; - } - } - - if (sv->leb_count != leb_count) { - ubi_err("bad leb_count, %d objects in the tree", - leb_count); - goto bad_sv; - } - - if (!last_seb) - continue; - - seb = last_seb; - - if (seb->lnum != sv->highest_lnum) { - ubi_err("bad highest_lnum"); - goto bad_seb; - } - } - - if (vols_found != si->vols_found) { - ubi_err("bad si->vols_found %d, should be %d", - si->vols_found, vols_found); - goto out; - } - - /* Check that scanning information is correct */ - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { - last_seb = NULL; - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { - int vol_type; - - cond_resched(); - - last_seb = seb; - - err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1); - if (err && err != UBI_IO_BITFLIPS) { - ubi_err("VID header is not OK (%d)", err); - if (err > 0) - err = -EIO; - return err; - } - - vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? - UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; - if (sv->vol_type != vol_type) { - ubi_err("bad vol_type"); - goto bad_vid_hdr; - } - - if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) { - ubi_err("bad sqnum %llu", seb->sqnum); - goto bad_vid_hdr; - } - - if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) { - ubi_err("bad vol_id %d", sv->vol_id); - goto bad_vid_hdr; - } - - if (sv->compat != vidh->compat) { - ubi_err("bad compat %d", vidh->compat); - goto bad_vid_hdr; - } - - if (seb->lnum != ubi32_to_cpu(vidh->lnum)) { - ubi_err("bad lnum %d", seb->lnum); - goto bad_vid_hdr; - } - - if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) { - ubi_err("bad used_ebs %d", sv->used_ebs); - goto bad_vid_hdr; - } - - if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) { - ubi_err("bad data_pad %d", sv->data_pad); - goto bad_vid_hdr; - } - - if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) { - ubi_err("bad leb_ver %u", seb->leb_ver); - goto bad_vid_hdr; - } - } - - if (!last_seb) - continue; - - if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) { - ubi_err("bad highest_lnum %d", sv->highest_lnum); - goto bad_vid_hdr; - } - - if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) { - ubi_err("bad last_data_size %d", sv->last_data_size); - goto bad_vid_hdr; - } - } - - /* - * Make sure that all the physical eraseblocks are in one of the lists - * or trees. - */ - buf = kmalloc(ubi->peb_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - memset(buf, 1, ubi->peb_count); - for (pnum = 0; pnum < ubi->peb_count; pnum++) { - err = ubi_io_is_bad(ubi, pnum); - if (err < 0) - return err; - else if (err) - buf[pnum] = 0; - } - - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) - buf[seb->pnum] = 0; - - list_for_each_entry(seb, &si->free, u.list) - buf[seb->pnum] = 0; - - list_for_each_entry(seb, &si->corr, u.list) - buf[seb->pnum] = 0; - - list_for_each_entry(seb, &si->erase, u.list) - buf[seb->pnum] = 0; - - list_for_each_entry(seb, &si->alien, u.list) - buf[seb->pnum] = 0; - - err = 0; - for (pnum = 0; pnum < ubi->peb_count; pnum++) - if (buf[pnum]) { - ubi_err("PEB %d is not referred", pnum); - err = 1; - } - - kfree(buf); - if (err) - goto out; - return 0; - -bad_seb: - ubi_err("bad scanning information about LEB %d", seb->lnum); - ubi_dbg_dump_seb(seb, 0); - ubi_dbg_dump_sv(sv); - goto out; - -bad_sv: - ubi_err("bad scanning information about volume %d", sv->vol_id); - ubi_dbg_dump_sv(sv); - goto out; - -bad_vid_hdr: - ubi_err("bad scanning information about volume %d", sv->vol_id); - ubi_dbg_dump_sv(sv); - ubi_dbg_dump_vid_hdr(vidh); - -out: - ubi_dbg_dump_stack(); - return 1; -} - -#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/trunk/drivers/mtd/ubi/scan.h b/trunk/drivers/mtd/ubi/scan.h deleted file mode 100644 index 3949f6192c76..000000000000 --- a/trunk/drivers/mtd/ubi/scan.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -#ifndef __UBI_SCAN_H__ -#define __UBI_SCAN_H__ - -/* The erase counter value for this physical eraseblock is unknown */ -#define UBI_SCAN_UNKNOWN_EC (-1) - -/** - * struct ubi_scan_leb - scanning information about a physical eraseblock. - * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown) - * @pnum: physical eraseblock number - * @lnum: logical eraseblock number - * @scrub: if this physical eraseblock needs scrubbing - * @sqnum: sequence number - * @u: unions RB-tree or @list links - * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects - * @u.list: link in one of the eraseblock lists - * @leb_ver: logical eraseblock version (obsolete) - * - * One object of this type is allocated for each physical eraseblock during - * scanning. - */ -struct ubi_scan_leb { - int ec; - int pnum; - int lnum; - int scrub; - unsigned long long sqnum; - union { - struct rb_node rb; - struct list_head list; - } u; - uint32_t leb_ver; -}; - -/** - * struct ubi_scan_volume - scanning information about a volume. - * @vol_id: volume ID - * @highest_lnum: highest logical eraseblock number in this volume - * @leb_count: number of logical eraseblocks in this volume - * @vol_type: volume type - * @used_ebs: number of used logical eraseblocks in this volume (only for - * static volumes) - * @last_data_size: amount of data in the last logical eraseblock of this - * volume (always equivalent to the usable logical eraseblock size in case of - * dynamic volumes) - * @data_pad: how many bytes at the end of logical eraseblocks of this volume - * are not used (due to volume alignment) - * @compat: compatibility flags of this volume - * @rb: link in the volume RB-tree - * @root: root of the RB-tree containing all the eraseblock belonging to this - * volume (&struct ubi_scan_leb objects) - * - * One object of this type is allocated for each volume during scanning. - */ -struct ubi_scan_volume { - int vol_id; - int highest_lnum; - int leb_count; - int vol_type; - int used_ebs; - int last_data_size; - int data_pad; - int compat; - struct rb_node rb; - struct rb_root root; -}; - -/** - * struct ubi_scan_info - UBI scanning information. - * @volumes: root of the volume RB-tree - * @corr: list of corrupted physical eraseblocks - * @free: list of free physical eraseblocks - * @erase: list of physical eraseblocks which have to be erased - * @alien: list of physical eraseblocks which should not be used by UBI (e.g., - * @bad_peb_count: count of bad physical eraseblocks - * those belonging to "preserve"-compatible internal volumes) - * @vols_found: number of volumes found during scanning - * @highest_vol_id: highest volume ID - * @alien_peb_count: count of physical eraseblocks in the @alien list - * @is_empty: flag indicating whether the MTD device is empty or not - * @min_ec: lowest erase counter value - * @max_ec: highest erase counter value - * @max_sqnum: highest sequence number value - * @mean_ec: mean erase counter value - * @ec_sum: a temporary variable used when calculating @mean_ec - * @ec_count: a temporary variable used when calculating @mean_ec - * - * This data structure contains the result of scanning and may be used by other - * UBI units to build final UBI data structures, further error-recovery and so - * on. - */ -struct ubi_scan_info { - struct rb_root volumes; - struct list_head corr; - struct list_head free; - struct list_head erase; - struct list_head alien; - int bad_peb_count; - int vols_found; - int highest_vol_id; - int alien_peb_count; - int is_empty; - int min_ec; - int max_ec; - unsigned long long max_sqnum; - int mean_ec; - int ec_sum; - int ec_count; -}; - -struct ubi_device; -struct ubi_vid_hdr; - -/* - * ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a - * list. - * - * @sv: volume scanning information - * @seb: scanning eraseblock infprmation - * @list: the list to move to - */ -static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, - struct ubi_scan_leb *seb, - struct list_head *list) -{ - rb_erase(&seb->u.rb, &sv->root); - list_add_tail(&seb->u.list, list); -} - -int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, - struct list_head *list); -int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, - int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, - int bitflips); -struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, - int vol_id); -struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, - int lnum); -void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv); -struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, - struct ubi_scan_info *si); -int ubi_scan_erase_peb(const struct ubi_device *ubi, - const struct ubi_scan_info *si, int pnum, int ec); -struct ubi_scan_info *ubi_scan(struct ubi_device *ubi); -void ubi_scan_destroy_si(struct ubi_scan_info *si); - -#endif /* !__UBI_SCAN_H__ */ diff --git a/trunk/drivers/mtd/ubi/ubi.h b/trunk/drivers/mtd/ubi/ubi.h deleted file mode 100644 index feb647f108f0..000000000000 --- a/trunk/drivers/mtd/ubi/ubi.h +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (c) Nokia Corporation, 2006, 2007 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -#ifndef __UBI_UBI_H__ -#define __UBI_UBI_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scan.h" -#include "debug.h" - -/* Maximum number of supported UBI devices */ -#define UBI_MAX_DEVICES 32 - -/* UBI name used for character devices, sysfs, etc */ -#define UBI_NAME_STR "ubi" - -/* Normal UBI messages */ -#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__) -/* UBI warning messages */ -#define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \ - __FUNCTION__, ##__VA_ARGS__) -/* UBI error messages */ -#define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \ - __FUNCTION__, ##__VA_ARGS__) - -/* Lowest number PEBs reserved for bad PEB handling */ -#define MIN_RESEVED_PEBS 2 - -/* Background thread name pattern */ -#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd" - -/* This marker in the EBA table means that the LEB is um-mapped */ -#define UBI_LEB_UNMAPPED -1 - -/* - * In case of errors, UBI tries to repeat the operation several times before - * returning error. The below constant defines how many times UBI re-tries. - */ -#define UBI_IO_RETRIES 3 - -/* - * Error codes returned by the I/O unit. - * - * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only - * 0xFF bytes - * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a - * valid erase counter header, and the rest are %0xFF bytes - * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC) - * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or - * CRC) - * UBI_IO_BITFLIPS: bit-flips were detected and corrected - */ -enum { - UBI_IO_PEB_EMPTY = 1, - UBI_IO_PEB_FREE, - UBI_IO_BAD_EC_HDR, - UBI_IO_BAD_VID_HDR, - UBI_IO_BITFLIPS -}; - -extern int ubi_devices_cnt; -extern struct ubi_device *ubi_devices[]; - -struct ubi_volume_desc; - -/** - * struct ubi_volume - UBI volume description data structure. - * @dev: device object to make use of the the Linux device model - * @cdev: character device object to create character device - * @ubi: reference to the UBI device description object - * @vol_id: volume ID - * @readers: number of users holding this volume in read-only mode - * @writers: number of users holding this volume in read-write mode - * @exclusive: whether somebody holds this volume in exclusive mode - * @removed: if the volume was removed - * @checked: if this static volume was checked - * - * @reserved_pebs: how many physical eraseblocks are reserved for this volume - * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * @usable_leb_size: logical eraseblock size without padding - * @used_ebs: how many logical eraseblocks in this volume contain data - * @last_eb_bytes: how many bytes are stored in the last logical eraseblock - * @used_bytes: how many bytes of data this volume contains - * @upd_marker: non-zero if the update marker is set for this volume - * @corrupted: non-zero if the volume is corrupted (static volumes only) - * @alignment: volume alignment - * @data_pad: how many bytes are not used at the end of physical eraseblocks to - * satisfy the requested alignment - * @name_len: volume name length - * @name: volume name - * - * @updating: whether the volume is being updated - * @upd_ebs: how many eraseblocks are expected to be updated - * @upd_bytes: how many bytes are expected to be received - * @upd_received: how many update bytes were already received - * @upd_buf: update buffer which is used to collect update data - * - * @eba_tbl: EBA table of this volume (LEB->PEB mapping) - * - * @gluebi_desc: gluebi UBI volume descriptor - * @gluebi_refcount: reference count of the gluebi MTD device - * @gluebi_mtd: MTD device description object of the gluebi MTD device - * - * The @corrupted field indicates that the volume's contents is corrupted. - * Since UBI protects only static volumes, this field is not relevant to - * dynamic volumes - it is user's responsibility to assure their data - * integrity. - * - * The @upd_marker flag indicates that this volume is either being updated at - * the moment or is damaged because of an unclean reboot. - */ -struct ubi_volume { - struct device dev; - struct cdev cdev; - struct ubi_device *ubi; - int vol_id; - int readers; - int writers; - int exclusive; - int removed; - int checked; - - int reserved_pebs; - int vol_type; - int usable_leb_size; - int used_ebs; - int last_eb_bytes; - long long used_bytes; - int upd_marker; - int corrupted; - int alignment; - int data_pad; - int name_len; - char name[UBI_VOL_NAME_MAX+1]; - - int updating; - int upd_ebs; - long long upd_bytes; - long long upd_received; - void *upd_buf; - - int *eba_tbl; - -#ifdef CONFIG_MTD_UBI_GLUEBI - /* Gluebi-related stuff may be compiled out */ - struct ubi_volume_desc *gluebi_desc; - int gluebi_refcount; - struct mtd_info gluebi_mtd; -#endif -}; - -/** - * struct ubi_volume_desc - descriptor of the UBI volume returned when it is - * opened. - * @vol: reference to the corresponding volume description object - * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE) - */ -struct ubi_volume_desc { - struct ubi_volume *vol; - int mode; -}; - -struct ubi_wl_entry; - -/** - * struct ubi_device - UBI device description structure - * @dev: class device object to use the the Linux device model - * @cdev: character device object to create character device - * @ubi_num: UBI device number - * @ubi_name: UBI device name - * @major: character device major number - * @vol_count: number of volumes in this UBI device - * @volumes: volumes of this UBI device - * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, - * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers, - * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and - * @vol->eba_tbl. - * - * @rsvd_pebs: count of reserved physical eraseblocks - * @avail_pebs: count of available physical eraseblocks - * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB - * handling - * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling - * - * @vtbl_slots: how many slots are available in the volume table - * @vtbl_size: size of the volume table in bytes - * @vtbl: in-RAM volume table copy - * - * @max_ec: current highest erase counter value - * @mean_ec: current mean erase counter value - * - * global_sqnum: global sequence number - * @ltree_lock: protects the lock tree and @global_sqnum - * @ltree: the lock tree - * @vtbl_mutex: protects on-flash volume table - * - * @used: RB-tree of used physical eraseblocks - * @free: RB-tree of free physical eraseblocks - * @scrub: RB-tree of physical eraseblocks which need scrubbing - * @prot: protection trees - * @prot.pnum: protection tree indexed by physical eraseblock numbers - * @prot.aec: protection tree indexed by absolute erase counter value - * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, - * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works - * fields - * @wl_scheduled: non-zero if the wear-leveling was scheduled - * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any - * physical eraseblock - * @abs_ec: absolute erase counter - * @move_from: physical eraseblock from where the data is being moved - * @move_to: physical eraseblock where the data is being moved to - * @move_from_put: if the "from" PEB was put - * @move_to_put: if the "to" PEB was put - * @works: list of pending works - * @works_count: count of pending works - * @bgt_thread: background thread description object - * @thread_enabled: if the background thread is enabled - * @bgt_name: background thread name - * - * @flash_size: underlying MTD device size (in bytes) - * @peb_count: count of physical eraseblocks on the MTD device - * @peb_size: physical eraseblock size - * @bad_peb_count: count of bad physical eraseblocks - * @good_peb_count: count of good physical eraseblocks - * @min_io_size: minimal input/output unit size of the underlying MTD device - * @hdrs_min_io_size: minimal I/O unit size used for VID and EC headers - * @ro_mode: if the UBI device is in read-only mode - * @leb_size: logical eraseblock size - * @leb_start: starting offset of logical eraseblocks within physical - * eraseblocks - * @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size - * @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size - * @vid_hdr_offset: starting offset of the volume identifier header (might be - * unaligned) - * @vid_hdr_aloffset: starting offset of the VID header aligned to - * @hdrs_min_io_size - * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset - * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or - * not - * @mtd: MTD device descriptor - */ -struct ubi_device { - struct cdev cdev; - struct device dev; - int ubi_num; - char ubi_name[sizeof(UBI_NAME_STR)+5]; - int major; - int vol_count; - struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; - spinlock_t volumes_lock; - - int rsvd_pebs; - int avail_pebs; - int beb_rsvd_pebs; - int beb_rsvd_level; - - int vtbl_slots; - int vtbl_size; - struct ubi_vtbl_record *vtbl; - struct mutex vtbl_mutex; - - int max_ec; - int mean_ec; - - /* EBA unit's stuff */ - unsigned long long global_sqnum; - spinlock_t ltree_lock; - struct rb_root ltree; - - /* Wear-leveling unit's stuff */ - struct rb_root used; - struct rb_root free; - struct rb_root scrub; - struct { - struct rb_root pnum; - struct rb_root aec; - } prot; - spinlock_t wl_lock; - int wl_scheduled; - struct ubi_wl_entry **lookuptbl; - unsigned long long abs_ec; - struct ubi_wl_entry *move_from; - struct ubi_wl_entry *move_to; - int move_from_put; - int move_to_put; - struct list_head works; - int works_count; - struct task_struct *bgt_thread; - int thread_enabled; - char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; - - /* I/O unit's stuff */ - long long flash_size; - int peb_count; - int peb_size; - int bad_peb_count; - int good_peb_count; - int min_io_size; - int hdrs_min_io_size; - int ro_mode; - int leb_size; - int leb_start; - int ec_hdr_alsize; - int vid_hdr_alsize; - int vid_hdr_offset; - int vid_hdr_aloffset; - int vid_hdr_shift; - int bad_allowed; - struct mtd_info *mtd; -}; - -extern struct file_operations ubi_cdev_operations; -extern struct file_operations ubi_vol_cdev_operations; -extern struct class *ubi_class; - -/* vtbl.c */ -int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, - struct ubi_vtbl_record *vtbl_rec); -int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); - -/* vmt.c */ -int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); -int ubi_remove_volume(struct ubi_volume_desc *desc); -int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); -int ubi_add_volume(struct ubi_device *ubi, int vol_id); -void ubi_free_volume(struct ubi_device *ubi, int vol_id); - -/* upd.c */ -int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes); -int ubi_more_update_data(struct ubi_device *ubi, int vol_id, - const void __user *buf, int count); - -/* misc.c */ -int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); -int ubi_check_volume(struct ubi_device *ubi, int vol_id); -void ubi_calculate_reserved(struct ubi_device *ubi); - -/* gluebi.c */ -#ifdef CONFIG_MTD_UBI_GLUEBI -int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol); -int ubi_destroy_gluebi(struct ubi_volume *vol); -#else -#define ubi_create_gluebi(ubi, vol) 0 -#define ubi_destroy_gluebi(vol) 0 -#endif - -/* eba.c */ -int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum); -int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, - int offset, int len, int check); -int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int offset, int len, int dtype); -int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int len, int dtype, - int used_ebs); -int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, - const void *buf, int len, int dtype); -int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr); -int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); -void ubi_eba_close(const struct ubi_device *ubi); - -/* wl.c */ -int ubi_wl_get_peb(struct ubi_device *ubi, int dtype); -int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture); -int ubi_wl_flush(struct ubi_device *ubi); -int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); -int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); -void ubi_wl_close(struct ubi_device *ubi); - -/* io.c */ -int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, - int len); -int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, - int offset, int len); -int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture); -int ubi_io_is_bad(const struct ubi_device *ubi, int pnum); -int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum); -int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_ec_hdr *ec_hdr, int verbose); -int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_ec_hdr *ec_hdr); -int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr, int verbose); -int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr); - -/* - * ubi_rb_for_each_entry - walk an RB-tree. - * @rb: a pointer to type 'struct rb_node' to to use as a loop counter - * @pos: a pointer to RB-tree entry type to use as a loop counter - * @root: RB-tree's root - * @member: the name of the 'struct rb_node' within the RB-tree entry - */ -#define ubi_rb_for_each_entry(rb, pos, root, member) \ - for (rb = rb_first(root), \ - pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \ - rb; \ - rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member)) - -/** - * ubi_zalloc_vid_hdr - allocate a volume identifier header object. - * @ubi: UBI device description object - * - * This function returns a pointer to the newly allocated and zero-filled - * volume identifier header object in case of success and %NULL in case of - * failure. - */ -static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi) -{ - void *vid_hdr; - - vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL); - if (!vid_hdr) - return NULL; - - /* - * VID headers may be stored at un-aligned flash offsets, so we shift - * the pointer. - */ - return vid_hdr + ubi->vid_hdr_shift; -} - -/** - * ubi_free_vid_hdr - free a volume identifier header object. - * @ubi: UBI device description object - * @vid_hdr: the object to free - */ -static inline void ubi_free_vid_hdr(const struct ubi_device *ubi, - struct ubi_vid_hdr *vid_hdr) -{ - void *p = vid_hdr; - - if (!p) - return; - - kfree(p - ubi->vid_hdr_shift); -} - -/* - * This function is equivalent to 'ubi_io_read()', but @offset is relative to - * the beginning of the logical eraseblock, not to the beginning of the - * physical eraseblock. - */ -static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf, - int pnum, int offset, int len) -{ - ubi_assert(offset >= 0); - return ubi_io_read(ubi, buf, pnum, offset + ubi->leb_start, len); -} - -/* - * This function is equivalent to 'ubi_io_write()', but @offset is relative to - * the beginning of the logical eraseblock, not to the beginning of the - * physical eraseblock. - */ -static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf, - int pnum, int offset, int len) -{ - ubi_assert(offset >= 0); - return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len); -} - -/** - * ubi_ro_mode - switch to read-only mode. - * @ubi: UBI device description object - */ -static inline void ubi_ro_mode(struct ubi_device *ubi) -{ - ubi->ro_mode = 1; - ubi_warn("switch to read-only mode"); -} - -/** - * vol_id2idx - get table index by volume ID. - * @ubi: UBI device description object - * @vol_id: volume ID - */ -static inline int vol_id2idx(const struct ubi_device *ubi, int vol_id) -{ - if (vol_id >= UBI_INTERNAL_VOL_START) - return vol_id - UBI_INTERNAL_VOL_START + ubi->vtbl_slots; - else - return vol_id; -} - -/** - * idx2vol_id - get volume ID by table index. - * @ubi: UBI device description object - * @idx: table index - */ -static inline int idx2vol_id(const struct ubi_device *ubi, int idx) -{ - if (idx >= ubi->vtbl_slots) - return idx - ubi->vtbl_slots + UBI_INTERNAL_VOL_START; - else - return idx; -} - -#endif /* !__UBI_UBI_H__ */ diff --git a/trunk/drivers/mtd/ubi/upd.c b/trunk/drivers/mtd/ubi/upd.c deleted file mode 100644 index 8925b977e3dc..000000000000 --- a/trunk/drivers/mtd/ubi/upd.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (c) Nokia Corporation, 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - * - * Jan 2007: Alexander Schmidt, hacked per-volume update. - */ - -/* - * This file contains implementation of the volume update functionality. - * - * The update operation is based on the per-volume update marker which is - * stored in the volume table. The update marker is set before the update - * starts, and removed after the update has been finished. So if the update was - * interrupted by an unclean re-boot or due to some other reasons, the update - * marker stays on the flash media and UBI finds it when it attaches the MTD - * device next time. If the update marker is set for a volume, the volume is - * treated as damaged and most I/O operations are prohibited. Only a new update - * operation is allowed. - * - * Note, in general it is possible to implement the update operation as a - * transaction with a roll-back capability. - */ - -#include -#include -#include -#include "ubi.h" - -/** - * set_update_marker - set update marker. - * @ubi: UBI device description object - * @vol_id: volume ID - * - * This function sets the update marker flag for volume @vol_id. Returns zero - * in case of success and a negative error code in case of failure. - */ -static int set_update_marker(struct ubi_device *ubi, int vol_id) -{ - int err; - struct ubi_vtbl_record vtbl_rec; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - dbg_msg("set update marker for volume %d", vol_id); - - if (vol->upd_marker) { - ubi_assert(ubi->vtbl[vol_id].upd_marker); - dbg_msg("already set"); - return 0; - } - - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); - vtbl_rec.upd_marker = 1; - - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); - vol->upd_marker = 1; - return err; -} - -/** - * clear_update_marker - clear update marker. - * @ubi: UBI device description object - * @vol_id: volume ID - * @bytes: new data size in bytes - * - * This function clears the update marker for volume @vol_id, sets new volume - * data size and clears the "corrupted" flag (static volumes only). Returns - * zero in case of success and a negative error code in case of failure. - */ -static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes) -{ - int err; - uint64_t tmp; - struct ubi_vtbl_record vtbl_rec; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - dbg_msg("clear update marker for volume %d", vol_id); - - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); - ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); - vtbl_rec.upd_marker = 0; - - if (vol->vol_type == UBI_STATIC_VOLUME) { - vol->corrupted = 0; - vol->used_bytes = tmp = bytes; - vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size); - vol->used_ebs = tmp; - if (vol->last_eb_bytes) - vol->used_ebs += 1; - else - vol->last_eb_bytes = vol->usable_leb_size; - } - - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); - vol->upd_marker = 0; - return err; -} - -/** - * ubi_start_update - start volume update. - * @ubi: UBI device description object - * @vol_id: volume ID - * @bytes: update bytes - * - * This function starts volume update operation. If @bytes is zero, the volume - * is just wiped out. Returns zero in case of success and a negative error code - * in case of failure. - */ -int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) -{ - int i, err; - uint64_t tmp; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes); - vol->updating = 1; - - err = set_update_marker(ubi, vol_id); - if (err) - return err; - - /* Before updating - wipe out the volume */ - for (i = 0; i < vol->reserved_pebs; i++) { - err = ubi_eba_unmap_leb(ubi, vol_id, i); - if (err) - return err; - } - - if (bytes == 0) { - err = clear_update_marker(ubi, vol_id, 0); - if (err) - return err; - err = ubi_wl_flush(ubi); - if (!err) - vol->updating = 0; - } - - vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL); - if (!vol->upd_buf) - return -ENOMEM; - - tmp = bytes; - vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size); - vol->upd_ebs += tmp; - vol->upd_bytes = bytes; - vol->upd_received = 0; - return 0; -} - -/** - * write_leb - write update data. - * @ubi: UBI device description object - * @vol_id: volume ID - * @lnum: logical eraseblock number - * @buf: data to write - * @len: data size - * @used_ebs: how many logical eraseblocks will this volume contain (static - * volumes only) - * - * This function writes update data to corresponding logical eraseblock. In - * case of dynamic volume, this function checks if the data contains 0xFF bytes - * at the end. If yes, the 0xFF bytes are cut and not written. So if the whole - * buffer contains only 0xFF bytes, the LEB is left unmapped. - * - * The reason why we skip the trailing 0xFF bytes in case of dynamic volume is - * that we want to make sure that more data may be appended to the logical - * eraseblock in future. Indeed, writing 0xFF bytes may have side effects and - * this PEB won't be writable anymore. So if one writes the file-system image - * to the UBI volume where 0xFFs mean free space - UBI makes sure this free - * space is writable after the update. - * - * We do not do this for static volumes because they are read-only. But this - * also cannot be done because we have to store per-LEB CRC and the correct - * data length. - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, - int len, int used_ebs) -{ - int err, l; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - l = ALIGN(len, ubi->min_io_size); - memset(buf + len, 0xFF, l - len); - - l = ubi_calc_data_len(ubi, buf, l); - if (l == 0) { - dbg_msg("all %d bytes contain 0xFF - skip", len); - return 0; - } - if (len != l) - dbg_msg("skip last %d bytes (0xFF)", len - l); - - err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l, - UBI_UNKNOWN); - } else { - /* - * When writing static volume, and this is the last logical - * eraseblock, the length (@len) does not have to be aligned to - * the minimal flash I/O unit. The 'ubi_eba_write_leb_st()' - * function accepts exact (unaligned) length and stores it in - * the VID header. And it takes care of proper alignment by - * padding the buffer. Here we just make sure the padding will - * contain zeros, not random trash. - */ - memset(buf + len, 0, vol->usable_leb_size - len); - err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len, - UBI_UNKNOWN, used_ebs); - } - - return err; -} - -/** - * ubi_more_update_data - write more update data. - * @vol: volume description object - * @buf: write data (user-space memory buffer) - * @count: how much bytes to write - * - * This function writes more data to the volume which is being updated. It may - * be called arbitrary number of times until all of the update data arrive. - * This function returns %0 in case of success, number of bytes written during - * the last call if the whole volume update was successfully finished, and a - * negative error code in case of failure. - */ -int ubi_more_update_data(struct ubi_device *ubi, int vol_id, - const void __user *buf, int count) -{ - uint64_t tmp; - struct ubi_volume *vol = ubi->volumes[vol_id]; - int lnum, offs, err = 0, len, to_write = count; - - dbg_msg("write %d of %lld bytes, %lld already passed", - count, vol->upd_bytes, vol->upd_received); - - if (ubi->ro_mode) - return -EROFS; - - tmp = vol->upd_received; - offs = do_div(tmp, vol->usable_leb_size); - lnum = tmp; - - if (vol->upd_received + count > vol->upd_bytes) - to_write = count = vol->upd_bytes - vol->upd_received; - - /* - * When updating volumes, we accumulate whole logical eraseblock of - * data and write it at once. - */ - if (offs != 0) { - /* - * This is a write to the middle of the logical eraseblock. We - * copy the data to our update buffer and wait for more data or - * flush it if the whole eraseblock is written or the update - * is finished. - */ - - len = vol->usable_leb_size - offs; - if (len > count) - len = count; - - err = copy_from_user(vol->upd_buf + offs, buf, len); - if (err) - return -EFAULT; - - if (offs + len == vol->usable_leb_size || - vol->upd_received + len == vol->upd_bytes) { - int flush_len = offs + len; - - /* - * OK, we gathered either the whole eraseblock or this - * is the last chunk, it's time to flush the buffer. - */ - ubi_assert(flush_len <= vol->usable_leb_size); - err = write_leb(ubi, vol_id, lnum, vol->upd_buf, - flush_len, vol->upd_ebs); - if (err) - return err; - } - - vol->upd_received += len; - count -= len; - buf += len; - lnum += 1; - } - - /* - * If we've got more to write, let's continue. At this point we know we - * are starting from the beginning of an eraseblock. - */ - while (count) { - if (count > vol->usable_leb_size) - len = vol->usable_leb_size; - else - len = count; - - err = copy_from_user(vol->upd_buf, buf, len); - if (err) - return -EFAULT; - - if (len == vol->usable_leb_size || - vol->upd_received + len == vol->upd_bytes) { - err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len, - vol->upd_ebs); - if (err) - break; - } - - vol->upd_received += len; - count -= len; - lnum += 1; - buf += len; - } - - ubi_assert(vol->upd_received <= vol->upd_bytes); - if (vol->upd_received == vol->upd_bytes) { - /* The update is finished, clear the update marker */ - err = clear_update_marker(ubi, vol_id, vol->upd_bytes); - if (err) - return err; - err = ubi_wl_flush(ubi); - if (err == 0) { - err = to_write; - kfree(vol->upd_buf); - vol->updating = 0; - } - } - - return err; -} diff --git a/trunk/drivers/mtd/ubi/vmt.c b/trunk/drivers/mtd/ubi/vmt.c deleted file mode 100644 index 622d0d18952c..000000000000 --- a/trunk/drivers/mtd/ubi/vmt.c +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * This file contains implementation of volume creation, deletion, updating and - * resizing. - */ - -#include -#include -#include "ubi.h" - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static void paranoid_check_volumes(struct ubi_device *ubi); -#else -#define paranoid_check_volumes(ubi) -#endif - -static ssize_t vol_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf); - -/* Device attributes corresponding to files in '//class/ubi/ubiX_Y' */ -static struct device_attribute vol_reserved_ebs = - __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_type = - __ATTR(type, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_name = - __ATTR(name, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_corrupted = - __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_alignment = - __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_usable_eb_size = - __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_data_bytes = - __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); -static struct device_attribute vol_upd_marker = - __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); - -/* - * "Show" method for files in '//class/ubi/ubiX_Y/'. - * - * Consider a situation: - * A. process 1 opens a sysfs file related to volume Y, say - * //class/ubi/ubiX_Y/reserved_ebs; - * B. process 2 removes volume Y; - * C. process 1 starts reading the //class/ubi/ubiX_Y/reserved_ebs file; - * - * What we want to do in a situation like that is to return error when the file - * is read. This is done by means of the 'removed' flag and the 'vol_lock' of - * the UBI volume description object. - */ -static ssize_t vol_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int ret; - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); - - spin_lock(&vol->ubi->volumes_lock); - if (vol->removed) { - spin_unlock(&vol->ubi->volumes_lock); - return -ENODEV; - } - if (attr == &vol_reserved_ebs) - ret = sprintf(buf, "%d\n", vol->reserved_pebs); - else if (attr == &vol_type) { - const char *tp; - tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static"; - ret = sprintf(buf, "%s\n", tp); - } else if (attr == &vol_name) - ret = sprintf(buf, "%s\n", vol->name); - else if (attr == &vol_corrupted) - ret = sprintf(buf, "%d\n", vol->corrupted); - else if (attr == &vol_alignment) - ret = sprintf(buf, "%d\n", vol->alignment); - else if (attr == &vol_usable_eb_size) { - ret = sprintf(buf, "%d\n", vol->usable_leb_size); - } else if (attr == &vol_data_bytes) - ret = sprintf(buf, "%lld\n", vol->used_bytes); - else if (attr == &vol_upd_marker) - ret = sprintf(buf, "%d\n", vol->upd_marker); - else - BUG(); - spin_unlock(&vol->ubi->volumes_lock); - return ret; -} - -/* Release method for volume devices */ -static void vol_release(struct device *dev) -{ - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); - ubi_assert(vol->removed); - kfree(vol); -} - -/** - * volume_sysfs_init - initialize sysfs for new volume. - * @ubi: UBI device description object - * @vol: volume description object - * - * This function returns zero in case of success and a negative error code in - * case of failure. - * - * Note, this function does not free allocated resources in case of failure - - * the caller does it. This is because this would cause release() here and the - * caller would oops. - */ -static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) -{ - int err; - - err = device_create_file(&vol->dev, &vol_reserved_ebs); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_type); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_name); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_corrupted); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_alignment); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_usable_eb_size); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_data_bytes); - if (err) - return err; - err = device_create_file(&vol->dev, &vol_upd_marker); - if (err) - return err; - return 0; -} - -/** - * volume_sysfs_close - close sysfs for a volume. - * @vol: volume description object - */ -static void volume_sysfs_close(struct ubi_volume *vol) -{ - device_remove_file(&vol->dev, &vol_upd_marker); - device_remove_file(&vol->dev, &vol_data_bytes); - device_remove_file(&vol->dev, &vol_usable_eb_size); - device_remove_file(&vol->dev, &vol_alignment); - device_remove_file(&vol->dev, &vol_corrupted); - device_remove_file(&vol->dev, &vol_name); - device_remove_file(&vol->dev, &vol_type); - device_remove_file(&vol->dev, &vol_reserved_ebs); - device_unregister(&vol->dev); -} - -/** - * ubi_create_volume - create volume. - * @ubi: UBI device description object - * @req: volume creation request - * - * This function creates volume described by @req. If @req->vol_id id - * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume - * and saves it in @req->vol_id. Returns zero in case of success and a negative - * error code in case of failure. - */ -int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) -{ - int i, err, vol_id = req->vol_id; - struct ubi_volume *vol; - struct ubi_vtbl_record vtbl_rec; - uint64_t bytes; - - if (ubi->ro_mode) - return -EROFS; - - vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); - if (!vol) - return -ENOMEM; - - spin_lock(&ubi->volumes_lock); - - if (vol_id == UBI_VOL_NUM_AUTO) { - /* Find unused volume ID */ - dbg_msg("search for vacant volume ID"); - for (i = 0; i < ubi->vtbl_slots; i++) - if (!ubi->volumes[i]) { - vol_id = i; - break; - } - - if (vol_id == UBI_VOL_NUM_AUTO) { - dbg_err("out of volume IDs"); - err = -ENFILE; - goto out_unlock; - } - req->vol_id = vol_id; - } - - dbg_msg("volume ID %d, %llu bytes, type %d, name %s", - vol_id, (unsigned long long)req->bytes, - (int)req->vol_type, req->name); - - /* Ensure that this volume does not exist */ - err = -EEXIST; - if (ubi->volumes[vol_id]) { - dbg_err("volume %d already exists", vol_id); - goto out_unlock; - } - - /* Ensure that the name is unique */ - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i] && - ubi->volumes[i]->name_len == req->name_len && - strcmp(ubi->volumes[i]->name, req->name) == 0) { - dbg_err("volume \"%s\" exists (ID %d)", req->name, i); - goto out_unlock; - } - - /* Calculate how many eraseblocks are requested */ - vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; - bytes = req->bytes; - if (do_div(bytes, vol->usable_leb_size)) - vol->reserved_pebs = 1; - vol->reserved_pebs += bytes; - - /* Reserve physical eraseblocks */ - if (vol->reserved_pebs > ubi->avail_pebs) { - dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); - spin_unlock(&ubi->volumes_lock); - err = -ENOSPC; - goto out_unlock; - } - ubi->avail_pebs -= vol->reserved_pebs; - ubi->rsvd_pebs += vol->reserved_pebs; - - vol->vol_id = vol_id; - vol->alignment = req->alignment; - vol->data_pad = ubi->leb_size % vol->alignment; - vol->vol_type = req->vol_type; - vol->name_len = req->name_len; - memcpy(vol->name, req->name, vol->name_len + 1); - vol->exclusive = 1; - vol->ubi = ubi; - ubi->volumes[vol_id] = vol; - spin_unlock(&ubi->volumes_lock); - - /* - * Finish all pending erases because there may be some LEBs belonging - * to the same volume ID. - */ - err = ubi_wl_flush(ubi); - if (err) - goto out_acc; - - vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL); - if (!vol->eba_tbl) { - err = -ENOMEM; - goto out_acc; - } - - for (i = 0; i < vol->reserved_pebs; i++) - vol->eba_tbl[i] = UBI_LEB_UNMAPPED; - - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - vol->used_ebs = vol->reserved_pebs; - vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; - } else { - bytes = vol->used_bytes; - vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); - vol->used_ebs = bytes; - if (vol->last_eb_bytes) - vol->used_ebs += 1; - else - vol->last_eb_bytes = vol->usable_leb_size; - } - - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; - err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1); - if (err) { - ubi_err("cannot add character device for volume %d", vol_id); - goto out_mapping; - } - - err = ubi_create_gluebi(ubi, vol); - if (err) - goto out_cdev; - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; - vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); - vol->dev.class = ubi_class; - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); - if (err) - goto out_gluebi; - - err = volume_sysfs_init(ubi, vol); - if (err) - goto out_sysfs; - - /* Fill volume table record */ - memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); - vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs); - vtbl_rec.alignment = cpu_to_ubi32(vol->alignment); - vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad); - vtbl_rec.name_len = cpu_to_ubi16(vol->name_len); - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - vtbl_rec.vol_type = UBI_VID_DYNAMIC; - else - vtbl_rec.vol_type = UBI_VID_STATIC; - memcpy(vtbl_rec.name, vol->name, vol->name_len + 1); - - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); - if (err) - goto out_sysfs; - - spin_lock(&ubi->volumes_lock); - ubi->vol_count += 1; - vol->exclusive = 0; - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); - return 0; - -out_gluebi: - err = ubi_destroy_gluebi(vol); -out_cdev: - cdev_del(&vol->cdev); -out_mapping: - kfree(vol->eba_tbl); -out_acc: - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= vol->reserved_pebs; - ubi->avail_pebs += vol->reserved_pebs; -out_unlock: - spin_unlock(&ubi->volumes_lock); - kfree(vol); - return err; - - /* - * We are registered, so @vol is destroyed in the release function and - * we have to de-initialize differently. - */ -out_sysfs: - err = ubi_destroy_gluebi(vol); - cdev_del(&vol->cdev); - kfree(vol->eba_tbl); - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= vol->reserved_pebs; - ubi->avail_pebs += vol->reserved_pebs; - spin_unlock(&ubi->volumes_lock); - volume_sysfs_close(vol); - return err; -} - -/** - * ubi_remove_volume - remove volume. - * @desc: volume descriptor - * - * This function removes volume described by @desc. The volume has to be opened - * in "exclusive" mode. Returns zero in case of success and a negative error - * code in case of failure. - */ -int ubi_remove_volume(struct ubi_volume_desc *desc) -{ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; - - dbg_msg("remove UBI volume %d", vol_id); - ubi_assert(desc->mode == UBI_EXCLUSIVE); - ubi_assert(vol == ubi->volumes[vol_id]); - - if (ubi->ro_mode) - return -EROFS; - - err = ubi_destroy_gluebi(vol); - if (err) - return err; - - err = ubi_change_vtbl_record(ubi, vol_id, NULL); - if (err) - return err; - - for (i = 0; i < vol->reserved_pebs; i++) { - err = ubi_eba_unmap_leb(ubi, vol_id, i); - if (err) - return err; - } - - spin_lock(&ubi->volumes_lock); - vol->removed = 1; - ubi->volumes[vol_id] = NULL; - spin_unlock(&ubi->volumes_lock); - - kfree(vol->eba_tbl); - vol->eba_tbl = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); - kfree(desc); - - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= reserved_pebs; - ubi->avail_pebs += reserved_pebs; - i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; - if (i > 0) { - i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; - ubi->avail_pebs -= i; - ubi->rsvd_pebs += i; - ubi->beb_rsvd_pebs += i; - if (i > 0) - ubi_msg("reserve more %d PEBs", i); - } - ubi->vol_count -= 1; - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); - module_put(THIS_MODULE); - return 0; -} - -/** - * ubi_resize_volume - re-size volume. - * @desc: volume descriptor - * @reserved_pebs: new size in physical eraseblocks - * - * This function returns zero in case of success, and a negative error code in - * case of failure. - */ -int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) -{ - int i, err, pebs, *new_mapping; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - struct ubi_vtbl_record vtbl_rec; - int vol_id = vol->vol_id; - - if (ubi->ro_mode) - return -EROFS; - - dbg_msg("re-size volume %d to from %d to %d PEBs", - vol_id, vol->reserved_pebs, reserved_pebs); - ubi_assert(desc->mode == UBI_EXCLUSIVE); - ubi_assert(vol == ubi->volumes[vol_id]); - - if (vol->vol_type == UBI_STATIC_VOLUME && - reserved_pebs < vol->used_ebs) { - dbg_err("too small size %d, %d LEBs contain data", - reserved_pebs, vol->used_ebs); - return -EINVAL; - } - - /* If the size is the same, we have nothing to do */ - if (reserved_pebs == vol->reserved_pebs) - return 0; - - new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL); - if (!new_mapping) - return -ENOMEM; - - for (i = 0; i < reserved_pebs; i++) - new_mapping[i] = UBI_LEB_UNMAPPED; - - /* Reserve physical eraseblocks */ - pebs = reserved_pebs - vol->reserved_pebs; - if (pebs > 0) { - spin_lock(&ubi->volumes_lock); - if (pebs > ubi->avail_pebs) { - dbg_err("not enough PEBs: requested %d, available %d", - pebs, ubi->avail_pebs); - spin_unlock(&ubi->volumes_lock); - err = -ENOSPC; - goto out_free; - } - ubi->avail_pebs -= pebs; - ubi->rsvd_pebs += pebs; - for (i = 0; i < vol->reserved_pebs; i++) - new_mapping[i] = vol->eba_tbl[i]; - kfree(vol->eba_tbl); - vol->eba_tbl = new_mapping; - spin_unlock(&ubi->volumes_lock); - } - - /* Change volume table record */ - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); - vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs); - err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); - if (err) - goto out_acc; - - if (pebs < 0) { - for (i = 0; i < -pebs; i++) { - err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i); - if (err) - goto out_acc; - } - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs += pebs; - ubi->avail_pebs -= pebs; - pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; - if (pebs > 0) { - pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs; - ubi->avail_pebs -= pebs; - ubi->rsvd_pebs += pebs; - ubi->beb_rsvd_pebs += pebs; - if (pebs > 0) - ubi_msg("reserve more %d PEBs", pebs); - } - for (i = 0; i < reserved_pebs; i++) - new_mapping[i] = vol->eba_tbl[i]; - kfree(vol->eba_tbl); - vol->eba_tbl = new_mapping; - spin_unlock(&ubi->volumes_lock); - } - - vol->reserved_pebs = reserved_pebs; - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - vol->used_ebs = reserved_pebs; - vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; - } - - paranoid_check_volumes(ubi); - return 0; - -out_acc: - if (pebs > 0) { - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= pebs; - ubi->avail_pebs += pebs; - spin_unlock(&ubi->volumes_lock); - } -out_free: - kfree(new_mapping); - return err; -} - -/** - * ubi_add_volume - add volume. - * @ubi: UBI device description object - * @vol_id: volume ID - * - * This function adds an existin volume and initializes all its data - * structures. Returnes zero in case of success and a negative error code in - * case of failure. - */ -int ubi_add_volume(struct ubi_device *ubi, int vol_id) -{ - int err; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - dbg_msg("add volume %d", vol_id); - ubi_dbg_dump_vol_info(vol); - ubi_assert(vol); - - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; - err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1); - if (err) { - ubi_err("cannot add character device for volume %d", vol_id); - return err; - } - - err = ubi_create_gluebi(ubi, vol); - if (err) - goto out_cdev; - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; - vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); - vol->dev.class = ubi_class; - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); - if (err) - goto out_gluebi; - - err = volume_sysfs_init(ubi, vol); - if (err) { - cdev_del(&vol->cdev); - err = ubi_destroy_gluebi(vol); - volume_sysfs_close(vol); - return err; - } - - paranoid_check_volumes(ubi); - return 0; - -out_gluebi: - err = ubi_destroy_gluebi(vol); -out_cdev: - cdev_del(&vol->cdev); - return err; -} - -/** - * ubi_free_volume - free volume. - * @ubi: UBI device description object - * @vol_id: volume ID - * - * This function frees all resources for volume @vol_id but does not remove it. - * Used only when the UBI device is detached. - */ -void ubi_free_volume(struct ubi_device *ubi, int vol_id) -{ - int err; - struct ubi_volume *vol = ubi->volumes[vol_id]; - - dbg_msg("free volume %d", vol_id); - ubi_assert(vol); - - vol->removed = 1; - err = ubi_destroy_gluebi(vol); - ubi->volumes[vol_id] = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); -} - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID - -/** - * paranoid_check_volume - check volume information. - * @ubi: UBI device description object - * @vol_id: volume ID - */ -static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) -{ - int idx = vol_id2idx(ubi, vol_id); - int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; - const struct ubi_volume *vol = ubi->volumes[idx]; - long long n; - const char *name; - - reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); - - if (!vol) { - if (reserved_pebs) { - ubi_err("no volume info, but volume exists"); - goto fail; - } - return; - } - - if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || - vol->name_len < 0) { - ubi_err("negative values"); - goto fail; - } - if (vol->alignment > ubi->leb_size || vol->alignment == 0) { - ubi_err("bad alignment"); - goto fail; - } - - n = vol->alignment % ubi->min_io_size; - if (vol->alignment != 1 && n) { - ubi_err("alignment is not multiple of min I/O unit"); - goto fail; - } - - n = ubi->leb_size % vol->alignment; - if (vol->data_pad != n) { - ubi_err("bad data_pad, has to be %lld", n); - goto fail; - } - - if (vol->vol_type != UBI_DYNAMIC_VOLUME && - vol->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); - goto fail; - } - - if (vol->upd_marker != 0 && vol->upd_marker != 1) { - ubi_err("bad upd_marker"); - goto fail; - } - - if (vol->upd_marker && vol->corrupted) { - dbg_err("update marker and corrupted simultaneously"); - goto fail; - } - - if (vol->reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs"); - goto fail; - } - - n = ubi->leb_size - vol->data_pad; - if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { - ubi_err("bad usable_leb_size, has to be %lld", n); - goto fail; - } - - if (vol->name_len > UBI_VOL_NAME_MAX) { - ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); - goto fail; - } - - if (!vol->name) { - ubi_err("NULL volume name"); - goto fail; - } - - n = strnlen(vol->name, vol->name_len + 1); - if (n != vol->name_len) { - ubi_err("bad name_len %lld", n); - goto fail; - } - - n = vol->used_ebs * vol->usable_leb_size; - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - if (vol->corrupted != 0) { - ubi_err("corrupted dynamic volume"); - goto fail; - } - if (vol->used_ebs != vol->reserved_pebs) { - ubi_err("bad used_ebs"); - goto fail; - } - if (vol->last_eb_bytes != vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); - goto fail; - } - if (vol->used_bytes != n) { - ubi_err("bad used_bytes"); - goto fail; - } - } else { - if (vol->corrupted != 0 && vol->corrupted != 1) { - ubi_err("bad corrupted"); - goto fail; - } - if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { - ubi_err("bad used_ebs"); - goto fail; - } - if (vol->last_eb_bytes < 0 || - vol->last_eb_bytes > vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); - goto fail; - } - if (vol->used_bytes < 0 || vol->used_bytes > n || - vol->used_bytes < n - vol->usable_leb_size) { - ubi_err("bad used_bytes"); - goto fail; - } - } - - alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment); - data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad); - name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len); - upd_marker = ubi->vtbl[vol_id].upd_marker; - name = &ubi->vtbl[vol_id].name[0]; - if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) - vol_type = UBI_DYNAMIC_VOLUME; - else - vol_type = UBI_STATIC_VOLUME; - - if (alignment != vol->alignment || data_pad != vol->data_pad || - upd_marker != vol->upd_marker || vol_type != vol->vol_type || - name_len!= vol->name_len || strncmp(name, vol->name, name_len)) { - ubi_err("volume info is different"); - goto fail; - } - - return; - -fail: - ubi_err("paranoid check failed"); - ubi_dbg_dump_vol_info(vol); - ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); - BUG(); -} - -/** - * paranoid_check_volumes - check information about all volumes. - * @ubi: UBI device description object - */ -static void paranoid_check_volumes(struct ubi_device *ubi) -{ - int i; - - mutex_lock(&ubi->vtbl_mutex); - spin_lock(&ubi->volumes_lock); - for (i = 0; i < ubi->vtbl_slots; i++) - paranoid_check_volume(ubi, i); - spin_unlock(&ubi->volumes_lock); - mutex_unlock(&ubi->vtbl_mutex); -} -#endif diff --git a/trunk/drivers/mtd/ubi/vtbl.c b/trunk/drivers/mtd/ubi/vtbl.c deleted file mode 100644 index b6fd6bbd941e..000000000000 --- a/trunk/drivers/mtd/ubi/vtbl.c +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (c) Nokia Corporation, 2006, 2007 - * - * 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 - * - * Author: Artem Bityutskiy (Битюцкий Ðртём) - */ - -/* - * This file includes volume table manipulation code. The volume table is an - * on-flash table containing volume meta-data like name, number of reserved - * physical eraseblocks, type, etc. The volume table is stored in the so-called - * "layout volume". - * - * The layout volume is an internal volume which is organized as follows. It - * consists of two logical eraseblocks - LEB 0 and LEB 1. Each logical - * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each - * other. This redundancy guarantees robustness to unclean reboots. The volume - * table is basically an array of volume table records. Each record contains - * full information about the volume and protected by a CRC checksum. - * - * The volume table is changed, it is first changed in RAM. Then LEB 0 is - * erased, and the updated volume table is written back to LEB 0. Then same for - * LEB 1. This scheme guarantees recoverability from unclean reboots. - * - * In this UBI implementation the on-flash volume table does not contain any - * information about how many data static volumes contain. This information may - * be found from the scanning data. - * - * But it would still be beneficial to store this information in the volume - * table. For example, suppose we have a static volume X, and all its physical - * eraseblocks became bad for some reasons. Suppose we are attaching the - * corresponding MTD device, the scanning has found no logical eraseblocks - * corresponding to the volume X. According to the volume table volume X does - * exist. So we don't know whether it is just empty or all its physical - * eraseblocks went bad. So we cannot alarm the user about this corruption. - * - * The volume table also stores so-called "update marker", which is used for - * volume updates. Before updating the volume, the update marker is set, and - * after the update operation is finished, the update marker is cleared. So if - * the update operation was interrupted (e.g. by an unclean reboot) - the - * update marker is still there and we know that the volume's contents is - * damaged. - */ - -#include -#include -#include -#include "ubi.h" - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static void paranoid_vtbl_check(const struct ubi_device *ubi); -#else -#define paranoid_vtbl_check(ubi) -#endif - -/* Empty volume table record */ -static struct ubi_vtbl_record empty_vtbl_record; - -/** - * ubi_change_vtbl_record - change volume table record. - * @ubi: UBI device description object - * @idx: table index to change - * @vtbl_rec: new volume table record - * - * This function changes volume table record @idx. If @vtbl_rec is %NULL, empty - * volume table record is written. The caller does not have to calculate CRC of - * the record as it is done by this function. Returns zero in case of success - * and a negative error code in case of failure. - */ -int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, - struct ubi_vtbl_record *vtbl_rec) -{ - int i, err; - uint32_t crc; - - ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); - - if (!vtbl_rec) - vtbl_rec = &empty_vtbl_record; - else { - crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); - vtbl_rec->crc = cpu_to_ubi32(crc); - } - - dbg_msg("change record %d", idx); - ubi_dbg_dump_vtbl_record(vtbl_rec, idx); - - mutex_lock(&ubi->vtbl_mutex); - memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { - err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i); - if (err) { - mutex_unlock(&ubi->vtbl_mutex); - return err; - } - err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0, - ubi->vtbl_size, UBI_LONGTERM); - if (err) { - mutex_unlock(&ubi->vtbl_mutex); - return err; - } - } - - paranoid_vtbl_check(ubi); - mutex_unlock(&ubi->vtbl_mutex); - return ubi_wl_flush(ubi); -} - -/** - * vol_til_check - check if volume table is not corrupted and contains sensible - * data. - * - * @ubi: UBI device description object - * @vtbl: volume table - * - * This function returns zero if @vtbl is all right, %1 if CRC is incorrect, - * and %-EINVAL if it contains inconsistent data. - */ -static int vtbl_check(const struct ubi_device *ubi, - const struct ubi_vtbl_record *vtbl) -{ - int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; - int upd_marker; - uint32_t crc; - const char *name; - - for (i = 0; i < ubi->vtbl_slots; i++) { - cond_resched(); - - reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); - alignment = ubi32_to_cpu(vtbl[i].alignment); - data_pad = ubi32_to_cpu(vtbl[i].data_pad); - upd_marker = vtbl[i].upd_marker; - vol_type = vtbl[i].vol_type; - name_len = ubi16_to_cpu(vtbl[i].name_len); - name = &vtbl[i].name[0]; - - crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); - if (ubi32_to_cpu(vtbl[i].crc) != crc) { - ubi_err("bad CRC at record %u: %#08x, not %#08x", - i, crc, ubi32_to_cpu(vtbl[i].crc)); - ubi_dbg_dump_vtbl_record(&vtbl[i], i); - return 1; - } - - if (reserved_pebs == 0) { - if (memcmp(&vtbl[i], &empty_vtbl_record, - UBI_VTBL_RECORD_SIZE)) { - dbg_err("bad empty record"); - goto bad; - } - continue; - } - - if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || - name_len < 0) { - dbg_err("negative values"); - goto bad; - } - - if (alignment > ubi->leb_size || alignment == 0) { - dbg_err("bad alignment"); - goto bad; - } - - n = alignment % ubi->min_io_size; - if (alignment != 1 && n) { - dbg_err("alignment is not multiple of min I/O unit"); - goto bad; - } - - n = ubi->leb_size % alignment; - if (data_pad != n) { - dbg_err("bad data_pad, has to be %d", n); - goto bad; - } - - if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { - dbg_err("bad vol_type"); - goto bad; - } - - if (upd_marker != 0 && upd_marker != 1) { - dbg_err("bad upd_marker"); - goto bad; - } - - if (reserved_pebs > ubi->good_peb_count) { - dbg_err("too large reserved_pebs, good PEBs %d", - ubi->good_peb_count); - goto bad; - } - - if (name_len > UBI_VOL_NAME_MAX) { - dbg_err("too long volume name, max %d", - UBI_VOL_NAME_MAX); - goto bad; - } - - if (name[0] == '\0') { - dbg_err("NULL volume name"); - goto bad; - } - - if (name_len != strnlen(name, name_len + 1)) { - dbg_err("bad name_len"); - goto bad; - } - } - - /* Checks that all names are unique */ - for (i = 0; i < ubi->vtbl_slots - 1; i++) { - for (n = i + 1; n < ubi->vtbl_slots; n++) { - int len1 = ubi16_to_cpu(vtbl[i].name_len); - int len2 = ubi16_to_cpu(vtbl[n].name_len); - - if (len1 > 0 && len1 == len2 && - !strncmp(vtbl[i].name, vtbl[n].name, len1)) { - ubi_err("volumes %d and %d have the same name" - " \"%s\"", i, n, vtbl[i].name); - ubi_dbg_dump_vtbl_record(&vtbl[i], i); - ubi_dbg_dump_vtbl_record(&vtbl[n], n); - return -EINVAL; - } - } - } - - return 0; - -bad: - ubi_err("volume table check failed, record %d", i); - ubi_dbg_dump_vtbl_record(&vtbl[i], i); - return -EINVAL; -} - -/** - * create_vtbl - create a copy of volume table. - * @ubi: UBI device description object - * @si: scanning information - * @copy: number of the volume table copy - * @vtbl: contents of the volume table - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si, - int copy, void *vtbl) -{ - int err, tries = 0; - static struct ubi_vid_hdr *vid_hdr; - struct ubi_scan_volume *sv; - struct ubi_scan_leb *new_seb, *old_seb = NULL; - - ubi_msg("create volume table (copy #%d)", copy + 1); - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) - return -ENOMEM; - - /* - * Check if there is a logical eraseblock which would have to contain - * this volume table copy was found during scanning. It has to be wiped - * out. - */ - sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); - if (sv) - old_seb = ubi_scan_find_seb(sv, copy); - -retry: - new_seb = ubi_scan_get_free_peb(ubi, si); - if (IS_ERR(new_seb)) { - err = PTR_ERR(new_seb); - goto out_free; - } - - vid_hdr->vol_type = UBI_VID_DYNAMIC; - vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID); - vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; - vid_hdr->data_size = vid_hdr->used_ebs = - vid_hdr->data_pad = cpu_to_ubi32(0); - vid_hdr->lnum = cpu_to_ubi32(copy); - vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum); - vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0); - - /* The EC header is already there, write the VID header */ - err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); - if (err) - goto write_error; - - /* Write the layout volume contents */ - err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size); - if (err) - goto write_error; - - /* - * And add it to the scanning information. Don't delete the old - * @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'. - */ - err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec, - vid_hdr, 0); - kfree(new_seb); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - -write_error: - kfree(new_seb); - /* May be this physical eraseblock went bad, try to pick another one */ - if (++tries <= 5) { - err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec, - &si->corr); - if (!err) - goto retry; - } -out_free: - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - -} - -/** - * process_lvol - process the layout volume. - * @ubi: UBI device description object - * @si: scanning information - * @sv: layout volume scanning information - * - * This function is responsible for reading the layout volume, ensuring it is - * not corrupted, and recovering from corruptions if needed. Returns volume - * table in case of success and a negative error code in case of failure. - */ -static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, - struct ubi_scan_info *si, - struct ubi_scan_volume *sv) -{ - int err; - struct rb_node *rb; - struct ubi_scan_leb *seb; - struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL }; - int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1}; - - /* - * UBI goes through the following steps when it changes the layout - * volume: - * a. erase LEB 0; - * b. write new data to LEB 0; - * c. erase LEB 1; - * d. write new data to LEB 1. - * - * Before the change, both LEBs contain the same data. - * - * Due to unclean reboots, the contents of LEB 0 may be lost, but there - * should LEB 1. So it is OK if LEB 0 is corrupted while LEB 1 is not. - * Similarly, LEB 1 may be lost, but there should be LEB 0. And - * finally, unclean reboots may result in a situation when neither LEB - * 0 nor LEB 1 are corrupted, but they are different. In this case, LEB - * 0 contains more recent information. - * - * So the plan is to first check LEB 0. Then - * a. if LEB 0 is OK, it must be containing the most resent data; then - * we compare it with LEB 1, and if they are different, we copy LEB - * 0 to LEB 1; - * b. if LEB 0 is corrupted, but LEB 1 has to be OK, and we copy LEB 1 - * to LEB 0. - */ - - dbg_msg("check layout volume"); - - /* Read both LEB 0 and LEB 1 into memory */ - ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { - leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL); - if (!leb[seb->lnum]) { - err = -ENOMEM; - goto out_free; - } - - err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, - ubi->vtbl_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) - /* Scrub the PEB later */ - seb->scrub = 1; - else if (err) - goto out_free; - } - - err = -EINVAL; - if (leb[0]) { - leb_corrupted[0] = vtbl_check(ubi, leb[0]); - if (leb_corrupted[0] < 0) - goto out_free; - } - - if (!leb_corrupted[0]) { - /* LEB 0 is OK */ - if (leb[1]) - leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); - if (leb_corrupted[1]) { - ubi_warn("volume table copy #2 is corrupted"); - err = create_vtbl(ubi, si, 1, leb[0]); - if (err) - goto out_free; - ubi_msg("volume table was restored"); - } - - /* Both LEB 1 and LEB 2 are OK and consistent */ - kfree(leb[1]); - return leb[0]; - } else { - /* LEB 0 is corrupted or does not exist */ - if (leb[1]) { - leb_corrupted[1] = vtbl_check(ubi, leb[1]); - if (leb_corrupted[1] < 0) - goto out_free; - } - if (leb_corrupted[1]) { - /* Both LEB 0 and LEB 1 are corrupted */ - ubi_err("both volume tables are corrupted"); - goto out_free; - } - - ubi_warn("volume table copy #1 is corrupted"); - err = create_vtbl(ubi, si, 0, leb[1]); - if (err) - goto out_free; - ubi_msg("volume table was restored"); - - kfree(leb[0]); - return leb[1]; - } - -out_free: - kfree(leb[0]); - kfree(leb[1]); - return ERR_PTR(err); -} - -/** - * create_empty_lvol - create empty layout volume. - * @ubi: UBI device description object - * @si: scanning information - * - * This function returns volume table contents in case of success and a - * negative error code in case of failure. - */ -static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi, - struct ubi_scan_info *si) -{ - int i; - struct ubi_vtbl_record *vtbl; - - vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL); - if (!vtbl) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < ubi->vtbl_slots; i++) - memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); - - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { - int err; - - err = create_vtbl(ubi, si, i, vtbl); - if (err) { - kfree(vtbl); - return ERR_PTR(err); - } - } - - return vtbl; -} - -/** - * init_volumes - initialize volume information for existing volumes. - * @ubi: UBI device description object - * @si: scanning information - * @vtbl: volume table - * - * This function allocates volume description objects for existing volumes. - * Returns zero in case of success and a negative error code in case of - * failure. - */ -static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, - const struct ubi_vtbl_record *vtbl) -{ - int i, reserved_pebs = 0; - struct ubi_scan_volume *sv; - struct ubi_volume *vol; - - for (i = 0; i < ubi->vtbl_slots; i++) { - cond_resched(); - - if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0) - continue; /* Empty record */ - - vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); - if (!vol) - return -ENOMEM; - - vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); - vol->alignment = ubi32_to_cpu(vtbl[i].alignment); - vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad); - vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? - UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; - vol->name_len = ubi16_to_cpu(vtbl[i].name_len); - vol->usable_leb_size = ubi->leb_size - vol->data_pad; - memcpy(vol->name, vtbl[i].name, vol->name_len); - vol->name[vol->name_len] = '\0'; - vol->vol_id = i; - - ubi_assert(!ubi->volumes[i]); - ubi->volumes[i] = vol; - ubi->vol_count += 1; - vol->ubi = ubi; - reserved_pebs += vol->reserved_pebs; - - /* - * In case of dynamic volume UBI knows nothing about how many - * data is stored there. So assume the whole volume is used. - */ - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { - vol->used_ebs = vol->reserved_pebs; - vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; - continue; - } - - /* Static volumes only */ - sv = ubi_scan_find_sv(si, i); - if (!sv) { - /* - * No eraseblocks belonging to this volume found. We - * don't actually know whether this static volume is - * completely corrupted or just contains no data. And - * we cannot know this as long as data size is not - * stored on flash. So we just assume the volume is - * empty. FIXME: this should be handled. - */ - continue; - } - - if (sv->leb_count != sv->used_ebs) { - /* - * We found a static volume which misses several - * eraseblocks. Treat it as corrupted. - */ - ubi_warn("static volume %d misses %d LEBs - corrupted", - sv->vol_id, sv->used_ebs - sv->leb_count); - vol->corrupted = 1; - continue; - } - - vol->used_ebs = sv->used_ebs; - vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size; - vol->used_bytes += sv->last_data_size; - vol->last_eb_bytes = sv->last_data_size; - } - - vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); - if (!vol) - return -ENOMEM; - - vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS; - vol->alignment = 1; - vol->vol_type = UBI_DYNAMIC_VOLUME; - vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1; - memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1); - vol->usable_leb_size = ubi->leb_size; - vol->used_ebs = vol->reserved_pebs; - vol->last_eb_bytes = vol->reserved_pebs; - vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad); - vol->vol_id = UBI_LAYOUT_VOL_ID; - - ubi_assert(!ubi->volumes[i]); - ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; - reserved_pebs += vol->reserved_pebs; - ubi->vol_count += 1; - vol->ubi = ubi; - - if (reserved_pebs > ubi->avail_pebs) - ubi_err("not enough PEBs, required %d, available %d", - reserved_pebs, ubi->avail_pebs); - ubi->rsvd_pebs += reserved_pebs; - ubi->avail_pebs -= reserved_pebs; - - return 0; -} - -/** - * check_sv - check volume scanning information. - * @vol: UBI volume description object - * @sv: volume scanning information - * - * This function returns zero if the volume scanning information is consistent - * to the data read from the volume tabla, and %-EINVAL if not. - */ -static int check_sv(const struct ubi_volume *vol, - const struct ubi_scan_volume *sv) -{ - if (sv->highest_lnum >= vol->reserved_pebs) { - dbg_err("bad highest_lnum"); - goto bad; - } - if (sv->leb_count > vol->reserved_pebs) { - dbg_err("bad leb_count"); - goto bad; - } - if (sv->vol_type != vol->vol_type) { - dbg_err("bad vol_type"); - goto bad; - } - if (sv->used_ebs > vol->reserved_pebs) { - dbg_err("bad used_ebs"); - goto bad; - } - if (sv->data_pad != vol->data_pad) { - dbg_err("bad data_pad"); - goto bad; - } - return 0; - -bad: - ubi_err("bad scanning information"); - ubi_dbg_dump_sv(sv); - ubi_dbg_dump_vol_info(vol); - return -EINVAL; -} - -/** - * check_scanning_info - check that scanning information. - * @ubi: UBI device description object - * @si: scanning information - * - * Even though we protect on-flash data by CRC checksums, we still don't trust - * the media. This function ensures that scanning information is consistent to - * the information read from the volume table. Returns zero if the scanning - * information is OK and %-EINVAL if it is not. - */ -static int check_scanning_info(const struct ubi_device *ubi, - struct ubi_scan_info *si) -{ - int err, i; - struct ubi_scan_volume *sv; - struct ubi_volume *vol; - - if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { - ubi_err("scanning found %d volumes, maximum is %d + %d", - si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); - return -EINVAL; - } - - if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&& - si->highest_vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("too large volume ID %d found by scanning", - si->highest_vol_id); - return -EINVAL; - } - - - for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { - cond_resched(); - - sv = ubi_scan_find_sv(si, i); - vol = ubi->volumes[i]; - if (!vol) { - if (sv) - ubi_scan_rm_volume(si, sv); - continue; - } - - if (vol->reserved_pebs == 0) { - ubi_assert(i < ubi->vtbl_slots); - - if (!sv) - continue; - - /* - * During scanning we found a volume which does not - * exist according to the information in the volume - * table. This must have happened due to an unclean - * reboot while the volume was being removed. Discard - * these eraseblocks. - */ - ubi_msg("finish volume %d removal", sv->vol_id); - ubi_scan_rm_volume(si, sv); - } else if (sv) { - err = check_sv(vol, sv); - if (err) - return err; - } - } - - return 0; -} - -/** - * ubi_read_volume_table - read volume table. - * information. - * @ubi: UBI device description object - * @si: scanning information - * - * This function reads volume table, checks it, recover from errors if needed, - * or creates it if needed. Returns zero in case of success and a negative - * error code in case of failure. - */ -int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) -{ - int i, err; - struct ubi_scan_volume *sv; - - empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b); - - /* - * The number of supported volumes is limited by the eraseblock size - * and by the UBI_MAX_VOLUMES constant. - */ - ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE; - if (ubi->vtbl_slots > UBI_MAX_VOLUMES) - ubi->vtbl_slots = UBI_MAX_VOLUMES; - - ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; - ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); - - sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); - if (!sv) { - /* - * No logical eraseblocks belonging to the layout volume were - * found. This could mean that the flash is just empty. In - * this case we create empty layout volume. - * - * But if flash is not empty this must be a corruption or the - * MTD device just contains garbage. - */ - if (si->is_empty) { - ubi->vtbl = create_empty_lvol(ubi, si); - if (IS_ERR(ubi->vtbl)) - return PTR_ERR(ubi->vtbl); - } else { - ubi_err("the layout volume was not found"); - return -EINVAL; - } - } else { - if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) { - /* This must not happen with proper UBI images */ - dbg_err("too many LEBs (%d) in layout volume", - sv->leb_count); - return -EINVAL; - } - - ubi->vtbl = process_lvol(ubi, si, sv); - if (IS_ERR(ubi->vtbl)) - return PTR_ERR(ubi->vtbl); - } - - ubi->avail_pebs = ubi->good_peb_count; - - /* - * The layout volume is OK, initialize the corresponding in-RAM data - * structures. - */ - err = init_volumes(ubi, si, ubi->vtbl); - if (err) - goto out_free; - - /* - * Get sure that the scanning information is consistent to the - * information stored in the volume table. - */ - err = check_scanning_info(ubi, si); - if (err) - goto out_free; - - return 0; - -out_free: - kfree(ubi->vtbl); - for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) - if (ubi->volumes[i]) { - kfree(ubi->volumes[i]); - ubi->volumes[i] = NULL; - } - return err; -} - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID - -/** - * paranoid_vtbl_check - check volume table. - * @ubi: UBI device description object - */ -static void paranoid_vtbl_check(const struct ubi_device *ubi) -{ - if (vtbl_check(ubi, ubi->vtbl)) { - ubi_err("paranoid check failed"); - BUG(); - } -} - -#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/trunk/drivers/mtd/ubi/wl.c b/trunk/drivers/mtd/ubi/wl.c deleted file mode 100644 index 9ecaf77eca9e..000000000000 --- a/trunk/drivers/mtd/ubi/wl.c +++ /dev/null @@ -1,1671 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * 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 - * - * Authors: Artem Bityutskiy (Битюцкий Ðртём), Thomas Gleixner - */ - -/* - * UBI wear-leveling unit. - * - * This unit is responsible for wear-leveling. It works in terms of physical - * eraseblocks and erase counters and knows nothing about logical eraseblocks, - * volumes, etc. From this unit's perspective all physical eraseblocks are of - * two types - used and free. Used physical eraseblocks are those that were - * "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are - * those that were put by the 'ubi_wl_put_peb()' function. - * - * Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter - * header. The rest of the physical eraseblock contains only 0xFF bytes. - * - * When physical eraseblocks are returned to the WL unit by means of the - * 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is - * done asynchronously in context of the per-UBI device background thread, - * which is also managed by the WL unit. - * - * The wear-leveling is ensured by means of moving the contents of used - * physical eraseblocks with low erase counter to free physical eraseblocks - * with high erase counter. - * - * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick - * an "optimal" physical eraseblock. For example, when it is known that the - * physical eraseblock will be "put" soon because it contains short-term data, - * the WL unit may pick a free physical eraseblock with low erase counter, and - * so forth. - * - * If the WL unit fails to erase a physical eraseblock, it marks it as bad. - * - * This unit is also responsible for scrubbing. If a bit-flip is detected in a - * physical eraseblock, it has to be moved. Technically this is the same as - * moving it for wear-leveling reasons. - * - * As it was said, for the UBI unit all physical eraseblocks are either "free" - * or "used". Free eraseblock are kept in the @wl->free RB-tree, while used - * eraseblocks are kept in a set of different RB-trees: @wl->used, - * @wl->prot.pnum, @wl->prot.aec, and @wl->scrub. - * - * Note, in this implementation, we keep a small in-RAM object for each physical - * eraseblock. This is surely not a scalable solution. But it appears to be good - * enough for moderately large flashes and it is simple. In future, one may - * re-work this unit and make it more scalable. - * - * At the moment this unit does not utilize the sequence number, which was - * introduced relatively recently. But it would be wise to do this because the - * sequence number of a logical eraseblock characterizes how old is it. For - * example, when we move a PEB with low erase counter, and we need to pick the - * target PEB, we pick a PEB with the highest EC if our PEB is "old" and we - * pick target PEB with an average EC if our PEB is not very "old". This is a - * room for future re-works of the WL unit. - * - * FIXME: looks too complex, should be simplified (later). - */ - -#include -#include -#include -#include -#include "ubi.h" - -/* Number of physical eraseblocks reserved for wear-leveling purposes */ -#define WL_RESERVED_PEBS 1 - -/* - * How many erase cycles are short term, unknown, and long term physical - * eraseblocks protected. - */ -#define ST_PROTECTION 16 -#define U_PROTECTION 10 -#define LT_PROTECTION 4 - -/* - * Maximum difference between two erase counters. If this threshold is - * exceeded, the WL unit starts moving data from used physical eraseblocks with - * low erase counter to free physical eraseblocks with high erase counter. - */ -#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD - -/* - * When a physical eraseblock is moved, the WL unit has to pick the target - * physical eraseblock to move to. The simplest way would be just to pick the - * one with the highest erase counter. But in certain workloads this could lead - * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a - * situation when the picked physical eraseblock is constantly erased after the - * data is written to it. So, we have a constant which limits the highest erase - * counter of the free physical eraseblock to pick. Namely, the WL unit does - * not pick eraseblocks with erase counter greater then the lowest erase - * counter plus %WL_FREE_MAX_DIFF. - */ -#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD) - -/* - * Maximum number of consecutive background thread failures which is enough to - * switch to read-only mode. - */ -#define WL_MAX_FAILURES 32 - -/** - * struct ubi_wl_entry - wear-leveling entry. - * @rb: link in the corresponding RB-tree - * @ec: erase counter - * @pnum: physical eraseblock number - * - * Each physical eraseblock has a corresponding &struct wl_entry object which - * may be kept in different RB-trees. - */ -struct ubi_wl_entry { - struct rb_node rb; - int ec; - int pnum; -}; - -/** - * struct ubi_wl_prot_entry - PEB protection entry. - * @rb_pnum: link in the @wl->prot.pnum RB-tree - * @rb_aec: link in the @wl->prot.aec RB-tree - * @abs_ec: the absolute erase counter value when the protection ends - * @e: the wear-leveling entry of the physical eraseblock under protection - * - * When the WL unit returns a physical eraseblock, the physical eraseblock is - * protected from being moved for some "time". For this reason, the physical - * eraseblock is not directly moved from the @wl->free tree to the @wl->used - * tree. There is one more tree in between where this physical eraseblock is - * temporarily stored (@wl->prot). - * - * All this protection stuff is needed because: - * o we don't want to move physical eraseblocks just after we have given them - * to the user; instead, we first want to let users fill them up with data; - * - * o there is a chance that the user will put the physical eraseblock very - * soon, so it makes sense not to move it for some time, but wait; this is - * especially important in case of "short term" physical eraseblocks. - * - * Physical eraseblocks stay protected only for limited time. But the "time" is - * measured in erase cycles in this case. This is implemented with help of the - * absolute erase counter (@wl->abs_ec). When it reaches certain value, the - * physical eraseblocks are moved from the protection trees (@wl->prot.*) to - * the @wl->used tree. - * - * Protected physical eraseblocks are searched by physical eraseblock number - * (when they are put) and by the absolute erase counter (to check if it is - * time to move them to the @wl->used tree). So there are actually 2 RB-trees - * storing the protected physical eraseblocks: @wl->prot.pnum and - * @wl->prot.aec. They are referred to as the "protection" trees. The - * first one is indexed by the physical eraseblock number. The second one is - * indexed by the absolute erase counter. Both trees store - * &struct ubi_wl_prot_entry objects. - * - * Each physical eraseblock has 2 main states: free and used. The former state - * corresponds to the @wl->free tree. The latter state is split up on several - * sub-states: - * o the WL movement is allowed (@wl->used tree); - * o the WL movement is temporarily prohibited (@wl->prot.pnum and - * @wl->prot.aec trees); - * o scrubbing is needed (@wl->scrub tree). - * - * Depending on the sub-state, wear-leveling entries of the used physical - * eraseblocks may be kept in one of those trees. - */ -struct ubi_wl_prot_entry { - struct rb_node rb_pnum; - struct rb_node rb_aec; - unsigned long long abs_ec; - struct ubi_wl_entry *e; -}; - -/** - * struct ubi_work - UBI work description data structure. - * @list: a link in the list of pending works - * @func: worker function - * @priv: private data of the worker function - * - * @e: physical eraseblock to erase - * @torture: if the physical eraseblock has to be tortured - * - * The @func pointer points to the worker function. If the @cancel argument is - * not zero, the worker has to free the resources and exit immediately. The - * worker has to return zero in case of success and a negative error code in - * case of failure. - */ -struct ubi_work { - struct list_head list; - int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); - /* The below fields are only relevant to erasure works */ - struct ubi_wl_entry *e; - int torture; -}; - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec); -static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, - struct rb_root *root); -#else -#define paranoid_check_ec(ubi, pnum, ec) 0 -#define paranoid_check_in_wl_tree(e, root) -#endif - -/* Slab cache for wear-leveling entries */ -static struct kmem_cache *wl_entries_slab; - -/** - * tree_empty - a helper function to check if an RB-tree is empty. - * @root: the root of the tree - * - * This function returns non-zero if the RB-tree is empty and zero if not. - */ -static inline int tree_empty(struct rb_root *root) -{ - return root->rb_node == NULL; -} - -/** - * wl_tree_add - add a wear-leveling entry to a WL RB-tree. - * @e: the wear-leveling entry to add - * @root: the root of the tree - * - * Note, we use (erase counter, physical eraseblock number) pairs as keys in - * the @ubi->used and @ubi->free RB-trees. - */ -static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root) -{ - struct rb_node **p, *parent = NULL; - - p = &root->rb_node; - while (*p) { - struct ubi_wl_entry *e1; - - parent = *p; - e1 = rb_entry(parent, struct ubi_wl_entry, rb); - - if (e->ec < e1->ec) - p = &(*p)->rb_left; - else if (e->ec > e1->ec) - p = &(*p)->rb_right; - else { - ubi_assert(e->pnum != e1->pnum); - if (e->pnum < e1->pnum) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - } - - rb_link_node(&e->rb, parent, p); - rb_insert_color(&e->rb, root); -} - - -/* - * Helper functions to add and delete wear-leveling entries from different - * trees. - */ - -static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->free); -} -static inline void used_tree_add(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->used); -} -static inline void scrub_tree_add(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - wl_tree_add(e, &ubi->scrub); -} -static inline void free_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->free); - rb_erase(&e->rb, &ubi->free); -} -static inline void used_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->used); - rb_erase(&e->rb, &ubi->used); -} -static inline void scrub_tree_del(struct ubi_device *ubi, - struct ubi_wl_entry *e) -{ - paranoid_check_in_wl_tree(e, &ubi->scrub); - rb_erase(&e->rb, &ubi->scrub); -} - -/** - * do_work - do one pending work. - * @ubi: UBI device description object - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int do_work(struct ubi_device *ubi) -{ - int err; - struct ubi_work *wrk; - - spin_lock(&ubi->wl_lock); - - if (list_empty(&ubi->works)) { - spin_unlock(&ubi->wl_lock); - return 0; - } - - wrk = list_entry(ubi->works.next, struct ubi_work, list); - list_del(&wrk->list); - spin_unlock(&ubi->wl_lock); - - /* - * Call the worker function. Do not touch the work structure - * after this call as it will have been freed or reused by that - * time by the worker function. - */ - err = wrk->func(ubi, wrk, 0); - if (err) - ubi_err("work failed with error code %d", err); - - spin_lock(&ubi->wl_lock); - ubi->works_count -= 1; - ubi_assert(ubi->works_count >= 0); - spin_unlock(&ubi->wl_lock); - return err; -} - -/** - * produce_free_peb - produce a free physical eraseblock. - * @ubi: UBI device description object - * - * This function tries to make a free PEB by means of synchronous execution of - * pending works. This may be needed if, for example the background thread is - * disabled. Returns zero in case of success and a negative error code in case - * of failure. - */ -static int produce_free_peb(struct ubi_device *ubi) -{ - int err; - - spin_lock(&ubi->wl_lock); - while (tree_empty(&ubi->free)) { - spin_unlock(&ubi->wl_lock); - - dbg_wl("do one work synchronously"); - err = do_work(ubi); - if (err) - return err; - - spin_lock(&ubi->wl_lock); - } - spin_unlock(&ubi->wl_lock); - - return 0; -} - -/** - * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree. - * @e: the wear-leveling entry to check - * @root: the root of the tree - * - * This function returns non-zero if @e is in the @root RB-tree and zero if it - * is not. - */ -static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root) -{ - struct rb_node *p; - - p = root->rb_node; - while (p) { - struct ubi_wl_entry *e1; - - e1 = rb_entry(p, struct ubi_wl_entry, rb); - - if (e->pnum == e1->pnum) { - ubi_assert(e == e1); - return 1; - } - - if (e->ec < e1->ec) - p = p->rb_left; - else if (e->ec > e1->ec) - p = p->rb_right; - else { - ubi_assert(e->pnum != e1->pnum); - if (e->pnum < e1->pnum) - p = p->rb_left; - else - p = p->rb_right; - } - } - - return 0; -} - -/** - * prot_tree_add - add physical eraseblock to protection trees. - * @ubi: UBI device description object - * @e: the physical eraseblock to add - * @pe: protection entry object to use - * @abs_ec: absolute erase counter value when this physical eraseblock has - * to be removed from the protection trees. - * - * @wl->lock has to be locked. - */ -static void prot_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e, - struct ubi_wl_prot_entry *pe, int abs_ec) -{ - struct rb_node **p, *parent = NULL; - struct ubi_wl_prot_entry *pe1; - - pe->e = e; - pe->abs_ec = ubi->abs_ec + abs_ec; - - p = &ubi->prot.pnum.rb_node; - while (*p) { - parent = *p; - pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_pnum); - - if (e->pnum < pe1->e->pnum) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&pe->rb_pnum, parent, p); - rb_insert_color(&pe->rb_pnum, &ubi->prot.pnum); - - p = &ubi->prot.aec.rb_node; - parent = NULL; - while (*p) { - parent = *p; - pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_aec); - - if (pe->abs_ec < pe1->abs_ec) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&pe->rb_aec, parent, p); - rb_insert_color(&pe->rb_aec, &ubi->prot.aec); -} - -/** - * find_wl_entry - find wear-leveling entry closest to certain erase counter. - * @root: the RB-tree where to look for - * @max: highest possible erase counter - * - * This function looks for a wear leveling entry with erase counter closest to - * @max and less then @max. - */ -static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max) -{ - struct rb_node *p; - struct ubi_wl_entry *e; - - e = rb_entry(rb_first(root), struct ubi_wl_entry, rb); - max += e->ec; - - p = root->rb_node; - while (p) { - struct ubi_wl_entry *e1; - - e1 = rb_entry(p, struct ubi_wl_entry, rb); - if (e1->ec >= max) - p = p->rb_left; - else { - p = p->rb_right; - e = e1; - } - } - - return e; -} - -/** - * ubi_wl_get_peb - get a physical eraseblock. - * @ubi: UBI device description object - * @dtype: type of data which will be stored in this physical eraseblock - * - * This function returns a physical eraseblock in case of success and a - * negative error code in case of failure. Might sleep. - */ -int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) -{ - int err, protect, medium_ec; - struct ubi_wl_entry *e, *first, *last; - struct ubi_wl_prot_entry *pe; - - ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM || - dtype == UBI_UNKNOWN); - - pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL); - if (!pe) - return -ENOMEM; - -retry: - spin_lock(&ubi->wl_lock); - if (tree_empty(&ubi->free)) { - if (ubi->works_count == 0) { - ubi_assert(list_empty(&ubi->works)); - ubi_err("no free eraseblocks"); - spin_unlock(&ubi->wl_lock); - kfree(pe); - return -ENOSPC; - } - spin_unlock(&ubi->wl_lock); - - err = produce_free_peb(ubi); - if (err < 0) { - kfree(pe); - return err; - } - goto retry; - } - - switch (dtype) { - case UBI_LONGTERM: - /* - * For long term data we pick a physical eraseblock - * with high erase counter. But the highest erase - * counter we can pick is bounded by the the lowest - * erase counter plus %WL_FREE_MAX_DIFF. - */ - e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - protect = LT_PROTECTION; - break; - case UBI_UNKNOWN: - /* - * For unknown data we pick a physical eraseblock with - * medium erase counter. But we by no means can pick a - * physical eraseblock with erase counter greater or - * equivalent than the lowest erase counter plus - * %WL_FREE_MAX_DIFF. - */ - first = rb_entry(rb_first(&ubi->free), - struct ubi_wl_entry, rb); - last = rb_entry(rb_last(&ubi->free), - struct ubi_wl_entry, rb); - - if (last->ec - first->ec < WL_FREE_MAX_DIFF) - e = rb_entry(ubi->free.rb_node, - struct ubi_wl_entry, rb); - else { - medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2; - e = find_wl_entry(&ubi->free, medium_ec); - } - protect = U_PROTECTION; - break; - case UBI_SHORTTERM: - /* - * For short term data we pick a physical eraseblock - * with the lowest erase counter as we expect it will - * be erased soon. - */ - e = rb_entry(rb_first(&ubi->free), - struct ubi_wl_entry, rb); - protect = ST_PROTECTION; - break; - default: - protect = 0; - e = NULL; - BUG(); - } - - /* - * Move the physical eraseblock to the protection trees where it will - * be protected from being moved for some time. - */ - free_tree_del(ubi, e); - prot_tree_add(ubi, e, pe, protect); - - dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect); - spin_unlock(&ubi->wl_lock); - - return e->pnum; -} - -/** - * prot_tree_del - remove a physical eraseblock from the protection trees - * @ubi: UBI device description object - * @pnum: the physical eraseblock to remove - */ -static void prot_tree_del(struct ubi_device *ubi, int pnum) -{ - struct rb_node *p; - struct ubi_wl_prot_entry *pe = NULL; - - p = ubi->prot.pnum.rb_node; - while (p) { - - pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); - - if (pnum == pe->e->pnum) - break; - - if (pnum < pe->e->pnum) - p = p->rb_left; - else - p = p->rb_right; - } - - ubi_assert(pe->e->pnum == pnum); - rb_erase(&pe->rb_aec, &ubi->prot.aec); - rb_erase(&pe->rb_pnum, &ubi->prot.pnum); - kfree(pe); -} - -/** - * sync_erase - synchronously erase a physical eraseblock. - * @ubi: UBI device description object - * @e: the the physical eraseblock to erase - * @torture: if the physical eraseblock has to be tortured - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture) -{ - int err; - struct ubi_ec_hdr *ec_hdr; - unsigned long long ec = e->ec; - - dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec); - - err = paranoid_check_ec(ubi, e->pnum, e->ec); - if (err > 0) - return -EINVAL; - - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - - err = ubi_io_sync_erase(ubi, e->pnum, torture); - if (err < 0) - goto out_free; - - ec += err; - if (ec > UBI_MAX_ERASECOUNTER) { - /* - * Erase counter overflow. Upgrade UBI and use 64-bit - * erase counters internally. - */ - ubi_err("erase counter overflow at PEB %d, EC %llu", - e->pnum, ec); - err = -EINVAL; - goto out_free; - } - - dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec); - - ec_hdr->ec = cpu_to_ubi64(ec); - - err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr); - if (err) - goto out_free; - - e->ec = ec; - spin_lock(&ubi->wl_lock); - if (e->ec > ubi->max_ec) - ubi->max_ec = e->ec; - spin_unlock(&ubi->wl_lock); - -out_free: - kfree(ec_hdr); - return err; -} - -/** - * check_protection_over - check if it is time to stop protecting some - * physical eraseblocks. - * @ubi: UBI device description object - * - * This function is called after each erase operation, when the absolute erase - * counter is incremented, to check if some physical eraseblock have not to be - * protected any longer. These physical eraseblocks are moved from the - * protection trees to the used tree. - */ -static void check_protection_over(struct ubi_device *ubi) -{ - struct ubi_wl_prot_entry *pe; - - /* - * There may be several protected physical eraseblock to remove, - * process them all. - */ - while (1) { - spin_lock(&ubi->wl_lock); - if (tree_empty(&ubi->prot.aec)) { - spin_unlock(&ubi->wl_lock); - break; - } - - pe = rb_entry(rb_first(&ubi->prot.aec), - struct ubi_wl_prot_entry, rb_aec); - - if (pe->abs_ec > ubi->abs_ec) { - spin_unlock(&ubi->wl_lock); - break; - } - - dbg_wl("PEB %d protection over, abs_ec %llu, PEB abs_ec %llu", - pe->e->pnum, ubi->abs_ec, pe->abs_ec); - rb_erase(&pe->rb_aec, &ubi->prot.aec); - rb_erase(&pe->rb_pnum, &ubi->prot.pnum); - used_tree_add(ubi, pe->e); - spin_unlock(&ubi->wl_lock); - - kfree(pe); - cond_resched(); - } -} - -/** - * schedule_ubi_work - schedule a work. - * @ubi: UBI device description object - * @wrk: the work to schedule - * - * This function enqueues a work defined by @wrk to the tail of the pending - * works list. - */ -static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) -{ - spin_lock(&ubi->wl_lock); - list_add_tail(&wrk->list, &ubi->works); - ubi_assert(ubi->works_count >= 0); - ubi->works_count += 1; - if (ubi->thread_enabled) - wake_up_process(ubi->bgt_thread); - spin_unlock(&ubi->wl_lock); -} - -static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel); - -/** - * schedule_erase - schedule an erase work. - * @ubi: UBI device description object - * @e: the WL entry of the physical eraseblock to erase - * @torture: if the physical eraseblock has to be tortured - * - * This function returns zero in case of success and a %-ENOMEM in case of - * failure. - */ -static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, - int torture) -{ - struct ubi_work *wl_wrk; - - dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", - e->pnum, e->ec, torture); - - wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL); - if (!wl_wrk) - return -ENOMEM; - - wl_wrk->func = &erase_worker; - wl_wrk->e = e; - wl_wrk->torture = torture; - - schedule_ubi_work(ubi, wl_wrk); - return 0; -} - -/** - * wear_leveling_worker - wear-leveling worker function. - * @ubi: UBI device description object - * @wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit - * - * This function copies a more worn out physical eraseblock to a less worn out - * one. Returns zero in case of success and a negative error code in case of - * failure. - */ -static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, - int cancel) -{ - int err, put = 0; - struct ubi_wl_entry *e1, *e2; - struct ubi_vid_hdr *vid_hdr; - - kfree(wrk); - - if (cancel) - return 0; - - vid_hdr = ubi_zalloc_vid_hdr(ubi); - if (!vid_hdr) - return -ENOMEM; - - spin_lock(&ubi->wl_lock); - - /* - * Only one WL worker at a time is supported at this implementation, so - * make sure a PEB is not being moved already. - */ - if (ubi->move_to || tree_empty(&ubi->free) || - (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) { - /* - * Only one WL worker at a time is supported at this - * implementation, so if a LEB is already being moved, cancel. - * - * No free physical eraseblocks? Well, we cancel wear-leveling - * then. It will be triggered again when a free physical - * eraseblock appears. - * - * No used physical eraseblocks? They must be temporarily - * protected from being moved. They will be moved to the - * @ubi->used tree later and the wear-leveling will be - * triggered again. - */ - dbg_wl("cancel WL, a list is empty: free %d, used %d", - tree_empty(&ubi->free), tree_empty(&ubi->used)); - ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - ubi_free_vid_hdr(ubi, vid_hdr); - return 0; - } - - if (tree_empty(&ubi->scrub)) { - /* - * Now pick the least worn-out used physical eraseblock and a - * highly worn-out free physical eraseblock. If the erase - * counters differ much enough, start wear-leveling. - */ - e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb); - e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - - if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { - dbg_wl("no WL needed: min used EC %d, max free EC %d", - e1->ec, e2->ec); - ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - ubi_free_vid_hdr(ubi, vid_hdr); - return 0; - } - used_tree_del(ubi, e1); - dbg_wl("move PEB %d EC %d to PEB %d EC %d", - e1->pnum, e1->ec, e2->pnum, e2->ec); - } else { - e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); - e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - scrub_tree_del(ubi, e1); - dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); - } - - free_tree_del(ubi, e2); - ubi_assert(!ubi->move_from && !ubi->move_to); - ubi_assert(!ubi->move_to_put && !ubi->move_from_put); - ubi->move_from = e1; - ubi->move_to = e2; - spin_unlock(&ubi->wl_lock); - - /* - * Now we are going to copy physical eraseblock @e1->pnum to @e2->pnum. - * We so far do not know which logical eraseblock our physical - * eraseblock (@e1) belongs to. We have to read the volume identifier - * header first. - */ - - err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); - if (err && err != UBI_IO_BITFLIPS) { - if (err == UBI_IO_PEB_FREE) { - /* - * We are trying to move PEB without a VID header. UBI - * always write VID headers shortly after the PEB was - * given, so we have a situation when it did not have - * chance to write it down because it was preempted. - * Just re-schedule the work, so that next time it will - * likely have the VID header in place. - */ - dbg_wl("PEB %d has no VID header", e1->pnum); - err = 0; - } else { - ubi_err("error %d while reading VID header from PEB %d", - err, e1->pnum); - if (err > 0) - err = -EIO; - } - goto error; - } - - err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); - if (err) { - if (err == UBI_IO_BITFLIPS) - err = 0; - goto error; - } - - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); - if (!ubi->move_to_put) - used_tree_add(ubi, e2); - else - put = 1; - ubi->move_from = ubi->move_to = NULL; - ubi->move_from_put = ubi->move_to_put = 0; - ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - - if (put) { - /* - * Well, the target PEB was put meanwhile, schedule it for - * erasure. - */ - dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); - err = schedule_erase(ubi, e2, 0); - if (err) { - kmem_cache_free(wl_entries_slab, e2); - ubi_ro_mode(ubi); - } - } - - err = schedule_erase(ubi, e1, 0); - if (err) { - kmem_cache_free(wl_entries_slab, e1); - ubi_ro_mode(ubi); - } - - dbg_wl("done"); - return err; - - /* - * Some error occurred. @e1 was not changed, so return it back. @e2 - * might be changed, schedule it for erasure. - */ -error: - if (err) - dbg_wl("error %d occurred, cancel operation", err); - ubi_assert(err <= 0); - - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); - ubi->wl_scheduled = 0; - if (ubi->move_from_put) - put = 1; - else - used_tree_add(ubi, e1); - ubi->move_from = ubi->move_to = NULL; - ubi->move_from_put = ubi->move_to_put = 0; - spin_unlock(&ubi->wl_lock); - - if (put) { - /* - * Well, the target PEB was put meanwhile, schedule it for - * erasure. - */ - dbg_wl("PEB %d was put meanwhile, erase", e1->pnum); - err = schedule_erase(ubi, e1, 0); - if (err) { - kmem_cache_free(wl_entries_slab, e1); - ubi_ro_mode(ubi); - } - } - - err = schedule_erase(ubi, e2, 0); - if (err) { - kmem_cache_free(wl_entries_slab, e2); - ubi_ro_mode(ubi); - } - - yield(); - return err; -} - -/** - * ensure_wear_leveling - schedule wear-leveling if it is needed. - * @ubi: UBI device description object - * - * This function checks if it is time to start wear-leveling and schedules it - * if yes. This function returns zero in case of success and a negative error - * code in case of failure. - */ -static int ensure_wear_leveling(struct ubi_device *ubi) -{ - int err = 0; - struct ubi_wl_entry *e1; - struct ubi_wl_entry *e2; - struct ubi_work *wrk; - - spin_lock(&ubi->wl_lock); - if (ubi->wl_scheduled) - /* Wear-leveling is already in the work queue */ - goto out_unlock; - - /* - * If the ubi->scrub tree is not empty, scrubbing is needed, and the - * the WL worker has to be scheduled anyway. - */ - if (tree_empty(&ubi->scrub)) { - if (tree_empty(&ubi->used) || tree_empty(&ubi->free)) - /* No physical eraseblocks - no deal */ - goto out_unlock; - - /* - * We schedule wear-leveling only if the difference between the - * lowest erase counter of used physical eraseblocks and a high - * erase counter of free physical eraseblocks is greater then - * %UBI_WL_THRESHOLD. - */ - e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb); - e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - - if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) - goto out_unlock; - dbg_wl("schedule wear-leveling"); - } else - dbg_wl("schedule scrubbing"); - - ubi->wl_scheduled = 1; - spin_unlock(&ubi->wl_lock); - - wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL); - if (!wrk) { - err = -ENOMEM; - goto out_cancel; - } - - wrk->func = &wear_leveling_worker; - schedule_ubi_work(ubi, wrk); - return err; - -out_cancel: - spin_lock(&ubi->wl_lock); - ubi->wl_scheduled = 0; -out_unlock: - spin_unlock(&ubi->wl_lock); - return err; -} - -/** - * erase_worker - physical eraseblock erase worker function. - * @ubi: UBI device description object - * @wl_wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit - * - * This function erases a physical eraseblock and perform torture testing if - * needed. It also takes care about marking the physical eraseblock bad if - * needed. Returns zero in case of success and a negative error code in case of - * failure. - */ -static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel) -{ - int err; - struct ubi_wl_entry *e = wl_wrk->e; - int pnum = e->pnum; - - if (cancel) { - dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); - kfree(wl_wrk); - kmem_cache_free(wl_entries_slab, e); - return 0; - } - - dbg_wl("erase PEB %d EC %d", pnum, e->ec); - - err = sync_erase(ubi, e, wl_wrk->torture); - if (!err) { - /* Fine, we've erased it successfully */ - kfree(wl_wrk); - - spin_lock(&ubi->wl_lock); - ubi->abs_ec += 1; - free_tree_add(ubi, e); - spin_unlock(&ubi->wl_lock); - - /* - * One more erase operation has happened, take care about protected - * physical eraseblocks. - */ - check_protection_over(ubi); - - /* And take care about wear-leveling */ - err = ensure_wear_leveling(ubi); - return err; - } - - kfree(wl_wrk); - kmem_cache_free(wl_entries_slab, e); - - if (err != -EIO) { - /* - * If this is not %-EIO, we have no idea what to do. Scheduling - * this physical eraseblock for erasure again would cause - * errors again and again. Well, lets switch to RO mode. - */ - ubi_ro_mode(ubi); - return err; - } - - /* It is %-EIO, the PEB went bad */ - - if (!ubi->bad_allowed) { - ubi_err("bad physical eraseblock %d detected", pnum); - ubi_ro_mode(ubi); - err = -EIO; - } else { - int need; - - spin_lock(&ubi->volumes_lock); - need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; - if (need > 0) { - need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; - ubi->avail_pebs -= need; - ubi->rsvd_pebs += need; - ubi->beb_rsvd_pebs += need; - if (need > 0) - ubi_msg("reserve more %d PEBs", need); - } - - if (ubi->beb_rsvd_pebs == 0) { - spin_unlock(&ubi->volumes_lock); - ubi_err("no reserved physical eraseblocks"); - ubi_ro_mode(ubi); - return -EIO; - } - - spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); - - err = ubi_io_mark_bad(ubi, pnum); - if (err) { - ubi_ro_mode(ubi); - return err; - } - - spin_lock(&ubi->volumes_lock); - ubi->beb_rsvd_pebs -= 1; - ubi->bad_peb_count += 1; - ubi->good_peb_count -= 1; - ubi_calculate_reserved(ubi); - if (ubi->beb_rsvd_pebs == 0) - ubi_warn("last PEB from the reserved pool was used"); - spin_unlock(&ubi->volumes_lock); - } - - return err; -} - -/** - * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling - * unit. - * @ubi: UBI device description object - * @pnum: physical eraseblock to return - * @torture: if this physical eraseblock has to be tortured - * - * This function is called to return physical eraseblock @pnum to the pool of - * free physical eraseblocks. The @torture flag has to be set if an I/O error - * occurred to this @pnum and it has to be tested. This function returns zero - * in case of success and a negative error code in case of failure. - */ -int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) -{ - int err; - struct ubi_wl_entry *e; - - dbg_wl("PEB %d", pnum); - ubi_assert(pnum >= 0); - ubi_assert(pnum < ubi->peb_count); - - spin_lock(&ubi->wl_lock); - - e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from) { - /* - * User is putting the physical eraseblock which was selected to - * be moved. It will be scheduled for erasure in the - * wear-leveling worker. - */ - dbg_wl("PEB %d is being moved", pnum); - ubi_assert(!ubi->move_from_put); - ubi->move_from_put = 1; - spin_unlock(&ubi->wl_lock); - return 0; - } else if (e == ubi->move_to) { - /* - * User is putting the physical eraseblock which was selected - * as the target the data is moved to. It may happen if the EBA - * unit already re-mapped the LEB but the WL unit did has not - * put the PEB to the "used" tree. - */ - dbg_wl("PEB %d is the target of data moving", pnum); - ubi_assert(!ubi->move_to_put); - ubi->move_to_put = 1; - spin_unlock(&ubi->wl_lock); - return 0; - } else { - if (in_wl_tree(e, &ubi->used)) - used_tree_del(ubi, e); - else if (in_wl_tree(e, &ubi->scrub)) - scrub_tree_del(ubi, e); - else - prot_tree_del(ubi, e->pnum); - } - spin_unlock(&ubi->wl_lock); - - err = schedule_erase(ubi, e, torture); - if (err) { - spin_lock(&ubi->wl_lock); - used_tree_add(ubi, e); - spin_unlock(&ubi->wl_lock); - } - - return err; -} - -/** - * ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing. - * @ubi: UBI device description object - * @pnum: the physical eraseblock to schedule - * - * If a bit-flip in a physical eraseblock is detected, this physical eraseblock - * needs scrubbing. This function schedules a physical eraseblock for - * scrubbing which is done in background. This function returns zero in case of - * success and a negative error code in case of failure. - */ -int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) -{ - struct ubi_wl_entry *e; - - ubi_msg("schedule PEB %d for scrubbing", pnum); - -retry: - spin_lock(&ubi->wl_lock); - e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub)) { - spin_unlock(&ubi->wl_lock); - return 0; - } - - if (e == ubi->move_to) { - /* - * This physical eraseblock was used to move data to. The data - * was moved but the PEB was not yet inserted to the proper - * tree. We should just wait a little and let the WL worker - * proceed. - */ - spin_unlock(&ubi->wl_lock); - dbg_wl("the PEB %d is not in proper tree, retry", pnum); - yield(); - goto retry; - } - - if (in_wl_tree(e, &ubi->used)) - used_tree_del(ubi, e); - else - prot_tree_del(ubi, pnum); - - scrub_tree_add(ubi, e); - spin_unlock(&ubi->wl_lock); - - /* - * Technically scrubbing is the same as wear-leveling, so it is done - * by the WL worker. - */ - return ensure_wear_leveling(ubi); -} - -/** - * ubi_wl_flush - flush all pending works. - * @ubi: UBI device description object - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ -int ubi_wl_flush(struct ubi_device *ubi) -{ - int err, pending_count; - - pending_count = ubi->works_count; - - dbg_wl("flush (%d pending works)", pending_count); - - /* - * Erase while the pending works queue is not empty, but not more then - * the number of currently pending works. - */ - while (pending_count-- > 0) { - err = do_work(ubi); - if (err) - return err; - } - - return 0; -} - -/** - * tree_destroy - destroy an RB-tree. - * @root: the root of the tree to destroy - */ -static void tree_destroy(struct rb_root *root) -{ - struct rb_node *rb; - struct ubi_wl_entry *e; - - rb = root->rb_node; - while (rb) { - if (rb->rb_left) - rb = rb->rb_left; - else if (rb->rb_right) - rb = rb->rb_right; - else { - e = rb_entry(rb, struct ubi_wl_entry, rb); - - rb = rb_parent(rb); - if (rb) { - if (rb->rb_left == &e->rb) - rb->rb_left = NULL; - else - rb->rb_right = NULL; - } - - kmem_cache_free(wl_entries_slab, e); - } - } -} - -/** - * ubi_thread - UBI background thread. - * @u: the UBI device description object pointer - */ -static int ubi_thread(void *u) -{ - int failures = 0; - struct ubi_device *ubi = u; - - ubi_msg("background thread \"%s\" started, PID %d", - ubi->bgt_name, current->pid); - - for (;;) { - int err; - - if (kthread_should_stop()) - goto out; - - if (try_to_freeze()) - continue; - - spin_lock(&ubi->wl_lock); - if (list_empty(&ubi->works) || ubi->ro_mode || - !ubi->thread_enabled) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock(&ubi->wl_lock); - schedule(); - continue; - } - spin_unlock(&ubi->wl_lock); - - err = do_work(ubi); - if (err) { - ubi_err("%s: work failed with error code %d", - ubi->bgt_name, err); - if (failures++ > WL_MAX_FAILURES) { - /* - * Too many failures, disable the thread and - * switch to read-only mode. - */ - ubi_msg("%s: %d consecutive failures", - ubi->bgt_name, WL_MAX_FAILURES); - ubi_ro_mode(ubi); - break; - } - } else - failures = 0; - - cond_resched(); - } - -out: - dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); - return 0; -} - -/** - * cancel_pending - cancel all pending works. - * @ubi: UBI device description object - */ -static void cancel_pending(struct ubi_device *ubi) -{ - while (!list_empty(&ubi->works)) { - struct ubi_work *wrk; - - wrk = list_entry(ubi->works.next, struct ubi_work, list); - list_del(&wrk->list); - wrk->func(ubi, wrk, 1); - ubi->works_count -= 1; - ubi_assert(ubi->works_count >= 0); - } -} - -/** - * ubi_wl_init_scan - initialize the wear-leveling unit using scanning - * information. - * @ubi: UBI device description object - * @si: scanning information - * - * This function returns zero in case of success, and a negative error code in - * case of failure. - */ -int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) -{ - int err; - struct rb_node *rb1, *rb2; - struct ubi_scan_volume *sv; - struct ubi_scan_leb *seb, *tmp; - struct ubi_wl_entry *e; - - - ubi->used = ubi->free = ubi->scrub = RB_ROOT; - ubi->prot.pnum = ubi->prot.aec = RB_ROOT; - spin_lock_init(&ubi->wl_lock); - ubi->max_ec = si->max_ec; - INIT_LIST_HEAD(&ubi->works); - - sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); - - ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); - if (IS_ERR(ubi->bgt_thread)) { - err = PTR_ERR(ubi->bgt_thread); - ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, - err); - return err; - } - - if (ubi_devices_cnt == 0) { - wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab", - sizeof(struct ubi_wl_entry), - 0, 0, NULL, NULL); - if (!wl_entries_slab) - return -ENOMEM; - } - - err = -ENOMEM; - ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); - if (!ubi->lookuptbl) - goto out_free; - - list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { - cond_resched(); - - e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); - if (!e) - goto out_free; - - e->pnum = seb->pnum; - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { - kmem_cache_free(wl_entries_slab, e); - goto out_free; - } - } - - list_for_each_entry(seb, &si->free, u.list) { - cond_resched(); - - e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); - if (!e) - goto out_free; - - e->pnum = seb->pnum; - e->ec = seb->ec; - ubi_assert(e->ec >= 0); - free_tree_add(ubi, e); - ubi->lookuptbl[e->pnum] = e; - } - - list_for_each_entry(seb, &si->corr, u.list) { - cond_resched(); - - e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); - if (!e) - goto out_free; - - e->pnum = seb->pnum; - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { - kmem_cache_free(wl_entries_slab, e); - goto out_free; - } - } - - ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { - cond_resched(); - - e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); - if (!e) - goto out_free; - - e->pnum = seb->pnum; - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (!seb->scrub) { - dbg_wl("add PEB %d EC %d to the used tree", - e->pnum, e->ec); - used_tree_add(ubi, e); - } else { - dbg_wl("add PEB %d EC %d to the scrub tree", - e->pnum, e->ec); - scrub_tree_add(ubi, e); - } - } - } - - if (WL_RESERVED_PEBS > ubi->avail_pebs) { - ubi_err("no enough physical eraseblocks (%d, need %d)", - ubi->avail_pebs, WL_RESERVED_PEBS); - goto out_free; - } - ubi->avail_pebs -= WL_RESERVED_PEBS; - ubi->rsvd_pebs += WL_RESERVED_PEBS; - - /* Schedule wear-leveling if needed */ - err = ensure_wear_leveling(ubi); - if (err) - goto out_free; - - return 0; - -out_free: - cancel_pending(ubi); - tree_destroy(&ubi->used); - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); - if (ubi_devices_cnt == 0) - kmem_cache_destroy(wl_entries_slab); - return err; -} - -/** - * protection_trees_destroy - destroy the protection RB-trees. - * @ubi: UBI device description object - */ -static void protection_trees_destroy(struct ubi_device *ubi) -{ - struct rb_node *rb; - struct ubi_wl_prot_entry *pe; - - rb = ubi->prot.aec.rb_node; - while (rb) { - if (rb->rb_left) - rb = rb->rb_left; - else if (rb->rb_right) - rb = rb->rb_right; - else { - pe = rb_entry(rb, struct ubi_wl_prot_entry, rb_aec); - - rb = rb_parent(rb); - if (rb) { - if (rb->rb_left == &pe->rb_aec) - rb->rb_left = NULL; - else - rb->rb_right = NULL; - } - - kmem_cache_free(wl_entries_slab, pe->e); - kfree(pe); - } - } -} - -/** - * ubi_wl_close - close the wear-leveling unit. - * @ubi: UBI device description object - */ -void ubi_wl_close(struct ubi_device *ubi) -{ - dbg_wl("disable \"%s\"", ubi->bgt_name); - if (ubi->bgt_thread) - kthread_stop(ubi->bgt_thread); - - dbg_wl("close the UBI wear-leveling unit"); - - cancel_pending(ubi); - protection_trees_destroy(ubi); - tree_destroy(&ubi->used); - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); - if (ubi_devices_cnt == 1) - kmem_cache_destroy(wl_entries_slab); -} - -#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID - -/** - * paranoid_check_ec - make sure that the erase counter of a physical eraseblock - * is correct. - * @ubi: UBI device description object - * @pnum: the physical eraseblock number to check - * @ec: the erase counter to check - * - * This function returns zero if the erase counter of physical eraseblock @pnum - * is equivalent to @ec, %1 if not, and a negative error code if an error - * occurred. - */ -static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec) -{ - int err; - long long read_ec; - struct ubi_ec_hdr *ec_hdr; - - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - - err = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0); - if (err && err != UBI_IO_BITFLIPS) { - /* The header does not have to exist */ - err = 0; - goto out_free; - } - - read_ec = ubi64_to_cpu(ec_hdr->ec); - if (ec != read_ec) { - ubi_err("paranoid check failed for PEB %d", pnum); - ubi_err("read EC is %lld, should be %d", read_ec, ec); - ubi_dbg_dump_stack(); - err = 1; - } else - err = 0; - -out_free: - kfree(ec_hdr); - return err; -} - -/** - * paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present - * in a WL RB-tree. - * @e: the wear-leveling entry to check - * @root: the root of the tree - * - * This function returns zero if @e is in the @root RB-tree and %1 if it - * is not. - */ -static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, - struct rb_root *root) -{ - if (in_wl_tree(e, root)) - return 0; - - ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ", - e->pnum, e->ec, root); - ubi_dbg_dump_stack(); - return 1; -} - -#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/trunk/drivers/net/3c501.c b/trunk/drivers/net/3c501.c index 4bee99ba7dbb..06e33786078d 100644 --- a/trunk/drivers/net/3c501.c +++ b/trunk/drivers/net/3c501.c @@ -735,6 +735,7 @@ static void el_receive(struct net_device *dev) else { skb_reserve(skb,2); /* Force 16 byte alignment */ + skb->dev = dev; /* * The read increments through the bytes. The interrupt * handler will fix the pointer when it returns to diff --git a/trunk/drivers/net/3c505.c b/trunk/drivers/net/3c505.c index e985a85a5623..702bfb2a5e99 100644 --- a/trunk/drivers/net/3c505.c +++ b/trunk/drivers/net/3c505.c @@ -615,6 +615,7 @@ static void receive_packet(struct net_device *dev, int len) if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction); + skb->dev = dev; adapter->current_dma.direction = 0; adapter->current_dma.length = rlen; adapter->current_dma.skb = skb; @@ -1025,7 +1026,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) adapter->current_dma.start_time = jiffies; if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) { - skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen); + memcpy(adapter->dma_buffer, skb->data, nlen); memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len); target = isa_virt_to_bus(adapter->dma_buffer); } diff --git a/trunk/drivers/net/3c507.c b/trunk/drivers/net/3c507.c index eed4299dc426..54e1d5aebed3 100644 --- a/trunk/drivers/net/3c507.c +++ b/trunk/drivers/net/3c507.c @@ -873,6 +873,7 @@ static void el16_rx(struct net_device *dev) } skb_reserve(skb,2); + skb->dev = dev; /* 'skb->data' points to the start of sk_buff data area. */ memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len); diff --git a/trunk/drivers/net/3c509.c b/trunk/drivers/net/3c509.c index 9588da3a30e7..f791bf026e51 100644 --- a/trunk/drivers/net/3c509.c +++ b/trunk/drivers/net/3c509.c @@ -83,6 +83,7 @@ static int max_interrupt_work = 10; #include #include #include +#include #include #include /* for udelay() */ #include @@ -1090,6 +1091,7 @@ el3_rx(struct net_device *dev) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte */ /* 'skb->data' points to the start of sk_buff data area. */ diff --git a/trunk/drivers/net/3c515.c b/trunk/drivers/net/3c515.c index 290166d5e7d1..c307ce66145c 100644 --- a/trunk/drivers/net/3c515.c +++ b/trunk/drivers/net/3c515.c @@ -1292,6 +1292,7 @@ static int corkscrew_rx(struct net_device *dev) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ insl(ioaddr + RX_FIFO, @@ -1362,6 +1363,7 @@ static int boomerang_rx(struct net_device *dev) copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 4)) != 0) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), diff --git a/trunk/drivers/net/3c523.c b/trunk/drivers/net/3c523.c index da1a22c13865..17d61eb0a7e5 100644 --- a/trunk/drivers/net/3c523.c +++ b/trunk/drivers/net/3c523.c @@ -988,6 +988,7 @@ static void elmc_rcv_int(struct net_device *dev) rbd->status = 0; skb = (struct sk_buff *) dev_alloc_skb(totlen + 2); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte alignment */ skb_put(skb,totlen); eth_copy_and_sum(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen,0); @@ -1145,7 +1146,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) if (len != skb->len) memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len); + memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); #if (NUM_XMIT_BUFFS == 1) #ifdef NO_NOPCOMMANDS diff --git a/trunk/drivers/net/3c527.c b/trunk/drivers/net/3c527.c index c7b571be20e0..6c7437e60bd2 100644 --- a/trunk/drivers/net/3c527.c +++ b/trunk/drivers/net/3c527.c @@ -1189,6 +1189,7 @@ static void mc32_rx_ring(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; dev->last_rx = jiffies; lp->net_stats.rx_packets++; lp->net_stats.rx_bytes += length; diff --git a/trunk/drivers/net/3c59x.c b/trunk/drivers/net/3c59x.c index 80924f76dee8..b406ecfa7268 100644 --- a/trunk/drivers/net/3c59x.c +++ b/trunk/drivers/net/3c59x.c @@ -2414,6 +2414,7 @@ static int vortex_rx(struct net_device *dev) printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master && @@ -2490,6 +2491,7 @@ boomerang_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ diff --git a/trunk/drivers/net/7990.c b/trunk/drivers/net/7990.c index 0877fc372f4b..1b3d11ed6cff 100644 --- a/trunk/drivers/net/7990.c +++ b/trunk/drivers/net/7990.c @@ -331,6 +331,7 @@ static int lance_rx (struct net_device *dev) return 0; } + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put (skb, len); /* make room */ eth_copy_and_sum(skb, @@ -565,9 +566,9 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - if (skb->len < ETH_ZLEN) - memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen); + if (skb->len < ETH_ZLEN) + memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); + memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); diff --git a/trunk/drivers/net/8139cp.c b/trunk/drivers/net/8139cp.c index e8c9f27817b0..12c8453f44bc 100644 --- a/trunk/drivers/net/8139cp.c +++ b/trunk/drivers/net/8139cp.c @@ -573,6 +573,7 @@ static int cp_rx_poll (struct net_device *dev, int *budget) } skb_reserve(new_skb, RX_OFFSET); + new_skb->dev = dev; pci_unmap_single(cp->pdev, mapping, buflen, PCI_DMA_FROMDEVICE); @@ -806,7 +807,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) if (mss) flags |= LargeSend | ((mss & MSSMask) << MSSShift); else if (skb->ip_summed == CHECKSUM_PARTIAL) { - const struct iphdr *ip = ip_hdr(skb); + const struct iphdr *ip = skb->nh.iph; if (ip->protocol == IPPROTO_TCP) flags |= IPCS | TCPCS; else if (ip->protocol == IPPROTO_UDP) @@ -825,7 +826,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) u32 first_len, first_eor; dma_addr_t first_mapping; int frag, first_entry = entry; - const struct iphdr *ip = ip_hdr(skb); + const struct iphdr *ip = skb->nh.iph; /* We must give this initial chunk to the device last. * Otherwise we could race with the device. @@ -1081,6 +1082,7 @@ static int cp_refill_rx (struct cp_private *cp) if (!skb) goto err_out; + skb->dev = cp->dev; skb_reserve(skb, RX_OFFSET); mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz, diff --git a/trunk/drivers/net/8139too.c b/trunk/drivers/net/8139too.c index a844b1fe2dc4..99304b2aa86e 100644 --- a/trunk/drivers/net/8139too.c +++ b/trunk/drivers/net/8139too.c @@ -1904,10 +1904,10 @@ static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring, u32 left = RX_BUF_LEN - offset; if (size > left) { - skb_copy_to_linear_data(skb, ring + offset, left); - skb_copy_to_linear_data_offset(skb, left, ring, size - left); + memcpy(skb->data, ring + offset, left); + memcpy(skb->data+left, ring, size - left); } else - skb_copy_to_linear_data(skb, ring + offset, size); + memcpy(skb->data, ring + offset, size); } #endif @@ -2013,6 +2013,7 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, skb = dev_alloc_skb (pkt_size + 2); if (likely(skb)) { + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ #if RX_BUF_IDX == 3 wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); diff --git a/trunk/drivers/net/82596.c b/trunk/drivers/net/82596.c index 3ff1155459a3..640d7ca2ebcf 100644 --- a/trunk/drivers/net/82596.c +++ b/trunk/drivers/net/82596.c @@ -830,6 +830,7 @@ static inline int i596_rx(struct net_device *dev) lp->stats.rx_dropped++; } else { + skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ skb_reserve(skb, 2); diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 69dba62e0bad..a3d46ea37126 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -311,7 +311,7 @@ config MAC8390 config MAC89x0 tristate "Macintosh CS89x0 based ethernet cards" - depends on NET_ETHERNET && MAC + depends on NET_ETHERNET && MAC && BROKEN ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a Nubus or LC-PDS network (Ethernet) card of this type, say Y and @@ -337,8 +337,8 @@ config MACSONIC be called macsonic. config MACMACE - bool "Macintosh (AV) onboard MACE ethernet" - depends on NET_ETHERNET && MAC + bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)" + depends on NET_ETHERNET && MAC && EXPERIMENTAL select CRC32 help Support for the onboard AMD 79C940 MACE Ethernet controller used in @@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM enables offloading for checksums on transmit. If unsure, say Y. config MIPS_SIM_NET - tristate "MIPS simulator Network device" - depends on NET_ETHERNET && MIPS_SIM + tristate "MIPS simulator Network device (EXPERIMENTAL)" + depends on MIPS_SIM && EXPERIMENTAL help The MIPSNET device is a simple Ethernet network device which is emulated by the MIPS Simulator. @@ -1444,8 +1444,7 @@ config CS89x0 config TC35815 tristate "TOSHIBA TC35815 Ethernet support" - depends on NET_PCI && PCI && MIPS - select MII + depends on NET_PCI && PCI && TOSHIBA_JMR3927 config DGRS tristate "Digi Intl. RightSwitch SE-X support" @@ -2274,12 +2273,11 @@ config GFAR_NAPI depends on GIANFAR config UCC_GETH - tristate "Freescale QE Gigabit Ethernet" - depends on QUICC_ENGINE - select UCC_FAST + tristate "Freescale QE UCC GETH" + depends on QUICC_ENGINE && UCC_FAST help - This driver supports the Gigabit Ethernet mode of the QUICC Engine, - which is available on some Freescale SOCs. + This driver supports the Gigabit Ethernet mode of QE UCC. + QE can be found on MPC836x CPUs. config UGETH_NAPI bool "NAPI Support" @@ -2293,10 +2291,14 @@ config UGETH_FILTERING bool "Mac address filtering support" depends on UCC_GETH -config UGETH_TX_ON_DEMAND - bool "Transmit on Demand support" +config UGETH_TX_ON_DEMOND + bool "Transmit on Demond support" depends on UCC_GETH +config UGETH_HAS_GIGA + bool + depends on UCC_GETH && PPC_MPC836x + config MV643XX_ETH tristate "MV-643XX Ethernet support" depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) @@ -2927,6 +2929,11 @@ endif #NETDEVICES config NETPOLL def_bool NETCONSOLE +config NETPOLL_RX + bool "Netpoll support for trapping incoming packets" + default n + depends on NETPOLL + config NETPOLL_TRAP bool "Netpoll traffic trapping" default n diff --git a/trunk/drivers/net/Makefile b/trunk/drivers/net/Makefile index 59c0459a037c..33af833667da 100644 --- a/trunk/drivers/net/Makefile +++ b/trunk/drivers/net/Makefile @@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \ gianfar_sysfs.o obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o -ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o +ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o # # link order important here @@ -206,7 +206,7 @@ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ obj-$(CONFIG_NET_PCMCIA) += pcmcia/ -obj-y += wireless/ +obj-$(CONFIG_NET_RADIO) += wireless/ obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ diff --git a/trunk/drivers/net/Space.c b/trunk/drivers/net/Space.c index 1c3e293fbaf7..dd8ed456c8b2 100644 --- a/trunk/drivers/net/Space.c +++ b/trunk/drivers/net/Space.c @@ -83,6 +83,7 @@ extern struct net_device *bagetlance_probe(int unit); extern struct net_device *mvme147lance_probe(int unit); extern struct net_device *tc515_probe(int unit); extern struct net_device *lance_probe(int unit); +extern struct net_device *mace_probe(int unit); extern struct net_device *mac8390_probe(int unit); extern struct net_device *mac89x0_probe(int unit); extern struct net_device *mc32_probe(int unit); @@ -273,6 +274,9 @@ static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ {mvme147lance_probe, 0}, #endif +#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ + {mace_probe, 0}, +#endif #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ {mac8390_probe, 0}, #endif diff --git a/trunk/drivers/net/a2065.c b/trunk/drivers/net/a2065.c index 81d5a374042a..d76548e75350 100644 --- a/trunk/drivers/net/a2065.c +++ b/trunk/drivers/net/a2065.c @@ -320,6 +320,7 @@ static int lance_rx (struct net_device *dev) return 0; } + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put (skb, len); /* make room */ eth_copy_and_sum(skb, @@ -562,6 +563,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; int status = 0; + static int outs; unsigned long flags; skblen = skb->len; @@ -597,16 +599,17 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - skb_copy_from_linear_data(skb, (void *)&ib->tx_buf [entry][0], skblen); + memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); /* Clear the slack of the packet, do I need this? */ if (len != skblen) - memset ((void *) &ib->tx_buf [entry][skblen], 0, len - skblen); + memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; - lp->stats.tx_bytes += skblen; + + outs++; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); diff --git a/trunk/drivers/net/acenic.c b/trunk/drivers/net/acenic.c index 7122b7ba8d61..7138e0e025bc 100644 --- a/trunk/drivers/net/acenic.c +++ b/trunk/drivers/net/acenic.c @@ -2027,6 +2027,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) */ csum = retdesc->tcp_udp_csum; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* diff --git a/trunk/drivers/net/amd8111e.c b/trunk/drivers/net/amd8111e.c index 675fe918421b..962c954c2d56 100644 --- a/trunk/drivers/net/amd8111e.c +++ b/trunk/drivers/net/amd8111e.c @@ -798,7 +798,9 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index], lp->rx_buff_len-2, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); + skb->dev = dev; lp->rx_skbuff[rx_index] = new_skb; + new_skb->dev = dev; lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev, new_skb->data, lp->rx_buff_len-2, @@ -924,7 +926,9 @@ static int amd8111e_rx(struct net_device *dev) pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index], lp->rx_buff_len-2, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); + skb->dev = dev; lp->rx_skbuff[rx_index] = new_skb; + new_skb->dev = dev; lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev, new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE); diff --git a/trunk/drivers/net/appletalk/cops.c b/trunk/drivers/net/appletalk/cops.c index da6ffa8cd81e..dba5e5165452 100644 --- a/trunk/drivers/net/appletalk/cops.c +++ b/trunk/drivers/net/appletalk/cops.c @@ -853,9 +853,9 @@ static void cops_rx(struct net_device *dev) return; } - skb_reset_mac_header(skb); /* Point to entire packet. */ + skb->mac.raw = skb->data; /* Point to entire packet. */ skb_pull(skb,3); - skb_reset_transport_header(skb); /* Point to data (Skip header). */ + skb->h.raw = skb->data; /* Point to data (Skip header). */ /* Update the counters. */ lp->stats.rx_packets++; diff --git a/trunk/drivers/net/appletalk/ltpc.c b/trunk/drivers/net/appletalk/ltpc.c index 6a6cbd331a16..2ea44ce49810 100644 --- a/trunk/drivers/net/appletalk/ltpc.c +++ b/trunk/drivers/net/appletalk/ltpc.c @@ -770,13 +770,13 @@ static int sendup_buffer (struct net_device *dev) skb->data[0] = dnode; skb->data[1] = snode; skb->data[2] = llaptype; - skb_reset_mac_header(skb); /* save pointer to llap header */ + skb->mac.raw = skb->data; /* save pointer to llap header */ skb_pull(skb,3); /* copy ddp(s,e)hdr + contents */ - skb_copy_to_linear_data(skb, ltdmabuf, len); + memcpy(skb->data,(void*)ltdmabuf,len); - skb_reset_transport_header(skb); + skb->h.raw = skb->data; stats->rx_packets++; stats->rx_bytes+=skb->len; @@ -917,14 +917,13 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) int i; struct lt_sendlap cbuf; - unsigned char *hdr; cbuf.command = LT_SENDLAP; cbuf.dnode = skb->data[0]; cbuf.laptype = skb->data[2]; skb_pull(skb,3); /* skip past LLAP header */ cbuf.length = skb->len; /* this is host order */ - skb_reset_transport_header(skb); + skb->h.raw=skb->data; if(debug & DEBUG_UPPER) { printk("command "); @@ -933,13 +932,11 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) printk("\n"); } - hdr = skb_transport_header(skb); - do_write(dev, &cbuf, sizeof(cbuf), hdr, skb->len); + do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len); if(debug & DEBUG_UPPER) { printk("sent %d ddp bytes\n",skb->len); - for (i = 0; i < skb->len; i++) - printk("%02x ", hdr[i]); + for(i=0;ilen;i++) printk("%02x ",skb->h.raw[i]); printk("\n"); } diff --git a/trunk/drivers/net/arcnet/arc-rawmode.c b/trunk/drivers/net/arcnet/arc-rawmode.c index e0a18e7c73cb..6318814a11a8 100644 --- a/trunk/drivers/net/arcnet/arc-rawmode.c +++ b/trunk/drivers/net/arcnet/arc-rawmode.c @@ -110,7 +110,7 @@ static void rx(struct net_device *dev, int bufnum, pkt = (struct archdr *) skb->data; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, ARC_HDR_SIZE); /* up to sizeof(pkt->soft) has already been copied from the card */ diff --git a/trunk/drivers/net/arcnet/arcnet.c b/trunk/drivers/net/arcnet/arcnet.c index 681e20b8466f..83004fdab0a4 100644 --- a/trunk/drivers/net/arcnet/arcnet.c +++ b/trunk/drivers/net/arcnet/arcnet.c @@ -519,12 +519,9 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, * real header when we do rebuild_header. */ *(uint16_t *) skb_push(skb, 2) = type; - /* - * XXX: Why not use skb->mac_len? - */ - if (skb->network_header - skb->mac_header != 2) + if (skb->nh.raw - skb->mac.raw != 2) BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n", - (int)(skb->network_header - skb->mac_header)); + (int)(skb->nh.raw - skb->mac.raw)); return -2; /* return error -- can't transmit yet! */ } else { @@ -557,13 +554,11 @@ static int arcnet_rebuild_header(struct sk_buff *skb) unsigned short type; uint8_t daddr=0; struct ArcProto *proto; - /* - * XXX: Why not use skb->mac_len? - */ - if (skb->network_header - skb->mac_header != 2) { + + if (skb->nh.raw - skb->mac.raw != 2) { BUGMSG(D_NORMAL, - "rebuild_header: shouldn't be here! (hdrsize=%d)\n", - (int)(skb->network_header - skb->mac_header)); + "rebuild_header: shouldn't be here! (hdrsize=%d)\n", + (int)(skb->nh.raw - skb->mac.raw)); return 0; } type = *(uint16_t *) skb_pull(skb, 2); diff --git a/trunk/drivers/net/arcnet/capmode.c b/trunk/drivers/net/arcnet/capmode.c index cc4610db6395..66485585ab39 100644 --- a/trunk/drivers/net/arcnet/capmode.c +++ b/trunk/drivers/net/arcnet/capmode.c @@ -122,8 +122,10 @@ static void rx(struct net_device *dev, int bufnum, } skb_put(skb, length + ARC_HDR_SIZE + sizeof(int)); skb->dev = dev; - skb_reset_mac_header(skb); - pkt = (struct archdr *)skb_mac_header(skb); + + pkt = (struct archdr *) skb->data; + + skb->mac.raw = skb->data; skb_pull(skb, ARC_HDR_SIZE); /* up to sizeof(pkt->soft) has already been copied from the card */ @@ -268,13 +270,13 @@ static int ack_tx(struct net_device *dev, int acked) skb_put(ackskb, length + ARC_HDR_SIZE ); ackskb->dev = dev; - skb_reset_mac_header(ackskb); - ackpkt = (struct archdr *)skb_mac_header(ackskb); + ackpkt = (struct archdr *) ackskb->data; + + ackskb->mac.raw = ackskb->data; /* skb_pull(ackskb, ARC_HDR_SIZE); */ - skb_copy_from_linear_data(lp->outgoing.skb, ackpkt, - ARC_HDR_SIZE + sizeof(struct arc_cap)); + memcpy(ackpkt, lp->outgoing.skb->data, ARC_HDR_SIZE+sizeof(struct arc_cap)); ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */ ackpkt->soft.cap.mes.ack=acked; diff --git a/trunk/drivers/net/arcnet/rfc1051.c b/trunk/drivers/net/arcnet/rfc1051.c index 2de8877ece29..6d6c69f036ef 100644 --- a/trunk/drivers/net/arcnet/rfc1051.c +++ b/trunk/drivers/net/arcnet/rfc1051.c @@ -94,7 +94,7 @@ static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; /* Pull off the arcnet header. */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, hdr_size); if (pkt->hard.dest == 0) diff --git a/trunk/drivers/net/arcnet/rfc1201.c b/trunk/drivers/net/arcnet/rfc1201.c index 460a095000c2..bee34226abfa 100644 --- a/trunk/drivers/net/arcnet/rfc1201.c +++ b/trunk/drivers/net/arcnet/rfc1201.c @@ -96,7 +96,7 @@ static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; /* Pull off the arcnet header. */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, hdr_size); if (pkt->hard.dest == 0) diff --git a/trunk/drivers/net/ariadne.c b/trunk/drivers/net/ariadne.c index a241ae7855a3..9dfc09b181c1 100644 --- a/trunk/drivers/net/ariadne.c +++ b/trunk/drivers/net/ariadne.c @@ -677,7 +677,6 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->cur_tx -= TX_RING_SIZE; priv->dirty_tx -= TX_RING_SIZE; } - priv->stats.tx_bytes += len; /* Trigger an immediate send poll. */ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ @@ -744,6 +743,7 @@ static int ariadne_rx(struct net_device *dev) } + skb->dev = dev; skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, (char *)priv->rx_buff[entry], pkt_len,0); diff --git a/trunk/drivers/net/arm/am79c961a.c b/trunk/drivers/net/arm/am79c961a.c index 8f0d7ce503c9..ddd12d44ff22 100644 --- a/trunk/drivers/net/arm/am79c961a.c +++ b/trunk/drivers/net/arm/am79c961a.c @@ -526,6 +526,7 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv) skb = dev_alloc_skb(len + 2); if (skb) { + skb->dev = dev; skb_reserve(skb, 2); am_readbuffer(dev, pktaddr, skb_put(skb, len), len); diff --git a/trunk/drivers/net/arm/at91_ether.c b/trunk/drivers/net/arm/at91_ether.c index 152fa7a042b8..1621b8fe35cf 100644 --- a/trunk/drivers/net/arm/at91_ether.c +++ b/trunk/drivers/net/arm/at91_ether.c @@ -858,6 +858,7 @@ static void at91ether_rx(struct net_device *dev) skb_reserve(skb, 2); memcpy(skb_put(skb, pktlen), p_recv, pktlen); + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; lp->stats.rx_bytes += pktlen; diff --git a/trunk/drivers/net/arm/ep93xx_eth.c b/trunk/drivers/net/arm/ep93xx_eth.c index 2438c5bff237..dd698b033a62 100644 --- a/trunk/drivers/net/arm/ep93xx_eth.c +++ b/trunk/drivers/net/arm/ep93xx_eth.c @@ -255,6 +255,7 @@ static int ep93xx_rx(struct net_device *dev, int *budget) skb = dev_alloc_skb(length + 2); if (likely(skb != NULL)) { + skb->dev = dev; skb_reserve(skb, 2); dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, length, DMA_FROM_DEVICE); diff --git a/trunk/drivers/net/arm/ether1.c b/trunk/drivers/net/arm/ether1.c index f075cebe84ad..a2921882eba8 100644 --- a/trunk/drivers/net/arm/ether1.c +++ b/trunk/drivers/net/arm/ether1.c @@ -875,6 +875,7 @@ ether1_recv_done (struct net_device *dev) skb = dev_alloc_skb (length + 2); if (skb) { + skb->dev = dev; skb_reserve (skb, 2); ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length); diff --git a/trunk/drivers/net/arm/ether3.c b/trunk/drivers/net/arm/ether3.c index 32da2eb9bcee..841178343a07 100644 --- a/trunk/drivers/net/arm/ether3.c +++ b/trunk/drivers/net/arm/ether3.c @@ -661,6 +661,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) { if (skb) { unsigned char *buf; + skb->dev = dev; skb_reserve(skb, 2); buf = skb_put(skb, length); ether3_readbuffer(dev, buf + 12, length - 12); diff --git a/trunk/drivers/net/at1700.c b/trunk/drivers/net/at1700.c index bed8e0ebaf19..56ae8babd919 100644 --- a/trunk/drivers/net/at1700.c +++ b/trunk/drivers/net/at1700.c @@ -768,6 +768,7 @@ net_rx(struct net_device *dev) lp->stats.rx_dropped++; break; } + skb->dev = dev; skb_reserve(skb,2); insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1); diff --git a/trunk/drivers/net/atari_bionet.c b/trunk/drivers/net/atari_bionet.c index 3d87bd2b4194..4e3bf6a1f22c 100644 --- a/trunk/drivers/net/atari_bionet.c +++ b/trunk/drivers/net/atari_bionet.c @@ -453,8 +453,7 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { stdma_lock(bionet_intr, NULL); local_irq_restore(flags); if( !STRAM_ADDR(buf+length-1) ) { - skb_copy_from_linear_data(skb, nic_packet->buffer, - length); + memcpy(nic_packet->buffer, skb->data, length); buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer; } @@ -545,13 +544,13 @@ bionet_poll_rx(struct net_device *dev) { break; } + skb->dev = dev; skb_reserve( skb, 2 ); /* 16 Byte align */ skb_put( skb, pkt_len ); /* make room */ /* 'skb->data' points to the start of sk_buff data area. */ - skb_copy_to_linear_data(skb, nic_packet->buffer, - pkt_len); + memcpy(skb->data, nic_packet->buffer, pkt_len); skb->protocol = eth_type_trans( skb, dev ); netif_rx(skb); dev->last_rx = jiffies; diff --git a/trunk/drivers/net/atari_pamsnet.c b/trunk/drivers/net/atari_pamsnet.c index 54714409a09b..3b5436149286 100644 --- a/trunk/drivers/net/atari_pamsnet.c +++ b/trunk/drivers/net/atari_pamsnet.c @@ -717,8 +717,7 @@ pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) { local_irq_restore(flags); if( !STRAM_ADDR(buf+length-1) ) { - skb_copy_from_linear_data(skb, nic_packet->buffer, - length); + memcpy(nic_packet->buffer, skb->data, length); buf = (unsigned long)phys_nic_packet; } @@ -793,8 +792,7 @@ pamsnet_poll_rx(struct net_device *dev) { /* 'skb->data' points to the start of sk_buff data area. */ - skb_copy_to_linear_data(skb, nic_packet->buffer, - pkt_len); + memcpy(skb->data, nic_packet->buffer, pkt_len); netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; diff --git a/trunk/drivers/net/atarilance.c b/trunk/drivers/net/atarilance.c index dfa8b9ba4c80..7e37ac86a69a 100644 --- a/trunk/drivers/net/atarilance.c +++ b/trunk/drivers/net/atarilance.c @@ -1047,6 +1047,7 @@ static int lance_rx( struct net_device *dev ) pkt_len ); } + skb->dev = dev; skb_reserve( skb, 2 ); /* 16 byte align */ skb_put( skb, pkt_len ); /* Make room */ lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len ); diff --git a/trunk/drivers/net/atl1/atl1_main.c b/trunk/drivers/net/atl1/atl1_main.c index 4b1d4d153ecf..8606eac5bec8 100644 --- a/trunk/drivers/net/atl1/atl1_main.c +++ b/trunk/drivers/net/atl1/atl1_main.c @@ -408,6 +408,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter, static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) { struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct page *page; unsigned long offset; @@ -443,6 +444,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) * the 14 byte MAC header is removed */ skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; buffer_info->alloced = 1; buffer_info->skb = skb; @@ -1294,21 +1296,19 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, } if (skb->protocol == ntohs(ETH_P_IP)) { - struct iphdr *iph = ip_hdr(skb); - - iph->tot_len = 0; - iph->check = 0; - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); - ipofst = skb_network_offset(skb); + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, 0, + IPPROTO_TCP, 0); + ipofst = skb->nh.raw - skb->data; if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */ tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT; - tso->tsopl |= (iph->ihl & + tso->tsopl |= (skb->nh.iph->ihl & CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT; - tso->tsopl |= (tcp_hdrlen(skb) & + tso->tsopl |= ((skb->h.th->doff << 2) & TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT; tso->tsopl |= (skb_shinfo(skb)->gso_size & TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT; @@ -1327,8 +1327,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, u8 css, cso; if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { - cso = skb_transport_offset(skb); - css = cso + skb->csum_offset; + cso = skb->h.raw - skb->data; + css = (skb->h.raw + skb->csum_offset) - skb->data; if (unlikely(cso & 0x1)) { printk(KERN_DEBUG "%s: payload offset != even number\n", atl1_driver_name); @@ -1370,7 +1370,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, if (tcp_seg) { /* TSO/GSO */ - proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + proto_hdr_len = + ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); buffer_info->length = proto_hdr_len; page = virt_to_page(skb->data); offset = (unsigned long)skb->data & ~PAGE_MASK; @@ -1562,8 +1563,8 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) mss = skb_shinfo(skb)->gso_size; if (mss) { if (skb->protocol == htons(ETH_P_IP)) { - proto_hdr_len = (skb_transport_offset(skb) + - tcp_hdrlen(skb)); + proto_hdr_len = ((skb->h.raw - skb->data) + + (skb->h.th->doff << 2)); if (unlikely(proto_hdr_len > len)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; diff --git a/trunk/drivers/net/atl1/atl1_param.c b/trunk/drivers/net/atl1/atl1_param.c index bcd0bd891722..c407214339f6 100644 --- a/trunk/drivers/net/atl1/atl1_param.c +++ b/trunk/drivers/net/atl1/atl1_param.c @@ -22,6 +22,7 @@ */ #include +#include #include #include "atl1.h" diff --git a/trunk/drivers/net/atp.c b/trunk/drivers/net/atp.c index 18aba838c1ff..2d306fcb7f36 100644 --- a/trunk/drivers/net/atp.c +++ b/trunk/drivers/net/atp.c @@ -793,6 +793,7 @@ static void net_rx(struct net_device *dev) lp->stats.rx_dropped++; goto done; } + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port); diff --git a/trunk/drivers/net/au1000_eth.c b/trunk/drivers/net/au1000_eth.c index c39ab803c5d8..69ae229b680e 100644 --- a/trunk/drivers/net/au1000_eth.c +++ b/trunk/drivers/net/au1000_eth.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1124,7 +1125,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) } pDB = aup->tx_db_inuse[aup->tx_head]; - skb_copy_from_linear_data(skb, pDB->vaddr, skb->len); + memcpy((void *)pDB->vaddr, skb->data, skb->len); if (skb->len < ETH_ZLEN) { for (i=skb->len; ivaddr)[i] = 0; @@ -1204,6 +1205,7 @@ static int au1000_rx(struct net_device *dev) aup->stats.rx_dropped++; continue; } + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte IP header align */ eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, frmlen, 0); diff --git a/trunk/drivers/net/b44.c b/trunk/drivers/net/b44.c index 879a2fff474e..d742bfe24471 100644 --- a/trunk/drivers/net/b44.c +++ b/trunk/drivers/net/b44.c @@ -825,11 +825,12 @@ static int b44_rx(struct b44 *bp, int budget) if (copy_skb == NULL) goto drop_it_no_recycle; + copy_skb->dev = bp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); /* DMA sync done above, copy just the actual packet */ - skb_copy_from_linear_data_offset(skb, bp->rx_offset, - copy_skb->data, len); + memcpy(copy_skb->data, skb->data+bp->rx_offset, len); + skb = copy_skb; } skb->ip_summed = CHECKSUM_NONE; @@ -1006,8 +1007,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_out; } - skb_copy_from_linear_data(skb, skb_put(bounce_skb, len), - skb->len); + memcpy(skb_put(bounce_skb, len), skb->data, skb->len); dev_kfree_skb_any(skb); skb = bounce_skb; } diff --git a/trunk/drivers/net/bmac.c b/trunk/drivers/net/bmac.c index 4612725965df..c143304dcff5 100644 --- a/trunk/drivers/net/bmac.c +++ b/trunk/drivers/net/bmac.c @@ -715,6 +715,7 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) if (skb != NULL) { nb -= ETHERCRC; skb_put(skb, nb); + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; diff --git a/trunk/drivers/net/bnx2.c b/trunk/drivers/net/bnx2.c index 88b33c6ddda8..0b7aded8dcfd 100644 --- a/trunk/drivers/net/bnx2.c +++ b/trunk/drivers/net/bnx2.c @@ -1,6 +1,6 @@ /* bnx2.c: Broadcom NX2 network driver. * - * Copyright (c) 2004-2007 Broadcom Corporation + * Copyright (c) 2004, 2005, 2006 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,8 +54,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.5.10" -#define DRV_MODULE_RELDATE "May 1, 2007" +#define DRV_MODULE_VERSION "1.5.7" +#define DRV_MODULE_RELDATE "March 29, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -84,7 +84,6 @@ typedef enum { BCM5708, BCM5708S, BCM5709, - BCM5709S, } board_t; /* indexed by board_t, above */ @@ -99,7 +98,6 @@ static const struct { { "Broadcom NetXtreme II BCM5708 1000Base-T" }, { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, { "Broadcom NetXtreme II BCM5709 1000Base-T" }, - { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, }; static struct pci_device_id bnx2_pci_tbl[] = { @@ -119,8 +117,6 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, { 0, } }; @@ -234,29 +230,21 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp) static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset) { - u32 val; - - spin_lock_bh(&bp->indirect_lock); REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); - val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW); - spin_unlock_bh(&bp->indirect_lock); - return val; + return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW)); } static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val) { - spin_lock_bh(&bp->indirect_lock); REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val); - spin_unlock_bh(&bp->indirect_lock); } static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) { offset += cid_addr; - spin_lock_bh(&bp->indirect_lock); if (CHIP_NUM(bp) == CHIP_NUM_5709) { int i; @@ -274,7 +262,6 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) REG_WR(bp, BNX2_CTX_DATA_ADR, offset); REG_WR(bp, BNX2_CTX_DATA, val); } - spin_unlock_bh(&bp->indirect_lock); } static int @@ -585,8 +572,8 @@ bnx2_report_fw_link(struct bnx2 *bp) if (bp->autoneg) { fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED; - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); if (!(bmsr & BMSR_ANEGCOMPLETE) || bp->phy_flags & PHY_PARALLEL_DETECT_FLAG) @@ -667,8 +654,8 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) return; } - bnx2_read_phy(bp, bp->mii_adv, &local_adv); - bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); + bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); + bnx2_read_phy(bp, MII_LPA, &remote_adv); if (bp->phy_flags & PHY_SERDES_FLAG) { u32 new_local_adv = 0; @@ -712,45 +699,6 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) } } -static int -bnx2_5709s_linkup(struct bnx2 *bp) -{ - u32 val, speed; - - bp->link_up = 1; - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS); - bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val); - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - - if ((bp->autoneg & AUTONEG_SPEED) == 0) { - bp->line_speed = bp->req_line_speed; - bp->duplex = bp->req_duplex; - return 0; - } - speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK; - switch (speed) { - case MII_BNX2_GP_TOP_AN_SPEED_10: - bp->line_speed = SPEED_10; - break; - case MII_BNX2_GP_TOP_AN_SPEED_100: - bp->line_speed = SPEED_100; - break; - case MII_BNX2_GP_TOP_AN_SPEED_1G: - case MII_BNX2_GP_TOP_AN_SPEED_1GKV: - bp->line_speed = SPEED_1000; - break; - case MII_BNX2_GP_TOP_AN_SPEED_2_5G: - bp->line_speed = SPEED_2500; - break; - } - if (val & MII_BNX2_GP_TOP_AN_FD) - bp->duplex = DUPLEX_FULL; - else - bp->duplex = DUPLEX_HALF; - return 0; -} - static int bnx2_5708s_linkup(struct bnx2 *bp) { @@ -788,7 +736,7 @@ bnx2_5706s_linkup(struct bnx2 *bp) bp->link_up = 1; bp->line_speed = SPEED_1000; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); if (bmcr & BMCR_FULLDPLX) { bp->duplex = DUPLEX_FULL; } @@ -800,8 +748,8 @@ bnx2_5706s_linkup(struct bnx2 *bp) return 0; } - bnx2_read_phy(bp, bp->mii_adv, &local_adv); - bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); + bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); + bnx2_read_phy(bp, MII_LPA, &remote_adv); common = local_adv & remote_adv; if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) { @@ -822,7 +770,7 @@ bnx2_copper_linkup(struct bnx2 *bp) { u32 bmcr; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); if (bmcr & BMCR_ANENABLE) { u32 local_adv, remote_adv, common; @@ -839,8 +787,8 @@ bnx2_copper_linkup(struct bnx2 *bp) bp->duplex = DUPLEX_HALF; } else { - bnx2_read_phy(bp, bp->mii_adv, &local_adv); - bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); + bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); + bnx2_read_phy(bp, MII_LPA, &remote_adv); common = local_adv & remote_adv; if (common & ADVERTISE_100FULL) { @@ -950,145 +898,6 @@ bnx2_set_mac_link(struct bnx2 *bp) return 0; } -static void -bnx2_enable_bmsr1(struct bnx2 *bp) -{ - if ((bp->phy_flags & PHY_SERDES_FLAG) && - (CHIP_NUM(bp) == CHIP_NUM_5709)) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_GP_STATUS); -} - -static void -bnx2_disable_bmsr1(struct bnx2 *bp) -{ - if ((bp->phy_flags & PHY_SERDES_FLAG) && - (CHIP_NUM(bp) == CHIP_NUM_5709)) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_COMBO_IEEEB0); -} - -static int -bnx2_test_and_enable_2g5(struct bnx2 *bp) -{ - u32 up1; - int ret = 1; - - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) - return 0; - - if (bp->autoneg & AUTONEG_SPEED) - bp->advertising |= ADVERTISED_2500baseX_Full; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); - - bnx2_read_phy(bp, bp->mii_up1, &up1); - if (!(up1 & BCM5708S_UP1_2G5)) { - up1 |= BCM5708S_UP1_2G5; - bnx2_write_phy(bp, bp->mii_up1, up1); - ret = 0; - } - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - - return ret; -} - -static int -bnx2_test_and_disable_2g5(struct bnx2 *bp) -{ - u32 up1; - int ret = 0; - - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) - return 0; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); - - bnx2_read_phy(bp, bp->mii_up1, &up1); - if (up1 & BCM5708S_UP1_2G5) { - up1 &= ~BCM5708S_UP1_2G5; - bnx2_write_phy(bp, bp->mii_up1, up1); - ret = 1; - } - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - - return ret; -} - -static void -bnx2_enable_forced_2g5(struct bnx2 *bp) -{ - u32 bmcr; - - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) - return; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - u32 val; - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_SERDES_DIG); - bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val); - val &= ~MII_BNX2_SD_MISC1_FORCE_MSK; - val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G; - bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); - - } else if (CHIP_NUM(bp) == CHIP_NUM_5708) { - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); - bmcr |= BCM5708S_BMCR_FORCE_2500; - } - - if (bp->autoneg & AUTONEG_SPEED) { - bmcr &= ~BMCR_ANENABLE; - if (bp->req_duplex == DUPLEX_FULL) - bmcr |= BMCR_FULLDPLX; - } - bnx2_write_phy(bp, bp->mii_bmcr, bmcr); -} - -static void -bnx2_disable_forced_2g5(struct bnx2 *bp) -{ - u32 bmcr; - - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) - return; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - u32 val; - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_SERDES_DIG); - bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val); - val &= ~MII_BNX2_SD_MISC1_FORCE; - bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, - MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); - - } else if (CHIP_NUM(bp) == CHIP_NUM_5708) { - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); - bmcr &= ~BCM5708S_BMCR_FORCE_2500; - } - - if (bp->autoneg & AUTONEG_SPEED) - bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART; - bnx2_write_phy(bp, bp->mii_bmcr, bmcr); -} - static int bnx2_set_link(struct bnx2 *bp) { @@ -1102,10 +911,8 @@ bnx2_set_link(struct bnx2 *bp) link_up = bp->link_up; - bnx2_enable_bmsr1(bp); - bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); - bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); - bnx2_disable_bmsr1(bp); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); if ((bp->phy_flags & PHY_SERDES_FLAG) && (CHIP_NUM(bp) == CHIP_NUM_5706)) { @@ -1126,8 +933,6 @@ bnx2_set_link(struct bnx2 *bp) bnx2_5706s_linkup(bp); else if (CHIP_NUM(bp) == CHIP_NUM_5708) bnx2_5708s_linkup(bp); - else if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_5709s_linkup(bp); } else { bnx2_copper_linkup(bp); @@ -1136,9 +941,17 @@ bnx2_set_link(struct bnx2 *bp) } else { if ((bp->phy_flags & PHY_SERDES_FLAG) && - (bp->autoneg & AUTONEG_SPEED)) - bnx2_disable_forced_2g5(bp); + (bp->autoneg & AUTONEG_SPEED)) { + + u32 bmcr; + bnx2_read_phy(bp, MII_BMCR, &bmcr); + bmcr &= ~BCM5708S_BMCR_FORCE_2500; + if (!(bmcr & BMCR_ANENABLE)) { + bnx2_write_phy(bp, MII_BMCR, bmcr | + BMCR_ANENABLE); + } + } bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; bp->link_up = 0; } @@ -1158,13 +971,13 @@ bnx2_reset_phy(struct bnx2 *bp) int i; u32 reg; - bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET); + bnx2_write_phy(bp, MII_BMCR, BMCR_RESET); #define PHY_RESET_MAX_WAIT 100 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) { udelay(10); - bnx2_read_phy(bp, bp->mii_bmcr, ®); + bnx2_read_phy(bp, MII_BMCR, ®); if (!(reg & BMCR_RESET)) { udelay(20); break; @@ -1213,40 +1026,34 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) static int bnx2_setup_serdes_phy(struct bnx2 *bp) { - u32 adv, bmcr; + u32 adv, bmcr, up1; u32 new_adv = 0; if (!(bp->autoneg & AUTONEG_SPEED)) { u32 new_bmcr; int force_link_down = 0; - if (bp->req_line_speed == SPEED_2500) { - if (!bnx2_test_and_enable_2g5(bp)) - force_link_down = 1; - } else if (bp->req_line_speed == SPEED_1000) { - if (bnx2_test_and_disable_2g5(bp)) - force_link_down = 1; - } - bnx2_read_phy(bp, bp->mii_adv, &adv); + bnx2_read_phy(bp, MII_ADVERTISE, &adv); adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); - new_bmcr = bmcr & ~BMCR_ANENABLE; + bnx2_read_phy(bp, MII_BMCR, &bmcr); + new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500); new_bmcr |= BMCR_SPEED1000; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - if (bp->req_line_speed == SPEED_2500) - bnx2_enable_forced_2g5(bp); - else if (bp->req_line_speed == SPEED_1000) { - bnx2_disable_forced_2g5(bp); - new_bmcr &= ~0x2000; + if (bp->req_line_speed == SPEED_2500) { + new_bmcr |= BCM5708S_BMCR_FORCE_2500; + bnx2_read_phy(bp, BCM5708S_UP1, &up1); + if (!(up1 & BCM5708S_UP1_2G5)) { + up1 |= BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, up1); + force_link_down = 1; } - } else if (CHIP_NUM(bp) == CHIP_NUM_5708) { - if (bp->req_line_speed == SPEED_2500) - new_bmcr |= BCM5708S_BMCR_FORCE_2500; - else - new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500; + bnx2_read_phy(bp, BCM5708S_UP1, &up1); + if (up1 & BCM5708S_UP1_2G5) { + up1 &= ~BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, up1); + force_link_down = 1; + } } if (bp->req_duplex == DUPLEX_FULL) { @@ -1260,48 +1067,49 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) if ((new_bmcr != bmcr) || (force_link_down)) { /* Force a link down visible on the other side */ if (bp->link_up) { - bnx2_write_phy(bp, bp->mii_adv, adv & + bnx2_write_phy(bp, MII_ADVERTISE, adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF)); - bnx2_write_phy(bp, bp->mii_bmcr, bmcr | + bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); bp->link_up = 0; netif_carrier_off(bp->dev); - bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); + bnx2_write_phy(bp, MII_BMCR, new_bmcr); bnx2_report_link(bp); } - bnx2_write_phy(bp, bp->mii_adv, adv); - bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); - } else { - bnx2_resolve_flow_ctrl(bp); - bnx2_set_mac_link(bp); + bnx2_write_phy(bp, MII_ADVERTISE, adv); + bnx2_write_phy(bp, MII_BMCR, new_bmcr); } return 0; } - bnx2_test_and_enable_2g5(bp); + if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { + bnx2_read_phy(bp, BCM5708S_UP1, &up1); + up1 |= BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, up1); + } if (bp->advertising & ADVERTISED_1000baseT_Full) new_adv |= ADVERTISE_1000XFULL; new_adv |= bnx2_phy_get_pause_adv(bp); - bnx2_read_phy(bp, bp->mii_adv, &adv); - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_ADVERTISE, &adv); + bnx2_read_phy(bp, MII_BMCR, &bmcr); bp->serdes_an_pending = 0; if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) { /* Force a link down visible on the other side */ if (bp->link_up) { - bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); + bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); msleep(20); spin_lock_bh(&bp->phy_lock); } - bnx2_write_phy(bp, bp->mii_adv, new_adv); - bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | + bnx2_write_phy(bp, MII_ADVERTISE, new_adv); + bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); /* Speed up link-up time when the link partner * does not autonegotiate which is very common @@ -1314,9 +1122,6 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) bp->current_interval = SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); - } else { - bnx2_resolve_flow_ctrl(bp); - bnx2_set_mac_link(bp); } return 0; @@ -1341,14 +1146,14 @@ bnx2_setup_copper_phy(struct bnx2 *bp) u32 bmcr; u32 new_bmcr; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); if (bp->autoneg & AUTONEG_SPEED) { u32 adv_reg, adv1000_reg; u32 new_adv_reg = 0; u32 new_adv1000_reg = 0; - bnx2_read_phy(bp, bp->mii_adv, &adv_reg); + bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg); adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -1374,9 +1179,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp) (adv_reg != new_adv_reg) || ((bmcr & BMCR_ANENABLE) == 0)) { - bnx2_write_phy(bp, bp->mii_adv, new_adv_reg); + bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg); bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg); - bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART | + bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE); } else if (bp->link_up) { @@ -1399,21 +1204,21 @@ bnx2_setup_copper_phy(struct bnx2 *bp) if (new_bmcr != bmcr) { u32 bmsr; - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); if (bmsr & BMSR_LSTATUS) { /* Force link down */ - bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); + bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); msleep(50); spin_lock_bh(&bp->phy_lock); - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); - bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); } - bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); + bnx2_write_phy(bp, MII_BMCR, new_bmcr); /* Normally, the new speed is setup after the link has * gone down and up again. In some cases, link will not go @@ -1425,9 +1230,6 @@ bnx2_setup_copper_phy(struct bnx2 *bp) bnx2_resolve_flow_ctrl(bp); bnx2_set_mac_link(bp); } - } else { - bnx2_resolve_flow_ctrl(bp); - bnx2_set_mac_link(bp); } return 0; } @@ -1446,64 +1248,11 @@ bnx2_setup_phy(struct bnx2 *bp) } } -static int -bnx2_init_5709s_phy(struct bnx2 *bp) -{ - u32 val; - - bp->mii_bmcr = MII_BMCR + 0x10; - bp->mii_bmsr = MII_BMSR + 0x10; - bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1; - bp->mii_adv = MII_ADVERTISE + 0x10; - bp->mii_lpa = MII_LPA + 0x10; - bp->mii_up1 = MII_BNX2_OVER1G_UP1; - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER); - bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_reset_phy(bp); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG); - - bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val); - val &= ~MII_BNX2_SD_1000XCTL1_AUTODET; - val |= MII_BNX2_SD_1000XCTL1_FIBER; - bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); - bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val); - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) - val |= BCM5708S_UP1_2G5; - else - val &= ~BCM5708S_UP1_2G5; - bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG); - bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val); - val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM; - bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0); - - val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN | - MII_BNX2_CL73_BAM_NP_AFT_BP_EN; - bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val); - - bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - - return 0; -} - static int bnx2_init_5708s_phy(struct bnx2 *bp) { u32 val; - bnx2_reset_phy(bp); - - bp->mii_up1 = BCM5708S_UP1; - bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3); bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE); bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG); @@ -1556,8 +1305,6 @@ bnx2_init_5708s_phy(struct bnx2 *bp) static int bnx2_init_5706s_phy(struct bnx2 *bp) { - bnx2_reset_phy(bp); - bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; if (CHIP_NUM(bp) == CHIP_NUM_5706) @@ -1595,8 +1342,6 @@ bnx2_init_copper_phy(struct bnx2 *bp) { u32 val; - bnx2_reset_phy(bp); - if (bp->phy_flags & PHY_CRC_FIX_FLAG) { bnx2_write_phy(bp, 0x18, 0x0c00); bnx2_write_phy(bp, 0x17, 0x000a); @@ -1651,14 +1396,10 @@ bnx2_init_phy(struct bnx2 *bp) bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG; bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG; - bp->mii_bmcr = MII_BMCR; - bp->mii_bmsr = MII_BMSR; - bp->mii_bmsr1 = MII_BMSR; - bp->mii_adv = MII_ADVERTISE; - bp->mii_lpa = MII_LPA; - REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); + bnx2_reset_phy(bp); + bnx2_read_phy(bp, MII_PHYSID1, &val); bp->phy_id = val << 16; bnx2_read_phy(bp, MII_PHYSID2, &val); @@ -1669,8 +1410,6 @@ bnx2_init_phy(struct bnx2 *bp) rc = bnx2_init_5706s_phy(bp); else if (CHIP_NUM(bp) == CHIP_NUM_5708) rc = bnx2_init_5708s_phy(bp); - else if (CHIP_NUM(bp) == CHIP_NUM_5709) - rc = bnx2_init_5709s_phy(bp); } else { rc = bnx2_init_copper_phy(bp); @@ -1703,7 +1442,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp) int rc, i; spin_lock_bh(&bp->phy_lock); - rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX | + rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000); spin_unlock_bh(&bp->phy_lock); if (rc) @@ -1942,33 +1681,25 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) return 0; } -static int -bnx2_phy_event_is_set(struct bnx2 *bp, u32 event) +static void +bnx2_phy_int(struct bnx2 *bp) { - struct status_block *sblk = bp->status_blk; u32 new_link_state, old_link_state; - int is_set = 1; - new_link_state = sblk->status_attn_bits & event; - old_link_state = sblk->status_attn_bits_ack & event; + new_link_state = bp->status_blk->status_attn_bits & + STATUS_ATTN_BITS_LINK_STATE; + old_link_state = bp->status_blk->status_attn_bits_ack & + STATUS_ATTN_BITS_LINK_STATE; if (new_link_state != old_link_state) { - if (new_link_state) - REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event); - else - REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event); - } else - is_set = 0; - - return is_set; -} - -static void -bnx2_phy_int(struct bnx2 *bp) -{ - if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) { - spin_lock(&bp->phy_lock); + if (new_link_state) { + REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, + STATUS_ATTN_BITS_LINK_STATE); + } + else { + REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, + STATUS_ATTN_BITS_LINK_STATE); + } bnx2_set_link(bp); - spin_unlock(&bp->phy_lock); } } @@ -2153,8 +1884,10 @@ bnx2_rx_int(struct bnx2 *bp, int budget) goto reuse_rx; /* aligned copy */ - skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2, - new_skb->data, len + 2); + memcpy(new_skb->data, + skb->data + bp->rx_offset - 2, + len + 2); + skb_reserve(new_skb, 2); skb_put(new_skb, len); @@ -2261,23 +1994,6 @@ bnx2_msi(int irq, void *dev_instance) return IRQ_HANDLED; } -static irqreturn_t -bnx2_msi_1shot(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - - prefetch(bp->status_blk); - - /* Return here if interrupt is disabled. */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) - return IRQ_HANDLED; - - netif_rx_schedule(dev); - - return IRQ_HANDLED; -} - static irqreturn_t bnx2_interrupt(int irq, void *dev_instance) { @@ -2308,8 +2024,6 @@ bnx2_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -#define STATUS_ATTN_EVENTS STATUS_ATTN_BITS_LINK_STATE - static inline int bnx2_has_work(struct bnx2 *bp) { @@ -2319,8 +2033,8 @@ bnx2_has_work(struct bnx2 *bp) (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) return 1; - if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != - (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) + if ((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != + (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) return 1; return 0; @@ -2330,14 +2044,15 @@ static int bnx2_poll(struct net_device *dev, int *budget) { struct bnx2 *bp = netdev_priv(dev); - struct status_block *sblk = bp->status_blk; - u32 status_attn_bits = sblk->status_attn_bits; - u32 status_attn_bits_ack = sblk->status_attn_bits_ack; - if ((status_attn_bits & STATUS_ATTN_EVENTS) != - (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { + if ((bp->status_blk->status_attn_bits & + STATUS_ATTN_BITS_LINK_STATE) != + (bp->status_blk->status_attn_bits_ack & + STATUS_ATTN_BITS_LINK_STATE)) { + spin_lock(&bp->phy_lock); bnx2_phy_int(bp); + spin_unlock(&bp->phy_lock); /* This is needed to take care of transient status * during link changes. @@ -3706,9 +3421,6 @@ bnx2_init_chip(struct bnx2 *bp) val = REG_RD(bp, BNX2_MQ_CONFIG); val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; - if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1) - val |= BNX2_MQ_CONFIG_HALT_DIS; - REG_WR(bp, BNX2_MQ_CONFIG, val); val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE); @@ -3776,21 +3488,17 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */ if (CHIP_ID(bp) == CHIP_ID_5706_A1) - val = BNX2_HC_CONFIG_COLLECT_STATS; + REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS); else { - val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE | - BNX2_HC_CONFIG_COLLECT_STATS; + REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE | + BNX2_HC_CONFIG_TX_TMR_MODE | + BNX2_HC_CONFIG_COLLECT_STATS); } - if (bp->flags & ONE_SHOT_MSI_FLAG) - val |= BNX2_HC_CONFIG_ONE_SHOT; - - REG_WR(bp, BNX2_HC_CONFIG, val); - /* Clear internal stats counters. */ REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW); - REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS); + REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE); if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) & BNX2_PORT_FEATURE_ASF_ENABLED) @@ -4054,11 +3762,10 @@ static int bnx2_test_registers(struct bnx2 *bp) { int ret; - int i, is_5709; + int i; static const struct { u16 offset; u16 flags; -#define BNX2_FL_NOT_5709 1 u32 rw_mask; u32 ro_mask; } reg_tbl[] = { @@ -4066,26 +3773,26 @@ bnx2_test_registers(struct bnx2 *bp) { 0x0090, 0, 0xffffffff, 0x00000000 }, { 0x0094, 0, 0x00000000, 0x00000000 }, - { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 }, - { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff }, - { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 }, - { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, - { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff }, - { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - - { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, - { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, - { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, - { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, - { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, - - { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, - { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 }, - { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 }, + { 0x0404, 0, 0x00003f00, 0x00000000 }, + { 0x0418, 0, 0x00000000, 0xffffffff }, + { 0x041c, 0, 0x00000000, 0xffffffff }, + { 0x0420, 0, 0x00000000, 0x80ffffff }, + { 0x0424, 0, 0x00000000, 0x00000000 }, + { 0x0428, 0, 0x00000000, 0x00000001 }, + { 0x0450, 0, 0x00000000, 0x0000ffff }, + { 0x0454, 0, 0x00000000, 0xffffffff }, + { 0x0458, 0, 0x00000000, 0xffffffff }, + + { 0x0808, 0, 0x00000000, 0xffffffff }, + { 0x0854, 0, 0x00000000, 0xffffffff }, + { 0x0868, 0, 0x00000000, 0x77777777 }, + { 0x086c, 0, 0x00000000, 0x77777777 }, + { 0x0870, 0, 0x00000000, 0x77777777 }, + { 0x0874, 0, 0x00000000, 0x77777777 }, + + { 0x0c00, 0, 0x00000000, 0x00000001 }, + { 0x0c04, 0, 0x00000000, 0x03ff0001 }, + { 0x0c08, 0, 0x0f0ff073, 0x00000000 }, { 0x1000, 0, 0x00000000, 0x00000001 }, { 0x1004, 0, 0x00000000, 0x000f0001 }, @@ -4132,6 +3839,7 @@ bnx2_test_registers(struct bnx2 *bp) { 0x5004, 0, 0x00000000, 0x0000007f }, { 0x5008, 0, 0x0f0007ff, 0x00000000 }, + { 0x500c, 0, 0xf800f800, 0x07ff07ff }, { 0x5c00, 0, 0x00000000, 0x00000001 }, { 0x5c04, 0, 0x00000000, 0x0003000f }, @@ -4171,16 +3879,8 @@ bnx2_test_registers(struct bnx2 *bp) }; ret = 0; - is_5709 = 0; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - is_5709 = 1; - for (i = 0; reg_tbl[i].offset != 0xffff; i++) { u32 offset, rw_mask, ro_mask, save_val, val; - u16 flags = reg_tbl[i].flags; - - if (is_5709 && (flags & BNX2_FL_NOT_5709)) - continue; offset = (u32) reg_tbl[i].offset; rw_mask = reg_tbl[i].rw_mask; @@ -4249,10 +3949,10 @@ bnx2_test_memory(struct bnx2 *bp) { int ret = 0; int i; - static struct mem_entry { + static const struct { u32 offset; u32 len; - } mem_tbl_5706[] = { + } mem_tbl[] = { { 0x60000, 0x4000 }, { 0xa0000, 0x3000 }, { 0xe0000, 0x4000 }, @@ -4260,21 +3960,7 @@ bnx2_test_memory(struct bnx2 *bp) { 0x1a0000, 0x4000 }, { 0x160000, 0x4000 }, { 0xffffffff, 0 }, - }, - mem_tbl_5709[] = { - { 0x60000, 0x4000 }, - { 0xa0000, 0x3000 }, - { 0xe0000, 0x4000 }, - { 0x120000, 0x4000 }, - { 0x1a0000, 0x4000 }, - { 0xffffffff, 0 }, }; - struct mem_entry *mem_tbl; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - mem_tbl = mem_tbl_5709; - else - mem_tbl = mem_tbl_5706; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset, @@ -4476,10 +4162,8 @@ bnx2_test_link(struct bnx2 *bp) u32 bmsr; spin_lock_bh(&bp->phy_lock); - bnx2_enable_bmsr1(bp); - bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); - bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); - bnx2_disable_bmsr1(bp); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); spin_unlock_bh(&bp->phy_lock); if (bmsr & BMSR_LSTATUS) { @@ -4529,7 +4213,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bp->current_interval = bp->timer_interval; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); if (bmcr & BMCR_ANENABLE) { u32 phy1, phy2; @@ -4547,7 +4231,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bmcr &= ~BMCR_ANENABLE; bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX; - bnx2_write_phy(bp, bp->mii_bmcr, bmcr); + bnx2_write_phy(bp, MII_BMCR, bmcr); bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG; } } @@ -4561,9 +4245,9 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) if (phy2 & 0x20) { u32 bmcr; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); bmcr |= BMCR_ANENABLE; - bnx2_write_phy(bp, bp->mii_bmcr, bmcr); + bnx2_write_phy(bp, MII_BMCR, bmcr); bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; } @@ -4587,12 +4271,17 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { u32 bmcr; - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); + if (bmcr & BMCR_ANENABLE) { - bnx2_enable_forced_2g5(bp); + bmcr &= ~BMCR_ANENABLE; + bmcr |= BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500; + bnx2_write_phy(bp, MII_BMCR, bmcr); bp->current_interval = SERDES_FORCED_TIMEOUT; } else { - bnx2_disable_forced_2g5(bp); + bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500); + bmcr |= BMCR_ANENABLE; + bnx2_write_phy(bp, MII_BMCR, bmcr); bp->serdes_an_pending = 2; bp->current_interval = bp->timer_interval; } @@ -4623,7 +4312,7 @@ bnx2_timer(unsigned long data) if (bp->phy_flags & PHY_SERDES_FLAG) { if (CHIP_NUM(bp) == CHIP_NUM_5706) bnx2_5706_serdes_timer(bp); - else + else if (CHIP_NUM(bp) == CHIP_NUM_5708) bnx2_5708_serdes_timer(bp); } @@ -4631,38 +4320,6 @@ bnx2_timer(unsigned long data) mod_timer(&bp->timer, jiffies + bp->current_interval); } -static int -bnx2_request_irq(struct bnx2 *bp) -{ - struct net_device *dev = bp->dev; - int rc = 0; - - if (bp->flags & USING_MSI_FLAG) { - irq_handler_t fn = bnx2_msi; - - if (bp->flags & ONE_SHOT_MSI_FLAG) - fn = bnx2_msi_1shot; - - rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev); - } else - rc = request_irq(bp->pdev->irq, bnx2_interrupt, - IRQF_SHARED, dev->name, dev); - return rc; -} - -static void -bnx2_free_irq(struct bnx2 *bp) -{ - struct net_device *dev = bp->dev; - - if (bp->flags & USING_MSI_FLAG) { - free_irq(bp->pdev->irq, dev); - pci_disable_msi(bp->pdev); - bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG); - } else - free_irq(bp->pdev->irq, dev); -} - /* Called with rtnl_lock */ static int bnx2_open(struct net_device *dev) @@ -4670,8 +4327,6 @@ bnx2_open(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); int rc; - netif_carrier_off(dev); - bnx2_set_power_state(bp, PCI_D0); bnx2_disable_int(bp); @@ -4679,15 +4334,24 @@ bnx2_open(struct net_device *dev) if (rc) return rc; - if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) { + if ((CHIP_ID(bp) != CHIP_ID_5706_A0) && + (CHIP_ID(bp) != CHIP_ID_5706_A1) && + !disable_msi) { + if (pci_enable_msi(bp->pdev) == 0) { bp->flags |= USING_MSI_FLAG; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bp->flags |= ONE_SHOT_MSI_FLAG; + rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name, + dev); + } + else { + rc = request_irq(bp->pdev->irq, bnx2_interrupt, + IRQF_SHARED, dev->name, dev); } } - rc = bnx2_request_irq(bp); - + else { + rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED, + dev->name, dev); + } if (rc) { bnx2_free_mem(bp); return rc; @@ -4696,7 +4360,11 @@ bnx2_open(struct net_device *dev) rc = bnx2_init_nic(bp); if (rc) { - bnx2_free_irq(bp); + free_irq(bp->pdev->irq, dev); + if (bp->flags & USING_MSI_FLAG) { + pci_disable_msi(bp->pdev); + bp->flags &= ~USING_MSI_FLAG; + } bnx2_free_skbs(bp); bnx2_free_mem(bp); return rc; @@ -4720,13 +4388,16 @@ bnx2_open(struct net_device *dev) bp->dev->name); bnx2_disable_int(bp); - bnx2_free_irq(bp); + free_irq(bp->pdev->irq, dev); + pci_disable_msi(bp->pdev); + bp->flags &= ~USING_MSI_FLAG; rc = bnx2_init_nic(bp); - if (!rc) - rc = bnx2_request_irq(bp); - + if (!rc) { + rc = request_irq(bp->pdev->irq, bnx2_interrupt, + IRQF_SHARED, dev->name, dev); + } if (rc) { bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -4836,53 +4507,41 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } - if ((mss = skb_shinfo(skb)->gso_size)) { + if ((mss = skb_shinfo(skb)->gso_size) && + (skb->len > (bp->dev->mtu + ETH_HLEN))) { u32 tcp_opt_len, ip_tcp_len; - struct iphdr *iph; - vlan_tag_flags |= TX_BD_FLAGS_SW_LSO; + if (skb_header_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } - tcp_opt_len = tcp_optlen(skb); + tcp_opt_len = ((skb->h.th->doff - 5) * 4); + vlan_tag_flags |= TX_BD_FLAGS_SW_LSO; - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { - u32 tcp_off = skb_transport_offset(skb) - - sizeof(struct ipv6hdr) - ETH_HLEN; + tcp_opt_len = 0; + if (skb->h.th->doff > 5) { + tcp_opt_len = (skb->h.th->doff - 5) << 2; + } + ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr); - vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) | - TX_BD_FLAGS_SW_FLAGS; - if (likely(tcp_off == 0)) - vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK; - else { - tcp_off >>= 3; - vlan_tag_flags |= ((tcp_off & 0x3) << - TX_BD_FLAGS_TCP6_OFF0_SHL) | - ((tcp_off & 0x10) << - TX_BD_FLAGS_TCP6_OFF4_SHL); - mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL; - } - } else { - if (skb_header_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } + skb->nh.iph->check = 0; + skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, IPPROTO_TCP, 0); - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); - - iph = ip_hdr(skb); - iph->check = 0; - iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); - if (tcp_opt_len || (iph->ihl > 5)) { - vlan_tag_flags |= ((iph->ihl - 5) + - (tcp_opt_len >> 2)) << 8; - } + if (tcp_opt_len || (skb->nh.iph->ihl > 5)) { + vlan_tag_flags |= ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)) << 8; } - } else + } + else + { mss = 0; + } mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); @@ -4963,7 +4622,11 @@ bnx2_close(struct net_device *dev) else reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; bnx2_reset_chip(bp, reset_code); - bnx2_free_irq(bp); + free_irq(bp->pdev->irq, dev); + if (bp->flags & USING_MSI_FLAG) { + pci_disable_msi(bp->pdev); + bp->flags &= ~USING_MSI_FLAG; + } bnx2_free_skbs(bp); bnx2_free_mem(bp); bp->link_up = 0; @@ -5072,8 +4735,6 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bp->phy_flags & PHY_SERDES_FLAG) { cmd->supported |= SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE; - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) - cmd->supported |= SUPPORTED_2500baseX_Full; cmd->port = PORT_FIBRE; } @@ -5137,10 +4798,8 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = cmd->advertising; - } else if (cmd->advertising == ADVERTISED_2500baseX_Full) { - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) - return -EINVAL; - } else if (cmd->advertising == ADVERTISED_1000baseT_Full) { + } + else if (cmd->advertising == ADVERTISED_1000baseT_Full) { advertising = cmd->advertising; } else if (cmd->advertising == ADVERTISED_1000baseT_Half) { @@ -5316,7 +4975,7 @@ bnx2_nway_reset(struct net_device *dev) /* Force a link down visible on the other side */ if (bp->phy_flags & PHY_SERDES_FLAG) { - bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); + bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); msleep(20); @@ -5328,9 +4987,9 @@ bnx2_nway_reset(struct net_device *dev) mod_timer(&bp->timer, jiffies + bp->current_interval); } - bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bnx2_read_phy(bp, MII_BMCR, &bmcr); bmcr &= ~BMCR_LOOPBACK; - bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); + bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); spin_unlock_bh(&bp->phy_lock); @@ -5550,15 +5209,10 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data) static int bnx2_set_tso(struct net_device *dev, u32 data) { - struct bnx2 *bp = netdev_priv(dev); - - if (data) { + if (data) dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_TSO_ECN); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); return 0; } @@ -5856,17 +5510,6 @@ bnx2_phys_id(struct net_device *dev, u32 data) return 0; } -static int -bnx2_set_tx_csum(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - return (ethtool_op_set_tx_hw_csum(dev, data)); - else - return (ethtool_op_set_tx_csum(dev, data)); -} - static const struct ethtool_ops bnx2_ethtool_ops = { .get_settings = bnx2_get_settings, .set_settings = bnx2_set_settings, @@ -5889,7 +5532,7 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .get_rx_csum = bnx2_get_rx_csum, .set_rx_csum = bnx2_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = bnx2_set_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, @@ -5919,9 +5562,6 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: { u32 mii_regval; - if (!netif_running(dev)) - return -EAGAIN; - spin_lock_bh(&bp->phy_lock); err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval); spin_unlock_bh(&bp->phy_lock); @@ -5935,9 +5575,6 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (!netif_running(dev)) - return -EAGAIN; - spin_lock_bh(&bp->phy_lock); err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in); spin_unlock_bh(&bp->phy_lock); @@ -6039,58 +5676,6 @@ bnx2_get_5709_media(struct bnx2 *bp) } } -static void __devinit -bnx2_get_pci_speed(struct bnx2 *bp) -{ - u32 reg; - - reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS); - if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { - u32 clkreg; - - bp->flags |= PCIX_FLAG; - - clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS); - - clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET; - switch (clkreg) { - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ: - bp->bus_speed_mhz = 133; - break; - - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ: - bp->bus_speed_mhz = 100; - break; - - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ: - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ: - bp->bus_speed_mhz = 66; - break; - - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ: - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ: - bp->bus_speed_mhz = 50; - break; - - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW: - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ: - case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ: - bp->bus_speed_mhz = 33; - break; - } - } - else { - if (reg & BNX2_PCICFG_MISC_STATUS_M66EN) - bp->bus_speed_mhz = 66; - else - bp->bus_speed_mhz = 33; - } - - if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET) - bp->flags |= PCI_32BIT_FLAG; - -} - static int __devinit bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) { @@ -6098,7 +5683,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) unsigned long mem_len; int rc; u32 reg; - u64 dma_mask, persist_dma_mask; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -6137,11 +5721,25 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_release; } + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { + bp->flags |= USING_DAC_FLAG; + if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + dev_err(&pdev->dev, + "pci_set_consistent_dma_mask failed, aborting.\n"); + rc = -EIO; + goto err_out_release; + } + } + else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { + dev_err(&pdev->dev, "System does not support DMA, aborting.\n"); + rc = -EIO; + goto err_out_release; + } + bp->dev = dev; bp->pdev = pdev; spin_lock_init(&bp->phy_lock); - spin_lock_init(&bp->indirect_lock); INIT_WORK(&bp->reset_task, bnx2_reset_task); dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); @@ -6169,15 +5767,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->chip_id = REG_RD(bp, BNX2_MISC_ID); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) { - dev_err(&pdev->dev, - "Cannot find PCIE capability, aborting.\n"); - rc = -EIO; - goto err_out_unmap; - } - bp->flags |= PCIE_FLAG; - } else { + if (CHIP_NUM(bp) != CHIP_NUM_5709) { bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX); if (bp->pcix_cap == 0) { dev_err(&pdev->dev, @@ -6187,33 +5777,51 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } } - if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) { - if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) - bp->flags |= MSI_CAP_FLAG; - } + /* Get bus information. */ + reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS); + if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { + u32 clkreg; - /* 5708 cannot support DMA addresses > 40-bit. */ - if (CHIP_NUM(bp) == CHIP_NUM_5708) - persist_dma_mask = dma_mask = DMA_40BIT_MASK; - else - persist_dma_mask = dma_mask = DMA_64BIT_MASK; + bp->flags |= PCIX_FLAG; - /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, dma_mask) == 0) { - dev->features |= NETIF_F_HIGHDMA; - rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask); - if (rc) { - dev_err(&pdev->dev, - "pci_set_consistent_dma_mask failed, aborting.\n"); - goto err_out_unmap; + clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS); + + clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET; + switch (clkreg) { + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ: + bp->bus_speed_mhz = 133; + break; + + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ: + bp->bus_speed_mhz = 100; + break; + + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ: + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ: + bp->bus_speed_mhz = 66; + break; + + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ: + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ: + bp->bus_speed_mhz = 50; + break; + + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW: + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ: + case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ: + bp->bus_speed_mhz = 33; + break; } - } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) { - dev_err(&pdev->dev, "System does not support DMA, aborting.\n"); - goto err_out_unmap; + } + else { + if (reg & BNX2_PCICFG_MISC_STATUS_M66EN) + bp->bus_speed_mhz = 66; + else + bp->bus_speed_mhz = 33; } - if (!(bp->flags & PCIE_FLAG)) - bnx2_get_pci_speed(bp); + if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET) + bp->flags |= PCI_32BIT_FLAG; /* 5706A0 may falsely detect SERR and PERR. */ if (CHIP_ID(bp) == CHIP_ID_5706_A0) { @@ -6397,26 +6005,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) return rc; } -static char * __devinit -bnx2_bus_string(struct bnx2 *bp, char *str) -{ - char *s = str; - - if (bp->flags & PCIE_FLAG) { - s += sprintf(s, "PCI Express"); - } else { - s += sprintf(s, "PCI"); - if (bp->flags & PCIX_FLAG) - s += sprintf(s, "-X"); - if (bp->flags & PCI_32BIT_FLAG) - s += sprintf(s, " 32-bit"); - else - s += sprintf(s, " 64-bit"); - s += sprintf(s, " %dMHz", bp->bus_speed_mhz); - } - return str; -} - static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -6424,7 +6012,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev = NULL; struct bnx2 *bp; int rc, i; - char str[40]; if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -6465,23 +6052,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->poll_controller = poll_bnx2; #endif - pci_set_drvdata(pdev, dev); - - memcpy(dev->dev_addr, bp->mac_addr, 6); - memcpy(dev->perm_addr, bp->mac_addr, 6); - bp->name = board_info[ent->driver_data].name; - - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; - else - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; -#ifdef BCM_VLAN - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; -#endif - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_TSO6; - if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); if (bp->regview) @@ -6493,13 +6063,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } - printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " + pci_set_drvdata(pdev, dev); + + memcpy(dev->dev_addr, bp->mac_addr, 6); + memcpy(dev->perm_addr, bp->mac_addr, 6); + bp->name = board_info[ent->driver_data].name, + printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, " "IRQ %d, ", dev->name, bp->name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), - bnx2_bus_string(bp, str), + ((bp->flags & PCIX_FLAG) ? "-X" : ""), + ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"), + bp->bus_speed_mhz, dev->base_addr, bp->pdev->irq); @@ -6508,6 +6085,17 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk("%2.2x", dev->dev_addr[i]); printk("\n"); + dev->features |= NETIF_F_SG; + if (bp->flags & USING_DAC_FLAG) + dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_IP_CSUM; +#ifdef BCM_VLAN + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; + + netif_carrier_off(bp->dev); + return 0; } @@ -6552,7 +6140,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; bnx2_reset_chip(bp, reset_code); bnx2_free_skbs(bp); - pci_save_state(pdev); bnx2_set_power_state(bp, pci_choose_state(pdev, state)); return 0; } @@ -6566,7 +6153,6 @@ bnx2_resume(struct pci_dev *pdev) if (!netif_running(dev)) return 0; - pci_restore_state(pdev); bnx2_set_power_state(bp, PCI_D0); netif_device_attach(dev); bnx2_init_nic(bp); diff --git a/trunk/drivers/net/bnx2.h b/trunk/drivers/net/bnx2.h index bd6288d6350f..ccbdf81c6599 100644 --- a/trunk/drivers/net/bnx2.h +++ b/trunk/drivers/net/bnx2.h @@ -1,6 +1,6 @@ /* bnx2.h: Broadcom NX2 network driver. * - * Copyright (c) 2004-2007 Broadcom Corporation + * Copyright (c) 2004, 2005, 2006 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,11 +24,8 @@ struct tx_bd { u32 tx_bd_haddr_hi; u32 tx_bd_haddr_lo; u32 tx_bd_mss_nbytes; - #define TX_BD_TCP6_OFF2_SHL (14) u32 tx_bd_vlan_tag_flags; #define TX_BD_FLAGS_CONN_FAULT (1<<0) - #define TX_BD_FLAGS_TCP6_OFF0_MSK (3<<1) - #define TX_BD_FLAGS_TCP6_OFF0_SHL (1) #define TX_BD_FLAGS_TCP_UDP_CKSUM (1<<1) #define TX_BD_FLAGS_IP_CKSUM (1<<2) #define TX_BD_FLAGS_VLAN_TAG (1<<3) @@ -37,7 +34,6 @@ struct tx_bd { #define TX_BD_FLAGS_END (1<<6) #define TX_BD_FLAGS_START (1<<7) #define TX_BD_FLAGS_SW_OPTION_WORD (0x1f<<8) - #define TX_BD_FLAGS_TCP6_OFF4_SHL (12) #define TX_BD_FLAGS_SW_FLAGS (1<<13) #define TX_BD_FLAGS_SW_SNAP (1<<14) #define TX_BD_FLAGS_SW_LSO (1<<15) @@ -6296,41 +6292,6 @@ struct l2_fhdr { #define MII_BNX2_DSP_ADDRESS 0x17 #define MII_BNX2_DSP_EXPAND_REG 0x0f00 -#define MII_BNX2_BLK_ADDR 0x1f -#define MII_BNX2_BLK_ADDR_IEEE0 0x0000 -#define MII_BNX2_BLK_ADDR_GP_STATUS 0x8120 -#define MII_BNX2_GP_TOP_AN_STATUS1 0x1b -#define MII_BNX2_GP_TOP_AN_SPEED_MSK 0x3f00 -#define MII_BNX2_GP_TOP_AN_SPEED_10 0x0000 -#define MII_BNX2_GP_TOP_AN_SPEED_100 0x0100 -#define MII_BNX2_GP_TOP_AN_SPEED_1G 0x0200 -#define MII_BNX2_GP_TOP_AN_SPEED_2_5G 0x0300 -#define MII_BNX2_GP_TOP_AN_SPEED_1GKV 0x0d00 -#define MII_BNX2_GP_TOP_AN_FD 0x8 -#define MII_BNX2_BLK_ADDR_SERDES_DIG 0x8300 -#define MII_BNX2_SERDES_DIG_1000XCTL1 0x10 -#define MII_BNX2_SD_1000XCTL1_FIBER 0x01 -#define MII_BNX2_SD_1000XCTL1_AUTODET 0x10 -#define MII_BNX2_SERDES_DIG_MISC1 0x18 -#define MII_BNX2_SD_MISC1_FORCE_MSK 0xf -#define MII_BNX2_SD_MISC1_FORCE_2_5G 0x0 -#define MII_BNX2_SD_MISC1_FORCE 0x10 -#define MII_BNX2_BLK_ADDR_OVER1G 0x8320 -#define MII_BNX2_OVER1G_UP1 0x19 -#define MII_BNX2_BLK_ADDR_BAM_NXTPG 0x8350 -#define MII_BNX2_BAM_NXTPG_CTL 0x10 -#define MII_BNX2_NXTPG_CTL_BAM 0x1 -#define MII_BNX2_NXTPG_CTL_T2 0x2 -#define MII_BNX2_BLK_ADDR_CL73_USERB0 0x8370 -#define MII_BNX2_CL73_BAM_CTL1 0x12 -#define MII_BNX2_CL73_BAM_EN 0x8000 -#define MII_BNX2_CL73_BAM_STA_MGR_EN 0x4000 -#define MII_BNX2_CL73_BAM_NP_AFT_BP_EN 0x2000 -#define MII_BNX2_BLK_ADDR_AER 0xffd0 -#define MII_BNX2_AER_AER 0x1e -#define MII_BNX2_AER_AER_AN_MMD 0x3800 -#define MII_BNX2_BLK_ADDR_COMBO_IEEEB0 0xffe0 - #define MIN_ETHERNET_PACKET_SIZE 60 #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 @@ -6468,15 +6429,13 @@ struct bnx2 { u32 last_status_idx; u32 flags; -#define PCIX_FLAG 0x00000001 -#define PCI_32BIT_FLAG 0x00000002 -#define ONE_TDMA_FLAG 0x00000004 /* no longer used */ -#define NO_WOL_FLAG 0x00000008 -#define USING_MSI_FLAG 0x00000020 -#define ASF_ENABLE_FLAG 0x00000040 -#define MSI_CAP_FLAG 0x00000080 -#define ONE_SHOT_MSI_FLAG 0x00000100 -#define PCIE_FLAG 0x00000200 +#define PCIX_FLAG 1 +#define PCI_32BIT_FLAG 2 +#define ONE_TDMA_FLAG 4 /* no longer used */ +#define NO_WOL_FLAG 8 +#define USING_DAC_FLAG 0x10 +#define USING_MSI_FLAG 0x20 +#define ASF_ENABLE_FLAG 0x40 /* Put tx producer and consumer fields in separate cache lines. */ @@ -6525,7 +6484,6 @@ struct bnx2 { /* Used to synchronize phy accesses. */ spinlock_t phy_lock; - spinlock_t indirect_lock; u32 phy_flags; #define PHY_SERDES_FLAG 1 @@ -6537,13 +6495,6 @@ struct bnx2 { #define PHY_INT_MODE_LINK_READY_FLAG 0x200 #define PHY_DIS_EARLY_DAC_FLAG 0x400 - u32 mii_bmcr; - u32 mii_bmsr; - u32 mii_bmsr1; - u32 mii_adv; - u32 mii_lpa; - u32 mii_up1; - u32 chip_id; /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ #define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000) @@ -6567,7 +6518,6 @@ struct bnx2 { #define CHIP_ID_5708_B0 0x57081000 #define CHIP_ID_5708_B1 0x57081010 #define CHIP_ID_5709_A0 0x57090000 -#define CHIP_ID_5709_A1 0x57090010 #define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0xf) diff --git a/trunk/drivers/net/bnx2_fw.h b/trunk/drivers/net/bnx2_fw.h index b49f439e0f67..21d368ff424d 100644 --- a/trunk/drivers/net/bnx2_fw.h +++ b/trunk/drivers/net/bnx2_fw.h @@ -15,1071 +15,680 @@ */ static u8 bnx2_COM_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a, - 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15, - 0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96, - 0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1, - 0x65, 0x6b, 0x4a, 0xa2, 0x6d, 0x05, 0x11, 0x02, 0x62, 0x49, 0xa9, 0x46, - 0x50, 0xb7, 0x92, 0xab, 0xb6, 0x81, 0x6b, 0x4b, 0x6b, 0x92, 0x6a, 0x09, - 0x84, 0xe6, 0x08, 0x11, 0x43, 0x19, 0xa9, 0x11, 0x10, 0xa4, 0x1c, 0xbb, - 0xc0, 0xb6, 0x2b, 0xbf, 0x05, 0x34, 0x2e, 0x15, 0x4a, 0x6e, 0xd4, 0x34, - 0x30, 0xfc, 0xa7, 0xa8, 0x51, 0x38, 0xad, 0xe1, 0x04, 0xa8, 0x9b, 0x16, - 0x45, 0xd0, 0xfc, 0x88, 0x0a, 0xdb, 0xd9, 0x7e, 0xdf, 0x9d, 0x3b, 0xcb, - 0xe1, 0x92, 0xd4, 0xc3, 0x8f, 0xfe, 0x28, 0x81, 0xe5, 0xcc, 0xbd, 0x73, - 0xe7, 0xde, 0x73, 0xcf, 0xe3, 0x3b, 0x8f, 0xb9, 0x77, 0x8a, 0x34, 0x88, - 0xfe, 0x5b, 0x8f, 0x5f, 0xf2, 0xd1, 0x3f, 0x18, 0xbe, 0xab, 0xe7, 0xae, - 0xbb, 0x71, 0x7b, 0xb7, 0x19, 0xb1, 0x22, 0xec, 0xe7, 0x3f, 0x07, 0xbf, - 0x6e, 0x7d, 0xbf, 0xda, 0x9f, 0x8d, 0xdf, 0x65, 0xfc, 0x86, 0x7e, 0x2e, - 0x62, 0xac, 0x31, 0x26, 0xfc, 0x57, 0xa9, 0x5c, 0xfd, 0xb9, 0x49, 0x5a, - 0xae, 0xf2, 0x3c, 0xe2, 0x2f, 0xa9, 0x68, 0xe6, 0x4f, 0x62, 0x66, 0x46, - 0x8e, 0xe7, 0x5c, 0x89, 0x45, 0x32, 0x1f, 0x1c, 0x1f, 0x76, 0x45, 0xb2, - 0xa5, 0x6d, 0xc9, 0xbc, 0x7c, 0x5c, 0x29, 0x3a, 0x96, 0xb0, 0xff, 0xd6, - 0xcc, 0x47, 0x27, 0xde, 0xd8, 0x91, 0xfa, 0xc5, 0x6c, 0x44, 0x62, 0x76, - 0xe6, 0x15, 0xb1, 0xb7, 0x4a, 0xac, 0x15, 0xef, 0x3c, 0xdb, 0x99, 0x33, - 0xa4, 0x29, 0x98, 0xeb, 0x83, 0xca, 0x1b, 0x9d, 0x52, 0xdc, 0x9c, 0x89, - 0x89, 0x99, 0xe9, 0x78, 0x27, 0x17, 0xb1, 0x87, 0x22, 0x19, 0x5b, 0x16, - 0xca, 0x32, 0x30, 0x32, 0x29, 0xb1, 0x58, 0x66, 0x22, 0x56, 0xdf, 0x21, - 0xb1, 0x68, 0x66, 0xe8, 0xf8, 0xf7, 0xdc, 0x13, 0x15, 0xd3, 0x75, 0x93, - 0xa3, 0x12, 0xef, 0x1d, 0xef, 0xc1, 0xf3, 0x52, 0x0a, 0x04, 0xef, 0x10, - 0xd3, 0x2d, 0xc6, 0x23, 0x6e, 0x4c, 0x72, 0x65, 0x57, 0xf2, 0x65, 0x91, - 0x1f, 0x96, 0x0c, 0x19, 0x77, 0x5b, 0x64, 0x74, 0xfb, 0x47, 0x95, 0x2c, - 0x68, 0xf9, 0x3b, 0x77, 0xe8, 0xf8, 0x73, 0x2e, 0xe9, 0x9d, 0x8e, 0xf9, - 0xf4, 0x8e, 0xd7, 0x0f, 0xbb, 0x96, 0xcc, 0x95, 0xd8, 0x77, 0xd0, 0x64, - 0x9f, 0x95, 0xf9, 0x7e, 0xc3, 0xb8, 0x1b, 0xd7, 0x7d, 0x13, 0xd9, 0x1c, - 0xe6, 0x9b, 0x2f, 0x71, 0xec, 0xbb, 0x5f, 0x18, 0x76, 0x1d, 0xdd, 0x9f, - 0xdd, 0x91, 0x73, 0x13, 0xe8, 0x6f, 0xd5, 0xcf, 0x9e, 0x79, 0x74, 0xd8, - 0x75, 0xf5, 0x33, 0xcb, 0xca, 0xb9, 0x5d, 0xba, 0xbf, 0xb4, 0x6b, 0xd8, - 0xdd, 0xae, 0xfb, 0x7f, 0xbc, 0x2b, 0xe7, 0xa6, 0x75, 0x7f, 0xef, 0x57, - 0x86, 0xdd, 0x1e, 0xdd, 0xff, 0xf6, 0xce, 0x9c, 0xdb, 0xab, 0xfb, 0x4f, - 0xf5, 0x0e, 0xbb, 0xb6, 0x9c, 0x2d, 0x25, 0xf1, 0x9b, 0x88, 0x59, 0x1d, - 0x19, 0x3d, 0xe6, 0x59, 0xd0, 0x9b, 0xc5, 0x98, 0x3e, 0xf4, 0xef, 0xc1, - 0xaf, 0x1f, 0xbf, 0xf2, 0x06, 0x69, 0x1a, 0xc0, 0xf3, 0x0f, 0xb7, 0xf8, - 0x3c, 0x04, 0xaf, 0xbc, 0x98, 0xbc, 0x17, 0x49, 0xc8, 0x1b, 0x9d, 0xef, - 0x81, 0x97, 0xb6, 0x9c, 0x2b, 0x8b, 0x31, 0xd0, 0x99, 0x00, 0x0f, 0x1d, - 0x79, 0xb1, 0xdc, 0x28, 0x91, 0x6f, 0x45, 0xc0, 0xa3, 0xaf, 0x4a, 0xc1, - 0x89, 0xc9, 0xc6, 0x19, 0x43, 0xda, 0xba, 0xd7, 0x49, 0xd6, 0x2e, 0x4a, - 0xbe, 0x13, 0x52, 0x9f, 0x72, 0xc4, 0x9a, 0x59, 0xdc, 0x68, 0xa2, 0xc7, - 0x94, 0x54, 0xa2, 0x80, 0x19, 0x47, 0xce, 0xbe, 0x4b, 0x1d, 0xa5, 0x7c, - 0xf1, 0x4b, 0x4a, 0x7e, 0xf2, 0x0e, 0x19, 0xb2, 0x49, 0xe7, 0x9f, 0xdd, - 0xea, 0xaf, 0x19, 0x33, 0x72, 0x67, 0x06, 0xe5, 0xa4, 0x17, 0x37, 0xf2, - 0x67, 0x76, 0x4a, 0x2e, 0x2d, 0x8e, 0x29, 0x1d, 0xea, 0xdd, 0xf9, 0xd2, - 0xa0, 0x8c, 0x7b, 0x62, 0xe4, 0x3c, 0x4b, 0x46, 0x4b, 0x2d, 0x78, 0xde, - 0xa4, 0xc6, 0xa2, 0xaf, 0x35, 0x22, 0x1d, 0x76, 0x5e, 0x62, 0xe8, 0xb7, - 0xd1, 0xdf, 0x6c, 0xf4, 0xa9, 0x39, 0x54, 0x7f, 0x72, 0x4c, 0xe2, 0xd8, - 0x9b, 0xa3, 0xc7, 0x56, 0x2a, 0xb9, 0xb4, 0x8d, 0x71, 0x83, 0x32, 0xe6, - 0x39, 0x32, 0x84, 0xeb, 0xa8, 0xc7, 0xf5, 0x13, 0xd0, 0xb1, 0xb7, 0x8e, - 0x17, 0xa6, 0xd5, 0x7c, 0xc9, 0x48, 0x86, 0xf3, 0xb5, 0x62, 0xdc, 0x05, - 0xd0, 0x65, 0x88, 0xa5, 0x64, 0x9b, 0x95, 0xc2, 0xa4, 0x21, 0xe4, 0x5b, - 0x41, 0xf1, 0xb0, 0x0f, 0xf4, 0x5b, 0xe2, 0x76, 0x1b, 0x32, 0xec, 0xde, - 0x2c, 0x45, 0x1b, 0xed, 0xd2, 0x79, 0x33, 0xe7, 0xd5, 0x4b, 0xde, 0x4a, - 0x62, 0xff, 0x94, 0xfd, 0x90, 0x8c, 0xe1, 0x1d, 0xd3, 0xe5, 0x98, 0x8f, - 0xb0, 0x77, 0xb4, 0xf1, 0x6e, 0x5d, 0xe6, 0xa0, 0x5c, 0x9a, 0x2c, 0x9a, - 0xb9, 0x72, 0x8b, 0x44, 0x66, 0x52, 0xd0, 0xfe, 0x71, 0x33, 0xff, 0xbc, - 0x25, 0xd1, 0x29, 0xea, 0x97, 0xd8, 0x91, 0xcc, 0x84, 0xb9, 0xbb, 0x7c, - 0xde, 0xcc, 0x97, 0xf9, 0x0e, 0xc6, 0x96, 0x4c, 0xf0, 0x96, 0xf7, 0xdb, - 0xc0, 0x4b, 0xea, 0x36, 0xdf, 0x81, 0x1c, 0xb0, 0x87, 0x17, 0x3d, 0xc8, - 0x45, 0xc9, 0x29, 0x09, 0x39, 0x89, 0xd1, 0xd7, 0x19, 0x93, 0xb1, 0x69, - 0x4b, 0x0a, 0xe9, 0x9b, 0x15, 0xe7, 0x0b, 0xe9, 0x25, 0x9a, 0x46, 0x27, - 0x6b, 0x69, 0xe2, 0x7b, 0xa4, 0xc9, 0xa7, 0x65, 0x6c, 0x9a, 0xb4, 0xf9, - 0xb4, 0x9c, 0x9c, 0x24, 0x8d, 0x5c, 0x87, 0xf4, 0x90, 0xae, 0x80, 0x26, - 0xbe, 0x43, 0x9a, 0x36, 0x61, 0x7e, 0x65, 0xc0, 0x46, 0x1f, 0x68, 0x18, - 0xf3, 0x2c, 0xc8, 0x26, 0x2e, 0x05, 0xbb, 0x68, 0x8c, 0xf5, 0x6e, 0x4b, - 0xc0, 0xaa, 0x8d, 0xd1, 0x5e, 0xd2, 0xeb, 0x42, 0x7e, 0x75, 0x4a, 0xce, - 0x66, 0x66, 0x9c, 0x3c, 0xc3, 0x78, 0xae, 0x8d, 0xfb, 0x92, 0x2d, 0xe3, - 0x6a, 0x3e, 0xd2, 0xf3, 0x59, 0xcc, 0x43, 0x7a, 0x2f, 0x43, 0x57, 0x7b, - 0xa0, 0xa3, 0x69, 0xf9, 0xdb, 0xf2, 0x76, 0x79, 0xbd, 0xdc, 0x25, 0xaf, - 0xc1, 0x7e, 0x5f, 0x2d, 0x27, 0xe5, 0x95, 0x72, 0xab, 0xbc, 0x5c, 0x4e, - 0xc8, 0x4b, 0x4a, 0x7f, 0xfb, 0x44, 0x9a, 0x94, 0x4e, 0xc7, 0x6e, 0x86, - 0x3e, 0xb6, 0x40, 0x1f, 0x9b, 0x61, 0x4f, 0x1b, 0x61, 0xab, 0xdf, 0x06, - 0x0f, 0xa7, 0x3b, 0x25, 0xbb, 0x09, 0xfd, 0xb7, 0x65, 0x2c, 0xa5, 0x23, - 0x16, 0x9e, 0x8f, 0x4d, 0x46, 0x25, 0x6f, 0x9f, 0x95, 0xf7, 0xa7, 0x2c, - 0x19, 0x2b, 0x3f, 0x79, 0x9b, 0xaf, 0xb3, 0x6c, 0xcf, 0xca, 0x45, 0xf4, - 0xe5, 0xed, 0x59, 0xb9, 0xb4, 0xd5, 0x94, 0xd1, 0xe9, 0xef, 0x4a, 0xee, - 0xf9, 0xb3, 0xf2, 0xd3, 0xbf, 0x16, 0x19, 0x00, 0xef, 0xcd, 0xee, 0xff, - 0xaa, 0x64, 0x6d, 0xec, 0xb1, 0x7b, 0xbb, 0x92, 0x89, 0xd9, 0x4d, 0x3d, - 0x4e, 0x02, 0x57, 0x2c, 0x23, 0xef, 0xbd, 0x00, 0x6c, 0x69, 0x34, 0x72, - 0xa7, 0x45, 0x86, 0x4f, 0x57, 0x64, 0x38, 0x1d, 0x95, 0xc7, 0xec, 0x8a, - 0xf4, 0xa5, 0xeb, 0xe4, 0xa8, 0x4d, 0xac, 0x39, 0x6e, 0x04, 0xb8, 0xfe, - 0xed, 0xf2, 0x09, 0xdc, 0xb3, 0x4f, 0x64, 0x5a, 0xdd, 0xfb, 0xfd, 0xc5, - 0x72, 0x54, 0xb2, 0x4e, 0x31, 0x61, 0x49, 0x9b, 0xe9, 0xd3, 0xf4, 0xcd, - 0xe0, 0x19, 0x78, 0x35, 0x04, 0x2c, 0xf5, 0xed, 0xaf, 0x30, 0xb9, 0xee, - 0x4a, 0x56, 0x75, 0x47, 0x29, 0x3b, 0xe8, 0x34, 0x79, 0x9d, 0x1c, 0x32, - 0x32, 0x8e, 0xb4, 0x29, 0xbc, 0xe8, 0xc1, 0x98, 0x5e, 0x63, 0x7f, 0x99, - 0x7a, 0x8e, 0xfb, 0x12, 0x69, 0xdd, 0x8c, 0xb1, 0x16, 0xae, 0x59, 0x4d, - 0x73, 0x98, 0x4e, 0xce, 0x45, 0x3a, 0x79, 0x7d, 0x21, 0x44, 0xe7, 0x5f, - 0x56, 0xef, 0xa7, 0x43, 0xf7, 0xc5, 0xf2, 0x0f, 0x1a, 0x7c, 0xfa, 0xc8, - 0xcf, 0x5e, 0xe8, 0xe3, 0x37, 0xf4, 0x5a, 0xb8, 0x2f, 0x71, 0x8d, 0xb3, - 0x15, 0x5f, 0xa7, 0x8a, 0xd7, 0x58, 0xeb, 0x62, 0x68, 0xad, 0x4b, 0xa1, - 0xb5, 0x2e, 0x85, 0xd6, 0x2a, 0x82, 0xb7, 0xb2, 0xc1, 0x74, 0xa3, 0xc0, - 0x27, 0xf6, 0x4c, 0x60, 0xce, 0x67, 0x21, 0x97, 0x9f, 0x60, 0x4c, 0x46, - 0x16, 0x3d, 0xf0, 0xe3, 0x74, 0x54, 0xf6, 0xa9, 0x67, 0xbd, 0x9a, 0xae, - 0xf0, 0xb3, 0x98, 0xec, 0x75, 0x78, 0x1f, 0x3c, 0xb3, 0xc0, 0x63, 0xb6, - 0xff, 0xe1, 0x16, 0xbf, 0xcd, 0xfb, 0xf3, 0x9a, 0xfe, 0x87, 0xfc, 0xf7, - 0xca, 0x1f, 0x28, 0x9c, 0x5c, 0x28, 0x13, 0xc7, 0x24, 0x1d, 0x71, 0xe5, - 0x48, 0x5f, 0x1a, 0x76, 0x65, 0x1b, 0xe9, 0xd1, 0xae, 0x7a, 0xf2, 0x3c, - 0x6b, 0xba, 0x8d, 0xc0, 0x0a, 0x49, 0x9a, 0xd0, 0xb3, 0x51, 0xb5, 0x97, - 0x75, 0xa6, 0x4f, 0xb3, 0xcd, 0xf6, 0x80, 0xe9, 0x36, 0xd7, 0xf4, 0xd3, - 0xde, 0x1b, 0x71, 0x4f, 0xdd, 0x7e, 0x4c, 0xcb, 0x37, 0x8e, 0x36, 0xf1, - 0xb9, 0x5f, 0xb7, 0x83, 0xe7, 0x39, 0x6b, 0x79, 0xfb, 0xed, 0x2d, 0xcb, - 0xdb, 0x01, 0x76, 0x84, 0xb1, 0x9d, 0x7b, 0x4d, 0x4a, 0xc4, 0xa5, 0xce, - 0x45, 0x41, 0x6b, 0x1a, 0xb6, 0x58, 0xaf, 0x69, 0xb8, 0x5d, 0xd3, 0x00, - 0x5a, 0x31, 0x6e, 0x54, 0xd9, 0x98, 0x12, 0x5f, 0x4d, 0x9b, 0xfc, 0x0e, - 0xee, 0xd7, 0xab, 0xe7, 0xbe, 0x2d, 0x06, 0x57, 0x31, 0x76, 0x77, 0x52, - 0xe6, 0x13, 0x90, 0x79, 0x5c, 0xe6, 0xa7, 0xc9, 0xb3, 0x54, 0xe2, 0x71, - 0x41, 0xbb, 0x94, 0x90, 0xb3, 0x93, 0x92, 0x3d, 0x7c, 0xaa, 0x57, 0xfa, - 0x60, 0x9f, 0x73, 0x93, 0x57, 0x2a, 0xe0, 0xdb, 0xbd, 0x75, 0xe2, 0x02, - 0x83, 0xe1, 0xef, 0x7b, 0xa2, 0x12, 0xc9, 0x64, 0xa0, 0x0b, 0x69, 0xe5, - 0x83, 0x97, 0xfe, 0x2c, 0xeb, 0xfe, 0x65, 0xed, 0x3a, 0xf8, 0x79, 0xcc, - 0xdb, 0x93, 0x56, 0x7a, 0x13, 0xfe, 0xcb, 0x01, 0x57, 0x72, 0xe9, 0x8f, - 0xa1, 0x5b, 0x01, 0x4d, 0x81, 0x6d, 0xd0, 0x07, 0x7d, 0x10, 0xf2, 0x6d, - 0xad, 0xc0, 0x17, 0x07, 0xf2, 0x0b, 0xfc, 0x11, 0xfd, 0x44, 0x82, 0x58, - 0x0e, 0x5b, 0xa0, 0x6f, 0x88, 0x8b, 0x39, 0x63, 0x69, 0xff, 0x11, 0xd3, - 0xfe, 0x23, 0x0e, 0xdf, 0xc1, 0xb6, 0xad, 0xdb, 0x8e, 0x6e, 0x27, 0xd0, - 0x46, 0xec, 0x31, 0x43, 0xbb, 0x7a, 0xeb, 0xf8, 0xc8, 0xb4, 0xf2, 0x49, - 0xf4, 0x67, 0xf0, 0x14, 0xf4, 0x29, 0xf4, 0x2d, 0xd8, 0x6f, 0x09, 0xeb, - 0x55, 0x31, 0x9c, 0xf2, 0x08, 0xd3, 0x43, 0x5a, 0xd6, 0x89, 0x09, 0x3f, - 0x9b, 0x75, 0x48, 0xef, 0x77, 0x20, 0x0f, 0x62, 0x25, 0xe9, 0xbe, 0x15, - 0xb4, 0x72, 0x3f, 0xff, 0x97, 0xb4, 0x72, 0xbd, 0x5a, 0x7a, 0x3f, 0x2d, - 0x66, 0x2b, 0xec, 0xc0, 0x9e, 0x33, 0xc0, 0x66, 0x31, 0xf6, 0x77, 0x0e, - 0x62, 0xcf, 0x03, 0xc0, 0xee, 0x7e, 0x60, 0xf7, 0x1e, 0x60, 0x77, 0x1f, - 0xb0, 0x3b, 0x0b, 0xec, 0xee, 0x05, 0x6e, 0xf7, 0x00, 0xb7, 0xd3, 0xe0, - 0x8d, 0x23, 0xb3, 0xc0, 0xf1, 0x59, 0xe8, 0xcb, 0x2c, 0xe6, 0x28, 0xcc, - 0x88, 0xf1, 0x35, 0xec, 0xe1, 0xe8, 0x54, 0x6a, 0x16, 0xfa, 0x9d, 0x18, - 0x32, 0xa1, 0x07, 0xe9, 0xbb, 0x61, 0x6f, 0x88, 0x9b, 0xca, 0x83, 0x32, - 0x0c, 0xbf, 0xdf, 0xb6, 0xb5, 0x1d, 0xfa, 0x84, 0x68, 0x24, 0x11, 0xe8, - 0x68, 0xbf, 0x14, 0xbc, 0x76, 0xbb, 0xcd, 0xec, 0x42, 0x5f, 0x2a, 0x89, - 0x18, 0xd5, 0x38, 0x74, 0x3a, 0x65, 0x8c, 0x9c, 0x26, 0x0f, 0x26, 0x81, - 0x83, 0x15, 0x19, 0x4f, 0x53, 0x4f, 0x2b, 0xf2, 0x5c, 0x3a, 0xd5, 0x5b, - 0x94, 0x46, 0x39, 0xe9, 0x4c, 0x2a, 0xdf, 0x6f, 0x65, 0x4e, 0x29, 0x1f, - 0x3a, 0xec, 0xe2, 0x5a, 0x6a, 0x33, 0x0a, 0xa7, 0xb9, 0xd7, 0x76, 0xfc, - 0xa2, 0x58, 0xf7, 0x57, 0x90, 0x91, 0x25, 0x7d, 0x3d, 0x62, 0x1c, 0xee, - 0x2c, 0x02, 0x39, 0x53, 0xf6, 0x22, 0x56, 0xcb, 0x4f, 0xb6, 0x27, 0xda, - 0x4d, 0x4b, 0x86, 0x2c, 0x43, 0x46, 0x61, 0x5f, 0x7d, 0xe9, 0xff, 0xa9, - 0x9c, 0x74, 0xf8, 0xbc, 0x5e, 0xfe, 0x5c, 0x61, 0x31, 0xd6, 0x9e, 0x9f, - 0xc6, 0xba, 0x51, 0xf0, 0x9b, 0xeb, 0x72, 0x1e, 0xb4, 0x81, 0x8b, 0x96, - 0x9b, 0x9a, 0x2d, 0xca, 0x2e, 0xd8, 0xe9, 0x06, 0xc9, 0x6d, 0xaf, 0x93, - 0xec, 0x40, 0x52, 0x0a, 0x53, 0xbb, 0x80, 0x8d, 0x31, 0x65, 0xab, 0x85, - 0xc1, 0xa4, 0x3c, 0x36, 0xc5, 0xbe, 0x2c, 0xf6, 0x9a, 0x3a, 0x95, 0x15, - 0xee, 0xd5, 0x90, 0xec, 0xc1, 0xac, 0x3c, 0xe6, 0x65, 0x65, 0x04, 0xf2, - 0x3a, 0x0b, 0x5e, 0x1e, 0xf2, 0x5c, 0x79, 0x0e, 0xbe, 0x26, 0x7f, 0x1a, - 0x58, 0xeb, 0xae, 0x07, 0x2e, 0xa6, 0xce, 0x31, 0xc6, 0x37, 0x19, 0x87, - 0x82, 0x97, 0x7f, 0x34, 0x45, 0x5e, 0x9a, 0x32, 0x7d, 0xaf, 0x01, 0x3c, - 0x48, 0x82, 0x77, 0xae, 0xfc, 0xb1, 0x97, 0x3a, 0x9f, 0x35, 0x81, 0xc5, - 0xe9, 0xde, 0x88, 0x34, 0x24, 0x30, 0xce, 0x1f, 0x93, 0x4f, 0x47, 0x20, - 0xd7, 0x22, 0xc6, 0xa6, 0xd0, 0xcf, 0x77, 0x1d, 0xfc, 0xb2, 0x18, 0x07, - 0x5d, 0xb5, 0x53, 0xe7, 0x67, 0x4d, 0x8e, 0x4f, 0x42, 0x3e, 0x36, 0xc6, - 0x03, 0xf8, 0x6c, 0xde, 0xa7, 0x8d, 0x02, 0x69, 0xf0, 0xa8, 0x53, 0x88, - 0x49, 0xcb, 0xc4, 0xd4, 0xf6, 0x73, 0xaf, 0x0b, 0xd7, 0xf9, 0x22, 0xc6, - 0x7f, 0x88, 0x38, 0xdc, 0x96, 0x79, 0xc8, 0xe5, 0xa7, 0xe0, 0x55, 0x36, - 0xe1, 0xb7, 0x0b, 0x33, 0xa9, 0x73, 0x8b, 0x26, 0xef, 0xdd, 0xe2, 0xa8, - 0xd9, 0x23, 0xd2, 0x4c, 0x7e, 0xa5, 0xc1, 0x2b, 0xd7, 0x36, 0xcd, 0xb4, - 0xf2, 0x65, 0xbe, 0x2d, 0xdf, 0x05, 0x9a, 0xa0, 0xf3, 0xdd, 0x61, 0x9b, - 0xa0, 0xaf, 0x0d, 0x6c, 0x22, 0x95, 0x98, 0x35, 0xe1, 0x9f, 0xbb, 0x2d, - 0x39, 0xa5, 0xda, 0xe0, 0xd1, 0x60, 0x2a, 0x91, 0x35, 0x11, 0x33, 0x95, - 0xba, 0xe4, 0xac, 0xc7, 0xf1, 0x49, 0x85, 0x51, 0xfe, 0x78, 0xc4, 0x7a, - 0x1e, 0xe3, 0xc5, 0x2e, 0xd0, 0xec, 0xdb, 0xc9, 0xdc, 0xa4, 0xa3, 0x9e, - 0x9d, 0xf4, 0xfc, 0xb8, 0xd0, 0x44, 0xec, 0x38, 0x8b, 0xd8, 0x31, 0xaf, - 0x6c, 0xc6, 0xce, 0x22, 0xd7, 0x80, 0xce, 0xfb, 0xf6, 0x32, 0x5f, 0xba, - 0x4f, 0x86, 0xcf, 0x7c, 0x3f, 0x6e, 0x22, 0xce, 0x2a, 0x38, 0xa4, 0x8b, - 0xe3, 0xcf, 0x81, 0x4e, 0xf2, 0x4e, 0x86, 0x18, 0x57, 0x21, 0x16, 0x7e, - 0x84, 0x32, 0x1e, 0xed, 0x7e, 0x88, 0x7c, 0x2b, 0x82, 0xe8, 0x53, 0x3e, - 0x8e, 0x49, 0x91, 0x71, 0xe8, 0x62, 0xe4, 0x09, 0x19, 0x9a, 0xa7, 0x2f, - 0xc4, 0xcf, 0x23, 0x26, 0x02, 0xc7, 0x94, 0xcf, 0x6a, 0x87, 0x3e, 0x14, - 0xc1, 0xef, 0x8d, 0x3a, 0x0e, 0x3b, 0x08, 0xf9, 0xf6, 0x43, 0xfe, 0x19, - 0x19, 0x39, 0x33, 0x42, 0xdd, 0xee, 0x9a, 0x97, 0x54, 0xd7, 0x49, 0xd9, - 0x66, 0xcf, 0xc1, 0x06, 0xb3, 0x83, 0x95, 0x5d, 0x66, 0x86, 0xef, 0x9c, - 0xc0, 0x3b, 0xb8, 0xce, 0x8f, 0xc8, 0xd1, 0x32, 0xfb, 0x9e, 0x05, 0xdf, - 0x11, 0x17, 0xf7, 0x1c, 0xd4, 0xf6, 0x80, 0xf9, 0xac, 0x60, 0xbe, 0x11, - 0x3d, 0x1f, 0xc7, 0x71, 0x0c, 0xdf, 0x59, 0x9a, 0x77, 0x37, 0x7d, 0x22, - 0x30, 0xa8, 0xc3, 0xac, 0xec, 0x8a, 0xe2, 0xf9, 0x73, 0x3d, 0xbc, 0xc7, - 0x3c, 0xf0, 0x89, 0xb6, 0xdb, 0x8f, 0xb1, 0x83, 0x98, 0x73, 0x9d, 0xb4, - 0xb5, 0x04, 0xf4, 0x52, 0x3f, 0x18, 0xab, 0xb0, 0x3d, 0xb2, 0xc9, 0x97, - 0xd1, 0xab, 0x11, 0xdf, 0xc7, 0xcc, 0xa2, 0x4d, 0x3b, 0x3c, 0x26, 0x79, - 0x2f, 0x85, 0x7d, 0x42, 0x06, 0xe5, 0x51, 0xbd, 0x47, 0xc8, 0x69, 0xe0, - 0x29, 0xf0, 0x41, 0x8a, 0x3e, 0x6f, 0xc8, 0x17, 0xf2, 0xe4, 0x38, 0x6c, - 0xe0, 0x71, 0x8c, 0x41, 0xbc, 0xab, 0x78, 0x60, 0x6f, 0xf2, 0xe3, 0xf5, - 0x54, 0x31, 0xcb, 0xbc, 0xb3, 0x99, 0xba, 0x0d, 0xdc, 0x2a, 0x0f, 0xd8, - 0x9c, 0x7b, 0xd6, 0x64, 0x7e, 0x92, 0x4a, 0x5e, 0x88, 0xec, 0x67, 0xbb, - 0x6b, 0xd6, 0x84, 0x8c, 0x20, 0xc7, 0xdc, 0xf6, 0x76, 0x8d, 0x55, 0xef, - 0x28, 0x5d, 0xa6, 0xde, 0x17, 0xbc, 0x6d, 0xf6, 0x43, 0x42, 0x5d, 0x76, - 0xa0, 0x17, 0xc4, 0x0b, 0x5e, 0x2d, 0xf8, 0xee, 0x04, 0x74, 0x61, 0xbd, - 0xa6, 0x9d, 0xf7, 0x96, 0xcc, 0xda, 0x58, 0xc3, 0xfb, 0x8f, 0x0d, 0x7e, - 0x1f, 0xef, 0x19, 0x33, 0x05, 0x72, 0x0c, 0x68, 0xa5, 0x3c, 0x6b, 0x65, - 0xf8, 0x24, 0x68, 0x67, 0x3f, 0xae, 0xf3, 0xc7, 0x60, 0xa7, 0xc0, 0x94, - 0x9e, 0x8e, 0xc4, 0x45, 0x8c, 0xcf, 0x03, 0xf7, 0x8b, 0x16, 0x9f, 0x5d, - 0x31, 0x96, 0xde, 0x31, 0x19, 0x27, 0x23, 0x1e, 0xbf, 0x60, 0x7c, 0x0d, - 0xb1, 0x4e, 0x6e, 0xfe, 0x8a, 0x91, 0x87, 0x5e, 0xcc, 0x7b, 0x77, 0x43, - 0x9f, 0x68, 0x57, 0x36, 0xd6, 0x4e, 0x25, 0xfe, 0xc9, 0x6c, 0x4f, 0xce, - 0x01, 0x03, 0x0e, 0x81, 0xb1, 0xbe, 0x2c, 0x5d, 0x25, 0xdb, 0x45, 0x33, - 0xaa, 0xf1, 0x8f, 0xed, 0x94, 0xfd, 0xb0, 0xc0, 0x58, 0x1a, 0xf6, 0x80, - 0xcf, 0x7b, 0x64, 0xb8, 0x9c, 0x91, 0xc2, 0x99, 0x6d, 0xf6, 0x28, 0x72, - 0xf5, 0x25, 0xda, 0x89, 0x75, 0x45, 0x60, 0x1d, 0xfc, 0xb7, 0x27, 0xc5, - 0xba, 0x0c, 0x31, 0xaf, 0x03, 0xfa, 0x84, 0xbe, 0xd2, 0x92, 0x4e, 0xde, - 0xbf, 0x62, 0x3f, 0xf4, 0xdb, 0xcb, 0xf7, 0x34, 0x2f, 0xd7, 0xde, 0xd3, - 0xee, 0xea, 0x9e, 0x88, 0x31, 0xf0, 0x03, 0x1e, 0xfc, 0x00, 0x74, 0xfa, - 0x75, 0x0f, 0x7e, 0xc0, 0x83, 0x1f, 0x80, 0x3d, 0xbe, 0x02, 0x7d, 0x7c, - 0xd9, 0x83, 0x2f, 0xf0, 0xe0, 0x0b, 0x3c, 0xf8, 0x02, 0x2f, 0x07, 0xd9, - 0x11, 0xef, 0xe9, 0x4b, 0x0e, 0x54, 0xfd, 0xa7, 0x1f, 0x83, 0xdd, 0xa2, - 0xe3, 0x1a, 0xd8, 0xae, 0xbd, 0x59, 0x46, 0xbb, 0x98, 0x13, 0x35, 0xe0, - 0xda, 0x88, 0x2b, 0x62, 0x98, 0xae, 0x2f, 0x69, 0xdb, 0x79, 0x1c, 0x74, - 0x01, 0x17, 0xba, 0xbe, 0x08, 0xdd, 0x44, 0x1c, 0xe1, 0xfe, 0x86, 0x8e, - 0x7f, 0x7e, 0x64, 0xf9, 0xba, 0xd9, 0x88, 0xbe, 0xfb, 0xd0, 0xd7, 0x88, - 0x31, 0x47, 0x31, 0x86, 0xf1, 0x53, 0x93, 0xee, 0x0b, 0x8f, 0x63, 0x1c, - 0xf5, 0x00, 0xd6, 0x4a, 0x61, 0x5c, 0x13, 0xe6, 0x6e, 0xc5, 0x98, 0x9d, - 0x18, 0x73, 0x2b, 0xda, 0x8c, 0xb9, 0xb7, 0xa0, 0x7d, 0x4f, 0xcd, 0x3b, - 0xb7, 0xa3, 0xef, 0x4b, 0x35, 0x7d, 0x8b, 0xe8, 0xeb, 0x41, 0xdf, 0x45, - 0xfd, 0x5e, 0x11, 0xed, 0x96, 0x9a, 0x31, 0x97, 0xd1, 0x87, 0xb8, 0xd9, - 0xfe, 0x7b, 0x5c, 0xfb, 0x71, 0x25, 0x4d, 0xc1, 0x33, 0xc6, 0xcd, 0xc8, - 0x41, 0xab, 0xb1, 0xef, 0x5b, 0x8c, 0x0b, 0xe1, 0x7b, 0x7f, 0x6c, 0xf9, - 0x71, 0xe3, 0x77, 0x6d, 0x5f, 0x57, 0x83, 0xf6, 0x8f, 0x6a, 0xda, 0x1c, - 0xfb, 0xdf, 0x35, 0x7d, 0x3b, 0x36, 0x2e, 0x6f, 0xdf, 0x59, 0xb7, 0xf2, - 0x9d, 0x89, 0x9a, 0x31, 0x2f, 0x37, 0x2f, 0x6f, 0xff, 0xe9, 0x2a, 0xef, - 0xec, 0xd9, 0xb0, 0xbc, 0xef, 0xd1, 0x4d, 0x35, 0x63, 0xa0, 0x53, 0x0e, - 0x72, 0xab, 0x60, 0xfc, 0x03, 0x37, 0xf9, 0xcf, 0xc9, 0xdf, 0x5a, 0x5d, - 0x52, 0x5b, 0x47, 0xdb, 0x84, 0x1c, 0x2e, 0x18, 0xb0, 0x39, 0xdb, 0xcc, - 0x5c, 0x32, 0xf2, 0xd0, 0xa9, 0x5c, 0x39, 0x98, 0x8f, 0xb6, 0x5c, 0x5b, - 0xdb, 0x08, 0x6a, 0x1a, 0x8c, 0xbb, 0xe2, 0xd0, 0x9b, 0xfd, 0x90, 0x71, - 0x6a, 0xa2, 0x28, 0x4b, 0x36, 0xdc, 0x66, 0xae, 0x65, 0xc3, 0x4f, 0x6b, - 0xdc, 0x7a, 0x0a, 0x74, 0x56, 0x64, 0x20, 0x5d, 0x4f, 0xff, 0xa4, 0xf1, - 0x8c, 0x58, 0x54, 0xa9, 0x44, 0xb6, 0x56, 0xe4, 0x48, 0xfa, 0xc3, 0x8a, - 0x28, 0x1c, 0x9c, 0x50, 0x58, 0x94, 0x34, 0xdb, 0x21, 0x23, 0x1b, 0xb9, - 0x8d, 0x23, 0x43, 0x0e, 0xfd, 0xd9, 0x31, 0xc6, 0x29, 0x27, 0x7c, 0x9c, - 0x25, 0x16, 0xa1, 0x8d, 0xbc, 0xae, 0x70, 0xda, 0x50, 0x31, 0x70, 0x61, - 0x9e, 0xd8, 0x4e, 0x3c, 0x85, 0xdf, 0xb6, 0x39, 0xef, 0x6a, 0x78, 0x19, - 0x8b, 0x32, 0x3e, 0xb4, 0xdc, 0x17, 0xe0, 0x1b, 0xf9, 0x8c, 0x71, 0x04, - 0xee, 0x4b, 0xaa, 0xae, 0x56, 0x5c, 0xbe, 0x97, 0xcd, 0xcc, 0x43, 0xae, - 0x63, 0x7f, 0xab, 0x63, 0x54, 0xbb, 0x79, 0x6d, 0x7b, 0xde, 0x5b, 0xb5, - 0xe7, 0x40, 0xdf, 0x56, 0xab, 0x59, 0xbc, 0xa3, 0xf8, 0xff, 0x52, 0x39, - 0x75, 0xaa, 0x08, 0xfb, 0x59, 0x50, 0x39, 0x7a, 0x20, 0x0b, 0xc6, 0x3c, - 0xa9, 0x67, 0x66, 0xe9, 0x2d, 0x54, 0x8e, 0xc2, 0xfc, 0xa4, 0x22, 0xbb, - 0xd3, 0xff, 0xa6, 0xf6, 0x9e, 0x35, 0x3b, 0xeb, 0x18, 0x63, 0x2c, 0x78, - 0xe4, 0x53, 0x1a, 0xcf, 0x11, 0xfb, 0xa7, 0x7f, 0x26, 0x79, 0x87, 0x7d, - 0xbf, 0xac, 0xcc, 0x21, 0x36, 0x52, 0xf1, 0x92, 0x8a, 0x0f, 0x18, 0xef, - 0x1d, 0x01, 0x8f, 0xc8, 0xc7, 0x01, 0xf0, 0x36, 0x88, 0x19, 0xfe, 0x91, - 0xbe, 0x58, 0x96, 0xc7, 0xd1, 0xc8, 0xb4, 0x4a, 0x97, 0x30, 0xa7, 0x89, - 0xf9, 0xe8, 0xe3, 0xe8, 0x47, 0xd8, 0x5f, 0x88, 0x32, 0xb6, 0xf3, 0x63, - 0x83, 0x08, 0xd6, 0xb3, 0x80, 0x83, 0xef, 0x0a, 0x63, 0x9a, 0x61, 0x25, - 0x03, 0x62, 0x29, 0x9f, 0xb1, 0x2f, 0xa6, 0x63, 0xef, 0xb8, 0x8e, 0xb5, - 0x6d, 0x1d, 0x6b, 0x93, 0x0e, 0xd6, 0x2d, 0x83, 0x38, 0x82, 0x72, 0xba, - 0x70, 0xdc, 0xdc, 0xca, 0x38, 0xa2, 0x49, 0x56, 0x8f, 0x23, 0x02, 0x9a, - 0x76, 0x82, 0x26, 0xc6, 0x7d, 0xaa, 0x4e, 0xd5, 0xec, 0xd7, 0xc6, 0x48, - 0x43, 0xe0, 0x27, 0x95, 0x3f, 0x9e, 0x80, 0xeb, 0xc3, 0xde, 0x10, 0x48, - 0x02, 0xdb, 0x73, 0x93, 0x3b, 0xb5, 0xdf, 0x65, 0x0e, 0xc1, 0xf8, 0xdd, - 0xd7, 0xd3, 0x5c, 0x7a, 0x34, 0x98, 0xa7, 0x05, 0x9e, 0x32, 0x54, 0x43, - 0xe3, 0x5a, 0x8c, 0x7b, 0x82, 0x18, 0x68, 0x8f, 0x8e, 0x81, 0xfa, 0xe5, - 0x88, 0xe7, 0xe7, 0x0c, 0x03, 0xa5, 0x01, 0xf4, 0x29, 0xda, 0x13, 0x8c, - 0x35, 0x4d, 0x93, 0xb1, 0x66, 0x0a, 0xc9, 0x87, 0xbf, 0x97, 0xb6, 0xad, - 0xac, 0x65, 0x06, 0x7b, 0x69, 0xbc, 0xb0, 0x7c, 0x2f, 0xbb, 0x94, 0xde, - 0x9b, 0xe0, 0x9d, 0x8f, 0x4d, 0x9c, 0xf3, 0x7c, 0x94, 0xb8, 0x35, 0x50, - 0x1a, 0x54, 0xf3, 0x8e, 0xaf, 0x98, 0x57, 0xb0, 0xc7, 0x03, 0x6b, 0x3c, - 0xe3, 0xfe, 0x19, 0x5b, 0xd8, 0x7a, 0xff, 0x81, 0x0c, 0x2f, 0x63, 0xce, - 0x2e, 0xa3, 0xa0, 0xe2, 0xb6, 0x83, 0x4a, 0x1e, 0x85, 0xd2, 0x10, 0xae, - 0xb4, 0x17, 0x35, 0x8f, 0xb2, 0x99, 0x51, 0x25, 0x83, 0x11, 0xb5, 0xc7, - 0xb9, 0xd2, 0x23, 0x88, 0xd7, 0xbe, 0x0e, 0x3f, 0x18, 0xae, 0x2b, 0x3a, - 0x18, 0x43, 0x5e, 0x15, 0x43, 0x78, 0x4a, 0x9a, 0x59, 0x33, 0xbc, 0x82, - 0x35, 0xb8, 0xe7, 0x38, 0xe4, 0x6f, 0xf8, 0xcf, 0xd5, 0xfa, 0x01, 0xcf, - 0xeb, 0x42, 0xf4, 0x54, 0x10, 0xbf, 0x26, 0x40, 0x43, 0xf8, 0x9d, 0x63, - 0xd2, 0xe7, 0x51, 0x56, 0xed, 0x89, 0x11, 0xe4, 0xbb, 0x05, 0x09, 0x62, - 0x11, 0xae, 0x4f, 0x0c, 0xc8, 0x23, 0x97, 0x4a, 0x60, 0x7f, 0x01, 0x5f, - 0x03, 0x9e, 0xc6, 0x2f, 0xd4, 0xea, 0xc7, 0x38, 0xe8, 0x19, 0xf6, 0xc8, - 0xa7, 0x40, 0x6f, 0x83, 0xb5, 0x2f, 0xab, 0xfd, 0x8c, 0xa9, 0xda, 0xe7, - 0xfa, 0xba, 0x40, 0x7f, 0x47, 0x11, 0xb7, 0xf8, 0xfa, 0xf8, 0x7b, 0x9a, - 0x37, 0x81, 0xde, 0xc6, 0xb5, 0x0e, 0x30, 0x47, 0xa4, 0x5d, 0x05, 0x3a, - 0xd2, 0x61, 0xef, 0x57, 0xbc, 0xe0, 0x33, 0x95, 0x13, 0x2a, 0x39, 0x0f, - 0x55, 0xe5, 0xbc, 0xbe, 0x46, 0x67, 0x3b, 0x6d, 0xdf, 0x46, 0x69, 0x8b, - 0xb0, 0x69, 0xd0, 0xf7, 0xd2, 0x32, 0xdb, 0xef, 0x5a, 0xa3, 0xae, 0x1c, - 0x97, 0xc8, 0xcc, 0x0f, 0xc0, 0xcb, 0xdb, 0x91, 0xd7, 0x20, 0xcb, 0x9f, - 0x22, 0x46, 0x31, 0xfe, 0x58, 0x8a, 0x89, 0xe7, 0x64, 0xb5, 0x78, 0xf8, - 0x5a, 0xb1, 0xc7, 0x9d, 0xd7, 0x19, 0x7b, 0xfc, 0x49, 0x1d, 0xf3, 0x9c, - 0x05, 0xd8, 0xe9, 0x21, 0xbc, 0x5f, 0xe7, 0xfe, 0x10, 0x3e, 0xed, 0xaf, - 0xac, 0x7a, 0x37, 0xc0, 0x8b, 0xb8, 0x6c, 0x9c, 0xd9, 0xac, 0x30, 0xc3, - 0x9e, 0x5a, 0xc2, 0x8c, 0x51, 0xcf, 0xd7, 0x5f, 0xf0, 0xca, 0xd9, 0x28, - 0xd7, 0x9b, 0x77, 0x2f, 0xe5, 0x10, 0x43, 0xd5, 0x1c, 0xe2, 0x96, 0x1a, - 0x3e, 0xae, 0x86, 0x99, 0xe7, 0x54, 0xbe, 0xfc, 0x6a, 0x39, 0xf5, 0x82, - 0x48, 0x1f, 0xf2, 0xe4, 0xd4, 0x79, 0x91, 0x2c, 0x72, 0x65, 0xe6, 0x73, - 0x7b, 0x90, 0x3b, 0xa7, 0x7e, 0x21, 0xd2, 0x8b, 0x9c, 0x99, 0xf9, 0x70, - 0x3f, 0xf8, 0xda, 0x03, 0x4c, 0x4d, 0x03, 0x63, 0xb7, 0x83, 0xbf, 0x5d, - 0x0a, 0x57, 0x0f, 0x9d, 0x46, 0xae, 0xad, 0xea, 0xec, 0xb4, 0x75, 0x07, - 0x7e, 0xb5, 0x52, 0x79, 0x2c, 0xdd, 0x8e, 0x7c, 0x3f, 0x29, 0x5f, 0xb6, - 0x98, 0xf3, 0x1a, 0x56, 0xae, 0x7b, 0x26, 0x12, 0x8e, 0x63, 0x0b, 0xd7, - 0xf4, 0x11, 0x2b, 0x79, 0x3f, 0xac, 0xfc, 0xc4, 0x78, 0xe4, 0x6a, 0xbc, - 0xdf, 0x5f, 0xe5, 0xfd, 0x9d, 0x0d, 0xd2, 0xd0, 0xaf, 0xea, 0x0b, 0xb9, - 0xee, 0xaf, 0x13, 0xcb, 0xd2, 0xf0, 0xf3, 0xf0, 0xc7, 0x15, 0xb9, 0x3f, - 0x7d, 0xa5, 0x72, 0xd1, 0xdd, 0x20, 0x85, 0xed, 0x07, 0x34, 0x9e, 0x1f, - 0x78, 0x32, 0xe7, 0x16, 0x61, 0x1f, 0xfa, 0xdb, 0xc2, 0x64, 0x0c, 0x51, - 0x29, 0xff, 0x9a, 0x65, 0xae, 0xf7, 0xf6, 0x7a, 0x69, 0xd8, 0xf6, 0x02, - 0x8b, 0x63, 0xc4, 0x99, 0x39, 0x27, 0xae, 0xea, 0xdd, 0x37, 0xb9, 0xec, - 0xb7, 0x21, 0xd3, 0xdf, 0x92, 0x39, 0xc4, 0x13, 0xf3, 0xbd, 0xa0, 0x71, - 0x7b, 0x0b, 0xc6, 0xd3, 0xee, 0xc8, 0xf3, 0xdf, 0x96, 0xa1, 0x41, 0xf2, - 0xd4, 0xc1, 0xf8, 0xfb, 0x31, 0xa6, 0x19, 0xd7, 0x07, 0x23, 0x73, 0x76, - 0xcc, 0x6f, 0x0f, 0x70, 0x0e, 0xfa, 0x52, 0xce, 0xc3, 0xb5, 0x5a, 0x94, - 0xcd, 0x2f, 0xcd, 0xcf, 0xb9, 0xf9, 0xec, 0xe3, 0xca, 0xbe, 0xee, 0xee, - 0xd0, 0x1a, 0x4d, 0xa1, 0x35, 0x7a, 0x42, 0x6b, 0x90, 0xb6, 0xe6, 0x10, - 0x6d, 0xcd, 0x78, 0xff, 0x3e, 0xac, 0xd7, 0xaf, 0xe3, 0x94, 0x60, 0x9d, - 0x60, 0x1f, 0x2d, 0xa1, 0xb1, 0x1f, 0x62, 0x0d, 0xf6, 0x39, 0xa1, 0x3e, - 0xae, 0x0b, 0x1c, 0x73, 0xd8, 0x6e, 0x0e, 0xd1, 0x42, 0xfa, 0x1a, 0xd0, - 0xaf, 0xe6, 0x02, 0x3f, 0x1b, 0xe0, 0xbb, 0x4c, 0xf8, 0x8f, 0x08, 0xe2, - 0xaa, 0x60, 0x4f, 0xc1, 0x1c, 0x0e, 0xde, 0xe3, 0x18, 0xff, 0xb9, 0xff, - 0x0e, 0xfb, 0xf9, 0x3c, 0x22, 0xdf, 0x53, 0xf4, 0xb2, 0xcd, 0x3d, 0x34, - 0x81, 0x56, 0x5e, 0x53, 0x32, 0xdb, 0x0c, 0xd9, 0x77, 0x33, 0x9f, 0x36, - 0xe4, 0x36, 0xd7, 0x34, 0xf2, 0xdd, 0x94, 0xef, 0x06, 0x8d, 0x97, 0x0d, - 0x46, 0xee, 0x34, 0x6b, 0x08, 0x8d, 0x3a, 0xf7, 0x43, 0xbe, 0xa1, 0x7c, - 0x4c, 0xe0, 0x03, 0xe8, 0x63, 0x18, 0xab, 0xd0, 0x7f, 0x66, 0xf5, 0x3d, - 0xae, 0xd0, 0xd3, 0xc3, 0xf3, 0xcd, 0x72, 0x51, 0xf1, 0xd0, 0x96, 0xc5, - 0x2a, 0x0f, 0xa3, 0xfa, 0xbb, 0xd1, 0x31, 0xfd, 0x4d, 0x66, 0x3f, 0xe2, - 0x01, 0xdc, 0x97, 0x80, 0xb9, 0xdd, 0xd0, 0xb7, 0x6e, 0xe6, 0x70, 0x45, - 0x5c, 0x59, 0xc3, 0x30, 0x70, 0x75, 0x70, 0x8d, 0xe1, 0x0a, 0xbf, 0x04, - 0xac, 0xc9, 0x77, 0xbf, 0x0d, 0x1d, 0x82, 0x6c, 0xca, 0xb6, 0x71, 0xbf, - 0xe7, 0xd7, 0x87, 0x16, 0xdd, 0xd5, 0xeb, 0x43, 0x8b, 0xa2, 0xea, 0x43, - 0x13, 0xd7, 0xa8, 0x0f, 0x65, 0xaf, 0xbf, 0x3e, 0x74, 0xa2, 0x9e, 0x18, - 0xbc, 0xb7, 0x47, 0x8c, 0xdf, 0xd5, 0xf5, 0xa1, 0xf7, 0xc5, 0xaf, 0x0f, - 0x5d, 0x94, 0xd5, 0xeb, 0x43, 0x13, 0x35, 0xf5, 0xa1, 0x8d, 0xaa, 0x3e, - 0xc4, 0x79, 0xfc, 0xfa, 0x10, 0xdb, 0x6d, 0xdd, 0xbd, 0xa1, 0x3a, 0x08, - 0xf0, 0x54, 0xe5, 0x84, 0xb6, 0x31, 0xe8, 0x05, 0x18, 0x45, 0x2c, 0xbf, - 0xb9, 0xea, 0x8f, 0x96, 0xf0, 0xca, 0x50, 0xba, 0x75, 0x2d, 0xbc, 0x1a, - 0xf4, 0x63, 0x90, 0x65, 0x58, 0x35, 0x5e, 0x8d, 0x53, 0x5e, 0xab, 0x67, - 0xde, 0x3c, 0x56, 0x5a, 0x9a, 0x77, 0x0c, 0xb2, 0x1d, 0xaa, 0xd6, 0x50, - 0xd6, 0x8a, 0x85, 0x1c, 0x39, 0xb6, 0xea, 0x37, 0xb8, 0x44, 0x76, 0xe5, - 0x37, 0x38, 0x43, 0x1c, 0xd0, 0xd9, 0xd6, 0x5d, 0x50, 0x79, 0xd5, 0x9c, - 0xf7, 0x55, 0xb9, 0xf0, 0xb0, 0x0d, 0x3c, 0x09, 0x6a, 0x26, 0x94, 0xe5, - 0x92, 0x8f, 0x28, 0x98, 0x9f, 0x5f, 0xdd, 0xe4, 0xb0, 0xaa, 0x9b, 0xfc, - 0xbc, 0x3e, 0x5c, 0x37, 0x59, 0x94, 0xab, 0xd7, 0x4d, 0x0e, 0xaf, 0x52, - 0x37, 0x79, 0x53, 0x96, 0xea, 0x26, 0x6f, 0x4a, 0x50, 0x37, 0x89, 0xc8, - 0x85, 0x4d, 0x9c, 0xe7, 0x08, 0xde, 0x19, 0xc0, 0xaf, 0x1f, 0x3f, 0xbf, - 0x8e, 0xb2, 0x58, 0xa5, 0x7f, 0xb5, 0x3a, 0x4a, 0x7d, 0xec, 0x93, 0xd4, - 0x51, 0x7c, 0x4c, 0x0f, 0xea, 0x28, 0x0d, 0x88, 0x5f, 0xe0, 0x43, 0xcc, - 0x70, 0x1d, 0xa5, 0x15, 0xf3, 0xb2, 0x8f, 0x6d, 0xf6, 0xc3, 0x2e, 0xe0, - 0x67, 0xb2, 0xaa, 0xce, 0xf1, 0x9b, 0x9a, 0x87, 0x07, 0xb0, 0xe7, 0x24, - 0x64, 0x41, 0x3e, 0xb6, 0xab, 0x38, 0x32, 0x6b, 0x25, 0x8c, 0x5c, 0x27, - 0xbc, 0xd3, 0x24, 0xbf, 0xd9, 0x27, 0x64, 0xa4, 0x4c, 0x1d, 0x6f, 0x45, - 0xdc, 0x6d, 0xa1, 0xef, 0x00, 0xda, 0x41, 0x8c, 0xd4, 0x5d, 0x9d, 0x83, - 0x76, 0x38, 0xc7, 0x7a, 0x9f, 0x73, 0x3d, 0x3e, 0x67, 0x27, 0x68, 0x0e, - 0xef, 0xa3, 0x08, 0x7f, 0x83, 0x3e, 0x25, 0x73, 0xc6, 0x8a, 0x01, 0x2d, - 0x49, 0xda, 0xf4, 0x75, 0xcc, 0xc7, 0xbe, 0x9d, 0x2a, 0xdf, 0x1a, 0xee, - 0xe1, 0x5e, 0xe9, 0xbb, 0x16, 0x40, 0x1f, 0xfa, 0xe6, 0x99, 0xe3, 0xd1, - 0x8f, 0x05, 0x39, 0x58, 0x5c, 0xe5, 0x60, 0x2d, 0x8a, 0x1f, 0xe4, 0xf5, - 0x23, 0x31, 0xe2, 0x63, 0x8b, 0xcb, 0x3d, 0xf4, 0x6b, 0x5c, 0x63, 0xdb, - 0xcf, 0xf5, 0x58, 0x8f, 0x6e, 0x71, 0x9f, 0x80, 0x5c, 0x59, 0xab, 0x09, - 0xe4, 0xf7, 0x0d, 0xbd, 0xef, 0x5e, 0x29, 0xb6, 0x48, 0x6c, 0x23, 0xe8, - 0x69, 0x9b, 0x62, 0x8c, 0x7d, 0x8f, 0xca, 0x37, 0x1c, 0x77, 0x6d, 0xbb, - 0xdd, 0x7f, 0x03, 0x76, 0x3b, 0x70, 0x55, 0xbb, 0x3d, 0x1b, 0x0b, 0xdb, - 0xed, 0xfe, 0x1b, 0xb0, 0xdb, 0x23, 0x37, 0x64, 0xb7, 0xdc, 0x1b, 0x31, - 0x29, 0xa8, 0x8b, 0xad, 0x8c, 0x9b, 0x82, 0x75, 0x47, 0xb1, 0x66, 0x76, - 0x8d, 0x35, 0x87, 0xd6, 0xac, 0xbb, 0xd6, 0xc6, 0x4c, 0xd7, 0x23, 0x6f, - 0xe6, 0x21, 0xf4, 0xab, 0x71, 0xed, 0x83, 0x9e, 0xd6, 0x3a, 0x1f, 0xe4, - 0xed, 0x61, 0xfb, 0xa1, 0x5e, 0x50, 0x17, 0x7e, 0x02, 0x7e, 0x51, 0x1f, - 0x02, 0x9b, 0x6b, 0xaf, 0xd1, 0xc1, 0x05, 0xe4, 0xf3, 0xed, 0x5a, 0x07, - 0x29, 0xeb, 0x4e, 0xf5, 0x3d, 0x69, 0xde, 0x7b, 0xc2, 0xcf, 0xe3, 0xa1, - 0x03, 0x85, 0xf9, 0xc0, 0xd6, 0x92, 0x58, 0x37, 0x78, 0x46, 0x3e, 0xba, - 0x88, 0x61, 0xb6, 0x21, 0xfe, 0x02, 0x8f, 0x54, 0xff, 0xf2, 0x3a, 0xf0, - 0xd5, 0xf1, 0x4c, 0x8a, 0x51, 0x8c, 0x7d, 0xae, 0x07, 0x36, 0xde, 0x43, - 0x8c, 0xca, 0x20, 0x8f, 0xa1, 0x1e, 0x52, 0x37, 0x3b, 0xba, 0x0e, 0x99, - 0x8c, 0x91, 0x0e, 0xc2, 0xf6, 0x6c, 0xa5, 0xc7, 0xbb, 0xcb, 0x1d, 0xe7, - 0x16, 0x4d, 0xae, 0x51, 0xa9, 0x14, 0x54, 0xbd, 0x5e, 0xcc, 0x5c, 0xf7, - 0x4d, 0xeb, 0xe8, 0x97, 0x6e, 0x76, 0x23, 0x5a, 0xd7, 0xb2, 0xb8, 0xa7, - 0xde, 0xfe, 0x2b, 0x7c, 0x3b, 0xf2, 0x89, 0xee, 0x7f, 0x41, 0x7f, 0x02, - 0x36, 0x4f, 0x5f, 0xce, 0xfc, 0x62, 0x87, 0x1e, 0xd7, 0xae, 0xbe, 0x95, - 0xaa, 0xef, 0x2d, 0x4e, 0xe0, 0x7f, 0x52, 0xf4, 0xcf, 0xcb, 0xe4, 0xcc, - 0xb3, 0x1b, 0x79, 0x95, 0x9f, 0xf0, 0x7d, 0xa5, 0x93, 0xc8, 0x29, 0xac, - 0x50, 0x9d, 0x3d, 0xa6, 0x73, 0x31, 0xda, 0x58, 0x5c, 0xe5, 0x89, 0x7e, - 0xee, 0xc1, 0x5c, 0x75, 0xf9, 0x99, 0x8d, 0xd5, 0x75, 0x60, 0xf3, 0x27, - 0xd0, 0x81, 0x5a, 0xf9, 0xc5, 0x60, 0xfb, 0x81, 0xfc, 0x82, 0x98, 0x65, - 0x56, 0xef, 0xbb, 0xdd, 0x97, 0xe1, 0xff, 0x8b, 0x7d, 0x1a, 0xa1, 0x7d, - 0x06, 0x78, 0x74, 0x58, 0xef, 0x73, 0x47, 0x0d, 0x1e, 0x0d, 0xd4, 0xd8, - 0xec, 0xe7, 0x89, 0x47, 0x97, 0xd7, 0x7d, 0xfe, 0x78, 0xc4, 0x7d, 0x6d, - 0x59, 0x15, 0x87, 0xfc, 0x7d, 0x3c, 0x2d, 0x66, 0xe6, 0xb3, 0xcc, 0xdf, - 0x3e, 0x89, 0x7c, 0xc2, 0x38, 0x42, 0x99, 0x34, 0xa9, 0x78, 0xd5, 0xb7, - 0x3d, 0xf8, 0xf2, 0xf9, 0xa8, 0xbc, 0xf7, 0x50, 0x4c, 0x7e, 0x75, 0x2f, - 0xbf, 0x95, 0x59, 0xba, 0x7e, 0xc5, 0x76, 0xb4, 0xc1, 0xf7, 0x43, 0x48, - 0x24, 0x94, 0xdf, 0xe1, 0x3b, 0x81, 0x3d, 0xdb, 0x78, 0xce, 0x67, 0x5b, - 0xe4, 0x42, 0xf3, 0x8d, 0xe4, 0x74, 0x1d, 0xf6, 0xfb, 0xe6, 0x6a, 0x39, - 0xdd, 0xd5, 0x6b, 0x7f, 0x4b, 0x39, 0x1d, 0x71, 0xb6, 0x59, 0xd7, 0x7b, - 0x98, 0xd7, 0xec, 0xd7, 0xd8, 0xc9, 0x7b, 0xe4, 0xaa, 0x1e, 0xf2, 0x57, - 0xc8, 0xf6, 0x35, 0xc4, 0x4b, 0xaf, 0x7a, 0xc8, 0x59, 0x3d, 0xe4, 0xaa, - 0x1e, 0x72, 0x55, 0x0f, 0xb9, 0xaa, 0xd7, 0xa5, 0x73, 0xde, 0x01, 0x5d, - 0xd7, 0xe7, 0xf7, 0x70, 0xd6, 0x0b, 0x8a, 0xf0, 0x25, 0xe3, 0x3c, 0x63, - 0x61, 0xe6, 0xd2, 0xeb, 0x82, 0x73, 0x48, 0xba, 0xe6, 0xdd, 0xaa, 0x6b, - 0x30, 0x75, 0x37, 0x29, 0xdf, 0x6c, 0xbe, 0xd1, 0xe0, 0x7f, 0x33, 0xe7, - 0xf9, 0x8f, 0x3f, 0x44, 0x5c, 0xc2, 0x1a, 0xd8, 0x04, 0x6d, 0xb4, 0x62, - 0x66, 0x58, 0x63, 0x11, 0xd3, 0xcc, 0x7c, 0x01, 0xef, 0x6c, 0xc3, 0x1e, - 0xea, 0x69, 0xdb, 0x11, 0x33, 0xd3, 0x48, 0x9e, 0x1a, 0x66, 0x66, 0xbd, - 0x9e, 0xeb, 0x6f, 0x1a, 0xfc, 0xd8, 0xaa, 0x93, 0x6d, 0xcb, 0x64, 0x9c, - 0xa0, 0x62, 0xed, 0xa0, 0x7f, 0x4f, 0xf3, 0xf2, 0xb5, 0xa2, 0x0a, 0xdf, - 0x73, 0xe9, 0x87, 0x31, 0x9f, 0x3a, 0xdb, 0x54, 0xe5, 0xb7, 0xb9, 0x26, - 0xbf, 0xa3, 0x9a, 0xdf, 0x3e, 0x8f, 0x23, 0x1c, 0xa7, 0xea, 0xbe, 0xe4, - 0x75, 0x30, 0x9f, 0xaa, 0xe1, 0x61, 0x1d, 0x75, 0x8e, 0x03, 0xd7, 0xbb, - 0xa2, 0xd2, 0x34, 0x78, 0x20, 0xea, 0x86, 0xd7, 0x25, 0x46, 0xf5, 0x2e, - 0xfb, 0xfe, 0xb4, 0xf6, 0x9a, 0xed, 0xea, 0xdb, 0x99, 0xef, 0x33, 0xa2, - 0x4a, 0x07, 0x2d, 0x75, 0x36, 0xef, 0xd7, 0xea, 0xcc, 0x0d, 0xf5, 0x2f, - 0x8f, 0x3c, 0x66, 0xbc, 0xa7, 0x23, 0x69, 0x99, 0x7f, 0xd1, 0xc0, 0x5a, - 0x6b, 0x5f, 0x39, 0xc0, 0x3d, 0xae, 0x57, 0xeb, 0xc7, 0x59, 0x27, 0x0b, - 0xf0, 0x4c, 0x36, 0xfb, 0xf5, 0xb3, 0x4f, 0x63, 0x4b, 0x0d, 0x35, 0xb6, - 0x14, 0xec, 0xd3, 0xcf, 0x57, 0xf9, 0xdd, 0x7a, 0xb5, 0xb3, 0x13, 0x0b, - 0xe5, 0xd0, 0xf7, 0x8f, 0xaa, 0x6e, 0xf0, 0x5c, 0xcb, 0x83, 0xd0, 0x41, - 0xd6, 0xfe, 0xf7, 0xc0, 0x8e, 0x2a, 0x95, 0x3e, 0xd6, 0x93, 0xb7, 0x3f, - 0xa0, 0xcf, 0x27, 0x3c, 0xa3, 0xea, 0x09, 0xd6, 0x8a, 0x7a, 0x42, 0x1f, - 0x74, 0x05, 0x31, 0x00, 0x6c, 0xb0, 0xa0, 0x64, 0xc9, 0x78, 0xa0, 0xf6, - 0xfb, 0xca, 0xf9, 0x46, 0x9f, 0x0f, 0xb7, 0x37, 0xfa, 0xdf, 0x18, 0x7e, - 0xe9, 0x2c, 0x6f, 0xf3, 0xfd, 0x44, 0x63, 0x70, 0xce, 0x67, 0xf8, 0x4c, - 0x1f, 0x74, 0xb1, 0x4e, 0xf2, 0x6a, 0x3e, 0xc4, 0xbb, 0xcf, 0xff, 0xac, - 0x79, 0xf9, 0x78, 0xf4, 0x9d, 0x09, 0xc6, 0x37, 0xd7, 0x8c, 0x6f, 0xc6, - 0xf8, 0x7f, 0xaf, 0x19, 0xdf, 0x1c, 0x1a, 0xef, 0xd4, 0x8c, 0x77, 0x30, - 0xbe, 0x7e, 0xd3, 0xf2, 0xf1, 0x4e, 0x68, 0x7c, 0x4b, 0xcd, 0xf8, 0x16, - 0x8c, 0x6f, 0xa8, 0x19, 0x8f, 0xbe, 0x33, 0x75, 0xfa, 0xbb, 0x17, 0x31, - 0xf6, 0x88, 0xce, 0xbb, 0x71, 0x2d, 0xd5, 0x7e, 0x4b, 0xa1, 0xde, 0xb5, - 0x42, 0x06, 0xc1, 0x39, 0x3b, 0xda, 0x6b, 0x16, 0xf6, 0xba, 0x14, 0xcb, - 0xf8, 0xfa, 0x18, 0xd6, 0x45, 0xe2, 0x43, 0x51, 0x22, 0x2e, 0x74, 0x67, - 0x1e, 0x3a, 0x34, 0x1f, 0xf8, 0x24, 0x9e, 0x99, 0x4a, 0x75, 0xf9, 0x7a, - 0x6a, 0x48, 0xd4, 0x5d, 0xd0, 0x39, 0xd8, 0x4e, 0xd2, 0x0e, 0xbc, 0x0c, - 0x30, 0x53, 0x4e, 0xf9, 0x76, 0x43, 0xfd, 0xe5, 0xfc, 0xda, 0x7e, 0xa8, - 0xab, 0x7a, 0x9d, 0xbe, 0x15, 0xb8, 0x96, 0x5c, 0x51, 0xab, 0x8a, 0x5c, - 0x07, 0xae, 0x0d, 0x54, 0x71, 0xed, 0x41, 0x99, 0xad, 0xe6, 0xdb, 0xfd, - 0x72, 0xd4, 0xdb, 0xcb, 0xf3, 0x38, 0xa7, 0xb2, 0xf2, 0xd9, 0xe4, 0xdb, - 0x7b, 0xab, 0x7e, 0x32, 0x35, 0x91, 0x95, 0x0b, 0xc7, 0x99, 0x43, 0x05, - 0xb5, 0xd6, 0x71, 0xef, 0x5b, 0x94, 0x0b, 0x6c, 0xe3, 0x46, 0xf3, 0x6d, - 0xce, 0xe7, 0xc8, 0x51, 0xff, 0x2c, 0x44, 0x75, 0xde, 0x62, 0x75, 0xde, - 0x84, 0xb6, 0x37, 0xfa, 0xe0, 0x25, 0x7f, 0x99, 0x87, 0xbf, 0x1c, 0x42, - 0xce, 0xbd, 0xe0, 0xad, 0x56, 0xef, 0xbc, 0x51, 0x7f, 0x59, 0x5b, 0x37, - 0xae, 0xf5, 0x97, 0x5c, 0xa7, 0xb6, 0x56, 0x9c, 0xac, 0xc1, 0x7f, 0xea, - 0xd3, 0x53, 0x3a, 0xa6, 0xc6, 0x75, 0xfe, 0x29, 0xd8, 0xa3, 0x29, 0x43, - 0x4a, 0x7f, 0xd9, 0x0e, 0x72, 0xcb, 0x03, 0xd5, 0xdc, 0x72, 0x29, 0x1f, - 0x44, 0xec, 0xda, 0x75, 0x9f, 0xc6, 0x47, 0xc6, 0xc8, 0xe3, 0xe8, 0x3f, - 0x05, 0x1d, 0xe0, 0x33, 0xd6, 0x3f, 0xef, 0x90, 0x2f, 0x5b, 0xbe, 0x7f, - 0xf2, 0xeb, 0x50, 0x07, 0x54, 0xfc, 0xcf, 0xfa, 0xff, 0x70, 0x7a, 0xa3, - 0x8e, 0xf7, 0xae, 0x85, 0xab, 0xcb, 0x73, 0x53, 0xd3, 0x3c, 0x81, 0x77, - 0x99, 0x9b, 0x3e, 0x10, 0x27, 0x86, 0xe6, 0xca, 0x57, 0x7d, 0xbf, 0x48, - 0xff, 0x32, 0xac, 0xbe, 0xfb, 0xa9, 0x3c, 0x14, 0xe3, 0x16, 0xf4, 0xfb, - 0x7e, 0x1e, 0x9a, 0x2b, 0x6f, 0x89, 0xfb, 0x38, 0x78, 0xb5, 0x9c, 0xe5, - 0x58, 0x9c, 0xb5, 0xbc, 0x05, 0xef, 0x5a, 0xb4, 0xae, 0xcc, 0x7b, 0x23, - 0x2b, 0xf2, 0xde, 0x41, 0x9d, 0xd7, 0x7e, 0x45, 0xe5, 0xbd, 0x3e, 0x8f, - 0xb9, 0x97, 0x70, 0x1e, 0xe5, 0x02, 0x0b, 0xf9, 0x8d, 0x84, 0xf8, 0x30, - 0xaa, 0xfc, 0x56, 0x61, 0xf2, 0x77, 0xd4, 0xf9, 0x89, 0x95, 0x7a, 0xf3, - 0x79, 0xfb, 0x89, 0x60, 0xef, 0x4f, 0x89, 0x5f, 0xaf, 0xdb, 0x03, 0x5a, - 0x98, 0x5b, 0x45, 0xb5, 0x3e, 0xa4, 0x34, 0x5e, 0x07, 0xe3, 0x82, 0x3c, - 0xbe, 0xfa, 0x5d, 0xb5, 0x98, 0x5d, 0x56, 0x3f, 0xd9, 0x42, 0x18, 0x86, - 0xdc, 0xb3, 0x37, 0xf0, 0x1d, 0xe2, 0xd3, 0x9c, 0x7f, 0xa8, 0xf5, 0x6b, - 0xfc, 0x46, 0xda, 0xaa, 0xcf, 0xc7, 0xb9, 0xb0, 0x01, 0x9e, 0x65, 0x0e, - 0xe3, 0xab, 0x3a, 0x03, 0x17, 0x73, 0x32, 0x62, 0xec, 0x23, 0x7d, 0xe9, - 0x7f, 0xd6, 0xfb, 0x4c, 0xc8, 0x91, 0x29, 0xbf, 0xbe, 0x69, 0xae, 0x71, - 0xfe, 0xcd, 0x34, 0xaf, 0xab, 0xbe, 0x79, 0x03, 0xe7, 0xdf, 0x5e, 0x8f, - 0x07, 0xf5, 0xcd, 0xda, 0xf3, 0x6f, 0x91, 0xeb, 0x3c, 0xff, 0xe6, 0xd7, - 0x37, 0x39, 0x4f, 0xb8, 0xbe, 0x79, 0x8f, 0x3a, 0x43, 0x36, 0x3a, 0xd5, - 0xa3, 0xce, 0x23, 0xb7, 0x75, 0xaf, 0x8d, 0xb3, 0xfb, 0x3e, 0xb3, 0x7c, - 0xe4, 0x3f, 0xe3, 0xe1, 0x7c, 0x64, 0xdf, 0xe7, 0x92, 0x8f, 0x70, 0x2f, - 0xbf, 0xef, 0x7f, 0xb7, 0xad, 0x39, 0xfb, 0x95, 0xfb, 0x1c, 0x6b, 0x98, - 0x47, 0x54, 0x0d, 0x73, 0xcb, 0xfa, 0x70, 0x0d, 0xd3, 0xbc, 0xc6, 0xd9, - 0xaf, 0x23, 0xab, 0xd4, 0x30, 0xa3, 0xa1, 0xb3, 0x5f, 0x51, 0x7d, 0xf6, - 0x6b, 0xa3, 0x8b, 0xbc, 0x51, 0xd7, 0x2c, 0xcd, 0xab, 0x9e, 0xfd, 0xea, - 0x59, 0xff, 0x49, 0x6a, 0x96, 0xb9, 0x65, 0x35, 0xcb, 0x15, 0x67, 0xbf, - 0xe0, 0xd7, 0x36, 0x4b, 0x32, 0x94, 0xe3, 0xe4, 0x6e, 0xf0, 0x6c, 0x43, - 0xfe, 0x3a, 0xe2, 0x80, 0x7d, 0x55, 0x5b, 0xe5, 0xd9, 0xfd, 0x3a, 0xec, - 0x39, 0x2a, 0x7b, 0x1d, 0xea, 0x27, 0xcf, 0x38, 0x76, 0xc2, 0x16, 0x70, - 0x2d, 0xb3, 0xdd, 0x45, 0x19, 0x19, 0x03, 0x9d, 0xcb, 0xcf, 0x17, 0x2c, - 0x9d, 0xd3, 0x8d, 0x55, 0xcf, 0xe9, 0x9e, 0x84, 0xde, 0x98, 0x53, 0x31, - 0x99, 0x0b, 0xe9, 0xd4, 0x38, 0x62, 0x3b, 0x73, 0xc6, 0xd6, 0xcf, 0x93, - 0x12, 0x99, 0x72, 0x80, 0x6f, 0x3c, 0xdb, 0xdb, 0x24, 0x91, 0x19, 0xff, - 0x7b, 0xa3, 0xa9, 0xf0, 0x33, 0x81, 0x31, 0x3c, 0xdb, 0x19, 0x95, 0xa3, - 0xaa, 0x3e, 0x11, 0xe8, 0xf2, 0x37, 0xc1, 0xe3, 0x4d, 0xd9, 0xa5, 0xb6, - 0xb3, 0x8a, 0x8f, 0x47, 0xcc, 0x38, 0x45, 0x7d, 0xbe, 0x5b, 0xf2, 0xba, - 0xf6, 0x33, 0x5c, 0xde, 0xa9, 0x73, 0x09, 0xf5, 0xcd, 0x06, 0xbc, 0x6c, - 0xd3, 0xfe, 0x16, 0xd7, 0xf9, 0x36, 0xfa, 0x37, 0xc6, 0xcc, 0xd2, 0x37, - 0xb9, 0x2d, 0x31, 0x02, 0x6c, 0x1b, 0x52, 0x6b, 0xde, 0x08, 0xcf, 0x8d, - 0x15, 0xf1, 0xd7, 0x8d, 0xf1, 0x3d, 0x88, 0x85, 0xdf, 0xc4, 0xfe, 0xda, - 0xa0, 0x1f, 0x8f, 0x4b, 0xfe, 0xcc, 0x1d, 0xd2, 0x37, 0x9d, 0x02, 0x3d, - 0xbf, 0xae, 0x0c, 0xa7, 0x11, 0x37, 0x3f, 0xcf, 0x33, 0x60, 0xc0, 0x4b, - 0xf0, 0xed, 0x95, 0x15, 0xdf, 0xa0, 0xc3, 0xe7, 0xc6, 0xba, 0xaa, 0xe7, - 0x80, 0x5e, 0x2a, 0x4b, 0xac, 0x99, 0x34, 0x4f, 0x2d, 0x9d, 0x09, 0x5f, - 0x28, 0xef, 0x56, 0x7e, 0xec, 0xc5, 0xf2, 0xff, 0x52, 0x77, 0x6d, 0xb1, - 0x6d, 0x9d, 0xf7, 0xfd, 0xcf, 0x43, 0xea, 0x12, 0xdd, 0x7c, 0x24, 0xd3, - 0x32, 0x2d, 0xd1, 0xf2, 0x39, 0xd2, 0xb1, 0xc5, 0xd8, 0x5a, 0xc7, 0x6a, - 0xca, 0x26, 0xac, 0x5a, 0xc2, 0x52, 0xf4, 0x65, 0x59, 0x36, 0xd0, 0x97, - 0x76, 0x1e, 0x16, 0xa0, 0x0e, 0x65, 0x3b, 0x1d, 0xd0, 0x07, 0xb7, 0xd9, - 0x80, 0xa4, 0x03, 0x6c, 0x96, 0xb2, 0x1c, 0xaf, 0x53, 0x4d, 0x36, 0x66, - 0xd5, 0xac, 0x1b, 0x50, 0x4e, 0x92, 0x9d, 0xb4, 0x50, 0xc0, 0x64, 0xbd, - 0x60, 0xd8, 0x43, 0xad, 0xc9, 0xf6, 0xf6, 0xb2, 0x87, 0x6c, 0xd8, 0x83, - 0x81, 0x0d, 0x98, 0x63, 0x05, 0x68, 0x96, 0x02, 0x49, 0x87, 0x15, 0x43, - 0x1e, 0x36, 0x70, 0xff, 0xdf, 0x77, 0x21, 0x0f, 0x0f, 0x0f, 0x75, 0x89, - 0x9d, 0x01, 0x33, 0x60, 0x88, 0xe7, 0x9c, 0xef, 0x9c, 0xf3, 0x7d, 0xff, - 0xef, 0x7f, 0xbf, 0x9d, 0x3a, 0x3f, 0x8f, 0xd8, 0xc3, 0xdc, 0xca, 0x5b, - 0x0c, 0x8b, 0xbb, 0x42, 0x96, 0xcd, 0xe5, 0x69, 0x28, 0x48, 0xd8, 0x0f, - 0x0a, 0x30, 0x0c, 0x44, 0x6e, 0x86, 0x8c, 0xcd, 0x47, 0xc5, 0xbe, 0x4a, - 0x5e, 0x71, 0xcc, 0x95, 0x5b, 0x51, 0xdb, 0x5b, 0x99, 0x73, 0x21, 0xf7, - 0x42, 0xe6, 0x85, 0x00, 0x9e, 0xab, 0x17, 0x8f, 0x3b, 0x32, 0x2f, 0x64, - 0x64, 0x01, 0xe7, 0xfa, 0x3d, 0x72, 0xae, 0x9d, 0x71, 0x00, 0x39, 0x44, - 0xc8, 0x05, 0xc7, 0x9c, 0x85, 0x5f, 0xc3, 0x37, 0x2e, 0xbd, 0x3d, 0xff, - 0xaa, 0x7c, 0xe7, 0xb0, 0x78, 0xe7, 0x2e, 0xc5, 0xb3, 0x74, 0x0e, 0x78, - 0x3c, 0x30, 0x93, 0x1f, 0x8d, 0x04, 0x19, 0xbf, 0x67, 0xca, 0xb0, 0xa5, - 0x9b, 0xe9, 0x6b, 0x1b, 0xc1, 0x33, 0xd1, 0x00, 0xcf, 0x7a, 0x9a, 0x60, - 0xdb, 0xbb, 0xca, 0xbb, 0x25, 0xec, 0xe4, 0x79, 0xe4, 0xb7, 0xeb, 0xfc, - 0x04, 0x09, 0xbb, 0x2a, 0x0d, 0x5d, 0x73, 0xe7, 0x26, 0xd4, 0x60, 0x77, - 0xa6, 0x0a, 0xbb, 0xdd, 0xff, 0x8f, 0x60, 0x77, 0x4f, 0xe8, 0xba, 0x6f, - 0x95, 0x91, 0x83, 0xa6, 0xe5, 0xbd, 0xae, 0x5d, 0x02, 0x1c, 0xc1, 0x4f, - 0xed, 0xd2, 0x2a, 0x81, 0xa7, 0x22, 0x6f, 0xb8, 0x52, 0xf9, 0x41, 0xbc, - 0xea, 0x93, 0x64, 0x1b, 0x04, 0xb6, 0x08, 0x7c, 0x77, 0xcd, 0x65, 0xe4, - 0xf1, 0x8f, 0x25, 0x23, 0xa1, 0x17, 0x79, 0x6d, 0x91, 0x1f, 0xf5, 0xb8, - 0x6d, 0x91, 0xe3, 0xdb, 0xb4, 0x45, 0x2e, 0x48, 0x5b, 0x24, 0xbb, 0x75, - 0x5b, 0x64, 0xa0, 0x21, 0x5f, 0xab, 0xb6, 0x9e, 0xed, 0xdb, 0x22, 0xc6, - 0x86, 0xb6, 0xc8, 0x88, 0xcb, 0xef, 0x82, 0xf9, 0xfe, 0x2e, 0x65, 0x4f, - 0x80, 0xc7, 0x69, 0x38, 0x03, 0xc6, 0x27, 0x3c, 0x3e, 0xe0, 0x4f, 0x12, - 0xd6, 0xe6, 0x8e, 0xff, 0x5b, 0x58, 0x0f, 0x36, 0xf8, 0xb7, 0x6b, 0xeb, - 0xa1, 0xf0, 0xce, 0x6d, 0xe9, 0xec, 0x5e, 0x58, 0x0f, 0x36, 0xf5, 0x93, - 0x36, 0xcf, 0x45, 0xac, 0xf7, 0x93, 0x0e, 0x1b, 0xcd, 0x78, 0xfb, 0x77, - 0x5d, 0xfe, 0x53, 0x37, 0x7f, 0x07, 0x4d, 0x51, 0xe0, 0xf8, 0xa8, 0x7e, - 0x17, 0x68, 0xc9, 0xce, 0x66, 0x09, 0xf6, 0x11, 0xde, 0x17, 0x11, 0xb4, - 0xe6, 0xd1, 0xb7, 0xf8, 0x7d, 0xbc, 0xbe, 0xd7, 0x9e, 0x15, 0x72, 0x4a, - 0xfa, 0x1a, 0x30, 0x3e, 0x16, 0x38, 0x2b, 0xc6, 0xca, 0xdc, 0x24, 0xe5, - 0x7b, 0x50, 0x7a, 0x7e, 0x33, 0x9f, 0x43, 0xa3, 0xcc, 0xdb, 0x9e, 0x5d, - 0xa0, 0x69, 0x7c, 0x1f, 0xef, 0x4b, 0xa4, 0xce, 0xae, 0x02, 0xff, 0xbc, - 0xc0, 0x7a, 0xc1, 0x70, 0x55, 0x27, 0xa8, 0xdf, 0x9b, 0xcb, 0xc2, 0x7e, - 0xd3, 0xbc, 0x33, 0x2d, 0xf2, 0xdd, 0x24, 0xef, 0x84, 0x9e, 0xa6, 0x79, - 0xa7, 0x57, 0x0f, 0xde, 0xe7, 0x83, 0x17, 0xbe, 0x75, 0xa7, 0x7a, 0xef, - 0x2c, 0xe4, 0x8f, 0xa7, 0x7c, 0xf7, 0xae, 0x5a, 0x77, 0x95, 0xad, 0x8d, - 0x95, 0xf7, 0xa7, 0xc4, 0xba, 0xa2, 0x4f, 0x27, 0x51, 0x13, 0x57, 0xad, - 0x09, 0xf2, 0xd6, 0x41, 0x41, 0x0e, 0x68, 0x3a, 0xd4, 0x75, 0xe2, 0x80, - 0x45, 0xcc, 0xa7, 0x0e, 0xca, 0x2d, 0x4b, 0x70, 0x9f, 0x17, 0x16, 0x35, - 0x39, 0x32, 0xa7, 0xe4, 0xc8, 0xa2, 0x8b, 0x8f, 0x37, 0xea, 0xed, 0x7d, - 0x3e, 0x7a, 0xbb, 0xbb, 0xb6, 0x43, 0xd4, 0xb8, 0x35, 0xa9, 0xed, 0xf0, - 0xab, 0x99, 0xc2, 0xd8, 0x17, 0x59, 0x5f, 0xf9, 0x14, 0xf4, 0x15, 0x13, - 0x35, 0x4b, 0x52, 0x67, 0xc1, 0x75, 0x96, 0x49, 0xaf, 0x45, 0x18, 0xa7, - 0x8e, 0xd1, 0x79, 0xd6, 0xc9, 0x6f, 0xd2, 0xe3, 0xca, 0x66, 0x4b, 0xb8, - 0xf2, 0x4c, 0x91, 0xdf, 0x1f, 0xa0, 0xec, 0xb3, 0x76, 0x2c, 0x41, 0xc7, - 0xe8, 0x9c, 0xc8, 0x99, 0x41, 0xcc, 0x0f, 0x79, 0x08, 0x07, 0xc5, 0x3c, - 0xa5, 0x7f, 0xe3, 0x51, 0xe4, 0xcd, 0x6d, 0x3d, 0x67, 0x5f, 0xd7, 0xfa, - 0x25, 0xc5, 0x3b, 0x97, 0x15, 0xed, 0x89, 0x73, 0x7c, 0xff, 0x8b, 0x46, - 0xe3, 0xfd, 0x09, 0x23, 0x55, 0x4e, 0x19, 0xc9, 0x25, 0x8c, 0x7b, 0xd1, - 0x98, 0x2e, 0xc3, 0xd6, 0xd4, 0xb8, 0x64, 0xc7, 0x41, 0x97, 0x6b, 0xb4, - 0x79, 0x7c, 0x62, 0x91, 0x3c, 0xf5, 0x13, 0x5b, 0x98, 0xf7, 0x91, 0xba, - 0x79, 0x6b, 0xf8, 0xe2, 0x37, 0x7c, 0x40, 0x09, 0x86, 0xa9, 0xd6, 0x7f, - 0x3b, 0xe0, 0x73, 0x8f, 0x65, 0x69, 0x23, 0xfd, 0xd7, 0x6e, 0xd0, 0x7f, - 0x17, 0x37, 0x9d, 0xf7, 0xc3, 0xf2, 0x02, 0x59, 0xc3, 0x1d, 0x74, 0x84, - 0x9e, 0xcb, 0xf3, 0xae, 0xd3, 0x81, 0x3d, 0x38, 0x85, 0x31, 0xda, 0x37, - 0xae, 0x7d, 0x63, 0x3d, 0x2a, 0x1f, 0x58, 0xe7, 0x2c, 0x74, 0x28, 0x3c, - 0xc6, 0x75, 0xd8, 0x62, 0xab, 0x3c, 0x3f, 0xd8, 0x65, 0x4f, 0x8a, 0x39, - 0xb2, 0x5d, 0x66, 0x4d, 0x93, 0xf4, 0x7f, 0x9f, 0x2d, 0xd7, 0xd5, 0x8f, - 0xfa, 0xd4, 0x51, 0x0e, 0xfb, 0xd4, 0x51, 0xba, 0x69, 0x32, 0xe4, 0xa2, - 0xc9, 0x88, 0x4b, 0xbf, 0x8b, 0xb2, 0x7d, 0xd3, 0xc5, 0xbc, 0x06, 0xf6, - 0x4d, 0x07, 0x05, 0x5f, 0x71, 0xdb, 0x37, 0xde, 0xba, 0x7d, 0xd0, 0x27, - 0x74, 0x38, 0x69, 0xeb, 0xa4, 0x8a, 0xd5, 0x9a, 0x7f, 0x5e, 0x77, 0xad, - 0x66, 0x71, 0xa9, 0xa1, 0xbe, 0xd2, 0x6f, 0xbe, 0x43, 0x0d, 0xf3, 0x85, - 0x9c, 0x4b, 0x34, 0xd5, 0xfd, 0xfc, 0xec, 0xaf, 0x47, 0x35, 0x3f, 0x2f, - 0xdf, 0xc3, 0xbb, 0x86, 0x85, 0x1f, 0x3c, 0x5b, 0xe5, 0x79, 0x93, 0x72, - 0xbe, 0xf9, 0x7a, 0x7b, 0x24, 0x78, 0x8d, 0x14, 0xec, 0xfc, 0x65, 0xc0, - 0xf6, 0x7c, 0x6a, 0x9d, 0x1e, 0xf9, 0x3c, 0xd1, 0x2b, 0x7d, 0x65, 0x2d, - 0x2a, 0xd7, 0x7a, 0x97, 0xb2, 0x0b, 0x37, 0xc3, 0x77, 0x9c, 0x6b, 0x51, - 0xfe, 0x45, 0xdb, 0x2a, 0x11, 0xf0, 0xfc, 0xc4, 0xe9, 0x16, 0xc7, 0x54, - 0xf1, 0x2d, 0xc4, 0xb0, 0x80, 0xf7, 0xfa, 0xf9, 0xb2, 0xd6, 0x6a, 0xf3, - 0x3d, 0xb3, 0x1a, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x32, 0xe4, 0x10, 0x8f, - 0x79, 0xf2, 0xb8, 0x1f, 0x06, 0x16, 0x3d, 0x3e, 0xb9, 0xcd, 0xc8, 0x4d, - 0x6e, 0x36, 0xcf, 0xfb, 0x2e, 0xfd, 0x1d, 0xf3, 0xad, 0x54, 0xde, 0x8c, - 0x0f, 0x48, 0x99, 0x5d, 0xf6, 0xd7, 0xa5, 0xcc, 0x2d, 0xcf, 0xcf, 0x2b, - 0xa3, 0xf7, 0x6c, 0x51, 0x46, 0x8b, 0x7e, 0x28, 0x81, 0xc3, 0x82, 0x07, - 0xa0, 0x06, 0x1b, 0x39, 0xd6, 0x9f, 0x06, 0xcd, 0x33, 0x9f, 0x75, 0xd5, - 0xaa, 0xf9, 0xef, 0x63, 0x35, 0xce, 0x12, 0x42, 0x2f, 0x88, 0x09, 0xe4, - 0x9b, 0xf4, 0x31, 0xef, 0xc1, 0xf8, 0xfd, 0xd6, 0x1d, 0xf8, 0x80, 0x95, - 0x9f, 0x2a, 0xa5, 0xe4, 0xcb, 0xe1, 0x2d, 0xc4, 0x5b, 0xb6, 0xc7, 0xa7, - 0x6d, 0x6b, 0x95, 0x10, 0x0b, 0x42, 0x4e, 0xf0, 0x0b, 0x3d, 0xd4, 0x73, - 0xaa, 0xad, 0xcd, 0xb9, 0xdb, 0x2b, 0xe3, 0x53, 0xb8, 0xd6, 0x45, 0x37, - 0x8a, 0xc8, 0xd7, 0xc6, 0xb5, 0xdf, 0xe3, 0x6b, 0x7e, 0x3c, 0x4a, 0xe7, - 0x9b, 0x43, 0xe7, 0x93, 0xfb, 0x53, 0x22, 0xd8, 0x54, 0x15, 0xfa, 0xa7, - 0xf8, 0xaf, 0xc8, 0x18, 0x47, 0xf9, 0x51, 0xc7, 0x6f, 0xfc, 0xfc, 0x8a, - 0x46, 0xdf, 0xc7, 0xcd, 0x97, 0xfc, 0xf2, 0x96, 0xfc, 0x8a, 0xc8, 0xbb, - 0xdf, 0x4a, 0x1c, 0x45, 0xc7, 0x8b, 0x27, 0x44, 0xed, 0xa9, 0x1b, 0x0f, - 0x1e, 0x4d, 0xcc, 0x18, 0xf8, 0x30, 0xd4, 0xc0, 0xab, 0x1e, 0x3e, 0x06, - 0xe0, 0x85, 0x6b, 0x87, 0xaf, 0x4f, 0xcb, 0x3f, 0x36, 0x8c, 0x3c, 0x00, - 0xf8, 0xb3, 0x9f, 0xa2, 0xb3, 0xd7, 0x81, 0xc3, 0x06, 0x63, 0xdb, 0x08, - 0xcd, 0x86, 0x51, 0x57, 0x24, 0x6a, 0x73, 0x54, 0x2c, 0x51, 0xd6, 0x0a, - 0x9d, 0x15, 0x75, 0x8f, 0xfb, 0x23, 0xeb, 0x94, 0x66, 0xb9, 0x97, 0xa5, - 0x73, 0x2c, 0x63, 0xcf, 0x2d, 0xd5, 0x74, 0xfc, 0xc6, 0xda, 0xc7, 0x7a, - 0x1c, 0x5f, 0x17, 0x38, 0x1e, 0xdd, 0x10, 0xc7, 0x8f, 0x56, 0x71, 0x7c, - 0xae, 0x4f, 0xe2, 0xf3, 0x45, 0x7e, 0x56, 0x0f, 0x1d, 0x16, 0xcf, 0xcd, - 0xf2, 0xef, 0x4e, 0x3a, 0x2c, 0xfb, 0x62, 0xf0, 0xbb, 0x99, 0xc7, 0xe7, - 0xb3, 0x74, 0xfe, 0x7a, 0x36, 0x90, 0x12, 0x35, 0x0a, 0xee, 0xbe, 0x1e, - 0xfa, 0x7e, 0x8c, 0x6b, 0x86, 0xff, 0x9a, 0x2f, 0xc9, 0x9a, 0xab, 0x92, - 0xe4, 0x4f, 0xf4, 0x76, 0x7c, 0xd0, 0x83, 0xff, 0xf5, 0x36, 0xe6, 0x05, - 0x25, 0x03, 0x4f, 0x6c, 0xe0, 0xff, 0x68, 0xc4, 0xcb, 0x5e, 0x1f, 0xbd, - 0xf9, 0x8d, 0x3e, 0x19, 0xbb, 0xda, 0xc8, 0xff, 0xe1, 0xc6, 0xd1, 0xba, - 0x58, 0x3e, 0xf3, 0xfd, 0x84, 0xaa, 0xff, 0x7b, 0xa7, 0x4f, 0xca, 0x0b, - 0xd4, 0x04, 0xa6, 0x19, 0x0e, 0x6f, 0xb2, 0xae, 0x32, 0x48, 0xad, 0xaf, - 0xe8, 0xb5, 0x0e, 0x0a, 0x7e, 0xeb, 0xf6, 0xe7, 0x5c, 0x56, 0xb5, 0xe0, - 0x39, 0xd7, 0x9a, 0x2e, 0x0b, 0x5b, 0xa8, 0x39, 0xbd, 0x35, 0xcf, 0xc3, - 0x8a, 0x7a, 0x64, 0x82, 0x17, 0xdf, 0xd0, 0x2f, 0x05, 0xfb, 0x4b, 0x86, - 0xd4, 0x83, 0x27, 0x59, 0xbf, 0xdd, 0x6e, 0x0c, 0xe9, 0x61, 0x75, 0x44, - 0x6f, 0x4f, 0x0e, 0xef, 0x6f, 0xec, 0x83, 0xb4, 0x39, 0x32, 0xaf, 0x3d, - 0x25, 0x78, 0xc1, 0xe5, 0xb1, 0x0a, 0x4d, 0xc7, 0xbb, 0x29, 0x33, 0xc6, - 0xef, 0x9e, 0x44, 0x4f, 0xac, 0x20, 0x65, 0x99, 0x7e, 0x33, 0x63, 0x8f, - 0x29, 0x7d, 0x51, 0xfb, 0xdd, 0xdb, 0x54, 0xee, 0xc3, 0x45, 0x11, 0xab, - 0x94, 0xfd, 0x84, 0xf8, 0xf7, 0x92, 0x7e, 0xf6, 0x45, 0x11, 0x33, 0xcd, - 0x5c, 0x6f, 0x55, 0xe3, 0x3a, 0x5d, 0xe3, 0x30, 0xa6, 0x53, 0x8d, 0xc5, - 0x33, 0xb5, 0x4e, 0xd1, 0xae, 0xf8, 0x2d, 0xe8, 0x30, 0xad, 0x6a, 0xf5, - 0x70, 0xfd, 0x02, 0xcd, 0x54, 0xd7, 0xd2, 0xc9, 0x63, 0xff, 0x5b, 0xf5, - 0xf2, 0xe8, 0x64, 0x9d, 0x17, 0xf3, 0x6e, 0x9c, 0x13, 0xd6, 0x12, 0x14, - 0x71, 0x24, 0xfe, 0xad, 0xde, 0x73, 0xa6, 0x3a, 0x27, 0xe4, 0x6d, 0xd8, - 0x11, 0xf9, 0x2c, 0x3d, 0xae, 0xd3, 0x35, 0x4e, 0xf3, 0x0a, 0x1d, 0xa7, - 0xf8, 0x57, 0x9e, 0xc7, 0x3f, 0xa8, 0xbc, 0x5e, 0x53, 0xc4, 0x54, 0x65, - 0xde, 0x86, 0xfe, 0x0d, 0x3f, 0x34, 0xf2, 0x2c, 0x90, 0x3b, 0xe1, 0xe6, - 0x37, 0x72, 0xbd, 0x21, 0xc8, 0xa2, 0x32, 0x62, 0xa9, 0x88, 0x6b, 0x34, - 0xd3, 0x9d, 0xf7, 0x20, 0x5f, 0x7f, 0x1b, 0x3a, 0xe8, 0x56, 0xe8, 0xcf, - 0xf2, 0xa1, 0x3f, 0xf7, 0xfb, 0x51, 0xeb, 0x86, 0x9a, 0xb7, 0x6c, 0xcc, - 0xa0, 0x0a, 0xdb, 0x0a, 0x06, 0x95, 0xcc, 0x00, 0x9d, 0x77, 0xec, 0xf8, - 0x12, 0xc9, 0x9a, 0xc9, 0xe9, 0x79, 0x3b, 0xb6, 0x4a, 0x87, 0xcc, 0x73, - 0x24, 0x7b, 0x25, 0x94, 0x58, 0x06, 0x9f, 0xa1, 0x18, 0xdb, 0x47, 0x6c, - 0x7f, 0x9e, 0x42, 0x5c, 0x46, 0xef, 0x0b, 0x6a, 0xe3, 0xf1, 0x37, 0xc6, - 0x70, 0xba, 0xb9, 0x93, 0x3a, 0x12, 0xfc, 0xcc, 0x18, 0xf8, 0x13, 0x3f, - 0x27, 0x4d, 0x49, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x39, 0x65, 0x9b, 0x25, - 0x32, 0x78, 0x2c, 0x6c, 0x57, 0x3c, 0x07, 0xf7, 0x27, 0xcc, 0x16, 0xf2, - 0xd6, 0xe1, 0x5e, 0x14, 0x75, 0x8a, 0x6f, 0xc7, 0x0f, 0x92, 0xd1, 0x0f, - 0x7e, 0x85, 0x7d, 0x1b, 0x55, 0xf1, 0xa4, 0x4b, 0xfc, 0xdb, 0x51, 0xbf, - 0xbf, 0x2a, 0xea, 0xdd, 0xe4, 0x6f, 0xe0, 0xf6, 0x2f, 0xab, 0x3d, 0xab, - 0xcb, 0x09, 0x89, 0x8c, 0x18, 0x5f, 0xa5, 0x0b, 0x4b, 0x1b, 0xf9, 0x66, - 0xfc, 0xea, 0x5b, 0xbb, 0xb6, 0x58, 0xdf, 0xba, 0xbe, 0x53, 0xd6, 0x8c, - 0xe1, 0xfd, 0x7e, 0xba, 0x97, 0x77, 0x6d, 0xee, 0x7a, 0xd5, 0xef, 0xd0, - 0xb4, 0xac, 0x35, 0x56, 0xb8, 0x70, 0xbd, 0x89, 0x7f, 0xf3, 0x49, 0x21, - 0x2f, 0xcf, 0xca, 0x38, 0xc3, 0x80, 0xec, 0x6d, 0x16, 0xa2, 0xe5, 0x6a, - 0xed, 0x67, 0x50, 0xd5, 0x7f, 0x30, 0x53, 0x7c, 0xa4, 0x75, 0x9f, 0x3a, - 0x57, 0x15, 0x71, 0xa7, 0xb4, 0x2b, 0x8f, 0x22, 0xa4, 0xf2, 0x24, 0x70, - 0xdf, 0x48, 0x18, 0x75, 0x5b, 0xb2, 0xd6, 0x12, 0x63, 0x50, 0xe7, 0x08, - 0x1b, 0x12, 0x75, 0xae, 0xf0, 0xfb, 0x35, 0xab, 0x05, 0xc5, 0x78, 0xf8, - 0x9f, 0xb4, 0x5d, 0x78, 0x5a, 0xd0, 0x98, 0x7c, 0xa7, 0xac, 0xd9, 0x5c, - 0x5c, 0x39, 0x23, 0xea, 0x24, 0x93, 0xaa, 0xf6, 0x33, 0x43, 0x5d, 0x42, - 0x6f, 0xfa, 0xf8, 0x35, 0x9b, 0xe7, 0xc2, 0xdb, 0xaf, 0xd9, 0x74, 0xdf, - 0xb3, 0xbd, 0x9a, 0x4d, 0x93, 0xd7, 0x6e, 0x2c, 0xc8, 0x9a, 0xcd, 0xfa, - 0x58, 0x80, 0xf4, 0x43, 0x65, 0x5c, 0xf2, 0x48, 0xea, 0x7f, 0x5f, 0x72, - 0xe5, 0x08, 0xcb, 0x7a, 0xcc, 0xc5, 0xaa, 0x0e, 0x24, 0xeb, 0x31, 0x65, - 0x4e, 0xb1, 0xbb, 0x0f, 0x89, 0x8c, 0x39, 0xc8, 0xf7, 0x74, 0x7b, 0x62, - 0x0e, 0x2d, 0x4c, 0xa3, 0xa3, 0xaa, 0xe6, 0xbc, 0x19, 0x6e, 0xd6, 0xd9, - 0x2a, 0x4c, 0x73, 0x15, 0xfa, 0x69, 0xfc, 0xd3, 0x74, 0x3f, 0x1c, 0x51, - 0xb9, 0x74, 0xc8, 0x9d, 0x3b, 0xa8, 0xe0, 0xa8, 0xf5, 0x0f, 0xf2, 0xd1, - 0x3f, 0x7e, 0x5b, 0xe4, 0x10, 0x4b, 0xfd, 0x65, 0x50, 0xd1, 0x24, 0xe8, - 0x36, 0xe2, 0xa2, 0xdb, 0x5d, 0x4d, 0xe8, 0x16, 0xf4, 0xf9, 0xdd, 0x1d, - 0xb2, 0x4f, 0x01, 0xe2, 0xde, 0xdf, 0x57, 0xbf, 0x37, 0xa3, 0xbf, 0xf7, - 0x78, 0x6f, 0x40, 0x83, 0x78, 0xc6, 0x87, 0xe1, 0x1a, 0x1d, 0xea, 0xdf, - 0x98, 0xcb, 0x7e, 0xd7, 0x5c, 0x86, 0x5d, 0x73, 0xd9, 0xd7, 0x64, 0x2e, - 0xac, 0x4f, 0x94, 0x2f, 0xf0, 0xff, 0x8f, 0x3b, 0x27, 0xe1, 0xab, 0x65, - 0x5a, 0x8d, 0x0b, 0xf9, 0x9a, 0x03, 0x1c, 0x85, 0x9e, 0x32, 0xaa, 0xea, - 0xe0, 0xdd, 0xf3, 0x6c, 0x66, 0xab, 0x41, 0x16, 0xa0, 0xd7, 0x41, 0x82, - 0xef, 0xeb, 0x6c, 0xd2, 0xeb, 0x00, 0x3a, 0x86, 0x5f, 0xaf, 0x03, 0x37, - 0x8f, 0x77, 0xeb, 0x52, 0xd0, 0x7d, 0x21, 0x03, 0xa1, 0xf3, 0xa2, 0x57, - 0xc1, 0x2f, 0xd1, 0x85, 0xaa, 0x8e, 0x79, 0x90, 0xd2, 0x4a, 0xc7, 0xbc, - 0xb0, 0xa4, 0xf7, 0x7c, 0xd8, 0xb3, 0xe7, 0x7e, 0x3a, 0xe7, 0x90, 0xca, - 0xf1, 0xd1, 0xb0, 0xca, 0xba, 0x60, 0x95, 0xf5, 0x81, 0x95, 0x78, 0x47, - 0x93, 0x79, 0x03, 0x3e, 0xb8, 0x07, 0xff, 0xbf, 0x13, 0x41, 0x8f, 0x16, - 0xa2, 0xdf, 0xd8, 0x55, 0xf3, 0x0b, 0xe8, 0xdf, 0x98, 0x63, 0xd3, 0xdc, - 0x4f, 0xa5, 0x0f, 0x0e, 0x06, 0x8e, 0x5c, 0x67, 0x03, 0x9d, 0x65, 0x5e, - 0xbd, 0x2d, 0xa8, 0x75, 0x85, 0x03, 0x82, 0xef, 0xdd, 0x0f, 0x22, 0x77, - 0x45, 0x9f, 0xeb, 0xd6, 0xbe, 0x5c, 0xb5, 0xfe, 0xd6, 0x3a, 0x7d, 0xa2, - 0xa6, 0x4b, 0xe8, 0x1c, 0x54, 0xfd, 0x5b, 0xcb, 0xc0, 0x7b, 0x75, 0xfe, - 0x89, 0x5b, 0x75, 0xfd, 0x06, 0xe1, 0x0b, 0xea, 0x4e, 0x1b, 0x4e, 0x4a, - 0xe4, 0x91, 0xf6, 0x3a, 0xf0, 0x7b, 0x25, 0x99, 0x37, 0xf7, 0xa6, 0x91, - 0xb3, 0xdc, 0x7b, 0xcd, 0xa2, 0x93, 0xf9, 0x2f, 0xed, 0x95, 0x74, 0x7a, - 0x89, 0x86, 0xc7, 0x79, 0xfc, 0x14, 0x7c, 0xbd, 0x76, 0x2c, 0xc9, 0x4a, - 0xe4, 0x5c, 0xb9, 0x8d, 0x16, 0x59, 0x5b, 0x0f, 0x3a, 0x25, 0xe1, 0xbb, - 0x63, 0x99, 0x51, 0x40, 0x6f, 0x55, 0x63, 0xa1, 0x95, 0x9f, 0xdb, 0x4f, - 0xcb, 0x45, 0xd0, 0x7c, 0x8b, 0xea, 0x11, 0x82, 0xb1, 0x01, 0xea, 0x73, - 0xfe, 0x84, 0xe1, 0xf5, 0x05, 0x91, 0x47, 0xb9, 0x58, 0xb8, 0x24, 0xff, - 0x96, 0x5e, 0x52, 0xef, 0xe0, 0xf7, 0x95, 0xff, 0x86, 0x12, 0x7d, 0x96, - 0xcb, 0x36, 0x73, 0xff, 0xf3, 0xd7, 0x3f, 0x8e, 0x6f, 0x4b, 0xff, 0xc8, - 0xa6, 0x6b, 0xfa, 0x87, 0xfb, 0xd9, 0x5a, 0x17, 0x39, 0xd6, 0x2f, 0xfb, - 0x37, 0x00, 0x06, 0x9d, 0xd0, 0xad, 0xd2, 0x80, 0xa5, 0x31, 0x65, 0x47, - 0x92, 0xc1, 0x49, 0x9a, 0x2d, 0x47, 0x8d, 0x4c, 0x01, 0x3a, 0x30, 0xff, - 0x2d, 0x5d, 0xd9, 0x2d, 0x7d, 0x2e, 0xfa, 0x1e, 0xf0, 0xf5, 0x9d, 0x3c, - 0xfe, 0x3f, 0xfa, 0x65, 0xee, 0xb5, 0xfb, 0x7c, 0x0f, 0x9f, 0x7f, 0x2e, - 0x52, 0x7f, 0xfe, 0x31, 0x3e, 0xdf, 0xc7, 0xe7, 0xe1, 0x87, 0x84, 0x9f, - 0x31, 0x46, 0x39, 0xde, 0x9f, 0xd9, 0x32, 0xf3, 0xa9, 0x57, 0x58, 0x5e, - 0x2c, 0xe9, 0x71, 0xbb, 0x50, 0x97, 0x23, 0xf6, 0xc4, 0xe0, 0x31, 0x97, - 0xf3, 0x63, 0x3c, 0x6e, 0x90, 0x82, 0xaf, 0x58, 0x34, 0xbb, 0xa4, 0x71, - 0x52, 0xe7, 0xd4, 0xbf, 0xc3, 0xf0, 0x45, 0xde, 0xce, 0x47, 0xbb, 0x25, - 0xfc, 0x62, 0xc2, 0x87, 0x89, 0x3c, 0x8e, 0x2b, 0x02, 0xf7, 0xec, 0x49, - 0xab, 0xfa, 0x7e, 0xe0, 0x96, 0x88, 0x73, 0xf0, 0x1a, 0x58, 0x2e, 0x4d, - 0x39, 0x66, 0xae, 0x9a, 0x8f, 0xf6, 0xe7, 0x03, 0xf2, 0xfe, 0xff, 0xda, - 0x25, 0xfb, 0xa3, 0xbe, 0x3f, 0xa0, 0xfb, 0x24, 0x4a, 0x9d, 0x00, 0x39, - 0xca, 0x01, 0x01, 0x9b, 0xe0, 0x02, 0xe4, 0x95, 0xc1, 0xbf, 0x79, 0x3d, - 0x69, 0xcc, 0xb1, 0xad, 0x5f, 0xf7, 0x7c, 0x91, 0xeb, 0x3a, 0xc6, 0xf3, - 0x4d, 0xf1, 0xba, 0xf4, 0xf9, 0x04, 0x1f, 0xfb, 0xed, 0x2f, 0x9e, 0xd5, - 0x91, 0x46, 0x5d, 0x70, 0xe6, 0x54, 0x47, 0x3a, 0x13, 0x93, 0xfb, 0x5c, - 0xf3, 0xd1, 0x46, 0xaa, 0x3e, 0xda, 0xb9, 0xfc, 0x78, 0x3f, 0xfc, 0x15, - 0xc6, 0x35, 0xde, 0xef, 0xf0, 0x15, 0x1e, 0x8b, 0x7a, 0x84, 0x1c, 0xff, - 0xed, 0x52, 0xf9, 0x3c, 0x8d, 0xb8, 0x22, 0xf3, 0x23, 0xb4, 0x5e, 0x81, - 0x7b, 0x9f, 0xe0, 0x67, 0x48, 0xdd, 0xa2, 0xf9, 0x7b, 0xa8, 0x21, 0xff, - 0xa5, 0x11, 0xc7, 0x36, 0xf2, 0xab, 0x8a, 0x38, 0xa2, 0x0f, 0x9e, 0x6d, - 0xd4, 0x83, 0xe0, 0x9e, 0xf0, 0x8b, 0x4d, 0x37, 0xd0, 0x2b, 0xe8, 0x38, - 0x44, 0x2f, 0xcc, 0x67, 0xe9, 0x31, 0xde, 0xab, 0x3f, 0x30, 0x3e, 0x83, - 0x38, 0x3b, 0xc9, 0x5c, 0x27, 0x86, 0x71, 0xde, 0x89, 0x9d, 0x33, 0x52, - 0xe0, 0x8b, 0x95, 0x90, 0xd3, 0x45, 0xad, 0x4c, 0xab, 0xbf, 0x49, 0x23, - 0x6c, 0xcf, 0x81, 0x66, 0x9d, 0x48, 0x8a, 0x40, 0x6f, 0xb6, 0x79, 0x84, - 0x71, 0x62, 0xba, 0x0c, 0x7c, 0x36, 0xe8, 0x8b, 0x45, 0xa2, 0xe7, 0x8b, - 0x23, 0xe6, 0xf7, 0xc8, 0xb1, 0x6a, 0xd7, 0x6d, 0x33, 0xc9, 0xf3, 0x48, - 0x95, 0x5f, 0xa2, 0xf7, 0x44, 0xdf, 0x12, 0xc0, 0x51, 0xef, 0xfb, 0x1f, - 0xd1, 0x99, 0x34, 0xe6, 0xbd, 0x75, 0xfa, 0x3c, 0xb9, 0x2d, 0xfa, 0xec, - 0xf0, 0xa1, 0xcf, 0x7f, 0x54, 0x78, 0x53, 0x61, 0x1c, 0xed, 0xa0, 0x99, - 0x02, 0x72, 0xbf, 0x3e, 0x8b, 0xfe, 0x52, 0x85, 0x0c, 0xf3, 0xa5, 0x4c, - 0x8d, 0x2f, 0x5d, 0x4d, 0x06, 0x13, 0xa0, 0x71, 0xf4, 0x65, 0x53, 0xf9, - 0x3e, 0x58, 0xc7, 0x00, 0x8d, 0x2c, 0x74, 0x22, 0xf6, 0xb5, 0x9a, 0x9c, - 0x48, 0xa8, 0xfa, 0x7c, 0xdb, 0x9a, 0x66, 0xfe, 0x38, 0xc7, 0xb4, 0x9c, - 0x2b, 0x1c, 0xa4, 0xc5, 0x70, 0x94, 0x86, 0x17, 0x74, 0xbf, 0x12, 0x11, - 0x37, 0x89, 0x4a, 0x9e, 0xa4, 0xd7, 0xfd, 0x84, 0xf0, 0x45, 0x58, 0x37, - 0x3f, 0xa9, 0x75, 0x77, 0x6e, 0xc2, 0x97, 0xde, 0x57, 0x34, 0x5b, 0xb9, - 0x95, 0x8c, 0x53, 0x36, 0x39, 0xf1, 0xef, 0x02, 0xff, 0x87, 0x6f, 0xc2, - 0xaf, 0x06, 0x1e, 0x6d, 0x51, 0x3a, 0xef, 0x85, 0x45, 0x94, 0xd7, 0x8d, - 0xeb, 0x95, 0x0f, 0x67, 0xe2, 0x2f, 0x09, 0xdd, 0x6b, 0xe4, 0x26, 0x8f, - 0x13, 0xf2, 0x48, 0xf3, 0x0d, 0x3f, 0x3c, 0xd4, 0x3d, 0x29, 0x35, 0x2e, - 0xca, 0x7c, 0x4e, 0x93, 0x9f, 0x9b, 0x0e, 0x7a, 0x71, 0xf2, 0x5e, 0xe0, - 0xf8, 0xbc, 0x45, 0x27, 0xf2, 0xf6, 0xab, 0x59, 0x9a, 0x64, 0xba, 0x76, - 0xcb, 0x0b, 0x1e, 0x4f, 0xc0, 0xb3, 0x29, 0xd0, 0x3e, 0x65, 0x0a, 0x96, - 0xcc, 0xb7, 0x13, 0x3d, 0xe5, 0x70, 0x8c, 0xda, 0xe2, 0xee, 0xdd, 0x5a, - 0x1e, 0x64, 0x0a, 0xa8, 0x15, 0xe4, 0xbf, 0x25, 0x1e, 0x8f, 0xfc, 0xfe, - 0x22, 0x9e, 0x03, 0x19, 0x87, 0xb9, 0xf3, 0xf1, 0xb2, 0xdc, 0xd7, 0x61, - 0x7e, 0xf6, 0xc8, 0x38, 0xbf, 0xb3, 0x3c, 0xc6, 0xfb, 0xdb, 0x23, 0x78, - 0xb3, 0xdc, 0xcf, 0x29, 0xba, 0xec, 0xcb, 0x57, 0xe4, 0xbe, 0x64, 0x5c, - 0xf4, 0x9d, 0x11, 0xf4, 0x3d, 0x25, 0xf6, 0x23, 0x53, 0x34, 0x58, 0x5f, - 0xd6, 0xbe, 0x04, 0xb6, 0x9b, 0x8b, 0x21, 0xc5, 0x43, 0x70, 0xed, 0x89, - 0xdd, 0x22, 0x1f, 0x11, 0xf6, 0x74, 0x11, 0x7f, 0xa7, 0xe8, 0x0a, 0xeb, - 0xfd, 0x2f, 0xe7, 0xdb, 0xe8, 0x4e, 0xa1, 0x8d, 0xee, 0x16, 0xa2, 0x74, - 0x7b, 0x7e, 0x07, 0x5d, 0x66, 0x9b, 0xe6, 0xb2, 0x13, 0xb2, 0x72, 0xb4, - 0x03, 0xf1, 0x42, 0xe4, 0x0a, 0x31, 0xdd, 0x61, 0x3c, 0xf4, 0xef, 0xe4, - 0x1e, 0xc6, 0x39, 0xb6, 0x8d, 0xda, 0xe9, 0x5d, 0x7e, 0x67, 0x2e, 0xaf, - 0x73, 0x1c, 0xe0, 0x63, 0xdf, 0x5f, 0xb5, 0x1f, 0x36, 0xc7, 0x11, 0x73, - 0x13, 0x1c, 0x99, 0x12, 0xbc, 0x7e, 0x76, 0x3e, 0x8a, 0xbe, 0xca, 0xd9, - 0x16, 0xf8, 0x49, 0x99, 0x3f, 0x3f, 0x17, 0xc2, 0x78, 0x9c, 0x73, 0x64, - 0x8e, 0xa4, 0x58, 0x5b, 0x84, 0x8f, 0x03, 0xa2, 0x0e, 0x5a, 0xc2, 0xa1, - 0x9d, 0xd7, 0x17, 0x10, 0xe3, 0x33, 0xcb, 0xed, 0x74, 0xb6, 0x68, 0xf2, - 0x71, 0x90, 0xf5, 0x44, 0x8c, 0xed, 0xdd, 0xa7, 0xfb, 0xcb, 0x5e, 0xe6, - 0xb9, 0xe7, 0xc4, 0x38, 0xfe, 0xbb, 0xdc, 0x43, 0xb3, 0xc5, 0x2e, 0x75, - 0x7c, 0x50, 0xe6, 0xf2, 0x8a, 0x5c, 0x6c, 0x5c, 0xdb, 0x88, 0xbf, 0xbd, - 0xcd, 0x38, 0x05, 0x99, 0x2a, 0x75, 0x7c, 0xf0, 0x9a, 0x5b, 0x0d, 0xfd, - 0x90, 0x81, 0x73, 0x93, 0xf4, 0x4d, 0x96, 0xb7, 0xc3, 0xaf, 0xc0, 0x1f, - 0xfc, 0xfb, 0xc0, 0x9b, 0x52, 0x96, 0x06, 0xf9, 0x18, 0x7d, 0x8e, 0x82, - 0xa2, 0x96, 0x69, 0x3a, 0x1c, 0x13, 0xf5, 0x1f, 0x92, 0x46, 0x4f, 0x89, - 0x9e, 0x73, 0x3f, 0x12, 0xbc, 0xc9, 0xce, 0x5a, 0x06, 0xf4, 0x11, 0xf8, - 0x54, 0x64, 0xee, 0xd5, 0x49, 0xa7, 0xf7, 0xed, 0x5d, 0x53, 0xa3, 0x94, - 0xe8, 0x07, 0xde, 0x4b, 0x9a, 0x55, 0x3d, 0x04, 0x04, 0xbf, 0x37, 0x0f, - 0xe8, 0x9a, 0x48, 0x7d, 0xac, 0x65, 0x85, 0x3e, 0xee, 0xf2, 0x5c, 0x37, - 0x3d, 0xd7, 0xab, 0x79, 0x72, 0x2c, 0xf3, 0x58, 0xce, 0x93, 0xec, 0x39, - 0x84, 0xbe, 0x71, 0xc0, 0x3f, 0xf3, 0xc0, 0x7e, 0xf3, 0x73, 0xca, 0x06, - 0xca, 0xac, 0x8c, 0x44, 0x7a, 0x8d, 0x98, 0x91, 0x19, 0xfb, 0x97, 0x4a, - 0x22, 0x0d, 0xbd, 0xe8, 0xc6, 0x6e, 0xc9, 0xe3, 0x30, 0xaf, 0x6c, 0x1c, - 0xaa, 0xdb, 0xa9, 0x95, 0x2e, 0x5a, 0x15, 0x7d, 0xb5, 0xa0, 0x63, 0xe0, - 0x7e, 0x3c, 0x27, 0x6b, 0xb6, 0xb0, 0x7d, 0x77, 0xc3, 0x01, 0x8d, 0x1f, - 0x8a, 0xdc, 0xe4, 0xfd, 0x4c, 0xad, 0x7c, 0x54, 0x39, 0x23, 0xfa, 0xd2, - 0x60, 0x6c, 0x0f, 0xcd, 0x08, 0x9b, 0x8b, 0xf5, 0x97, 0x3a, 0xbb, 0x76, - 0x12, 0xf3, 0xcc, 0x22, 0x56, 0x62, 0x38, 0xdf, 0x0e, 0x64, 0x4a, 0x32, - 0xf6, 0x9d, 0xf2, 0xc4, 0xbe, 0x4f, 0x89, 0xd8, 0x37, 0xe2, 0xde, 0x80, - 0x2b, 0x60, 0xe9, 0x97, 0xcb, 0x82, 0x7d, 0x8c, 0xf3, 0x3e, 0x5a, 0x34, - 0x77, 0x5d, 0xf0, 0x9b, 0xc9, 0xe9, 0x60, 0xa2, 0xb7, 0x85, 0xac, 0x40, - 0xd2, 0xb1, 0xe3, 0x0f, 0x58, 0x87, 0xb8, 0x5d, 0xc0, 0x3c, 0x5f, 0xa2, - 0xf5, 0x52, 0x0b, 0xd3, 0x89, 0xcd, 0x78, 0xb7, 0xca, 0x3a, 0xed, 0x2c, - 0xbd, 0x5b, 0x22, 0xba, 0x5d, 0xbc, 0x8a, 0x5e, 0xbb, 0xb1, 0x07, 0x4c, - 0x2b, 0x88, 0x05, 0x67, 0x62, 0xf0, 0xb1, 0xb1, 0x5e, 0x1b, 0x6b, 0x55, - 0xb8, 0xd9, 0xc5, 0xb6, 0xa3, 0xc9, 0xff, 0x1d, 0xfe, 0x1f, 0x89, 0x00, - 0x2e, 0x6b, 0xc5, 0x31, 0xc1, 0x4b, 0x97, 0xf8, 0xfc, 0x12, 0x9f, 0x87, - 0x4c, 0x5d, 0x2b, 0x56, 0xde, 0x49, 0xc6, 0x13, 0x56, 0x72, 0xe2, 0xa4, - 0x1c, 0xc3, 0x38, 0x77, 0xf9, 0x7a, 0x62, 0x4f, 0x88, 0xe7, 0x31, 0xc3, - 0xf3, 0x58, 0x27, 0x99, 0xeb, 0x9d, 0x12, 0xef, 0x26, 0xba, 0x23, 0xde, - 0xcb, 0x3a, 0x53, 0xfc, 0x71, 0x3a, 0x13, 0x96, 0xef, 0xcf, 0xc5, 0x51, - 0x73, 0xd5, 0x49, 0xb3, 0x63, 0xa3, 0xaa, 0xe6, 0xea, 0xcd, 0x26, 0x35, - 0x57, 0xed, 0xb4, 0x36, 0x0f, 0xbb, 0xb7, 0x9d, 0xe9, 0xdd, 0x14, 0xb9, - 0x7a, 0x6b, 0xf3, 0xa2, 0x1f, 0x3e, 0xaf, 0xa7, 0xb2, 0x3e, 0xc3, 0xaa, - 0x79, 0x26, 0xde, 0x2d, 0x74, 0xa7, 0xdb, 0xcb, 0xbf, 0xc5, 0xf3, 0x49, - 0x58, 0x99, 0x09, 0xf7, 0x3a, 0xc4, 0x7c, 0xd7, 0xa7, 0xc5, 0xb8, 0xa0, - 0x67, 0x5c, 0x82, 0x32, 0x13, 0x98, 0xbf, 0x18, 0xf3, 0x3f, 0xc9, 0xb8, - 0x5e, 0x8f, 0xfb, 0x7e, 0x8b, 0x72, 0x42, 0xdf, 0xe7, 0xbf, 0x4b, 0x3d, - 0x81, 0xf5, 0x02, 0xfc, 0x26, 0x06, 0xe3, 0x3f, 0xe6, 0x66, 0x51, 0x76, - 0x89, 0xd7, 0x75, 0xbd, 0x2b, 0xf0, 0xa0, 0xf0, 0x93, 0x4a, 0xa6, 0x2e, - 0xb7, 0xa5, 0xde, 0xbf, 0x2e, 0x6d, 0xae, 0x28, 0x39, 0xd7, 0x20, 0x4b, - 0x21, 0x47, 0xb3, 0x95, 0xa0, 0x03, 0xbd, 0x0f, 0xb6, 0xd0, 0x25, 0xe6, - 0x63, 0x32, 0x3f, 0x89, 0x79, 0x2a, 0xf3, 0x32, 0x49, 0x47, 0xa9, 0xba, - 0xcf, 0x32, 0x48, 0x5c, 0x1e, 0xae, 0xe5, 0x45, 0xba, 0xe2, 0xe6, 0x21, - 0x57, 0xdc, 0xdc, 0x74, 0xe5, 0x45, 0x86, 0x85, 0x9e, 0x56, 0xd3, 0xad, - 0xc2, 0x4a, 0xb7, 0x8a, 0x8a, 0x9e, 0xf4, 0xe0, 0x71, 0x8b, 0x55, 0x1e, - 0xb7, 0x73, 0x13, 0x1e, 0xe7, 0x67, 0x9b, 0xae, 0x2a, 0x7e, 0x62, 0xc7, - 0x21, 0x6b, 0x6e, 0x31, 0xdf, 0xf8, 0x71, 0x79, 0x82, 0xf9, 0x49, 0x9c, - 0xf9, 0xc9, 0x18, 0xf3, 0x93, 0x18, 0xf3, 0x13, 0x87, 0x61, 0x60, 0xf1, - 0xda, 0xef, 0x05, 0x6e, 0xcf, 0x43, 0x8e, 0x4c, 0xd2, 0x95, 0x32, 0x78, - 0xf3, 0x18, 0xeb, 0x42, 0xf7, 0x02, 0x6b, 0xf3, 0x3d, 0x8c, 0xc7, 0x52, - 0xff, 0xa9, 0xb7, 0x6f, 0xec, 0x57, 0x51, 0x1f, 0x97, 0x8c, 0xaf, 0x81, - 0xff, 0xbc, 0x99, 0xa5, 0xee, 0xc0, 0xed, 0x42, 0x57, 0x60, 0xad, 0xf0, - 0x13, 0xf4, 0xa5, 0x78, 0x1d, 0x34, 0x8e, 0xbe, 0xbf, 0x3f, 0x1c, 0x9d, - 0xe4, 0xb9, 0x77, 0x07, 0x66, 0x79, 0x5f, 0xbe, 0x12, 0x4f, 0xf4, 0xf6, - 0x49, 0x5a, 0xc8, 0xe6, 0xc0, 0x3d, 0x17, 0x76, 0xd0, 0xfe, 0xf1, 0xe4, - 0x9e, 0x5e, 0xa6, 0x5b, 0xe0, 0x7b, 0xad, 0xef, 0x4e, 0x90, 0xf1, 0xb0, - 0x43, 0xf5, 0xeb, 0xb1, 0x58, 0x5e, 0x7e, 0xc8, 0xf7, 0x7f, 0x10, 0xc8, - 0x15, 0x5e, 0xe3, 0x67, 0xe3, 0xf8, 0x4f, 0xe1, 0xdf, 0x64, 0x7b, 0x01, - 0xbd, 0x7e, 0x3a, 0x79, 0x0c, 0xc6, 0xe2, 0xd8, 0x8e, 0x31, 0x6f, 0x8b, - 0xaf, 0x1a, 0xf6, 0x64, 0xc2, 0x78, 0x3e, 0x8a, 0x9e, 0xf1, 0x3f, 0x2c, - 0x3f, 0x15, 0x95, 0x31, 0xb6, 0xe7, 0xf6, 0x48, 0x3e, 0xc2, 0xb8, 0x19, - 0x4e, 0x08, 0x9b, 0xad, 0xe5, 0x9a, 0x94, 0x9b, 0x8b, 0xbc, 0xbf, 0x4b, - 0xf1, 0x18, 0xef, 0x6f, 0x97, 0x92, 0x99, 0x59, 0xbe, 0x2e, 0xe4, 0x31, - 0xcb, 0x4e, 0x86, 0x77, 0x91, 0x4c, 0xd1, 0x03, 0xe2, 0x14, 0xfa, 0xea, - 0x3c, 0x83, 0xe7, 0x31, 0xb6, 0x82, 0x6f, 0x7c, 0x18, 0xc8, 0x14, 0xf0, - 0x5e, 0xe0, 0x1f, 0xff, 0x2e, 0x4d, 0xd2, 0xd5, 0xbc, 0x9e, 0xc3, 0x80, - 0x61, 0x7c, 0x13, 0xf3, 0x08, 0xd0, 0x4e, 0xe7, 0xdf, 0x18, 0x4e, 0x7c, - 0xfc, 0x97, 0xde, 0x39, 0x9d, 0x57, 0x73, 0x42, 0x9f, 0xca, 0x36, 0x5e, - 0xc3, 0x4e, 0x42, 0xff, 0xa2, 0x45, 0xd1, 0x47, 0xb2, 0x55, 0xd8, 0xaa, - 0x8b, 0xc2, 0xe6, 0x38, 0xba, 0xa7, 0xd6, 0xdb, 0xf2, 0x71, 0xcf, 0xb9, - 0x9f, 0x07, 0x72, 0xf3, 0x87, 0x85, 0x6e, 0x36, 0x3c, 0xbe, 0x47, 0xd5, - 0x9c, 0x7e, 0x5e, 0x5c, 0x33, 0x16, 0x70, 0xed, 0x49, 0x75, 0xed, 0xd7, - 0x84, 0x4e, 0x8c, 0xfc, 0xb8, 0xd0, 0x35, 0x81, 0xdf, 0xbc, 0xaf, 0x4e, - 0x8c, 0xf1, 0x3b, 0xb2, 0x04, 0xdf, 0xbc, 0x80, 0xa7, 0x86, 0x07, 0x60, - 0x01, 0x9c, 0xef, 0x52, 0xf8, 0x6e, 0x5b, 0xa9, 0xa0, 0x5e, 0x77, 0x33, - 0x38, 0xb3, 0x8e, 0x93, 0xc7, 0x5a, 0xb1, 0xa6, 0xdd, 0x81, 0x44, 0xc9, - 0x32, 0x72, 0xf3, 0xb0, 0x71, 0xe0, 0x7f, 0xdc, 0x8b, 0xbc, 0x28, 0x9e, - 0xc3, 0x6e, 0x4a, 0xa4, 0x31, 0x2f, 0x8c, 0xd3, 0x30, 0x18, 0xf7, 0xc0, - 0xc2, 0x7d, 0xdf, 0x0e, 0x75, 0x5f, 0xbb, 0xd8, 0x0b, 0x32, 0xf0, 0x1e, - 0xfd, 0x6e, 0xbc, 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x2e, - 0xe6, 0xd7, 0xc9, 0x09, 0xf9, 0x2c, 0xe3, 0xa6, 0xbc, 0xb6, 0xcb, 0xf1, - 0x9f, 0xaf, 0xdc, 0x3f, 0xdc, 0xab, 0xf7, 0x6f, 0x07, 0x95, 0x84, 0x5f, - 0x09, 0xd7, 0xba, 0xc5, 0xb5, 0xa4, 0xd3, 0x2d, 0xf6, 0x75, 0x8e, 0x8f, - 0xcf, 0x16, 0x7a, 0x02, 0xb0, 0xd5, 0x73, 0xe9, 0xee, 0x40, 0xa9, 0x84, - 0xf5, 0x76, 0x07, 0x52, 0x8c, 0xf3, 0xd3, 0x85, 0x23, 0x95, 0x59, 0xc1, - 0x5b, 0x58, 0xc7, 0xed, 0xb3, 0xcd, 0x33, 0xc6, 0xcf, 0xc4, 0x9a, 0xf8, - 0x7d, 0xfc, 0x9b, 0xe9, 0x2e, 0xcf, 0x74, 0x97, 0x67, 0xba, 0xcb, 0x33, - 0xdd, 0xb1, 0x8d, 0xfa, 0x83, 0x3c, 0xd3, 0x1d, 0xcb, 0x90, 0xb7, 0x58, - 0x86, 0x48, 0x5a, 0x4d, 0x28, 0xdf, 0x9e, 0xa6, 0x55, 0x6f, 0x4d, 0xa6, - 0xa6, 0x4d, 0xc8, 0x6d, 0x0a, 0x1c, 0x1d, 0xad, 0xa7, 0xd1, 0x3b, 0x4c, - 0xa3, 0x2d, 0x53, 0xfd, 0xf4, 0xa0, 0x88, 0x3d, 0xb3, 0xad, 0x39, 0xe6, - 0xd1, 0xa9, 0x20, 0x74, 0xac, 0x10, 0xd3, 0x13, 0x74, 0x4c, 0x9b, 0xe1, - 0xde, 0x4f, 0xeb, 0xc5, 0x76, 0x1e, 0x03, 0x9a, 0xdd, 0xab, 0x8e, 0xf3, - 0x4c, 0xb3, 0x90, 0x7b, 0xd7, 0x02, 0x77, 0x0a, 0x06, 0xeb, 0x62, 0x21, - 0x33, 0x43, 0xe0, 0x9f, 0x42, 0x3f, 0xe3, 0x7d, 0x5f, 0x65, 0x7e, 0x0f, - 0xdf, 0x29, 0x7a, 0x77, 0x95, 0x20, 0x3b, 0x22, 0xb7, 0x99, 0x7f, 0x5e, - 0x28, 0x5e, 0x63, 0x3a, 0xef, 0xa3, 0x2f, 0x17, 0x21, 0x9f, 0x01, 0x23, - 0x3e, 0x2e, 0x91, 0xf0, 0x7d, 0x19, 0x53, 0x58, 0xfb, 0xfe, 0xac, 0x21, - 0xf0, 0xe4, 0xaf, 0x01, 0x07, 0x86, 0xfd, 0xdd, 0x3d, 0xe8, 0x69, 0x9f, - 0x30, 0x5a, 0x95, 0x8f, 0x17, 0xbf, 0x31, 0x1e, 0x63, 0x01, 0x37, 0x1c, - 0x37, 0x8b, 0x2f, 0xe2, 0x1b, 0x11, 0x71, 0x86, 0x87, 0x97, 0x5f, 0x5d, - 0xe5, 0xfb, 0x05, 0xbc, 0x26, 0x93, 0x41, 0xd4, 0x87, 0xd3, 0xd7, 0x82, - 0x53, 0x93, 0xf4, 0x72, 0x19, 0xf3, 0xbe, 0x42, 0xb3, 0x61, 0xf0, 0x1f, - 0x3b, 0x7e, 0x9f, 0x24, 0xec, 0xda, 0x59, 0xdf, 0xfc, 0xa2, 0x3f, 0x4f, - 0xb3, 0x92, 0x42, 0x3f, 0x6e, 0x63, 0x7b, 0x07, 0xb0, 0x79, 0x83, 0x71, - 0x2d, 0x0e, 0x1f, 0x80, 0xe2, 0x67, 0xdf, 0x67, 0x9e, 0x83, 0x3d, 0xc3, - 0x71, 0x3d, 0x0f, 0x5b, 0x53, 0x3c, 0xcc, 0x71, 0xf1, 0xb0, 0x5c, 0x95, - 0x87, 0x31, 0x2e, 0x08, 0xde, 0x05, 0xde, 0x74, 0x82, 0xf5, 0x45, 0xf9, - 0x1b, 0x7a, 0xe0, 0x4e, 0xc1, 0xab, 0x98, 0xb7, 0xb3, 0xfd, 0xb0, 0x58, - 0xce, 0x06, 0x8e, 0x08, 0x9e, 0xa1, 0xf1, 0xf9, 0xa9, 0x01, 0x49, 0x07, - 0xed, 0xd2, 0x1f, 0x79, 0x0a, 0x7c, 0xca, 0x6f, 0xfc, 0x67, 0x78, 0x1c, - 0xc6, 0x3b, 0x91, 0xd7, 0x99, 0x7f, 0x2d, 0xc6, 0x63, 0x22, 0x06, 0x22, - 0x6d, 0x9c, 0x2c, 0xdb, 0x01, 0xbb, 0x90, 0x6b, 0x69, 0x25, 0xab, 0xfc, - 0x4b, 0xd7, 0x1f, 0xc1, 0xaf, 0x88, 0x3d, 0x4e, 0xf4, 0x1a, 0x72, 0x1d, - 0x16, 0xd6, 0x31, 0x5b, 0xa4, 0xd0, 0x4c, 0x1c, 0xb9, 0x71, 0xe0, 0xeb, - 0x1f, 0xf0, 0xba, 0xb1, 0xaf, 0x1f, 0x60, 0x5f, 0xe5, 0xb5, 0x89, 0x63, - 0x62, 0x5e, 0xb3, 0xcb, 0x35, 0xfe, 0x37, 0x97, 0x1f, 0x30, 0x16, 0x0b, - 0x72, 0x6e, 0x4b, 0xa3, 0x92, 0xc7, 0x2d, 0x96, 0xd0, 0xab, 0x4b, 0xcc, - 0x91, 0xe7, 0xa6, 0xd7, 0x85, 0xf7, 0x6a, 0x7a, 0xdf, 0x0a, 0x6d, 0x3d, - 0xc3, 0x74, 0x84, 0x3d, 0xc8, 0xba, 0x70, 0xe4, 0x5b, 0xfc, 0x7e, 0x9c, - 0x6b, 0x9c, 0xff, 0x83, 0xea, 0xfc, 0x9f, 0xe4, 0xf9, 0x63, 0xcc, 0x07, - 0x2c, 0xef, 0xe5, 0xfc, 0x1f, 0x54, 0xe7, 0x5f, 0x54, 0xf3, 0xa7, 0x9c, - 0x31, 0xd5, 0xab, 0xf4, 0xf7, 0xa6, 0xcf, 0x6a, 0x9f, 0x99, 0x10, 0x63, - 0xcd, 0x19, 0xe8, 0x44, 0xa6, 0x9e, 0x8b, 0xb6, 0x0d, 0xdd, 0x73, 0xb1, - 0x63, 0xf7, 0xe9, 0x8f, 0x49, 0xea, 0x1d, 0x43, 0xac, 0x77, 0xe0, 0x3c, - 0xcd, 0x82, 0xcf, 0xe6, 0xc2, 0xe8, 0x11, 0x3b, 0xc8, 0x30, 0x62, 0x3b, - 0x6a, 0x82, 0xff, 0x0a, 0xbf, 0x18, 0x9e, 0xa3, 0xef, 0xff, 0x43, 0x5a, - 0x9f, 0x07, 0x2f, 0x86, 0xfe, 0x29, 0xfb, 0xc8, 0xae, 0xaf, 0x48, 0xff, - 0x6b, 0xca, 0xd7, 0xff, 0x0a, 0xdf, 0xeb, 0x04, 0xf4, 0x73, 0x13, 0x7e, - 0xda, 0x69, 0xf5, 0xed, 0x8f, 0x5c, 0x19, 0xcf, 0xf2, 0xe3, 0x2b, 0x93, - 0xae, 0x1c, 0x35, 0xe4, 0x8c, 0x64, 0x99, 0x4f, 0x38, 0x66, 0x8b, 0x21, - 0x6b, 0x64, 0x6e, 0x95, 0xb5, 0xae, 0x73, 0x8c, 0xf7, 0xc4, 0x89, 0x1b, - 0x46, 0x4a, 0xf8, 0x08, 0xda, 0x9d, 0x2e, 0x6a, 0x63, 0x39, 0x78, 0x8e, - 0xd0, 0xe7, 0xcc, 0xb6, 0x10, 0x3b, 0xb9, 0xca, 0x38, 0x36, 0x1b, 0xb7, - 0x23, 0xcf, 0x0b, 0x7b, 0x12, 0xf2, 0x01, 0xdf, 0x4e, 0x01, 0xac, 0x30, - 0x07, 0xfe, 0xbd, 0x8c, 0x9e, 0x95, 0x71, 0x5e, 0x3f, 0x7c, 0xbd, 0x23, - 0xd6, 0x5d, 0x96, 0x2b, 0x57, 0x85, 0x3f, 0xe5, 0x12, 0xeb, 0x92, 0xb6, - 0x79, 0x54, 0xd0, 0x99, 0x31, 0xc4, 0x54, 0xc1, 0x74, 0x82, 0x1c, 0x81, - 0xfd, 0xa2, 0xa7, 0x8e, 0xb4, 0x51, 0x78, 0x95, 0x2b, 0xaa, 0x57, 0x41, - 0x1a, 0xb4, 0xbf, 0x75, 0x5f, 0x42, 0xfa, 0xa1, 0x7d, 0x28, 0x6e, 0x1d, - 0xca, 0xeb, 0xa7, 0x86, 0x3d, 0x66, 0x89, 0xde, 0x8c, 0x80, 0x9d, 0xf0, - 0x03, 0x1a, 0x63, 0x0c, 0x37, 0xfd, 0x9d, 0x1a, 0xb7, 0xbd, 0x7f, 0x5e, - 0xd4, 0xdc, 0xbf, 0x59, 0x96, 0x32, 0x34, 0xc7, 0xb6, 0xf8, 0xec, 0xb8, - 0x5b, 0xa7, 0xb0, 0x0b, 0xd3, 0xc2, 0x07, 0x33, 0x40, 0xc9, 0x85, 0x31, - 0xfa, 0x7c, 0x1e, 0x3c, 0x88, 0xee, 0x27, 0x1d, 0xf1, 0xcd, 0x25, 0x9e, - 0xd3, 0x18, 0xa5, 0xca, 0x80, 0x51, 0x80, 0x66, 0x99, 0xcb, 0xe7, 0x0a, - 0x88, 0xbd, 0xf3, 0xef, 0x12, 0xbe, 0xa9, 0xf2, 0x3b, 0xca, 0xb7, 0x1d, - 0xa5, 0xe9, 0x05, 0xca, 0x66, 0xe2, 0x4f, 0x8b, 0x3e, 0xd3, 0x99, 0xf8, - 0xa8, 0xf2, 0xc9, 0x44, 0xf8, 0x3c, 0xfc, 0x5c, 0x16, 0x7d, 0x2e, 0x6f, - 0x67, 0x33, 0x24, 0x7d, 0x0d, 0xc4, 0x73, 0x30, 0x58, 0x76, 0xee, 0x64, - 0x9e, 0x70, 0x52, 0xf8, 0x1b, 0x58, 0xd3, 0x98, 0xc7, 0x78, 0xf8, 0x0a, - 0xfa, 0x08, 0xf6, 0x55, 0xa6, 0xf0, 0x92, 0x1a, 0x5b, 0x21, 0x93, 0x71, - 0xc1, 0xfc, 0x55, 0x27, 0x1b, 0x37, 0x6a, 0xf7, 0xc3, 0x57, 0x71, 0x52, - 0xe8, 0x7d, 0x43, 0xb4, 0x24, 0x68, 0xbd, 0x52, 0x99, 0x11, 0x7e, 0x07, - 0x3e, 0x2e, 0x4d, 0x0e, 0x4a, 0x5e, 0x25, 0xcf, 0x4b, 0x7f, 0x04, 0x3f, - 0xb3, 0xc4, 0xf3, 0xa8, 0xcb, 0x7f, 0x8f, 0x52, 0x62, 0x1b, 0xfe, 0xa1, - 0x53, 0x8f, 0xd4, 0x3f, 0xc4, 0xb0, 0x66, 0xd9, 0x71, 0x8b, 0x69, 0xe3, - 0xc7, 0x9b, 0xda, 0x6d, 0xef, 0x69, 0x19, 0xcc, 0xb0, 0x32, 0xc5, 0xb7, - 0x2b, 0xa0, 0x33, 0xcf, 0x96, 0xe7, 0xf0, 0x1d, 0x99, 0x40, 0x5a, 0xe8, - 0xb2, 0x11, 0xd6, 0x4d, 0xa0, 0xa3, 0x8c, 0x88, 0x78, 0x62, 0xe2, 0x59, - 0xcb, 0x98, 0x5d, 0xc1, 0xb7, 0xa1, 0xa0, 0x9b, 0xe9, 0x9c, 0x86, 0x76, - 0x91, 0xa7, 0x2e, 0xe3, 0xbc, 0x90, 0xaf, 0xe0, 0x79, 0x3f, 0x0f, 0x64, - 0x56, 0x9e, 0xde, 0xa5, 0xf3, 0xd5, 0x12, 0x61, 0x9d, 0x0f, 0xa3, 0x79, - 0x8a, 0xc6, 0x3d, 0x1d, 0xa3, 0x70, 0x7f, 0xcb, 0x0b, 0xb4, 0xeb, 0xd6, - 0x09, 0xe0, 0x57, 0x12, 0x7b, 0x74, 0x15, 0xb1, 0x31, 0xa3, 0x2e, 0xfe, - 0xd0, 0xc6, 0xfb, 0x64, 0x31, 0x6e, 0xc0, 0x5f, 0xf7, 0x05, 0xfe, 0x8b, - 0x38, 0x42, 0x69, 0x10, 0x7a, 0x50, 0xaf, 0xc3, 0x38, 0x33, 0x81, 0xe3, - 0x7e, 0x5a, 0x2c, 0x6a, 0xbd, 0x55, 0xfa, 0x90, 0x16, 0x97, 0xf5, 0x7e, - 0xc1, 0x7f, 0x34, 0xac, 0x7a, 0x08, 0xd8, 0x64, 0xf5, 0x01, 0x4e, 0x9f, - 0x14, 0x3d, 0x6e, 0x16, 0x73, 0xd8, 0x4a, 0xce, 0x11, 0xbe, 0x2f, 0x86, - 0x9e, 0x99, 0xfb, 0x00, 0x7b, 0xde, 0x23, 0x77, 0x4c, 0x62, 0x4e, 0x7d, - 0xff, 0xe7, 0x51, 0xed, 0xdb, 0x63, 0x3e, 0xfb, 0xf6, 0xd1, 0xa0, 0x8c, - 0x73, 0x3d, 0xa7, 0xc6, 0xf8, 0xe5, 0x99, 0xfe, 0xf3, 0x0b, 0xf0, 0x1f, - 0xd5, 0xea, 0x25, 0xee, 0x09, 0xbe, 0xd2, 0xe8, 0xc3, 0x8e, 0x30, 0x3f, - 0x95, 0x74, 0x7c, 0xd2, 0x87, 0x8e, 0xfb, 0x78, 0x8f, 0x4f, 0x3c, 0x04, - 0x1d, 0x9f, 0x68, 0x4a, 0xc7, 0x87, 0xa2, 0xd2, 0x87, 0xda, 0x48, 0xc7, - 0xa8, 0xd9, 0x39, 0x59, 0x6e, 0xe6, 0xaf, 0xc2, 0x3e, 0xa0, 0xf6, 0x1c, - 0xfe, 0x04, 0xc0, 0x4a, 0xfb, 0x14, 0x10, 0xdb, 0x03, 0x3e, 0x22, 0x56, - 0xf2, 0x17, 0x94, 0x9a, 0xf7, 0xc6, 0x38, 0x37, 0xba, 0xe7, 0x7d, 0x9f, - 0x7b, 0xa0, 0x6b, 0x83, 0x16, 0xec, 0x88, 0xb4, 0xd5, 0x35, 0xbc, 0xde, - 0x0d, 0x1c, 0x29, 0xda, 0xd9, 0x12, 0x18, 0x63, 0x4f, 0x98, 0xce, 0x23, - 0x8e, 0xaf, 0x7c, 0xbe, 0xc7, 0xf3, 0x72, 0xdd, 0xe6, 0xb8, 0xc0, 0x07, - 0xe8, 0xa3, 0x91, 0x74, 0x30, 0xcd, 0x7b, 0x2a, 0xfd, 0xbd, 0x99, 0xe5, - 0x88, 0xda, 0x27, 0x1e, 0x8b, 0xe7, 0xf9, 0xd6, 0xf3, 0x61, 0x7f, 0xec, - 0x57, 0x57, 0xab, 0x79, 0xc1, 0x90, 0x05, 0x15, 0xfa, 0x05, 0xcb, 0xb9, - 0xe0, 0xb8, 0x29, 0xfa, 0x28, 0xdc, 0x2a, 0x8f, 0xb3, 0x7e, 0x88, 0x3d, - 0x84, 0xaf, 0x50, 0xfb, 0x72, 0x7f, 0x31, 0x44, 0x3d, 0x87, 0x58, 0xea, - 0x1b, 0xe4, 0xb0, 0x7e, 0x68, 0x8c, 0x23, 0xbf, 0xdb, 0xe2, 0x7b, 0xd0, - 0xff, 0x69, 0xbf, 0x95, 0xa2, 0x2e, 0xf8, 0x09, 0xd0, 0xa7, 0xd9, 0xca, - 0xd5, 0xd1, 0xd4, 0x69, 0x41, 0x53, 0xa9, 0x95, 0xd3, 0x8a, 0xa6, 0x4e, - 0x2b, 0x7f, 0xf9, 0x69, 0x45, 0x53, 0xa7, 0x15, 0x4d, 0x9d, 0x56, 0x34, - 0x75, 0x9a, 0xf1, 0x7a, 0xc4, 0xec, 0x13, 0x3a, 0xbb, 0xf6, 0x57, 0xf6, - 0x50, 0xa6, 0x88, 0xf3, 0x90, 0xc7, 0x5e, 0xba, 0x7a, 0x75, 0x48, 0xd2, - 0xd5, 0x24, 0x2d, 0xca, 0x3c, 0x39, 0x7e, 0x17, 0xf6, 0xe0, 0xeb, 0x83, - 0xd4, 0x73, 0x2f, 0x70, 0x76, 0x1e, 0x73, 0x0d, 0xd0, 0xb4, 0xe8, 0xe1, - 0xda, 0x42, 0x49, 0xb7, 0x2e, 0x6b, 0xa2, 0x7e, 0x4b, 0xda, 0x6a, 0xd9, - 0xa6, 0xb5, 0x5c, 0x1a, 0x2f, 0xa6, 0xd4, 0x7e, 0x79, 0xed, 0x98, 0x36, - 0x4a, 0x17, 0x00, 0x57, 0xe4, 0x32, 0x5a, 0xbc, 0x37, 0x02, 0x4e, 0x59, - 0xd3, 0x07, 0x06, 0xc7, 0x15, 0x0c, 0xbe, 0x22, 0xd6, 0x88, 0x5c, 0x40, - 0xf8, 0x1c, 0x9b, 0xc3, 0x21, 0x97, 0x1f, 0xe1, 0xe7, 0x30, 0xee, 0x8f, - 0x47, 0x98, 0x07, 0x6d, 0x1d, 0x0e, 0xb5, 0xb5, 0x37, 0xe3, 0x35, 0x5b, - 0xad, 0x87, 0xb9, 0xef, 0x92, 0x1d, 0x11, 0x25, 0x37, 0xa4, 0x9e, 0xfb, - 0x98, 0x63, 0xa7, 0xb3, 0x3c, 0xb7, 0xbf, 0x8f, 0xb7, 0xef, 0xa5, 0x8e, - 0x0a, 0x1d, 0x8b, 0x03, 0x9f, 0x7b, 0xd8, 0x6e, 0xe4, 0x39, 0xec, 0xaf, - 0xd0, 0xd5, 0xf8, 0x01, 0xb6, 0x4d, 0xf0, 0x2d, 0xa6, 0x11, 0xfe, 0xef, - 0x24, 0x82, 0x01, 0xcc, 0xab, 0x8b, 0xef, 0x0d, 0x93, 0xd1, 0x9b, 0xe8, - 0x6d, 0x57, 0xba, 0x29, 0xfc, 0x6e, 0xac, 0x9b, 0x1a, 0x33, 0xf1, 0x1d, - 0xaa, 0xa6, 0x0c, 0xbe, 0x6a, 0xc4, 0xb1, 0x7e, 0x56, 0x91, 0xbd, 0x00, - 0xa2, 0xea, 0xf8, 0xa7, 0x95, 0x44, 0x14, 0xc7, 0x26, 0xdd, 0x60, 0x7b, - 0x39, 0x11, 0x18, 0xd9, 0x2b, 0x74, 0xf6, 0x80, 0x7d, 0x4c, 0xe6, 0x30, - 0xd8, 0xa6, 0x15, 0xf0, 0xc3, 0x77, 0xa9, 0xeb, 0xd4, 0xf2, 0x4c, 0x81, - 0xff, 0x15, 0xfa, 0x4f, 0xa6, 0x55, 0x93, 0x10, 0xb3, 0x98, 0x14, 0xb5, - 0xce, 0xc8, 0x33, 0x3e, 0x3b, 0x0f, 0x9a, 0x85, 0xdf, 0xd0, 0x51, 0x7b, - 0xfc, 0x29, 0xe4, 0x89, 0x15, 0x16, 0x69, 0x63, 0x59, 0x01, 0xbf, 0xd8, - 0xc8, 0xc2, 0x5a, 0x6f, 0x58, 0xd4, 0x5e, 0xc3, 0xcf, 0xa9, 0xf3, 0x89, - 0xf7, 0xf3, 0xf3, 0x43, 0xe2, 0xdb, 0x72, 0xd3, 0xd7, 0x30, 0xae, 0x95, - 0x86, 0x17, 0x2a, 0x4f, 0xf1, 0x75, 0x11, 0x2f, 0xcc, 0x50, 0xbb, 0x8a, - 0x05, 0x74, 0xa9, 0xf8, 0x51, 0x84, 0x69, 0xa8, 0x56, 0x53, 0x3c, 0x5c, - 0xf5, 0x9d, 0x01, 0xb7, 0xbd, 0xbe, 0xb3, 0xaf, 0x6d, 0x22, 0x67, 0x36, - 0xc3, 0x67, 0xe4, 0x82, 0xb6, 0x91, 0xf2, 0x09, 0x5a, 0xb3, 0xb4, 0xd5, - 0xda, 0xb9, 0x6d, 0xdf, 0xd3, 0xde, 0x3a, 0xb5, 0x7a, 0xf1, 0xae, 0xd3, - 0xa1, 0xf0, 0xa8, 0x95, 0xce, 0x16, 0x3b, 0x58, 0x56, 0xa3, 0xce, 0x09, - 0xf0, 0x0a, 0x46, 0x51, 0x27, 0xf2, 0x5c, 0xa8, 0x95, 0x96, 0x97, 0x91, - 0xd3, 0xf0, 0x67, 0x7b, 0x65, 0x7e, 0x6e, 0x9a, 0xe1, 0x72, 0x88, 0xe5, - 0x9a, 0xa1, 0x62, 0x35, 0x38, 0x07, 0x9e, 0x20, 0x7a, 0x78, 0x86, 0x9e, - 0x1e, 0xed, 0x60, 0x7d, 0x5e, 0xfa, 0xfa, 0x0f, 0xf3, 0xb3, 0xbf, 0x57, - 0x4c, 0xc3, 0x4f, 0x65, 0x1e, 0xe5, 0xe7, 0x4f, 0xb3, 0x1e, 0x90, 0xa0, - 0x56, 0x5a, 0x5a, 0x6e, 0x65, 0x7d, 0xbe, 0x95, 0xf5, 0x80, 0x11, 0x73, - 0x38, 0x20, 0xde, 0x25, 0x6a, 0x52, 0x3e, 0x1b, 0x3a, 0x64, 0x1e, 0x13, - 0x79, 0x36, 0x7f, 0xa5, 0xde, 0xe5, 0x7d, 0xc7, 0x07, 0x15, 0x1c, 0x1f, - 0x0d, 0xae, 0x5e, 0xbc, 0xe3, 0x98, 0x8c, 0x7f, 0x93, 0xac, 0xf3, 0x86, - 0xc5, 0xf7, 0x17, 0x8d, 0xa9, 0x29, 0xd6, 0xff, 0xf1, 0x8d, 0xb7, 0x67, - 0x28, 0x5b, 0x3e, 0x45, 0x5f, 0x2f, 0xbb, 0x7d, 0xaf, 0xcf, 0xf0, 0x9c, - 0x65, 0xed, 0x7c, 0x1b, 0xcf, 0xeb, 0x3d, 0xc7, 0xcb, 0x2b, 0x3a, 0x28, - 0xf8, 0xad, 0x30, 0xb5, 0x7e, 0x03, 0x3e, 0x8f, 0x0a, 0x15, 0xe2, 0xf6, - 0xd5, 0xfb, 0x24, 0xfd, 0xbc, 0x37, 0x44, 0x5e, 0x2a, 0xdf, 0xcf, 0xcf, - 0x9c, 0xc3, 0xb8, 0x1b, 0x16, 0xdd, 0x76, 0x24, 0xbc, 0xff, 0x36, 0x14, - 0xa6, 0xe0, 0x1b, 0xc8, 0xf5, 0x82, 0x8e, 0xb5, 0x7a, 0xd1, 0x39, 0xc0, - 0x7c, 0xfa, 0x1b, 0xb8, 0x8f, 0xff, 0xbe, 0x81, 0xe3, 0x0e, 0x5e, 0x27, - 0xe4, 0x2c, 0x72, 0x4a, 0xc0, 0xdf, 0x0e, 0x45, 0x4c, 0x81, 0x7f, 0xcf, - 0x30, 0x4e, 0xb5, 0x08, 0x1f, 0x5f, 0x1f, 0xc6, 0x3a, 0x83, 0xac, 0x13, - 0xac, 0x5e, 0x1c, 0x3d, 0x80, 0xe3, 0x44, 0x6f, 0x90, 0x61, 0x24, 0x71, - 0xa8, 0xe1, 0x9b, 0x75, 0xa1, 0xc3, 0xa3, 0xe4, 0xfa, 0x6e, 0x1d, 0x7a, - 0x26, 0x75, 0x50, 0x8a, 0xdf, 0x31, 0x5d, 0x94, 0xeb, 0x9e, 0x2b, 0x07, - 0x49, 0xfa, 0x87, 0x52, 0x43, 0xfa, 0xfb, 0x84, 0xd4, 0x8f, 0x67, 0x6b, - 0x5a, 0xc1, 0xef, 0x1e, 0x7a, 0x50, 0xec, 0xa2, 0x75, 0x15, 0x43, 0x7a, - 0x20, 0xec, 0x29, 0xe6, 0xc5, 0xe9, 0x1e, 0xba, 0xbf, 0xdc, 0x42, 0xd4, - 0xd7, 0x21, 0x62, 0xbc, 0x0f, 0x8a, 0x8b, 0x94, 0x7c, 0xed, 0xc9, 0x21, - 0xe9, 0x4f, 0xa9, 0xe1, 0xc8, 0x03, 0x1f, 0x1c, 0x79, 0x57, 0xe0, 0xc8, - 0xf0, 0xd0, 0xc6, 0x38, 0xb2, 0x47, 0xe7, 0x22, 0x52, 0xab, 0xc2, 0x8f, - 0xd7, 0x19, 0x3f, 0x5e, 0x66, 0xfc, 0x38, 0xd2, 0x04, 0x3f, 0x0c, 0x0f, - 0x7e, 0x1c, 0x15, 0xf8, 0xf1, 0xeb, 0x43, 0x1b, 0xe1, 0xc7, 0x91, 0xe0, - 0x46, 0x3e, 0x1e, 0x8d, 0x9b, 0x03, 0xb4, 0x54, 0x74, 0x68, 0x79, 0xde, - 0x8e, 0x27, 0x68, 0x35, 0x22, 0x63, 0x83, 0x53, 0xa2, 0x4e, 0x65, 0x51, - 0xe0, 0x55, 0x5a, 0xf8, 0x2f, 0xfd, 0xbf, 0x1b, 0x68, 0x29, 0xf8, 0xcb, - 0x3d, 0x99, 0xce, 0xaf, 0x5e, 0xfc, 0x3b, 0xde, 0xc7, 0xdb, 0x2b, 0xa1, - 0x10, 0xae, 0x05, 0xa7, 0xc2, 0xb4, 0xb6, 0x82, 0xef, 0x12, 0x46, 0xe8, - 0x4e, 0x31, 0x4a, 0xb7, 0x8b, 0x03, 0xb4, 0x56, 0x1c, 0xa2, 0xbb, 0x45, - 0xbc, 0x03, 0x30, 0xe7, 0x63, 0x01, 0x73, 0x83, 0x0e, 0x87, 0x79, 0xcc, - 0xf2, 0x00, 0xad, 0x2e, 0x6b, 0x7c, 0x05, 0xae, 0x62, 0xff, 0xe1, 0x27, - 0xf0, 0xc7, 0x81, 0xe9, 0x3a, 0x1c, 0x90, 0xf7, 0x60, 0xef, 0x67, 0x1b, - 0x6b, 0x64, 0x45, 0x9e, 0xa5, 0xc9, 0x38, 0xd2, 0x32, 0x65, 0x0b, 0x5f, - 0xea, 0xe1, 0x20, 0x74, 0xd9, 0xc4, 0x3e, 0xea, 0xe1, 0x3d, 0x70, 0x90, - 0x27, 0x34, 0xc4, 0x7a, 0xe9, 0x0e, 0xa1, 0x87, 0x26, 0x9d, 0x50, 0x64, - 0x9a, 0x2a, 0x97, 0x0c, 0x07, 0x3d, 0x0f, 0xd3, 0xfc, 0x3c, 0x43, 0xf9, - 0x71, 0xba, 0x5d, 0xf8, 0xe4, 0xd5, 0x39, 0x11, 0x8b, 0x7d, 0x96, 0xe7, - 0x0c, 0xf9, 0x58, 0x8b, 0x73, 0x50, 0x35, 0xce, 0xd1, 0xce, 0xeb, 0x96, - 0xb4, 0x34, 0xe3, 0xf0, 0xb8, 0x32, 0x8f, 0x2b, 0x23, 0x76, 0xc6, 0xe7, - 0x97, 0x11, 0xb7, 0x8d, 0xd2, 0xda, 0x3c, 0x68, 0x0e, 0x7e, 0x89, 0x5a, - 0xac, 0x74, 0x6d, 0x05, 0xe7, 0xe1, 0x9b, 0xa8, 0xc5, 0x4a, 0xd7, 0x54, - 0xac, 0x74, 0x6d, 0x65, 0x4a, 0xf0, 0xe1, 0xd9, 0xff, 0xdd, 0x14, 0x60, - 0x19, 0x30, 0x85, 0x19, 0xba, 0x4e, 0x53, 0x0d, 0x7a, 0xbf, 0x4e, 0x0c, - 0x78, 0x6c, 0x58, 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d, - 0xb8, 0xfd, 0xe3, 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23, - 0x80, 0x79, 0x49, 0x18, 0x9a, 0x97, 0x60, 0x73, 0xaf, 0xfc, 0x0c, 0x90, - 0xbb, 0x7a, 0x6c, 0xc0, 0x6d, 0x7c, 0x48, 0xf9, 0x23, 0x83, 0x56, 0xfe, - 0x30, 0xb0, 0x38, 0xa9, 0x43, 0xf4, 0x37, 0xad, 0x7f, 0x2c, 0x07, 0x1b, - 0x5f, 0x6b, 0x02, 0x9a, 0xdb, 0x3c, 0x85, 0x94, 0xb9, 0x5b, 0x60, 0xbd, - 0x89, 0x75, 0x5d, 0x26, 0xb1, 0x76, 0xc3, 0xd2, 0x42, 0x0c, 0x19, 0xe9, - 0x09, 0x62, 0x06, 0x22, 0x3d, 0xd9, 0x00, 0xcb, 0x4e, 0x16, 0x60, 0x5e, - 0x11, 0x02, 0xd6, 0x0f, 0x0c, 0xd0, 0x3a, 0xe6, 0x00, 0x78, 0x2c, 0xa1, - 0x89, 0x01, 0x74, 0x07, 0x27, 0xd0, 0xfe, 0x7e, 0x65, 0xf0, 0xba, 0xe3, - 0x06, 0x09, 0x88, 0xa1, 0x8b, 0x7a, 0x14, 0xe5, 0x41, 0x79, 0xd4, 0x49, - 0x85, 0x81, 0xc4, 0xfc, 0x04, 0xf2, 0x1f, 0xd0, 0x1f, 0x20, 0x3f, 0x02, - 0xf3, 0x93, 0x33, 0x50, 0x0e, 0xb4, 0x36, 0xaa, 0x79, 0x0d, 0x48, 0x1f, - 0x28, 0x0c, 0x41, 0x65, 0x2a, 0x68, 0x8c, 0x03, 0xc8, 0x5e, 0x22, 0x04, - 0x0d, 0x3b, 0x20, 0x0d, 0x64, 0x37, 0x4f, 0x11, 0x01, 0xf3, 0x93, 0x02, - 0x84, 0x18, 0x1a, 0xe0, 0xf9, 0x89, 0x1d, 0xe8, 0x52, 0x98, 0x9b, 0xfe, - 0xff, 0x3f, 0xa6, 0xc2, 0x02, 0x4c, 0x7b, 0xa0, 0xb5, 0xb5, 0xbf, 0xff, - 0x1f, 0x10, 0x61, 0x61, 0x68, 0x81, 0xaf, 0xd1, 0x0b, 0x94, 0x07, 0x95, - 0x73, 0x0b, 0x80, 0xac, 0x36, 0x78, 0xbd, 0x0d, 0x92, 0x07, 0x89, 0xfd, - 0x02, 0x96, 0x2b, 0xff, 0xff, 0x2f, 0x85, 0xab, 0x05, 0x01, 0x00, 0xb3, - 0x28, 0x79, 0xae, 0x58, 0x7d, 0x00, 0x00, 0x00 }; + 0x1f, 0x8b, 0x08, 0x08, 0x09, 0x83, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5b, 0x7d, 0x6c, + 0x5b, 0xd7, 0x75, 0x3f, 0xef, 0xf1, 0x51, 0x7a, 0x96, 0x68, 0xf9, 0x99, + 0x7e, 0x96, 0x59, 0x4f, 0xb1, 0x49, 0xf1, 0xc9, 0xd2, 0x62, 0x2d, 0x63, + 0x34, 0x35, 0xd1, 0x3a, 0x26, 0x66, 0x48, 0xda, 0x71, 0x36, 0x67, 0xa0, + 0x1d, 0x05, 0x51, 0x51, 0xaf, 0xd0, 0x48, 0xd9, 0xcd, 0xb2, 0x0c, 0x73, + 0x96, 0xb4, 0x70, 0xbc, 0xb4, 0xa1, 0x25, 0x79, 0xf5, 0x06, 0x45, 0xcf, + 0xb3, 0x34, 0x39, 0xc0, 0x82, 0x41, 0x10, 0x9d, 0x3a, 0x7f, 0x30, 0xa5, + 0xed, 0x7c, 0x19, 0xe8, 0x12, 0x29, 0xb2, 0x93, 0xb5, 0x43, 0xd0, 0xa6, + 0x68, 0xff, 0xe8, 0x8a, 0x6e, 0x30, 0x52, 0x0c, 0xf3, 0x3a, 0xa0, 0x30, + 0xfa, 0xc7, 0xe6, 0x2d, 0x1f, 0xdc, 0xef, 0xdc, 0x77, 0x1f, 0xf9, 0x48, + 0x51, 0x96, 0x1c, 0x34, 0x5d, 0xb7, 0x99, 0x80, 0xf0, 0xde, 0xbd, 0xf7, + 0xbc, 0x7b, 0xcf, 0x3d, 0xdf, 0xe7, 0xdc, 0xab, 0x5f, 0x53, 0xa9, 0x85, + 0xe4, 0x6f, 0x2d, 0xfe, 0xc2, 0x7f, 0xf4, 0xc7, 0xb9, 0xdb, 0x3e, 0x7d, + 0x5b, 0x1f, 0x5e, 0x07, 0x54, 0xdd, 0xaf, 0x72, 0xbf, 0x0f, 0x7f, 0x26, + 0xfe, 0xfa, 0xe4, 0x7b, 0xa3, 0x9f, 0x81, 0xbf, 0x2b, 0x18, 0x1c, 0xfe, + 0x09, 0x91, 0xb2, 0x0c, 0x8c, 0xf7, 0x57, 0x2e, 0x5f, 0x7f, 0x9c, 0x17, + 0x0e, 0xaf, 0x62, 0x9e, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, + 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0xff, 0x3f, 0x3f, 0x9f, 0x13, 0x72, + 0x88, 0x98, 0x85, 0xff, 0x48, 0x57, 0xe3, 0x89, 0xa1, 0xa4, 0x45, 0xba, + 0x2f, 0x7e, 0x65, 0x28, 0x67, 0x11, 0x25, 0x8a, 0xdb, 0xc3, 0x29, 0xfa, + 0xb0, 0x9c, 0x37, 0x35, 0xe2, 0xfe, 0x5b, 0xe2, 0x1f, 0x3c, 0xfd, 0xfa, + 0x9d, 0x91, 0xab, 0xb3, 0x3e, 0xd2, 0x8d, 0xf8, 0xcb, 0xba, 0xb1, 0x8d, + 0xf4, 0x0e, 0x7c, 0xf3, 0x5c, 0xf7, 0x7f, 0xa8, 0xd4, 0xe6, 0xce, 0x75, + 0xa5, 0xfc, 0x7a, 0x37, 0xe5, 0x37, 0xc7, 0x75, 0x52, 0xe3, 0x5d, 0x3f, + 0x48, 0xfa, 0x8c, 0x61, 0x5f, 0xdc, 0xa0, 0xf9, 0x12, 0x65, 0x0e, 0x4c, + 0xf0, 0x1a, 0xb1, 0x75, 0xf7, 0x62, 0x2e, 0x2d, 0x3e, 0x3c, 0xf4, 0x67, + 0xd6, 0xd3, 0x65, 0xd5, 0xb2, 0x7a, 0xe6, 0x28, 0x30, 0xf0, 0x7c, 0x3f, + 0xc6, 0x8b, 0x91, 0x1e, 0xa2, 0x3b, 0x49, 0xb5, 0xf2, 0x01, 0x9f, 0xa5, + 0x53, 0xb2, 0x64, 0x51, 0xaa, 0x44, 0xf4, 0x77, 0x45, 0x85, 0x9e, 0xb7, + 0xda, 0x69, 0xae, 0xf7, 0x83, 0x72, 0x02, 0xb8, 0xbc, 0x6d, 0x0d, 0x0f, + 0x8d, 0x5b, 0x3c, 0x57, 0x7c, 0x9d, 0x83, 0x6f, 0x6f, 0x5b, 0xce, 0xd2, + 0x68, 0xb4, 0xc8, 0x7d, 0xbd, 0x2d, 0xdc, 0xe7, 0x8f, 0x3f, 0x1c, 0x7c, + 0xde, 0x0a, 0xc8, 0xbe, 0x1f, 0xa5, 0x92, 0x98, 0x6f, 0xac, 0xc8, 0xb0, + 0xcf, 0xde, 0x91, 0xb3, 0x4c, 0xd9, 0x6f, 0xc5, 0x93, 0x56, 0x08, 0xfd, + 0x1d, 0x72, 0x2c, 0xbd, 0x2e, 0x67, 0x59, 0x72, 0xac, 0x88, 0x6f, 0x7a, + 0x65, 0xff, 0x3b, 0xa9, 0x9c, 0x15, 0x93, 0xfd, 0x57, 0x93, 0x49, 0xab, + 0x5f, 0xf6, 0x1f, 0xbe, 0x2b, 0x67, 0xc5, 0x65, 0xff, 0xf7, 0x81, 0x8b, + 0x41, 0xc7, 0x8a, 0x61, 0xfc, 0x25, 0x30, 0xfe, 0x9a, 0x41, 0x6d, 0x19, + 0x8c, 0x61, 0xef, 0xb6, 0x4e, 0x97, 0x7d, 0x21, 0x7a, 0xbd, 0xfb, 0x32, + 0x68, 0x63, 0xd0, 0xd9, 0x12, 0x29, 0x99, 0xee, 0x10, 0x68, 0x62, 0xd2, + 0xb9, 0x52, 0x2b, 0xf9, 0x4e, 0xfa, 0xb0, 0xe7, 0xcf, 0x51, 0xd6, 0xd4, + 0x69, 0xfd, 0x8c, 0x42, 0x9d, 0x7d, 0x6b, 0x28, 0x61, 0xe4, 0x29, 0xd5, + 0x8d, 0x28, 0x6e, 0xd2, 0x24, 0x6d, 0x66, 0x71, 0xbd, 0x8a, 0x1e, 0x95, + 0x22, 0xa1, 0x2c, 0x28, 0x3c, 0x72, 0xfa, 0x5d, 0x8e, 0x39, 0xb1, 0x26, + 0xff, 0x85, 0x29, 0x35, 0x71, 0x2b, 0x0d, 0x1b, 0x8c, 0x0f, 0x80, 0x05, + 0x1f, 0x74, 0x25, 0x79, 0x2a, 0x44, 0xc7, 0xec, 0x80, 0x92, 0x3a, 0x75, + 0x37, 0x25, 0x63, 0x64, 0xaa, 0xd4, 0x25, 0xbe, 0x2d, 0x14, 0x43, 0x34, + 0x6e, 0x93, 0x92, 0xb4, 0x99, 0x5e, 0xed, 0x18, 0x6f, 0x13, 0xb0, 0xe8, + 0xeb, 0xf0, 0x51, 0x97, 0x91, 0x22, 0x9d, 0x71, 0x46, 0x7f, 0x50, 0x49, + 0x8b, 0x39, 0x44, 0x7f, 0x78, 0x8c, 0x02, 0x74, 0xba, 0x68, 0x4a, 0xd8, + 0x72, 0x39, 0x19, 0x33, 0x00, 0x07, 0xda, 0xd9, 0x26, 0x0d, 0xe3, 0x39, + 0x6a, 0xf3, 0xfa, 0x21, 0xc8, 0xcc, 0xb7, 0x87, 0xb2, 0xd3, 0x62, 0xbe, + 0xb0, 0x2f, 0xce, 0xf3, 0x75, 0x00, 0xee, 0x1d, 0xe0, 0xa5, 0x90, 0x26, + 0x78, 0x95, 0xa0, 0xec, 0x84, 0x02, 0x79, 0xc2, 0x53, 0xd0, 0x2d, 0x0d, + 0xfc, 0x35, 0xb2, 0xfa, 0x14, 0xca, 0x59, 0x9b, 0x28, 0x6f, 0xa0, 0x5d, + 0xbc, 0xa0, 0x26, 0xed, 0x66, 0x4a, 0x69, 0x61, 0xec, 0x5f, 0xc8, 0x0a, + 0x8d, 0xe1, 0x1b, 0xd5, 0x62, 0x98, 0x9f, 0x61, 0xef, 0xc3, 0x82, 0xfe, + 0x4d, 0xf1, 0xfd, 0x74, 0x69, 0x22, 0xaf, 0x26, 0x4b, 0xed, 0xe4, 0x9b, + 0x89, 0x40, 0x9a, 0xc7, 0xd5, 0xd4, 0x19, 0x8d, 0xfc, 0x93, 0x0a, 0x41, + 0x3e, 0x0c, 0x5f, 0xfc, 0xb8, 0xba, 0xb3, 0x74, 0x41, 0x4d, 0x95, 0xf8, + 0x1b, 0xc0, 0x16, 0x55, 0xd0, 0x96, 0xdf, 0xb7, 0x83, 0x96, 0x34, 0xac, + 0xc6, 0x75, 0x3d, 0x51, 0x64, 0x99, 0xe5, 0x6f, 0xc1, 0x0f, 0xec, 0xe5, + 0x9c, 0x0d, 0xfe, 0x08, 0x7e, 0x85, 0xc1, 0xaf, 0x6f, 0x82, 0x5f, 0xfd, + 0xe0, 0x53, 0x8c, 0xde, 0x28, 0xf5, 0xd2, 0x6b, 0xa5, 0x1e, 0x7a, 0x15, + 0x32, 0xf9, 0x4a, 0x29, 0x4c, 0x2f, 0x97, 0x3a, 0xe8, 0xa5, 0x52, 0x88, + 0xce, 0x0b, 0x1e, 0xa6, 0x21, 0xff, 0x82, 0xaf, 0xfa, 0x26, 0xf0, 0xa4, + 0x1d, 0x3c, 0x59, 0x0f, 0x79, 0xd9, 0x08, 0xf9, 0x9b, 0xee, 0xd6, 0x69, + 0xaa, 0x9b, 0x12, 0x41, 0xf4, 0x6f, 0x89, 0x6b, 0x82, 0x4e, 0x1a, 0xc6, + 0xc7, 0x26, 0xfc, 0x94, 0x32, 0x4e, 0xd3, 0x7b, 0x93, 0x1a, 0x8d, 0x95, + 0xa6, 0x36, 0x3a, 0x7c, 0xe3, 0xf6, 0x2c, 0x5d, 0x44, 0x5f, 0xca, 0x98, + 0xa5, 0x4b, 0xdb, 0x54, 0x1a, 0x9d, 0xfe, 0x1b, 0x4a, 0x9e, 0x39, 0x4d, + 0x3f, 0xfe, 0x3a, 0x51, 0x06, 0x34, 0x51, 0xfb, 0x7e, 0x5a, 0x4e, 0x18, + 0xa0, 0x45, 0x5f, 0xaf, 0x90, 0x08, 0xb5, 0x8f, 0x79, 0x19, 0x86, 0xae, + 0x68, 0x4a, 0xca, 0x7e, 0x01, 0xfa, 0xd2, 0xaa, 0x24, 0xa7, 0x88, 0x72, + 0x53, 0x65, 0xca, 0xc5, 0xfc, 0xf4, 0x98, 0x51, 0xa6, 0x74, 0xac, 0x89, + 0xbe, 0x68, 0xb4, 0xd3, 0x68, 0xef, 0x6f, 0xf8, 0xdc, 0x5c, 0x65, 0xba, + 0xd4, 0x8f, 0x77, 0xee, 0x23, 0x9a, 0x12, 0xef, 0x4e, 0x7f, 0xbe, 0xe4, + 0xa7, 0x84, 0x99, 0x0f, 0x69, 0xf4, 0x8e, 0xcf, 0xc1, 0x29, 0xe1, 0x8e, + 0x81, 0x57, 0xc3, 0xb0, 0x0f, 0x8e, 0x0c, 0x66, 0x27, 0xd6, 0x5c, 0x4b, + 0x88, 0x6e, 0xc0, 0x0b, 0xd9, 0xd3, 0x18, 0x8f, 0x61, 0x25, 0x6e, 0x52, + 0xa7, 0xd0, 0x8d, 0x7e, 0xc0, 0x0c, 0x28, 0xfb, 0x4a, 0xcc, 0x6b, 0xbc, + 0x17, 0x19, 0xd7, 0xcd, 0x80, 0xd5, 0xf0, 0x4c, 0x48, 0x9c, 0xbd, 0x78, + 0xf2, 0x5c, 0x8c, 0x27, 0x3f, 0x7f, 0xcf, 0x83, 0xe7, 0xe7, 0x2b, 0xef, + 0x53, 0x9e, 0xf7, 0x7c, 0xe9, 0x4f, 0x03, 0x0e, 0x7e, 0x4c, 0xcf, 0x01, + 0x1a, 0x9d, 0x38, 0x2c, 0xd7, 0xc2, 0x7b, 0x91, 0xd7, 0x38, 0x0d, 0x3a, + 0x09, 0xc8, 0x15, 0xd6, 0x3a, 0xec, 0x59, 0xeb, 0x49, 0xcf, 0x5a, 0x4f, + 0x7a, 0xd6, 0xca, 0x83, 0xb6, 0xb4, 0x4e, 0xb5, 0xfc, 0xd0, 0x51, 0xee, + 0x39, 0x8e, 0x39, 0x9f, 0x03, 0x5f, 0xbe, 0x0a, 0x98, 0x38, 0x2d, 0xda, + 0xa0, 0xc7, 0x94, 0x46, 0x7b, 0x4d, 0x7e, 0x7f, 0xb1, 0xd5, 0xc1, 0x8b, + 0xdf, 0x2f, 0x48, 0x9c, 0x5a, 0x1d, 0xb8, 0xd2, 0x15, 0xa1, 0xff, 0xf3, + 0x25, 0xd6, 0x4f, 0x8a, 0xf9, 0x2c, 0x3a, 0x94, 0x8e, 0xb5, 0xd3, 0x98, + 0xa1, 0xc4, 0x46, 0x7b, 0x9a, 0x99, 0x8e, 0x09, 0xd5, 0x6a, 0x85, 0x0e, + 0x50, 0x58, 0x65, 0xdb, 0x25, 0xf0, 0x7b, 0x49, 0xe2, 0x61, 0x70, 0x3b, + 0xa3, 0x5a, 0xc1, 0xba, 0x7e, 0x96, 0xdf, 0x57, 0xf0, 0xce, 0x32, 0x9c, + 0xd4, 0x9c, 0xb5, 0x5f, 0x45, 0x9b, 0xed, 0xce, 0x66, 0xd9, 0x76, 0xc7, + 0xff, 0xa0, 0xa9, 0xb6, 0xfd, 0x05, 0xb3, 0xb6, 0xed, 0xea, 0x82, 0xd7, + 0x66, 0xf1, 0xde, 0xc2, 0xe4, 0xb3, 0x58, 0x8e, 0xfc, 0xc0, 0x35, 0x06, + 0x3d, 0x6c, 0x96, 0x38, 0x7c, 0x4b, 0xe2, 0x00, 0x5c, 0x01, 0x37, 0x5a, + 0xe2, 0x6f, 0x04, 0x4b, 0xea, 0xda, 0x4c, 0x43, 0xf7, 0x7d, 0xad, 0x18, + 0xbf, 0xec, 0xe3, 0x75, 0xdc, 0x27, 0x29, 0x69, 0xe8, 0xc9, 0xd8, 0xb4, + 0x46, 0xd9, 0xd8, 0x26, 0x21, 0xd7, 0xd9, 0x58, 0xd5, 0x06, 0x8c, 0x4e, + 0xd4, 0xdb, 0x00, 0xfe, 0x8e, 0x6d, 0x80, 0xa3, 0xfb, 0x63, 0xd3, 0x6c, + 0x0b, 0x1c, 0xdd, 0x3f, 0x36, 0xc1, 0x36, 0x41, 0xcc, 0x09, 0xfd, 0x67, + 0x3b, 0xe0, 0xda, 0x00, 0xfe, 0x86, 0x6d, 0x80, 0x0f, 0xf2, 0xcd, 0xf3, + 0xb9, 0x6b, 0x8f, 0xd7, 0xcd, 0x3b, 0xce, 0xb6, 0x45, 0xd9, 0xd9, 0xcd, + 0x30, 0xc7, 0xb1, 0x76, 0x80, 0x0a, 0xd3, 0xcc, 0xc3, 0x48, 0xe8, 0x08, + 0x1d, 0x17, 0x36, 0xef, 0xf4, 0x04, 0x25, 0x0e, 0x9e, 0x18, 0xa0, 0x34, + 0x6c, 0xc0, 0xdc, 0xc4, 0xb5, 0x32, 0xf8, 0x78, 0x47, 0x13, 0x59, 0xb0, + 0x75, 0xf0, 0x93, 0xfd, 0x7e, 0xf2, 0xc5, 0xe3, 0x90, 0xb7, 0x98, 0xf0, + 0x5d, 0xd5, 0x9f, 0xa6, 0xed, 0xaa, 0x69, 0x37, 0xc1, 0x3f, 0x62, 0xde, + 0xfe, 0x98, 0x90, 0x4d, 0xef, 0x2f, 0x09, 0x1b, 0x94, 0x8c, 0x7d, 0x08, + 0xf9, 0x75, 0x69, 0xe4, 0xea, 0x1f, 0xdb, 0xfa, 0x2b, 0x1e, 0x1f, 0xb2, + 0x05, 0x76, 0xdf, 0x84, 0x3c, 0xb9, 0x76, 0x9f, 0xed, 0x71, 0x88, 0x6d, + 0x26, 0xf4, 0x8d, 0x6d, 0x70, 0x80, 0xd4, 0x19, 0x4d, 0xda, 0x69, 0x5d, + 0xda, 0xe9, 0x00, 0x6c, 0x34, 0xb7, 0x0d, 0xd9, 0x36, 0x45, 0x1b, 0xf6, + 0x1a, 0xf6, 0x70, 0x77, 0x3a, 0x35, 0xc1, 0xfe, 0x10, 0xbe, 0x7b, 0x86, + 0x75, 0xf8, 0xdb, 0x43, 0x23, 0xd3, 0xc2, 0x07, 0xb0, 0xff, 0x80, 0x65, + 0x66, 0x1b, 0xce, 0xb6, 0x1c, 0xfb, 0x2e, 0x62, 0xdd, 0x8a, 0xad, 0x64, + 0x39, 0xf1, 0xe2, 0xc5, 0x38, 0xad, 0x21, 0xf5, 0xa4, 0x43, 0x6b, 0x35, + 0xfe, 0xa8, 0x46, 0x2d, 0x4c, 0x63, 0xc6, 0x7f, 0x2b, 0x70, 0xe6, 0x7d, + 0xfd, 0x4f, 0xe0, 0xcc, 0xeb, 0xd6, 0xe3, 0x4d, 0x7a, 0x6b, 0xfc, 0xac, + 0xfe, 0xf0, 0x33, 0xa4, 0x37, 0xc7, 0xcf, 0xd2, 0xbf, 0x58, 0x74, 0x9f, + 0x0e, 0x3f, 0xdb, 0xad, 0xc0, 0xcf, 0x16, 0xa1, 0xef, 0x53, 0x3a, 0x1d, + 0x3c, 0x15, 0xc9, 0xfc, 0x2b, 0x45, 0x61, 0x3f, 0x76, 0xd0, 0xc8, 0x94, + 0x42, 0x7a, 0x17, 0xb5, 0xc3, 0x7f, 0xf4, 0x37, 0x61, 0xfe, 0x5d, 0x44, + 0x9b, 0x1d, 0xbf, 0xd9, 0x15, 0x1e, 0x05, 0xff, 0xd3, 0x2f, 0x7e, 0x05, + 0xdf, 0x3c, 0x4d, 0x07, 0xa7, 0x0e, 0x2b, 0x39, 0xfb, 0x08, 0xe0, 0x97, + 0x83, 0xd5, 0x01, 0x9b, 0x07, 0xec, 0x97, 0x31, 0xef, 0xd3, 0xa4, 0xdf, + 0x1e, 0x19, 0x48, 0x28, 0xc0, 0xe3, 0x45, 0x01, 0x2f, 0x7d, 0x71, 0x97, + 0xb1, 0x53, 0xf0, 0x3f, 0x40, 0xef, 0x15, 0x2f, 0x80, 0xbe, 0xbd, 0xf0, + 0x39, 0x91, 0x67, 0x61, 0x93, 0xe1, 0x8f, 0x22, 0x57, 0x31, 0x2d, 0x7c, + 0x11, 0x29, 0x0f, 0x76, 0xa7, 0x41, 0xef, 0x38, 0xfc, 0xd3, 0x00, 0xfc, + 0x53, 0x0c, 0xbe, 0xa9, 0x07, 0x7e, 0xc9, 0x82, 0x5f, 0x0a, 0x83, 0x1f, + 0x06, 0xcd, 0xc2, 0x47, 0xcd, 0x42, 0xfe, 0xe7, 0x66, 0x48, 0x19, 0x04, + 0xad, 0xcf, 0xc1, 0x3f, 0x26, 0x63, 0x77, 0x42, 0xcf, 0x22, 0x17, 0x66, + 0xd5, 0x41, 0xca, 0xc1, 0x9f, 0x77, 0x6e, 0x8b, 0x62, 0xbd, 0x26, 0x4a, + 0x84, 0x5c, 0x1d, 0xe5, 0xdf, 0x7e, 0x85, 0xac, 0x7f, 0x06, 0xef, 0x22, + 0x61, 0xa2, 0x3d, 0x94, 0xb5, 0xa3, 0x46, 0xa7, 0xda, 0x03, 0x18, 0x6e, + 0x87, 0x95, 0x03, 0x53, 0x11, 0x05, 0xfb, 0x03, 0xcd, 0x27, 0x60, 0xeb, + 0xcb, 0x34, 0x1e, 0x63, 0x3d, 0x29, 0xd3, 0xf3, 0xb1, 0xc8, 0x40, 0x9e, + 0x5a, 0xe9, 0x98, 0x39, 0x21, 0x7c, 0xbc, 0x16, 0x3f, 0x21, 0x74, 0x2c, + 0x67, 0xe1, 0x59, 0xec, 0x54, 0xb2, 0x53, 0xbc, 0x7e, 0x14, 0x5a, 0xee, + 0xc7, 0x93, 0xe7, 0x07, 0xdd, 0xfa, 0x49, 0x39, 0xd8, 0x9d, 0x87, 0x77, + 0x88, 0x18, 0x8b, 0x58, 0x39, 0x35, 0x11, 0x0d, 0x45, 0x55, 0x8d, 0x86, + 0x35, 0x85, 0x46, 0x61, 0x6f, 0xd2, 0xb1, 0xff, 0x2c, 0x1f, 0x33, 0x79, + 0xbc, 0x99, 0xbe, 0x2a, 0xfc, 0x0d, 0xd6, 0x2e, 0x4c, 0x63, 0x5d, 0x3f, + 0xf8, 0xcb, 0xeb, 0xf2, 0x3c, 0x68, 0xc3, 0xf6, 0x6b, 0x56, 0xe4, 0xd9, + 0x3c, 0xed, 0x00, 0x6d, 0xd9, 0x66, 0xc1, 0x3e, 0x0c, 0x60, 0xed, 0x5e, + 0xd8, 0x4f, 0x3c, 0x93, 0xbd, 0x1c, 0x07, 0x05, 0x68, 0xd8, 0x64, 0x79, + 0xd4, 0xe5, 0x98, 0xe9, 0x19, 0xf3, 0xcb, 0xb1, 0x20, 0xfe, 0xe0, 0x7f, + 0x4d, 0x96, 0x19, 0x6e, 0x73, 0x4c, 0xc6, 0x34, 0x09, 0xd3, 0xdc, 0x64, + 0x02, 0x34, 0x8b, 0x9c, 0x4d, 0x10, 0xd3, 0x0c, 0x46, 0x7b, 0x7f, 0x82, + 0xbe, 0x64, 0xaf, 0xf7, 0x3b, 0xb6, 0xb0, 0x55, 0x49, 0xc1, 0x17, 0xa8, + 0x56, 0x0b, 0x7c, 0x45, 0x98, 0x5e, 0x15, 0xb0, 0x64, 0xa8, 0xf1, 0x68, + 0xe8, 0x4b, 0x74, 0xab, 0xb0, 0x11, 0x09, 0xc3, 0x4b, 0xe3, 0xff, 0x52, + 0xc9, 0x72, 0xbf, 0x69, 0xa5, 0xec, 0x20, 0xf3, 0x89, 0xd7, 0x33, 0x68, + 0xae, 0xe4, 0xbc, 0xfb, 0x10, 0xa3, 0x16, 0x60, 0x6b, 0xce, 0x4f, 0xaa, + 0xf4, 0xf8, 0x1d, 0xf0, 0x65, 0xb1, 0x6d, 0x58, 0xcb, 0xc4, 0x78, 0x1e, + 0x6d, 0x15, 0x6d, 0xe8, 0x99, 0x11, 0x02, 0x8f, 0xb9, 0x9f, 0xe1, 0x4c, + 0xfc, 0xbd, 0xcf, 0xb1, 0x75, 0x3e, 0xab, 0xde, 0x4a, 0x14, 0x64, 0x7a, + 0xc5, 0x40, 0x2b, 0xcb, 0x50, 0xd5, 0x6d, 0xc2, 0x5f, 0x3b, 0xb6, 0xc4, + 0x82, 0x2e, 0xc2, 0xe6, 0xf6, 0x79, 0x75, 0x91, 0xe3, 0x09, 0x57, 0x17, + 0x23, 0xa1, 0x84, 0x0a, 0x5b, 0xdc, 0xa7, 0xd1, 0x09, 0xd1, 0x56, 0x28, + 0x31, 0x18, 0x09, 0x2d, 0xa8, 0x1c, 0x4b, 0x33, 0x6c, 0x18, 0xf1, 0x4a, + 0x40, 0xc2, 0x22, 0x9e, 0xb3, 0xdd, 0x98, 0x30, 0x84, 0x7e, 0x53, 0xf4, + 0x1f, 0xab, 0xe8, 0xa8, 0x13, 0xff, 0xa9, 0x88, 0x11, 0x0b, 0x88, 0x11, + 0x53, 0x42, 0x47, 0x8d, 0x04, 0x72, 0x04, 0xd0, 0xdc, 0xd1, 0xcf, 0x42, + 0x91, 0x71, 0xc9, 0xb1, 0x5c, 0x0e, 0x00, 0x99, 0x13, 0x8e, 0x7d, 0xa4, + 0x3c, 0xc7, 0x91, 0xa3, 0xea, 0x53, 0x34, 0x5c, 0x60, 0x3f, 0x8e, 0x3f, + 0x9b, 0x6d, 0x2d, 0xec, 0xa3, 0xf0, 0xc5, 0x51, 0xf0, 0x39, 0x0f, 0x1a, + 0xac, 0x97, 0x74, 0xdd, 0x4f, 0x07, 0xec, 0x3d, 0xa0, 0x79, 0x9c, 0x46, + 0x4e, 0x8d, 0xb0, 0xcc, 0xf6, 0x14, 0x28, 0xd2, 0x73, 0x8c, 0xb6, 0x1b, + 0x73, 0x2c, 0xdf, 0x83, 0xe5, 0x1d, 0xe0, 0x85, 0xd0, 0x51, 0xc8, 0x20, + 0x65, 0x0b, 0x23, 0xf4, 0x58, 0x89, 0xfb, 0xf2, 0xa0, 0x1d, 0xe2, 0xda, + 0xfe, 0xfd, 0x52, 0xce, 0x31, 0x9f, 0xe6, 0xce, 0x37, 0x22, 0xe7, 0x63, + 0x38, 0x86, 0xe1, 0x6f, 0xaa, 0xf3, 0xee, 0x14, 0x3c, 0x8d, 0x18, 0x5d, + 0x6a, 0x79, 0x87, 0x1f, 0xe3, 0xcf, 0xf7, 0xf3, 0x3b, 0xe6, 0x81, 0xef, + 0x6f, 0xb6, 0xf6, 0x00, 0x76, 0x10, 0x73, 0xfa, 0xa9, 0xb3, 0xdd, 0xc5, + 0x37, 0x81, 0xb5, 0xd9, 0xcf, 0x31, 0x9f, 0x1f, 0xa1, 0xec, 0xa9, 0x7c, + 0x8f, 0x0a, 0x19, 0x9b, 0xcd, 0x28, 0xe4, 0xb7, 0x1e, 0xa6, 0xdc, 0xa9, + 0xa3, 0x6c, 0x37, 0x40, 0xab, 0x3d, 0xb4, 0x6b, 0x22, 0xd2, 0x73, 0x80, + 0x34, 0xb1, 0xce, 0x5b, 0x24, 0xe8, 0x1f, 0x9b, 0x15, 0xbe, 0x20, 0x43, + 0xe9, 0x89, 0xed, 0xa1, 0x4b, 0xe8, 0x1b, 0x1e, 0x8c, 0x84, 0x17, 0xe8, + 0x09, 0xd0, 0xe5, 0x23, 0xf8, 0x22, 0xab, 0x67, 0x0c, 0x3a, 0x84, 0x9c, + 0x0a, 0xeb, 0x8f, 0x4a, 0xda, 0xe0, 0xbb, 0xcc, 0x51, 0xd0, 0x8f, 0xf2, + 0x0e, 0x4d, 0x99, 0x9e, 0x4c, 0xcb, 0xaf, 0xc0, 0xf6, 0x1c, 0x11, 0xb1, + 0x4b, 0x56, 0xd0, 0xee, 0xd2, 0x06, 0x47, 0x0e, 0x60, 0x8b, 0x30, 0xef, + 0xe5, 0x41, 0x85, 0xb6, 0x20, 0x4e, 0x3f, 0x24, 0x78, 0xeb, 0xa3, 0x7d, + 0x66, 0xd4, 0xd8, 0x47, 0xf3, 0x7e, 0x27, 0x56, 0xc0, 0x3c, 0x3d, 0xf7, + 0x60, 0x0f, 0x90, 0x53, 0xfb, 0xeb, 0xeb, 0xa8, 0x2d, 0x12, 0x4e, 0xa8, + 0x09, 0xfa, 0x93, 0xd2, 0xdd, 0xe4, 0xe8, 0x77, 0x2b, 0xdb, 0x7e, 0xf0, + 0xb0, 0xd3, 0x69, 0x5b, 0x78, 0x16, 0x3a, 0xb1, 0x1e, 0xe3, 0xfe, 0xac, + 0xc0, 0x7d, 0x84, 0xba, 0xa1, 0x6b, 0x22, 0x8f, 0x39, 0x51, 0x8b, 0x17, + 0xf3, 0xbc, 0x9e, 0xcf, 0x5f, 0xc6, 0x3c, 0xdc, 0xcf, 0x70, 0x78, 0x2f, + 0x3c, 0x41, 0x23, 0x90, 0xc7, 0x5c, 0x7f, 0x57, 0x68, 0x0c, 0xdf, 0xa4, + 0x4a, 0x4d, 0x74, 0x54, 0xe3, 0xf1, 0x48, 0x38, 0xaf, 0x1e, 0x42, 0xdc, + 0xf3, 0xb8, 0xea, 0xb7, 0x7e, 0xe6, 0x67, 0xbf, 0xe3, 0xb7, 0xae, 0x29, + 0xd5, 0xb9, 0x10, 0x87, 0x8a, 0xdc, 0x60, 0x41, 0x19, 0x2c, 0x5d, 0x52, + 0x92, 0x85, 0x6b, 0x4a, 0xaa, 0xc4, 0x30, 0x8e, 0xce, 0x67, 0xcf, 0x74, + 0x82, 0x4e, 0x1f, 0x89, 0xef, 0xe6, 0x7a, 0x8f, 0x50, 0xea, 0xd4, 0xad, + 0x94, 0x9e, 0xe6, 0xbc, 0x34, 0x02, 0x7c, 0x3f, 0x2a, 0xe7, 0x62, 0x41, + 0xca, 0x9d, 0xe1, 0x31, 0xb6, 0x5f, 0xd6, 0xd5, 0x45, 0x1f, 0xef, 0x9f, + 0xf9, 0x6f, 0x52, 0xc1, 0x7e, 0x53, 0xd2, 0x8f, 0xdf, 0x7d, 0x9c, 0x93, + 0xe1, 0xf7, 0x6f, 0x86, 0xd3, 0xb7, 0x95, 0x16, 0x36, 0xdc, 0xc8, 0x3e, + 0x57, 0xb3, 0xc7, 0x47, 0x7d, 0x7e, 0x6b, 0x7b, 0x13, 0xb5, 0x84, 0x80, + 0xc3, 0x4a, 0x7b, 0x64, 0x98, 0x5f, 0x87, 0x1c, 0xb0, 0x4d, 0xd9, 0x0d, + 0x7e, 0x5a, 0x6c, 0xc3, 0x60, 0x93, 0x76, 0x53, 0xae, 0xc4, 0xb2, 0x1d, + 0x35, 0x32, 0x90, 0xb1, 0x34, 0x75, 0xb1, 0x1e, 0xb9, 0xba, 0x07, 0xdb, + 0x9d, 0x87, 0xed, 0x46, 0x3c, 0x64, 0x53, 0xbe, 0x29, 0xce, 0x36, 0xbc, + 0x0b, 0xb2, 0x85, 0xbe, 0x62, 0x55, 0x17, 0x77, 0x2d, 0xc1, 0x5d, 0x5b, + 0xc2, 0xa3, 0x02, 0xd5, 0xe2, 0x3f, 0x4b, 0x8c, 0xff, 0x5f, 0x00, 0xff, + 0xcf, 0x01, 0x7f, 0xc6, 0xa9, 0x31, 0xfe, 0x3b, 0x2b, 0xf8, 0x33, 0x0c, + 0xfc, 0x1c, 0x64, 0xf1, 0x0d, 0xe8, 0xe2, 0x6b, 0x36, 0x7c, 0x9d, 0x0d, + 0xff, 0x67, 0xc3, 0xdf, 0xd9, 0xf0, 0x8b, 0x36, 0x7c, 0x1e, 0xf6, 0x74, + 0x0e, 0x36, 0xe9, 0xac, 0x9d, 0x34, 0x58, 0x9f, 0x92, 0x31, 0xf6, 0x9d, + 0xbb, 0x65, 0xde, 0x1d, 0x92, 0x71, 0xf7, 0xa7, 0x64, 0x2c, 0x7b, 0x00, + 0xb1, 0xec, 0x66, 0x1a, 0xed, 0xe1, 0x9c, 0xa4, 0x05, 0xcf, 0x75, 0x78, + 0x22, 0x6e, 0xed, 0x49, 0x48, 0xbd, 0xfc, 0x0c, 0x62, 0x5c, 0xd8, 0xff, + 0x1e, 0xe4, 0x37, 0x19, 0xc4, 0x6a, 0x56, 0x1f, 0xc7, 0xe5, 0xb0, 0x65, + 0xef, 0x37, 0x39, 0x76, 0xfe, 0x2e, 0x19, 0x03, 0xbb, 0xed, 0x56, 0xc0, + 0xa4, 0xd1, 0xd7, 0x8a, 0x6f, 0x7e, 0x07, 0xb2, 0xdf, 0x86, 0xf6, 0xce, + 0x3a, 0x18, 0xe4, 0xb3, 0x56, 0x16, 0x7d, 0x11, 0xc0, 0xb4, 0x61, 0x9d, + 0x0e, 0xb4, 0xf7, 0xa0, 0x7d, 0x8b, 0xb3, 0x8e, 0xf1, 0x2b, 0x68, 0xa7, + 0xea, 0xbe, 0xd9, 0x8a, 0xbe, 0x4c, 0x5d, 0xdf, 0x9b, 0xe8, 0x4b, 0xa2, + 0x6f, 0x51, 0x7e, 0x97, 0x47, 0x3b, 0x52, 0x07, 0xb3, 0x88, 0x3e, 0xc6, + 0xf1, 0x5b, 0x78, 0xde, 0x47, 0xa3, 0x19, 0x8e, 0x03, 0xdc, 0xb1, 0xdc, + 0x7a, 0x6a, 0xe3, 0xdc, 0xf7, 0x43, 0x21, 0x3b, 0xf3, 0xd2, 0x46, 0xa7, + 0x27, 0xd8, 0x4f, 0x8c, 0x20, 0xee, 0xe1, 0x71, 0xe1, 0x9c, 0x3c, 0xfd, + 0x1f, 0x00, 0xf6, 0x61, 0x8c, 0x21, 0x56, 0xb7, 0xcb, 0x4d, 0x8d, 0xc7, + 0x1f, 0xc5, 0xf8, 0x5f, 0xca, 0x6f, 0x2b, 0x73, 0x03, 0xfe, 0x1b, 0x75, + 0x7d, 0x6a, 0xb0, 0xb6, 0xbd, 0xd6, 0xf3, 0xbe, 0x4d, 0x5f, 0xfa, 0xfd, + 0x48, 0x1d, 0xfc, 0xef, 0x6e, 0xa8, 0x6d, 0x3f, 0xc5, 0xdf, 0x20, 0x87, + 0x70, 0xdb, 0x09, 0xc8, 0x1d, 0xdb, 0xa4, 0xfa, 0x79, 0x3e, 0x6b, 0xd4, + 0xf6, 0x6d, 0x32, 0x6b, 0xdb, 0x1c, 0x27, 0x31, 0x5c, 0x08, 0xf2, 0xde, + 0xa1, 0xec, 0xb2, 0x7f, 0x13, 0xe3, 0x61, 0xe5, 0x5e, 0xdb, 0x8b, 0x67, + 0x48, 0xe6, 0x46, 0xe1, 0x4a, 0xcc, 0x3b, 0x5f, 0x0a, 0x40, 0xae, 0x3e, + 0x0f, 0x9e, 0x73, 0xdc, 0x53, 0xd5, 0xf1, 0xf7, 0x68, 0x39, 0x1d, 0x67, + 0x1f, 0xc0, 0x31, 0xfe, 0x36, 0x11, 0x1f, 0xfb, 0xe2, 0x4f, 0x70, 0x0c, + 0xf6, 0xb4, 0xe3, 0x5b, 0x2c, 0xf8, 0x43, 0xb4, 0x4b, 0x7e, 0xc7, 0x6e, + 0x22, 0x9f, 0xc8, 0x16, 0xd8, 0x9f, 0xb1, 0x0f, 0x89, 0xc0, 0x4e, 0xb3, + 0x1f, 0xfd, 0x24, 0x7d, 0xc6, 0x5d, 0xcd, 0x6c, 0xfb, 0x34, 0xeb, 0x05, + 0xc4, 0x0b, 0x1c, 0xe7, 0xb1, 0xed, 0xc6, 0x7b, 0xd1, 0x8d, 0x57, 0xee, + 0xd7, 0xc8, 0xaa, 0xfa, 0x11, 0x67, 0x8f, 0x5b, 0x59, 0x37, 0x56, 0xb1, + 0xef, 0xc6, 0xb6, 0xed, 0xc7, 0x75, 0xb6, 0xe1, 0xb2, 0xb0, 0x0d, 0x0f, + 0x6a, 0x7e, 0xeb, 0xf7, 0x9b, 0x1d, 0x79, 0x6d, 0x6c, 0x1b, 0xee, 0xad, + 0xd8, 0x06, 0x57, 0x5e, 0xbd, 0x79, 0xeb, 0x0f, 0xc0, 0x1b, 0x0b, 0xbc, + 0xa9, 0xaf, 0xd5, 0x70, 0x8e, 0xe2, 0x87, 0x1f, 0xe2, 0x18, 0x91, 0x73, + 0xd9, 0x18, 0xe5, 0x62, 0x45, 0xc4, 0x6a, 0x91, 0xd9, 0xd9, 0x4a, 0x8e, + 0xf5, 0x35, 0x69, 0xbb, 0x6b, 0xe2, 0x22, 0x7a, 0xbc, 0x78, 0x09, 0xf8, + 0x73, 0xbc, 0xa5, 0x49, 0x1b, 0xc1, 0xfd, 0xe3, 0x12, 0x47, 0x7e, 0xe7, + 0x3a, 0x1e, 0x7c, 0x69, 0xf1, 0x47, 0xe0, 0x15, 0xc7, 0x7d, 0x51, 0x27, + 0xde, 0xab, 0x89, 0xa9, 0xd7, 0xf8, 0xc9, 0xe2, 0x78, 0x89, 0x61, 0x74, + 0x19, 0x2f, 0x05, 0x64, 0x5e, 0x63, 0xc8, 0x3c, 0x87, 0x63, 0x6d, 0xae, + 0xb1, 0xd6, 0xc7, 0x50, 0x0b, 0x43, 0xc1, 0x6d, 0xcc, 0x13, 0x8e, 0xa1, + 0xda, 0x28, 0x39, 0xe3, 0xc4, 0x50, 0x4e, 0x9d, 0xcd, 0xcd, 0x71, 0x5c, + 0x5c, 0xd9, 0x0f, 0xef, 0xc0, 0x3e, 0x45, 0x9e, 0x14, 0x74, 0xea, 0x7f, + 0x1a, 0xec, 0xf6, 0x51, 0xf4, 0x8f, 0xba, 0xfd, 0x9e, 0x5c, 0xc3, 0xc5, + 0x85, 0x7d, 0xbd, 0x1b, 0xd3, 0xed, 0x96, 0x31, 0x1d, 0x62, 0x18, 0xdb, + 0xc9, 0xbb, 0xf6, 0x16, 0x33, 0xe8, 0xe3, 0x75, 0x11, 0x1b, 0x12, 0xc7, + 0x49, 0x90, 0xaf, 0xfd, 0x91, 0x50, 0x58, 0xad, 0xc7, 0xab, 0x75, 0xa1, + 0x16, 0xaf, 0x41, 0xf1, 0xdd, 0xf8, 0x92, 0xef, 0x48, 0xc4, 0x92, 0xe3, + 0xf6, 0x10, 0xe8, 0xc5, 0xf8, 0xb9, 0xba, 0xe1, 0xc6, 0xc9, 0x8c, 0xd3, + 0x3f, 0x82, 0xc6, 0xbb, 0x15, 0xfe, 0x7e, 0xcc, 0xde, 0x2f, 0xe8, 0x96, + 0x15, 0xb8, 0x0e, 0x7b, 0x70, 0x1d, 0x91, 0xb8, 0xb2, 0x2e, 0xb0, 0x7e, + 0x78, 0x6b, 0x9a, 0xa6, 0xd8, 0x1b, 0x70, 0x0e, 0xf3, 0xb9, 0xb9, 0x6a, + 0x2d, 0x0c, 0xf9, 0xb6, 0xc1, 0x1f, 0x02, 0xd7, 0xac, 0x88, 0x43, 0x03, + 0x0b, 0xf5, 0x34, 0x1c, 0xc7, 0x5a, 0x88, 0xdb, 0x81, 0x8f, 0xcb, 0xf3, + 0x26, 0x89, 0xcf, 0x37, 0xc5, 0xdc, 0x63, 0xa2, 0x06, 0xea, 0xd3, 0x39, + 0x77, 0xc9, 0x0a, 0xde, 0x69, 0x92, 0x77, 0x8f, 0x56, 0xf0, 0x73, 0x78, + 0x1c, 0x90, 0x74, 0xe5, 0xdc, 0x95, 0x75, 0x5a, 0xf0, 0xa7, 0x9d, 0x73, + 0xd3, 0x41, 0x6a, 0x14, 0x23, 0x2f, 0x0c, 0xa9, 0xdb, 0x1c, 0x3a, 0x3a, + 0x31, 0xf2, 0xda, 0xba, 0x18, 0xf9, 0xb6, 0x20, 0xc7, 0x5a, 0xc3, 0x50, + 0x82, 0x79, 0xf8, 0xba, 0x97, 0x6d, 0xc8, 0x36, 0x70, 0x3d, 0x5f, 0x53, + 0xbb, 0xec, 0x59, 0xa6, 0xd6, 0x1c, 0x20, 0xdf, 0x0c, 0xfb, 0x0e, 0x0b, + 0x79, 0x06, 0x91, 0x36, 0xc9, 0x3a, 0xcb, 0xbe, 0xbd, 0x1a, 0x67, 0xcf, + 0x51, 0xa3, 0x18, 0xfb, 0x46, 0xfd, 0xfa, 0x79, 0xbf, 0xdf, 0x3a, 0xac, + 0x3b, 0x36, 0x73, 0x25, 0xbf, 0xee, 0xc2, 0xed, 0x41, 0x9c, 0xad, 0x50, + 0x93, 0x55, 0xc0, 0xfe, 0xde, 0xf0, 0x37, 0x5b, 0xae, 0x2e, 0x06, 0x68, + 0xfd, 0xcc, 0x2d, 0x42, 0x1f, 0x8d, 0xc9, 0xaa, 0x3e, 0x8e, 0x82, 0x37, + 0x19, 0xa7, 0x06, 0x60, 0xae, 0xa7, 0xeb, 0xd7, 0x0b, 0xc6, 0xed, 0x37, + 0xfd, 0xaa, 0xe5, 0xca, 0xc0, 0xf5, 0xf2, 0x91, 0x4f, 0xd5, 0xd1, 0xba, + 0x51, 0x4d, 0xf8, 0x2c, 0xe8, 0x1a, 0x47, 0xde, 0x1d, 0x79, 0x81, 0x10, + 0x3b, 0x39, 0x79, 0x78, 0x1a, 0xb9, 0x77, 0xe4, 0x02, 0xe7, 0xe3, 0x6e, + 0x7e, 0xfe, 0x6a, 0x29, 0x72, 0x36, 0x8f, 0x9c, 0x79, 0x1e, 0x39, 0xf9, + 0xcb, 0xc8, 0xc9, 0xcf, 0x97, 0x7a, 0x41, 0xff, 0x1e, 0x99, 0x8f, 0xb3, + 0x8e, 0x99, 0x74, 0x11, 0xb9, 0xd3, 0x77, 0x67, 0xd8, 0x46, 0x74, 0xd1, + 0x3d, 0xc8, 0x35, 0xbe, 0x3f, 0xa9, 0x68, 0x9d, 0x7d, 0x01, 0x5f, 0xc2, + 0xb8, 0x91, 0x38, 0x71, 0x29, 0x4f, 0x1a, 0xc7, 0x8a, 0x23, 0x4d, 0x7e, + 0x6b, 0xae, 0x95, 0x5a, 0xf6, 0x2c, 0xcb, 0x93, 0x6a, 0xac, 0xe8, 0xc2, + 0x19, 0xd4, 0xd9, 0xf7, 0x87, 0x9c, 0xdb, 0xc4, 0x48, 0xe4, 0xd3, 0xeb, + 0xe8, 0xed, 0x93, 0x65, 0xda, 0x19, 0xbb, 0x56, 0xbe, 0x68, 0xad, 0xa3, + 0x6c, 0xef, 0x43, 0x32, 0x97, 0x5c, 0x78, 0x28, 0x69, 0xe5, 0x43, 0x3e, + 0xf7, 0x7c, 0x62, 0x42, 0x47, 0x84, 0xc8, 0xbf, 0x20, 0xcd, 0x0d, 0x20, + 0x71, 0x6e, 0xd9, 0xfe, 0x02, 0x1f, 0x10, 0xb1, 0x6d, 0x9c, 0x33, 0x03, + 0xa2, 0xd6, 0xb6, 0xd1, 0xe2, 0x7e, 0x03, 0xfc, 0xbe, 0x8f, 0xe6, 0x90, + 0x43, 0x14, 0x44, 0x1e, 0xde, 0x0e, 0x78, 0x37, 0x0f, 0xbf, 0x1f, 0xb9, + 0x01, 0xd3, 0xd8, 0x04, 0xfc, 0x6f, 0x03, 0xc6, 0x6b, 0x43, 0x9f, 0x6b, + 0x22, 0xf1, 0x3d, 0x8f, 0xb7, 0x13, 0xd7, 0x65, 0xab, 0xf3, 0xf2, 0x9c, + 0x3c, 0xf6, 0x61, 0xf9, 0xf6, 0xbe, 0x3e, 0xcf, 0xdc, 0x6d, 0x9e, 0xb9, + 0xef, 0xf0, 0xcc, 0xed, 0xc3, 0xb7, 0x2e, 0x3e, 0x41, 0x7c, 0xeb, 0xae, + 0xf1, 0xb7, 0x9e, 0x35, 0x5c, 0xdc, 0xdb, 0x3d, 0xb8, 0xbf, 0x8f, 0xf9, + 0xb9, 0xcf, 0xf4, 0xf4, 0xf1, 0x9a, 0x1b, 0x68, 0x6e, 0xb0, 0x8d, 0x16, + 0x4f, 0x72, 0x5f, 0xd0, 0x83, 0x0b, 0xe3, 0x17, 0x90, 0x63, 0x6d, 0x74, + 0xf1, 0x64, 0x8b, 0xc0, 0x9b, 0xfd, 0xf9, 0xc6, 0xca, 0x9a, 0x57, 0xb0, + 0xa6, 0x3b, 0x97, 0x89, 0x6f, 0x19, 0x96, 0xf1, 0xe3, 0x31, 0xee, 0xe3, + 0xb1, 0x37, 0xcb, 0x5f, 0x33, 0x82, 0xce, 0x9e, 0x0d, 0xc6, 0xcd, 0xfd, + 0x56, 0x6b, 0x26, 0x8b, 0xdb, 0x9d, 0x34, 0x1b, 0xd4, 0xc0, 0x37, 0x55, + 0xfa, 0x28, 0xae, 0x23, 0xa8, 0x4a, 0xb4, 0x8f, 0xf9, 0xbc, 0x4e, 0xd6, + 0xaf, 0x5b, 0x30, 0x6f, 0xd8, 0xcd, 0xd1, 0x88, 0xe5, 0x38, 0x27, 0xec, + 0xbe, 0x26, 0xc7, 0xd9, 0xee, 0xb3, 0xdf, 0xc7, 0x53, 0xc8, 0xaa, 0x3c, + 0xaf, 0x29, 0xed, 0xa0, 0x83, 0x50, 0xcf, 0x8b, 0xb2, 0x9e, 0xb2, 0xe8, + 0xad, 0x99, 0x18, 0x4e, 0x1c, 0xe3, 0x9c, 0xed, 0xac, 0x85, 0xfe, 0xe0, + 0xbd, 0x98, 0x00, 0x1e, 0x61, 0x8a, 0xe2, 0xaf, 0x50, 0xca, 0xe3, 0x69, + 0xe1, 0xa9, 0xe0, 0xc9, 0xf5, 0x0c, 0x1d, 0x4f, 0xe8, 0x18, 0xec, 0x53, + 0xb4, 0xef, 0x92, 0x93, 0x3f, 0x41, 0x37, 0xde, 0x9e, 0x74, 0xea, 0x51, + 0x8b, 0xd6, 0x72, 0xf5, 0xa8, 0x3f, 0x67, 0x9e, 0x9c, 0x70, 0xeb, 0x51, + 0x8b, 0x24, 0xea, 0x51, 0x27, 0x56, 0xa8, 0x47, 0x25, 0x56, 0x5f, 0x8f, + 0xe2, 0xf9, 0x35, 0xda, 0xd7, 0x4f, 0xca, 0x17, 0x64, 0x3d, 0xea, 0x3d, + 0x72, 0xea, 0x51, 0x17, 0xa9, 0x71, 0x3d, 0xea, 0x78, 0x5d, 0x3d, 0x2a, + 0x28, 0xea, 0x51, 0x3c, 0x8f, 0x53, 0x8f, 0x12, 0xed, 0xbe, 0x88, 0xa7, + 0xee, 0x42, 0xf4, 0xee, 0x64, 0x07, 0x68, 0x66, 0xd0, 0xf7, 0x1a, 0xda, + 0x34, 0x45, 0xc8, 0xdb, 0x4a, 0x35, 0xd0, 0x07, 0x6e, 0xb8, 0xbe, 0xa2, + 0xd0, 0x06, 0xcc, 0x9b, 0xec, 0x7b, 0xd8, 0x53, 0x63, 0x61, 0x9a, 0xff, + 0x62, 0xea, 0x2c, 0x07, 0x45, 0x9d, 0xe5, 0x87, 0x6b, 0xbc, 0x75, 0x96, + 0x45, 0xba, 0x7e, 0x9d, 0xe5, 0x60, 0x83, 0x3a, 0xcb, 0x5b, 0x54, 0xad, + 0xb3, 0xbc, 0x45, 0xd5, 0x3a, 0xcb, 0xc1, 0x12, 0xe7, 0xe2, 0x3e, 0x89, + 0x5f, 0x06, 0xed, 0x41, 0xf1, 0xc7, 0xb5, 0x97, 0xc5, 0xca, 0x1e, 0x7e, + 0xd9, 0x6a, 0x2f, 0x6c, 0x03, 0x22, 0x17, 0x2e, 0xd7, 0xd4, 0x5e, 0xb8, + 0x0d, 0x9d, 0xb1, 0xd7, 0x08, 0x19, 0x99, 0x83, 0x7f, 0x5f, 0x9c, 0x0c, + 0x61, 0xce, 0x0e, 0xf8, 0x8c, 0x0e, 0xe4, 0x06, 0x61, 0xb4, 0x15, 0xda, + 0x64, 0x0d, 0xa1, 0x8f, 0xc7, 0xd9, 0x0e, 0x43, 0xb7, 0x6c, 0x77, 0x7f, + 0x0f, 0x48, 0x1a, 0x44, 0x68, 0xb8, 0x9d, 0xf4, 0x20, 0xfb, 0x8e, 0xc9, + 0x3d, 0x74, 0xc8, 0xde, 0x22, 0xf6, 0xbd, 0xc1, 0xaa, 0x95, 0xb9, 0xc1, + 0x1b, 0x90, 0xb9, 0xcc, 0xaa, 0x65, 0x8e, 0xe5, 0xcd, 0x39, 0xf7, 0xdd, + 0x60, 0xf1, 0xfa, 0x1d, 0x02, 0xa7, 0x77, 0x1b, 0xc8, 0xfb, 0x18, 0xec, + 0x8e, 0x33, 0xbf, 0x2e, 0xd7, 0xab, 0x8f, 0x87, 0x9f, 0x6d, 0x66, 0xff, + 0xbd, 0x72, 0x3d, 0xb1, 0xde, 0x7f, 0xaf, 0xe4, 0x47, 0x15, 0x61, 0x93, + 0xb3, 0x25, 0xae, 0xed, 0x7b, 0xf9, 0x33, 0x8f, 0x9c, 0x00, 0x7d, 0x42, + 0x0f, 0x98, 0xae, 0x41, 0xf0, 0x01, 0xeb, 0xd8, 0x4f, 0xc9, 0x5a, 0x16, + 0x9e, 0x05, 0x97, 0x7f, 0xad, 0xb0, 0x99, 0xee, 0x18, 0xdb, 0x01, 0x0b, + 0xfe, 0x8f, 0xeb, 0x28, 0x7c, 0x8e, 0xca, 0xfd, 0x2e, 0x5f, 0xbb, 0x2e, + 0xbc, 0xa7, 0x72, 0xbb, 0x5c, 0xce, 0x8a, 0x7a, 0x2d, 0xa9, 0x9d, 0x7d, + 0xd3, 0x2d, 0x6c, 0x6b, 0xb6, 0x58, 0xae, 0xcc, 0x26, 0xf0, 0xce, 0x7c, + 0x7d, 0x17, 0x36, 0x9c, 0xcf, 0xaa, 0xbf, 0x23, 0x6a, 0x04, 0x73, 0x36, + 0xdb, 0x6b, 0x8e, 0x41, 0x7f, 0x0b, 0xb2, 0xc4, 0xef, 0x51, 0x71, 0x2e, + 0x21, 0x6a, 0xf8, 0x83, 0xdc, 0x76, 0xed, 0x4a, 0x94, 0xed, 0x30, 0xf6, + 0x5c, 0xa5, 0x31, 0xe2, 0x23, 0xc8, 0x0c, 0xc7, 0xb1, 0x0c, 0xe7, 0xc6, + 0x9e, 0x9a, 0xa7, 0x66, 0xab, 0xcb, 0xb8, 0x88, 0x75, 0x39, 0x00, 0x9a, + 0xed, 0x10, 0x31, 0xea, 0xb8, 0x5d, 0xa6, 0xea, 0x19, 0x3f, 0xd3, 0xdc, + 0x39, 0xe7, 0x3f, 0x66, 0x2f, 0x47, 0xfb, 0xcd, 0x37, 0x48, 0x7b, 0x47, + 0x1f, 0x6b, 0xe9, 0xae, 0x23, 0x7e, 0x71, 0xe9, 0xee, 0xfa, 0xa8, 0x49, + 0x49, 0x83, 0xa8, 0xac, 0x2b, 0x7e, 0x5a, 0x9e, 0x29, 0xfd, 0x5f, 0xd8, + 0xaf, 0xe2, 0xd9, 0xaf, 0xab, 0xbb, 0xfb, 0xe4, 0x7e, 0xc3, 0x75, 0xba, + 0x1b, 0x97, 0x75, 0xb9, 0x5f, 0x84, 0xee, 0xba, 0x7b, 0xe2, 0xb5, 0xb7, + 0x5c, 0x67, 0xdd, 0x67, 0x48, 0x8d, 0xaf, 0x14, 0x7b, 0xff, 0xb4, 0xf9, + 0xe3, 0xc5, 0xde, 0x1f, 0x87, 0x9e, 0x5e, 0xbd, 0x65, 0x1a, 0xb6, 0x89, + 0xb8, 0xc2, 0xd1, 0x1f, 0xd8, 0xe3, 0x82, 0x9f, 0x16, 0x1e, 0xd2, 0xe9, + 0x9f, 0xee, 0xe4, 0xfa, 0xac, 0x26, 0x73, 0x7c, 0x6e, 0x7f, 0xb1, 0x95, + 0x63, 0xab, 0x4d, 0xd6, 0x77, 0x44, 0x6e, 0x95, 0x57, 0x4d, 0x8f, 0x1f, + 0x31, 0x30, 0xce, 0x63, 0x61, 0xba, 0x1c, 0xbc, 0x91, 0xb8, 0xbc, 0xcb, + 0x58, 0xf4, 0xad, 0x26, 0x2e, 0xbf, 0x55, 0xf7, 0x5b, 0x7f, 0xdd, 0x7a, + 0xbd, 0x3a, 0x47, 0x35, 0x2e, 0xe7, 0x7c, 0x3e, 0xe8, 0xd4, 0x18, 0x4c, + 0x8e, 0xcf, 0xd7, 0x4a, 0x9e, 0xf0, 0x3b, 0x72, 0x11, 0x1b, 0x79, 0x08, + 0x64, 0xfc, 0x55, 0xc8, 0xca, 0x2b, 0x36, 0xf2, 0x0e, 0x1b, 0xf9, 0x88, + 0x8d, 0xdc, 0xc3, 0x46, 0xee, 0x61, 0xf7, 0xc8, 0x1c, 0x26, 0x23, 0xeb, + 0x56, 0x7c, 0x46, 0xcb, 0xf9, 0x61, 0x5e, 0xc9, 0xd8, 0xe3, 0x7c, 0x1f, + 0x41, 0x4d, 0xc6, 0x36, 0xca, 0x78, 0xf0, 0x38, 0xdf, 0x77, 0x28, 0xab, + 0x71, 0xae, 0x45, 0x91, 0xaa, 0xc6, 0x6f, 0x87, 0x8f, 0xda, 0x0e, 0xbc, + 0x9a, 0x79, 0xdc, 0xa7, 0xc6, 0x5b, 0x99, 0x76, 0x8a, 0x1a, 0x5f, 0x2b, + 0xcf, 0x0d, 0x7a, 0x03, 0x0e, 0xfe, 0xdd, 0xdc, 0xd6, 0xd4, 0xf8, 0xdd, + 0xec, 0xd3, 0xc2, 0xa4, 0xba, 0xfd, 0xb7, 0x07, 0x98, 0xae, 0xa4, 0xde, + 0x16, 0xe0, 0xb8, 0x76, 0xde, 0xf6, 0x8b, 0x3b, 0x05, 0xc9, 0x18, 0xd7, + 0xcc, 0xb8, 0x5d, 0xa5, 0xab, 0xba, 0x2c, 0x5d, 0xfd, 0x95, 0xfa, 0x3f, + 0xd3, 0xd2, 0xc7, 0x70, 0xa2, 0x36, 0xc6, 0x34, 0x75, 0xe7, 0xe3, 0xf3, + 0x66, 0x5e, 0x47, 0xdc, 0x63, 0xc0, 0xf3, 0x60, 0x33, 0xb5, 0x0d, 0x0e, + 0xf9, 0x2d, 0xef, 0xba, 0x6c, 0x43, 0x76, 0x90, 0x37, 0xc7, 0x5a, 0x7e, + 0xcd, 0xa8, 0x38, 0x1b, 0x49, 0xf6, 0x47, 0x85, 0xec, 0xb0, 0xac, 0x69, + 0xe2, 0xce, 0xd5, 0x47, 0xe2, 0x1e, 0x09, 0xcb, 0x19, 0xcb, 0xf2, 0x78, + 0x7f, 0x57, 0x58, 0x53, 0x5b, 0xb0, 0x46, 0x98, 0xd2, 0x25, 0x71, 0x56, + 0x80, 0x7c, 0xe9, 0xdc, 0x3a, 0x6a, 0xfb, 0x07, 0xbd, 0x9a, 0xc7, 0x46, + 0x9d, 0xb3, 0x7a, 0xbb, 0xde, 0xff, 0x8d, 0x8a, 0x73, 0x65, 0xc7, 0x06, + 0xb9, 0xe7, 0xc3, 0xab, 0x3b, 0xff, 0xbe, 0xbe, 0x3e, 0xb5, 0xd4, 0xd7, + 0x0d, 0x24, 0x0d, 0x98, 0x36, 0x8d, 0xcf, 0xee, 0xe7, 0x4b, 0x7c, 0xaf, + 0x25, 0x12, 0xe3, 0xdc, 0x6d, 0x44, 0xdc, 0xf9, 0x50, 0x21, 0x85, 0x3a, + 0x8d, 0x19, 0x9c, 0xf3, 0x85, 0x86, 0x7d, 0x71, 0xca, 0x64, 0x27, 0x48, + 0x43, 0xac, 0x98, 0xa9, 0xd6, 0x03, 0x1f, 0x5c, 0x43, 0x96, 0x2b, 0x97, + 0x51, 0xce, 0x1f, 0x6a, 0xce, 0xed, 0x16, 0xe9, 0xb0, 0x72, 0xa0, 0x74, + 0x84, 0x0e, 0x34, 0x8c, 0x29, 0x1b, 0xd7, 0x03, 0x2f, 0xd6, 0xd5, 0x14, + 0x16, 0x44, 0x4d, 0x21, 0xb7, 0xc6, 0x6f, 0x3d, 0x19, 0x70, 0xee, 0xb5, + 0x34, 0xd6, 0x93, 0x5d, 0x15, 0x3d, 0x71, 0xe1, 0xf8, 0x2c, 0xbe, 0x8d, + 0x76, 0x8a, 0xb5, 0x0e, 0x2b, 0x59, 0xbb, 0x95, 0x76, 0x1a, 0x0e, 0xd6, + 0xa3, 0x36, 0xe3, 0x75, 0x58, 0x39, 0x68, 0xe7, 0x95, 0xb4, 0xa8, 0x3d, + 0x70, 0x8c, 0xbf, 0xe6, 0xda, 0x30, 0x95, 0xe9, 0xed, 0x98, 0xfb, 0x3d, + 0xc3, 0x78, 0x6b, 0x8a, 0x2e, 0x9d, 0xf8, 0x2e, 0x51, 0x58, 0xe6, 0x6f, + 0xce, 0x7c, 0xb9, 0x29, 0xae, 0x25, 0xde, 0x8f, 0xfd, 0x33, 0xfc, 0x6e, + 0x25, 0x39, 0x55, 0x2e, 0xa7, 0x31, 0x3e, 0xd6, 0x7b, 0xaf, 0xc8, 0x8d, + 0xd4, 0x38, 0x0d, 0x71, 0x8e, 0xac, 0x2d, 0xc9, 0x91, 0xd3, 0xd0, 0x35, + 0xc4, 0x20, 0x76, 0x13, 0xbe, 0x75, 0xe3, 0x91, 0xcf, 0xae, 0x75, 0x64, + 0xe4, 0xbb, 0x12, 0x0f, 0x1e, 0xff, 0xfb, 0x80, 0x7b, 0x0f, 0x28, 0x77, + 0x2a, 0x8d, 0xfd, 0x37, 0x51, 0xca, 0x74, 0xf2, 0xbb, 0xec, 0x99, 0x23, + 0x1b, 0x6a, 0xe1, 0xd1, 0x77, 0xca, 0x85, 0x0f, 0xd6, 0xc1, 0xf3, 0x19, + 0xd7, 0x5f, 0xd5, 0xc1, 0x07, 0x3d, 0xf0, 0x66, 0x1d, 0x3c, 0xe2, 0xae, + 0x33, 0xdf, 0xa8, 0x83, 0x37, 0x3d, 0xf0, 0xed, 0x75, 0xf0, 0xed, 0x80, + 0x7f, 0xa3, 0x0e, 0x1e, 0x7d, 0xa7, 0x90, 0x13, 0x08, 0xda, 0x70, 0x8c, + 0x74, 0x48, 0xe6, 0x89, 0x78, 0x2e, 0xb9, 0x1f, 0xc9, 0xf2, 0xd3, 0x01, + 0x1a, 0x7b, 0xeb, 0xb5, 0x09, 0xd8, 0xa8, 0xaa, 0x4c, 0x39, 0xfa, 0xea, + 0x95, 0x25, 0x96, 0xbd, 0x3c, 0xe4, 0x15, 0x7a, 0x54, 0x80, 0x3e, 0x15, + 0x5c, 0x5f, 0xca, 0x77, 0xaa, 0x22, 0xc7, 0x1d, 0x3d, 0x56, 0x68, 0xbd, + 0x35, 0x2f, 0x73, 0x91, 0xab, 0x8c, 0x3b, 0xfc, 0x86, 0xeb, 0x3b, 0xe8, + 0x84, 0x63, 0x57, 0x58, 0xbf, 0x79, 0x7e, 0x69, 0x5f, 0x4a, 0x2c, 0x87, + 0xce, 0x3a, 0xe9, 0x25, 0x32, 0x1b, 0x5e, 0x52, 0x77, 0xf1, 0xd5, 0xd9, + 0x77, 0x12, 0xf6, 0x3d, 0xd7, 0xe2, 0xb7, 0x36, 0xac, 0xbd, 0x9e, 0x7d, + 0xcf, 0x78, 0xec, 0x7b, 0x38, 0x58, 0xf5, 0xf9, 0x8f, 0x09, 0x9f, 0xdf, + 0xd1, 0xc0, 0x66, 0xac, 0xde, 0xe7, 0xef, 0xfd, 0xd8, 0x3e, 0x7f, 0xb9, + 0x75, 0x57, 0xe3, 0xf3, 0x1f, 0x69, 0xf9, 0x78, 0x3e, 0x9f, 0xd7, 0xac, + 0xaf, 0x65, 0x7a, 0xcf, 0x59, 0x8e, 0xca, 0x18, 0x7b, 0xb7, 0x27, 0xc6, + 0x66, 0xfc, 0xbe, 0x27, 0xef, 0x02, 0x9e, 0x5e, 0xeb, 0xc8, 0xdb, 0x51, + 0x19, 0xa7, 0x73, 0xec, 0x8d, 0xf7, 0xc2, 0x23, 0x90, 0xd1, 0x7c, 0x8f, + 0x8f, 0x54, 0x9a, 0x35, 0x9d, 0xb3, 0xed, 0x9f, 0x6f, 0xae, 0x17, 0xa1, + 0xcb, 0xc2, 0x9f, 0x24, 0x3e, 0x81, 0x5a, 0xea, 0x49, 0xc8, 0x8f, 0xbb, + 0xaf, 0x95, 0x6a, 0xa9, 0xf5, 0xe7, 0x1f, 0x7c, 0xee, 0x41, 0xca, 0x03, + 0x95, 0x73, 0x10, 0xaf, 0x4e, 0xe9, 0x94, 0x9d, 0x21, 0xdd, 0x8c, 0x93, + 0xb2, 0x8f, 0x71, 0x8e, 0xfd, 0xb0, 0x52, 0x6f, 0x3f, 0x24, 0x6b, 0x30, + 0xea, 0xb2, 0x77, 0x82, 0x7e, 0x02, 0x7c, 0x58, 0xaf, 0x9c, 0x1a, 0x8c, + 0xea, 0xdc, 0x09, 0x3a, 0xfe, 0xf3, 0xbb, 0x13, 0xc4, 0xf3, 0x6b, 0xb4, + 0xb7, 0xc1, 0x9d, 0x20, 0xdf, 0x2a, 0xef, 0x04, 0xad, 0x17, 0x35, 0x18, + 0x9e, 0xc7, 0xa9, 0xc1, 0x70, 0xbb, 0xb3, 0x8f, 0xe5, 0x3a, 0x4c, 0xa3, + 0x93, 0xb7, 0x88, 0x7b, 0xa8, 0x9d, 0x7d, 0xb5, 0xf2, 0xbd, 0xef, 0x13, + 0x8d, 0xa5, 0x79, 0xbd, 0xa3, 0x0d, 0xef, 0xb6, 0x24, 0x3f, 0xc1, 0x9a, + 0xcb, 0x21, 0x51, 0x73, 0xb9, 0xb3, 0xcd, 0x5b, 0x73, 0x51, 0x57, 0xb8, + 0xdb, 0x72, 0xa8, 0x41, 0xcd, 0xc5, 0xef, 0xb9, 0xdb, 0xe2, 0xf7, 0xdc, + 0x6d, 0x39, 0x24, 0xeb, 0x2b, 0xea, 0x2f, 0xd1, 0xdd, 0x96, 0xe4, 0x8a, + 0x77, 0x5b, 0xb6, 0x4a, 0x7d, 0xf5, 0xc2, 0xaf, 0xfe, 0xbc, 0x32, 0x55, + 0x67, 0xe7, 0x13, 0xc2, 0xce, 0xdf, 0xd5, 0xea, 0xb7, 0x9e, 0x69, 0xbb, + 0x9e, 0x9d, 0xdf, 0x57, 0xd1, 0x53, 0xbe, 0xa3, 0xcd, 0x77, 0xbe, 0x58, + 0x16, 0xf9, 0x7c, 0xa6, 0x89, 0x72, 0x03, 0xbf, 0x2a, 0x68, 0xf6, 0x58, + 0x6f, 0xed, 0x99, 0x63, 0xf5, 0x5e, 0xa4, 0xee, 0xb9, 0x17, 0x69, 0xa2, + 0x5f, 0xaf, 0xab, 0x87, 0x04, 0xe4, 0xdd, 0x7e, 0xf8, 0xc2, 0x19, 0x43, + 0xda, 0x5e, 0xc4, 0x70, 0x98, 0xae, 0x50, 0xe4, 0x3b, 0x95, 0x6d, 0xe4, + 0x9b, 0x71, 0xce, 0x4b, 0x54, 0x11, 0x63, 0x42, 0x8e, 0x8b, 0x7e, 0xe1, + 0x6f, 0xd4, 0xb8, 0x23, 0xb3, 0xe3, 0xf6, 0x05, 0xe0, 0xbf, 0x21, 0x51, + 0x6d, 0x9b, 0x95, 0x5a, 0xce, 0x58, 0xe5, 0x0e, 0xbf, 0x09, 0xfb, 0xe0, + 0xdc, 0x07, 0xca, 0x98, 0x7c, 0x67, 0xe4, 0x62, 0x5b, 0xf5, 0x3e, 0xd0, + 0x67, 0xa4, 0x9c, 0x3a, 0xf7, 0x81, 0x48, 0x4d, 0x40, 0x3e, 0x6e, 0xe4, + 0x3e, 0x50, 0xd7, 0x92, 0xfb, 0x40, 0x2b, 0xf3, 0x66, 0xe9, 0x7d, 0xa0, + 0xc6, 0xfc, 0xe1, 0xfb, 0x40, 0xff, 0xde, 0xe6, 0xdc, 0x43, 0x5d, 0x89, + 0x3f, 0x6e, 0x9c, 0xf4, 0x11, 0xe0, 0xf9, 0x3e, 0x50, 0xe5, 0x1e, 0x90, + 0xe7, 0x0e, 0x10, 0xdf, 0x25, 0x59, 0xee, 0x0c, 0xce, 0x7b, 0xff, 0xa4, + 0xa7, 0x72, 0xff, 0xe4, 0x7c, 0xc9, 0xf5, 0xed, 0xee, 0xb9, 0x1c, 0xc7, + 0x39, 0xbb, 0x44, 0x8e, 0x7a, 0xae, 0x54, 0x5b, 0xc3, 0x60, 0xbe, 0x8f, + 0x16, 0xcf, 0x81, 0x3e, 0x6f, 0x89, 0xdc, 0x00, 0x7c, 0xde, 0xe2, 0x23, + 0xe6, 0x1d, 0x29, 0xa0, 0x8b, 0x38, 0xcb, 0x75, 0xf8, 0xdd, 0x21, 0x64, + 0xc1, 0x91, 0x8b, 0xdd, 0x9e, 0xf3, 0xd0, 0xaa, 0x1c, 0x38, 0x67, 0xba, + 0x0e, 0xef, 0x6a, 0x65, 0x46, 0x9c, 0xdd, 0x0c, 0xed, 0xb5, 0x9c, 0xf3, + 0xc6, 0xa8, 0x38, 0xb7, 0x6d, 0xaf, 0xb3, 0x5b, 0x3a, 0xe4, 0x06, 0x31, + 0x67, 0x8c, 0xeb, 0xd5, 0x8c, 0xfb, 0x66, 0xc1, 0xe3, 0x46, 0x67, 0x71, + 0x2b, 0xd7, 0xf1, 0xdc, 0x9a, 0x0a, 0x21, 0x97, 0xd8, 0x9d, 0xce, 0x09, + 0xbb, 0xe9, 0xac, 0xdd, 0x29, 0xd6, 0xde, 0x58, 0x77, 0x96, 0xcd, 0x72, + 0xb5, 0x5c, 0x4c, 0x70, 0x3d, 0x9a, 0xde, 0xb3, 0x84, 0xa6, 0xb5, 0xba, + 0x84, 0xdc, 0xb5, 0x62, 0xe3, 0x3b, 0x2a, 0xba, 0x34, 0x2e, 0xee, 0x21, + 0xbb, 0xe7, 0xb5, 0x0e, 0xfd, 0xaa, 0xba, 0xb7, 0x5c, 0x3c, 0x53, 0x4f, + 0xbf, 0x4d, 0xff, 0x4b, 0xe8, 0x77, 0x15, 0xf4, 0xe3, 0x77, 0x03, 0xef, + 0xef, 0x8a, 0x7a, 0xc0, 0xb9, 0x52, 0xe4, 0x78, 0x9e, 0x38, 0x4e, 0x88, + 0xcc, 0x2e, 0x50, 0x0f, 0xe8, 0xc8, 0xff, 0xeb, 0xe2, 0xde, 0x9d, 0x60, + 0xfa, 0xb2, 0x7d, 0x8f, 0xbc, 0x70, 0x99, 0xd8, 0xc6, 0xdf, 0x8d, 0x7d, + 0x94, 0xcb, 0x2f, 0xc5, 0x5c, 0xfa, 0xb3, 0xee, 0x73, 0x9d, 0xaa, 0x76, + 0x5f, 0x7b, 0x57, 0xed, 0x53, 0x1d, 0xf9, 0xcc, 0x34, 0x90, 0xcf, 0x8c, + 0xdc, 0xa3, 0x6f, 0xa6, 0x71, 0xbc, 0x9a, 0x9a, 0xfc, 0xef, 0x5e, 0xae, + 0x26, 0xb6, 0x8d, 0x22, 0x0a, 0xbf, 0xac, 0xd7, 0x4e, 0xe3, 0xa4, 0x61, + 0x93, 0x3a, 0xad, 0x69, 0xd2, 0x60, 0xc7, 0x4b, 0x12, 0x29, 0xa5, 0xa4, + 0x52, 0x55, 0x45, 0x60, 0xa9, 0x21, 0x4e, 0xda, 0x0a, 0x71, 0x70, 0x0b, + 0x48, 0x51, 0xc5, 0x21, 0x4d, 0xd3, 0x7b, 0x85, 0x84, 0x54, 0xa1, 0x8a, + 0x46, 0x4e, 0x02, 0x15, 0x4a, 0xe5, 0x0a, 0x96, 0x72, 0x41, 0xa2, 0xd8, + 0x8e, 0x02, 0x52, 0x2a, 0xf7, 0xca, 0x85, 0xba, 0xbf, 0x08, 0x89, 0x03, + 0x70, 0x06, 0x29, 0x2a, 0x3f, 0xe2, 0xc0, 0x8d, 0x1b, 0x54, 0x5d, 0xde, + 0x37, 0xb3, 0x63, 0xaf, 0x77, 0xd7, 0x8e, 0x03, 0x11, 0x07, 0x27, 0xbb, + 0xf6, 0xcc, 0xce, 0xec, 0xcc, 0x37, 0x6f, 0xbe, 0xf7, 0x37, 0xfd, 0xbe, + 0x78, 0x8d, 0x5a, 0xdb, 0x5b, 0xf3, 0x55, 0xec, 0xe7, 0xaf, 0x37, 0x18, + 0x57, 0xed, 0xba, 0xe4, 0xa9, 0xf5, 0xe3, 0x9a, 0x72, 0xd9, 0x1b, 0xf0, + 0xfe, 0xc7, 0x68, 0x51, 0xd8, 0x86, 0x94, 0xad, 0xee, 0xc5, 0x40, 0x9b, + 0xd9, 0xff, 0x33, 0x16, 0x03, 0x3e, 0x9b, 0x68, 0xad, 0x6d, 0x8a, 0xed, + 0x71, 0xd9, 0x16, 0xde, 0xda, 0xc2, 0xb6, 0x10, 0x3c, 0x16, 0xfd, 0x9e, + 0xb1, 0xa8, 0xc9, 0xea, 0xa1, 0x16, 0xed, 0x74, 0x88, 0x21, 0xbf, 0x9d, + 0x67, 0x6c, 0x05, 0xca, 0xce, 0x4f, 0x5d, 0x36, 0x3c, 0xe0, 0x73, 0xdc, + 0x59, 0xeb, 0xc0, 0x27, 0xb5, 0x9d, 0x1a, 0x51, 0xed, 0x01, 0x8f, 0xc9, + 0xc5, 0x45, 0x82, 0xbe, 0x86, 0x36, 0xe3, 0x82, 0xe3, 0xfa, 0x39, 0x14, + 0x8f, 0xf1, 0xfa, 0x1b, 0x88, 0xe5, 0x70, 0xda, 0x3f, 0xd9, 0x76, 0xae, + 0x9c, 0xe5, 0xbd, 0x42, 0xd4, 0x63, 0xbd, 0xef, 0x52, 0xdb, 0x82, 0xa8, + 0x27, 0xe3, 0x20, 0x1c, 0x1d, 0xd0, 0xe1, 0xe2, 0x8d, 0x74, 0x3f, 0xff, + 0x9e, 0x13, 0xcc, 0xdd, 0x7f, 0xdd, 0x1d, 0x36, 0x3f, 0x34, 0x64, 0xae, + 0xde, 0x56, 0xdc, 0x5d, 0xd9, 0x89, 0x06, 0x85, 0xaf, 0xc1, 0xad, 0x7b, + 0x41, 0x76, 0x5d, 0xe0, 0x3d, 0x7c, 0xa8, 0xba, 0x7f, 0xef, 0x84, 0x7d, + 0xe8, 0x99, 0x16, 0x62, 0x1d, 0x44, 0x8e, 0xe5, 0x2b, 0x53, 0xc8, 0x45, + 0xaa, 0xe6, 0xef, 0x78, 0xf3, 0x3c, 0x20, 0x3f, 0x55, 0x9e, 0x87, 0xca, + 0x23, 0xc5, 0x7b, 0x24, 0x02, 0xf2, 0x3c, 0xdc, 0x32, 0x18, 0xf5, 0xea, + 0xdf, 0xc3, 0x2d, 0x7f, 0x57, 0x1c, 0xf9, 0x5b, 0xf0, 0xd8, 0xe3, 0x97, + 0xf3, 0x6a, 0x2d, 0x20, 0xe7, 0x43, 0xf1, 0x94, 0xde, 0x00, 0x9e, 0x12, + 0x9c, 0xeb, 0xa1, 0xa5, 0x2f, 0xf2, 0x5e, 0x7e, 0x08, 0x7b, 0xb9, 0x51, + 0x8b, 0xe9, 0x95, 0x72, 0xf0, 0xdc, 0x3a, 0x64, 0xa2, 0xca, 0xb9, 0x81, + 0x5c, 0x44, 0x2c, 0x3c, 0xe6, 0xba, 0xe4, 0x60, 0x11, 0xbf, 0xa9, 0x58, + 0x52, 0xa5, 0x47, 0xbd, 0x23, 0xf2, 0x0c, 0xbe, 0x1b, 0x3f, 0xcc, 0x1c, + 0x18, 0xf2, 0x13, 0x76, 0xa6, 0x43, 0x0e, 0x1f, 0xbe, 0xcc, 0xbf, 0x8d, + 0x39, 0xd7, 0x92, 0x8b, 0xca, 0x6b, 0xa5, 0x4b, 0xfd, 0xd0, 0x41, 0xe6, + 0x6f, 0x0e, 0x2f, 0xad, 0xb3, 0x41, 0xc4, 0x53, 0xda, 0xdb, 0x74, 0xa1, + 0xd8, 0x0c, 0x83, 0xf5, 0xf8, 0x4b, 0x79, 0x38, 0x4f, 0x42, 0x70, 0x9e, + 0x9f, 0x3a, 0xc2, 0xe6, 0x44, 0x4f, 0xb3, 0x38, 0x9c, 0x53, 0x55, 0xfc, + 0xa9, 0x72, 0xaa, 0x6f, 0x8f, 0x3a, 0x10, 0xa7, 0xe6, 0xc7, 0x04, 0xe6, + 0x1f, 0xfa, 0x9c, 0x5a, 0x87, 0xd0, 0xeb, 0x10, 0xf3, 0x87, 0x76, 0x8d, + 0x06, 0x6b, 0xb0, 0x66, 0x13, 0x2f, 0x50, 0x2b, 0xb1, 0x7f, 0xc9, 0xd1, + 0x0a, 0x9d, 0xed, 0x69, 0xa6, 0xf3, 0x9e, 0x08, 0xd4, 0x79, 0x83, 0x72, + 0xa4, 0xcc, 0x80, 0x1c, 0x29, 0x37, 0x0e, 0x75, 0x17, 0x0e, 0xe3, 0x2e, + 0x2e, 0x30, 0xc0, 0xdc, 0xb9, 0x8b, 0xf1, 0x04, 0xee, 0x1c, 0xa5, 0xd0, + 0x07, 0x6e, 0xee, 0xec, 0xf7, 0x13, 0x49, 0x5c, 0xfe, 0xdb, 0xdc, 0xa9, + 0xa0, 0x7e, 0x27, 0x7c, 0xfd, 0x86, 0x1c, 0x9f, 0x6c, 0xc8, 0x13, 0x82, + 0x38, 0xfe, 0x4e, 0xf7, 0xd3, 0xbb, 0xf6, 0xd1, 0xa6, 0x09, 0xfd, 0x70, + 0x74, 0xb1, 0xba, 0xee, 0x5f, 0xf0, 0xd9, 0xb9, 0xc1, 0x67, 0x43, 0xc2, + 0x27, 0xd7, 0x25, 0xf6, 0x90, 0x9d, 0x93, 0x61, 0x9d, 0x1e, 0x19, 0x66, + 0xf7, 0xd4, 0xec, 0xfc, 0x88, 0x21, 0xec, 0x73, 0x74, 0x0e, 0xb9, 0xef, + 0x14, 0x1a, 0xc6, 0xa5, 0xe2, 0x3b, 0xe9, 0x1b, 0x38, 0x77, 0x04, 0xb2, + 0x1b, 0xf2, 0xfc, 0xf4, 0x6c, 0xd8, 0x34, 0x1c, 0x1f, 0x03, 0xfc, 0x08, + 0xc0, 0xa9, 0x7a, 0x7e, 0x90, 0x0d, 0x3d, 0x68, 0x0e, 0x87, 0x7c, 0x73, + 0x28, 0xf1, 0x06, 0x6e, 0x8f, 0x58, 0xbc, 0x83, 0x9e, 0x38, 0xc5, 0x9d, + 0x18, 0x93, 0xee, 0x80, 0x78, 0x41, 0xc4, 0xfa, 0xf9, 0xfa, 0xcb, 0xef, + 0x7c, 0x51, 0xf3, 0xaf, 0xad, 0x49, 0x6d, 0xba, 0x3c, 0xad, 0x4d, 0x15, + 0x51, 0xee, 0xa2, 0x56, 0xdb, 0x97, 0x36, 0x5d, 0x1c, 0x11, 0x7c, 0x30, + 0x79, 0xad, 0x42, 0x78, 0x4f, 0xdb, 0xbe, 0x25, 0xb8, 0xed, 0x80, 0x0f, + 0xab, 0x8a, 0x73, 0x18, 0x2d, 0xbc, 0x97, 0xb4, 0xbd, 0xb8, 0xb9, 0x8e, + 0x5b, 0xbe, 0x3f, 0x1d, 0x20, 0xdf, 0x9b, 0xd9, 0x0a, 0x91, 0xbf, 0x29, + 0xe2, 0xb2, 0xa9, 0x68, 0x21, 0xde, 0xf1, 0x30, 0xe2, 0x7b, 0xe1, 0xd7, + 0xa8, 0x62, 0xe1, 0x6e, 0x30, 0x16, 0xaa, 0xf6, 0x60, 0x1d, 0xb9, 0xa3, + 0x2c, 0x8b, 0xc3, 0xe9, 0x5e, 0x0a, 0x99, 0x28, 0xff, 0x6c, 0xe2, 0x3e, + 0x1d, 0x73, 0x78, 0x09, 0xfc, 0x3c, 0xb2, 0xde, 0x4c, 0x0b, 0x76, 0xe1, + 0x60, 0x7f, 0x46, 0x84, 0x65, 0xf3, 0x67, 0xbd, 0xad, 0xf9, 0x33, 0x54, + 0x39, 0xd4, 0xed, 0xa2, 0x35, 0x0b, 0x71, 0x92, 0xf0, 0x2f, 0x75, 0x77, + 0xb4, 0x9b, 0x41, 0xf2, 0x4f, 0xc5, 0x7e, 0x82, 0x1f, 0xc9, 0xb9, 0xba, + 0x41, 0x98, 0x3b, 0x9b, 0xbe, 0x6f, 0x30, 0x57, 0xdb, 0xb1, 0x29, 0x37, + 0x9f, 0x2b, 0xc3, 0x33, 0x57, 0xd8, 0x8b, 0x9a, 0xcd, 0x95, 0xf2, 0x43, + 0x2a, 0xdf, 0xdc, 0x51, 0xc8, 0x93, 0x45, 0xf7, 0x5c, 0xed, 0x8c, 0x7f, + 0x4e, 0xce, 0xd9, 0x4e, 0xfb, 0xe0, 0x1a, 0x8f, 0x43, 0x34, 0xd0, 0x76, + 0x12, 0x2c, 0x33, 0xfc, 0x6b, 0xeb, 0x86, 0x5c, 0x5b, 0xcc, 0x2b, 0x9e, + 0x6f, 0xb8, 0xb6, 0xb0, 0x0f, 0x5c, 0x70, 0xf6, 0x81, 0xd3, 0x3e, 0x7d, + 0x51, 0xd9, 0xbc, 0xff, 0xab, 0xed, 0x0d, 0xcf, 0x7d, 0x22, 0xce, 0xe9, + 0xc8, 0x91, 0xdc, 0x47, 0xce, 0x37, 0xe4, 0x61, 0x3d, 0xdb, 0x5c, 0xa7, + 0x6a, 0xee, 0x91, 0x73, 0x01, 0x79, 0x99, 0xa5, 0xf3, 0xf9, 0xc7, 0x06, + 0x75, 0xf7, 0x53, 0xa4, 0x1a, 0xd3, 0x72, 0x40, 0xf0, 0x61, 0xb7, 0xbe, + 0xbc, 0xec, 0xe4, 0x28, 0xe6, 0x5c, 0x63, 0xb0, 0x9c, 0xcf, 0x36, 0x89, + 0xa7, 0x6f, 0x25, 0x9e, 0x63, 0xc0, 0x23, 0x37, 0xbd, 0x73, 0x35, 0xa1, + 0x65, 0xf2, 0xa8, 0xb3, 0x87, 0xce, 0xea, 0x9f, 0xf0, 0x18, 0x3d, 0xb1, + 0x23, 0xe2, 0x9c, 0x11, 0xe0, 0xd2, 0xb6, 0x97, 0xcd, 0x0e, 0x5a, 0x94, + 0x7e, 0x46, 0x9a, 0xfa, 0xf8, 0x12, 0x15, 0x85, 0x7f, 0x0b, 0xb9, 0x51, + 0xb0, 0x71, 0xc3, 0x47, 0x87, 0xe7, 0xf0, 0xf7, 0x1b, 0x13, 0x8e, 0xcc, + 0xfd, 0x93, 0x31, 0x8c, 0x7a, 0x38, 0x0b, 0x01, 0xeb, 0x9d, 0x34, 0xc9, + 0x31, 0xb9, 0x1d, 0x71, 0x4e, 0x80, 0x8c, 0xcd, 0xbb, 0x5d, 0xde, 0x8e, + 0x4f, 0xa1, 0x55, 0xbd, 0xe4, 0xeb, 0x68, 0xd8, 0xfc, 0x72, 0xcf, 0xf6, + 0x7d, 0x0a, 0x2a, 0x77, 0x5f, 0x71, 0x58, 0x75, 0x2d, 0x73, 0x69, 0xc1, + 0x99, 0xe7, 0xd7, 0x55, 0xde, 0x6d, 0x77, 0x40, 0xde, 0x6d, 0x88, 0xe6, + 0x84, 0xaf, 0x2e, 0x44, 0x39, 0x47, 0x37, 0x93, 0x9c, 0x5a, 0xd9, 0x6a, + 0x23, 0x4e, 0xfc, 0x29, 0xee, 0xdd, 0x39, 0xf9, 0x7c, 0x5f, 0x04, 0xcf, + 0x46, 0x4e, 0xb5, 0x2d, 0x62, 0xf1, 0x33, 0xa2, 0x5c, 0xa7, 0xa7, 0x1c, + 0xdf, 0x17, 0xd5, 0x33, 0x3b, 0xb9, 0x7c, 0x8a, 0x64, 0x0e, 0x7d, 0x27, + 0xcd, 0x15, 0x9b, 0xf5, 0x6b, 0x1f, 0xe2, 0x81, 0xe3, 0xf0, 0x95, 0x0a, + 0xbf, 0x95, 0xa1, 0xfa, 0x80, 0x3e, 0xb5, 0x57, 0xfb, 0x04, 0xf9, 0x14, + 0x12, 0x7e, 0x05, 0xbe, 0x76, 0xda, 0x99, 0x23, 0x77, 0xbf, 0xc2, 0xdc, + 0x2f, 0x3c, 0xa7, 0xd3, 0x55, 0xb6, 0xd3, 0x55, 0xb6, 0x36, 0x5e, 0x3a, + 0xeb, 0x54, 0x0b, 0xe5, 0x1f, 0x59, 0x2f, 0xfd, 0x56, 0xd8, 0xe6, 0xe6, + 0xb3, 0x06, 0x2d, 0xac, 0xf7, 0xf2, 0x27, 0xc6, 0x1f, 0x94, 0xdb, 0xcb, + 0xff, 0xdd, 0x9c, 0xa2, 0x5f, 0xc4, 0x02, 0xb6, 0xce, 0x07, 0x83, 0xf1, + 0x1f, 0xbc, 0x6e, 0x13, 0x01, 0xeb, 0xb6, 0xf9, 0xbe, 0x22, 0xf7, 0x93, + 0xe4, 0x95, 0x8a, 0x23, 0xaf, 0x36, 0x69, 0xd0, 0x27, 0xa7, 0x82, 0xd6, + 0x29, 0xfa, 0x78, 0xca, 0xe9, 0xe3, 0x9b, 0xa2, 0x3f, 0xe3, 0x54, 0xa8, + 0xe6, 0x0d, 0x1f, 0xe1, 0xeb, 0x98, 0xb2, 0xd1, 0x35, 0x90, 0xab, 0xdf, + 0x6c, 0x43, 0xc6, 0x04, 0x71, 0xb2, 0x03, 0x01, 0xfa, 0x80, 0xee, 0xd2, + 0x07, 0xe2, 0x55, 0x7d, 0x60, 0x45, 0xe8, 0x09, 0xbb, 0x1c, 0x1d, 0x34, + 0xd8, 0x16, 0x97, 0xcb, 0xe3, 0xcc, 0x1b, 0xd8, 0xf8, 0xa4, 0x1d, 0x7d, + 0xda, 0xaa, 0x9e, 0x99, 0xc3, 0xba, 0x65, 0x8d, 0x4b, 0xfb, 0xe5, 0x09, + 0xce, 0xac, 0xa8, 0xcc, 0x3e, 0x30, 0xa3, 0xa4, 0xa5, 0x93, 0xf1, 0xa9, + 0x50, 0x84, 0x16, 0xac, 0x28, 0x15, 0xac, 0x14, 0x73, 0x70, 0xf0, 0xe3, + 0xd0, 0x80, 0x46, 0x11, 0x96, 0x35, 0x11, 0x2a, 0x95, 0x94, 0x4e, 0x76, + 0x86, 0xc8, 0x2c, 0xc6, 0xa4, 0x0d, 0x9b, 0x71, 0x9a, 0x1f, 0x33, 0xe6, + 0x49, 0x43, 0xcc, 0x8b, 0x93, 0xa3, 0x0e, 0x0c, 0x8a, 0x38, 0x4b, 0xfd, + 0xe5, 0x91, 0x28, 0xb5, 0xa7, 0xa5, 0xcd, 0x68, 0x86, 0xdb, 0xf8, 0xc2, + 0x8a, 0xd1, 0x95, 0x7c, 0xd2, 0x38, 0xc1, 0xed, 0x64, 0xac, 0x64, 0x62, + 0x92, 0x9f, 0x5d, 0x2c, 0x45, 0x28, 0x67, 0x45, 0xa8, 0x50, 0x4a, 0x19, + 0x43, 0x6d, 0xa2, 0xcd, 0x18, 0xda, 0x7c, 0x49, 0x1f, 0x33, 0x4e, 0x92, + 0xbb, 0xcd, 0xaf, 0x9c, 0x36, 0xbd, 0x6d, 0xfd, 0x61, 0xe3, 0xfe, 0x44, + 0xa8, 0x32, 0x7b, 0x9f, 0xf1, 0x92, 0x5b, 0x9d, 0x60, 0xd9, 0x14, 0x13, + 0x67, 0xdb, 0x68, 0xe9, 0x34, 0xcb, 0x1d, 0x9c, 0x6d, 0x61, 0xd0, 0x62, + 0x39, 0x4e, 0xef, 0x57, 0xed, 0x07, 0x12, 0x43, 0x39, 0x91, 0x43, 0x84, + 0x33, 0x17, 0x2a, 0xb3, 0xbf, 0x9b, 0x5e, 0x7f, 0x3f, 0xeb, 0x5b, 0x1f, + 0xc5, 0x28, 0x72, 0x15, 0x71, 0xdd, 0x36, 0x5d, 0x1b, 0x4f, 0x5e, 0xd9, + 0x14, 0x79, 0x68, 0x09, 0x5a, 0x33, 0xa5, 0x3c, 0xcd, 0x71, 0xf9, 0x15, + 0x94, 0x5b, 0x4b, 0xd0, 0x3d, 0x91, 0x8f, 0xd6, 0x4e, 0x77, 0xf4, 0x18, + 0x85, 0x6e, 0x9a, 0xc6, 0xbc, 0xf0, 0x0b, 0x57, 0x66, 0x87, 0x86, 0x0d, + 0xd2, 0xae, 0xa2, 0x1e, 0xff, 0xbf, 0x89, 0xfb, 0x28, 0x61, 0x7e, 0x66, + 0xac, 0x31, 0x5e, 0x49, 0xc3, 0xf1, 0x12, 0x64, 0xf3, 0x41, 0x89, 0xa5, + 0x39, 0x23, 0x42, 0xd0, 0x5f, 0x61, 0x7b, 0xeb, 0x35, 0x27, 0x7b, 0xa4, + 0xfe, 0xe4, 0x3b, 0x9b, 0x43, 0x9f, 0x19, 0x71, 0x9f, 0xcf, 0x51, 0x7b, + 0x66, 0xc6, 0x92, 0xef, 0xb9, 0x52, 0xee, 0xa5, 0x25, 0x6e, 0x7b, 0x64, + 0xf8, 0x8c, 0x73, 0xa6, 0x0f, 0xff, 0xd9, 0x8b, 0x7b, 0x85, 0xb7, 0x7d, + 0x7d, 0x14, 0xc5, 0x3d, 0x0d, 0xe8, 0x3c, 0xc7, 0xb0, 0xe9, 0x87, 0xc5, + 0xb8, 0xa7, 0xe2, 0x98, 0xcb, 0xb9, 0xb8, 0x3a, 0x97, 0x08, 0x65, 0xba, + 0xe9, 0x91, 0xd5, 0x45, 0x3f, 0x8b, 0xf3, 0x47, 0xf8, 0xba, 0x84, 0x9c, + 0xa3, 0x36, 0xca, 0x64, 0xbb, 0x69, 0xb3, 0x14, 0x66, 0x71, 0x05, 0xec, + 0x44, 0xb9, 0x4c, 0x81, 0xa6, 0xd6, 0x5f, 0xeb, 0x83, 0x1f, 0x66, 0x52, + 0xab, 0x61, 0xe9, 0x51, 0x00, 0x96, 0x7e, 0xa9, 0xc3, 0xd2, 0xd1, 0xbe, + 0xe6, 0x58, 0xea, 0x77, 0x62, 0xd6, 0xa3, 0x14, 0x71, 0x70, 0xf4, 0x39, + 0xe3, 0xe8, 0x3d, 0xc6, 0xd1, 0xf1, 0x06, 0x38, 0xd2, 0x3c, 0x38, 0x3a, + 0x51, 0x87, 0xa3, 0x6c, 0x5f, 0x33, 0x1c, 0x1d, 0x0f, 0xa1, 0xff, 0xcd, + 0xd6, 0x32, 0xfa, 0xb0, 0x9f, 0x39, 0xbd, 0x49, 0xa5, 0xd5, 0xe4, 0xf8, + 0x24, 0x55, 0x90, 0x73, 0x92, 0x58, 0xa2, 0xb4, 0xe0, 0x76, 0x05, 0x81, + 0xbf, 0x2c, 0x8f, 0xc9, 0xae, 0x06, 0xe7, 0xaa, 0x24, 0x9c, 0x79, 0x93, + 0x73, 0x99, 0xc9, 0x57, 0x66, 0x1f, 0x32, 0x36, 0xee, 0x6d, 0xe8, 0x3a, + 0x7e, 0x0b, 0xb1, 0x8c, 0xbc, 0xbb, 0x81, 0x73, 0x5b, 0xe2, 0x74, 0xdf, + 0x1a, 0xa0, 0x7b, 0xd6, 0x7e, 0xba, 0x6b, 0x0d, 0xd2, 0x03, 0x0b, 0x6d, + 0x60, 0x0e, 0xf8, 0x5e, 0xcc, 0x81, 0x46, 0x33, 0x31, 0x2e, 0x53, 0xda, + 0x4f, 0x95, 0x92, 0xc2, 0x35, 0xb0, 0x03, 0x0c, 0x35, 0xc6, 0x4e, 0xa6, + 0x0e, 0x3b, 0xb2, 0x0e, 0x30, 0xb3, 0xe4, 0xb7, 0xad, 0xed, 0x32, 0xf8, + 0x5d, 0x0d, 0xc6, 0x56, 0x58, 0xc4, 0x91, 0x24, 0x47, 0x67, 0x42, 0x90, + 0x59, 0xb7, 0x18, 0x53, 0x3c, 0x17, 0x3c, 0x7e, 0xda, 0xf5, 0x41, 0x96, + 0x39, 0x4f, 0x09, 0x1b, 0xf4, 0x94, 0xa9, 0xc7, 0x33, 0x64, 0x5f, 0xd6, + 0xcc, 0x31, 0x91, 0xeb, 0xb6, 0x54, 0xf6, 0x9e, 0x31, 0x91, 0xe1, 0xb1, + 0x57, 0x78, 0xf4, 0xca, 0xa1, 0x76, 0xaa, 0x38, 0x31, 0x4c, 0x85, 0x55, + 0xdb, 0x7e, 0xc8, 0xfc, 0x7f, 0xcd, 0x84, 0xcc, 0xfe, 0xdb, 0xae, 0xc4, + 0x74, 0x5a, 0x36, 0x55, 0xdf, 0xee, 0x08, 0x7c, 0x31, 0x47, 0xa4, 0x77, + 0x37, 0xaa, 0xaf, 0xc4, 0xbf, 0xe3, 0xbb, 0xbf, 0x04, 0x97, 0x59, 0xab, + 0x96, 0x85, 0xed, 0xf8, 0xd2, 0xd8, 0xc2, 0x2a, 0xce, 0x7e, 0x7b, 0xfc, + 0xea, 0xf9, 0xd5, 0x5c, 0x1f, 0x4b, 0xd8, 0x94, 0x4e, 0x76, 0x68, 0x79, + 0x3c, 0xf7, 0x5c, 0x98, 0x86, 0x19, 0x97, 0x38, 0x83, 0x6b, 0x6c, 0x34, + 0x2c, 0xce, 0x38, 0xd9, 0xcd, 0x78, 0xc8, 0x0a, 0x3b, 0xfd, 0xd4, 0x91, + 0x09, 0x9a, 0x2c, 0xa7, 0xf9, 0x53, 0x3f, 0x7e, 0xb5, 0xb9, 0xe3, 0xe1, + 0x48, 0xe3, 0x37, 0x37, 0xff, 0xa8, 0xd5, 0x9d, 0xe6, 0xba, 0x33, 0x5b, + 0xd6, 0x55, 0xe7, 0x12, 0xfd, 0x03, 0x69, 0xae, 0x1b, 0xa3, 0xbc, 0x57, + 0x00, 0x00, 0x00 }; -static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = { - 0x08001c1c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, - 0x08001b74, 0x08001c4c, 0x08001bdc, 0x08001c4c, 0x08001b08, 0x08001c4c, - 0x08001c4c, 0x08001c4c, 0x08001b14, 0x00000000, 0x08002b58, 0x08002ba8, - 0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc, - 0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140, - 0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = { + 0x08002428, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, + 0x08002380, 0x0800245c, 0x080023e4, 0x0800245c, 0x0800231c, 0x0800245c, + 0x0800245c, 0x0800245c, 0x08002328, 0x00000000, 0x08003240, 0x08003270, + 0x080032a0, 0x080032d0, 0x08003300, 0x00000000, 0x00000000 }; +static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_06 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, - .start_addr = 0x080000b4, + .start_addr = 0x080008b4, .text_addr = 0x08000000, - .text_len = 0x7d54, + .text_len = 0x57bc, .text_index = 0x0, .gz_text = bnx2_COM_b06FwText, .gz_text_len = sizeof(bnx2_COM_b06FwText), - .data_addr = 0x08007e00, + .data_addr = 0x08005840, .data_len = 0x0, .data_index = 0x0, .data = bnx2_COM_b06FwData, - .sbss_addr = 0x08007e00, - .sbss_len = 0x60, + .sbss_addr = 0x08005840, + .sbss_len = 0x1c, .sbss_index = 0x0, .sbss = bnx2_COM_b06FwSbss, - .bss_addr = 0x08007e60, + .bss_addr = 0x08005860, .bss_len = 0x88, .bss_index = 0x0, .bss = bnx2_COM_b06FwBss, - .rodata_addr = 0x08007d58, - .rodata_len = 0x88, + .rodata_addr = 0x080057c0, + .rodata_len = 0x58, .rodata_index = 0x0, .rodata = bnx2_COM_b06FwRodata, }; diff --git a/trunk/drivers/net/bnx2_fw2.h b/trunk/drivers/net/bnx2_fw2.h index 2c067531f031..680c769a3fc0 100644 --- a/trunk/drivers/net/bnx2_fw2.h +++ b/trunk/drivers/net/bnx2_fw2.h @@ -1,13 +1,13 @@ /* bnx2_fw2.h: Broadcom NX2 network driver. * - * Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation + * Copyright (c) 2006 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, except as noted below. * * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation. + * source code, Copyright (c) 2006 Broadcom Corporation. * * Permission is hereby granted for the distribution of this firmware data * in hexadecimal or equivalent format, provided this copyright notice is @@ -15,3260 +15,3289 @@ */ static u8 bnx2_COM_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b, - 0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92, - 0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0, - 0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c, - 0x69, 0x64, 0x50, 0x80, 0xb6, 0x4c, 0x46, 0xec, 0x1a, 0x9a, 0x4e, 0x87, - 0xd6, 0xa6, 0x6e, 0x9b, 0xc9, 0x34, 0x78, 0x47, 0x1f, 0x8d, 0xa7, 0x15, - 0xba, 0x06, 0x1b, 0xd9, 0xd3, 0xd0, 0xa0, 0x6a, 0x71, 0xf1, 0x8f, 0x8d, - 0xaf, 0xf9, 0x48, 0xaa, 0x4c, 0x4d, 0xa5, 0x18, 0x48, 0x69, 0xa7, 0x4d, - 0xfb, 0xa3, 0x9e, 0xa1, 0x5f, 0x84, 0x32, 0xfd, 0xc1, 0x74, 0xda, 0x4e, - 0x3a, 0x24, 0x53, 0x08, 0x84, 0xed, 0xf3, 0x9c, 0x7b, 0xee, 0xea, 0x6a, - 0x25, 0x7f, 0xf1, 0x91, 0x1f, 0xd5, 0xcc, 0xfa, 0xde, 0xf3, 0xfd, 0x9e, - 0xf7, 0xbc, 0xef, 0xf3, 0x7e, 0xdc, 0xe3, 0x4f, 0x8a, 0xb4, 0x8a, 0xf9, - 0xdb, 0x80, 0x5f, 0xfa, 0xc1, 0xdf, 0x2c, 0x5f, 0x37, 0x78, 0xdd, 0x0d, - 0x78, 0xbd, 0x41, 0xc5, 0xec, 0x18, 0xeb, 0xf9, 0x4f, 0x12, 0xbf, 0x01, - 0xf3, 0xbe, 0xd6, 0x9f, 0x83, 0xdf, 0x9b, 0x68, 0x1c, 0xfb, 0x0f, 0x11, - 0xeb, 0x3c, 0x7d, 0xa2, 0x7f, 0xf5, 0xfa, 0x85, 0xdb, 0x15, 0x69, 0xb9, - 0x40, 0x7b, 0x2c, 0x58, 0x52, 0xd3, 0xcc, 0x9f, 0x24, 0x54, 0x6e, 0xec, - 0xe1, 0x82, 0x2b, 0x89, 0x58, 0x6e, 0xf7, 0xc1, 0xb2, 0x2b, 0x92, 0xaf, - 0xed, 0x48, 0x17, 0xe5, 0x67, 0xf5, 0x4a, 0xd2, 0x16, 0xd6, 0x5f, 0x95, - 0x7b, 0xef, 0xc9, 0x17, 0x6e, 0xca, 0xfc, 0x68, 0x2e, 0x26, 0x09, 0x27, - 0xf7, 0xbc, 0x38, 0xdb, 0x25, 0xd1, 0x83, 0x31, 0x4f, 0xf4, 0xe5, 0x2d, - 0xe9, 0x08, 0xe7, 0x7a, 0xb3, 0xfe, 0x42, 0x9f, 0x54, 0xb6, 0xe4, 0x12, - 0xa2, 0x72, 0xdb, 0x5e, 0x2d, 0xc4, 0x9c, 0xb1, 0x58, 0xce, 0x91, 0x45, - 0x5f, 0x46, 0xee, 0x9f, 0x96, 0x44, 0x22, 0xf7, 0xe5, 0xc4, 0xba, 0x6d, - 0x92, 0xb0, 0x73, 0x4b, 0x0f, 0xff, 0xbe, 0x7b, 0xb0, 0xae, 0x5c, 0xb7, - 0x7f, 0x5e, 0xda, 0x87, 0x4e, 0x0c, 0xa2, 0xbd, 0x96, 0xe9, 0x17, 0xb9, - 0x49, 0x94, 0x5b, 0x69, 0x8f, 0xb9, 0x09, 0x29, 0xf8, 0xae, 0x14, 0x7d, - 0x91, 0xbf, 0xac, 0x59, 0x72, 0xc2, 0xed, 0x92, 0xf9, 0x9d, 0xef, 0xd5, - 0xf3, 0xa0, 0xe5, 0xfb, 0xee, 0xd2, 0xc3, 0x93, 0x2e, 0xe9, 0x3d, 0x90, - 0x08, 0xe8, 0xdd, 0xbb, 0xae, 0xec, 0xda, 0x32, 0x5e, 0x63, 0xdd, 0xa8, - 0x62, 0x5d, 0x3c, 0x97, 0x68, 0x3d, 0xe1, 0xb6, 0x9b, 0xba, 0x57, 0x6f, - 0x29, 0x60, 0xbe, 0x89, 0x1a, 0xfb, 0xe6, 0xaf, 0x2f, 0xbb, 0x49, 0x53, - 0xbf, 0x70, 0x63, 0xc1, 0x4d, 0xa1, 0xbe, 0xc7, 0xb4, 0x8d, 0x3d, 0x58, - 0x76, 0x5d, 0xd3, 0xf6, 0x76, 0xac, 0xe0, 0xf6, 0x9b, 0xfa, 0xf7, 0x6e, - 0x2e, 0xbb, 0x3b, 0x4d, 0x7d, 0x0f, 0xe6, 0xca, 0x9a, 0xfa, 0x85, 0x7b, - 0xca, 0xee, 0xa0, 0xa9, 0xdf, 0x7d, 0x73, 0xc1, 0x1d, 0x32, 0xf5, 0x89, - 0xa1, 0xb2, 0x9b, 0x43, 0xfd, 0x97, 0x13, 0x6a, 0x9b, 0x23, 0x53, 0xb5, - 0x34, 0x7e, 0x79, 0xb4, 0x0d, 0xa3, 0x6e, 0x37, 0x7e, 0xb7, 0xe3, 0xf7, - 0xc8, 0x46, 0xe9, 0x18, 0xc1, 0xf3, 0xbf, 0xba, 0x03, 0xde, 0x81, 0x47, - 0x5e, 0x42, 0x5e, 0x8f, 0xa5, 0xe4, 0x85, 0xbe, 0xd7, 0xc1, 0x43, 0x47, - 0x4e, 0xfb, 0x62, 0x8d, 0xf4, 0xa5, 0xc0, 0xbb, 0xa4, 0x3c, 0xe3, 0xb7, - 0x49, 0xec, 0xb1, 0x18, 0x78, 0xf3, 0xcb, 0x52, 0x4a, 0x26, 0x64, 0xd3, - 0xac, 0x25, 0x5b, 0x07, 0x12, 0x92, 0x77, 0xb8, 0x36, 0x4e, 0x7b, 0x26, - 0x29, 0xb1, 0xd9, 0xfc, 0x66, 0x25, 0xdb, 0x9c, 0xa2, 0x54, 0xc0, 0xbb, - 0x57, 0x29, 0x97, 0x68, 0x4b, 0x4b, 0x71, 0xfa, 0x5a, 0x19, 0x73, 0x48, - 0xd7, 0x1f, 0x5c, 0x15, 0xac, 0x95, 0xb0, 0x0a, 0xc7, 0x46, 0x65, 0xca, - 0x6b, 0xb7, 0x8a, 0xc7, 0x6e, 0x96, 0x42, 0x56, 0x92, 0x18, 0x97, 0x2a, - 0xa1, 0xa5, 0x5a, 0x1b, 0x95, 0x49, 0x4f, 0xac, 0x82, 0x47, 0x7e, 0x76, - 0xa1, 0xbd, 0x43, 0xf7, 0x45, 0x5d, 0x4f, 0x4c, 0xcf, 0x9d, 0x40, 0xbd, - 0x83, 0xfa, 0x4e, 0x6b, 0x58, 0xcf, 0xa1, 0xeb, 0xd3, 0x13, 0xd2, 0x2e, - 0x4f, 0xd5, 0x92, 0xa6, 0x6f, 0xbd, 0x5e, 0xc8, 0x3a, 0xe8, 0x37, 0x2a, - 0x13, 0x5e, 0x52, 0xc6, 0xf0, 0x1c, 0xf7, 0xb8, 0x7e, 0x0a, 0x32, 0x75, - 0xdd, 0xc1, 0xd2, 0x51, 0x3d, 0x5f, 0x3a, 0x96, 0xe3, 0x7c, 0x3d, 0xe8, - 0xf7, 0x12, 0xe8, 0xb2, 0xc4, 0xd6, 0x67, 0x99, 0x97, 0xd2, 0xb4, 0x05, - 0x79, 0xc3, 0x53, 0xf3, 0x75, 0x18, 0xf4, 0xdb, 0xe2, 0x0e, 0x58, 0x52, - 0xc6, 0x59, 0x55, 0x1c, 0x94, 0x6b, 0x0b, 0xaa, 0xe0, 0xad, 0x93, 0xa2, - 0x9d, 0x96, 0xd8, 0x0c, 0x65, 0x69, 0x4c, 0x26, 0x30, 0x46, 0xb9, 0xec, - 0xf3, 0x0e, 0xf6, 0x3d, 0xa6, 0xcf, 0xa1, 0x25, 0x57, 0x51, 0x45, 0xbf, - 0x4b, 0xd4, 0xec, 0xbd, 0xf2, 0xd2, 0xb4, 0x38, 0x38, 0xc7, 0x7a, 0xc1, - 0x9d, 0x54, 0x85, 0xa7, 0x6d, 0x89, 0xcf, 0x58, 0x32, 0xe9, 0x66, 0xa0, - 0x01, 0x87, 0xd4, 0x2e, 0x7f, 0x01, 0xfd, 0x38, 0x0e, 0xfd, 0x6a, 0x0a, - 0x7c, 0xe5, 0xfb, 0x0e, 0x47, 0x69, 0x79, 0x66, 0x1f, 0x9c, 0x01, 0xf6, - 0xf1, 0x8c, 0x87, 0x33, 0xd1, 0x67, 0x94, 0xc6, 0x19, 0x89, 0x35, 0xdc, - 0x07, 0x99, 0x3a, 0x6a, 0x4b, 0x29, 0x8b, 0x7d, 0xa1, 0x77, 0x29, 0xbb, - 0x4c, 0xd7, 0xc4, 0x74, 0x33, 0x5d, 0x1c, 0x47, 0xba, 0x02, 0x9a, 0xc6, - 0x8f, 0x92, 0xbe, 0x65, 0x7a, 0xa6, 0xa6, 0x43, 0x1a, 0xb9, 0x1e, 0x69, - 0x0b, 0xe9, 0xe2, 0x38, 0xd2, 0xb5, 0x99, 0x67, 0xcd, 0x3f, 0x6b, 0x18, - 0x74, 0x4c, 0x78, 0x36, 0xce, 0xa8, 0x5d, 0x4a, 0x4e, 0xc5, 0x9a, 0x18, - 0xda, 0x91, 0x82, 0x36, 0x5b, 0xe3, 0x43, 0xa4, 0xd9, 0xc5, 0x39, 0xb6, - 0xe8, 0xf3, 0x56, 0xb9, 0x49, 0xf2, 0x0e, 0xfd, 0xb9, 0x3e, 0xde, 0x6b, - 0x8e, 0x4c, 0xea, 0xf9, 0x48, 0xd3, 0x47, 0x31, 0x0f, 0x69, 0x7d, 0x05, - 0xb2, 0x3a, 0x08, 0x19, 0xcd, 0xca, 0x5f, 0xf8, 0x3b, 0xe5, 0xcf, 0xfc, - 0x7e, 0xf9, 0x0e, 0xf4, 0xf6, 0xdb, 0x7e, 0x5a, 0x9e, 0xf7, 0x7b, 0xe4, - 0x39, 0x3f, 0x25, 0xcf, 0x6a, 0xf9, 0x1d, 0x16, 0xe9, 0xa0, 0x4c, 0xa7, - 0xa5, 0x13, 0xfa, 0xb3, 0x09, 0xba, 0xf9, 0x38, 0xf8, 0x77, 0xb4, 0x4f, - 0xf2, 0x9b, 0x73, 0x92, 0xb8, 0x1a, 0xbf, 0x2b, 0xf0, 0xeb, 0xca, 0xd9, - 0x5a, 0x56, 0xec, 0x1c, 0x79, 0x68, 0x4b, 0x51, 0xef, 0xd9, 0x96, 0x09, - 0xff, 0x91, 0xab, 0x03, 0xd9, 0x15, 0x19, 0x01, 0x8f, 0xd5, 0xc0, 0x4f, - 0xea, 0x79, 0x07, 0xfb, 0x18, 0xd8, 0xa1, 0x79, 0xaf, 0x06, 0x28, 0xb3, - 0x69, 0xc8, 0xbd, 0x6d, 0x15, 0xbd, 0x93, 0xc0, 0x8d, 0x36, 0xab, 0x70, - 0xa4, 0x22, 0xe5, 0x23, 0x75, 0x29, 0x67, 0xe3, 0xf2, 0x90, 0x53, 0x97, - 0xe1, 0x6c, 0x8b, 0xec, 0x77, 0xc0, 0xfb, 0x9d, 0xbf, 0x6d, 0x85, 0x98, - 0xfd, 0xb8, 0xff, 0x3b, 0x78, 0x67, 0x9d, 0xc8, 0x51, 0xfd, 0x1e, 0xd4, - 0x57, 0xfc, 0xb8, 0xe4, 0x93, 0x95, 0x94, 0x2d, 0x5b, 0x54, 0xb0, 0xee, - 0x78, 0xd8, 0x06, 0x7e, 0x2c, 0x01, 0x27, 0x33, 0x5a, 0x5f, 0x4a, 0xd3, - 0xeb, 0xdf, 0xce, 0xeb, 0x6a, 0xf4, 0x77, 0x06, 0xe5, 0xac, 0xe6, 0x67, - 0x7a, 0xcc, 0xca, 0x25, 0x65, 0x6b, 0x8d, 0xe5, 0x21, 0xeb, 0x4e, 0x9f, - 0xf2, 0x8c, 0x77, 0x9f, 0x74, 0x5e, 0x89, 0x7e, 0x36, 0x9e, 0x79, 0x43, - 0x6f, 0x94, 0x46, 0xce, 0x43, 0x1a, 0xf9, 0xfc, 0x66, 0x84, 0xc6, 0x27, - 0x1b, 0xef, 0x47, 0x23, 0xef, 0x15, 0xff, 0x8f, 0x5a, 0x03, 0xda, 0x86, - 0xe4, 0x8d, 0x99, 0xaf, 0x98, 0x75, 0xf0, 0x7e, 0x8a, 0xf3, 0x7f, 0xab, - 0x1e, 0xc8, 0x4b, 0xe5, 0x22, 0xeb, 0x2c, 0x44, 0xd6, 0xf9, 0x6e, 0x64, - 0x9d, 0xef, 0x46, 0xd6, 0xa9, 0x80, 0xa7, 0xb2, 0x51, 0x41, 0x86, 0x4b, - 0x34, 0x63, 0x72, 0x08, 0x73, 0xbe, 0x2e, 0xb1, 0x1c, 0xf5, 0x3c, 0xc4, - 0x9b, 0x73, 0xe8, 0x9f, 0x93, 0xb3, 0x33, 0x15, 0x29, 0x1d, 0x89, 0xcb, - 0x1d, 0xba, 0xdf, 0x26, 0x43, 0x5f, 0xb4, 0x2d, 0x21, 0x7b, 0x92, 0x7c, - 0x0f, 0xdb, 0x6c, 0xf0, 0x99, 0xe5, 0x6f, 0x5d, 0x19, 0x94, 0xf9, 0xbe, - 0x60, 0xf6, 0x32, 0x1a, 0x8c, 0x3b, 0xf5, 0xa6, 0xc6, 0xc3, 0x45, 0x9f, - 0xb8, 0x25, 0xd9, 0x98, 0x2b, 0xfb, 0x86, 0xb3, 0x5d, 0x32, 0xe1, 0x58, - 0xd9, 0xf1, 0xfe, 0x75, 0xd4, 0x8b, 0xbc, 0x72, 0xdb, 0x80, 0x0d, 0x92, - 0x56, 0xc4, 0x7c, 0xbd, 0x2f, 0x4b, 0x05, 0xf4, 0x3b, 0x2c, 0x8f, 0x28, - 0xb7, 0xb3, 0xa9, 0x9e, 0xba, 0x1d, 0xc3, 0x3b, 0x65, 0x78, 0x97, 0x39, - 0x63, 0x1b, 0x65, 0xe2, 0xf0, 0x35, 0xa6, 0x1c, 0xb6, 0x6f, 0xb6, 0x57, - 0x96, 0xcf, 0x76, 0xaf, 0x2c, 0x87, 0x38, 0x11, 0xc5, 0x70, 0xee, 0x15, - 0xf8, 0xe4, 0x52, 0xee, 0xe2, 0xa0, 0x35, 0x0b, 0x9d, 0x5b, 0x67, 0x68, - 0xb8, 0xc2, 0xd0, 0x00, 0x5a, 0xfb, 0x20, 0x59, 0x5a, 0x97, 0xb4, 0x68, - 0x35, 0x95, 0xc9, 0xfb, 0xf0, 0x7d, 0x83, 0x6e, 0x0f, 0x74, 0x2e, 0x7c, - 0x86, 0xf8, 0xfe, 0x66, 0xc4, 0x5e, 0xf4, 0x40, 0x67, 0x93, 0xe0, 0x55, - 0x88, 0xf5, 0xc4, 0xe0, 0x14, 0xec, 0x03, 0x64, 0x55, 0x63, 0x7b, 0x3b, - 0xf0, 0xd0, 0x36, 0xd8, 0x9c, 0x30, 0xd8, 0xdc, 0x0e, 0x5c, 0x66, 0xd9, - 0x31, 0xe5, 0xa4, 0x29, 0xa7, 0x50, 0x86, 0x1d, 0x9f, 0x25, 0x2e, 0x5f, - 0x77, 0x70, 0xef, 0x51, 0x8d, 0xf7, 0xb4, 0x15, 0x40, 0x61, 0xe2, 0x35, - 0x71, 0xbb, 0x47, 0xe6, 0x6b, 0x58, 0xaf, 0x81, 0x8d, 0xdc, 0x7b, 0x94, - 0x1e, 0xd2, 0xb2, 0x5e, 0x14, 0x6c, 0x57, 0x3e, 0x49, 0x7a, 0x1f, 0xc4, - 0xde, 0x89, 0x3f, 0xa4, 0xfb, 0x2a, 0xd0, 0xca, 0x7d, 0xfc, 0x3c, 0x69, - 0xe5, 0x7a, 0xcd, 0xf4, 0x7e, 0x58, 0x1c, 0x24, 0xed, 0x27, 0xb1, 0xe7, - 0x3c, 0x30, 0x4f, 0xac, 0xd1, 0xbe, 0x51, 0xec, 0x79, 0x04, 0x78, 0x78, - 0x3b, 0xf0, 0x70, 0x37, 0xf0, 0x70, 0x18, 0x78, 0x98, 0x03, 0x16, 0x0e, - 0x01, 0x0b, 0x07, 0x81, 0x85, 0x59, 0xf0, 0x26, 0x29, 0x73, 0xc0, 0xc6, - 0x39, 0x60, 0xe4, 0x1c, 0xe6, 0x18, 0x9f, 0x15, 0xeb, 0x4b, 0xd8, 0xc3, - 0x63, 0x33, 0x99, 0x93, 0x90, 0xa5, 0x54, 0x45, 0x41, 0xfe, 0xb3, 0x43, - 0x90, 0xed, 0x7e, 0xa9, 0xfa, 0xb6, 0x94, 0x69, 0x53, 0xb7, 0xf7, 0x42, - 0xd7, 0x20, 0xef, 0x29, 0x31, 0x7f, 0x1b, 0xcc, 0xf3, 0x1f, 0x45, 0xdc, - 0xbf, 0xa3, 0x2c, 0xa6, 0x45, 0xce, 0x48, 0xc9, 0xeb, 0x75, 0x0a, 0xaa, - 0x1f, 0xfd, 0x58, 0xce, 0xaa, 0xfb, 0x8f, 0x5c, 0xaf, 0xf6, 0x1e, 0x21, - 0x5f, 0xa6, 0x81, 0x57, 0x75, 0x99, 0xcc, 0x52, 0xb7, 0xea, 0x72, 0x22, - 0x9b, 0x19, 0xaa, 0x48, 0x9b, 0x4c, 0x25, 0xa7, 0xb5, 0xad, 0xb5, 0x73, - 0x87, 0xb5, 0xbd, 0x2a, 0xbb, 0x78, 0xd6, 0x06, 0x54, 0xe9, 0x08, 0xf7, - 0xdf, 0x8b, 0x5f, 0x1c, 0xb4, 0x70, 0x7e, 0x5b, 0x86, 0x07, 0x1d, 0xf5, - 0x40, 0x5f, 0x05, 0x08, 0x96, 0x71, 0xce, 0x62, 0xe5, 0xe2, 0x74, 0x6f, - 0xaa, 0xa8, 0x6c, 0x19, 0xb3, 0x2d, 0x19, 0x87, 0x7c, 0x0f, 0x67, 0xdf, - 0xa9, 0x4f, 0x25, 0xd9, 0xbe, 0x4e, 0xbe, 0xae, 0x7d, 0x0e, 0xac, 0x5d, - 0x3d, 0x8a, 0x75, 0xe3, 0x38, 0x03, 0xae, 0xcb, 0x79, 0x50, 0xae, 0xd9, - 0x28, 0x67, 0x4e, 0x56, 0xc4, 0x87, 0x9e, 0x6c, 0x94, 0xc2, 0xce, 0x16, - 0xc9, 0x8f, 0xa4, 0x65, 0x7c, 0xc6, 0x07, 0x4e, 0xe1, 0x1c, 0xdd, 0x56, - 0x29, 0x8d, 0xa6, 0xe5, 0xd1, 0x19, 0xd6, 0x9d, 0xc6, 0xfe, 0x33, 0x87, - 0xf2, 0xc2, 0xfd, 0xc7, 0xf5, 0xbe, 0xd2, 0xea, 0xb4, 0xec, 0xf7, 0xde, - 0x30, 0x7a, 0x14, 0x94, 0xef, 0xc7, 0x99, 0x9e, 0xf0, 0x17, 0xb0, 0x7f, - 0x57, 0xe6, 0x81, 0xff, 0xc5, 0x23, 0xc0, 0x41, 0xb7, 0x03, 0x98, 0x95, - 0x59, 0xa0, 0x4d, 0x8d, 0xc1, 0xef, 0xab, 0x6a, 0x5e, 0xf7, 0xc8, 0x91, - 0x19, 0x25, 0xdf, 0xbe, 0x31, 0x8d, 0x32, 0xb0, 0x31, 0x9b, 0x39, 0x3d, - 0xa6, 0x7a, 0xe4, 0x86, 0xce, 0x14, 0xc6, 0xe5, 0x54, 0xc9, 0xdb, 0x18, - 0x03, 0x2f, 0x8f, 0xa7, 0x15, 0xfb, 0x2a, 0x29, 0x66, 0x63, 0x38, 0xff, - 0x0a, 0xfa, 0xbf, 0x8f, 0xf5, 0x7a, 0x64, 0x16, 0xbe, 0xd6, 0xec, 0x4c, - 0x1e, 0xe3, 0x88, 0x5d, 0x99, 0xe3, 0x4b, 0x0a, 0x18, 0x33, 0x0b, 0xf9, - 0x1e, 0x85, 0x2f, 0x33, 0x03, 0xd1, 0x69, 0x4d, 0xe3, 0x4c, 0x7b, 0x9d, - 0x71, 0xe0, 0x41, 0xbe, 0x87, 0xef, 0x9c, 0xd3, 0x95, 0x13, 0x1e, 0xe5, - 0x30, 0x2d, 0x4f, 0xf9, 0x1c, 0xd7, 0xbb, 0xf0, 0x1c, 0x7c, 0x9f, 0xdf, - 0xf5, 0xae, 0x44, 0xff, 0x77, 0xe1, 0x07, 0x3b, 0x52, 0xc5, 0xb9, 0x95, - 0xc1, 0xcb, 0x7c, 0x2a, 0x28, 0x8f, 0xcf, 0x66, 0x16, 0xde, 0x50, 0x7c, - 0x77, 0x2b, 0xf3, 0xea, 0x5a, 0x91, 0x4e, 0xf2, 0x33, 0x0b, 0x5e, 0xba, - 0x8e, 0x52, 0xdb, 0x8d, 0xef, 0x47, 0x3d, 0x72, 0x41, 0x9f, 0x2d, 0xf3, - 0x03, 0x51, 0x3d, 0xa2, 0x3d, 0x0c, 0xf5, 0x28, 0x93, 0x5a, 0x52, 0x0a, - 0xed, 0xb6, 0x1c, 0xd6, 0x65, 0x0b, 0xb4, 0x66, 0x52, 0xdc, 0xdf, 0x44, - 0xad, 0x5f, 0x9e, 0xf2, 0xd8, 0x1f, 0x7c, 0x9e, 0x6e, 0x37, 0xfd, 0x4f, - 0x83, 0x87, 0xf4, 0xdf, 0xfa, 0x41, 0x73, 0xa0, 0x5b, 0xf3, 0xd3, 0x49, - 0xdd, 0x36, 0xe5, 0x05, 0x7e, 0x9a, 0x82, 0x2f, 0x37, 0x07, 0x5f, 0xae, - 0xa8, 0xf5, 0xcc, 0xc9, 0xc3, 0xd7, 0x87, 0x9e, 0x04, 0x3a, 0x56, 0xad, - 0x91, 0x96, 0xbb, 0x40, 0x5f, 0xa6, 0x02, 0x62, 0x0e, 0xab, 0x1c, 0xce, - 0x7d, 0x50, 0x2a, 0xf4, 0xf7, 0xce, 0xc6, 0x9e, 0x92, 0xb1, 0x2a, 0xed, - 0x11, 0x7e, 0x9e, 0xeb, 0x30, 0xbe, 0xc8, 0x6b, 0x5b, 0xd1, 0x0d, 0x39, - 0x80, 0x1d, 0xc9, 0x6e, 0x32, 0x7e, 0xce, 0x13, 0x38, 0xcf, 0x33, 0x38, - 0xf7, 0x9a, 0xec, 0x3d, 0xf6, 0x0a, 0x65, 0xba, 0xbf, 0x2a, 0x99, 0xfe, - 0x29, 0xd9, 0xe1, 0xcc, 0x43, 0x1f, 0xf3, 0xa3, 0xf5, 0x5b, 0x54, 0x8e, - 0x63, 0x0e, 0x62, 0x0c, 0x9e, 0xd5, 0x57, 0xe4, 0x21, 0x9f, 0x75, 0x0f, - 0x81, 0x9f, 0xd0, 0x95, 0xc1, 0x27, 0x8c, 0x1e, 0x60, 0x3e, 0x3b, 0x9c, - 0xef, 0x15, 0x33, 0x1f, 0xfb, 0xb1, 0x0f, 0xc7, 0x2c, 0xcf, 0xbb, 0x8b, - 0xb6, 0x08, 0x78, 0xb4, 0x4b, 0xd5, 0x6f, 0x89, 0xa3, 0xfd, 0xc4, 0x20, - 0xdf, 0x31, 0x0f, 0x6c, 0x91, 0xe3, 0x9e, 0x41, 0x5f, 0xf8, 0x7a, 0xde, - 0x7a, 0x29, 0x74, 0x85, 0xf4, 0x52, 0x06, 0xe8, 0x27, 0x68, 0x1b, 0xbc, - 0x39, 0xe0, 0xfd, 0x1f, 0xc6, 0x02, 0x99, 0x3c, 0x80, 0x32, 0xf5, 0xef, - 0x80, 0x14, 0xbd, 0x0c, 0xf6, 0x09, 0x1d, 0xf3, 0x3b, 0xac, 0x60, 0x8f, - 0xe0, 0xff, 0xc8, 0x39, 0xf0, 0x41, 0x2a, 0x01, 0x6f, 0xc8, 0x17, 0xf2, - 0xa4, 0x03, 0xb2, 0x0f, 0xb9, 0x87, 0xdc, 0x96, 0x34, 0x0f, 0xfe, 0xbd, - 0x33, 0xf0, 0x8b, 0x33, 0x95, 0x3c, 0xe3, 0xb9, 0x4e, 0xe2, 0x26, 0x30, - 0xcc, 0x87, 0x70, 0x60, 0xee, 0x25, 0xb5, 0x9e, 0xf4, 0xa6, 0x97, 0x62, - 0x7d, 0x2c, 0xf7, 0x2f, 0x41, 0x86, 0xab, 0x38, 0x9f, 0xc2, 0xce, 0x5e, - 0x83, 0x5b, 0xcf, 0xc6, 0x28, 0xaf, 0x55, 0x60, 0x4c, 0xc9, 0xdb, 0xe1, - 0xdc, 0x4d, 0xbe, 0x39, 0x8e, 0x3c, 0xe7, 0x45, 0xb1, 0x03, 0xb6, 0xcf, - 0xa5, 0x1c, 0x26, 0x21, 0x07, 0x36, 0x6c, 0x68, 0x0a, 0x67, 0xfe, 0x6f, - 0x9d, 0xc1, 0x5e, 0xf8, 0x6e, 0xcb, 0x9c, 0x83, 0x35, 0xbd, 0xc5, 0x8d, - 0x41, 0x1d, 0xdf, 0xb7, 0xf0, 0x8c, 0x0e, 0xaf, 0xa4, 0x9d, 0xe7, 0xdb, - 0x7c, 0xa6, 0x27, 0xb0, 0x17, 0xd6, 0xe3, 0x59, 0x3d, 0x2e, 0x7b, 0x89, - 0x9b, 0x83, 0xdb, 0x52, 0x2f, 0xa2, 0x7f, 0x11, 0x36, 0xa1, 0x62, 0xb3, - 0xed, 0x6d, 0x6b, 0x79, 0x8c, 0xa2, 0x5f, 0x0a, 0x1f, 0x78, 0xc9, 0xfa, - 0x92, 0xff, 0x92, 0x55, 0xa8, 0xbe, 0x6d, 0x15, 0x21, 0x27, 0x55, 0x8f, - 0xf1, 0x0b, 0xf5, 0xc7, 0xc1, 0xda, 0x99, 0xd4, 0x5b, 0xaa, 0x37, 0x3d, - 0x0f, 0x2c, 0xb8, 0x1f, 0x3a, 0x5d, 0xb4, 0x17, 0xa4, 0xec, 0xd7, 0xa4, - 0x74, 0x6c, 0x07, 0xf4, 0x2d, 0x1d, 0xa1, 0x8b, 0x78, 0x56, 0xa1, 0x1f, - 0x6e, 0xed, 0xf2, 0xa4, 0xd2, 0x92, 0x23, 0xae, 0x6d, 0x83, 0xec, 0xa0, - 0xae, 0xb6, 0x2c, 0x7f, 0xb7, 0xad, 0xa2, 0x15, 0xb1, 0xee, 0xe0, 0x4a, - 0x7a, 0xab, 0x72, 0x71, 0x7a, 0x77, 0x35, 0xe8, 0x25, 0x66, 0x00, 0xff, - 0x3d, 0xe0, 0xbf, 0x07, 0xfc, 0xf7, 0x80, 0xff, 0x1e, 0xf0, 0xdf, 0x83, - 0x6d, 0xf0, 0x60, 0x03, 0x3c, 0xd8, 0x00, 0x0f, 0x36, 0xc0, 0x83, 0x0d, - 0xf0, 0x0a, 0x38, 0x27, 0xe2, 0x3c, 0x6d, 0xc8, 0x3d, 0x0d, 0xbb, 0x19, - 0xf8, 0x39, 0x57, 0x1a, 0xdf, 0x01, 0xfa, 0xe7, 0x6c, 0x91, 0xf1, 0xfe, - 0x2b, 0xb0, 0xb7, 0x56, 0x3c, 0xdb, 0xf0, 0xc4, 0x1a, 0xfd, 0x9f, 0x35, - 0x7a, 0xf2, 0x55, 0xd0, 0xa5, 0x50, 0xfe, 0x05, 0xc8, 0x61, 0x0b, 0xe8, - 0xf9, 0x94, 0xf1, 0x31, 0xbe, 0x61, 0x07, 0x72, 0xd8, 0x86, 0xba, 0xcf, - 0xa0, 0xae, 0x0d, 0x7d, 0xf6, 0xa3, 0x0f, 0x7d, 0x94, 0x0e, 0x53, 0x17, - 0xed, 0x47, 0x5f, 0xe5, 0x0b, 0x58, 0x2b, 0x83, 0x7e, 0x1d, 0x98, 0xbb, - 0x07, 0x7d, 0x6e, 0x46, 0x9f, 0xab, 0x50, 0xa6, 0x6f, 0xdb, 0x8d, 0xf2, - 0xa7, 0x9b, 0xc6, 0x5c, 0x83, 0xba, 0xcf, 0x36, 0xd5, 0x9d, 0x45, 0x1d, - 0x62, 0x62, 0xe7, 0x45, 0x33, 0xae, 0x82, 0x72, 0x57, 0x53, 0x9f, 0x57, - 0x50, 0x37, 0x84, 0xba, 0xbf, 0xc2, 0x13, 0xb1, 0xb0, 0x43, 0x9a, 0xc2, - 0x36, 0xfa, 0xa9, 0x69, 0xd4, 0xc7, 0x8d, 0xaf, 0xf9, 0x24, 0x7d, 0x2f, - 0xd8, 0xdc, 0x3f, 0xb6, 0x03, 0xdf, 0x0c, 0xde, 0xab, 0x96, 0xc3, 0xb0, - 0xfc, 0xcd, 0xa6, 0x32, 0xfb, 0x7e, 0xbf, 0xa9, 0xae, 0x6d, 0xd3, 0xca, - 0xf2, 0x4f, 0xe3, 0xab, 0xc7, 0xdc, 0xdb, 0xd4, 0xe7, 0xeb, 0x9d, 0x2b, - 0xcb, 0xbb, 0x5b, 0x56, 0x8f, 0xd9, 0xbe, 0x71, 0x65, 0xdd, 0xad, 0x9b, - 0x57, 0x96, 0xe9, 0x03, 0x26, 0x11, 0xc3, 0x84, 0xfd, 0x77, 0x7e, 0x22, - 0x68, 0x27, 0x7f, 0x9b, 0x65, 0x49, 0x2b, 0x23, 0xca, 0x0a, 0xe7, 0xb0, - 0x64, 0x41, 0x9f, 0x1c, 0x95, 0x7b, 0xc9, 0x2a, 0x42, 0xa6, 0x0a, 0x7e, - 0x38, 0x1f, 0x75, 0xb6, 0x39, 0x4f, 0x10, 0xe6, 0x07, 0xe8, 0x6f, 0xb5, - 0x43, 0x6e, 0xee, 0xa2, 0x4d, 0x3a, 0x54, 0x91, 0x65, 0xfd, 0xdc, 0xaa, - 0xce, 0xa7, 0x9f, 0xf7, 0x19, 0x8c, 0x3a, 0x07, 0x3a, 0xeb, 0x32, 0x92, - 0x5d, 0x47, 0x1b, 0x63, 0xb0, 0x8b, 0xb8, 0x53, 0xaf, 0xc7, 0xb6, 0xd7, - 0x65, 0x5f, 0xf6, 0xdd, 0xba, 0x68, 0xcc, 0xbb, 0x57, 0xe3, 0x4e, 0x5a, - 0x75, 0xe3, 0x8c, 0x1c, 0xc4, 0x12, 0x88, 0xed, 0x93, 0xb4, 0x49, 0xc7, - 0xe9, 0x9f, 0x1c, 0x0c, 0x30, 0x95, 0xb8, 0x83, 0xb2, 0x3f, 0x85, 0x39, - 0xb9, 0x3e, 0x9e, 0x55, 0xe2, 0xb8, 0xad, 0x6d, 0x4a, 0xc9, 0xe1, 0xbc, - 0x6b, 0x61, 0xe3, 0xbf, 0xd8, 0xf4, 0x0b, 0x6d, 0xf7, 0x24, 0xec, 0x1b, - 0xdb, 0xe8, 0x2b, 0x9c, 0xa4, 0x5f, 0x12, 0xc1, 0xaa, 0x9b, 0x62, 0xe2, - 0x2e, 0x63, 0x66, 0xb0, 0xaf, 0x2d, 0xf4, 0xfb, 0x2f, 0x61, 0xaf, 0x6b, - 0x63, 0x51, 0xaf, 0xba, 0xb8, 0x6e, 0xef, 0x69, 0xe8, 0x76, 0x28, 0x7b, - 0x6b, 0xe5, 0x03, 0x5e, 0xd5, 0x67, 0xf1, 0xac, 0x9f, 0x39, 0x5c, 0x81, - 0x2e, 0x2d, 0xea, 0xd8, 0x37, 0x3c, 0x17, 0xfa, 0x38, 0x99, 0xe3, 0x73, - 0x90, 0xed, 0xbd, 0x3a, 0x26, 0x60, 0x3c, 0x50, 0x97, 0x5d, 0xd9, 0x4f, - 0x25, 0xc9, 0x87, 0xbc, 0xfa, 0x71, 0x9c, 0x3e, 0xc3, 0xa2, 0x47, 0x9e, - 0x65, 0xd1, 0x9e, 0x05, 0x26, 0xfc, 0xab, 0x14, 0x93, 0xac, 0x7b, 0xab, - 0x3e, 0x0f, 0xbf, 0x4a, 0xfb, 0x47, 0xda, 0xde, 0xd3, 0xbf, 0x83, 0x5d, - 0xf7, 0xc9, 0xd3, 0x25, 0xf0, 0x39, 0xf4, 0x01, 0x7e, 0x40, 0x1f, 0x55, - 0x56, 0xfa, 0xd2, 0x22, 0x0f, 0xd5, 0xfe, 0x01, 0x36, 0x47, 0x05, 0xbe, - 0x0a, 0xe3, 0x65, 0x97, 0xf5, 0x37, 0xc6, 0xe9, 0xcb, 0x05, 0xb6, 0x3e, - 0x86, 0xf5, 0x10, 0x5f, 0xd7, 0xfe, 0xd3, 0x2a, 0x79, 0x3d, 0xf4, 0xb3, - 0xb0, 0x7f, 0xf8, 0x50, 0x3e, 0xdb, 0x58, 0x97, 0x30, 0xfe, 0x77, 0xbb, - 0xf1, 0xb7, 0x1d, 0xe3, 0x6f, 0x6b, 0x3a, 0x12, 0x4e, 0x2e, 0xf4, 0x0b, - 0x78, 0x66, 0xe9, 0x83, 0x6a, 0x3b, 0xfd, 0x82, 0x0e, 0x59, 0xdb, 0x2f, - 0x08, 0x69, 0x3a, 0x85, 0x7d, 0xd2, 0xcf, 0xd3, 0x79, 0xa0, 0xce, 0x20, - 0xf7, 0x44, 0x1a, 0x42, 0xfb, 0xa8, 0xed, 0xf0, 0x21, 0x98, 0x3c, 0xe6, - 0x24, 0x41, 0xeb, 0x6e, 0x29, 0x4c, 0x9f, 0x32, 0xf6, 0x96, 0x71, 0x04, - 0x7d, 0xf8, 0x40, 0x66, 0x0b, 0xd9, 0x0e, 0xcb, 0xcc, 0xd3, 0x05, 0x0b, - 0x19, 0xc9, 0x51, 0x71, 0x2d, 0xfa, 0x31, 0xa1, 0x4f, 0xb3, 0x60, 0x7c, - 0x9a, 0x33, 0xb2, 0xcf, 0x0b, 0xe2, 0x86, 0x91, 0xda, 0x12, 0xea, 0x34, - 0xed, 0x29, 0xfa, 0x96, 0x0a, 0x3e, 0x77, 0xfe, 0xde, 0x0c, 0x02, 0x90, - 0x60, 0x2f, 0x5b, 0xb1, 0x97, 0x6a, 0x63, 0x2f, 0x6d, 0x4b, 0xcd, 0x3e, - 0x0e, 0xc7, 0x4e, 0xae, 0x1a, 0x2b, 0xd8, 0xc7, 0xdc, 0x79, 0xda, 0xb8, - 0x47, 0xfa, 0x0d, 0x8e, 0xd9, 0x63, 0x78, 0x4e, 0x8f, 0x63, 0x8f, 0x49, - 0xab, 0xa4, 0x7d, 0x2d, 0xfa, 0x2d, 0x88, 0xb3, 0x6b, 0x2f, 0xe1, 0x49, - 0xfd, 0xd0, 0xf3, 0x60, 0x4f, 0xed, 0x7a, 0x4f, 0x53, 0xde, 0x2b, 0x7a, - 0x1f, 0xf3, 0xb5, 0xbf, 0x91, 0xf2, 0xb1, 0x1f, 0xc0, 0xee, 0x45, 0x73, - 0x73, 0xcc, 0x6b, 0x92, 0x1f, 0x95, 0x08, 0x7e, 0x72, 0xaf, 0xcc, 0xbb, - 0xbd, 0x1c, 0x0f, 0xe2, 0x83, 0x69, 0x9c, 0xb1, 0x15, 0xb4, 0xeb, 0xf5, - 0x43, 0xbe, 0xb6, 0x44, 0xe8, 0xa9, 0xc3, 0xe7, 0x4c, 0x81, 0x86, 0xe8, - 0x98, 0x03, 0x32, 0xec, 0xf1, 0x3c, 0x7a, 0x53, 0x7b, 0xc5, 0x75, 0x4a, - 0x12, 0xfa, 0x19, 0x5c, 0x9f, 0x3a, 0x5f, 0x84, 0xe3, 0xcb, 0x5c, 0x6a, - 0xc8, 0xbb, 0x90, 0x6f, 0xed, 0x4b, 0xcd, 0x32, 0x30, 0x89, 0x58, 0xab, - 0xec, 0x91, 0x4f, 0xa1, 0x6c, 0x86, 0x6b, 0xbf, 0x6a, 0x71, 0x3f, 0x13, - 0x3a, 0x7f, 0xf8, 0x4f, 0x0d, 0x19, 0x1d, 0x07, 0x76, 0x04, 0x32, 0xf7, - 0xf7, 0x86, 0x37, 0xa1, 0x6c, 0xb6, 0x9b, 0x73, 0x66, 0x2c, 0x48, 0xdd, - 0x09, 0xe5, 0x60, 0x9b, 0x73, 0xa7, 0xe6, 0x05, 0xdb, 0xb4, 0xcf, 0xad, - 0xcf, 0x72, 0xac, 0x71, 0x96, 0x1b, 0x9a, 0xe4, 0xf2, 0xdd, 0x8d, 0x81, - 0x1e, 0x52, 0xdf, 0xa0, 0xb7, 0xe0, 0xd7, 0xb3, 0x2b, 0xf4, 0xbb, 0xff, - 0x3c, 0x39, 0xd9, 0x76, 0x89, 0xcd, 0x7e, 0x0f, 0xbc, 0xbc, 0x06, 0xb1, - 0x8a, 0x88, 0x3d, 0x43, 0x1c, 0xa2, 0xbf, 0xb1, 0xec, 0xef, 0xce, 0xcb, - 0x5a, 0xbe, 0xee, 0xc5, 0x7c, 0x8d, 0x4f, 0x5e, 0xa2, 0xaf, 0x31, 0xdc, - 0x22, 0xad, 0xc4, 0xa2, 0x33, 0xf0, 0x6d, 0x2d, 0x69, 0x71, 0xbf, 0x01, - 0x1b, 0x76, 0xda, 0x5e, 0xe7, 0x86, 0x98, 0xd0, 0x2e, 0x9b, 0x66, 0xb7, - 0x68, 0x5c, 0x70, 0x66, 0x96, 0x71, 0x61, 0x1c, 0xbc, 0x1f, 0x09, 0xf2, - 0xbc, 0xc9, 0x4d, 0x72, 0xa9, 0xf1, 0xf5, 0xb2, 0xdf, 0x3f, 0xd6, 0xf0, - 0xfb, 0xaf, 0x6c, 0xe2, 0xe3, 0x5a, 0xb8, 0x78, 0x1a, 0x7c, 0xcb, 0x21, - 0xfe, 0x65, 0x5c, 0x3b, 0x8c, 0x78, 0x98, 0xb1, 0x58, 0x1e, 0x31, 0x71, - 0xe6, 0xb4, 0xc8, 0x6e, 0xc4, 0xc8, 0x99, 0x1f, 0x31, 0x7f, 0xf5, 0xbc, - 0x9f, 0x99, 0x13, 0xb9, 0x1d, 0x7c, 0x1d, 0x04, 0x6e, 0x66, 0x81, 0xa3, - 0x3b, 0xc1, 0xdf, 0x7e, 0x8d, 0x9d, 0xf7, 0x1f, 0x11, 0xeb, 0x0e, 0x9d, - 0xab, 0xa6, 0x3e, 0x27, 0x61, 0x47, 0xeb, 0xf5, 0xfd, 0xd9, 0x5e, 0xc4, - 0xf5, 0x69, 0xb9, 0xd5, 0x66, 0x1c, 0x6b, 0xd9, 0x5b, 0x07, 0xe6, 0x63, - 0x51, 0x9f, 0xb4, 0x70, 0x51, 0x3b, 0xb0, 0x9a, 0xf7, 0x45, 0x6d, 0x0b, - 0x0e, 0xc7, 0x2e, 0xc4, 0xfb, 0x3b, 0x1a, 0xbc, 0x6f, 0x69, 0x95, 0xd6, - 0xdb, 0x75, 0x1e, 0x61, 0xeb, 0xc0, 0x7e, 0xe2, 0x55, 0x16, 0x76, 0x1d, - 0xf6, 0xb7, 0x2e, 0xb7, 0x65, 0xdf, 0xae, 0xbf, 0xe8, 0x6e, 0x94, 0xd2, - 0xce, 0xfb, 0x0c, 0x66, 0x2f, 0x7d, 0xad, 0xe0, 0x56, 0xa0, 0x1f, 0x41, - 0xce, 0x70, 0xef, 0x74, 0x02, 0x96, 0x80, 0x7f, 0x9d, 0x32, 0x3f, 0xf4, - 0x16, 0xce, 0x70, 0xc7, 0x49, 0x26, 0x9c, 0x14, 0x70, 0x78, 0x3e, 0xd9, - 0xae, 0xf3, 0xc5, 0x9f, 0x70, 0x59, 0xef, 0xe0, 0x4c, 0x47, 0x65, 0x1e, - 0xfe, 0x43, 0x75, 0x08, 0x34, 0xee, 0xec, 0x42, 0x7f, 0xea, 0x1d, 0x79, - 0x3e, 0x0a, 0xdb, 0x4b, 0x9e, 0x26, 0xd1, 0x7f, 0x0f, 0xfa, 0x74, 0xe2, - 0x79, 0x5f, 0x6c, 0xde, 0x61, 0xec, 0xfc, 0x79, 0x94, 0x39, 0x47, 0xd4, - 0x76, 0x7e, 0x2e, 0x2e, 0x7a, 0x4e, 0x8e, 0xe9, 0xd2, 0xfa, 0xbf, 0xbc, - 0x16, 0xd7, 0x61, 0xdb, 0xcf, 0xea, 0xd7, 0x0f, 0x0c, 0x45, 0xd6, 0xeb, - 0x88, 0xac, 0x37, 0x14, 0x59, 0x8f, 0x74, 0x76, 0x46, 0xe8, 0xec, 0xc4, - 0xf8, 0x22, 0xd6, 0x26, 0x3f, 0xa2, 0x6b, 0x3e, 0x18, 0x59, 0x33, 0xdc, - 0x5f, 0x57, 0x64, 0xdc, 0xbb, 0x58, 0x8f, 0x75, 0xc9, 0x48, 0x1d, 0x69, - 0xd8, 0x8c, 0x3a, 0x96, 0x3b, 0x23, 0x74, 0x91, 0xd6, 0x0d, 0xa8, 0xd7, - 0xfe, 0x13, 0xf8, 0xdc, 0x0a, 0xbb, 0xa5, 0x60, 0x3b, 0x5a, 0xe0, 0x5f, - 0x35, 0xef, 0xf5, 0x51, 0xac, 0x1b, 0xce, 0x97, 0xc4, 0x1c, 0xec, 0xcf, - 0xbe, 0x31, 0x33, 0x9e, 0xf5, 0x6c, 0xff, 0xf3, 0xfa, 0x9f, 0x6a, 0xbe, - 0x6d, 0x06, 0xed, 0x3a, 0xef, 0x22, 0x73, 0x9d, 0x36, 0xce, 0x93, 0xf1, - 0xb1, 0x25, 0x57, 0xbb, 0xca, 0xea, 0x1d, 0xe0, 0xd9, 0x6f, 0x34, 0x58, - 0xda, 0x6a, 0x15, 0x8e, 0x30, 0x5f, 0xd0, 0x66, 0x62, 0x3e, 0xc4, 0x1e, - 0xda, 0xc6, 0xd8, 0xa6, 0x9d, 0x36, 0x86, 0x7e, 0x0b, 0xed, 0xe7, 0x69, - 0xf3, 0x8e, 0x27, 0x64, 0xf8, 0x81, 0x6a, 0xa7, 0xbc, 0xa8, 0x79, 0xea, - 0xc8, 0xd9, 0x06, 0x4f, 0xe3, 0xe6, 0xbb, 0xcc, 0x01, 0xf3, 0xcd, 0xa3, - 0x0f, 0x7e, 0x11, 0xde, 0x6b, 0x79, 0xd0, 0x90, 0x96, 0xde, 0x01, 0xc6, - 0x6e, 0x15, 0x3c, 0x99, 0xa7, 0xb0, 0xf0, 0x0c, 0xf2, 0x17, 0xbd, 0x03, - 0xb0, 0x4b, 0xc0, 0xa1, 0xde, 0x81, 0x73, 0x3a, 0x9e, 0xab, 0xfa, 0x8e, - 0x75, 0x9b, 0x17, 0xe4, 0x88, 0xce, 0xba, 0x17, 0xca, 0x11, 0xdd, 0xb3, - 0x8e, 0x79, 0x8d, 0x30, 0x47, 0x74, 0x56, 0x74, 0x8e, 0xe8, 0xf8, 0x45, - 0x72, 0x44, 0xf9, 0x4b, 0xcf, 0x11, 0x71, 0x7e, 0x5b, 0xee, 0x1c, 0x74, - 0xd4, 0xaf, 0x9a, 0x1c, 0xd1, 0x1b, 0x12, 0xe4, 0x88, 0x5e, 0x94, 0xb5, - 0x73, 0x44, 0x87, 0x9a, 0x72, 0x44, 0x9b, 0x75, 0x8e, 0x88, 0xf3, 0x04, - 0x39, 0x22, 0x96, 0x4b, 0x03, 0x43, 0x91, 0x5c, 0x07, 0xf0, 0xd7, 0xbb, - 0x01, 0x7c, 0x73, 0xac, 0x51, 0x2f, 0xc4, 0x34, 0x62, 0xff, 0x15, 0x0d, - 0xfb, 0xb5, 0x8c, 0x6f, 0x96, 0x96, 0xb9, 0x8b, 0xe1, 0xdb, 0x68, 0xe0, - 0x97, 0xac, 0xc0, 0xb6, 0xc9, 0x86, 0xef, 0xe2, 0xad, 0x63, 0x0c, 0x3d, - 0x51, 0x5b, 0x9e, 0x77, 0x02, 0xbc, 0x1e, 0x6b, 0xe4, 0x49, 0xce, 0xe7, - 0x1f, 0x25, 0xe5, 0xc0, 0x9a, 0xdf, 0xbd, 0x52, 0xf9, 0xd5, 0xdf, 0xbd, - 0x2c, 0x49, 0x82, 0xce, 0xd2, 0x40, 0x49, 0xc7, 0x5d, 0xf3, 0xde, 0xaf, - 0xc8, 0xd2, 0xdd, 0x0e, 0xf0, 0x27, 0xcc, 0x9f, 0xf0, 0x7c, 0x97, 0x6d, - 0x4a, 0x41, 0x7d, 0x7c, 0x39, 0x94, 0x07, 0x74, 0x0e, 0xe5, 0xc5, 0x75, - 0xd1, 0x1c, 0xca, 0x59, 0xb9, 0x70, 0x0e, 0xe5, 0x81, 0x35, 0x72, 0x28, - 0x2f, 0xcb, 0x72, 0x0e, 0xe5, 0x65, 0x09, 0x73, 0x28, 0x31, 0x59, 0xda, - 0x1c, 0x48, 0xe3, 0x03, 0xfe, 0x12, 0x7e, 0x67, 0xf0, 0x0b, 0x72, 0x2a, - 0x67, 0x1b, 0xf4, 0xaf, 0x95, 0x53, 0x79, 0x7d, 0xdd, 0x07, 0xc9, 0xa9, - 0x04, 0x36, 0x20, 0xcc, 0xa9, 0xe0, 0xe7, 0xc0, 0xe6, 0xa8, 0x68, 0x4e, - 0xe5, 0x27, 0xd4, 0x07, 0xd4, 0xb1, 0xcc, 0x7a, 0xe8, 0x05, 0xec, 0x52, - 0x5e, 0xe7, 0x38, 0x3e, 0x67, 0x78, 0x38, 0x87, 0x3d, 0xa7, 0x71, 0x16, - 0xe4, 0x63, 0xaf, 0xf6, 0x2d, 0xf3, 0x76, 0xca, 0x2a, 0xf4, 0xc1, 0x9a, - 0x4d, 0xf3, 0xbb, 0xb8, 0x6d, 0xed, 0xf5, 0x29, 0xe3, 0x09, 0xab, 0x8c, - 0xbd, 0x0c, 0x4f, 0xcf, 0xc9, 0x5e, 0x3f, 0xf4, 0xa9, 0x06, 0x1a, 0x73, - 0x50, 0x37, 0xe7, 0x81, 0xb3, 0xc0, 0x89, 0x4b, 0xb0, 0x51, 0xa7, 0x40, - 0x73, 0x74, 0x1f, 0x88, 0x89, 0x07, 0x51, 0xa7, 0xcf, 0x9c, 0xbe, 0x65, - 0x48, 0x4b, 0x9a, 0x7a, 0x7e, 0x09, 0xf3, 0xb1, 0xee, 0x94, 0x8e, 0xc7, - 0xca, 0x83, 0xdc, 0x2b, 0x6d, 0xdd, 0x22, 0xe8, 0x43, 0x5d, 0x95, 0x31, - 0x20, 0xed, 0x5e, 0x18, 0xa3, 0xb5, 0xeb, 0x18, 0xad, 0x4b, 0xf3, 0x83, - 0xbc, 0xbe, 0x35, 0x41, 0xac, 0xec, 0x72, 0xb9, 0x87, 0x33, 0x06, 0xeb, - 0x58, 0x0e, 0x62, 0xc1, 0xbc, 0xe2, 0xfb, 0xef, 0xe1, 0x5c, 0x99, 0xa7, - 0x09, 0xcf, 0xef, 0x2b, 0x66, 0xdf, 0x43, 0x52, 0xe9, 0x92, 0xc4, 0x66, - 0xd0, 0x53, 0x9a, 0xa1, 0xdf, 0xfd, 0x69, 0x1d, 0x83, 0x24, 0xdd, 0xf3, - 0xeb, 0xed, 0x1d, 0x97, 0xa1, 0xb7, 0x23, 0x17, 0xd4, 0xdb, 0xaf, 0x25, - 0xa2, 0x7a, 0x7b, 0xc7, 0x65, 0xe8, 0xed, 0xbe, 0xcb, 0xd2, 0x5b, 0xee, - 0x8d, 0x98, 0x14, 0xe6, 0xc4, 0x56, 0xfb, 0x59, 0xe1, 0xba, 0xe3, 0x58, - 0x33, 0x7f, 0x9e, 0x35, 0xc7, 0xce, 0x9b, 0x5b, 0x6d, 0xf6, 0xb1, 0x2e, - 0xe5, 0xbc, 0x19, 0x5b, 0xd1, 0xde, 0xb6, 0x1b, 0xbb, 0x74, 0x9f, 0x89, - 0xe7, 0xc3, 0xb8, 0x3e, 0xaa, 0x3f, 0x94, 0x0b, 0xca, 0xc2, 0x77, 0xc0, - 0x2f, 0xca, 0x43, 0xa8, 0x73, 0xdd, 0x4d, 0x32, 0xb8, 0x88, 0x78, 0xbf, - 0xdb, 0xc8, 0x20, 0xcf, 0xba, 0x4f, 0x7f, 0x67, 0xaa, 0x7a, 0x4f, 0x05, - 0x71, 0xbe, 0x8b, 0x67, 0x35, 0xd4, 0x35, 0xf0, 0x24, 0x19, 0xb6, 0x91, - 0x8f, 0x2e, 0x7c, 0x9e, 0x1d, 0xf0, 0xd7, 0xc0, 0x23, 0x5d, 0xbf, 0x32, - 0x27, 0x7c, 0x61, 0x3c, 0x93, 0x4a, 0x1c, 0x7d, 0x4f, 0x0c, 0x42, 0xc7, - 0x07, 0x89, 0x51, 0x35, 0xc4, 0x3d, 0x94, 0x43, 0xca, 0xe6, 0xb6, 0xfe, - 0x5d, 0x8a, 0x3e, 0xd5, 0x13, 0x88, 0x83, 0x29, 0xaf, 0x69, 0xd9, 0xe5, - 0x6f, 0x3b, 0x7d, 0x56, 0x71, 0x8d, 0x7a, 0xbd, 0xc4, 0x58, 0xd1, 0x11, - 0xb5, 0x75, 0xe0, 0xbf, 0x13, 0xb4, 0x4b, 0x57, 0xb8, 0x31, 0x23, 0x6b, - 0x79, 0xbc, 0x53, 0x6e, 0x7f, 0x08, 0x7b, 0xcf, 0xef, 0xfd, 0xaf, 0xa1, - 0x3e, 0x05, 0x9d, 0xa7, 0x7d, 0x67, 0x3c, 0x72, 0x93, 0xe9, 0xd7, 0xad, - 0xbf, 0x57, 0x16, 0xb2, 0x37, 0x98, 0x6f, 0x57, 0xb4, 0x3f, 0x19, 0xda, - 0xec, 0x15, 0xe7, 0xcc, 0xfb, 0x12, 0x45, 0x1d, 0xcf, 0x70, 0xbc, 0x96, - 0x49, 0xc4, 0x20, 0x76, 0x24, 0x97, 0x9e, 0x30, 0xb1, 0x1b, 0x75, 0xac, - 0x1d, 0x67, 0xe8, 0x9b, 0x58, 0x85, 0xf1, 0xeb, 0xca, 0x7b, 0x12, 0x6b, - 0xcb, 0xc0, 0x96, 0x0f, 0x20, 0x03, 0xcd, 0xe7, 0x97, 0x80, 0xee, 0x87, - 0xe7, 0x17, 0xfa, 0x31, 0x73, 0x66, 0xdf, 0xdd, 0xc1, 0x19, 0xfe, 0xbf, - 0xd8, 0xa7, 0x15, 0xd9, 0x67, 0x88, 0x47, 0x0f, 0x98, 0x7d, 0xde, 0xd4, - 0x84, 0x47, 0x23, 0x4d, 0x3a, 0xfb, 0x71, 0xe2, 0xd1, 0x9f, 0xac, 0xff, - 0xf8, 0xf1, 0x88, 0xfb, 0xea, 0x5e, 0x13, 0x87, 0x82, 0x7d, 0x3c, 0x22, - 0x2a, 0xf7, 0x51, 0xc6, 0x7b, 0x1f, 0xe4, 0x7c, 0xa2, 0x38, 0xc2, 0x33, - 0xe9, 0xd0, 0x3e, 0x6c, 0xa0, 0x7b, 0xb0, 0xe5, 0xd5, 0xb8, 0xbc, 0x7e, - 0x57, 0x42, 0xfe, 0xf7, 0x46, 0x7e, 0x0f, 0xb3, 0x4d, 0x4e, 0x8b, 0xe5, - 0xd7, 0xd6, 0x07, 0x76, 0xe8, 0xb5, 0x4d, 0x81, 0xdd, 0xe1, 0x98, 0x50, - 0x9f, 0x1d, 0xb4, 0xb3, 0xad, 0x5b, 0x96, 0x3a, 0x2f, 0x27, 0x06, 0xdc, - 0xe6, 0xbc, 0xa1, 0xd6, 0x8a, 0x01, 0x2f, 0x9c, 0x0f, 0x5c, 0x8e, 0x01, - 0x89, 0xb3, 0x9d, 0x5a, 0x36, 0x4a, 0x49, 0xc6, 0x3e, 0x7d, 0x06, 0x3b, - 0xf9, 0x8e, 0xd8, 0xd6, 0x43, 0xbc, 0xeb, 0x21, 0xd6, 0xf5, 0x10, 0xff, - 0x7a, 0x88, 0x71, 0x3d, 0xc4, 0xb6, 0x1e, 0x62, 0x5b, 0x0f, 0xb1, 0xad, - 0xd7, 0x6f, 0x62, 0xe4, 0x11, 0x93, 0xf7, 0xe7, 0x77, 0x72, 0xe6, 0x17, - 0x2a, 0xb0, 0x25, 0x93, 0xbc, 0xe7, 0xa0, 0x0a, 0xd9, 0xf5, 0x66, 0x7f, - 0x61, 0x4e, 0xbc, 0xc7, 0xe4, 0x6c, 0x5e, 0xd7, 0x79, 0x43, 0x51, 0xb3, - 0xad, 0xc1, 0xb7, 0x74, 0xde, 0xc7, 0xf8, 0x2d, 0xf8, 0x25, 0xfa, 0x3e, - 0x13, 0x75, 0xb4, 0xae, 0x72, 0xcc, 0xc9, 0x88, 0x52, 0xb9, 0xeb, 0x31, - 0x66, 0x47, 0x10, 0x13, 0x24, 0x25, 0xa6, 0x72, 0x6d, 0xe4, 0xa9, 0xa5, - 0x72, 0x1b, 0xcc, 0x5c, 0x47, 0x5b, 0x03, 0xdf, 0xaa, 0x8f, 0x65, 0x5b, - 0xe5, 0x6e, 0xe6, 0x13, 0xe7, 0x1e, 0xd6, 0xf7, 0x74, 0xae, 0x5c, 0x6b, - 0x4a, 0xe3, 0x7b, 0x21, 0x7b, 0x37, 0xe6, 0xd3, 0xf7, 0x88, 0x1a, 0xfc, - 0x56, 0xe7, 0xe5, 0xf7, 0x94, 0xe1, 0x77, 0xc0, 0xe3, 0x18, 0xfb, 0xe9, - 0xbc, 0x30, 0x79, 0x1d, 0xce, 0xa7, 0xf3, 0x7a, 0x58, 0x47, 0xdf, 0xa5, - 0xc0, 0x53, 0xc5, 0xa5, 0x63, 0xf4, 0x9e, 0xb8, 0x1b, 0x5d, 0x37, 0xfc, - 0x26, 0x7e, 0x29, 0x6b, 0x76, 0xeb, 0xef, 0x68, 0x81, 0xcd, 0x98, 0xd2, - 0x32, 0x68, 0xe7, 0xb8, 0xaf, 0xf7, 0x21, 0x7f, 0x53, 0x5a, 0xfe, 0x8a, - 0x88, 0x63, 0x26, 0x07, 0xb7, 0xa5, 0x6d, 0x75, 0xa0, 0x95, 0xf9, 0xd7, - 0x61, 0x3f, 0xc4, 0x3d, 0xae, 0xd7, 0x6c, 0xc7, 0x99, 0x57, 0x0b, 0xf1, - 0x4c, 0xb6, 0x04, 0xf9, 0xb6, 0x0f, 0xa3, 0x4b, 0xad, 0x4d, 0xba, 0x14, - 0xee, 0x93, 0xfb, 0xe7, 0x73, 0xed, 0x3b, 0x15, 0x8b, 0x7e, 0xe4, 0xfb, - 0x48, 0x43, 0x36, 0x78, 0xb7, 0xe4, 0x8b, 0x90, 0x41, 0xfd, 0x9d, 0x02, - 0x7a, 0x54, 0xaf, 0x0f, 0x33, 0xc7, 0xbc, 0xf3, 0x0b, 0xe6, 0xde, 0x82, - 0x3c, 0xcc, 0xfc, 0x83, 0xbd, 0x2a, 0xff, 0x30, 0x0c, 0x59, 0x81, 0x0f, - 0xe0, 0x75, 0x68, 0x9f, 0x4e, 0xb9, 0xf4, 0x07, 0x9a, 0xbf, 0xbf, 0x3c, - 0xda, 0x16, 0xf0, 0xe1, 0xed, 0xd6, 0xe0, 0x1b, 0xc4, 0xdf, 0x26, 0x57, - 0x96, 0x39, 0xfe, 0x7f, 0x8c, 0xac, 0x1c, 0x86, 0x6d, 0x1e, 0x86, 0x2c, - 0x22, 0x26, 0xd7, 0xf3, 0x1d, 0x96, 0xd2, 0xd3, 0x0b, 0x9d, 0x2b, 0xfb, - 0xa3, 0xee, 0x58, 0xd8, 0xff, 0xb1, 0xa6, 0xfe, 0x8f, 0xa1, 0xff, 0x0b, - 0x4d, 0xfd, 0x1f, 0x8b, 0xf4, 0x3f, 0xda, 0xd4, 0x1f, 0x31, 0xe2, 0xd3, - 0xff, 0xdc, 0xd4, 0xff, 0x68, 0xa4, 0xff, 0x6c, 0x53, 0xff, 0x59, 0xf4, - 0x7f, 0xad, 0xa9, 0x3f, 0xea, 0x8e, 0xb5, 0x98, 0xef, 0x62, 0xc4, 0xd8, - 0x7d, 0x26, 0x16, 0xc7, 0xb3, 0xd6, 0xfc, 0xad, 0x85, 0x72, 0xd7, 0x83, - 0x33, 0x08, 0xef, 0xb4, 0x51, 0x5f, 0xf3, 0xd0, 0xd7, 0x65, 0x5f, 0x26, - 0x90, 0xc7, 0xa8, 0x2c, 0x12, 0x1f, 0x2a, 0x12, 0x73, 0x7d, 0xfa, 0x47, - 0x56, 0xb9, 0x1a, 0xda, 0x24, 0xde, 0x5b, 0xe2, 0x7d, 0xd7, 0xc0, 0xf6, - 0xc6, 0xdd, 0x45, 0x13, 0x83, 0x5d, 0xd1, 0x06, 0xda, 0x81, 0x97, 0x21, - 0x66, 0xca, 0xe1, 0x40, 0x6f, 0x28, 0xbf, 0x9c, 0xdf, 0xe8, 0x0f, 0x65, - 0xd5, 0xac, 0x33, 0xbc, 0x0a, 0xd7, 0xd2, 0xab, 0x72, 0x5b, 0xb1, 0x4b, - 0xc0, 0xb5, 0x91, 0x06, 0xae, 0x7d, 0x51, 0xe6, 0x1a, 0xf1, 0xf6, 0x19, - 0xd9, 0xef, 0xed, 0xe1, 0x3d, 0x9d, 0xc3, 0x79, 0xf9, 0x68, 0xe2, 0xed, - 0x3d, 0x0d, 0x3b, 0xc9, 0x3b, 0x1d, 0xe9, 0x83, 0xbc, 0x83, 0x1b, 0xe6, - 0x66, 0x27, 0xbd, 0x5f, 0xc7, 0xfe, 0x69, 0x33, 0x2f, 0x37, 0xde, 0xe6, - 0x7c, 0x49, 0xd9, 0x1f, 0xdc, 0x77, 0x68, 0xcc, 0x5b, 0x69, 0xcc, 0x9b, - 0x32, 0xfa, 0x46, 0x1b, 0xbc, 0x6c, 0x2f, 0x8b, 0xb0, 0x97, 0x63, 0x88, - 0xb9, 0x17, 0xbd, 0xb5, 0xf2, 0xa3, 0x97, 0x6b, 0x2f, 0x9b, 0xf3, 0xcc, - 0xcd, 0xf6, 0x92, 0xeb, 0x34, 0xe7, 0x96, 0xd3, 0x4d, 0xf8, 0x4f, 0x79, - 0x3a, 0x67, 0x7c, 0x6a, 0x3c, 0xab, 0xe7, 0xa0, 0x8f, 0x4a, 0xc6, 0xb4, - 0xfc, 0xb2, 0x1c, 0xc6, 0x96, 0xf7, 0x34, 0x62, 0xcb, 0xe5, 0x78, 0x10, - 0xbe, 0x6b, 0xff, 0x67, 0x0c, 0x3e, 0xd2, 0x47, 0x76, 0xac, 0xb2, 0xb7, - 0x5b, 0xed, 0xd5, 0x6d, 0xcc, 0x97, 0x5e, 0x2b, 0xb7, 0xea, 0x38, 0xfe, - 0x8c, 0xc9, 0x4d, 0xcd, 0x69, 0xff, 0x9f, 0xdf, 0x0b, 0xca, 0xd9, 0x4d, - 0xc6, 0xdf, 0xbb, 0x18, 0xae, 0xae, 0x8c, 0x4d, 0x95, 0x3a, 0x88, 0xb1, - 0x8c, 0x4d, 0xfb, 0xdb, 0x89, 0xa1, 0x05, 0xff, 0x82, 0xe3, 0x31, 0x8e, - 0xe3, 0xd9, 0x47, 0xc7, 0xa1, 0xe8, 0xb7, 0x68, 0xc6, 0x07, 0x71, 0x68, - 0xc1, 0xff, 0x71, 0x5b, 0x80, 0x83, 0x17, 0x8a, 0x59, 0x3e, 0xdf, 0xce, - 0xbc, 0xde, 0xa2, 0x77, 0x31, 0x5a, 0x57, 0xc7, 0xbd, 0xb1, 0x55, 0x71, - 0xaf, 0x6d, 0xe2, 0xda, 0x5f, 0xd2, 0x71, 0x6f, 0xc0, 0x63, 0xee, 0x25, - 0x1a, 0x47, 0xb9, 0xc0, 0x42, 0x7e, 0x53, 0x21, 0x3e, 0xd0, 0x47, 0x81, - 0x9f, 0x35, 0xfd, 0x8b, 0xe0, 0x73, 0x72, 0x0d, 0xb9, 0xf9, 0xb8, 0xed, - 0x44, 0xb8, 0xf7, 0x73, 0x12, 0xe4, 0xeb, 0x76, 0x83, 0x16, 0xc6, 0x56, - 0x71, 0x23, 0x0f, 0x3f, 0x35, 0xf7, 0x2a, 0xc3, 0x7e, 0x61, 0x1c, 0xdf, - 0xf8, 0xee, 0x5a, 0xc9, 0xaf, 0xc8, 0x9f, 0x74, 0x33, 0x0d, 0x8d, 0x73, - 0xcf, 0x5f, 0xc6, 0x77, 0x8b, 0x0f, 0x73, 0x3f, 0xa2, 0xd9, 0xae, 0xf1, - 0xbb, 0x29, 0xbf, 0x95, 0x8a, 0x75, 0x67, 0x9f, 0x0b, 0x1d, 0xe0, 0xbd, - 0xe1, 0x28, 0xbe, 0x26, 0xa4, 0x34, 0x2b, 0x89, 0x64, 0x8e, 0xdf, 0x00, - 0x68, 0xff, 0x7f, 0x68, 0xf6, 0x99, 0x92, 0x7d, 0x33, 0x41, 0xce, 0x53, - 0x5d, 0xf0, 0x5e, 0xdc, 0xe3, 0xe0, 0x43, 0xe6, 0x50, 0x98, 0xf3, 0x54, - 0xc1, 0xbd, 0xb8, 0x43, 0x1f, 0xdd, 0xbd, 0x38, 0xce, 0x6f, 0xcb, 0x9e, - 0x35, 0xee, 0xc5, 0xc5, 0x2e, 0xf1, 0x5e, 0xdc, 0x26, 0x9d, 0xf3, 0xe4, - 0x3c, 0x41, 0xce, 0x93, 0xe5, 0xad, 0x03, 0xcc, 0x95, 0xf0, 0xee, 0xdb, - 0xa0, 0xbe, 0x2f, 0xbc, 0x75, 0xe0, 0xe7, 0x11, 0xa3, 0xfc, 0x75, 0xfb, - 0xc7, 0x1f, 0xa3, 0x70, 0x2f, 0xbf, 0x11, 0x7c, 0xdf, 0x95, 0xcb, 0xc9, - 0x03, 0x7c, 0xb8, 0xbc, 0xe6, 0x3e, 0x9d, 0xd7, 0x7c, 0xa7, 0x3d, 0x9a, - 0xd7, 0x54, 0x17, 0xb9, 0x1b, 0xb6, 0x6f, 0x8d, 0xbc, 0x66, 0x3c, 0x72, - 0x37, 0x2c, 0x6e, 0xee, 0x86, 0x6d, 0x72, 0x11, 0x4b, 0x9a, 0x3c, 0xa6, - 0xba, 0xe0, 0xdd, 0xb0, 0xce, 0x0d, 0x1f, 0x3e, 0x8f, 0xb9, 0xea, 0x6e, - 0x18, 0x6c, 0xdd, 0x16, 0x49, 0x5f, 0x56, 0xdc, 0xf3, 0x61, 0x62, 0x1e, - 0xde, 0xab, 0x6f, 0xc1, 0x9e, 0xe3, 0xb2, 0x27, 0x49, 0xf9, 0xe4, 0xdd, - 0xc6, 0x3e, 0xe8, 0x02, 0x9e, 0x3e, 0xcb, 0xfd, 0x3c, 0x23, 0x6b, 0xa4, - 0x6f, 0xe5, 0x3d, 0x84, 0xe5, 0x3b, 0xbd, 0x89, 0xc6, 0x9d, 0xde, 0x29, - 0xc8, 0x8d, 0x9a, 0x49, 0xc8, 0x7c, 0x44, 0xa6, 0x26, 0x3d, 0xf8, 0x4b, - 0xb3, 0x8e, 0x69, 0xe7, 0xff, 0xef, 0x48, 0x02, 0xf3, 0x78, 0x0f, 0xb8, - 0x43, 0x62, 0xb3, 0xc1, 0x37, 0xcb, 0xe0, 0xff, 0xb8, 0xa4, 0xd0, 0x87, - 0x77, 0x3c, 0xe3, 0xb2, 0x5f, 0xe7, 0x2c, 0x42, 0x59, 0xfe, 0x35, 0xf0, - 0x78, 0x73, 0x7e, 0xb9, 0x9c, 0x5c, 0xc3, 0xee, 0x27, 0xa5, 0x3c, 0x43, - 0x79, 0xbe, 0xc1, 0xfc, 0xff, 0x82, 0xd3, 0x52, 0xf6, 0x4f, 0x99, 0xf8, - 0x42, 0x7f, 0xdb, 0x01, 0x2f, 0xb7, 0x18, 0x1b, 0x8c, 0x67, 0x75, 0x0b, - 0x6d, 0x1e, 0xd6, 0x38, 0x2e, 0xc3, 0xd3, 0x3b, 0x52, 0x7b, 0x81, 0x77, - 0x63, 0x7a, 0xcd, 0xcb, 0xe1, 0xb9, 0x75, 0x9e, 0xef, 0x8d, 0x97, 0xca, - 0xf7, 0xd0, 0x3f, 0xae, 0x62, 0x7f, 0x5b, 0x20, 0x1f, 0x5f, 0x95, 0xe2, - 0xb1, 0x6b, 0x65, 0xf8, 0x68, 0x06, 0xf4, 0xbc, 0x5f, 0x2f, 0x67, 0xe1, - 0x4b, 0x3f, 0xcd, 0x7b, 0x63, 0xc0, 0x50, 0xf0, 0xed, 0xf9, 0x55, 0xdf, - 0xb1, 0xa3, 0x77, 0xcd, 0xfa, 0x1b, 0x77, 0x87, 0x9e, 0xf5, 0x25, 0xd1, - 0x49, 0x9a, 0x67, 0x96, 0xef, 0x8f, 0x2f, 0xfa, 0xbb, 0xb4, 0x6d, 0x7b, - 0xc6, 0x5f, 0x91, 0xfb, 0xd1, 0x67, 0x38, 0x5e, 0xfb, 0x1e, 0xec, 0xdb, - 0x39, 0x8b, 0xf6, 0x6d, 0xca, 0x93, 0xab, 0x63, 0xc2, 0xf3, 0x10, 0x0b, - 0x3c, 0xd0, 0x77, 0x38, 0x82, 0xef, 0xfb, 0x3d, 0xfa, 0x5c, 0x03, 0xac, - 0x58, 0x88, 0xdc, 0xc1, 0x58, 0x3e, 0xdb, 0xe0, 0x6e, 0x46, 0x70, 0x16, - 0xc1, 0xfd, 0x11, 0xed, 0x6f, 0x1e, 0xdc, 0xe3, 0x06, 0xf7, 0x47, 0x7a, - 0x67, 0x59, 0xd7, 0xd5, 0x64, 0xfb, 0x12, 0x90, 0x01, 0xde, 0x3b, 0xe2, - 0xbd, 0x71, 0xd2, 0xac, 0x73, 0x1d, 0xff, 0x47, 0xdd, 0xd5, 0xc7, 0xb6, - 0x75, 0x5d, 0xf7, 0xc3, 0x47, 0xea, 0xc3, 0xb4, 0x2c, 0x53, 0x32, 0x25, - 0xd3, 0x96, 0x2c, 0xbf, 0x27, 0x3d, 0x59, 0x72, 0xac, 0x14, 0xac, 0xab, - 0xad, 0x02, 0x46, 0xa4, 0x0c, 0x49, 0x7f, 0xb4, 0x08, 0x06, 0xfa, 0xa3, - 0x99, 0x8b, 0x66, 0xab, 0x4b, 0xd9, 0x4e, 0x0a, 0xf4, 0x0f, 0xb7, 0xc5, - 0x80, 0x6c, 0x58, 0x60, 0x86, 0xb4, 0x12, 0x63, 0x56, 0x4c, 0xd6, 0x66, - 0x85, 0x0c, 0xd8, 0x30, 0x4e, 0x54, 0x9c, 0x14, 0x50, 0xc6, 0x04, 0x69, - 0x83, 0xa2, 0x58, 0x61, 0x45, 0x76, 0x36, 0x6c, 0x7f, 0x65, 0x43, 0xd0, - 0x05, 0x9b, 0xb3, 0x38, 0x76, 0xb0, 0x06, 0x45, 0xd6, 0x7d, 0x62, 0x18, - 0xd0, 0x0d, 0xdc, 0xf9, 0xdd, 0x0f, 0xf2, 0xf1, 0xf1, 0x51, 0x1f, 0x89, - 0x33, 0x60, 0x02, 0x04, 0xbe, 0xf7, 0x78, 0xdf, 0x7b, 0xf7, 0x9e, 0x7b, - 0xce, 0xb9, 0xbf, 0x73, 0xee, 0x39, 0x87, 0x9e, 0x7b, 0xdb, 0x9b, 0xf3, - 0xb9, 0xca, 0x77, 0x8e, 0x8a, 0x77, 0x0e, 0x28, 0x9d, 0xa5, 0xe3, 0xc5, - 0x63, 0xc6, 0x6c, 0x61, 0x22, 0xe2, 0x67, 0xfe, 0x9e, 0xad, 0xc2, 0xbe, - 0x6e, 0x87, 0xe1, 0xd6, 0xa2, 0x67, 0xbc, 0x85, 0x9e, 0xcd, 0x32, 0xc1, - 0xf6, 0x78, 0x5d, 0x77, 0x4b, 0xda, 0xc9, 0xeb, 0x88, 0x85, 0xd7, 0x31, - 0x0e, 0x92, 0x76, 0x75, 0x19, 0xba, 0xe2, 0x8c, 0x6f, 0x68, 0xd0, 0xee, - 0x74, 0x9d, 0x76, 0x3b, 0xff, 0x1f, 0xd1, 0xee, 0x1d, 0x81, 0x7f, 0x5f, - 0xad, 0x22, 0x6e, 0x4d, 0x63, 0x00, 0x9d, 0x3b, 0x04, 0x3a, 0x42, 0x9f, - 0x5a, 0xe5, 0x15, 0x82, 0x4e, 0x45, 0x5c, 0x71, 0xad, 0xf6, 0x5a, 0xb4, - 0xee, 0xa7, 0x64, 0xbb, 0x04, 0xf6, 0x09, 0xfc, 0x79, 0xed, 0xd7, 0xc8, - 0x63, 0x1f, 0x6b, 0x8d, 0x04, 0x56, 0x72, 0xdb, 0x27, 0x0c, 0x08, 0x1d, - 0xf6, 0xc9, 0xb1, 0x4d, 0xda, 0x27, 0xe7, 0xa5, 0x7d, 0x92, 0xdd, 0xb8, - 0x7d, 0xb2, 0xbb, 0x25, 0xae, 0xab, 0x31, 0x9e, 0xcd, 0xdb, 0x27, 0xc6, - 0x9a, 0xf6, 0xc9, 0x90, 0xc3, 0x17, 0x83, 0xfe, 0xfe, 0x06, 0x65, 0x8f, - 0x43, 0xc7, 0x69, 0x3a, 0x83, 0xc6, 0xc7, 0x5d, 0x7e, 0xe1, 0x4f, 0x93, - 0xd6, 0xbf, 0xf8, 0x3f, 0xa6, 0xf5, 0x50, 0x8b, 0xcf, 0xbb, 0x31, 0x1e, - 0x0a, 0xef, 0xd8, 0x14, 0x8e, 0x77, 0xd3, 0x7a, 0xa8, 0xad, 0xef, 0xb4, - 0x7d, 0xcc, 0x62, 0xb3, 0xef, 0x74, 0xd4, 0x68, 0xa7, 0xdb, 0xff, 0xd8, - 0xe1, 0x53, 0x75, 0xea, 0x77, 0xc8, 0x14, 0xf9, 0x8e, 0x4d, 0xe8, 0x77, - 0x41, 0x96, 0xac, 0x6c, 0x96, 0x60, 0x33, 0xe1, 0x7d, 0x11, 0x21, 0x6b, - 0x2e, 0xbc, 0xc5, 0xef, 0x63, 0x7a, 0xbe, 0xf8, 0x87, 0x62, 0x9d, 0x92, - 0xfe, 0x07, 0xb4, 0x0f, 0xfb, 0xce, 0x88, 0xb6, 0x32, 0xbe, 0x49, 0xf9, - 0x23, 0x14, 0xf6, 0x6f, 0xe7, 0x87, 0x68, 0x5d, 0xf3, 0x36, 0x67, 0x2b, - 0x68, 0x19, 0xdf, 0xcb, 0xf3, 0x12, 0x69, 0xb2, 0xb5, 0xa0, 0x3f, 0xcf, - 0x33, 0x2e, 0x18, 0xad, 0x63, 0x82, 0xe6, 0xb9, 0xb9, 0x28, 0x6c, 0x3a, - 0xad, 0x3b, 0x57, 0x64, 0xec, 0xa9, 0xb8, 0x0e, 0x9c, 0xa6, 0x75, 0xa7, - 0x1b, 0x07, 0xef, 0xf5, 0xe0, 0x0b, 0xcf, 0xdc, 0x4f, 0x3d, 0x77, 0x26, - 0x62, 0xce, 0x53, 0x9e, 0x73, 0x57, 0xcf, 0xe1, 0xca, 0x36, 0xda, 0xca, - 0xfb, 0x53, 0x62, 0x5c, 0xdf, 0xfc, 0x62, 0x02, 0xb9, 0x6a, 0xf5, 0xfc, - 0x21, 0x77, 0xce, 0x14, 0xd6, 0x01, 0x2d, 0x87, 0x3a, 0x3f, 0x1b, 0xb4, - 0x18, 0xf1, 0xc8, 0x99, 0x72, 0xae, 0x25, 0xb8, 0xcf, 0x4d, 0x8b, 0xc6, - 0x3a, 0x32, 0xa7, 0xd6, 0x91, 0x45, 0x87, 0x1e, 0x6f, 0xc5, 0xed, 0xfd, - 0x1e, 0xb8, 0xdd, 0x2b, 0x6f, 0x0a, 0x7d, 0x7a, 0x92, 0x71, 0xc8, 0x67, - 0x80, 0x43, 0x42, 0xc8, 0x5b, 0x92, 0x58, 0x04, 0xdf, 0x17, 0x19, 0x8f, - 0x44, 0x98, 0x57, 0x7e, 0x44, 0xe7, 0x18, 0x6b, 0x5f, 0xa7, 0xfd, 0xca, - 0x3e, 0x83, 0xdc, 0xea, 0x38, 0x53, 0xc4, 0xf1, 0xfb, 0x28, 0xfb, 0x98, - 0x35, 0x19, 0xa7, 0x1f, 0xd1, 0x59, 0x11, 0x33, 0x83, 0xfd, 0x3d, 0xc4, - 0x1c, 0x3c, 0x20, 0xde, 0x2f, 0x7d, 0x19, 0xf7, 0x23, 0xa6, 0x6e, 0xe3, - 0xf1, 0xfb, 0x2a, 0xb7, 0x8e, 0xdb, 0xe1, 0x9d, 0x4b, 0x4a, 0xa6, 0xc4, - 0x35, 0xbe, 0xff, 0x49, 0xa3, 0xf5, 0xfe, 0xb8, 0x91, 0xaa, 0xa6, 0x8c, - 0x44, 0x05, 0xed, 0x9e, 0x34, 0x92, 0x55, 0xd8, 0x90, 0x9a, 0x47, 0xac, - 0x28, 0xe4, 0x6d, 0x95, 0xd6, 0xdf, 0x8b, 0x58, 0x24, 0x57, 0x9e, 0xc4, - 0x06, 0xfa, 0x7d, 0xb8, 0xa9, 0xdf, 0x9a, 0xbe, 0x38, 0x86, 0xbf, 0xe7, - 0x15, 0xa6, 0xa9, 0xc6, 0xb5, 0x41, 0xf8, 0xd7, 0x27, 0xb3, 0xb4, 0x16, - 0xae, 0xb5, 0x5a, 0x70, 0xed, 0xe2, 0xba, 0xfd, 0xfe, 0xa4, 0x32, 0x2e, - 0xf3, 0xa3, 0xfd, 0xb6, 0xc0, 0xaf, 0xdc, 0xef, 0x26, 0x6c, 0xeb, 0xe2, - 0x29, 0xb4, 0xd1, 0x7e, 0x70, 0xed, 0x07, 0xeb, 0x55, 0xf1, 0xc0, 0x3a, - 0x3e, 0x21, 0x88, 0x7c, 0xaf, 0x90, 0x8c, 0x6b, 0x85, 0x8d, 0xb5, 0xc2, - 0xfd, 0x83, 0xbd, 0x05, 0x9f, 0x8f, 0xb0, 0xb7, 0xcc, 0x24, 0x49, 0x5f, - 0xf7, 0x99, 0xaa, 0xd3, 0xbf, 0xeb, 0x95, 0x4b, 0x39, 0xea, 0x91, 0x4b, - 0xe9, 0x94, 0xb5, 0x80, 0x43, 0xd6, 0x22, 0x0e, 0xdc, 0x36, 0xcc, 0x76, - 0x4b, 0x0f, 0xeb, 0x90, 0x1e, 0xb1, 0x6d, 0xe2, 0xbf, 0xea, 0xb4, 0x5b, - 0xdc, 0x79, 0xf1, 0x90, 0x3b, 0x60, 0x33, 0x69, 0xc3, 0xa4, 0x4a, 0xf5, - 0x9c, 0x7a, 0x1e, 0x77, 0x23, 0x6f, 0xb1, 0xd2, 0x92, 0x63, 0xe9, 0xd5, - 0xdf, 0x91, 0x96, 0xfe, 0x62, 0xfd, 0x8a, 0xb7, 0xc5, 0x74, 0x5e, 0x76, - 0xd5, 0xfd, 0xea, 0x9f, 0x5b, 0x9f, 0xe1, 0x5d, 0xa3, 0xc2, 0xe7, 0x9d, - 0xad, 0xeb, 0xb2, 0x19, 0xd9, 0xdf, 0x42, 0xb3, 0x9d, 0xe1, 0xbf, 0x42, - 0x8a, 0x76, 0xde, 0xba, 0x7d, 0x73, 0xfe, 0xb3, 0xad, 0x6e, 0x1c, 0xdc, - 0x27, 0xfd, 0x62, 0x73, 0x2a, 0x0e, 0x7b, 0x40, 0xd9, 0x7b, 0xeb, 0xf1, - 0x3b, 0xae, 0xcd, 0x29, 0x5f, 0xa2, 0x65, 0x96, 0x09, 0x7c, 0x7e, 0xfc, - 0x54, 0x87, 0x1d, 0x52, 0x7b, 0x59, 0xd8, 0xaf, 0x02, 0xdf, 0xeb, 0xe7, - 0x43, 0x67, 0x6f, 0x64, 0xce, 0xcc, 0x96, 0x39, 0x93, 0x7c, 0x05, 0x5b, - 0x0b, 0xf1, 0xc5, 0x53, 0xae, 0x18, 0xef, 0x4f, 0x42, 0x8b, 0x5e, 0x8f, - 0xb8, 0x67, 0xc4, 0x2d, 0xb7, 0xeb, 0xe7, 0x1d, 0x07, 0x2e, 0x47, 0x7f, - 0x6b, 0xb5, 0x57, 0xa2, 0xbb, 0xe5, 0x5a, 0x5c, 0xf5, 0xc6, 0x48, 0xa1, - 0x0d, 0xf7, 0xcf, 0xbd, 0xf6, 0xee, 0xda, 0xe0, 0xda, 0x2b, 0xea, 0x8b, - 0xf8, 0x0e, 0x09, 0x1d, 0xd0, 0x43, 0x95, 0x12, 0xe2, 0xaf, 0x3f, 0x0b, - 0x99, 0x67, 0x3d, 0xeb, 0xc8, 0x49, 0xf3, 0x9e, 0xc7, 0xfa, 0x9e, 0x4a, - 0x20, 0x86, 0xbd, 0x3f, 0xc4, 0x96, 0xf4, 0xb3, 0xee, 0x41, 0xfb, 0x71, - 0xf3, 0x16, 0xfc, 0xbd, 0xca, 0xff, 0x94, 0x52, 0xeb, 0xcb, 0xa1, 0x0d, - 0xec, 0xad, 0x6c, 0x4e, 0x4f, 0x5b, 0xe6, 0x0a, 0x61, 0xdf, 0x07, 0xf1, - 0xc2, 0xc7, 0x7a, 0xa9, 0xf7, 0x2b, 0x5d, 0x5d, 0xf6, 0x1f, 0xf4, 0xc9, - 0xbd, 0x28, 0x7c, 0xd7, 0x43, 0x2f, 0x94, 0x10, 0xcb, 0x8d, 0xef, 0x7e, - 0x8b, 0xbf, 0xf3, 0xd2, 0x51, 0x3a, 0x16, 0x1d, 0x58, 0x4e, 0xce, 0x4f, - 0x99, 0x60, 0x2b, 0xd5, 0xe8, 0x6f, 0xa2, 0x9f, 0x93, 0xfb, 0x19, 0xd5, - 0xfb, 0xbd, 0x57, 0xe3, 0xe5, 0x2f, 0xfc, 0x69, 0xdf, 0xc7, 0x8d, 0x8d, - 0xfc, 0xd6, 0x86, 0xfc, 0x85, 0xd8, 0xe7, 0xdf, 0xc8, 0x9e, 0x89, 0xde, - 0x1b, 0x9e, 0x16, 0x39, 0xa7, 0x4e, 0x3e, 0xb8, 0x3f, 0xfb, 0xc3, 0xe0, - 0x87, 0x91, 0x16, 0x5d, 0xf5, 0xc9, 0xfd, 0xfd, 0x6e, 0xba, 0x06, 0x3d, - 0x7d, 0x55, 0xde, 0xfb, 0xc0, 0xd8, 0xf3, 0x87, 0x9f, 0xba, 0x4a, 0x67, - 0xae, 0x81, 0x87, 0x0d, 0xe6, 0xb6, 0x31, 0xca, 0x87, 0x91, 0x57, 0x24, - 0x72, 0x73, 0xf4, 0xbe, 0xa1, 0xc8, 0x15, 0x3a, 0x23, 0x72, 0x20, 0xc7, - 0x23, 0xf7, 0x78, 0x3d, 0x3c, 0x53, 0x7d, 0x9b, 0xce, 0x56, 0x82, 0xfc, - 0xdf, 0xc0, 0xee, 0xad, 0x79, 0x90, 0xcd, 0x3c, 0x7e, 0x4f, 0xf0, 0xf8, - 0xf0, 0x9a, 0x3c, 0x7e, 0xa4, 0xce, 0xe3, 0x5f, 0xe9, 0x97, 0xfc, 0xdc, - 0xcb, 0xcf, 0xea, 0xa5, 0x43, 0xe2, 0xb9, 0x6f, 0xf3, 0xf1, 0x56, 0x3a, - 0x14, 0x92, 0xc7, 0x67, 0x2b, 0xac, 0xe3, 0x0b, 0x6f, 0xd3, 0xb9, 0x6b, - 0x59, 0x5f, 0x4a, 0xe4, 0x2f, 0x38, 0x6b, 0x69, 0xe8, 0xfb, 0xd1, 0xae, - 0x1d, 0xff, 0x6b, 0xbd, 0x24, 0x73, 0xae, 0xca, 0x52, 0x3f, 0xd1, 0x5b, - 0xd1, 0x21, 0x17, 0xff, 0x37, 0xdb, 0x8e, 0xe7, 0xd5, 0x1a, 0x78, 0x7c, - 0x0d, 0xbf, 0x46, 0x2b, 0x5f, 0xf6, 0x79, 0xe0, 0xe1, 0xa7, 0xfb, 0xe5, - 0x3e, 0xd5, 0x5a, 0x7e, 0x8d, 0xa6, 0xb8, 0x0e, 0xe7, 0xbe, 0x3d, 0xeb, - 0xfd, 0x3d, 0x2a, 0x17, 0xf0, 0x87, 0xfd, 0x72, 0xbd, 0x40, 0x7e, 0xe0, - 0x0a, 0xd3, 0xe1, 0x22, 0x63, 0x95, 0x21, 0xea, 0xbc, 0xaa, 0xc7, 0x3a, - 0x24, 0xf4, 0xad, 0xd3, 0x4f, 0x73, 0x51, 0xe5, 0x76, 0xe7, 0x1c, 0x63, - 0xba, 0x28, 0x6c, 0x9c, 0xf6, 0xf2, 0xd6, 0x3e, 0xe6, 0x6a, 0xd8, 0xb5, - 0x26, 0xb8, 0xf9, 0x0d, 0x75, 0x4a, 0x30, 0xbf, 0x64, 0x48, 0x1c, 0x3c, - 0xc3, 0xf8, 0x76, 0xb3, 0xfb, 0x45, 0x9f, 0x14, 0x23, 0xba, 0x6b, 0x60, - 0xb8, 0x8f, 0x31, 0x0f, 0xd2, 0xe6, 0xc8, 0xbc, 0x58, 0x15, 0xba, 0xe0, - 0xe2, 0x54, 0x8d, 0x92, 0xd1, 0x6d, 0x94, 0x99, 0xe2, 0x77, 0xcf, 0xd8, - 0x6c, 0x7b, 0xf9, 0x29, 0xcb, 0xf2, 0x9b, 0x99, 0xda, 0xa2, 0xf0, 0xa2, - 0xf6, 0xa7, 0x77, 0xa9, 0x38, 0x87, 0x5e, 0xb1, 0x2f, 0x29, 0x6b, 0xf5, - 0xf0, 0x71, 0x45, 0x3f, 0x1b, 0xd7, 0xc1, 0xbb, 0x9d, 0xaa, 0xdd, 0x65, - 0x47, 0x3b, 0xb4, 0xb9, 0xac, 0xda, 0xe2, 0x99, 0x1a, 0x53, 0x74, 0x2b, - 0x7d, 0x0b, 0x39, 0x5c, 0x51, 0xb9, 0x7a, 0xc2, 0x7e, 0xa0, 0xd9, 0xfa, - 0x58, 0x2e, 0x73, 0xdb, 0xff, 0xae, 0xc5, 0x85, 0x2d, 0x77, 0x99, 0x31, - 0x6f, 0x55, 0xc8, 0x8a, 0xbb, 0x4f, 0x18, 0x8b, 0x5f, 0xec, 0x0f, 0xf1, - 0xb1, 0x7a, 0xcf, 0xe9, 0x7a, 0x9f, 0x10, 0xa3, 0x61, 0x45, 0xe4, 0xb3, - 0x74, 0xbb, 0xcb, 0x8e, 0x76, 0x5a, 0x57, 0xe8, 0xfd, 0x87, 0x8f, 0x7c, - 0xb3, 0x85, 0xdb, 0x3e, 0x19, 0xc3, 0x1b, 0x12, 0xfb, 0xa7, 0x32, 0x46, - 0x43, 0x1f, 0xc3, 0xbf, 0x8c, 0x98, 0x0a, 0xc4, 0x49, 0x38, 0xf5, 0x8d, - 0x1c, 0x6f, 0x00, 0x6b, 0x51, 0x15, 0xfb, 0xa6, 0xd8, 0xaf, 0x68, 0x87, - 0x9d, 0x77, 0x21, 0x36, 0x7f, 0x13, 0x18, 0x74, 0x23, 0xf2, 0x67, 0x7a, - 0xc8, 0x9f, 0xf3, 0xfd, 0xc8, 0x83, 0x43, 0x3e, 0x5c, 0x76, 0xd2, 0xa0, - 0x1a, 0xdb, 0x0a, 0x06, 0x95, 0x43, 0x3e, 0x3a, 0x67, 0x5b, 0xd1, 0x8a, - 0xc0, 0x9a, 0x8f, 0xc0, 0x7f, 0x35, 0xb9, 0x42, 0x07, 0x44, 0xce, 0x38, - 0x6a, 0x1f, 0x94, 0x79, 0x0d, 0x3e, 0xcd, 0x3c, 0x78, 0x96, 0xed, 0x8f, - 0xec, 0x49, 0xec, 0xb7, 0xe8, 0x79, 0x41, 0x0e, 0x3c, 0x3e, 0x4d, 0x9e, - 0xbb, 0xdf, 0xdd, 0x41, 0xc1, 0x38, 0x3f, 0xd3, 0x84, 0x7e, 0xe2, 0xe7, - 0xa4, 0x29, 0xc1, 0x76, 0x12, 0x6c, 0xd6, 0xd3, 0x27, 0xad, 0x50, 0x99, - 0x0c, 0x6e, 0x0b, 0xdb, 0x15, 0xcf, 0xc1, 0xfd, 0xf1, 0x50, 0x07, 0xb9, - 0x73, 0x72, 0x7b, 0x45, 0x9e, 0xe2, 0x5b, 0xd1, 0x07, 0xc9, 0x18, 0x84, - 0xbe, 0xc2, 0xbc, 0x3d, 0xa0, 0xf6, 0x89, 0xb6, 0xf3, 0xf1, 0x84, 0x3a, - 0x0e, 0x8a, 0xf9, 0x94, 0xc7, 0x9a, 0xbf, 0xf1, 0xf7, 0xf3, 0x2e, 0xb2, - 0xfd, 0x6a, 0xfe, 0x9a, 0x62, 0x41, 0x22, 0x63, 0x46, 0x90, 0xce, 0x57, - 0xd6, 0xf2, 0xbf, 0x78, 0xe5, 0xba, 0x6e, 0xdf, 0x60, 0xae, 0xeb, 0x4f, - 0x76, 0xc8, 0xdc, 0x32, 0x67, 0x5f, 0xfe, 0x93, 0xfb, 0xe2, 0x85, 0xc9, - 0x5a, 0x70, 0x22, 0x8f, 0xb7, 0x46, 0x3f, 0x8b, 0x7e, 0x9e, 0xee, 0x84, - 0x23, 0x2a, 0x66, 0x09, 0x31, 0x4a, 0x0f, 0x2a, 0xbe, 0xd6, 0xba, 0x9f, - 0x3c, 0x74, 0xff, 0xa3, 0x22, 0x56, 0x53, 0xae, 0x1d, 0x43, 0x8a, 0x1e, - 0xa0, 0x59, 0xc4, 0x41, 0xb3, 0x01, 0x07, 0xcd, 0x0c, 0x75, 0xbc, 0x4d, - 0x9c, 0x9f, 0xaf, 0x3c, 0xb5, 0x5d, 0xe6, 0x8b, 0x63, 0x2f, 0xf1, 0x92, - 0x3a, 0x5e, 0x6f, 0xbc, 0x56, 0x98, 0x82, 0xc2, 0xdf, 0xe4, 0x18, 0xeb, - 0xcb, 0x44, 0xf6, 0x81, 0x70, 0x2b, 0x0d, 0x5e, 0x73, 0x5c, 0x47, 0x1f, - 0xc7, 0x1d, 0x7d, 0x1c, 0x75, 0xf4, 0x71, 0x6f, 0x9b, 0x3e, 0xb2, 0x8e, - 0xe7, 0xf7, 0x9c, 0xad, 0x7e, 0xdc, 0xbe, 0xa2, 0x9f, 0xc8, 0x23, 0x06, - 0x3d, 0xb7, 0x52, 0x2e, 0x1c, 0x51, 0x6b, 0xc7, 0x2f, 0x55, 0x2e, 0xba, - 0x57, 0x9f, 0xff, 0x8e, 0xda, 0xcf, 0x9b, 0x93, 0x57, 0x9d, 0xf9, 0xc7, - 0xdf, 0xa5, 0xa4, 0xcc, 0x23, 0x57, 0xb2, 0x7d, 0xb9, 0x8d, 0x1f, 0x1a, - 0xf1, 0x1c, 0xc0, 0x20, 0xc2, 0x2e, 0xdc, 0x2d, 0x6b, 0xc1, 0x05, 0x68, - 0xa9, 0x9e, 0xcb, 0xeb, 0x57, 0xb9, 0x3b, 0xc7, 0xc3, 0xf7, 0x37, 0x8f, - 0x17, 0xd7, 0xff, 0x4c, 0xf8, 0xf2, 0xe4, 0xfe, 0xd1, 0x8a, 0xca, 0x47, - 0xb6, 0x4c, 0xc4, 0x06, 0x2c, 0x2e, 0xc3, 0xff, 0xda, 0x2e, 0x77, 0x57, - 0xea, 0xa2, 0x4c, 0xbd, 0x3e, 0x4a, 0x59, 0xe4, 0x35, 0x48, 0xff, 0x98, - 0xcc, 0xbf, 0x5d, 0x5c, 0xbe, 0x25, 0x72, 0x5e, 0x13, 0x2a, 0x8f, 0x37, - 0x43, 0x3d, 0x02, 0xe7, 0x7e, 0xfc, 0xfc, 0xdb, 0x17, 0xc2, 0x9b, 0xcf, - 0xbf, 0x75, 0xde, 0xb3, 0xb9, 0xfc, 0xdb, 0x10, 0x8f, 0xdd, 0x58, 0x90, - 0xf9, 0xb7, 0xcd, 0x7b, 0x32, 0x32, 0xff, 0x36, 0xe3, 0xc0, 0x0f, 0x12, - 0xaf, 0xbf, 0xe5, 0x88, 0xdf, 0x96, 0xb9, 0xb5, 0x8b, 0x75, 0xcc, 0x2a, - 0x73, 0x6b, 0x65, 0xbc, 0xb7, 0xb3, 0x0e, 0x8c, 0xdc, 0xfb, 0x91, 0xef, - 0xd9, 0xe6, 0xda, 0xfb, 0x91, 0x39, 0xb5, 0xa6, 0xd1, 0xce, 0x86, 0xc3, - 0x1a, 0x81, 0x7a, 0x08, 0x71, 0xe6, 0xdd, 0xad, 0x6d, 0xea, 0x21, 0xc4, - 0xdb, 0xd4, 0x43, 0x70, 0xea, 0x7e, 0x27, 0xc6, 0x02, 0x26, 0xc6, 0xda, - 0x08, 0x2c, 0x8c, 0x7a, 0x06, 0x51, 0x3a, 0x5f, 0xc7, 0x9e, 0x0f, 0x52, - 0x5a, 0x61, 0xcf, 0xf3, 0x15, 0xad, 0x8f, 0x46, 0x5d, 0xfa, 0xc8, 0x0b, - 0x8b, 0x5a, 0x2a, 0xce, 0x47, 0xcb, 0x6b, 0xd6, 0x21, 0xaf, 0x59, 0x0f, - 0x79, 0xc5, 0x3d, 0xd9, 0x36, 0xfd, 0xfe, 0xa5, 0xba, 0x07, 0xff, 0x4f, - 0x46, 0x50, 0xb3, 0x85, 0x68, 0xf7, 0x80, 0xc2, 0x7f, 0x0e, 0x79, 0x3d, - 0xcb, 0xf2, 0xaa, 0xaf, 0xa3, 0xbf, 0xed, 0x6c, 0x00, 0x8d, 0x19, 0x87, - 0x7c, 0x87, 0xaf, 0xbd, 0x21, 0xe2, 0xa4, 0x9a, 0xed, 0x45, 0x8d, 0x27, - 0xf6, 0x09, 0x59, 0xba, 0xe3, 0x47, 0xdc, 0x8a, 0xbe, 0x16, 0x52, 0x7e, - 0x32, 0x4d, 0x8b, 0xce, 0x26, 0xcc, 0xd1, 0xc0, 0x1b, 0x22, 0xc6, 0xd7, - 0xd1, 0xb7, 0x7f, 0xe5, 0xbe, 0xe9, 0xeb, 0x7a, 0xcd, 0x7c, 0xa7, 0xc9, - 0x9f, 0x71, 0xa3, 0xa9, 0xee, 0x1f, 0x7c, 0x47, 0xdb, 0xd2, 0x86, 0x9d, - 0x12, 0x31, 0xa6, 0x7d, 0x36, 0xfc, 0x64, 0x09, 0x96, 0xfd, 0xbe, 0x34, - 0xe2, 0x99, 0xfb, 0xae, 0x98, 0x74, 0xa2, 0x70, 0x7e, 0x8f, 0xe4, 0x95, - 0x0b, 0xa2, 0xa6, 0x25, 0x6a, 0x20, 0x26, 0x79, 0x7d, 0x4e, 0x30, 0xe8, - 0x9c, 0xab, 0x76, 0xd1, 0x22, 0xa3, 0x7b, 0xbf, 0x5d, 0x16, 0xbe, 0x3e, - 0xd6, 0x49, 0x45, 0xd4, 0x36, 0x35, 0x16, 0x3a, 0xf9, 0xb9, 0x83, 0xb4, - 0x54, 0x1a, 0x17, 0x35, 0xa1, 0x64, 0x7d, 0x11, 0xb4, 0xf5, 0x51, 0xbf, - 0xfd, 0x0d, 0xa6, 0xdd, 0xd7, 0x44, 0x8c, 0xe5, 0x62, 0xf1, 0x82, 0xfc, - 0x2c, 0x3f, 0xa5, 0xde, 0xc1, 0xef, 0xab, 0xfe, 0x98, 0xe2, 0xfd, 0xa6, - 0xc3, 0x96, 0x73, 0xfe, 0x79, 0xe3, 0x95, 0x63, 0x9b, 0xc2, 0x2b, 0xd9, - 0x74, 0x03, 0xaf, 0x38, 0x9f, 0xad, 0xb1, 0xcb, 0xe4, 0xa0, 0xac, 0xf7, - 0x00, 0x1a, 0x6c, 0x05, 0x16, 0x4b, 0x83, 0x96, 0x46, 0xcc, 0x8a, 0x24, - 0xfc, 0x33, 0x94, 0xaf, 0x5e, 0xa7, 0x4c, 0x11, 0x98, 0x99, 0x3f, 0xcb, - 0xe7, 0x76, 0x4a, 0x1f, 0x8d, 0xbe, 0x07, 0x7a, 0x65, 0x07, 0xb7, 0xff, - 0xeb, 0x41, 0x19, 0x97, 0xed, 0xbc, 0xde, 0xcb, 0xd7, 0xbf, 0x10, 0x69, - 0xbe, 0xbe, 0x85, 0xaf, 0xf7, 0xa7, 0x31, 0x87, 0xc6, 0x15, 0xf8, 0x25, - 0x27, 0x29, 0xc7, 0xf3, 0x93, 0xaf, 0xf2, 0xda, 0x7a, 0x95, 0xf5, 0x55, - 0x45, 0xb7, 0x1b, 0x40, 0xce, 0x8e, 0x98, 0x13, 0x83, 0xdb, 0x5c, 0x2c, - 0x4c, 0x71, 0xbb, 0x21, 0xf2, 0x5f, 0x35, 0x29, 0x5f, 0xd1, 0xbc, 0xaa, - 0xe3, 0xed, 0xdf, 0x18, 0x90, 0x31, 0x55, 0xef, 0xec, 0x94, 0xf4, 0x9b, - 0x14, 0x3e, 0x4f, 0xc4, 0x73, 0x3c, 0x23, 0xf8, 0xd0, 0x9a, 0x31, 0xeb, - 0xef, 0xdf, 0x06, 0xbe, 0x42, 0xdd, 0x54, 0x1e, 0x03, 0xeb, 0xc5, 0x98, - 0x1d, 0xca, 0xd5, 0x63, 0xd5, 0x9e, 0xdb, 0x2d, 0xef, 0xff, 0xe9, 0x80, - 0xac, 0x55, 0x7a, 0x5b, 0x9d, 0xeb, 0x35, 0x07, 0xf1, 0xcb, 0x3e, 0x41, - 0x1b, 0xff, 0x02, 0xf4, 0xa5, 0xc1, 0xc7, 0x3c, 0x9e, 0x34, 0xfa, 0xf8, - 0xb3, 0x01, 0x5d, 0x9f, 0x50, 0x8e, 0xeb, 0x28, 0xf7, 0x37, 0xc5, 0xe3, - 0xd2, 0xd7, 0xe3, 0x7c, 0xee, 0x35, 0xbf, 0x78, 0x56, 0x30, 0x2d, 0xeb, - 0x8b, 0x05, 0xd3, 0x99, 0x49, 0x39, 0xcf, 0x0d, 0x9f, 0x6e, 0xa4, 0xee, - 0xd3, 0x9d, 0x2b, 0xf4, 0x0f, 0xc2, 0xbf, 0x61, 0x5c, 0xe1, 0xf9, 0x0e, - 0x3f, 0xc3, 0x6d, 0x91, 0xab, 0x90, 0xe3, 0xcf, 0x1e, 0x15, 0xd7, 0xd3, - 0xca, 0x2b, 0x32, 0x4e, 0x42, 0xaf, 0x5b, 0xb8, 0x77, 0x80, 0x9f, 0x21, - 0xd7, 0xae, 0xf6, 0xef, 0xa1, 0x96, 0x38, 0x98, 0x56, 0x1e, 0x5b, 0xcb, - 0x0f, 0x2b, 0xf6, 0x13, 0x3d, 0xf8, 0x6c, 0xad, 0x7a, 0x06, 0xef, 0x08, - 0x3f, 0x5a, 0xb2, 0x45, 0x5e, 0x21, 0xc7, 0x01, 0xfa, 0xce, 0x7c, 0x96, - 0xb6, 0xf0, 0x5c, 0x7d, 0xc3, 0xf8, 0x35, 0xec, 0xb7, 0x93, 0x8c, 0x79, - 0x62, 0x1a, 0x17, 0xec, 0xc9, 0xb3, 0x06, 0xd3, 0xb9, 0x90, 0xad, 0x05, - 0xec, 0x1e, 0xea, 0x64, 0x59, 0xfd, 0x22, 0x8d, 0xb1, 0xfd, 0x07, 0x99, - 0xb5, 0x23, 0x29, 0x82, 0xbc, 0x59, 0xa1, 0xc3, 0xcc, 0x13, 0xc9, 0x2a, - 0xf8, 0xd9, 0xa0, 0x27, 0x4a, 0x44, 0x8f, 0x97, 0xc6, 0x42, 0xdf, 0x27, - 0xdb, 0x6c, 0x7c, 0x6f, 0x85, 0x12, 0xdc, 0x8f, 0x54, 0xf5, 0x77, 0xe8, - 0x43, 0x51, 0xe7, 0x04, 0x74, 0xd4, 0xf3, 0xfe, 0xdb, 0x74, 0x3a, 0x8d, - 0x7e, 0x6f, 0x5c, 0x3e, 0x4f, 0x6c, 0x4a, 0x3e, 0x83, 0x1e, 0xf2, 0xf9, - 0xea, 0xa0, 0xe4, 0x9b, 0x1a, 0xf3, 0x68, 0x90, 0x66, 0x8b, 0x88, 0x01, - 0x7b, 0x18, 0x75, 0xa7, 0x8a, 0x19, 0xd6, 0x4b, 0x99, 0x86, 0x5e, 0xba, - 0x94, 0xf0, 0xc7, 0x21, 0xe3, 0xa8, 0xcb, 0xa6, 0xe2, 0x7e, 0x30, 0x8e, - 0xdd, 0x34, 0xb6, 0xb0, 0x95, 0xef, 0xa5, 0x95, 0xc4, 0x74, 0x5c, 0xe5, - 0xfa, 0x5b, 0x66, 0x92, 0xf5, 0xe3, 0x1c, 0xcb, 0x72, 0xae, 0xf8, 0x00, - 0x2d, 0x86, 0x87, 0x69, 0x74, 0x41, 0xd7, 0x37, 0xc1, 0x58, 0xff, 0x6d, - 0x48, 0xea, 0x24, 0x3d, 0xee, 0x5f, 0x11, 0xbe, 0x0b, 0xf3, 0xfa, 0xa7, - 0x35, 0xee, 0xad, 0xeb, 0xe8, 0xa5, 0xbf, 0x52, 0x32, 0x5b, 0xbb, 0x91, - 0x88, 0x52, 0x36, 0x31, 0xfd, 0x97, 0x82, 0xff, 0x47, 0xaf, 0xc3, 0x0f, - 0x07, 0x1d, 0x6d, 0x52, 0xba, 0xe0, 0xa6, 0xc5, 0x30, 0x8f, 0x1b, 0xdf, - 0xd7, 0xfe, 0x79, 0x36, 0xfa, 0x94, 0x58, 0xfb, 0xc7, 0xae, 0x73, 0x3b, - 0xb1, 0x36, 0x69, 0xbd, 0xe1, 0xc5, 0x87, 0xba, 0x8e, 0xa5, 0xe6, 0x45, - 0x19, 0xeb, 0xc9, 0xf8, 0x2d, 0x94, 0xf6, 0xbb, 0x79, 0xf2, 0x23, 0x3a, - 0x36, 0x6f, 0xd2, 0xf1, 0x82, 0xf5, 0x7c, 0x96, 0x66, 0x58, 0xae, 0x9d, - 0xeb, 0x05, 0xb7, 0x27, 0xf0, 0x59, 0x8c, 0x65, 0x9f, 0xed, 0xe6, 0xa2, - 0x29, 0xe3, 0xee, 0x44, 0xed, 0xb9, 0x2e, 0xa1, 0x47, 0x43, 0xf6, 0x3f, - 0x0d, 0xea, 0xf5, 0x20, 0x53, 0x44, 0x1e, 0x21, 0x7f, 0x96, 0xb9, 0x7d, - 0x61, 0x90, 0x32, 0x25, 0x3c, 0x07, 0xeb, 0x1d, 0xfa, 0xce, 0xe7, 0x4b, - 0x72, 0x5e, 0x47, 0xf9, 0xd9, 0xc8, 0xbb, 0x3f, 0x5e, 0x9d, 0x12, 0xb1, - 0x77, 0xd0, 0xcd, 0x72, 0x3e, 0x63, 0x74, 0xd1, 0x53, 0xaf, 0x28, 0x4c, - 0xe9, 0x90, 0xef, 0x8c, 0x90, 0xef, 0x98, 0x98, 0x8f, 0x4c, 0xc9, 0x60, - 0xbc, 0xa6, 0x7d, 0x0f, 0xfd, 0x7c, 0x1e, 0x50, 0x3a, 0x04, 0xdf, 0x0d, - 0xec, 0x14, 0x71, 0x89, 0x36, 0xae, 0xe3, 0x33, 0x46, 0xcf, 0x30, 0xee, - 0x7c, 0xb6, 0xd0, 0x45, 0xb7, 0x8a, 0x5d, 0xf4, 0x66, 0x71, 0x98, 0x6e, - 0xce, 0x6f, 0xa7, 0x8b, 0x8c, 0x99, 0x2f, 0xda, 0x01, 0x33, 0xc7, 0xf6, - 0xc5, 0x0b, 0x51, 0x11, 0x33, 0xc4, 0x72, 0x87, 0xf6, 0xc0, 0x7f, 0x89, - 0x5d, 0xcc, 0x73, 0x8c, 0xbd, 0xbb, 0xe9, 0x03, 0x7e, 0x67, 0xae, 0xa0, - 0x63, 0x1d, 0xe0, 0x93, 0x1f, 0xaf, 0xe3, 0xd7, 0xf5, 0x79, 0x24, 0xb4, - 0x0e, 0x8f, 0xc4, 0x84, 0xae, 0xcf, 0xcf, 0xf3, 0xf7, 0xf3, 0xf0, 0x9f, - 0x33, 0xbd, 0x59, 0x3f, 0x7f, 0x3d, 0x80, 0xf6, 0xb8, 0x66, 0xcb, 0x58, - 0x49, 0x31, 0xb6, 0x08, 0x9f, 0x83, 0xb6, 0x11, 0x45, 0x87, 0x6e, 0x1e, - 0x9f, 0x4f, 0xb4, 0xcf, 0x2c, 0x75, 0xd3, 0x99, 0x12, 0x63, 0x90, 0x92, - 0x9f, 0x6d, 0x18, 0xb4, 0x0d, 0xec, 0xd5, 0xf5, 0x5f, 0x2f, 0x72, 0xdf, - 0x73, 0x25, 0x89, 0x41, 0x72, 0x4b, 0xbd, 0x94, 0x2f, 0xf5, 0xa8, 0xf3, - 0x07, 0x44, 0x8c, 0xbb, 0xac, 0x63, 0x84, 0xef, 0xd6, 0xd2, 0x6f, 0x6f, - 0x31, 0x4f, 0x61, 0x4d, 0x95, 0x76, 0x29, 0x74, 0xcd, 0x8d, 0x96, 0xba, - 0xc4, 0xe0, 0xb9, 0x19, 0xfa, 0x2e, 0xaf, 0xb7, 0xa3, 0x57, 0xe1, 0x3f, - 0xfe, 0x2a, 0xf8, 0xa6, 0x0c, 0x1e, 0x1b, 0xbd, 0x8a, 0xba, 0x48, 0x7e, - 0x91, 0xe7, 0x94, 0x0c, 0x4f, 0x8a, 0xdc, 0x10, 0x29, 0xa3, 0x27, 0x45, - 0x2d, 0xba, 0x1f, 0x0a, 0xdd, 0x64, 0x65, 0x4d, 0x03, 0x78, 0x04, 0x3e, - 0x18, 0x19, 0x83, 0x75, 0xc2, 0xee, 0x7b, 0x6b, 0x20, 0x36, 0x41, 0xf1, - 0x41, 0xf0, 0xbd, 0x94, 0x59, 0x55, 0x5f, 0x40, 0xe8, 0xfb, 0xd0, 0x3e, - 0x9d, 0x2f, 0xa9, 0xcf, 0xf5, 0x5a, 0xa1, 0xcf, 0x7b, 0x5c, 0xdf, 0x87, - 0x5c, 0xdf, 0xd7, 0xe3, 0xe5, 0x78, 0xcd, 0xe3, 0x75, 0x9e, 0x64, 0x8d, - 0xa2, 0xcc, 0x82, 0xe4, 0xbf, 0xd0, 0xbe, 0xf1, 0xd0, 0x97, 0x15, 0x06, - 0xcf, 0x2c, 0x8f, 0x45, 0xfa, 0x8c, 0x1e, 0x7f, 0x66, 0xea, 0xef, 0x6b, - 0xf1, 0x34, 0x70, 0xd1, 0xdc, 0x4e, 0xa9, 0xe3, 0xd0, 0xaf, 0x6c, 0x14, - 0xd0, 0xed, 0xe4, 0x72, 0x0f, 0xad, 0x88, 0x9a, 0x5c, 0xc0, 0x18, 0xb8, - 0x1f, 0xcf, 0xc9, 0x86, 0x3a, 0x08, 0x35, 0xd7, 0x21, 0xe3, 0x07, 0x22, - 0xd7, 0x79, 0x3e, 0x53, 0xcb, 0xff, 0x55, 0x3b, 0x2d, 0x6a, 0xdc, 0xa0, - 0x2d, 0x63, 0x48, 0x81, 0xf9, 0x19, 0xbf, 0x34, 0xd9, 0x55, 0x33, 0xe8, - 0x67, 0x16, 0x7b, 0x2b, 0x86, 0xfd, 0x22, 0xcb, 0x98, 0xdc, 0x2b, 0x4f, - 0xb9, 0xf6, 0xca, 0x4f, 0x8a, 0xbd, 0x72, 0xec, 0x93, 0x83, 0xae, 0xa0, - 0xa5, 0x57, 0x4c, 0x0b, 0xe6, 0x31, 0xca, 0xf3, 0x68, 0xd2, 0xc5, 0x6b, - 0x42, 0xdf, 0x44, 0x93, 0x7e, 0x19, 0x5f, 0x9d, 0xa2, 0xac, 0x88, 0xbf, - 0x96, 0x9f, 0x71, 0x23, 0x61, 0x5b, 0x93, 0xab, 0x8c, 0x29, 0x2a, 0xc5, - 0x2d, 0x74, 0xb3, 0xdc, 0xc1, 0x98, 0xef, 0x6f, 0x69, 0xb5, 0x4c, 0x8c, - 0x0d, 0xb7, 0x53, 0x3e, 0xca, 0xbc, 0x36, 0x19, 0xe4, 0x79, 0x65, 0x7c, - 0x3b, 0xc9, 0xf2, 0xc7, 0x63, 0xa8, 0x94, 0x6a, 0xef, 0xe7, 0xa2, 0x71, - 0x33, 0x31, 0xdd, 0xc3, 0xf6, 0x4b, 0x88, 0xff, 0x6d, 0xfe, 0xff, 0x6c, - 0x04, 0xb4, 0x59, 0x5c, 0xc2, 0xf7, 0x8c, 0x7d, 0x0a, 0xb5, 0xf7, 0x67, - 0xb9, 0xcd, 0xec, 0x34, 0xec, 0x20, 0xd8, 0x7b, 0x36, 0xff, 0xcb, 0x36, - 0x15, 0xe6, 0xbb, 0xdc, 0xb5, 0x6c, 0xc4, 0x10, 0x3a, 0x1e, 0x75, 0x5d, - 0xc6, 0xd4, 0x67, 0xdc, 0x98, 0xe5, 0xbe, 0xdc, 0x24, 0x3c, 0xc3, 0xa4, - 0x4c, 0x74, 0x1f, 0xcb, 0xc1, 0x76, 0xfe, 0x44, 0x3e, 0xd6, 0x56, 0xca, - 0x4f, 0x8d, 0xab, 0x7c, 0xac, 0x48, 0x9b, 0x7c, 0x2c, 0xdc, 0xc7, 0x38, - 0x60, 0xbe, 0x76, 0x6f, 0x36, 0xea, 0x7c, 0x2f, 0x19, 0x99, 0xe8, 0x36, - 0x81, 0x99, 0x2a, 0x4b, 0xfb, 0xb9, 0x0f, 0x71, 0x33, 0x33, 0xcd, 0x7d, - 0x2d, 0x39, 0xfb, 0x5f, 0xbb, 0x97, 0x8c, 0xa2, 0x9d, 0xdf, 0xd5, 0x2e, - 0x4e, 0xa2, 0xed, 0x12, 0xda, 0xd7, 0xfe, 0x27, 0x11, 0xd5, 0xe3, 0x74, - 0xde, 0x8b, 0xf1, 0x40, 0xbe, 0xf8, 0xb3, 0x72, 0x9b, 0x6e, 0x16, 0x61, - 0x8f, 0x1b, 0xcc, 0xf7, 0xe8, 0x91, 0x49, 0xd9, 0x0a, 0x63, 0xc0, 0x6b, - 0x7b, 0x7d, 0xab, 0xc5, 0x37, 0x6a, 0x99, 0xa6, 0xd8, 0x96, 0x66, 0x3f, - 0xbc, 0xb4, 0xc1, 0x86, 0xc9, 0xbe, 0x82, 0x35, 0x14, 0xeb, 0x67, 0xb6, - 0xe6, 0xb7, 0x81, 0xf7, 0x60, 0x1b, 0x5d, 0x60, 0xfd, 0x25, 0xe3, 0x93, - 0x58, 0x97, 0xb2, 0x0e, 0x93, 0xf2, 0x93, 0x6a, 0xfa, 0x39, 0x04, 0xc9, - 0xc3, 0xa3, 0x8d, 0xb8, 0x48, 0xc7, 0xfe, 0x7a, 0xc0, 0xb1, 0xbf, 0x1e, - 0x72, 0xc4, 0x45, 0x86, 0x05, 0x3e, 0x6b, 0x60, 0xaa, 0xb0, 0xc2, 0x54, - 0xc0, 0x5e, 0x52, 0xb7, 0x2d, 0xd6, 0x75, 0xdb, 0x8e, 0x75, 0x74, 0x9b, - 0x97, 0xad, 0xba, 0xa2, 0xf4, 0x88, 0x15, 0xc5, 0x1a, 0x73, 0x83, 0xf5, - 0xc5, 0xeb, 0xd5, 0x69, 0xd6, 0x23, 0x51, 0xd6, 0x23, 0x53, 0xac, 0x47, - 0x26, 0x59, 0x8f, 0xd8, 0x4c, 0x03, 0x93, 0xc7, 0xfe, 0x11, 0xeb, 0x69, - 0xac, 0x1f, 0x33, 0xf4, 0x4c, 0x15, 0x3a, 0x79, 0x8a, 0x31, 0xd0, 0x47, - 0xb4, 0x3a, 0xdf, 0xcb, 0xfc, 0x2b, 0x71, 0x4f, 0xb3, 0x5d, 0x83, 0xda, - 0x2b, 0xf0, 0x17, 0xff, 0x39, 0xf4, 0xce, 0x2b, 0x59, 0x1a, 0xf1, 0xdd, - 0x2c, 0x82, 0xce, 0xab, 0xa8, 0x55, 0xf1, 0x12, 0x64, 0x1b, 0x35, 0x82, - 0x7f, 0x30, 0x31, 0xc3, 0x7d, 0x1f, 0xf1, 0xe5, 0x79, 0x5e, 0xbe, 0x1d, - 0xcd, 0x86, 0xfa, 0x59, 0x06, 0x8e, 0x2b, 0x19, 0x38, 0xde, 0x90, 0x81, - 0x6c, 0x8e, 0x47, 0xd2, 0xb7, 0xb0, 0x9d, 0xc6, 0x0f, 0x26, 0x76, 0xf5, - 0xb1, 0xfc, 0x22, 0x66, 0xa2, 0x51, 0xbf, 0xc7, 0x4f, 0xa7, 0xc3, 0x41, - 0x55, 0xf7, 0xc7, 0x14, 0x39, 0xef, 0xf9, 0xe2, 0xbb, 0x8c, 0x4b, 0x58, - 0x4e, 0x43, 0x38, 0xbf, 0x0c, 0xbf, 0x28, 0xdb, 0x0d, 0xdd, 0xc2, 0xaf, - 0xb4, 0x28, 0xda, 0xe2, 0xdc, 0x9a, 0x64, 0x1d, 0x17, 0x5d, 0x31, 0xac, - 0x99, 0xb8, 0xf1, 0x9b, 0xc3, 0xa8, 0xe1, 0xfe, 0x83, 0xea, 0xe7, 0x86, - 0xe5, 0xde, 0x5c, 0x72, 0x97, 0xd4, 0x27, 0xcc, 0xa3, 0xe1, 0xb8, 0xb0, - 0xdd, 0x3a, 0xae, 0xc8, 0xf5, 0x73, 0x91, 0xe7, 0xbb, 0x12, 0x9d, 0xe4, - 0xf9, 0xee, 0x51, 0x6b, 0x67, 0x96, 0xbf, 0x17, 0xeb, 0x32, 0xaf, 0xa1, - 0xc3, 0xa8, 0x7f, 0x1f, 0x12, 0x75, 0x22, 0x4e, 0xa2, 0x0e, 0x4f, 0x02, - 0xcf, 0x63, 0xee, 0x85, 0xfe, 0xf8, 0x07, 0x5e, 0xa3, 0xf1, 0x5e, 0xf0, - 0x23, 0x1f, 0x97, 0x67, 0xe8, 0x52, 0x41, 0xf7, 0xe1, 0x3d, 0x32, 0xbe, - 0x8b, 0x7e, 0xf8, 0x68, 0x87, 0xfd, 0x9e, 0xc8, 0x05, 0x31, 0xfe, 0xc4, - 0xdd, 0xa7, 0xa3, 0xaa, 0x4f, 0xa8, 0x75, 0xd9, 0x85, 0xda, 0x3e, 0x84, - 0x9a, 0x48, 0x8b, 0xa2, 0x16, 0x65, 0xa7, 0xb0, 0x59, 0x17, 0x85, 0xed, - 0xb1, 0x7f, 0x57, 0xa3, 0x3e, 0xe6, 0x7e, 0xd7, 0xb5, 0x3b, 0xbc, 0x6e, - 0x1d, 0x12, 0x18, 0x6d, 0x14, 0xf5, 0xda, 0x45, 0x5e, 0xea, 0x8c, 0xf8, - 0xce, 0x58, 0xc0, 0x77, 0x0f, 0xa9, 0xef, 0x3e, 0x2f, 0xb0, 0xb1, 0x11, - 0xeb, 0x66, 0xbd, 0x28, 0xf8, 0x9d, 0xe7, 0xd9, 0x9e, 0x64, 0x7e, 0x8f, - 0x54, 0xf8, 0xb9, 0xa7, 0x05, 0x3d, 0x35, 0x3d, 0x40, 0x0b, 0xc8, 0x40, - 0x8f, 0xe2, 0x7f, 0xcb, 0x4c, 0xf9, 0xf5, 0xb8, 0xdb, 0xd1, 0x99, 0xb1, - 0x4e, 0x01, 0x63, 0xc5, 0x98, 0x4c, 0x5f, 0xbc, 0x1c, 0xf1, 0xe5, 0xe6, - 0x61, 0xeb, 0x20, 0xdf, 0x65, 0x0f, 0xe2, 0xa9, 0xb8, 0x0f, 0x3b, 0x29, - 0x9e, 0x46, 0xbf, 0xd0, 0x4e, 0xd3, 0xc0, 0x76, 0xd1, 0xc2, 0x79, 0xdf, - 0x76, 0x75, 0x5f, 0xb7, 0x98, 0x0b, 0x32, 0xf0, 0x1e, 0xfd, 0x6e, 0xbc, - 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x00, 0xeb, 0xed, 0xc4, - 0xb4, 0x7c, 0x96, 0x71, 0x5d, 0x7e, 0x37, 0x60, 0x7b, 0xf7, 0x57, 0xce, - 0x9f, 0x4f, 0xd5, 0xf1, 0xc1, 0xfc, 0x6d, 0xa7, 0xb2, 0xf0, 0x7d, 0xe2, - 0xbb, 0x11, 0x9f, 0xb0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xf3, - 0x33, 0xc5, 0xdb, 0xc2, 0x66, 0xcf, 0xa5, 0x47, 0x7c, 0xe5, 0x32, 0xc6, - 0x3b, 0xe2, 0x4b, 0xb1, 0x0c, 0x24, 0x8b, 0x89, 0x5a, 0x5e, 0xe2, 0x02, - 0x3a, 0xdd, 0x6f, 0x85, 0x4e, 0x1b, 0xef, 0x0f, 0xcb, 0x9a, 0xb7, 0x38, - 0x66, 0x39, 0x2c, 0xb0, 0x1c, 0x16, 0x58, 0x0e, 0x0b, 0x2c, 0x87, 0x6c, - 0xab, 0xbe, 0x56, 0x60, 0x39, 0xe4, 0xb5, 0xe4, 0x55, 0x5e, 0x4b, 0xa4, - 0xec, 0xc6, 0x95, 0x7f, 0x53, 0xcb, 0xae, 0x3b, 0x6f, 0x53, 0xcb, 0x2a, - 0xd6, 0x6f, 0xf2, 0x1d, 0x99, 0x68, 0x96, 0xd9, 0x5b, 0x2c, 0xb3, 0x1d, - 0xb1, 0x41, 0xba, 0x5b, 0xc2, 0x9c, 0x59, 0xe6, 0x1c, 0xeb, 0xea, 0x94, - 0x1f, 0x58, 0x2b, 0xc0, 0xf2, 0x04, 0xac, 0x69, 0x31, 0xdd, 0x07, 0xe9, - 0x1e, 0xeb, 0xeb, 0xbb, 0x25, 0xc8, 0xf0, 0x1e, 0x75, 0x6e, 0xb1, 0x0c, - 0x63, 0xfd, 0xb3, 0x7d, 0xb7, 0x8a, 0x06, 0x63, 0xb2, 0x40, 0x28, 0x43, - 0xd0, 0xa7, 0x02, 0xa7, 0xf1, 0xbc, 0xaf, 0xb0, 0xde, 0x87, 0x0f, 0x0f, - 0xeb, 0xc5, 0x19, 0x1f, 0xaf, 0x17, 0x91, 0x9b, 0xac, 0x4f, 0xcf, 0x97, - 0x6c, 0x96, 0xfb, 0x7e, 0xfa, 0x56, 0x09, 0xeb, 0x34, 0x68, 0xc4, 0xe7, - 0x65, 0x12, 0xbe, 0x31, 0x23, 0x86, 0xb1, 0x8f, 0x67, 0x0d, 0xc1, 0x27, - 0x7f, 0x0a, 0x3a, 0x30, 0xed, 0x5f, 0xdc, 0x85, 0xda, 0xf3, 0x71, 0xa3, - 0x53, 0xf9, 0x1a, 0x71, 0x8c, 0xf6, 0x68, 0x0b, 0xba, 0xe1, 0xbc, 0xdd, - 0xbe, 0x24, 0x7e, 0xb3, 0x21, 0x0a, 0xff, 0x9b, 0x4b, 0x7f, 0x5d, 0xe2, - 0xfb, 0x05, 0xbd, 0x66, 0x12, 0x7e, 0xe4, 0x90, 0xd3, 0xd3, 0xfe, 0xd8, - 0x0c, 0x3d, 0x5b, 0x45, 0xbf, 0xaf, 0x52, 0x3e, 0x0c, 0x7d, 0x64, 0x45, - 0xef, 0x90, 0xa4, 0x5d, 0x37, 0xe3, 0xce, 0x27, 0xbc, 0x75, 0x9c, 0x99, - 0x10, 0x38, 0xb9, 0x8b, 0xf5, 0x0b, 0x68, 0xf3, 0x13, 0xe6, 0x35, 0x7e, - 0x5f, 0x41, 0xeb, 0xb7, 0x1f, 0xb3, 0xce, 0xc1, 0x9c, 0xe1, 0x7c, 0x6d, - 0x9d, 0xb6, 0xaa, 0x74, 0x9a, 0xed, 0xd0, 0x69, 0xb9, 0xba, 0x4e, 0x63, - 0xde, 0x10, 0xba, 0x0c, 0xba, 0xea, 0x51, 0xc6, 0x91, 0xf2, 0x18, 0xf8, - 0x70, 0x87, 0xd0, 0x5d, 0xac, 0xfb, 0xd9, 0xae, 0x58, 0xac, 0x66, 0x7d, - 0x87, 0x85, 0x0e, 0xd1, 0xfc, 0xbd, 0x7f, 0xb7, 0x94, 0x8b, 0x6e, 0xa1, - 0x0f, 0x72, 0x27, 0xa1, 0xb7, 0xbc, 0xda, 0x8f, 0x73, 0x3b, 0xb4, 0xb7, - 0x23, 0x2f, 0xb1, 0x3e, 0x5b, 0x8c, 0xc2, 0xa6, 0xed, 0x51, 0xb6, 0x0f, - 0xea, 0x72, 0x61, 0xaf, 0x0b, 0x63, 0xd5, 0xfa, 0x6c, 0x40, 0xf9, 0x35, - 0xe0, 0x87, 0xc4, 0x9c, 0xb7, 0xc5, 0x08, 0x26, 0x30, 0x02, 0xdf, 0x13, - 0x60, 0x7a, 0x89, 0x1a, 0xe2, 0x44, 0xef, 0xd2, 0xaa, 0x90, 0x8d, 0x77, - 0x05, 0x76, 0xc9, 0xf3, 0x77, 0xb3, 0xd3, 0x07, 0x45, 0x3f, 0xf3, 0x4b, - 0x0d, 0xfd, 0x38, 0x57, 0x78, 0x0f, 0xeb, 0x86, 0xe8, 0x6b, 0x65, 0x42, - 0xea, 0xc0, 0xc5, 0x32, 0x6a, 0x80, 0x89, 0x3e, 0x73, 0x5f, 0xf5, 0x38, - 0xd1, 0x0f, 0xad, 0x0f, 0x36, 0x22, 0x7b, 0x8c, 0x6b, 0xfb, 0x31, 0x47, - 0x59, 0x07, 0x0f, 0x3d, 0xcb, 0xef, 0xc7, 0xb5, 0xf5, 0xc7, 0x73, 0xaf, - 0x3e, 0x1e, 0xf8, 0xf6, 0x70, 0xcf, 0xbb, 0x74, 0x57, 0x8d, 0xe7, 0x6e, - 0x7d, 0x3c, 0xcf, 0xa8, 0xf1, 0x50, 0xce, 0x88, 0x0d, 0x28, 0xdc, 0xbf, - 0xe1, 0x67, 0x77, 0x27, 0x18, 0xc7, 0xe4, 0x96, 0x40, 0xe7, 0xfd, 0x8a, - 0x9f, 0x9c, 0x7e, 0x54, 0x67, 0x5f, 0xad, 0xc9, 0x3b, 0xac, 0x7f, 0xef, - 0x09, 0x1c, 0x33, 0xc2, 0x38, 0x06, 0xd7, 0x29, 0x0f, 0x3d, 0x9d, 0x0b, - 0xa3, 0x4e, 0xed, 0x0c, 0x8f, 0x9b, 0xed, 0xb1, 0x69, 0xfe, 0x14, 0xfe, - 0x35, 0x3c, 0x47, 0xdf, 0xff, 0x3c, 0xdd, 0x9b, 0x87, 0x2e, 0x07, 0x8e, - 0x95, 0xb5, 0x6c, 0xef, 0x2d, 0x4b, 0xff, 0x6e, 0xca, 0xd3, 0xbf, 0x0b, - 0xdf, 0xee, 0x34, 0x70, 0x7e, 0x08, 0x7e, 0xe0, 0xa4, 0xfa, 0xad, 0x8f, - 0x5c, 0x15, 0xcf, 0xf2, 0xd2, 0x4b, 0x33, 0x8e, 0xd8, 0x38, 0xc4, 0xaa, - 0x64, 0x59, 0xcf, 0xd8, 0xa1, 0x0e, 0x43, 0xe6, 0xdc, 0xdc, 0xa8, 0x6a, - 0xec, 0x74, 0x94, 0xe7, 0xcc, 0x8e, 0x1a, 0x46, 0x4a, 0xf8, 0x1a, 0xba, - 0xed, 0x1e, 0xea, 0xe2, 0x75, 0xf4, 0x2c, 0xa1, 0x96, 0x9a, 0x65, 0x62, - 0x0f, 0xe0, 0x12, 0xf3, 0x64, 0x3e, 0x6a, 0x45, 0x1e, 0x17, 0x76, 0x29, - 0xd6, 0x17, 0x03, 0x74, 0x62, 0x5a, 0xa3, 0x0f, 0x7c, 0xbc, 0x84, 0x3a, - 0x9a, 0x51, 0x1e, 0x3f, 0xfc, 0xc7, 0x63, 0xe6, 0x9b, 0xbc, 0x2e, 0x5d, - 0x12, 0x7e, 0x99, 0x0b, 0x94, 0x63, 0x39, 0x3d, 0x22, 0xe4, 0xd4, 0x18, - 0x61, 0x29, 0x62, 0xb9, 0x42, 0x6c, 0xc2, 0xb8, 0xa8, 0xdb, 0x23, 0x6d, - 0x1d, 0x1e, 0xe5, 0xb2, 0xaa, 0x87, 0x90, 0x86, 0xee, 0xd8, 0xb8, 0x4f, - 0x22, 0xfd, 0x89, 0x7d, 0x31, 0x4e, 0x4c, 0xe6, 0xf6, 0x7d, 0xc3, 0xae, - 0x33, 0x45, 0xbd, 0x48, 0xd0, 0x4e, 0xf8, 0x13, 0x8d, 0x29, 0xa6, 0x9b, - 0xfe, 0xdd, 0x19, 0xa7, 0xdf, 0xe0, 0x9c, 0xc8, 0xeb, 0x7f, 0xa5, 0x2a, - 0xd7, 0xe0, 0x1c, 0xdb, 0xf4, 0xf9, 0x83, 0x4e, 0x4c, 0x62, 0x15, 0x93, - 0xc2, 0x97, 0xb3, 0x9b, 0x12, 0x0b, 0x53, 0xf4, 0x68, 0x01, 0x3a, 0x8c, - 0xee, 0x24, 0x6c, 0xfc, 0xa2, 0x0c, 0x64, 0x7c, 0x8a, 0x52, 0x55, 0xd0, - 0xc8, 0xc7, 0x58, 0x89, 0x79, 0xaf, 0x88, 0x3d, 0x7f, 0x3e, 0x2e, 0xe3, - 0x77, 0x54, 0x7e, 0x5d, 0xf9, 0xcb, 0x87, 0x29, 0xb9, 0x40, 0xd9, 0x4c, - 0xf4, 0x4b, 0xa2, 0xd6, 0x75, 0x26, 0x3a, 0xa1, 0x7c, 0x3b, 0x11, 0xbe, - 0x0e, 0x7f, 0x99, 0x49, 0x5f, 0x2e, 0x58, 0xd9, 0x0c, 0x49, 0x9f, 0x05, - 0x71, 0x1f, 0x0c, 0x5e, 0x7b, 0x77, 0xb0, 0x0e, 0x39, 0x21, 0xfc, 0x16, - 0x8c, 0x54, 0xe6, 0xd1, 0x1e, 0x3e, 0x87, 0x7e, 0x82, 0x9d, 0x96, 0x29, - 0x3e, 0xa5, 0xda, 0xd6, 0x28, 0xc4, 0xbc, 0x10, 0xfa, 0x55, 0x3b, 0x1b, - 0x35, 0x1a, 0xf7, 0xc3, 0xe7, 0x71, 0x42, 0xe0, 0xc8, 0x11, 0xb6, 0x79, - 0x44, 0xbb, 0xda, 0xac, 0xf0, 0x5f, 0xf0, 0x79, 0xf9, 0x81, 0x21, 0xfd, - 0x9b, 0x08, 0xb8, 0x2e, 0xfd, 0x1a, 0xfc, 0xcc, 0x32, 0xf7, 0xa3, 0x29, - 0x9e, 0x7e, 0x98, 0xe2, 0x9b, 0xf0, 0x33, 0x9d, 0xbc, 0xaf, 0x7e, 0x26, - 0xa6, 0x35, 0xaf, 0x3d, 0x37, 0x58, 0x36, 0x5e, 0x5f, 0xd7, 0xfe, 0xfb, - 0x50, 0xaf, 0xe1, 0x4c, 0xab, 0x90, 0xf8, 0xdd, 0x0c, 0x60, 0xf0, 0x7c, - 0xf5, 0x71, 0xfc, 0x5e, 0x8c, 0x2f, 0x2d, 0xb0, 0x71, 0x84, 0xb1, 0x0d, - 0x30, 0xce, 0x98, 0xd8, 0x17, 0x8b, 0x3f, 0x16, 0xf1, 0xe5, 0x97, 0x07, - 0xc9, 0x0f, 0x7f, 0x9c, 0xad, 0x63, 0x29, 0xba, 0x45, 0xdc, 0xbb, 0xdc, - 0x8f, 0xc4, 0xfa, 0x0c, 0x9d, 0x78, 0x87, 0xed, 0x86, 0x09, 0x15, 0x87, - 0xd3, 0x21, 0x6a, 0x53, 0xc9, 0xbd, 0x54, 0xad, 0x53, 0x34, 0xef, 0xe9, - 0xbd, 0x0e, 0xe7, 0x6f, 0x73, 0x41, 0x76, 0x9d, 0x98, 0x02, 0xfe, 0x29, - 0x31, 0x47, 0x97, 0x88, 0xe4, 0x1c, 0x37, 0xf6, 0x31, 0xba, 0x78, 0x9e, - 0x60, 0x0f, 0xc2, 0xef, 0xf7, 0x35, 0xfe, 0xc4, 0x7e, 0xc4, 0xd5, 0x21, - 0xe0, 0xa8, 0x3e, 0x9b, 0x79, 0x66, 0x1a, 0xe7, 0x83, 0x6c, 0x9f, 0x69, - 0xdc, 0x2b, 0x7d, 0x51, 0x6c, 0xb3, 0xa9, 0xf9, 0x82, 0x1f, 0x6a, 0x54, - 0xd5, 0x29, 0xb0, 0xc8, 0xec, 0x07, 0x9d, 0x3e, 0x2d, 0x79, 0x5c, 0x6f, - 0xef, 0x62, 0x23, 0xb1, 0x4e, 0xf8, 0xdd, 0x30, 0xd4, 0xeb, 0xdc, 0x0b, - 0xda, 0xf3, 0x1c, 0x39, 0xf7, 0x36, 0x1e, 0xdf, 0xa5, 0x7f, 0xb3, 0xe8, - 0xfe, 0xcc, 0xdb, 0x16, 0x8f, 0x79, 0xfb, 0xf9, 0x90, 0xdc, 0x3b, 0x7b, - 0x58, 0xb5, 0xf1, 0x8a, 0x6f, 0x5d, 0xfe, 0x0e, 0xfc, 0x50, 0x8d, 0xfc, - 0x8b, 0x77, 0x84, 0x5e, 0x69, 0xf5, 0x85, 0x47, 0x58, 0x9f, 0x4a, 0x39, - 0x3e, 0xe1, 0x21, 0xc7, 0xfd, 0x31, 0xe0, 0x96, 0x8f, 0x2f, 0xc7, 0xc7, - 0xdb, 0xca, 0xf1, 0x9e, 0x61, 0xe9, 0x8b, 0x6d, 0x95, 0x63, 0xe4, 0x00, - 0x9d, 0xa8, 0xb6, 0xf3, 0x7b, 0x61, 0x1e, 0x90, 0xcb, 0xee, 0xf4, 0x95, - 0x80, 0x66, 0xda, 0x5f, 0x82, 0x7d, 0x43, 0xf0, 0x25, 0xf6, 0x5e, 0x4e, - 0x1a, 0xa9, 0x79, 0xf7, 0x5e, 0xea, 0x46, 0xee, 0xbd, 0xed, 0x71, 0x2f, - 0xb0, 0x3b, 0x64, 0xc3, 0x8a, 0x48, 0x5f, 0x80, 0xa6, 0xdf, 0xb0, 0xef, - 0x70, 0xc9, 0xca, 0x96, 0x09, 0xbe, 0xee, 0x30, 0x9d, 0xc3, 0xfe, 0xb4, - 0xf2, 0x25, 0x1f, 0x2b, 0x48, 0x3a, 0x84, 0x0e, 0x0a, 0xfe, 0x00, 0xbe, - 0x8d, 0xa4, 0xfd, 0x69, 0x9e, 0x63, 0xe9, 0x47, 0xce, 0x2c, 0x45, 0xd4, - 0xbc, 0x71, 0x5b, 0x3c, 0xcf, 0x33, 0x5f, 0x10, 0xf3, 0x65, 0x3d, 0xbf, - 0x52, 0x8f, 0x4f, 0xc6, 0xda, 0x50, 0xa3, 0xff, 0xe0, 0x75, 0xcf, 0x7f, - 0x30, 0x24, 0x6a, 0x37, 0xdc, 0xa8, 0x1e, 0x64, 0xbc, 0x89, 0x39, 0x85, - 0x0f, 0x52, 0xfb, 0x88, 0x1f, 0xda, 0x4b, 0xbd, 0x07, 0x18, 0x05, 0x18, - 0x64, 0x33, 0xbe, 0x34, 0x0e, 0x22, 0xce, 0xdc, 0xe4, 0x7b, 0x50, 0x73, - 0x6a, 0xdc, 0x4c, 0x51, 0x0f, 0xfc, 0x10, 0xa8, 0x25, 0x6d, 0xe6, 0x9a, - 0x64, 0xec, 0x94, 0x90, 0xb1, 0xd4, 0xf2, 0x29, 0x25, 0x63, 0xa7, 0x94, - 0x1f, 0xfe, 0x94, 0x92, 0xb1, 0x53, 0x4a, 0xc6, 0x4e, 0x29, 0x19, 0x3b, - 0xc5, 0x7c, 0x3e, 0xc6, 0xf8, 0x16, 0x58, 0x44, 0xfb, 0x41, 0x7b, 0x29, - 0x53, 0xc2, 0x75, 0xac, 0xcf, 0x6e, 0x39, 0x7b, 0x69, 0x44, 0xca, 0x19, - 0x63, 0x13, 0x19, 0xaf, 0xc7, 0xef, 0xc2, 0x1c, 0xfc, 0x1e, 0xd3, 0xef, - 0x23, 0x3a, 0x33, 0x8f, 0xbe, 0xfa, 0x28, 0x29, 0x6a, 0xc9, 0x76, 0x50, - 0xc2, 0x89, 0x85, 0x43, 0xc8, 0x0f, 0x93, 0xb6, 0x5f, 0xb6, 0x6d, 0xae, - 0x98, 0xe6, 0x93, 0x98, 0x9a, 0x2f, 0xb7, 0x5d, 0xd4, 0x45, 0xe9, 0x22, - 0xe8, 0x8a, 0x98, 0x4a, 0x93, 0xe7, 0x46, 0xd0, 0x49, 0x86, 0x44, 0xb9, - 0x68, 0x70, 0x4c, 0xd1, 0xe0, 0xdb, 0x62, 0x8c, 0x88, 0x49, 0x84, 0x2f, - 0xb3, 0x3d, 0x1d, 0x72, 0x85, 0x31, 0x7e, 0x0e, 0xcb, 0xc2, 0xc1, 0x08, - 0xeb, 0xa4, 0x8d, 0xd3, 0xa1, 0x31, 0xf6, 0x76, 0xba, 0x67, 0xa3, 0x79, - 0x39, 0x77, 0x1c, 0x6b, 0x49, 0x44, 0xad, 0x23, 0x12, 0x17, 0x6f, 0xb1, - 0x6b, 0x74, 0x34, 0xba, 0x97, 0x8f, 0xad, 0x74, 0x96, 0x0e, 0x90, 0xd1, - 0x57, 0xa3, 0xbf, 0x60, 0x39, 0xe8, 0x66, 0x39, 0x38, 0xaa, 0xec, 0x92, - 0xa3, 0x75, 0xbb, 0x64, 0xcf, 0x1e, 0xc4, 0x65, 0x64, 0xc4, 0xbe, 0xd7, - 0x56, 0x55, 0x43, 0x00, 0xbe, 0x6f, 0x9c, 0x77, 0x51, 0x7c, 0x18, 0xe7, - 0xf8, 0x2d, 0x22, 0x6b, 0x32, 0xee, 0x1b, 0xdf, 0x23, 0xb0, 0xbb, 0xcf, - 0xc2, 0x3d, 0x47, 0xa5, 0xde, 0xf3, 0x91, 0x7f, 0xfc, 0x36, 0xe3, 0x89, - 0x1a, 0x3d, 0xc1, 0xef, 0xcc, 0x17, 0xf7, 0xf1, 0xb3, 0x75, 0x4d, 0x09, - 0x3b, 0x6e, 0xf8, 0xb6, 0x92, 0xbf, 0xaf, 0xdd, 0xbb, 0x2d, 0xc1, 0x8f, - 0x8c, 0xa7, 0x8d, 0xd9, 0xe8, 0x7b, 0xb5, 0xd3, 0x27, 0xe1, 0x63, 0x87, - 0x9c, 0x58, 0x21, 0xd3, 0xe7, 0x25, 0x1f, 0x12, 0x2b, 0x35, 0xe2, 0x63, - 0x21, 0x2f, 0x35, 0xfa, 0x77, 0x1e, 0x5b, 0x88, 0xb0, 0x77, 0x22, 0x9f, - 0x9f, 0xa6, 0x19, 0x91, 0x83, 0x8d, 0x38, 0xe9, 0x33, 0xf3, 0xfa, 0x5d, - 0xb6, 0xe2, 0x8d, 0xcf, 0x20, 0xce, 0xad, 0xb8, 0x48, 0x6b, 0xaf, 0x39, - 0xf0, 0xd7, 0x8d, 0x2d, 0xac, 0xf6, 0x85, 0x45, 0x4e, 0xf8, 0x76, 0xc6, - 0x48, 0x3a, 0x1e, 0x7a, 0x9c, 0x9f, 0x0f, 0x3f, 0x5e, 0x80, 0x92, 0x57, - 0xd0, 0xae, 0x93, 0x46, 0x17, 0x6a, 0x5f, 0xe0, 0xef, 0xc5, 0xfe, 0x65, - 0x86, 0xba, 0xd5, 0xde, 0x44, 0x8f, 0xda, 0xcf, 0x8a, 0xb0, 0xec, 0x35, - 0x72, 0x9d, 0x47, 0xeb, 0x3e, 0x3d, 0xc8, 0x84, 0xdb, 0xa7, 0xf7, 0xf4, - 0x3a, 0xeb, 0xd5, 0x7a, 0x72, 0x80, 0x58, 0xd6, 0x2e, 0x52, 0xbe, 0x4a, - 0x33, 0x4f, 0x1b, 0xcd, 0xe9, 0xdb, 0xf4, 0x3d, 0xdd, 0x9d, 0x31, 0xf3, - 0xc2, 0x9b, 0x76, 0x50, 0xf1, 0x5f, 0x27, 0x9d, 0x29, 0x05, 0x79, 0xcd, - 0x87, 0x6e, 0x05, 0xbd, 0xfc, 0xc3, 0xc8, 0x73, 0xf9, 0x7a, 0xa0, 0x93, - 0x96, 0x96, 0x10, 0x6b, 0xf1, 0x47, 0x7b, 0x64, 0x7c, 0x71, 0x9a, 0xe9, - 0x72, 0x80, 0xd7, 0x47, 0x43, 0xed, 0x1d, 0xe1, 0x1a, 0x74, 0x89, 0xa8, - 0x37, 0x1a, 0xf8, 0xd2, 0x44, 0x90, 0xed, 0x02, 0xb9, 0xf7, 0x70, 0x88, - 0x9f, 0xfd, 0xfd, 0x52, 0x1a, 0xfe, 0xb2, 0xd0, 0x11, 0x7e, 0x7e, 0x92, - 0xf1, 0x44, 0x9c, 0x3a, 0xa9, 0xb2, 0xd4, 0xc9, 0x76, 0x41, 0x27, 0xe3, - 0x89, 0xb1, 0xd0, 0xa8, 0x4f, 0xbc, 0x4b, 0xe4, 0xd4, 0x3c, 0x1c, 0x38, - 0xc0, 0x7c, 0x85, 0x77, 0xbd, 0xae, 0xde, 0xe5, 0x7e, 0xc7, 0x2f, 0x6a, - 0x38, 0x3f, 0xe2, 0x37, 0x2f, 0xdc, 0xc2, 0xef, 0x51, 0xcd, 0xcf, 0x30, - 0x76, 0x0e, 0x53, 0x7e, 0xbe, 0x83, 0xc7, 0x10, 0x63, 0x3b, 0x22, 0xca, - 0xe7, 0x8f, 0x50, 0xb6, 0x7a, 0x92, 0x7e, 0xbf, 0xea, 0xf4, 0x09, 0x3f, - 0xc2, 0x7d, 0x96, 0x39, 0xfd, 0x5d, 0xdc, 0xaf, 0x0f, 0x6d, 0xb7, 0x8e, - 0x09, 0x92, 0xff, 0x7b, 0x61, 0xea, 0x7c, 0x0e, 0xbe, 0x97, 0x1a, 0x15, - 0xa3, 0xd6, 0xa5, 0x3b, 0x24, 0xfd, 0xcf, 0x2f, 0x88, 0xb8, 0x5a, 0xbe, - 0x9f, 0x9f, 0x39, 0x87, 0x76, 0x2f, 0x98, 0x74, 0xd3, 0x96, 0xf4, 0x7e, - 0x23, 0x10, 0x26, 0xff, 0xcb, 0x88, 0x7d, 0x02, 0x56, 0x33, 0x2f, 0xd8, - 0xfb, 0x58, 0xbf, 0x3f, 0x87, 0xfb, 0xf8, 0xf3, 0x65, 0x9c, 0x07, 0x79, - 0x9c, 0x58, 0xaf, 0x11, 0xef, 0x02, 0xbd, 0x78, 0x20, 0x12, 0x12, 0xfc, - 0xf7, 0x08, 0xf3, 0x54, 0x87, 0xf0, 0x35, 0xf6, 0xa3, 0xad, 0x3d, 0xc4, - 0xd8, 0xc2, 0xbc, 0x30, 0xb1, 0x0f, 0xe7, 0xf1, 0x3e, 0x3f, 0xd3, 0x48, - 0xf2, 0x10, 0xc6, 0xd3, 0xc4, 0xdc, 0x81, 0x43, 0x13, 0xc4, 0xf3, 0x09, - 0xfc, 0xc1, 0xf3, 0x19, 0x42, 0x7d, 0xa7, 0x20, 0xa5, 0xf8, 0x1d, 0xc9, - 0x92, 0x1c, 0xf7, 0x5c, 0xd5, 0x4f, 0xd2, 0x4f, 0x75, 0x74, 0x44, 0xff, - 0x9e, 0x21, 0x0d, 0xe2, 0xd9, 0x5a, 0x56, 0x70, 0xdc, 0x4b, 0x77, 0x4b, - 0x3d, 0x74, 0x4f, 0xed, 0x69, 0xdd, 0x15, 0x76, 0x19, 0xeb, 0xf0, 0x74, - 0x2f, 0xdd, 0x59, 0xea, 0x20, 0xea, 0x0f, 0x8a, 0x3d, 0xe7, 0xbb, 0xa5, - 0x32, 0xbf, 0x3f, 0x31, 0x22, 0xfd, 0x3a, 0x0d, 0x1e, 0xb9, 0xeb, 0xc1, - 0x23, 0x1f, 0x08, 0x1e, 0xd9, 0x37, 0xb2, 0x36, 0x8f, 0xec, 0x52, 0xb6, - 0x48, 0x90, 0x3a, 0x15, 0x7f, 0xbc, 0xc4, 0xfc, 0xf1, 0x2c, 0xf3, 0xc7, - 0xe1, 0x36, 0xfc, 0x61, 0xb8, 0xf8, 0xe3, 0x88, 0xe0, 0x8f, 0x87, 0x46, - 0xd6, 0xe2, 0x8f, 0xc3, 0xfe, 0xb5, 0x7c, 0x4d, 0xe2, 0xb7, 0x3c, 0x2f, - 0xcc, 0xd9, 0xbb, 0x99, 0xd7, 0x6d, 0xaa, 0xcc, 0x23, 0x67, 0x61, 0x25, - 0x6a, 0xd0, 0xbf, 0x08, 0x9b, 0x6c, 0x55, 0xd8, 0xfc, 0x31, 0x11, 0xc3, - 0xba, 0x28, 0xf8, 0x8b, 0xd7, 0xff, 0x18, 0x72, 0xaa, 0xdc, 0x73, 0xd1, - 0x4d, 0x37, 0xa3, 0x98, 0x0b, 0x53, 0xcd, 0x05, 0xae, 0x75, 0xe9, 0xfa, - 0x90, 0x01, 0xbe, 0x7e, 0xe1, 0x03, 0xf0, 0xe8, 0x72, 0x4f, 0x20, 0x59, - 0xf8, 0xe6, 0x08, 0xf0, 0x5f, 0x7e, 0x99, 0x1c, 0xd7, 0x03, 0x7c, 0x3d, - 0x2c, 0x7e, 0xfb, 0x09, 0xb2, 0xf2, 0x8f, 0x88, 0x71, 0x64, 0x9e, 0xbc, - 0x59, 0x1a, 0xa6, 0x5b, 0xa5, 0xdd, 0xb4, 0x5a, 0x1a, 0xa1, 0x37, 0x45, - 0x2d, 0x0d, 0x99, 0x1b, 0xb9, 0x2a, 0xe6, 0xc8, 0xa0, 0x43, 0x61, 0x6e, - 0xb3, 0xb4, 0x9b, 0x56, 0x96, 0x34, 0x7f, 0x83, 0xb7, 0xc1, 0x2f, 0xf1, - 0x3e, 0x99, 0x2f, 0xd7, 0xca, 0x33, 0xc9, 0x26, 0x9e, 0x91, 0xf7, 0x80, - 0x57, 0xf2, 0xad, 0xb9, 0xbe, 0xdd, 0xa1, 0x18, 0x62, 0xf5, 0x82, 0xd4, - 0x81, 0xb8, 0x45, 0xc3, 0x9a, 0x3c, 0xe4, 0x07, 0x86, 0xfe, 0x2a, 0xaf, - 0xb9, 0x3c, 0x67, 0x36, 0xe2, 0x9c, 0x46, 0x18, 0x0f, 0x6f, 0x17, 0xf8, - 0x37, 0x61, 0x07, 0x22, 0x49, 0xaa, 0x5d, 0x30, 0x6c, 0xd4, 0x73, 0x4c, - 0xf3, 0xf3, 0x0c, 0xe5, 0x6f, 0xda, 0xe6, 0xe0, 0x3f, 0x37, 0xd6, 0xc5, - 0x5e, 0xf2, 0x63, 0xdc, 0x67, 0xac, 0xc3, 0x8d, 0xfd, 0x1a, 0xaa, 0xef, - 0xd7, 0x74, 0xf3, 0xb8, 0xa5, 0xec, 0xcd, 0xda, 0xdc, 0xae, 0xca, 0xed, - 0xaa, 0xd8, 0xfb, 0xe3, 0xeb, 0x4b, 0xd8, 0x77, 0x1e, 0xa6, 0xd5, 0x79, - 0xc8, 0x28, 0xfc, 0x21, 0x8d, 0xbd, 0xde, 0xd5, 0x65, 0x5c, 0x87, 0x4f, - 0xa4, 0xb1, 0xd7, 0xbb, 0xaa, 0xf6, 0x7a, 0x57, 0x97, 0x63, 0x42, 0x6f, - 0xe7, 0x4b, 0x4c, 0xf7, 0x92, 0x5f, 0xc5, 0x39, 0xee, 0x53, 0xbf, 0x2d, - 0xf4, 0x98, 0xf0, 0x69, 0xf7, 0xd9, 0x6b, 0xd3, 0xf0, 0x50, 0x0b, 0x0d, - 0x63, 0x02, 0x67, 0xa5, 0xf8, 0x99, 0xc9, 0xd2, 0x63, 0xff, 0x3b, 0x60, - 0x78, 0x46, 0x00, 0xf3, 0x9e, 0x30, 0x34, 0xef, 0xc1, 0xe6, 0x8e, 0xf9, - 0x19, 0x20, 0xf7, 0x14, 0xd9, 0x80, 0xfb, 0x16, 0x90, 0xf2, 0x4a, 0x06, - 0xad, 0xbc, 0x02, 0xa6, 0x09, 0x75, 0x88, 0xfe, 0xa6, 0xf5, 0x9f, 0xe5, - 0x60, 0xe3, 0x80, 0x4d, 0x40, 0x73, 0x9b, 0xa7, 0x90, 0x32, 0xf7, 0x0c, - 0xac, 0x6f, 0xb1, 0xae, 0x6d, 0xb4, 0x01, 0xef, 0xb1, 0x5e, 0x34, 0x85, - 0x85, 0x61, 0x49, 0x0f, 0x03, 0xb0, 0x7e, 0x00, 0xa5, 0x75, 0x50, 0x1d, - 0x01, 0x4f, 0xef, 0x02, 0x4d, 0x40, 0xf7, 0x39, 0x01, 0xdb, 0xa2, 0xce, - 0xfd, 0xca, 0xe0, 0xb5, 0xb2, 0x0d, 0xd0, 0x73, 0xab, 0x16, 0xf5, 0x88, - 0xc9, 0x83, 0xf2, 0x99, 0x93, 0x0a, 0x03, 0x19, 0x79, 0x81, 0x0d, 0x9a, - 0x17, 0xc0, 0xe1, 0x04, 0x4c, 0xeb, 0xc0, 0x32, 0x6a, 0x8d, 0x2e, 0xd0, - 0x3c, 0x1e, 0x16, 0x97, 0x7e, 0x90, 0x18, 0x03, 0x54, 0x8c, 0x05, 0xc8, - 0x97, 0x01, 0xb6, 0x29, 0x41, 0x7e, 0x05, 0xe5, 0x05, 0x90, 0xd9, 0x20, - 0xbf, 0x83, 0xca, 0x4e, 0x50, 0x5e, 0x04, 0xb2, 0x97, 0x08, 0x41, 0xfd, - 0x0c, 0xa4, 0x81, 0xec, 0xe6, 0x29, 0x22, 0x60, 0x7e, 0x52, 0x80, 0x10, - 0x43, 0x03, 0x3c, 0x1f, 0x10, 0x1b, 0xc6, 0x30, 0xf5, 0x31, 0x64, 0xe4, - 0x1b, 0x88, 0x19, 0x88, 0x7c, 0xc3, 0xce, 0x70, 0x40, 0x00, 0x16, 0x56, - 0xff, 0xff, 0x1f, 0x53, 0x61, 0x01, 0xa6, 0x53, 0xd0, 0x3a, 0xd6, 0xdf, - 0xff, 0x0f, 0x88, 0xb0, 0x30, 0xb4, 0xc0, 0xd7, 0x23, 0xe6, 0xc8, 0x83, - 0xca, 0xd0, 0x05, 0x40, 0x56, 0x1b, 0xbc, 0x4d, 0xc0, 0x02, 0xbe, 0xef, - 0x79, 0x01, 0xc3, 0x2f, 0x60, 0x99, 0xf5, 0xff, 0xff, 0x52, 0xb8, 0x5a, - 0x10, 0x00, 0x00, 0x19, 0x3f, 0x16, 0x21, 0xc4, 0x7d, 0x00, 0x00, 0x00 }; - -static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = { - 0x08001b68, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4, - 0x08001ab4, 0x08001ba4, 0x08001b28, 0x08001ba4, 0x08001a3c, 0x08001ba4, - 0x08001ba4, 0x08001ba4, 0x08001a48, 0x00000000, 0x08002abc, 0x08002b0c, - 0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c, - 0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8, - 0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 }; + 0x1f, 0x8b, 0x08, 0x08, 0xac, 0xfb, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xdc, 0x5b, 0x6b, 0x70, + 0x1b, 0xd7, 0x75, 0x3e, 0xfb, 0x00, 0x09, 0x91, 0x10, 0xb5, 0xa4, 0x60, + 0x1a, 0x96, 0x68, 0x07, 0x20, 0x57, 0x22, 0x6a, 0xb1, 0x29, 0x4c, 0x33, + 0x16, 0x9b, 0xc2, 0x12, 0x02, 0x50, 0xae, 0x26, 0xc3, 0x3a, 0x94, 0xcd, + 0xd8, 0x4a, 0xaa, 0xc9, 0x30, 0x00, 0xa5, 0xf4, 0x61, 0xb7, 0x92, 0xab, + 0xa9, 0x5d, 0xd7, 0xaa, 0x21, 0x92, 0x6a, 0xf5, 0x83, 0xe5, 0x2a, 0x16, + 0x43, 0xa9, 0xd3, 0x74, 0xc2, 0x12, 0x56, 0xac, 0x4e, 0x31, 0x85, 0xfc, + 0xd6, 0x38, 0xb1, 0xc9, 0x4a, 0x76, 0xeb, 0xf4, 0xe1, 0xa6, 0x33, 0xcd, + 0xa3, 0x9d, 0x36, 0xf6, 0xa8, 0x3f, 0xea, 0xe9, 0xd3, 0x33, 0x6e, 0xa7, + 0xea, 0xd8, 0x0e, 0xfa, 0x7d, 0x77, 0x77, 0x81, 0x25, 0x48, 0xbd, 0xfc, + 0xc8, 0x8f, 0x70, 0x06, 0xb3, 0x7b, 0xef, 0xde, 0xbd, 0xf7, 0xdc, 0xf3, + 0xf8, 0xce, 0x63, 0x2f, 0xfb, 0x44, 0x5a, 0xc4, 0xfb, 0x5b, 0x8b, 0x5f, + 0xfc, 0xfe, 0x5f, 0x2d, 0x7c, 0x7c, 0xf0, 0xe3, 0xfd, 0x22, 0xb7, 0xdc, + 0xa2, 0xb7, 0x86, 0x75, 0xf6, 0x1b, 0xf8, 0x45, 0xf1, 0xeb, 0xf7, 0xee, + 0x57, 0xfb, 0xb3, 0xf0, 0x7b, 0x13, 0x0f, 0xc7, 0xfe, 0x55, 0x44, 0xbb, + 0xc4, 0x98, 0xe0, 0x5f, 0xb5, 0x7a, 0xf9, 0xe7, 0x5c, 0x38, 0x7e, 0x89, + 0x67, 0x86, 0xbb, 0x9c, 0xa2, 0x97, 0x3f, 0x09, 0xeb, 0x69, 0x39, 0x94, + 0xb5, 0x25, 0x6c, 0xa4, 0xdf, 0x3c, 0x54, 0xb0, 0x45, 0x32, 0xe5, 0x2d, + 0xf1, 0x9c, 0xbc, 0x57, 0x2d, 0x46, 0x4d, 0x61, 0xff, 0x8d, 0xe9, 0x77, + 0xbf, 0xf6, 0xe2, 0xd6, 0xc4, 0x5b, 0xf3, 0x86, 0x84, 0xad, 0xf4, 0x19, + 0xb1, 0x36, 0x4b, 0xb8, 0x0b, 0xef, 0x7c, 0xb5, 0xf7, 0x3d, 0x91, 0x36, + 0x7f, 0xae, 0x37, 0xab, 0x2f, 0xf6, 0x4a, 0x71, 0x43, 0x3a, 0x2c, 0x7a, + 0x7a, 0xd3, 0xf7, 0xb3, 0x86, 0x35, 0x66, 0xa4, 0x2d, 0x59, 0xac, 0xc8, + 0xc8, 0xde, 0x69, 0x09, 0x87, 0xd3, 0x47, 0x9b, 0x9b, 0x37, 0x49, 0xd8, + 0x4c, 0x8f, 0x1d, 0xfa, 0x6d, 0xfb, 0xd1, 0xaa, 0x6e, 0xdb, 0xc9, 0x05, + 0x89, 0x0c, 0x9e, 0x1a, 0xc0, 0xf3, 0x72, 0x22, 0x29, 0xb2, 0x55, 0x74, + 0xbb, 0x18, 0x31, 0xec, 0xb0, 0x64, 0x2b, 0xb6, 0xe4, 0x2a, 0x22, 0x7f, + 0x5e, 0xd6, 0xe4, 0x94, 0xdd, 0x29, 0x0b, 0x7d, 0xef, 0x56, 0x33, 0xa0, + 0xe5, 0xcf, 0xec, 0xb1, 0x43, 0x53, 0x36, 0xe9, 0x9d, 0x6d, 0x76, 0xe9, + 0x9d, 0x6a, 0x2a, 0xd8, 0xa6, 0x4c, 0x94, 0xd9, 0x37, 0xa2, 0xb3, 0x2f, + 0x94, 0x7e, 0x68, 0xcd, 0x29, 0x3b, 0xe2, 0xf5, 0xed, 0xdc, 0x9e, 0xc5, + 0x7c, 0x93, 0x65, 0x8e, 0x3d, 0x93, 0x2a, 0xd8, 0x51, 0xaf, 0x3f, 0x79, + 0x5b, 0xd6, 0x8e, 0xa1, 0xbf, 0xcb, 0x7b, 0x76, 0xf2, 0xbe, 0x82, 0x6d, + 0x7b, 0xcf, 0xbe, 0x8a, 0xb9, 0x93, 0x5e, 0xff, 0x7d, 0xdb, 0x0a, 0x76, + 0x9f, 0xd7, 0x3f, 0xbd, 0x2d, 0x6b, 0xa7, 0xbc, 0xfe, 0xe4, 0xee, 0x82, + 0x3d, 0xe0, 0xf5, 0x9f, 0xbd, 0x3d, 0x6b, 0x0f, 0x7a, 0xfd, 0x0f, 0x6d, + 0x2d, 0xd8, 0x69, 0xf4, 0x1f, 0x6d, 0xd6, 0x37, 0x59, 0x72, 0xa4, 0x1c, + 0xc7, 0x2f, 0x83, 0x67, 0x43, 0xe8, 0xdb, 0x89, 0xdf, 0x30, 0x7e, 0xbf, + 0xb8, 0x4e, 0xda, 0x46, 0x70, 0xfd, 0xc6, 0x46, 0x97, 0x77, 0xe0, 0x91, + 0x13, 0x96, 0x37, 0x8c, 0x98, 0xbc, 0xd8, 0xfb, 0x06, 0x78, 0x68, 0xc9, + 0x99, 0x8a, 0x68, 0x23, 0xbd, 0x31, 0xf0, 0x2e, 0x2a, 0x4f, 0x56, 0x5a, + 0xc5, 0x78, 0xcc, 0x00, 0x6f, 0x3e, 0x2f, 0xf9, 0x68, 0x58, 0xda, 0xe7, + 0x34, 0xe9, 0xee, 0x0f, 0x4b, 0xc6, 0x52, 0x72, 0x13, 0x7d, 0x26, 0x2a, + 0xc6, 0x5c, 0x66, 0xbd, 0x2e, 0x9b, 0xac, 0x9c, 0x14, 0xc1, 0xbb, 0xef, + 0x51, 0x27, 0xf1, 0x2c, 0x2e, 0xb9, 0xe9, 0x9b, 0x65, 0xcc, 0x22, 0x5d, + 0x3b, 0x6f, 0x74, 0xd7, 0x0a, 0x6b, 0xd9, 0x13, 0x23, 0x72, 0xc4, 0x89, + 0x68, 0xb9, 0x13, 0xdb, 0x24, 0x9b, 0x92, 0x28, 0xde, 0x8b, 0xe5, 0xf1, + 0xa4, 0x54, 0x1e, 0x91, 0x29, 0x47, 0xb4, 0xac, 0x43, 0x7e, 0x76, 0xe2, + 0x79, 0x9b, 0x1a, 0x8b, 0xbe, 0x2e, 0x43, 0xcd, 0x1d, 0x46, 0xbf, 0x85, + 0xfe, 0x0e, 0x6d, 0x48, 0xcd, 0xa1, 0xfa, 0xe3, 0x93, 0x12, 0x91, 0xc7, + 0xcb, 0x51, 0x6f, 0x6c, 0xb5, 0x9a, 0x4d, 0x59, 0x18, 0x37, 0x22, 0x93, + 0x4e, 0x54, 0xc6, 0x70, 0x9d, 0x70, 0xb8, 0x7e, 0x0c, 0x3a, 0xf5, 0xda, + 0xa1, 0xfc, 0xac, 0x9a, 0x2f, 0x6e, 0xa4, 0x39, 0x5f, 0x17, 0xc6, 0x4d, + 0x80, 0x2e, 0x4d, 0x4c, 0x25, 0xcb, 0x8c, 0xe4, 0xa7, 0x35, 0xe8, 0x1b, + 0xae, 0x8a, 0xaf, 0x43, 0xa0, 0xdf, 0x14, 0xbb, 0x5f, 0x93, 0x02, 0x64, + 0x55, 0xb4, 0xd0, 0x2e, 0x9f, 0xd5, 0xb3, 0x4e, 0xb3, 0xe4, 0xcc, 0xb8, + 0x18, 0x33, 0x4a, 0x97, 0x64, 0x12, 0xef, 0xe8, 0x36, 0xc7, 0x5c, 0xc4, + 0xbe, 0xc7, 0x94, 0x1c, 0x9a, 0xd2, 0x45, 0x3d, 0x57, 0xe9, 0x14, 0x7d, + 0x6e, 0x8f, 0xbc, 0x3c, 0x2d, 0x96, 0x91, 0x7e, 0xb7, 0x9a, 0xb5, 0xa7, + 0xf4, 0xec, 0x13, 0xa6, 0x84, 0x66, 0x34, 0x99, 0xb2, 0x13, 0xb0, 0x80, + 0xa3, 0xfa, 0x8e, 0xca, 0x59, 0x8c, 0xe3, 0x7b, 0x18, 0x57, 0xd6, 0xc1, + 0x57, 0xde, 0x6f, 0xb1, 0x74, 0xa5, 0xcf, 0x1c, 0x03, 0x19, 0x60, 0x1f, + 0x4f, 0x3a, 0x90, 0x89, 0x92, 0x51, 0x1c, 0x32, 0x7a, 0x15, 0x32, 0x1a, + 0x80, 0x6c, 0x52, 0xf2, 0x52, 0xa5, 0x4f, 0x9e, 0xaf, 0x24, 0xe5, 0x39, + 0xe8, 0xeb, 0xb3, 0x95, 0xb8, 0x3c, 0x53, 0xe9, 0x92, 0xa7, 0x2b, 0x31, + 0x79, 0x4a, 0xc9, 0x2d, 0x07, 0xdb, 0x50, 0xb2, 0x0c, 0x5f, 0x9f, 0x96, + 0x70, 0x27, 0xe4, 0xd1, 0x01, 0xfd, 0x69, 0x87, 0x6e, 0x7e, 0xa5, 0x37, + 0x2c, 0xb3, 0xbd, 0x92, 0x59, 0x8f, 0xfe, 0x9b, 0xd2, 0xa6, 0xe2, 0x91, + 0x89, 0xe7, 0x93, 0xd3, 0x21, 0xc9, 0x59, 0x8f, 0xcb, 0x85, 0x19, 0x53, + 0x26, 0x2b, 0xdb, 0x6f, 0x72, 0x65, 0xc6, 0xf6, 0xbc, 0x9c, 0x9f, 0x69, + 0xc2, 0xb3, 0x79, 0x79, 0x79, 0xb3, 0x2e, 0x13, 0xb3, 0x6f, 0x89, 0x09, + 0x1e, 0x0e, 0x29, 0x79, 0x3f, 0x2e, 0xff, 0xfc, 0x27, 0x22, 0x23, 0xe0, + 0x8b, 0xde, 0xff, 0xef, 0xd5, 0x8c, 0x05, 0x7e, 0xf4, 0xf7, 0x41, 0x3f, + 0x74, 0x5c, 0x29, 0xcf, 0x38, 0xc6, 0x98, 0x5a, 0xce, 0x39, 0x0d, 0x9b, + 0x6a, 0xd5, 0xb2, 0xc7, 0x45, 0x0a, 0xc7, 0xab, 0x52, 0x48, 0x85, 0xe4, + 0x01, 0xab, 0x2a, 0x43, 0xa9, 0x26, 0x39, 0x60, 0x75, 0xca, 0x44, 0xdf, + 0xcf, 0x68, 0x3e, 0x96, 0x7d, 0xa5, 0x92, 0xc6, 0x3d, 0xfb, 0x44, 0x66, + 0xd5, 0xbd, 0xdb, 0x5f, 0xac, 0x84, 0x24, 0x13, 0x2d, 0xc6, 0x4c, 0xb9, + 0xa0, 0xb9, 0xb4, 0xed, 0xf4, 0x9f, 0x41, 0x5e, 0x63, 0xc0, 0x90, 0x84, + 0xd2, 0xa5, 0xfc, 0xf4, 0x9a, 0x8b, 0x19, 0xd5, 0x1d, 0x52, 0x7a, 0x6a, + 0xa4, 0x4d, 0xd2, 0x31, 0xa6, 0xa5, 0xa3, 0xd2, 0xad, 0xec, 0x64, 0x00, + 0x63, 0x06, 0xb5, 0xbb, 0x2b, 0x94, 0x37, 0xee, 0xcb, 0xa4, 0x75, 0x03, + 0xc6, 0x9a, 0xb8, 0x66, 0x3c, 0x9a, 0x83, 0x74, 0x72, 0x2e, 0xd2, 0xc9, + 0xeb, 0xde, 0x00, 0x9d, 0xfb, 0x6a, 0xf7, 0xb3, 0x81, 0xfb, 0x62, 0xe5, + 0xd7, 0x5b, 0x5c, 0xfa, 0xc8, 0xd7, 0x41, 0x99, 0x98, 0x7e, 0xc8, 0x5b, + 0x0b, 0xf7, 0x65, 0xae, 0xb1, 0x00, 0x3e, 0xa9, 0x91, 0x57, 0x58, 0xab, + 0x18, 0x58, 0xeb, 0x70, 0x60, 0xad, 0xc3, 0x81, 0xb5, 0x8a, 0xe0, 0xad, + 0xac, 0xd3, 0x81, 0x33, 0x79, 0xc2, 0xbc, 0x1c, 0xc5, 0x9c, 0x6f, 0x88, + 0x91, 0xa6, 0x2d, 0xf8, 0x36, 0xf9, 0x07, 0x18, 0x9f, 0x96, 0x73, 0x0e, + 0x78, 0x73, 0x3c, 0x24, 0x77, 0xa9, 0x71, 0xff, 0xb1, 0xc6, 0xa5, 0x31, + 0xf8, 0x2c, 0x2c, 0xbb, 0xa2, 0xbc, 0xf7, 0x9f, 0x99, 0xe0, 0x37, 0xdb, + 0x93, 0x37, 0xb8, 0x6d, 0xde, 0x9f, 0xf5, 0xf6, 0xd2, 0xee, 0xbe, 0x57, + 0x79, 0x53, 0x61, 0xc6, 0x62, 0x85, 0xb6, 0x2d, 0x29, 0xc3, 0x96, 0xfd, + 0x43, 0xa9, 0x4e, 0x99, 0xb4, 0xb4, 0xd4, 0x44, 0xb2, 0x99, 0xfc, 0xcf, + 0xe8, 0x76, 0x2b, 0xec, 0x47, 0xe2, 0x3a, 0x71, 0x51, 0xed, 0xeb, 0x5b, + 0x1e, 0xfd, 0x16, 0xdb, 0x23, 0xba, 0xdd, 0xd1, 0xd0, 0x4f, 0xfd, 0xff, + 0x4b, 0xdc, 0xd3, 0x06, 0xfa, 0x75, 0x77, 0xed, 0xbf, 0x42, 0x9b, 0x58, + 0x15, 0xf1, 0xda, 0xfe, 0xf3, 0xff, 0x32, 0x96, 0xb7, 0x8f, 0x6d, 0x5c, + 0xde, 0xf6, 0x6d, 0x29, 0x88, 0x73, 0xdc, 0x2b, 0x6c, 0xd8, 0xa6, 0xfe, + 0x85, 0x40, 0x6b, 0x0a, 0x36, 0xdc, 0xec, 0xd1, 0xf0, 0xba, 0x47, 0x03, + 0x68, 0xc5, 0xb8, 0x89, 0x0a, 0xdf, 0x51, 0xa2, 0x6c, 0x68, 0x93, 0xf7, + 0xfe, 0xfd, 0x5a, 0xf5, 0xfc, 0x0d, 0x83, 0xeb, 0xf8, 0x57, 0xd1, 0x86, + 0x60, 0x67, 0x93, 0xb3, 0xa6, 0xe4, 0x53, 0x31, 0x65, 0x0f, 0xf9, 0x54, + 0x1d, 0x3f, 0x26, 0xa7, 0x1b, 0xf1, 0x83, 0xef, 0x11, 0x3f, 0x5c, 0xec, + 0x98, 0x98, 0x25, 0x8e, 0xd4, 0x71, 0xe3, 0xc8, 0xb4, 0x8f, 0x25, 0x9c, + 0x9b, 0x18, 0xe2, 0xe3, 0x07, 0xdf, 0x23, 0x7e, 0x18, 0x90, 0x15, 0xe7, + 0xf4, 0xd7, 0x9f, 0x6a, 0x98, 0x7b, 0x4a, 0x61, 0x93, 0x8b, 0xcb, 0x6f, + 0x06, 0x70, 0xbe, 0x0b, 0x18, 0x1d, 0x85, 0xfc, 0x7c, 0x8c, 0x26, 0x76, + 0xc6, 0x80, 0xeb, 0xe0, 0x91, 0xc2, 0xe4, 0x08, 0x70, 0xcc, 0xf4, 0x30, + 0x35, 0xec, 0x61, 0x6a, 0x04, 0x78, 0xca, 0xb6, 0xe5, 0xb5, 0xa3, 0x5e, + 0x3b, 0x86, 0x36, 0xfc, 0xef, 0x1c, 0x6d, 0xec, 0xb5, 0x43, 0xe3, 0xb3, + 0x0a, 0xa7, 0x89, 0xf1, 0xc0, 0x0a, 0xe2, 0x2c, 0xf1, 0xb6, 0x4b, 0x16, + 0xca, 0x58, 0xaf, 0x86, 0x69, 0x94, 0x47, 0x90, 0x1e, 0xd2, 0xb2, 0x46, + 0xf4, 0xc7, 0xdc, 0xfd, 0xe8, 0xe9, 0xcf, 0xeb, 0xd2, 0xc2, 0x7d, 0x90, + 0xee, 0x1b, 0x41, 0x2b, 0xf7, 0xf6, 0xa3, 0xa4, 0x95, 0xeb, 0x35, 0xd2, + 0x7b, 0x1a, 0xf4, 0x66, 0x80, 0xb7, 0xa2, 0x8d, 0xf6, 0x8e, 0x82, 0xde, + 0x11, 0x60, 0xf1, 0x30, 0xb0, 0x78, 0x27, 0xb0, 0x78, 0x08, 0x58, 0x9c, + 0x06, 0x0e, 0x0f, 0x02, 0x87, 0x07, 0x80, 0xc3, 0x29, 0xec, 0x2b, 0x2a, + 0xf3, 0xc0, 0xe5, 0x79, 0xe0, 0xf3, 0x3c, 0xe4, 0x35, 0x31, 0x27, 0xda, + 0x17, 0xb0, 0xfe, 0x63, 0x33, 0x89, 0xd3, 0xd0, 0xcd, 0x58, 0x51, 0x87, + 0x3d, 0xa5, 0x06, 0xa1, 0x23, 0x49, 0x29, 0x55, 0x46, 0xa5, 0x40, 0x3f, + 0xb6, 0xb9, 0x07, 0xb6, 0x0b, 0xfb, 0x89, 0xf9, 0x71, 0xd3, 0x5a, 0xef, + 0xfa, 0xf7, 0x22, 0xf6, 0x1f, 0x83, 0x27, 0x89, 0xb8, 0xc8, 0xb0, 0xe4, + 0x9d, 0x1e, 0x2b, 0xab, 0x27, 0x31, 0x8e, 0xed, 0xb8, 0xb6, 0xf7, 0x78, + 0x42, 0x1b, 0x3f, 0xce, 0x3d, 0x4d, 0x03, 0xe3, 0xaa, 0x32, 0x95, 0xa2, + 0xad, 0x56, 0xe5, 0x54, 0x2a, 0x31, 0x58, 0x94, 0x56, 0x39, 0x12, 0x9d, + 0x56, 0xfe, 0xcd, 0x4c, 0x1f, 0x53, 0xfa, 0x51, 0xb0, 0x71, 0x2d, 0x77, + 0x6b, 0xf9, 0xe3, 0xf4, 0x3b, 0x3d, 0xf8, 0x85, 0x40, 0x0b, 0xe7, 0x37, + 0x65, 0x68, 0x40, 0xb4, 0x7d, 0xbd, 0x45, 0xa0, 0x62, 0xc2, 0x3a, 0x87, + 0x95, 0x73, 0xd3, 0x3d, 0xb1, 0x9c, 0x6e, 0xca, 0x98, 0xa9, 0xc9, 0x04, + 0xec, 0x65, 0x28, 0xf5, 0x7f, 0xd5, 0x23, 0x51, 0x3e, 0x6f, 0x96, 0xdf, + 0x51, 0x38, 0x8b, 0xb5, 0x4b, 0xb3, 0x58, 0x37, 0x04, 0xfe, 0x71, 0x5d, + 0xce, 0x83, 0x36, 0x30, 0xcf, 0xb4, 0x13, 0xa7, 0x8b, 0xb2, 0x1d, 0x76, + 0xb7, 0x4e, 0xb2, 0x7d, 0x4d, 0x92, 0x19, 0x89, 0xcb, 0xc4, 0xcc, 0x76, + 0xe0, 0x1e, 0x64, 0x60, 0xb7, 0x48, 0x7e, 0x34, 0x2e, 0x5f, 0x9e, 0x61, + 0x5f, 0x06, 0xfb, 0x4f, 0x1c, 0xcd, 0x08, 0xf7, 0x1f, 0x52, 0xfb, 0x8a, + 0xeb, 0x19, 0x39, 0xe0, 0xbc, 0xa4, 0xbb, 0x76, 0xe9, 0xb6, 0xf7, 0x42, + 0x1e, 0xa7, 0xc0, 0xef, 0xbc, 0x63, 0xcb, 0x02, 0xfc, 0x4a, 0xee, 0x38, + 0x70, 0xd5, 0x6e, 0x03, 0x06, 0x26, 0xce, 0xd2, 0x3e, 0x0c, 0xc4, 0x5a, + 0x25, 0xc5, 0xeb, 0x2e, 0x39, 0x3e, 0xa3, 0xcb, 0xb3, 0xb7, 0xc5, 0xd1, + 0x06, 0xd6, 0xa6, 0x12, 0x67, 0xc6, 0xf4, 0x2e, 0xb9, 0xb5, 0x23, 0x86, + 0xf7, 0x52, 0x5a, 0xde, 0xf9, 0x37, 0xf2, 0xf2, 0x64, 0x5c, 0xe7, 0x58, + 0x5d, 0x72, 0x29, 0x03, 0x3a, 0x56, 0xc4, 0xf8, 0x7f, 0x40, 0x7f, 0x97, + 0xcc, 0x21, 0xbe, 0x99, 0x03, 0x4d, 0xd9, 0x14, 0xb1, 0x30, 0x71, 0x72, + 0x49, 0x07, 0x66, 0xcd, 0x41, 0x37, 0x47, 0x11, 0x3f, 0xcc, 0xfc, 0x37, + 0xc6, 0xc4, 0x21, 0xd3, 0x1e, 0x6b, 0x02, 0xf8, 0x92, 0xe9, 0xe2, 0x3d, + 0xe7, 0xb4, 0xe5, 0x94, 0x43, 0x1d, 0x8a, 0xcb, 0xe3, 0x15, 0xbe, 0xd7, + 0x73, 0xf6, 0x69, 0xb1, 0xe5, 0x41, 0xe7, 0x7f, 0x30, 0xfe, 0x1d, 0xc4, + 0x9e, 0x96, 0x94, 0x20, 0xb7, 0x02, 0x78, 0x99, 0x89, 0xb9, 0xed, 0x89, + 0xb9, 0xc4, 0xd9, 0x0b, 0x3a, 0xef, 0xed, 0xe2, 0x82, 0x7e, 0xb3, 0x48, + 0x07, 0xf9, 0x99, 0x02, 0x2f, 0x6d, 0x4b, 0xd7, 0x37, 0x7b, 0xf1, 0x16, + 0x6d, 0xc0, 0x06, 0x7d, 0xa6, 0x2c, 0xf4, 0x07, 0x6d, 0x80, 0x7e, 0xd6, + 0xb7, 0x81, 0x44, 0x6c, 0x49, 0xd7, 0xf1, 0xdc, 0x94, 0x63, 0xaa, 0xad, + 0x81, 0xd6, 0x44, 0x8c, 0xfb, 0x9b, 0x2c, 0x27, 0xe5, 0x71, 0x87, 0xe3, + 0xc1, 0xe7, 0xe9, 0x88, 0x37, 0x1e, 0xf1, 0x8e, 0xc3, 0x98, 0x29, 0x09, + 0x9a, 0x5d, 0xbb, 0x58, 0x98, 0x8e, 0xaa, 0x67, 0x47, 0x1c, 0x37, 0x36, + 0xd2, 0x11, 0x3f, 0xcd, 0x23, 0x7e, 0xca, 0x29, 0x1b, 0xb1, 0x32, 0x88, + 0xaf, 0xe1, 0x67, 0x5d, 0xfb, 0x28, 0x95, 0x49, 0xcb, 0x3d, 0xa0, 0x2f, + 0x51, 0x04, 0x31, 0xc7, 0x74, 0xb8, 0xeb, 0xec, 0x80, 0x14, 0x19, 0x63, + 0x9d, 0x33, 0x1e, 0x91, 0xb1, 0x12, 0xfd, 0x1b, 0x7e, 0x8e, 0x6d, 0x31, + 0xa6, 0xcf, 0x28, 0xdf, 0xd3, 0x03, 0x3d, 0x80, 0x5f, 0x4a, 0xb5, 0x8b, + 0xeb, 0x07, 0xf7, 0x40, 0x9e, 0xc3, 0x90, 0x7b, 0x5a, 0xc6, 0x4f, 0x8c, + 0x53, 0xa7, 0x93, 0x25, 0x49, 0x24, 0x8f, 0xc8, 0x16, 0x6b, 0x01, 0xbe, + 0x30, 0x33, 0x5a, 0xdd, 0xae, 0xa7, 0xf9, 0xce, 0xa3, 0x78, 0x07, 0xd7, + 0xd2, 0xb8, 0x3c, 0x50, 0x61, 0xdf, 0x9d, 0x86, 0xb4, 0xc0, 0x56, 0x06, + 0xf6, 0x78, 0x76, 0x80, 0xf9, 0x4c, 0x7f, 0xbe, 0x71, 0x6f, 0x3e, 0x8e, + 0xe3, 0x18, 0xbe, 0x53, 0x9f, 0x77, 0x07, 0x7d, 0x1b, 0xb0, 0x64, 0x87, + 0x5e, 0xdd, 0x1e, 0xc2, 0xf3, 0x53, 0x03, 0xbc, 0xc7, 0x3c, 0xf0, 0x6d, + 0x96, 0x3d, 0x8c, 0xb1, 0xa3, 0x98, 0x73, 0x8d, 0x64, 0x3b, 0x7d, 0x7a, + 0xa9, 0x03, 0x8c, 0x3f, 0xd8, 0x8e, 0xae, 0x77, 0x79, 0xff, 0x25, 0xc3, + 0xd5, 0xc9, 0x11, 0xb4, 0x69, 0x7f, 0x07, 0x25, 0xe7, 0x24, 0xb0, 0x4f, + 0xf0, 0xb6, 0x32, 0xe1, 0xed, 0x11, 0xfc, 0x1f, 0x39, 0x0c, 0x3e, 0x48, + 0xd1, 0xe5, 0x0d, 0xf9, 0x42, 0x9e, 0xfc, 0x16, 0x74, 0xff, 0x61, 0x8c, + 0x81, 0x7f, 0x50, 0x3c, 0x58, 0xea, 0x70, 0x63, 0xd1, 0x44, 0x31, 0xc3, + 0xfc, 0xa9, 0x83, 0x98, 0x07, 0xfc, 0xa9, 0x40, 0xb1, 0x30, 0xf7, 0x92, + 0xbe, 0x86, 0xf4, 0xc6, 0x97, 0x0c, 0x83, 0xed, 0xe4, 0x12, 0x74, 0xb8, + 0x04, 0xf9, 0x64, 0xfb, 0x68, 0xb3, 0x36, 0xe4, 0x31, 0x63, 0x50, 0x5f, + 0x4b, 0x88, 0x05, 0xf3, 0xce, 0x16, 0xeb, 0x5e, 0xf2, 0xcd, 0xb2, 0xe4, + 0x69, 0x27, 0x88, 0x1d, 0x3b, 0x30, 0x94, 0x7a, 0x18, 0x85, 0x1e, 0x98, + 0xf0, 0xc9, 0x31, 0xc8, 0xfc, 0xc5, 0x0e, 0x77, 0x2f, 0xbc, 0x37, 0x65, + 0xde, 0xc2, 0x9a, 0xce, 0xef, 0xaf, 0x73, 0xfb, 0x78, 0xcf, 0xb8, 0xc8, + 0x97, 0xab, 0x4f, 0x3b, 0xe5, 0xdb, 0x28, 0xd3, 0x43, 0xd8, 0x0b, 0xfb, + 0x71, 0x2d, 0x1d, 0x94, 0x71, 0xd0, 0x56, 0x18, 0xd8, 0x14, 0x3b, 0x8f, + 0xf1, 0x39, 0xe0, 0x79, 0xd1, 0xe4, 0xb3, 0x8b, 0x5a, 0xfd, 0x1d, 0xc4, + 0x5c, 0x36, 0xfd, 0xd9, 0x92, 0xf6, 0x85, 0xca, 0xcb, 0x5a, 0xb6, 0x74, + 0x51, 0xcb, 0x41, 0x4f, 0x4a, 0x0e, 0x73, 0x06, 0xda, 0x8f, 0x85, 0xb5, + 0x13, 0xb1, 0xb7, 0xf5, 0x9e, 0xf8, 0x02, 0xb0, 0x60, 0x2f, 0x6c, 0x3a, + 0x67, 0xee, 0x94, 0x02, 0xb0, 0x35, 0x7f, 0x62, 0x0b, 0xec, 0x2d, 0x1e, + 0xa0, 0x8b, 0x78, 0x56, 0xa4, 0x4f, 0xd5, 0x76, 0x38, 0x52, 0x6c, 0x4a, + 0x13, 0xd7, 0x36, 0x41, 0x77, 0xd0, 0x57, 0xae, 0xeb, 0xdf, 0x1d, 0x2b, + 0x68, 0x45, 0x7e, 0x39, 0xb0, 0x9c, 0xde, 0x92, 0x5c, 0x99, 0xde, 0x1d, + 0x35, 0x7a, 0x89, 0x19, 0xc0, 0x7f, 0xd8, 0xcd, 0x4b, 0xd0, 0xdf, 0xe7, + 0x1d, 0xe0, 0xbf, 0x03, 0xfc, 0x87, 0x4d, 0x3d, 0x03, 0xdd, 0x7b, 0xda, + 0x81, 0x0f, 0x70, 0xe0, 0x03, 0x1c, 0xf8, 0x00, 0x27, 0x0b, 0x39, 0x11, + 0xe7, 0xe9, 0x43, 0x76, 0xd7, 0x7c, 0x9e, 0x1b, 0x37, 0xdd, 0xe0, 0xc5, + 0x22, 0xa3, 0x88, 0x45, 0x36, 0xc8, 0x44, 0xf2, 0x7a, 0xec, 0xad, 0x05, + 0xd7, 0x56, 0x5c, 0xb1, 0x46, 0xf2, 0x76, 0xcf, 0x4e, 0x1e, 0x06, 0x5d, + 0x88, 0xbf, 0x93, 0x3f, 0x0d, 0x3d, 0x6c, 0x02, 0x3d, 0x3f, 0xe5, 0xc5, + 0x2c, 0x0f, 0x9a, 0xae, 0x1e, 0xb6, 0xa2, 0xef, 0x93, 0xe8, 0x6b, 0xc5, + 0x98, 0x03, 0x18, 0xc3, 0x98, 0xa7, 0xcd, 0xeb, 0x0b, 0x8e, 0x63, 0xec, + 0xf3, 0x19, 0xac, 0x95, 0xc0, 0xb8, 0x36, 0xcc, 0xdd, 0x85, 0x31, 0xdb, + 0x30, 0xe6, 0x46, 0xb4, 0x19, 0x33, 0x6f, 0x44, 0xfb, 0x13, 0x0d, 0xef, + 0x7c, 0x0c, 0x7d, 0xb7, 0x37, 0xf4, 0x9d, 0x43, 0x1f, 0xf2, 0x50, 0xeb, + 0xbc, 0xf7, 0x5e, 0x11, 0xed, 0xce, 0x86, 0x31, 0xaf, 0xa2, 0x0f, 0x71, + 0xaf, 0xf5, 0x2d, 0x5c, 0x91, 0x7f, 0x5a, 0xa4, 0xc9, 0x7f, 0xc6, 0xb8, + 0x37, 0x8e, 0xfe, 0x90, 0x17, 0xbb, 0xfe, 0xa6, 0x09, 0xbd, 0xd3, 0x86, + 0x9c, 0xdf, 0x30, 0xdd, 0x58, 0xef, 0x4e, 0xcb, 0xd5, 0x43, 0xbf, 0xfd, + 0x70, 0x43, 0x9b, 0x63, 0x17, 0x1a, 0xfa, 0xfe, 0xa5, 0xa1, 0xfd, 0xdd, + 0xd0, 0xca, 0x77, 0x06, 0xdb, 0x97, 0xf7, 0x15, 0x3a, 0x96, 0xb7, 0xed, + 0xa6, 0x95, 0xef, 0xe8, 0xeb, 0x96, 0xf7, 0xdd, 0xb8, 0xbe, 0x61, 0x0c, + 0x74, 0x2a, 0x8a, 0x1c, 0xc9, 0x1f, 0x1f, 0xbe, 0xce, 0x7d, 0x4e, 0xfe, + 0x36, 0xea, 0x92, 0xda, 0x3a, 0xda, 0x3a, 0xe4, 0xb0, 0xa4, 0xc1, 0x9e, + 0x2c, 0x3d, 0xfd, 0xb2, 0x96, 0x83, 0x4e, 0x65, 0x2b, 0xfe, 0x7c, 0xb4, + 0xd9, 0xc6, 0xdc, 0xdc, 0xcf, 0xc9, 0x19, 0x2b, 0x45, 0xa0, 0x37, 0xf7, + 0xd0, 0x27, 0x1d, 0x2d, 0x4a, 0xdd, 0x3e, 0xbb, 0xf5, 0x4b, 0xd9, 0xe7, + 0xed, 0x1e, 0x46, 0x1d, 0x06, 0x9d, 0x55, 0x19, 0x49, 0x35, 0xd3, 0xc7, + 0x78, 0xd8, 0x45, 0xdc, 0xa9, 0x56, 0x8d, 0xcd, 0x55, 0xd9, 0x9f, 0x7a, + 0xa7, 0x2a, 0x0a, 0xf3, 0x06, 0x15, 0xee, 0xc4, 0xf5, 0x1e, 0xc8, 0xc8, + 0x42, 0x6e, 0x82, 0x7c, 0x3a, 0x4a, 0x9f, 0x74, 0x90, 0xf1, 0xc9, 0xa3, + 0x2e, 0xa6, 0x12, 0x77, 0xd0, 0x46, 0x5e, 0x96, 0x3f, 0xce, 0xf5, 0x71, + 0x2d, 0x11, 0xc7, 0x47, 0x95, 0x4f, 0xc9, 0x5b, 0x9c, 0x77, 0x35, 0x6c, + 0x3c, 0x6b, 0x32, 0xa6, 0x33, 0xed, 0xd3, 0xf0, 0x6f, 0x7c, 0xc6, 0x58, + 0xe1, 0x34, 0xe3, 0x92, 0x00, 0x56, 0x6d, 0x35, 0xe0, 0x32, 0x8b, 0xcb, + 0xf7, 0xb5, 0x81, 0x79, 0xc4, 0x55, 0xec, 0x75, 0x75, 0x2c, 0xea, 0xd1, + 0xaf, 0x6c, 0xdb, 0xbb, 0x6a, 0xb6, 0xed, 0xeb, 0xde, 0x6a, 0x39, 0xf8, + 0xf7, 0x95, 0x2c, 0x9e, 0xaa, 0x24, 0x8e, 0x15, 0x61, 0x4b, 0x8b, 0x2a, + 0xef, 0xf6, 0xe5, 0xc2, 0x18, 0x27, 0x71, 0x72, 0x1e, 0x6f, 0x8e, 0xab, + 0x1c, 0x83, 0xf9, 0x45, 0x55, 0x76, 0xa4, 0x5a, 0xa3, 0xe4, 0x43, 0x46, + 0xff, 0x76, 0x88, 0x31, 0xc3, 0xa2, 0x43, 0x9e, 0xa5, 0xf0, 0x3c, 0x05, + 0x4c, 0xf8, 0x27, 0xc9, 0x45, 0xd9, 0xf7, 0x76, 0x75, 0x01, 0x71, 0x95, + 0x8a, 0x8f, 0x94, 0xbf, 0x67, 0x7c, 0xb7, 0x1f, 0xfc, 0x22, 0x4f, 0x47, + 0xc0, 0x67, 0x3f, 0x06, 0x78, 0x8d, 0x75, 0x15, 0x59, 0x1e, 0x07, 0x8b, + 0x3c, 0x50, 0x7e, 0x19, 0x73, 0xea, 0x6e, 0xac, 0xc2, 0x3c, 0xdc, 0x66, + 0x7f, 0x47, 0x88, 0xb1, 0x9c, 0xeb, 0xeb, 0x0d, 0xac, 0x87, 0xdc, 0xbe, + 0xfc, 0x8f, 0x2a, 0x6e, 0x2a, 0x28, 0x79, 0x20, 0x86, 0xaa, 0xf0, 0x19, + 0xfb, 0xc2, 0x5e, 0xec, 0x1c, 0xf1, 0x62, 0x65, 0xcb, 0x8b, 0x95, 0x49, + 0x07, 0x6b, 0x6f, 0x7e, 0x5c, 0x40, 0x99, 0x2d, 0x1d, 0xd2, 0x37, 0x33, + 0x2e, 0x68, 0x93, 0xd5, 0xe3, 0x02, 0x9f, 0xa6, 0x6d, 0xa0, 0x89, 0x71, + 0x9e, 0xaa, 0xbd, 0x74, 0xb8, 0xf5, 0x1e, 0xd2, 0xe0, 0xfb, 0x47, 0xe5, + 0x87, 0x8f, 0xc2, 0xe5, 0x61, 0x6f, 0x69, 0xd0, 0xba, 0x53, 0xb2, 0xd3, + 0xdb, 0x3c, 0x7f, 0xcb, 0x1c, 0x80, 0xf1, 0xb7, 0xab, 0xb3, 0xd9, 0xd4, + 0x84, 0x3f, 0x4f, 0x27, 0x3c, 0x64, 0xa0, 0x2e, 0xc4, 0xb5, 0x18, 0xc7, + 0xf8, 0x31, 0xcd, 0x4e, 0x2f, 0xa6, 0x19, 0x96, 0xfd, 0x8e, 0x1b, 0xf3, + 0x8f, 0xa0, 0x3f, 0xef, 0x28, 0xda, 0x63, 0x8c, 0x2d, 0x75, 0xc4, 0xdc, + 0x99, 0x3d, 0x09, 0x24, 0x0f, 0xee, 0x5e, 0xba, 0xb1, 0x97, 0x52, 0x6d, + 0x2f, 0xad, 0x4b, 0xcb, 0xf7, 0x32, 0xaa, 0xde, 0x9d, 0x5a, 0xf1, 0xae, + 0x60, 0x1f, 0xbb, 0x2f, 0xf1, 0x8c, 0x7b, 0x64, 0xdc, 0x60, 0x79, 0x7b, + 0xf4, 0xe5, 0x74, 0x00, 0x7b, 0x4c, 0x6a, 0x79, 0x15, 0x6b, 0xed, 0x51, + 0x3c, 0xcf, 0x97, 0xc7, 0x70, 0xa5, 0x7d, 0xa8, 0x79, 0x94, 0x8d, 0x4c, + 0x28, 0x3e, 0x8f, 0xab, 0x7d, 0x2c, 0x94, 0x7f, 0x41, 0x0a, 0x27, 0x7e, + 0x09, 0x7e, 0x2f, 0x58, 0x0f, 0x63, 0x2d, 0x91, 0xfc, 0x28, 0x06, 0xf0, + 0x93, 0x7b, 0x65, 0xad, 0xeb, 0x0f, 0x43, 0x6e, 0x7e, 0x10, 0x81, 0x8c, + 0x35, 0xf7, 0xb9, 0x5a, 0xdf, 0xe7, 0x6b, 0x53, 0x80, 0x9e, 0x2a, 0x62, + 0xce, 0x18, 0x68, 0x08, 0xbe, 0x73, 0x50, 0x86, 0x1c, 0xca, 0xa3, 0x27, + 0x36, 0x2e, 0xb6, 0x95, 0x17, 0x3f, 0xce, 0xe0, 0xfa, 0xb4, 0xf9, 0x5c, + 0xcc, 0x10, 0xd6, 0x2f, 0x7d, 0xde, 0xf9, 0x7c, 0x8b, 0x2c, 0x35, 0xea, + 0xc0, 0x14, 0xe8, 0x29, 0x38, 0xe4, 0x93, 0xaf, 0x9b, 0xfe, 0xda, 0xaf, + 0xaa, 0xfd, 0x4c, 0xaa, 0x9a, 0xdd, 0x73, 0x35, 0x1d, 0x9d, 0x40, 0x0c, + 0xe2, 0xea, 0xdc, 0x7d, 0x1e, 0x6f, 0x7c, 0xdd, 0x8c, 0x78, 0x72, 0x66, + 0x1e, 0x47, 0xdb, 0xf1, 0xf5, 0x60, 0x93, 0x75, 0xb7, 0xe2, 0x05, 0x9f, + 0x11, 0x53, 0x5c, 0x59, 0x8e, 0xd5, 0x64, 0xb9, 0xb6, 0x41, 0x2f, 0xbf, + 0xb7, 0xce, 0xb5, 0x43, 0xda, 0x1b, 0xec, 0x16, 0xf4, 0x3d, 0xb5, 0xcc, + 0xbe, 0x93, 0x97, 0xa8, 0x83, 0x46, 0xc4, 0x98, 0xfb, 0x53, 0xf0, 0xf2, + 0x63, 0xc8, 0x55, 0x44, 0xcc, 0x19, 0xe2, 0x10, 0xe3, 0x8d, 0x7a, 0xbc, + 0xbb, 0x20, 0xab, 0xc5, 0xba, 0x57, 0x8a, 0x35, 0x7e, 0xf2, 0x2a, 0x63, + 0x8d, 0x78, 0x93, 0xb4, 0x10, 0x8b, 0x86, 0x11, 0xdb, 0x6a, 0xd2, 0x64, + 0x3f, 0x08, 0x1f, 0x76, 0xc6, 0x6c, 0xb6, 0x7d, 0x4c, 0x88, 0x48, 0xfb, + 0xdc, 0x06, 0x85, 0x0b, 0xd6, 0x4c, 0x1d, 0x17, 0x26, 0xc0, 0xfb, 0x11, + 0xb7, 0xb6, 0x1a, 0x6d, 0x97, 0xab, 0xcd, 0x8d, 0xeb, 0x71, 0xff, 0x58, + 0x2d, 0xee, 0xbf, 0xa1, 0x81, 0x8f, 0xab, 0xe1, 0xe2, 0x19, 0xf0, 0x2d, + 0x8d, 0xfc, 0x97, 0x79, 0xed, 0x10, 0xf2, 0x61, 0xe6, 0x62, 0x19, 0xe4, + 0xc4, 0x89, 0x33, 0xc0, 0x2a, 0xe4, 0xc8, 0x89, 0xb7, 0xe0, 0x57, 0x90, + 0x37, 0x27, 0xe6, 0x99, 0xbb, 0x2e, 0x22, 0x3f, 0x7e, 0x1a, 0xf9, 0xf1, + 0x53, 0x95, 0x3e, 0xf0, 0x37, 0xa9, 0xb0, 0x73, 0xef, 0x71, 0xd1, 0xee, + 0x52, 0xf5, 0x61, 0xda, 0x73, 0x14, 0x7e, 0xb4, 0x5a, 0x3d, 0x90, 0xea, + 0x41, 0x4e, 0x1e, 0x97, 0x4f, 0x99, 0xcc, 0x63, 0x35, 0xb3, 0xbb, 0x7f, + 0xc1, 0x08, 0xc6, 0xa4, 0xd9, 0x2b, 0xfa, 0x81, 0x95, 0xbc, 0xcf, 0x29, + 0x5f, 0x70, 0xcc, 0xb8, 0x1c, 0xef, 0xef, 0xaa, 0xf1, 0xfe, 0xc2, 0x1a, + 0x69, 0x19, 0x56, 0x35, 0x80, 0xee, 0xfe, 0x03, 0xc4, 0xab, 0x14, 0xfc, + 0x3a, 0xfc, 0x6f, 0x55, 0xee, 0x48, 0x5d, 0xac, 0x9e, 0xb7, 0xd7, 0x49, + 0xbe, 0xef, 0x8b, 0x1e, 0x66, 0x8f, 0x3d, 0x92, 0xb5, 0x8b, 0xb0, 0x0f, + 0xb7, 0x16, 0x39, 0x3e, 0x1d, 0x46, 0x14, 0xca, 0xbf, 0x0e, 0x59, 0x18, + 0xfc, 0x1b, 0xc8, 0x70, 0xcb, 0x69, 0x16, 0xb0, 0x74, 0xe0, 0xf0, 0x42, + 0x34, 0xa2, 0xea, 0x33, 0xd7, 0xd9, 0xec, 0xb7, 0x20, 0xd3, 0x51, 0x59, + 0x40, 0xfc, 0x50, 0x1a, 0x04, 0x8d, 0x7d, 0x9d, 0x18, 0x4f, 0xbb, 0x23, + 0xcf, 0x47, 0xe1, 0x7b, 0xc9, 0xd3, 0x28, 0xc6, 0xef, 0xc2, 0x98, 0x0e, + 0x5c, 0xbf, 0x68, 0x2c, 0x58, 0xcc, 0x9d, 0x7f, 0x0e, 0x6d, 0xce, 0x11, + 0xf4, 0x9d, 0x9f, 0x0e, 0x89, 0x9a, 0x93, 0xef, 0x74, 0x2a, 0xfb, 0xaf, + 0xaf, 0xc5, 0x75, 0xf8, 0xec, 0xbd, 0xea, 0x2d, 0xfd, 0x83, 0x81, 0xf5, + 0xda, 0x02, 0xeb, 0x0d, 0x06, 0xd6, 0x23, 0x9d, 0x1d, 0x01, 0x3a, 0x3b, + 0xf0, 0x7e, 0x0e, 0x6b, 0x0f, 0xab, 0x98, 0xa7, 0xbe, 0xe6, 0xfd, 0x81, + 0x35, 0xfd, 0xfd, 0x75, 0x06, 0xde, 0x7b, 0x07, 0xeb, 0xb1, 0x2f, 0x1a, + 0xe8, 0x23, 0x0d, 0xeb, 0xd1, 0xc7, 0x76, 0x47, 0x80, 0x2e, 0xd2, 0xba, + 0x16, 0xfd, 0x2a, 0x7e, 0x02, 0x9f, 0x5b, 0xe0, 0xb7, 0x74, 0xf8, 0x0e, + 0xd6, 0xa0, 0x1b, 0xf7, 0xfa, 0x65, 0xac, 0xeb, 0xcf, 0x17, 0xc5, 0x1c, + 0x1c, 0xcf, 0xb1, 0x86, 0xf7, 0x3e, 0xfb, 0xf9, 0xfc, 0x1b, 0xd5, 0xaf, + 0x2b, 0xbe, 0xad, 0x07, 0xed, 0xaa, 0xee, 0x22, 0xf3, 0x1d, 0x26, 0xe4, + 0xc9, 0xfc, 0x58, 0x93, 0x9b, 0x6c, 0x5d, 0xeb, 0xe9, 0xa7, 0xec, 0xd7, + 0x79, 0x58, 0xda, 0xa2, 0x65, 0x8f, 0xb3, 0x5e, 0xd0, 0xea, 0xe5, 0x7c, + 0xc8, 0x3d, 0x94, 0x8f, 0x31, 0xbd, 0xe7, 0xf4, 0x31, 0x8c, 0x5b, 0xe8, + 0x3f, 0x33, 0xde, 0x3d, 0xae, 0xd0, 0xe1, 0x7d, 0xa5, 0x0e, 0x39, 0xaf, + 0x78, 0x6a, 0xc9, 0xb9, 0x1a, 0x4f, 0x43, 0xde, 0xb7, 0x90, 0x83, 0xde, + 0x77, 0x06, 0x03, 0x71, 0x11, 0xee, 0xcb, 0x19, 0xd0, 0x10, 0x97, 0x9e, + 0x7e, 0xe6, 0x6e, 0x45, 0x5c, 0x59, 0xa7, 0xd0, 0x70, 0x75, 0xeb, 0x17, + 0x3d, 0xfd, 0xf0, 0x4b, 0xc0, 0xa1, 0x9e, 0xfe, 0xef, 0xa8, 0x7c, 0xae, + 0x54, 0xb1, 0xb4, 0x3b, 0x1c, 0xb7, 0x46, 0x74, 0xce, 0xbe, 0x5c, 0x8d, + 0x68, 0xa0, 0x99, 0x75, 0x0d, 0xbf, 0x46, 0x74, 0x4e, 0x54, 0x8d, 0xe8, + 0xe4, 0x15, 0x6a, 0x44, 0x99, 0xab, 0xaf, 0x11, 0x71, 0x7e, 0x53, 0xee, + 0x1e, 0x10, 0xed, 0x4b, 0x5e, 0x8d, 0xe8, 0x82, 0xb8, 0x35, 0xa2, 0xf3, + 0xb2, 0x7a, 0x8d, 0xe8, 0x68, 0x43, 0x8d, 0x68, 0xbd, 0xaa, 0x11, 0x71, + 0x1e, 0xb7, 0x46, 0xc4, 0x76, 0xbe, 0x7f, 0x30, 0x50, 0xeb, 0x00, 0xfe, + 0x3a, 0xb7, 0x82, 0x6f, 0x96, 0x36, 0xea, 0xf8, 0x98, 0x46, 0xec, 0xbf, + 0xbe, 0xe6, 0xbf, 0xea, 0xf8, 0xa6, 0x29, 0x9d, 0xbb, 0x12, 0xbe, 0x8d, + 0xba, 0x71, 0xc9, 0x32, 0x6c, 0x9b, 0xaa, 0xc5, 0x2e, 0xbf, 0xdc, 0xcc, + 0x1c, 0x7a, 0xb2, 0x5c, 0x9f, 0x77, 0x12, 0xf2, 0x1e, 0xab, 0xd5, 0x49, + 0x2e, 0x15, 0x1f, 0x45, 0xe5, 0xe0, 0xaa, 0xdf, 0x9a, 0x62, 0x99, 0x95, + 0xdf, 0x9a, 0x34, 0x89, 0x82, 0xce, 0x7c, 0x7f, 0x5e, 0xe5, 0x5d, 0x0b, + 0xce, 0xcf, 0xcb, 0xd2, 0xbd, 0x16, 0xf0, 0xc7, 0xaf, 0x9f, 0x50, 0xbe, + 0x75, 0x9f, 0x92, 0xd5, 0x3f, 0xba, 0x1a, 0xca, 0x3e, 0x55, 0x43, 0xf9, + 0x5a, 0x73, 0xb0, 0x86, 0x72, 0x4e, 0x2e, 0x5f, 0x43, 0xd9, 0xb7, 0x4a, + 0x0d, 0xe5, 0x15, 0xa9, 0xd7, 0x50, 0x5e, 0x11, 0xbf, 0x86, 0x62, 0xc8, + 0xd2, 0x7a, 0xce, 0xb3, 0x1f, 0xef, 0x8c, 0xe0, 0x37, 0x8c, 0x9f, 0x5b, + 0x53, 0x39, 0x57, 0xa3, 0x7f, 0xb5, 0x9a, 0xca, 0x37, 0x9b, 0xdf, 0x4f, + 0x4d, 0xc5, 0xf5, 0x01, 0x7e, 0x4d, 0xa5, 0x05, 0xf1, 0x0e, 0x7c, 0x8e, + 0x1e, 0xac, 0xa9, 0xfc, 0x2d, 0xed, 0x01, 0x7d, 0x2a, 0x46, 0x40, 0x3f, + 0xec, 0x02, 0x7e, 0x29, 0xa3, 0x6a, 0x1c, 0x9f, 0xf6, 0x78, 0xb8, 0x1b, + 0x7b, 0x8e, 0x43, 0x16, 0xe4, 0x63, 0x8f, 0x8a, 0x2d, 0x33, 0x66, 0x4c, + 0xcb, 0xf6, 0xc2, 0x9b, 0x4d, 0xf3, 0x5b, 0x74, 0x4c, 0xc6, 0x2b, 0xd4, + 0xf1, 0x2e, 0xc4, 0xe2, 0x26, 0xfa, 0x76, 0xa3, 0xed, 0xc7, 0x54, 0xfd, + 0xb5, 0x39, 0x68, 0x9b, 0x0b, 0xc0, 0x59, 0xe0, 0xc4, 0x55, 0xf8, 0xa8, + 0x6d, 0xa0, 0x39, 0xb8, 0x8f, 0x22, 0xfc, 0x13, 0xfa, 0x94, 0xcc, 0x19, + 0x5b, 0xfa, 0xb4, 0xc4, 0x69, 0xe7, 0x57, 0x31, 0x1f, 0xfb, 0xb6, 0xa9, + 0x7c, 0xac, 0x30, 0xc0, 0xbd, 0xd2, 0xd7, 0x2d, 0x82, 0x3e, 0xf4, 0x95, + 0x98, 0x03, 0xd2, 0xef, 0xf9, 0x39, 0x5a, 0x44, 0xe5, 0x68, 0x9d, 0x8a, + 0x1f, 0xe4, 0xf5, 0x8d, 0x61, 0x62, 0x65, 0xa7, 0xcd, 0x3d, 0x0c, 0x7b, + 0x58, 0xc7, 0xb6, 0x9b, 0x0b, 0x66, 0x74, 0xde, 0x3f, 0x02, 0xb9, 0xb2, + 0x4e, 0xe3, 0xcb, 0xef, 0x21, 0x6f, 0xdf, 0x83, 0x52, 0xec, 0x94, 0xf0, + 0x7a, 0xd0, 0x93, 0x9f, 0x61, 0xdc, 0xfd, 0x09, 0x95, 0x83, 0x44, 0xed, + 0x4b, 0xdb, 0xed, 0x5d, 0xd7, 0x60, 0xb7, 0x23, 0x97, 0xb5, 0xdb, 0xcf, + 0x85, 0x83, 0x76, 0x7b, 0xd7, 0x35, 0xd8, 0xed, 0xfe, 0x6b, 0xb2, 0x5b, + 0xee, 0x8d, 0x98, 0xe4, 0xd7, 0xc4, 0x56, 0xc6, 0x59, 0xfe, 0xba, 0x13, + 0x58, 0x33, 0x73, 0x89, 0x35, 0xc7, 0x2e, 0x59, 0x5b, 0x6d, 0x8c, 0xb1, + 0xae, 0x46, 0xde, 0xcc, 0xad, 0xe8, 0x6f, 0x23, 0x9e, 0x5f, 0xba, 0xdd, + 0xcb, 0xe7, 0xfd, 0xbc, 0x3e, 0x68, 0x3f, 0xd4, 0x0b, 0xea, 0xc2, 0x63, + 0xe0, 0x17, 0xf5, 0xc1, 0xb7, 0xb9, 0x9e, 0x06, 0x1d, 0x5c, 0x44, 0xbe, + 0xdf, 0xe3, 0xe9, 0x20, 0x65, 0xdd, 0xab, 0xbe, 0x11, 0x95, 0x9c, 0x47, + 0xdc, 0x3c, 0x1f, 0x3a, 0x90, 0x2f, 0xf9, 0xb6, 0x06, 0x9e, 0x44, 0xfd, + 0x67, 0xe4, 0xa3, 0x8d, 0x98, 0x67, 0x0b, 0xe2, 0x35, 0xf0, 0x48, 0xf5, + 0x2f, 0xaf, 0x09, 0x5f, 0x1e, 0xcf, 0xa4, 0x18, 0xc2, 0xd8, 0x53, 0x03, + 0xb0, 0xf1, 0x01, 0x62, 0x54, 0x1a, 0x79, 0x0f, 0xf5, 0x90, 0xba, 0xb9, + 0x29, 0xb9, 0x43, 0x67, 0x4c, 0xb5, 0x07, 0xb6, 0x47, 0x7d, 0x8d, 0xcb, + 0x8e, 0xca, 0xa6, 0x33, 0xe7, 0x74, 0xae, 0x51, 0xad, 0xe6, 0x99, 0x2b, + 0x5a, 0xa2, 0x77, 0xf7, 0xff, 0x45, 0x98, 0x7e, 0xe9, 0x7a, 0xdb, 0xf0, + 0x74, 0x2d, 0x83, 0x7b, 0xea, 0xed, 0xeb, 0xf0, 0xf7, 0xfc, 0xc6, 0xfe, + 0x03, 0xf4, 0xc7, 0x60, 0xf3, 0xf4, 0xef, 0xcc, 0x47, 0xb6, 0x7a, 0xe3, + 0x7a, 0xd4, 0xf7, 0xcf, 0x6c, 0xea, 0x56, 0xef, 0xbb, 0x13, 0xfd, 0x4f, + 0x82, 0x3e, 0x7b, 0x99, 0x9c, 0x79, 0x46, 0x21, 0xa7, 0xf2, 0x19, 0xbe, + 0xaf, 0x74, 0x12, 0x39, 0x88, 0x19, 0xa8, 0xa5, 0x87, 0xbd, 0xdc, 0x8d, + 0x36, 0x16, 0x81, 0x0c, 0xb7, 0x7b, 0xb9, 0x0a, 0xf3, 0xd7, 0xe5, 0x67, + 0x13, 0x56, 0xd7, 0x81, 0x0d, 0xef, 0x43, 0x07, 0x1a, 0xe5, 0x17, 0x86, + 0xed, 0xfb, 0xf2, 0xf3, 0xe3, 0x98, 0x79, 0x6f, 0xdf, 0x3d, 0xae, 0x0c, + 0x7f, 0x2c, 0xf6, 0xa9, 0x05, 0xf6, 0xe9, 0xe3, 0xd1, 0x3e, 0x6f, 0x9f, + 0x5b, 0x1b, 0xf0, 0x68, 0xa4, 0xc1, 0x66, 0x3f, 0x4a, 0x3c, 0x3a, 0xb4, + 0xe6, 0xa3, 0xc7, 0x23, 0xee, 0x6b, 0xe3, 0xaa, 0x38, 0xe4, 0xee, 0xe3, + 0x77, 0x45, 0x4f, 0x7f, 0x98, 0xf9, 0xde, 0xfb, 0x91, 0x4f, 0x10, 0x47, + 0x28, 0x93, 0x36, 0x15, 0xc3, 0xba, 0xb6, 0x07, 0x5f, 0x5e, 0x0a, 0xc9, + 0x1b, 0xf7, 0x84, 0xe5, 0x7f, 0x6f, 0xe3, 0xf7, 0x30, 0xd3, 0xab, 0x69, + 0xb1, 0xfd, 0xc2, 0x1a, 0xd7, 0x0f, 0xbd, 0xd0, 0xee, 0xfa, 0x1d, 0xbe, + 0xe3, 0xdb, 0xb3, 0x85, 0xe7, 0x7c, 0xb6, 0x91, 0x5f, 0x4c, 0xae, 0x21, + 0x07, 0xdc, 0x64, 0x5d, 0xd0, 0x57, 0xcb, 0x01, 0x2f, 0x5f, 0x0f, 0xac, + 0xe7, 0x80, 0xc4, 0xd9, 0x0e, 0xa5, 0x1b, 0xf9, 0x28, 0x73, 0x1f, 0xc3, + 0xc3, 0x4e, 0xde, 0x23, 0xb7, 0x75, 0x90, 0xef, 0x42, 0xb6, 0xcf, 0x21, + 0x5e, 0x7a, 0xd6, 0x41, 0x8e, 0xeb, 0x20, 0xb7, 0x75, 0x90, 0xdb, 0x3a, + 0xc8, 0x6d, 0x9d, 0xa4, 0x97, 0x23, 0x8f, 0x78, 0x75, 0x7f, 0x7e, 0xe3, + 0x66, 0x7d, 0xa1, 0x08, 0x5f, 0x32, 0xc5, 0x73, 0x13, 0x7a, 0x36, 0xb5, + 0xc6, 0xdb, 0x9f, 0x5f, 0x13, 0xef, 0xf2, 0x6a, 0x36, 0xdf, 0x54, 0x75, + 0x43, 0xd1, 0x1f, 0x68, 0x71, 0xbf, 0x83, 0xf3, 0x7c, 0xc7, 0xaf, 0x21, + 0x2e, 0x51, 0x67, 0x88, 0x68, 0xa3, 0x55, 0x3d, 0xcd, 0x9a, 0x8c, 0xe8, + 0x7a, 0xfa, 0x16, 0xbc, 0xb3, 0xc5, 0xcd, 0x09, 0xa2, 0x62, 0xe8, 0xe9, + 0x56, 0xf2, 0x54, 0xd3, 0xd3, 0x6b, 0xbd, 0xb9, 0xf6, 0xb7, 0xb8, 0xb1, + 0x55, 0x2f, 0xdb, 0xa6, 0xce, 0x38, 0x41, 0xc5, 0xda, 0x7e, 0xff, 0xc5, + 0xf6, 0xe5, 0x6b, 0x85, 0x14, 0xbe, 0x67, 0x53, 0xf7, 0x62, 0x3e, 0xb6, + 0xeb, 0xfc, 0xd6, 0x2f, 0xc9, 0xef, 0x90, 0xc7, 0x6f, 0x97, 0xc7, 0x06, + 0xc7, 0xa9, 0xba, 0x30, 0x79, 0xed, 0xcf, 0xa7, 0xea, 0x7a, 0x58, 0x47, + 0x9d, 0xcd, 0xc0, 0xf5, 0x07, 0xa6, 0xb4, 0x8d, 0xee, 0x0e, 0xd9, 0xc1, + 0x75, 0xfd, 0x6f, 0xe2, 0x57, 0xb3, 0x66, 0x8f, 0xfa, 0x8e, 0xe6, 0xfa, + 0x8c, 0x90, 0xd2, 0x41, 0x33, 0xcd, 0x7d, 0xfd, 0x50, 0x9d, 0xa9, 0xa1, + 0xfe, 0xe5, 0x90, 0xc7, 0x4c, 0x0d, 0x6c, 0x8a, 0x9b, 0xfa, 0x48, 0x0b, + 0xeb, 0xaf, 0x43, 0x15, 0x1f, 0xf7, 0xb8, 0x5e, 0xa3, 0x1f, 0x67, 0x5d, + 0xcd, 0xc7, 0x33, 0xd9, 0xe0, 0xd6, 0xdb, 0x3e, 0x88, 0x2d, 0xb5, 0x34, + 0xd8, 0x92, 0xbf, 0x4f, 0xee, 0x9f, 0xd7, 0xd5, 0xcf, 0x43, 0x2c, 0x56, + 0x02, 0xdf, 0x47, 0x6a, 0xba, 0xc1, 0xb3, 0x2a, 0x9f, 0x85, 0x0e, 0xf2, + 0xdb, 0xc0, 0x4e, 0xd8, 0x51, 0xb5, 0x3a, 0xc4, 0x1a, 0x73, 0xdf, 0x67, + 0x54, 0x7e, 0xa9, 0xa7, 0xe7, 0x55, 0xfd, 0xc1, 0x5c, 0x51, 0x7f, 0x18, + 0x82, 0xae, 0x20, 0x06, 0x70, 0xda, 0x54, 0x4c, 0xa7, 0xe2, 0x85, 0x4a, + 0xe3, 0xf7, 0x97, 0xfb, 0x5b, 0x5d, 0x3e, 0xfc, 0x5d, 0x8b, 0xfb, 0x0d, + 0xe2, 0x8f, 0xa2, 0xcb, 0xdb, 0x7c, 0xff, 0xaf, 0x5b, 0xfc, 0xb3, 0x3b, + 0x85, 0x13, 0x43, 0xd0, 0x45, 0xe4, 0xe4, 0x6a, 0x3e, 0xc4, 0xbb, 0x4f, + 0xcc, 0x76, 0x2c, 0x1f, 0x8f, 0xbe, 0x13, 0xfe, 0xf8, 0x8e, 0x86, 0xf1, + 0x1d, 0x18, 0xff, 0x7b, 0x0d, 0xe3, 0x3b, 0x02, 0xe3, 0xa3, 0x0d, 0xe3, + 0xa3, 0x18, 0xff, 0x7c, 0xc3, 0xf8, 0x68, 0x60, 0x7c, 0x67, 0xc3, 0xf8, + 0x4e, 0x8c, 0x7f, 0xa1, 0x61, 0x3c, 0xfa, 0x4e, 0x34, 0x79, 0xdf, 0xc5, + 0x88, 0xb1, 0xfb, 0xbd, 0x5c, 0x1c, 0xd7, 0x72, 0xe3, 0xb7, 0x16, 0xea, + 0x5d, 0x17, 0x64, 0xe0, 0x9f, 0xa7, 0xa3, 0xbd, 0x66, 0x60, 0xaf, 0xf5, + 0x58, 0xc6, 0xd5, 0xc7, 0xa0, 0x2e, 0x12, 0x1f, 0x8a, 0x62, 0xd8, 0xd0, + 0x9d, 0x12, 0x74, 0xa8, 0xe4, 0xfb, 0x24, 0x9e, 0x83, 0xe2, 0x19, 0x53, + 0xd7, 0xf7, 0x86, 0xec, 0x45, 0x2f, 0x07, 0x7b, 0x9b, 0xb4, 0x03, 0x2f, + 0x7d, 0xcc, 0x94, 0x63, 0xae, 0xdd, 0x50, 0x7f, 0x39, 0xbf, 0x67, 0x3f, + 0xd4, 0x55, 0x6f, 0x9d, 0xa1, 0x15, 0xb8, 0x16, 0x5f, 0x51, 0xdb, 0x32, + 0xae, 0x02, 0xd7, 0x46, 0x6a, 0xb8, 0xf6, 0x59, 0x99, 0xaf, 0xe5, 0xdb, + 0xc3, 0x72, 0xc0, 0xd9, 0xc5, 0x33, 0x36, 0xc7, 0x32, 0xf2, 0xe1, 0xe4, + 0xdb, 0xbb, 0x6a, 0x7e, 0x92, 0x67, 0x3a, 0x96, 0x0e, 0x31, 0x87, 0xf2, + 0x6b, 0xb3, 0x53, 0xce, 0xcf, 0xb6, 0x42, 0x2e, 0xb0, 0x8d, 0x6b, 0xcd, + 0xb7, 0x39, 0x5f, 0x54, 0x0e, 0xb8, 0xe7, 0x1d, 0x6a, 0xf3, 0x16, 0x6b, + 0xf3, 0xc6, 0x3c, 0x7b, 0xa3, 0x0f, 0xae, 0xfb, 0xcb, 0x1c, 0xfc, 0xe5, + 0x18, 0x72, 0xee, 0x45, 0x67, 0xb5, 0xfa, 0xe8, 0xb5, 0xfa, 0xcb, 0xc6, + 0x3a, 0x73, 0xa3, 0xbf, 0xe4, 0x3a, 0x8d, 0xb5, 0xe5, 0x78, 0x03, 0xfe, + 0x53, 0x9f, 0x0e, 0x7b, 0x31, 0x35, 0xae, 0xa5, 0xc3, 0xb0, 0x47, 0x5d, + 0xc6, 0x94, 0xfe, 0xb2, 0xed, 0xe7, 0x96, 0xbb, 0x6b, 0xb9, 0x65, 0x3d, + 0x1f, 0x44, 0xec, 0x9a, 0xfc, 0xa4, 0x87, 0x8f, 0x8c, 0x91, 0xa7, 0xd0, + 0x7f, 0x0c, 0x3a, 0xc0, 0x67, 0xac, 0x97, 0xde, 0x2c, 0x9f, 0x32, 0x5d, + 0xff, 0xe4, 0xd6, 0xa6, 0x76, 0xab, 0xf8, 0x9f, 0xdf, 0x0b, 0x0a, 0xa9, + 0x76, 0x2f, 0xde, 0xbb, 0x12, 0xae, 0x2e, 0xcf, 0x4d, 0x75, 0xfd, 0x51, + 0xbc, 0xcb, 0xdc, 0xd4, 0x8c, 0x10, 0x43, 0xb3, 0x95, 0xcb, 0xbe, 0x5f, + 0xa4, 0x7f, 0x29, 0xa8, 0xef, 0x82, 0x2a, 0x0f, 0xc5, 0xb8, 0x45, 0xef, + 0x7d, 0x37, 0x0f, 0xcd, 0x56, 0xbe, 0xdd, 0xea, 0xe2, 0xe0, 0xe5, 0x72, + 0x96, 0x9f, 0x88, 0xb0, 0xae, 0xb7, 0xe8, 0x5c, 0x89, 0xd6, 0x95, 0x79, + 0xaf, 0xb1, 0x22, 0xef, 0x1d, 0xf5, 0xf2, 0xda, 0xcf, 0xa9, 0xbc, 0xd7, + 0xe5, 0x31, 0xf7, 0x12, 0xcc, 0xa3, 0x6c, 0x60, 0x21, 0xbf, 0xa9, 0x10, + 0x1f, 0x26, 0x94, 0xdf, 0xca, 0x4f, 0xdf, 0x09, 0x3e, 0x47, 0x57, 0xd1, + 0x9b, 0x8f, 0xda, 0x4f, 0xf8, 0x7b, 0x3f, 0x2c, 0x6e, 0xbd, 0x6e, 0x27, + 0x68, 0x61, 0x6e, 0x15, 0xf2, 0xf4, 0xe1, 0xbb, 0xde, 0x39, 0x53, 0x7f, + 0x9c, 0x9f, 0xc7, 0xd7, 0xbe, 0xbb, 0x16, 0x33, 0xcb, 0xea, 0x27, 0x1b, + 0x09, 0xc3, 0x90, 0x7b, 0xe6, 0x1a, 0xbe, 0x5b, 0x7c, 0x90, 0xf3, 0x11, + 0x8d, 0x7e, 0x8d, 0xdf, 0x4d, 0xf9, 0xad, 0x54, 0xb4, 0xbb, 0x7b, 0x6d, + 0xd8, 0x00, 0xcf, 0x2c, 0x07, 0xf1, 0x35, 0x2c, 0xf9, 0x39, 0x09, 0x47, + 0xd3, 0xfc, 0x06, 0x40, 0xff, 0xff, 0xba, 0xb7, 0xcf, 0x98, 0xec, 0x9f, + 0x71, 0x6b, 0x9e, 0xfa, 0x65, 0xcf, 0xc5, 0x1d, 0x00, 0x1f, 0x12, 0x47, + 0xfd, 0x9a, 0xa7, 0xee, 0x9e, 0x8b, 0x3b, 0xfa, 0xe1, 0x9d, 0x8b, 0xe3, + 0xfc, 0xa6, 0xec, 0x5a, 0xe5, 0x5c, 0x9c, 0x71, 0x95, 0xe7, 0xe2, 0xda, + 0x55, 0xcd, 0x93, 0xf3, 0xb8, 0x35, 0x4f, 0xb6, 0xbb, 0xfb, 0x59, 0x2b, + 0xe1, 0xd9, 0xb7, 0x01, 0x75, 0x06, 0xb9, 0xbb, 0xff, 0x47, 0x91, 0xa3, + 0x7c, 0x3d, 0xf2, 0xd1, 0xe7, 0x28, 0xdc, 0xcb, 0xaf, 0xb8, 0xdf, 0x77, + 0xe5, 0x5a, 0xea, 0x00, 0x1f, 0xac, 0xae, 0xb9, 0x5f, 0xd5, 0x35, 0xbf, + 0x13, 0x09, 0xd6, 0x35, 0xf5, 0x2b, 0x9c, 0x0d, 0xdb, 0xbf, 0x4a, 0x5d, + 0x33, 0x14, 0x38, 0x1b, 0x16, 0xf2, 0xce, 0x86, 0xb5, 0xdb, 0xc8, 0x25, + 0xbd, 0x3a, 0xa6, 0x7e, 0xd9, 0xb3, 0x61, 0xff, 0x19, 0xf9, 0xe0, 0x75, + 0xcc, 0x15, 0x67, 0xc3, 0xe0, 0xeb, 0x36, 0x48, 0xfc, 0x9a, 0xf2, 0x9e, + 0x0f, 0x92, 0xf3, 0xf0, 0xbc, 0x7e, 0x13, 0xf6, 0x1c, 0x92, 0x5d, 0x51, + 0xea, 0x27, 0xcf, 0x36, 0xf6, 0xc2, 0x16, 0x70, 0xad, 0xb0, 0x9d, 0xa4, + 0x8c, 0xb4, 0x91, 0xde, 0xe5, 0xe7, 0x10, 0xea, 0xe7, 0x71, 0xc3, 0xb5, + 0xf3, 0xb8, 0x47, 0xa0, 0x37, 0xfa, 0x4c, 0x58, 0x16, 0x02, 0x3a, 0x35, + 0x85, 0x78, 0x4f, 0x9f, 0xb3, 0xbc, 0xe7, 0xfc, 0x9f, 0x8a, 0x28, 0x30, + 0x8f, 0x67, 0x78, 0xdb, 0xc4, 0x98, 0x73, 0xbf, 0x59, 0xba, 0xff, 0x57, + 0x12, 0xc3, 0x18, 0x9e, 0xf1, 0x0c, 0xc9, 0x01, 0x55, 0xb3, 0xf0, 0x75, + 0x79, 0xc7, 0x5a, 0x69, 0x59, 0x9f, 0xa9, 0xb7, 0xa3, 0xab, 0xf8, 0x7d, + 0xc4, 0x91, 0x33, 0xd4, 0xe7, 0x5b, 0x25, 0xe7, 0xd5, 0x83, 0x0a, 0x95, + 0x6d, 0x5e, 0x7e, 0xa1, 0xbe, 0xed, 0x80, 0x97, 0xdd, 0x9e, 0x0f, 0xc6, + 0xb5, 0xd4, 0x4d, 0x9f, 0x87, 0x35, 0x4e, 0xca, 0xd0, 0xf4, 0x96, 0xd8, + 0x38, 0xf0, 0x6e, 0x4c, 0xad, 0x79, 0x2d, 0x3c, 0xd7, 0x2e, 0xf1, 0xbd, + 0xf1, 0x6a, 0xf9, 0xee, 0xc7, 0xc7, 0x8f, 0x62, 0x7f, 0xdd, 0xd0, 0x8f, + 0x87, 0x25, 0x77, 0xe2, 0x66, 0x19, 0x9a, 0x4d, 0x80, 0x9e, 0x1f, 0x56, + 0x0b, 0x29, 0xc4, 0xd2, 0x4f, 0xf0, 0xdc, 0x18, 0x30, 0x14, 0x7c, 0x7b, + 0x66, 0xc5, 0x77, 0xec, 0xe0, 0x59, 0xb3, 0x64, 0xed, 0xec, 0xd0, 0x53, + 0x15, 0x09, 0x77, 0x90, 0xe6, 0x99, 0xfa, 0xd9, 0xef, 0xc5, 0xca, 0x0e, + 0xe5, 0xdb, 0x9e, 0xac, 0x2c, 0xab, 0xfd, 0x28, 0x19, 0x4e, 0x94, 0x9f, + 0x04, 0x2f, 0x5e, 0x51, 0xfe, 0xed, 0x88, 0x23, 0x37, 0x19, 0x42, 0x79, + 0x88, 0x06, 0x1e, 0xa8, 0x33, 0x1c, 0xee, 0xf7, 0xfd, 0x2e, 0x25, 0x57, + 0x17, 0x2b, 0x76, 0x06, 0xce, 0x60, 0xd4, 0x65, 0xeb, 0x9e, 0xcd, 0x70, + 0x65, 0xe1, 0x9e, 0x1f, 0x21, 0x3f, 0x97, 0x0e, 0xed, 0xb2, 0xdd, 0xf3, + 0x23, 0x3d, 0x73, 0xec, 0xeb, 0x6c, 0xf0, 0x7d, 0x61, 0xe8, 0x00, 0xcf, + 0x1d, 0xf1, 0xcc, 0x37, 0x69, 0x56, 0xb5, 0x8e, 0x55, 0xbf, 0x6d, 0x5f, + 0x5b, 0xcd, 0xd5, 0x5d, 0xb3, 0x5b, 0xad, 0x79, 0x9d, 0x87, 0x59, 0xfe, + 0x59, 0xef, 0x94, 0xf6, 0xff, 0xd4, 0x5d, 0x7b, 0x6c, 0x1b, 0xf7, 0x7d, + 0xff, 0xf2, 0x48, 0x3d, 0xac, 0xe7, 0x49, 0xa6, 0x64, 0x5a, 0x52, 0x94, + 0x3b, 0xe9, 0x64, 0x29, 0xb1, 0x12, 0x70, 0x9e, 0xba, 0x0a, 0x88, 0x9a, + 0xb0, 0x24, 0xfd, 0x58, 0x10, 0x0c, 0xb4, 0xad, 0x64, 0xee, 0x92, 0xad, + 0x0e, 0x25, 0xa7, 0x1d, 0x30, 0x60, 0x6e, 0xd6, 0x02, 0x69, 0x07, 0xc7, + 0x0c, 0x65, 0x27, 0xc6, 0xaa, 0x88, 0x4c, 0xcc, 0x6a, 0x1d, 0xb0, 0x62, + 0x1c, 0xa5, 0x38, 0x69, 0xa7, 0x80, 0x69, 0xda, 0x04, 0xc5, 0xfe, 0xb1, + 0x26, 0x3b, 0x7b, 0x61, 0x7f, 0x04, 0xdb, 0x80, 0x1a, 0x5b, 0x81, 0xba, + 0x76, 0x8a, 0x65, 0x1b, 0xe0, 0x34, 0xdb, 0xb0, 0x75, 0x58, 0x0b, 0xee, + 0xfb, 0xf9, 0x3d, 0xc8, 0x23, 0x79, 0xd4, 0xc3, 0x71, 0x06, 0x4c, 0x80, + 0x40, 0xde, 0xf1, 0x77, 0x77, 0xbf, 0xdf, 0xf7, 0xf7, 0x7d, 0xbf, 0x6e, + 0x2e, 0x33, 0x1e, 0xf2, 0x33, 0x7e, 0xcf, 0x15, 0x61, 0x5f, 0x37, 0xd2, + 0xe1, 0x36, 0x83, 0x67, 0xa4, 0x0e, 0x9e, 0xd5, 0x34, 0xc1, 0xf6, 0x78, + 0x99, 0x77, 0x4b, 0xd8, 0xc9, 0xf3, 0xc8, 0x63, 0xd7, 0x39, 0x0e, 0x12, + 0x76, 0x65, 0x1a, 0x5a, 0x72, 0xe7, 0x37, 0x54, 0x60, 0x77, 0xb2, 0x0c, + 0xbb, 0x3d, 0xff, 0x8f, 0x60, 0x77, 0x4d, 0xe8, 0xbf, 0xdf, 0x2e, 0x22, + 0x6f, 0x4d, 0xeb, 0x00, 0xba, 0x6e, 0x09, 0x70, 0x04, 0x3f, 0xb5, 0xf3, + 0xeb, 0x04, 0x9e, 0x8a, 0xbc, 0xe2, 0x52, 0xe9, 0x3b, 0xe1, 0xb2, 0x9f, + 0x92, 0xed, 0x12, 0xd8, 0x27, 0xf0, 0xe7, 0x35, 0x96, 0x91, 0x47, 0x6f, + 0x4b, 0x46, 0x42, 0x57, 0xaa, 0xb5, 0x4f, 0x7e, 0xbb, 0xcb, 0x6d, 0x9f, + 0x1c, 0xdd, 0xa1, 0x7d, 0x72, 0x5a, 0xda, 0x27, 0xa9, 0xed, 0xdb, 0x27, + 0x03, 0x75, 0x79, 0x5d, 0x95, 0xf5, 0xec, 0xdc, 0x3e, 0x31, 0x36, 0xb5, + 0x4f, 0x46, 0x5d, 0xbe, 0x18, 0xcc, 0xf7, 0x57, 0x29, 0x75, 0x0c, 0x3c, + 0x4e, 0xc3, 0x19, 0x30, 0x3e, 0x56, 0xe3, 0x17, 0xfe, 0x38, 0x61, 0xfd, + 0xd7, 0xff, 0xc7, 0xb0, 0x1e, 0xac, 0xf3, 0x79, 0x57, 0xd6, 0x03, 0x21, + 0xfe, 0x51, 0x60, 0x3d, 0xd8, 0xd0, 0x77, 0xda, 0x38, 0x67, 0xb1, 0xda, + 0x77, 0x3a, 0x62, 0x34, 0xe2, 0xed, 0x7f, 0xe4, 0xf2, 0xa9, 0xba, 0xf9, + 0x3b, 0x68, 0x8a, 0x7c, 0x47, 0xc7, 0xf5, 0xb3, 0x40, 0x4b, 0x76, 0x2a, + 0x45, 0xb0, 0x99, 0xf0, 0xbc, 0x90, 0xa0, 0xb5, 0x1a, 0x7d, 0x8b, 0x9f, + 0xc7, 0xeb, 0x7b, 0xf5, 0x09, 0x21, 0xa7, 0xa4, 0xff, 0x01, 0xe3, 0x27, + 0x7c, 0xf3, 0x62, 0xac, 0xcc, 0x6f, 0x52, 0xfe, 0x08, 0xa5, 0xfb, 0x37, + 0xf2, 0x43, 0xd4, 0xcb, 0xbc, 0x9d, 0xd9, 0x0a, 0x9a, 0xc6, 0xef, 0xe6, + 0x7d, 0x09, 0x55, 0xd9, 0x5a, 0xe0, 0x9f, 0xa7, 0x59, 0x2f, 0x18, 0x29, + 0xeb, 0x04, 0xd5, 0x7b, 0x73, 0x4e, 0xd8, 0x74, 0x9a, 0x77, 0x26, 0x64, + 0xee, 0xa9, 0x38, 0x0f, 0x3d, 0x4d, 0xf3, 0xce, 0x5a, 0x3d, 0xf8, 0x6e, + 0x0f, 0xbc, 0xf0, 0xca, 0x69, 0x2a, 0xef, 0x9d, 0x85, 0x9c, 0xf3, 0xb8, + 0xe7, 0xde, 0x95, 0x6b, 0xc2, 0x52, 0x95, 0xb1, 0xf2, 0xfa, 0xb8, 0x58, + 0xd7, 0x0f, 0x8e, 0x44, 0x51, 0xfb, 0x56, 0xae, 0x17, 0xab, 0xad, 0x77, + 0x82, 0x1c, 0xd0, 0x74, 0xa8, 0x6b, 0xa2, 0x01, 0x8b, 0x61, 0x8f, 0x7a, + 0x27, 0xb7, 0x2c, 0xc1, 0x75, 0xb5, 0xb0, 0xa8, 0xc8, 0x91, 0xf3, 0x4a, + 0x8e, 0x14, 0x5c, 0x7c, 0xbc, 0x5e, 0x6f, 0xef, 0xf5, 0xd0, 0xdb, 0xbd, + 0x6a, 0x9e, 0x30, 0xa7, 0x67, 0x58, 0x0f, 0xb9, 0x1f, 0x7a, 0x88, 0x89, + 0xba, 0x25, 0xa9, 0x8b, 0xe0, 0x77, 0x96, 0x35, 0xaf, 0x86, 0x18, 0x57, + 0x8e, 0xd0, 0x53, 0xac, 0x6b, 0x5f, 0xa2, 0x7b, 0x94, 0x7d, 0x16, 0x71, + 0xe5, 0x99, 0x22, 0x8f, 0xdf, 0x47, 0xa9, 0x27, 0xec, 0x89, 0x08, 0x1d, + 0xa1, 0x53, 0x22, 0x67, 0x06, 0xf1, 0x3d, 0xe4, 0x1c, 0xdc, 0x2b, 0x9e, + 0x2f, 0x7d, 0x19, 0x77, 0x22, 0xa7, 0x6e, 0xfb, 0xf9, 0xfb, 0xba, 0x56, + 0x2f, 0x2a, 0x9e, 0xb9, 0xaa, 0x68, 0x4a, 0x9c, 0xe3, 0xeb, 0x9f, 0x31, + 0xea, 0xaf, 0x8f, 0x18, 0xf1, 0x62, 0xdc, 0x88, 0xae, 0x60, 0xdc, 0x33, + 0x46, 0xac, 0x08, 0x1b, 0x52, 0xe3, 0x88, 0x1d, 0x06, 0xbd, 0x6d, 0xd0, + 0xd6, 0xb1, 0x88, 0x02, 0xd5, 0xd4, 0x49, 0x6c, 0x63, 0xde, 0x87, 0xaa, + 0xe6, 0xad, 0xe1, 0x8b, 0xef, 0xf0, 0xf7, 0x44, 0x18, 0xa6, 0x5a, 0xaf, + 0x6d, 0x83, 0x7f, 0x7d, 0x22, 0x45, 0x9b, 0xe9, 0xb5, 0x76, 0x9d, 0x5e, + 0x5b, 0xd8, 0x72, 0xde, 0x1f, 0x95, 0xc6, 0x65, 0x3d, 0xa2, 0xdf, 0x11, + 0xfa, 0x2b, 0xcf, 0xbb, 0x4a, 0xb7, 0xad, 0xc1, 0x29, 0x8c, 0xd1, 0x7e, + 0x70, 0xed, 0x07, 0xeb, 0x52, 0xf9, 0xc0, 0x3a, 0x3f, 0xa1, 0x0d, 0xf5, + 0x5e, 0xa6, 0xcc, 0x6b, 0x85, 0x8d, 0xb5, 0xce, 0xf3, 0x83, 0xbd, 0xf5, + 0xa0, 0x98, 0x23, 0xdb, 0x5b, 0x56, 0x8c, 0xa4, 0xaf, 0x7b, 0xbe, 0x58, + 0x55, 0xff, 0xe9, 0x51, 0x07, 0x39, 0xe2, 0x51, 0x07, 0xe9, 0xa6, 0xb5, + 0x80, 0x8b, 0xd6, 0x42, 0x2e, 0xbd, 0x6d, 0x88, 0xed, 0x96, 0x0e, 0xe6, + 0x21, 0xb0, 0x5b, 0xda, 0xc8, 0xff, 0xb2, 0xdb, 0x6e, 0xa9, 0xad, 0x45, + 0x07, 0xdd, 0x41, 0x37, 0x93, 0x36, 0x4c, 0x3c, 0x57, 0xae, 0x63, 0xe7, + 0x75, 0x57, 0x6a, 0x0e, 0x57, 0xea, 0xea, 0x23, 0xbd, 0xe6, 0x3b, 0x5c, + 0x37, 0x5f, 0xc8, 0xaf, 0x48, 0x43, 0x9d, 0xce, 0xcb, 0xae, 0xba, 0x53, + 0xf3, 0xab, 0xe5, 0x67, 0x78, 0xd6, 0x88, 0xf0, 0x79, 0xa7, 0xca, 0xbc, + 0x6c, 0x5a, 0xce, 0x37, 0x53, 0x6d, 0x67, 0xf8, 0x97, 0x48, 0xc1, 0xce, + 0x9b, 0xb7, 0xef, 0xcc, 0x7f, 0xd6, 0x5e, 0x23, 0x77, 0xdf, 0x33, 0xa5, + 0x5f, 0xac, 0x49, 0xe5, 0x61, 0xf7, 0x29, 0x7b, 0x6f, 0x2b, 0x7c, 0xc7, + 0xb9, 0x26, 0xe5, 0x4b, 0xb4, 0xad, 0x3c, 0x01, 0xcf, 0x8f, 0x9d, 0x68, + 0x72, 0x4c, 0x15, 0xcb, 0x42, 0xbc, 0x0a, 0x78, 0xaf, 0xef, 0x0f, 0x9e, + 0xbd, 0x9d, 0x3d, 0xb3, 0xea, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x2d, 0xe4, + 0x17, 0x4f, 0xd6, 0xe4, 0x78, 0x7f, 0x14, 0x58, 0x74, 0x79, 0xe4, 0x3d, + 0x23, 0x6f, 0xb9, 0xd1, 0x3c, 0xaf, 0xbb, 0xf4, 0x72, 0xcc, 0xb7, 0x54, + 0x7a, 0x23, 0x3c, 0x20, 0x65, 0x71, 0xd1, 0x5b, 0x47, 0x32, 0xb7, 0x3d, + 0xbf, 0x5a, 0xd9, 0xbb, 0x77, 0x9b, 0xb2, 0x57, 0xf4, 0xf4, 0xf0, 0x1d, + 0x14, 0x3c, 0xa0, 0x83, 0x56, 0x72, 0xc8, 0xbf, 0xfe, 0x05, 0xd0, 0x3c, + 0xf3, 0x59, 0x57, 0x4d, 0x9a, 0xf7, 0x3e, 0x96, 0x63, 0x2a, 0x81, 0x19, + 0xc4, 0xfe, 0x90, 0x5b, 0xd2, 0xcb, 0xbc, 0x07, 0xe3, 0xc7, 0xac, 0xab, + 0xf0, 0xf7, 0x2a, 0xff, 0x53, 0x5c, 0xc9, 0x97, 0x83, 0xdb, 0x88, 0xad, + 0xec, 0x8c, 0x4f, 0xdb, 0xd6, 0x3a, 0x21, 0xee, 0x83, 0x7c, 0xe1, 0xfb, + 0xba, 0xa8, 0xeb, 0x33, 0x2d, 0x2d, 0xce, 0x97, 0x7a, 0x64, 0x2c, 0x0a, + 0xbf, 0x75, 0xd0, 0x2b, 0x39, 0xe4, 0x72, 0xe3, 0xb7, 0xdf, 0xe0, 0xdf, + 0xbc, 0x78, 0x94, 0xce, 0x45, 0x87, 0x2e, 0x27, 0xf7, 0x27, 0x4f, 0xb0, + 0x95, 0x4a, 0xf4, 0xb7, 0xe1, 0x5f, 0x94, 0xf1, 0x8c, 0xe2, 0x9d, 0x8e, + 0xd5, 0x78, 0xf9, 0x0b, 0xdf, 0xec, 0xb9, 0xdd, 0xdc, 0xc8, 0x2f, 0x6c, + 0xcb, 0x5f, 0x88, 0x38, 0xff, 0x76, 0x62, 0x26, 0x3a, 0x36, 0x3c, 0x25, + 0x6a, 0x4e, 0xdd, 0x78, 0x70, 0x67, 0xe2, 0xc3, 0xc0, 0x87, 0xe1, 0x3a, + 0x5e, 0xf5, 0xd1, 0xfd, 0xfd, 0xb5, 0x70, 0x6d, 0xf3, 0xf4, 0x55, 0x79, + 0xc7, 0x81, 0x11, 0xf3, 0x87, 0x9f, 0xfa, 0x21, 0x9a, 0xbf, 0x08, 0x1c, + 0x36, 0x18, 0xdb, 0x46, 0x69, 0x21, 0x88, 0xba, 0x22, 0x51, 0x9b, 0xa3, + 0xe2, 0x86, 0xb2, 0x56, 0x68, 0x5e, 0xd4, 0x40, 0x8e, 0x85, 0x6e, 0xf2, + 0xbc, 0xe7, 0x8b, 0x29, 0x3a, 0xc5, 0x32, 0xf6, 0xd4, 0x4a, 0x45, 0x77, + 0xaf, 0xaf, 0x83, 0xac, 0xc6, 0xf1, 0x9b, 0x02, 0xc7, 0x87, 0x36, 0xc5, + 0xf1, 0xc3, 0x65, 0x1c, 0xff, 0x44, 0xaf, 0xc4, 0xe7, 0x67, 0xf9, 0x5e, + 0x5d, 0x74, 0x50, 0xdc, 0x37, 0xc5, 0xdf, 0xdb, 0xe9, 0xa0, 0xec, 0x61, + 0xc1, 0xcf, 0x66, 0x1e, 0x9f, 0x49, 0xd1, 0x53, 0x17, 0x53, 0xbe, 0xb8, + 0xa8, 0x5f, 0x70, 0xf7, 0xe8, 0xd0, 0xd7, 0x63, 0x5c, 0x23, 0xfc, 0xd7, + 0x7c, 0x49, 0xd6, 0x5c, 0xe5, 0x25, 0x7f, 0xa2, 0x77, 0xc3, 0x83, 0x35, + 0xf8, 0x5f, 0x6d, 0x3b, 0x9e, 0x56, 0x32, 0xf0, 0xd8, 0x26, 0x7e, 0x8d, + 0x7a, 0xbc, 0xec, 0xf1, 0xd0, 0x87, 0x7f, 0xbd, 0x57, 0xc6, 0xa9, 0x36, + 0xf3, 0x6b, 0xb8, 0x71, 0xb4, 0x2a, 0x6e, 0xcf, 0x7c, 0xff, 0xbf, 0x55, + 0x1c, 0xfd, 0xa5, 0x5e, 0x29, 0x2f, 0x50, 0x1f, 0x98, 0x60, 0x38, 0x9c, + 0x64, 0x5d, 0x65, 0x90, 0x9a, 0x5f, 0xd6, 0x6b, 0x1d, 0x14, 0xfc, 0xd6, + 0xed, 0xa7, 0x39, 0xa7, 0x6a, 0xbb, 0xd3, 0xae, 0x35, 0x9d, 0x13, 0x36, + 0x4e, 0x63, 0x7a, 0x6b, 0x9c, 0x73, 0x35, 0x54, 0x23, 0x13, 0x6a, 0xf1, + 0x0d, 0xbd, 0x4f, 0xb0, 0xbf, 0x64, 0x48, 0x3d, 0x78, 0x9a, 0xf5, 0xdb, + 0x9d, 0xc6, 0x8b, 0x3e, 0xaa, 0x8e, 0x58, 0xdb, 0x53, 0xa3, 0xf6, 0x3b, + 0xf6, 0x41, 0xda, 0x1c, 0xc9, 0x57, 0x1f, 0x12, 0xbc, 0xe0, 0xdc, 0x64, + 0x89, 0x62, 0xe1, 0x4e, 0x4a, 0x4e, 0xf2, 0xb3, 0xa7, 0x1d, 0xb6, 0xbd, + 0xfc, 0x94, 0x62, 0xfa, 0x4d, 0x4e, 0xee, 0x52, 0xfa, 0xa2, 0xf6, 0xa7, + 0xb7, 0xa8, 0x3c, 0x87, 0x67, 0x45, 0x5c, 0x52, 0xf6, 0xc6, 0xe0, 0xef, + 0x2b, 0xfa, 0xde, 0xcf, 0x8a, 0xf8, 0x68, 0xf2, 0x62, 0xb3, 0x1a, 0xd7, + 0xee, 0x1a, 0x87, 0x31, 0xed, 0x6a, 0x2c, 0xee, 0xa9, 0x75, 0x8a, 0x56, + 0xc5, 0x6f, 0x1f, 0x11, 0x75, 0x60, 0xb2, 0x56, 0x0f, 0xbf, 0x9f, 0xa6, + 0xb9, 0xf2, 0x5a, 0xda, 0x79, 0xec, 0xcf, 0x4a, 0x11, 0x61, 0xcb, 0xb5, + 0xb3, 0xce, 0x8b, 0x79, 0xd7, 0xcf, 0x09, 0x6b, 0xf1, 0x8b, 0xf8, 0x10, + 0x7f, 0x57, 0xcf, 0x39, 0x59, 0x9e, 0x13, 0x72, 0x34, 0xec, 0x90, 0xbc, + 0x97, 0x1e, 0xd7, 0xee, 0x1a, 0xa7, 0x79, 0x85, 0x8e, 0x3f, 0xfc, 0x80, + 0xe7, 0xf1, 0x37, 0x2a, 0x87, 0xd7, 0x14, 0xf1, 0x53, 0x99, 0xa3, 0xa1, + 0xbf, 0xc3, 0xbf, 0x8c, 0x9c, 0x0a, 0xe4, 0x49, 0xb8, 0xf9, 0x8d, 0x5c, + 0x6f, 0x00, 0xb2, 0xa8, 0x88, 0xb8, 0x29, 0xe2, 0x15, 0x8d, 0x74, 0xe7, + 0xbd, 0xc8, 0xcd, 0xdf, 0x81, 0x0e, 0xba, 0x1d, 0xfa, 0xb3, 0x3c, 0xe8, + 0xcf, 0xfd, 0x7c, 0xd4, 0xc1, 0xa1, 0x1e, 0x2e, 0x35, 0x61, 0x50, 0x89, + 0x6d, 0x05, 0x83, 0xf2, 0xa6, 0x8f, 0x9e, 0x72, 0xec, 0xf0, 0x0a, 0xc9, + 0x9a, 0xc9, 0xd8, 0xa2, 0x3d, 0xb1, 0x4e, 0xfb, 0x45, 0xcd, 0x38, 0x7a, + 0x1f, 0xe4, 0x59, 0x06, 0x9f, 0xa4, 0x09, 0xb6, 0x8f, 0xd8, 0xfe, 0x9c, + 0x45, 0xbc, 0x45, 0xef, 0x0b, 0x6a, 0xe0, 0xf1, 0x39, 0xc1, 0x70, 0x7a, + 0x6c, 0x37, 0xb5, 0x45, 0xf8, 0x9e, 0x13, 0xe0, 0x4f, 0xe8, 0xe7, 0x45, + 0x51, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x9c, 0xb5, 0xcd, 0x3c, 0x19, 0x3c, + 0x16, 0xb6, 0x2b, 0xee, 0x83, 0xeb, 0x23, 0x66, 0x13, 0xd5, 0xd6, 0xe4, + 0x3e, 0x2b, 0xea, 0x14, 0xdf, 0x0d, 0xdf, 0x47, 0x46, 0x3f, 0xf8, 0x15, + 0xf6, 0xed, 0x5e, 0x15, 0x27, 0x3a, 0xcb, 0xdf, 0xc7, 0xd5, 0xf7, 0xaf, + 0x88, 0xfd, 0x94, 0xdf, 0x35, 0x7e, 0xe3, 0xef, 0x5f, 0x5a, 0xc8, 0xf9, + 0xa1, 0xca, 0x59, 0xa9, 0xca, 0x05, 0x09, 0x8d, 0x1a, 0x5f, 0xa1, 0xd3, + 0x2b, 0x9b, 0xf9, 0x5f, 0xbc, 0x6a, 0x5d, 0xbb, 0xb7, 0x59, 0xeb, 0xfa, + 0x07, 0xbb, 0x65, 0x6d, 0x99, 0x7b, 0x2e, 0xff, 0xc9, 0x73, 0xf1, 0xd2, + 0xc9, 0xea, 0xf4, 0x44, 0x5e, 0x6f, 0x89, 0xfe, 0x29, 0xfc, 0x49, 0xba, + 0x1e, 0x0c, 0xa9, 0x9c, 0x25, 0xe4, 0x28, 0xdd, 0xa7, 0xf0, 0x5a, 0xf3, + 0x7e, 0xf2, 0xe0, 0xfd, 0x8f, 0x89, 0x5c, 0x4d, 0x29, 0x3b, 0x06, 0x15, + 0x3c, 0x00, 0xb3, 0x90, 0x0b, 0x66, 0x7d, 0x2e, 0x98, 0x19, 0xea, 0x7b, + 0xa7, 0x38, 0x3e, 0xbd, 0xf2, 0x99, 0x6e, 0x59, 0x2f, 0x8e, 0x58, 0xe2, + 0xbc, 0xfa, 0xbe, 0xd5, 0x7a, 0x7f, 0xce, 0x6b, 0x15, 0xfe, 0x26, 0xd7, + 0x5a, 0x5f, 0x27, 0x72, 0x5a, 0x82, 0xf5, 0x30, 0xf8, 0x8e, 0xeb, 0x3c, + 0xe6, 0x38, 0xe6, 0x9a, 0xe3, 0x88, 0x6b, 0x8e, 0x77, 0x37, 0x98, 0x23, + 0xf3, 0xf8, 0xe2, 0x69, 0xfe, 0xbf, 0xdd, 0xb9, 0xca, 0x79, 0xce, 0x0b, + 0x78, 0xb6, 0x53, 0x3a, 0x18, 0x52, 0xb2, 0xe3, 0xfb, 0xaa, 0x16, 0xdd, + 0x6b, 0xce, 0xff, 0x40, 0x8d, 0xf7, 0xcd, 0x8d, 0xab, 0xee, 0xfa, 0xe3, + 0x97, 0x28, 0x26, 0xeb, 0xc8, 0x15, 0x6d, 0x7f, 0xb5, 0x81, 0x1f, 0xfa, + 0x41, 0xa1, 0xff, 0xcc, 0xcb, 0x78, 0xd0, 0x80, 0xec, 0xbf, 0x16, 0xa0, + 0xd5, 0x72, 0x2d, 0xaf, 0x5f, 0xd5, 0xee, 0xdc, 0x1f, 0xbc, 0xb3, 0x75, + 0xbc, 0x38, 0xff, 0x88, 0xf0, 0xe5, 0xc9, 0xf8, 0x51, 0x42, 0xd5, 0x23, + 0xdb, 0x16, 0x72, 0x03, 0x0a, 0x6b, 0xf0, 0xbf, 0x36, 0xaa, 0xdd, 0xc5, + 0xb5, 0xf0, 0x03, 0x6a, 0x3b, 0xfe, 0x84, 0xe0, 0x89, 0xd2, 0x3f, 0x26, + 0xeb, 0x6f, 0x0b, 0x6b, 0x27, 0x45, 0xcd, 0x6b, 0x54, 0xd5, 0xf1, 0x26, + 0xa9, 0x43, 0xe8, 0xb9, 0xb7, 0x5f, 0x7f, 0xfb, 0x5c, 0x70, 0xe7, 0xf5, + 0xb7, 0xee, 0x6b, 0x76, 0x56, 0x7f, 0x6b, 0xf2, 0xda, 0x8d, 0x65, 0x59, + 0x7f, 0x5b, 0x1d, 0x93, 0x91, 0xfe, 0xc0, 0xa4, 0x4b, 0x7f, 0x90, 0xfa, + 0xfa, 0x6f, 0xb9, 0xf2, 0xb7, 0x65, 0x6d, 0x6d, 0xa1, 0xac, 0xb3, 0xca, + 0xda, 0x5a, 0x99, 0xef, 0xed, 0xee, 0x03, 0x23, 0x63, 0x3f, 0xf2, 0x39, + 0x9d, 0x35, 0xb1, 0x1f, 0x59, 0x53, 0x6b, 0x19, 0x8d, 0x6c, 0x38, 0xd1, + 0xe7, 0xa2, 0x8f, 0xba, 0x22, 0x8c, 0xbb, 0xed, 0x0d, 0xfa, 0x21, 0x44, + 0x1a, 0xf4, 0x43, 0x70, 0xf3, 0x7e, 0xb7, 0x8e, 0x05, 0x9d, 0x18, 0xb2, + 0x11, 0xba, 0x30, 0xfa, 0x19, 0x84, 0xe9, 0x74, 0x59, 0xf7, 0xbc, 0x8f, + 0x12, 0x4a, 0xf7, 0x3c, 0xbd, 0xa2, 0xf9, 0xd1, 0x48, 0x0d, 0x3f, 0xf2, + 0xd2, 0x45, 0x6d, 0x95, 0xe7, 0xa3, 0xe9, 0x35, 0xe5, 0xa2, 0xd7, 0x94, + 0x07, 0xbd, 0x8a, 0x67, 0x34, 0x98, 0xf7, 0xf7, 0xd5, 0x35, 0xf8, 0x4f, + 0x84, 0xd0, 0xb3, 0x85, 0x79, 0x6a, 0x50, 0xe9, 0x7f, 0x2e, 0x7a, 0x3d, + 0xc5, 0xf4, 0xaa, 0xcf, 0x63, 0xbe, 0x0d, 0x73, 0x41, 0x95, 0xce, 0x38, + 0xe8, 0x3b, 0x74, 0xf1, 0x1b, 0x22, 0x4f, 0xaa, 0xda, 0x5e, 0xd4, 0xfa, + 0xc4, 0x3e, 0x41, 0x4b, 0xd7, 0xfd, 0xc8, 0x5b, 0xd1, 0xe7, 0x4c, 0xe5, + 0x27, 0xd3, 0xb0, 0x68, 0xae, 0xd2, 0x39, 0x2a, 0xfa, 0x86, 0xc8, 0xf1, + 0x75, 0xcd, 0xed, 0x43, 0x9e, 0x9b, 0x3e, 0xaf, 0x65, 0xe6, 0xb5, 0x2a, + 0x7f, 0xc6, 0xe5, 0xaa, 0x9e, 0x83, 0xf0, 0x1d, 0x75, 0x26, 0x0c, 0x27, + 0x2e, 0x72, 0x4c, 0x7b, 0x1c, 0xf8, 0xc9, 0xa2, 0x4c, 0xfb, 0x3d, 0x09, + 0xe4, 0x33, 0xf7, 0x2c, 0x59, 0x74, 0x3c, 0x73, 0xff, 0x5d, 0x12, 0x57, + 0xce, 0x8a, 0x3e, 0x92, 0xe8, 0x67, 0x16, 0x63, 0xf9, 0x1c, 0xf5, 0x4f, + 0xd3, 0xf9, 0x62, 0x0b, 0x15, 0x58, 0xbb, 0xf7, 0x3b, 0x79, 0xe1, 0xeb, + 0x63, 0x9e, 0x94, 0x45, 0x2f, 0x51, 0x63, 0xb9, 0x99, 0xef, 0xdb, 0x4f, + 0xab, 0xb9, 0x31, 0xd1, 0x13, 0x4a, 0xf6, 0x17, 0xc1, 0x58, 0x1f, 0xf5, + 0x3a, 0x07, 0xfb, 0xa8, 0xed, 0xb3, 0x22, 0xc7, 0xb2, 0x90, 0x3d, 0x2b, + 0x3f, 0xf3, 0x0f, 0xa8, 0x67, 0xf0, 0xf3, 0x8a, 0x7f, 0x4a, 0x91, 0x5e, + 0xcb, 0x65, 0xcb, 0xb9, 0xff, 0xbc, 0xf5, 0x95, 0xa3, 0x3b, 0xd2, 0x57, + 0x52, 0x89, 0x8a, 0xbe, 0xe2, 0xbe, 0x77, 0x39, 0x07, 0xa6, 0x5f, 0xf6, + 0x7b, 0x00, 0x0c, 0xda, 0xa1, 0x8b, 0x25, 0x00, 0x4b, 0x63, 0xc6, 0x0e, + 0x45, 0xfd, 0x53, 0xb4, 0x50, 0x1c, 0x32, 0x92, 0x59, 0xe8, 0xcc, 0xfc, + 0x99, 0x8f, 0xee, 0x91, 0x3e, 0x1a, 0x7d, 0x0d, 0xf8, 0xca, 0x6e, 0x1e, + 0xff, 0x7a, 0xbf, 0xcc, 0xcb, 0x76, 0x9f, 0xef, 0xe2, 0xf3, 0x7b, 0x42, + 0xd5, 0xe7, 0x77, 0xf1, 0xf9, 0xde, 0x04, 0xf6, 0xd0, 0x58, 0x82, 0x5f, + 0xd2, 0xa1, 0x34, 0xef, 0xcd, 0x42, 0x91, 0x65, 0xeb, 0xcb, 0xcc, 0x47, + 0x57, 0xf4, 0xb8, 0x3e, 0xd4, 0xec, 0x88, 0x3d, 0x31, 0x78, 0xcc, 0xb9, + 0xcc, 0x04, 0x8f, 0x1b, 0x24, 0xff, 0xcb, 0x6c, 0x8b, 0xae, 0x68, 0x5c, + 0xd5, 0xf9, 0xf6, 0xdf, 0xe8, 0x93, 0x39, 0x55, 0xdf, 0xdd, 0x23, 0xe1, + 0xe7, 0x08, 0x9e, 0x72, 0x9e, 0xe1, 0xf2, 0xbc, 0xc0, 0x43, 0x7b, 0xda, + 0x2a, 0x3f, 0xbf, 0x13, 0x78, 0xd5, 0x8a, 0xbc, 0xd9, 0xc0, 0x12, 0xf3, + 0xc5, 0x19, 0xc7, 0x4c, 0x97, 0x73, 0xd5, 0x1e, 0x1f, 0x90, 0xd7, 0xbf, + 0xd9, 0x27, 0xfb, 0x83, 0x7e, 0x6b, 0x40, 0xf7, 0x48, 0x94, 0x32, 0x07, + 0xf9, 0xcb, 0x3e, 0x01, 0x1b, 0xff, 0x32, 0xf8, 0xa5, 0xc1, 0xdf, 0x79, + 0x3d, 0x09, 0xcc, 0xf1, 0x4a, 0x9f, 0xee, 0x17, 0x23, 0xd7, 0x15, 0xe7, + 0xf9, 0x46, 0x78, 0x5d, 0xfa, 0xfc, 0x0c, 0x1f, 0x7b, 0xed, 0x2f, 0xee, + 0xd5, 0x96, 0x90, 0xfd, 0xc5, 0xda, 0x12, 0xc9, 0x09, 0xb9, 0xcf, 0x15, + 0x9f, 0x6e, 0xa8, 0xec, 0xd3, 0x3d, 0x9f, 0xb9, 0xd5, 0x07, 0xff, 0x86, + 0xb1, 0xc4, 0xfb, 0x1d, 0x7c, 0x9e, 0xc7, 0xa2, 0x56, 0x21, 0xcd, 0x9f, + 0x1d, 0x2a, 0xaf, 0xa7, 0x1e, 0x57, 0x64, 0x9e, 0x84, 0x96, 0x5b, 0xb8, + 0xf6, 0x43, 0xbe, 0x87, 0x94, 0x5d, 0x8d, 0x9f, 0x43, 0x75, 0x79, 0x30, + 0xf5, 0x38, 0xb6, 0x99, 0x1f, 0x56, 0xc4, 0x13, 0x3d, 0xf0, 0x6c, 0xb3, + 0x7e, 0x06, 0xd7, 0x84, 0x1f, 0x2d, 0x56, 0x47, 0xaf, 0xa0, 0xe3, 0x00, + 0xfd, 0xce, 0x62, 0x8a, 0x76, 0xf1, 0x5e, 0xfd, 0xa6, 0xf1, 0x00, 0xe2, + 0xed, 0x24, 0x73, 0x9e, 0x18, 0xc6, 0x19, 0x67, 0xe2, 0x94, 0x11, 0x01, + 0xbf, 0x2c, 0x05, 0x9c, 0x0e, 0x6a, 0x66, 0x5a, 0xfd, 0x65, 0x1a, 0x65, + 0xfb, 0x0f, 0x34, 0xeb, 0x84, 0xe2, 0x04, 0x7a, 0xb3, 0xcd, 0x43, 0xac, + 0x13, 0xc7, 0x8a, 0xc0, 0x67, 0x83, 0x3e, 0x9f, 0x23, 0xfa, 0x5c, 0x6e, + 0xd4, 0xfc, 0x26, 0x39, 0x56, 0xe5, 0x77, 0xdb, 0x8c, 0xf2, 0x3c, 0xe2, + 0xc5, 0x2f, 0xd3, 0xfb, 0xa2, 0xcf, 0x09, 0xe0, 0xa8, 0xf7, 0xfd, 0x4b, + 0x74, 0x32, 0x81, 0x79, 0x6f, 0x9f, 0x3e, 0x8f, 0xef, 0x88, 0x3e, 0xdb, + 0x3c, 0xe8, 0xf3, 0xc5, 0x7e, 0x89, 0x37, 0x25, 0xc6, 0xd1, 0x36, 0x9a, + 0xcb, 0x22, 0x07, 0xec, 0xd3, 0xe8, 0x3b, 0x95, 0x4d, 0x32, 0x5f, 0x4a, + 0x56, 0xf8, 0xd2, 0x85, 0x28, 0x1b, 0xc3, 0x4c, 0xe3, 0xe8, 0xcb, 0xa6, + 0xf2, 0x7e, 0xb0, 0x8e, 0x01, 0x1a, 0x5d, 0x6e, 0xe7, 0x6b, 0x69, 0x3d, + 0x3a, 0x15, 0x51, 0xb5, 0xfe, 0xb6, 0x15, 0x63, 0xfe, 0x78, 0x9e, 0x69, + 0x39, 0x9d, 0xbd, 0x97, 0x0a, 0xc1, 0x21, 0x1a, 0x59, 0xd6, 0xfd, 0x4d, + 0x44, 0xce, 0xc6, 0xa0, 0xe4, 0x49, 0x7a, 0xdd, 0x9f, 0x10, 0xbe, 0x0b, + 0xeb, 0xd2, 0xc7, 0xb5, 0xee, 0xf6, 0x2d, 0xf8, 0xd2, 0x25, 0x45, 0xb3, + 0xa5, 0xcb, 0xd1, 0x30, 0xa5, 0xa2, 0x53, 0xaf, 0xf4, 0x03, 0xff, 0x47, + 0x2e, 0xc1, 0x0f, 0x07, 0x1e, 0x6d, 0x51, 0x22, 0x53, 0x0b, 0x8b, 0x21, + 0x5e, 0x37, 0x7e, 0x2f, 0x7d, 0x30, 0x17, 0x7e, 0x40, 0xc8, 0xfe, 0xd1, + 0x4b, 0x3c, 0x4e, 0xca, 0x26, 0xc5, 0x37, 0xbc, 0xf0, 0x50, 0xf7, 0xc5, + 0xd4, 0xb8, 0x28, 0x73, 0x3d, 0x59, 0x7f, 0x33, 0x13, 0xfe, 0x5a, 0x9c, + 0xbc, 0xe6, 0x3b, 0xba, 0x68, 0xd1, 0xb1, 0x8c, 0xfd, 0xf5, 0x14, 0x4d, + 0x31, 0x5d, 0xbb, 0xe5, 0x05, 0x8f, 0x27, 0xe0, 0xd9, 0x34, 0xd3, 0x3e, + 0xdb, 0xcd, 0x59, 0x4b, 0xe6, 0xdd, 0x89, 0xde, 0x73, 0x38, 0x46, 0xdd, + 0xf1, 0x5f, 0xf5, 0x6b, 0x79, 0x90, 0xcc, 0xa2, 0x8e, 0x90, 0x3f, 0xf3, + 0x3c, 0x1e, 0xb9, 0xff, 0x39, 0xdc, 0x07, 0xf2, 0x0e, 0x73, 0xe7, 0xe3, + 0x55, 0xb9, 0xaf, 0x23, 0x7c, 0x6f, 0xd4, 0xdd, 0x1f, 0x2b, 0x4e, 0xf2, + 0xfe, 0x76, 0x09, 0xde, 0x2c, 0xf7, 0x73, 0x9a, 0xce, 0x79, 0xf2, 0x15, + 0xb9, 0x2f, 0x49, 0x17, 0x7d, 0x27, 0x05, 0x7d, 0x4f, 0x8b, 0xfd, 0x48, + 0xe6, 0x0c, 0xd6, 0xd7, 0xb4, 0xef, 0x81, 0xed, 0xec, 0x5c, 0x40, 0xe7, + 0x06, 0xf2, 0xf7, 0x0f, 0xfb, 0x45, 0x5e, 0x22, 0xec, 0xef, 0x1c, 0x3e, + 0xa7, 0xe9, 0x79, 0x96, 0xeb, 0x2f, 0x64, 0x5a, 0xe8, 0x6a, 0xb6, 0x85, + 0xde, 0xc9, 0x0e, 0xd1, 0x95, 0xc5, 0x6e, 0x3a, 0xc7, 0x3a, 0xf3, 0x39, + 0x27, 0x60, 0xa5, 0xa9, 0x1b, 0xf1, 0x45, 0xe4, 0x0c, 0x31, 0xdd, 0x61, + 0x3c, 0xf4, 0xbf, 0xe8, 0x5e, 0xc6, 0x39, 0xd6, 0xbd, 0x5b, 0xe9, 0x3d, + 0x7e, 0x66, 0x3a, 0xa3, 0x73, 0x1d, 0xe0, 0x93, 0x1f, 0x2b, 0xeb, 0xaf, + 0x5b, 0xe3, 0x88, 0xb9, 0x05, 0x8e, 0x4c, 0x8b, 0xf8, 0xd6, 0xc2, 0x22, + 0xff, 0xbe, 0x08, 0xff, 0x39, 0xc3, 0x9b, 0xf9, 0xf3, 0x93, 0x01, 0x8c, + 0xc7, 0x39, 0x47, 0xe6, 0x4a, 0x8a, 0xb5, 0x85, 0xf8, 0xd8, 0x27, 0x6a, + 0xa4, 0x25, 0x1c, 0x5a, 0x79, 0x7d, 0x3e, 0x31, 0x3e, 0xb9, 0xda, 0x4a, + 0xf3, 0x39, 0xd6, 0x41, 0x72, 0x7e, 0xb6, 0x61, 0x30, 0xf6, 0xef, 0x54, + 0x6f, 0x61, 0xdc, 0xbf, 0x8b, 0xd2, 0x62, 0x1c, 0x7f, 0xae, 0x76, 0xd1, + 0x42, 0xae, 0x43, 0x1d, 0xdf, 0x2b, 0x72, 0xdc, 0x65, 0x1f, 0x23, 0xfc, + 0xb6, 0x19, 0x7f, 0x7b, 0x97, 0x71, 0x0a, 0x32, 0x55, 0xda, 0xa5, 0xe0, + 0x35, 0x97, 0xeb, 0x7a, 0x22, 0x03, 0xe7, 0xa6, 0xe8, 0x25, 0x96, 0xb7, + 0x23, 0x2f, 0xc3, 0x7f, 0xfc, 0x38, 0xf0, 0x26, 0x9f, 0xa2, 0x41, 0x3e, + 0x46, 0x5f, 0x24, 0xbf, 0xa8, 0x73, 0x8a, 0x05, 0x27, 0x44, 0x6d, 0x88, + 0xa4, 0xd1, 0x59, 0xd1, 0x8b, 0xee, 0x2d, 0xc1, 0x9b, 0xec, 0x94, 0x65, + 0x40, 0x1f, 0x81, 0x0f, 0x46, 0xe6, 0x60, 0x1d, 0x77, 0x7a, 0xde, 0xed, + 0x9b, 0x19, 0xa7, 0x48, 0x3f, 0xf0, 0x5e, 0xd2, 0xac, 0xea, 0x2f, 0x20, + 0xf8, 0xbd, 0xb9, 0x4f, 0xd7, 0x4b, 0xea, 0x63, 0x2d, 0x2b, 0xf4, 0x71, + 0x47, 0xcd, 0xef, 0x66, 0xcd, 0xef, 0xe5, 0x7c, 0x39, 0x96, 0x79, 0x2c, + 0xe7, 0x49, 0xf6, 0x28, 0x4a, 0x2e, 0x4b, 0xfc, 0x33, 0xf7, 0x8d, 0x99, + 0x8f, 0x2a, 0x1d, 0x3c, 0xb9, 0x36, 0x1a, 0xea, 0x31, 0x26, 0x8c, 0xe4, + 0xe4, 0x3f, 0x96, 0x22, 0x09, 0xe8, 0x45, 0x4f, 0xee, 0x51, 0xf9, 0xa7, + 0x3c, 0xaf, 0x54, 0x18, 0xaa, 0xdb, 0xec, 0x5a, 0x07, 0xad, 0x8b, 0x9e, + 0x5c, 0x42, 0xc7, 0xe0, 0xeb, 0x71, 0x9f, 0x94, 0xd9, 0x44, 0xe8, 0x73, + 0x0e, 0x1a, 0xdf, 0x1f, 0xba, 0xc4, 0xfb, 0x19, 0x5f, 0xfb, 0x69, 0xe9, + 0xa4, 0xe8, 0x71, 0x83, 0xb1, 0x5d, 0x34, 0x27, 0x74, 0x7e, 0xd6, 0x5f, + 0xaa, 0xec, 0xaa, 0x29, 0xcc, 0x33, 0x85, 0xd8, 0x8a, 0xe1, 0xfc, 0xbe, + 0x2f, 0x99, 0x97, 0xb1, 0xf2, 0x78, 0x4d, 0xac, 0x7c, 0x56, 0xc4, 0xca, + 0x11, 0x27, 0x07, 0x5c, 0x01, 0x4b, 0xaf, 0x9c, 0x16, 0xec, 0x63, 0x98, + 0x90, 0x1b, 0x7e, 0xee, 0xa2, 0xe0, 0x37, 0xe1, 0x98, 0x5f, 0xe6, 0x57, + 0xc7, 0x79, 0xc6, 0x06, 0x5d, 0x60, 0x7c, 0xb0, 0x27, 0x36, 0x58, 0x97, + 0x58, 0xc9, 0x7e, 0x99, 0xae, 0xe4, 0x9b, 0x58, 0xd7, 0x5b, 0xa0, 0x8d, + 0x3c, 0xb1, 0x4e, 0xd8, 0x4d, 0x0b, 0x61, 0xc6, 0xb1, 0x89, 0x36, 0xde, + 0x4f, 0xd6, 0x6b, 0x27, 0x98, 0xee, 0x78, 0xee, 0x2b, 0xb9, 0xd2, 0x8f, + 0xd2, 0xe1, 0x88, 0x15, 0x9d, 0xea, 0x60, 0xbb, 0xc5, 0xe4, 0x7f, 0x87, + 0xff, 0x77, 0x85, 0x00, 0x93, 0xc2, 0x2a, 0x7e, 0x67, 0x9d, 0x27, 0x53, + 0xfa, 0xd1, 0x1c, 0x8f, 0x99, 0x9b, 0x82, 0xfd, 0x03, 0x3b, 0xcf, 0xe1, + 0x7f, 0x39, 0x66, 0x65, 0x95, 0xf1, 0xfb, 0x62, 0x2a, 0x64, 0x08, 0xde, + 0xbe, 0xce, 0x3c, 0xfe, 0x02, 0xcd, 0xf1, 0x1c, 0xae, 0x10, 0xae, 0xb5, + 0x28, 0x19, 0xde, 0xc7, 0x78, 0xdf, 0xcd, 0x9f, 0xa8, 0xbf, 0x6a, 0xa7, + 0x85, 0xc9, 0x31, 0x55, 0x7f, 0xf5, 0xbd, 0x06, 0xf5, 0x57, 0xb8, 0x8e, + 0xe5, 0xfe, 0x62, 0xe9, 0xe6, 0x5c, 0xd8, 0xfd, 0x3c, 0x32, 0x92, 0xe1, + 0x4e, 0xa1, 0x23, 0xad, 0xac, 0xfa, 0xf8, 0xd9, 0x11, 0x2b, 0x39, 0xc5, + 0x73, 0xcc, 0xb9, 0xe7, 0x5d, 0xba, 0x19, 0x0b, 0x63, 0x9c, 0xbf, 0x66, + 0x1c, 0xdb, 0xca, 0x53, 0x72, 0x3d, 0x85, 0x5c, 0xe9, 0xe7, 0xd1, 0xb0, + 0x5e, 0x9f, 0xfb, 0x5a, 0xac, 0x03, 0xf4, 0xc4, 0x9f, 0x2b, 0x5d, 0xbe, + 0x2b, 0x59, 0xd8, 0xdf, 0x06, 0xe3, 0x39, 0x66, 0x34, 0x44, 0xa9, 0x15, + 0xa6, 0xef, 0x8b, 0x1d, 0xbe, 0x8d, 0xec, 0x95, 0x52, 0xb2, 0x2a, 0x97, + 0xa5, 0xda, 0xef, 0x2e, 0x6d, 0xae, 0x21, 0x72, 0x96, 0x20, 0x33, 0x21, + 0x2f, 0x53, 0x25, 0xbf, 0x03, 0xfd, 0x0e, 0xb6, 0xd0, 0x59, 0xe6, 0x57, + 0x32, 0x1f, 0x89, 0x79, 0x27, 0xf3, 0x2c, 0x49, 0x2f, 0xf1, 0xaa, 0xd7, + 0x0d, 0x48, 0x9c, 0x1d, 0xa9, 0xe4, 0x41, 0xba, 0xe2, 0xe9, 0x01, 0x57, + 0x3c, 0xdd, 0x74, 0xe5, 0x41, 0x06, 0x85, 0x3e, 0x56, 0xd1, 0xa1, 0x82, + 0x4a, 0x87, 0x82, 0xae, 0x25, 0x79, 0x59, 0xa1, 0xcc, 0xcb, 0x76, 0x6f, + 0xc1, 0xcb, 0xbc, 0x6c, 0xd3, 0x75, 0xc5, 0x37, 0xec, 0x30, 0xe4, 0xfc, + 0xe5, 0xe2, 0x34, 0xbd, 0xcd, 0x3c, 0xe2, 0xad, 0x62, 0x98, 0xf9, 0xc6, + 0x24, 0xf3, 0x8d, 0x09, 0xe6, 0x1b, 0x0e, 0xc3, 0xc0, 0xe2, 0xb5, 0x5f, + 0xf3, 0x5d, 0x59, 0x84, 0xbc, 0x98, 0xa2, 0xe7, 0x8b, 0xe0, 0xc1, 0x93, + 0xac, 0xf3, 0x5c, 0xf3, 0x6d, 0x2c, 0x76, 0x31, 0xbe, 0x4a, 0x3d, 0xa7, + 0xda, 0x8e, 0x41, 0xaf, 0x15, 0xf8, 0x87, 0xaf, 0x82, 0xcf, 0xbc, 0x91, + 0xa2, 0x4e, 0x86, 0x3d, 0xe0, 0xbc, 0x8e, 0xde, 0x14, 0xaf, 0x81, 0x96, + 0xd1, 0x13, 0xf8, 0xbb, 0xe3, 0x53, 0x3c, 0xf7, 0x4e, 0xdf, 0x02, 0xef, + 0xcb, 0xd3, 0xe1, 0x94, 0xd9, 0xcb, 0x38, 0x7f, 0xac, 0x82, 0xf3, 0xa9, + 0x34, 0xaf, 0xa0, 0x67, 0xb9, 0x9b, 0xc6, 0x0e, 0x44, 0xf7, 0xf6, 0x30, + 0x9d, 0x22, 0x37, 0xa2, 0xd2, 0xa7, 0xc7, 0x4f, 0x27, 0x83, 0x6d, 0xaa, + 0xbf, 0x8f, 0xc5, 0xf2, 0xf1, 0x03, 0xbe, 0xcf, 0x2d, 0x5f, 0x3a, 0xfb, + 0x2a, 0x3f, 0x03, 0xc7, 0x5f, 0x85, 0xff, 0x93, 0xed, 0x83, 0x56, 0xe1, + 0x3f, 0x2a, 0x88, 0xb1, 0x38, 0xb6, 0x27, 0x98, 0x97, 0x85, 0xd7, 0x0d, + 0x7b, 0x3a, 0x62, 0x30, 0xd1, 0x75, 0x99, 0xbc, 0xde, 0xd2, 0xa0, 0x8c, + 0xc1, 0xed, 0xdd, 0x2b, 0xf9, 0x06, 0xe3, 0x66, 0x30, 0x22, 0x6c, 0xb4, + 0xa6, 0x25, 0x29, 0x27, 0x0b, 0xbc, 0xcf, 0x2b, 0xe1, 0x09, 0xde, 0xe7, + 0x0e, 0x25, 0x23, 0x53, 0xfc, 0xbb, 0x90, 0xbf, 0x2c, 0x2b, 0x87, 0xd0, + 0xb3, 0xda, 0x14, 0xfd, 0x20, 0x66, 0xd1, 0x6f, 0xa7, 0x83, 0xef, 0x6b, + 0x33, 0xd6, 0x82, 0x4f, 0x7c, 0xe0, 0x4b, 0x66, 0xf1, 0x5c, 0xe0, 0x21, + 0x7f, 0xcf, 0x4f, 0xd1, 0x85, 0x8c, 0x9e, 0xc3, 0x80, 0x61, 0xbc, 0x84, + 0x79, 0xf8, 0x68, 0xb7, 0xf3, 0x43, 0x86, 0x17, 0x1f, 0xff, 0x71, 0xed, + 0x9c, 0x86, 0xd5, 0x9c, 0xd0, 0xd3, 0xb2, 0x05, 0x3d, 0x7c, 0x08, 0xbd, + 0x8f, 0x0a, 0xa2, 0xe7, 0x64, 0xb3, 0xb0, 0x4d, 0x0b, 0xc2, 0xc6, 0x28, + 0x85, 0x2a, 0x7d, 0x30, 0xef, 0xa9, 0x39, 0xf7, 0x13, 0x5f, 0x7a, 0xf1, + 0xa0, 0xd0, 0xc5, 0x46, 0x0e, 0xec, 0x55, 0xf5, 0xa7, 0x5d, 0xe2, 0xbe, + 0xc6, 0x32, 0x7e, 0x7b, 0x50, 0xfd, 0xf6, 0x49, 0xa1, 0x03, 0x23, 0x2f, + 0x2e, 0xb0, 0x24, 0xf0, 0x9c, 0xf7, 0xd7, 0x99, 0x60, 0x3c, 0x0f, 0xad, + 0xc0, 0x77, 0x2f, 0xe0, 0xa9, 0xe1, 0x01, 0x58, 0x00, 0xf7, 0x3b, 0x14, + 0xde, 0xdb, 0x56, 0xdc, 0xaf, 0xd7, 0xdd, 0x08, 0xce, 0xac, 0xd3, 0x64, + 0xb0, 0x56, 0xac, 0x69, 0x8f, 0x2f, 0x92, 0xb7, 0x8c, 0xf4, 0x22, 0x6c, + 0x1a, 0xd4, 0xb5, 0xdc, 0x85, 0xbc, 0x29, 0x9e, 0xc3, 0x1e, 0x8a, 0x24, + 0x30, 0x2f, 0x8c, 0xd3, 0x30, 0xf8, 0xb7, 0x1a, 0x58, 0xb8, 0xaf, 0xeb, + 0x56, 0xd7, 0xb5, 0x8a, 0xbd, 0x20, 0x03, 0xcf, 0xd1, 0xcf, 0xc6, 0x73, + 0xf1, 0x7c, 0x5c, 0x87, 0xfb, 0xc9, 0xfb, 0xf6, 0x31, 0x7f, 0x8e, 0x4e, + 0xc9, 0x7b, 0x19, 0x97, 0xe4, 0x6f, 0x7d, 0x8e, 0xf7, 0x7c, 0xe5, 0xfe, + 0xf9, 0x54, 0xbf, 0x1e, 0xec, 0x5f, 0x37, 0xe5, 0x85, 0x8f, 0x13, 0xbf, + 0x75, 0x8a, 0xdf, 0xa2, 0x4e, 0xa7, 0xd8, 0xd7, 0xf3, 0x7c, 0x3c, 0x9f, + 0xed, 0xf2, 0xc1, 0x36, 0x4f, 0x27, 0x3a, 0x7d, 0xf9, 0x3c, 0xd6, 0xdb, + 0xe9, 0x8b, 0x33, 0xee, 0xc7, 0xb2, 0xf1, 0xd2, 0x82, 0xe0, 0x31, 0xac, + 0xd3, 0xf6, 0xda, 0xe6, 0x49, 0xe3, 0x4f, 0x86, 0x64, 0x6f, 0x5b, 0x7c, + 0x67, 0xfa, 0xcb, 0x30, 0xfd, 0x65, 0x98, 0xfe, 0x32, 0x4c, 0x7f, 0x19, + 0xa6, 0x3f, 0xb6, 0x4b, 0xdf, 0x64, 0x99, 0xf1, 0x6d, 0x96, 0x19, 0x92, + 0x66, 0x23, 0xca, 0x8f, 0xa9, 0x69, 0xb6, 0xb6, 0x3e, 0x53, 0xd3, 0x28, + 0xe4, 0x34, 0xf9, 0x0e, 0x8f, 0x57, 0xd3, 0xea, 0x55, 0xa6, 0xd5, 0xa6, + 0x99, 0x7e, 0xba, 0x91, 0xc3, 0x9e, 0xd9, 0xd6, 0x79, 0xe6, 0xd1, 0x71, + 0x3f, 0x74, 0xaa, 0x00, 0xd3, 0x13, 0x74, 0x4a, 0x9b, 0xe1, 0xde, 0x4f, + 0x37, 0x99, 0x4f, 0xdf, 0xc8, 0x81, 0x76, 0xef, 0x52, 0xc7, 0x19, 0xa6, + 0x5d, 0xc8, 0xb9, 0x25, 0xdf, 0xd5, 0xac, 0xc1, 0xba, 0x57, 0xc0, 0x4c, + 0x12, 0xf8, 0xa8, 0xd0, 0xc7, 0x78, 0xdf, 0xd7, 0x99, 0xdf, 0xc3, 0x57, + 0x87, 0xbe, 0x5f, 0x79, 0x1f, 0xcb, 0x89, 0xd0, 0x15, 0xe6, 0xa3, 0xa7, + 0x73, 0x4b, 0x4c, 0xef, 0xbd, 0xf4, 0x85, 0x1c, 0xe4, 0x31, 0x60, 0xc4, + 0xc7, 0x79, 0x12, 0x3e, 0x30, 0x63, 0x06, 0x6b, 0x1f, 0x4b, 0x19, 0x02, + 0x4f, 0x9e, 0x01, 0x1c, 0x18, 0xf6, 0x67, 0xf6, 0xa2, 0x67, 0x7d, 0xc4, + 0x68, 0x56, 0x3e, 0x45, 0x7c, 0xc7, 0x78, 0x8c, 0x05, 0xdc, 0x70, 0xdc, + 0x28, 0xfe, 0x88, 0xf7, 0x42, 0x84, 0x19, 0x1e, 0xb5, 0x7c, 0xeb, 0x02, + 0x7a, 0x91, 0x02, 0x5e, 0xd3, 0x51, 0x3f, 0x6a, 0xc5, 0xe9, 0x39, 0xbc, + 0xff, 0xe0, 0x85, 0x22, 0xe6, 0xbd, 0x48, 0x0b, 0x41, 0xf0, 0x21, 0x3b, + 0x7c, 0x9d, 0x24, 0xec, 0x5a, 0x59, 0xbf, 0xfc, 0xbc, 0x37, 0x6f, 0xb3, + 0xa2, 0x42, 0x1f, 0x6e, 0x61, 0xfb, 0x06, 0xb0, 0x79, 0x8b, 0x71, 0x2d, + 0x0c, 0x9b, 0x5f, 0xf1, 0xb5, 0x37, 0x99, 0xe7, 0x60, 0xcf, 0x3a, 0x85, + 0x8c, 0xf1, 0xe2, 0x65, 0x1b, 0x8a, 0x97, 0x39, 0x2e, 0x5e, 0x96, 0x2e, + 0xf3, 0x32, 0xc6, 0x09, 0xc1, 0xc3, 0xc0, 0xa3, 0x66, 0x59, 0x4f, 0x94, + 0xdf, 0xa1, 0xff, 0xed, 0x16, 0x3c, 0x8b, 0x79, 0x3d, 0xdb, 0x0d, 0x85, + 0x62, 0xca, 0x77, 0x48, 0xf0, 0x0e, 0x8d, 0xd7, 0xff, 0xa3, 0xe8, 0xa1, + 0x55, 0xf0, 0x81, 0xf4, 0x2c, 0xf8, 0x95, 0xd7, 0xf8, 0xff, 0x02, 0x6c, + 0x79, 0xbc, 0x13, 0x7a, 0x8d, 0xf9, 0x58, 0x21, 0x0c, 0x9b, 0xb5, 0x43, + 0xd9, 0x36, 0xe8, 0xbb, 0xb5, 0x07, 0xb9, 0x96, 0x56, 0xb4, 0xcc, 0xc7, + 0x76, 0x2b, 0xbf, 0x05, 0xfc, 0x8c, 0xd8, 0xeb, 0x3a, 0x5d, 0xc0, 0x82, + 0x2e, 0xc0, 0x63, 0x03, 0x0c, 0x1f, 0xd1, 0x1b, 0x9c, 0xe8, 0x16, 0xc3, + 0x01, 0xfb, 0x7c, 0x0b, 0xfb, 0xcc, 0xba, 0x2c, 0x05, 0xe6, 0xa6, 0x02, + 0x03, 0x98, 0xdf, 0xc2, 0x6a, 0x85, 0x1f, 0x9e, 0xcf, 0x0c, 0x18, 0x85, + 0xac, 0x9c, 0xe3, 0xca, 0xb8, 0xe4, 0x79, 0x85, 0x3c, 0x7a, 0x7b, 0x89, + 0xb9, 0xf2, 0x1c, 0xf5, 0xfa, 0x04, 0xff, 0x52, 0x74, 0xbf, 0x1d, 0x5a, + 0x4b, 0x30, 0x5d, 0x61, 0x4f, 0x52, 0x2e, 0x9c, 0x79, 0x94, 0x9f, 0x8f, + 0x73, 0x8d, 0xd7, 0x71, 0xb3, 0xbc, 0x8e, 0x08, 0xaf, 0x03, 0x63, 0x6f, + 0xf9, 0x6e, 0xa8, 0x75, 0xdc, 0x28, 0xaf, 0x63, 0x56, 0xad, 0x83, 0xd2, + 0xc6, 0xcc, 0x6e, 0xa5, 0xc7, 0x6f, 0x79, 0xcf, 0xd6, 0x28, 0xeb, 0x27, + 0xe9, 0x55, 0xc0, 0xf3, 0x1e, 0x85, 0x2f, 0x6e, 0x7f, 0xa8, 0x7b, 0x6e, + 0xf6, 0xc4, 0x75, 0xfa, 0x5d, 0xba, 0x29, 0xf4, 0x93, 0x61, 0xd6, 0x4f, + 0x70, 0x9e, 0x16, 0xc0, 0x87, 0xd3, 0x41, 0xf4, 0x9b, 0x1d, 0x64, 0x98, + 0xb1, 0x5d, 0x35, 0xc5, 0x9f, 0xc2, 0x4f, 0x86, 0xfb, 0xe8, 0xeb, 0xbf, + 0x48, 0x37, 0x17, 0xc1, 0xab, 0xa1, 0x8f, 0xca, 0x9e, 0xb4, 0x37, 0xd7, + 0xa4, 0x9f, 0x36, 0xee, 0xe9, 0xa7, 0x85, 0x8f, 0x36, 0x0c, 0x7d, 0xdd, + 0x84, 0x3f, 0x37, 0x26, 0xde, 0x67, 0xc1, 0xc7, 0x45, 0xdc, 0xcb, 0x8b, + 0xef, 0x4c, 0xbb, 0x72, 0xdc, 0x90, 0x73, 0x92, 0x62, 0x3e, 0xe2, 0x98, + 0x4d, 0x86, 0xac, 0x9d, 0xb9, 0x5c, 0xd4, 0x3a, 0x51, 0x9c, 0xf7, 0xc8, + 0x09, 0x1b, 0x46, 0x44, 0xf8, 0x0c, 0x5a, 0x9d, 0x0e, 0x6a, 0x61, 0x39, + 0x79, 0x8a, 0xd0, 0x13, 0xcd, 0xb6, 0xe0, 0xcb, 0xbf, 0xc0, 0xb8, 0xb7, + 0x10, 0xb6, 0x43, 0x9f, 0x13, 0xf6, 0x25, 0xe4, 0x07, 0xde, 0xa7, 0x02, + 0x18, 0x63, 0x0e, 0xfc, 0x7d, 0x15, 0xfd, 0x30, 0xc3, 0xbc, 0x7e, 0xf8, + 0x81, 0x47, 0xad, 0x77, 0x58, 0xee, 0x5c, 0x10, 0xfe, 0x95, 0xb3, 0x94, + 0x66, 0x3a, 0x3c, 0x2c, 0xe8, 0xd0, 0x18, 0x66, 0x6a, 0x61, 0xfa, 0x41, + 0x8e, 0xc1, 0x98, 0xe8, 0xbf, 0x23, 0x6d, 0x16, 0x5e, 0xe5, 0x9a, 0xea, + 0x6b, 0x90, 0x00, 0x6f, 0xd8, 0xbe, 0x6f, 0x21, 0xf1, 0x91, 0x7d, 0x2a, + 0x6e, 0x5d, 0xab, 0xd6, 0x87, 0x0d, 0xfb, 0xcc, 0x12, 0x7d, 0x1f, 0x01, + 0x3b, 0xe1, 0x17, 0x34, 0x26, 0x19, 0x6e, 0xfa, 0xdd, 0x35, 0x6e, 0xfb, + 0xff, 0x29, 0x51, 0x9f, 0xff, 0x46, 0x51, 0xca, 0xd8, 0x34, 0xdb, 0xe6, + 0x0b, 0x07, 0xdc, 0x3a, 0x87, 0x9d, 0x8d, 0x09, 0x9f, 0xcc, 0x00, 0x45, + 0x97, 0x27, 0xe9, 0xb1, 0x0c, 0x78, 0x14, 0x5d, 0x8f, 0x3a, 0x78, 0xc3, + 0x06, 0x68, 0x79, 0x92, 0xe2, 0x45, 0xc0, 0xc8, 0x47, 0x0b, 0x2c, 0x05, + 0xd2, 0x59, 0xc4, 0xee, 0xf9, 0x7b, 0x1e, 0xef, 0x57, 0xf9, 0x15, 0xe5, + 0xf7, 0x1e, 0xa2, 0xd8, 0x32, 0xa5, 0x92, 0xe1, 0x87, 0x45, 0xcf, 0xea, + 0x64, 0x78, 0x5c, 0xf9, 0x68, 0x42, 0x7c, 0x1e, 0x7e, 0x2f, 0x8b, 0x1e, + 0xcd, 0xd8, 0xa9, 0x24, 0x49, 0xdf, 0x03, 0xf1, 0x1c, 0x0c, 0x96, 0xad, + 0xbb, 0x99, 0x57, 0x1c, 0x17, 0xfe, 0x07, 0xd6, 0x44, 0x16, 0x31, 0x1e, + 0xbe, 0x83, 0x5e, 0x82, 0xbd, 0x95, 0xcc, 0x3e, 0xa0, 0xc6, 0x96, 0xc8, + 0x64, 0x5c, 0x30, 0x7f, 0xc9, 0x49, 0x85, 0x8d, 0xca, 0xf5, 0xf0, 0x5d, + 0x1c, 0x17, 0xfa, 0xe1, 0x30, 0xdb, 0x30, 0x62, 0x5c, 0x69, 0x4e, 0xf8, + 0x21, 0xf8, 0x38, 0xff, 0xd3, 0x01, 0xfd, 0x6e, 0x03, 0x9c, 0x97, 0xfe, + 0x09, 0xbe, 0x67, 0x9e, 0xe7, 0x51, 0x95, 0x17, 0x3f, 0x44, 0x91, 0x1d, + 0xf8, 0x8b, 0x66, 0xef, 0xa8, 0xbf, 0x88, 0x61, 0xcd, 0xb2, 0xe5, 0x32, + 0xd3, 0xc6, 0xdb, 0x5b, 0xda, 0x71, 0xef, 0x6b, 0x19, 0xcd, 0xb0, 0x32, + 0xc5, 0xfb, 0x2f, 0xd0, 0xeb, 0x73, 0xa1, 0xf8, 0x29, 0xbc, 0x47, 0xc6, + 0x97, 0x10, 0x3a, 0x6f, 0x88, 0x75, 0x17, 0xe8, 0x30, 0xa3, 0x22, 0xbe, + 0x15, 0x79, 0xc2, 0x32, 0x16, 0xd6, 0xfa, 0xc9, 0x0f, 0xbf, 0x9a, 0xa3, + 0x73, 0x22, 0x5a, 0x45, 0xfe, 0xba, 0x8c, 0x2b, 0x42, 0xfe, 0x82, 0x07, + 0xfe, 0xc4, 0x97, 0x5c, 0xf3, 0xf7, 0xe9, 0x7c, 0xb7, 0x48, 0xb0, 0x9c, + 0x4f, 0xa3, 0x78, 0x8a, 0xc6, 0x3d, 0x1d, 0xb3, 0x70, 0xbf, 0xd7, 0x0a, + 0xb4, 0xeb, 0xd6, 0x19, 0xe0, 0x67, 0x12, 0x7b, 0x74, 0x01, 0x71, 0x5c, + 0xa3, 0x2a, 0x1e, 0xd1, 0xc2, 0xfb, 0x04, 0x3b, 0x0f, 0xfe, 0xbb, 0xcf, + 0xf2, 0x27, 0xe2, 0x0a, 0x27, 0x07, 0xa1, 0x27, 0xf5, 0x38, 0x8c, 0x33, + 0x53, 0x38, 0xee, 0x67, 0xbb, 0x4b, 0xeb, 0xb5, 0xd2, 0xa7, 0xc4, 0xb6, + 0x98, 0xda, 0x2f, 0xf8, 0x93, 0x46, 0x54, 0xbf, 0x01, 0x9b, 0xac, 0x5e, + 0xc0, 0xe9, 0xe3, 0xa2, 0xc7, 0xad, 0x62, 0x10, 0xdb, 0xc9, 0x59, 0xc2, + 0x3b, 0xb7, 0xd0, 0x77, 0xf3, 0x6e, 0xc0, 0x9e, 0xf7, 0xc8, 0x1d, 0xa3, + 0xf8, 0x94, 0x7a, 0xff, 0xcf, 0x9d, 0xda, 0xb7, 0x5d, 0x1e, 0xfb, 0xf6, + 0xbd, 0x41, 0x19, 0x03, 0xbb, 0x4b, 0x8d, 0xf1, 0xca, 0x53, 0xfd, 0xfb, + 0xa7, 0xe1, 0x4f, 0xaa, 0xd4, 0x51, 0x5c, 0x13, 0x7c, 0xa5, 0xde, 0xa7, + 0x1d, 0x62, 0x7e, 0x2a, 0xe9, 0xf8, 0xb8, 0x07, 0x1d, 0xf7, 0xce, 0x40, + 0x2f, 0xb9, 0x7d, 0x3a, 0x3e, 0xd6, 0x90, 0x8e, 0xff, 0x75, 0x50, 0xfa, + 0x54, 0xeb, 0xe9, 0x18, 0xb5, 0x3c, 0xc7, 0x8b, 0x8d, 0xfc, 0x57, 0xd8, + 0x07, 0xd4, 0xa4, 0xc3, 0xe7, 0x01, 0x58, 0x69, 0xbf, 0x07, 0xe2, 0x7e, + 0xc0, 0x47, 0xc4, 0x4e, 0xfe, 0x90, 0xe2, 0x8b, 0xb5, 0xb1, 0xd0, 0xcd, + 0xae, 0xf9, 0x96, 0xc7, 0x35, 0xd0, 0xc5, 0x41, 0x0b, 0x76, 0x48, 0xda, + 0xf4, 0x1a, 0x5e, 0xef, 0xf9, 0x0e, 0xe5, 0xec, 0x54, 0x9e, 0xe0, 0xa3, + 0x0e, 0xd2, 0x53, 0x88, 0x2b, 0x2b, 0x1f, 0xf0, 0xd1, 0x8c, 0x5c, 0xb7, + 0x79, 0x40, 0xe0, 0x03, 0xf4, 0xd5, 0x50, 0xc2, 0x9f, 0xe0, 0x3d, 0x95, + 0xfe, 0xdf, 0xe4, 0x6a, 0x48, 0xed, 0x13, 0x8f, 0xc5, 0xfd, 0x3c, 0xeb, + 0xfc, 0xb0, 0x3f, 0xf6, 0xd7, 0xd7, 0xcb, 0x79, 0xc5, 0x90, 0x05, 0x25, + 0xfa, 0x0f, 0x96, 0x73, 0xfe, 0x03, 0xa6, 0xe8, 0xb9, 0x70, 0xb9, 0x78, + 0x80, 0xf5, 0x47, 0xec, 0x21, 0x7c, 0x87, 0xda, 0xb7, 0xfb, 0xf6, 0x30, + 0x75, 0xed, 0x67, 0xa9, 0x6f, 0x90, 0xc3, 0x7a, 0xa3, 0x71, 0x00, 0xf9, + 0xe1, 0x16, 0x5f, 0x83, 0x5e, 0x51, 0x63, 0x56, 0x9c, 0x3a, 0xe0, 0x4f, + 0x40, 0x0f, 0x68, 0x2b, 0x5d, 0x45, 0x53, 0xb3, 0x82, 0xa6, 0xe2, 0x6b, + 0xb3, 0x8a, 0xa6, 0x66, 0x95, 0xff, 0x7c, 0x56, 0xd1, 0xd4, 0xac, 0xa2, + 0xa9, 0x59, 0x45, 0x53, 0xb3, 0x8c, 0xd7, 0xa3, 0xac, 0xaf, 0x42, 0xf7, + 0xd0, 0xfe, 0xcb, 0x2e, 0x4a, 0xe6, 0x70, 0x1e, 0xf2, 0xb8, 0x96, 0xae, + 0x7e, 0x6d, 0x58, 0xfb, 0x47, 0x0b, 0x32, 0xcf, 0x8e, 0x9f, 0x85, 0x3d, + 0x78, 0x98, 0xe1, 0x77, 0xcd, 0x37, 0xbf, 0x88, 0xb9, 0xfa, 0x28, 0x26, + 0x7a, 0xc0, 0x36, 0x51, 0xd4, 0xad, 0xe3, 0x9a, 0xa8, 0xeb, 0x92, 0xb6, + 0x5c, 0xaa, 0x61, 0x8d, 0x97, 0xc6, 0x8b, 0x69, 0xb5, 0x5f, 0xb5, 0x76, + 0x4e, 0x0b, 0x25, 0xb2, 0x80, 0x2b, 0x72, 0x21, 0x2d, 0xde, 0x1b, 0x01, + 0xa7, 0x94, 0xe9, 0x01, 0x83, 0xa3, 0x0a, 0x06, 0x4f, 0x8b, 0x35, 0x22, + 0x97, 0x10, 0x3e, 0xc8, 0xc6, 0x70, 0x48, 0x67, 0x46, 0xf9, 0x3e, 0x8c, + 0xfb, 0x07, 0x42, 0xcc, 0x83, 0xb6, 0x0b, 0x07, 0xf7, 0xda, 0x1b, 0xf1, + 0x9a, 0xed, 0xd6, 0xd3, 0x5c, 0x77, 0xc9, 0x8e, 0x90, 0x92, 0x1b, 0x52, + 0xef, 0xdd, 0xe5, 0xd8, 0x89, 0x14, 0xcf, 0xed, 0x2f, 0xc2, 0x7f, 0x39, + 0x44, 0x6d, 0x25, 0x3a, 0x12, 0x06, 0x3e, 0x77, 0xb1, 0x5d, 0xc9, 0x73, + 0x18, 0x2b, 0xd1, 0x85, 0xf0, 0x3e, 0xb6, 0x5d, 0xf6, 0xb3, 0x0e, 0x3a, + 0xca, 0xff, 0x4e, 0xc4, 0xef, 0xc3, 0xbc, 0x3a, 0xf8, 0xda, 0x7e, 0x32, + 0x7a, 0x52, 0x66, 0x2b, 0xeb, 0x07, 0x47, 0x2a, 0xf6, 0x88, 0x05, 0xff, + 0x1c, 0xeb, 0xb6, 0xc6, 0x5c, 0xb8, 0x5b, 0xd5, 0x9c, 0xc1, 0x87, 0x8d, + 0xf8, 0xd6, 0x3f, 0x97, 0x64, 0xaf, 0x80, 0x21, 0x75, 0xfc, 0xe3, 0x52, + 0x64, 0x08, 0xc7, 0x78, 0xe7, 0x90, 0x3d, 0x11, 0xf1, 0xfd, 0x58, 0xea, + 0xf2, 0x3e, 0xfb, 0x88, 0x7c, 0x3f, 0x80, 0x6d, 0x5a, 0x3e, 0x2f, 0xbc, + 0x97, 0x3a, 0x4f, 0x25, 0x5f, 0x15, 0x74, 0x50, 0xa2, 0x7f, 0x67, 0x9a, + 0x35, 0x09, 0xb1, 0x8c, 0x29, 0x51, 0x0b, 0x8d, 0x7c, 0xe5, 0xf9, 0x45, + 0x3d, 0x2f, 0x47, 0xed, 0xf5, 0xfd, 0xc8, 0x37, 0xcb, 0x16, 0x68, 0x73, + 0x99, 0x01, 0x3f, 0xda, 0xe8, 0xf2, 0x46, 0x4f, 0x50, 0xd4, 0x66, 0x77, + 0xb3, 0x8e, 0xa3, 0xf3, 0x92, 0xc7, 0xf8, 0xfe, 0x01, 0xf1, 0xbe, 0xb9, + 0xd8, 0x12, 0xc6, 0x35, 0xd3, 0xc8, 0x72, 0xe9, 0x21, 0xfe, 0x5d, 0xc4, + 0x11, 0x93, 0xd4, 0xaa, 0x62, 0x04, 0x1d, 0x2a, 0xae, 0x14, 0x62, 0x5a, + 0xaa, 0xd4, 0x1c, 0x8f, 0x94, 0x7d, 0x6d, 0xc0, 0xf1, 0x5a, 0x5f, 0xdb, + 0x73, 0x5b, 0xc8, 0x9b, 0xad, 0xf0, 0x1a, 0x39, 0xa5, 0x2d, 0xa4, 0x7c, + 0x88, 0xd6, 0x02, 0x6d, 0xb7, 0xb6, 0x6e, 0xc7, 0xd7, 0xb4, 0x36, 0xcf, + 0xac, 0x9f, 0x79, 0xc7, 0x69, 0x53, 0xf8, 0xd4, 0x4c, 0xf3, 0xb9, 0x36, + 0x96, 0xd9, 0xa8, 0x97, 0x02, 0xbc, 0xfc, 0x43, 0xa8, 0x37, 0x79, 0x32, + 0xd0, 0x4c, 0xab, 0xab, 0xc8, 0x79, 0x78, 0xfc, 0x2e, 0x99, 0xe7, 0xfb, + 0x08, 0xc3, 0x65, 0x3f, 0xcb, 0x37, 0x43, 0xc5, 0x70, 0x70, 0x0e, 0xbc, + 0x41, 0xf4, 0xfd, 0x0c, 0x3c, 0x3c, 0xde, 0xc6, 0x7a, 0xbd, 0x8c, 0x01, + 0x1c, 0xe4, 0x7b, 0x7f, 0x33, 0xf7, 0x08, 0xfc, 0x59, 0xe6, 0x61, 0xbe, + 0x7f, 0x8c, 0xf5, 0x81, 0x08, 0x35, 0xd3, 0xca, 0x6a, 0x33, 0xeb, 0xf5, + 0xcd, 0xac, 0x0f, 0x8c, 0x9a, 0x23, 0x3e, 0xf1, 0x2c, 0x51, 0xdb, 0xf2, + 0xe9, 0xc0, 0x7e, 0xc6, 0x41, 0x3c, 0xeb, 0x8b, 0xea, 0x59, 0xb5, 0xcf, + 0xb8, 0x55, 0xc2, 0xf1, 0x61, 0xff, 0xfa, 0x99, 0xab, 0x78, 0x2f, 0xd4, + 0xe2, 0x34, 0xeb, 0xbe, 0x41, 0xf1, 0x6e, 0x46, 0x63, 0x66, 0x86, 0xed, + 0x80, 0x30, 0x1f, 0x1f, 0xa1, 0x54, 0x31, 0x41, 0xbf, 0x57, 0x74, 0xfb, + 0x6a, 0x8f, 0xf0, 0x9c, 0x65, 0x6d, 0x7d, 0x0b, 0xcf, 0xeb, 0x7d, 0xa7, + 0x96, 0x67, 0xb4, 0x91, 0xff, 0x6b, 0x41, 0x6a, 0x7e, 0x11, 0xbe, 0x91, + 0x12, 0x65, 0xc3, 0xf6, 0x85, 0xeb, 0xe2, 0xbd, 0x1b, 0x16, 0xbd, 0x22, + 0xf2, 0x5b, 0xf9, 0x7a, 0xbe, 0xe7, 0x79, 0x8c, 0x7b, 0xc5, 0xa2, 0x2b, + 0x8e, 0x84, 0xf7, 0x9f, 0x05, 0x82, 0xe4, 0x7f, 0x1d, 0x39, 0x48, 0xd0, + 0xb5, 0xd6, 0xcf, 0x38, 0xfb, 0x98, 0x5f, 0xbf, 0x88, 0xeb, 0xf8, 0xf3, + 0x75, 0x1c, 0xb7, 0xf1, 0x3a, 0x21, 0x6f, 0x91, 0x77, 0x02, 0x3e, 0xb7, + 0x3f, 0x64, 0x0a, 0xfc, 0x3b, 0xc2, 0x38, 0xd5, 0x24, 0x7c, 0x81, 0xbd, + 0x18, 0xeb, 0x0c, 0xb2, 0x6e, 0xb0, 0x7e, 0x66, 0x7c, 0x1f, 0x8e, 0x23, + 0x3d, 0x7e, 0x86, 0x91, 0xc4, 0xa1, 0xb0, 0x78, 0xff, 0xa1, 0xeb, 0x2f, + 0x70, 0x70, 0x9c, 0x78, 0x3f, 0xa1, 0x3f, 0xf0, 0x7e, 0x9a, 0xe8, 0xb3, + 0xd4, 0x46, 0x71, 0x7e, 0x46, 0x2c, 0x27, 0xd7, 0x7d, 0xbe, 0xe8, 0x27, + 0xe9, 0x47, 0x6a, 0x1e, 0xd6, 0xef, 0x29, 0xa4, 0x7e, 0xdc, 0x5b, 0xd3, + 0x0a, 0xbe, 0x77, 0xd1, 0x8d, 0x5c, 0x07, 0xdd, 0x54, 0xb1, 0xa5, 0x1b, + 0xc2, 0xae, 0x62, 0x9e, 0x9c, 0xe8, 0xa2, 0xeb, 0xab, 0x4d, 0x44, 0xbd, + 0x6d, 0x22, 0xf6, 0x7b, 0x23, 0x97, 0xc7, 0xf3, 0x87, 0xa5, 0xdf, 0xa5, + 0x82, 0x23, 0x37, 0x3c, 0x70, 0xe4, 0x3d, 0x81, 0x23, 0xef, 0x6d, 0x81, + 0x23, 0x7b, 0x95, 0x2d, 0xd1, 0x46, 0xcd, 0x0a, 0x3f, 0x5e, 0x63, 0xfc, + 0x78, 0x81, 0xf1, 0xe3, 0x50, 0x03, 0xfc, 0x30, 0x6a, 0xf0, 0xe3, 0xb0, + 0xc0, 0x8f, 0x9f, 0x6d, 0x8a, 0x1f, 0x87, 0xfc, 0x9b, 0xf9, 0x82, 0x34, + 0x6e, 0x0e, 0xd0, 0x4a, 0xce, 0xa1, 0xd5, 0x45, 0x9b, 0x2d, 0x7b, 0xd8, + 0xe6, 0x88, 0x19, 0xce, 0x88, 0x7a, 0x97, 0x82, 0xc0, 0x2b, 0x96, 0xe3, + 0x33, 0xa8, 0x69, 0xaa, 0xdb, 0x03, 0x12, 0xef, 0xa5, 0x14, 0xf0, 0x97, + 0x7b, 0x12, 0xcb, 0xac, 0x9f, 0xf9, 0x73, 0xde, 0xc7, 0x2b, 0x6b, 0x81, + 0x00, 0x7e, 0xf3, 0xcf, 0x04, 0x69, 0x63, 0x8d, 0xed, 0x54, 0xc6, 0xb1, + 0xab, 0xb9, 0x21, 0xba, 0x92, 0x1b, 0xa0, 0x8d, 0xdc, 0x30, 0xbd, 0x93, + 0xc3, 0x33, 0x00, 0x73, 0x3e, 0x16, 0x30, 0x37, 0xe8, 0x60, 0x90, 0xc7, + 0xac, 0x0e, 0xd0, 0xfa, 0xaa, 0xc6, 0x57, 0xe0, 0x2a, 0xf6, 0x3f, 0xd2, + 0x23, 0xeb, 0xd0, 0xea, 0x71, 0x20, 0x56, 0x85, 0x03, 0xf2, 0x1a, 0xec, + 0xfd, 0x42, 0x7d, 0x0d, 0x6d, 0xab, 0x39, 0x83, 0x1c, 0xb8, 0x36, 0xb6, + 0xc9, 0x6d, 0xe1, 0x73, 0x3d, 0xe8, 0x87, 0x4e, 0x6b, 0xdc, 0x4d, 0x5d, + 0xbc, 0x07, 0x0e, 0xf2, 0x87, 0x86, 0x59, 0x3f, 0xed, 0x16, 0xfa, 0x68, + 0xd4, 0x09, 0x84, 0x62, 0x54, 0x3a, 0x6b, 0x38, 0xe8, 0x93, 0xf8, 0x08, + 0xdf, 0xcf, 0x50, 0x7e, 0x9e, 0x4e, 0x17, 0x3e, 0xd5, 0xea, 0x9e, 0x88, + 0xd1, 0x9e, 0xe0, 0x39, 0x43, 0x4e, 0x56, 0xe2, 0x22, 0x54, 0x8e, 0x8b, + 0xb4, 0xf2, 0xba, 0x25, 0x2d, 0xcd, 0x39, 0x3c, 0xae, 0xc8, 0xe3, 0x8a, + 0x88, 0xa9, 0xf1, 0xf9, 0x55, 0xc4, 0x73, 0x87, 0x68, 0x63, 0x11, 0x34, + 0x07, 0xff, 0x44, 0x25, 0x86, 0xba, 0xb1, 0x86, 0xf3, 0xf0, 0x51, 0x54, + 0x62, 0xa8, 0x1b, 0x2a, 0x86, 0xba, 0xb1, 0x36, 0x2d, 0xf8, 0xf0, 0x42, + 0x8e, 0x79, 0x40, 0xce, 0xaf, 0xf2, 0x07, 0xf7, 0xa9, 0x77, 0xf6, 0x9c, + 0x10, 0x3e, 0xe4, 0x1e, 0x67, 0x73, 0x18, 0x1e, 0xac, 0x83, 0xe1, 0xb4, + 0xd0, 0x83, 0xe2, 0x7c, 0xcf, 0x58, 0xee, 0x04, 0xc3, 0x73, 0x96, 0x69, + 0x69, 0xb7, 0xa2, 0x25, 0x1d, 0x93, 0xed, 0x26, 0xf5, 0xfe, 0x1f, 0xa1, + 0xeb, 0x4b, 0xfe, 0x33, 0x54, 0xc3, 0x7f, 0x28, 0x10, 0x1d, 0x97, 0xd7, + 0xa7, 0x8b, 0xaf, 0x0c, 0x6b, 0xff, 0x5b, 0x9a, 0xef, 0xbb, 0x90, 0xdb, + 0x49, 0x4c, 0x97, 0xe5, 0xa6, 0x67, 0xce, 0xe0, 0x76, 0x9f, 0xad, 0x71, + 0xe1, 0xc4, 0x6d, 0xe0, 0x93, 0xbc, 0x47, 0x05, 0x9f, 0xfe, 0x77, 0x16, + 0xc0, 0xb2, 0x93, 0x05, 0x98, 0x57, 0x84, 0x80, 0xf5, 0x03, 0x03, 0xb4, + 0x8e, 0x39, 0x00, 0x1e, 0x53, 0x68, 0x02, 0xe6, 0x19, 0xa7, 0xf5, 0x40, + 0xfb, 0xfb, 0x95, 0xc1, 0xeb, 0x5d, 0x1b, 0xa0, 0x67, 0x4f, 0x2d, 0xea, + 0x79, 0x2c, 0x07, 0xca, 0xa3, 0x4e, 0x2a, 0x0c, 0x24, 0xe6, 0x27, 0x90, + 0xff, 0x80, 0xfe, 0x00, 0xf9, 0x11, 0x98, 0x9f, 0x9c, 0x81, 0x72, 0xa0, + 0x35, 0x53, 0xcd, 0x6b, 0x40, 0xfa, 0x40, 0x61, 0x08, 0x2a, 0x53, 0x41, + 0x63, 0x1d, 0x40, 0xf6, 0x12, 0x21, 0x68, 0xd8, 0x01, 0x69, 0x20, 0xbb, + 0x79, 0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x4f, + 0xec, 0x40, 0x97, 0xc2, 0xdc, 0xf4, 0xff, 0xff, 0x31, 0x15, 0x16, 0x60, + 0xda, 0x03, 0xad, 0xf9, 0xfc, 0xfd, 0xff, 0x80, 0x08, 0x0b, 0x43, 0x0b, + 0x7c, 0xed, 0x9e, 0xb0, 0x3c, 0xa8, 0x9c, 0x5b, 0x00, 0x64, 0xb5, 0xc1, + 0xeb, 0x6d, 0x16, 0xf0, 0x7d, 0xc4, 0x0b, 0x18, 0x7e, 0x01, 0xcb, 0x95, + 0xff, 0xff, 0x97, 0xc2, 0xd5, 0x82, 0x00, 0x00, 0xd4, 0xc2, 0xcb, 0x42, + 0x60, 0x7c, 0x00, 0x00, 0x00 }; +static u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = { + 0x08001ad8, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14, + 0x08001a24, 0x08001b14, 0x08001a98, 0x08001b14, 0x080019ac, 0x08001b14, + 0x08001b14, 0x08001b14, 0x080019b8, 0x0, 0x08002a2c, 0x08002a7c, + 0x08002aac, 0x08002adc, 0x08002b0c, 0x0, 0x08005fac, 0x08005fac, + 0x08005fac, 0x08005fac, 0x08005fac, 0x08005fd8, 0x08005fd8, 0x08006018, + 0x08006024, 0x08006024, 0x08005fac, 0x0, 0x0 }; +static u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b09FwSbss[(0x5c/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_09 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, - .start_addr = 0x080000b4, + .start_addr = 0x080000b0, .text_addr = 0x08000000, - .text_len = 0x7dc0, + .text_len = 0x7c5c, .text_index = 0x0, .gz_text = bnx2_COM_b09FwText, .gz_text_len = sizeof(bnx2_COM_b09FwText), - .data_addr = 0x08007e60, + .data_addr = 0x08007d00, .data_len = 0x0, .data_index = 0x0, .data = bnx2_COM_b09FwData, - .sbss_addr = 0x08007e60, - .sbss_len = 0x60, + .sbss_addr = 0x08007d00, + .sbss_len = 0x5c, .sbss_index = 0x0, .sbss = bnx2_COM_b09FwSbss, - .bss_addr = 0x08007ec0, + .bss_addr = 0x08007d60, .bss_len = 0x88, .bss_index = 0x0, .bss = bnx2_COM_b09FwBss, - .rodata_addr = 0x08007dc0, + .rodata_addr = 0x08007c60, .rodata_len = 0x88, .rodata_index = 0x0, .rodata = bnx2_COM_b09FwRodata, }; static u8 bnx2_CP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d, - 0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59, - 0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22, - 0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12, - 0x02, 0xab, 0x10, 0x43, 0xb3, 0x1c, 0x4a, 0xc5, 0x48, 0x4e, 0x02, 0x04, - 0xea, 0x40, 0xe8, 0x86, 0xdd, 0xec, 0x66, 0x32, 0x92, 0x3f, 0x9a, 0x8e, - 0x3d, 0x93, 0x44, 0x89, 0xbd, 0xdd, 0x9c, 0xad, 0x90, 0x14, 0x3b, 0x74, - 0x07, 0x4f, 0xe2, 0x98, 0x96, 0x73, 0x0a, 0x8d, 0x50, 0x8c, 0x9b, 0xe6, - 0xb0, 0xdd, 0xd0, 0xa6, 0x34, 0xdb, 0x86, 0x22, 0x8c, 0x81, 0xf4, 0x2c, - 0xdd, 0x86, 0x42, 0x77, 0xd3, 0x36, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d, - 0x9a, 0x91, 0x34, 0xce, 0x07, 0xdd, 0xad, 0xcf, 0x79, 0x7e, 0xf3, 0xee, - 0xbb, 0x1f, 0xff, 0xfb, 0xbf, 0xff, 0xef, 0xfb, 0xbf, 0x4f, 0x97, 0x8b, - 0x34, 0x8b, 0xfd, 0xb7, 0x01, 0xd7, 0xd5, 0xc9, 0xfd, 0xe3, 0x57, 0x5f, - 0x39, 0x70, 0x25, 0x9f, 0xa3, 0x91, 0x68, 0x44, 0xde, 0xc4, 0xbf, 0xe4, - 0x1b, 0xa8, 0x83, 0x0e, 0xdd, 0x70, 0x2c, 0x5e, 0x12, 0x53, 0x43, 0xde, - 0xfe, 0x8c, 0x27, 0xb1, 0xc8, 0x50, 0xee, 0xce, 0x71, 0x4f, 0x24, 0x5d, - 0xee, 0x4b, 0x0e, 0xcb, 0x3f, 0x05, 0xb9, 0x78, 0x54, 0x58, 0xfe, 0x96, - 0xa1, 0x57, 0x7f, 0xeb, 0x2b, 0xff, 0x2a, 0xf5, 0xf2, 0x4c, 0x44, 0x62, - 0xee, 0xd0, 0xed, 0xe2, 0x6e, 0x93, 0x58, 0xe7, 0x50, 0x72, 0xff, 0x23, - 0xdb, 0x97, 0x44, 0x5a, 0xc3, 0xbe, 0x5e, 0x0a, 0xbe, 0xb2, 0x5d, 0x72, - 0x1d, 0x43, 0x89, 0xb1, 0x86, 0x21, 0x57, 0x9e, 0xaa, 0xc8, 0xe8, 0x89, - 0xc2, 0xcb, 0x41, 0x74, 0x28, 0x88, 0x4c, 0x0d, 0x38, 0x12, 0x19, 0x92, - 0xb3, 0xe3, 0x03, 0xf7, 0x04, 0xca, 0xf3, 0xfc, 0x45, 0x69, 0x19, 0x3c, - 0x37, 0x80, 0xf7, 0x65, 0x41, 0xdd, 0xbd, 0xd7, 0x9c, 0x28, 0xc4, 0x44, - 0x0d, 0xf5, 0xbc, 0x90, 0x89, 0x5c, 0x25, 0x7c, 0x7f, 0x56, 0x7a, 0xfc, - 0xa7, 0x05, 0xe5, 0xe5, 0x98, 0x64, 0x2a, 0xd2, 0x82, 0x32, 0xdc, 0x9b, - 0x51, 0x27, 0xe5, 0x66, 0x22, 0xae, 0xe4, 0x2b, 0x3f, 0x5e, 0x67, 0xc6, - 0x9d, 0xb3, 0xf7, 0xbf, 0x8e, 0x99, 0x3b, 0xc6, 0x2d, 0xc6, 0x64, 0x29, - 0x92, 0x10, 0xc0, 0x82, 0x79, 0x25, 0x64, 0xb2, 0x98, 0x94, 0x4c, 0x81, - 0xb0, 0x45, 0x25, 0xeb, 0x12, 0xae, 0x04, 0xda, 0xb7, 0x39, 0xf5, 0xeb, - 0xb3, 0xee, 0x0b, 0xa8, 0x9b, 0x44, 0xbd, 0x4e, 0x79, 0x12, 0x75, 0x4f, - 0x57, 0xe2, 0xf2, 0x44, 0xe5, 0x57, 0x25, 0x8d, 0xb6, 0x8f, 0x57, 0x30, - 0x76, 0xb1, 0x51, 0x86, 0xa7, 0x9b, 0x25, 0x33, 0xdd, 0x9d, 0xc8, 0x4a, - 0x10, 0x7c, 0xda, 0xff, 0xa8, 0x8c, 0xb5, 0xa1, 0x7e, 0x91, 0xef, 0x12, - 0x2b, 0xde, 0x65, 0xfd, 0x3e, 0x37, 0xab, 0x1c, 0x49, 0xef, 0x4d, 0x25, - 0xc6, 0x14, 0x9f, 0x1b, 0x24, 0xd3, 0x8f, 0xe7, 0xd1, 0xa8, 0x44, 0xbc, - 0x20, 0xb8, 0xc3, 0xbf, 0x0c, 0x70, 0xa4, 0x92, 0x49, 0xc5, 0xb6, 0x6c, - 0x97, 0xca, 0x25, 0x55, 0x5c, 0x72, 0x95, 0x2b, 0x25, 0xd9, 0x16, 0x04, - 0xef, 0xf3, 0x3b, 0x51, 0x2e, 0x32, 0x5c, 0x90, 0xfd, 0x58, 0x23, 0xf4, - 0x29, 0xbe, 0x1a, 0xda, 0x8c, 0x79, 0xf4, 0xb9, 0xc3, 0xd2, 0x28, 0xe9, - 0xb8, 0xa4, 0xd5, 0x90, 0x24, 0xd5, 0xd0, 0x3a, 0x94, 0x39, 0xd2, 0xe0, - 0x7d, 0xc1, 0xd2, 0xd2, 0x46, 0x3c, 0xcb, 0xa8, 0x1a, 0x6a, 0x5b, 0x55, - 0x9e, 0x4a, 0x8a, 0x5a, 0x07, 0x5c, 0xa5, 0x7a, 0xd3, 0x8a, 0x65, 0xb8, - 0xeb, 0xb2, 0x0f, 0x36, 0xad, 0x2d, 0xdb, 0xef, 0xac, 0x2c, 0xbb, 0xbd, - 0x85, 0xb0, 0x8a, 0xe2, 0xef, 0xb8, 0x9e, 0x6b, 0x3a, 0xde, 0xed, 0x36, - 0x60, 0x5e, 0xa3, 0x7e, 0xca, 0xdd, 0xa9, 0x9e, 0x0f, 0xa4, 0x9d, 0x30, - 0xf3, 0x9d, 0xc2, 0x3b, 0x54, 0x1d, 0xf2, 0xb1, 0x6e, 0xae, 0x1c, 0xc2, - 0xdc, 0xce, 0x4f, 0xa7, 0xdc, 0x2e, 0x85, 0xfb, 0x3c, 0x7f, 0x07, 0x41, - 0xc6, 0xcf, 0xe9, 0x35, 0xfd, 0xee, 0x74, 0x02, 0xcf, 0x80, 0x3f, 0x9e, - 0x4e, 0x6d, 0x92, 0xab, 0xed, 0xba, 0x7c, 0x13, 0x63, 0x76, 0xbb, 0x77, - 0xa8, 0x6e, 0xd7, 0x57, 0x29, 0x77, 0x56, 0xce, 0xe0, 0x39, 0x08, 0x6e, - 0xf4, 0x53, 0x89, 0x1c, 0xd6, 0xec, 0x42, 0x21, 0x2e, 0xdf, 0x2b, 0xa4, - 0x40, 0xc5, 0xa9, 0xde, 0x39, 0xe9, 0xf3, 0xe7, 0x00, 0x6f, 0x1e, 0xd7, - 0x41, 0xbe, 0x2b, 0xe3, 0x5d, 0x99, 0x6d, 0x83, 0xe0, 0x26, 0xff, 0x37, - 0x83, 0xb1, 0x76, 0xc3, 0x17, 0x4f, 0x15, 0xb1, 0x9e, 0x80, 0xf9, 0x74, - 0x11, 0xeb, 0x89, 0xb5, 0x7a, 0x5c, 0xaf, 0x7b, 0x2f, 0xd6, 0x9d, 0xb4, - 0x41, 0xba, 0xd8, 0x61, 0x69, 0xf9, 0x03, 0xf6, 0x2e, 0x92, 0x29, 0x3a, - 0x92, 0xf1, 0xff, 0x31, 0x48, 0x6b, 0x7e, 0x11, 0x67, 0xb8, 0x48, 0x5a, - 0x6c, 0x00, 0xac, 0x7c, 0xcc, 0xda, 0x7a, 0x1b, 0x1d, 0xe0, 0x96, 0xeb, - 0xc0, 0xf7, 0x31, 0xe5, 0x35, 0xd9, 0xf7, 0x21, 0x5f, 0xf0, 0xdf, 0x26, - 0x47, 0xbc, 0x6a, 0xbd, 0x0c, 0x69, 0xb2, 0x92, 0x93, 0xec, 0x83, 0x81, - 0x0c, 0xfb, 0xc0, 0x13, 0xfb, 0x74, 0x7d, 0xd1, 0x6d, 0x5d, 0xd6, 0xd1, - 0x75, 0xf1, 0x6f, 0x7d, 0x23, 0xc6, 0x70, 0x46, 0x8a, 0xd5, 0xb6, 0x23, - 0xc5, 0xfc, 0x66, 0x0b, 0x1f, 0x9e, 0x07, 0x9d, 0x4c, 0xe5, 0x82, 0x5d, - 0xdb, 0x70, 0x1e, 0x57, 0xd7, 0xa1, 0x6d, 0x17, 0x7c, 0xe0, 0x4a, 0xb6, - 0x30, 0x88, 0x71, 0xe3, 0xb8, 0x07, 0xc1, 0x94, 0x9f, 0x4e, 0x45, 0x65, - 0x08, 0xcf, 0xa3, 0xe4, 0x3d, 0xe0, 0x4f, 0xa2, 0x99, 0xed, 0xbe, 0x8c, - 0x80, 0xee, 0xf3, 0x95, 0xd7, 0x97, 0x22, 0x7a, 0x0e, 0xfe, 0x3f, 0x59, - 0xdc, 0x70, 0x1c, 0x33, 0xe6, 0x54, 0xb1, 0x43, 0xf2, 0xd3, 0x9e, 0x4c, - 0x16, 0x16, 0x7a, 0x95, 0xbc, 0x4c, 0x7e, 0xc7, 0xfa, 0xa5, 0x40, 0xbb, - 0x43, 0x32, 0x5c, 0xf1, 0x24, 0x5f, 0xc0, 0xbd, 0xd8, 0x0d, 0xfa, 0x8d, - 0x4a, 0x3a, 0x61, 0xd6, 0x26, 0x5f, 0x18, 0xc1, 0xfc, 0x80, 0x6b, 0x8f, - 0xbf, 0x07, 0x2d, 0x4c, 0xae, 0x64, 0x06, 0x48, 0x3f, 0x6f, 0x06, 0x96, - 0x98, 0xcc, 0xfa, 0xe0, 0x0b, 0xd7, 0xc0, 0x92, 0x2f, 0xc6, 0xa2, 0xc3, - 0x98, 0xf7, 0x70, 0xf9, 0x57, 0xd0, 0x7f, 0x8b, 0xfe, 0x0d, 0x7e, 0xb2, - 0x65, 0x51, 0xdc, 0xe3, 0xb8, 0x13, 0xe6, 0x90, 0x56, 0x21, 0x1b, 0xa6, - 0x3b, 0x65, 0x12, 0xb4, 0x3a, 0x2c, 0xf8, 0x3d, 0xcf, 0xb9, 0x10, 0xae, - 0x0e, 0xfd, 0x7b, 0x72, 0x7a, 0x8b, 0x7e, 0xce, 0x8e, 0x76, 0x48, 0x6e, - 0x3e, 0x9c, 0x33, 0xe5, 0x05, 0x65, 0x44, 0xea, 0xb0, 0x08, 0x65, 0x46, - 0x10, 0x3c, 0xe8, 0x53, 0x6e, 0x04, 0xc1, 0x69, 0x9f, 0x72, 0xe4, 0x0c, - 0xe4, 0x03, 0x65, 0x07, 0x79, 0xd9, 0x53, 0x5c, 0xab, 0x4c, 0xa1, 0x17, - 0xeb, 0xd1, 0x28, 0xd9, 0xfe, 0xe3, 0x84, 0x15, 0x72, 0xe7, 0xa5, 0x4f, - 0x66, 0xbc, 0x5c, 0x22, 0xa2, 0xf1, 0x04, 0xca, 0x82, 0x3c, 0x4c, 0xeb, - 0x99, 0x75, 0x49, 0xbe, 0xbf, 0x64, 0xeb, 0xc8, 0xaf, 0xb2, 0x4e, 0x74, - 0x4d, 0x9d, 0x7f, 0xa7, 0x0c, 0x5f, 0xf6, 0x62, 0xdd, 0x3a, 0x14, 0xf1, - 0xd8, 0xb5, 0x8d, 0xcf, 0x12, 0x6b, 0x18, 0xfa, 0x3d, 0xbc, 0x7b, 0xee, - 0x53, 0x8f, 0x7a, 0xf5, 0xde, 0xfd, 0x28, 0xba, 0xf6, 0xdd, 0x94, 0x44, - 0xbd, 0x54, 0xef, 0x8d, 0xea, 0x4f, 0x1a, 0xa4, 0x35, 0x08, 0x1e, 0xf5, - 0xc3, 0xf2, 0xc6, 0x86, 0xb5, 0x63, 0x5c, 0x55, 0xa7, 0xec, 0x68, 0x9d, - 0xb2, 0xcf, 0xd7, 0x29, 0x7b, 0x7b, 0xe3, 0xda, 0xb2, 0xdb, 0xeb, 0x94, - 0xcd, 0xd6, 0x29, 0xfb, 0x69, 0x9d, 0x32, 0x69, 0x5a, 0x5b, 0x16, 0xa9, - 0x53, 0xd6, 0x57, 0xa7, 0x2c, 0x0a, 0xbe, 0xdb, 0x26, 0xf9, 0xf8, 0xbd, - 0x9c, 0xbb, 0xc5, 0x4d, 0x29, 0xb2, 0x16, 0x37, 0x0d, 0xa8, 0xd7, 0xb9, - 0xaa, 0xde, 0x17, 0xeb, 0xd4, 0x6b, 0x44, 0xbd, 0xb6, 0x55, 0xf5, 0x76, - 0xd4, 0xc1, 0x75, 0x13, 0xea, 0xc5, 0x56, 0xd5, 0x7b, 0xb0, 0x4e, 0x3d, - 0x96, 0x7f, 0xc6, 0x8e, 0xd3, 0x07, 0x2d, 0xf4, 0x5a, 0xeb, 0xd5, 0x28, - 0xd2, 0xce, 0xf2, 0x5e, 0xe8, 0x90, 0x0e, 0x65, 0xe4, 0x02, 0x65, 0x10, - 0xcb, 0x3a, 0x41, 0xe7, 0x71, 0xd0, 0x1d, 0xe5, 0x28, 0xf8, 0x8c, 0x73, - 0xa9, 0x6c, 0x90, 0xb1, 0x78, 0x9f, 0x7b, 0xb5, 0x6a, 0x01, 0x8d, 0xa5, - 0xdc, 0xa4, 0x22, 0xff, 0x49, 0x2e, 0x32, 0xe4, 0xe5, 0x86, 0x45, 0xc5, - 0x95, 0x04, 0x32, 0xe2, 0xab, 0x36, 0x25, 0xf7, 0x80, 0xbf, 0xd2, 0xd0, - 0x59, 0x37, 0x06, 0xc3, 0x9a, 0xb7, 0x4c, 0xdd, 0x8b, 0xcb, 0x54, 0x5f, - 0x0e, 0x52, 0x16, 0x0e, 0x8d, 0x7e, 0x2a, 0xe3, 0x2d, 0x0c, 0x36, 0x82, - 0x66, 0xcf, 0xa3, 0xcd, 0x6e, 0xb4, 0xdc, 0x57, 0x8e, 0xca, 0x48, 0x79, - 0x00, 0xbc, 0xe0, 0xc8, 0x39, 0x6f, 0xa3, 0x9c, 0xf3, 0x51, 0xb7, 0x12, - 0x91, 0xc5, 0xb8, 0x23, 0x8b, 0x78, 0xce, 0xf8, 0x78, 0x57, 0x09, 0x79, - 0x6b, 0x40, 0x0e, 0x14, 0x7d, 0x39, 0x5c, 0xbc, 0x41, 0x85, 0x7a, 0x6d, - 0xa7, 0xbf, 0x5e, 0x1e, 0x73, 0x4d, 0xdf, 0xbb, 0xbd, 0x05, 0x68, 0xd4, - 0xa8, 0x9c, 0xf7, 0x52, 0x89, 0x45, 0xcd, 0x13, 0xff, 0x27, 0x18, 0x41, - 0x3f, 0xb3, 0x5e, 0xca, 0xfd, 0x03, 0x3c, 0x8f, 0x95, 0x69, 0xcb, 0x54, - 0xfb, 0x9a, 0x44, 0x5f, 0x87, 0x8a, 0x1b, 0xe4, 0x56, 0xdb, 0x7e, 0x97, - 0xb7, 0xd0, 0x0b, 0x9e, 0x73, 0x4f, 0x50, 0x86, 0x14, 0x00, 0xd7, 0x5e, - 0xf0, 0x36, 0xda, 0x7e, 0x4d, 0xcb, 0x33, 0xd8, 0x3e, 0x85, 0x8d, 0x90, - 0xcf, 0x7f, 0x17, 0xdc, 0x1a, 0x67, 0x7d, 0x96, 0x51, 0xe7, 0x48, 0x49, - 0x0d, 0x41, 0x26, 0x0c, 0x50, 0x66, 0x26, 0x21, 0x2f, 0x21, 0x7b, 0x8a, - 0x3f, 0x0d, 0xd2, 0xd1, 0x5a, 0x39, 0x28, 0xb9, 0x6a, 0x1d, 0x96, 0x25, - 0x8d, 0x5c, 0x2d, 0x2e, 0x2d, 0xcb, 0x8a, 0x1c, 0xe4, 0xcb, 0x53, 0x15, - 0xca, 0x85, 0x0f, 0x82, 0x47, 0x3b, 0x65, 0xa4, 0x90, 0xca, 0xa5, 0x65, - 0x1b, 0xd6, 0xef, 0xd7, 0xb1, 0xa6, 0x51, 0x5c, 0x0f, 0xad, 0x97, 0x56, - 0x1f, 0xba, 0x9b, 0xe5, 0xe8, 0xb4, 0x9d, 0x36, 0xd2, 0x6f, 0x03, 0x0f, - 0x93, 0x5c, 0xf3, 0x44, 0x26, 0xe2, 0x8c, 0xd2, 0x5e, 0x19, 0x85, 0x7c, - 0xcc, 0x96, 0xd9, 0x37, 0xe1, 0x4d, 0xd8, 0xdf, 0xb0, 0x9b, 0x0a, 0x9d, - 0xf6, 0x77, 0x0b, 0x7e, 0x27, 0xed, 0x6f, 0xc8, 0xd4, 0x82, 0x67, 0x7f, - 0xc7, 0xb5, 0x1c, 0x32, 0xbf, 0x13, 0xf8, 0xdd, 0xaf, 0x7f, 0x4f, 0x15, - 0x77, 0xed, 0x52, 0xde, 0x95, 0x92, 0x9d, 0xef, 0x94, 0x03, 0x85, 0x77, - 0x58, 0xd9, 0x82, 0x4b, 0xbe, 0xe4, 0x98, 0x79, 0x26, 0xf4, 0xba, 0xe7, - 0x8b, 0x39, 0x67, 0x94, 0xf0, 0xe3, 0xf7, 0x70, 0xa1, 0xcf, 0xdd, 0x24, - 0xa4, 0x81, 0x29, 0x67, 0xb8, 0xe2, 0xa4, 0x23, 0x43, 0x3d, 0x89, 0x49, - 0x39, 0x8c, 0xdf, 0xe2, 0x46, 0x86, 0xbe, 0x84, 0xbb, 0xc1, 0xc1, 0x57, - 0xb6, 0x43, 0xb6, 0x16, 0x29, 0x2f, 0x3d, 0xcc, 0x3d, 0x29, 0x67, 0x56, - 0xd8, 0x58, 0xc4, 0x85, 0x92, 0xec, 0x74, 0xea, 0x78, 0x4e, 0x52, 0xb9, - 0x19, 0x30, 0xc4, 0x8d, 0x7e, 0x54, 0xde, 0xe7, 0x83, 0x76, 0xaf, 0x74, - 0x64, 0xd7, 0x95, 0x51, 0xd8, 0x44, 0xde, 0xcc, 0x2e, 0xc8, 0x58, 0xc8, - 0xbe, 0x08, 0xe9, 0x41, 0x9d, 0x92, 0xb1, 0xe8, 0x10, 0xb0, 0x7d, 0xaa, - 0x7f, 0x64, 0xb2, 0x90, 0xbd, 0x5d, 0x0d, 0xed, 0xff, 0x6c, 0x66, 0xe0, - 0xad, 0x92, 0xdd, 0xab, 0x80, 0xa3, 0xf6, 0x31, 0xc8, 0x4c, 0xcc, 0x2b, - 0x08, 0x40, 0xcf, 0x90, 0xe7, 0x37, 0xdd, 0x14, 0x19, 0x6a, 0x90, 0xe1, - 0xbd, 0xed, 0x68, 0xc3, 0x77, 0xc4, 0xd7, 0x79, 0xe0, 0x33, 0x95, 0x1c, - 0x11, 0xb9, 0x7b, 0x6a, 0x60, 0xc9, 0x99, 0x2c, 0x7d, 0x10, 0x3c, 0x79, - 0x15, 0xda, 0x3f, 0x80, 0xf6, 0x2f, 0x3b, 0xf9, 0xe9, 0x57, 0x9c, 0xc9, - 0xe9, 0xbf, 0x75, 0xa6, 0xa6, 0xb7, 0x6c, 0xd9, 0x39, 0xb8, 0x65, 0xcb, - 0xf8, 0x60, 0xd4, 0xea, 0x97, 0x2d, 0x5b, 0xa6, 0x06, 0x07, 0x81, 0x83, - 0x3e, 0x77, 0x44, 0x3c, 0x77, 0x97, 0x80, 0x7f, 0xe2, 0x1c, 0x93, 0xfa, - 0x27, 0x85, 0xf7, 0x6c, 0xef, 0xe9, 0xf7, 0xc3, 0xd2, 0x97, 0x68, 0x13, - 0x8e, 0x1f, 0xb1, 0x75, 0xda, 0x01, 0xfb, 0x03, 0x76, 0x7d, 0x0b, 0xaa, - 0xc1, 0x63, 0x39, 0xe7, 0xc2, 0x72, 0xae, 0xed, 0x8f, 0xac, 0x2d, 0xbb, - 0x11, 0xe5, 0x7c, 0x26, 0xce, 0x88, 0x17, 0xda, 0x22, 0x0d, 0xda, 0x76, - 0xcc, 0x16, 0x48, 0x33, 0x51, 0x99, 0x28, 0xb4, 0xa1, 0x0d, 0xe8, 0xe2, - 0x94, 0xbd, 0x8e, 0x02, 0xb6, 0xbd, 0xe8, 0xeb, 0xe8, 0x21, 0xb4, 0xa3, - 0xcc, 0x48, 0xf5, 0x8a, 0xfa, 0x04, 0xea, 0xf4, 0xb9, 0x9b, 0x85, 0x36, - 0xc7, 0x71, 0xc9, 0x16, 0xc9, 0xdf, 0x3d, 0x80, 0x27, 0x26, 0xc9, 0x76, - 0x3c, 0x57, 0x0e, 0xc0, 0x0e, 0x69, 0xb0, 0x3a, 0x33, 0x94, 0x17, 0xfc, - 0x77, 0x87, 0x12, 0xef, 0x80, 0x8c, 0xcd, 0x5d, 0x8e, 0x7a, 0x0e, 0xf0, - 0x42, 0x3b, 0x05, 0x36, 0xcb, 0x5c, 0x5a, 0x32, 0xdb, 0xee, 0xc5, 0xdd, - 0xc5, 0x73, 0x1e, 0xf7, 0xb7, 0xe0, 0x3e, 0x89, 0x7b, 0x08, 0x27, 0xf0, - 0xea, 0x47, 0xac, 0xce, 0xba, 0x06, 0x63, 0xff, 0x6b, 0xc9, 0x94, 0x12, - 0xb4, 0x39, 0x36, 0x66, 0xbc, 0xb4, 0xab, 0x44, 0x6d, 0x56, 0x32, 0x85, - 0xfa, 0xf0, 0x09, 0xbc, 0x83, 0x32, 0x7e, 0x12, 0xbf, 0x1f, 0xa4, 0x4d, - 0x3c, 0x25, 0xe3, 0x73, 0x1c, 0xa7, 0x00, 0x98, 0x4a, 0x92, 0x3d, 0xf9, - 0x00, 0xae, 0x69, 0x5c, 0x0f, 0xe3, 0xe2, 0xdc, 0xd8, 0xff, 0xe2, 0x26, - 0x05, 0x5c, 0xf3, 0x39, 0x4b, 0x3a, 0xae, 0xe0, 0x37, 0x69, 0xb8, 0x42, - 0xdb, 0x06, 0xf4, 0x5b, 0x09, 0xe9, 0xda, 0xb7, 0xbf, 0x13, 0x9a, 0xaf, - 0x73, 0x6d, 0xa0, 0x99, 0xca, 0xa0, 0x96, 0x39, 0x19, 0x0f, 0xf7, 0x0a, - 0x6c, 0x8f, 0x36, 0xce, 0xd1, 0xb3, 0x65, 0x9e, 0x2e, 0x4b, 0xea, 0xb2, - 0x7e, 0x5b, 0x86, 0x7b, 0xa5, 0x41, 0xc6, 0xda, 0x01, 0x31, 0xe5, 0xb3, - 0x84, 0xf8, 0xa4, 0x0c, 0x00, 0xfd, 0xc2, 0x66, 0x38, 0x73, 0x51, 0xf9, - 0xb7, 0xa4, 0x6d, 0xb1, 0xc7, 0x2b, 0xa4, 0x63, 0xd2, 0x76, 0x10, 0xdc, - 0xef, 0x37, 0xa1, 0x7f, 0xf2, 0xbc, 0x48, 0xc3, 0xd1, 0xa8, 0xcc, 0xb8, - 0xa4, 0x85, 0x77, 0xb4, 0x90, 0x06, 0x1a, 0x3d, 0xd2, 0x70, 0x2d, 0x7f, - 0x71, 0x0d, 0xd9, 0x5f, 0x0e, 0xf6, 0x1d, 0xed, 0xbc, 0x1e, 0xd8, 0xce, - 0x1c, 0xe3, 0x30, 0x9f, 0x5d, 0x05, 0x9e, 0xca, 0x2c, 0xf3, 0x94, 0xc8, - 0x6c, 0x81, 0xb8, 0x09, 0xed, 0x3f, 0xae, 0x33, 0xf1, 0xf3, 0x38, 0xe6, - 0xcc, 0xfb, 0x19, 0x8b, 0xa7, 0x2f, 0x59, 0x3c, 0x7d, 0xd9, 0xde, 0x5d, - 0x27, 0xab, 0x6d, 0xc1, 0x05, 0x3c, 0x73, 0x7d, 0xa2, 0x1a, 0x67, 0xd9, - 0xc2, 0x0c, 0xee, 0xa8, 0x5b, 0x7c, 0x5c, 0xc6, 0xb5, 0x9d, 0x16, 0x91, - 0x77, 0x69, 0xd9, 0x06, 0x21, 0xdd, 0x5c, 0x00, 0xcc, 0x0d, 0x92, 0x8b, - 0x47, 0xf4, 0xda, 0x47, 0xbd, 0x03, 0x51, 0x43, 0xab, 0xc4, 0xc9, 0x0a, - 0x5f, 0xaa, 0x06, 0xa6, 0xb8, 0x95, 0x73, 0x84, 0x8b, 0xb4, 0xfb, 0x88, - 0x86, 0xeb, 0x16, 0xc8, 0xbb, 0x9c, 0xa8, 0xf6, 0x46, 0xb9, 0x0c, 0xb4, - 0xa0, 0xe2, 0xd0, 0x5c, 0xc1, 0xd3, 0xb0, 0x9b, 0xb2, 0x73, 0xb4, 0xa1, - 0xbb, 0xe8, 0xb7, 0xc4, 0xb2, 0xfd, 0xad, 0xa4, 0x23, 0xa5, 0x60, 0x7f, - 0xe1, 0x59, 0x65, 0xfb, 0x35, 0x9d, 0x3a, 0xca, 0x8b, 0x6b, 0x3b, 0x19, - 0xbc, 0x12, 0xb1, 0xbe, 0x73, 0x54, 0x79, 0x9b, 0x57, 0x97, 0x25, 0xa9, - 0x87, 0xd1, 0x2e, 0x99, 0xed, 0x6f, 0x27, 0x8f, 0xb9, 0xca, 0x03, 0x2e, - 0x3d, 0xed, 0x1b, 0xe5, 0xd4, 0xc0, 0xc6, 0x55, 0xf5, 0xf5, 0xdd, 0xb1, - 0xcf, 0x51, 0x7b, 0x77, 0xed, 0x3d, 0x69, 0xef, 0xb9, 0xe8, 0x00, 0xef, - 0x8e, 0x44, 0x87, 0x78, 0xc7, 0x1a, 0x0e, 0xb1, 0x0f, 0xcd, 0x57, 0x56, - 0xce, 0xf4, 0xb8, 0x79, 0x21, 0x5f, 0xfd, 0xa9, 0xdc, 0x32, 0x67, 0xe4, - 0xef, 0x2e, 0xc8, 0x20, 0xf8, 0x6f, 0xee, 0xa2, 0x00, 0xfe, 0xbd, 0x65, - 0xb9, 0xa5, 0x42, 0xbc, 0xfd, 0x06, 0xf0, 0xb7, 0x35, 0x4a, 0xde, 0x74, - 0x85, 0x72, 0xf7, 0x4e, 0xd1, 0xf6, 0x69, 0x81, 0x38, 0x3f, 0x2b, 0x5c, - 0x9b, 0x7c, 0xe1, 0x19, 0xbd, 0x36, 0x07, 0x0b, 0x8b, 0xc0, 0xcf, 0xd7, - 0x41, 0xf7, 0x41, 0xb0, 0xe8, 0xe7, 0x41, 0x39, 0x7f, 0x84, 0xdf, 0xe8, - 0xbb, 0xf0, 0x1c, 0xde, 0xb7, 0x4a, 0xbe, 0x44, 0x9e, 0x8b, 0x5a, 0x1e, - 0x3e, 0x05, 0x7e, 0xba, 0x0c, 0xfd, 0xa2, 0x6c, 0x80, 0xbf, 0xff, 0x11, - 0xef, 0x70, 0x9f, 0xc3, 0x22, 0xb6, 0xd3, 0xd6, 0xe1, 0xd8, 0x5c, 0x3b, - 0xae, 0x59, 0x5c, 0xfb, 0xad, 0x8f, 0x2f, 0xaf, 0x1b, 0xd7, 0x2b, 0xd5, - 0x9b, 0x93, 0x70, 0xcd, 0x44, 0x1e, 0x2f, 0xb0, 0x3e, 0xe9, 0xff, 0x1f, - 0x62, 0x46, 0x17, 0xfc, 0xc9, 0x3a, 0x73, 0x5f, 0xdd, 0x96, 0x6b, 0x5e, - 0x4b, 0x83, 0xf4, 0x6f, 0x52, 0x83, 0x39, 0xc8, 0x9d, 0xa8, 0xd7, 0x2a, - 0x23, 0xda, 0x27, 0x22, 0x4d, 0x90, 0x06, 0x6e, 0x56, 0x86, 0x36, 0x3f, - 0xa4, 0x0c, 0x6d, 0x3e, 0x03, 0x5a, 0xc4, 0x55, 0x5c, 0x72, 0x0c, 0x6d, - 0x7e, 0x1d, 0x77, 0x5c, 0xc5, 0x0b, 0x4e, 0xc8, 0xc7, 0xc3, 0xf0, 0xf9, - 0x76, 0x15, 0xa2, 0xce, 0x78, 0x05, 0xf4, 0x5b, 0x8c, 0xa1, 0x7c, 0x81, - 0x38, 0xc7, 0xfc, 0x39, 0xce, 0x56, 0xdb, 0xff, 0xe3, 0x32, 0x51, 0x0c, - 0xb4, 0x5d, 0x95, 0x9d, 0xbb, 0x17, 0xf7, 0xf5, 0x5a, 0xce, 0x28, 0x2f, - 0xad, 0x8c, 0xbc, 0x7a, 0x17, 0xee, 0xdd, 0x89, 0x83, 0xd2, 0xed, 0x46, - 0xe4, 0x39, 0xf4, 0xf5, 0x43, 0x67, 0xa2, 0xf2, 0x32, 0xae, 0x9f, 0xe0, - 0x7a, 0x15, 0xd7, 0x2b, 0xe8, 0xf7, 0x45, 0x94, 0xaf, 0x97, 0x05, 0xb7, - 0x19, 0xf5, 0x45, 0x8d, 0x57, 0x5e, 0x70, 0xc6, 0x4e, 0xbe, 0x84, 0x2b, - 0xaa, 0x26, 0x2a, 0xcf, 0x3b, 0xd9, 0xb9, 0x60, 0xe3, 0xa2, 0x47, 0x19, - 0xf6, 0xa7, 0x8e, 0xe9, 0x7b, 0x08, 0x73, 0x00, 0x4d, 0x17, 0x17, 0x30, - 0xf6, 0x33, 0x9a, 0x67, 0x46, 0x20, 0xf3, 0xb3, 0xb0, 0x4b, 0xc6, 0x34, - 0x4c, 0x97, 0x03, 0x3e, 0xf8, 0xba, 0x03, 0xb8, 0xcf, 0x35, 0xca, 0x52, - 0x9c, 0x76, 0xe4, 0x97, 0x75, 0xfd, 0x6c, 0xb1, 0x5b, 0xe3, 0x76, 0x66, - 0x0d, 0xff, 0xd0, 0x3f, 0x0b, 0xe5, 0x81, 0x91, 0xc6, 0xb3, 0x05, 0xca, - 0x02, 0xe8, 0x9f, 0xc2, 0x14, 0xee, 0x8d, 0x5a, 0x26, 0xe4, 0x25, 0x94, - 0x07, 0x6c, 0x47, 0x99, 0x50, 0x2b, 0x77, 0x28, 0x6b, 0x28, 0x7b, 0x28, - 0x4b, 0xcc, 0x7a, 0x8c, 0x3f, 0x48, 0x19, 0x7e, 0x2d, 0xfc, 0x53, 0xda, - 0x1f, 0x9d, 0xc6, 0x07, 0x99, 0xce, 0x28, 0x23, 0x4f, 0xf7, 0xe8, 0xb5, - 0x98, 0x28, 0xa8, 0x38, 0x20, 0x47, 0x19, 0xae, 0x63, 0x7b, 0x71, 0xcf, - 0xaa, 0x09, 0x5c, 0xd9, 0x63, 0x1f, 0xc0, 0x6f, 0xae, 0xcd, 0x04, 0xea, - 0xe1, 0x2a, 0x8e, 0xe2, 0x8e, 0x0b, 0xb6, 0x99, 0x91, 0x23, 0x5c, 0xd3, - 0x84, 0x5d, 0xd3, 0x2f, 0x03, 0x0f, 0x9c, 0x9f, 0xd2, 0xf1, 0x07, 0xe5, - 0xed, 0x00, 0xde, 0x2b, 0xd6, 0xdf, 0x6d, 0x15, 0xc3, 0x83, 0xb8, 0x7a, - 0xc9, 0xcf, 0x2d, 0x66, 0xbd, 0x34, 0xed, 0x7e, 0x37, 0x6a, 0x78, 0x31, - 0x8e, 0xb2, 0x08, 0xca, 0xda, 0x45, 0xf3, 0xfe, 0x32, 0x1e, 0xd3, 0x16, - 0x8f, 0xfc, 0xad, 0xec, 0x6f, 0xd0, 0x13, 0x6c, 0xda, 0x8c, 0x37, 0x80, - 0x71, 0x31, 0x97, 0x63, 0x7b, 0xd4, 0x38, 0xe4, 0xf7, 0xb8, 0x47, 0x19, - 0xce, 0x38, 0x03, 0xe7, 0xc7, 0x7e, 0x51, 0xae, 0x71, 0xe0, 0x4b, 0xd5, - 0x87, 0xff, 0x32, 0xd6, 0xec, 0x71, 0xd9, 0x57, 0xbc, 0x5a, 0xfb, 0xd4, - 0x8d, 0x47, 0xcd, 0x7a, 0x88, 0x0a, 0xeb, 0xa1, 0xef, 0x38, 0x6d, 0x9b, - 0x31, 0xfd, 0x3e, 0x7a, 0x94, 0xbf, 0x29, 0x9f, 0x6b, 0xe5, 0xbd, 0xb1, - 0x6b, 0xf2, 0x2b, 0x64, 0x1d, 0x6d, 0x0b, 0xac, 0x59, 0xb9, 0x16, 0xef, - 0xf4, 0xf1, 0x29, 0xf3, 0xc8, 0x4f, 0x07, 0xc1, 0x13, 0xaa, 0xc1, 0xf0, - 0x3e, 0x7d, 0x8d, 0x7a, 0xfc, 0x04, 0xfb, 0x0b, 0xbc, 0x72, 0x02, 0xb6, - 0xdb, 0xae, 0xe5, 0x3e, 0x20, 0x2b, 0xe3, 0x31, 0x39, 0x59, 0x68, 0x91, - 0xb9, 0x82, 0x82, 0xc1, 0x60, 0x64, 0x67, 0x44, 0x12, 0x5a, 0xff, 0xd2, - 0xbe, 0x1b, 0x9e, 0x8e, 0x58, 0xba, 0x83, 0xc3, 0xd2, 0xfc, 0x1b, 0xd0, - 0xb1, 0x65, 0xe8, 0xd8, 0x56, 0xe8, 0xe0, 0xd5, 0x32, 0xa2, 0xab, 0x61, - 0xad, 0x8c, 0x60, 0x9b, 0x14, 0xbc, 0xf2, 0x83, 0x68, 0x17, 0xd2, 0x5f, - 0x4c, 0xd3, 0x5a, 0x56, 0x72, 0xce, 0xae, 0xca, 0x94, 0xb3, 0xbb, 0xb2, - 0x5a, 0x07, 0xf5, 0xb9, 0x51, 0x31, 0xb0, 0x9e, 0xd4, 0x71, 0xbc, 0x94, - 0x9f, 0x01, 0x4e, 0x76, 0x83, 0xee, 0x9e, 0x2e, 0xc1, 0x8f, 0xa7, 0x5c, - 0x06, 0xcc, 0x8f, 0x01, 0xe6, 0xd9, 0x92, 0x13, 0xda, 0x06, 0xc2, 0xe0, - 0xc9, 0xec, 0x74, 0xbf, 0x2c, 0xce, 0x93, 0x0e, 0x21, 0x03, 0x4a, 0x58, - 0x4f, 0x7f, 0x1d, 0xec, 0x00, 0x8e, 0x0f, 0xb9, 0x3d, 0xdd, 0xa1, 0xdf, - 0x19, 0x7d, 0xde, 0x29, 0x8b, 0xe5, 0xf7, 0x58, 0xd8, 0x0e, 0xd7, 0xc0, - 0xb6, 0x6e, 0x19, 0xb6, 0xdd, 0x80, 0x6d, 0x4f, 0x5d, 0xd8, 0xea, 0xe9, - 0xe2, 0x2e, 0xd8, 0x34, 0xe4, 0x8f, 0x10, 0xaf, 0xed, 0x96, 0x1e, 0x6e, - 0xb7, 0xf6, 0x2e, 0x6d, 0xa2, 0x9f, 0x02, 0x1e, 0xd2, 0x18, 0x7e, 0xcf, - 0x3d, 0x4a, 0x59, 0x86, 0x72, 0x3e, 0x7f, 0x06, 0x75, 0xf0, 0x3c, 0xf7, - 0xe7, 0x56, 0x0e, 0xde, 0x65, 0x61, 0xa1, 0x9d, 0x90, 0x86, 0x4d, 0x3c, - 0xe2, 0x64, 0xe6, 0x08, 0x43, 0x0e, 0xf0, 0xe2, 0x5d, 0xa5, 0xb6, 0x4f, - 0xde, 0xd9, 0xef, 0x15, 0xb6, 0x1f, 0xf6, 0x1d, 0xce, 0x65, 0xbd, 0xd5, - 0xf3, 0x21, 0x7d, 0x85, 0xf6, 0xf5, 0x94, 0x93, 0x5e, 0x33, 0xaf, 0x5a, - 0x9a, 0xa3, 0xbc, 0x8d, 0xca, 0x4e, 0xd0, 0xc9, 0xce, 0x15, 0xb4, 0xa6, - 0xdd, 0x10, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x18, 0xbe, 0xf1, 0x63, - 0xd0, 0x87, 0x94, 0x37, 0x37, 0x1b, 0xdf, 0x5c, 0x4e, 0x00, 0xd6, 0xf0, - 0x99, 0xb4, 0xc9, 0xdf, 0x94, 0x49, 0x55, 0x5a, 0x34, 0xbe, 0x4b, 0xa7, - 0x8e, 0x9f, 0x56, 0xed, 0xf5, 0xa8, 0x8c, 0x9a, 0x35, 0x3f, 0xcc, 0x35, - 0xa7, 0x2f, 0xd2, 0xfd, 0xc0, 0xa8, 0xe5, 0xaf, 0x54, 0x29, 0x27, 0xbb, - 0xed, 0xdc, 0xbf, 0x5c, 0x67, 0xed, 0x5a, 0x97, 0xd7, 0x6e, 0xb4, 0xb2, - 0x7a, 0x8e, 0x22, 0x5d, 0x0f, 0x44, 0xb5, 0x6f, 0x2b, 0xca, 0x97, 0x46, - 0x8f, 0xf2, 0x93, 0xb6, 0x12, 0xca, 0x67, 0xfb, 0xdc, 0x36, 0xd0, 0xdb, - 0x53, 0x6b, 0xec, 0xae, 0xa4, 0x95, 0x9b, 0xf4, 0x83, 0xc3, 0x31, 0x72, - 0x56, 0x4e, 0xe6, 0xd0, 0xff, 0x94, 0xb3, 0xb3, 0x52, 0x4f, 0x5e, 0x86, - 0x72, 0x92, 0xf3, 0xb9, 0x57, 0xee, 0x78, 0x90, 0x3c, 0x7a, 0xbb, 0xb6, - 0xaf, 0xaf, 0xda, 0x71, 0x00, 0xf8, 0x23, 0xfc, 0x8b, 0x9b, 0x60, 0x32, - 0x40, 0xe7, 0xa6, 0x65, 0xdc, 0xae, 0xdb, 0xf8, 0xf2, 0xfa, 0xf3, 0x6a, - 0xc7, 0x6f, 0xc6, 0x59, 0x95, 0x85, 0x59, 0xdb, 0xb1, 0xb0, 0xeb, 0x56, - 0xdb, 0xb2, 0x9c, 0x03, 0xed, 0xd9, 0x46, 0x63, 0x0b, 0x16, 0x69, 0x7f, - 0x52, 0x76, 0xd1, 0xfe, 0x8c, 0x35, 0x4a, 0x33, 0xe7, 0x33, 0x68, 0xcb, - 0x68, 0xa7, 0xae, 0x9e, 0xdf, 0x6a, 0xff, 0x91, 0x70, 0x12, 0x6e, 0x43, - 0x5b, 0x49, 0x45, 0xd8, 0x02, 0x19, 0xf5, 0xaf, 0xd5, 0x6b, 0xa0, 0x68, - 0xbb, 0xee, 0xf8, 0x76, 0x83, 0x89, 0x31, 0x27, 0xd1, 0x3f, 0xc7, 0x24, - 0xff, 0xf1, 0x4e, 0x3b, 0xbf, 0x9e, 0x2c, 0xab, 0xd5, 0x3d, 0x97, 0x2d, - 0xe3, 0x6f, 0xe7, 0x8a, 0x35, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x2d, 0x0e, - 0x49, 0x13, 0xa4, 0x85, 0x90, 0x16, 0xb7, 0x5a, 0x7d, 0x13, 0xd2, 0xde, - 0xa5, 0xa0, 0xbd, 0xfb, 0x80, 0x27, 0xca, 0x70, 0xc6, 0xed, 0x36, 0xe3, - 0xf9, 0x08, 0x9e, 0x43, 0x3e, 0xb9, 0x98, 0x0c, 0xa7, 0xfc, 0x66, 0x9b, - 0x8c, 0x95, 0xfb, 0xa1, 0x9f, 0xcb, 0x36, 0x9c, 0x37, 0xe5, 0xff, 0x57, - 0xe9, 0x77, 0x35, 0x1a, 0x3b, 0xfd, 0x43, 0x8d, 0x94, 0xaf, 0x9b, 0xe4, - 0x60, 0x4d, 0xd9, 0xc5, 0xe4, 0x77, 0xed, 0x9c, 0x2f, 0xff, 0x7f, 0x30, - 0xe7, 0xc4, 0xaa, 0x39, 0xbb, 0x76, 0xce, 0x15, 0xbc, 0x6f, 0xc3, 0xfb, - 0x16, 0xea, 0x82, 0x64, 0x55, 0xde, 0x58, 0x5c, 0xe8, 0x79, 0xd5, 0xca, - 0x89, 0x50, 0x46, 0x70, 0x5e, 0x1f, 0xb1, 0x73, 0x78, 0xa0, 0x66, 0x5e, - 0x1f, 0x79, 0x13, 0xf3, 0xea, 0x5c, 0x31, 0xaf, 0x5d, 0x17, 0x9d, 0x57, - 0x3d, 0x1e, 0x27, 0x2f, 0x87, 0xf3, 0x8b, 0xc9, 0x8d, 0x05, 0xce, 0x71, - 0x27, 0xe6, 0x48, 0x18, 0xc2, 0x39, 0x0e, 0xd9, 0x39, 0x8a, 0xea, 0xda, - 0xf1, 0x73, 0xf8, 0x5d, 0x3b, 0x3f, 0xea, 0xfe, 0x1f, 0x83, 0xa6, 0x9b, - 0x24, 0xd3, 0xdf, 0x64, 0xe5, 0xff, 0x97, 0xe5, 0xd6, 0x22, 0xd7, 0x3a, - 0x95, 0x16, 0xd9, 0xa3, 0xf6, 0x15, 0x9f, 0x6d, 0x64, 0x8c, 0x7f, 0x97, - 0x6f, 0xf5, 0x18, 0xf4, 0xc5, 0x6e, 0xd8, 0x7c, 0x3b, 0x0b, 0x6a, 0x20, - 0x22, 0x41, 0x70, 0x9b, 0xdf, 0x8c, 0xb1, 0x37, 0x6a, 0x5f, 0x75, 0x6d, - 0x7c, 0xfd, 0x99, 0x46, 0xf1, 0x68, 0x6f, 0x50, 0x9f, 0x43, 0xdf, 0x1d, - 0xa3, 0x0d, 0x96, 0x81, 0x9d, 0x9c, 0x4e, 0x44, 0xb4, 0x2d, 0x46, 0x9d, - 0x98, 0x4a, 0xa4, 0xa5, 0x2c, 0xd9, 0x63, 0xe9, 0x84, 0x12, 0x8e, 0x01, - 0x5b, 0x0d, 0x36, 0xe4, 0xad, 0x90, 0x35, 0xb7, 0x56, 0xf6, 0xaa, 0x5b, - 0x60, 0xef, 0xdc, 0x72, 0xf2, 0x03, 0xea, 0x36, 0xd8, 0x3a, 0xb7, 0x9d, - 0xbc, 0x41, 0xed, 0x83, 0x6d, 0xb3, 0x0f, 0x76, 0xce, 0xbe, 0x0a, 0x6d, - 0xcf, 0x9b, 0x41, 0x7b, 0x9d, 0x35, 0xb4, 0x46, 0x1b, 0x87, 0xf3, 0x23, - 0xee, 0x8f, 0x71, 0x0d, 0xfc, 0xa4, 0x7a, 0x45, 0xaf, 0x4b, 0xdb, 0x8a, - 0xb2, 0xd7, 0x92, 0x55, 0xa1, 0x7e, 0xda, 0x60, 0xe3, 0x46, 0x94, 0xb7, - 0xaf, 0x45, 0x5b, 0xa4, 0x11, 0x17, 0x78, 0x26, 0xfe, 0x48, 0x5b, 0xb5, - 0xf3, 0xdf, 0xd4, 0x24, 0x5e, 0x67, 0x93, 0x34, 0xdf, 0x0b, 0xf9, 0x5a, - 0x4b, 0x53, 0xbc, 0xbb, 0x56, 0xd7, 0x90, 0xb6, 0x28, 0x83, 0x43, 0x7a, - 0xd8, 0xfa, 0x1a, 0xf2, 0xf7, 0xa2, 0xf4, 0x74, 0x4f, 0x64, 0x28, 0x08, - 0xc6, 0x07, 0x64, 0x23, 0xe3, 0x01, 0x99, 0x4a, 0x35, 0x26, 0xa0, 0xbc, - 0xda, 0x98, 0x00, 0xfd, 0xac, 0x47, 0x80, 0xdf, 0x19, 0x5c, 0x22, 0x63, - 0x8c, 0x3b, 0x54, 0x42, 0xbb, 0xfc, 0x1b, 0xd6, 0x2e, 0x0f, 0xe1, 0x48, - 0x02, 0x0e, 0x23, 0x9f, 0xd7, 0xea, 0xb9, 0x95, 0xfa, 0x3b, 0xb7, 0x6c, - 0xd3, 0x26, 0xe5, 0xc6, 0x22, 0xe7, 0x4d, 0x19, 0x4c, 0xdc, 0xd4, 0xca, - 0xe0, 0x84, 0xb5, 0xa3, 0x50, 0x47, 0xcb, 0xcf, 0xb5, 0xb2, 0x93, 0x72, - 0x8f, 0xf1, 0xf9, 0x07, 0x7c, 0xd2, 0xfa, 0x7b, 0x24, 0xbd, 0x1c, 0x9f, - 0x17, 0xd0, 0x9b, 0xf8, 0x91, 0x21, 0xbd, 0xdf, 0xe6, 0xce, 0xca, 0x6e, - 0x19, 0x8e, 0x33, 0xd6, 0xc9, 0x78, 0x9e, 0x97, 0x9b, 0x05, 0x0f, 0x4c, - 0x16, 0x15, 0x2c, 0xf8, 0x46, 0x19, 0x73, 0x03, 0xd9, 0xe5, 0x3b, 0x3a, - 0x76, 0x6c, 0x74, 0xed, 0x4c, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0xff, 0x5d, - 0x04, 0xf5, 0x2d, 0x6a, 0xfb, 0x56, 0x69, 0xfd, 0xbb, 0xa0, 0xeb, 0x7c, - 0xae, 0x29, 0x8c, 0x63, 0x2e, 0xba, 0x11, 0x5b, 0xaf, 0xb6, 0xfc, 0x8b, - 0x36, 0x3e, 0x9d, 0x84, 0xec, 0x0f, 0xcb, 0xfe, 0xb0, 0x4e, 0xd9, 0xb7, - 0xea, 0x94, 0xfd, 0xcf, 0x3a, 0x65, 0x26, 0x2e, 0xb8, 0xb3, 0xf0, 0xf7, - 0x78, 0x37, 0xa5, 0x7d, 0x77, 0xb1, 0xfb, 0x61, 0xb9, 0xe5, 0x3a, 0x1b, - 0xac, 0x5f, 0xc6, 0x18, 0xb1, 0x89, 0x0d, 0x67, 0x75, 0x6c, 0xb8, 0xcf, - 0xdd, 0xa1, 0xf4, 0x5e, 0xca, 0x7e, 0xc6, 0x19, 0xf7, 0x69, 0xbc, 0x10, - 0x27, 0x5f, 0x61, 0x0c, 0x38, 0xc7, 0xbd, 0xd8, 0xa4, 0xba, 0x18, 0x6d, - 0x57, 0x6d, 0x13, 0xb3, 0x6e, 0xb4, 0x8b, 0x5b, 0x64, 0x04, 0xb6, 0xc2, - 0xce, 0x42, 0x9b, 0xec, 0x9a, 0x1e, 0x58, 0x47, 0xbd, 0xb5, 0x7b, 0xda, - 0xf8, 0x83, 0xfb, 0xc0, 0x57, 0x69, 0x21, 0x8c, 0x29, 0x5f, 0x84, 0x36, - 0xf1, 0x5a, 0x5b, 0xf8, 0xb5, 0xfb, 0xfb, 0xa5, 0x8b, 0xf4, 0xe7, 0xc0, - 0x76, 0x78, 0xa3, 0xfd, 0x35, 0xcb, 0xc8, 0x74, 0x88, 0x2b, 0xf5, 0x33, - 0xb6, 0x8b, 0x5c, 0xa4, 0x9d, 0xb6, 0x4b, 0xe4, 0xe9, 0x65, 0x59, 0xbc, - 0x15, 0x36, 0x93, 0x04, 0x99, 0x01, 0xe9, 0x8c, 0x88, 0x8e, 0xf1, 0xf8, - 0x46, 0x36, 0xf7, 0x70, 0x6f, 0x07, 0xf4, 0x6f, 0x6c, 0x15, 0x13, 0x37, - 0x0d, 0xed, 0x94, 0x7a, 0xb4, 0x7b, 0x9d, 0xa5, 0x5d, 0xee, 0xb9, 0xee, - 0xa6, 0xcc, 0xd5, 0x6b, 0x42, 0x3a, 0xde, 0x55, 0x90, 0x64, 0x48, 0xc7, - 0x8b, 0x92, 0x5e, 0x41, 0xc7, 0x8b, 0x32, 0xa4, 0xe9, 0xb8, 0x71, 0x05, - 0x1d, 0x77, 0x5a, 0x3a, 0xde, 0x13, 0x33, 0x74, 0xa1, 0xb4, 0x9e, 0x22, - 0x9d, 0x1a, 0x3a, 0x76, 0x34, 0x1d, 0x2f, 0xe2, 0x1e, 0xf5, 0xae, 0xb3, - 0x75, 0x22, 0xb6, 0x8c, 0xbf, 0xc3, 0x32, 0xca, 0xc5, 0x4f, 0xc6, 0x8c, - 0x5e, 0x1a, 0x02, 0x1d, 0x85, 0xe5, 0xfb, 0x6d, 0xfc, 0xa0, 0xb6, 0xcc, - 0xc4, 0x47, 0x76, 0x16, 0xc6, 0x62, 0x2b, 0xe9, 0x73, 0x08, 0xf4, 0x19, - 0xd6, 0x79, 0x2d, 0xfa, 0x6c, 0xb6, 0xfb, 0x16, 0x71, 0xbd, 0x2f, 0x9f, - 0x8e, 0x1b, 0x5a, 0xbd, 0x45, 0xcf, 0x9d, 0xf3, 0x3e, 0xfb, 0x06, 0x68, - 0xd5, 0xac, 0xcd, 0xb9, 0xaa, 0xbf, 0xcd, 0x58, 0x54, 0xd2, 0xc4, 0xb0, - 0x19, 0x27, 0xbd, 0x98, 0xed, 0x68, 0xe4, 0x53, 0x83, 0x96, 0x4f, 0xad, - 0x63, 0xcc, 0x35, 0xa8, 0xca, 0xec, 0x01, 0xe8, 0x0a, 0xda, 0xd8, 0x5a, - 0x4e, 0xe3, 0x5d, 0x67, 0x32, 0x53, 0x78, 0x35, 0x88, 0x78, 0x8c, 0x0f, - 0x71, 0x5f, 0x40, 0xc6, 0x1c, 0x94, 0x75, 0x95, 0xcd, 0xbc, 0x94, 0xd7, - 0x8a, 0xe7, 0x01, 0xe9, 0x2a, 0x2b, 0xf9, 0xe8, 0x74, 0x8b, 0xec, 0x2f, - 0x44, 0xe5, 0xe3, 0x68, 0xff, 0xb1, 0x82, 0x0b, 0x7f, 0xfc, 0x4c, 0x8c, - 0x76, 0xe1, 0xbe, 0x02, 0xf7, 0x27, 0x59, 0x37, 0xbe, 0x6a, 0x7f, 0x36, - 0x22, 0x5d, 0x3d, 0x79, 0x78, 0x2a, 0x12, 0xdd, 0x03, 0x38, 0x9a, 0x86, - 0x86, 0xe4, 0x07, 0x03, 0x1b, 0x51, 0xf6, 0xb2, 0x1d, 0x6f, 0xd4, 0x31, - 0xf1, 0xde, 0x41, 0x79, 0x77, 0x65, 0x48, 0xae, 0xaf, 0x98, 0x3d, 0xd5, - 0xea, 0x9e, 0x69, 0xca, 0x5d, 0x80, 0xfe, 0x49, 0xbb, 0x41, 0x70, 0xce, - 0xc3, 0xaa, 0x1f, 0x89, 0x4a, 0xac, 0x27, 0x95, 0x58, 0x10, 0xf3, 0x7c, - 0xbe, 0xfc, 0x0f, 0xc1, 0x58, 0x3c, 0x2a, 0x3f, 0xf0, 0x38, 0xc7, 0x41, - 0xb9, 0xae, 0x5c, 0x3b, 0x36, 0x97, 0xf3, 0x0f, 0x63, 0xdc, 0xa7, 0xc8, - 0x54, 0x16, 0x62, 0x8c, 0xa5, 0xd3, 0xe7, 0xe8, 0x7a, 0x1b, 0xfc, 0x38, - 0x48, 0xee, 0xae, 0xb7, 0x81, 0x6e, 0xe2, 0xd0, 0xf9, 0x57, 0x01, 0xc6, - 0xab, 0x18, 0xfb, 0x62, 0xcc, 0x8b, 0xcf, 0x5f, 0xc7, 0xb8, 0x6c, 0xfb, - 0x1b, 0xd6, 0x5e, 0xe6, 0xfa, 0x1b, 0xde, 0xa9, 0xaf, 0x77, 0x5a, 0xc7, - 0x62, 0x43, 0xe2, 0xc4, 0xde, 0x91, 0x90, 0x75, 0x5e, 0xed, 0xf8, 0xdc, - 0x27, 0x86, 0xc5, 0x38, 0x20, 0xd1, 0xdd, 0xdb, 0x07, 0x65, 0x04, 0xf3, - 0xdb, 0xb9, 0x66, 0x7e, 0xf7, 0x08, 0xe3, 0xab, 0xe7, 0x0b, 0x9c, 0x43, - 0x75, 0x5e, 0xea, 0x0b, 0x66, 0x5e, 0xb1, 0x9e, 0xd5, 0xf3, 0xd1, 0xed, - 0xd5, 0x09, 0xc0, 0xf2, 0x35, 0x9d, 0x57, 0x10, 0x04, 0x6f, 0xed, 0x39, - 0x1f, 0x24, 0x2f, 0x49, 0xf5, 0x2e, 0x54, 0xf7, 0x77, 0xc6, 0x22, 0x43, - 0x69, 0xad, 0xcf, 0xf0, 0x9c, 0xcc, 0x96, 0xd3, 0x58, 0x47, 0x89, 0x66, - 0xfb, 0xa3, 0x9a, 0x4f, 0xb2, 0x5e, 0xda, 0xee, 0x61, 0x85, 0x3e, 0x54, - 0x10, 0x28, 0x6f, 0xb5, 0xdc, 0xa0, 0xbe, 0xc2, 0xdc, 0xe5, 0xdf, 0xda, - 0x1c, 0x96, 0x5e, 0xc6, 0xb3, 0xc6, 0xa2, 0x43, 0xb1, 0x64, 0xbe, 0xec, - 0xe1, 0x77, 0x0b, 0xee, 0x3b, 0x60, 0xaf, 0xf8, 0xb0, 0x67, 0x24, 0xae, - 0x8c, 0x6c, 0x00, 0x2d, 0xf7, 0xe4, 0x94, 0x22, 0x6f, 0xba, 0xc9, 0xc9, - 0x72, 0x3c, 0x59, 0x2a, 0x7f, 0x96, 0xed, 0x51, 0xb7, 0x5e, 0x2c, 0xcf, - 0xc8, 0x86, 0xa7, 0x2a, 0x1c, 0x83, 0xfe, 0xef, 0x1b, 0x19, 0x23, 0x6a, - 0xfb, 0x66, 0x9f, 0x21, 0x5e, 0xa2, 0x74, 0xc9, 0xf1, 0x2f, 0x6d, 0x7d, - 0x13, 0xce, 0xef, 0xb3, 0x16, 0xee, 0xd5, 0xe3, 0xbe, 0xa0, 0xed, 0x97, - 0xd3, 0x15, 0xda, 0x8c, 0xdc, 0xdf, 0x49, 0x1d, 0x9f, 0x11, 0xc2, 0x11, - 0x04, 0xcf, 0xf9, 0x46, 0x77, 0x3f, 0x55, 0xe1, 0x1e, 0x47, 0x10, 0xfc, - 0x88, 0x76, 0xf1, 0xde, 0x22, 0xc6, 0x0b, 0x71, 0xb0, 0x35, 0x17, 0x85, - 0x5c, 0x9c, 0x1a, 0x20, 0x7e, 0x05, 0x1e, 0x6a, 0x8f, 0x7b, 0xa3, 0xc4, - 0x92, 0x9f, 0x2a, 0xb7, 0x24, 0x3f, 0x5d, 0x76, 0x81, 0x67, 0xce, 0x3b, - 0x9e, 0x9c, 0xb0, 0x73, 0xce, 0x96, 0x89, 0xdf, 0xd7, 0xda, 0x87, 0x7c, - 0x61, 0x85, 0xbf, 0x44, 0x98, 0xaa, 0xb0, 0x10, 0xb6, 0xa4, 0xc5, 0x4d, - 0x10, 0xfc, 0xd8, 0x37, 0x6b, 0x3a, 0x55, 0x94, 0x29, 0x8c, 0x9b, 0xdb, - 0xac, 0x88, 0x87, 0x58, 0xf2, 0x0e, 0x8c, 0xfd, 0x29, 0x8c, 0xbd, 0xbf, - 0xcc, 0xf1, 0x20, 0x2b, 0x30, 0xf7, 0xa9, 0x4a, 0x08, 0x6f, 0xbd, 0xb1, - 0xc3, 0x35, 0xef, 0xb5, 0x36, 0x5e, 0xf8, 0xac, 0x11, 0xd9, 0xae, 0xbc, - 0x7e, 0xd0, 0xd7, 0xe2, 0xa6, 0xa8, 0xfc, 0x22, 0xe4, 0x6e, 0x20, 0x8f, - 0x42, 0x9e, 0x2d, 0x6a, 0xba, 0xc9, 0x5c, 0xce, 0xff, 0x23, 0xf2, 0xeb, - 0xeb, 0x18, 0x5f, 0x1e, 0xf6, 0x68, 0xbb, 0x2e, 0x05, 0x8b, 0x1e, 0xe5, - 0xf3, 0x06, 0x99, 0x71, 0x73, 0xbd, 0xd0, 0x15, 0x28, 0x6b, 0xa5, 0xbf, - 0x9d, 0xcc, 0x44, 0x52, 0xc9, 0x49, 0x61, 0x3e, 0x14, 0x73, 0x15, 0x98, - 0x23, 0x44, 0xd9, 0x10, 0x85, 0xcc, 0xe3, 0x1a, 0x9a, 0xf1, 0x26, 0xcb, - 0xd5, 0xba, 0x07, 0x84, 0x7b, 0x86, 0xa9, 0xc4, 0x3e, 0x6d, 0x9f, 0x88, - 0x8c, 0x17, 0x58, 0x77, 0x3b, 0xac, 0x13, 0xaf, 0xa6, 0xbe, 0xce, 0xe1, - 0x02, 0x9f, 0x87, 0x71, 0xac, 0x58, 0x2c, 0x53, 0x90, 0x97, 0x23, 0x03, - 0xf2, 0x32, 0xed, 0xce, 0x61, 0xd0, 0xb6, 0xeb, 0xf1, 0xbd, 0x29, 0xcf, - 0xf8, 0xb2, 0x94, 0x19, 0xec, 0xa3, 0x9d, 0x9d, 0x53, 0x9a, 0x27, 0x44, - 0xa1, 0x6d, 0x2c, 0x5b, 0x96, 0x91, 0x6c, 0xc1, 0xc6, 0x7a, 0x46, 0x39, - 0xe7, 0x0d, 0x35, 0x73, 0x6f, 0x95, 0x28, 0x60, 0x1a, 0x89, 0x24, 0x9d, - 0x06, 0xef, 0x23, 0x2d, 0x46, 0xe7, 0x43, 0xee, 0xb7, 0xdd, 0xdf, 0xce, - 0x3d, 0x53, 0x05, 0x1f, 0x5a, 0xb5, 0xdf, 0x7e, 0x8d, 0x1a, 0xfa, 0xf3, - 0x04, 0xf4, 0xa0, 0x95, 0x95, 0xb1, 0x91, 0xae, 0x65, 0xfa, 0xe6, 0xf8, - 0xd2, 0x1e, 0xf1, 0x92, 0x23, 0xc3, 0x65, 0x51, 0x91, 0x21, 0x37, 0x36, - 0x5c, 0x5e, 0x49, 0xf3, 0x4f, 0x55, 0xfe, 0xbd, 0xb5, 0x05, 0x6b, 0x63, - 0xaa, 0xb5, 0xef, 0xc8, 0x77, 0x2b, 0xf6, 0x2b, 0x92, 0x26, 0x07, 0x86, - 0xfb, 0xb4, 0x5c, 0x93, 0xf4, 0x5b, 0x1b, 0xa0, 0x7c, 0x66, 0xb4, 0x8f, - 0xc6, 0x9c, 0x8b, 0x98, 0xcd, 0x3d, 0x33, 0xb8, 0x4e, 0x97, 0x1d, 0x99, - 0x82, 0x7c, 0x38, 0x20, 0x7f, 0x1f, 0xa4, 0xe3, 0xe6, 0xbd, 0x59, 0x5f, - 0xd6, 0xe7, 0x5e, 0x44, 0xb3, 0xe4, 0x4f, 0x46, 0x25, 0x77, 0x92, 0x7b, - 0x60, 0xcf, 0xed, 0xaf, 0xe6, 0x6d, 0x50, 0x0e, 0x70, 0xbf, 0xd6, 0x91, - 0x3c, 0xfc, 0xda, 0x11, 0xee, 0xc3, 0xf7, 0xff, 0x1f, 0xf4, 0xc1, 0x7a, - 0x61, 0xdb, 0x16, 0xb4, 0x6d, 0xb4, 0x6d, 0x47, 0xef, 0x78, 0x73, 0x6d, - 0x5b, 0xd1, 0x36, 0x16, 0x8e, 0xfb, 0x06, 0xdb, 0x6a, 0x7c, 0x5e, 0x33, - 0x5c, 0x28, 0x2e, 0xc1, 0x4f, 0x4e, 0x4c, 0x48, 0xda, 0x19, 0x1f, 0xd0, - 0xf3, 0xb9, 0x66, 0xb8, 0x0c, 0x38, 0xe2, 0x41, 0x90, 0xf7, 0x43, 0x3d, - 0xcc, 0x7f, 0xc7, 0x44, 0x3c, 0x96, 0x71, 0xdf, 0x92, 0xfe, 0x04, 0xa3, - 0xa4, 0x2e, 0xf3, 0xd9, 0x24, 0xcf, 0xfd, 0xc9, 0xf8, 0x46, 0xdc, 0x55, - 0x17, 0x71, 0x92, 0xf5, 0x18, 0xef, 0xdd, 0x68, 0xcb, 0x23, 0x2c, 0x4f, - 0x45, 0x21, 0x4b, 0x4c, 0x79, 0xc4, 0x96, 0x03, 0x26, 0x3f, 0x9f, 0x04, - 0xb7, 0xd9, 0x72, 0x3e, 0x2b, 0x5d, 0x6e, 0x9e, 0x0d, 0x0f, 0x8d, 0x09, - 0xe3, 0x3a, 0x99, 0xeb, 0x1a, 0x64, 0x2b, 0xd6, 0x87, 0x3e, 0xa3, 0x23, - 0xcd, 0x80, 0xe3, 0x9c, 0xff, 0x76, 0xd8, 0xd6, 0x81, 0xfc, 0xc0, 0x37, - 0xf4, 0x3f, 0x2b, 0x3d, 0x69, 0xe5, 0x30, 0x07, 0x20, 0x90, 0x9d, 0xfe, - 0xb6, 0xc4, 0x2e, 0xfc, 0x1e, 0xef, 0x4f, 0xca, 0xec, 0x20, 0xe8, 0xb1, - 0x9f, 0xbc, 0xb1, 0x15, 0x36, 0x0f, 0x7e, 0xf7, 0xb4, 0xc8, 0x92, 0x9b, - 0x73, 0xd7, 0xc1, 0x5f, 0x1b, 0xc1, 0xac, 0xe6, 0x0a, 0x9e, 0x7b, 0x1b, - 0x84, 0x5c, 0xda, 0xed, 0xc1, 0xbd, 0x76, 0xbe, 0xdf, 0xc2, 0x7c, 0x7f, - 0xad, 0x59, 0x9a, 0x59, 0x5e, 0x5b, 0xb7, 0x51, 0xf6, 0xb8, 0xdb, 0xdd, - 0xd8, 0x8a, 0xba, 0xe7, 0x51, 0x97, 0x65, 0x9e, 0xcb, 0x1c, 0x9d, 0xd9, - 0x32, 0xe9, 0xcc, 0xc0, 0xda, 0xd5, 0x13, 0x04, 0xd7, 0xf9, 0x1c, 0x37, - 0x08, 0xae, 0xf7, 0xfb, 0xdc, 0x67, 0xe5, 0xf9, 0xc0, 0xd8, 0x54, 0x21, - 0xed, 0x3c, 0x67, 0xe5, 0x75, 0x10, 0xbc, 0xec, 0xf7, 0xca, 0xef, 0x54, - 0x52, 0x8f, 0xd3, 0xe7, 0x3e, 0x83, 0xe7, 0x33, 0xbe, 0xc9, 0x2b, 0xfa, - 0x13, 0xb4, 0x8b, 0xab, 0x7e, 0xd0, 0xb0, 0x27, 0x5f, 0xd4, 0x3e, 0x3a, - 0xf1, 0x67, 0x62, 0xfc, 0x55, 0x18, 0x30, 0x61, 0x2f, 0xb3, 0xc9, 0x65, - 0x7e, 0xa0, 0xa6, 0xdf, 0xda, 0x77, 0x0a, 0xef, 0x58, 0x16, 0x04, 0x97, - 0x0c, 0xfc, 0x31, 0xe6, 0x94, 0x2a, 0x71, 0xef, 0xee, 0x03, 0x9a, 0xff, - 0x04, 0x7e, 0x3d, 0xe9, 0x24, 0xea, 0x2a, 0xe5, 0x1d, 0xee, 0x52, 0xa9, - 0x9c, 0xc8, 0x5b, 0xb0, 0xfe, 0x5c, 0x63, 0x30, 0x48, 0x1b, 0x60, 0xdf, - 0xb6, 0xbd, 0xd9, 0xc4, 0x92, 0xe8, 0x4b, 0xa7, 0x37, 0xc1, 0xd7, 0xd5, - 0xf6, 0x4c, 0x14, 0x7c, 0x3d, 0xd1, 0x16, 0x04, 0xef, 0xf7, 0xc3, 0x35, - 0xb3, 0xb1, 0x6a, 0xe8, 0xf8, 0x6c, 0xff, 0xb9, 0x66, 0x63, 0xc7, 0x31, - 0x4f, 0x30, 0xa9, 0xe3, 0xfa, 0xaa, 0x1d, 0x3a, 0x64, 0xdb, 0x57, 0x39, - 0x7e, 0x8e, 0xe5, 0xef, 0xf3, 0x43, 0x98, 0xaa, 0xed, 0xb3, 0xfd, 0xeb, - 0xac, 0xcd, 0x19, 0x05, 0x2e, 0x3d, 0xb7, 0x4b, 0xfd, 0x4d, 0x60, 0x74, - 0x6b, 0x48, 0xc3, 0x7f, 0x17, 0x3c, 0x18, 0x37, 0xcf, 0x99, 0x6d, 0xec, - 0x63, 0xab, 0x4c, 0x6e, 0xc3, 0x73, 0xf4, 0x5a, 0xdc, 0x87, 0x2f, 0x8b, - 0xc8, 0x15, 0x89, 0x61, 0xb5, 0xcd, 0x7d, 0x50, 0xfa, 0xac, 0x8c, 0xfb, - 0x1a, 0xf4, 0x7d, 0x0e, 0xfe, 0x78, 0x93, 0x3c, 0x08, 0x9a, 0x56, 0x03, - 0xa9, 0xe4, 0x82, 0x4a, 0xf5, 0xce, 0xa8, 0x94, 0x3f, 0xa6, 0xae, 0xe7, - 0xbc, 0x06, 0x89, 0x8b, 0x19, 0xe2, 0xb7, 0x08, 0xfc, 0x17, 0x81, 0xe3, - 0x8b, 0xee, 0xf1, 0xfa, 0x56, 0xb7, 0x18, 0xfd, 0x96, 0xd3, 0xb4, 0x69, - 0xec, 0xf2, 0x3f, 0xf6, 0xc3, 0x35, 0x84, 0x6d, 0xc8, 0x1c, 0x99, 0xba, - 0x6b, 0x94, 0xe5, 0x1a, 0x41, 0x31, 0xe4, 0x40, 0xf7, 0xa9, 0xe4, 0x84, - 0x5a, 0x0a, 0x36, 0xed, 0xe8, 0xee, 0x7d, 0x42, 0xf7, 0x93, 0xf2, 0xd3, - 0x2a, 0x0f, 0x78, 0xb6, 0x4a, 0xd3, 0x0e, 0xe2, 0x99, 0xb0, 0xc6, 0x18, - 0x4f, 0x72, 0xef, 0x40, 0xdd, 0x31, 0xa5, 0xf7, 0xa0, 0x6d, 0x1d, 0xc2, - 0x1c, 0x5f, 0x2f, 0xcd, 0xd4, 0x43, 0x8c, 0x93, 0xbd, 0x96, 0x2e, 0x84, - 0x4c, 0x3a, 0x46, 0x19, 0x18, 0x31, 0xb1, 0xdf, 0xca, 0xcf, 0xa1, 0x9d, - 0xce, 0x67, 0x89, 0x45, 0x21, 0xa3, 0xa6, 0xc0, 0xc5, 0x87, 0x8e, 0x49, - 0xb4, 0xc1, 0xfb, 0x5f, 0xcd, 0xc6, 0x6f, 0xa2, 0x0f, 0xc5, 0xb1, 0x1b, - 0x24, 0xbf, 0x26, 0xde, 0x52, 0x02, 0xfc, 0xcd, 0x32, 0x79, 0x8c, 0x6b, - 0x11, 0x85, 0xcc, 0xe1, 0xd8, 0x12, 0xcd, 0xf4, 0x07, 0xc1, 0x38, 0xcb, - 0x4f, 0x92, 0x7f, 0x25, 0xc5, 0x77, 0xb9, 0x93, 0x0b, 0x9b, 0xd4, 0x0a, - 0x59, 0xdb, 0x62, 0xe1, 0xd0, 0x78, 0x92, 0x92, 0x96, 0x23, 0xd4, 0x37, - 0xb7, 0xd5, 0xc0, 0x33, 0x7a, 0xc7, 0x94, 0xd7, 0xf8, 0x26, 0xe0, 0xf9, - 0x3d, 0xc0, 0xd3, 0x62, 0xe1, 0x69, 0x5c, 0x05, 0x4f, 0x4b, 0x08, 0x0f, - 0xe4, 0x1c, 0xe5, 0x6a, 0xec, 0x9a, 0x74, 0x59, 0x9c, 0xbc, 0x27, 0x9d, - 0x4a, 0xfb, 0x2f, 0xd4, 0x37, 0x8d, 0xee, 0xf8, 0x80, 0x2b, 0xe3, 0x5a, - 0xd7, 0x44, 0xaf, 0xe9, 0x2e, 0x2f, 0xc0, 0x7a, 0x15, 0x27, 0xe3, 0x11, - 0xf6, 0x7a, 0x76, 0xd5, 0x3d, 0x90, 0xff, 0x8b, 0xa9, 0xa8, 0xb5, 0x25, - 0x4a, 0x3e, 0xfd, 0x96, 0xb8, 0xde, 0xdb, 0xaf, 0xc2, 0xf4, 0x12, 0x60, - 0x82, 0x3c, 0x3e, 0xd6, 0xe7, 0x8e, 0xca, 0xa5, 0xda, 0x37, 0xb3, 0xb8, - 0xc6, 0xdc, 0x62, 0x35, 0x73, 0x83, 0xfe, 0x53, 0xe1, 0xdc, 0x20, 0x13, - 0x51, 0xaf, 0x24, 0xf7, 0x5b, 0x5c, 0xb4, 0x62, 0x4e, 0xb1, 0x9a, 0xf9, - 0x74, 0x27, 0xf6, 0xb3, 0xcc, 0xcc, 0xa7, 0x27, 0xef, 0xc5, 0x2c, 0x7e, - 0x57, 0xc3, 0x58, 0xf5, 0x17, 0x67, 0x24, 0x90, 0x29, 0x1f, 0x6b, 0xd4, - 0x4b, 0xff, 0x24, 0x66, 0xf3, 0x98, 0x15, 0x9e, 0x37, 0x58, 0xfe, 0x72, - 0x25, 0xaf, 0xfd, 0xb7, 0x2f, 0xad, 0x37, 0x7c, 0x1a, 0xb5, 0xf9, 0x6b, - 0xfc, 0xdd, 0xb1, 0xde, 0xee, 0xef, 0xe7, 0xd2, 0xf2, 0xfb, 0xeb, 0x69, - 0x97, 0x34, 0x78, 0x43, 0xab, 0xca, 0x62, 0x28, 0xbb, 0x7d, 0xbd, 0x95, - 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1a, 0xf3, 0x34, 0xf8, 0x8e, 0x32, 0xb8, - 0x16, 0x27, 0x7d, 0x60, 0x45, 0xf2, 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc, - 0x51, 0x7d, 0x27, 0x8c, 0xa3, 0xe3, 0x77, 0x3d, 0xdb, 0x9f, 0xf8, 0x26, - 0xae, 0xe5, 0xdb, 0x53, 0xe0, 0xfb, 0x03, 0xbe, 0x13, 0x9d, 0x65, 0x1e, - 0x80, 0xa6, 0xe1, 0xda, 0xbe, 0xaf, 0x47, 0xdf, 0x21, 0x2d, 0x93, 0x5e, - 0xae, 0xd7, 0x74, 0xd3, 0x44, 0x5d, 0x7c, 0x8c, 0xf4, 0xc7, 0x58, 0x72, - 0xb3, 0xd6, 0x8f, 0xd5, 0x75, 0x6c, 0x82, 0xae, 0x89, 0x1b, 0x1e, 0x75, - 0xcd, 0x7e, 0x77, 0xb5, 0xbf, 0x31, 0xf4, 0x47, 0x3b, 0x0d, 0x7e, 0xba, - 0xc7, 0x68, 0x0e, 0xe5, 0x97, 0x13, 0x55, 0x57, 0x6a, 0x3f, 0x33, 0xa6, - 0xf3, 0x8e, 0x96, 0xeb, 0x4e, 0xd8, 0xb1, 0x49, 0xb7, 0x26, 0xfe, 0x5f, - 0x1d, 0x5f, 0x1c, 0xb5, 0x4d, 0x40, 0x65, 0x8d, 0x32, 0x35, 0x40, 0x1a, - 0xe5, 0xdc, 0xb5, 0x0d, 0x75, 0x0d, 0xed, 0x08, 0x43, 0x9f, 0xb4, 0x9d, - 0xa2, 0xd7, 0x64, 0x0b, 0x8d, 0xc6, 0x67, 0x89, 0xcb, 0xe6, 0x06, 0x9d, - 0x47, 0x80, 0xb2, 0x72, 0xa8, 0xcb, 0xa2, 0x32, 0xdb, 0xff, 0xbf, 0x83, - 0xf4, 0x5e, 0xd6, 0xad, 0xbb, 0x6f, 0x9f, 0x98, 0x11, 0x8d, 0xa7, 0xbf, - 0xa8, 0xe2, 0xc9, 0xce, 0x2d, 0xbe, 0x7a, 0x6e, 0x05, 0xc0, 0x7b, 0x0f, - 0x64, 0x27, 0xd7, 0xc9, 0xe4, 0x6f, 0x3f, 0x2e, 0x4e, 0x34, 0xd3, 0x5b, - 0x6f, 0x6e, 0xa5, 0x10, 0xaf, 0x9c, 0x1b, 0x68, 0x35, 0x9c, 0x17, 0x69, - 0x3b, 0xae, 0xf7, 0x89, 0x94, 0x22, 0x2c, 0xad, 0xab, 0x70, 0x1b, 0xd2, - 0x9d, 0xa1, 0xb9, 0xa7, 0x34, 0xcd, 0xb5, 0x58, 0x9a, 0x43, 0x5d, 0x97, - 0xfb, 0xde, 0xa3, 0x2d, 0x55, 0x9a, 0xdb, 0x60, 0x69, 0xee, 0x99, 0xf5, - 0x66, 0x4f, 0xfc, 0xfd, 0x2d, 0x66, 0x4f, 0xea, 0x2f, 0x57, 0x3d, 0x6f, - 0xa2, 0xcd, 0x08, 0x5f, 0x2c, 0x7c, 0xae, 0x85, 0xf5, 0x0c, 0x60, 0xad, - 0x95, 0x35, 0x4d, 0x36, 0xee, 0xc6, 0xfd, 0x73, 0xfa, 0x7d, 0x51, 0x79, - 0x14, 0x76, 0x50, 0xbe, 0xfc, 0x8f, 0xc1, 0x02, 0x7c, 0xbf, 0xa9, 0x65, - 0xdd, 0x7b, 0x5b, 0x0b, 0xf9, 0x6d, 0x06, 0xbf, 0x0e, 0xd6, 0xf8, 0x3c, - 0x98, 0x2f, 0xca, 0xfe, 0x01, 0xeb, 0x01, 0xb9, 0xbc, 0x5c, 0x97, 0x31, - 0x0b, 0xe3, 0xe3, 0x30, 0x66, 0x68, 0xf6, 0x13, 0x29, 0xe7, 0xef, 0x84, - 0x4f, 0x74, 0x0f, 0xf4, 0x24, 0xe9, 0xfb, 0xa5, 0x16, 0x93, 0xe7, 0x1b, - 0x87, 0x1e, 0xfb, 0x65, 0x9b, 0x0b, 0x75, 0xf8, 0x57, 0xeb, 0xe7, 0xf8, - 0x82, 0xf6, 0x1d, 0xd2, 0xcc, 0xdf, 0xb7, 0x98, 0x98, 0xf1, 0xb7, 0x5a, - 0xc8, 0x67, 0x6a, 0xdb, 0x0f, 0x37, 0x68, 0xbe, 0x70, 0xc2, 0xe7, 0xcf, - 0xb4, 0xae, 0x7c, 0x0e, 0xdb, 0x3d, 0xd9, 0xba, 0xb2, 0x5d, 0x58, 0xfe, - 0x73, 0x1b, 0x57, 0x96, 0x5f, 0xe3, 0xae, 0x6c, 0xff, 0xf5, 0x55, 0xcf, - 0x2d, 0x9b, 0x56, 0x3e, 0x5f, 0xbd, 0xea, 0x79, 0x6a, 0xd5, 0xf3, 0x85, - 0x55, 0xcf, 0x57, 0xb5, 0xad, 0x7c, 0xbe, 0xbd, 0xad, 0x3e, 0xbc, 0x87, - 0xdb, 0x56, 0xc2, 0x75, 0xa7, 0x8e, 0xf7, 0xcf, 0x54, 0xa2, 0xb2, 0xab, - 0x80, 0xf7, 0x4e, 0xe7, 0x66, 0xa3, 0xd7, 0x6a, 0xdf, 0x33, 0xbe, 0xf6, - 0xd7, 0xab, 0xfa, 0xab, 0xb6, 0xdb, 0x5d, 0x6d, 0xe7, 0x57, 0xdb, 0x19, - 0xd9, 0x36, 0x5b, 0xe1, 0x3b, 0x96, 0x87, 0xfd, 0x9a, 0xb6, 0x53, 0xc5, - 0x4e, 0x9d, 0x0b, 0x3b, 0xaa, 0x73, 0x61, 0x93, 0xe0, 0xc3, 0x3b, 0x75, - 0x4c, 0x69, 0x93, 0x42, 0x79, 0xa5, 0x55, 0xc7, 0x95, 0x74, 0x2c, 0xb5, - 0x30, 0x0a, 0xdb, 0x96, 0x39, 0xb0, 0x81, 0xec, 0xf1, 0xcd, 0xdd, 0xe4, - 0xc4, 0x1e, 0x0e, 0x86, 0xdd, 0x20, 0x98, 0xf4, 0x6e, 0xb3, 0xf9, 0x62, - 0xb8, 0x57, 0x4c, 0x1b, 0xea, 0xe0, 0x27, 0xa0, 0x83, 0xab, 0xba, 0xf7, - 0x4e, 0x8c, 0xb5, 0x00, 0x9a, 0x19, 0x90, 0xdf, 0xad, 0xa4, 0xbe, 0x24, - 0xfa, 0xcc, 0x4d, 0x3f, 0x6c, 0xb8, 0xa5, 0x4f, 0xbd, 0xdf, 0xf3, 0x61, - 0xeb, 0x05, 0xf2, 0xb0, 0x3f, 0x08, 0x1a, 0xea, 0x85, 0xbd, 0xe7, 0x69, - 0xbf, 0xf4, 0xb4, 0xa6, 0x2d, 0xd2, 0x58, 0x8b, 0xce, 0xd7, 0x7f, 0xd4, - 0x77, 0x62, 0x99, 0xfe, 0x3f, 0x32, 0x71, 0x1a, 0xbf, 0xdb, 0xfd, 0x1a, - 0xf8, 0x76, 0xa7, 0xb7, 0x05, 0x3e, 0x0a, 0x69, 0x88, 0xf1, 0xaf, 0xcb, - 0x75, 0x1e, 0x21, 0x03, 0x68, 0x33, 0x51, 0xc6, 0x09, 0x53, 0x83, 0x63, - 0xc2, 0x79, 0xa7, 0x12, 0x49, 0xa5, 0xed, 0xaa, 0xe0, 0x46, 0x9f, 0x39, - 0xb6, 0xdc, 0x63, 0x21, 0x3f, 0xef, 0xff, 0xf4, 0x94, 0x97, 0x73, 0x23, - 0x36, 0x2f, 0x37, 0x53, 0x30, 0xb4, 0x39, 0x41, 0xda, 0x84, 0x3f, 0xb5, - 0xd8, 0xff, 0xb7, 0x01, 0xed, 0xfb, 0xa4, 0x22, 0xed, 0xff, 0x4d, 0x30, - 0x17, 0x65, 0x5f, 0x84, 0x7b, 0xff, 0xa7, 0x33, 0x1a, 0x57, 0x77, 0xca, - 0x81, 0x22, 0x6d, 0xe1, 0x98, 0xce, 0xe7, 0x18, 0xf7, 0x69, 0xa7, 0xc5, - 0x80, 0xc7, 0x0f, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x47, 0x50, 0x27, 0x22, - 0x63, 0x60, 0xf1, 0xd9, 0x02, 0xf9, 0x93, 0xf7, 0x28, 0xea, 0xbb, 0x32, - 0x5f, 0xb8, 0x59, 0xe7, 0xdb, 0x9d, 0x46, 0xdb, 0x27, 0x71, 0xcd, 0x16, - 0x26, 0xd0, 0x66, 0xaf, 0xae, 0x3f, 0x5b, 0x62, 0x8e, 0xb2, 0x40, 0x2e, - 0xed, 0x97, 0xfc, 0x5c, 0x97, 0x8c, 0xc5, 0x17, 0x66, 0xa2, 0xcb, 0x71, - 0x99, 0x8f, 0x6f, 0xe0, 0x1e, 0x47, 0xfe, 0x4a, 0xee, 0x07, 0x4b, 0x74, - 0x74, 0xbb, 0xea, 0x6d, 0xd3, 0x3e, 0xd7, 0xa0, 0xec, 0xac, 0x0c, 0xc9, - 0x4d, 0x95, 0xcf, 0x6e, 0x36, 0xb1, 0xa8, 0x15, 0xf1, 0xad, 0xc3, 0xc4, - 0x8a, 0x3a, 0x1a, 0xe5, 0xb9, 0x25, 0x99, 0x3d, 0x25, 0x12, 0x39, 0x1a, - 0xc6, 0x12, 0x59, 0xe6, 0x4a, 0xd7, 0x95, 0x80, 0xeb, 0x14, 0x64, 0x6b, - 0x3c, 0x26, 0x5f, 0xdc, 0x16, 0x8e, 0x95, 0x0b, 0xa6, 0xb7, 0xe5, 0xe4, - 0xd3, 0xb8, 0xb2, 0x57, 0xa6, 0x4a, 0x19, 0xc5, 0x71, 0xbf, 0x13, 0x50, - 0x96, 0xa9, 0x21, 0x4f, 0x72, 0x6d, 0xe1, 0xd8, 0xf0, 0x6f, 0x76, 0x84, - 0xe3, 0xd3, 0xe6, 0x36, 0x67, 0x1e, 0xf2, 0xdc, 0x77, 0x01, 0xfd, 0x45, - 0x86, 0xee, 0xde, 0x40, 0xdf, 0x61, 0x58, 0xd8, 0x0e, 0x32, 0x5d, 0xb1, - 0x6f, 0xc2, 0x49, 0xf8, 0x6b, 0xe1, 0x5c, 0x4c, 0xc6, 0x81, 0xa3, 0xdc, - 0xeb, 0xc2, 0xdb, 0xe7, 0x7a, 0xaa, 0x1e, 0xbc, 0xa3, 0x36, 0x96, 0xc8, - 0xf8, 0xe0, 0x3a, 0xe0, 0xad, 0x05, 0xe5, 0x1f, 0x94, 0xa9, 0x63, 0x6f, - 0xdb, 0xcc, 0xbd, 0xec, 0x06, 0xcf, 0xb1, 0x39, 0xa7, 0x3c, 0xbf, 0x73, - 0x37, 0xea, 0xf0, 0xfd, 0xcd, 0x68, 0x93, 0xca, 0x65, 0x22, 0x9b, 0xe1, - 0x13, 0x71, 0xdc, 0x20, 0xd2, 0xb5, 0xa3, 0x59, 0xe7, 0x90, 0xca, 0x29, - 0xea, 0xf3, 0xb0, 0xed, 0xdd, 0x3a, 0x47, 0x03, 0x7e, 0x7b, 0x6e, 0x24, - 0x42, 0xf9, 0xd5, 0x2b, 0xc3, 0xd4, 0x27, 0xa7, 0x6e, 0xd6, 0xb4, 0xdf, - 0xbd, 0x8d, 0x67, 0x99, 0xfa, 0x8c, 0x8d, 0x1e, 0x27, 0x8c, 0xa3, 0x28, - 0x87, 0xfd, 0xfe, 0x9a, 0x30, 0xdc, 0xf5, 0x26, 0x61, 0xb8, 0xeb, 0x4d, - 0xc2, 0x40, 0x5c, 0x00, 0x8e, 0xca, 0x5f, 0x6c, 0x08, 0x63, 0xd5, 0x97, - 0x62, 0x1e, 0x07, 0x8b, 0x77, 0xc9, 0xa1, 0xa2, 0xa3, 0xe3, 0x8e, 0x0b, - 0x8a, 0x32, 0xc1, 0x05, 0x4f, 0x82, 0xf7, 0x8a, 0xe0, 0xcd, 0x22, 0x78, - 0xb1, 0x08, 0xbe, 0x84, 0xfd, 0x7f, 0x06, 0xf6, 0xff, 0x93, 0x58, 0x9b, - 0xd3, 0x2b, 0x78, 0x39, 0xad, 0x79, 0x39, 0x5f, 0xa4, 0xaf, 0xd6, 0x7f, - 0x11, 0x7e, 0x8d, 0xca, 0x70, 0x21, 0x05, 0x55, 0xe2, 0x44, 0xb3, 0xfd, - 0x9f, 0x24, 0xbf, 0xca, 0x83, 0xfe, 0x0d, 0x68, 0x73, 0x18, 0x34, 0x9e, - 0xa2, 0x1d, 0x48, 0xfb, 0x27, 0x07, 0xde, 0x3c, 0x4c, 0x5f, 0x4d, 0x5d, - 0xb9, 0x49, 0xa8, 0x5f, 0xa2, 0x3b, 0x98, 0x7b, 0xc8, 0xb9, 0x26, 0x57, - 0xe1, 0xc9, 0xf0, 0xef, 0x84, 0x47, 0x3d, 0x43, 0xbe, 0x7d, 0x99, 0x7c, - 0x5b, 0xc3, 0xab, 0x01, 0xe7, 0x17, 0xb8, 0xdb, 0xea, 0xb5, 0xad, 0xd6, - 0xdf, 0xb4, 0x5c, 0x5f, 0x8f, 0x5f, 0x22, 0x3f, 0x42, 0x27, 0x11, 0xf7, - 0xc9, 0x4c, 0x64, 0x8b, 0xc5, 0x3d, 0x6c, 0xb7, 0x1d, 0x97, 0x00, 0xf7, - 0x9d, 0x92, 0x9b, 0x0f, 0xc4, 0xdb, 0x11, 0xf6, 0x59, 0xed, 0xc7, 0xb5, - 0xfd, 0x8c, 0x17, 0x1c, 0x19, 0xd9, 0xc6, 0x7d, 0x08, 0x07, 0x7a, 0x3e, - 0x5c, 0x0f, 0xd8, 0xfb, 0x7a, 0xcd, 0x29, 0x63, 0x29, 0x5b, 0x5b, 0x6c, - 0xfc, 0x89, 0xfd, 0x1d, 0x5e, 0xb5, 0x4e, 0x17, 0x02, 0x9e, 0x11, 0x9b, - 0xf2, 0x6e, 0xa8, 0xa1, 0x95, 0xfb, 0x2c, 0xad, 0xa8, 0x55, 0xf3, 0xb8, - 0xdd, 0xd2, 0x4a, 0x08, 0x6f, 0x3c, 0xa4, 0x95, 0xa6, 0x90, 0x56, 0x72, - 0x33, 0x21, 0xad, 0xb0, 0xed, 0xed, 0x21, 0xad, 0x24, 0x6b, 0x69, 0x25, - 0x37, 0xe3, 0xe0, 0x5a, 0x0d, 0x07, 0xe9, 0x85, 0xfd, 0x90, 0x5e, 0x00, - 0x4b, 0xe5, 0xd6, 0xd6, 0x90, 0x5e, 0xe2, 0xe8, 0xe7, 0x50, 0xd1, 0xe4, - 0x74, 0xc0, 0xef, 0xb2, 0x3a, 0xc4, 0xc5, 0x9a, 0x1b, 0x1f, 0xb1, 0x3e, - 0x8d, 0xf8, 0x96, 0x46, 0xaa, 0x79, 0xee, 0xab, 0x68, 0x03, 0xb8, 0x67, - 0x2e, 0xeb, 0x76, 0x4d, 0x1b, 0xf7, 0xfb, 0x53, 0xa8, 0xbb, 0x07, 0xb4, - 0x11, 0xe2, 0xe0, 0x7a, 0x8b, 0x83, 0xd5, 0x6b, 0x39, 0x66, 0x71, 0xb0, - 0xc7, 0xe2, 0x40, 0xf3, 0x4b, 0x8e, 0x6b, 0xa6, 0x34, 0x0e, 0x9a, 0x34, - 0x0e, 0x44, 0x85, 0x6d, 0xc7, 0xea, 0xe0, 0x80, 0x75, 0xf6, 0xe8, 0xf9, - 0x47, 0x30, 0xff, 0xfd, 0x98, 0xbf, 0xd2, 0xf3, 0xe7, 0x3a, 0x70, 0xfe, - 0x80, 0xa5, 0x72, 0x72, 0x79, 0xfe, 0x6d, 0xe8, 0xe3, 0x60, 0x31, 0xa2, - 0xe7, 0x0f, 0xdb, 0x7e, 0x30, 0x9c, 0xff, 0xe9, 0x8a, 0xc9, 0x7f, 0x3e, - 0xbd, 0x46, 0xcf, 0x4d, 0x59, 0xde, 0xf0, 0xb4, 0x5f, 0xcc, 0x98, 0xf6, - 0x19, 0xe8, 0xb6, 0x69, 0x3f, 0x69, 0xcf, 0x43, 0x19, 0x7b, 0xe9, 0x1b, - 0x3e, 0x79, 0xe7, 0xe3, 0x3a, 0x0f, 0xe5, 0x71, 0xda, 0x4d, 0xc5, 0x36, - 0x19, 0x99, 0xae, 0x85, 0x9b, 0xf0, 0xe6, 0xb4, 0x1c, 0xcd, 0x62, 0x7e, - 0xe3, 0x7e, 0x2f, 0xe4, 0x9b, 0xa6, 0x25, 0x94, 0xa7, 0x72, 0xc3, 0x91, - 0x26, 0x51, 0x0f, 0x7c, 0x08, 0x73, 0x8e, 0xca, 0x66, 0xaf, 0xdb, 0xdd, - 0xa1, 0xa8, 0x0b, 0x2f, 0xab, 0xd1, 0x85, 0xed, 0x56, 0x17, 0x6e, 0xa2, - 0x2e, 0x04, 0xdc, 0x77, 0xca, 0xe1, 0x22, 0xd7, 0x2f, 0x97, 0x6c, 0x82, - 0xfe, 0xff, 0x81, 0xc7, 0xb3, 0x27, 0x3a, 0x6e, 0x96, 0x38, 0xac, 0x69, - 0x99, 0x3a, 0x2d, 0xa5, 0xcf, 0x6a, 0x2c, 0xd2, 0xc6, 0x8e, 0x33, 0x16, - 0x4a, 0xbd, 0xf7, 0xe3, 0xe0, 0x73, 0x75, 0xf4, 0xde, 0x64, 0xd1, 0xd8, - 0x6f, 0x0d, 0xb0, 0x09, 0xe5, 0x44, 0x3b, 0xae, 0x8d, 0x3c, 0xab, 0xd0, - 0xdb, 0xa3, 0x9a, 0xa5, 0xe1, 0x44, 0xab, 0x4c, 0x4c, 0x1b, 0x1b, 0x57, - 0x9d, 0x00, 0xfe, 0x4f, 0x30, 0xdf, 0x55, 0x74, 0x7e, 0x7e, 0xb6, 0x04, - 0x3b, 0x77, 0xf6, 0x4e, 0x93, 0xb7, 0x32, 0xdd, 0xa0, 0x7f, 0xd3, 0x06, - 0xc9, 0xfb, 0x69, 0xe8, 0xbb, 0x98, 0x4c, 0xa0, 0xcf, 0xee, 0x6d, 0x8d, - 0x98, 0x73, 0x1c, 0x6d, 0xe9, 0xf3, 0x31, 0x8e, 0xd6, 0x28, 0xd1, 0xd9, - 0xb8, 0xce, 0xad, 0xe7, 0xd9, 0xd1, 0xcc, 0x60, 0x1b, 0xde, 0x31, 0x9f, - 0xc1, 0xc5, 0x58, 0xa1, 0xec, 0x47, 0xbf, 0x47, 0xc5, 0xee, 0xf7, 0x0c, - 0x69, 0xfd, 0x17, 0x39, 0xea, 0xda, 0x33, 0x74, 0x83, 0x58, 0xf7, 0x7a, - 0x7a, 0xd1, 0x18, 0xb9, 0x19, 0xac, 0x9f, 0x3a, 0x15, 0xc5, 0xbd, 0x13, - 0xf7, 0xb0, 0xbf, 0x50, 0x8f, 0x40, 0x37, 0xbe, 0xb3, 0x6f, 0xa3, 0x34, - 0x03, 0xdf, 0xb3, 0x0a, 0xb8, 0x36, 0x39, 0x59, 0x39, 0xcd, 0x0b, 0x55, - 0x7a, 0x78, 0xf2, 0x75, 0xf9, 0x81, 0x34, 0x41, 0x5a, 0xa0, 0x5c, 0x24, - 0x6d, 0x50, 0x26, 0x3a, 0xfa, 0x6c, 0x03, 0xe9, 0xe1, 0x09, 0xdf, 0x8b, - 0x70, 0xdf, 0xde, 0xc4, 0xe5, 0x49, 0x1b, 0xa4, 0xf9, 0xa4, 0x8e, 0xd7, - 0xa7, 0xe5, 0x7b, 0x92, 0x6e, 0xeb, 0x86, 0x5d, 0xf6, 0x2f, 0xbb, 0xc6, - 0xe6, 0xdc, 0xad, 0xa6, 0x39, 0xe8, 0x26, 0xe6, 0xd0, 0xf5, 0xca, 0xfb, - 0x2a, 0x39, 0xe0, 0xe1, 0x5e, 0x28, 0xe5, 0x3b, 0x75, 0x5e, 0xe2, 0xee, - 0xc2, 0x46, 0xb9, 0xc5, 0x8f, 0xd9, 0xb8, 0xfb, 0x41, 0xd0, 0xc1, 0xa2, - 0x23, 0x27, 0xce, 0xe2, 0x3a, 0xe7, 0x70, 0xfd, 0xce, 0xfb, 0xe9, 0x94, - 0x22, 0xb3, 0x7b, 0xd1, 0xc4, 0xa2, 0xf4, 0xb9, 0x13, 0xfa, 0x0c, 0xc8, - 0x82, 0xd3, 0x74, 0xe2, 0xd0, 0x46, 0xe3, 0x4b, 0x03, 0x16, 0xaf, 0xd1, - 0x1d, 0xa1, 0x2d, 0xe7, 0x07, 0x41, 0x96, 0x76, 0x83, 0x28, 0xed, 0x23, - 0xc1, 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x5b, 0x9d, 0xc6, 0x53, 0x2f, 0x5a, - 0x5a, 0x91, 0x88, 0x1a, 0x7a, 0xc6, 0x69, 0x38, 0x71, 0x9c, 0x6b, 0xa6, - 0xf3, 0xa4, 0x0d, 0x5d, 0x3d, 0xe7, 0x54, 0xe9, 0xea, 0x1b, 0xf6, 0xb7, - 0x1a, 0x6a, 0x92, 0x74, 0xaa, 0x09, 0xf3, 0x1d, 0x2e, 0x84, 0x30, 0x7e, - 0x1f, 0x70, 0x11, 0x1e, 0xd0, 0xed, 0xec, 0x9f, 0xe1, 0x5a, 0x02, 0x2c, - 0xf7, 0x01, 0xee, 0xf3, 0x80, 0xf9, 0x02, 0x2e, 0xd5, 0x11, 0x91, 0x3f, - 0x76, 0x22, 0xb3, 0xb5, 0xf0, 0x12, 0xc6, 0xd3, 0x16, 0xde, 0xd7, 0x82, - 0xd5, 0x95, 0xc5, 0x81, 0x2e, 0xc0, 0x43, 0x38, 0x5f, 0x02, 0x8c, 0xb4, - 0x5b, 0x9f, 0xc7, 0xb3, 0x0b, 0xf8, 0x5e, 0xb0, 0x30, 0x81, 0x1e, 0xa7, - 0xff, 0x47, 0xf5, 0x77, 0x81, 0x76, 0xf4, 0x9f, 0xdb, 0xe7, 0xce, 0x55, - 0x32, 0xa0, 0xc7, 0x21, 0x9e, 0xa7, 0x8a, 0x4b, 0xb4, 0x03, 0xc0, 0xf7, - 0x3f, 0x94, 0xc8, 0xa9, 0x84, 0x1c, 0x2a, 0x70, 0x0f, 0xe8, 0x24, 0xf0, - 0xa1, 0xcf, 0xa4, 0xa0, 0xce, 0x15, 0xb8, 0xa0, 0xec, 0x67, 0xb7, 0xe3, - 0xea, 0xc5, 0xf5, 0x56, 0x5c, 0x20, 0x87, 0xd9, 0x13, 0xb8, 0xfa, 0xd0, - 0xb7, 0x8a, 0x37, 0x09, 0x73, 0xa9, 0xbe, 0x8d, 0x36, 0xda, 0xb6, 0xcc, - 0xa9, 0xa1, 0x01, 0xe0, 0x6f, 0x00, 0xb0, 0x25, 0x70, 0x31, 0xff, 0xf8, - 0x87, 0x8e, 0x9c, 0x7a, 0x19, 0x17, 0x18, 0xec, 0x14, 0x08, 0xf3, 0xd4, - 0x20, 0x2e, 0x28, 0xb1, 0x53, 0x69, 0x5c, 0x23, 0xb8, 0xfe, 0xd2, 0x31, - 0x3c, 0xd7, 0x09, 0x7c, 0x85, 0x3c, 0x02, 0x9c, 0xaf, 0xe0, 0xb9, 0xaf, - 0x3b, 0x6f, 0x9c, 0xe7, 0x7e, 0xe2, 0x18, 0x9e, 0x7b, 0xc5, 0xa9, 0xf2, - 0xdc, 0x59, 0x47, 0x3d, 0xfc, 0x8c, 0x13, 0x79, 0x98, 0xbe, 0xc4, 0x59, - 0xc7, 0xf0, 0x7f, 0x44, 0x86, 0xf7, 0x82, 0x96, 0x1e, 0x5e, 0xc0, 0x45, - 0xba, 0x7a, 0x16, 0xe5, 0x2f, 0xac, 0x1a, 0xf7, 0xf9, 0x37, 0x31, 0xee, - 0xab, 0x76, 0x5c, 0x51, 0xd5, 0x71, 0x2f, 0xa0, 0xef, 0x97, 0xec, 0xb8, - 0x17, 0x6a, 0xc6, 0x05, 0xad, 0x3c, 0xbc, 0x84, 0x8b, 0x74, 0xf1, 0x22, - 0xca, 0x43, 0x99, 0x80, 0x85, 0x6e, 0x6e, 0xd0, 0x67, 0x9d, 0xe2, 0x5e, - 0xc3, 0xb2, 0x6e, 0x4c, 0xd7, 0xe8, 0x87, 0x37, 0xa2, 0x1f, 0x27, 0x8b, - 0xb4, 0x11, 0x17, 0x6a, 0xe4, 0x02, 0x7d, 0xa3, 0x40, 0x8e, 0x69, 0x3f, - 0x88, 0x3e, 0x11, 0xfd, 0xa3, 0xd5, 0xb6, 0xd5, 0x27, 0x75, 0xee, 0xd8, - 0xaf, 0x15, 0x3a, 0xe5, 0xd3, 0x05, 0xda, 0x84, 0xa4, 0x97, 0x20, 0x98, - 0xd8, 0x41, 0xfb, 0x34, 0x17, 0x5c, 0xe2, 0x91, 0x4e, 0x3c, 0xf7, 0x33, - 0x6b, 0x75, 0x46, 0x69, 0x18, 0xbe, 0x7b, 0xe6, 0xe8, 0xaf, 0x40, 0x67, - 0x34, 0x00, 0x6e, 0xd2, 0x5b, 0x87, 0xdc, 0x58, 0x52, 0x53, 0x9b, 0x25, - 0x21, 0x37, 0x15, 0x1a, 0x61, 0xf7, 0x30, 0xaf, 0xaa, 0x59, 0xba, 0x77, - 0xc4, 0x4c, 0xde, 0xb7, 0x1b, 0xc7, 0x6f, 0xd7, 0xe4, 0xa1, 0xc7, 0x13, - 0x78, 0xff, 0x7b, 0x2e, 0xe5, 0x60, 0xdc, 0xbb, 0x56, 0xe7, 0xf4, 0x74, - 0xed, 0xa0, 0xdd, 0x72, 0xbd, 0xd6, 0xe1, 0xd1, 0x35, 0x76, 0x92, 0xea, - 0x70, 0xa5, 0x6a, 0xa3, 0x8d, 0x17, 0x52, 0x49, 0xc2, 0xf5, 0x90, 0x70, - 0xff, 0xeb, 0x1e, 0xc9, 0xfb, 0xad, 0xf0, 0x0b, 0x18, 0x3b, 0x4f, 0xf5, - 0xd2, 0x36, 0x9a, 0x9d, 0x76, 0x6d, 0x5e, 0xf4, 0x46, 0x79, 0x4e, 0x8f, - 0xd3, 0xa8, 0x61, 0x34, 0x67, 0x25, 0xb8, 0x8f, 0x10, 0xd3, 0xe7, 0x73, - 0x66, 0xcb, 0x2d, 0x5a, 0xef, 0xcc, 0x96, 0x99, 0x87, 0x0f, 0x7f, 0xaa, - 0xcc, 0xbc, 0x7b, 0x5f, 0xdc, 0x77, 0xc2, 0xcf, 0x2d, 0x6f, 0x91, 0xf1, - 0xe9, 0x75, 0xd2, 0xe8, 0xa9, 0xf8, 0x66, 0xc8, 0x47, 0xb6, 0xe9, 0xda, - 0x01, 0xff, 0x70, 0x66, 0xab, 0x3c, 0x39, 0xc3, 0xbe, 0x3b, 0x64, 0x6e, - 0x5e, 0x1c, 0xf7, 0x9d, 0xeb, 0x51, 0x07, 0x72, 0x7d, 0x07, 0xcb, 0x92, - 0xb8, 0x8b, 0x72, 0xdf, 0x19, 0x95, 0x73, 0x03, 0x7c, 0x66, 0xee, 0xbf, - 0x44, 0xd9, 0xdf, 0xb9, 0x81, 0x4e, 0x79, 0x7c, 0x1e, 0x34, 0x01, 0xb9, - 0x3f, 0x72, 0x82, 0x30, 0x89, 0xec, 0x9a, 0x65, 0x2c, 0xbd, 0xdb, 0x65, - 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0x0c, 0x70, 0x2c, 0xe8, 0x25, 0xe8, 0xb8, - 0xae, 0x1d, 0x46, 0x16, 0xa4, 0x67, 0x1b, 0x50, 0xce, 0x7e, 0xe1, 0x3f, - 0xee, 0x65, 0x3f, 0x61, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59, 0x5a, - 0xa5, 0x3f, 0xce, 0xfc, 0x4c, 0xf6, 0x37, 0xfb, 0xe8, 0xd5, 0x7b, 0x21, - 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae, 0xba, - 0x42, 0xdb, 0x17, 0x73, 0x15, 0xae, 0x20, 0x63, 0x51, 0xe1, 0x1a, 0x25, - 0xe4, 0xd1, 0xe2, 0xf2, 0x3a, 0x6d, 0x69, 0x58, 0xb9, 0x4e, 0xa4, 0x15, - 0x7f, 0xcc, 0xda, 0x1e, 0x8b, 0x92, 0x83, 0x5d, 0xd6, 0xab, 0xd7, 0x6c, - 0x11, 0xb6, 0xac, 0x5d, 0x33, 0x6d, 0xcf, 0xe6, 0xc3, 0x35, 0x1b, 0x85, - 0xc6, 0x29, 0xab, 0x4d, 0x5c, 0x33, 0x97, 0xf1, 0x6e, 0xe0, 0x3d, 0x87, - 0x75, 0xca, 0x61, 0x8d, 0x72, 0xe5, 0x0e, 0x99, 0x3d, 0xa6, 0x3a, 0x1b, - 0x44, 0x92, 0xe3, 0x5e, 0x87, 0x4c, 0xce, 0x33, 0x96, 0xb0, 0x05, 0x36, - 0xd8, 0x56, 0x5c, 0x9d, 0x78, 0x66, 0x3b, 0xf0, 0x54, 0x59, 0xa1, 0x6d, - 0xd3, 0x1a, 0x3b, 0xeb, 0x71, 0x8c, 0xcd, 0x1c, 0xe1, 0x27, 0x80, 0x87, - 0x2a, 0xef, 0x4c, 0xd5, 0xc4, 0x9f, 0x38, 0x57, 0xad, 0x43, 0x31, 0xdf, - 0xb8, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x36, 0xbe, 0x19, 0x7b, 0x2a, 0x41, - 0x7b, 0x2a, 0x5b, 0x72, 0xcd, 0xf9, 0x80, 0x51, 0xf8, 0x4e, 0x5e, 0xef, - 0x26, 0xd2, 0xfa, 0xd8, 0x0c, 0xe1, 0x8a, 0x85, 0x70, 0xad, 0x58, 0x33, - 0x9e, 0xe7, 0x5a, 0x1b, 0xe7, 0x98, 0x5a, 0xce, 0x5f, 0x34, 0xb1, 0x7d, - 0xc6, 0x51, 0x3a, 0xeb, 0xc0, 0x74, 0xa7, 0xb6, 0x61, 0x45, 0x8d, 0xc9, - 0x81, 0x22, 0xcf, 0x82, 0x31, 0x9e, 0x78, 0x23, 0xe3, 0x49, 0xbd, 0xb3, - 0xf2, 0x5e, 0x8c, 0xcd, 0x5c, 0x1d, 0x65, 0xe3, 0x37, 0x1b, 0x6c, 0x8e, - 0x48, 0x6d, 0x0c, 0xc7, 0xe4, 0xf2, 0xac, 0xcc, 0x8b, 0x4e, 0x8d, 0x2e, - 0x61, 0x9d, 0x7f, 0x5d, 0xef, 0x0d, 0x4a, 0x29, 0x02, 0xed, 0x37, 0x3e, - 0x90, 0x1a, 0x34, 0xe7, 0x60, 0x92, 0xb2, 0xb3, 0x68, 0xe6, 0x7f, 0x5e, - 0xe7, 0xf4, 0x98, 0xdc, 0x45, 0x93, 0xef, 0x73, 0x8f, 0x9c, 0x87, 0x0e, - 0xaf, 0xae, 0x6d, 0x93, 0x4c, 0x02, 0x17, 0x59, 0xbd, 0x2f, 0x91, 0x94, - 0xec, 0xc0, 0xc7, 0x37, 0xf1, 0x9c, 0x44, 0x0c, 0xeb, 0x93, 0x9f, 0xe1, - 0xd9, 0x49, 0xf6, 0x7b, 0xb1, 0xbe, 0x28, 0x66, 0x99, 0x87, 0x0f, 0x59, - 0xf9, 0xb6, 0xbe, 0x44, 0xb3, 0x7e, 0xbf, 0xce, 0xe6, 0x5b, 0x3b, 0x22, - 0x37, 0x06, 0xf2, 0x87, 0x10, 0x9f, 0x8f, 0xd9, 0x39, 0x25, 0x75, 0xcc, - 0x4a, 0x82, 0x73, 0x7e, 0xc2, 0xc6, 0x2c, 0x39, 0x97, 0x1b, 0x2c, 0x7d, - 0x1b, 0xfb, 0xa7, 0x6a, 0x43, 0x9b, 0x7d, 0xbf, 0x27, 0xb5, 0x2c, 0xec, - 0xb7, 0xb6, 0xb3, 0x8e, 0xf3, 0x1c, 0x17, 0x9d, 0x13, 0x10, 0xfa, 0x46, - 0x3d, 0x35, 0x7e, 0x81, 0xf1, 0xe5, 0xf2, 0xd3, 0xf5, 0x64, 0x54, 0xd5, - 0x27, 0xa4, 0x2f, 0x37, 0xb1, 0x8d, 0xdf, 0x2d, 0x08, 0x7d, 0xb9, 0x7e, - 0xeb, 0xcb, 0xb5, 0x6a, 0x5f, 0xce, 0xc4, 0x1e, 0x5a, 0x97, 0x7d, 0xb9, - 0xfc, 0x74, 0x0e, 0xb4, 0x12, 0x7e, 0x67, 0xc1, 0xd8, 0x42, 0x93, 0x05, - 0x9e, 0x79, 0x69, 0x94, 0xec, 0xa8, 0x82, 0xdf, 0x60, 0x7c, 0x2c, 0xc6, - 0x2a, 0x94, 0xfa, 0x96, 0xf5, 0x2f, 0x3a, 0x25, 0xdd, 0xbe, 0x0e, 0xf3, - 0xbe, 0x53, 0xaf, 0xf9, 0x5c, 0xc1, 0xec, 0x7d, 0x66, 0xf7, 0x32, 0x26, - 0xc4, 0x73, 0x4d, 0x9a, 0xbf, 0x92, 0xc3, 0x91, 0x5e, 0x63, 0xcf, 0x7a, - 0xdf, 0x04, 0xde, 0x4f, 0x02, 0xe7, 0x31, 0x3b, 0x6e, 0x12, 0x30, 0x1d, - 0xc0, 0xda, 0x5c, 0x6b, 0x65, 0x32, 0xc7, 0xde, 0xd3, 0xc4, 0xd8, 0xc0, - 0x7c, 0x21, 0x8c, 0x11, 0x46, 0xec, 0x99, 0x4a, 0x2f, 0xd2, 0xe8, 0xad, - 0xab, 0x6b, 0xab, 0x9e, 0x7e, 0x5d, 0xdd, 0x44, 0x5a, 0xba, 0x53, 0xe7, - 0xb9, 0xac, 0x1f, 0x48, 0xed, 0xd1, 0x39, 0xf2, 0x3a, 0xc6, 0x98, 0x13, - 0xe6, 0x94, 0x7d, 0x57, 0xde, 0xa1, 0x65, 0xfe, 0x01, 0x9f, 0xfa, 0x6b, - 0x87, 0xfe, 0xdd, 0x38, 0x14, 0x04, 0xe7, 0x06, 0xee, 0x86, 0xad, 0xe2, - 0xb9, 0xdf, 0x97, 0xee, 0xc4, 0xb0, 0xb6, 0x9d, 0xb0, 0x46, 0x7b, 0x9b, - 0x65, 0x9d, 0x77, 0xb3, 0xcd, 0x99, 0xc9, 0x41, 0x6e, 0xa6, 0x60, 0x33, - 0xf1, 0x4c, 0x70, 0x8f, 0x7d, 0x97, 0x0b, 0x9a, 0x41, 0x47, 0x1f, 0x13, - 0x23, 0x63, 0xb2, 0x55, 0x19, 0xc3, 0x5c, 0x83, 0x34, 0x09, 0x39, 0x7a, - 0x44, 0x52, 0xfc, 0xee, 0x07, 0xc7, 0xce, 0xcb, 0xa5, 0xd0, 0xcb, 0x6c, - 0xa7, 0xbf, 0xd9, 0x83, 0x67, 0xee, 0xe1, 0x78, 0xee, 0x41, 0xe8, 0x96, - 0xeb, 0xd7, 0xea, 0x96, 0x04, 0xfd, 0xfa, 0x6c, 0x89, 0xbe, 0xe1, 0x7a, - 0xb4, 0xe9, 0x90, 0x8f, 0x4f, 0x77, 0xb7, 0x91, 0xb7, 0xc6, 0x20, 0xd7, - 0xd5, 0xfd, 0xe1, 0x59, 0x20, 0x96, 0xf1, 0x3d, 0xfb, 0x6d, 0x92, 0xe4, - 0xfb, 0x5d, 0xf9, 0x7c, 0x25, 0x95, 0x5c, 0x82, 0x6e, 0x1a, 0x73, 0x7e, - 0xf1, 0x72, 0x13, 0x53, 0x7d, 0x7b, 0x9b, 0x39, 0x3b, 0xd0, 0x4c, 0x9b, - 0xdd, 0xc6, 0x59, 0x6b, 0x69, 0x76, 0xc9, 0xca, 0xe3, 0x20, 0x68, 0x1e, - 0xd0, 0x32, 0x78, 0x0f, 0x65, 0xf0, 0x01, 0xbf, 0xc7, 0xd0, 0xbe, 0xf6, - 0x99, 0x02, 0xac, 0x23, 0xf0, 0x30, 0x10, 0x65, 0x7e, 0x9e, 0xe5, 0x4f, - 0x2f, 0xbd, 0x68, 0xe5, 0x92, 0x72, 0xd6, 0xf2, 0xa5, 0xba, 0x2a, 0xb6, - 0x42, 0xe6, 0x1e, 0x9a, 0xa6, 0x3e, 0xf6, 0x17, 0xbe, 0x0b, 0x39, 0x95, - 0xd5, 0x78, 0xe8, 0x90, 0xfb, 0xa6, 0x25, 0x7d, 0x1e, 0xba, 0x2a, 0x3f, - 0xbf, 0x92, 0x37, 0xd7, 0xf6, 0xc7, 0xb9, 0x7e, 0xb8, 0xcd, 0xf8, 0xb6, - 0x2b, 0xe7, 0xba, 0x80, 0xb9, 0xa6, 0xf5, 0x5c, 0xb9, 0x6f, 0xf3, 0x31, - 0x3b, 0xd7, 0xf5, 0xe1, 0x5c, 0x07, 0x57, 0xce, 0x35, 0xf4, 0xed, 0x43, - 0xb9, 0x9b, 0xd4, 0xf9, 0xf2, 0x3a, 0x4f, 0x7b, 0x7a, 0xbd, 0x0c, 0x97, - 0x5a, 0xad, 0xbc, 0x74, 0xa1, 0x7b, 0x98, 0xc3, 0xbe, 0x70, 0xaf, 0x2b, - 0x16, 0x67, 0x8a, 0x78, 0xa0, 0xac, 0x6d, 0xd3, 0x67, 0x6c, 0x66, 0xe1, - 0x5f, 0xdd, 0x5a, 0x60, 0xdd, 0xf0, 0xfd, 0xc5, 0x62, 0xc7, 0xa1, 0x4f, - 0x4d, 0xbf, 0xa9, 0x77, 0x4d, 0x4c, 0xc1, 0xc4, 0x87, 0x19, 0x17, 0x36, - 0x67, 0x7f, 0x99, 0x8b, 0x78, 0x07, 0x78, 0xea, 0x53, 0x85, 0xd4, 0x60, - 0x26, 0x42, 0x39, 0x7a, 0x5c, 0x0e, 0x55, 0x46, 0xa4, 0x4b, 0x9f, 0xff, - 0x7c, 0xdd, 0xd8, 0x71, 0xba, 0x36, 0x76, 0xcc, 0x74, 0x02, 0xc6, 0x8e, - 0xf7, 0xfc, 0x0c, 0xb1, 0x63, 0x71, 0x4c, 0xec, 0xb8, 0x9e, 0x7f, 0x35, - 0x55, 0x3c, 0x8e, 0x79, 0x35, 0x43, 0x96, 0x2c, 0x3a, 0xd9, 0xf9, 0x16, - 0xdc, 0xcf, 0xe2, 0x1e, 0xc3, 0xfd, 0x3c, 0xee, 0x2e, 0xee, 0x17, 0x70, - 0x8f, 0xcb, 0xd4, 0xb2, 0xce, 0x38, 0x0e, 0xb9, 0x41, 0x5d, 0xc6, 0xb6, - 0xc6, 0x1f, 0x98, 0x2b, 0xb7, 0xf3, 0x7b, 0x2d, 0xce, 0xec, 0x3c, 0xe7, - 0xd0, 0x2a, 0x93, 0xd3, 0x94, 0xd9, 0x6d, 0x52, 0x9a, 0x0e, 0x6d, 0xdb, - 0x9f, 0xef, 0xe0, 0x9e, 0xc1, 0x98, 0x84, 0xb6, 0xeb, 0x3d, 0x1d, 0x66, - 0xaf, 0xf1, 0x3b, 0x58, 0xe3, 0x8d, 0x58, 0x83, 0x93, 0x72, 0x7e, 0x66, - 0xe3, 0x0a, 0x1b, 0x36, 0x69, 0x63, 0x82, 0x33, 0x56, 0xf7, 0xd6, 0x97, - 0x11, 0xb5, 0xeb, 0x9f, 0xb0, 0x67, 0xcb, 0xc2, 0x1c, 0xa1, 0xa4, 0x5e, - 0x9f, 0xd1, 0xca, 0x71, 0x8c, 0x37, 0x28, 0xe9, 0x19, 0xce, 0x73, 0xf9, - 0x9b, 0x11, 0x90, 0x87, 0x27, 0xa0, 0x57, 0x57, 0xd0, 0x25, 0xe8, 0x96, - 0x73, 0x73, 0x40, 0xbb, 0x8f, 0xca, 0x6c, 0x89, 0xf0, 0xf5, 0x24, 0x22, - 0xfa, 0xac, 0x19, 0x9e, 0x67, 0x4c, 0x8e, 0xfb, 0x70, 0x25, 0x3c, 0x67, - 0xb6, 0x89, 0x67, 0x07, 0x57, 0x9d, 0x35, 0xb3, 0xfa, 0x59, 0xdb, 0x0e, - 0x3c, 0x73, 0x16, 0xce, 0xa1, 0x1e, 0x3d, 0x05, 0x32, 0xa9, 0xf3, 0xce, - 0x36, 0xcb, 0x63, 0x0f, 0x2e, 0xe7, 0xbc, 0xb6, 0xc1, 0x46, 0xe9, 0x84, - 0x89, 0x3c, 0x1a, 0x1d, 0xea, 0x81, 0x8f, 0xc7, 0x3c, 0x99, 0x9e, 0xc4, - 0x6d, 0x3a, 0x17, 0xb9, 0x7a, 0xee, 0xaf, 0x9a, 0x8f, 0x1c, 0x9e, 0xb3, - 0x4a, 0xe8, 0xef, 0x5a, 0xec, 0xd4, 0xe5, 0x71, 0xcc, 0x87, 0xfb, 0x7e, - 0x1a, 0x0f, 0x09, 0x7e, 0xa7, 0xeb, 0x29, 0xe0, 0x60, 0xb2, 0xf2, 0x6d, - 0xd0, 0xbb, 0x63, 0xcf, 0x9c, 0x91, 0xc6, 0x06, 0x64, 0xa2, 0x9c, 0x70, - 0x26, 0xca, 0x03, 0xce, 0xbe, 0xb2, 0x7d, 0x37, 0xb0, 0x67, 0xb3, 0x34, - 0xe3, 0xf7, 0x4c, 0x97, 0x33, 0x06, 0x7c, 0xe5, 0x8b, 0xdd, 0x4e, 0x5a, - 0xdf, 0x3d, 0x7b, 0x87, 0x1c, 0xc0, 0x5a, 0x0d, 0xcf, 0xc4, 0xb5, 0x9c, - 0xaf, 0x7e, 0x5b, 0x2a, 0x5c, 0x57, 0x7e, 0x13, 0x89, 0x7c, 0x7c, 0x5c, - 0x7f, 0xe7, 0xc8, 0xd8, 0x0e, 0x27, 0xd1, 0xdf, 0x71, 0x1b, 0x13, 0xef, - 0x73, 0xb2, 0xba, 0x1f, 0xb3, 0x1e, 0xf9, 0xe2, 0x09, 0xdc, 0x57, 0x9f, - 0x79, 0x0e, 0xf5, 0x8c, 0x85, 0xbb, 0x10, 0xdc, 0x63, 0xe4, 0xd5, 0x71, - 0x99, 0xaa, 0x30, 0x7f, 0xc4, 0xd1, 0x7c, 0x34, 0x59, 0x3e, 0x00, 0x9d, - 0xb4, 0xf2, 0xcc, 0xdf, 0xce, 0xea, 0x3a, 0x24, 0x67, 0x84, 0xb0, 0x70, - 0x0d, 0x56, 0x9e, 0x87, 0xbf, 0xf8, 0xbf, 0x70, 0x5f, 0xd1, 0xc8, 0x50, - 0x0b, 0x47, 0x9a, 0xf2, 0xce, 0xc8, 0x95, 0x69, 0x39, 0x08, 0x78, 0x0e, - 0xe3, 0x52, 0xf7, 0xf3, 0x3b, 0x2c, 0xf3, 0x92, 0x9f, 0xbb, 0x4f, 0xd4, - 0x43, 0xe7, 0x9d, 0xe8, 0x43, 0x07, 0x25, 0xf2, 0xd0, 0xa2, 0xd3, 0xf0, - 0x50, 0xb7, 0xf6, 0xcb, 0x77, 0xfb, 0xdd, 0x89, 0x7d, 0x72, 0x52, 0xa2, - 0xf7, 0x2b, 0x7d, 0xfe, 0x2b, 0xef, 0x32, 0xc6, 0x77, 0x52, 0x22, 0xf7, - 0xc7, 0xec, 0xd9, 0x51, 0x13, 0xd7, 0x5b, 0xd2, 0x7c, 0xff, 0x9b, 0x71, - 0xe2, 0x6c, 0x49, 0x8e, 0x6b, 0xde, 0x19, 0x86, 0x9e, 0xc8, 0x94, 0x92, - 0xcb, 0x75, 0x4c, 0xbe, 0xe7, 0xf3, 0x9b, 0x0d, 0xbf, 0xb0, 0x4e, 0x8f, - 0xc3, 0xef, 0x38, 0x18, 0x9d, 0x91, 0xb9, 0x2c, 0xcc, 0xfd, 0x34, 0x6b, - 0xca, 0xf7, 0x67, 0xb1, 0x86, 0x3d, 0x58, 0x2f, 0x8e, 0xe7, 0xe8, 0xfd, - 0x5c, 0x9e, 0x9d, 0x75, 0xa5, 0x2f, 0xd1, 0xb4, 0x6c, 0x07, 0xb1, 0xee, - 0x7d, 0xd2, 0x04, 0xb8, 0xd5, 0x43, 0x79, 0x63, 0xd7, 0x09, 0xe9, 0x54, - 0x20, 0xb9, 0x49, 0xb3, 0x3d, 0x83, 0xbb, 0xf5, 0x1a, 0xde, 0x6b, 0x69, - 0x66, 0x9d, 0xb1, 0x1f, 0xf1, 0x6c, 0xe8, 0x22, 0x2f, 0xbb, 0xa6, 0x7f, - 0x08, 0x3d, 0xcf, 0x7d, 0x17, 0x6d, 0x2f, 0xd6, 0xb1, 0x05, 0xc9, 0x4b, - 0xcf, 0x58, 0xbf, 0x32, 0x08, 0xa6, 0x7d, 0x1f, 0x78, 0xac, 0xe7, 0x4b, - 0x6e, 0x71, 0xe6, 0x4a, 0x5b, 0x9d, 0xd9, 0x52, 0x20, 0x13, 0x3e, 0xbf, - 0xe3, 0xc1, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x86, 0x6e, 0xfd, 0xeb, - 0xcd, 0x3c, 0x8f, 0x74, 0x93, 0xf7, 0xa2, 0x98, 0x7a, 0xc4, 0x31, 0x7d, - 0xe4, 0xee, 0xe3, 0x59, 0xe1, 0xf7, 0x34, 0xfa, 0x12, 0x71, 0xfd, 0x5d, - 0x8f, 0xcf, 0xa1, 0x1d, 0xc6, 0x28, 0x72, 0xdc, 0x67, 0x9d, 0x59, 0xc8, - 0xb3, 0xb9, 0x69, 0x9e, 0xe1, 0x67, 0x3e, 0x6d, 0xa4, 0x53, 0xc9, 0x15, - 0xee, 0xa4, 0xfd, 0x06, 0x5c, 0x0e, 0x2e, 0x50, 0x44, 0x97, 0xf5, 0xb9, - 0xe3, 0xcb, 0xdf, 0x85, 0x0b, 0xcb, 0xc2, 0xef, 0xc3, 0x29, 0x9d, 0x3b, - 0x0d, 0x5f, 0xf6, 0xb1, 0x31, 0xf9, 0x89, 0x33, 0x5f, 0x78, 0xc5, 0x79, - 0xb4, 0x90, 0xbe, 0xea, 0x12, 0xd0, 0xc7, 0x39, 0xbf, 0x97, 0xf2, 0x0b, - 0x36, 0x5f, 0x41, 0x72, 0x95, 0x09, 0x99, 0xe9, 0xe8, 0x76, 0xef, 0xd7, - 0x6b, 0x33, 0x03, 0x9c, 0x7d, 0x1b, 0xeb, 0xf7, 0xc9, 0x38, 0xf5, 0xdb, - 0x78, 0x41, 0x81, 0x97, 0xd5, 0xcf, 0xe3, 0x82, 0x6d, 0xdb, 0xa8, 0x6d, - 0x94, 0x7d, 0x3e, 0xeb, 0x6d, 0x75, 0x86, 0x4b, 0x5b, 0xb0, 0x8e, 0x7b, - 0xa1, 0x3f, 0x1d, 0xd8, 0x69, 0xa0, 0x6d, 0x94, 0x4d, 0x02, 0x07, 0xe3, - 0xbe, 0x91, 0xe7, 0xc3, 0x92, 0xd3, 0x3e, 0x9e, 0xb9, 0xa7, 0x95, 0x89, - 0x99, 0x05, 0xc1, 0x1c, 0xec, 0x83, 0x6c, 0x7f, 0x09, 0xbc, 0xf0, 0x08, - 0xae, 0xb7, 0xdb, 0x3d, 0xed, 0x17, 0x2e, 0xb2, 0xa7, 0xed, 0xca, 0xc9, - 0x8a, 0x3e, 0xd7, 0xae, 0xf3, 0xab, 0x92, 0xea, 0xbf, 0x5f, 0xa2, 0xd7, - 0x4a, 0xf5, 0xe8, 0x9c, 0xb4, 0xb4, 0x7c, 0x38, 0x6e, 0xf4, 0x30, 0x61, - 0x4a, 0x02, 0x9e, 0xad, 0xc0, 0x05, 0xe1, 0x31, 0x6d, 0x44, 0x6d, 0xba, - 0x94, 0xfa, 0x70, 0x49, 0x3e, 0x12, 0x0f, 0xcf, 0x14, 0xa0, 0x1f, 0xc8, - 0xb8, 0x8f, 0x5d, 0x6a, 0xf4, 0xe4, 0xe6, 0x3a, 0xfd, 0x84, 0x73, 0x73, - 0xec, 0xdc, 0x48, 0xb7, 0x7f, 0x96, 0xa0, 0x4f, 0xb1, 0x24, 0x4d, 0xab, - 0xea, 0x33, 0xa6, 0xbf, 0xe1, 0x72, 0x73, 0x46, 0x81, 0x75, 0x5d, 0xd8, - 0xa6, 0xb4, 0x73, 0x89, 0x47, 0xbd, 0x6e, 0x05, 0x25, 0x3c, 0x67, 0x00, - 0x6e, 0xae, 0x5c, 0xe1, 0xbe, 0x43, 0x91, 0x0e, 0x43, 0x5c, 0x7f, 0x5b, - 0xf3, 0xc9, 0x78, 0x81, 0xb1, 0x95, 0x47, 0x83, 0xf4, 0x28, 0x79, 0x8c, - 0x7d, 0xf0, 0x7d, 0x41, 0xc7, 0x73, 0xf7, 0xfa, 0x8c, 0x15, 0x75, 0x1f, - 0xbf, 0x43, 0x85, 0x72, 0x0a, 0xfa, 0xb7, 0xb8, 0xe8, 0xf0, 0x1b, 0x78, - 0x37, 0x0a, 0xee, 0xf3, 0x8b, 0xce, 0x77, 0xa7, 0x9f, 0xc5, 0x73, 0x83, - 0xfd, 0xee, 0x9d, 0xd1, 0x53, 0x22, 0xc5, 0x70, 0xbe, 0x89, 0x1c, 0xd6, - 0xfe, 0x02, 0xd6, 0xbe, 0xfe, 0x77, 0xee, 0xf0, 0xae, 0x8c, 0x77, 0xe5, - 0x0f, 0x07, 0xe9, 0x36, 0xd2, 0x22, 0xe9, 0xef, 0xb5, 0xfc, 0xe6, 0x41, - 0xcd, 0x17, 0x93, 0xc5, 0xc7, 0xc1, 0x17, 0x69, 0xee, 0x37, 0x07, 0x0f, - 0xfb, 0x37, 0x80, 0x2f, 0xf6, 0xc8, 0xef, 0xc3, 0x2e, 0xf8, 0xdd, 0xca, - 0x10, 0xf8, 0x63, 0x10, 0xfc, 0x32, 0x00, 0x1e, 0xf1, 0xb5, 0x8d, 0xfc, - 0x04, 0xf4, 0x1f, 0xf4, 0x9a, 0xb3, 0xaf, 0xd4, 0xe5, 0x64, 0x4b, 0x9e, - 0x33, 0x51, 0xe2, 0xf7, 0x5a, 0xd4, 0x5b, 0x1b, 0x24, 0x9a, 0x98, 0x13, - 0xf2, 0x42, 0x37, 0x73, 0x1c, 0xdb, 0x81, 0xab, 0x53, 0xc4, 0xd5, 0x5c, - 0xa5, 0xcf, 0xbd, 0x04, 0x3c, 0xd1, 0xae, 0x79, 0xa2, 0xd5, 0x49, 0xbb, - 0x37, 0x58, 0x9e, 0x78, 0x11, 0x3c, 0x71, 0x7e, 0x0d, 0x4f, 0x3c, 0x6d, - 0xe9, 0x7f, 0xa1, 0x86, 0x27, 0xe6, 0x6c, 0xd9, 0xcc, 0x45, 0x78, 0xe2, - 0x52, 0x2f, 0xf5, 0xa5, 0x31, 0x79, 0x15, 0x3c, 0x21, 0x8a, 0x3c, 0x71, - 0xa9, 0xe6, 0x09, 0xc6, 0x8e, 0xc8, 0x17, 0x9d, 0x90, 0x23, 0xe4, 0x8b, - 0xb3, 0xb2, 0x04, 0xbe, 0x78, 0x5e, 0x71, 0xec, 0x19, 0xda, 0x0a, 0x25, - 0xfa, 0x64, 0x27, 0x8a, 0x5d, 0xe0, 0x77, 0x25, 0xff, 0x65, 0x3a, 0x08, - 0x16, 0xe1, 0xa7, 0x3f, 0x08, 0x7b, 0x3e, 0xaa, 0xbf, 0xa9, 0xb8, 0x00, - 0xba, 0x0f, 0xe9, 0x7d, 0xc2, 0x01, 0xbd, 0x1f, 0x9e, 0xc5, 0x1c, 0x26, - 0xd4, 0x7f, 0x86, 0x2f, 0xec, 0x62, 0x5d, 0x69, 0xe7, 0x1f, 0xd3, 0x3c, - 0xd4, 0x00, 0x7d, 0xf0, 0xe8, 0x00, 0x63, 0x4d, 0x9e, 0xbb, 0x4f, 0x75, - 0xe7, 0x46, 0x00, 0x73, 0x44, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xad, 0xb2, - 0xf3, 0x29, 0x23, 0x46, 0x21, 0xeb, 0xcc, 0xbb, 0x5c, 0xd0, 0x04, 0x9b, - 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x48, 0xb9, 0x1f, 0x84, 0x00, 0x6d, - 0x84, 0xbd, 0xb0, 0x0b, 0xab, 0x3d, 0x52, 0xa8, 0xb5, 0xf1, 0xff, 0x03, - 0x6c, 0x7c, 0xb6, 0x91, 0xa8, 0xb1, 0xf1, 0x7f, 0xcd, 0xf2, 0x1a, 0x7f, - 0xbb, 0xda, 0xde, 0x3f, 0x00, 0xf8, 0x76, 0x2f, 0xdb, 0xfb, 0xec, 0x83, - 0x76, 0x87, 0xc8, 0xf5, 0xb0, 0xf9, 0xde, 0x0d, 0x1e, 0xbc, 0x01, 0xbe, - 0xd4, 0x7b, 0x0a, 0xae, 0xec, 0x29, 0xb4, 0xc3, 0xe7, 0xee, 0x94, 0xf7, - 0x4e, 0x6f, 0x95, 0x9d, 0x25, 0xff, 0x12, 0x69, 0xee, 0x80, 0x8d, 0x5a, - 0x00, 0x9c, 0x11, 0x2b, 0xb7, 0xcf, 0x02, 0x6f, 0xdd, 0xc9, 0x9f, 0xa8, - 0x17, 0xad, 0x5d, 0xc4, 0xb3, 0x8e, 0xf5, 0xfa, 0x89, 0xa3, 0x3d, 0x63, - 0x29, 0x1d, 0x72, 0xea, 0x18, 0xbd, 0xaf, 0x24, 0xec, 0x72, 0x1f, 0x36, - 0xc9, 0x16, 0xf4, 0xc7, 0x78, 0xf2, 0x46, 0x79, 0xfa, 0xaa, 0xe8, 0x5d, - 0x59, 0xcd, 0x87, 0x9d, 0x4e, 0x66, 0x1a, 0x3e, 0xc0, 0xde, 0x18, 0xe6, - 0xa0, 0xda, 0x37, 0xcb, 0x75, 0xb2, 0x53, 0xcf, 0x67, 0x46, 0x0e, 0x42, - 0x37, 0xff, 0x41, 0x61, 0xa7, 0x2c, 0x8d, 0xb6, 0xe1, 0x39, 0x26, 0x4f, - 0x17, 0xfa, 0xe0, 0xfb, 0xbc, 0x0b, 0x38, 0x6a, 0xc4, 0x73, 0xa3, 0x0c, - 0x5f, 0x42, 0x5e, 0x6d, 0x91, 0x45, 0x94, 0xbf, 0x5b, 0x7e, 0xc1, 0x96, - 0xb3, 0x8c, 0xbc, 0xd1, 0x82, 0xb6, 0x31, 0x39, 0x57, 0xa0, 0x5d, 0xa9, - 0x79, 0x62, 0xf0, 0x7b, 0xd2, 0x97, 0xfe, 0x1e, 0xec, 0xd4, 0xb3, 0xb8, - 0x9e, 0x91, 0xd4, 0x9e, 0x71, 0xa7, 0x2f, 0xd9, 0xed, 0x40, 0x77, 0xe2, - 0x8a, 0x3a, 0x7d, 0x6e, 0xa3, 0x73, 0x85, 0xed, 0xa3, 0x41, 0x9e, 0xd9, - 0xab, 0x12, 0x2d, 0x58, 0x93, 0xed, 0x4e, 0x8f, 0x2d, 0xe3, 0x73, 0xca, - 0x78, 0x40, 0xa7, 0xd4, 0x96, 0x0d, 0x22, 0x5d, 0x2d, 0xb0, 0x79, 0x26, - 0x44, 0xb5, 0xb7, 0x48, 0x54, 0xba, 0x67, 0x55, 0x27, 0xca, 0x3c, 0x5b, - 0x16, 0x6f, 0x81, 0x7e, 0x40, 0x59, 0x07, 0xca, 0xb6, 0xd9, 0xb2, 0xb6, - 0x16, 0x69, 0x44, 0xd9, 0x8c, 0xe6, 0xf9, 0xf3, 0x3d, 0x9e, 0x9b, 0x75, - 0x9a, 0xa5, 0xeb, 0x44, 0x0b, 0x64, 0xc3, 0x46, 0x59, 0xbc, 0xaa, 0x49, - 0xba, 0xf0, 0x8e, 0x71, 0x6e, 0xff, 0x44, 0x4c, 0xae, 0x3d, 0xd1, 0x9d, - 0xf8, 0x38, 0xe6, 0xd0, 0x7d, 0x8a, 0x71, 0xef, 0xfc, 0x25, 0x8c, 0xfb, - 0x74, 0x9d, 0xe2, 0xbd, 0x49, 0xcb, 0x1f, 0xe2, 0xc3, 0x7c, 0x93, 0x88, - 0x32, 0xf9, 0x24, 0xfc, 0x5c, 0xea, 0xf0, 0x6e, 0xfb, 0xfd, 0x8c, 0xe3, - 0x97, 0xd0, 0x6f, 0x9b, 0xa5, 0x5d, 0x52, 0x24, 0x3f, 0x52, 0x0f, 0xe1, - 0x3e, 0xe3, 0x48, 0xbe, 0x2a, 0xb3, 0xe6, 0xc9, 0x57, 0xc7, 0x14, 0x73, - 0x59, 0x50, 0x56, 0xf9, 0xc5, 0xc0, 0xac, 0x31, 0x79, 0xc1, 0xc8, 0xa5, - 0x0f, 0x18, 0xb9, 0xf4, 0xd8, 0x99, 0x15, 0x72, 0xe9, 0xbc, 0x96, 0x4b, - 0x7b, 0x05, 0xf7, 0xf9, 0xf3, 0x90, 0x4b, 0x2f, 0xe2, 0xd9, 0xd5, 0x72, - 0x29, 0x2e, 0xd6, 0x5e, 0x96, 0xaf, 0xea, 0xf1, 0xe7, 0x8a, 0x51, 0x6d, - 0x57, 0xe5, 0x67, 0x60, 0x93, 0x14, 0xa7, 0xac, 0xfe, 0x96, 0xa1, 0x36, - 0xe9, 0x19, 0xfc, 0xa9, 0x84, 0x36, 0xe7, 0x7f, 0xba, 0x84, 0xdf, 0xee, - 0x7c, 0x5e, 0x51, 0x86, 0xbd, 0x0a, 0x19, 0x26, 0xaa, 0xbe, 0x0c, 0xc3, - 0xbb, 0x32, 0xde, 0x95, 0xd9, 0xef, 0x8f, 0x7e, 0x3a, 0xe6, 0x52, 0x7e, - 0x50, 0x66, 0x40, 0x26, 0x15, 0x21, 0x93, 0x8a, 0x90, 0x53, 0x45, 0xc8, - 0x25, 0xd8, 0x6c, 0x67, 0x8a, 0x90, 0x4b, 0x45, 0xc8, 0x25, 0xc8, 0xb8, - 0x27, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x85, 0x4c, 0x9b, 0x91, 0xfb, 0xac, - 0xae, 0x37, 0xb1, 0x92, 0x7e, 0xeb, 0x23, 0x0d, 0xe8, 0x18, 0xf2, 0x99, - 0x9a, 0xd8, 0xe0, 0x8d, 0x47, 0x34, 0xbf, 0xbb, 0x9e, 0xba, 0xc2, 0x61, - 0x0e, 0xcd, 0x4f, 0xb4, 0xff, 0xbe, 0x9d, 0xbf, 0xa5, 0x09, 0x7c, 0xfd, - 0x03, 0xcb, 0xd7, 0xdb, 0x97, 0xf9, 0x3a, 0xe5, 0x30, 0x56, 0x5c, 0x9f, - 0xaf, 0x3b, 0xec, 0xbb, 0x5c, 0xb0, 0x0e, 0x7c, 0xbd, 0x6e, 0x15, 0x5f, - 0xc7, 0xc0, 0xd7, 0x7b, 0xd6, 0xf0, 0xf5, 0x06, 0x67, 0x58, 0xb7, 0xe1, - 0x19, 0x09, 0x3e, 0x37, 0x3a, 0x55, 0xbe, 0xbe, 0x47, 0xf3, 0xf5, 0x21, - 0xf0, 0xf5, 0x75, 0x35, 0x7c, 0xbd, 0x47, 0x52, 0x37, 0x67, 0x22, 0x5b, - 0x65, 0xfc, 0x7e, 0xd5, 0xbe, 0x49, 0xfe, 0x49, 0x4c, 0x7b, 0xc3, 0x63, - 0xc3, 0xd3, 0xed, 0x92, 0x7d, 0xe8, 0x15, 0x94, 0x91, 0xcf, 0x52, 0x63, - 0x69, 0xc7, 0x95, 0x83, 0x47, 0x7e, 0x22, 0x0b, 0x9a, 0xb7, 0x44, 0x26, - 0x8e, 0xc4, 0x64, 0xf2, 0x08, 0xe3, 0x10, 0x7f, 0x63, 0xe9, 0xbd, 0x49, - 0x26, 0xf7, 0x32, 0x6f, 0x2e, 0x2a, 0xe3, 0x47, 0xe0, 0x6f, 0x1d, 0x61, - 0x1c, 0xe2, 0xa5, 0x65, 0x1e, 0x5b, 0x80, 0x6c, 0x19, 0x3f, 0xc2, 0xb5, - 0x8e, 0xa1, 0x9f, 0x16, 0x39, 0x74, 0x44, 0xe4, 0xb6, 0x23, 0x51, 0xf9, - 0xe8, 0x91, 0x65, 0x5e, 0x1b, 0x0d, 0x79, 0xed, 0x59, 0xf0, 0x5a, 0xb7, - 0xe5, 0x35, 0xb5, 0xcc, 0x6b, 0x7f, 0x5a, 0xc3, 0x6b, 0x6c, 0x4f, 0x5e, - 0x7b, 0xce, 0x96, 0xf1, 0x39, 0x2a, 0xfb, 0x8e, 0x74, 0xca, 0xf8, 0x43, - 0x6f, 0x91, 0x89, 0xfb, 0x09, 0xab, 0xf9, 0x8e, 0x13, 0x6d, 0xb1, 0x99, - 0x4a, 0x37, 0xfa, 0x0f, 0x73, 0x88, 0xf4, 0xf7, 0x10, 0x7a, 0x67, 0x25, - 0x95, 0xe3, 0x78, 0x8d, 0xf0, 0xa3, 0x4f, 0xc0, 0xbf, 0xd8, 0x07, 0x98, - 0x6e, 0x39, 0x22, 0xa9, 0xa8, 0xbc, 0x2c, 0x53, 0xfe, 0x27, 0x2e, 0x37, - 0xf6, 0x04, 0x6c, 0x11, 0x6d, 0xfb, 0xa4, 0x25, 0xfb, 0xce, 0x40, 0xfb, - 0x18, 0xa5, 0xb2, 0x30, 0x16, 0xc0, 0xb8, 0xb9, 0x63, 0xbe, 0xc7, 0xc4, - 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0x07, 0xf8, 0x9e, 0xcf, - 0xb0, 0x67, 0xf4, 0x59, 0x43, 0xb6, 0x7f, 0x44, 0x7f, 0x1b, 0x91, 0x31, - 0xf5, 0x7c, 0x99, 0xdf, 0xb0, 0x81, 0xff, 0x59, 0xe6, 0xb7, 0xb0, 0xf6, - 0xb7, 0x9b, 0xf8, 0x2c, 0xf9, 0xee, 0x87, 0x0e, 0xbf, 0x5d, 0x35, 0xa5, - 0x73, 0xbd, 0xf0, 0xbb, 0xcc, 0x67, 0xd6, 0x7f, 0x84, 0xf1, 0x8e, 0x64, - 0x52, 0xbd, 0xf7, 0x72, 0xe6, 0x1e, 0xec, 0x9d, 0x67, 0xdd, 0xad, 0x96, - 0x47, 0xb7, 0x6a, 0xbf, 0x83, 0x36, 0xd6, 0x78, 0xe9, 0x45, 0xc9, 0xd3, - 0x36, 0x19, 0xdd, 0xea, 0xe4, 0x66, 0x92, 0x97, 0x1b, 0xfb, 0x79, 0xdd, - 0xa5, 0xcc, 0x3b, 0x4c, 0xab, 0xb5, 0x32, 0xf9, 0x84, 0x84, 0x32, 0x39, - 0x75, 0x33, 0xbf, 0xb7, 0x9b, 0x3d, 0xa2, 0xbf, 0x2f, 0x95, 0xec, 0x56, - 0x9c, 0xd3, 0xa7, 0x21, 0x5f, 0x43, 0x5a, 0x48, 0xc8, 0x27, 0x8f, 0x90, - 0x1e, 0x54, 0xbc, 0x55, 0x3e, 0x61, 0xe9, 0x61, 0x46, 0x0a, 0x90, 0x3b, - 0x47, 0x8e, 0x7c, 0x54, 0x66, 0x6e, 0x5c, 0x4d, 0x0f, 0x13, 0x55, 0x7a, - 0x88, 0xc3, 0x3e, 0x73, 0x6a, 0xe9, 0xe1, 0x97, 0x97, 0xe9, 0x61, 0xc6, - 0xf9, 0xe7, 0xd2, 0xc3, 0xf5, 0x2b, 0xe8, 0x61, 0x4a, 0xd3, 0xc3, 0xce, - 0x65, 0x7a, 0x98, 0x3a, 0xc2, 0x71, 0xf5, 0xde, 0xa8, 0xbb, 0xe8, 0x70, - 0xcd, 0x97, 0x69, 0x21, 0x39, 0xa9, 0xf3, 0xf5, 0x53, 0x39, 0x9e, 0x6f, - 0xda, 0xa0, 0x18, 0x27, 0xa9, 0xae, 0x7f, 0xeb, 0xbf, 0xe8, 0xfa, 0xbf, - 0xfc, 0xff, 0x79, 0xfd, 0xd5, 0xa5, 0xcc, 0xdd, 0xe7, 0x99, 0x55, 0x23, - 0x8f, 0x43, 0x7a, 0x88, 0x5d, 0x6a, 0xf4, 0x02, 0xd7, 0x98, 0xcf, 0x90, - 0x67, 0x90, 0x7f, 0x67, 0x20, 0xff, 0x9e, 0x84, 0xfc, 0x3b, 0xbd, 0x62, - 0x4f, 0x60, 0xd0, 0xc6, 0x23, 0x02, 0x39, 0xe8, 0x57, 0xf1, 0xb1, 0x38, - 0x40, 0x7c, 0x98, 0xfc, 0x13, 0xe6, 0xfe, 0xae, 0xc4, 0x49, 0x54, 0xe7, - 0x1c, 0x3d, 0xea, 0xd7, 0xe2, 0x84, 0x70, 0xbf, 0x5c, 0x33, 0x47, 0xfc, - 0x2e, 0xf3, 0x79, 0x46, 0xe7, 0x91, 0xe4, 0xf5, 0x1e, 0x14, 0xf1, 0xc2, - 0x3d, 0x28, 0xe2, 0x24, 0xaa, 0xed, 0xfd, 0x7c, 0xb9, 0x49, 0xe7, 0xd0, - 0x1f, 0x98, 0x8f, 0xcb, 0x62, 0x9c, 0x31, 0x3e, 0x7e, 0x97, 0x90, 0x7e, - 0xb3, 0x97, 0xc8, 0x4b, 0x8e, 0xb9, 0x72, 0xe0, 0xe9, 0x0d, 0x96, 0xb6, - 0x19, 0x1b, 0xe4, 0x99, 0xdd, 0x70, 0x2f, 0xa2, 0xd7, 0xca, 0xba, 0x96, - 0x9a, 0x98, 0x25, 0xf0, 0x3e, 0x2d, 0xc9, 0xcc, 0x00, 0xee, 0xf3, 0x1c, - 0x7b, 0xbf, 0x4c, 0x3d, 0x38, 0x01, 0x5b, 0x6e, 0x2f, 0x74, 0x0e, 0xcf, - 0x9f, 0x99, 0xef, 0x70, 0x13, 0x86, 0x59, 0xfd, 0xdd, 0x29, 0xfa, 0x80, - 0xa4, 0x87, 0x04, 0x9e, 0x67, 0x6c, 0x5c, 0x29, 0x21, 0xf9, 0xc2, 0x05, - 0xf3, 0x6d, 0xcb, 0xc2, 0x4b, 0xb8, 0xbf, 0xde, 0x7a, 0x18, 0x3f, 0x64, - 0xd4, 0xdc, 0xd1, 0xd7, 0x92, 0xa4, 0xcb, 0x26, 0xc7, 0xa5, 0x1a, 0x37, - 0x99, 0x91, 0xc3, 0xda, 0x7e, 0x1e, 0xb2, 0xb9, 0x2d, 0xa9, 0xd1, 0x9c, - 0x18, 0x1b, 0xfa, 0x77, 0x60, 0x43, 0x7f, 0xb1, 0x92, 0xd6, 0xfb, 0x58, - 0xa7, 0x61, 0x43, 0x3f, 0x01, 0xdd, 0x43, 0x9d, 0x13, 0xb7, 0x3a, 0x67, - 0x4a, 0xdd, 0xa8, 0x75, 0xce, 0x37, 0xb5, 0xce, 0x79, 0xef, 0x1a, 0x9d, - 0x73, 0x48, 0x75, 0x97, 0xa8, 0x73, 0x86, 0xd5, 0x1e, 0x87, 0xf6, 0xe2, - 0xe6, 0x3a, 0x3a, 0xe7, 0x7d, 0xf2, 0x2e, 0xfb, 0xee, 0x1e, 0x79, 0xff, - 0x0e, 0xbd, 0x77, 0xe3, 0xce, 0x2a, 0x7e, 0x6b, 0xc9, 0xe8, 0xa0, 0xeb, - 0x54, 0xaf, 0xde, 0xf3, 0xfd, 0x46, 0x8d, 0xce, 0xe9, 0x52, 0x03, 0xce, - 0xb0, 0x6e, 0xc3, 0xd8, 0x04, 0x9f, 0x7d, 0x27, 0x3d, 0xda, 0x84, 0xe7, - 0x84, 0x44, 0x8e, 0x60, 0xee, 0xe6, 0x7b, 0x50, 0xca, 0xbc, 0x7b, 0xab, - 0x7d, 0xa7, 0xc2, 0xf2, 0xa8, 0x29, 0xef, 0xb6, 0xe5, 0x46, 0x57, 0x75, - 0xa9, 0x4e, 0xad, 0xab, 0xb6, 0x83, 0xa1, 0x66, 0xa1, 0x5f, 0x67, 0x8b, - 0xa1, 0xce, 0xe2, 0x6f, 0xc6, 0x9e, 0x19, 0xa3, 0x08, 0x63, 0xd8, 0x49, - 0xd4, 0xc1, 0x55, 0x0c, 0x6d, 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x1e, - 0x78, 0xbd, 0x19, 0xfc, 0xf3, 0x6f, 0x0a, 0x8c, 0x81, 0xb6, 0xcb, 0xd1, - 0xe9, 0xda, 0x77, 0x9d, 0xf2, 0x9e, 0xe9, 0x2d, 0xb2, 0xbf, 0xf4, 0x2d, - 0xf0, 0xc1, 0x56, 0x99, 0x2a, 0x15, 0xf4, 0x79, 0xf5, 0x4d, 0xfa, 0x3b, - 0x1e, 0xfc, 0xbe, 0x8d, 0x91, 0x91, 0x3b, 0x1d, 0x23, 0x23, 0xd3, 0xaa, - 0x6a, 0xb3, 0x86, 0x7d, 0xf2, 0xdb, 0x21, 0x23, 0xa5, 0x84, 0xfe, 0xc6, - 0xe9, 0x6c, 0xe5, 0x0a, 0xf9, 0xc2, 0x31, 0x75, 0xa7, 0xaa, 0x9e, 0xef, - 0xd5, 0x36, 0xeb, 0xdc, 0x0a, 0x9b, 0xf5, 0xaf, 0x64, 0xf1, 0xfd, 0x31, - 0xcc, 0x13, 0x34, 0x7c, 0xe5, 0xf7, 0xb8, 0x17, 0xda, 0x1e, 0x97, 0x0b, - 0x32, 0xa2, 0xf1, 0x47, 0x79, 0xda, 0x02, 0x39, 0xb8, 0xa4, 0xf5, 0xeb, - 0x66, 0xd0, 0x20, 0x65, 0xe9, 0xc7, 0xe4, 0x45, 0x2d, 0xcf, 0x36, 0x5b, - 0xdb, 0x75, 0x81, 0xb1, 0xd4, 0x23, 0xb4, 0x5d, 0xbf, 0x69, 0xcb, 0x59, - 0x96, 0x4a, 0x2c, 0x09, 0xf5, 0x5d, 0x1c, 0x32, 0x94, 0xf2, 0xf4, 0x8d, - 0xda, 0xae, 0x5f, 0xb3, 0x7d, 0x50, 0x7e, 0x1a, 0xd9, 0xbd, 0xdd, 0x59, - 0xb0, 0x65, 0x7c, 0x0e, 0xe3, 0xe9, 0x5e, 0x3a, 0x6b, 0xf9, 0x4c, 0x39, - 0x5f, 0xc2, 0xfb, 0x4d, 0x78, 0x4f, 0x3e, 0x3b, 0xad, 0xf9, 0x4c, 0xdb, - 0x27, 0x4e, 0xbf, 0xdd, 0x5f, 0x58, 0xde, 0x1b, 0xc8, 0x91, 0xcf, 0xd4, - 0x51, 0x77, 0xc1, 0xc8, 0x03, 0xe6, 0xa9, 0x7e, 0x1e, 0xba, 0x83, 0x6d, - 0x51, 0xfe, 0x70, 0x9a, 0xbe, 0x2d, 0xfc, 0x9f, 0x56, 0x3c, 0xb7, 0xe3, - 0x79, 0x56, 0xde, 0xbb, 0x37, 0xa6, 0xe7, 0x3d, 0x85, 0x79, 0x1c, 0x38, - 0x82, 0x39, 0x39, 0xc6, 0x76, 0x8e, 0x9e, 0x8a, 0x4a, 0xc3, 0x29, 0xf2, - 0x1d, 0xcf, 0xda, 0x04, 0xc1, 0xbe, 0x7e, 0xd2, 0x6d, 0xca, 0xdd, 0xa9, - 0xcf, 0x96, 0x6e, 0x4f, 0x44, 0x80, 0x93, 0x03, 0x58, 0x8f, 0xa9, 0x82, - 0xe7, 0x66, 0x1c, 0x2f, 0x81, 0x79, 0xc2, 0x06, 0xec, 0x86, 0x2d, 0xd8, - 0x0d, 0x3b, 0xb0, 0x1b, 0x76, 0xe0, 0x46, 0x39, 0x71, 0x15, 0x73, 0x4c, - 0x72, 0xd7, 0xc2, 0x2b, 0x97, 0xef, 0xe8, 0x38, 0x7d, 0xe3, 0xcd, 0x23, - 0xf0, 0xd9, 0xc5, 0x4d, 0x8d, 0x32, 0x0f, 0x7f, 0xc9, 0x6d, 0xbc, 0x79, - 0xa7, 0x74, 0x0f, 0xe2, 0xfd, 0xe0, 0x05, 0xe9, 0xb9, 0xf9, 0x56, 0xa7, - 0x71, 0x74, 0x04, 0x78, 0x4c, 0x3b, 0xa9, 0xc4, 0x98, 0xb3, 0x80, 0x71, - 0x32, 0xdb, 0x23, 0xc2, 0xb8, 0xe5, 0x02, 0x63, 0x11, 0x37, 0x77, 0x47, - 0xfa, 0x92, 0xe3, 0x4e, 0x6a, 0x54, 0x45, 0x52, 0xa3, 0x23, 0x4e, 0x58, - 0x8f, 0xdf, 0x48, 0x85, 0x9c, 0x01, 0xac, 0x07, 0x8a, 0xd3, 0xa0, 0xa7, - 0xff, 0x28, 0xf9, 0x63, 0x2d, 0x32, 0x5f, 0xe8, 0x76, 0x33, 0x2a, 0xae, - 0x73, 0x4b, 0xd4, 0x09, 0x10, 0xfd, 0xa9, 0x98, 0xcc, 0x96, 0xb6, 0x8a, - 0xd2, 0xb6, 0x7b, 0x87, 0x64, 0xa6, 0x4b, 0x72, 0x6e, 0x40, 0xda, 0x14, - 0xfa, 0xe7, 0xb7, 0x67, 0xd5, 0x09, 0xee, 0x25, 0x86, 0xbc, 0x70, 0x39, - 0xf9, 0xa4, 0x04, 0x1c, 0x82, 0x6e, 0x19, 0xe3, 0x6d, 0x12, 0xca, 0xbd, - 0x8f, 0xea, 0xf8, 0x29, 0x63, 0xb6, 0xb5, 0x7b, 0x0f, 0xe4, 0x8f, 0x58, - 0x5d, 0xfe, 0x98, 0x2b, 0x72, 0x9f, 0x46, 0x72, 0x51, 0xc6, 0x88, 0x3d, - 0xfc, 0x9e, 0x61, 0xdd, 0x26, 0x99, 0x1a, 0xc8, 0xd9, 0x3c, 0x8f, 0x47, - 0x12, 0xcc, 0x21, 0x26, 0x4e, 0xc6, 0x07, 0xc8, 0xeb, 0xab, 0xf7, 0x36, - 0x62, 0x35, 0xf2, 0xc0, 0x91, 0xc5, 0x52, 0xb8, 0x17, 0xc2, 0xfe, 0xf0, - 0x3c, 0x63, 0xe4, 0x6d, 0x66, 0x4d, 0x3b, 0xc2, 0xc5, 0xfd, 0xca, 0x95, - 0x32, 0x56, 0x79, 0x94, 0xa9, 0xae, 0x96, 0xaf, 0x8f, 0x55, 0x8c, 0x6c, - 0x9d, 0xa9, 0x84, 0xba, 0x25, 0x66, 0x74, 0xe9, 0x1a, 0x7d, 0x62, 0xa2, - 0x99, 0x55, 0x7d, 0x42, 0xbd, 0xa8, 0xe4, 0x03, 0xf3, 0x1d, 0x12, 0x7d, - 0x58, 0x96, 0xa6, 0xbc, 0xec, 0xe5, 0xcc, 0xd5, 0x98, 0xf2, 0xdf, 0x8c, - 0x7e, 0xfc, 0x6f, 0x09, 0xea, 0xc3, 0x31, 0xf5, 0x75, 0xdc, 0x37, 0x69, - 0xfa, 0x03, 0x4f, 0xe1, 0xd9, 0xf8, 0x09, 0xbf, 0x03, 0x3f, 0xe1, 0x8b, - 0xd0, 0x75, 0x67, 0xe0, 0x27, 0x3c, 0x09, 0x3f, 0xe1, 0x34, 0xfc, 0x84, - 0x27, 0xa0, 0x27, 0x6b, 0xfd, 0x83, 0xc9, 0x15, 0xfe, 0x41, 0xa0, 0xf9, - 0x9f, 0xf1, 0xc0, 0x27, 0x6b, 0x7c, 0x83, 0x7d, 0x46, 0x5f, 0xc1, 0xef, - 0x37, 0x7c, 0xd4, 0xa5, 0x6e, 0xd2, 0xfa, 0xd1, 0xe4, 0xed, 0x8e, 0x2e, - 0xeb, 0xab, 0x2e, 0x65, 0xf4, 0xd5, 0x6c, 0x55, 0x5f, 0x19, 0x3e, 0x7a, - 0xb8, 0x24, 0x11, 0xaf, 0xb4, 0x90, 0xf1, 0x77, 0x69, 0x1e, 0x6a, 0xf3, - 0xb6, 0x4a, 0xe4, 0x01, 0xd5, 0xde, 0x20, 0x19, 0xfb, 0x0c, 0xfa, 0x3a, - 0x3a, 0x8d, 0xbe, 0xae, 0x95, 0xac, 0xb6, 0xcf, 0x2e, 0x8e, 0xef, 0x27, - 0x56, 0xe1, 0x3b, 0x5f, 0xbc, 0x5b, 0xe3, 0xfc, 0xfe, 0x32, 0xf7, 0x59, - 0x5a, 0x64, 0xb2, 0x1c, 0xe2, 0x9c, 0xe7, 0x59, 0x99, 0x8b, 0xd1, 0x29, - 0x91, 0x87, 0x3b, 0x78, 0xce, 0x4a, 0x65, 0xfd, 0xf5, 0x3a, 0x87, 0xe5, - 0xc4, 0x80, 0x24, 0xb2, 0x03, 0xa4, 0xd5, 0xfb, 0x64, 0x56, 0xaf, 0x45, - 0x87, 0x34, 0x3c, 0x4c, 0x1b, 0x25, 0xdc, 0xcf, 0xeb, 0xba, 0xcc, 0x7e, - 0x23, 0x35, 0x66, 0xea, 0x89, 0x1c, 0xd4, 0xeb, 0x75, 0x5c, 0xe7, 0x19, - 0xde, 0x34, 0xcf, 0xb8, 0x3c, 0xbf, 0x47, 0xc5, 0x98, 0xfc, 0x3f, 0x67, - 0xfd, 0x7e, 0xe1, 0x32, 0x63, 0xcf, 0x6c, 0xb2, 0x76, 0x8c, 0x89, 0x53, - 0xd5, 0xb7, 0x61, 0xd8, 0x4f, 0xed, 0x37, 0x14, 0xb7, 0x38, 0x93, 0xa5, - 0xad, 0x4e, 0xbe, 0xc4, 0xbd, 0x6c, 0xfb, 0xf7, 0x2e, 0xdc, 0x3d, 0xce, - 0x01, 0x6f, 0x0b, 0xca, 0x18, 0xb3, 0x64, 0xcc, 0xe6, 0x97, 0x2e, 0x63, - 0x8c, 0x36, 0xe3, 0x71, 0x6c, 0x96, 0x6d, 0x71, 0xa6, 0x4a, 0xdd, 0xf0, - 0xcd, 0x79, 0xae, 0x8a, 0xef, 0x77, 0x72, 0xed, 0xa0, 0x83, 0x5d, 0x7d, - 0x66, 0x77, 0x42, 0xae, 0xb0, 0x31, 0x68, 0xea, 0xe1, 0x9f, 0x5f, 0xb1, - 0x77, 0x7b, 0x08, 0x7a, 0xec, 0x16, 0xc8, 0x23, 0xea, 0xe1, 0x43, 0x72, - 0xb5, 0xa5, 0xe7, 0x95, 0x7a, 0xf8, 0xbc, 0x30, 0x4e, 0xdc, 0x8f, 0x77, - 0xb9, 0x20, 0x06, 0x7a, 0x38, 0x5c, 0xe3, 0xab, 0xd1, 0xef, 0x6b, 0x1a, - 0x32, 0xfb, 0x61, 0x2b, 0xfd, 0x3e, 0xc8, 0x81, 0x78, 0xe8, 0xe7, 0x35, - 0x2e, 0xef, 0xd7, 0xee, 0xb1, 0x6d, 0xa7, 0xfc, 0xfb, 0x89, 0xa3, 0xe4, - 0x21, 0xe9, 0x81, 0x2e, 0x63, 0x0e, 0xc8, 0x6f, 0x69, 0x9c, 0x89, 0x22, - 0xed, 0x6d, 0xd2, 0x30, 0x5a, 0x39, 0x9f, 0x0c, 0x73, 0x38, 0xf2, 0xb6, - 0xed, 0x84, 0xdd, 0x93, 0xcf, 0xcb, 0xdc, 0x65, 0xd4, 0x83, 0x23, 0x91, - 0xf5, 0xfc, 0x7e, 0x22, 0xda, 0xf6, 0x18, 0xbd, 0x28, 0x61, 0x5f, 0x7c, - 0x6e, 0xa8, 0xe9, 0x9b, 0x76, 0x14, 0xef, 0xab, 0xcf, 0x91, 0x3d, 0xa3, - 0xf7, 0x19, 0xcd, 0xf7, 0x12, 0x42, 0x3e, 0x21, 0xef, 0x24, 0xf5, 0x59, - 0x27, 0xef, 0x61, 0xda, 0x3d, 0xdc, 0x83, 0x75, 0x17, 0x26, 0xfd, 0x4f, - 0xe8, 0x6f, 0xfc, 0xcd, 0x88, 0x38, 0x79, 0xff, 0x36, 0x9d, 0x7b, 0x92, - 0xd7, 0xb1, 0xe6, 0x1c, 0xee, 0x55, 0x1f, 0xb5, 0xeb, 0x61, 0xfe, 0x4d, - 0x0b, 0x96, 0x65, 0x01, 0x1b, 0x75, 0x08, 0x65, 0x6f, 0x5c, 0xba, 0x8e, - 0x7e, 0x58, 0xf3, 0xc2, 0x66, 0xf8, 0x02, 0xc3, 0x47, 0xa1, 0xab, 0x8f, - 0x26, 0x64, 0xe7, 0x51, 0xad, 0x1b, 0xd3, 0x6b, 0x63, 0x05, 0x7d, 0x6e, - 0xd4, 0x79, 0x8f, 0x3e, 0xc7, 0xf6, 0xd6, 0xa3, 0x11, 0x39, 0x1c, 0xef, - 0x73, 0x7b, 0x9c, 0xf7, 0x5a, 0x5d, 0x18, 0xc6, 0xb0, 0x5b, 0xd0, 0xfe, - 0xf5, 0xe2, 0xd8, 0x61, 0xfc, 0x3a, 0x22, 0x33, 0x7b, 0x3b, 0x01, 0xdb, - 0x5f, 0x5d, 0x66, 0xce, 0x20, 0x63, 0xad, 0xf4, 0xb7, 0xe7, 0xa3, 0x09, - 0xca, 0xb2, 0x2e, 0xc0, 0x32, 0x72, 0x94, 0xfa, 0xcc, 0xd3, 0x3c, 0x0e, - 0x18, 0xdc, 0x06, 0xed, 0x87, 0x90, 0x2f, 0xdf, 0x22, 0xde, 0x03, 0x90, - 0x71, 0x47, 0x63, 0xd2, 0x73, 0xb4, 0x45, 0xb6, 0x1d, 0xa5, 0x1f, 0x52, - 0xeb, 0x97, 0xd2, 0x2e, 0x7d, 0x04, 0x73, 0x7c, 0xb7, 0x96, 0x93, 0xdc, - 0xd3, 0xdc, 0x4f, 0xde, 0x45, 0xdd, 0x2c, 0x6c, 0xe6, 0xcc, 0x51, 0x57, - 0xef, 0x91, 0x66, 0x30, 0xe7, 0x6c, 0xd9, 0xc5, 0x38, 0x46, 0xe6, 0xe4, - 0xe9, 0xa7, 0x8c, 0x76, 0x00, 0xc7, 0xef, 0xb5, 0xbc, 0xb3, 0xbe, 0xc3, - 0xf2, 0xe8, 0xcf, 0xc8, 0x7b, 0x5b, 0x3a, 0x8c, 0xec, 0x7c, 0x4b, 0x07, - 0x73, 0x93, 0x36, 0x7b, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7, - 0xe2, 0x45, 0x01, 0x8e, 0xc2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0x38, 0xe7, - 0xeb, 0xf3, 0x2b, 0xfe, 0xa2, 0xfe, 0x3b, 0x21, 0xdc, 0x23, 0xab, 0x7e, - 0x6f, 0x65, 0x57, 0x85, 0x71, 0xf2, 0xcf, 0x86, 0x7f, 0x97, 0xa4, 0x26, - 0xef, 0xb0, 0x76, 0x0f, 0x8c, 0xb1, 0xa6, 0xe5, 0xdc, 0xa0, 0xa0, 0xa4, - 0xbf, 0x5f, 0xf4, 0x9c, 0x73, 0xbe, 0x70, 0xd6, 0xf9, 0xee, 0xb4, 0x04, - 0x51, 0xef, 0x27, 0xce, 0xf7, 0x3d, 0xee, 0x99, 0x7f, 0xdd, 0xf9, 0x5e, - 0xc1, 0x03, 0x1f, 0xde, 0x87, 0x79, 0xbc, 0xe2, 0xfc, 0x00, 0xeb, 0x7b, - 0xb0, 0x98, 0x4e, 0xb9, 0x36, 0x26, 0x7e, 0xb6, 0xf0, 0x8a, 0xf3, 0xb5, - 0x6a, 0x3c, 0x69, 0x30, 0xa4, 0x91, 0x43, 0x7c, 0x57, 0xc6, 0xbb, 0xb2, - 0xde, 0xff, 0x71, 0xe6, 0xa6, 0x6d, 0x7e, 0x89, 0xe6, 0xe3, 0x85, 0xe5, - 0x7d, 0x99, 0x51, 0xbd, 0x57, 0xf1, 0xac, 0x33, 0x37, 0x7f, 0x77, 0x87, - 0xc9, 0x33, 0x3a, 0x8b, 0x77, 0x26, 0xe7, 0x72, 0x76, 0xfe, 0x2c, 0xea, - 0x3c, 0xe3, 0xcc, 0xea, 0xf8, 0x97, 0xf6, 0xc5, 0x9d, 0x99, 0xf9, 0x67, - 0x9c, 0x79, 0xbd, 0x07, 0x7d, 0xce, 0x79, 0x74, 0x9a, 0x7d, 0x9f, 0x43, - 0x9d, 0x05, 0xe7, 0x04, 0xfa, 0x9b, 0x9f, 0xe6, 0x79, 0xdc, 0x6e, 0xd8, - 0x05, 0xfc, 0x7b, 0x3f, 0xfc, 0x1e, 0xc7, 0xb3, 0xce, 0xfc, 0x72, 0xbf, - 0x8b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x59, 0xf4, 0xbf, 0x76, - 0xaf, 0x6a, 0x2d, 0x4e, 0x5e, 0x00, 0x4e, 0x2e, 0x58, 0x9c, 0xbc, 0x6a, - 0x71, 0xf2, 0x7c, 0x0d, 0x4e, 0x44, 0xad, 0xc4, 0xc9, 0xab, 0xc0, 0x89, - 0xa8, 0xfa, 0x38, 0xc1, 0xbb, 0x32, 0xde, 0x69, 0x9c, 0xbc, 0xb4, 0x0a, - 0x27, 0x4b, 0xcb, 0x71, 0x79, 0x83, 0x93, 0x17, 0x81, 0x93, 0xaf, 0x5a, - 0xd8, 0x2f, 0x58, 0x9c, 0xe0, 0x3e, 0x7f, 0x01, 0x75, 0x5e, 0xaa, 0xc1, - 0xc9, 0x05, 0xe0, 0xe4, 0x25, 0x8b, 0x93, 0xef, 0x5b, 0x9c, 0x7c, 0x1f, - 0x75, 0x96, 0x80, 0x93, 0xf3, 0x75, 0x70, 0xf2, 0x22, 0x70, 0x12, 0xf6, - 0x7b, 0x1e, 0xfd, 0x7c, 0xbf, 0x06, 0x27, 0x2f, 0xd6, 0xc1, 0x09, 0xf7, - 0x62, 0xc3, 0x9c, 0xee, 0x99, 0xd7, 0xc9, 0xe9, 0x96, 0x3b, 0x5f, 0x3f, - 0xa7, 0x9b, 0x75, 0x66, 0xa4, 0xfa, 0x37, 0x25, 0xee, 0xb6, 0x39, 0x6a, - 0x26, 0x17, 0xb0, 0xfa, 0xcd, 0xa6, 0x6e, 0xf0, 0x79, 0x3e, 0xe7, 0x8a, - 0xc9, 0x29, 0x8d, 0xee, 0xf8, 0x10, 0x78, 0x6d, 0x97, 0x1c, 0x38, 0xd6, - 0x78, 0x38, 0x6b, 0xcb, 0xbc, 0x1d, 0xdd, 0x39, 0xa5, 0xf8, 0x2e, 0xcc, - 0x49, 0xa0, 0x5f, 0xd2, 0xc0, 0x6f, 0x0b, 0xf6, 0xa6, 0xa5, 0x76, 0x4f, - 0xba, 0xc0, 0x6f, 0x34, 0x61, 0xec, 0x25, 0xfe, 0xfd, 0x8b, 0x24, 0xf3, - 0xac, 0xf2, 0x1a, 0xde, 0x14, 0xf4, 0xc7, 0xa0, 0xce, 0xad, 0xca, 0x14, - 0x68, 0x73, 0x27, 0x99, 0xa3, 0x06, 0x5b, 0x79, 0xc8, 0x9e, 0x09, 0xf3, - 0xf5, 0x39, 0x95, 0x2a, 0xff, 0xd4, 0x9e, 0x87, 0x26, 0xdf, 0x55, 0xe9, - 0xe6, 0xe0, 0xf2, 0x77, 0x02, 0x4f, 0xca, 0xd3, 0x3a, 0x56, 0xdc, 0x8c, - 0xf5, 0x09, 0x82, 0xc7, 0x7c, 0x13, 0xa3, 0x5d, 0xd4, 0x31, 0x5a, 0x81, - 0x37, 0x3e, 0x69, 0xe3, 0xb4, 0x3d, 0x83, 0x2f, 0x2d, 0xc7, 0x68, 0x6b, - 0xf3, 0x59, 0xcc, 0xfe, 0x7a, 0xa6, 0xf4, 0x88, 0xce, 0xd1, 0x19, 0xe1, - 0xf7, 0x37, 0x20, 0x23, 0x26, 0x66, 0xe6, 0x65, 0xf2, 0x41, 0x3e, 0x53, - 0xbf, 0x45, 0xa0, 0xc3, 0x28, 0xc3, 0x73, 0x92, 0x19, 0x64, 0x99, 0x69, - 0x33, 0xa2, 0xfd, 0xe5, 0x93, 0x32, 0xbc, 0x3c, 0x3e, 0xf1, 0x7b, 0x57, - 0xcd, 0x77, 0xab, 0x69, 0xf3, 0xa4, 0x9d, 0x4c, 0x85, 0xef, 0xc3, 0x3d, - 0xf2, 0xbb, 0xec, 0xb7, 0xb3, 0xf8, 0xbe, 0xf6, 0x5b, 0xad, 0x5a, 0x74, - 0xe0, 0x37, 0xbf, 0x87, 0x36, 0xe5, 0x8c, 0xa0, 0xcd, 0x82, 0xdb, 0x32, - 0xaa, 0x86, 0x6e, 0x18, 0xe5, 0xb9, 0xb9, 0xd9, 0x35, 0xdf, 0xba, 0xae, - 0xea, 0xc5, 0xbc, 0x5e, 0x53, 0xe6, 0x67, 0xdd, 0x05, 0x5a, 0xd4, 0xb4, - 0xa5, 0xe9, 0xff, 0xc0, 0xb2, 0xbe, 0xa4, 0x9e, 0x35, 0xdf, 0x9e, 0x31, - 0xfa, 0x32, 0x95, 0x18, 0xc1, 0xf8, 0xfa, 0x6f, 0x2a, 0xd8, 0x73, 0xbd, - 0xd9, 0xf9, 0xdb, 0xb5, 0xae, 0x9f, 0xf2, 0xd3, 0xc9, 0xa8, 0xd4, 0xa9, - 0x5b, 0xaa, 0xa9, 0xab, 0xe7, 0xed, 0xca, 0x7f, 0xc5, 0xda, 0x7c, 0xbe, - 0x58, 0x96, 0xe1, 0xe9, 0xbf, 0x84, 0xff, 0x98, 0x90, 0xdf, 0x2e, 0x96, - 0x40, 0xaf, 0xb9, 0xcd, 0xf6, 0x5b, 0x4d, 0x19, 0xc0, 0xcd, 0x6f, 0xaf, - 0xe8, 0x7c, 0xe2, 0xc8, 0x17, 0x40, 0x17, 0x9f, 0x2b, 0x71, 0x0c, 0xc0, - 0x12, 0x81, 0x6d, 0x0f, 0x3b, 0x61, 0xa6, 0xa4, 0x73, 0xe7, 0xae, 0x2b, - 0x97, 0x74, 0xcc, 0x62, 0x67, 0xb9, 0x53, 0x76, 0x95, 0x5b, 0x64, 0x37, - 0xf4, 0xc2, 0xee, 0xb2, 0x87, 0x2b, 0x26, 0xef, 0x2e, 0x9b, 0x75, 0xfa, - 0x58, 0x99, 0xeb, 0xbd, 0x43, 0x66, 0x8f, 0xad, 0xfe, 0x3e, 0xe7, 0x42, - 0x2e, 0xfc, 0x3b, 0x4b, 0x4a, 0x31, 0xbf, 0x8c, 0xb4, 0x84, 0xab, 0x98, - 0x3a, 0xbc, 0xa0, 0xf1, 0xc0, 0x0c, 0xd7, 0x54, 0x69, 0x49, 0x98, 0xa7, - 0xcf, 0xbf, 0xad, 0x34, 0x73, 0x39, 0xcf, 0x4d, 0xf3, 0x5b, 0x5e, 0x3b, - 0x2b, 0x61, 0xde, 0x78, 0xbd, 0x9c, 0x71, 0xd8, 0xf9, 0x3b, 0xc2, 0x1c, - 0xbf, 0x18, 0x73, 0xc6, 0xa5, 0xeb, 0x54, 0x0b, 0xee, 0xa7, 0x2f, 0xd7, - 0x67, 0x9b, 0x4f, 0x89, 0x2d, 0xd3, 0xf9, 0xe4, 0x78, 0x5e, 0xfd, 0x7d, - 0xb5, 0x90, 0x1f, 0xaa, 0x7f, 0xa7, 0x40, 0xe4, 0xff, 0x02, 0xfb, 0x2e, - 0x88, 0x71, 0xec, 0x6e, 0x00, 0x00, 0x00 }; - -static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = { - 0x0800061c, 0x0800083c, 0x08000780, 0x080007a8, 0x080007d0, 0x080007f8, - 0x08000654, 0x08000640, 0x08000864, 0x08000864, 0x08000670, 0x0800068c, - 0x0800068c, 0x08000864, 0x080006a4, 0x080006b8, 0x08000864, 0x080006cc, - 0x08000864, 0x08000864, 0x080006e0, 0x08000864, 0x08000864, 0x08000864, - 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864, - 0x08000864, 0x080006f4, 0x08000864, 0x08000708, 0x0800071c, 0x08000730, - 0x08000864, 0x08000744, 0x08000758, 0x0800076c, 0x08003200, 0x08003218, - 0x08003228, 0x08003238, 0x08003250, 0x08003268, 0x08003278, 0x08003288, - 0x080032a8, 0x080032b8, 0x080032c8, 0x08003358, 0x08003298, 0x080032d8, - 0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338, - 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc, - 0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 }; -static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 }; -static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 }; + 0x1f, 0x8b, 0x08, 0x08, 0x8e, 0xfc, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xbd, 0x7d, 0x0d, 0x74, + 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x79, 0x92, 0xc6, 0xb2, 0x2c, 0x3f, + 0xcb, 0x63, 0x65, 0x22, 0x0b, 0x7b, 0x46, 0x7a, 0xb2, 0x95, 0x58, 0x64, + 0xc7, 0xae, 0x00, 0x6d, 0x3b, 0x85, 0xe9, 0x48, 0xb2, 0x9d, 0x0f, 0x8a, + 0x4c, 0x44, 0x4f, 0x5a, 0xe8, 0x22, 0xc6, 0x76, 0x48, 0x80, 0xb2, 0x4e, + 0x09, 0x69, 0x80, 0x04, 0x0f, 0x23, 0xf9, 0x83, 0x74, 0xec, 0x51, 0x12, + 0xc5, 0x76, 0x4f, 0x73, 0x58, 0x55, 0x92, 0x1d, 0x43, 0xa7, 0x1e, 0x27, + 0x71, 0x68, 0xf6, 0x6c, 0x68, 0xb4, 0x4a, 0xe2, 0xa6, 0x3d, 0xd9, 0xd6, + 0xf4, 0x84, 0x6e, 0xda, 0x43, 0x77, 0x85, 0x71, 0x88, 0x4b, 0xb3, 0x4b, + 0xf8, 0x68, 0x61, 0xa1, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d, 0xd2, 0xe8, + 0xc3, 0x09, 0xa1, 0xbb, 0xf5, 0x39, 0xcf, 0x6f, 0xde, 0xfd, 0xfc, 0xdf, + 0xff, 0xfd, 0x7f, 0xdf, 0x0f, 0xad, 0x17, 0xa9, 0x17, 0xfb, 0x6f, 0x15, + 0x9e, 0x6d, 0x89, 0x7d, 0xbb, 0xb7, 0x5e, 0xd7, 0x73, 0x1d, 0x7e, 0x6e, + 0x75, 0x57, 0x46, 0x95, 0xbc, 0x89, 0x7f, 0x89, 0x9f, 0xa1, 0x4c, 0x44, + 0xc4, 0x0b, 0xfb, 0xe2, 0x23, 0x51, 0x95, 0x1e, 0xfc, 0x64, 0xd6, 0x97, + 0x68, 0x24, 0x7d, 0xf6, 0xb3, 0xbb, 0x7d, 0x91, 0x4c, 0x79, 0x4b, 0xa2, + 0x57, 0xfe, 0x25, 0xc8, 0xc7, 0x5c, 0x61, 0xfa, 0x5b, 0xd2, 0xff, 0xfc, + 0x9f, 0xbe, 0xf2, 0x8e, 0xe4, 0x6b, 0xe3, 0x11, 0x89, 0x7a, 0xe9, 0x8f, + 0x89, 0xb7, 0x49, 0xa2, 0xad, 0xe9, 0x81, 0x4f, 0x3e, 0xbc, 0xf9, 0x6f, + 0x44, 0x1a, 0xc3, 0xb6, 0x2e, 0x07, 0x5f, 0xd9, 0x2c, 0xf9, 0x96, 0x74, + 0x7c, 0xc8, 0x4d, 0x7b, 0xf2, 0x74, 0x45, 0x06, 0x0a, 0xc5, 0xa8, 0x44, + 0xd2, 0x1d, 0x2f, 0xf5, 0x46, 0xf6, 0x07, 0x11, 0xdf, 0xf7, 0x7a, 0xa5, + 0xa1, 0x27, 0xdb, 0x8d, 0xf4, 0xf2, 0x56, 0x51, 0x7e, 0x54, 0xb2, 0x15, + 0x69, 0x50, 0xbe, 0x8f, 0x77, 0xbd, 0xa8, 0x74, 0xd2, 0xcb, 0x46, 0x5c, + 0x29, 0x54, 0x2e, 0xac, 0x30, 0x6d, 0x96, 0xec, 0xfb, 0x6f, 0xa2, 0xe6, + 0x8d, 0x36, 0x4b, 0x51, 0x99, 0x8d, 0xc4, 0x05, 0xfd, 0x00, 0xe6, 0x06, + 0x19, 0x2e, 0x25, 0x24, 0x5b, 0x64, 0xbf, 0xae, 0xe4, 0x3c, 0xf6, 0xd9, + 0x80, 0xfa, 0x2b, 0x9d, 0xe5, 0xcb, 0xb3, 0xec, 0x4b, 0x28, 0x9b, 0x40, + 0xb9, 0x56, 0x79, 0xbc, 0x12, 0x97, 0xc7, 0x2a, 0x31, 0x79, 0xb4, 0x72, + 0x87, 0x64, 0x50, 0xf7, 0x6c, 0x05, 0x7d, 0x97, 0x6a, 0xa5, 0x77, 0xac, + 0x5e, 0xb2, 0x63, 0xed, 0xf1, 0x9c, 0x04, 0xc1, 0x27, 0x52, 0x1f, 0x95, + 0xa1, 0x26, 0x94, 0x2f, 0x31, 0x2f, 0xbe, 0x20, 0x2f, 0x97, 0xda, 0xe2, + 0xe5, 0x94, 0x23, 0x99, 0xc1, 0x64, 0x7c, 0x48, 0xf1, 0xbb, 0x46, 0xb2, + 0x5d, 0xf8, 0x1e, 0x70, 0x25, 0xe2, 0x07, 0xc1, 0x1d, 0xa9, 0x26, 0xc0, + 0x91, 0x4c, 0x24, 0x14, 0xeb, 0xb2, 0x5e, 0x32, 0x9f, 0x50, 0x51, 0xc9, + 0x57, 0xae, 0x93, 0x44, 0x53, 0x10, 0xbc, 0x37, 0xe5, 0x21, 0x5d, 0xa4, + 0xb7, 0x28, 0xfb, 0x54, 0xda, 0x47, 0x9b, 0x92, 0x52, 0xe9, 0xb5, 0x18, + 0xc7, 0x16, 0xe0, 0xa9, 0x56, 0x32, 0x31, 0xc9, 0xa8, 0xb4, 0x24, 0x54, + 0x7a, 0x05, 0xd2, 0x1c, 0xa9, 0xf1, 0xa7, 0x2c, 0x9d, 0xac, 0xc6, 0xb7, + 0x0c, 0xa8, 0x74, 0xd3, 0xa2, 0xf4, 0x64, 0x42, 0xd4, 0x8f, 0xea, 0xd0, + 0x67, 0x67, 0x46, 0x31, 0x0d, 0x6f, 0x9d, 0x76, 0xfd, 0x32, 0x69, 0x1f, + 0x74, 0x16, 0xa6, 0x3d, 0xb5, 0x8a, 0xb0, 0x8a, 0xe2, 0xef, 0x28, 0xe0, + 0x6a, 0x41, 0xff, 0xed, 0x5e, 0x0d, 0xc6, 0x35, 0x90, 0x4a, 0x7a, 0xfd, + 0xea, 0xc5, 0x40, 0x9a, 0x09, 0x33, 0xf3, 0x14, 0xf2, 0x50, 0x34, 0x9d, + 0xc2, 0xbc, 0xb9, 0x72, 0x08, 0x63, 0xbb, 0x38, 0x96, 0xf4, 0xda, 0x14, + 0xde, 0x53, 0xfc, 0xdd, 0x34, 0x14, 0x49, 0x07, 0x41, 0x36, 0x35, 0x2e, + 0xb9, 0x72, 0xd2, 0x9b, 0x05, 0x70, 0xbd, 0x63, 0x71, 0x8c, 0x1f, 0xe3, + 0x88, 0x65, 0x92, 0x6b, 0xa4, 0xcb, 0xce, 0xcf, 0x5f, 0xa2, 0xef, 0x76, + 0xef, 0x0e, 0xd5, 0xee, 0xa5, 0x54, 0xd2, 0x9b, 0x90, 0x3f, 0xc4, 0x77, + 0x10, 0xec, 0x4a, 0x25, 0xe3, 0x79, 0xcc, 0xdd, 0xa5, 0x62, 0x4c, 0x5e, + 0x2e, 0x26, 0x41, 0xa9, 0xc9, 0xce, 0x49, 0xd9, 0x92, 0x9a, 0x04, 0xdc, + 0x05, 0x3c, 0x07, 0x99, 0x57, 0x46, 0x5e, 0x99, 0x75, 0x83, 0xe0, 0xe6, + 0xd4, 0x89, 0x60, 0xa8, 0xd9, 0xd0, 0xfe, 0xd3, 0x25, 0xcc, 0x2b, 0xe6, + 0xe9, 0xb1, 0x12, 0xe6, 0xb5, 0x84, 0x39, 0xd5, 0xf3, 0xdf, 0x89, 0xf9, + 0x27, 0x8d, 0x90, 0x3e, 0xb6, 0x59, 0x7a, 0x7d, 0xb7, 0x7d, 0x8b, 0x64, + 0x4b, 0x8e, 0x64, 0x53, 0x3f, 0x09, 0x32, 0x9a, 0x27, 0xc4, 0xe9, 0x2d, + 0x91, 0x26, 0x6b, 0x00, 0x2b, 0x3f, 0x7f, 0xdd, 0x96, 0x8b, 0x3a, 0x18, + 0x06, 0xe7, 0x83, 0xf9, 0x51, 0xe5, 0xd7, 0xd9, 0xfc, 0x90, 0xf6, 0xf9, + 0x0f, 0x74, 0xe7, 0xcf, 0x97, 0xcb, 0x92, 0x36, 0x2b, 0x22, 0xb9, 0x07, + 0x03, 0xe9, 0x4d, 0x01, 0x5f, 0x6c, 0xd3, 0x4b, 0x89, 0xae, 0xeb, 0xb1, + 0x8c, 0x2e, 0x8b, 0x7f, 0x3f, 0xae, 0x41, 0x1f, 0x4e, 0x5f, 0x69, 0xbe, + 0x6e, 0x5f, 0xe9, 0x85, 0x98, 0x85, 0x0f, 0xdf, 0x3d, 0x4e, 0xb6, 0xf2, + 0x77, 0x76, 0x8e, 0xc3, 0x71, 0x74, 0x2d, 0x43, 0xe3, 0x2e, 0xf8, 0xc1, + 0x93, 0x5c, 0xb1, 0x07, 0xfd, 0xc6, 0xf0, 0x0e, 0x82, 0x91, 0x54, 0x26, + 0xe9, 0x4a, 0x1a, 0xdf, 0x03, 0x98, 0xaf, 0x0e, 0xe0, 0x4f, 0xdc, 0xec, + 0xe6, 0x94, 0xf4, 0x55, 0x40, 0x7b, 0x95, 0x37, 0x96, 0x14, 0x7a, 0x0c, + 0xa9, 0x7f, 0xb1, 0xb8, 0x61, 0x3f, 0x7c, 0xbb, 0x32, 0x02, 0xfa, 0x28, + 0x8c, 0xf9, 0x32, 0x5c, 0x9c, 0xf6, 0x94, 0x24, 0x41, 0xbb, 0x69, 0xe9, + 0xad, 0xf8, 0x52, 0x28, 0xe2, 0x5d, 0x6a, 0x07, 0xfd, 0xba, 0x92, 0x89, + 0x9b, 0x39, 0x29, 0x14, 0x7f, 0x09, 0xe3, 0x02, 0x8e, 0x7d, 0xfe, 0xee, + 0xb1, 0xb0, 0x80, 0xf7, 0xbb, 0x53, 0x1a, 0x3f, 0x6f, 0x0e, 0x06, 0xf6, + 0x8d, 0x31, 0x60, 0x9c, 0x85, 0xb2, 0x8b, 0x77, 0x0c, 0xef, 0x90, 0x16, + 0xe3, 0x80, 0xa9, 0x55, 0x86, 0x41, 0x8b, 0xbd, 0x82, 0xdf, 0x53, 0x84, + 0x91, 0xfd, 0xb6, 0xe8, 0xdf, 0xc3, 0x63, 0x1b, 0xf4, 0x77, 0x6e, 0xa0, + 0x45, 0xf2, 0x53, 0xe1, 0x58, 0x28, 0x0f, 0x28, 0x03, 0x92, 0x87, 0x45, + 0x28, 0x13, 0x82, 0xe0, 0xc1, 0x14, 0xe5, 0x42, 0x10, 0x3c, 0x96, 0xa2, + 0x9c, 0x38, 0x07, 0xfe, 0xa7, 0x6c, 0x20, 0xaf, 0xae, 0x55, 0x9c, 0x83, + 0x6c, 0x11, 0x7d, 0x40, 0x4e, 0xe4, 0xba, 0x4e, 0x40, 0x6e, 0x50, 0xae, + 0x5c, 0xf8, 0x44, 0xd6, 0xcf, 0xc7, 0x23, 0x1a, 0x0f, 0x98, 0x6f, 0xc8, + 0xbc, 0x8c, 0x86, 0xbc, 0x4d, 0x0a, 0x5d, 0xa3, 0xb6, 0xcc, 0x65, 0x5d, + 0xc6, 0x5d, 0x52, 0xe6, 0x76, 0x65, 0xf8, 0xae, 0x15, 0xf3, 0xb1, 0x42, + 0x11, 0x4f, 0x6d, 0x9b, 0xf8, 0x2d, 0xd1, 0x9a, 0xf4, 0x97, 0x90, 0x37, + 0x7d, 0xd7, 0x49, 0x7f, 0xb9, 0xbc, 0x59, 0x77, 0x69, 0xde, 0x88, 0xb8, + 0x7e, 0xb2, 0x73, 0x97, 0x9a, 0x01, 0x3d, 0x05, 0xc1, 0xc9, 0x54, 0x98, + 0xfe, 0x8f, 0xee, 0xd2, 0x3e, 0x12, 0x35, 0x4b, 0xd3, 0xee, 0x5d, 0x26, + 0xed, 0xc4, 0x32, 0x69, 0x1b, 0x6a, 0x97, 0xa6, 0xbd, 0x7f, 0x99, 0xb4, + 0xfb, 0x97, 0x49, 0xfb, 0x5f, 0xcb, 0xa4, 0x7d, 0x67, 0x99, 0xb4, 0xef, + 0x2d, 0x93, 0xd6, 0x52, 0xb7, 0x34, 0xcd, 0x05, 0x3f, 0x6d, 0x92, 0x42, + 0xec, 0x73, 0x1c, 0xbb, 0xc5, 0xcd, 0xfe, 0xc8, 0x52, 0xdc, 0xd4, 0xa0, + 0x5c, 0xeb, 0xa2, 0x72, 0x53, 0xcb, 0x94, 0xab, 0x45, 0xb9, 0xa6, 0x45, + 0xe5, 0x92, 0xcb, 0xe0, 0xba, 0x4e, 0xeb, 0xaf, 0x85, 0xe5, 0x0a, 0xcb, + 0x94, 0x63, 0xfa, 0x1e, 0xdb, 0xcf, 0x16, 0x68, 0x99, 0xd7, 0x9b, 0xaf, + 0x5a, 0x91, 0x66, 0xa6, 0xb7, 0x42, 0x47, 0xac, 0x50, 0x86, 0xdf, 0x29, + 0x5b, 0x98, 0xe6, 0x81, 0xee, 0xa3, 0xa0, 0x3b, 0xca, 0x47, 0xf0, 0x91, + 0x4f, 0xfe, 0x5d, 0x25, 0x43, 0xb1, 0x2d, 0xde, 0x2f, 0xa8, 0x06, 0xd0, + 0x58, 0xd2, 0x4b, 0x28, 0xf2, 0x97, 0xe4, 0x23, 0x69, 0x3f, 0xdf, 0x2b, + 0x2a, 0xa6, 0x24, 0x90, 0xbe, 0x94, 0x6a, 0x52, 0xb2, 0x1f, 0xfc, 0x93, + 0x81, 0x4e, 0xda, 0x15, 0xf4, 0x6a, 0x1e, 0x32, 0x65, 0xaf, 0x2c, 0x2b, + 0x7d, 0x39, 0x48, 0x19, 0x97, 0xce, 0xdc, 0x95, 0xf5, 0xa7, 0x7b, 0x6a, + 0x41, 0xb3, 0x17, 0x51, 0x67, 0x07, 0x6a, 0xee, 0x2d, 0xbb, 0xd2, 0x57, + 0xee, 0x04, 0x2f, 0x38, 0x72, 0xde, 0x5f, 0x2d, 0xe7, 0x53, 0x28, 0x5b, + 0x89, 0xc8, 0x4c, 0xcc, 0x91, 0x19, 0x7c, 0x67, 0x53, 0xc8, 0xab, 0x84, + 0xbc, 0xd5, 0x29, 0x07, 0x4a, 0xbe, 0x1c, 0x2e, 0xfd, 0x92, 0x0a, 0xf5, + 0x56, 0x7f, 0x6a, 0xa5, 0x9c, 0xf6, 0x4c, 0xdb, 0x3b, 0xfc, 0x69, 0x68, + 0x4c, 0x57, 0x2e, 0xfa, 0xc9, 0xf8, 0x8c, 0xe6, 0x89, 0x1f, 0x06, 0x7d, + 0x68, 0x67, 0xc2, 0x4f, 0x7a, 0x7f, 0x8a, 0xef, 0xa1, 0x32, 0xed, 0x90, + 0xf9, 0xb6, 0x86, 0xd1, 0xd6, 0xa1, 0xd2, 0x2a, 0xf9, 0xb0, 0xad, 0xbf, + 0xdd, 0x9f, 0xee, 0x04, 0xcf, 0x79, 0xa7, 0x28, 0x23, 0x8a, 0x80, 0x6b, + 0x10, 0xbc, 0x8d, 0xba, 0xcf, 0x69, 0x39, 0x05, 0xbb, 0xa5, 0xb8, 0x1a, + 0x72, 0xf7, 0x1f, 0x83, 0x0f, 0xc7, 0x58, 0x9e, 0x69, 0xd4, 0x25, 0x32, + 0xaa, 0xd2, 0x90, 0x09, 0xdd, 0x94, 0x85, 0x09, 0xc8, 0x41, 0xc8, 0x96, + 0xd2, 0x4f, 0x83, 0x8c, 0x5b, 0x2d, 0xdf, 0x24, 0x3f, 0x5f, 0x86, 0x69, + 0x09, 0x23, 0x2f, 0x4b, 0xb3, 0x73, 0xb2, 0x22, 0x0f, 0xf9, 0xf2, 0x74, + 0x85, 0x72, 0xe1, 0x7a, 0xf0, 0x68, 0xab, 0xf4, 0x15, 0x93, 0xf9, 0x8c, + 0x6c, 0xc2, 0xfc, 0x7d, 0x1e, 0x73, 0xea, 0xe2, 0xb9, 0xaf, 0x5e, 0x1a, + 0x53, 0xd0, 0xcd, 0x4c, 0x47, 0xa3, 0xcd, 0x51, 0xc8, 0xa8, 0xdf, 0x03, + 0x1e, 0x86, 0x39, 0xe7, 0xf1, 0x6c, 0xc4, 0x19, 0xa0, 0x3d, 0x32, 0x40, + 0xfd, 0x50, 0x66, 0xdb, 0x84, 0x37, 0x6e, 0x7f, 0x47, 0xb5, 0x8c, 0x31, + 0xbf, 0x1b, 0xf0, 0x3b, 0x61, 0x7f, 0x7b, 0xf8, 0xed, 0xdb, 0xdf, 0x31, + 0xfc, 0xee, 0xb4, 0xbf, 0xa1, 0x5b, 0x8b, 0x5d, 0xfa, 0xf7, 0x48, 0x69, + 0xfb, 0x76, 0xe5, 0x5f, 0x27, 0xb9, 0xa9, 0x56, 0x39, 0x50, 0xf4, 0xad, + 0x6c, 0xc1, 0x23, 0x4f, 0x3a, 0x66, 0x9c, 0x80, 0x9b, 0xb2, 0xb3, 0x94, + 0x77, 0x06, 0x08, 0x3f, 0x68, 0xa0, 0xb7, 0xb8, 0xc5, 0x5b, 0x23, 0xa4, + 0x81, 0x11, 0xa7, 0xb7, 0xe2, 0x64, 0x60, 0xaf, 0xc5, 0x87, 0xe5, 0x30, + 0x7e, 0x8b, 0x17, 0x49, 0x3f, 0x89, 0xb7, 0xc1, 0x01, 0xf5, 0xce, 0x70, + 0x89, 0xf2, 0xd2, 0xc7, 0xd8, 0x13, 0x72, 0x6e, 0x81, 0x0d, 0x45, 0x5c, + 0x28, 0xc9, 0x8d, 0x25, 0x4f, 0xe4, 0x25, 0x99, 0x1f, 0x07, 0x43, 0xec, + 0x4a, 0xb9, 0xf2, 0xde, 0x14, 0x68, 0xf7, 0x3a, 0x47, 0xb6, 0x5f, 0xe7, + 0xc2, 0xe6, 0xf1, 0xc7, 0xb7, 0x83, 0xfe, 0x31, 0xcf, 0x9a, 0x1e, 0xd4, + 0x19, 0x81, 0x9d, 0x08, 0x6c, 0x9f, 0xe9, 0xea, 0x1b, 0x2e, 0xe6, 0x3e, + 0xa6, 0xd2, 0xfb, 0x3e, 0x95, 0xed, 0xbe, 0x46, 0x72, 0x83, 0x0a, 0x38, + 0x6a, 0x1e, 0x82, 0x1e, 0xc4, 0xb8, 0x82, 0x00, 0xf4, 0x0c, 0x79, 0x7e, + 0xf3, 0xcd, 0x91, 0x74, 0x8d, 0xf4, 0x0e, 0x36, 0xa3, 0x0e, 0xf3, 0x88, + 0xaf, 0xaf, 0xa2, 0x9d, 0x64, 0xa2, 0x4f, 0xe4, 0x9e, 0x91, 0xee, 0x59, + 0x67, 0x78, 0xf4, 0x37, 0xc0, 0x93, 0x5b, 0x51, 0xff, 0x01, 0xd4, 0x7f, + 0xcd, 0x29, 0x8c, 0xfd, 0xc8, 0x19, 0x1e, 0xfb, 0x9e, 0x33, 0x32, 0xb6, + 0x61, 0x43, 0x7f, 0xcf, 0x86, 0x0d, 0xbb, 0x7b, 0x5c, 0x99, 0x00, 0x8f, + 0x65, 0xbc, 0x0d, 0x1b, 0x46, 0x7a, 0xba, 0x80, 0x83, 0x2d, 0x5e, 0x9f, + 0xf8, 0xde, 0x76, 0x01, 0xff, 0xc4, 0xd8, 0x67, 0x14, 0xf9, 0x49, 0xe4, + 0xb3, 0x7e, 0x5c, 0xe7, 0xf7, 0xca, 0x96, 0x78, 0x93, 0xb0, 0xff, 0x88, + 0x2d, 0x53, 0x13, 0x91, 0xfa, 0x07, 0xec, 0xfc, 0x66, 0x9c, 0x1a, 0x9f, + 0xe9, 0x1c, 0x0b, 0xd3, 0x39, 0xb7, 0x7f, 0x67, 0x6d, 0xd5, 0xd5, 0x48, + 0xe7, 0x37, 0x71, 0x46, 0xbc, 0xd0, 0xc6, 0xa8, 0xd1, 0xb6, 0x61, 0xae, + 0x48, 0x9a, 0x71, 0x65, 0x4f, 0xd1, 0x41, 0x1d, 0xd0, 0xc5, 0x19, 0xfb, + 0x1c, 0x05, 0x6c, 0x83, 0x68, 0xeb, 0xe8, 0x21, 0xd4, 0xa3, 0xcc, 0x48, + 0x76, 0x8a, 0xfa, 0x00, 0xca, 0x6c, 0xf1, 0xd6, 0x0a, 0x6d, 0x89, 0x3b, + 0x25, 0x57, 0x22, 0x7f, 0x77, 0x00, 0x9e, 0xa8, 0x24, 0x9a, 0xf1, 0x5d, + 0x81, 0x4d, 0xf1, 0x60, 0x8d, 0x58, 0xdb, 0x45, 0xe6, 0x6d, 0x91, 0x3b, + 0x94, 0xc0, 0xde, 0x18, 0x9a, 0x5c, 0x8f, 0x72, 0x0e, 0xf0, 0x42, 0xfb, + 0x03, 0xb4, 0x36, 0x99, 0x91, 0xec, 0x26, 0xf0, 0xc9, 0xa4, 0x87, 0x6f, + 0xc0, 0x35, 0xf9, 0x16, 0xbc, 0x23, 0xfa, 0xdb, 0xc0, 0x09, 0xbc, 0xa6, + 0x22, 0x56, 0x67, 0x75, 0xa1, 0xef, 0xf7, 0x48, 0x76, 0x34, 0x4e, 0x5b, + 0x62, 0x75, 0xd6, 0xcf, 0x40, 0xd7, 0x2b, 0x28, 0x41, 0x8c, 0x61, 0xd2, + 0x81, 0x3c, 0xa9, 0x95, 0xdd, 0x8f, 0xe0, 0xf7, 0x83, 0xc6, 0xe6, 0xdd, + 0x3d, 0xc9, 0x7e, 0x1a, 0x00, 0x13, 0x6c, 0x90, 0x47, 0x60, 0x9b, 0x3e, + 0x02, 0x1b, 0xe4, 0x91, 0x66, 0x3c, 0x1c, 0x1b, 0xdb, 0x9f, 0x59, 0x03, + 0x31, 0xa9, 0xbf, 0x73, 0xa4, 0x57, 0xd8, 0xea, 0xb9, 0x62, 0xca, 0x94, + 0x2f, 0x76, 0xeb, 0xb7, 0xa1, 0xeb, 0x1e, 0xfb, 0x3b, 0xae, 0xf9, 0x3a, + 0xdf, 0x04, 0x9a, 0xaf, 0x74, 0x69, 0x99, 0x93, 0xf5, 0xf1, 0x86, 0xcd, + 0x99, 0x69, 0xe2, 0x18, 0xe3, 0x36, 0x2d, 0xae, 0xd3, 0x12, 0x4d, 0xd6, + 0xde, 0x28, 0x59, 0x5b, 0x03, 0xb8, 0x19, 0x6a, 0x06, 0xc4, 0x94, 0xcf, + 0x12, 0xe2, 0x93, 0x32, 0x00, 0xf4, 0x0b, 0x9b, 0xe2, 0xdc, 0x15, 0xe5, + 0xdf, 0xac, 0xb6, 0xb1, 0xce, 0x56, 0x48, 0xc7, 0xa4, 0xed, 0x20, 0xb8, + 0x3f, 0x55, 0x87, 0xf6, 0xc9, 0xf3, 0xb0, 0x40, 0x8e, 0x02, 0x26, 0x60, + 0xa2, 0xc6, 0x3f, 0xab, 0x69, 0xa0, 0xd6, 0x27, 0x0d, 0x57, 0xf3, 0x97, + 0xe8, 0xf1, 0x9e, 0x05, 0x8f, 0xc1, 0xbe, 0x81, 0xfd, 0xd6, 0x01, 0xdb, + 0x98, 0x7d, 0x1c, 0xe6, 0xb7, 0xa7, 0xc0, 0x53, 0xd9, 0x39, 0x9e, 0x12, + 0x99, 0x28, 0x12, 0x37, 0xa1, 0x5d, 0xc7, 0x79, 0x26, 0x7e, 0x32, 0x18, + 0x33, 0xdf, 0x7d, 0x16, 0x4f, 0x3b, 0x2d, 0x9e, 0x6e, 0xb2, 0xef, 0x11, + 0xbc, 0x69, 0xe3, 0x0d, 0xe0, 0xcd, 0xf9, 0x19, 0xc4, 0x9b, 0xbc, 0x75, + 0x0b, 0xde, 0x28, 0x5b, 0xca, 0xc8, 0x6e, 0x6d, 0x87, 0x45, 0xe4, 0x57, + 0xb4, 0x6c, 0xfb, 0x02, 0xe6, 0xb2, 0x48, 0xfa, 0x95, 0x7c, 0x2c, 0x02, + 0x9c, 0x14, 0xf0, 0xfb, 0x4e, 0xd7, 0xd0, 0x2a, 0x71, 0xb2, 0xc0, 0x57, + 0xaa, 0x82, 0x29, 0x66, 0xe5, 0x5c, 0x42, 0xdb, 0xfa, 0xb9, 0xe2, 0x07, + 0x34, 0x5c, 0xb7, 0x42, 0xde, 0xe5, 0x45, 0x35, 0x43, 0x37, 0x80, 0x16, + 0x54, 0x0c, 0x9a, 0x2b, 0x78, 0x06, 0x7a, 0x29, 0x37, 0x49, 0xdb, 0xb8, + 0x8d, 0x7e, 0x49, 0x34, 0xd7, 0xd5, 0x48, 0x3a, 0x52, 0x0a, 0xf6, 0x17, + 0xbe, 0x55, 0xae, 0x4b, 0xd3, 0xa9, 0xa3, 0xfc, 0x98, 0xb6, 0x7f, 0x5d, + 0x1f, 0xd2, 0xd6, 0xf8, 0xbd, 0xae, 0xf2, 0xd7, 0x2e, 0x4e, 0x4b, 0x50, + 0x0f, 0xa3, 0x5e, 0x22, 0xd7, 0xd5, 0x4c, 0x1e, 0xf3, 0x40, 0xbf, 0x19, + 0xe5, 0x6b, 0xdf, 0x27, 0xaf, 0xba, 0x57, 0x2f, 0x2a, 0xaf, 0xdf, 0x8e, + 0xfd, 0x76, 0xed, 0xdb, 0xb3, 0xef, 0x84, 0x7d, 0xe7, 0xdd, 0x6e, 0xbe, + 0x1d, 0x71, 0xd3, 0x7c, 0x83, 0x92, 0xd3, 0x6c, 0x43, 0xf3, 0x95, 0x95, + 0x33, 0x1d, 0x5e, 0x41, 0xc8, 0x57, 0x9f, 0x93, 0x5b, 0x27, 0x8d, 0xfc, + 0xdd, 0x0e, 0x19, 0x04, 0xff, 0xcc, 0x9b, 0x11, 0xc0, 0x3f, 0x98, 0x96, + 0x5b, 0x2b, 0xc4, 0xdb, 0xef, 0x02, 0x7f, 0x60, 0xe2, 0x7a, 0xea, 0x74, + 0xca, 0xdd, 0x3b, 0x61, 0xf7, 0xa2, 0x7c, 0x91, 0x38, 0x1f, 0xd2, 0x73, + 0x53, 0x28, 0xee, 0xd1, 0x73, 0x73, 0xb0, 0x38, 0x03, 0xfc, 0xdc, 0x06, + 0xba, 0x0f, 0x82, 0x99, 0x54, 0x01, 0x94, 0xf3, 0x11, 0xfc, 0x86, 0x1d, + 0x50, 0xfc, 0x18, 0xf2, 0x1b, 0xa5, 0x30, 0x4a, 0x9e, 0x73, 0x2d, 0x0f, + 0xbf, 0x13, 0xfc, 0x14, 0x45, 0xbb, 0x48, 0xeb, 0xe6, 0xef, 0x9f, 0x20, + 0x0f, 0xef, 0x49, 0x4c, 0x62, 0x33, 0x6d, 0x1d, 0xf6, 0xcd, 0xb9, 0xe3, + 0x9c, 0xc5, 0xb4, 0x2c, 0x3f, 0x3b, 0x37, 0x6f, 0x97, 0xe7, 0xe8, 0x36, + 0x4f, 0x1f, 0x8f, 0xf9, 0x1a, 0x56, 0xd2, 0xfd, 0xb7, 0xb4, 0x5c, 0x72, + 0x8f, 0xce, 0xac, 0x30, 0xef, 0xc5, 0x75, 0x39, 0xe7, 0xd5, 0x34, 0x48, + 0xbf, 0x25, 0xd9, 0x93, 0x07, 0x3f, 0x61, 0x9c, 0xd2, 0xa7, 0x7d, 0x1d, + 0xd2, 0x04, 0x69, 0x60, 0xdc, 0xd2, 0xe6, 0x94, 0xa5, 0xcd, 0x27, 0xf1, + 0xc6, 0x53, 0xba, 0x60, 0x69, 0xf3, 0x29, 0xbc, 0xf1, 0x94, 0x5e, 0x9c, + 0xe3, 0xe3, 0x5e, 0xf8, 0x72, 0xdb, 0xa1, 0xdf, 0x76, 0x57, 0x40, 0xbf, + 0xe0, 0xbb, 0x1c, 0x7c, 0x80, 0x5c, 0x69, 0x1f, 0xde, 0xec, 0x67, 0xa3, + 0x6d, 0x3f, 0x23, 0x7b, 0x4a, 0x01, 0xc6, 0x78, 0x37, 0xc6, 0xfb, 0x39, + 0xbc, 0x3f, 0xa3, 0xe5, 0x8c, 0xf2, 0x0f, 0x5b, 0x79, 0xf5, 0x79, 0xbc, + 0xdb, 0xe3, 0x07, 0xa5, 0xdd, 0x8b, 0xc8, 0x34, 0xda, 0xfa, 0xba, 0xec, + 0xa9, 0xcc, 0xe2, 0xb9, 0x84, 0xe7, 0x55, 0x3c, 0x97, 0xd1, 0xde, 0x0b, + 0x48, 0x5f, 0x29, 0xd3, 0x5e, 0x3d, 0xca, 0xbf, 0x86, 0xdf, 0xcf, 0xcb, + 0xd0, 0x23, 0x2f, 0xe1, 0xf9, 0x01, 0xf2, 0x9f, 0x45, 0xfd, 0x60, 0xf5, + 0x8c, 0x4f, 0x19, 0xf6, 0x9c, 0x6d, 0x3b, 0xe5, 0xe4, 0x2a, 0xa0, 0xe9, + 0xd2, 0x00, 0xfa, 0xde, 0xa3, 0x79, 0xa6, 0x0f, 0x32, 0x3f, 0x07, 0x19, + 0x37, 0xa4, 0x61, 0x6a, 0x07, 0x7c, 0x79, 0xcc, 0x05, 0xde, 0x93, 0xb5, + 0x32, 0x1b, 0xa3, 0x1d, 0x79, 0x93, 0x2e, 0x9f, 0x2b, 0x35, 0x69, 0xbb, + 0x7a, 0x7c, 0x09, 0xff, 0xd0, 0xef, 0x0a, 0xe5, 0x81, 0x91, 0xc6, 0x13, + 0x45, 0xca, 0x02, 0xe8, 0x9f, 0xe2, 0x08, 0xde, 0xb5, 0x5a, 0x26, 0x14, + 0x24, 0x94, 0x07, 0xac, 0x47, 0x99, 0x50, 0x2d, 0x77, 0x28, 0x6b, 0x28, + 0x7b, 0x28, 0x4b, 0xcc, 0x7c, 0xec, 0x7e, 0x90, 0x32, 0x1c, 0xb4, 0x10, + 0xa3, 0xfd, 0xe1, 0x19, 0x1f, 0x64, 0xec, 0x3e, 0x2b, 0x4f, 0x47, 0xf5, + 0x5c, 0xec, 0x29, 0xaa, 0x98, 0x2b, 0xa7, 0x91, 0x86, 0xe7, 0xf8, 0xc3, + 0x78, 0x7f, 0x49, 0xf6, 0xe0, 0xc9, 0x1d, 0xff, 0x02, 0x7e, 0x73, 0x6e, + 0xca, 0x28, 0x87, 0xa7, 0x74, 0x02, 0x6f, 0x3c, 0xa5, 0x31, 0x2b, 0x47, + 0xc6, 0xad, 0x1c, 0xe1, 0x9c, 0xde, 0x04, 0x3c, 0x70, 0x7c, 0x4a, 0xc7, + 0x17, 0xc0, 0xcf, 0x4e, 0x6e, 0xf2, 0x5d, 0xd6, 0x8f, 0x6d, 0x14, 0xc3, + 0x83, 0x78, 0x3a, 0xc9, 0xcf, 0x0d, 0xda, 0x0e, 0xce, 0x69, 0xda, 0xfd, + 0x2b, 0xd7, 0xf0, 0x62, 0xcc, 0xe8, 0x14, 0xaf, 0x59, 0x34, 0xef, 0xcf, + 0xe1, 0x31, 0x63, 0xf1, 0xc8, 0xdf, 0xca, 0xfe, 0x86, 0xdc, 0x82, 0x4d, + 0x9b, 0xf5, 0x7d, 0xcc, 0x03, 0xc6, 0x72, 0x7c, 0x14, 0x7d, 0x3b, 0xb2, + 0xdb, 0xa7, 0x0c, 0x67, 0x0c, 0x81, 0xe3, 0x63, 0xbb, 0x48, 0xd7, 0x38, + 0x48, 0xc9, 0xbc, 0x6f, 0x7e, 0x13, 0xe6, 0x2c, 0x23, 0x7b, 0x4b, 0xf7, + 0x6a, 0x5f, 0xb9, 0xf6, 0x68, 0x93, 0xf5, 0x73, 0xc2, 0x72, 0xa0, 0xd5, + 0x18, 0x6d, 0x9b, 0x2f, 0xc5, 0x0c, 0xcd, 0xf3, 0x37, 0xe5, 0x73, 0xb5, + 0xbc, 0x37, 0x76, 0x4d, 0x61, 0x81, 0xac, 0xa3, 0x6d, 0x81, 0x39, 0x2b, + 0x57, 0xe3, 0x9d, 0xbe, 0x3b, 0xf9, 0x8a, 0xfc, 0x74, 0x10, 0x3c, 0xf1, + 0x5d, 0xcb, 0xfb, 0xf4, 0x35, 0xd8, 0xe7, 0x62, 0x7e, 0xf2, 0x60, 0xfb, + 0xba, 0x72, 0x0a, 0xb6, 0xdb, 0xf6, 0xb9, 0x36, 0xae, 0x06, 0x3c, 0x51, + 0x79, 0xa4, 0xd8, 0x20, 0x93, 0x45, 0xd5, 0x1c, 0xb1, 0xb2, 0x33, 0x22, + 0x09, 0x4d, 0xdf, 0xb4, 0xef, 0x7a, 0xc7, 0x22, 0x96, 0xee, 0xd6, 0xd5, + 0x48, 0xfd, 0xef, 0x42, 0xc7, 0xa6, 0xa1, 0x63, 0x1b, 0xa1, 0x83, 0x17, + 0xcb, 0x88, 0x35, 0x35, 0x4b, 0x65, 0x04, 0xeb, 0x24, 0xe1, 0x75, 0x1f, + 0x44, 0xbd, 0x90, 0xfe, 0xa2, 0x9a, 0xd6, 0x72, 0x92, 0x77, 0xb6, 0x57, + 0x46, 0x9c, 0x1d, 0x95, 0xc5, 0x3a, 0x68, 0x8b, 0xe7, 0x8a, 0x81, 0xf5, + 0x91, 0x22, 0x6d, 0xd4, 0x64, 0x2a, 0x0b, 0x9c, 0xec, 0x00, 0xcc, 0xcf, + 0x8c, 0xc2, 0x4f, 0xa7, 0x5c, 0x06, 0xcc, 0xa7, 0x01, 0xf3, 0xc4, 0xa8, + 0x13, 0xda, 0x06, 0xc2, 0xa0, 0xc8, 0xc4, 0x58, 0x97, 0xcc, 0x4c, 0x91, + 0x0e, 0x21, 0x03, 0x46, 0x31, 0x9f, 0xa9, 0x15, 0xb0, 0x03, 0xd8, 0x3f, + 0xe4, 0xf6, 0x58, 0x8b, 0xce, 0x33, 0xfa, 0xbc, 0x55, 0x66, 0xca, 0x69, + 0x0b, 0xdb, 0xe1, 0x2a, 0xd8, 0x56, 0xcc, 0xc1, 0xb6, 0x03, 0xb0, 0xed, + 0x5c, 0x16, 0xb6, 0xe5, 0x74, 0x71, 0x1b, 0x6c, 0x1a, 0xa3, 0x8b, 0x0d, + 0x5e, 0x9b, 0x2d, 0x3d, 0xbc, 0xdf, 0xda, 0xbb, 0xb4, 0x89, 0x7e, 0x0a, + 0x78, 0x48, 0x63, 0xf8, 0x3d, 0x79, 0x2f, 0x65, 0x19, 0xd2, 0xf9, 0xbd, + 0x07, 0x65, 0xf0, 0x3d, 0xf9, 0x67, 0x2b, 0x4c, 0xd9, 0xbb, 0x2d, 0x2c, + 0xb4, 0x13, 0x32, 0xb0, 0x89, 0xfb, 0x9c, 0xec, 0x24, 0x61, 0xf8, 0x8f, + 0x80, 0x17, 0x79, 0x95, 0xea, 0x36, 0xf9, 0x66, 0xbb, 0xd7, 0xda, 0x76, + 0xd8, 0x76, 0x38, 0x96, 0x95, 0x56, 0xcf, 0x87, 0xf4, 0x15, 0xda, 0xd7, + 0x23, 0x4e, 0x66, 0xc9, 0xb8, 0xaa, 0x69, 0x8e, 0xf2, 0xd6, 0x95, 0x7e, + 0xd0, 0x49, 0xff, 0x02, 0x5a, 0x33, 0x72, 0xc3, 0xd0, 0xf1, 0x0a, 0x3b, + 0xbe, 0x1a, 0xc3, 0x37, 0xa9, 0x28, 0xf4, 0x21, 0xe5, 0xcd, 0x0e, 0xe3, + 0x9b, 0xcb, 0x43, 0x80, 0x35, 0xfc, 0x3e, 0xa8, 0x6d, 0xce, 0xa7, 0x4b, + 0x94, 0x49, 0xf3, 0xb4, 0x68, 0x7c, 0x97, 0x56, 0xf4, 0x55, 0x6d, 0xaf, + 0xbb, 0x32, 0x60, 0xe6, 0xfc, 0x30, 0xe7, 0x9c, 0xbe, 0x48, 0xfb, 0x03, + 0x03, 0x96, 0xbf, 0x92, 0xa3, 0x79, 0x79, 0xbb, 0x1d, 0xfb, 0x1f, 0x2e, + 0x33, 0x77, 0x8d, 0x73, 0x73, 0x37, 0x50, 0x59, 0x3c, 0x46, 0x91, 0xb6, + 0x07, 0x58, 0xcf, 0x85, 0x8d, 0x94, 0x92, 0x5a, 0x9f, 0xf2, 0x93, 0xb6, + 0x12, 0xd2, 0x27, 0xb6, 0x78, 0x4d, 0xf0, 0x01, 0x9e, 0x5e, 0x62, 0x77, + 0x25, 0xac, 0xdc, 0xa4, 0x1f, 0x1c, 0xf6, 0x91, 0xb7, 0x72, 0x32, 0x8f, + 0xf6, 0x47, 0x9c, 0xfe, 0xca, 0x72, 0xf2, 0x32, 0x94, 0x93, 0x1c, 0x8f, + 0x23, 0x77, 0x3c, 0x48, 0x1e, 0x7d, 0xbf, 0xb6, 0xaf, 0xb7, 0x6e, 0xab, + 0x01, 0xfe, 0x08, 0xc7, 0xcc, 0x1a, 0xa2, 0x33, 0xf7, 0x08, 0x6c, 0x22, + 0x3b, 0x6f, 0xbb, 0xe7, 0xe6, 0x5f, 0xd3, 0x05, 0x7e, 0x33, 0x8e, 0x6a, + 0x68, 0xa4, 0xc6, 0x77, 0x34, 0x2d, 0xd4, 0x2e, 0xb1, 0x65, 0x39, 0x06, + 0xda, 0xb3, 0xb5, 0xc6, 0x16, 0x2c, 0xd1, 0xfe, 0xa4, 0xec, 0xa2, 0xfd, + 0xf9, 0x43, 0xe0, 0x88, 0xe3, 0xe9, 0xb2, 0x69, 0xb4, 0x53, 0x17, 0x8f, + 0x6f, 0xb1, 0xff, 0x48, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x84, 0x22, 0x6c, + 0x81, 0x0c, 0x80, 0x97, 0x39, 0x07, 0x8a, 0xb6, 0xeb, 0xb6, 0xbf, 0xa8, + 0x31, 0x31, 0xe4, 0xd5, 0xb5, 0x52, 0xcf, 0x3e, 0xc9, 0x7f, 0x7c, 0xaf, + 0xd2, 0xf6, 0xef, 0x52, 0x59, 0x56, 0xad, 0x7b, 0xae, 0x9e, 0xc3, 0x5f, + 0xff, 0x82, 0x39, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x35, 0x0e, 0x49, 0x13, + 0x86, 0x16, 0x0c, 0x2d, 0x6e, 0xb4, 0xfa, 0x26, 0xa4, 0xbd, 0xab, 0x40, + 0x7b, 0xf7, 0x81, 0xc6, 0x28, 0xc3, 0x19, 0x97, 0x5b, 0x8b, 0xef, 0x23, + 0xf8, 0x0e, 0xf9, 0xe4, 0x4a, 0x32, 0x9c, 0xf2, 0x9b, 0x75, 0xb2, 0x56, + 0xee, 0x87, 0x7e, 0x2e, 0xeb, 0x70, 0xdc, 0x94, 0xff, 0xff, 0x15, 0xed, + 0xac, 0xad, 0x35, 0xf6, 0xca, 0x8d, 0xb5, 0x94, 0xaf, 0x6b, 0xe4, 0x60, + 0x55, 0xda, 0x95, 0xe4, 0x77, 0xf5, 0x98, 0xd7, 0xff, 0x3f, 0x18, 0x73, + 0x7c, 0xd1, 0x98, 0x3d, 0x3b, 0xe6, 0x77, 0x21, 0xbf, 0xc9, 0xf8, 0x38, + 0x1e, 0xf9, 0x2e, 0x1c, 0xb3, 0xc5, 0x85, 0x1e, 0x57, 0xb5, 0x9c, 0x08, + 0x65, 0x04, 0xc7, 0x35, 0x60, 0xc7, 0xf0, 0xb9, 0xaa, 0x71, 0x0d, 0xbc, + 0x89, 0x71, 0xb5, 0x2e, 0x18, 0xd7, 0xf6, 0x2b, 0x8e, 0x6b, 0x39, 0x1e, + 0x27, 0x2f, 0x87, 0xe3, 0x8b, 0xca, 0xae, 0x22, 0xc7, 0xd8, 0x8f, 0x31, + 0x1e, 0xd4, 0xfe, 0x80, 0x19, 0x63, 0xda, 0x8e, 0x51, 0x54, 0xdb, 0xb6, + 0x7f, 0x8f, 0xdf, 0xd5, 0xe3, 0xa3, 0xee, 0xff, 0x3e, 0x68, 0xba, 0x4e, + 0xb2, 0x5d, 0x75, 0x56, 0xfe, 0xdf, 0x24, 0x1f, 0x2e, 0x71, 0xae, 0x93, + 0x19, 0x91, 0x51, 0xe8, 0xe0, 0xff, 0x5c, 0xcb, 0xd8, 0xfd, 0xf6, 0x94, + 0xd5, 0x63, 0xd0, 0x17, 0x3b, 0x60, 0xf3, 0xf5, 0x17, 0x55, 0x77, 0x44, + 0x82, 0xe0, 0xb6, 0xd4, 0xa7, 0xd1, 0xf7, 0x7e, 0xed, 0xab, 0x2e, 0x8d, + 0x9b, 0x3f, 0x57, 0x2b, 0x3e, 0xed, 0x0d, 0xea, 0x73, 0xe8, 0xbb, 0xe3, + 0xb4, 0xc1, 0xb2, 0xb0, 0x93, 0x33, 0xf1, 0x88, 0xb6, 0xc5, 0xa8, 0x13, + 0x93, 0xf1, 0x8c, 0xa4, 0xd1, 0x5f, 0x26, 0xae, 0x84, 0x7d, 0xc0, 0x56, + 0x83, 0x0d, 0xf9, 0xe1, 0xca, 0x3e, 0x3c, 0x0f, 0xcb, 0xad, 0xb0, 0x77, + 0x6e, 0x7d, 0xe4, 0x0b, 0x72, 0x1b, 0x6c, 0x9d, 0xdb, 0x1e, 0x19, 0x93, + 0xbd, 0xb0, 0x6d, 0xf6, 0xc2, 0xce, 0xd9, 0x5b, 0xa1, 0xed, 0x39, 0x8e, + 0xb2, 0xad, 0x55, 0xb4, 0x46, 0x1b, 0x87, 0xe3, 0x23, 0xee, 0x0f, 0x72, + 0x0e, 0x52, 0x09, 0xf5, 0x8a, 0x9e, 0x97, 0xa6, 0x05, 0x69, 0xaf, 0x27, + 0xab, 0x42, 0xfd, 0xb4, 0xca, 0xc6, 0x8d, 0x8c, 0x0d, 0x78, 0x65, 0xda, + 0x22, 0x8d, 0x78, 0xc0, 0x33, 0xf1, 0x47, 0xda, 0xaa, 0x1e, 0x7f, 0x63, + 0x9d, 0xf8, 0x2b, 0xeb, 0xa4, 0xfe, 0x73, 0x90, 0xaf, 0xd5, 0x34, 0xc5, + 0xb7, 0x67, 0x75, 0x0d, 0x69, 0x8b, 0x32, 0x38, 0xa4, 0x87, 0x8d, 0xaf, + 0x23, 0x7f, 0xaf, 0x48, 0x4f, 0xfb, 0xb9, 0x2e, 0xb3, 0xbb, 0x5b, 0x56, + 0x33, 0x1e, 0x90, 0xad, 0xcc, 0xc7, 0x04, 0x94, 0x5f, 0x1d, 0x13, 0xa0, + 0x9f, 0xf5, 0x01, 0xe0, 0xec, 0x16, 0x3c, 0xfb, 0x64, 0x88, 0x71, 0x87, + 0x4a, 0x68, 0x97, 0x7f, 0xd5, 0xda, 0xe5, 0x21, 0x1c, 0x09, 0xc0, 0x61, + 0xe4, 0xf3, 0x52, 0x3d, 0xb7, 0x50, 0x7f, 0xe7, 0xe7, 0x6c, 0xda, 0x84, + 0xec, 0x2a, 0x71, 0xdc, 0x94, 0xc1, 0xc4, 0x4d, 0xb5, 0x0c, 0x8e, 0x5b, + 0x3b, 0x0a, 0x65, 0xb4, 0xfc, 0x5c, 0x2a, 0x3b, 0x29, 0xf7, 0x18, 0x9f, + 0x7f, 0x20, 0x45, 0x5a, 0x7f, 0xb7, 0x64, 0xe6, 0xe2, 0xf3, 0x02, 0x7a, + 0x93, 0x54, 0x24, 0xad, 0xd7, 0xd3, 0xbc, 0x09, 0xd9, 0x21, 0xbd, 0x31, + 0xc6, 0x3a, 0x19, 0xcf, 0xf3, 0xf3, 0x13, 0xb0, 0x1f, 0x86, 0x4b, 0x0a, + 0x16, 0x7c, 0xad, 0x0c, 0x79, 0x81, 0x6c, 0x4f, 0x39, 0x3a, 0x76, 0x6c, + 0x74, 0x6d, 0xa9, 0xce, 0xd8, 0xae, 0x8e, 0x8e, 0xff, 0xce, 0x80, 0xfa, + 0x66, 0xb4, 0x7d, 0xab, 0xb4, 0xfe, 0x9d, 0xd6, 0x65, 0x46, 0xeb, 0xc2, + 0x38, 0xe6, 0x8c, 0x17, 0xb1, 0xe5, 0xaa, 0xd3, 0xa7, 0xea, 0x42, 0x5b, + 0xb0, 0x50, 0x09, 0xd3, 0x9e, 0x5c, 0x26, 0xed, 0x85, 0x65, 0xd2, 0xfe, + 0x76, 0x99, 0x34, 0x13, 0x17, 0xec, 0x2f, 0x5e, 0x46, 0xde, 0x88, 0xe6, + 0x55, 0x69, 0x36, 0xf6, 0x75, 0x7e, 0xae, 0xcc, 0x2a, 0xeb, 0x97, 0x31, + 0x46, 0x6c, 0x62, 0xc3, 0x39, 0x1d, 0x1b, 0xde, 0xe2, 0x6d, 0x53, 0x8c, + 0x75, 0x11, 0x17, 0x09, 0xd9, 0xab, 0xf1, 0x42, 0x9c, 0x7c, 0x85, 0x31, + 0xe0, 0x3c, 0xd7, 0x5a, 0x13, 0xea, 0x4a, 0xb4, 0x3d, 0x6f, 0x9b, 0x98, + 0x79, 0x8b, 0xe9, 0x75, 0xd5, 0x3e, 0xd8, 0x0a, 0xfd, 0xc5, 0x26, 0xd9, + 0x3e, 0x96, 0x58, 0x41, 0xbd, 0xb5, 0x63, 0xcc, 0xf8, 0x83, 0x7b, 0xc1, + 0x57, 0x19, 0x21, 0x8c, 0xc9, 0x94, 0x08, 0x6d, 0xe2, 0xa5, 0xb6, 0xf0, + 0xeb, 0xb7, 0xd7, 0x7b, 0x85, 0xf6, 0x1c, 0xd8, 0x0e, 0x3f, 0x6b, 0x7b, + 0xf5, 0xd2, 0x37, 0x16, 0xe2, 0x4a, 0xfd, 0x9c, 0xf5, 0x22, 0x57, 0xa8, + 0xa7, 0xed, 0x12, 0x79, 0x66, 0x4e, 0x16, 0x6f, 0x84, 0xcd, 0x24, 0x41, + 0xb6, 0x5b, 0x5a, 0x23, 0xa2, 0x63, 0x3c, 0x29, 0x23, 0x9b, 0x3b, 0xb8, + 0xb6, 0x03, 0xfa, 0x37, 0xb6, 0x8a, 0x89, 0x9b, 0x86, 0x76, 0xca, 0x72, + 0xb4, 0x7b, 0xbd, 0xa5, 0x5d, 0xae, 0xa9, 0xee, 0xa0, 0xcc, 0xc5, 0x9c, + 0x18, 0x3a, 0xde, 0x5e, 0x94, 0x44, 0x48, 0xc7, 0x33, 0xf0, 0x8b, 0xab, + 0xe9, 0x78, 0x46, 0x52, 0x9a, 0x8e, 0x6b, 0x17, 0xd0, 0x71, 0xab, 0xa5, + 0xe3, 0x77, 0x44, 0x0d, 0x5d, 0x28, 0xad, 0xa7, 0x48, 0xa7, 0x86, 0x8e, + 0x1d, 0x4d, 0xc7, 0x33, 0x78, 0xbb, 0x7e, 0x8f, 0x2d, 0x13, 0xb1, 0x69, + 0xfc, 0x1d, 0xa6, 0x51, 0x2e, 0xfe, 0x66, 0xd4, 0xe8, 0xa5, 0x14, 0xe8, + 0x28, 0x4c, 0xff, 0x60, 0xd4, 0xd0, 0x67, 0x75, 0x9a, 0x89, 0x8f, 0xf4, + 0x17, 0xdf, 0x13, 0x5d, 0x48, 0x9f, 0x29, 0xd0, 0x67, 0x58, 0xe6, 0xf5, + 0xe8, 0xb3, 0xde, 0xae, 0x5b, 0x44, 0xf5, 0xba, 0x7b, 0x26, 0x66, 0x68, + 0xf5, 0x56, 0x3d, 0x76, 0x8e, 0xfb, 0xd9, 0x9f, 0x81, 0x56, 0xcd, 0xdc, + 0x9c, 0x9f, 0xf7, 0xb7, 0x19, 0x8b, 0x4a, 0x98, 0x18, 0x36, 0xe3, 0xa4, + 0x57, 0xb2, 0x1d, 0x8d, 0x7c, 0xaa, 0xd1, 0xf2, 0xa9, 0x71, 0x48, 0xa5, + 0xab, 0x65, 0x76, 0x37, 0x74, 0x05, 0x6d, 0x6c, 0x2d, 0xa7, 0x91, 0xd7, + 0x9a, 0xc8, 0x16, 0xff, 0xd9, 0xee, 0x5f, 0xe0, 0xba, 0x80, 0x0c, 0x39, + 0x48, 0x6b, 0x2b, 0x9b, 0x71, 0x29, 0xbf, 0x11, 0xdf, 0xdd, 0xd2, 0x56, + 0x56, 0x72, 0xfb, 0x58, 0x83, 0xec, 0x2b, 0xba, 0xf2, 0x51, 0xd4, 0xff, + 0x48, 0xd1, 0x83, 0x3f, 0x3e, 0x1e, 0xa5, 0x5d, 0xb8, 0xb7, 0xc8, 0xf5, + 0x49, 0xc7, 0xac, 0x19, 0x2d, 0x58, 0xf3, 0x8c, 0x48, 0x5b, 0x47, 0x01, + 0x9e, 0x8a, 0xb8, 0x3b, 0x01, 0x47, 0x5d, 0x3a, 0x2d, 0xaf, 0x74, 0x0f, + 0x38, 0xda, 0x97, 0x70, 0x7a, 0xe4, 0xc6, 0x4a, 0x5a, 0x6e, 0xa8, 0x98, + 0x75, 0xd2, 0xf9, 0x75, 0xd0, 0xa4, 0x37, 0x0d, 0x9d, 0x93, 0xf1, 0x82, + 0xe0, 0x3c, 0xe4, 0xb7, 0x3a, 0xe2, 0x4a, 0xb4, 0x23, 0x19, 0x9f, 0x16, + 0xf3, 0x7d, 0xb1, 0xfc, 0xe3, 0x60, 0x28, 0xe6, 0xca, 0x2b, 0x3e, 0xc7, + 0xd5, 0x23, 0xd7, 0x97, 0xab, 0xfb, 0xe3, 0x5a, 0xe9, 0x13, 0x51, 0xae, + 0x4d, 0x64, 0x2b, 0xe5, 0x28, 0xe3, 0xe7, 0x22, 0x79, 0x69, 0x7b, 0x2b, + 0x7c, 0x37, 0x48, 0xeb, 0xb6, 0xb7, 0x82, 0x56, 0x62, 0xd0, 0xf3, 0x5b, + 0x01, 0xd7, 0x56, 0xc6, 0xbb, 0x18, 0xe7, 0xe2, 0xf7, 0x5f, 0xa2, 0x5f, + 0xd6, 0xfd, 0x5d, 0xbd, 0x66, 0x25, 0x8a, 0x73, 0x6e, 0xf8, 0x65, 0x79, + 0x5d, 0xd3, 0x38, 0x14, 0x4d, 0x8b, 0x13, 0x7d, 0x5b, 0x5c, 0x56, 0xf8, + 0xd5, 0xfd, 0x73, 0xed, 0x57, 0x14, 0x70, 0xe8, 0xee, 0xd8, 0xdc, 0x23, + 0x7d, 0x18, 0x5f, 0xff, 0x92, 0xf1, 0xed, 0x17, 0xc6, 0x54, 0x2f, 0x16, + 0x39, 0x86, 0xf9, 0x71, 0xa9, 0x3f, 0x32, 0xe3, 0x8a, 0x76, 0x2c, 0x1e, + 0x8f, 0xae, 0xaf, 0x4e, 0x01, 0x96, 0xe7, 0xf4, 0x1e, 0x81, 0x20, 0xb8, + 0xa6, 0xe3, 0x62, 0x90, 0x58, 0x97, 0xec, 0x9c, 0x9e, 0x5f, 0xd3, 0x19, + 0x8a, 0xa4, 0x33, 0x1a, 0xff, 0xf8, 0x4e, 0xe4, 0xca, 0xdd, 0x98, 0x3b, + 0x71, 0x73, 0x5d, 0xae, 0xe6, 0x8d, 0x9c, 0xdf, 0x6d, 0xd7, 0xad, 0x42, + 0xbf, 0x29, 0x08, 0x94, 0xbf, 0x58, 0x56, 0x50, 0x47, 0x61, 0xec, 0xb2, + 0xdb, 0xee, 0x4b, 0x49, 0x31, 0x6e, 0x38, 0xe4, 0xa6, 0xa3, 0x89, 0x42, + 0xb9, 0x0b, 0xbf, 0x1b, 0xf0, 0xfe, 0x45, 0xd8, 0x28, 0x3d, 0xb0, 0x61, + 0x24, 0xa6, 0x8c, 0x3c, 0x00, 0xfd, 0x76, 0xe4, 0x95, 0x22, 0x3f, 0x7a, + 0x89, 0xe1, 0x72, 0x2c, 0x31, 0x5a, 0xde, 0xcb, 0xfa, 0x28, 0x7b, 0xa5, + 0xf8, 0x1d, 0xfb, 0x62, 0x1f, 0xf4, 0x79, 0x7f, 0x96, 0x3e, 0x5c, 0xdb, + 0x36, 0xdb, 0x0c, 0xf1, 0xe2, 0xd2, 0x0d, 0xc7, 0xbf, 0x6e, 0xeb, 0x8f, + 0x70, 0x7c, 0x7b, 0x2d, 0xdc, 0x8b, 0xfb, 0x7d, 0x49, 0xdb, 0x2c, 0x8f, + 0x55, 0x68, 0x27, 0x72, 0x4d, 0x27, 0x79, 0x62, 0x5c, 0x08, 0x47, 0x10, + 0x5c, 0x48, 0x19, 0x7d, 0xfd, 0x74, 0x85, 0xeb, 0x1a, 0x41, 0xf0, 0x5d, + 0xda, 0xc2, 0x83, 0x25, 0xf4, 0x17, 0xe2, 0x60, 0x63, 0xde, 0x85, 0x2c, + 0x1c, 0xe9, 0x26, 0x7e, 0x05, 0x5e, 0x69, 0x87, 0xb7, 0x4b, 0xa2, 0x89, + 0xdf, 0x2e, 0x37, 0x24, 0x3e, 0x51, 0xf6, 0x80, 0x67, 0x8e, 0x3b, 0x96, + 0xd8, 0x63, 0xc7, 0xcc, 0xfd, 0x20, 0xaf, 0xbf, 0x4f, 0xe3, 0xa5, 0x05, + 0x3e, 0x12, 0x61, 0x9a, 0x87, 0x85, 0xb0, 0x25, 0x2c, 0x6e, 0x82, 0xe0, + 0xfb, 0x29, 0xf6, 0xd9, 0xcd, 0xfd, 0x00, 0x23, 0xe8, 0x37, 0xbf, 0x56, + 0x11, 0x0f, 0xd1, 0xc4, 0x1d, 0xe8, 0xfb, 0xb7, 0xd1, 0xf7, 0xbe, 0x32, + 0xfb, 0x83, 0x7c, 0xc0, 0xd8, 0x47, 0x2a, 0x21, 0xbc, 0xcb, 0xf5, 0x1d, + 0xce, 0x79, 0xa7, 0xb5, 0xeb, 0xc2, 0x6f, 0x8d, 0x48, 0x4f, 0xc1, 0x97, + 0xcb, 0x56, 0x66, 0xd6, 0xb8, 0xf2, 0x2e, 0xc8, 0xda, 0x40, 0x4e, 0x42, + 0x86, 0xcd, 0x68, 0xba, 0xc9, 0xae, 0xe7, 0xff, 0x11, 0xf9, 0xe4, 0x0a, + 0xc6, 0x94, 0x7b, 0x7d, 0xda, 0xab, 0xb3, 0xc1, 0x8c, 0x4f, 0x99, 0xbc, + 0x4a, 0xc6, 0xbd, 0x7c, 0x27, 0xf4, 0x03, 0xd2, 0x1a, 0xe9, 0x63, 0x27, + 0xb2, 0x91, 0x64, 0x62, 0x58, 0xb8, 0xc7, 0x89, 0xfb, 0x13, 0xb8, 0xef, + 0x87, 0xf2, 0xc0, 0x85, 0x9c, 0xe3, 0x1c, 0x9a, 0xfe, 0x86, 0xcb, 0xf3, + 0x65, 0x0f, 0x08, 0xd7, 0x09, 0x93, 0xf1, 0xbd, 0xda, 0x26, 0x01, 0xd5, + 0x15, 0x59, 0x76, 0x33, 0x2c, 0x12, 0xbf, 0xaa, 0xbc, 0xde, 0x73, 0x05, + 0x3e, 0x67, 0x1c, 0x21, 0x1a, 0xcd, 0x16, 0xe5, 0xb5, 0x48, 0xb7, 0xbc, + 0x96, 0x4d, 0xd5, 0x4b, 0xaf, 0x96, 0xf9, 0xcc, 0xd3, 0xe9, 0xb3, 0x26, + 0xdd, 0x85, 0x2e, 0xe1, 0x9c, 0xf4, 0x40, 0x46, 0x4f, 0x00, 0x6e, 0xe2, + 0xb0, 0x87, 0x32, 0x89, 0xf3, 0xa7, 0x54, 0x3a, 0x16, 0xcd, 0x95, 0xa5, + 0x2f, 0x57, 0xb4, 0xb1, 0x9e, 0x01, 0x8e, 0x7f, 0x95, 0xc5, 0x43, 0xa3, + 0xb8, 0x80, 0xad, 0x2f, 0x92, 0x70, 0xe0, 0x2b, 0x43, 0xd7, 0x3f, 0xba, + 0x4a, 0x1a, 0x89, 0x9b, 0x1e, 0xf0, 0x52, 0x0d, 0x74, 0xd1, 0xfd, 0xcd, + 0x5c, 0x37, 0xd5, 0x36, 0x64, 0xec, 0x63, 0xbf, 0xac, 0xd2, 0x7f, 0x1b, + 0x57, 0xe9, 0x51, 0x2b, 0x2f, 0xa3, 0x7d, 0x94, 0x97, 0x4f, 0x97, 0x08, + 0x8f, 0x78, 0x11, 0x3f, 0xd1, 0xd7, 0x5b, 0x16, 0x15, 0x49, 0x7b, 0xd1, + 0xde, 0xf2, 0x42, 0xfa, 0x7f, 0xba, 0xf2, 0x61, 0x6b, 0x0b, 0x56, 0xc7, + 0x54, 0xab, 0xf3, 0xc8, 0x83, 0xcb, 0xe5, 0x11, 0x26, 0x89, 0xae, 0x48, + 0x5f, 0xf8, 0x54, 0x7b, 0x47, 0xde, 0xab, 0x15, 0xe2, 0x39, 0x80, 0xdc, + 0x06, 0xae, 0xcb, 0x5c, 0xaf, 0xde, 0x8f, 0x79, 0xfb, 0x3f, 0x41, 0x26, + 0xc6, 0x7c, 0x4f, 0xea, 0xe0, 0xdb, 0xbe, 0x0c, 0xdd, 0xf9, 0x8a, 0x7f, + 0xe1, 0x53, 0x9d, 0x1d, 0x41, 0xf0, 0xac, 0x9f, 0x4f, 0xb8, 0x90, 0x1f, + 0x87, 0x2d, 0xbe, 0x87, 0x81, 0xef, 0x89, 0x39, 0x7c, 0x27, 0xe4, 0x62, + 0xd7, 0xf7, 0x03, 0xae, 0xf5, 0x0d, 0x97, 0x6f, 0xbd, 0x55, 0xa5, 0x3f, + 0xfe, 0xa1, 0x6c, 0x37, 0xfb, 0x1b, 0x91, 0xc3, 0x95, 0x9b, 0x88, 0xbf, + 0x28, 0xc6, 0x7a, 0x4f, 0x9f, 0x6f, 0xfa, 0xed, 0x5b, 0xd0, 0x2f, 0xe9, + 0xe5, 0x47, 0xac, 0x8b, 0x32, 0xd5, 0x75, 0x33, 0xa0, 0xcb, 0xbc, 0xad, + 0x3b, 0x70, 0x85, 0xba, 0xde, 0x15, 0xea, 0x1e, 0x46, 0xdd, 0x3d, 0xb6, + 0xee, 0x85, 0xcf, 0xbc, 0xb9, 0x7e, 0x07, 0xb8, 0xc7, 0x0e, 0x3e, 0x80, + 0xb8, 0x11, 0xff, 0x36, 0xfc, 0xbe, 0x85, 0xed, 0x28, 0xda, 0xf7, 0x23, + 0x95, 0x21, 0x19, 0xae, 0xec, 0xc4, 0x33, 0x88, 0xb4, 0x3e, 0x3c, 0xfb, + 0xf0, 0x3b, 0x8d, 0x47, 0xa2, 0x6e, 0xfa, 0xc2, 0x5d, 0xc3, 0x7e, 0x88, + 0x57, 0xae, 0xcd, 0xb3, 0x0f, 0xd8, 0x17, 0x5d, 0x3f, 0x41, 0x1f, 0x61, + 0xfa, 0x07, 0x50, 0x67, 0x1a, 0x69, 0x2b, 0x69, 0x7b, 0x62, 0xae, 0xab, + 0xeb, 0x54, 0xc3, 0x36, 0x1d, 0xce, 0x05, 0xf2, 0x0d, 0x8d, 0xf6, 0x16, + 0x43, 0x18, 0xef, 0x44, 0x1b, 0xe3, 0x57, 0x29, 0xff, 0x1e, 0xc2, 0x15, + 0x57, 0xfe, 0xc7, 0xf0, 0x7e, 0x2d, 0xd8, 0x9d, 0x62, 0x4c, 0x9e, 0xf3, + 0x7e, 0xdd, 0xaa, 0xa5, 0x7b, 0x9f, 0x42, 0x1a, 0xe8, 0x84, 0x4e, 0x69, + 0xb0, 0x74, 0x5a, 0x80, 0xe5, 0x43, 0x1a, 0xe5, 0x98, 0x17, 0x97, 0x4d, + 0x76, 0xe6, 0xa5, 0x07, 0xba, 0x8c, 0xb2, 0xf6, 0xd3, 0xf5, 0x26, 0x0e, + 0x03, 0xcb, 0xd1, 0xef, 0x04, 0x3d, 0x37, 0x88, 0x87, 0xfa, 0x03, 0x11, + 0x0f, 0x34, 0x18, 0xd6, 0x4f, 0x7a, 0x03, 0x11, 0x8e, 0x19, 0x1c, 0x5f, + 0xe6, 0xba, 0x34, 0x6d, 0x6b, 0xd6, 0x0f, 0x6d, 0x1c, 0xfe, 0x7b, 0x59, + 0xc4, 0x67, 0x1a, 0xdb, 0x0b, 0xde, 0x55, 0xe3, 0x2f, 0x59, 0x63, 0xc1, + 0x38, 0xf3, 0x49, 0x68, 0x30, 0xaf, 0x4f, 0xcb, 0xe9, 0xfc, 0x35, 0x35, + 0xd2, 0xe0, 0xf5, 0xeb, 0xdf, 0x2c, 0xd3, 0xe0, 0x81, 0x4f, 0x17, 0x95, + 0x61, 0x1a, 0xf3, 0x0a, 0x6b, 0x94, 0xde, 0xab, 0xa4, 0xf7, 0x28, 0xc9, + 0x83, 0xa9, 0x64, 0x62, 0x48, 0x25, 0xbd, 0x71, 0xd9, 0x0f, 0xb9, 0x43, + 0x39, 0x39, 0x73, 0x7f, 0x44, 0xb8, 0x9f, 0xef, 0x5d, 0x92, 0xf5, 0x29, + 0x3f, 0x0b, 0x9f, 0x57, 0x94, 0x75, 0x95, 0x97, 0x1a, 0xcc, 0xd8, 0xb8, + 0x0f, 0x01, 0x70, 0x36, 0xd1, 0x86, 0xbb, 0xb5, 0x81, 0x3c, 0x94, 0x50, + 0x11, 0xd9, 0x45, 0x3f, 0x5f, 0x7d, 0xb1, 0x5e, 0xea, 0xa7, 0xd7, 0x78, + 0x52, 0xd1, 0xe9, 0x66, 0x7f, 0x60, 0xb2, 0x73, 0x48, 0x89, 0x1e, 0x7b, + 0x46, 0xbd, 0x91, 0xcc, 0x9e, 0xb5, 0xfa, 0x23, 0x90, 0xc7, 0xb4, 0xbe, + 0x98, 0xf9, 0xbc, 0x2b, 0x17, 0x82, 0xb6, 0x4d, 0x17, 0xda, 0xb3, 0x5d, + 0xb4, 0x73, 0x57, 0xd9, 0xfd, 0x95, 0x8c, 0x63, 0xbd, 0x4b, 0x9e, 0xf3, + 0x0b, 0x18, 0xf7, 0x7e, 0xb9, 0xe0, 0xb3, 0xbf, 0x99, 0xcf, 0x79, 0xc2, + 0x74, 0xc2, 0x6e, 0xfa, 0x13, 0xf5, 0xa7, 0x80, 0x87, 0x7d, 0x52, 0x07, + 0x5f, 0xc9, 0xee, 0x4b, 0x0e, 0xe4, 0x45, 0xcf, 0x4b, 0x8f, 0xa0, 0xad, + 0x15, 0x3e, 0xf8, 0x10, 0x76, 0x73, 0xcd, 0x91, 0xab, 0x21, 0x77, 0x1d, + 0xbd, 0xc7, 0x02, 0x93, 0xe1, 0x4d, 0x61, 0xde, 0x33, 0x03, 0x2c, 0x57, + 0x2f, 0xd3, 0x31, 0xf2, 0xba, 0xe6, 0x97, 0x4f, 0x65, 0xfd, 0x76, 0x4f, + 0x39, 0xc3, 0x8c, 0x31, 0x00, 0xaf, 0xa4, 0xcd, 0x54, 0x6c, 0xbb, 0xcf, + 0xb6, 0x58, 0xe6, 0x2a, 0xf9, 0xf6, 0xc0, 0x85, 0x7f, 0x78, 0xd6, 0xff, + 0x7b, 0xc0, 0x91, 0x81, 0x4c, 0xe0, 0xf3, 0x6a, 0x90, 0x8f, 0x31, 0xa6, + 0xf5, 0xbf, 0xeb, 0xad, 0x9d, 0xac, 0x79, 0x7f, 0x58, 0xef, 0x93, 0x79, + 0xfe, 0x33, 0x59, 0xae, 0x77, 0xc0, 0x36, 0xc9, 0x69, 0xb9, 0x18, 0xfd, + 0x69, 0x0e, 0xf0, 0x14, 0x2a, 0xb4, 0x43, 0xfe, 0x06, 0x76, 0x88, 0xd6, + 0x93, 0xf2, 0xed, 0x41, 0xe6, 0xb1, 0xdd, 0xec, 0xd5, 0xae, 0xd6, 0x0b, + 0x21, 0x2c, 0xc9, 0xce, 0x1c, 0xf2, 0x47, 0xb4, 0x1d, 0xef, 0xc9, 0xac, + 0xe7, 0xea, 0x7d, 0x27, 0xf9, 0xc1, 0x20, 0x78, 0xc5, 0x77, 0xe5, 0xa4, + 0x86, 0xf9, 0x05, 0xf4, 0xe1, 0xc8, 0xc4, 0x80, 0xfb, 0xd3, 0x93, 0x3e, + 0xc7, 0xc7, 0x3c, 0xae, 0x2b, 0x6d, 0x8e, 0x1b, 0xf8, 0x68, 0x9b, 0x7e, + 0x2f, 0x98, 0x8d, 0x71, 0xdd, 0x02, 0x3c, 0x5d, 0x6a, 0xf7, 0x6e, 0x90, + 0xdb, 0xe6, 0x6c, 0x9a, 0x69, 0x31, 0x36, 0xa3, 0xd1, 0x69, 0x17, 0xfe, + 0x61, 0xc4, 0xbf, 0xb0, 0xba, 0x80, 0xb9, 0x81, 0x0e, 0x5b, 0x0c, 0x4b, + 0x8a, 0xb0, 0x0c, 0x6b, 0x58, 0x62, 0xc0, 0xa5, 0x0b, 0xd9, 0x77, 0x9b, + 0x1c, 0x02, 0xde, 0x87, 0x06, 0x45, 0x9e, 0x85, 0x4d, 0x76, 0xbe, 0x0a, + 0x9e, 0x19, 0xc0, 0x73, 0xde, 0xe7, 0x5e, 0x00, 0xe6, 0xf9, 0xde, 0xb0, + 0x70, 0x2f, 0x00, 0x71, 0xd8, 0x81, 0xdf, 0x22, 0x33, 0xd0, 0xbf, 0x27, + 0xfd, 0xd7, 0x82, 0xf1, 0x18, 0x75, 0x23, 0xda, 0x99, 0xdb, 0x1b, 0x14, + 0xc8, 0xe7, 0x53, 0xd4, 0x43, 0xb5, 0xd2, 0xb6, 0x8e, 0x7e, 0x88, 0x91, + 0x9f, 0x37, 0xf8, 0x19, 0xf4, 0xf5, 0x5b, 0x2b, 0xa5, 0x3e, 0x2f, 0xfd, + 0x1d, 0x75, 0xc8, 0x73, 0x6d, 0xde, 0x80, 0xce, 0xeb, 0xef, 0x38, 0x8c, + 0xfc, 0x8f, 0xaf, 0x64, 0xbc, 0xdb, 0xf5, 0xd7, 0x4b, 0xdb, 0x1a, 0xe6, + 0x55, 0xf3, 0xe0, 0xab, 0xdc, 0x83, 0x69, 0x75, 0x38, 0x64, 0x59, 0x29, + 0xef, 0x71, 0xa7, 0xdd, 0x21, 0xcc, 0xc5, 0x6e, 0x9f, 0xb2, 0xed, 0xbf, + 0xa3, 0x6e, 0x4a, 0x6e, 0xf4, 0x07, 0x91, 0x37, 0x8d, 0xbc, 0xc3, 0x36, + 0x6f, 0xd0, 0xe6, 0x6d, 0x43, 0xde, 0x3e, 0xe0, 0xef, 0x6e, 0x9d, 0x9e, + 0xe5, 0x6f, 0x53, 0xc7, 0x5b, 0xd9, 0x71, 0xe1, 0x33, 0x37, 0xf8, 0x84, + 0x0b, 0x79, 0x25, 0xae, 0x8b, 0xde, 0x26, 0x79, 0x2f, 0x79, 0x0b, 0x7b, + 0xfd, 0x66, 0xb1, 0x0e, 0xb2, 0x89, 0x7b, 0x80, 0x69, 0xb3, 0x6e, 0xf1, + 0x5e, 0x96, 0xff, 0x40, 0xba, 0xeb, 0xc9, 0x38, 0x5f, 0x5b, 0xc9, 0xb8, + 0xd8, 0x88, 0x4f, 0xfb, 0x3a, 0x90, 0x9c, 0x5e, 0x3f, 0xa1, 0x7f, 0x5b, + 0x44, 0x3a, 0xe9, 0x41, 0x35, 0x45, 0xf4, 0x3e, 0x2d, 0x7e, 0x47, 0x61, + 0xf7, 0x06, 0x42, 0x9f, 0x8f, 0x36, 0x5d, 0xc6, 0xe3, 0xda, 0x50, 0x98, + 0xe7, 0x21, 0x4f, 0x6d, 0x8a, 0xc0, 0x26, 0xaa, 0xf5, 0x1d, 0x1d, 0xa3, + 0x2e, 0xe8, 0x75, 0x00, 0xc6, 0xdf, 0x32, 0xf0, 0x63, 0x02, 0xe9, 0x47, + 0xdf, 0xa4, 0xfd, 0x68, 0x87, 0xef, 0x1d, 0x10, 0xee, 0x67, 0x65, 0x7a, + 0xbb, 0xf7, 0x6d, 0x99, 0xa7, 0xf3, 0x19, 0x49, 0x66, 0x94, 0x03, 0xff, + 0x75, 0xab, 0x23, 0xf5, 0xb0, 0x3d, 0x6e, 0x30, 0xfa, 0xcd, 0xe3, 0x9e, + 0xc4, 0x8b, 0xda, 0x56, 0x6b, 0xb4, 0xf3, 0x91, 0x05, 0x6e, 0xb8, 0x1f, + 0x7c, 0xe0, 0x9e, 0xdd, 0x7e, 0x21, 0x09, 0x6a, 0xd4, 0xba, 0x71, 0x18, + 0xb4, 0x91, 0x4d, 0x19, 0xdd, 0x78, 0xc3, 0x9c, 0x6e, 0xfc, 0xf3, 0x95, + 0xe4, 0x89, 0xe1, 0x72, 0x1c, 0x75, 0xf5, 0x3a, 0x4a, 0x82, 0x75, 0x6b, + 0x31, 0x9f, 0xe7, 0xfd, 0xec, 0x35, 0xa0, 0x2f, 0xc8, 0xe1, 0x64, 0xe7, + 0x29, 0xd4, 0x2d, 0xa0, 0xee, 0xe4, 0x5c, 0x5d, 0x47, 0x46, 0x7c, 0xbd, + 0xef, 0x59, 0x26, 0xcb, 0x21, 0x1d, 0x26, 0xe3, 0xb7, 0x6a, 0x5e, 0xe0, + 0x7e, 0x30, 0x37, 0x71, 0x9f, 0x6c, 0xd6, 0xb4, 0xdd, 0x27, 0xdc, 0x27, + 0xc5, 0xb6, 0xef, 0x0b, 0xda, 0xd6, 0x10, 0xbe, 0x12, 0xde, 0xa4, 0x8d, + 0x31, 0xbc, 0xc3, 0xf9, 0x37, 0xf3, 0x3e, 0xe4, 0x10, 0xdf, 0xbf, 0x1f, + 0xe4, 0x07, 0x39, 0x2f, 0xfc, 0x9e, 0xa7, 0xb9, 0x11, 0xd0, 0x5c, 0xc4, + 0x7f, 0xbb, 0x0c, 0xeb, 0x3d, 0x10, 0x29, 0x99, 0xd0, 0xf1, 0xcc, 0x0b, + 0xc1, 0x23, 0x0b, 0xe4, 0xf8, 0x47, 0x94, 0xa1, 0x21, 0xfe, 0x2e, 0x24, + 0xea, 0x64, 0x66, 0x4d, 0x9d, 0xde, 0xf1, 0x41, 0x7c, 0x8c, 0xde, 0x73, + 0x3b, 0xf8, 0xf5, 0xfa, 0xb9, 0xb1, 0x00, 0xdf, 0xc0, 0xe3, 0x4e, 0x63, + 0xeb, 0x63, 0x1c, 0x19, 0xed, 0xbf, 0x67, 0x8b, 0x4a, 0xef, 0x0b, 0xa2, + 0x8e, 0x3f, 0x00, 0x9d, 0x6a, 0xf6, 0xa4, 0xe0, 0x5d, 0xe1, 0xbc, 0x29, + 0xed, 0x73, 0x1c, 0x04, 0x0f, 0x1f, 0xf4, 0xb3, 0x6b, 0x6a, 0x75, 0xdb, + 0x49, 0xef, 0x7a, 0x6d, 0x13, 0x6e, 0x94, 0x99, 0x14, 0xdb, 0x23, 0x5e, + 0xfe, 0x47, 0x30, 0xe4, 0xcd, 0xa0, 0x7f, 0x43, 0xff, 0x59, 0x5f, 0xb5, + 0xd4, 0x49, 0xf5, 0x3e, 0x53, 0xe2, 0xc9, 0x85, 0xbd, 0xd2, 0x01, 0xfc, + 0x18, 0x78, 0x73, 0xe5, 0xb7, 0x49, 0x21, 0xe6, 0xda, 0xb1, 0x45, 0xb4, + 0x2f, 0x37, 0x91, 0xaa, 0x83, 0x2d, 0xf8, 0x17, 0xc1, 0xe4, 0x82, 0x31, + 0x1e, 0xac, 0x1a, 0xe3, 0x4c, 0x02, 0xd8, 0x68, 0x89, 0xcc, 0xc9, 0x01, + 0xf6, 0x65, 0x64, 0x52, 0x38, 0xc6, 0x3a, 0x8c, 0x71, 0xc7, 0xdc, 0x18, + 0x0f, 0x2f, 0x1a, 0xe3, 0x61, 0x8c, 0x11, 0xf6, 0x42, 0x29, 0xd3, 0xe9, + 0xce, 0xcf, 0xfb, 0xd5, 0x35, 0x73, 0xf3, 0x29, 0xdc, 0xeb, 0x84, 0xf1, + 0xd3, 0xa6, 0xd8, 0x08, 0x78, 0x74, 0x5b, 0x90, 0x71, 0x0e, 0x64, 0x5b, + 0x76, 0x4d, 0x8d, 0x1d, 0xff, 0x76, 0x96, 0x2b, 0x1b, 0x1c, 0x9c, 0x4c, + 0xb9, 0x9d, 0x8f, 0xa0, 0xbf, 0xbd, 0x76, 0x5c, 0xbd, 0xe5, 0xab, 0x31, + 0xae, 0x0b, 0xdf, 0xc1, 0x18, 0xe0, 0xb3, 0x9d, 0xa0, 0x0f, 0x9c, 0x18, + 0x92, 0x05, 0xb2, 0xeb, 0x33, 0xf3, 0x72, 0xd4, 0xc0, 0x4c, 0xdb, 0xba, + 0x30, 0x07, 0xf3, 0xdd, 0x8b, 0x60, 0xbe, 0x1b, 0x30, 0xef, 0xb3, 0xf3, + 0xb2, 0xaf, 0x6a, 0xcf, 0x62, 0x48, 0x47, 0xfc, 0xfd, 0xbc, 0xf5, 0x45, + 0x3e, 0x20, 0xf7, 0x97, 0x3a, 0xe5, 0xcb, 0x95, 0xe4, 0x59, 0xc6, 0xd1, + 0xcf, 0x55, 0x92, 0xe3, 0x22, 0x5d, 0xf2, 0xc7, 0xb0, 0x73, 0xae, 0x82, + 0x6f, 0xf1, 0x34, 0xfc, 0xd7, 0x3f, 0xa9, 0xf8, 0xf2, 0xc4, 0xdc, 0x7e, + 0x38, 0xea, 0xba, 0xb4, 0x9c, 0x84, 0x4f, 0xbb, 0xed, 0x68, 0x1b, 0xf7, + 0x2a, 0x11, 0xbe, 0xbb, 0xa8, 0x73, 0xda, 0x94, 0xe6, 0xc5, 0xef, 0x62, + 0xbc, 0xa7, 0xa9, 0x6b, 0xd6, 0xfa, 0xbe, 0x77, 0xb3, 0x5a, 0x47, 0x99, + 0x90, 0xff, 0x5a, 0xe4, 0x03, 0xf5, 0x26, 0xc6, 0x92, 0xf1, 0x9a, 0xc9, + 0x1b, 0xdb, 0x3a, 0x12, 0x7d, 0x42, 0x5b, 0x82, 0xfe, 0x36, 0x6c, 0xa1, + 0xd2, 0xe6, 0xf8, 0x5a, 0xa1, 0x4c, 0xa2, 0x5d, 0x94, 0x96, 0x09, 0xc0, + 0x3e, 0x06, 0x89, 0x50, 0x68, 0xf6, 0x47, 0x7b, 0xd5, 0x44, 0x03, 0x79, + 0x70, 0xdb, 0x19, 0xd0, 0xd7, 0x36, 0x8c, 0xa9, 0x2b, 0x79, 0x76, 0x46, + 0x65, 0x4e, 0xac, 0x95, 0x57, 0x82, 0xa1, 0x66, 0x47, 0x9e, 0xd8, 0xc4, + 0x3c, 0x2d, 0xb7, 0x3f, 0xd5, 0x0b, 0xf9, 0xd4, 0xce, 0x73, 0x0b, 0x03, + 0xf2, 0x2f, 0x77, 0x80, 0x06, 0x7f, 0xb8, 0xe9, 0x6b, 0xc1, 0x6c, 0xb3, + 0x2b, 0x5b, 0x37, 0x25, 0xbd, 0xbc, 0xc2, 0x78, 0x4a, 0x18, 0x4f, 0x09, + 0xe3, 0xe3, 0x98, 0x4b, 0x18, 0xd7, 0x15, 0xf7, 0x4a, 0xf5, 0x2c, 0x88, + 0xcb, 0x1a, 0x3f, 0x2d, 0x93, 0x77, 0x65, 0x83, 0xdd, 0x2b, 0x35, 0x5c, + 0x1f, 0xae, 0xb1, 0x65, 0x64, 0x3c, 0x28, 0xf8, 0x7f, 0x70, 0x55, 0xb6, + 0x2b, 0xb6, 0x58, 0xe7, 0xdc, 0x35, 0xaf, 0x73, 0x44, 0x9e, 0x33, 0xf3, + 0x86, 0x39, 0xf3, 0xbd, 0x49, 0x6e, 0x86, 0x87, 0x0e, 0xdc, 0xaa, 0xf7, + 0x3c, 0x77, 0xe0, 0x9b, 0x36, 0xd5, 0xa7, 0xf5, 0x3a, 0xe2, 0x4c, 0xf9, + 0x1e, 0x3b, 0x77, 0xf7, 0x68, 0x3d, 0xbb, 0x75, 0xd3, 0xa5, 0x80, 0xfb, + 0xdc, 0xbc, 0x4d, 0xcb, 0xc5, 0x22, 0x68, 0xef, 0xd5, 0x69, 0xde, 0xe7, + 0x7a, 0x76, 0x41, 0x9f, 0x13, 0x01, 0xde, 0xe6, 0xe2, 0x62, 0xf5, 0x48, + 0xa3, 0xbe, 0xf8, 0x69, 0x83, 0x59, 0x47, 0xa5, 0x6c, 0x58, 0x83, 0x34, + 0xd7, 0xec, 0x05, 0x5e, 0x90, 0xf7, 0xdf, 0xea, 0xcd, 0x9e, 0x8f, 0xea, + 0xb2, 0xe0, 0x31, 0xbd, 0x2f, 0x84, 0xfb, 0x03, 0x7f, 0x79, 0xa5, 0xb1, + 0x4d, 0xc3, 0x7c, 0xa6, 0xff, 0x38, 0x98, 0xd0, 0x31, 0x36, 0xf6, 0xf5, + 0x43, 0xfc, 0x5e, 0xbc, 0x5f, 0x24, 0xb4, 0x5d, 0xeb, 0x40, 0xf7, 0xda, + 0x5f, 0x16, 0x94, 0x89, 0xe7, 0x25, 0x22, 0x13, 0x55, 0x30, 0x4e, 0x10, + 0xee, 0x52, 0xd7, 0xaa, 0xf9, 0xd8, 0xdd, 0x6a, 0xa4, 0x11, 0xc6, 0x75, + 0x8b, 0xf2, 0xc8, 0x1b, 0xad, 0x2b, 0x49, 0x37, 0xd3, 0xc2, 0xb4, 0xf9, + 0x31, 0xcd, 0x68, 0xfb, 0xb9, 0x6d, 0x95, 0xde, 0xfb, 0xc4, 0x35, 0x46, + 0xc6, 0x08, 0x63, 0x26, 0xdf, 0xf5, 0xff, 0x56, 0xd7, 0x19, 0x9a, 0xab, + 0xa3, 0xe7, 0x02, 0xf9, 0x6e, 0x55, 0x5e, 0x35, 0xdc, 0xd4, 0x5f, 0x43, + 0x9d, 0x75, 0xd0, 0x89, 0x17, 0x53, 0xab, 0xc3, 0xbd, 0xf0, 0xb0, 0x21, + 0xb2, 0xd7, 0xd4, 0x5a, 0x99, 0x3f, 0x81, 0x79, 0x7d, 0x26, 0x65, 0x78, + 0x51, 0xf3, 0x61, 0xf1, 0x36, 0xf8, 0xeb, 0xa1, 0xde, 0xa0, 0x9c, 0x26, + 0x6f, 0x22, 0xad, 0x42, 0x9f, 0xe0, 0xc2, 0xea, 0x99, 0xae, 0x57, 0x03, + 0xee, 0xb3, 0x7c, 0x45, 0xdb, 0x51, 0x43, 0xb2, 0xb0, 0xed, 0xd1, 0x7b, + 0x5e, 0xbf, 0xed, 0xa1, 0x65, 0xda, 0x1e, 0xb2, 0x6d, 0x8b, 0x6b, 0xda, + 0x8e, 0x5e, 0xa1, 0xed, 0x81, 0x37, 0x68, 0x7b, 0x70, 0x99, 0xb6, 0x07, + 0xc3, 0xb6, 0x95, 0x69, 0xdb, 0x0b, 0xdb, 0x4e, 0x2c, 0xc2, 0xc9, 0x67, + 0x5e, 0xbf, 0xed, 0x7d, 0xcb, 0xb4, 0xbd, 0x6f, 0x11, 0xdc, 0xc4, 0x49, + 0x2d, 0x74, 0xff, 0x3d, 0xda, 0xe6, 0xac, 0x03, 0xdf, 0x5c, 0x84, 0xfc, + 0x36, 0xfe, 0xc8, 0x85, 0xbb, 0x66, 0xcb, 0xe0, 0x2b, 0xf8, 0xd7, 0x99, + 0x72, 0x03, 0x9e, 0x71, 0xd8, 0x33, 0x28, 0x07, 0x7b, 0xbc, 0x26, 0x1d, + 0xc8, 0xc9, 0x6e, 0x96, 0xcd, 0xc7, 0x6b, 0xe7, 0xf4, 0xc6, 0x3d, 0xe8, + 0x8f, 0x6d, 0xfb, 0x5e, 0xbf, 0xbc, 0xa6, 0xfb, 0xcb, 0x95, 0xe9, 0x8f, + 0x21, 0xbd, 0x42, 0x1f, 0x97, 0xf5, 0x42, 0x19, 0x58, 0x67, 0xd7, 0x3e, + 0x68, 0x6b, 0x32, 0x0e, 0xa7, 0xed, 0x51, 0x29, 0x94, 0x7f, 0x12, 0x4c, + 0x83, 0x2e, 0x46, 0xe6, 0x74, 0xc8, 0x93, 0xab, 0x68, 0xb3, 0x8f, 0x53, + 0xb3, 0x54, 0xc5, 0xa0, 0x46, 0x7c, 0xa6, 0xfd, 0x98, 0x6d, 0xc2, 0x0e, + 0x0c, 0xcb, 0x32, 0x6e, 0x6c, 0x62, 0x4e, 0x67, 0x21, 0x33, 0xcd, 0x9e, + 0x0e, 0xfa, 0x2a, 0x4f, 0x81, 0x97, 0xf7, 0x43, 0x76, 0x24, 0xf3, 0x22, + 0x3d, 0x8d, 0xe6, 0xac, 0x45, 0x4c, 0x72, 0x5d, 0xbf, 0x69, 0xf1, 0xb8, + 0xef, 0xce, 0xe5, 0xcf, 0x59, 0x40, 0x3e, 0x38, 0x94, 0x91, 0xd7, 0x37, + 0x9a, 0x75, 0xbb, 0xb7, 0x36, 0x32, 0x1e, 0xa3, 0x36, 0x75, 0xaf, 0xd6, + 0xf2, 0xc7, 0x09, 0xbf, 0xbf, 0xb2, 0xe8, 0x3b, 0xac, 0xf7, 0x93, 0xd5, + 0x0b, 0xeb, 0x85, 0xe9, 0x70, 0x4d, 0x16, 0xa4, 0x1f, 0x58, 0xb3, 0xb0, + 0x7e, 0xac, 0x69, 0xe1, 0xf7, 0xe0, 0xa2, 0xef, 0xcf, 0x2c, 0xfa, 0x7e, + 0x61, 0xd1, 0xf7, 0x75, 0x6b, 0x17, 0x95, 0x5f, 0xf4, 0xfd, 0xe5, 0xb5, + 0xcb, 0xc3, 0xfb, 0x57, 0x6b, 0x17, 0xc2, 0xf5, 0x94, 0x5e, 0x73, 0x1d, + 0xaf, 0xb8, 0xb2, 0xbd, 0x88, 0x7c, 0xe7, 0xd6, 0x18, 0xf2, 0xe1, 0xcb, + 0x54, 0xe7, 0x73, 0x8d, 0xe3, 0x1d, 0xb1, 0x85, 0xed, 0xcd, 0xd7, 0xdb, + 0x31, 0x5f, 0x2f, 0x35, 0x5f, 0xcf, 0xf8, 0x23, 0x13, 0x15, 0xe6, 0x31, + 0x3d, 0x6c, 0xd7, 0xd4, 0x1d, 0x29, 0x79, 0xfa, 0x3c, 0xc2, 0x80, 0x3e, + 0x8f, 0x90, 0x80, 0x6f, 0xf4, 0x94, 0x8e, 0xeb, 0xaf, 0x51, 0x48, 0xaf, + 0x34, 0xea, 0xd8, 0xbe, 0xe8, 0x33, 0x09, 0x03, 0xb0, 0xb9, 0x78, 0x0e, + 0x21, 0x90, 0x9d, 0x29, 0xf3, 0x36, 0xe7, 0x12, 0x0e, 0x07, 0xbd, 0x5e, + 0x10, 0x0c, 0xfb, 0x67, 0xad, 0x2c, 0xc7, 0xbb, 0x62, 0xea, 0xd0, 0xd7, + 0x7c, 0x14, 0xfa, 0x66, 0xde, 0xc7, 0x7c, 0x8a, 0xf6, 0x3a, 0x68, 0xa6, + 0x1b, 0x7a, 0x37, 0xf9, 0xa4, 0x68, 0xdd, 0xd1, 0x05, 0x9d, 0xeb, 0xdd, + 0xfb, 0x3e, 0xd8, 0x3a, 0x5f, 0x06, 0xad, 0x1f, 0x4b, 0xf5, 0x68, 0xff, + 0xff, 0x1c, 0x74, 0x31, 0xe3, 0x84, 0x8f, 0x69, 0xda, 0x22, 0x8d, 0x35, + 0xe8, 0xb3, 0x50, 0x27, 0x53, 0x4e, 0x34, 0xdb, 0x75, 0xde, 0xc4, 0xcd, + 0x53, 0xed, 0xde, 0x73, 0xe0, 0xb5, 0x7e, 0x7f, 0x03, 0x6c, 0x66, 0xd1, + 0x3a, 0xbf, 0x50, 0x5a, 0x6f, 0x6d, 0x83, 0x66, 0x19, 0x77, 0xb9, 0x56, + 0x93, 0xec, 0x19, 0x32, 0x3e, 0x66, 0x3c, 0xa1, 0x18, 0x23, 0xe6, 0xfa, + 0x05, 0xcf, 0x39, 0x70, 0x9d, 0x9b, 0xf1, 0x90, 0xf1, 0x7b, 0x47, 0xfc, + 0xbc, 0x17, 0xb1, 0x67, 0x23, 0xb2, 0x45, 0x43, 0x9b, 0x7b, 0xb4, 0xad, + 0x1a, 0x05, 0x3f, 0x7d, 0x0f, 0x74, 0xcf, 0xba, 0xa4, 0xfd, 0xef, 0x04, + 0x93, 0xae, 0x89, 0x4f, 0x29, 0xd4, 0xcb, 0x6a, 0x5c, 0x3d, 0x25, 0x07, + 0x4a, 0xe4, 0xff, 0xa8, 0x96, 0xe5, 0xbb, 0x53, 0x94, 0x07, 0x51, 0xe0, + 0x71, 0x0a, 0xf8, 0x6b, 0x90, 0xdd, 0x5d, 0x45, 0x94, 0x89, 0xc8, 0xd0, + 0x40, 0x03, 0x78, 0x8f, 0x76, 0x09, 0xdf, 0x2e, 0xca, 0x7b, 0x32, 0x55, + 0x1c, 0xd7, 0x7b, 0x9e, 0x1f, 0x43, 0xdd, 0xc7, 0xf1, 0x4c, 0x14, 0xcb, + 0xa8, 0xf3, 0xb0, 0x2e, 0x3f, 0x31, 0xca, 0x73, 0x22, 0x02, 0x7b, 0xff, + 0x49, 0x29, 0x4c, 0xb6, 0xc1, 0x2f, 0x99, 0x1e, 0x77, 0xe7, 0xe2, 0xe4, + 0xff, 0xa5, 0x91, 0xeb, 0xcc, 0x85, 0xeb, 0xb8, 0x27, 0x47, 0xdc, 0x81, + 0xcd, 0xaa, 0xb3, 0x49, 0xaf, 0xf9, 0xf4, 0x48, 0x3f, 0x6c, 0x8a, 0x9b, + 0x2b, 0xcf, 0xc4, 0xcc, 0xda, 0xc0, 0x82, 0xf5, 0x86, 0xc3, 0xc4, 0x8a, + 0x3a, 0xea, 0xf2, 0xdc, 0xa7, 0x4c, 0x9c, 0x81, 0xf6, 0x39, 0x1a, 0xae, + 0xe7, 0x30, 0xcd, 0x93, 0xb6, 0xeb, 0x00, 0xd7, 0x99, 0x7f, 0xd2, 0xf2, + 0xf5, 0x89, 0x4d, 0x61, 0x5f, 0xf9, 0x60, 0x6c, 0x53, 0x5e, 0x3e, 0x81, + 0x27, 0x77, 0x5d, 0x72, 0x34, 0xab, 0xd8, 0xef, 0x37, 0x02, 0xc6, 0x02, + 0x54, 0xba, 0x55, 0xf2, 0x4d, 0xd5, 0xfd, 0x33, 0xad, 0xc3, 0x2b, 0xa8, + 0xd7, 0x83, 0x63, 0x26, 0x11, 0x03, 0x0e, 0xf2, 0x6f, 0x08, 0xcf, 0x16, + 0xcf, 0x57, 0xcb, 0xc1, 0x73, 0xc2, 0xae, 0xd7, 0x70, 0x0d, 0x66, 0x05, + 0xf0, 0xd2, 0x80, 0xf4, 0x09, 0x19, 0x39, 0xfe, 0x3b, 0x31, 0xee, 0x17, + 0xaa, 0xd1, 0x7e, 0xf5, 0x7d, 0xf5, 0x26, 0x06, 0xf2, 0x2c, 0xca, 0x30, + 0x7f, 0x1c, 0x75, 0x92, 0xf9, 0x6c, 0x64, 0xad, 0x0c, 0xe9, 0x7e, 0x83, + 0x48, 0xdb, 0xb6, 0x7a, 0xbd, 0x4f, 0x5f, 0xce, 0x30, 0x6e, 0x11, 0xd6, + 0x7d, 0x56, 0xef, 0x83, 0x73, 0xd3, 0xc9, 0x7c, 0x5f, 0x84, 0xf2, 0xa9, + 0x53, 0x7a, 0xb9, 0xce, 0x73, 0x66, 0x5c, 0xd3, 0x76, 0xfb, 0x26, 0x9e, + 0x07, 0xdd, 0x02, 0xfb, 0xef, 0x3b, 0x80, 0x89, 0x30, 0x9e, 0x40, 0x3a, + 0x7c, 0xc2, 0xd7, 0x85, 0x61, 0xfa, 0x4d, 0xc2, 0x30, 0xfd, 0x26, 0x61, + 0x20, 0x2e, 0x00, 0x47, 0xa5, 0x7d, 0x75, 0x68, 0x53, 0x5c, 0x85, 0x71, + 0x1c, 0x2c, 0x4d, 0xc3, 0xbf, 0xd5, 0x31, 0x94, 0xce, 0x69, 0x45, 0x9e, + 0xf7, 0xc0, 0x73, 0xe0, 0xad, 0x12, 0x78, 0x0f, 0xb6, 0xe1, 0x97, 0x61, + 0x1b, 0x3e, 0x01, 0xdb, 0xf0, 0x1c, 0x6c, 0xc3, 0xc7, 0x31, 0x37, 0x8f, + 0x2d, 0xe0, 0xd5, 0x8c, 0xe6, 0xd5, 0x42, 0xe9, 0x02, 0x78, 0xb5, 0xeb, + 0x0a, 0xfc, 0xe8, 0xc2, 0xc6, 0xa7, 0x0d, 0xed, 0xc0, 0x96, 0xff, 0xb8, + 0xf6, 0x8b, 0x1f, 0x4c, 0x8d, 0xb1, 0x0e, 0x68, 0x38, 0x49, 0x9f, 0x16, + 0xf2, 0x3f, 0x99, 0x07, 0xef, 0x61, 0xac, 0x8e, 0xa3, 0xae, 0x5b, 0x23, + 0xd4, 0x1f, 0xee, 0x36, 0xee, 0xef, 0xe6, 0x58, 0x13, 0x8b, 0xf0, 0x64, + 0xf8, 0x73, 0x8f, 0x4f, 0x3d, 0x42, 0xbe, 0x4c, 0x7c, 0x76, 0xc4, 0xaf, + 0xe6, 0xc5, 0x1d, 0x1c, 0x5f, 0xe0, 0x6d, 0x5a, 0xae, 0xee, 0x7c, 0xf9, + 0x35, 0x73, 0xe5, 0x75, 0xff, 0xa3, 0xe4, 0x37, 0xe8, 0x6e, 0xe2, 0x3e, + 0x91, 0x8d, 0x6c, 0xb0, 0xb8, 0xdf, 0x2f, 0x6d, 0xdb, 0x60, 0xaf, 0x0f, + 0x82, 0x7e, 0xa7, 0x02, 0xf1, 0xb7, 0x85, 0x6d, 0xce, 0xb7, 0xe3, 0xd9, + 0x76, 0x76, 0xc3, 0x96, 0xed, 0xdb, 0xc4, 0xb5, 0x5e, 0xd8, 0xf2, 0xa9, + 0x70, 0x3e, 0x60, 0xf9, 0xea, 0x39, 0xa7, 0x0c, 0xa5, 0xec, 0x6c, 0xb0, + 0xf1, 0x7e, 0xb6, 0x77, 0x61, 0xd1, 0x3c, 0x5d, 0x0a, 0x78, 0xce, 0x76, + 0xc4, 0x1f, 0xab, 0xa2, 0x95, 0xbf, 0xb2, 0xb4, 0xa2, 0x16, 0x8d, 0xe3, + 0x9c, 0xa5, 0x95, 0x10, 0xde, 0x58, 0x48, 0x2b, 0x75, 0x21, 0xad, 0xe4, + 0xc7, 0x43, 0x5a, 0x61, 0xdd, 0x73, 0x21, 0xad, 0x24, 0xaa, 0x69, 0x25, + 0x3f, 0xee, 0xe0, 0x59, 0x0c, 0x07, 0xe9, 0x85, 0xed, 0x90, 0x5e, 0x00, + 0x4b, 0xa5, 0x32, 0x47, 0x2f, 0x31, 0xb4, 0x73, 0xa8, 0xa4, 0x34, 0xad, + 0x0c, 0xa9, 0x50, 0x47, 0x78, 0x98, 0x73, 0xcc, 0xfd, 0x15, 0x69, 0x24, + 0x65, 0x69, 0x64, 0xfe, 0x2c, 0xd1, 0x22, 0xda, 0x00, 0xee, 0x79, 0x5e, + 0x60, 0xb3, 0xa6, 0x8d, 0xfb, 0x53, 0x2f, 0xa0, 0xec, 0x28, 0x68, 0x23, + 0xc4, 0xc1, 0x03, 0x16, 0x07, 0x8b, 0xe7, 0xf2, 0xb4, 0xc5, 0xc1, 0xa8, + 0xc5, 0x81, 0xe6, 0x97, 0x3c, 0xe7, 0x4c, 0x69, 0x1c, 0xd4, 0x69, 0x1c, + 0x88, 0x0a, 0xeb, 0x9e, 0x5e, 0x06, 0x07, 0x2c, 0x33, 0xaa, 0xc7, 0x1f, + 0xc1, 0xf8, 0xf7, 0x61, 0xfc, 0x4a, 0x8f, 0x9f, 0xf3, 0xc0, 0xf1, 0x03, + 0x96, 0xca, 0x77, 0xe6, 0xc6, 0xdf, 0x84, 0x36, 0x0e, 0x6a, 0xdb, 0x99, + 0xf1, 0x54, 0xea, 0x46, 0x33, 0xfe, 0xc7, 0x2a, 0xe6, 0x8c, 0xc9, 0x63, + 0x4b, 0xf4, 0xd8, 0x0b, 0x96, 0x37, 0x7c, 0xbd, 0xce, 0xc6, 0x73, 0x6d, + 0xe7, 0xa0, 0xbb, 0xc6, 0x52, 0x09, 0x7b, 0xe6, 0xd4, 0xd8, 0x43, 0x5f, + 0x4d, 0x91, 0x77, 0x3e, 0xaa, 0xf7, 0xfa, 0x9d, 0xa5, 0x5d, 0x54, 0x6a, + 0x92, 0xbe, 0xb1, 0x6a, 0xb8, 0x09, 0x6f, 0x3e, 0x50, 0x3e, 0x63, 0x37, + 0xfb, 0xa1, 0x3b, 0x4c, 0xdc, 0x1a, 0xb4, 0x84, 0xf4, 0x64, 0xbe, 0x37, + 0x52, 0x27, 0xea, 0x81, 0x0f, 0x60, 0xcc, 0x2e, 0x7c, 0xcc, 0x76, 0x6f, + 0x9b, 0xa2, 0xae, 0xbb, 0xba, 0x4a, 0xd7, 0x35, 0x5b, 0x5d, 0xb7, 0x86, + 0xba, 0x0e, 0x70, 0x3f, 0x25, 0x87, 0x4b, 0x9c, 0xbf, 0x7c, 0xa2, 0x4e, + 0xc7, 0x40, 0x1d, 0x1b, 0xe7, 0x4b, 0xc6, 0x0f, 0x6b, 0x5a, 0xa6, 0xce, + 0x4a, 0xea, 0xb8, 0xe4, 0x4c, 0xd7, 0x3f, 0xd9, 0x75, 0x10, 0xea, 0xb5, + 0xef, 0x07, 0x7f, 0xb0, 0x8c, 0x5e, 0x83, 0xfe, 0xd1, 0xf6, 0x59, 0x0d, + 0x64, 0xad, 0x9c, 0x6a, 0xc6, 0xb3, 0x9a, 0xe7, 0xc1, 0x3a, 0x3b, 0x54, + 0xbd, 0xd4, 0x9c, 0x6a, 0x94, 0x3d, 0x63, 0x7a, 0xdd, 0x5c, 0xd4, 0x29, + 0xe0, 0xff, 0x14, 0xcf, 0x14, 0x88, 0x3e, 0x03, 0x95, 0x1b, 0x85, 0x3f, + 0x33, 0xf1, 0x94, 0xd9, 0x1b, 0x38, 0x56, 0xa3, 0x7f, 0xd3, 0xc6, 0x28, + 0xa4, 0x32, 0xfa, 0xec, 0xd0, 0x1e, 0xb4, 0xd9, 0xbe, 0xa9, 0x16, 0x63, + 0x8e, 0xa1, 0x2e, 0xf7, 0x16, 0xaa, 0x36, 0x57, 0x6a, 0xc5, 0x9d, 0x88, + 0xea, 0xf3, 0x4b, 0x3c, 0x7f, 0x9f, 0xed, 0x69, 0x42, 0x5e, 0x44, 0xaf, + 0x15, 0xd4, 0x9c, 0x9a, 0x3f, 0xa7, 0xae, 0x8e, 0x8a, 0x5d, 0xc3, 0x4f, + 0x6b, 0xbd, 0x12, 0x39, 0x4a, 0x9d, 0xc3, 0xfd, 0x55, 0x3d, 0x98, 0xf7, + 0xe5, 0xf4, 0x8d, 0x31, 0x62, 0xb3, 0x98, 0x3f, 0x75, 0x86, 0x67, 0x8d, + 0x5b, 0xf1, 0x0e, 0xdb, 0x0b, 0xf5, 0x08, 0x74, 0xdf, 0xdb, 0x3f, 0xe1, + 0x49, 0x3d, 0xf0, 0x3d, 0xa1, 0x80, 0x6b, 0x57, 0xd3, 0x42, 0x5e, 0x85, + 0xb1, 0x69, 0x43, 0x0f, 0x8f, 0xbf, 0x21, 0x3f, 0x90, 0x26, 0x3a, 0x6d, + 0x6c, 0xc1, 0xb7, 0x31, 0x7e, 0xd2, 0xb6, 0xa1, 0x87, 0x47, 0x53, 0x19, + 0xc5, 0xbd, 0x51, 0x66, 0x1d, 0x94, 0xb4, 0x41, 0x9a, 0x4f, 0xe8, 0xf5, + 0xd1, 0x8c, 0xbc, 0x2c, 0x99, 0xa6, 0x76, 0xd8, 0x5d, 0xff, 0xb6, 0x73, + 0x6c, 0xee, 0x2e, 0xd0, 0x34, 0x07, 0xdd, 0xc4, 0x7d, 0xca, 0x9d, 0xf2, + 0x5e, 0x9e, 0x57, 0x98, 0x70, 0xa0, 0x94, 0x9f, 0xd2, 0x7b, 0xbf, 0x77, + 0x14, 0x57, 0xcb, 0xad, 0xa9, 0xa8, 0x5d, 0xe7, 0xac, 0x05, 0x1d, 0x40, + 0x50, 0x9f, 0xaa, 0xc5, 0x13, 0x75, 0x38, 0x7f, 0x17, 0x53, 0x99, 0xa4, + 0x22, 0xb3, 0xc3, 0xe7, 0x9f, 0x91, 0x2d, 0xde, 0x1e, 0x7d, 0xce, 0x4e, + 0x9c, 0xba, 0x53, 0x7f, 0xe9, 0xd1, 0x06, 0x25, 0xfd, 0xcc, 0xf8, 0xb5, + 0x7a, 0x5d, 0xab, 0x3f, 0x15, 0x04, 0x39, 0xcc, 0x5f, 0x41, 0x4c, 0xfc, + 0x6c, 0xc2, 0x67, 0x1a, 0xfd, 0xda, 0x06, 0xa7, 0xf6, 0x4c, 0xa3, 0x63, + 0x68, 0x45, 0x22, 0x2a, 0x5d, 0xef, 0xd4, 0x9c, 0xba, 0x93, 0x73, 0x06, + 0xba, 0xf2, 0x1c, 0x43, 0x57, 0x31, 0x67, 0x9e, 0xae, 0xd6, 0xd9, 0xdf, + 0x2a, 0x5d, 0x27, 0x99, 0x64, 0x1d, 0xc6, 0xdb, 0x5b, 0x0c, 0x61, 0x3c, + 0x0c, 0xb8, 0x08, 0xcf, 0xdd, 0x18, 0xc3, 0x30, 0x9e, 0x3c, 0x60, 0x01, + 0xb3, 0x9f, 0x2a, 0x00, 0xe6, 0x83, 0x78, 0x18, 0x27, 0x6b, 0x76, 0x22, + 0x13, 0xd5, 0xf0, 0x12, 0xc6, 0x1f, 0x5b, 0x78, 0x5f, 0x0f, 0x56, 0x4f, + 0x66, 0xba, 0x8b, 0x80, 0x87, 0x70, 0xde, 0x07, 0x18, 0x69, 0x97, 0x8e, + 0xe2, 0xdb, 0x03, 0x7c, 0x63, 0x16, 0x26, 0xd0, 0xe3, 0xd8, 0x43, 0xf3, + 0xbf, 0x8b, 0xb4, 0x93, 0x8f, 0xd9, 0xef, 0xd6, 0x45, 0x32, 0xe0, 0x15, + 0x87, 0x78, 0x1e, 0x29, 0xbd, 0xe6, 0xc0, 0x0e, 0x00, 0xdf, 0xbf, 0xe4, + 0x44, 0xce, 0xc4, 0xe5, 0x50, 0x91, 0x31, 0x84, 0xe3, 0x0e, 0xe7, 0x41, + 0xf9, 0x57, 0xa1, 0x4c, 0x5c, 0xc9, 0xc4, 0xd5, 0x78, 0xde, 0x82, 0x67, + 0x03, 0x9e, 0x8d, 0x78, 0xd6, 0xe3, 0x69, 0xc5, 0xf3, 0x2d, 0x94, 0x53, + 0xb1, 0x3a, 0xe1, 0x7e, 0xd5, 0x16, 0xa5, 0x34, 0x1f, 0x71, 0xcf, 0xc2, + 0x65, 0xc0, 0xe5, 0x2b, 0xd0, 0x3b, 0x1e, 0x9e, 0xf1, 0xf8, 0x3a, 0xfa, + 0x98, 0xc5, 0xd3, 0xa9, 0xe4, 0x4c, 0x17, 0x9e, 0x14, 0x9e, 0x6e, 0x3c, + 0x3d, 0x78, 0xd2, 0x78, 0x5e, 0x75, 0x0c, 0xcf, 0x5d, 0x02, 0xbe, 0x42, + 0x1e, 0x01, 0xce, 0x17, 0xf0, 0x9c, 0xe7, 0xbc, 0x09, 0x9e, 0x73, 0x2c, + 0xcf, 0x39, 0xf3, 0x3c, 0x57, 0xeb, 0xa8, 0x63, 0xf5, 0x4e, 0xe4, 0x18, + 0x7d, 0x85, 0x5a, 0xc7, 0xf0, 0x7f, 0x44, 0x7a, 0x07, 0x41, 0x4b, 0xc7, + 0x30, 0x67, 0xc7, 0x48, 0x57, 0x2e, 0xd2, 0xc7, 0x16, 0xf5, 0x3b, 0xfa, + 0x26, 0xfa, 0x3d, 0x61, 0xfb, 0x7d, 0xb8, 0xaa, 0xdf, 0x83, 0x68, 0xfb, + 0x3e, 0xdb, 0xef, 0xc1, 0xaa, 0x7e, 0x41, 0x2b, 0xc7, 0xf2, 0x78, 0x48, + 0x17, 0x23, 0x48, 0x0f, 0x65, 0xc2, 0xdd, 0x6b, 0xa4, 0xbe, 0x46, 0x9f, + 0x27, 0x8d, 0xf9, 0x35, 0x73, 0xba, 0x31, 0x53, 0xa5, 0x1f, 0x7e, 0x16, + 0xfd, 0x38, 0x5c, 0xa2, 0x8d, 0x38, 0x5d, 0x25, 0x17, 0xe8, 0xfb, 0x04, + 0x72, 0x5c, 0xfb, 0x39, 0xf4, 0x79, 0xe8, 0xff, 0x2c, 0xb6, 0xad, 0x3e, + 0xae, 0xf7, 0xe7, 0xde, 0x55, 0x6c, 0x95, 0x4f, 0x14, 0x69, 0x13, 0x92, + 0x5e, 0x82, 0x60, 0xcf, 0x36, 0xda, 0xa7, 0xf9, 0x60, 0x9d, 0x9f, 0xd4, + 0xb1, 0xb5, 0x4f, 0x2e, 0xd5, 0x19, 0xa3, 0xbd, 0xf0, 0xcd, 0xb3, 0x47, + 0x3f, 0x08, 0x9d, 0x51, 0x03, 0xb8, 0x9f, 0xd2, 0x77, 0x80, 0xec, 0x1a, + 0x55, 0x23, 0x6b, 0x25, 0x2e, 0x37, 0x17, 0x6b, 0x61, 0xf7, 0x30, 0x56, + 0x5e, 0x2f, 0xed, 0xdb, 0xa2, 0xe6, 0x6c, 0x8d, 0x17, 0xc3, 0x6f, 0xcf, + 0x9c, 0xf5, 0x89, 0xc5, 0x91, 0x1f, 0x69, 0xa2, 0x1c, 0x8c, 0xf9, 0xef, + 0xd4, 0xfb, 0x26, 0xdb, 0xb6, 0xd1, 0x6e, 0xb9, 0x41, 0xeb, 0x70, 0x77, + 0x89, 0x9d, 0xa4, 0x5a, 0x3c, 0x99, 0xb7, 0xd1, 0x76, 0x17, 0x93, 0x09, + 0xc2, 0xf5, 0x90, 0x70, 0x3f, 0xc1, 0x7e, 0x29, 0xa4, 0x1a, 0x25, 0x92, + 0xe6, 0xba, 0x5c, 0xb2, 0x93, 0xb6, 0xd1, 0xc4, 0x98, 0x67, 0xcf, 0x9e, + 0xac, 0x96, 0x0b, 0xba, 0x9f, 0x5a, 0x0d, 0xa3, 0x39, 0x8f, 0xc6, 0x35, + 0x2f, 0x9e, 0x81, 0x72, 0xf1, 0x6e, 0xd0, 0x7a, 0x67, 0xa2, 0xcc, 0xb3, + 0x4e, 0xf0, 0x97, 0xca, 0x31, 0x7d, 0xc6, 0xd4, 0x7b, 0x3b, 0xfc, 0xd8, + 0xf2, 0x06, 0xd9, 0x3d, 0xb6, 0x82, 0xeb, 0x28, 0xb1, 0xb5, 0xd0, 0x1f, + 0xac, 0xd3, 0xb6, 0x0d, 0xfe, 0xdf, 0xf8, 0x46, 0x79, 0x7c, 0x9c, 0x6d, + 0xb7, 0xc8, 0xe4, 0x94, 0x38, 0xde, 0xdb, 0x57, 0xa2, 0x8c, 0xc7, 0xf1, + 0x08, 0xf7, 0x3c, 0xb5, 0x6d, 0x13, 0xe5, 0xbd, 0xdd, 0x95, 0xf3, 0xdd, + 0x11, 0xbd, 0x26, 0xe3, 0x82, 0x4e, 0xd8, 0xde, 0xf9, 0xee, 0x56, 0x39, + 0x3b, 0x05, 0x9a, 0x80, 0xdc, 0xef, 0x3b, 0x45, 0x98, 0x44, 0xb6, 0x4f, + 0xc0, 0x5e, 0x90, 0x76, 0x3c, 0xa0, 0x0f, 0xc8, 0xef, 0x5b, 0xbb, 0xd9, + 0x17, 0xf4, 0x12, 0x74, 0x5c, 0xdb, 0x36, 0x23, 0x0b, 0x32, 0x13, 0x35, + 0x48, 0x67, 0xbb, 0xf0, 0x0f, 0x07, 0xd9, 0x4e, 0x58, 0x57, 0x61, 0x4c, + 0xb5, 0x9a, 0x5e, 0x66, 0x17, 0xe9, 0x8f, 0x73, 0x3f, 0x97, 0xfd, 0xcd, + 0x36, 0x3a, 0x41, 0x2b, 0xbe, 0xde, 0xc3, 0x63, 0x6c, 0x2b, 0xce, 0x09, + 0x6d, 0x22, 0xda, 0x55, 0xd7, 0x6a, 0xfb, 0x62, 0xb2, 0xc2, 0x19, 0xe4, + 0xda, 0x48, 0x38, 0x47, 0x71, 0x39, 0x59, 0x9a, 0x9b, 0xa7, 0x0d, 0x35, + 0x0b, 0xe7, 0x89, 0xb4, 0x92, 0x1a, 0xb2, 0xb6, 0xc7, 0x8c, 0x3c, 0x0f, + 0xbb, 0xac, 0x53, 0xcf, 0xd9, 0x0c, 0x6c, 0x59, 0x3b, 0x67, 0xda, 0x9e, + 0x2d, 0x84, 0x73, 0x36, 0x00, 0x8d, 0x53, 0xbe, 0x41, 0xcf, 0x99, 0x07, + 0xba, 0xc9, 0x03, 0xef, 0x79, 0xcc, 0x53, 0x1e, 0x73, 0x94, 0x2f, 0xb7, + 0xc8, 0xc4, 0x71, 0xd5, 0x5a, 0x23, 0x92, 0xd8, 0xed, 0xb7, 0xc8, 0xf0, + 0x14, 0x63, 0x05, 0x1b, 0x60, 0x83, 0x6d, 0xc4, 0xd3, 0x8a, 0x6f, 0xd6, + 0xe3, 0x1d, 0x1f, 0x0a, 0x75, 0xeb, 0x96, 0xd8, 0x59, 0x67, 0xd1, 0xf7, + 0xd3, 0xc0, 0xc3, 0xa3, 0xc0, 0xc3, 0x3c, 0xef, 0xbc, 0x50, 0x15, 0x5f, + 0xe2, 0x58, 0xb5, 0x0e, 0xc5, 0x78, 0x63, 0x7a, 0x3e, 0x75, 0x9c, 0xa9, + 0x54, 0xfb, 0x66, 0xec, 0xa9, 0x38, 0xed, 0xa9, 0xdc, 0xa8, 0x67, 0xce, + 0x60, 0x0d, 0xc0, 0x77, 0xf2, 0xf7, 0x69, 0x5a, 0x1f, 0x1a, 0x27, 0x5c, + 0xd1, 0x10, 0xae, 0x05, 0x73, 0xc6, 0x33, 0xb3, 0x4b, 0xe3, 0x18, 0x2f, + 0xcc, 0xed, 0x11, 0x87, 0x2e, 0x97, 0xd1, 0x14, 0xe3, 0x24, 0xad, 0xcb, + 0xc0, 0xf4, 0x94, 0xb6, 0x61, 0x45, 0x9d, 0x96, 0x03, 0x25, 0x9e, 0xb7, + 0xe5, 0x1a, 0xcc, 0xef, 0x31, 0x7e, 0xd4, 0x39, 0x21, 0xc7, 0xd0, 0x37, + 0xd7, 0xc5, 0x95, 0x8d, 0xcf, 0xac, 0xb2, 0x7b, 0xf2, 0xaa, 0x63, 0x34, + 0x66, 0xdd, 0x7c, 0xe1, 0xd9, 0x93, 0xe4, 0xc0, 0xac, 0x5e, 0x77, 0xe5, + 0x9a, 0xa1, 0x8c, 0x46, 0xa0, 0xfd, 0x76, 0x77, 0x27, 0x7b, 0xcc, 0x59, + 0xc3, 0x84, 0xf4, 0x97, 0xcc, 0xf8, 0x2f, 0xea, 0x7d, 0x93, 0x66, 0x7f, + 0xb8, 0xd9, 0x53, 0xb9, 0x5f, 0x2e, 0xa6, 0xa2, 0x55, 0x73, 0x5b, 0x27, + 0xc3, 0xc0, 0x85, 0x5e, 0xcb, 0x84, 0x5d, 0x9c, 0xeb, 0x7e, 0xbc, 0x89, + 0x67, 0xd1, 0xa2, 0x98, 0x9f, 0xc2, 0x38, 0xcf, 0xa7, 0xb3, 0xdd, 0x2b, + 0xb5, 0x45, 0x31, 0xcb, 0xb3, 0x4e, 0x90, 0x95, 0x6f, 0xdd, 0x12, 0xaf, + 0xd7, 0xf9, 0x2b, 0xec, 0x99, 0x16, 0xd8, 0x0d, 0xbb, 0x02, 0xf9, 0x33, + 0xe8, 0xc9, 0xd3, 0x76, 0x4c, 0x09, 0x1d, 0x93, 0x92, 0xe0, 0x7c, 0x2a, + 0x6e, 0xe3, 0xce, 0x1c, 0xcb, 0x98, 0xa5, 0x6f, 0x63, 0xff, 0xcc, 0xdb, + 0xd0, 0x5d, 0x9a, 0xd6, 0x1f, 0xd7, 0xb2, 0xb0, 0xcb, 0xda, 0xce, 0x3a, + 0x8e, 0x73, 0x42, 0xf4, 0x1e, 0xac, 0xd0, 0x37, 0xea, 0xa8, 0xf2, 0x0b, + 0x8c, 0x2f, 0x57, 0x18, 0x5b, 0x4e, 0x46, 0xcd, 0xfb, 0x84, 0xf4, 0xe5, + 0xf6, 0x6c, 0xe2, 0xdd, 0x30, 0xa1, 0x2f, 0xd7, 0x65, 0x7d, 0xb9, 0x46, + 0xed, 0xcb, 0x99, 0xd8, 0x43, 0xe3, 0x9c, 0x2f, 0x57, 0x18, 0xcb, 0x83, + 0x56, 0x6a, 0xed, 0x59, 0x09, 0x63, 0x0b, 0x0d, 0x17, 0x5d, 0xbd, 0x6f, + 0x24, 0x37, 0xa0, 0xe0, 0x37, 0x18, 0x1f, 0x8b, 0xb1, 0x0a, 0xa5, 0xfe, + 0xce, 0xfa, 0x17, 0x1b, 0x24, 0xd3, 0xbc, 0x02, 0xe3, 0x7e, 0x4a, 0xcf, + 0xb9, 0x59, 0xc3, 0x82, 0x5c, 0x1b, 0x64, 0xcc, 0x87, 0x67, 0x47, 0x35, + 0x7f, 0x25, 0x7a, 0x23, 0x9d, 0xc6, 0x9e, 0xf5, 0x13, 0x6b, 0xa5, 0xfe, + 0xb8, 0x53, 0x18, 0x8f, 0xda, 0x7e, 0x13, 0x80, 0xa9, 0x06, 0x73, 0xf3, + 0x4e, 0x2b, 0x93, 0xd9, 0xf7, 0x3b, 0xea, 0x18, 0x1b, 0x98, 0x2a, 0x9a, + 0x18, 0x60, 0x5f, 0x31, 0x12, 0x9e, 0x5b, 0x57, 0x5c, 0x47, 0xce, 0x0c, + 0xae, 0x00, 0x2c, 0x2b, 0x96, 0xb5, 0x59, 0x1f, 0x7b, 0x43, 0x1d, 0x45, + 0x9a, 0x7a, 0x4a, 0xef, 0x2f, 0x5c, 0xd9, 0x9d, 0xdc, 0xa9, 0xcf, 0x23, + 0xe9, 0x58, 0x62, 0x5e, 0xb8, 0x7f, 0xf7, 0x9b, 0xf2, 0x36, 0x2d, 0xfb, + 0x0f, 0xa4, 0xa8, 0xc7, 0xb6, 0xe9, 0xdf, 0xb5, 0xe9, 0x20, 0x38, 0xdf, + 0xfd, 0x2c, 0x6c, 0x16, 0xdf, 0xfb, 0x96, 0xb4, 0xc7, 0x7b, 0xb5, 0x0d, + 0x85, 0xb9, 0x1a, 0xac, 0x97, 0x15, 0xfe, 0xb8, 0xdd, 0xab, 0x68, 0xd6, + 0x03, 0x0b, 0xc2, 0xfb, 0x17, 0x3a, 0x6c, 0x5e, 0x3e, 0xa8, 0x07, 0x3d, + 0x7d, 0x44, 0x8c, 0xac, 0xc9, 0xcd, 0xcb, 0x1a, 0xee, 0xa7, 0xcb, 0x90, + 0xa0, 0xdd, 0x23, 0x92, 0xe4, 0xdd, 0x49, 0xec, 0xbb, 0x20, 0x57, 0x41, + 0x3f, 0xb3, 0x1e, 0x6d, 0x56, 0x7e, 0x73, 0x0f, 0x8a, 0xef, 0x1d, 0x84, + 0x8e, 0xb9, 0x61, 0xa9, 0x8e, 0x89, 0xd3, 0xbf, 0xcf, 0x8d, 0xd2, 0x47, + 0x5c, 0x89, 0x3a, 0x2d, 0xf2, 0xd1, 0xb1, 0xdf, 0x5a, 0x4b, 0x1e, 0x1b, + 0x82, 0x7c, 0x57, 0xf7, 0x87, 0xe7, 0x2e, 0x99, 0xc6, 0x7c, 0xb6, 0x5b, + 0x27, 0x89, 0xf7, 0x79, 0xf2, 0xc5, 0x4a, 0x32, 0x31, 0x0b, 0x1d, 0x35, + 0xe4, 0x0c, 0xb7, 0x9a, 0xd8, 0xe9, 0xa7, 0xd6, 0x9a, 0x73, 0x5a, 0xf5, + 0xc0, 0x69, 0x18, 0x4f, 0xad, 0xa6, 0xdd, 0x59, 0x2b, 0x97, 0x83, 0xa0, + 0xbe, 0x5b, 0xcb, 0xe2, 0x9d, 0x94, 0xc5, 0x07, 0x52, 0x1d, 0x86, 0x07, + 0xb4, 0xef, 0xc4, 0x3d, 0x00, 0xc0, 0x43, 0xb7, 0xcb, 0xbd, 0xd0, 0x96, + 0x4f, 0xfd, 0xcc, 0x8c, 0x95, 0x4f, 0xca, 0x59, 0xca, 0x9f, 0x6a, 0x6b, + 0x74, 0x81, 0xec, 0x3d, 0x34, 0x46, 0xbd, 0x9c, 0x9a, 0xfe, 0x26, 0xe4, + 0x55, 0x4e, 0xe3, 0xa1, 0x45, 0xee, 0x1b, 0x93, 0xcc, 0x45, 0xe8, 0xac, + 0xc2, 0xd4, 0x42, 0x1e, 0x5d, 0xda, 0x1e, 0xc7, 0x7a, 0x7a, 0xad, 0xf1, + 0x71, 0x17, 0x8e, 0x75, 0x9a, 0x7b, 0x8c, 0xf4, 0x58, 0xb9, 0x37, 0xff, + 0x9c, 0x1d, 0xeb, 0xca, 0x70, 0xac, 0x3d, 0x0b, 0xc7, 0x1a, 0xfa, 0xf8, + 0xa1, 0xfc, 0x4d, 0xe8, 0xb3, 0x49, 0xfa, 0x4c, 0xcc, 0xd8, 0x4a, 0xe9, + 0x1d, 0x6d, 0xb4, 0x72, 0xd3, 0x83, 0x0e, 0xe2, 0x79, 0xa1, 0xe9, 0xcf, + 0x79, 0x62, 0x71, 0xa6, 0x88, 0x07, 0xca, 0xdc, 0x26, 0x7d, 0x9e, 0x71, + 0x02, 0x7e, 0xd6, 0x87, 0x8b, 0x2c, 0x1b, 0xe6, 0x5f, 0x29, 0x46, 0x1c, + 0xfa, 0xd6, 0xf4, 0x9f, 0x3a, 0x97, 0xc4, 0x16, 0x4c, 0x1c, 0x98, 0xf1, + 0x5f, 0x73, 0xcf, 0x02, 0xf7, 0x7d, 0xdf, 0x01, 0xde, 0xfa, 0xed, 0x62, + 0xb2, 0x27, 0x1b, 0xa1, 0x3c, 0x9d, 0x95, 0x43, 0x95, 0x3e, 0x69, 0xd3, + 0x67, 0xed, 0xdf, 0x30, 0x46, 0x9c, 0xa9, 0x8e, 0x11, 0x8b, 0x63, 0x62, + 0xc4, 0x3b, 0x7f, 0x8e, 0x18, 0xb1, 0x38, 0x26, 0x46, 0xbc, 0x9c, 0x9f, + 0x35, 0x52, 0x9a, 0xc5, 0xb8, 0xea, 0x21, 0x53, 0x94, 0x93, 0x9b, 0x6a, + 0xc0, 0xbb, 0x16, 0x6f, 0xc0, 0x32, 0x56, 0xc0, 0xdb, 0xc3, 0xfb, 0x20, + 0xde, 0x31, 0x19, 0x99, 0xd3, 0x1d, 0xb3, 0x90, 0x1f, 0xd4, 0x69, 0xac, + 0x6b, 0xfc, 0x82, 0xc9, 0x72, 0x33, 0xca, 0x5d, 0x72, 0x26, 0x58, 0xaf, + 0xd4, 0x28, 0xc3, 0x63, 0x94, 0xdd, 0x4d, 0x32, 0x3a, 0x16, 0xda, 0xb8, + 0x9f, 0x5d, 0xcf, 0xb5, 0x81, 0x21, 0x09, 0x6d, 0xd8, 0x67, 0xd6, 0x9b, + 0xb5, 0xdb, 0x2d, 0x31, 0xa9, 0x5f, 0x8d, 0x39, 0x38, 0xee, 0x5c, 0x1c, + 0x5f, 0xbd, 0xc0, 0x96, 0x4d, 0xd8, 0xd8, 0xe0, 0xb8, 0xd5, 0xc1, 0xcb, + 0xcb, 0x88, 0xea, 0xf9, 0x8f, 0xdb, 0x73, 0xbc, 0x51, 0x7b, 0xd7, 0x5f, + 0x42, 0xcf, 0xcf, 0x40, 0x65, 0x16, 0xfd, 0xad, 0x57, 0x99, 0x71, 0x8e, + 0x73, 0xee, 0x7e, 0x1e, 0xc8, 0xc5, 0x56, 0x35, 0x34, 0xbe, 0x80, 0x2e, + 0x41, 0xb7, 0x1c, 0x9b, 0x03, 0xda, 0xbd, 0x57, 0x26, 0x46, 0x09, 0x5f, + 0x47, 0x3c, 0xa2, 0xcf, 0xf5, 0xe2, 0x7b, 0xdc, 0x9c, 0x27, 0xea, 0xad, + 0x84, 0x67, 0x7a, 0xd7, 0x00, 0xde, 0xc5, 0xe7, 0x7a, 0xad, 0x9e, 0xd6, + 0x36, 0x04, 0xcf, 0xf7, 0x86, 0x63, 0x58, 0x8e, 0x9e, 0x02, 0x19, 0xd6, + 0xfb, 0x7d, 0xd7, 0xca, 0xe9, 0x07, 0xe7, 0xce, 0x17, 0x34, 0xc1, 0x56, + 0x69, 0x85, 0xa9, 0x3c, 0xe0, 0xa6, 0xb9, 0xef, 0x82, 0xfb, 0x0b, 0x3a, + 0xe2, 0xb7, 0xe9, 0x73, 0x1f, 0xf3, 0x67, 0xac, 0xe7, 0xcf, 0x7e, 0x84, + 0x67, 0x5a, 0xe3, 0xd2, 0x07, 0x3a, 0xec, 0xd7, 0xe9, 0x31, 0x8c, 0x87, + 0x6b, 0xbe, 0x1a, 0x0f, 0x90, 0x3d, 0x5c, 0xfb, 0xc5, 0xd8, 0x2b, 0x2d, + 0x2a, 0xa7, 0xcf, 0x58, 0x47, 0x2d, 0x8d, 0x5d, 0x76, 0xf6, 0x94, 0x13, + 0x6a, 0x4f, 0xd9, 0x57, 0x7b, 0xcb, 0x36, 0xaf, 0xfb, 0x01, 0xcc, 0x07, + 0x7e, 0x8f, 0x17, 0x9d, 0x21, 0xe0, 0xab, 0x50, 0x3a, 0xe2, 0x64, 0xf4, + 0xfb, 0xa8, 0x7d, 0x43, 0x0e, 0x60, 0xae, 0x7a, 0xc7, 0xa3, 0x5a, 0xde, + 0xcf, 0xdf, 0xd3, 0x17, 0xce, 0xeb, 0x0b, 0x7a, 0x0d, 0x68, 0x5a, 0x88, + 0x6b, 0xcf, 0xda, 0x10, 0xc7, 0x9d, 0x9c, 0xc6, 0x3d, 0xcb, 0x7c, 0x4b, + 0xff, 0x06, 0x9d, 0x2b, 0xd3, 0x5e, 0x2b, 0xde, 0x8b, 0xf7, 0x4d, 0x86, + 0xfa, 0x86, 0x70, 0xdf, 0x09, 0xbd, 0x16, 0xec, 0x37, 0xf2, 0x6a, 0x56, + 0x46, 0x2a, 0x5c, 0xc3, 0x64, 0x3b, 0x48, 0x2f, 0xd7, 0xc0, 0x1e, 0x58, + 0x78, 0xbe, 0xba, 0x7f, 0x7e, 0x1e, 0x12, 0xe3, 0x42, 0x58, 0xee, 0xd6, + 0x67, 0x17, 0xab, 0xef, 0x1e, 0xb9, 0xf2, 0xbf, 0x70, 0xfd, 0xd0, 0xc8, + 0x50, 0x0b, 0x47, 0x86, 0xf2, 0xce, 0xc8, 0x95, 0xaf, 0xcb, 0x41, 0xe0, + 0xf1, 0x30, 0x60, 0x52, 0xf7, 0xf3, 0xce, 0xab, 0x57, 0xa5, 0x30, 0x59, + 0x2f, 0xea, 0xa1, 0x82, 0xe3, 0x3e, 0x54, 0x2b, 0x91, 0x87, 0x94, 0x53, + 0xf3, 0x50, 0xbb, 0xf6, 0xcf, 0x77, 0xa4, 0xda, 0xe3, 0x7b, 0xe5, 0xb8, + 0xe3, 0xde, 0xaf, 0xf4, 0x59, 0xdb, 0x82, 0xc7, 0x58, 0xdf, 0x71, 0x27, + 0x72, 0x7f, 0xd4, 0x9e, 0xd3, 0x37, 0xf1, 0xbd, 0x59, 0xcd, 0xf7, 0xdf, + 0x58, 0x47, 0x9c, 0xcd, 0x0a, 0xf1, 0xf1, 0x59, 0xc8, 0xad, 0x4f, 0x4b, + 0x76, 0x34, 0x31, 0x57, 0xc6, 0xec, 0xb3, 0xdf, 0xb0, 0xce, 0xf0, 0x0b, + 0xcb, 0xbc, 0xe2, 0xf0, 0xce, 0x1c, 0xa3, 0x33, 0x3e, 0xdf, 0x12, 0xee, + 0xb9, 0x37, 0x73, 0xca, 0xfc, 0xc6, 0x75, 0x52, 0xff, 0x0a, 0xe6, 0x8b, + 0xfd, 0x11, 0x57, 0xab, 0xf4, 0x3d, 0x05, 0x9e, 0x6c, 0x89, 0xd7, 0xcd, + 0xd9, 0x43, 0x46, 0xf6, 0xd6, 0x01, 0x6e, 0xc0, 0x6f, 0xec, 0x3b, 0x21, + 0x9d, 0x0a, 0x24, 0x37, 0x69, 0xb6, 0xa3, 0x67, 0x87, 0x98, 0x39, 0x33, + 0x34, 0xb3, 0xc2, 0xd8, 0x91, 0xf8, 0x36, 0x74, 0xa1, 0x64, 0xfb, 0xd8, + 0x4b, 0x4e, 0x3f, 0xcf, 0x3c, 0x8a, 0xb6, 0x1b, 0x97, 0xb3, 0x09, 0xc1, + 0x4b, 0xcf, 0x5b, 0xff, 0x32, 0x08, 0xc6, 0x52, 0x29, 0xde, 0x2b, 0xb8, + 0x8c, 0x4f, 0xb9, 0xca, 0x99, 0x1c, 0x6d, 0x70, 0x26, 0x46, 0x03, 0xd9, + 0x93, 0xe2, 0x9d, 0x49, 0xdc, 0x93, 0xa0, 0xe3, 0xe3, 0x48, 0x6b, 0x87, + 0x6e, 0x7d, 0xc7, 0x3a, 0xee, 0x71, 0xbb, 0xd9, 0x6f, 0xb4, 0xe5, 0x88, + 0x63, 0xfa, 0xca, 0xed, 0x27, 0x72, 0xc2, 0xbb, 0x8b, 0xb6, 0xc4, 0x63, + 0x7a, 0x7f, 0xe2, 0x17, 0x50, 0x0f, 0x7d, 0x94, 0xd8, 0xaf, 0xeb, 0x4c, + 0x40, 0x9e, 0x4d, 0x8e, 0xf1, 0xbe, 0x14, 0x9e, 0x63, 0x88, 0xb4, 0x2a, + 0xb9, 0xd6, 0x1b, 0xb6, 0xf7, 0x69, 0xe6, 0xe1, 0x0a, 0x45, 0x74, 0xda, + 0x16, 0x6f, 0xf7, 0xdc, 0x1d, 0x9b, 0x61, 0x5a, 0x78, 0xd7, 0xa6, 0xd2, + 0x67, 0x56, 0xe0, 0xd3, 0x9e, 0x1e, 0x92, 0xb8, 0x33, 0x55, 0x6c, 0x75, + 0x4e, 0x16, 0x33, 0x5b, 0xd7, 0x81, 0x3e, 0xce, 0xa7, 0x3e, 0x46, 0xf9, + 0x05, 0xdb, 0xef, 0x45, 0xc9, 0x57, 0x3e, 0x24, 0xe3, 0x2d, 0xed, 0xde, + 0xfd, 0x7a, 0x6e, 0x2e, 0x03, 0x67, 0x2d, 0x2a, 0x3b, 0xfa, 0xc4, 0x3a, + 0xea, 0xb7, 0xdd, 0x45, 0x05, 0x5e, 0x56, 0xbf, 0x88, 0x07, 0x36, 0x6e, + 0xad, 0xb6, 0x51, 0xf6, 0xa6, 0x58, 0xae, 0xc1, 0xe9, 0x1d, 0x5d, 0x85, + 0x79, 0xdc, 0x05, 0xfd, 0xe9, 0xc0, 0x46, 0x22, 0xae, 0x1b, 0x9c, 0x3d, + 0xa3, 0x79, 0xf4, 0xc8, 0x7d, 0xd6, 0xbc, 0xf7, 0xf0, 0x30, 0xc6, 0xa8, + 0xe5, 0x2b, 0x78, 0xf7, 0x12, 0xd7, 0xdb, 0x83, 0x49, 0xd8, 0x06, 0xb9, + 0xae, 0x7f, 0x67, 0xd7, 0xab, 0xa7, 0xaf, 0xb0, 0x5e, 0xed, 0xc9, 0x23, + 0x15, 0x7d, 0x6f, 0x48, 0xe7, 0xb8, 0xe2, 0x3a, 0x6e, 0xf3, 0x55, 0x7a, + 0x7e, 0x54, 0x87, 0xdd, 0x1b, 0x78, 0x72, 0x9d, 0xbd, 0xd3, 0x06, 0x70, + 0x5c, 0x05, 0x18, 0x36, 0x62, 0xfc, 0x84, 0xc1, 0xd4, 0x11, 0x75, 0x4b, + 0x9c, 0x3a, 0x70, 0x56, 0x4e, 0xaf, 0x0b, 0xf7, 0x7b, 0xa0, 0x1d, 0xc8, + 0xb5, 0x47, 0xe3, 0x46, 0x37, 0xae, 0x5d, 0xa6, 0x9d, 0x70, 0x3c, 0x8e, + 0x1d, 0x0f, 0x69, 0x75, 0x43, 0x0b, 0xfd, 0x89, 0x59, 0xa9, 0x5b, 0x54, + 0x9e, 0xf1, 0xfc, 0x5d, 0xad, 0x66, 0xdf, 0x11, 0xcb, 0x7a, 0xb0, 0x4b, + 0x69, 0xe3, 0x12, 0x77, 0x7a, 0xae, 0x8a, 0xdc, 0x5b, 0x9c, 0xf3, 0x2f, + 0x43, 0x9e, 0x5c, 0xeb, 0xbd, 0x4d, 0x91, 0xf6, 0x42, 0xfc, 0x12, 0xb7, + 0x09, 0xe0, 0x95, 0x71, 0x95, 0xd3, 0x41, 0x66, 0x80, 0x7c, 0xc5, 0x36, + 0x98, 0xff, 0xa2, 0x8e, 0xe5, 0x0e, 0xa6, 0x18, 0x27, 0x6a, 0x3f, 0x71, + 0x87, 0x0a, 0x65, 0xd3, 0x2c, 0xd7, 0x10, 0x1c, 0xde, 0x21, 0xba, 0x0b, + 0x1d, 0x5e, 0x9c, 0x52, 0xce, 0x37, 0xc7, 0x5c, 0x7c, 0xd7, 0xd8, 0xfb, + 0x42, 0x8d, 0x6e, 0x12, 0xf9, 0xeb, 0x70, 0xbc, 0xf1, 0x3c, 0xe6, 0xfb, + 0x12, 0xe6, 0x7b, 0xf9, 0xfb, 0x41, 0x91, 0x57, 0x46, 0x5e, 0xf9, 0x43, + 0x41, 0xa6, 0x89, 0xf4, 0x47, 0x9a, 0x7b, 0x3d, 0x9f, 0x59, 0xef, 0x63, + 0x02, 0x6c, 0x67, 0xc1, 0x0b, 0x19, 0xae, 0x25, 0x07, 0xc7, 0x52, 0x37, + 0x81, 0x17, 0x76, 0xca, 0x9f, 0xc0, 0x16, 0xf8, 0xe3, 0x4a, 0x1a, 0x3c, + 0xd1, 0x03, 0x1e, 0xe9, 0x06, 0x5f, 0xa4, 0xb4, 0x5d, 0xfc, 0x28, 0x74, + 0xde, 0xd9, 0x4a, 0xc9, 0xd9, 0x3b, 0x5a, 0x74, 0x72, 0xa3, 0x47, 0x41, + 0x17, 0xdc, 0x03, 0xab, 0xae, 0xa9, 0x11, 0x37, 0x3e, 0x29, 0xa4, 0xff, + 0x76, 0xee, 0xed, 0x68, 0x06, 0xae, 0xce, 0x10, 0x57, 0x93, 0x95, 0x2d, + 0xde, 0x3a, 0xf0, 0x41, 0xb3, 0xe6, 0x83, 0x46, 0x27, 0xe3, 0xdd, 0x64, + 0xf9, 0x60, 0x04, 0x7c, 0x50, 0x58, 0xc2, 0x07, 0xcf, 0x58, 0x9a, 0x9f, + 0xae, 0xe2, 0x83, 0x49, 0x9b, 0x36, 0x7e, 0x05, 0x3e, 0xb8, 0xca, 0x4f, + 0x3e, 0x39, 0x24, 0x27, 0xc0, 0x07, 0x0f, 0x6b, 0x3e, 0xb8, 0x4a, 0xf3, + 0x01, 0xe3, 0x46, 0xe4, 0x85, 0x56, 0xc8, 0x0e, 0xf2, 0xc2, 0xb3, 0x32, + 0x0b, 0x5e, 0x78, 0x51, 0xb1, 0xef, 0xcb, 0xb4, 0x0f, 0x46, 0xe9, 0x8f, + 0x9d, 0x2a, 0x15, 0xc1, 0xbb, 0x4a, 0xbe, 0x30, 0x16, 0x04, 0x33, 0xf0, + 0xd1, 0x1f, 0x84, 0x0d, 0xef, 0xea, 0x3b, 0x69, 0xa7, 0x61, 0xbb, 0x10, + 0x36, 0xda, 0xe4, 0xe3, 0x0e, 0xe8, 0xfd, 0xf0, 0x04, 0xc6, 0xb0, 0x47, + 0xfd, 0x3e, 0xfc, 0x60, 0x0f, 0xf3, 0x4a, 0xdb, 0xfe, 0xb8, 0xe6, 0x9b, + 0x1a, 0xe8, 0x80, 0x93, 0xdd, 0x8c, 0x33, 0xf9, 0xde, 0x5e, 0xd5, 0x9e, + 0xef, 0x03, 0xcc, 0x11, 0x75, 0xbf, 0x30, 0xc6, 0xd1, 0xb4, 0xc8, 0xb6, + 0xa7, 0x5c, 0x18, 0x90, 0xfb, 0x6c, 0x5e, 0x3e, 0xa8, 0x83, 0x1d, 0x5a, + 0xa7, 0x8c, 0x5d, 0xae, 0xb6, 0x25, 0xbd, 0xdf, 0x80, 0xd0, 0xac, 0x4d, + 0x9b, 0x3d, 0x81, 0x7d, 0xc5, 0x6a, 0xbb, 0xfe, 0x5e, 0xd8, 0xf5, 0xac, + 0x23, 0xae, 0xb1, 0xeb, 0xef, 0xb2, 0xbc, 0xc6, 0xdf, 0x9e, 0xb6, 0xf1, + 0x0f, 0x00, 0xbe, 0x1d, 0x73, 0x36, 0x3e, 0xdb, 0xa0, 0xad, 0x21, 0x72, + 0x03, 0xec, 0xbc, 0x1b, 0xc1, 0x83, 0x37, 0xc1, 0x8f, 0x7a, 0x77, 0xd1, + 0x93, 0x9d, 0xc5, 0x66, 0xf8, 0xdb, 0xad, 0xf2, 0xab, 0x63, 0x1b, 0xa5, + 0x7f, 0xf4, 0x77, 0x9a, 0xa1, 0x57, 0x61, 0x97, 0xbe, 0x08, 0x38, 0x23, + 0x56, 0x56, 0x47, 0xc1, 0x03, 0xed, 0x89, 0x1f, 0xa8, 0x44, 0xab, 0x91, + 0xed, 0x3c, 0x4b, 0xbe, 0x5c, 0x3b, 0x31, 0xd4, 0x67, 0x1c, 0xa5, 0x45, + 0xce, 0x1c, 0xa7, 0xe7, 0x95, 0x80, 0x2d, 0x9e, 0x82, 0x1d, 0xb2, 0x01, + 0xed, 0x31, 0x96, 0xbc, 0x5a, 0x9e, 0xd9, 0xea, 0xde, 0x9d, 0xd3, 0x7c, + 0x78, 0xc9, 0xc9, 0x8e, 0xdd, 0x24, 0x85, 0xc1, 0x28, 0xc6, 0xa0, 0x9a, + 0xd7, 0xca, 0xf5, 0xd2, 0xaf, 0xc7, 0x73, 0x59, 0x0e, 0x42, 0x1f, 0xff, + 0x69, 0xb1, 0x5f, 0x66, 0x07, 0x9a, 0xf0, 0x1d, 0x95, 0x67, 0x8a, 0x5b, + 0xe0, 0xef, 0xfc, 0x0a, 0x70, 0x54, 0x8b, 0xef, 0x5a, 0xe9, 0x5d, 0x47, + 0x5e, 0x6d, 0x90, 0x19, 0xa4, 0xdf, 0x28, 0xbf, 0x64, 0xd3, 0x99, 0x46, + 0xde, 0x68, 0x40, 0xdd, 0xa8, 0x9c, 0x2f, 0xd2, 0x96, 0xd4, 0x3c, 0xd1, + 0xf3, 0xb2, 0x6c, 0xc9, 0xbc, 0x0c, 0xdb, 0xf4, 0x59, 0x3c, 0xcf, 0x4b, + 0x72, 0xe7, 0x6e, 0x67, 0x4b, 0xa2, 0xdd, 0x81, 0xbe, 0xc4, 0xe3, 0x3a, + 0x5b, 0xbc, 0x5a, 0xe7, 0x5a, 0xdb, 0x46, 0x8d, 0x3c, 0x3f, 0xa8, 0xe2, + 0x0d, 0x98, 0x93, 0xcd, 0x4e, 0x87, 0x4d, 0xe3, 0xb7, 0xbe, 0x2f, 0x51, + 0xda, 0xcf, 0xa8, 0x0d, 0xab, 0x44, 0xda, 0x1a, 0x60, 0xe7, 0xec, 0x11, + 0xd5, 0xdc, 0x20, 0xae, 0xb4, 0x4f, 0xa8, 0x56, 0xa4, 0xf9, 0x36, 0x2d, + 0xd6, 0x00, 0x9d, 0x80, 0xb4, 0x16, 0xa4, 0x6d, 0xb2, 0x69, 0x4d, 0x0d, + 0x52, 0x8b, 0xb4, 0xcb, 0x9a, 0xe7, 0x2f, 0x76, 0xf8, 0x5e, 0xce, 0xa9, + 0x97, 0xb6, 0x53, 0x0d, 0x90, 0x0d, 0xab, 0x65, 0x66, 0x6b, 0x9d, 0xb4, + 0x21, 0x8f, 0x31, 0xee, 0xd4, 0xa9, 0xa8, 0xbc, 0xf3, 0x54, 0x7b, 0xfc, + 0xa3, 0x18, 0x43, 0xfb, 0x19, 0xc6, 0xbc, 0xff, 0xac, 0x99, 0x31, 0x9f, + 0xb6, 0x33, 0x7c, 0xd7, 0x69, 0xf9, 0x43, 0x7c, 0x98, 0x3b, 0xdf, 0x60, + 0x63, 0x94, 0x8e, 0x3b, 0xc3, 0xa3, 0xd4, 0xdb, 0xed, 0xf6, 0x7e, 0xa2, + 0xff, 0xd9, 0x4c, 0x5f, 0x6d, 0x82, 0x36, 0x54, 0x89, 0xfc, 0x48, 0xdd, + 0x83, 0xf7, 0xb8, 0x23, 0x85, 0x79, 0x99, 0x35, 0x45, 0xbe, 0x3a, 0xae, + 0xb8, 0x4f, 0x05, 0x69, 0x95, 0x77, 0x05, 0x66, 0x8e, 0xc9, 0x0b, 0x46, + 0x2e, 0xfd, 0x9a, 0x91, 0x4b, 0xa7, 0xcf, 0x2d, 0x90, 0x4b, 0x05, 0x2d, + 0x97, 0x06, 0x05, 0xef, 0xa9, 0x02, 0xe4, 0xd2, 0x08, 0xbe, 0x3d, 0x2d, + 0x97, 0x62, 0x62, 0x6d, 0x64, 0x89, 0x5e, 0xc5, 0xfe, 0x27, 0x4b, 0xae, + 0xb6, 0xa5, 0x0a, 0xe3, 0xb0, 0x43, 0x4a, 0x23, 0x56, 0x67, 0x4b, 0xba, + 0x49, 0x3a, 0x7a, 0x7e, 0x2a, 0xa1, 0x9d, 0x39, 0xdb, 0xcc, 0x3b, 0x8f, + 0x5f, 0x54, 0x94, 0x61, 0x27, 0x20, 0xc3, 0x1e, 0xbe, 0x82, 0x0c, 0x43, + 0x5e, 0x19, 0x79, 0x65, 0xb6, 0xfb, 0xdd, 0x9f, 0x0e, 0x79, 0x94, 0x1f, + 0x94, 0x19, 0x90, 0x49, 0x25, 0xc8, 0xa4, 0x12, 0xe4, 0x54, 0x09, 0x72, + 0xa9, 0x04, 0xb9, 0x54, 0x82, 0x5c, 0x2a, 0x41, 0x2e, 0x41, 0xc6, 0x3d, + 0x0a, 0x19, 0x67, 0x64, 0xda, 0x00, 0xed, 0x35, 0xb9, 0xcf, 0xea, 0x77, + 0x13, 0x27, 0xe9, 0xb2, 0x7e, 0x91, 0xd9, 0xb3, 0x7a, 0xae, 0x2a, 0x2e, + 0xb8, 0xeb, 0x88, 0xe6, 0x77, 0xcf, 0x57, 0xd7, 0x3a, 0xdc, 0x1f, 0xf3, + 0x03, 0xed, 0xb3, 0x6f, 0xe6, 0x6f, 0xa9, 0x03, 0x5f, 0xbf, 0x62, 0xf9, + 0x7a, 0xf3, 0x1c, 0x5f, 0x27, 0x1d, 0xc6, 0x89, 0x97, 0xe7, 0xeb, 0x16, + 0x9b, 0x97, 0x0f, 0x56, 0x80, 0xaf, 0x57, 0x2c, 0xe2, 0xeb, 0x28, 0xf8, + 0x7a, 0xe7, 0x12, 0xbe, 0x5e, 0xe5, 0xf4, 0xea, 0x3a, 0x3c, 0x83, 0xc6, + 0xef, 0x5a, 0x67, 0x9e, 0xaf, 0xf7, 0x6b, 0xbe, 0x3e, 0x04, 0xbe, 0xbe, + 0xbe, 0x8a, 0xaf, 0x77, 0x4a, 0xf2, 0x96, 0x6c, 0x64, 0xa3, 0xec, 0xbe, + 0x5f, 0x35, 0xaf, 0x91, 0x7f, 0x11, 0x53, 0xdf, 0xf0, 0x58, 0xef, 0x58, + 0xb3, 0xe4, 0x1e, 0xfa, 0x11, 0xd7, 0x06, 0xc8, 0x23, 0x43, 0x19, 0xc7, + 0x93, 0x83, 0x47, 0x7e, 0x20, 0xd3, 0x9a, 0xb7, 0x44, 0xf6, 0x1c, 0x89, + 0xca, 0xf0, 0x11, 0xc6, 0x1e, 0xbe, 0x63, 0xe9, 0xbd, 0x4e, 0x86, 0x07, + 0xb9, 0x5f, 0xd2, 0x95, 0xdd, 0x47, 0xe0, 0x63, 0x1d, 0x61, 0xec, 0xe1, + 0xf2, 0x1c, 0x8f, 0x4d, 0x43, 0xb6, 0xec, 0x3e, 0xa2, 0xe7, 0x1a, 0xed, + 0x34, 0xc8, 0xa1, 0x23, 0x22, 0xb7, 0x1d, 0x71, 0xe5, 0xf6, 0x23, 0x73, + 0xbc, 0x36, 0x10, 0xf2, 0xda, 0x9f, 0x83, 0xd7, 0xda, 0x2d, 0xaf, 0xa9, + 0x39, 0x5e, 0xfb, 0x5a, 0x15, 0xaf, 0xb1, 0x3e, 0x79, 0xed, 0x82, 0x4d, + 0xe3, 0xb7, 0x2b, 0x7b, 0x8f, 0xb4, 0xca, 0xee, 0x87, 0xde, 0x22, 0x7b, + 0xee, 0x27, 0xac, 0xe6, 0x9e, 0x3c, 0xda, 0x5f, 0xe3, 0x95, 0x76, 0xb4, + 0x1f, 0xee, 0x0f, 0xd2, 0x77, 0x65, 0x75, 0x4e, 0x48, 0x32, 0xcf, 0xfe, + 0x6a, 0xe1, 0x3b, 0x9f, 0x82, 0x4f, 0xb1, 0x17, 0x30, 0xdd, 0x7a, 0x44, + 0x92, 0xae, 0xbc, 0x26, 0x23, 0xa9, 0x47, 0x5b, 0x8d, 0x3d, 0x71, 0x09, + 0xbc, 0x42, 0xfa, 0xcf, 0x48, 0xee, 0xed, 0x81, 0xf6, 0x2b, 0x46, 0xcb, + 0x42, 0xff, 0x9f, 0x31, 0x73, 0xc7, 0xdc, 0x77, 0xc7, 0xf3, 0xbe, 0x35, + 0xfa, 0xbc, 0x9b, 0x8e, 0xd7, 0x76, 0x33, 0xbf, 0x46, 0xef, 0x37, 0xcd, + 0xe9, 0xb3, 0xdc, 0xac, 0xcf, 0x76, 0x62, 0x3a, 0x9e, 0x5e, 0x28, 0xf3, + 0x8e, 0x30, 0xde, 0xbd, 0xcc, 0xbb, 0x06, 0xff, 0xf8, 0x2a, 0x13, 0x9b, + 0x25, 0xdf, 0x7d, 0xdd, 0xc9, 0x15, 0x2f, 0xe9, 0x7d, 0x85, 0x59, 0x1f, + 0xbf, 0xcb, 0xfc, 0x66, 0xf9, 0x4b, 0x8c, 0x71, 0x24, 0x12, 0xea, 0x81, + 0x56, 0xee, 0x3b, 0x18, 0x9c, 0x32, 0x76, 0x94, 0xe1, 0xd1, 0x06, 0xed, + 0x6b, 0x8c, 0xe0, 0x7b, 0xf7, 0x68, 0xa3, 0x53, 0xa0, 0x6d, 0x32, 0xd0, + 0xe0, 0xe4, 0xc7, 0xf7, 0xb4, 0x1a, 0x9b, 0x79, 0x20, 0xce, 0x3d, 0x85, + 0x19, 0xb5, 0x54, 0x26, 0x9f, 0x92, 0x50, 0x26, 0x27, 0x6f, 0xc9, 0xc0, + 0xb6, 0xce, 0x1d, 0xd1, 0xf7, 0xf7, 0x25, 0xda, 0x15, 0xc7, 0xf4, 0x09, + 0xc8, 0xd7, 0x90, 0x16, 0xe2, 0xf2, 0xf1, 0x23, 0xa4, 0x07, 0x15, 0x6b, + 0x94, 0xdf, 0xb2, 0xf4, 0x70, 0x59, 0x8a, 0x90, 0x3b, 0x47, 0x8e, 0xdc, + 0x2e, 0xe3, 0xbb, 0x16, 0xd3, 0xc3, 0x9e, 0x79, 0x7a, 0x88, 0xc1, 0x3e, + 0x73, 0xaa, 0xe9, 0xe1, 0x37, 0xe7, 0xe8, 0x61, 0xdc, 0xf9, 0xd7, 0xd2, + 0xc3, 0x0d, 0x0b, 0xe8, 0x61, 0x44, 0xd3, 0x43, 0xff, 0x1c, 0x3d, 0x8c, + 0x1c, 0x61, 0xbf, 0x7a, 0x5d, 0xd4, 0x9b, 0x71, 0x38, 0xe7, 0x73, 0xb4, + 0x90, 0x18, 0xd6, 0xfb, 0x44, 0x93, 0x79, 0x9e, 0x25, 0x5d, 0xa5, 0x18, + 0x1b, 0x99, 0x9f, 0xff, 0xc6, 0x7f, 0xd3, 0xf9, 0x7f, 0x47, 0xfc, 0xff, + 0xef, 0xfc, 0x5f, 0x8f, 0xf6, 0x29, 0x8b, 0x43, 0x79, 0x1c, 0xd2, 0xc3, + 0x7b, 0xe2, 0x46, 0x2f, 0x70, 0x8e, 0xf9, 0x6d, 0xf6, 0xac, 0x9f, 0x83, + 0xfc, 0x7b, 0x1c, 0xf2, 0xef, 0xb1, 0x05, 0xeb, 0x01, 0x3d, 0x36, 0x06, + 0x11, 0xc8, 0xc1, 0xd4, 0x3c, 0x3e, 0x66, 0xba, 0x89, 0x0f, 0xb3, 0xf7, + 0xe4, 0x6c, 0x65, 0x31, 0x4e, 0x5c, 0xbd, 0xdf, 0xe8, 0x64, 0xaa, 0x1a, + 0x27, 0x84, 0x7b, 0xb6, 0x6a, 0x8c, 0xf8, 0x5d, 0xe6, 0xf7, 0x65, 0xbd, + 0x87, 0xa4, 0xa0, 0xd7, 0x9f, 0x88, 0x17, 0xae, 0x3f, 0x11, 0x27, 0xae, + 0xb6, 0xf7, 0x0b, 0xe5, 0x3a, 0xbd, 0x2f, 0xfc, 0xc0, 0x54, 0x4c, 0x66, + 0x62, 0x8c, 0xeb, 0xf1, 0xde, 0x57, 0xfa, 0xca, 0x7e, 0xbc, 0x20, 0x79, + 0x7b, 0xd6, 0x67, 0x95, 0xa5, 0x6d, 0xc6, 0x03, 0x79, 0x27, 0x42, 0xb8, + 0x0e, 0xd1, 0x69, 0x65, 0x5d, 0x43, 0x55, 0x9c, 0x12, 0x78, 0x1f, 0x93, + 0x44, 0xb6, 0x1b, 0xef, 0x29, 0xf6, 0xfd, 0xa4, 0x8c, 0x3c, 0x58, 0x86, + 0x2d, 0xf7, 0x30, 0x74, 0x8e, 0x23, 0x10, 0x93, 0xfa, 0x2e, 0x14, 0xc2, + 0x30, 0xa1, 0xef, 0xf5, 0xa3, 0xdf, 0x47, 0x7a, 0x88, 0xe3, 0xfb, 0xb2, + 0x8d, 0x25, 0xc5, 0xa5, 0x50, 0xfc, 0x01, 0xe0, 0xe7, 0x1d, 0x94, 0x3f, + 0xc2, 0xfb, 0x8d, 0xe6, 0xc3, 0xf8, 0x21, 0x03, 0xfa, 0xcd, 0xb9, 0x79, + 0xcd, 0xc9, 0x94, 0xcd, 0xfe, 0x96, 0xaa, 0xfb, 0xf5, 0xe5, 0xb0, 0xb6, + 0x9f, 0xd3, 0x76, 0x5f, 0x0b, 0xcf, 0xe7, 0x19, 0x1b, 0xfa, 0xcb, 0xb0, + 0xa1, 0x9f, 0xa8, 0x64, 0xf4, 0x1a, 0xd6, 0x63, 0xb0, 0xa1, 0x1f, 0x85, + 0xee, 0xa1, 0xce, 0x89, 0x59, 0x9d, 0x33, 0xa2, 0x76, 0x69, 0x9d, 0xf3, + 0xd7, 0x5a, 0xe7, 0xfc, 0xea, 0x12, 0x9d, 0x73, 0x48, 0xb5, 0x8f, 0x52, + 0xe7, 0xf4, 0xaa, 0x9d, 0x0e, 0xed, 0xc5, 0xb5, 0xcb, 0xe8, 0x9c, 0xf7, + 0xca, 0xaf, 0xd8, 0xbc, 0xfd, 0xf2, 0xbe, 0x6d, 0x7a, 0xdd, 0xc6, 0x9b, + 0x50, 0xbc, 0xcb, 0xce, 0xe8, 0xa0, 0xeb, 0x55, 0xa7, 0x5e, 0xef, 0xfd, + 0x6a, 0x95, 0xce, 0x69, 0x53, 0xdd, 0x4e, 0xaf, 0xae, 0xc3, 0x78, 0x04, + 0xbf, 0x53, 0x4e, 0x66, 0xa0, 0x0e, 0xdf, 0x71, 0x89, 0x1c, 0xc1, 0xd8, + 0xcd, 0x7d, 0x7b, 0xca, 0xe4, 0x5d, 0x63, 0xf3, 0x54, 0x98, 0xee, 0x9a, + 0xf4, 0x76, 0x9b, 0x6e, 0x74, 0x55, 0x9b, 0x6a, 0xd5, 0xba, 0x6a, 0x33, + 0x18, 0x6a, 0x02, 0xfa, 0x75, 0xa2, 0x14, 0xea, 0x2c, 0xfe, 0x66, 0xbc, + 0x99, 0x71, 0x89, 0x30, 0x6e, 0x9d, 0x40, 0x19, 0x3c, 0xa5, 0xd0, 0xa6, + 0xe4, 0x6f, 0xf8, 0x0a, 0x78, 0xa6, 0x80, 0xd7, 0x5b, 0xc0, 0x3f, 0xbf, + 0x5e, 0x64, 0xdc, 0xb3, 0x59, 0x8e, 0x8e, 0x55, 0xe7, 0xb5, 0xca, 0xbb, + 0xc7, 0x36, 0xc8, 0xbe, 0x51, 0xff, 0x6a, 0xa9, 0xdf, 0x28, 0x23, 0xa3, + 0x2f, 0xea, 0xfb, 0x40, 0xd6, 0xe8, 0x7b, 0x92, 0x78, 0x7f, 0x98, 0x91, + 0x91, 0xfd, 0x8e, 0x91, 0x91, 0x19, 0x35, 0x6f, 0xb3, 0x86, 0x6d, 0xf2, + 0x6e, 0xa6, 0xbe, 0xd1, 0xb8, 0xbe, 0x43, 0x7a, 0xa2, 0x72, 0xad, 0xfc, + 0xd1, 0x71, 0x75, 0xa7, 0x9a, 0xbf, 0x4b, 0x41, 0xdb, 0xac, 0x93, 0x0b, + 0x6c, 0xd6, 0xbf, 0x97, 0x99, 0xf7, 0x45, 0x31, 0x4e, 0xd0, 0xf0, 0x75, + 0x2f, 0x73, 0x1d, 0xb4, 0x39, 0x26, 0x97, 0xa4, 0x4f, 0xe3, 0x8f, 0xf2, + 0xb4, 0x01, 0x72, 0x70, 0x56, 0xeb, 0xd7, 0xb5, 0xbc, 0xf3, 0xf8, 0x08, + 0x6d, 0xd7, 0xaf, 0x6b, 0x79, 0xb6, 0xd6, 0xda, 0xae, 0xd3, 0x90, 0xd3, + 0x94, 0xa3, 0x37, 0xca, 0x5f, 0xdb, 0x74, 0xa6, 0x25, 0xe3, 0xb3, 0x42, + 0x7d, 0x17, 0x83, 0x0c, 0xa5, 0x3c, 0xfd, 0x59, 0x6d, 0xd7, 0xe7, 0x6c, + 0x1b, 0x94, 0x9f, 0x46, 0x76, 0x6f, 0x76, 0xa6, 0x6d, 0x1a, 0xbf, 0xc3, + 0x18, 0xba, 0x9f, 0xc9, 0x59, 0x3e, 0x53, 0xce, 0x93, 0xc8, 0x5f, 0x83, + 0x7c, 0xf2, 0xd9, 0x63, 0x9a, 0xcf, 0xb4, 0x7d, 0xe2, 0x74, 0xd9, 0x35, + 0x85, 0xb9, 0xf5, 0x80, 0x3c, 0xf9, 0x4c, 0x1d, 0xf5, 0xa6, 0x8d, 0x3c, + 0xf0, 0x90, 0xfe, 0x45, 0xe8, 0x0e, 0xd6, 0x45, 0xfa, 0xb1, 0x0c, 0xe6, + 0xf0, 0x24, 0xfc, 0x9f, 0x46, 0x7c, 0x37, 0xe3, 0x7b, 0x42, 0x7e, 0x75, + 0x30, 0xaa, 0xc7, 0x3d, 0x82, 0x71, 0x1c, 0x38, 0x82, 0x31, 0x39, 0xc6, + 0x76, 0x76, 0xcf, 0xb8, 0x52, 0x73, 0x86, 0x7c, 0xc7, 0x33, 0x86, 0x41, + 0xb0, 0xb7, 0x8b, 0x74, 0x9b, 0xf4, 0xfa, 0xf5, 0xf9, 0xb7, 0xcd, 0xf1, + 0x08, 0x70, 0x72, 0x00, 0xf3, 0x31, 0x52, 0xf4, 0xbd, 0xac, 0xe3, 0xc7, + 0x31, 0x4e, 0xd8, 0x80, 0xed, 0xb0, 0x05, 0xdb, 0x61, 0x07, 0xb6, 0xc3, + 0x0e, 0x5c, 0x2d, 0xa7, 0xb6, 0x72, 0x7f, 0x49, 0xfe, 0x9d, 0xbc, 0x77, + 0xf9, 0x1b, 0x3a, 0x36, 0x5f, 0x7b, 0x4b, 0x1f, 0x7c, 0x76, 0xf1, 0x92, + 0x03, 0xdc, 0x63, 0x3f, 0xeb, 0xd5, 0xde, 0xd2, 0x2f, 0xed, 0x3d, 0xc8, + 0xef, 0xb9, 0x24, 0x1d, 0xb7, 0x7c, 0xd8, 0xa9, 0x1d, 0xe8, 0x03, 0x1e, + 0x33, 0x4e, 0x32, 0x3e, 0xe4, 0x30, 0x4e, 0x91, 0xdd, 0x1c, 0xd1, 0x67, + 0xc4, 0xa6, 0x19, 0x8b, 0xb8, 0xa5, 0x3d, 0xb2, 0x25, 0xb1, 0xdb, 0x49, + 0x0e, 0xa8, 0x48, 0x72, 0xa0, 0xcf, 0x09, 0xcb, 0xf1, 0x0e, 0x6a, 0xc8, + 0x19, 0xc0, 0x7a, 0xa0, 0xf4, 0x75, 0xd0, 0xd3, 0x79, 0x29, 0x1c, 0x6f, + 0x90, 0xa9, 0x62, 0xbb, 0x97, 0x55, 0x31, 0xe1, 0xbe, 0x12, 0x75, 0x0a, + 0x44, 0x7f, 0x26, 0x2a, 0x13, 0xa3, 0x1b, 0x45, 0x69, 0xdb, 0xbd, 0x45, + 0xb2, 0x63, 0xa3, 0x72, 0xbe, 0x5b, 0x9a, 0x14, 0xda, 0xe7, 0xdd, 0xde, + 0xea, 0x14, 0xd7, 0x11, 0x43, 0x5e, 0x58, 0x4f, 0x3e, 0x19, 0x05, 0x0e, + 0x41, 0xb7, 0x8c, 0xeb, 0xd6, 0x09, 0xe5, 0xde, 0xed, 0x3a, 0x66, 0xca, + 0x38, 0x6d, 0xf5, 0x7a, 0x03, 0xf9, 0x23, 0xba, 0x2c, 0x7f, 0x4c, 0x96, + 0xb8, 0x36, 0x23, 0x79, 0x97, 0x71, 0x61, 0x1f, 0xbf, 0xc7, 0x59, 0xb6, + 0x4e, 0x46, 0xba, 0xf3, 0x76, 0x8f, 0xc7, 0x37, 0xc1, 0x07, 0x1c, 0x9f, + 0x5e, 0x27, 0x01, 0xaf, 0x2f, 0x5e, 0xcf, 0x88, 0x56, 0xc9, 0x03, 0x47, + 0x66, 0x46, 0xc3, 0xf5, 0x0f, 0xb6, 0x87, 0xef, 0x71, 0x23, 0x6f, 0xb3, + 0x4b, 0xea, 0x11, 0x2e, 0xae, 0x55, 0x2e, 0x94, 0xb1, 0x4a, 0x9f, 0x13, + 0xf6, 0xb4, 0x7c, 0x3d, 0x5d, 0x31, 0xb2, 0x75, 0xbc, 0x12, 0xea, 0x96, + 0xa8, 0xd1, 0xa5, 0x4b, 0xf4, 0x89, 0x89, 0x60, 0xce, 0xeb, 0x93, 0x4b, + 0x3a, 0x46, 0xf7, 0x6b, 0x53, 0x2d, 0xe2, 0x1e, 0x93, 0xd9, 0x11, 0xff, + 0x54, 0x2b, 0xf7, 0x69, 0x8c, 0xa4, 0xde, 0x8c, 0x7e, 0x8c, 0xb5, 0x50, + 0x1f, 0x0e, 0xa9, 0xb5, 0x78, 0xaf, 0xd1, 0xf4, 0x07, 0x9e, 0xc2, 0xb7, + 0xf1, 0x13, 0xbe, 0x0c, 0x3f, 0xe1, 0x09, 0xe8, 0xba, 0x73, 0xf0, 0x13, + 0x1e, 0x87, 0x9f, 0xf0, 0x18, 0xfc, 0x84, 0x47, 0xa1, 0x27, 0xab, 0xfd, + 0x83, 0xe1, 0x05, 0xfe, 0x41, 0xa0, 0xf9, 0x9f, 0x31, 0xc0, 0xc7, 0xab, + 0x7c, 0x83, 0xbd, 0x46, 0x5f, 0xc1, 0xef, 0x37, 0x7c, 0xd4, 0xa6, 0x6e, + 0xd6, 0xfa, 0xd1, 0xec, 0xd9, 0x1d, 0x98, 0xd3, 0x57, 0x6d, 0xca, 0xe8, + 0xab, 0x89, 0x79, 0x7d, 0x65, 0xf8, 0xe8, 0xd8, 0xa8, 0x44, 0xfc, 0xd1, + 0xe9, 0x6c, 0x6a, 0xbb, 0xe6, 0xa1, 0x26, 0x7f, 0xa3, 0x44, 0x1e, 0x50, + 0xcd, 0x35, 0x92, 0xb5, 0xdf, 0xa0, 0xaf, 0xa3, 0x5f, 0x47, 0x5b, 0xef, + 0x94, 0x9c, 0xb6, 0xcf, 0xae, 0x8c, 0xef, 0x47, 0x17, 0xe1, 0xbb, 0x50, + 0x7a, 0x56, 0xe3, 0xfc, 0x7e, 0x7d, 0x26, 0xbf, 0x41, 0x86, 0xcb, 0x21, + 0xce, 0x79, 0x06, 0x8e, 0xfb, 0x30, 0x5a, 0x25, 0x72, 0xac, 0x45, 0xfa, + 0x53, 0xa2, 0x72, 0xa9, 0x95, 0x7a, 0xff, 0xca, 0xa9, 0x6e, 0x89, 0xe7, + 0xba, 0x49, 0xab, 0xf7, 0xc9, 0x84, 0x9e, 0x8b, 0x16, 0xa9, 0x39, 0x46, + 0x1b, 0x25, 0x5c, 0xc3, 0xbb, 0xbd, 0xc5, 0xde, 0x41, 0x1d, 0x35, 0xe5, + 0x44, 0x0e, 0xea, 0xf9, 0x9a, 0xd5, 0x7b, 0x0c, 0x6f, 0x9e, 0x62, 0x2c, + 0x9e, 0xf7, 0xfd, 0x31, 0x0e, 0xff, 0xaf, 0x99, 0xbf, 0x42, 0x8b, 0xb1, + 0x67, 0xd6, 0x58, 0x3b, 0xc6, 0xc4, 0xa9, 0x96, 0xb7, 0x61, 0xd8, 0x4e, + 0xf5, 0x1d, 0xb5, 0xab, 0xe0, 0x03, 0x37, 0xa0, 0x4d, 0xae, 0x63, 0xdb, + 0xbf, 0x17, 0xe4, 0xfd, 0xb3, 0x73, 0xc0, 0x5f, 0x85, 0xb4, 0x06, 0xe4, + 0x31, 0x66, 0xf3, 0x85, 0x16, 0xc6, 0x65, 0xb3, 0x7e, 0xa3, 0x4d, 0x5b, + 0xe5, 0x8c, 0x8c, 0xb6, 0xc3, 0x37, 0xe7, 0x39, 0x76, 0xe6, 0xf7, 0x73, + 0xee, 0x84, 0x7f, 0xab, 0x69, 0x12, 0xf2, 0x67, 0x8f, 0x5c, 0x6b, 0xe3, + 0xce, 0xd4, 0xc3, 0xbf, 0xb8, 0x60, 0xbd, 0xf6, 0x10, 0xf4, 0xd8, 0xad, + 0x90, 0x47, 0xd4, 0xc3, 0x87, 0xe4, 0x17, 0x2c, 0x3d, 0x2f, 0xd4, 0xc3, + 0x17, 0x85, 0xb1, 0xe1, 0x2e, 0xe4, 0xe5, 0x83, 0x28, 0xe8, 0xe1, 0x70, + 0x95, 0xaf, 0x46, 0xbf, 0xaf, 0x2e, 0x6d, 0xd6, 0xc0, 0x16, 0xfa, 0x7d, + 0x90, 0x03, 0xb1, 0xd0, 0xcf, 0xab, 0x9d, 0x5b, 0xa3, 0xdd, 0x69, 0xeb, + 0x8e, 0xa4, 0x5e, 0x22, 0x8e, 0x12, 0x87, 0xe4, 0xf6, 0xf5, 0xbc, 0x26, + 0xcf, 0xf5, 0xbf, 0xa5, 0x71, 0x26, 0x8a, 0xb4, 0xb7, 0x46, 0xc3, 0x68, + 0xe5, 0x7c, 0x22, 0xdc, 0xbf, 0x51, 0xb0, 0x75, 0xf7, 0xd8, 0xf5, 0xf8, + 0x82, 0x7c, 0x9b, 0x71, 0xce, 0x44, 0x5f, 0x64, 0x25, 0xcf, 0x64, 0xa3, + 0xee, 0xed, 0xda, 0x6f, 0xcf, 0x48, 0xd8, 0x16, 0xbf, 0x6b, 0xaa, 0xda, + 0xa6, 0x1d, 0xc5, 0xf7, 0xe2, 0xfb, 0x1b, 0x9e, 0xd7, 0x6b, 0x8b, 0xe6, + 0x6e, 0x9a, 0x90, 0x4f, 0xc8, 0x3b, 0x09, 0x7d, 0x8e, 0xc9, 0x3f, 0x46, + 0xbb, 0x87, 0xeb, 0xae, 0xde, 0xf4, 0x70, 0xea, 0x23, 0xfa, 0x0e, 0xd5, + 0x71, 0x11, 0xa7, 0x90, 0xda, 0xab, 0xf7, 0x9d, 0x14, 0x74, 0x7c, 0x39, + 0x8f, 0xf7, 0xbc, 0x8f, 0xda, 0x76, 0x8c, 0x7f, 0x0b, 0x88, 0x69, 0x1f, + 0x04, 0x6c, 0xd4, 0x21, 0x94, 0xbd, 0x31, 0x69, 0x3b, 0xfa, 0x7e, 0xcd, + 0x0b, 0x6b, 0xe1, 0x0b, 0xf4, 0x1e, 0x85, 0xae, 0x3e, 0x1a, 0x97, 0xfe, + 0xa3, 0x5a, 0x37, 0x66, 0x96, 0xc6, 0x0a, 0xb6, 0x78, 0x2e, 0xfd, 0x89, + 0x98, 0x27, 0xd7, 0x1c, 0x8d, 0xc8, 0xe1, 0xd8, 0x16, 0xaf, 0xc3, 0xb9, + 0xd1, 0xea, 0x42, 0x43, 0x7f, 0xa0, 0x15, 0xd4, 0x37, 0xeb, 0x90, 0xbd, + 0xf3, 0xb1, 0x6b, 0xd4, 0x7f, 0x49, 0x46, 0xc8, 0x4b, 0x95, 0x88, 0x8c, + 0x0f, 0xb6, 0x02, 0x9e, 0xb7, 0xae, 0x07, 0x0e, 0x40, 0x53, 0x98, 0x1f, + 0xfd, 0xf7, 0x3c, 0xdc, 0x38, 0xe5, 0x57, 0x1b, 0xfa, 0xef, 0x3b, 0x4a, + 0x1d, 0xe6, 0x6b, 0xbe, 0x46, 0xbf, 0x5e, 0x8d, 0xf6, 0x3d, 0xc8, 0x8b, + 0x6f, 0x11, 0xff, 0x01, 0xc8, 0xb5, 0xa3, 0x51, 0xe9, 0x38, 0xda, 0x20, + 0x9b, 0x8e, 0xd2, 0xf7, 0xa8, 0xf6, 0x45, 0x69, 0x8b, 0x5e, 0xc2, 0xb8, + 0x6e, 0x34, 0xf7, 0x0d, 0x4e, 0x45, 0x65, 0x1f, 0xf9, 0x15, 0x65, 0x73, + 0xb0, 0x93, 0xb3, 0x47, 0x3d, 0xbd, 0x16, 0x9a, 0xc5, 0x38, 0xf9, 0x37, + 0x2c, 0xfa, 0x8e, 0x1a, 0x39, 0x53, 0xa0, 0x6f, 0x32, 0xd0, 0x02, 0xbc, + 0x3e, 0x60, 0xf9, 0xe5, 0x3d, 0xeb, 0x2d, 0x5f, 0xfe, 0x9c, 0xfc, 0x96, + 0x5b, 0x6f, 0xe4, 0xe5, 0x87, 0xd6, 0x73, 0x2f, 0xd2, 0x5a, 0x9f, 0xef, + 0x3a, 0x6d, 0x43, 0x18, 0xb9, 0xf9, 0x7a, 0xfc, 0x27, 0xc0, 0x51, 0xb8, + 0xfe, 0x44, 0x3e, 0xe4, 0x1a, 0xb2, 0x3e, 0xb3, 0x92, 0x9a, 0xd1, 0x7f, + 0x53, 0x89, 0x6b, 0x61, 0xf3, 0xf7, 0x59, 0x6d, 0xaf, 0x30, 0x36, 0xfe, + 0x4c, 0xf8, 0x37, 0x9c, 0xaa, 0xf6, 0x19, 0x56, 0xaf, 0x75, 0x31, 0xbe, + 0x34, 0xb7, 0x17, 0x28, 0x18, 0xd5, 0x77, 0xc2, 0xc5, 0x9c, 0x8b, 0xc5, + 0x5a, 0xe7, 0x9b, 0x63, 0x12, 0xb8, 0x7e, 0xdc, 0xf9, 0x96, 0xcf, 0xb5, + 0x71, 0xcf, 0x79, 0xb9, 0xe8, 0x83, 0xf7, 0xfe, 0x02, 0xe3, 0x68, 0x75, + 0x5e, 0xc1, 0x9c, 0x1e, 0x2c, 0x65, 0x92, 0x9e, 0x8d, 0x83, 0x3f, 0x5b, + 0x6c, 0x75, 0x9e, 0x9b, 0x8f, 0x21, 0xf5, 0x84, 0x74, 0x71, 0x88, 0x79, + 0x65, 0xe4, 0x95, 0x19, 0xeb, 0xad, 0x77, 0x26, 0xc7, 0xec, 0x7e, 0x12, + 0xa3, 0x8b, 0xe6, 0xd6, 0x5f, 0x06, 0xf4, 0xfa, 0x84, 0xeb, 0x4c, 0x4e, + 0x4d, 0xaf, 0x37, 0xfb, 0x8a, 0x6a, 0x91, 0x67, 0xf6, 0x58, 0x4e, 0x4c, + 0xd5, 0xa2, 0x4c, 0xbd, 0x33, 0xa1, 0x63, 0x5e, 0xda, 0xf6, 0x70, 0xc6, + 0xa7, 0xea, 0x9d, 0x29, 0xbd, 0xd6, 0x1c, 0x75, 0x4e, 0x8e, 0xb1, 0xed, + 0x28, 0xca, 0x88, 0x73, 0x0a, 0xed, 0x4d, 0x8d, 0xb5, 0xc7, 0xf7, 0x49, + 0x3b, 0x6c, 0x01, 0xfe, 0x8d, 0x34, 0xde, 0x17, 0xe0, 0x3a, 0x53, 0x73, + 0xed, 0x2a, 0xb4, 0xc3, 0xb2, 0xa4, 0x41, 0xf6, 0xeb, 0xa2, 0xfd, 0xa5, + 0x6b, 0x52, 0x4b, 0x71, 0x32, 0x06, 0x9c, 0x1c, 0xb4, 0x38, 0x39, 0x61, + 0x71, 0x32, 0x5a, 0x85, 0x93, 0x87, 0x17, 0xe1, 0xe4, 0x04, 0x70, 0xf2, + 0xf0, 0x15, 0x70, 0x82, 0xbc, 0xf2, 0xc3, 0x16, 0x27, 0xf7, 0x2d, 0xc2, + 0x49, 0x7e, 0x2e, 0x16, 0x6f, 0x70, 0x32, 0x02, 0x9c, 0xd4, 0xb4, 0x1a, + 0xd8, 0x0f, 0x5a, 0x9c, 0xe0, 0x3d, 0x75, 0x10, 0x65, 0xee, 0xab, 0xc2, + 0xc9, 0x41, 0xe0, 0xe4, 0x3e, 0x8b, 0x93, 0xc3, 0x16, 0x27, 0x87, 0x51, + 0x26, 0x0f, 0x9c, 0x14, 0x96, 0xc1, 0xc9, 0x08, 0x70, 0x12, 0xb6, 0x5b, + 0x40, 0x3b, 0x87, 0xab, 0x70, 0x32, 0xb2, 0x0c, 0x4e, 0xb8, 0xe6, 0x1a, + 0xee, 0xe1, 0xbe, 0xfc, 0x06, 0x7b, 0xb8, 0x53, 0x9f, 0x7d, 0xe3, 0x3d, + 0xdc, 0x2c, 0x73, 0xb9, 0xea, 0xcc, 0xfb, 0xb3, 0x76, 0x4f, 0x9a, 0xd9, + 0xfb, 0x37, 0x7f, 0x0f, 0x5e, 0x3b, 0xf8, 0xbc, 0x90, 0xf7, 0xc4, 0xec, + 0x21, 0x75, 0xb7, 0x4d, 0x81, 0xd7, 0x8e, 0xca, 0x81, 0xe3, 0xb5, 0x87, + 0x73, 0x36, 0xcd, 0xdf, 0xd6, 0x9e, 0x57, 0x8a, 0x79, 0xe1, 0xde, 0x83, + 0x17, 0xcd, 0x5d, 0x50, 0x31, 0x9e, 0xc7, 0xa8, 0x5e, 0x7b, 0x7e, 0xd1, + 0xde, 0x55, 0xe4, 0xdd, 0x9b, 0xf5, 0xa7, 0x13, 0xdc, 0x57, 0x55, 0xd0, + 0xf0, 0x72, 0x2d, 0xad, 0x47, 0xef, 0xa5, 0xca, 0x16, 0x69, 0x67, 0x27, + 0xb8, 0x27, 0x0d, 0xf6, 0x31, 0xf7, 0xed, 0x9a, 0x7d, 0xba, 0xbd, 0x0b, + 0xf6, 0xe9, 0x56, 0x9f, 0xef, 0x26, 0xdf, 0xcd, 0xd3, 0xcd, 0xc1, 0xb9, + 0xbb, 0x57, 0x8f, 0x3b, 0xcf, 0xe8, 0xf8, 0x70, 0x3d, 0xe6, 0x27, 0x08, + 0x4e, 0xa7, 0x4c, 0x5c, 0x76, 0x46, 0xc7, 0x65, 0x05, 0x1e, 0xf8, 0xb0, + 0x8d, 0xcd, 0x76, 0xf4, 0x5c, 0x9e, 0x8b, 0xcb, 0x2e, 0xd8, 0xa3, 0xa3, + 0xef, 0xff, 0xc8, 0x8e, 0x5e, 0xd2, 0x7b, 0x71, 0xfa, 0x52, 0x8e, 0x14, + 0x20, 0x23, 0xf6, 0x8c, 0xbf, 0x2a, 0xc3, 0x0f, 0xf2, 0x9b, 0x3a, 0x2d, + 0x02, 0xbd, 0x45, 0xb9, 0x9d, 0x97, 0x6c, 0x0f, 0xd3, 0x4c, 0x9d, 0x3e, + 0xed, 0x23, 0x1f, 0x77, 0x7a, 0xe7, 0xfa, 0x27, 0x7e, 0xc3, 0x35, 0x70, + 0xfe, 0xa6, 0x9d, 0x93, 0x71, 0xb2, 0x15, 0xe6, 0x87, 0x6b, 0xe1, 0x77, + 0xdb, 0xfb, 0x08, 0x99, 0x5f, 0x7d, 0xff, 0xb5, 0xe1, 0xd3, 0xac, 0xfe, + 0x3b, 0x22, 0x23, 0x4e, 0x1f, 0xea, 0x4c, 0x7b, 0x0d, 0x03, 0x2a, 0x7d, + 0xd3, 0x00, 0xcf, 0xca, 0x4d, 0x2c, 0xf9, 0xfb, 0x01, 0xf3, 0xba, 0xb0, + 0xa0, 0xe7, 0x94, 0xfb, 0xb0, 0xa6, 0x41, 0x8b, 0x9a, 0xb6, 0x34, 0xfd, + 0x1f, 0x98, 0xd3, 0x91, 0xd4, 0xad, 0xd4, 0x93, 0xa1, 0x8e, 0x4c, 0xc6, + 0xfb, 0x78, 0x7f, 0x84, 0xa6, 0x71, 0x7b, 0x97, 0xc4, 0xd4, 0x39, 0xad, + 0xdf, 0x47, 0x52, 0xbc, 0x5f, 0x66, 0x99, 0xb2, 0xa3, 0x55, 0x65, 0xf5, + 0xb8, 0x3d, 0xf9, 0x43, 0xcc, 0xcd, 0x17, 0x61, 0x6f, 0xf6, 0x8e, 0xbd, + 0x0a, 0x9f, 0x31, 0x2e, 0x5f, 0x2a, 0xbd, 0x04, 0x7a, 0xcd, 0xaf, 0xb5, + 0x77, 0xe1, 0x65, 0x01, 0x37, 0xcf, 0x38, 0xeb, 0xfd, 0xc3, 0x91, 0x3f, + 0x02, 0x5d, 0xfc, 0xc1, 0x4b, 0xec, 0x03, 0xb0, 0x44, 0x60, 0xcf, 0xc3, + 0x36, 0x18, 0x7f, 0x49, 0xef, 0x95, 0xbb, 0xbe, 0xfc, 0x92, 0x8e, 0x53, + 0xf4, 0x97, 0x5b, 0x65, 0x7b, 0xb9, 0x41, 0x76, 0x40, 0x2f, 0xec, 0x28, + 0xfb, 0x78, 0xa2, 0x72, 0x63, 0xd9, 0xcc, 0xd3, 0x47, 0xca, 0x9c, 0xef, + 0x6d, 0x32, 0x71, 0xbc, 0x9a, 0x66, 0xa7, 0xed, 0xde, 0x31, 0xd2, 0x0f, + 0x9e, 0x52, 0x32, 0x3f, 0xad, 0xc7, 0xce, 0x5d, 0xac, 0xc9, 0xc3, 0xb3, + 0xc2, 0xbd, 0xf8, 0xfc, 0x1b, 0x74, 0xdf, 0x68, 0xe5, 0x19, 0x77, 0xde, + 0x8f, 0xd8, 0x5f, 0x09, 0xf7, 0x86, 0xbf, 0xfe, 0x19, 0x10, 0xfd, 0x77, + 0x5d, 0xf4, 0xde, 0x70, 0x4d, 0x7b, 0xd2, 0x76, 0x26, 0xa6, 0x75, 0x84, + 0xa1, 0xf1, 0xf9, 0xbf, 0xe7, 0x22, 0xf2, 0x7f, 0x01, 0x95, 0xf6, 0x2d, + 0x58, 0xd0, 0x73, 0x00, 0x00, 0x00 }; +static u32 bnx2_CP_b09FwData[(0x50/4) + 1] = { + 0x00010030, 0x00000030, 0x00000000, 0x00000001, 0x00010fd0, 0x00000fd0, + 0x00001430, 0x0000007f, 0x00030400, 0x00001000, 0x00000030, 0x00000020, + 0x00050200, 0x00001000, 0x00000030, 0x00000010, 0x00010400, 0x00000400, + 0x00001030, 0x00000020, 0x00000000 }; +static u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = { + 0x080005d8, 0x080007f8, 0x0800073c, 0x08000764, 0x0800078c, 0x080007b4, + 0x08000610, 0x080005fc, 0x08000820, 0x08000820, 0x0800062c, 0x08000648, + 0x08000648, 0x08000820, 0x08000660, 0x08000674, 0x08000820, 0x08000688, + 0x08000820, 0x08000820, 0x0800069c, 0x08000820, 0x08000820, 0x08000820, + 0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820, + 0x08000820, 0x080006b0, 0x08000820, 0x080006c4, 0x080006d8, 0x080006ec, + 0x08000820, 0x08000700, 0x08000714, 0x08000728, 0x08003740, 0x08003758, + 0x08003768, 0x08003778, 0x08003790, 0x080037a8, 0x080037b8, 0x080037c8, + 0x080037e8, 0x080037f8, 0x08003808, 0x08003898, 0x080037d8, 0x08003818, + 0x08003828, 0x08003840, 0x08003860, 0x08003898, 0x08003878, 0x08003878, + 0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x08005618, + 0x08005618, 0x08005640, 0x08005690, 0x08005660, 0x00000000 }; +static u32 bnx2_CP_b09FwBss[(0x870/4) + 1] = { 0x0 }; +static u32 bnx2_CP_b09FwSbss[(0xe9/4) + 1] = { 0x0 }; static struct fw_info bnx2_cp_fw_09 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, .start_addr = 0x0800006c, .text_addr = 0x08000000, - .text_len = 0x6ee8, + .text_len = 0x73cc, .text_index = 0x0, .gz_text = bnx2_CP_b09FwText, .gz_text_len = sizeof(bnx2_CP_b09FwText), - .data_addr = 0x08007020, - .data_len = 0x0, + .data_addr = 0x08007500, + .data_len = 0x50, .data_index = 0x0, .data = bnx2_CP_b09FwData, - .sbss_addr = 0x08007024, - .sbss_len = 0xa1, + .sbss_addr = 0x08007554, + .sbss_len = 0xe9, .sbss_index = 0x0, .sbss = bnx2_CP_b09FwSbss, - .bss_addr = 0x080070d0, - .bss_len = 0x3b0, + .bss_addr = 0x08007640, + .bss_len = 0x870, .bss_index = 0x0, .bss = bnx2_CP_b09FwBss, - .rodata_addr = 0x08006ee8, + .rodata_addr = 0x080073d0, .rodata_len = 0x118, .rodata_index = 0x0, .rodata = bnx2_CP_b09FwRodata, }; static u8 bnx2_RXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c, - 0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67, - 0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a, - 0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1, - 0x03, 0x53, 0xb6, 0x62, 0x07, 0x45, 0x6a, 0xb0, 0x4b, 0xb9, 0x0e, 0x8c, - 0x06, 0x90, 0xff, 0x52, 0xbf, 0xb0, 0xde, 0x2c, 0xa9, 0x58, 0x4d, 0x17, - 0x9c, 0xb5, 0x4d, 0x9b, 0x0e, 0x60, 0xb7, 0x0b, 0x92, 0x12, 0xf5, 0xb0, - 0xd0, 0xb2, 0xa9, 0xdb, 0xea, 0xc1, 0x8e, 0x09, 0x56, 0xb1, 0x53, 0xa0, - 0x2d, 0x5c, 0x27, 0x69, 0xfc, 0x10, 0x14, 0xaa, 0xec, 0xc4, 0x42, 0xd1, - 0xa2, 0x02, 0x12, 0xd8, 0x29, 0x22, 0x7b, 0xfa, 0x7d, 0x77, 0x66, 0xc8, - 0x25, 0x2d, 0xdb, 0x41, 0x1f, 0xfa, 0xd2, 0xbd, 0xc0, 0x62, 0xee, 0xbd, - 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0xff, 0x73, 0x87, 0xd2, 0x1f, 0x74, 0x48, - 0xbb, 0x84, 0xad, 0x13, 0xbf, 0xd4, 0x89, 0x27, 0x1e, 0xb9, 0x69, 0xf4, - 0xa6, 0x9b, 0xd1, 0xbd, 0xd9, 0x30, 0x4c, 0x23, 0x9a, 0x6f, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, - 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0xfb, 0xff, 0xde, - 0x0c, 0x11, 0x8b, 0xcf, 0xce, 0xf0, 0x27, 0x31, 0x3d, 0x23, 0x0f, 0xb9, - 0xb6, 0xc4, 0x8c, 0xcc, 0xd5, 0xa9, 0x49, 0x5b, 0x24, 0x5b, 0xdb, 0x97, - 0xca, 0xc9, 0x87, 0x7e, 0x31, 0x61, 0x0a, 0xe7, 0xaf, 0xcf, 0x5c, 0xfd, - 0x8b, 0x57, 0x6f, 0x4d, 0x5f, 0xa9, 0x1a, 0x12, 0xb3, 0x32, 0x33, 0x07, - 0xac, 0xbd, 0x12, 0xeb, 0xc7, 0x9a, 0x17, 0x87, 0xfe, 0xa9, 0x4b, 0xba, - 0x22, 0x5c, 0x22, 0x0b, 0xe5, 0xb4, 0x73, 0x18, 0xcf, 0x33, 0xb5, 0x7d, - 0xce, 0x9a, 0x98, 0xb2, 0x6a, 0x05, 0x3b, 0x96, 0xca, 0x1a, 0xf1, 0x48, - 0xa9, 0x16, 0x93, 0x8b, 0xea, 0xdf, 0x79, 0x60, 0x4f, 0x9b, 0xfd, 0xf3, - 0x9a, 0x5b, 0xf7, 0xfd, 0xd3, 0x8e, 0xef, 0xbf, 0x8e, 0xdf, 0x7b, 0x0e, - 0xc6, 0xde, 0x47, 0x7e, 0xd6, 0x34, 0x44, 0xb7, 0xff, 0x4c, 0x73, 0x17, - 0x5b, 0xa5, 0x34, 0x2f, 0x32, 0xed, 0xc5, 0xe4, 0x94, 0x57, 0xd4, 0xf2, - 0xf5, 0xb2, 0x76, 0x68, 0x79, 0x56, 0x3b, 0xbc, 0x7c, 0x4a, 0x3b, 0xb2, - 0x5c, 0xd1, 0xdc, 0x65, 0x29, 0xea, 0x07, 0x3a, 0x24, 0x6b, 0x9d, 0xd5, - 0x72, 0xf5, 0x3e, 0xcd, 0x9d, 0xbf, 0xea, 0xbb, 0x4e, 0xda, 0xfa, 0x3d, - 0x31, 0xb3, 0xdc, 0xcf, 0x2d, 0xfb, 0x18, 0x9b, 0x92, 0x4d, 0xf8, 0xbe, - 0x9e, 0xf1, 0x9f, 0x74, 0x47, 0x6d, 0x4b, 0xd7, 0x62, 0x52, 0xaa, 0xb7, - 0x03, 0x6f, 0x87, 0x96, 0x9b, 0x37, 0xb5, 0xbc, 0xe7, 0xbf, 0xe6, 0x3a, - 0xd2, 0x6f, 0x88, 0xef, 0xcf, 0x38, 0x7b, 0x92, 0xc7, 0xe5, 0x0c, 0xf0, - 0xd6, 0x80, 0x4f, 0x2c, 0x3d, 0x43, 0xfa, 0x22, 0x9a, 0x8b, 0x5a, 0x6e, - 0x28, 0xa2, 0x4f, 0x52, 0xa4, 0xbf, 0xb0, 0xa4, 0x83, 0xce, 0xed, 0x52, - 0xa8, 0x5a, 0x32, 0xb1, 0xb4, 0x15, 0xfe, 0xa2, 0xff, 0xea, 0x50, 0x42, - 0xfe, 0xb2, 0x9e, 0x3e, 0x55, 0x04, 0x2f, 0x66, 0xbc, 0x94, 0x80, 0xcf, - 0x59, 0x77, 0xb4, 0x5f, 0x5e, 0xab, 0x27, 0xe5, 0xbb, 0x75, 0x3b, 0x59, - 0x92, 0x6d, 0x52, 0x48, 0x58, 0xb2, 0x82, 0x35, 0xd3, 0xa0, 0x43, 0xb7, - 0x6d, 0xab, 0x04, 0xd8, 0x52, 0xfd, 0x27, 0xfc, 0xb7, 0x32, 0xd6, 0xe4, - 0xa8, 0x5a, 0x53, 0x04, 0xdd, 0x21, 0x2c, 0xcf, 0xa1, 0x60, 0xd5, 0x59, - 0x02, 0x58, 0x29, 0x4e, 0x8e, 0x62, 0xae, 0xfe, 0x85, 0x50, 0x16, 0xad, - 0x38, 0x2f, 0x9f, 0xbb, 0x71, 0xbe, 0xdd, 0xe0, 0x89, 0x24, 0x74, 0xd9, - 0x93, 0x2c, 0x60, 0x66, 0xba, 0xde, 0x81, 0x31, 0x69, 0xf1, 0xfd, 0x23, - 0x8e, 0x58, 0x25, 0xa7, 0x1b, 0xbc, 0x4b, 0x49, 0xc9, 0xe9, 0xc2, 0x9a, - 0x16, 0xb1, 0x6c, 0x9e, 0x81, 0x78, 0xdb, 0x30, 0xef, 0x77, 0x1a, 0x19, - 0xdf, 0x9f, 0x1c, 0x95, 0xae, 0x60, 0x6e, 0x1f, 0x70, 0x98, 0x32, 0x31, - 0xae, 0x01, 0xee, 0x03, 0xd2, 0x17, 0x8b, 0x67, 0xd8, 0xe7, 0x73, 0x54, - 0xdc, 0xd9, 0x54, 0xb8, 0x6f, 0x87, 0x94, 0xbc, 0xeb, 0xc3, 0x3e, 0x78, - 0xed, 0xe1, 0xcc, 0xce, 0x4e, 0x8c, 0xb5, 0x1b, 0x80, 0xc7, 0x29, 0x09, - 0xf7, 0xd8, 0x21, 0x6b, 0x09, 0xd1, 0x2f, 0x39, 0xbd, 0x21, 0x5c, 0x17, - 0x68, 0x8d, 0x64, 0xde, 0x2e, 0x33, 0xf3, 0xad, 0x72, 0x72, 0x9e, 0xbc, - 0x2d, 0x43, 0x16, 0x78, 0xde, 0x52, 0xd4, 0xb2, 0xf5, 0x53, 0xe8, 0x9b, - 0x32, 0x69, 0xfb, 0xaf, 0xcd, 0x38, 0xb3, 0x5a, 0x6e, 0xf9, 0x8c, 0x96, - 0x87, 0x0e, 0x1c, 0x5a, 0x3e, 0xaf, 0x1d, 0xae, 0xaf, 0x76, 0x4a, 0x7b, - 0x1a, 0xda, 0x66, 0xca, 0x49, 0x4f, 0x13, 0xd2, 0xbb, 0x00, 0x7e, 0x65, - 0x2d, 0x70, 0xde, 0xee, 0xd2, 0x0e, 0x03, 0x57, 0x8b, 0xfd, 0xad, 0x0e, - 0xe9, 0x32, 0x64, 0x9b, 0x1d, 0xc1, 0xc6, 0xe4, 0x5b, 0xa0, 0x6d, 0xcd, - 0x49, 0x00, 0x4e, 0xba, 0x83, 0x35, 0x3d, 0x21, 0x3d, 0xd4, 0x25, 0xea, - 0x91, 0x9e, 0xcd, 0xcf, 0xfd, 0x69, 0x6f, 0x69, 0xff, 0x76, 0xc2, 0xc0, - 0x3e, 0x52, 0x0f, 0x4d, 0xda, 0x6e, 0x8f, 0x29, 0x45, 0x4b, 0x97, 0xb4, - 0x95, 0x93, 0x1b, 0x64, 0xc6, 0x11, 0xc9, 0x41, 0xbf, 0x75, 0xdb, 0x04, - 0x8f, 0x6c, 0xf0, 0x68, 0xcf, 0xa9, 0x41, 0xfd, 0x0e, 0x49, 0xf5, 0x15, - 0x35, 0x33, 0xe4, 0xe7, 0x82, 0xdc, 0xa6, 0xd6, 0xeb, 0x19, 0x07, 0x3a, - 0xd9, 0xce, 0x3e, 0xf6, 0x8d, 0xa9, 0x7d, 0x8d, 0x8c, 0x9d, 0x5c, 0x14, - 0xd1, 0xf4, 0xcc, 0x3e, 0xe0, 0xa3, 0xae, 0x12, 0xee, 0x29, 0xd0, 0x48, - 0xda, 0xd9, 0xb7, 0xb1, 0x26, 0x26, 0xae, 0xd3, 0xd9, 0x40, 0x27, 0xe8, - 0x49, 0x90, 0xe7, 0xe4, 0xa1, 0x3a, 0xa7, 0xb6, 0x71, 0xce, 0x5f, 0xfb, - 0xdb, 0x46, 0x4c, 0x79, 0x5d, 0x9d, 0x97, 0x76, 0x45, 0x38, 0x75, 0x46, - 0x21, 0x7f, 0xa6, 0x3d, 0xd1, 0x0a, 0x8e, 0xb5, 0x8e, 0x0b, 0x7a, 0xa1, - 0x1b, 0x99, 0x0e, 0xc9, 0x29, 0xfa, 0x0e, 0x62, 0x2f, 0xda, 0x1b, 0xec, - 0xc6, 0xe6, 0x59, 0x38, 0x97, 0x81, 0xed, 0xa6, 0x95, 0xfe, 0x14, 0x2a, - 0xf4, 0x07, 0xa4, 0x6d, 0x35, 0xad, 0x4b, 0x80, 0xaf, 0xf4, 0x6c, 0x37, - 0x68, 0xe3, 0x18, 0xb6, 0x67, 0xe3, 0xfd, 0x7e, 0xd8, 0xfa, 0xc1, 0x41, - 0xf0, 0x87, 0x70, 0x76, 0x0a, 0xf2, 0xce, 0xba, 0xd8, 0xd3, 0x75, 0x6e, - 0x56, 0x3c, 0xe8, 0xc1, 0x79, 0x06, 0x67, 0xc9, 0xaf, 0x76, 0xe8, 0xb3, - 0x26, 0x05, 0x27, 0x9d, 0xa2, 0xfc, 0x03, 0xda, 0x75, 0xd9, 0x76, 0x4b, - 0x23, 0xed, 0x91, 0xac, 0xa8, 0x8f, 0xa6, 0xc4, 0x47, 0x08, 0x4b, 0x38, - 0xc2, 0xa7, 0x0f, 0x8a, 0xfe, 0x6b, 0xdf, 0xda, 0x74, 0x56, 0x5b, 0x06, - 0x66, 0x41, 0x43, 0xc0, 0x5b, 0xf0, 0xe4, 0xb3, 0x60, 0xc9, 0xd7, 0xad, - 0xfc, 0x23, 0x6c, 0x23, 0x1c, 0x74, 0xa2, 0x8f, 0x34, 0xac, 0x74, 0x04, - 0xf6, 0x15, 0xd1, 0x14, 0xc9, 0x46, 0x0b, 0x71, 0x7c, 0xda, 0x39, 0x08, - 0x0f, 0xbb, 0xf7, 0x60, 0xf7, 0x1e, 0x7c, 0x82, 0x07, 0x9b, 0xf7, 0xe8, - 0x27, 0x52, 0xf2, 0xea, 0x10, 0xfc, 0xda, 0x86, 0x5f, 0x41, 0x1b, 0x43, - 0x5f, 0x17, 0x03, 0x7e, 0x65, 0xba, 0xaa, 0xc3, 0x76, 0x61, 0x43, 0x4b, - 0x9c, 0xb3, 0xf0, 0xcc, 0xe3, 0x69, 0xc3, 0x8f, 0x52, 0xaf, 0x22, 0xff, - 0x49, 0x3f, 0x93, 0x84, 0x4f, 0xa1, 0xaf, 0xa1, 0x2f, 0x21, 0xac, 0xef, - 0xe7, 0x1d, 0xae, 0xf5, 0x65, 0xdc, 0xa1, 0x1d, 0x75, 0x88, 0x1e, 0x2f, - 0x6a, 0x47, 0x87, 0x60, 0x63, 0x37, 0xb6, 0x80, 0x56, 0xda, 0xda, 0x75, - 0x74, 0x15, 0x68, 0xbf, 0xe8, 0x0c, 0xfe, 0x5d, 0xde, 0x36, 0xc0, 0x28, - 0xa1, 0x76, 0x05, 0xe3, 0xb6, 0xd0, 0x9f, 0xf0, 0x7d, 0x3a, 0x95, 0x95, - 0xdd, 0xe1, 0x98, 0xfd, 0x75, 0x7a, 0x1d, 0xfd, 0x96, 0x98, 0x0c, 0x9c, - 0x09, 0xfc, 0xe0, 0xc0, 0x82, 0x25, 0xf6, 0x99, 0x80, 0xc6, 0x81, 0x73, - 0x91, 0x3f, 0x6c, 0x01, 0x3e, 0xd0, 0xe7, 0x6d, 0xc4, 0x09, 0x91, 0xf7, - 0x34, 0x98, 0x0a, 0xe6, 0xb6, 0xf2, 0x82, 0x3e, 0x98, 0xf6, 0x66, 0x35, - 0xda, 0xdb, 0x01, 0xd8, 0x9b, 0xd3, 0x2a, 0x69, 0xe7, 0xef, 0x60, 0x6f, - 0x4f, 0x39, 0x1a, 0x78, 0x23, 0x72, 0xa1, 0xdc, 0x01, 0x5b, 0x37, 0x93, - 0xef, 0xc8, 0x9e, 0xd4, 0xb4, 0x68, 0x72, 0x9a, 0x73, 0x35, 0xcc, 0x29, - 0xff, 0x1b, 0xd8, 0xf7, 0x45, 0xe3, 0x69, 0xd0, 0xe5, 0xfb, 0xd3, 0xc0, - 0x59, 0xd8, 0x6f, 0x84, 0xb6, 0x15, 0xcd, 0xa7, 0x10, 0xf3, 0xdc, 0xcf, - 0x19, 0x52, 0x1c, 0x6e, 0x91, 0xf4, 0xf0, 0x02, 0x70, 0x4f, 0x3a, 0x81, - 0x1d, 0x53, 0xd7, 0x17, 0x81, 0x7f, 0xc6, 0x1b, 0x82, 0x1e, 0xd3, 0x0e, - 0x40, 0x17, 0xf0, 0x2f, 0x02, 0xff, 0x4c, 0xbd, 0x45, 0xbe, 0x69, 0x46, - 0xb1, 0x34, 0x3a, 0x4f, 0x1b, 0xc0, 0xa2, 0x7d, 0x4f, 0xc8, 0x17, 0xbd, - 0xb8, 0xe6, 0x3e, 0x4b, 0x3f, 0x5b, 0x1a, 0x86, 0x9d, 0x68, 0x25, 0x87, - 0x7b, 0x1b, 0xb2, 0xb8, 0x0e, 0x23, 0xd9, 0x52, 0x60, 0x83, 0x59, 0x77, - 0xa8, 0x98, 0x34, 0x94, 0x2f, 0x11, 0x39, 0x5c, 0x36, 0x01, 0xc3, 0x31, - 0xe7, 0x83, 0xb9, 0xb1, 0x72, 0x1f, 0x7c, 0x23, 0xc7, 0x57, 0xfd, 0x49, - 0x27, 0x98, 0xfb, 0xdd, 0x72, 0x81, 0x32, 0x62, 0xdc, 0x4e, 0x95, 0x9c, - 0x7f, 0xf7, 0xa1, 0xbf, 0x9b, 0xd6, 0x5c, 0x1b, 0x4f, 0x7a, 0x2c, 0x8c, - 0xf5, 0xda, 0x11, 0x5b, 0xef, 0x6b, 0x0d, 0x7d, 0xd8, 0x11, 0x4c, 0x1e, - 0x2a, 0x97, 0x7a, 0x5b, 0xe5, 0xaa, 0xc1, 0xd8, 0x79, 0x09, 0x46, 0xed, - 0x96, 0xf7, 0x82, 0x1f, 0xa5, 0x9e, 0x86, 0xb9, 0x58, 0xbe, 0xec, 0xcb, - 0x9a, 0x13, 0xac, 0xc1, 0xb8, 0x23, 0x57, 0xd6, 0xfb, 0x62, 0xb2, 0x3e, - 0xb6, 0xb8, 0x66, 0x49, 0xf6, 0x0e, 0x2f, 0x8a, 0x5a, 0xdb, 0x1b, 0xdb, - 0x58, 0x9b, 0xc8, 0x97, 0x4b, 0x3d, 0x0d, 0xe3, 0x64, 0x0e, 0xb8, 0xf4, - 0x03, 0xeb, 0x6b, 0xfb, 0x37, 0xd6, 0xee, 0x90, 0x54, 0x0f, 0xd7, 0xeb, - 0x7d, 0x6d, 0x1b, 0xb8, 0x53, 0x21, 0x3d, 0xbd, 0x6d, 0x1b, 0x38, 0x6c, - 0xe2, 0x6c, 0x18, 0x0f, 0x13, 0xe7, 0xc0, 0x06, 0xce, 0xfd, 0x9b, 0xe9, - 0x39, 0x21, 0xf0, 0x41, 0xb1, 0xd6, 0x8c, 0x1c, 0xb8, 0x50, 0x1e, 0x1c, - 0xff, 0xa2, 0x20, 0xe6, 0xed, 0xdf, 0x16, 0xfa, 0x64, 0xf3, 0x80, 0x0b, - 0x5e, 0x99, 0x42, 0x1f, 0xa7, 0x49, 0x09, 0x72, 0x7e, 0xa8, 0x26, 0x07, - 0xd6, 0x6a, 0x12, 0xea, 0x12, 0x75, 0xe2, 0x32, 0x6c, 0x4c, 0x8a, 0xbb, - 0x32, 0x1d, 0x13, 0x66, 0xc6, 0x82, 0xad, 0xc9, 0x78, 0x09, 0x3e, 0xd9, - 0xc8, 0xec, 0x79, 0x3b, 0x67, 0x3c, 0xe9, 0x1b, 0x88, 0xdb, 0x39, 0xe9, - 0x38, 0xe8, 0x8e, 0x62, 0xbe, 0x46, 0xdb, 0x82, 0x5f, 0xa9, 0x13, 0xf7, - 0x7c, 0xb7, 0x74, 0x21, 0x2e, 0xd6, 0x5e, 0xda, 0x11, 0xd8, 0x8e, 0x98, - 0x26, 0x7c, 0xed, 0xcc, 0x28, 0xe3, 0x78, 0x6b, 0x0c, 0xf0, 0x13, 0x46, - 0x66, 0x6c, 0xe7, 0xf1, 0xda, 0x9d, 0x3b, 0x0b, 0xb5, 0xe2, 0xce, 0x42, - 0xd9, 0xa2, 0x9d, 0xe8, 0xee, 0x28, 0xfa, 0x2a, 0x57, 0x4a, 0xc2, 0x26, - 0x2e, 0xab, 0x3c, 0xe2, 0xb5, 0x7a, 0x1d, 0xf6, 0x47, 0xfb, 0x16, 0x19, - 0xf7, 0xb0, 0xc7, 0xc8, 0x87, 0x90, 0x3b, 0x68, 0x83, 0x4f, 0xcb, 0xe2, - 0xd4, 0xfa, 0xc8, 0xbf, 0x85, 0xf6, 0xc9, 0xfe, 0xfb, 0x7e, 0xe0, 0xef, - 0xef, 0xe8, 0x0e, 0xe6, 0xde, 0x0a, 0x6d, 0x3a, 0xc2, 0x45, 0x3c, 0xc3, - 0xda, 0x38, 0x72, 0x92, 0xf1, 0xba, 0xa9, 0xd1, 0x3f, 0xe7, 0x3c, 0xe6, - 0x12, 0xcc, 0x23, 0xa6, 0x43, 0x3f, 0x27, 0xd9, 0x1c, 0xfc, 0x88, 0x8e, - 0xdc, 0xa2, 0x00, 0xbb, 0x31, 0x33, 0x57, 0x64, 0x46, 0xf9, 0x48, 0x89, - 0xb5, 0x64, 0x9e, 0x00, 0xcc, 0x7f, 0xc0, 0xe6, 0xda, 0xba, 0x43, 0x3d, - 0x0c, 0x7d, 0xbc, 0xf2, 0xbb, 0x80, 0xbd, 0xbc, 0x05, 0xf6, 0xdd, 0x46, - 0x58, 0xbc, 0xbf, 0xb8, 0xe5, 0xfd, 0x4f, 0x69, 0xbf, 0x78, 0xb7, 0x0a, - 0x7f, 0xda, 0x1a, 0xda, 0xfe, 0x05, 0x29, 0xc0, 0xb7, 0x9a, 0x36, 0x73, - 0xc7, 0xdb, 0xb0, 0x16, 0xe3, 0x1a, 0x68, 0x84, 0xbf, 0x40, 0xcc, 0x04, - 0xbf, 0x11, 0x13, 0x12, 0x37, 0x30, 0x3f, 0xa2, 0x9f, 0x00, 0x2c, 0xfd, - 0x2f, 0x61, 0x5f, 0xe9, 0x20, 0xcf, 0x0b, 0x35, 0xae, 0xa1, 0xaf, 0x12, - 0xdf, 0x1d, 0x6d, 0x83, 0x46, 0xf9, 0xaf, 0x19, 0x76, 0x04, 0x1b, 0xe1, - 0xdd, 0x0a, 0xcb, 0x7c, 0x85, 0xb8, 0xbb, 0xc3, 0x3c, 0x60, 0x4c, 0xb2, - 0xf5, 0x2c, 0x7e, 0x45, 0x99, 0x7c, 0x16, 0xb9, 0x98, 0xdd, 0x42, 0x5e, - 0x90, 0x35, 0x56, 0xc0, 0xa3, 0x68, 0xdd, 0x13, 0xbd, 0x9b, 0xc7, 0xf7, - 0xc5, 0x37, 0x7c, 0x25, 0x2d, 0x4d, 0xb2, 0x88, 0x15, 0xe0, 0x71, 0x6a, - 0x42, 0xcf, 0x24, 0x24, 0x57, 0x0b, 0xf8, 0x8b, 0x78, 0x0b, 0xff, 0xc8, - 0x2e, 0x64, 0xb2, 0xee, 0x07, 0x23, 0x99, 0x53, 0xcf, 0xb2, 0x90, 0x4d, - 0x0a, 0xba, 0x34, 0x86, 0xb5, 0x72, 0x02, 0x38, 0x18, 0x87, 0x1d, 0x3d, - 0x13, 0x97, 0x82, 0xc5, 0x7c, 0x41, 0xe5, 0x7a, 0x59, 0xfa, 0x01, 0x3d, - 0xd3, 0x86, 0x39, 0xf6, 0x1f, 0xee, 0x0e, 0x64, 0xdd, 0xc9, 0xf1, 0xb8, - 0x9e, 0xe9, 0xde, 0x32, 0xff, 0x7a, 0x67, 0x40, 0x9b, 0x1a, 0x63, 0xfe, - 0x5f, 0xb6, 0x8c, 0xbf, 0x1e, 0xdf, 0x3c, 0x7e, 0x60, 0x67, 0xa4, 0x0f, - 0x7a, 0xe6, 0x89, 0x90, 0x5e, 0xea, 0xe9, 0x56, 0x5a, 0x7f, 0x13, 0x7d, - 0x79, 0x0e, 0x38, 0x95, 0x8e, 0xff, 0x06, 0xfa, 0xb2, 0x0e, 0xfb, 0x09, - 0xfa, 0xd2, 0x48, 0xc3, 0x7a, 0x5d, 0x51, 0xd1, 0x91, 0x93, 0xba, 0xa3, - 0x7b, 0x90, 0x77, 0xa4, 0x24, 0x5f, 0x07, 0xef, 0xd6, 0xe3, 0xea, 0x3a, - 0x4c, 0x71, 0x03, 0x26, 0x88, 0x3b, 0xf9, 0xba, 0x8f, 0x3c, 0xae, 0x31, - 0x06, 0x0f, 0xa3, 0x5f, 0xc4, 0x59, 0x57, 0x64, 0xd2, 0x5b, 0xcb, 0xea, - 0xf6, 0xa9, 0x20, 0x0f, 0xb5, 0xbf, 0xad, 0xe5, 0x17, 0x99, 0xa3, 0xc6, - 0xd0, 0x57, 0xf5, 0x07, 0x62, 0xdc, 0x33, 0x5a, 0x76, 0x79, 0x0e, 0xf9, - 0xe9, 0x12, 0x7e, 0x67, 0xf1, 0xab, 0xe1, 0x17, 0xd5, 0x01, 0x2f, 0xa0, - 0x8e, 0x50, 0xfe, 0x1e, 0xb1, 0x29, 0xd8, 0xff, 0x67, 0x4b, 0xc8, 0x8f, - 0xe7, 0x12, 0xf2, 0x94, 0xad, 0xf7, 0xea, 0x81, 0x8f, 0xcb, 0x22, 0xb7, - 0xb6, 0x2e, 0xcb, 0x97, 0xc2, 0x1c, 0x4d, 0xe4, 0x9d, 0x0a, 0x64, 0xb9, - 0xff, 0x48, 0xe8, 0x9f, 0xbe, 0xf6, 0xa0, 0xab, 0x7c, 0x79, 0x98, 0x83, - 0xc1, 0xef, 0x64, 0x15, 0xd4, 0x1b, 0xe0, 0x8f, 0x26, 0xef, 0x41, 0x8f, - 0xdf, 0xa9, 0xb4, 0x83, 0x1e, 0x5b, 0x0a, 0xc7, 0x90, 0xbb, 0x68, 0x83, - 0xd6, 0x36, 0xad, 0x1d, 0x79, 0x18, 0xfc, 0x8e, 0x1a, 0x93, 0x67, 0x17, - 0xa7, 0x16, 0xca, 0x3a, 0x60, 0xc1, 0xf3, 0x51, 0xf4, 0xa1, 0x7f, 0x97, - 0x2a, 0x5c, 0xa7, 0xcb, 0xbb, 0x15, 0x43, 0x7e, 0x8e, 0xbc, 0xee, 0x3d, - 0xfb, 0xe2, 0x14, 0x6c, 0xb0, 0x0f, 0xf1, 0x0a, 0xb5, 0xd0, 0x1e, 0xc6, - 0x8c, 0x01, 0x13, 0xcf, 0x3c, 0x7e, 0x87, 0x91, 0xe7, 0x5d, 0x7b, 0xcd, - 0x27, 0xc1, 0x93, 0xb6, 0x18, 0xd6, 0x10, 0xde, 0x04, 0x6d, 0x5d, 0xd0, - 0xc1, 0xb4, 0x35, 0x21, 0xdd, 0x96, 0xca, 0x9d, 0x34, 0xce, 0x07, 0x7e, - 0xf2, 0xe3, 0xf3, 0xe4, 0xb3, 0x01, 0x1d, 0xe2, 0x98, 0xef, 0xe8, 0xcf, - 0x89, 0x2f, 0x7d, 0x30, 0x8b, 0xc3, 0x5c, 0xaa, 0x04, 0xfd, 0x68, 0x4e, - 0xb4, 0x28, 0xa6, 0xd2, 0x4f, 0xe7, 0x61, 0xab, 0x1c, 0x8f, 0x8b, 0x92, - 0xc1, 0x26, 0x79, 0x52, 0x8f, 0x56, 0xa7, 0x66, 0x6c, 0xca, 0xd5, 0x92, - 0xe9, 0x72, 0x24, 0x57, 0xca, 0x08, 0x75, 0x66, 0xe5, 0xdb, 0x90, 0xab, - 0x1e, 0xd6, 0x20, 0xf0, 0x03, 0x73, 0x94, 0x2f, 0xea, 0xc4, 0x0a, 0xf2, - 0xb0, 0x8a, 0xc4, 0x83, 0x1a, 0xea, 0x19, 0xd4, 0x1d, 0x90, 0x5f, 0x79, - 0x0e, 0x38, 0x12, 0x78, 0x2e, 0xe1, 0x99, 0xc4, 0xf3, 0x2c, 0x9e, 0xfd, - 0x78, 0xd6, 0x68, 0x1f, 0x61, 0xde, 0xf3, 0x31, 0x7a, 0x60, 0x27, 0x79, - 0xda, 0xb4, 0x7c, 0xaf, 0x9e, 0x91, 0xbf, 0xad, 0x1f, 0x94, 0xbf, 0xa9, - 0x8f, 0xca, 0x5f, 0xd7, 0x1d, 0x79, 0xb9, 0xbe, 0x5f, 0xfe, 0xaa, 0x3e, - 0xcc, 0x9a, 0x10, 0x39, 0x5c, 0x0a, 0xbe, 0xf9, 0xbc, 0x3c, 0xe8, 0xd5, - 0xe1, 0x73, 0x28, 0xff, 0x8b, 0x53, 0xd9, 0xda, 0x75, 0x52, 0x78, 0xd6, - 0x42, 0x9e, 0x69, 0xb0, 0x2e, 0x93, 0xc7, 0x9c, 0x3b, 0xe2, 0x94, 0xbd, - 0x6e, 0xb3, 0x4e, 0x39, 0x49, 0x38, 0xd4, 0xbb, 0x1a, 0xf2, 0x97, 0x16, - 0x99, 0x48, 0xa4, 0x57, 0x5c, 0x23, 0x19, 0xfa, 0xa3, 0x3b, 0x01, 0x87, - 0x3d, 0xbd, 0x0e, 0x59, 0x7b, 0x1e, 0xb6, 0xe0, 0xa0, 0x56, 0x4e, 0xc4, - 0xe0, 0xfb, 0x54, 0x7e, 0xa2, 0x7c, 0x4b, 0xe0, 0x4b, 0xa3, 0x9a, 0x91, - 0x73, 0xd9, 0x70, 0x8e, 0xf1, 0xd1, 0x02, 0xec, 0x72, 0x18, 0x43, 0xb6, - 0xe2, 0xa4, 0x6f, 0x3c, 0x16, 0xfa, 0xc7, 0x15, 0x39, 0xe1, 0x0d, 0x66, - 0xaf, 0x20, 0xf6, 0x68, 0x2d, 0x51, 0x5e, 0xb4, 0x0b, 0xb4, 0xf9, 0xfe, - 0xdd, 0xac, 0xbf, 0xe3, 0xa6, 0xfc, 0x70, 0x36, 0x6d, 0x3d, 0xa2, 0xcf, - 0x40, 0xce, 0xbe, 0x7f, 0xd4, 0x4e, 0x9f, 0x9a, 0xd0, 0x3b, 0xe5, 0x27, - 0xcf, 0x30, 0x26, 0xaf, 0x4e, 0x7d, 0x1f, 0x7a, 0x50, 0x5d, 0x6a, 0x95, - 0x6a, 0xd5, 0x94, 0x4b, 0x23, 0x83, 0x6a, 0xdf, 0x6a, 0x2d, 0x8e, 0x3c, - 0xaf, 0x4d, 0xa6, 0xfb, 0x94, 0xb2, 0xc3, 0x6f, 0x0f, 0x2b, 0xbf, 0xed, - 0xda, 0x78, 0xd6, 0x92, 0xd6, 0x66, 0x5a, 0x5e, 0x96, 0x82, 0x07, 0x1d, - 0x8b, 0xef, 0x02, 0x4f, 0xd8, 0x1f, 0xb4, 0x0a, 0x3a, 0x62, 0xa0, 0x39, - 0x68, 0x3d, 0xa8, 0xff, 0xd2, 0xff, 0x1d, 0x93, 0x7c, 0x7c, 0x1b, 0xb1, - 0x85, 0xb1, 0x52, 0x53, 0x7a, 0xb7, 0xb0, 0xf4, 0x53, 0x8b, 0xfe, 0x65, - 0xa5, 0xb6, 0x2b, 0x1c, 0xd3, 0xbf, 0x73, 0xdc, 0x2e, 0x2f, 0x57, 0xb7, - 0xcb, 0x62, 0x95, 0xef, 0x5b, 0x65, 0xa1, 0x3a, 0x78, 0xa5, 0x57, 0xef, - 0x93, 0xd5, 0xeb, 0x6e, 0xb4, 0xee, 0xd7, 0xc1, 0x93, 0x63, 0x1f, 0xc9, - 0x07, 0x23, 0xdd, 0xf2, 0xd6, 0x7d, 0xe9, 0x17, 0xfe, 0x44, 0x87, 0x3e, - 0x8e, 0x74, 0xd0, 0xce, 0xd0, 0xe7, 0x7c, 0xfa, 0x4a, 0x56, 0xa7, 0x9e, - 0xfd, 0x00, 0xfa, 0x95, 0xae, 0x04, 0x3a, 0x49, 0xdc, 0xc4, 0x0b, 0xf9, - 0xd8, 0x6f, 0x00, 0x27, 0xde, 0xd5, 0x06, 0x81, 0xeb, 0x0d, 0xc5, 0x8b, - 0xbb, 0x9d, 0xf4, 0x15, 0x84, 0x28, 0xff, 0x92, 0x3d, 0x38, 0x3c, 0xa0, - 0xef, 0x92, 0x6a, 0xf2, 0x46, 0xeb, 0xbb, 0x88, 0x07, 0xd9, 0x44, 0xfa, - 0xd4, 0x45, 0x59, 0x9d, 0xba, 0x60, 0x53, 0x17, 0x69, 0xc3, 0xff, 0x80, - 0x9c, 0xd4, 0x92, 0x4a, 0x8d, 0xbe, 0x8b, 0xb8, 0x58, 0x17, 0xec, 0xb5, - 0x4e, 0x80, 0x06, 0x77, 0x3f, 0xde, 0x61, 0xde, 0xf8, 0x3c, 0xe5, 0xd6, - 0xc2, 0xb5, 0xc3, 0x59, 0xbd, 0x7f, 0x0b, 0x8f, 0x06, 0xad, 0x43, 0x3a, - 0xf7, 0xfb, 0x2f, 0xec, 0xfb, 0x3e, 0x68, 0x1d, 0xc4, 0x5a, 0xc4, 0xd0, - 0x64, 0xe3, 0x1e, 0x3f, 0x52, 0x7b, 0x3c, 0x5b, 0x43, 0x0e, 0xb8, 0xbe, - 0x07, 0xe6, 0x6a, 0x3a, 0xce, 0x69, 0x2a, 0xb9, 0x5c, 0x1a, 0x21, 0x7f, - 0x6f, 0xef, 0x61, 0x2c, 0x37, 0x32, 0x2f, 0x85, 0x79, 0x46, 0x4c, 0x7e, - 0x8c, 0xba, 0x6b, 0x12, 0xfe, 0x7f, 0x61, 0xef, 0x20, 0x68, 0x40, 0x7d, - 0x9a, 0x54, 0xf1, 0x7c, 0xca, 0x05, 0x8e, 0x9c, 0xc2, 0xfd, 0xa6, 0x2c, - 0x01, 0xf7, 0x38, 0xf9, 0x00, 0xdc, 0x33, 0x9c, 0x57, 0x32, 0xc0, 0x7c, - 0x2d, 0x05, 0xbc, 0xbd, 0xa1, 0xff, 0x8b, 0x43, 0x57, 0xf7, 0x59, 0x77, - 0x4b, 0x2c, 0xf4, 0x7f, 0x71, 0x79, 0xeb, 0x79, 0xe8, 0x7d, 0x9c, 0xfa, - 0x93, 0xe8, 0xd9, 0xd0, 0x9f, 0x46, 0xfc, 0xad, 0x92, 0xaf, 0xc4, 0x80, - 0x17, 0x39, 0xf7, 0x28, 0xf1, 0x62, 0x5c, 0xa5, 0x2e, 0x17, 0x43, 0x5d, - 0xee, 0x08, 0x71, 0xaf, 0x41, 0x97, 0xd3, 0xa9, 0x55, 0x9d, 0xf5, 0xd5, - 0x4e, 0x55, 0xf3, 0x1a, 0xb0, 0xaf, 0x42, 0x99, 0xb1, 0x88, 0xb6, 0x75, - 0x71, 0x6a, 0x12, 0x35, 0x6c, 0xa1, 0x7c, 0x50, 0x2f, 0xd4, 0x47, 0xf5, - 0x82, 0x47, 0x7d, 0xdb, 0x6b, 0x2d, 0x28, 0x1e, 0x27, 0x65, 0xa1, 0xfe, - 0x81, 0x5f, 0xda, 0xbb, 0x0d, 0x7d, 0xe8, 0xfe, 0x38, 0xe5, 0x7b, 0x3d, - 0xe9, 0x42, 0x50, 0x27, 0xbf, 0x13, 0x72, 0x66, 0xe8, 0x7b, 0xdd, 0xcc, - 0xd1, 0x96, 0x87, 0x88, 0x1f, 0x74, 0x24, 0x12, 0xb2, 0xe8, 0x71, 0x8f, - 0xd5, 0x29, 0xf2, 0xb2, 0x30, 0x67, 0xc9, 0x09, 0x25, 0x3f, 0x9e, 0x9b, - 0xf7, 0x47, 0x86, 0x4c, 0xc6, 0x07, 0xad, 0x47, 0x25, 0x7d, 0x65, 0xcd, - 0x48, 0xbf, 0x30, 0x81, 0xb8, 0xba, 0x30, 0x6f, 0x88, 0xab, 0xea, 0x30, - 0xca, 0x28, 0x5d, 0x81, 0x35, 0x86, 0x67, 0xbf, 0xa7, 0xe1, 0xec, 0x5d, - 0x72, 0xe1, 0xf9, 0xcf, 0xc3, 0xee, 0x5f, 0x81, 0x2c, 0xcc, 0xd4, 0x71, - 0xe4, 0x19, 0xcf, 0xc9, 0xa0, 0x55, 0x42, 0xfe, 0x0c, 0xbe, 0xa3, 0xbd, - 0xa2, 0x6c, 0x60, 0x41, 0xc7, 0xb8, 0x9f, 0x7c, 0xe2, 0x78, 0xb7, 0x2c, - 0xf4, 0x05, 0x36, 0xce, 0x77, 0x03, 0xc0, 0x11, 0xbc, 0xe3, 0xf8, 0xb7, - 0x64, 0x40, 0xbd, 0xab, 0xaa, 0x75, 0x25, 0xe9, 0x0d, 0xe5, 0xf7, 0x18, - 0xf6, 0x24, 0x8f, 0xa3, 0xf9, 0x4e, 0x09, 0x6c, 0x29, 0xe2, 0xbb, 0x25, - 0x47, 0x6b, 0x09, 0xb9, 0xa7, 0x96, 0x94, 0x2f, 0xd7, 0xfa, 0x25, 0x0f, - 0x39, 0x4e, 0x8e, 0x3e, 0xd9, 0xc3, 0xb3, 0xe5, 0x96, 0xd2, 0x2f, 0x88, - 0x4e, 0x5a, 0xab, 0x72, 0xdc, 0x8b, 0xe8, 0xe9, 0x08, 0xe9, 0x33, 0xc3, - 0x71, 0x2c, 0xa4, 0xa1, 0x11, 0x5f, 0x07, 0x70, 0x65, 0x81, 0xe7, 0xa5, - 0x10, 0x0f, 0xfd, 0x08, 0x68, 0x3d, 0x96, 0x94, 0x25, 0x8f, 0x74, 0x6c, - 0x97, 0x52, 0x82, 0xfd, 0x57, 0xa0, 0x6f, 0xc4, 0xb3, 0x8d, 0xf9, 0xcd, - 0x26, 0x1e, 0x3f, 0x5c, 0x2b, 0x82, 0xc7, 0xe4, 0x2f, 0xe1, 0xe0, 0xaf, - 0xbf, 0x40, 0xf9, 0xed, 0x43, 0x8e, 0x6f, 0x07, 0xba, 0x69, 0x6d, 0xec, - 0x99, 0x9f, 0xeb, 0x82, 0xac, 0xb8, 0x6f, 0xbb, 0x1c, 0x83, 0xdd, 0xe7, - 0xaa, 0xdc, 0xff, 0x18, 0xf4, 0xe8, 0x2d, 0xb5, 0x7f, 0x7e, 0xa9, 0x2f, - 0x5c, 0xcf, 0xb5, 0x5d, 0x5b, 0xd6, 0xb6, 0xca, 0xa1, 0x8a, 0x75, 0x8d, - 0xf5, 0xbf, 0x8f, 0xf5, 0xba, 0x9c, 0x1e, 0xe5, 0x7a, 0xe2, 0x01, 0x5c, - 0x35, 0xf1, 0x29, 0x78, 0xe2, 0xaa, 0xde, 0xcf, 0x55, 0x5b, 0x25, 0x57, - 0x89, 0x70, 0x11, 0xcf, 0x47, 0xa8, 0x87, 0xbf, 0xaa, 0x70, 0x4d, 0x2a, - 0x5c, 0x78, 0x5f, 0xa5, 0xcf, 0xb9, 0x15, 0xeb, 0x3b, 0xe8, 0xff, 0xa5, - 0x14, 0xef, 0x94, 0x92, 0xaa, 0xe9, 0xdb, 0x95, 0xaf, 0x29, 0xc5, 0xdb, - 0xf0, 0xbe, 0x13, 0x36, 0xbf, 0x0f, 0xb9, 0x45, 0x17, 0xeb, 0xdc, 0x2d, - 0x73, 0x5b, 0xe9, 0x8f, 0x6d, 0xa1, 0x3f, 0x06, 0xb8, 0x5e, 0xec, 0x19, - 0xc0, 0xe5, 0x01, 0x37, 0x3d, 0x07, 0x3e, 0x3b, 0xf4, 0x2b, 0x8c, 0x93, - 0xd7, 0x29, 0x5a, 0xa6, 0x97, 0xfe, 0x1b, 0xe7, 0xea, 0xc3, 0xda, 0x68, - 0x1c, 0xf0, 0xe1, 0x69, 0xe0, 0x99, 0xab, 0xaa, 0xbb, 0x0b, 0xc8, 0x60, - 0x7b, 0x9c, 0x67, 0x2f, 0x55, 0x3f, 0x8b, 0x67, 0xd7, 0x35, 0xf0, 0x8b, - 0xbc, 0x22, 0xbd, 0xa4, 0x95, 0xf7, 0x48, 0xb0, 0x37, 0x07, 0x7a, 0x1c, - 0x37, 0x24, 0x3f, 0x6a, 0x21, 0x3f, 0xe7, 0x3d, 0x2c, 0xed, 0xd2, 0xe2, - 0xdd, 0x67, 0x4c, 0xb7, 0x19, 0x6b, 0x4d, 0x75, 0xf6, 0xe3, 0x4b, 0xbc, - 0x8b, 0x4d, 0xf1, 0xee, 0x6e, 0x98, 0xd7, 0x18, 0x8f, 0x2c, 0xd9, 0xf2, - 0x78, 0x6d, 0x58, 0x1e, 0xad, 0xa5, 0xad, 0xfb, 0xe1, 0x03, 0x0a, 0xeb, - 0x77, 0xb4, 0x43, 0x71, 0xfa, 0x2f, 0x13, 0x79, 0x60, 0x8b, 0x1d, 0xe4, - 0x05, 0x25, 0xd6, 0x6c, 0x73, 0x69, 0xde, 0xe3, 0x58, 0x55, 0xd9, 0x9a, - 0x3b, 0xfc, 0x5f, 0xe6, 0x0d, 0xdc, 0x9f, 0xfe, 0x1a, 0x79, 0x82, 0x87, - 0x3c, 0xc1, 0x43, 0x9e, 0xe0, 0x21, 0x4f, 0xf0, 0x90, 0x27, 0x78, 0xc8, - 0x13, 0x3c, 0xe4, 0x09, 0x1e, 0xf2, 0x04, 0xc4, 0xee, 0xa0, 0x5e, 0x18, - 0x43, 0xfe, 0x0b, 0xff, 0xe5, 0xdd, 0x06, 0x3e, 0xf1, 0xfe, 0x92, 0x31, - 0x87, 0xb1, 0x99, 0x73, 0xab, 0xdb, 0x5c, 0xca, 0x4d, 0xf9, 0xbe, 0x3b, - 0x31, 0x37, 0x1e, 0xe6, 0x23, 0x84, 0x89, 0x62, 0x37, 0xe1, 0xe4, 0xa0, - 0xeb, 0x68, 0xb0, 0x31, 0xe6, 0x2b, 0x41, 0xcc, 0x0a, 0x72, 0xe5, 0xb7, - 0x91, 0xb3, 0xa4, 0x90, 0xb3, 0xf4, 0x23, 0x3f, 0xe1, 0x9d, 0x75, 0x74, - 0xc7, 0x94, 0xd5, 0x8e, 0x7a, 0x63, 0xda, 0x3d, 0x1e, 0x73, 0x69, 0x3b, - 0x55, 0xd0, 0xf5, 0xb9, 0x5e, 0xf1, 0x25, 0x37, 0xf2, 0x4d, 0xe4, 0xad, - 0xcf, 0xa9, 0xfb, 0xb4, 0xf1, 0x21, 0xca, 0xbc, 0xf2, 0x09, 0xb9, 0x6b, - 0xc4, 0xdf, 0xe0, 0x1e, 0x50, 0x5f, 0x20, 0xff, 0x44, 0x7a, 0xce, 0x81, - 0xe1, 0xe7, 0x62, 0x12, 0x3f, 0xb3, 0x1d, 0x73, 0x96, 0xf4, 0xaa, 0xbb, - 0x24, 0x88, 0xf2, 0xdc, 0x55, 0xc8, 0xcb, 0x16, 0xfd, 0x1c, 0x6f, 0x1c, - 0x88, 0x97, 0xfe, 0x75, 0x65, 0x2a, 0x57, 0x5d, 0x51, 0x3a, 0x75, 0xb4, - 0x96, 0x47, 0x7d, 0xd4, 0xd3, 0x2b, 0xed, 0x26, 0x6a, 0xab, 0x08, 0x37, - 0x71, 0xfe, 0x32, 0xae, 0x6a, 0x9e, 0x73, 0xeb, 0xf2, 0x84, 0xac, 0xb9, - 0xcf, 0xca, 0x54, 0xa9, 0x92, 0x4e, 0xb2, 0x56, 0xce, 0x5a, 0x2b, 0x53, - 0x27, 0x81, 0x63, 0x11, 0xb9, 0x81, 0xa1, 0xf6, 0x5e, 0x99, 0x9a, 0xae, - 0x04, 0xf7, 0x59, 0x01, 0x0d, 0x8c, 0x57, 0xed, 0x62, 0x2c, 0x04, 0xf7, - 0x5a, 0xba, 0x5a, 0xcb, 0x75, 0x5c, 0x6f, 0x62, 0x1d, 0xe5, 0x36, 0x8c, - 0xb5, 0x94, 0x1d, 0x69, 0x58, 0x99, 0x2a, 0x56, 0x1b, 0x69, 0x20, 0x1e, - 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0xc4, 0x45, 0x3f, 0xe3, 0xfb, 0x85, 0x91, - 0xfe, 0x30, 0xef, 0x3a, 0x89, 0xfc, 0xce, 0x0c, 0xf4, 0x5c, 0x8d, 0xbf, - 0xa3, 0xe2, 0x54, 0x4a, 0xe7, 0x3c, 0x9f, 0x78, 0x37, 0xba, 0x80, 0x39, - 0x8c, 0x17, 0x23, 0x58, 0x3d, 0x84, 0xed, 0x6c, 0xe0, 0x67, 0x4b, 0xb8, - 0x1f, 0x69, 0xe2, 0x39, 0x2f, 0x61, 0x2f, 0xd2, 0x45, 0x98, 0x38, 0x68, - 0x83, 0x2c, 0xbd, 0xff, 0x2d, 0xef, 0x1b, 0xcf, 0x44, 0x9e, 0x9a, 0x58, - 0x43, 0x78, 0xe2, 0x88, 0xd6, 0xe0, 0xc5, 0xb9, 0x60, 0x9d, 0xbe, 0x7e, - 0xff, 0xf7, 0x69, 0xfb, 0x36, 0xd2, 0x1a, 0xed, 0x1f, 0xe1, 0x19, 0x0e, - 0xe4, 0xb6, 0xbe, 0x5e, 0xfd, 0x9f, 0x61, 0x78, 0x42, 0x17, 0x3f, 0x76, - 0x8f, 0x3a, 0xdc, 0x50, 0x87, 0x46, 0xf7, 0x17, 0xbc, 0x0f, 0x60, 0x7d, - 0xcf, 0x6f, 0x07, 0x8d, 0xb5, 0xe2, 0xcb, 0x61, 0x2c, 0xdb, 0x29, 0x59, - 0x93, 0x75, 0xc3, 0xf9, 0x70, 0xbc, 0x03, 0xb1, 0x8d, 0xe3, 0x3a, 0xf8, - 0x0b, 0x5d, 0x76, 0xda, 0xc3, 0xba, 0x25, 0x1e, 0x7c, 0xe3, 0x19, 0xa6, - 0x1d, 0xb1, 0xee, 0x6b, 0x0b, 0xe7, 0x22, 0x3b, 0xa2, 0x1f, 0x36, 0xc3, - 0x39, 0xfa, 0x5b, 0x1d, 0xb5, 0x0b, 0xfb, 0xc0, 0xb3, 0xd8, 0x68, 0x4b, - 0xd1, 0x33, 0x2e, 0x67, 0xe7, 0x23, 0xbf, 0x05, 0x9f, 0x32, 0x64, 0x86, - 0xbe, 0xbf, 0x03, 0xbe, 0xaf, 0x4b, 0x0e, 0xc1, 0x67, 0x1d, 0x86, 0xcf, - 0x3a, 0x82, 0x7a, 0x71, 0x6c, 0xa9, 0xf1, 0x9e, 0x97, 0x35, 0x6a, 0x97, - 0x76, 0x5c, 0xc9, 0xbf, 0xe8, 0x1b, 0xf6, 0x47, 0xd0, 0x01, 0xd6, 0x5d, - 0x91, 0x4e, 0xc0, 0xdf, 0x3a, 0x71, 0xe8, 0xc4, 0xd6, 0xfb, 0xe4, 0x61, - 0xd8, 0x46, 0x7b, 0x56, 0xc5, 0x86, 0xa5, 0x80, 0xf7, 0xa5, 0x6a, 0xc0, - 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5, 0x58, 0xb3, 0xa4, 0x88, 0x7d, 0x8b, - 0xd8, 0xb7, 0x88, 0x3a, 0x6f, 0xba, 0xd6, 0xf8, 0x1d, 0xab, 0x33, 0xa4, - 0x9d, 0x6b, 0xa3, 0xbe, 0xd5, 0x70, 0xfe, 0xe8, 0x79, 0x0a, 0xfc, 0x7f, - 0x0c, 0xfc, 0x3f, 0x81, 0xfa, 0xe6, 0x8f, 0x50, 0xdf, 0x7c, 0x0d, 0xf5, - 0xcd, 0x71, 0xd4, 0x37, 0x13, 0xa8, 0x6f, 0xbe, 0x0a, 0xff, 0xf1, 0x15, - 0xf8, 0x8f, 0x63, 0xf0, 0x1f, 0xe3, 0xea, 0xee, 0xe9, 0xa8, 0xb7, 0xf5, - 0x4e, 0x25, 0xda, 0x8b, 0xed, 0x67, 0x22, 0x76, 0x11, 0x67, 0x1a, 0x93, - 0x6a, 0x9d, 0xf5, 0x8d, 0x23, 0xee, 0x41, 0xd6, 0x37, 0xc7, 0xb4, 0x09, - 0xe4, 0xef, 0xf7, 0xef, 0x67, 0xdd, 0x13, 0xd7, 0x72, 0xaa, 0xee, 0x49, - 0x9f, 0x77, 0x91, 0x22, 0x21, 0xf7, 0xc3, 0x99, 0xd3, 0x67, 0x73, 0xa0, - 0x25, 0xc8, 0xf9, 0x7a, 0x42, 0xbf, 0xd7, 0x21, 0x8b, 0xb3, 0xa8, 0x19, - 0xbc, 0x1f, 0x6b, 0x05, 0xe5, 0x1b, 0x2d, 0x8c, 0x51, 0x2b, 0x7b, 0xff, - 0x1c, 0x8e, 0x47, 0x64, 0x72, 0x1e, 0xb5, 0xed, 0xf3, 0xff, 0xa8, 0xe5, - 0xd4, 0xd8, 0xc1, 0x18, 0xf9, 0xee, 0xf3, 0x7f, 0x1f, 0x8e, 0x8b, 0xa1, - 0x3e, 0x84, 0xb4, 0x5a, 0x0e, 0x9e, 0xdd, 0x61, 0xce, 0xf1, 0x6a, 0xef, - 0xe6, 0xff, 0xd3, 0x8e, 0xad, 0x45, 0x13, 0xfb, 0x1b, 0x3b, 0x82, 0xfa, - 0xac, 0x71, 0xbe, 0xab, 0x61, 0xfe, 0x8a, 0xfa, 0xce, 0x5a, 0x28, 0xb7, - 0xfd, 0x0a, 0x1e, 0x58, 0x96, 0x86, 0x98, 0xe7, 0x7d, 0xe4, 0xf3, 0xfb, - 0x9f, 0xab, 0xb7, 0xab, 0x6f, 0x72, 0xae, 0xca, 0xb7, 0x61, 0xe7, 0x23, - 0xa5, 0x1d, 0x81, 0x2f, 0x60, 0x3f, 0xa1, 0x05, 0xfe, 0xfd, 0x8f, 0x81, - 0x07, 0xbc, 0xf6, 0x1a, 0x6b, 0x38, 0x2b, 0xbc, 0x4b, 0xb9, 0x32, 0xc5, - 0xdc, 0xba, 0xa4, 0x70, 0xb3, 0xd6, 0x63, 0xdd, 0x17, 0xc5, 0x80, 0x08, - 0xd7, 0xcf, 0x13, 0x01, 0xdd, 0xe3, 0xa8, 0xe9, 0x08, 0x13, 0x8d, 0x1b, - 0xeb, 0xbf, 0x8e, 0xf0, 0x1e, 0xee, 0x4a, 0x90, 0x57, 0x29, 0x7c, 0x66, - 0x88, 0xef, 0x3f, 0xfd, 0xc0, 0xf7, 0x70, 0xbd, 0xd5, 0xb0, 0xfe, 0x3c, - 0x72, 0x3d, 0xde, 0x99, 0xec, 0x52, 0xdf, 0x19, 0xdf, 0x9f, 0xed, 0x94, - 0x5f, 0x3c, 0xe3, 0xfb, 0xe3, 0x4e, 0x7a, 0xf8, 0x4d, 0xd4, 0x1e, 0x67, - 0x68, 0x27, 0x23, 0xa4, 0x73, 0x30, 0x35, 0x2d, 0x03, 0xbd, 0x41, 0x2e, - 0xfe, 0x75, 0xed, 0xe3, 0x74, 0xeb, 0xe1, 0x3e, 0x3f, 0x6c, 0xd8, 0x27, - 0xd5, 0xb0, 0xcf, 0x0a, 0x6d, 0xb6, 0x7a, 0x2f, 0xce, 0x5c, 0xdc, 0x75, - 0xa3, 0x95, 0x08, 0xeb, 0xb2, 0x47, 0x47, 0xda, 0xa4, 0xd2, 0x97, 0x5e, - 0xf9, 0x11, 0xf2, 0xf5, 0xc2, 0x08, 0xe6, 0x12, 0x83, 0x78, 0xc7, 0xf9, - 0x74, 0x15, 0xb9, 0xe8, 0x4a, 0x55, 0x86, 0xb0, 0x3e, 0x5d, 0x14, 0xe1, - 0x3c, 0xfb, 0x8a, 0xb6, 0x6a, 0xe8, 0x03, 0x92, 0x6b, 0x38, 0xf3, 0x04, - 0xea, 0xaf, 0x13, 0xeb, 0xf5, 0x30, 0xf7, 0xb9, 0x59, 0x5b, 0x53, 0xb9, - 0xf1, 0x01, 0xad, 0x98, 0x08, 0xce, 0xf8, 0x87, 0xf0, 0x17, 0x86, 0xce, - 0xb5, 0xef, 0x03, 0xb7, 0x26, 0x0b, 0xcf, 0x18, 0xea, 0x0e, 0xb6, 0x30, - 0x42, 0x59, 0xf3, 0x79, 0x2d, 0xde, 0x45, 0x67, 0xfa, 0xf3, 0xf0, 0x4c, - 0xd9, 0xb0, 0x9e, 0x8e, 0xce, 0x14, 0x93, 0x77, 0x67, 0x2d, 0xac, 0xfd, - 0x1c, 0xf8, 0x91, 0x97, 0xa5, 0x7a, 0xea, 0x33, 0xf0, 0x94, 0x1b, 0x78, - 0x63, 0x6e, 0x91, 0x61, 0x71, 0xa3, 0x86, 0x1f, 0x4f, 0xc2, 0x0e, 0xbf, - 0xd1, 0x1b, 0xdd, 0x0d, 0x1b, 0xb6, 0xcf, 0xba, 0x07, 0x8d, 0xf3, 0xfd, - 0xb0, 0xc5, 0x14, 0xec, 0x93, 0x39, 0x53, 0x9e, 0xb5, 0x0a, 0xed, 0xc9, - 0x72, 0x8d, 0xb4, 0x75, 0x4c, 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x19, 0x59, - 0xac, 0x47, 0x34, 0x8c, 0xc2, 0x1e, 0x0f, 0xe2, 0xb7, 0x1f, 0xef, 0x1c, - 0xfc, 0x58, 0x2b, 0xad, 0xc8, 0xe3, 0x2a, 0x17, 0x47, 0xae, 0x3d, 0x44, - 0xfa, 0xee, 0x04, 0x3c, 0xf5, 0x99, 0x7a, 0x7a, 0xa7, 0xb8, 0x7d, 0xf4, - 0x15, 0x49, 0xe0, 0xc6, 0x1a, 0xef, 0x22, 0x6c, 0xbd, 0x1f, 0xcf, 0xb4, - 0x55, 0x20, 0x6f, 0x15, 0x7e, 0xdf, 0x37, 0x46, 0xf9, 0x8d, 0xe2, 0x7c, - 0x38, 0x1e, 0xb4, 0xbe, 0x4c, 0xdd, 0x4b, 0xee, 0x96, 0x95, 0xf9, 0x28, - 0x0e, 0x9e, 0x86, 0x0d, 0xf2, 0xce, 0x76, 0x0c, 0x7c, 0xe1, 0x58, 0x0b, - 0xe3, 0x21, 0xe6, 0x17, 0x97, 0x71, 0xee, 0x8c, 0x9c, 0x41, 0xfd, 0x2f, - 0x7d, 0x7c, 0xa6, 0x80, 0x7f, 0x7b, 0xa8, 0xef, 0x9b, 0xd7, 0x1b, 0x36, - 0xfb, 0x63, 0xa0, 0xcf, 0x6c, 0x58, 0xcf, 0x35, 0x41, 0x7d, 0xb2, 0x26, - 0x88, 0xc7, 0x49, 0xff, 0x76, 0x3d, 0xf3, 0xa2, 0x3c, 0xa0, 0xce, 0x54, - 0x93, 0xe3, 0xf3, 0xbe, 0xef, 0x8e, 0x0e, 0x0e, 0x2f, 0x4a, 0x7a, 0xf8, - 0xa4, 0xec, 0xb3, 0x0e, 0xb1, 0x1e, 0xb3, 0x88, 0xc7, 0xbf, 0xbd, 0x25, - 0xe3, 0xfb, 0xa7, 0x41, 0xfb, 0xf7, 0xd5, 0x3e, 0x2f, 0x82, 0x7e, 0xf0, - 0x4a, 0xd5, 0x24, 0xa4, 0x15, 0xcf, 0x04, 0xe9, 0x2d, 0xcb, 0xf1, 0xfa, - 0x85, 0x50, 0x36, 0x8f, 0x89, 0xeb, 0x5d, 0x36, 0x5c, 0xbb, 0x0c, 0xd8, - 0x85, 0x90, 0xb6, 0x0c, 0xe8, 0xc5, 0xfe, 0xf5, 0xb7, 0x13, 0xf4, 0x0d, - 0x94, 0xb9, 0x8b, 0xac, 0xd1, 0x1d, 0x41, 0x1e, 0x95, 0xf8, 0x24, 0x3f, - 0x10, 0x97, 0xcd, 0x7e, 0x80, 0xeb, 0xe2, 0xd7, 0xd0, 0x15, 0xd2, 0x51, - 0x54, 0xfe, 0x53, 0xc5, 0x2d, 0x85, 0xcf, 0xd8, 0xe2, 0x0b, 0x2a, 0xea, - 0xb9, 0x6a, 0xd0, 0x37, 0x31, 0xfe, 0x51, 0x87, 0xbb, 0xe0, 0xff, 0xa0, - 0x83, 0xb0, 0xe3, 0xdc, 0x3c, 0xef, 0x27, 0x86, 0x78, 0xaf, 0x74, 0x36, - 0x0f, 0xd9, 0x2e, 0xf0, 0xfb, 0x63, 0x22, 0xa8, 0x31, 0x83, 0xfa, 0x2b, - 0x45, 0x5f, 0x88, 0xb6, 0xa4, 0xfc, 0x64, 0x5e, 0x7d, 0x6f, 0x8c, 0x03, - 0xc6, 0xa7, 0xef, 0x6c, 0xf8, 0x9b, 0x89, 0x1f, 0x64, 0x83, 0xbf, 0x99, - 0x08, 0xbf, 0xfd, 0x56, 0x83, 0x3c, 0xe2, 0xe1, 0x9a, 0x29, 0x13, 0xb5, - 0xe8, 0x6f, 0x28, 0x28, 0x07, 0xf8, 0xe6, 0x5a, 0x94, 0x3b, 0xf8, 0x41, - 0x4d, 0xb3, 0x49, 0x96, 0x4b, 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4, - 0x78, 0x31, 0xaa, 0x2f, 0x07, 0x20, 0x3f, 0xf0, 0x1c, 0x74, 0xbd, 0x3b, - 0x1b, 0xd4, 0xb9, 0x25, 0xfa, 0xc5, 0xfe, 0xa8, 0xee, 0xdd, 0x25, 0xa5, - 0x63, 0x7c, 0x1f, 0x93, 0x77, 0x66, 0x63, 0xea, 0x7d, 0x41, 0x62, 0xe1, - 0x7b, 0x8e, 0xe3, 0x52, 0x50, 0xef, 0xab, 0x21, 0x3e, 0xd4, 0x69, 0x5f, - 0x89, 0xc6, 0xa6, 0x76, 0xbc, 0x1e, 0xac, 0x9b, 0xac, 0x57, 0xe5, 0xf1, - 0xfa, 0x2a, 0xce, 0xaf, 0x49, 0x6e, 0xbc, 0x28, 0xbb, 0x6d, 0x4b, 0xc5, - 0x7d, 0x37, 0x4e, 0x1d, 0xa3, 0x7e, 0x8d, 0xa9, 0xba, 0xb3, 0x88, 0x7c, - 0xa1, 0x30, 0xc2, 0x6f, 0x3c, 0xbf, 0xba, 0xab, 0x50, 0x4e, 0x5b, 0x59, - 0xf9, 0xd0, 0x77, 0x4d, 0x8e, 0x45, 0x47, 0x3d, 0x74, 0xd7, 0xc3, 0xb5, - 0x0b, 0x77, 0x05, 0x67, 0xc5, 0xfb, 0x1a, 0x61, 0x0d, 0xf5, 0x6d, 0xf6, - 0x5f, 0x6f, 0x35, 0x65, 0xed, 0x56, 0xdf, 0xbf, 0xdf, 0xb1, 0xc4, 0x0d, - 0x6b, 0x57, 0x4b, 0xd5, 0xae, 0xed, 0x2a, 0x07, 0x71, 0x47, 0x52, 0x5a, - 0x1e, 0xf6, 0x7a, 0xc6, 0x43, 0x9d, 0xa3, 0xa7, 0x0f, 0xae, 0xea, 0x16, - 0x62, 0x6e, 0x3a, 0x35, 0x27, 0x6e, 0x2f, 0xbf, 0x37, 0xcf, 0x38, 0x84, - 0xd9, 0x19, 0xdc, 0x75, 0xdd, 0x34, 0xae, 0xfc, 0xac, 0x48, 0x18, 0x7b, - 0x6e, 0x6a, 0xb4, 0x89, 0xc6, 0xdc, 0x92, 0xb6, 0x20, 0x13, 0x26, 0x68, - 0x29, 0x95, 0xa3, 0x3c, 0x8d, 0x7f, 0x1b, 0xb0, 0x7a, 0xd7, 0xd3, 0xa0, - 0x73, 0x1a, 0x74, 0xf2, 0x1c, 0xd3, 0xb5, 0x48, 0xe7, 0xa2, 0x5a, 0x81, - 0x7d, 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0x3d, - 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0xbd, 0xf1, - 0x30, 0x4f, 0x7b, 0x62, 0x3d, 0x4f, 0x5b, 0xa9, 0xf3, 0x3b, 0x94, 0xa2, - 0xa5, 0x58, 0x94, 0x20, 0xcf, 0x15, 0x9d, 0x39, 0x4d, 0x94, 0xe7, 0x5e, - 0xfb, 0x9b, 0x48, 0xb0, 0x8e, 0x39, 0x1e, 0xd7, 0x15, 0x35, 0xdd, 0xe6, - 0xba, 0x20, 0xcf, 0x63, 0x6d, 0xb5, 0x79, 0x0d, 0xf2, 0xb5, 0x0c, 0xfd, - 0x19, 0xed, 0x22, 0x11, 0xd4, 0x8b, 0x99, 0xf3, 0xf7, 0xba, 0x88, 0xbf, - 0x85, 0x9a, 0x8a, 0xc1, 0xbc, 0x17, 0xbc, 0x97, 0x7f, 0xb7, 0x00, 0x39, - 0xf0, 0xdd, 0x7d, 0xac, 0x27, 0x0a, 0xb5, 0xa4, 0x14, 0x17, 0xa3, 0xfc, - 0x07, 0xeb, 0xbc, 0x7d, 0x5a, 0xbe, 0x42, 0xd9, 0xea, 0x32, 0x9d, 0x00, - 0x53, 0xec, 0xc6, 0xbc, 0xee, 0x4d, 0x55, 0x23, 0xad, 0xd4, 0x49, 0xcf, - 0x7e, 0xd0, 0x16, 0xdd, 0xe3, 0x8a, 0x18, 0xb3, 0x09, 0xd1, 0x67, 0x91, - 0xd3, 0xda, 0x43, 0xea, 0x6f, 0x1d, 0x7a, 0xb0, 0x8f, 0x3e, 0x3b, 0x10, - 0xfd, 0x2d, 0x06, 0xeb, 0xae, 0xec, 0xc6, 0xfd, 0x2b, 0xcf, 0x91, 0x80, - 0xbd, 0x7e, 0x69, 0x27, 0xce, 0x06, 0xb9, 0x5e, 0xde, 0xa1, 0xf2, 0x6e, - 0xf8, 0xce, 0xd3, 0x43, 0xe9, 0x3e, 0xe9, 0xda, 0x25, 0x67, 0x86, 0x58, - 0xa3, 0xb5, 0x01, 0x1f, 0x61, 0x79, 0xe7, 0xb4, 0x4b, 0x96, 0xe7, 0xe1, - 0x5b, 0xe7, 0xd3, 0x0e, 0xff, 0xbe, 0x60, 0x01, 0x21, 0x6d, 0xa1, 0x3e, - 0xd6, 0xc7, 0x98, 0xbc, 0x58, 0xa7, 0xae, 0xf4, 0x60, 0x7d, 0x3f, 0x74, - 0x71, 0x1b, 0x6c, 0x48, 0xc7, 0xfe, 0x11, 0xee, 0xf7, 0x14, 0xee, 0x1e, - 0xfb, 0xb7, 0x77, 0x2a, 0xdd, 0xd0, 0xd3, 0x56, 0x4a, 0x07, 0xed, 0x1f, - 0xab, 0x2d, 0x1d, 0xe1, 0xf7, 0xc2, 0x69, 0xaf, 0xf1, 0xbb, 0xe1, 0x3e, - 0xad, 0x50, 0xe1, 0xdf, 0x38, 0x0c, 0xc9, 0x21, 0x8b, 0x7f, 0xff, 0xb3, - 0x4f, 0x7b, 0xa0, 0x4a, 0x18, 0x1b, 0x7d, 0xd6, 0xe1, 0xcb, 0xb0, 0xe5, - 0xff, 0x29, 0xdc, 0xea, 0x62, 0xdb, 0x3a, 0xcb, 0xf0, 0xfb, 0x1d, 0xe7, - 0xc7, 0x4d, 0xdd, 0xe4, 0x34, 0x71, 0x12, 0x27, 0xca, 0xc0, 0xc7, 0x39, - 0x49, 0x3d, 0x39, 0xd5, 0x4e, 0xa2, 0x14, 0x22, 0x88, 0x84, 0xe5, 0xfc, - 0xcc, 0x63, 0x14, 0x3c, 0xc8, 0xa6, 0x4e, 0x42, 0x55, 0x94, 0x74, 0x5b, - 0x27, 0xee, 0xb8, 0x40, 0x5c, 0x80, 0x6a, 0x39, 0x69, 0xe9, 0x86, 0x3d, - 0xa7, 0x5b, 0xba, 0x00, 0x57, 0x9e, 0xe3, 0xa4, 0x4d, 0xe7, 0xcc, 0x1a, - 0x03, 0x69, 0x70, 0x41, 0x23, 0x33, 0x6d, 0xe3, 0x66, 0x37, 0x48, 0x5c, - 0x57, 0x29, 0x83, 0x02, 0x6b, 0x2b, 0xb8, 0xe1, 0xef, 0xe2, 0xf0, 0x3c, - 0xdf, 0x39, 0x76, 0xd3, 0xc0, 0x44, 0x24, 0xeb, 0x7c, 0xe7, 0x3b, 0xdf, - 0xff, 0xf7, 0xbe, 0xcf, 0xfb, 0x9b, 0x6e, 0xb9, 0x08, 0x3a, 0xce, 0x8d, - 0xb5, 0xfa, 0xfe, 0xd6, 0x0e, 0x9f, 0x87, 0x07, 0xfb, 0x7c, 0x19, 0xa5, - 0x75, 0xc9, 0x9c, 0xd6, 0xa7, 0xbb, 0x0e, 0x7d, 0x7b, 0x16, 0x6b, 0x8a, - 0xe0, 0x1c, 0x1e, 0xe9, 0xd3, 0x78, 0x64, 0xf0, 0xbd, 0xff, 0xd0, 0x7b, - 0xdf, 0xa1, 0xf7, 0xde, 0xff, 0xd1, 0x9e, 0xe5, 0xc3, 0xf4, 0xc0, 0x75, - 0x5a, 0x53, 0x1a, 0xfd, 0xf2, 0x93, 0x6a, 0x39, 0x6f, 0x25, 0xa9, 0x0b, - 0xcc, 0x88, 0xab, 0x66, 0x9c, 0x36, 0x60, 0x5c, 0x9b, 0xac, 0xae, 0x83, - 0xe6, 0xb1, 0x8f, 0x76, 0x9b, 0xf1, 0xf2, 0x89, 0x3e, 0xf2, 0x4c, 0x10, - 0xd7, 0x60, 0xd8, 0xc3, 0x11, 0xb4, 0x73, 0x5f, 0x74, 0x12, 0xe6, 0x39, - 0xed, 0xbf, 0xa1, 0x0e, 0xe3, 0xaa, 0x9c, 0xce, 0xfd, 0x60, 0x9b, 0x16, - 0xb9, 0x6d, 0xa7, 0xba, 0xfd, 0xdc, 0x20, 0xd8, 0xbb, 0xa9, 0x3e, 0xea, - 0x17, 0x2f, 0x38, 0xcd, 0x3a, 0x73, 0x5f, 0x98, 0x77, 0x05, 0xa2, 0x79, - 0x4a, 0xa4, 0x54, 0x11, 0xb9, 0x86, 0xdf, 0x6f, 0x2a, 0x7e, 0xfc, 0x42, - 0xd1, 0xd6, 0x9e, 0x96, 0x1b, 0xc5, 0x2f, 0x48, 0x15, 0x32, 0x67, 0xc7, - 0x71, 0xdd, 0x3b, 0x4e, 0x54, 0x9f, 0xf9, 0x0f, 0xf2, 0x4a, 0x62, 0xe3, - 0x94, 0x69, 0x6d, 0xf2, 0xc3, 0x75, 0xe6, 0xd5, 0x59, 0xe6, 0x1d, 0x61, - 0x7e, 0x5b, 0x44, 0xd2, 0xe1, 0x80, 0xd6, 0x4b, 0xe5, 0x69, 0x68, 0x12, - 0xf8, 0xf6, 0x87, 0xf5, 0xb3, 0x7d, 0xf4, 0xb9, 0x7c, 0xbc, 0xce, 0x77, - 0x03, 0x4f, 0x43, 0xea, 0x76, 0x00, 0xfa, 0x2b, 0x80, 0xc7, 0xe4, 0xb9, - 0x73, 0xbf, 0xcf, 0x73, 0x6d, 0xa8, 0xa3, 0x0d, 0xdb, 0x26, 0xb9, 0x11, - 0xe0, 0xa0, 0x1a, 0xd6, 0xf9, 0x47, 0xf5, 0xb0, 0xc6, 0xe5, 0x40, 0x99, - 0x7e, 0x7b, 0xf3, 0xa8, 0xc6, 0xe8, 0xd4, 0xee, 0xf7, 0xf4, 0x5e, 0x50, - 0xce, 0x96, 0x1d, 0xd2, 0xaa, 0x29, 0x3b, 0xe0, 0xb5, 0xeb, 0xb5, 0x37, - 0xfa, 0x79, 0x57, 0x37, 0x6a, 0xdf, 0xef, 0xf3, 0x6c, 0x34, 0xd6, 0x5d, - 0xe8, 0xf3, 0xea, 0xa2, 0xbe, 0xcd, 0x45, 0xdb, 0xac, 0x84, 0xbd, 0x7d, - 0x5b, 0x6a, 0x1b, 0xdf, 0x95, 0x77, 0x8b, 0xdf, 0x91, 0x5f, 0x6c, 0x9c, - 0x81, 0xce, 0x61, 0x95, 0xb2, 0x90, 0x27, 0x6f, 0xd7, 0x5c, 0xf7, 0x6d, - 0x67, 0x01, 0xf6, 0x81, 0xeb, 0xfe, 0xd6, 0xd9, 0x93, 0xd8, 0xc4, 0x37, - 0xb1, 0xe7, 0x0c, 0x78, 0x88, 0x58, 0x98, 0x06, 0xbd, 0x7d, 0xb1, 0x5f, - 0x3a, 0x42, 0x9a, 0x4e, 0x86, 0x27, 0x5a, 0xb1, 0x07, 0xc3, 0xd7, 0xc3, - 0xb9, 0x97, 0xe9, 0x7e, 0xd2, 0x8c, 0x51, 0xfb, 0x09, 0xe6, 0x6f, 0x05, - 0x5f, 0x1c, 0xc5, 0x4f, 0xc9, 0x9d, 0x71, 0xac, 0x75, 0x9c, 0xb4, 0xd7, - 0x2a, 0xb1, 0xc7, 0xb0, 0x8f, 0x4c, 0x8b, 0xdc, 0xcb, 0x6f, 0xf6, 0xd1, - 0x9f, 0x77, 0x2f, 0xcf, 0xb2, 0xf1, 0xb9, 0x4e, 0x71, 0xa5, 0x05, 0xf2, - 0x7b, 0x75, 0xd2, 0xd3, 0x95, 0x7e, 0xad, 0x4e, 0xa0, 0xbd, 0x9d, 0x7d, - 0x4f, 0x51, 0xb7, 0xcb, 0xba, 0xad, 0xd0, 0xc5, 0xe7, 0xa0, 0x03, 0xa5, - 0x6a, 0x17, 0xa4, 0x3e, 0x1e, 0x42, 0x1b, 0xea, 0x28, 0x1a, 0x4b, 0x64, - 0x26, 0xcf, 0x7c, 0x2d, 0xe6, 0x4e, 0x61, 0x8d, 0x0b, 0xc4, 0x0d, 0xae, - 0xb1, 0x8d, 0x31, 0x38, 0xbf, 0xce, 0x06, 0x8d, 0xb0, 0x8e, 0xf4, 0x9d, - 0x04, 0x4f, 0x26, 0x29, 0x37, 0x31, 0xde, 0x18, 0xc6, 0x63, 0xb9, 0x13, - 0xe3, 0x5d, 0x90, 0x94, 0xd3, 0x18, 0x73, 0x0a, 0x6d, 0x88, 0x33, 0x53, - 0xd0, 0x1f, 0x86, 0xd4, 0xec, 0x7a, 0x18, 0xf2, 0xbb, 0x4f, 0x66, 0xcd, - 0x23, 0x07, 0xf6, 0x98, 0xd5, 0xf6, 0x81, 0x61, 0x8c, 0xf9, 0x6b, 0xea, - 0x3c, 0xb0, 0x26, 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x6a, 0x7d, 0x0d, 0x38, - 0xb5, 0xf6, 0x61, 0xca, 0x39, 0x2b, 0x33, 0x61, 0xae, 0x89, 0xf5, 0x61, - 0xac, 0x99, 0x7e, 0xac, 0x67, 0x81, 0x43, 0x47, 0xfc, 0x3a, 0xb6, 0x15, - 0x23, 0x85, 0xb3, 0xf7, 0xec, 0x5a, 0xd6, 0x7d, 0x56, 0x52, 0x6b, 0x19, - 0x99, 0xd7, 0xfd, 0x78, 0x86, 0x83, 0x5a, 0xf7, 0x20, 0xaf, 0xc6, 0x7a, - 0x70, 0x96, 0x89, 0x07, 0x36, 0x70, 0xb4, 0x47, 0xcb, 0xcc, 0x7e, 0x8f, - 0x67, 0xf1, 0xad, 0x87, 0x77, 0xd4, 0x26, 0xb1, 0x6f, 0x40, 0x46, 0xe6, - 0x1b, 0xf5, 0x21, 0xf9, 0x24, 0xdf, 0xd1, 0xcf, 0x38, 0xcb, 0xdd, 0xbc, - 0x29, 0x1f, 0xe7, 0x75, 0x2c, 0x74, 0x31, 0x20, 0xd6, 0x79, 0xcf, 0x3e, - 0x1f, 0x59, 0x5c, 0x55, 0xfc, 0x3e, 0x72, 0x7e, 0x4b, 0x05, 0xd1, 0x36, - 0x84, 0x76, 0x5c, 0x87, 0x29, 0x73, 0xf9, 0xbf, 0xb9, 0x4b, 0xa3, 0xae, - 0x3b, 0xaf, 0xf3, 0xc3, 0x12, 0xe6, 0xaa, 0x6a, 0xe8, 0xe4, 0x71, 0xc9, - 0x87, 0xdb, 0x31, 0x57, 0xc2, 0xdc, 0x52, 0x23, 0x58, 0x0f, 0xcb, 0x3d, - 0xe4, 0x89, 0xc8, 0x9e, 0x70, 0x7c, 0x2b, 0xbd, 0xa9, 0x12, 0xd1, 0x61, - 0x65, 0x25, 0x73, 0xf8, 0xb5, 0x28, 0x1d, 0x47, 0x8c, 0x44, 0x15, 0x78, - 0x17, 0x7b, 0xb2, 0x4f, 0xba, 0x6e, 0xda, 0x66, 0x7d, 0xc2, 0x0c, 0x29, - 0xfa, 0x5b, 0x3a, 0x74, 0xbc, 0xf1, 0x72, 0x6f, 0xc2, 0x3c, 0xa9, 0x8e, - 0xfb, 0xef, 0x53, 0xc0, 0xcc, 0xe6, 0x78, 0x67, 0x36, 0x95, 0x29, 0x2f, - 0xe5, 0x13, 0xd1, 0x65, 0x65, 0x65, 0x30, 0x66, 0x66, 0x56, 0x11, 0x37, - 0x12, 0x66, 0x87, 0xa2, 0x4f, 0xb4, 0x5d, 0xef, 0x3b, 0x8d, 0xfe, 0x09, - 0xd5, 0xe2, 0xaf, 0x87, 0xf7, 0xf5, 0xe3, 0x7e, 0x8f, 0x67, 0x88, 0x39, - 0xa3, 0xc0, 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x64, 0x6c, 0x62, 0x54, - 0x63, 0xe8, 0xfd, 0x53, 0x7f, 0x47, 0x1d, 0xca, 0x25, 0xd6, 0xc5, 0x7d, - 0x7e, 0x1b, 0xd5, 0x3a, 0xf3, 0xfd, 0x53, 0x59, 0x9d, 0xc7, 0x58, 0x57, - 0x31, 0x7f, 0xdf, 0xcd, 0x3b, 0x8b, 0xa6, 0x9c, 0x47, 0x38, 0xce, 0x5a, - 0x60, 0xba, 0x5d, 0x98, 0x23, 0x3a, 0x57, 0x6c, 0xd0, 0x06, 0xfd, 0x01, - 0xcc, 0x17, 0x68, 0xc4, 0xbd, 0x2f, 0x88, 0x31, 0x11, 0x3c, 0x40, 0x27, - 0xd0, 0x35, 0xa1, 0xa3, 0x56, 0x30, 0x4e, 0x6e, 0x5d, 0xb2, 0x5e, 0x7f, - 0x09, 0x32, 0x27, 0x35, 0x57, 0xf9, 0xb4, 0x31, 0x38, 0x37, 0xe6, 0xc0, - 0xfb, 0xfd, 0x53, 0xa4, 0x4f, 0x9e, 0x4d, 0x54, 0xcd, 0x6d, 0x70, 0x3d, - 0x83, 0x32, 0xbf, 0x3e, 0x24, 0xcb, 0xf8, 0xad, 0xae, 0x7b, 0xf7, 0xb6, - 0x0d, 0xdd, 0x7a, 0x3e, 0x6f, 0x6a, 0x7e, 0x5d, 0x76, 0x18, 0x33, 0x01, - 0xaf, 0xe8, 0x9c, 0x2a, 0xf6, 0x65, 0x5e, 0xe1, 0x10, 0xe5, 0xa3, 0x53, - 0x87, 0x5c, 0xdd, 0xae, 0x51, 0x4f, 0x65, 0xbd, 0x35, 0x15, 0x0d, 0x74, - 0xc9, 0x2a, 0xf0, 0xae, 0x0c, 0xd9, 0x99, 0x7b, 0x25, 0x24, 0xcb, 0x79, - 0x1d, 0x4f, 0x8e, 0xfe, 0x5e, 0x39, 0x52, 0xad, 0x4d, 0xca, 0x6e, 0x2d, - 0xae, 0xbf, 0x51, 0xae, 0xe5, 0x5e, 0x37, 0xe4, 0xf9, 0x51, 0x9d, 0x57, - 0x17, 0x2f, 0x4b, 0xef, 0x00, 0x75, 0x9e, 0x2d, 0x9d, 0x63, 0x07, 0xec, - 0x80, 0xce, 0xf1, 0x33, 0xe8, 0x1c, 0xef, 0x40, 0xe7, 0xf8, 0x69, 0x11, - 0xf8, 0x52, 0x4c, 0xfb, 0xf8, 0xbf, 0x08, 0x1c, 0xa2, 0xac, 0xb6, 0xce, - 0xe0, 0x4e, 0x17, 0xb3, 0xa0, 0xc1, 0x5b, 0x92, 0x06, 0xde, 0xa6, 0xe4, - 0xfa, 0xc6, 0xbc, 0xec, 0x6c, 0x78, 0x79, 0xc8, 0x1f, 0x30, 0x07, 0x6c, - 0x9c, 0xf7, 0x14, 0x07, 0x0e, 0x1d, 0x91, 0xd8, 0x49, 0xe2, 0x47, 0x50, - 0x36, 0x0b, 0xef, 0x68, 0x1c, 0xda, 0x2c, 0xb0, 0x1c, 0x10, 0x9d, 0x4f, - 0xb6, 0xb0, 0x27, 0x65, 0xe7, 0x97, 0xa8, 0x3f, 0xa6, 0x7d, 0x40, 0x9e, - 0x4f, 0x9e, 0x78, 0xf9, 0x67, 0xff, 0xee, 0x95, 0xce, 0xb3, 0x5b, 0x32, - 0xbb, 0xd0, 0xae, 0x81, 0x5d, 0xc3, 0x5e, 0xcc, 0x5b, 0xfd, 0x05, 0x6d, - 0x30, 0x47, 0xb1, 0x4b, 0xb6, 0x21, 0x43, 0xea, 0xf1, 0x2e, 0xad, 0xfb, - 0xd5, 0xe3, 0x43, 0x3a, 0x17, 0x97, 0xe3, 0xe4, 0x0a, 0xb6, 0xac, 0x14, - 0xac, 0x68, 0x16, 0xf4, 0xb7, 0x0b, 0x5b, 0xed, 0x3a, 0xee, 0x60, 0x07, - 0x67, 0x70, 0xa3, 0x46, 0x39, 0x7f, 0x57, 0x63, 0xef, 0x66, 0xed, 0x4f, - 0x18, 0xc7, 0x3a, 0x93, 0x94, 0x3f, 0xf6, 0x13, 0x03, 0xe9, 0x8f, 0x9a, - 0xd1, 0xfd, 0xbd, 0x7e, 0xd7, 0xd1, 0x76, 0xa7, 0x46, 0x3c, 0x16, 0xb9, - 0x94, 0xb7, 0x21, 0x4b, 0x5e, 0x8f, 0x50, 0x07, 0x28, 0xa9, 0x46, 0x3f, - 0xd7, 0x5f, 0xb3, 0xeb, 0x1e, 0xb5, 0xb9, 0xae, 0xb8, 0x8f, 0xdb, 0x94, - 0xfd, 0x7b, 0x5a, 0xee, 0xe7, 0x8b, 0x67, 0xe5, 0x2d, 0xdc, 0xb7, 0xa7, - 0xe3, 0x64, 0xe4, 0x4d, 0xe8, 0x78, 0xb5, 0x62, 0x23, 0x6f, 0x7b, 0x1a, - 0xe7, 0x64, 0xa9, 0x95, 0x2b, 0x2f, 0xcb, 0xe5, 0xab, 0xfb, 0xea, 0xa5, - 0xab, 0x31, 0xf5, 0xf2, 0x95, 0x61, 0x95, 0xbb, 0xe2, 0xba, 0xff, 0x74, - 0x96, 0xe4, 0xdd, 0x0d, 0x57, 0x4e, 0x3b, 0xc6, 0x40, 0x40, 0x1a, 0xb9, - 0x75, 0xae, 0x1b, 0x04, 0x36, 0xdf, 0xe8, 0x75, 0xdd, 0x47, 0xc7, 0xc7, - 0x25, 0xde, 0x4b, 0x1d, 0xe5, 0xf3, 0x11, 0xe6, 0xbb, 0x12, 0x73, 0x52, - 0xb6, 0x7d, 0xbe, 0xac, 0x14, 0xf0, 0xad, 0xcb, 0xd3, 0x5f, 0x1e, 0x3b, - 0xe6, 0xc7, 0x4a, 0x7e, 0xf4, 0x22, 0x7d, 0xc9, 0x91, 0xff, 0xf2, 0x25, - 0x9b, 0x72, 0xae, 0xf0, 0x19, 0xf4, 0x0f, 0xcb, 0xb7, 0x0a, 0xa1, 0x43, - 0x65, 0x13, 0xcf, 0x31, 0x95, 0x2b, 0xdc, 0x73, 0x87, 0x75, 0xcc, 0x00, - 0x3a, 0x89, 0xe9, 0xba, 0xcb, 0x0e, 0xe7, 0xeb, 0xc2, 0x7c, 0x7b, 0xe6, - 0x31, 0xc8, 0xff, 0xd3, 0x5a, 0x3e, 0x9f, 0x53, 0xb0, 0x7d, 0xc1, 0xdf, - 0x61, 0x99, 0x2d, 0x40, 0xc6, 0x2b, 0xe6, 0x9c, 0x52, 0x57, 0xb0, 0x22, - 0xcb, 0xc0, 0x8e, 0x25, 0xe0, 0xcd, 0x93, 0x3a, 0xb6, 0xda, 0xa3, 0xb1, - 0x67, 0x85, 0xe5, 0x8c, 0x24, 0xcb, 0x4e, 0xb7, 0x3e, 0xbf, 0xfd, 0xdd, - 0x57, 0x23, 0xde, 0x9d, 0x83, 0x8f, 0x33, 0x4a, 0xda, 0x60, 0x03, 0xcd, - 0x6c, 0x2d, 0x80, 0x27, 0x22, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x75, 0xc8, - 0xef, 0xba, 0xf6, 0x23, 0x7a, 0xf1, 0x8a, 0xba, 0xc9, 0x76, 0xcf, 0xa0, - 0x5f, 0xbb, 0xa4, 0xae, 0xb4, 0x69, 0x5c, 0x7d, 0xb8, 0x2e, 0x09, 0x3d, - 0xe4, 0x69, 0x94, 0x03, 0xa8, 0x8b, 0xfa, 0x65, 0x03, 0xe5, 0x45, 0x94, - 0x5b, 0xf0, 0x64, 0x9b, 0x11, 0xe8, 0x15, 0x78, 0xbe, 0x81, 0xf1, 0xc6, - 0xb1, 0xe6, 0x8c, 0x29, 0x1f, 0x9d, 0xa2, 0x2c, 0x19, 0x53, 0xcc, 0x4b, - 0x5e, 0xb6, 0xf1, 0xac, 0x0e, 0xab, 0x99, 0x35, 0x96, 0xf1, 0x2c, 0x79, - 0xdf, 0x1f, 0xc2, 0x24, 0xf4, 0x49, 0x5d, 0xf5, 0x30, 0xe9, 0xa3, 0x26, - 0x26, 0xb1, 0xae, 0x5d, 0x66, 0xaf, 0x90, 0xd7, 0x4d, 0xd0, 0x5b, 0x87, - 0xcc, 0x5c, 0x0d, 0x6b, 0x7d, 0xb4, 0x0c, 0x5a, 0xdc, 0x06, 0x5d, 0x6d, - 0x82, 0xa6, 0x52, 0x05, 0x6b, 0x6a, 0x51, 0x45, 0xb5, 0x2f, 0xe0, 0x09, - 0xd0, 0x6b, 0xf0, 0x15, 0xea, 0xa2, 0xe4, 0xe5, 0x38, 0x68, 0x4f, 0xdc, - 0xa0, 0x6d, 0xa7, 0xe3, 0xca, 0x06, 0x0d, 0x82, 0x2e, 0x0b, 0x1e, 0x4f, - 0xbf, 0xa7, 0x34, 0xae, 0x4e, 0xdd, 0x96, 0x44, 0xf2, 0xb6, 0x58, 0xc0, - 0x02, 0xcb, 0xf9, 0x50, 0x1c, 0x8c, 0x39, 0x29, 0xd7, 0x30, 0x8f, 0x01, - 0xfe, 0x1e, 0x3d, 0xa1, 0xf9, 0x7b, 0x4a, 0x02, 0x87, 0x79, 0x1c, 0xf4, - 0x06, 0x0c, 0xf2, 0x78, 0x3a, 0xe9, 0xd3, 0xe8, 0xd7, 0xc1, 0xbf, 0x16, - 0x2c, 0xb1, 0xb0, 0xac, 0x82, 0xff, 0xb7, 0xf1, 0xfd, 0x66, 0x6d, 0x44, - 0xad, 0xac, 0x29, 0x3f, 0x97, 0xe4, 0x19, 0xe8, 0xc9, 0xb7, 0x70, 0x76, - 0x9d, 0x5a, 0x77, 0x8f, 0x8d, 0x33, 0x7e, 0x96, 0x56, 0x97, 0xed, 0x93, - 0xb2, 0x3f, 0x36, 0x89, 0xf2, 0x31, 0x3c, 0x0d, 0x9c, 0x43, 0x48, 0xc7, - 0xbf, 0x37, 0xf3, 0x8e, 0xf2, 0xfe, 0x67, 0x61, 0x42, 0xe7, 0xe7, 0x1b, - 0x76, 0x2f, 0xbe, 0xd3, 0x17, 0xc3, 0xbd, 0x41, 0x67, 0x52, 0x11, 0x9d, - 0x6f, 0x5a, 0x86, 0x2e, 0xb1, 0x85, 0xf1, 0xde, 0xa7, 0x2f, 0xaf, 0x0a, - 0x1e, 0x1e, 0xfb, 0x97, 0x9b, 0x0c, 0x33, 0x47, 0xfd, 0x6e, 0xc4, 0x93, - 0x7f, 0x9f, 0xb8, 0xfb, 0xf6, 0xca, 0x94, 0x81, 0x97, 0x5b, 0x66, 0x18, - 0x6d, 0x21, 0xcb, 0x20, 0x8b, 0x4a, 0x9a, 0x7e, 0xd9, 0xce, 0xeb, 0x9b, - 0xab, 0x26, 0xcc, 0x0f, 0xc4, 0xeb, 0xbb, 0x6a, 0x53, 0xee, 0xb4, 0x03, - 0x5f, 0xa2, 0x5a, 0xaf, 0x7c, 0xdf, 0xce, 0x02, 0x15, 0xac, 0x68, 0x1a, - 0x34, 0xda, 0x26, 0x56, 0x7c, 0x4e, 0x1e, 0xcc, 0xbb, 0xac, 0xfb, 0xb2, - 0x6d, 0xa3, 0x6f, 0x63, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b, - 0x36, 0x35, 0x8d, 0xd6, 0xab, 0xdd, 0x03, 0x1e, 0x8d, 0x36, 0xf6, 0x11, - 0xfe, 0x3f, 0xfb, 0x20, 0x9d, 0x38, 0xca, 0xcb, 0xbb, 0xc0, 0xb3, 0xca, - 0xf3, 0x1c, 0x01, 0x6d, 0x1c, 0xa4, 0x9f, 0x86, 0x6f, 0xd1, 0xa3, 0x9f, - 0x47, 0x9b, 0xf4, 0x43, 0xba, 0xe9, 0x90, 0xd9, 0xab, 0xb6, 0xcc, 0x17, - 0xf4, 0x7d, 0x43, 0xd7, 0xa4, 0xcf, 0x68, 0x12, 0x74, 0x43, 0x5a, 0x27, - 0x6f, 0x99, 0x52, 0x02, 0x1d, 0x95, 0x80, 0x4f, 0x25, 0xd0, 0x54, 0x19, - 0xf8, 0x56, 0x02, 0xbe, 0x95, 0x6a, 0x56, 0xbc, 0x82, 0x3d, 0x53, 0x66, - 0x6f, 0x81, 0x8e, 0xb6, 0x6b, 0xbc, 0x7f, 0xbd, 0x66, 0x93, 0x72, 0xf0, - 0x66, 0xf3, 0xee, 0xff, 0x81, 0xbb, 0x1f, 0x92, 0x5d, 0xd8, 0x2d, 0x6f, - 0x15, 0xc7, 0x80, 0x49, 0x02, 0x8c, 0x72, 0x40, 0x1b, 0x53, 0x72, 0xbd, - 0x38, 0x2d, 0x3b, 0x90, 0x4f, 0x37, 0x36, 0x62, 0xd0, 0xa7, 0x23, 0xb2, - 0xf2, 0xda, 0xa8, 0xbc, 0xb9, 0xa1, 0x64, 0x09, 0xf4, 0x9b, 0xdb, 0xa4, - 0xdf, 0x1d, 0xf4, 0x5c, 0xea, 0xd0, 0x71, 0xfa, 0xd9, 0x8a, 0xe7, 0x7f, - 0x9f, 0xab, 0x74, 0xca, 0x7c, 0xc5, 0x94, 0xc7, 0x2b, 0xdd, 0xf2, 0xe5, - 0x4a, 0x58, 0x4e, 0xc3, 0x0e, 0xfc, 0x4a, 0x65, 0x50, 0x9e, 0xac, 0x0c, - 0xc9, 0x57, 0xab, 0x51, 0xf9, 0x5a, 0xd5, 0x96, 0x4c, 0x35, 0x2e, 0xe9, - 0xea, 0x98, 0x3c, 0x51, 0xa5, 0x5f, 0x1d, 0xf3, 0xe1, 0x37, 0xd3, 0xf4, - 0x57, 0x70, 0x5d, 0x41, 0xac, 0x2b, 0xae, 0xe6, 0x74, 0x9c, 0x52, 0x32, - 0x9e, 0xcf, 0x43, 0xe4, 0x39, 0x8c, 0x75, 0xf1, 0x35, 0x25, 0x65, 0x3d, - 0x7f, 0xe3, 0xff, 0x46, 0x42, 0xda, 0x36, 0x7a, 0xae, 0x34, 0x88, 0x36, - 0x90, 0x7b, 0xf9, 0x86, 0xef, 0xa3, 0xe1, 0xf3, 0x6f, 0xd8, 0x5e, 0x86, - 0xf6, 0x5b, 0xdf, 0xa4, 0xed, 0xa5, 0xcf, 0x9e, 0xf8, 0x41, 0x3b, 0xe7, - 0x9a, 0xf6, 0x9b, 0x3c, 0x88, 0x6d, 0x34, 0xe6, 0xbd, 0x98, 0x79, 0xf8, - 0xff, 0x53, 0xbc, 0x18, 0xd5, 0xb9, 0xea, 0x20, 0xff, 0x4f, 0x05, 0x6b, - 0xf9, 0xf4, 0xdc, 0xf1, 0xf9, 0xe2, 0xac, 0x7a, 0xbc, 0x48, 0x8d, 0xc6, - 0x95, 0x8b, 0xcd, 0x9c, 0xb8, 0x2f, 0xc9, 0xa6, 0x13, 0xd2, 0x6b, 0xf0, - 0xf3, 0x1f, 0x75, 0x7e, 0xdc, 0xec, 0x09, 0xd2, 0x1f, 0x63, 0x6f, 0x9d, - 0x7e, 0x3c, 0x01, 0xba, 0xad, 0x63, 0xca, 0xa5, 0x8a, 0xe7, 0xb3, 0x5a, - 0xd1, 0xf4, 0xf2, 0x2b, 0xd0, 0x1c, 0x63, 0x0e, 0xde, 0x33, 0x5b, 0xf2, - 0xfa, 0xce, 0xe0, 0xde, 0x60, 0x8f, 0x63, 0xbf, 0x46, 0x37, 0xe7, 0xe2, - 0xff, 0xe9, 0xa0, 0xec, 0xaf, 0x97, 0xb9, 0xc6, 0xb6, 0xa6, 0x45, 0x2f, - 0xae, 0x1b, 0x97, 0x17, 0x70, 0x7e, 0x65, 0x93, 0xeb, 0x0f, 0x4a, 0x39, - 0x4e, 0xdb, 0x96, 0xf8, 0x7d, 0x42, 0x4a, 0x98, 0xa7, 0x1c, 0x6f, 0xf8, - 0xc3, 0x3c, 0x9c, 0x2d, 0x9b, 0x0f, 0xe6, 0x5d, 0x2c, 0x1d, 0xc7, 0x3b, - 0xea, 0xe2, 0xd0, 0x99, 0x16, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0x56, - 0xf0, 0x8c, 0xf8, 0x75, 0xd5, 0x01, 0xad, 0xab, 0x4f, 0x3f, 0xe8, 0xb7, - 0x54, 0xb2, 0xb2, 0xa9, 0x40, 0x42, 0x19, 0xaf, 0xfe, 0x7c, 0x80, 0x98, - 0x7b, 0xdc, 0xe6, 0x2f, 0x24, 0x7f, 0x35, 0xb5, 0x4f, 0xc1, 0xff, 0x76, - 0x44, 0x9e, 0x32, 0x99, 0xc7, 0x9e, 0x54, 0xb3, 0xc5, 0x9c, 0x9f, 0xe3, - 0x9b, 0x50, 0xc7, 0xcb, 0x37, 0x07, 0xbc, 0x9c, 0x77, 0x8e, 0x7d, 0x30, - 0xcf, 0xfd, 0x20, 0x9d, 0x30, 0xdf, 0xbd, 0xbd, 0xf9, 0x3f, 0x52, 0xe5, - 0x3c, 0xf0, 0xce, 0x6e, 0xd1, 0xfc, 0x98, 0xab, 0xfe, 0xdb, 0xdd, 0xd3, - 0xfc, 0xdc, 0xf0, 0x31, 0xfc, 0x6e, 0x80, 0xb6, 0x2d, 0x71, 0xe3, 0x92, - 0x97, 0x3b, 0xaa, 0x6d, 0x68, 0x60, 0x05, 0xea, 0xc8, 0xab, 0xe0, 0x93, - 0x66, 0x5b, 0xfe, 0xfd, 0x07, 0x69, 0x3f, 0x51, 0x42, 0x6c, 0x67, 0x00, - 0x00, 0x00 }; - -static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = { - 0x08004050, 0x08003f50, 0x08003ff4, 0x0800400c, 0x08004024, 0x08004044, - 0x08004050, 0x08004050, 0x08003f58, 0x00000000, 0x08004a0c, 0x08004a44, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004a7c, 0x08004c40, - 0x08004b88, 0x08004bc0, 0x08004c40, 0x08004b10, 0x08004c40, 0x08004c40, - 0x08004bc0, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c00, - 0x08004c40, 0x08004c00, 0x08004b88, 0x08004c40, 0x08004c40, 0x08004c00, - 0x08004c00, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, - 0x08004aec, 0x00000000, 0x08006058, 0x08006070, 0x08006070, 0x08006070, - 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070, - 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070, - 0x08006064, 0x00000000, 0x00000000 }; -static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 }; + 0x1f, 0x8b, 0x08, 0x08, 0x19, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6b, 0x6c, + 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x20, 0xb5, 0xa2, 0xf8, 0x18, 0x2e, 0x57, + 0xcc, 0x4a, 0x66, 0xec, 0x5d, 0x71, 0x24, 0xb2, 0x16, 0x6b, 0x8c, 0xd8, + 0xad, 0x4d, 0x04, 0x6b, 0x7b, 0x33, 0xbb, 0x92, 0x98, 0x54, 0x85, 0x29, + 0x87, 0x75, 0x0c, 0xc3, 0x75, 0xd9, 0xa5, 0x1a, 0xbb, 0xae, 0x51, 0xc8, + 0x8f, 0xc4, 0x06, 0x6a, 0xd6, 0x9b, 0x25, 0xdd, 0xa8, 0xe9, 0x82, 0x43, + 0x4b, 0xaa, 0xe9, 0x02, 0x69, 0xbb, 0x20, 0xa9, 0xc7, 0x8f, 0x85, 0x56, + 0x76, 0x52, 0xc7, 0xf9, 0xe1, 0x48, 0x50, 0x95, 0x20, 0x28, 0x0c, 0x43, + 0x48, 0x8d, 0xd6, 0x3f, 0xda, 0x40, 0x95, 0x9f, 0x68, 0x92, 0x42, 0x41, + 0x0b, 0xc7, 0x68, 0x6c, 0x4f, 0xbf, 0xef, 0xce, 0x0c, 0xb9, 0xa4, 0x5f, + 0x40, 0x7f, 0xf4, 0x4f, 0xe7, 0x02, 0x8b, 0xb9, 0xf7, 0xce, 0x3d, 0xe7, + 0x9e, 0x7b, 0xde, 0xe7, 0x0e, 0xa5, 0xdf, 0xef, 0x94, 0x0e, 0x09, 0x5b, + 0x17, 0x7e, 0x99, 0xc3, 0x8f, 0x3d, 0x74, 0xc3, 0xd8, 0x0d, 0xa3, 0x22, + 0x7b, 0xf6, 0x18, 0x5b, 0x12, 0x7a, 0x34, 0x1f, 0xb7, 0xb8, 0xc5, 0x2d, + 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, + 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, + 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, + 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, + 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, + 0xe2, 0xf6, 0xff, 0xbd, 0x19, 0x22, 0x16, 0x9f, 0x5d, 0xe1, 0x4f, 0x12, + 0x7a, 0xfe, 0xf2, 0x1f, 0xba, 0xb6, 0x24, 0x8c, 0xfc, 0xcf, 0x66, 0xa6, + 0x6d, 0x91, 0x42, 0x63, 0x77, 0xa6, 0x28, 0xef, 0xfb, 0x95, 0x94, 0x29, + 0x9c, 0xff, 0x6c, 0xfe, 0xbd, 0xbf, 0x7d, 0xf1, 0xa6, 0xec, 0xd5, 0xba, + 0x21, 0x09, 0x2b, 0x3f, 0xb7, 0xc7, 0xda, 0x25, 0x89, 0x01, 0xc0, 0x7c, + 0x6b, 0xe8, 0xc7, 0xdd, 0xd2, 0x2d, 0x6b, 0x78, 0xec, 0x84, 0x5c, 0x36, + 0x5e, 0xd0, 0xdc, 0xa6, 0xef, 0x9f, 0x70, 0x7c, 0xff, 0x87, 0xf8, 0xbd, + 0xe5, 0x60, 0xec, 0x7d, 0xe0, 0x17, 0x4c, 0x43, 0x74, 0xfb, 0x2f, 0x34, + 0x77, 0xb9, 0x43, 0xaa, 0x8b, 0xa6, 0xcc, 0x7a, 0x29, 0x39, 0xe2, 0x55, + 0xb4, 0x52, 0xb3, 0xa6, 0xed, 0x3d, 0x35, 0xaf, 0xed, 0x3b, 0x75, 0x44, + 0xdb, 0x7f, 0x6a, 0x41, 0x73, 0x4f, 0x49, 0x45, 0xdf, 0xd3, 0x29, 0x05, + 0xeb, 0xb4, 0x56, 0x6c, 0xf6, 0x6b, 0xee, 0xe2, 0x7b, 0xbe, 0xeb, 0x64, + 0xad, 0xbb, 0xc4, 0x2c, 0x80, 0x16, 0x71, 0x6b, 0x3e, 0xc6, 0xa6, 0x14, + 0x52, 0xbe, 0xaf, 0xe7, 0xfd, 0x27, 0xdc, 0x9c, 0x6d, 0xe9, 0x5a, 0x4a, + 0xaa, 0xcd, 0x7e, 0xe0, 0xed, 0xd4, 0x8a, 0x8b, 0xa6, 0x56, 0xf2, 0xfc, + 0x73, 0xae, 0x23, 0x03, 0x86, 0xf8, 0xfe, 0x9c, 0xb3, 0x33, 0x7d, 0x48, + 0x4e, 0x02, 0x6f, 0x03, 0xf8, 0xc4, 0xd2, 0xf3, 0xa4, 0x8f, 0x74, 0x92, + 0xe4, 0x8a, 0x56, 0x1c, 0x8a, 0xe8, 0x93, 0x0c, 0xe9, 0x2f, 0xaf, 0xe8, + 0xa0, 0x73, 0x8b, 0x94, 0xeb, 0x96, 0x4c, 0xad, 0x6c, 0x5c, 0x7f, 0xd9, + 0x7f, 0x71, 0x28, 0x25, 0xcf, 0x36, 0xb3, 0x47, 0x2a, 0x92, 0x90, 0x39, + 0x2f, 0x23, 0x7a, 0x5e, 0x0a, 0x6e, 0x6e, 0x40, 0xce, 0x35, 0xd3, 0xf2, + 0x5c, 0xd3, 0x4e, 0x57, 0x65, 0x93, 0x94, 0x53, 0x96, 0x9c, 0x6d, 0xa6, + 0x70, 0x46, 0xff, 0x9c, 0x6e, 0xdb, 0x56, 0x15, 0x6b, 0xab, 0xcd, 0x97, + 0xf8, 0xef, 0x5f, 0xac, 0xe9, 0x9c, 0x82, 0xa9, 0x80, 0xee, 0x70, 0x2d, + 0xcf, 0xa1, 0xd6, 0xaa, 0xb3, 0x04, 0x6b, 0xa5, 0x32, 0x9d, 0xc3, 0x5c, + 0x73, 0x34, 0xe4, 0xef, 0x16, 0x9c, 0x97, 0x4f, 0x4b, 0xaa, 0x9e, 0x01, + 0xde, 0xb0, 0xff, 0xcf, 0xc0, 0x37, 0x80, 0xf3, 0x5e, 0xab, 0x7e, 0xee, + 0xa2, 0xa4, 0x74, 0xd9, 0x99, 0x2e, 0x0b, 0x78, 0xdb, 0xec, 0xc4, 0x98, + 0xf4, 0xf9, 0xfe, 0x7e, 0x47, 0xac, 0xaa, 0xd3, 0x03, 0x98, 0x8c, 0x54, + 0x9d, 0x6e, 0xe0, 0x69, 0x13, 0xcb, 0xe6, 0xb9, 0xb8, 0xd7, 0x66, 0xcc, + 0xfb, 0x5d, 0x46, 0xde, 0xf7, 0xa7, 0x73, 0xd2, 0x1d, 0xcc, 0xed, 0x56, + 0x38, 0xa6, 0x26, 0x34, 0xac, 0xfb, 0x05, 0x69, 0x4e, 0x24, 0xf3, 0xec, + 0xf3, 0x99, 0x13, 0x77, 0xfe, 0xda, 0x90, 0x96, 0x34, 0x68, 0xb9, 0x26, + 0xec, 0x83, 0xff, 0x1e, 0xf8, 0xe0, 0x7c, 0x06, 0x63, 0xed, 0x3a, 0xe0, + 0x19, 0xae, 0x0a, 0xf7, 0xe8, 0x93, 0xa5, 0x94, 0xe8, 0x57, 0x9c, 0xde, + 0x70, 0x5d, 0x37, 0x68, 0x8d, 0xf4, 0xa0, 0x5f, 0xe6, 0x16, 0xc9, 0xeb, + 0x1a, 0x64, 0x83, 0xe7, 0x8d, 0x15, 0xad, 0xd0, 0x3c, 0x82, 0xbe, 0x29, + 0xd3, 0xb6, 0x7f, 0x6e, 0xce, 0x99, 0xd7, 0x8a, 0xa7, 0x4e, 0x6a, 0xa5, + 0x53, 0x2f, 0x68, 0x7b, 0x9b, 0x2f, 0x74, 0x49, 0x47, 0x16, 0xa7, 0x4e, + 0xc8, 0x93, 0x9e, 0x26, 0xa4, 0x73, 0x09, 0xbc, 0x2b, 0x58, 0x15, 0x31, + 0xed, 0x6e, 0x6d, 0x1f, 0xf0, 0xb4, 0xd9, 0x7f, 0xd2, 0x29, 0xdd, 0x86, + 0x6c, 0xb2, 0xa3, 0xb5, 0x29, 0xf9, 0x33, 0xd0, 0x74, 0xc1, 0x49, 0x91, + 0x5f, 0x3d, 0x01, 0x4c, 0x44, 0x07, 0xf5, 0x8a, 0x3a, 0xa5, 0x17, 0x4a, + 0xc7, 0xff, 0xbc, 0xaf, 0x3a, 0xb2, 0x85, 0x6b, 0xa0, 0xff, 0xd6, 0xfd, + 0xd3, 0xb6, 0xdb, 0x6b, 0x4a, 0xc5, 0xd2, 0x25, 0x6b, 0x15, 0xe5, 0x3a, + 0x99, 0x73, 0x44, 0x8a, 0x35, 0xec, 0x69, 0x9b, 0xe0, 0x8d, 0x0d, 0xde, + 0xec, 0x3c, 0x32, 0xa8, 0xff, 0x96, 0x64, 0xfa, 0x2b, 0x9a, 0x19, 0xf2, + 0x71, 0x49, 0x6e, 0x51, 0xf0, 0x7a, 0xde, 0x81, 0x7e, 0x76, 0xb0, 0x8f, + 0x7d, 0x13, 0x6a, 0x5f, 0x23, 0x6f, 0xa7, 0x97, 0x45, 0x34, 0x3d, 0xbf, + 0x1b, 0xf8, 0xa8, 0xb7, 0x5c, 0xf7, 0x04, 0x68, 0x24, 0xed, 0xec, 0xdb, + 0x80, 0x49, 0x88, 0xeb, 0x74, 0xb5, 0xd0, 0x49, 0x79, 0x93, 0xd7, 0xe4, + 0x9d, 0x3a, 0xa7, 0xb6, 0x76, 0xce, 0x5f, 0xf9, 0x9b, 0x46, 0x4d, 0xf9, + 0xa1, 0x3a, 0x2f, 0x6d, 0x8c, 0xeb, 0x52, 0xa1, 0x4e, 0x24, 0xa0, 0x47, + 0xa2, 0x95, 0x1d, 0x6b, 0x15, 0x57, 0x59, 0x44, 0x37, 0xf2, 0x9d, 0x52, + 0x54, 0xf4, 0x8d, 0x61, 0x2f, 0xda, 0x1e, 0x6c, 0xc8, 0xe6, 0x59, 0x38, + 0x97, 0x87, 0x8d, 0x67, 0xd9, 0x97, 0xf2, 0x02, 0xed, 0x9d, 0xb4, 0x9d, + 0xcf, 0xaa, 0x7f, 0x8e, 0x45, 0x5d, 0x3c, 0xd6, 0x03, 0xda, 0x38, 0x86, + 0x1d, 0xda, 0x78, 0x3f, 0xa2, 0x89, 0x3b, 0x36, 0x08, 0xfe, 0x70, 0x9d, + 0x9d, 0x81, 0x9c, 0x0b, 0x2e, 0xf6, 0x74, 0x9d, 0xdf, 0x50, 0x3c, 0xe8, + 0xc5, 0x79, 0x06, 0xe7, 0xc9, 0xaf, 0x0e, 0xe8, 0xb6, 0x26, 0x65, 0x27, + 0x9b, 0xa1, 0xdc, 0x03, 0xda, 0x75, 0xd9, 0x74, 0x63, 0x2b, 0xed, 0x91, + 0xac, 0xa8, 0x87, 0xa6, 0x24, 0x47, 0xb9, 0x96, 0xeb, 0xb8, 0x3e, 0x3b, + 0x26, 0xfa, 0xaf, 0x7c, 0x6b, 0xdd, 0x59, 0x6d, 0xd9, 0x31, 0x0f, 0x1a, + 0x02, 0xde, 0x82, 0x27, 0x9f, 0xb6, 0x96, 0x7c, 0xdd, 0xc8, 0x3f, 0xae, + 0x6d, 0x5d, 0x07, 0x9d, 0xe8, 0x27, 0x0d, 0x27, 0x3a, 0x03, 0x5b, 0x8b, + 0x68, 0x8a, 0x64, 0xa3, 0x85, 0x38, 0x3e, 0xe9, 0x1c, 0x5c, 0x0f, 0x1f, + 0xe0, 0xc1, 0x07, 0xc0, 0xaf, 0x3d, 0xeb, 0xc1, 0xfe, 0x3d, 0xfa, 0x8c, + 0x8c, 0xbc, 0x38, 0x04, 0x1f, 0xb7, 0xe6, 0x63, 0xd0, 0xc6, 0xd1, 0xd7, + 0xc5, 0x80, 0x8f, 0x99, 0xad, 0xeb, 0xb0, 0x59, 0xf0, 0x78, 0x85, 0x73, + 0xb0, 0xed, 0x95, 0x12, 0x9e, 0xb6, 0x54, 0x1b, 0xd4, 0xab, 0xc8, 0x97, + 0xd2, 0xe7, 0xa4, 0xe1, 0x5f, 0xe8, 0x77, 0xe8, 0x57, 0xb8, 0xd6, 0xf7, + 0x4b, 0x0e, 0x61, 0x7d, 0x99, 0x70, 0x68, 0x43, 0x9d, 0xa2, 0x27, 0x2b, + 0xda, 0xc1, 0x21, 0xd8, 0xd6, 0xf5, 0x6d, 0xa0, 0x95, 0x36, 0x76, 0x8d, + 0x48, 0x3b, 0xf7, 0xfb, 0x69, 0x57, 0xf0, 0xef, 0xee, 0x36, 0x61, 0x0d, + 0x9f, 0xef, 0x86, 0x63, 0x2d, 0xf4, 0x2d, 0x7c, 0x9f, 0xcd, 0x14, 0xa4, + 0x3f, 0x1c, 0xb3, 0xbf, 0x4a, 0xaf, 0xa3, 0xdf, 0x98, 0x90, 0x1d, 0x27, + 0x03, 0x9f, 0xb8, 0x63, 0xc9, 0x12, 0xfb, 0x64, 0x40, 0xe3, 0x8e, 0x33, + 0x91, 0x6f, 0x7c, 0x1f, 0xf0, 0xa0, 0xcf, 0x5b, 0x8d, 0x03, 0x68, 0x3f, + 0xd3, 0x60, 0x2a, 0x98, 0xdb, 0xc8, 0x0b, 0xfa, 0x63, 0xda, 0x9b, 0xd5, + 0x6a, 0x6f, 0x7b, 0x60, 0x6f, 0x4e, 0xbb, 0x64, 0x9d, 0xbf, 0x87, 0xbd, + 0x7d, 0xc3, 0xd1, 0xc0, 0x1b, 0x91, 0x8b, 0xb5, 0x34, 0x6c, 0xdd, 0x4c, + 0xbf, 0x26, 0x3b, 0x33, 0xb3, 0xa2, 0xc9, 0x09, 0xce, 0x35, 0x30, 0xa7, + 0x7c, 0x71, 0xe0, 0x0b, 0x2e, 0x1b, 0x4f, 0x81, 0x2e, 0xdf, 0x9f, 0x05, + 0xce, 0xf2, 0x88, 0x11, 0xda, 0x56, 0x34, 0x6f, 0xdd, 0xef, 0xda, 0xee, + 0xaf, 0x19, 0x52, 0x19, 0x6e, 0x93, 0xec, 0xf0, 0x12, 0x70, 0x4f, 0x3b, + 0x81, 0x1d, 0x53, 0xd7, 0x97, 0x81, 0x7f, 0xce, 0x1b, 0x82, 0x1e, 0xd3, + 0x0e, 0x40, 0x17, 0xf0, 0x2f, 0x03, 0xff, 0x5c, 0xb3, 0x4d, 0xbe, 0x6e, + 0x46, 0xb1, 0x32, 0x3a, 0x4f, 0x37, 0x96, 0x45, 0xfb, 0x1e, 0x96, 0x2f, + 0x7a, 0x49, 0xcd, 0x3d, 0x46, 0xff, 0x5a, 0x1d, 0x86, 0x9d, 0x68, 0x55, + 0x87, 0x7b, 0x1b, 0xb2, 0xbc, 0xba, 0x46, 0x0a, 0xd5, 0xc0, 0x06, 0x0b, + 0xee, 0x50, 0x25, 0x6d, 0x28, 0x5f, 0x22, 0xb2, 0x0f, 0xb6, 0xb7, 0x6c, + 0x73, 0xcc, 0xf9, 0x60, 0x6e, 0xbc, 0xd6, 0x0f, 0x9f, 0xc8, 0xf1, 0x7b, + 0xfe, 0xb4, 0x13, 0xcc, 0x7d, 0xa1, 0x76, 0x57, 0x37, 0xfd, 0x2e, 0xe2, + 0x44, 0xa6, 0xea, 0xfc, 0xbb, 0x0f, 0xfd, 0x5d, 0x07, 0xf3, 0xd1, 0x78, + 0xb2, 0xe3, 0x81, 0xce, 0x8a, 0xb6, 0xdf, 0xd6, 0xfb, 0xdb, 0x43, 0x1f, + 0xb6, 0x1f, 0x93, 0x7b, 0x6b, 0xd5, 0xbe, 0x76, 0x79, 0xcf, 0x60, 0x1c, + 0xbd, 0x22, 0x62, 0xba, 0xb5, 0x5d, 0xe0, 0x47, 0xb5, 0xb7, 0x65, 0x2e, + 0x51, 0xaa, 0xf9, 0x72, 0xc1, 0x09, 0x60, 0x30, 0xee, 0x2c, 0xd6, 0xf4, + 0xfe, 0x84, 0xac, 0x8e, 0x2d, 0xc2, 0xac, 0xc8, 0xae, 0xe1, 0x65, 0x51, + 0xb0, 0x7d, 0x89, 0x35, 0xd8, 0x54, 0xa9, 0x56, 0xed, 0x6d, 0x19, 0xa7, + 0x8b, 0xc0, 0xa5, 0xef, 0x59, 0x85, 0x1d, 0x58, 0x83, 0xdd, 0x2a, 0x99, + 0x5e, 0xc2, 0xeb, 0xfd, 0x9b, 0xd7, 0x70, 0x67, 0x42, 0x7a, 0xfa, 0x36, + 0xaf, 0xe1, 0xb0, 0x89, 0xb3, 0x65, 0x3c, 0x4c, 0x9c, 0x3b, 0xd6, 0x70, + 0x8e, 0xac, 0xa7, 0xe7, 0xb0, 0xc0, 0x07, 0x25, 0xda, 0xf3, 0xb2, 0xe7, + 0x62, 0x6d, 0x70, 0xe2, 0x8b, 0x82, 0x58, 0x37, 0xb2, 0x29, 0xf4, 0xc9, + 0xe6, 0x1e, 0x17, 0xbc, 0x32, 0x85, 0x3e, 0x4e, 0x93, 0x2a, 0xe4, 0x7c, + 0x7f, 0x43, 0xf6, 0x5c, 0x68, 0x98, 0xa1, 0x2e, 0x51, 0x27, 0xde, 0x86, + 0x8d, 0x75, 0x4e, 0x99, 0x88, 0xc3, 0xe7, 0x94, 0x8d, 0xc9, 0x44, 0xb5, + 0x26, 0x95, 0xed, 0xf9, 0x27, 0x7c, 0xe8, 0xe2, 0x94, 0x05, 0x3f, 0x5a, + 0x94, 0xce, 0x31, 0x37, 0x87, 0xf9, 0x06, 0x6d, 0x0b, 0x7e, 0x05, 0xb0, + 0xd0, 0xb5, 0x84, 0x31, 0xbf, 0xf3, 0x55, 0xd7, 0xe0, 0x3e, 0x19, 0xe4, + 0x4d, 0x89, 0x84, 0x3e, 0x7f, 0xd5, 0xa7, 0x9e, 0x4d, 0x8f, 0x5c, 0x45, + 0x9e, 0x62, 0xc1, 0x57, 0xc2, 0x7f, 0x40, 0xdf, 0x67, 0x9b, 0x82, 0xb8, + 0xfe, 0x40, 0x4f, 0x60, 0x63, 0x47, 0xb7, 0x06, 0x4f, 0x31, 0xe9, 0x9b, + 0xa7, 0x73, 0xcc, 0x01, 0xda, 0x13, 0x6e, 0x6e, 0x7c, 0x9b, 0x71, 0xe6, + 0xc0, 0x36, 0xfd, 0x4c, 0x65, 0x9b, 0x0e, 0x9f, 0x0e, 0x9b, 0xd2, 0xdd, + 0x1c, 0xfa, 0x67, 0x22, 0x1b, 0x4a, 0xc3, 0x86, 0xde, 0x56, 0x39, 0xc8, + 0xb9, 0xe6, 0x29, 0xd8, 0xab, 0xa2, 0x55, 0x26, 0x90, 0x13, 0xe8, 0xa3, + 0xef, 0x43, 0x4f, 0x70, 0x16, 0xf8, 0xc0, 0x02, 0xb8, 0xa4, 0x8f, 0xbe, + 0x11, 0xda, 0x33, 0xfb, 0xef, 0xf8, 0x41, 0x7c, 0xf8, 0x7c, 0xb8, 0xff, + 0x3f, 0x75, 0x07, 0x3e, 0x20, 0xc2, 0x45, 0x3c, 0xc3, 0xda, 0x04, 0xf2, + 0x99, 0x89, 0xa6, 0xa9, 0xd1, 0x9f, 0x17, 0x3d, 0xe6, 0x21, 0xcc, 0x41, + 0x1e, 0x0b, 0xfd, 0x22, 0x73, 0x8f, 0xce, 0x90, 0xa7, 0xb9, 0x28, 0xce, + 0x29, 0x7b, 0x43, 0xcc, 0xc9, 0x94, 0x9d, 0x36, 0xe5, 0x93, 0xa7, 0x73, + 0x9d, 0x58, 0x87, 0xb9, 0x26, 0xce, 0x0d, 0xbf, 0x84, 0x5c, 0x06, 0x6b, + 0xce, 0x63, 0x7d, 0x7b, 0x68, 0xf3, 0x17, 0xa5, 0x0c, 0x9f, 0x6a, 0xda, + 0x7c, 0x9f, 0xeb, 0x91, 0x0e, 0x8c, 0x1b, 0xd8, 0x0b, 0x7e, 0xc2, 0x50, + 0x7c, 0x46, 0x2c, 0x48, 0x5d, 0xc7, 0x1c, 0x09, 0x6b, 0x33, 0x58, 0x4b, + 0xbf, 0xcb, 0xb5, 0xcf, 0x82, 0x0e, 0x8c, 0x1b, 0x84, 0xa1, 0x8f, 0x12, + 0xdf, 0xcd, 0x6d, 0x86, 0x26, 0xf9, 0xe7, 0x0c, 0x3b, 0x5a, 0x1b, 0xe1, + 0xdd, 0xb8, 0x96, 0xf9, 0x09, 0x71, 0xf7, 0x84, 0xf1, 0x7f, 0x5c, 0x0a, + 0xcd, 0x02, 0x7e, 0x22, 0xd3, 0xc7, 0x90, 0x8f, 0xd9, 0x6d, 0x88, 0x55, + 0x9c, 0xdf, 0x6a, 0x05, 0x67, 0x8d, 0xe0, 0xee, 0xef, 0x5b, 0x3f, 0xfe, + 0x42, 0x72, 0xcd, 0x47, 0xd2, 0xc2, 0xa4, 0x80, 0x18, 0x01, 0x5e, 0x65, + 0xa6, 0x98, 0xc3, 0x15, 0x1b, 0x4a, 0xa6, 0x98, 0x1b, 0x83, 0x5f, 0x0c, + 0xf2, 0xa2, 0x73, 0xde, 0x46, 0xd9, 0x59, 0xe0, 0x77, 0x01, 0x3c, 0xce, + 0x40, 0x87, 0xc6, 0x01, 0x2b, 0x87, 0x81, 0x83, 0xf1, 0xd7, 0xd1, 0xf3, + 0x49, 0x29, 0x5b, 0xcc, 0x13, 0xda, 0x49, 0x67, 0x81, 0xf6, 0xaf, 0xe7, + 0x37, 0x63, 0x8e, 0xfd, 0x7b, 0x7b, 0x02, 0x99, 0x75, 0x71, 0x3c, 0xa1, + 0xe7, 0x7b, 0x36, 0xcc, 0x7f, 0xbf, 0x2b, 0xa0, 0x4d, 0x8d, 0x31, 0xff, + 0xf2, 0x86, 0xf1, 0xef, 0x25, 0xd7, 0x8f, 0xef, 0xda, 0x16, 0xea, 0x20, + 0xfa, 0x8f, 0x85, 0xf4, 0x82, 0xb6, 0x55, 0x5a, 0xa3, 0x9c, 0x57, 0x16, + 0x74, 0xe4, 0x7f, 0x6e, 0x6e, 0x27, 0x62, 0x7d, 0x46, 0x4a, 0x4d, 0xd0, + 0xbd, 0x1a, 0xcb, 0x56, 0xd7, 0x54, 0xd6, 0xd6, 0x04, 0xbe, 0xbe, 0xd4, + 0xf4, 0x91, 0x3b, 0xb5, 0xc6, 0xbd, 0x61, 0xf4, 0x2b, 0xd8, 0xa7, 0x20, + 0xd3, 0xde, 0x85, 0x82, 0x6e, 0x1f, 0x09, 0xf2, 0x3e, 0xfb, 0x9b, 0x5a, + 0x69, 0x99, 0xf9, 0x20, 0xec, 0xc9, 0x56, 0xf9, 0x3f, 0xe2, 0xca, 0x51, + 0xad, 0x70, 0xea, 0x38, 0xf2, 0xc1, 0x15, 0xfc, 0x4e, 0xe3, 0xd7, 0xc0, + 0x2f, 0xca, 0xc3, 0x9f, 0x41, 0x1e, 0xaf, 0x7c, 0x2c, 0xe2, 0x41, 0xb0, + 0xff, 0x1b, 0x2b, 0xd0, 0xb3, 0xe3, 0x29, 0xf9, 0x86, 0xad, 0xf7, 0xe9, + 0x81, 0x5f, 0x29, 0x20, 0x8f, 0xb5, 0xde, 0x96, 0xdf, 0x0e, 0xf3, 0x22, + 0x91, 0xd7, 0x16, 0xc0, 0xc7, 0x91, 0xfd, 0xa1, 0xce, 0x16, 0xee, 0x75, + 0x95, 0xff, 0x0c, 0xf3, 0x1e, 0xe4, 0x5f, 0x05, 0xb5, 0xea, 0x5b, 0xe0, + 0x8d, 0x26, 0x6f, 0x41, 0x87, 0x5e, 0x5b, 0xe8, 0x00, 0x3d, 0xb6, 0x94, + 0x27, 0x91, 0x2f, 0x68, 0x83, 0xd6, 0x26, 0xad, 0x03, 0x76, 0x0c, 0x1b, + 0x57, 0x63, 0x49, 0xb4, 0xe5, 0x2f, 0xcd, 0x2c, 0xd5, 0x74, 0xac, 0x45, + 0xee, 0x93, 0x43, 0x1f, 0xb2, 0xbf, 0xb2, 0x40, 0x38, 0x5d, 0x5e, 0x5f, + 0x30, 0xe4, 0x4d, 0xe4, 0x52, 0x6f, 0xd9, 0x97, 0x66, 0x10, 0xb7, 0xfa, + 0x11, 0x23, 0x50, 0x8b, 0xec, 0xa4, 0x9f, 0xde, 0x61, 0xe2, 0x59, 0xc2, + 0x6f, 0x1f, 0x72, 0xc1, 0x8f, 0x86, 0xf9, 0xb8, 0xf5, 0xa4, 0x2d, 0x01, + 0x18, 0xae, 0x37, 0x41, 0x5b, 0x37, 0xe4, 0x9f, 0xb5, 0xa6, 0xe4, 0xf5, + 0x1e, 0x95, 0xaf, 0x68, 0x9c, 0x0f, 0x7c, 0xd3, 0x87, 0xe7, 0xc9, 0x67, + 0x03, 0x3a, 0xce, 0x31, 0xdf, 0xd1, 0x87, 0x12, 0x5f, 0x76, 0xac, 0x80, + 0xc3, 0x5c, 0x59, 0x08, 0xfa, 0xd1, 0x9c, 0x68, 0x51, 0x1c, 0xa3, 0x6f, + 0x2c, 0xc1, 0x4e, 0x38, 0x9e, 0x10, 0x25, 0x83, 0x75, 0xf2, 0x94, 0x84, + 0x99, 0x3f, 0x3b, 0x33, 0x67, 0x53, 0xae, 0xf0, 0x71, 0xb5, 0x48, 0xae, + 0x94, 0x51, 0xbb, 0x54, 0x17, 0xbe, 0x09, 0xb9, 0xea, 0x61, 0xbe, 0x0f, + 0x1b, 0x3f, 0x4e, 0xf9, 0xa2, 0xfe, 0x5b, 0x40, 0xee, 0xb3, 0x20, 0xc9, + 0xa0, 0x5e, 0x39, 0x8a, 0x3c, 0x1f, 0xf2, 0xab, 0x1d, 0x07, 0x0e, 0xd8, + 0x69, 0x6d, 0x05, 0x4f, 0xd4, 0x16, 0xb5, 0xd3, 0x78, 0x0e, 0xe0, 0xd9, + 0xa0, 0x6e, 0x86, 0xb9, 0xc6, 0x87, 0xe8, 0x81, 0x3d, 0x95, 0x68, 0x4f, + 0xf2, 0xfd, 0x66, 0x5e, 0xbe, 0xdb, 0x1c, 0x93, 0xe7, 0x9b, 0x39, 0xf9, + 0xbb, 0xa6, 0x23, 0xdf, 0x69, 0x8e, 0xc8, 0xb7, 0x9b, 0xc3, 0xac, 0xc9, + 0x90, 0x37, 0x65, 0x98, 0x37, 0xc9, 0xbd, 0xde, 0xad, 0xb0, 0x77, 0xca, + 0xff, 0xd2, 0x4c, 0xa1, 0x31, 0x28, 0xe5, 0x63, 0xf0, 0xcf, 0xce, 0xcd, + 0xac, 0x25, 0xe5, 0x11, 0x87, 0x35, 0x41, 0x1b, 0xdf, 0xa3, 0xce, 0x84, + 0xff, 0x86, 0x3f, 0x9b, 0x4a, 0x65, 0x4f, 0xbb, 0x46, 0x47, 0xe8, 0x03, + 0x6e, 0x49, 0x4a, 0x07, 0xf6, 0x82, 0x0f, 0x5c, 0x7a, 0x1a, 0x36, 0xa0, + 0x6a, 0x9a, 0x04, 0xfc, 0x0d, 0x73, 0x01, 0x93, 0x76, 0x8c, 0x3a, 0x30, + 0x9b, 0x71, 0x0d, 0xd6, 0x77, 0xb4, 0x67, 0x03, 0x81, 0x83, 0x70, 0xfb, + 0x2c, 0xca, 0xcd, 0xb4, 0xe9, 0x57, 0x0b, 0xa1, 0x8f, 0x4b, 0x84, 0x7a, + 0x69, 0x61, 0xfe, 0xf1, 0xd0, 0x27, 0x6f, 0xdc, 0x07, 0xf1, 0x02, 0xf9, + 0x64, 0xb0, 0x8e, 0xb0, 0x5a, 0x08, 0xdb, 0x17, 0xce, 0x75, 0x82, 0xdf, + 0x8e, 0x94, 0xbd, 0x37, 0x35, 0xe6, 0xd9, 0xc8, 0x77, 0x30, 0x1e, 0xc1, + 0xf8, 0x4a, 0x38, 0xfe, 0x9c, 0x4c, 0x2f, 0x0a, 0x68, 0xfd, 0x89, 0x56, + 0x54, 0xe3, 0x31, 0x8c, 0x75, 0x8c, 0x0d, 0xd6, 0x02, 0x68, 0x37, 0x27, + 0xa9, 0xeb, 0xba, 0x4d, 0x5f, 0x38, 0x19, 0xfa, 0xc3, 0x82, 0x1c, 0xf6, + 0x06, 0x0b, 0x57, 0x11, 0x33, 0xb4, 0xb6, 0x28, 0xff, 0xd9, 0x0e, 0xbe, + 0xf8, 0xfe, 0xed, 0xac, 0xb9, 0x93, 0xa6, 0x7c, 0x7b, 0x3e, 0x6b, 0x3d, + 0xa4, 0x7f, 0x0d, 0x67, 0xf2, 0xfd, 0x83, 0x76, 0xf6, 0xc8, 0x94, 0xde, + 0x25, 0xdf, 0x3d, 0xca, 0xd8, 0x7b, 0x76, 0xe6, 0x07, 0xd0, 0xbd, 0xfa, + 0x4a, 0xbb, 0xd4, 0xeb, 0xa6, 0x5c, 0x19, 0x1d, 0x04, 0x9d, 0x96, 0xd4, + 0x1b, 0x49, 0xe4, 0x73, 0x9b, 0x65, 0xb6, 0x5f, 0x19, 0x18, 0xfc, 0xf4, + 0xb0, 0xf2, 0xd3, 0xae, 0x8d, 0x67, 0xe3, 0xe7, 0x3d, 0xeb, 0xcf, 0x5c, + 0x02, 0xfd, 0xd0, 0xeb, 0xe4, 0x76, 0x25, 0xe7, 0xb2, 0x37, 0x68, 0x95, + 0x75, 0xc4, 0x2e, 0x73, 0xd0, 0xba, 0x57, 0xff, 0x2f, 0xff, 0xf3, 0x26, + 0x65, 0xf7, 0xaa, 0xaa, 0x61, 0x54, 0xac, 0xc3, 0x7e, 0x4b, 0x2b, 0x2f, + 0x83, 0x16, 0xf8, 0xd8, 0xc6, 0xf6, 0x70, 0x9c, 0x51, 0xbc, 0x38, 0xdb, + 0xe8, 0x90, 0xef, 0xd4, 0xb7, 0xc8, 0x72, 0x9d, 0xef, 0xdb, 0x65, 0xa9, + 0x3e, 0x78, 0xb5, 0x4f, 0xef, 0x97, 0xf3, 0xd7, 0x5c, 0x6f, 0xdd, 0xa3, + 0x23, 0x37, 0x98, 0xfc, 0x40, 0x7e, 0x39, 0xda, 0x23, 0x3f, 0xfe, 0x72, + 0xf6, 0x99, 0x3f, 0xd5, 0x61, 0x03, 0xa3, 0x9d, 0xb4, 0x6d, 0xf4, 0x39, + 0x9f, 0xbd, 0x5a, 0xd0, 0xa9, 0xdb, 0x3f, 0x02, 0x4f, 0xb3, 0x0b, 0x81, + 0x1d, 0x10, 0x37, 0xf1, 0x42, 0x37, 0xec, 0xef, 0x01, 0x27, 0xde, 0x35, + 0x06, 0x81, 0xeb, 0x7b, 0x8a, 0x17, 0xb7, 0x3b, 0xd9, 0xab, 0x08, 0x49, + 0xfe, 0x15, 0x7b, 0x70, 0x78, 0x87, 0xbe, 0x5d, 0xea, 0xe9, 0xeb, 0xad, + 0xe7, 0xe0, 0xff, 0x0b, 0xa9, 0xec, 0x91, 0xcb, 0x72, 0x76, 0xe6, 0xa2, + 0x4d, 0xfd, 0xa7, 0xdf, 0x78, 0x09, 0xb9, 0xa7, 0x25, 0x0b, 0x0d, 0xfa, + 0x4b, 0xe2, 0x62, 0xfe, 0xbf, 0xcb, 0x3a, 0xac, 0x33, 0x4f, 0xc0, 0x3b, + 0xcc, 0x1b, 0xbf, 0x4e, 0x39, 0xb7, 0x11, 0x76, 0xb8, 0xa0, 0xff, 0x62, + 0x03, 0x8f, 0x06, 0xad, 0xbd, 0x3a, 0xf7, 0xfb, 0x37, 0xec, 0xfb, 0x0e, + 0x68, 0x1d, 0x04, 0x2c, 0x62, 0x66, 0xba, 0x75, 0x8f, 0x57, 0xd4, 0x1e, + 0xc7, 0x1a, 0xc8, 0xf5, 0x56, 0xf7, 0xc0, 0x5c, 0x43, 0xc7, 0x39, 0x4d, + 0x25, 0x97, 0x2b, 0xa3, 0xe4, 0xef, 0x9e, 0x5e, 0xe6, 0x99, 0x46, 0xfe, + 0xaf, 0xfd, 0xa8, 0x7e, 0x7c, 0x7e, 0x7e, 0x12, 0xfe, 0xd9, 0xf7, 0x2f, + 0xec, 0x1a, 0x04, 0x0d, 0xa8, 0x43, 0xd3, 0xe4, 0xf9, 0xd9, 0x19, 0x17, + 0x38, 0x8a, 0x0a, 0xf7, 0x25, 0x59, 0x01, 0xee, 0x09, 0xf2, 0x01, 0xb8, + 0xe7, 0x38, 0xaf, 0x64, 0x80, 0xf9, 0x46, 0x06, 0x78, 0x23, 0xfd, 0x4c, + 0x42, 0xd7, 0x76, 0x5b, 0xb7, 0x07, 0xba, 0x9e, 0x60, 0x6c, 0x7b, 0x0e, + 0xba, 0x57, 0x48, 0x52, 0x7f, 0xda, 0x7b, 0xd7, 0xf4, 0xa7, 0x15, 0x7f, + 0xbb, 0x94, 0x16, 0x12, 0xc0, 0x6b, 0xca, 0x5c, 0x8e, 0x78, 0x31, 0xae, + 0x53, 0xf7, 0x2b, 0xa1, 0xee, 0x77, 0x86, 0xb8, 0x17, 0xc1, 0x93, 0x6c, + 0xa6, 0xae, 0xb3, 0x8e, 0xda, 0xa6, 0x6a, 0x5b, 0x03, 0x36, 0x5d, 0xae, + 0xb1, 0x0e, 0xe5, 0xfd, 0xc8, 0xa5, 0x99, 0x69, 0xd4, 0xaa, 0xe5, 0xda, + 0x88, 0x56, 0x6e, 0xda, 0x5a, 0xd9, 0xa3, 0xbe, 0xed, 0xb2, 0x2e, 0x28, + 0x1e, 0xa7, 0x65, 0xa9, 0xf9, 0x4b, 0xbf, 0xba, 0x6b, 0x13, 0xfa, 0xd0, + 0xfd, 0x09, 0xca, 0xf7, 0xb3, 0xa4, 0x0b, 0x41, 0x9c, 0xfc, 0x4e, 0xc9, + 0xc9, 0x21, 0x14, 0xbd, 0xc8, 0xad, 0x4e, 0x0d, 0x11, 0x3f, 0xe8, 0x48, + 0xa5, 0x64, 0xd9, 0xe3, 0x1e, 0x67, 0x67, 0xc8, 0xcb, 0xf2, 0x71, 0x4b, + 0x0e, 0x2b, 0xf9, 0xbd, 0xac, 0x6c, 0xbb, 0xbc, 0x62, 0xc8, 0x74, 0x72, + 0xd0, 0x7a, 0x58, 0xb2, 0x57, 0x2f, 0x18, 0xd9, 0x67, 0xa6, 0x60, 0xd7, + 0x4b, 0x8b, 0x86, 0xb8, 0xaa, 0xde, 0xa2, 0x8c, 0xb2, 0x0b, 0xb0, 0xfc, + 0xf0, 0xec, 0x7b, 0x5b, 0xce, 0xde, 0x2d, 0x2b, 0x4f, 0xff, 0x26, 0x7c, + 0xce, 0x01, 0xc8, 0xc2, 0xcc, 0x1c, 0x42, 0x5e, 0xf1, 0xb4, 0x0c, 0x5a, + 0x55, 0xe4, 0xc9, 0xe0, 0x3b, 0xda, 0x01, 0x65, 0x03, 0x17, 0x74, 0x8c, + 0x07, 0xc8, 0x27, 0x8e, 0xaf, 0x95, 0x0b, 0xca, 0x96, 0xd2, 0xea, 0xdd, + 0x0e, 0xe0, 0x08, 0xde, 0x71, 0xfc, 0x19, 0xd9, 0xa1, 0xde, 0xdd, 0xa9, + 0xde, 0x55, 0xe9, 0x2b, 0x94, 0xfc, 0xbe, 0x82, 0x3d, 0xc9, 0xe3, 0x68, + 0xbe, 0x4b, 0x02, 0x5b, 0x8a, 0xf8, 0x6e, 0xc9, 0xc1, 0x46, 0x4a, 0xbe, + 0x84, 0xfa, 0xe7, 0x8e, 0xc6, 0x80, 0x94, 0x20, 0xc7, 0xe9, 0xdc, 0x83, + 0xbd, 0x3c, 0x5b, 0x71, 0x25, 0xfb, 0x8c, 0xe8, 0xa4, 0xf5, 0x4e, 0x39, + 0xe4, 0x45, 0xf4, 0x74, 0x86, 0xf4, 0x4d, 0x86, 0xe3, 0x44, 0x48, 0x43, + 0x2b, 0xbe, 0x4e, 0xe0, 0x42, 0xac, 0xcf, 0x79, 0x21, 0x1e, 0xfa, 0x11, + 0xd0, 0x3a, 0x99, 0x96, 0x15, 0x8f, 0x74, 0x6c, 0x91, 0x6a, 0x8a, 0xfd, + 0x03, 0xd0, 0x37, 0xe2, 0xd9, 0xc4, 0x7c, 0x66, 0x1d, 0x8f, 0x1f, 0x6c, + 0x54, 0xc0, 0x63, 0xf2, 0x97, 0xeb, 0x10, 0x23, 0x3e, 0x47, 0xf9, 0xed, + 0x46, 0x2e, 0x6f, 0x07, 0xba, 0x69, 0xad, 0xed, 0x59, 0x3a, 0xde, 0x0d, + 0x59, 0x71, 0xdf, 0x0e, 0x99, 0x84, 0xdd, 0x17, 0xeb, 0xdc, 0x7f, 0x12, + 0x7a, 0x74, 0x51, 0xed, 0x5f, 0x5a, 0xe9, 0x0f, 0xe1, 0x09, 0xdb, 0xbd, + 0x01, 0xb6, 0x5d, 0xf6, 0x2e, 0x58, 0x1f, 0x01, 0xff, 0xbb, 0x80, 0xd7, + 0xe5, 0x44, 0x8e, 0xf0, 0xc4, 0x83, 0x75, 0xf5, 0xd4, 0x27, 0xe0, 0x49, + 0xaa, 0xba, 0xbe, 0x58, 0x6f, 0x97, 0xe2, 0x42, 0x84, 0x8b, 0x78, 0x3e, + 0x40, 0xdd, 0x7b, 0xb7, 0xc2, 0x35, 0xad, 0x70, 0xe1, 0x7d, 0x9d, 0x3e, + 0xe7, 0x26, 0xc0, 0xa3, 0x76, 0xb7, 0x41, 0x5b, 0xb2, 0x4b, 0xaa, 0xaa, + 0x76, 0xef, 0x50, 0xbe, 0xa6, 0x9a, 0xdc, 0x8c, 0xf7, 0x3e, 0xf6, 0xdc, + 0x8d, 0x7c, 0xa6, 0x1b, 0x73, 0x99, 0x0d, 0x73, 0x1b, 0xe9, 0x4f, 0x6c, + 0xa0, 0xff, 0xbf, 0x7b, 0x19, 0x52, 0xe6, 0x72, 0xc1, 0xba, 0x12, 0xd6, + 0xcd, 0x1e, 0x87, 0x4d, 0x30, 0x4f, 0x4f, 0x31, 0x36, 0x5f, 0xa3, 0x68, + 0x99, 0x5d, 0xf9, 0x29, 0xd6, 0xf5, 0x03, 0x36, 0x1a, 0x07, 0x7c, 0x78, + 0x0a, 0x78, 0x8e, 0xd7, 0xd5, 0x1d, 0x05, 0x64, 0xf0, 0xbe, 0x3a, 0x7b, + 0xb5, 0xfe, 0x69, 0x3c, 0xbb, 0xa6, 0x85, 0x5f, 0xe4, 0x15, 0xe9, 0x25, + 0xad, 0xbc, 0x2f, 0x82, 0xbd, 0x39, 0xd0, 0xe3, 0xa4, 0x21, 0xa5, 0x1c, + 0xe2, 0xba, 0xc7, 0xbb, 0x57, 0xda, 0xe5, 0x40, 0x50, 0x23, 0xd8, 0x8c, + 0xef, 0xa6, 0x3a, 0xfb, 0xa1, 0x15, 0xde, 0xbf, 0x66, 0x78, 0x47, 0x37, + 0x8c, 0xda, 0x5b, 0x1e, 0x5a, 0xb1, 0xe5, 0x6b, 0x8d, 0x61, 0x79, 0xb8, + 0x91, 0xb5, 0xee, 0x81, 0x0f, 0x28, 0xaf, 0xde, 0xcb, 0x6e, 0x4b, 0xd2, + 0x7f, 0x99, 0xc8, 0x3d, 0xdb, 0xec, 0x20, 0x17, 0xa9, 0xb2, 0x36, 0x3b, + 0x9e, 0xe5, 0x7d, 0x8d, 0x55, 0x97, 0x8d, 0xf9, 0xca, 0xff, 0x65, 0xae, + 0xc2, 0xfd, 0xe9, 0xaf, 0x91, 0x9b, 0x78, 0xc8, 0x4d, 0x3c, 0xe4, 0x26, + 0x1e, 0x72, 0x13, 0x0f, 0xb9, 0x89, 0x87, 0xdc, 0xc4, 0x43, 0x6e, 0xe2, + 0x21, 0x37, 0x41, 0x1d, 0x10, 0xd4, 0x07, 0xe3, 0xc8, 0xb9, 0xe1, 0xbf, + 0xbc, 0x5b, 0xc2, 0xdc, 0x22, 0x8a, 0xcd, 0x9c, 0x3b, 0xbf, 0xc9, 0x0d, + 0xea, 0x2b, 0xe5, 0x13, 0x0a, 0xcd, 0x89, 0x30, 0x07, 0xe2, 0x9a, 0x28, + 0x76, 0x73, 0x9d, 0x8c, 0xb9, 0xa8, 0x3d, 0x0b, 0x93, 0xcc, 0x91, 0x82, + 0x98, 0x15, 0xe4, 0xe7, 0xaf, 0x22, 0x4f, 0xca, 0x20, 0x4f, 0x1a, 0x40, + 0x4e, 0xc4, 0x7b, 0xea, 0xe8, 0x2e, 0xa9, 0xa0, 0x1d, 0xf4, 0xc6, 0xb5, + 0x2f, 0x79, 0xcc, 0xdf, 0xed, 0x4c, 0x59, 0xd7, 0x8f, 0xf7, 0x89, 0x2f, + 0xc5, 0xd1, 0xaf, 0x23, 0x57, 0xfe, 0x4b, 0x75, 0x6f, 0x36, 0x31, 0x44, + 0x99, 0xdf, 0xf7, 0x31, 0xf9, 0x72, 0xc4, 0xdf, 0xe0, 0xbe, 0x4f, 0x5f, + 0x22, 0xff, 0x44, 0x7a, 0xcf, 0x80, 0xe1, 0x67, 0x12, 0x92, 0x3c, 0xb9, + 0x05, 0x73, 0x96, 0xf4, 0xa9, 0x3b, 0x23, 0x88, 0xf2, 0xcc, 0x7f, 0x40, + 0x5e, 0xb6, 0xe8, 0x67, 0x78, 0xb3, 0x40, 0xbc, 0xf4, 0xaf, 0xf5, 0x99, + 0x62, 0xbd, 0xae, 0x74, 0xea, 0x60, 0xa3, 0x84, 0x3c, 0xca, 0xe8, 0x93, + 0x0e, 0x13, 0xb5, 0x54, 0x84, 0x9b, 0x38, 0xdf, 0x4c, 0xaa, 0x1a, 0xe7, + 0xcc, 0xaa, 0x3c, 0x21, 0x6b, 0xee, 0x53, 0x9f, 0xa9, 0x2e, 0x64, 0xd3, + 0xac, 0x71, 0x0b, 0x56, 0x7d, 0xe6, 0x49, 0xe0, 0x58, 0x46, 0x6e, 0x60, + 0xa8, 0xbd, 0xeb, 0x33, 0xb3, 0x0b, 0xc1, 0xbd, 0x55, 0x40, 0x03, 0xe3, + 0x55, 0x87, 0x18, 0x4b, 0xc1, 0xfd, 0x95, 0xae, 0x60, 0x09, 0x47, 0x78, + 0x13, 0x70, 0x94, 0xdb, 0x30, 0x60, 0x29, 0x3b, 0xd2, 0x50, 0x9f, 0xa9, + 0xd4, 0x5b, 0x69, 0x20, 0x1e, 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0x24, 0x45, + 0x3f, 0xe9, 0xfb, 0xe5, 0xd1, 0x81, 0xb0, 0xae, 0x44, 0x1d, 0x79, 0xcc, + 0x0c, 0xf4, 0x5c, 0x8d, 0xff, 0x58, 0xc5, 0xa9, 0x8c, 0xce, 0x79, 0x3e, + 0xf1, 0x2e, 0xf7, 0x28, 0xe6, 0x30, 0x5e, 0x8e, 0xd6, 0xea, 0xe1, 0xda, + 0xae, 0x16, 0x7e, 0xb6, 0x85, 0xfb, 0x91, 0x26, 0x9e, 0xf3, 0x15, 0xec, + 0x45, 0xba, 0xb8, 0xc6, 0x04, 0x6d, 0x90, 0xa5, 0xf7, 0xbf, 0xe5, 0x7d, + 0xeb, 0x99, 0xc8, 0x53, 0x13, 0x30, 0x5c, 0x4f, 0x1c, 0x11, 0x0c, 0x5e, + 0x9c, 0x09, 0xe0, 0xf4, 0xd5, 0x7b, 0xbe, 0x4f, 0xda, 0xb7, 0x95, 0xd6, + 0x68, 0xff, 0x08, 0xcf, 0x70, 0x20, 0xb7, 0x55, 0x78, 0xf5, 0x7f, 0x7f, + 0xe1, 0x09, 0x5d, 0xfc, 0xd0, 0x7d, 0xe9, 0x70, 0x4b, 0x8d, 0x1c, 0xdd, + 0x3b, 0xb0, 0xfe, 0x67, 0x3d, 0xcf, 0xef, 0x03, 0xad, 0xf5, 0x69, 0x29, + 0x8c, 0x65, 0xdb, 0xa4, 0x60, 0xb2, 0x56, 0x19, 0x0f, 0xc7, 0x5b, 0x11, + 0xdb, 0x38, 0xbe, 0x15, 0xfc, 0x85, 0x2e, 0x3b, 0x1d, 0x61, 0xad, 0x94, + 0x0c, 0xbe, 0xeb, 0x0c, 0xd3, 0x8e, 0x58, 0x6b, 0x6e, 0x0e, 0xe7, 0x22, + 0x3b, 0xa2, 0x1f, 0x36, 0xc3, 0x39, 0xfa, 0x5b, 0x1d, 0xf5, 0x12, 0xfb, + 0xc0, 0xb3, 0xdc, 0x6a, 0x4b, 0xd1, 0x33, 0x29, 0xa7, 0x17, 0x23, 0xbf, + 0x05, 0x9f, 0x32, 0x64, 0x86, 0xbe, 0xbf, 0x13, 0xbe, 0xaf, 0x5b, 0xf6, + 0xc2, 0x67, 0xed, 0x83, 0xcf, 0xda, 0x8f, 0x1a, 0x75, 0x7c, 0xa5, 0xf5, + 0x3e, 0x97, 0x75, 0x71, 0x55, 0x0e, 0x29, 0xf9, 0x57, 0x7c, 0xc3, 0xfe, + 0x00, 0x3a, 0xb0, 0x53, 0xe5, 0x7b, 0x81, 0x4e, 0xc0, 0xdf, 0x3a, 0x49, + 0xe8, 0xc4, 0xc6, 0x7b, 0xe3, 0x61, 0xd8, 0x46, 0x47, 0x41, 0xc5, 0x86, + 0x95, 0x80, 0xf7, 0xd5, 0x7a, 0xc0, 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5, + 0xd2, 0xb0, 0xa4, 0x82, 0x7d, 0x2b, 0xd8, 0xb7, 0x82, 0xda, 0x72, 0xb6, + 0xd1, 0xfa, 0xed, 0xaa, 0x2b, 0xa4, 0x9d, 0xb0, 0x51, 0xdf, 0x6a, 0x39, + 0x7f, 0xf4, 0x3c, 0x02, 0xfe, 0x3f, 0x02, 0xfe, 0x1f, 0x46, 0x4d, 0xf5, + 0x00, 0x6a, 0xaa, 0xfb, 0x50, 0x53, 0x1d, 0x42, 0x4d, 0x35, 0x85, 0x9a, + 0xea, 0x6e, 0xf8, 0x8f, 0x3b, 0xe1, 0x3f, 0x26, 0xe1, 0x3f, 0x26, 0xd4, + 0x9d, 0xd1, 0x41, 0x6f, 0xe3, 0x1d, 0x4a, 0xb4, 0x17, 0xdb, 0x1b, 0x22, + 0x50, 0x81, 0xf2, 0xb1, 0x71, 0xa9, 0x37, 0x59, 0x5b, 0x39, 0xea, 0x3e, + 0x6c, 0xda, 0x99, 0xd4, 0xa6, 0x90, 0xbf, 0xdf, 0x33, 0xc2, 0x9a, 0x2b, + 0xa9, 0x15, 0x55, 0xcd, 0x95, 0x7d, 0xc1, 0x45, 0x8a, 0x84, 0xdc, 0x0f, + 0x67, 0xce, 0x9e, 0x2e, 0x1a, 0x51, 0xbd, 0xd3, 0xbb, 0x5a, 0xef, 0x2c, + 0xcf, 0xb3, 0xde, 0x79, 0x75, 0xb5, 0xde, 0x59, 0x9e, 0x67, 0xbd, 0xf3, + 0xca, 0xba, 0x7a, 0xe7, 0xca, 0xd3, 0x97, 0xd6, 0xd5, 0x3b, 0x57, 0x9e, + 0x7e, 0x29, 0x1c, 0x4b, 0xa8, 0x0f, 0x21, 0xad, 0x96, 0x83, 0x67, 0x4f, + 0x98, 0x73, 0x34, 0xfb, 0xd6, 0xff, 0xdf, 0x74, 0xca, 0x96, 0x35, 0xb1, + 0xff, 0x68, 0x6b, 0x50, 0x23, 0xb5, 0xce, 0x77, 0xb7, 0xcc, 0x5f, 0x56, + 0xdf, 0x4b, 0xcb, 0xb5, 0xcd, 0xef, 0xc2, 0x03, 0xcb, 0xca, 0x10, 0xf3, + 0xbc, 0x0f, 0x7c, 0x7e, 0xf3, 0x73, 0xf5, 0x0e, 0xf5, 0xcd, 0xcd, 0x55, + 0xf9, 0x36, 0xec, 0x7c, 0xf4, 0xd1, 0xad, 0x81, 0x2f, 0x60, 0x3f, 0xa5, + 0x05, 0xfe, 0xfd, 0x01, 0xe0, 0x01, 0xaf, 0x3d, 0x53, 0xdd, 0x07, 0x05, + 0xe7, 0x0d, 0xee, 0xc6, 0xcd, 0xfc, 0xe5, 0x19, 0xe6, 0xd6, 0x55, 0x85, + 0x9b, 0xf5, 0x23, 0x6b, 0xce, 0x28, 0x06, 0x44, 0xb8, 0x5e, 0x4d, 0x05, + 0x74, 0xbb, 0xa8, 0x1d, 0xb9, 0x26, 0x1a, 0xb7, 0xd6, 0x9a, 0x9d, 0xe1, + 0xbd, 0xdb, 0xe5, 0x20, 0xaf, 0x52, 0xf8, 0xcc, 0x10, 0xdf, 0xcf, 0xfd, + 0xc0, 0xf7, 0x10, 0xde, 0x6a, 0x81, 0x1f, 0x47, 0xae, 0xc7, 0x7b, 0x1a, + 0xe6, 0x6c, 0xa6, 0xbc, 0x33, 0xdf, 0x25, 0xff, 0x79, 0xd4, 0xf7, 0x27, + 0x9c, 0xec, 0xf0, 0x25, 0xd4, 0x1e, 0x27, 0x69, 0x27, 0xa3, 0xa4, 0x73, + 0x30, 0x33, 0x2b, 0xa9, 0x3e, 0xd2, 0x72, 0x5e, 0x3f, 0xac, 0x7d, 0x98, + 0x6e, 0x3d, 0xdc, 0xe7, 0x1f, 0x5b, 0xf6, 0xc9, 0xb4, 0xec, 0x53, 0xa0, + 0xcd, 0xd6, 0xef, 0xc0, 0x99, 0x2b, 0xdb, 0xaf, 0xb7, 0x52, 0x61, 0x5d, + 0xf6, 0xf0, 0xe8, 0x66, 0x59, 0xe8, 0xcf, 0x9e, 0x7d, 0x05, 0xf9, 0x7a, + 0x79, 0x14, 0x73, 0xa9, 0x41, 0xbc, 0xe3, 0x7c, 0xb6, 0x8e, 0x5c, 0xf4, + 0x6c, 0x5d, 0xb6, 0x01, 0x3e, 0x5b, 0x11, 0xe1, 0x3c, 0xfb, 0x8a, 0xb6, + 0x7a, 0xe8, 0x03, 0xd2, 0x17, 0x70, 0xe6, 0x29, 0xd4, 0x5f, 0x87, 0x83, + 0x7b, 0xb4, 0x70, 0x9f, 0x1b, 0xb5, 0x20, 0x6f, 0xce, 0x69, 0x95, 0xf0, + 0x0e, 0xf0, 0x2b, 0xf0, 0x17, 0x86, 0x4e, 0xd8, 0x77, 0x80, 0x5b, 0x93, + 0xa5, 0xa3, 0x86, 0xba, 0x3b, 0x2d, 0x8f, 0x52, 0xd6, 0x7c, 0x7e, 0x14, + 0xef, 0xa2, 0x33, 0xfd, 0x4d, 0x78, 0xa6, 0xd1, 0xb0, 0x6e, 0x8f, 0xce, + 0x94, 0x90, 0xd7, 0xe7, 0x2d, 0xc0, 0x8e, 0x80, 0x1f, 0x25, 0x59, 0x69, + 0x66, 0x3e, 0x05, 0x4f, 0xad, 0x85, 0x37, 0xe6, 0x06, 0x19, 0x46, 0x75, + 0x0f, 0x78, 0x30, 0x91, 0x86, 0x1d, 0xde, 0xd7, 0x17, 0xdd, 0xe9, 0x1a, + 0xb6, 0xae, 0x05, 0x75, 0x3c, 0xe7, 0x07, 0x60, 0x8b, 0x19, 0xd8, 0x27, + 0x73, 0xa6, 0x12, 0x6b, 0x15, 0xda, 0x93, 0xe5, 0x1a, 0x59, 0x6b, 0x52, + 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x79, 0x59, 0x6e, 0x46, 0x34, 0xe4, 0x60, + 0x8f, 0x63, 0xf8, 0x8d, 0xe0, 0x9d, 0x83, 0x1f, 0x6b, 0xa5, 0x82, 0x7c, + 0x55, 0xe5, 0xe2, 0xc8, 0xb5, 0x87, 0x48, 0xdf, 0x01, 0xac, 0xa7, 0x3e, + 0x53, 0x4f, 0x0f, 0x88, 0xdb, 0x4f, 0x5f, 0x91, 0x06, 0x6e, 0xc0, 0x78, + 0xaf, 0xc1, 0xd6, 0x07, 0xf0, 0xcc, 0x5a, 0x65, 0xf2, 0x56, 0xe1, 0xf7, + 0x7d, 0x23, 0xc7, 0x6f, 0x11, 0xe3, 0xe1, 0x78, 0xd0, 0xfa, 0x1d, 0xea, + 0x5e, 0xfa, 0x5a, 0x39, 0xbb, 0x18, 0xc5, 0xc1, 0x19, 0xd8, 0x20, 0xef, + 0x68, 0xc7, 0xc1, 0x17, 0x8e, 0xb5, 0x30, 0x1e, 0x62, 0x7e, 0xf9, 0xaf, + 0x70, 0xee, 0xbc, 0x9c, 0x44, 0xfd, 0x2f, 0xfd, 0x7c, 0x66, 0x80, 0x7f, + 0x4b, 0xa8, 0xef, 0xeb, 0xe1, 0x0d, 0x9b, 0xfd, 0x71, 0xd0, 0x67, 0xb6, + 0xc0, 0x13, 0x26, 0xac, 0x4f, 0x04, 0xf1, 0x38, 0xed, 0xdf, 0xaa, 0xe7, + 0xef, 0x96, 0x3f, 0x50, 0x67, 0xca, 0xcb, 0xa1, 0x45, 0xdf, 0x77, 0x73, + 0x83, 0xc3, 0xcb, 0x92, 0x1d, 0x7e, 0x52, 0x76, 0x5b, 0x7b, 0x59, 0x8f, + 0x59, 0xc4, 0xe3, 0xdf, 0xda, 0x96, 0xf7, 0xfd, 0x13, 0xa0, 0xfd, 0x07, + 0x6a, 0x9f, 0xbb, 0x41, 0x3f, 0x78, 0xa5, 0x6a, 0x12, 0xd2, 0x0a, 0xde, + 0xa4, 0x48, 0x6f, 0xa7, 0x1c, 0x6a, 0x3e, 0x1f, 0xca, 0xe6, 0x11, 0x71, + 0xbd, 0xb7, 0x0d, 0xde, 0x6f, 0x97, 0x9b, 0x8f, 0x86, 0xb4, 0xe5, 0x41, + 0x2f, 0xf6, 0x6f, 0xfe, 0x43, 0x8a, 0xbe, 0x81, 0x32, 0x77, 0x91, 0x35, + 0xba, 0xa3, 0xcf, 0x40, 0x07, 0x3f, 0xce, 0x0f, 0x24, 0x65, 0xbd, 0x1f, + 0x20, 0x5c, 0xf2, 0x23, 0x74, 0x85, 0x74, 0x88, 0xf2, 0x9f, 0x2a, 0x6e, + 0x29, 0x7c, 0xc6, 0x06, 0x5f, 0xf0, 0xa4, 0x7a, 0x9e, 0x37, 0xe8, 0x9b, + 0x18, 0xff, 0xa8, 0xc3, 0xdd, 0xf0, 0x7f, 0xd0, 0x41, 0xd8, 0x71, 0x71, + 0x91, 0xf7, 0x13, 0x43, 0xea, 0x4e, 0xab, 0x04, 0xd9, 0x2e, 0xf1, 0x3b, + 0x63, 0x2a, 0xc8, 0x27, 0x83, 0xfa, 0x2b, 0x43, 0x5f, 0x88, 0xf6, 0xb8, + 0xf2, 0x93, 0x25, 0xf5, 0x5d, 0x31, 0x89, 0x35, 0x3e, 0x9e, 0xad, 0x7f, + 0x27, 0xf1, 0xa3, 0x42, 0xf0, 0x77, 0x12, 0xe1, 0x37, 0xde, 0x7a, 0x90, + 0x47, 0x3c, 0xd8, 0x30, 0x65, 0xaa, 0x11, 0xfd, 0xdd, 0x04, 0xe5, 0x60, + 0x4b, 0xb9, 0x11, 0xe5, 0x0e, 0x7e, 0x50, 0xd3, 0xac, 0x93, 0xe5, 0xe3, + 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4, 0x78, 0x39, 0x90, 0xdf, 0x92, + 0xbe, 0x03, 0xf2, 0x03, 0xcf, 0x3d, 0x13, 0xb6, 0x94, 0x0e, 0xe3, 0xba, + 0xc5, 0x1a, 0x33, 0xac, 0x7b, 0xb7, 0x4b, 0x75, 0x92, 0xef, 0x13, 0xf2, + 0xda, 0xfc, 0x40, 0x70, 0x4f, 0x24, 0x89, 0xf0, 0x3d, 0xc7, 0x49, 0x29, + 0xab, 0xf7, 0x77, 0x86, 0xf8, 0x50, 0xa7, 0xdd, 0x19, 0x8d, 0xd3, 0x90, + 0x63, 0x00, 0x37, 0x8d, 0x58, 0xf6, 0x55, 0xc4, 0xb1, 0x69, 0xf0, 0xbd, + 0x38, 0x51, 0x91, 0x6b, 0x6d, 0x4b, 0xc5, 0x7d, 0x37, 0x49, 0x1d, 0xa3, + 0x7e, 0x11, 0xa6, 0x07, 0xb9, 0x2a, 0xce, 0x3b, 0x2a, 0x53, 0x46, 0xfe, + 0xdd, 0xdb, 0xca, 0xb5, 0xac, 0x55, 0x90, 0xf7, 0x7d, 0xd7, 0xe4, 0xf8, + 0xfc, 0x6d, 0x0f, 0x06, 0x77, 0xfe, 0xba, 0x9e, 0xbf, 0x78, 0x5b, 0x39, + 0xe8, 0xe3, 0xcc, 0xef, 0x86, 0x7d, 0xc2, 0x19, 0xea, 0x7b, 0xec, 0x4f, + 0x6e, 0x32, 0xe5, 0xc2, 0x4d, 0xbe, 0x7f, 0x0f, 0xbf, 0x09, 0x85, 0x75, + 0xac, 0xa5, 0xea, 0xd8, 0x0e, 0x95, 0x8f, 0xb8, 0xa3, 0x19, 0xad, 0x04, + 0xdb, 0x3d, 0xe9, 0xa1, 0xe6, 0xd1, 0xb3, 0x63, 0xe7, 0x75, 0x0b, 0xf1, + 0x37, 0x9b, 0x39, 0x2e, 0xb9, 0x3e, 0x7e, 0x63, 0x9e, 0x73, 0xb8, 0x66, + 0x5b, 0x70, 0xef, 0x75, 0x83, 0xab, 0x7c, 0xae, 0x48, 0x18, 0x87, 0x6e, + 0x68, 0xb5, 0x8f, 0xd6, 0x3c, 0x93, 0x76, 0x21, 0x53, 0x26, 0xe8, 0xa9, + 0xd6, 0xa2, 0x9c, 0x8d, 0x7f, 0x0f, 0x70, 0xfe, 0xb6, 0xa7, 0x1a, 0x17, + 0x6f, 0x9b, 0x85, 0x7c, 0x78, 0xa6, 0xd9, 0x46, 0xa4, 0x7f, 0x51, 0xdd, + 0xc0, 0x3e, 0xe2, 0xbf, 0x87, 0xf8, 0xef, 0x21, 0xfe, 0x7b, 0x88, 0xff, + 0x1e, 0xe2, 0xbf, 0x87, 0xf8, 0x0f, 0x1e, 0x3e, 0x07, 0x7d, 0x79, 0xd6, + 0x9b, 0x08, 0x73, 0xb6, 0xc7, 0x56, 0x73, 0x36, 0xfe, 0xcd, 0xcb, 0xb9, + 0xa6, 0xa2, 0xa5, 0x52, 0x91, 0x20, 0xe7, 0x15, 0x9d, 0xf9, 0x4d, 0x94, + 0xf3, 0x7e, 0xf4, 0xf7, 0x90, 0x00, 0x8e, 0xf9, 0x1e, 0xe1, 0x2a, 0x9a, + 0x6e, 0x13, 0x2e, 0xc8, 0xf9, 0x58, 0x67, 0xad, 0x87, 0xe1, 0x77, 0x37, + 0xfa, 0xb6, 0xe0, 0x9b, 0x4f, 0xf0, 0x7d, 0xa9, 0x76, 0x87, 0x8b, 0x58, + 0x5c, 0x6e, 0xa8, 0x78, 0x8c, 0x71, 0xe3, 0x0e, 0xfe, 0xad, 0x02, 0x64, + 0xc0, 0x77, 0x5f, 0x66, 0x6d, 0x51, 0x6e, 0x20, 0x2f, 0x5a, 0x8e, 0x72, + 0x21, 0xc0, 0x79, 0x6f, 0x6a, 0xa5, 0x05, 0xca, 0x59, 0x97, 0xd9, 0x14, + 0x98, 0x62, 0xb7, 0xe6, 0x78, 0x97, 0x54, 0xbd, 0x74, 0xb6, 0x49, 0x7a, + 0x46, 0x40, 0x5b, 0x74, 0x8f, 0x2c, 0x62, 0xcc, 0xa7, 0x44, 0x9f, 0x47, + 0x7e, 0x6b, 0x0f, 0xa9, 0xbf, 0x6f, 0xe8, 0xc5, 0x3e, 0xfa, 0xfc, 0x8e, + 0x96, 0x7b, 0x5a, 0x29, 0x04, 0x3e, 0x9b, 0xb1, 0x87, 0xe7, 0x48, 0xc1, + 0x76, 0xdd, 0x6d, 0x38, 0x1b, 0xe4, 0xfa, 0xaf, 0x5b, 0x55, 0x0e, 0x0e, + 0x3f, 0x7a, 0x62, 0xa8, 0xbf, 0x5f, 0xba, 0xb7, 0xcb, 0xc9, 0x21, 0xd6, + 0x6b, 0x9b, 0x81, 0x8f, 0x6b, 0x79, 0xff, 0xb4, 0x5d, 0x4e, 0x2d, 0xc2, + 0xcf, 0x2e, 0x66, 0x1d, 0xea, 0xf2, 0xd2, 0x50, 0x0a, 0xfe, 0xf9, 0xe6, + 0x7e, 0xc6, 0xe7, 0xe5, 0x26, 0x75, 0xa5, 0x17, 0xf0, 0x03, 0xd0, 0xcb, + 0x4d, 0xb0, 0x27, 0x1d, 0xfb, 0x47, 0xb8, 0xff, 0x45, 0xe1, 0xee, 0xb5, + 0x9d, 0x6d, 0x4a, 0x37, 0xf4, 0xac, 0x95, 0xd1, 0x41, 0xfb, 0xff, 0x14, + 0x6e, 0x6d, 0x31, 0x71, 0x5c, 0x67, 0xf8, 0x3f, 0xb3, 0xdc, 0x8c, 0xd7, + 0x30, 0x86, 0xf5, 0xb2, 0x58, 0xae, 0xba, 0x03, 0x63, 0x33, 0xd1, 0x62, + 0x65, 0xb0, 0xec, 0x16, 0x55, 0x96, 0xba, 0xda, 0x05, 0x42, 0xe2, 0x3a, + 0xdd, 0x24, 0xb4, 0x72, 0xd5, 0x2a, 0x42, 0x60, 0x37, 0x8e, 0xfa, 0xd2, + 0x46, 0x55, 0xdb, 0x37, 0xaf, 0x16, 0xec, 0x38, 0xcd, 0xac, 0x17, 0x37, + 0x38, 0xf4, 0x71, 0xb3, 0x2c, 0x0e, 0x90, 0x75, 0x56, 0x6e, 0xf2, 0x90, + 0x3e, 0x19, 0x6d, 0xa2, 0x24, 0x55, 0xa5, 0xbc, 0x54, 0x7d, 0xab, 0x5a, + 0x0b, 0x27, 0xc4, 0x0f, 0xa9, 0xad, 0xf6, 0xa5, 0x77, 0x4d, 0xbf, 0xef, + 0xcc, 0x2c, 0xc6, 0xa4, 0x51, 0x91, 0x56, 0x73, 0xe6, 0xcc, 0xb9, 0x9f, + 0xff, 0xf2, 0xfd, 0x17, 0x3e, 0x67, 0x67, 0xba, 0xc2, 0xbd, 0xcd, 0x95, + 0x76, 0xc6, 0xfe, 0xb6, 0xd4, 0xcc, 0x02, 0xf3, 0x1a, 0x86, 0x64, 0xdc, + 0x64, 0xae, 0xcf, 0x96, 0x3a, 0x57, 0x66, 0x1b, 0x1b, 0x65, 0xda, 0xe4, + 0x4b, 0x6a, 0xa6, 0xdc, 0x23, 0x17, 0x41, 0xc7, 0x85, 0xe1, 0xd6, 0xd0, + 0xf7, 0xda, 0x19, 0xf2, 0x73, 0x77, 0x3c, 0xd4, 0x57, 0x1a, 0x57, 0x16, + 0x34, 0xb6, 0xee, 0xde, 0xf5, 0xed, 0x49, 0xac, 0x29, 0x41, 0x5f, 0x79, + 0x5c, 0xcb, 0x26, 0x83, 0xef, 0x7d, 0xbb, 0xde, 0xe3, 0xbb, 0xde, 0x0f, + 0xfc, 0x8f, 0xf6, 0x2c, 0xef, 0xa6, 0x07, 0xae, 0xd3, 0x1a, 0xe5, 0x2c, + 0x05, 0xcf, 0x36, 0x66, 0x3d, 0x2b, 0x4d, 0x5c, 0x90, 0x15, 0x5f, 0x65, + 0xdd, 0x36, 0xc8, 0xbb, 0x36, 0x99, 0x5f, 0x04, 0xcd, 0x63, 0x1f, 0xed, + 0x36, 0x63, 0xe4, 0x43, 0x71, 0xf2, 0x4c, 0x07, 0xae, 0xc1, 0xb0, 0x07, + 0x13, 0x68, 0xe7, 0x3f, 0xef, 0xa6, 0xcc, 0xb3, 0xda, 0x97, 0x43, 0x3c, + 0xe3, 0xab, 0x82, 0xce, 0xf7, 0x60, 0x9b, 0x16, 0xb9, 0x63, 0x67, 0x7a, + 0xc2, 0x7c, 0x20, 0xd8, 0xbe, 0x5f, 0x8d, 0x13, 0x6b, 0x3c, 0xe7, 0x6e, + 0xd7, 0x99, 0x9b, 0xc2, 0x1c, 0x2b, 0x10, 0xcd, 0x53, 0x22, 0xe5, 0xaa, + 0xc8, 0xeb, 0xf8, 0xfd, 0xa6, 0x1a, 0xc6, 0x4f, 0x14, 0xed, 0xee, 0x93, + 0xb2, 0x5e, 0xfa, 0x9a, 0xd4, 0xa0, 0x7f, 0xd6, 0x5c, 0xdf, 0xbf, 0xeb, + 0x26, 0xf5, 0x99, 0xbf, 0xe8, 0x29, 0x19, 0x18, 0xa1, 0x7e, 0x6b, 0x93, + 0x97, 0x17, 0x5b, 0x64, 0xc3, 0xb4, 0xcc, 0xbb, 0x44, 0x01, 0x5e, 0x42, + 0x26, 0x63, 0x11, 0x8d, 0x51, 0xe5, 0x5b, 0x22, 0x5b, 0xf8, 0xb6, 0xb5, + 0xf8, 0x4c, 0x9c, 0xfe, 0x97, 0x4f, 0x16, 0xf9, 0x6e, 0xe0, 0x69, 0x48, + 0xc3, 0x8e, 0x00, 0xcb, 0x42, 0x08, 0x99, 0x3c, 0x77, 0xee, 0xf7, 0xbb, + 0x5c, 0x1b, 0xea, 0x68, 0xcf, 0xb6, 0x49, 0xe1, 0x30, 0x64, 0xa2, 0x1a, + 0xd4, 0x39, 0x47, 0x8d, 0x98, 0x96, 0xd1, 0x91, 0x0a, 0x7d, 0xf8, 0xe6, + 0x5e, 0x2d, 0xaf, 0x33, 0x37, 0x7e, 0xa4, 0xf7, 0x82, 0x72, 0xbe, 0xe2, + 0x92, 0x56, 0x4d, 0x59, 0x03, 0xaf, 0xad, 0xd6, 0x5f, 0xed, 0xe3, 0x5d, + 0xad, 0xd7, 0x5f, 0x88, 0x07, 0xf6, 0x1a, 0xeb, 0x7e, 0x1c, 0x0f, 0xea, + 0x92, 0xa1, 0xfd, 0x45, 0x3b, 0xad, 0x8c, 0xbd, 0xbd, 0x20, 0xf5, 0xa5, + 0x9f, 0xc9, 0x3b, 0xa5, 0x9f, 0xc8, 0xaf, 0x97, 0xce, 0x00, 0x7f, 0x58, + 0xe5, 0x3c, 0xf4, 0xc9, 0xcd, 0xba, 0xef, 0xdf, 0x74, 0xa7, 0x60, 0x2b, + 0xf8, 0xfe, 0xef, 0xdc, 0x0d, 0x19, 0x38, 0xf6, 0x3d, 0xec, 0x39, 0x07, + 0x1e, 0xa2, 0x2c, 0x9c, 0x04, 0xbd, 0xb9, 0x7d, 0xd2, 0x19, 0xd5, 0x74, + 0x32, 0x78, 0xac, 0x15, 0x7b, 0x30, 0x42, 0x4c, 0xce, 0xbd, 0x8c, 0xf4, + 0x91, 0x66, 0x8c, 0x7a, 0x09, 0xf3, 0xb7, 0x82, 0x2f, 0xf6, 0xe2, 0xa7, + 0xe4, 0xee, 0x08, 0xd6, 0x3a, 0x42, 0xda, 0x6b, 0x95, 0x81, 0x47, 0xb1, + 0x8f, 0x5c, 0x8b, 0xdc, 0xf3, 0x7e, 0x19, 0xa7, 0x6f, 0xef, 0x9e, 0xc7, + 0xb2, 0xf1, 0x95, 0x2e, 0xf1, 0xa5, 0x05, 0xba, 0x7c, 0xfe, 0x78, 0x80, + 0x9b, 0xde, 0x55, 0x43, 0x68, 0x6f, 0xe7, 0xdf, 0x53, 0xc4, 0x79, 0x79, + 0xbf, 0x15, 0xb8, 0x7c, 0x1c, 0x78, 0x28, 0x53, 0xbf, 0x20, 0x8d, 0x91, + 0x28, 0xda, 0x10, 0xaf, 0x68, 0x59, 0x22, 0x59, 0x8f, 0x39, 0x5a, 0xcc, + 0x97, 0xc2, 0x1a, 0xa7, 0x74, 0x2e, 0x57, 0x1f, 0xcf, 0x9c, 0x58, 0x3e, + 0xa8, 0xb3, 0x41, 0x23, 0xac, 0x23, 0x7d, 0xa7, 0x35, 0xa6, 0x82, 0x0e, + 0xc5, 0x78, 0xc3, 0x92, 0xd1, 0xe5, 0x2e, 0x8c, 0x77, 0x41, 0x32, 0x6e, + 0x73, 0xcc, 0x51, 0xb4, 0xa1, 0x9c, 0x19, 0x05, 0x96, 0xf8, 0x58, 0x8d, + 0x2d, 0xc6, 0xa0, 0xcb, 0xe3, 0x32, 0x66, 0xee, 0xd9, 0xb1, 0xc7, 0xbc, + 0xb6, 0x15, 0x0c, 0x63, 0x38, 0x5c, 0x53, 0xd7, 0x8e, 0x35, 0xb1, 0x3f, + 0x7e, 0xb0, 0x93, 0x33, 0x8b, 0x0b, 0x90, 0x53, 0x0b, 0x1f, 0x66, 0xdc, + 0x67, 0x25, 0x1b, 0x6b, 0xd3, 0xb6, 0x4d, 0x05, 0xf7, 0x92, 0xf5, 0xe8, + 0xd3, 0xfa, 0x0e, 0xe4, 0xd0, 0x9e, 0xb0, 0x8e, 0x6d, 0xc5, 0xc8, 0xe0, + 0xec, 0x03, 0x1b, 0x97, 0x75, 0x5f, 0x96, 0xcc, 0x42, 0x4e, 0x26, 0x74, + 0x3f, 0x9e, 0xe1, 0x41, 0x8d, 0x43, 0xc8, 0xab, 0x03, 0xbd, 0x38, 0xcb, + 0xd4, 0x03, 0x7b, 0x38, 0xd9, 0x4b, 0x2e, 0xfa, 0x4f, 0xc8, 0xb3, 0xf8, + 0xd6, 0xcb, 0x3b, 0x6a, 0x93, 0x81, 0x67, 0xa0, 0x2f, 0xbd, 0x66, 0x7d, + 0x54, 0x3e, 0xf3, 0xfc, 0x38, 0x63, 0x2e, 0x7f, 0xf6, 0x4c, 0xf9, 0xc4, + 0xd3, 0xb1, 0xd8, 0xe9, 0x88, 0x58, 0xe7, 0x03, 0x5b, 0xfd, 0xf0, 0xf4, + 0xbc, 0xe2, 0xf7, 0xc3, 0xe7, 0x57, 0x54, 0x07, 0xda, 0x46, 0xd1, 0x8e, + 0xeb, 0x30, 0x65, 0xdc, 0xfb, 0xab, 0x3f, 0x73, 0xc4, 0xf7, 0x27, 0x74, + 0x4e, 0x58, 0xca, 0x9c, 0x57, 0x4d, 0x7c, 0xee, 0x88, 0x17, 0x6b, 0xc7, + 0x5c, 0x29, 0x73, 0x45, 0x1d, 0xc6, 0x7a, 0x58, 0xee, 0x25, 0x4f, 0x24, + 0x36, 0x84, 0xe3, 0x5b, 0x93, 0xcb, 0x2a, 0x95, 0x1c, 0x54, 0x56, 0xba, + 0x80, 0x5f, 0x8b, 0xd2, 0x71, 0xcc, 0x44, 0x52, 0x81, 0x77, 0xb1, 0x27, + 0xfb, 0xa8, 0xef, 0x4f, 0xda, 0xac, 0x4f, 0x99, 0x51, 0x45, 0xdf, 0x4b, + 0xa7, 0x8e, 0x77, 0x5e, 0x3e, 0x90, 0x32, 0x8f, 0xaa, 0xfd, 0xe1, 0xfb, + 0x28, 0x64, 0xe6, 0xf6, 0x78, 0x67, 0x96, 0x95, 0x29, 0x2f, 0x79, 0xa9, + 0xe4, 0xac, 0xb2, 0x72, 0x18, 0x33, 0x37, 0xa6, 0x28, 0x37, 0x52, 0x66, + 0xa7, 0xa2, 0x7f, 0xb4, 0x5d, 0xef, 0x7b, 0x12, 0xfd, 0x53, 0xaa, 0x25, + 0x5c, 0x0f, 0xef, 0xeb, 0x4a, 0x5f, 0xc0, 0x33, 0x94, 0x39, 0xfd, 0xc6, + 0xcc, 0x02, 0xf3, 0xcb, 0x74, 0x5e, 0x43, 0x7a, 0xe0, 0x18, 0xdf, 0x0d, + 0xb9, 0x7f, 0xe2, 0x6f, 0xa8, 0x43, 0xb9, 0xcc, 0x3a, 0x27, 0xe4, 0xb7, + 0x23, 0x1a, 0x3f, 0xdf, 0x3f, 0x91, 0xd7, 0xb9, 0x8b, 0x0d, 0x35, 0x10, + 0xee, 0x7b, 0xfb, 0xce, 0x92, 0x19, 0xf7, 0x4b, 0x1c, 0x67, 0x21, 0x72, + 0xb2, 0x5d, 0x98, 0x23, 0x3a, 0x5e, 0x6a, 0xd2, 0x06, 0x7d, 0x03, 0xcc, + 0x15, 0x68, 0xc6, 0xdd, 0x2f, 0x88, 0x71, 0xac, 0x63, 0x07, 0x9d, 0x00, + 0x77, 0x02, 0xaf, 0x56, 0x31, 0x4e, 0x61, 0x51, 0xf2, 0x41, 0x7f, 0xe9, + 0x60, 0x4e, 0x6a, 0xa1, 0xfa, 0x45, 0x63, 0x04, 0x3a, 0x70, 0x1c, 0xef, + 0xf7, 0x4f, 0x90, 0x3e, 0x79, 0x36, 0x49, 0x35, 0xbe, 0xc4, 0xf5, 0x1c, + 0x94, 0x89, 0x45, 0x60, 0x23, 0xfc, 0xe6, 0x17, 0x83, 0x7b, 0xbb, 0x0e, + 0x9c, 0x3d, 0xe1, 0x99, 0x9a, 0x5f, 0x67, 0x5d, 0xc6, 0x4f, 0xc0, 0x2b, + 0x3a, 0x8f, 0x8a, 0x7d, 0x99, 0x4b, 0x78, 0x88, 0xfa, 0xd1, 0x6d, 0x48, + 0x0c, 0x6d, 0x89, 0x59, 0x59, 0x6f, 0x8d, 0x26, 0x23, 0xdd, 0x32, 0x0f, + 0x79, 0x57, 0x81, 0xee, 0x2c, 0x5c, 0x89, 0xca, 0xac, 0xa7, 0xe3, 0xd9, + 0xc9, 0x8f, 0x95, 0x2b, 0xb5, 0xfa, 0x71, 0xb9, 0x51, 0x77, 0xf4, 0x37, + 0xea, 0xb5, 0xc2, 0xab, 0x86, 0x7c, 0xff, 0x88, 0xce, 0xa5, 0x73, 0x2a, + 0xd2, 0xd9, 0x4f, 0xcc, 0xb3, 0xa2, 0xf3, 0xea, 0x20, 0x3b, 0x80, 0x39, + 0xde, 0x06, 0xe6, 0x78, 0x0b, 0x98, 0xe3, 0x57, 0xc0, 0xd8, 0x37, 0x4b, + 0x93, 0xa1, 0xfc, 0x9f, 0x86, 0x1c, 0xa2, 0xae, 0xb6, 0xce, 0xe0, 0x4e, + 0xa7, 0xf3, 0xa0, 0xc1, 0xdb, 0xb0, 0x3f, 0xd6, 0x4b, 0x19, 0x59, 0x5d, + 0x9a, 0x90, 0xb5, 0xa5, 0x20, 0x0f, 0xf9, 0x03, 0xe6, 0x7d, 0x8d, 0xf0, + 0x9e, 0x1c, 0xc8, 0xa1, 0x3d, 0x32, 0x70, 0x94, 0xf2, 0xa3, 0x43, 0x96, + 0x8b, 0xab, 0x5a, 0x0e, 0x2d, 0x17, 0x59, 0x8e, 0x88, 0xce, 0x21, 0x9b, + 0xda, 0x90, 0x8a, 0x5b, 0x47, 0xfd, 0x3e, 0xed, 0x0f, 0x0a, 0xfc, 0xf3, + 0x94, 0x97, 0x7f, 0x0a, 0xef, 0x5e, 0xe9, 0xdc, 0xba, 0x19, 0xb3, 0x1b, + 0xed, 0x9a, 0xb2, 0x6b, 0x30, 0x88, 0xb9, 0xab, 0xdb, 0x68, 0x83, 0x39, + 0x80, 0x19, 0xaf, 0x43, 0x87, 0x34, 0x9c, 0x6e, 0x8d, 0xfd, 0x1a, 0xce, + 0x21, 0x9d, 0x77, 0xcb, 0x71, 0x0a, 0x45, 0x5b, 0xe6, 0x8a, 0x56, 0x32, + 0x0f, 0xfa, 0xbb, 0x01, 0xbb, 0x6d, 0x15, 0x77, 0xb0, 0x86, 0x33, 0x58, + 0xaf, 0x53, 0xcf, 0x6f, 0x6a, 0xd9, 0xbb, 0x5c, 0xff, 0x23, 0xc6, 0xb1, + 0xce, 0xa4, 0xe5, 0x0f, 0x7d, 0x94, 0x81, 0xf4, 0x4d, 0x65, 0x75, 0xff, + 0xa0, 0xdf, 0x2a, 0xda, 0xae, 0xd5, 0x29, 0x8f, 0x45, 0x2e, 0x79, 0x36, + 0x74, 0xc9, 0xcb, 0x09, 0x62, 0x80, 0xb2, 0x6a, 0xf6, 0xf3, 0xc3, 0x35, + 0xfb, 0xfe, 0x5e, 0x9b, 0xeb, 0x72, 0x42, 0xb9, 0x4d, 0xdd, 0xbf, 0xa1, + 0xb1, 0x8d, 0x57, 0x7a, 0x56, 0xde, 0xc4, 0x7d, 0x07, 0x18, 0x27, 0x27, + 0x6f, 0x00, 0xe3, 0xd5, 0x4b, 0xcd, 0xbc, 0xed, 0x93, 0x38, 0xa7, 0x92, + 0x9a, 0xbb, 0xda, 0x29, 0x97, 0xaf, 0x15, 0xd4, 0x4b, 0xd7, 0x3c, 0xf5, + 0xf3, 0xab, 0x45, 0x55, 0xb8, 0xea, 0xfb, 0xff, 0x70, 0x67, 0xe4, 0x9d, + 0x25, 0x5f, 0x4e, 0xbb, 0x46, 0x7f, 0x44, 0x9a, 0xf9, 0x74, 0xbe, 0xdf, + 0x01, 0xd9, 0xbc, 0x7e, 0xc0, 0xf7, 0x1f, 0x19, 0x19, 0x11, 0xe7, 0x00, + 0x31, 0xca, 0x70, 0x82, 0x39, 0xae, 0x94, 0x39, 0x19, 0xdb, 0x3e, 0x5f, + 0x51, 0x0a, 0xf2, 0xad, 0x3b, 0xc0, 0x2f, 0x8f, 0xee, 0x0b, 0xe3, 0x26, + 0x3f, 0x7c, 0x9e, 0x7e, 0xe5, 0xc4, 0xe7, 0xfc, 0xca, 0xa6, 0x9c, 0x2d, + 0xf6, 0xa2, 0x7f, 0x4c, 0x7e, 0x50, 0x8c, 0xee, 0x2a, 0x9b, 0x78, 0x3a, + 0x46, 0xa1, 0x78, 0xcf, 0x1f, 0xd4, 0xf1, 0x03, 0x60, 0x12, 0xd3, 0xf7, + 0x67, 0x5d, 0xce, 0xd7, 0x8d, 0xf9, 0x36, 0xcc, 0x7d, 0xd0, 0xff, 0xa7, + 0xb5, 0x7e, 0x2e, 0x2b, 0xd8, 0xc1, 0xe0, 0xef, 0x98, 0x8c, 0x15, 0xa1, + 0xe3, 0x15, 0xf3, 0x4c, 0x89, 0x15, 0xac, 0xc4, 0x2c, 0x64, 0xc7, 0x0c, + 0xe4, 0xcd, 0x29, 0x1d, 0x67, 0xed, 0xd5, 0xb2, 0x67, 0x8e, 0xe5, 0x9c, + 0xa4, 0x2b, 0x6e, 0x8f, 0x3e, 0xbf, 0xcd, 0x1b, 0x2f, 0x26, 0x82, 0x3b, + 0x07, 0x1f, 0xe7, 0x94, 0xb4, 0xc1, 0x1e, 0xca, 0xae, 0x4c, 0x81, 0x27, + 0x12, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xe8, 0xef, 0x86, 0xf6, 0x29, + 0x06, 0xb1, 0x8b, 0x86, 0xc9, 0x76, 0xa7, 0xd0, 0xaf, 0x5d, 0x32, 0x57, + 0xdb, 0xb4, 0x5c, 0x7d, 0xb8, 0x2e, 0x0d, 0x1c, 0xf2, 0x04, 0xca, 0x11, + 0xd4, 0x25, 0xc3, 0xb2, 0x81, 0xf2, 0x34, 0xca, 0x2d, 0x78, 0xb2, 0xcd, + 0x61, 0xe0, 0x0a, 0x3c, 0x5f, 0xc3, 0x78, 0x23, 0x58, 0x73, 0xce, 0x94, + 0x8f, 0x4e, 0x50, 0x97, 0x38, 0x06, 0x73, 0x91, 0x67, 0x6d, 0x3c, 0x6b, + 0x45, 0x95, 0x5d, 0x60, 0x19, 0xcf, 0x72, 0xf0, 0xfd, 0x21, 0x99, 0x84, + 0x3e, 0x99, 0x6b, 0x81, 0x4c, 0xfa, 0x68, 0x5b, 0x26, 0xb1, 0xae, 0x5d, + 0xc6, 0xae, 0x92, 0xd7, 0x4d, 0xd0, 0x5b, 0xa7, 0x64, 0xaf, 0xc5, 0x34, + 0x1e, 0xad, 0x80, 0x16, 0xaf, 0x83, 0xae, 0x96, 0x41, 0x53, 0x99, 0xa2, + 0x35, 0x3a, 0xad, 0x92, 0xda, 0x2f, 0xf0, 0x38, 0xe8, 0xb5, 0xe3, 0x0a, + 0xb1, 0x28, 0x79, 0xd9, 0x01, 0xed, 0x89, 0xdf, 0x61, 0xdb, 0x93, 0x8e, + 0xb2, 0x41, 0x83, 0xa0, 0xcb, 0x62, 0xc0, 0xd3, 0xef, 0x29, 0x2d, 0x57, + 0x47, 0xef, 0x48, 0x2a, 0x7d, 0x47, 0x2c, 0xc8, 0x02, 0xcb, 0xfd, 0x50, + 0x5c, 0x8c, 0x79, 0x5c, 0x5e, 0xc7, 0x3c, 0x06, 0xf8, 0xfb, 0xc8, 0x90, + 0xe6, 0xef, 0x51, 0x89, 0xec, 0xe6, 0x71, 0xd0, 0x1b, 0x64, 0x50, 0xc0, + 0xd3, 0xe9, 0x90, 0x46, 0x9f, 0x06, 0xff, 0x5a, 0xb0, 0xca, 0x92, 0x32, + 0x0f, 0xfe, 0xbf, 0x8e, 0xef, 0xb7, 0xea, 0x9f, 0xaa, 0xb9, 0x05, 0x15, + 0xe6, 0xb2, 0x7c, 0x1b, 0x38, 0xf9, 0xf7, 0x38, 0xbb, 0x2e, 0x8d, 0xdd, + 0x07, 0x46, 0x18, 0x4b, 0xfb, 0xb7, 0xba, 0x6c, 0x1f, 0x95, 0xcd, 0xe1, + 0xe3, 0x28, 0xef, 0xc3, 0xd3, 0xc0, 0x39, 0x44, 0x75, 0x2c, 0x7c, 0xd9, + 0x1b, 0x36, 0x0a, 0x3a, 0xef, 0xe0, 0x98, 0xce, 0xcf, 0x37, 0xec, 0x03, + 0xf8, 0x4e, 0xbf, 0x0c, 0xf7, 0x06, 0xcc, 0xa4, 0x12, 0x3a, 0xc7, 0xb4, + 0x02, 0x2c, 0xb1, 0x82, 0xf1, 0xde, 0xa7, 0x5f, 0xaf, 0x06, 0x1e, 0x1e, + 0xfe, 0xa7, 0x9f, 0x8e, 0x31, 0x27, 0x7d, 0x33, 0x11, 0xe8, 0xbf, 0xcf, + 0xfc, 0x4d, 0x7b, 0x6e, 0xd4, 0xc0, 0xcb, 0x6d, 0x33, 0x86, 0xb6, 0xd0, + 0x65, 0xd0, 0x45, 0x65, 0x4d, 0xbf, 0x6c, 0x17, 0xf4, 0x2d, 0xd4, 0x52, + 0xe6, 0x07, 0x12, 0xf4, 0x9d, 0xb7, 0xa9, 0x77, 0xda, 0x21, 0x5f, 0x92, + 0x1a, 0x57, 0xbe, 0x6f, 0xe7, 0x21, 0x15, 0xac, 0xe4, 0x24, 0x68, 0xb4, + 0x4d, 0x2c, 0x67, 0x5c, 0x1e, 0xcc, 0x3b, 0xab, 0xfb, 0xb2, 0x6d, 0xb3, + 0x6f, 0x73, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0xa7, 0x36, 0x35, + 0x8d, 0x36, 0x6a, 0xed, 0xfd, 0x01, 0x8d, 0x36, 0xf7, 0x11, 0xfb, 0x3f, + 0xfb, 0x20, 0x9d, 0x0c, 0x1b, 0x41, 0x0e, 0x06, 0x9e, 0x35, 0x9e, 0xe7, + 0xa7, 0xc0, 0xf7, 0x3b, 0xe9, 0xa7, 0xe9, 0x67, 0x0c, 0xe8, 0xe7, 0x91, + 0x6d, 0xfa, 0x21, 0xdd, 0x74, 0xca, 0xd8, 0x35, 0x5b, 0x26, 0x8a, 0xfa, + 0xbe, 0x81, 0x35, 0xe9, 0x3f, 0x3a, 0x0e, 0xba, 0x21, 0xad, 0x93, 0xb7, + 0x4c, 0x29, 0x83, 0x8e, 0xca, 0x90, 0x4f, 0x65, 0xd0, 0x14, 0x31, 0x50, + 0x19, 0xf2, 0xad, 0x5c, 0xb7, 0x9c, 0x2a, 0xf6, 0x4c, 0x9d, 0xbd, 0x02, + 0x3a, 0xba, 0x5e, 0xe7, 0xfd, 0xeb, 0x35, 0x9b, 0xd4, 0x83, 0xb7, 0xb6, + 0xef, 0xfe, 0xef, 0xb8, 0xfb, 0x43, 0x72, 0x03, 0x76, 0xcb, 0x9b, 0xa5, + 0x61, 0xc8, 0x24, 0x21, 0x5e, 0x04, 0x6d, 0x8c, 0xca, 0x6a, 0xe9, 0xa4, + 0xac, 0x41, 0x3f, 0xad, 0x2f, 0x0d, 0x00, 0x4f, 0x43, 0x8e, 0xbe, 0x72, + 0x44, 0xde, 0x58, 0x52, 0x32, 0x63, 0x43, 0xbf, 0x2c, 0xd3, 0x07, 0x0f, + 0x7a, 0x2e, 0x77, 0xea, 0x98, 0xfd, 0x58, 0x35, 0xf0, 0xc5, 0x8f, 0x57, + 0xbb, 0x64, 0xa2, 0x6a, 0xca, 0x63, 0xd5, 0x1e, 0x79, 0xa2, 0x1a, 0x93, + 0xd3, 0xb5, 0x84, 0x7c, 0xa3, 0x7a, 0x50, 0x4e, 0x55, 0x0f, 0xc9, 0x93, + 0xb5, 0xa4, 0x7c, 0x13, 0x76, 0x61, 0xae, 0xe6, 0xc8, 0x64, 0x6d, 0x58, + 0x1e, 0xaf, 0xd1, 0xc7, 0x8e, 0xf9, 0xf0, 0xcb, 0x6e, 0xfb, 0x2e, 0xb8, + 0xae, 0x0e, 0xac, 0xcb, 0x51, 0xe3, 0x3a, 0x66, 0x29, 0xb9, 0xc0, 0xff, + 0x21, 0x72, 0x0e, 0x7d, 0x2f, 0xbe, 0xa2, 0xa4, 0xa2, 0xe7, 0x6f, 0xfe, + 0xdf, 0x48, 0x54, 0xdb, 0x46, 0xe7, 0xca, 0x07, 0xd1, 0xc6, 0xa6, 0x4d, + 0x12, 0xfa, 0x41, 0x9a, 0xfe, 0xff, 0xa6, 0xed, 0x65, 0x68, 0x1f, 0xf6, + 0x2d, 0xda, 0x5e, 0xfa, 0xec, 0x29, 0x3f, 0x68, 0xe7, 0xd0, 0xd6, 0xda, + 0x19, 0xe7, 0x68, 0xce, 0x7b, 0x31, 0xf7, 0xf0, 0xff, 0xa7, 0x04, 0xf1, + 0xaa, 0xb3, 0xb5, 0x83, 0xfc, 0x3f, 0x15, 0xac, 0xe5, 0x8b, 0xf3, 0xc5, + 0x27, 0x4a, 0x63, 0xea, 0xb1, 0x12, 0x11, 0x8d, 0x2f, 0x17, 0xb7, 0x73, + 0xf2, 0xbe, 0x2e, 0xcb, 0x6e, 0x54, 0xaf, 0x21, 0xf0, 0xdb, 0xa7, 0x75, + 0x7e, 0xde, 0xd8, 0x10, 0xe9, 0x8f, 0x71, 0xb8, 0xae, 0x30, 0xb6, 0x00, + 0x6c, 0xeb, 0x9a, 0x72, 0xa9, 0x1a, 0xf8, 0xaf, 0xe6, 0x34, 0xbd, 0xbc, + 0x05, 0x9a, 0x63, 0xfc, 0x21, 0x78, 0xe6, 0xcb, 0x41, 0xdf, 0xec, 0x90, + 0x43, 0x7b, 0x1c, 0xfb, 0x35, 0x7a, 0x38, 0x17, 0xff, 0x4f, 0x07, 0xe5, + 0x70, 0xbd, 0xcc, 0x2f, 0xb6, 0x35, 0x2d, 0x06, 0x31, 0x5e, 0x47, 0x9e, + 0xc3, 0x5d, 0x54, 0x4c, 0xae, 0xbf, 0x43, 0x2a, 0x0e, 0x6d, 0x5b, 0xca, + 0xef, 0x21, 0x29, 0x63, 0x9e, 0x8a, 0xd3, 0xf4, 0x8d, 0x05, 0x72, 0xb6, + 0x62, 0x3e, 0x98, 0x77, 0xba, 0xbc, 0x1f, 0xef, 0xa8, 0x73, 0x80, 0x99, + 0xa6, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0xe6, 0xf0, 0x4c, 0x84, 0x75, + 0xaf, 0xf5, 0x6b, 0xac, 0x7e, 0xf2, 0x41, 0xbf, 0x99, 0xb2, 0x95, 0xcf, + 0x44, 0xb6, 0x94, 0xf1, 0x8b, 0xf5, 0x7e, 0xca, 0xdc, 0xfd, 0x36, 0x7f, + 0x51, 0xf9, 0x8b, 0xa9, 0x7d, 0x0a, 0xe1, 0xb7, 0x3d, 0xf2, 0x94, 0xc9, + 0xdc, 0xf5, 0xb4, 0x1a, 0x2b, 0xfd, 0x34, 0xcc, 0xd3, 0xdd, 0x52, 0xfb, + 0x2b, 0x6f, 0xf7, 0x07, 0x79, 0xee, 0x1c, 0x7b, 0x67, 0x6e, 0xfb, 0x4e, + 0x3a, 0x61, 0x8e, 0x7b, 0x3b, 0x70, 0xab, 0x56, 0x62, 0xe0, 0x41, 0xc8, + 0x3b, 0xbb, 0x45, 0xf3, 0x63, 0xa1, 0xf6, 0x2f, 0x7f, 0x43, 0xf3, 0x73, + 0xd3, 0xc7, 0xf0, 0xdb, 0x7e, 0xda, 0xb6, 0x94, 0x1b, 0x97, 0x02, 0xbf, + 0x91, 0xb6, 0xa1, 0x21, 0x2b, 0x50, 0x47, 0x5e, 0x05, 0x9f, 0x6c, 0xb7, + 0xe5, 0xdf, 0x7f, 0x01, 0x99, 0xe7, 0xd3, 0x46, 0x40, 0x67, 0x00, 0x00, + 0x00 }; +static u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = { + 0x08003fa4, 0x08003ea4, 0x08003f48, 0x08003f60, 0x08003f78, 0x08003f98, + 0x08003fa4, 0x08003fa4, 0x08003eac, 0x00000000, 0x080049d4, 0x08004a0c, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004a44, 0x08004c08, + 0x08004b50, 0x08004b88, 0x08004c08, 0x08004ad8, 0x08004c08, 0x08004c08, + 0x08004b88, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004bc8, + 0x08004c08, 0x08004bc8, 0x08004b50, 0x08004c08, 0x08004c08, 0x08004bc8, + 0x08004bc8, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, + 0x08004ab4, 0x00000000, 0x0800602c, 0x08006044, 0x08006044, 0x08006044, + 0x0800602c, 0x08006044, 0x08006044, 0x08006044, 0x0800602c, 0x08006044, + 0x08006044, 0x08006044, 0x0800602c, 0x08006044, 0x08006044, 0x08006044, + 0x08006038, 0x00000000, 0x00000000 }; +static u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 }; +static u32 bnx2_RXP_b09FwSbss[(0x2c/4) + 1] = { 0x0 }; static struct fw_info bnx2_rxp_fw_09 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, .start_addr = 0x08003184, .text_addr = 0x08000000, - .text_len = 0x6768, + .text_len = 0x673c, .text_index = 0x0, .gz_text = bnx2_RXP_b09FwText, .gz_text_len = sizeof(bnx2_RXP_b09FwText), - .data_addr = 0x08006a00, + .data_addr = 0x080069e0, .data_len = 0x0, .data_index = 0x0, .data = bnx2_RXP_b09FwData, - .sbss_addr = 0x08006a00, - .sbss_len = 0x20, + .sbss_addr = 0x080069e0, + .sbss_len = 0x2c, .sbss_index = 0x0, .sbss = bnx2_RXP_b09FwSbss, - .bss_addr = 0x08006a20, + .bss_addr = 0x08006a10, .bss_len = 0x13dc, .bss_index = 0x0, .bss = bnx2_RXP_b09FwBss, - .rodata_addr = 0x08006768, + .rodata_addr = 0x08006740, .rodata_len = 0x278, .rodata_index = 0x0, .rodata = bnx2_RXP_b09FwRodata, }; static u8 bnx2_TPAT_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58, - 0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb, - 0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13, - 0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c, - 0x28, 0xc5, 0x90, 0x87, 0x52, 0x50, 0x57, 0x32, 0x09, 0x79, 0x69, 0xda, - 0xc6, 0x90, 0x3e, 0x79, 0x3b, 0x2b, 0xc7, 0x0e, 0x6c, 0xbc, 0x8d, 0x52, - 0xe4, 0x52, 0xfa, 0x60, 0xd6, 0xb1, 0x05, 0xcd, 0x46, 0x93, 0xd4, 0x7e, - 0x35, 0x36, 0x4e, 0x93, 0xa7, 0x42, 0x9f, 0x52, 0xf4, 0x18, 0xd2, 0x12, - 0xda, 0x52, 0x8a, 0x69, 0xa1, 0x09, 0x8d, 0xeb, 0xdb, 0xef, 0xdc, 0x99, - 0x91, 0x57, 0xb6, 0xec, 0xa4, 0x25, 0x85, 0x0a, 0x56, 0x77, 0xe6, 0xce, - 0x3d, 0xe7, 0x9e, 0x7b, 0xee, 0x77, 0xbe, 0x73, 0xee, 0x2d, 0xeb, 0x34, - 0x48, 0xd9, 0xdf, 0x30, 0x7e, 0x2f, 0x7e, 0xf7, 0x85, 0x17, 0xab, 0x8f, - 0x3c, 0xea, 0x10, 0x3d, 0xfa, 0x88, 0x66, 0x98, 0x06, 0x7d, 0x09, 0x7f, - 0x50, 0x22, 0x72, 0xfd, 0xfc, 0x23, 0x5b, 0xaf, 0x9d, 0x72, 0x42, 0x8f, - 0x6c, 0xa3, 0x26, 0xbe, 0xbe, 0xe4, 0x11, 0x05, 0xbd, 0x69, 0xa7, 0x4e, - 0xff, 0x92, 0xcd, 0x92, 0x49, 0xdc, 0xff, 0x50, 0xed, 0xc6, 0xfe, 0xcb, - 0x07, 0xdd, 0xeb, 0x67, 0x0d, 0xb2, 0x45, 0x6d, 0xd1, 0x16, 0x93, 0x64, - 0x8f, 0xd5, 0x9a, 0xce, 0x2f, 0xf6, 0x1e, 0x28, 0xd0, 0xae, 0x5c, 0x97, - 0xa0, 0xb8, 0x43, 0x4d, 0xab, 0x66, 0x53, 0xd4, 0x7e, 0x49, 0x0b, 0x3b, - 0x9e, 0x98, 0x85, 0x8e, 0xa0, 0x04, 0xfd, 0x1e, 0xde, 0x13, 0x53, 0x8b, - 0xce, 0xd8, 0xa4, 0xd7, 0x02, 0x3c, 0x4f, 0x51, 0xab, 0x23, 0xe5, 0x2b, - 0xbe, 0x46, 0x4b, 0xbe, 0x4d, 0x8b, 0xc2, 0x0d, 0x1c, 0xed, 0xa6, 0xac, - 0x4c, 0x48, 0xf9, 0x9c, 0xaf, 0x93, 0xee, 0xcd, 0x69, 0xe1, 0xfa, 0xbc, - 0x56, 0x5f, 0x9f, 0x67, 0x7f, 0xc0, 0xbe, 0x39, 0x2d, 0x58, 0xe7, 0xb6, - 0x66, 0xd7, 0xdb, 0xbb, 0x68, 0xb1, 0x44, 0x23, 0xba, 0x37, 0x85, 0xf9, - 0x4a, 0xd0, 0xe3, 0x50, 0xe8, 0x4f, 0x0b, 0x9d, 0x2a, 0xf8, 0x0d, 0xd0, - 0xac, 0x4f, 0x03, 0xba, 0xa7, 0x53, 0xa3, 0xa4, 0xd1, 0x1b, 0x55, 0x0b, - 0xbf, 0xc3, 0x5a, 0xb4, 0xfe, 0x7c, 0xa6, 0x87, 0xc7, 0xdb, 0xf8, 0xc6, - 0x36, 0xb3, 0x7c, 0xbf, 0xec, 0x30, 0x9e, 0x9f, 0xc3, 0x38, 0x8b, 0xc2, - 0xea, 0xed, 0xdf, 0x06, 0xf0, 0xac, 0xa1, 0xff, 0x30, 0xec, 0x62, 0x3d, - 0x0e, 0xec, 0x28, 0xd3, 0x4a, 0x67, 0x1e, 0xeb, 0x29, 0x50, 0x53, 0x4c, - 0x4c, 0x35, 0xc8, 0x84, 0x8c, 0x41, 0x41, 0xe9, 0x8a, 0xd4, 0x6b, 0x52, - 0x86, 0x55, 0x6f, 0xaa, 0xab, 0xe6, 0xd0, 0xc9, 0xf0, 0x0a, 0x14, 0xf9, - 0xc3, 0xd4, 0x12, 0x06, 0xc5, 0xfb, 0x2c, 0x0a, 0x16, 0x4c, 0xac, 0x71, - 0x14, 0x72, 0x1a, 0xe4, 0x5f, 0xcb, 0xf6, 0xbc, 0x48, 0xb1, 0x28, 0xa0, - 0x7f, 0x84, 0xe2, 0xd2, 0x6e, 0x4d, 0xaf, 0xbd, 0x82, 0xfe, 0x09, 0xd1, - 0xa5, 0x53, 0x68, 0x35, 0xbc, 0xef, 0xc6, 0x58, 0x7e, 0xd7, 0xa0, 0x8f, - 0x44, 0x98, 0x78, 0xd4, 0x4a, 0x72, 0x59, 0xee, 0x4f, 0xfb, 0x9a, 0xc9, - 0xed, 0xfb, 0xed, 0xc1, 0x4e, 0x41, 0x27, 0x3a, 0xb3, 0x98, 0x8f, 0x9a, - 0x46, 0x0d, 0xe3, 0xb0, 0x37, 0xbc, 0xbf, 0x81, 0xc2, 0xc1, 0xe3, 0xdc, - 0xcf, 0x7f, 0xe8, 0x77, 0xc8, 0xa8, 0xf1, 0xb7, 0x6f, 0x52, 0xfa, 0x2d, - 0xb5, 0x3f, 0xf4, 0x1f, 0xcb, 0xde, 0x4b, 0x22, 0x3c, 0xf3, 0x28, 0xd6, - 0xa8, 0x60, 0x83, 0xe7, 0x02, 0xf0, 0x11, 0xcf, 0xe8, 0xd4, 0x2c, 0x17, - 0xc9, 0xf5, 0x8f, 0xa2, 0xf7, 0xd7, 0x6d, 0x83, 0xea, 0xec, 0x2b, 0xdf, - 0xcc, 0x64, 0x18, 0x1b, 0x1f, 0x64, 0x76, 0x0a, 0x5a, 0x3c, 0x22, 0xe5, - 0x8a, 0x2f, 0xa5, 0x55, 0xf3, 0x9c, 0x13, 0x34, 0x5d, 0x36, 0x69, 0x52, - 0xa0, 0x85, 0x8f, 0xbd, 0x72, 0x83, 0x2c, 0x60, 0xa1, 0x1f, 0xff, 0xfc, - 0xf7, 0xa6, 0x86, 0x25, 0xd0, 0xb5, 0x36, 0xeb, 0x98, 0x70, 0x66, 0x95, - 0x8c, 0x94, 0xf1, 0xcc, 0xbd, 0x64, 0x2e, 0x65, 0x32, 0x52, 0x46, 0x55, - 0x81, 0x3d, 0x6f, 0x0a, 0xd8, 0x87, 0x75, 0x31, 0xc6, 0x89, 0xa2, 0x9e, - 0x6f, 0x37, 0xda, 0xb0, 0xd1, 0x43, 0xdb, 0x13, 0xf0, 0x0f, 0x51, 0x0b, - 0x63, 0xf5, 0xea, 0x7d, 0x8c, 0x0d, 0xec, 0xef, 0x82, 0x1d, 0xb5, 0xdd, - 0xf2, 0x29, 0x5a, 0xb0, 0xeb, 0xbd, 0xe9, 0xf2, 0x32, 0x3d, 0xc4, 0x73, - 0xd8, 0x56, 0xed, 0x88, 0xdd, 0x55, 0x72, 0x88, 0xc4, 0x41, 0x3c, 0xf7, - 0x88, 0xe2, 0x36, 0x69, 0xa1, 0x7f, 0x1f, 0xaf, 0x15, 0x72, 0xf3, 0x99, - 0xdc, 0x7c, 0x26, 0x37, 0x92, 0xc9, 0x3d, 0xd5, 0x27, 0xf7, 0x14, 0xcb, - 0x61, 0x6c, 0x90, 0x8d, 0x0d, 0xb2, 0xb1, 0x66, 0x36, 0x36, 0xca, 0xc6, - 0xa2, 0xed, 0x8d, 0xc1, 0x36, 0x77, 0xca, 0xd1, 0x6c, 0x8a, 0x3d, 0xf9, - 0x70, 0xe8, 0x53, 0x50, 0xf7, 0xdc, 0xcd, 0xba, 0x31, 0x42, 0xe7, 0xfc, - 0x21, 0x5a, 0x49, 0xc6, 0x28, 0x4e, 0x56, 0x28, 0x4c, 0x74, 0xc8, 0x8e, - 0x50, 0xd7, 0xbb, 0x2e, 0x67, 0x7d, 0x1f, 0x7b, 0x66, 0xb3, 0x5c, 0x79, - 0x96, 0x1c, 0x7c, 0x9f, 0x16, 0xcb, 0xe4, 0x03, 0x2b, 0x3a, 0xf6, 0xad, - 0xa2, 0x9e, 0xe3, 0xc4, 0xe7, 0x35, 0x37, 0xf5, 0xaa, 0x2b, 0x62, 0x72, - 0xcb, 0xa1, 0x41, 0x42, 0xaf, 0xc1, 0x4f, 0x49, 0x93, 0xa2, 0xc4, 0xa6, - 0x0f, 0x8d, 0x97, 0x54, 0x8c, 0xc6, 0x9d, 0x4d, 0x79, 0x79, 0xaf, 0x43, - 0x57, 0x30, 0xcf, 0xc5, 0xa4, 0x4c, 0xbf, 0x4a, 0x4a, 0xf4, 0x4e, 0x42, - 0x7a, 0xe8, 0x03, 0xc3, 0x25, 0x41, 0x6f, 0x27, 0xfd, 0x3e, 0xff, 0x88, - 0x7d, 0x6e, 0xdf, 0x5f, 0x23, 0x7b, 0xb4, 0xc6, 0x38, 0x4b, 0x39, 0xa0, - 0x9e, 0x72, 0x80, 0xc2, 0x52, 0xab, 0x13, 0x3f, 0x68, 0x80, 0x7f, 0x96, - 0xfc, 0x60, 0xb7, 0xa1, 0xf6, 0xa3, 0x89, 0x3d, 0xcc, 0x5b, 0xde, 0x9b, - 0xab, 0xce, 0x92, 0xe7, 0x9e, 0xaa, 0x33, 0x6a, 0x4f, 0x5b, 0x39, 0x2e, - 0xfb, 0xe6, 0xf8, 0x33, 0xe6, 0x18, 0xa2, 0x06, 0xe2, 0xec, 0x09, 0x13, - 0xb1, 0xe3, 0xfd, 0xdd, 0x60, 0x5c, 0x39, 0x1b, 0x8c, 0x6f, 0xa2, 0xf1, - 0x0d, 0x9b, 0xd6, 0xdb, 0x45, 0x72, 0xba, 0x43, 0xb4, 0xd4, 0x19, 0xa4, - 0xca, 0x05, 0x13, 0x63, 0xef, 0xa3, 0xca, 0xaa, 0x5e, 0xe2, 0x38, 0xae, - 0xc3, 0xc7, 0xe3, 0x5d, 0x09, 0x7c, 0x0e, 0xd2, 0xf8, 0x9a, 0xab, 0xb0, - 0xb3, 0xe4, 0xb5, 0x7c, 0x83, 0x7e, 0x4c, 0xd7, 0xf6, 0x15, 0xb0, 0xa6, - 0x12, 0xf9, 0x93, 0xfd, 0xf3, 0xe9, 0x80, 0x18, 0xf7, 0xc5, 0x45, 0xda, - 0xe5, 0x3a, 0xa4, 0xb3, 0x3e, 0x9b, 0xc6, 0x2f, 0xd8, 0x5a, 0xbd, 0xc3, - 0x3e, 0x63, 0xfc, 0xd9, 0x19, 0xfe, 0x4c, 0x2d, 0x3c, 0x53, 0xc4, 0x5c, - 0x7f, 0x91, 0xa1, 0x27, 0xb1, 0x0f, 0x3a, 0x2d, 0x55, 0x7f, 0x04, 0xfb, - 0xd0, 0xd7, 0xe5, 0x6f, 0xd7, 0xb3, 0x7e, 0xd6, 0x01, 0x7e, 0xf0, 0xef, - 0xa7, 0x90, 0xb9, 0xe0, 0x08, 0xcb, 0x14, 0x69, 0x7c, 0x95, 0xf9, 0x05, - 0x6d, 0x97, 0xdf, 0x79, 0x6d, 0x03, 0xd4, 0x80, 0x57, 0x1a, 0x53, 0x25, - 0xd8, 0xa5, 0x2b, 0xbe, 0x68, 0x80, 0x3f, 0x74, 0x6f, 0x10, 0x2d, 0xcf, - 0xf7, 0x73, 0x23, 0x8f, 0xa9, 0xb8, 0x33, 0x44, 0x75, 0xe0, 0xd7, 0x84, - 0x3d, 0xcb, 0x34, 0x51, 0x3e, 0xaa, 0xbe, 0xa1, 0xaf, 0xc7, 0xdf, 0xc4, - 0x6d, 0xdf, 0xf0, 0xde, 0xcb, 0x6d, 0x40, 0x6c, 0x7b, 0x2d, 0xcc, 0x62, - 0x65, 0x7e, 0xe1, 0xf1, 0xcd, 0x32, 0xf6, 0x06, 0x7c, 0x46, 0xf0, 0x25, - 0x51, 0xb7, 0x6d, 0x82, 0x6f, 0xf4, 0xaf, 0xea, 0x2c, 0x57, 0x62, 0x3d, - 0x58, 0xff, 0x9a, 0xa9, 0xd5, 0xcf, 0x78, 0xce, 0x1f, 0x88, 0xe5, 0x2b, - 0xf0, 0xc1, 0xc4, 0x4c, 0x8b, 0xc7, 0xf7, 0x2c, 0xf2, 0x56, 0x9b, 0xc2, - 0xc4, 0x9e, 0xc2, 0x73, 0x54, 0xff, 0xc9, 0x08, 0xf6, 0xda, 0x75, 0x5a, - 0xf4, 0x5b, 0xd8, 0x53, 0x20, 0xaf, 0x6b, 0xd2, 0x1b, 0x6d, 0xf6, 0x85, - 0x4d, 0x95, 0x35, 0x29, 0x4f, 0xfa, 0xbc, 0x27, 0xbf, 0x83, 0x5f, 0x08, - 0x2b, 0x9c, 0x98, 0xf9, 0x08, 0xfb, 0xb3, 0xde, 0xe3, 0xbd, 0xb1, 0x94, - 0x4f, 0xbc, 0xd5, 0x29, 0xec, 0xeb, 0x54, 0x66, 0x23, 0xef, 0x97, 0x49, - 0x2b, 0x55, 0x9d, 0xce, 0x57, 0x3f, 0x93, 0xba, 0xc7, 0xfc, 0x5a, 0x80, - 0x6f, 0x31, 0xae, 0x8b, 0x71, 0x49, 0x01, 0x3e, 0xfc, 0x07, 0x78, 0x45, - 0xca, 0xf3, 0x55, 0xf4, 0xaf, 0x1e, 0x87, 0xad, 0x06, 0x64, 0x53, 0x8c, - 0xb1, 0x3d, 0x73, 0xed, 0x7c, 0x7d, 0xde, 0xcc, 0x7b, 0x4a, 0xdf, 0x10, - 0x4d, 0x6e, 0x0c, 0xd1, 0xb3, 0xbd, 0x21, 0x1a, 0x3f, 0xcd, 0x32, 0xe0, - 0xa6, 0xaa, 0x27, 0x22, 0xc6, 0xa8, 0xa7, 0xfc, 0x50, 0x36, 0x74, 0x5e, - 0x27, 0xbe, 0x6f, 0x10, 0x2d, 0xf7, 0x78, 0x0e, 0xb3, 0x4f, 0xa7, 0x4e, - 0x87, 0x7e, 0x4a, 0x74, 0xa8, 0xc7, 0xb2, 0x5b, 0xbe, 0x83, 0x5e, 0x01, - 0x9d, 0x82, 0x38, 0x0f, 0x19, 0x1e, 0xf2, 0xdd, 0x7a, 0x88, 0xfc, 0x15, - 0xe1, 0x37, 0x87, 0x9c, 0xc6, 0xeb, 0x9f, 0x42, 0xfc, 0x31, 0x8f, 0xdf, - 0xc4, 0xda, 0x0b, 0xb4, 0xe2, 0xcf, 0x63, 0x0c, 0xef, 0xf1, 0x61, 0x7c, - 0x1f, 0x46, 0x1e, 0xc8, 0xf2, 0x84, 0xe0, 0x3c, 0xb1, 0x1b, 0x71, 0x30, - 0x00, 0xee, 0xdf, 0x63, 0x6e, 0xcf, 0x13, 0x18, 0x57, 0xda, 0x83, 0xbc, - 0x70, 0x3f, 0xfa, 0x59, 0xd7, 0x28, 0xda, 0x01, 0xbc, 0xef, 0xc1, 0xd8, - 0xfe, 0x1c, 0x91, 0xcb, 0xdd, 0x2d, 0x3f, 0x20, 0x26, 0x56, 0x11, 0x2b, - 0x6b, 0x9c, 0x27, 0x38, 0x16, 0x79, 0x4f, 0x8b, 0xe0, 0x6f, 0x1b, 0x3a, - 0x78, 0x6f, 0x8b, 0xd8, 0x43, 0xce, 0x71, 0x82, 0x2a, 0x1b, 0x3b, 0xe5, - 0x0f, 0x5e, 0x0f, 0x38, 0xec, 0x34, 0xaf, 0xc5, 0x15, 0x0d, 0xf0, 0x59, - 0xb8, 0x31, 0x8d, 0xef, 0xc8, 0x85, 0x22, 0xb2, 0x1b, 0xa7, 0x53, 0x2e, - 0x6b, 0x6c, 0x8c, 0x29, 0x9c, 0xc6, 0x89, 0xc0, 0x3b, 0x73, 0x59, 0xce, - 0x5d, 0x8c, 0x25, 0x0a, 0x20, 0xbb, 0x19, 0x1a, 0x52, 0x2e, 0xf9, 0x23, - 0xd4, 0x00, 0x2e, 0x03, 0xf0, 0x59, 0x03, 0x7c, 0x56, 0xef, 0xe3, 0xb3, - 0xfa, 0xe7, 0xf2, 0x19, 0xb8, 0xaa, 0x03, 0xae, 0xea, 0x80, 0xab, 0x50, - 0x1b, 0xbc, 0x03, 0xec, 0xbf, 0xdd, 0xd9, 0x89, 0xe3, 0x98, 0xdf, 0x98, - 0xe7, 0xa6, 0xe8, 0xf2, 0xde, 0xff, 0x94, 0xe7, 0x8e, 0x83, 0x13, 0x6c, - 0xfa, 0xfe, 0xde, 0x7b, 0x73, 0xdd, 0x09, 0x70, 0x9d, 0xf5, 0xf9, 0x5c, - 0xd7, 0x64, 0xae, 0x33, 0x81, 0xbd, 0x26, 0x78, 0x40, 0x5f, 0xed, 0x9f, - 0xe7, 0x24, 0xe6, 0xe1, 0x3e, 0x33, 0xcb, 0xa5, 0x3a, 0x75, 0x81, 0x7b, - 0xc3, 0xe3, 0x79, 0x60, 0x73, 0x92, 0x72, 0xd1, 0x13, 0x66, 0x89, 0xac, - 0x49, 0xe0, 0x61, 0x75, 0x88, 0x8c, 0xd3, 0xb7, 0xf0, 0x8e, 0x7a, 0x00, - 0x71, 0x8e, 0x7f, 0x1b, 0xb9, 0x8e, 0x41, 0x70, 0x8d, 0x49, 0x85, 0x55, - 0x0b, 0xef, 0xda, 0xb6, 0x71, 0x87, 0x90, 0x6f, 0x8c, 0x9a, 0x3b, 0xf3, - 0x7b, 0x7e, 0xee, 0xf1, 0x98, 0x41, 0xd2, 0xd7, 0x5c, 0xc7, 0xd1, 0x5d, - 0xff, 0x1a, 0xb8, 0xe1, 0x7d, 0x8f, 0xf9, 0x2f, 0x06, 0x0a, 0x0a, 0x64, - 0xae, 0xca, 0xe3, 0x56, 0x8d, 0xe7, 0x6e, 0x3a, 0x88, 0x73, 0xe7, 0x35, - 0xe0, 0x87, 0x73, 0xe7, 0xf9, 0x2a, 0xd7, 0x7b, 0x69, 0x8c, 0xb6, 0x7a, - 0xf9, 0x9c, 0xa3, 0xb0, 0xdb, 0x82, 0x4c, 0xff, 0x58, 0xc6, 0x8b, 0x94, - 0xcf, 0x62, 0x4d, 0x06, 0xe6, 0xb1, 0xd6, 0x6c, 0x2a, 0xac, 0xb1, 0x5f, - 0x5c, 0xc8, 0x57, 0xc4, 0x1c, 0x6d, 0x6e, 0xe3, 0x83, 0x93, 0xbd, 0x0f, - 0x4c, 0xe6, 0x50, 0x03, 0xb1, 0x59, 0xc4, 0xbc, 0xd6, 0x96, 0x2e, 0xca, - 0x74, 0xb1, 0xbc, 0x57, 0x7e, 0x76, 0x4b, 0x9e, 0x79, 0x6d, 0xa2, 0xcc, - 0xfc, 0xc5, 0x76, 0x18, 0x8a, 0x4b, 0x07, 0x33, 0x2e, 0xad, 0x60, 0x3f, - 0x07, 0x55, 0x5c, 0xea, 0xde, 0xc3, 0x19, 0x9f, 0xee, 0x46, 0xcb, 0x7d, - 0x37, 0xb2, 0x38, 0x31, 0x61, 0x2f, 0xeb, 0x1d, 0x24, 0x03, 0x76, 0x45, - 0x6a, 0x4d, 0x7f, 0x93, 0x4b, 0x1e, 0x73, 0x04, 0xe3, 0x53, 0x71, 0x29, - 0xfa, 0x27, 0x60, 0x33, 0xf3, 0x02, 0xcb, 0xb1, 0xfc, 0x4e, 0x72, 0x7f, - 0x85, 0x9c, 0xd8, 0x41, 0x0e, 0x7d, 0x1b, 0x2c, 0xc3, 0xdc, 0x30, 0x8a, - 0xf1, 0x21, 0xf3, 0x02, 0x7c, 0xc6, 0xb2, 0xe5, 0x2c, 0x0e, 0x23, 0x7c, - 0xe3, 0xba, 0x97, 0xe3, 0x23, 0x20, 0xab, 0xc6, 0xeb, 0xe0, 0x9a, 0x98, - 0xf3, 0x22, 0xd7, 0xa1, 0x5c, 0x6f, 0xe6, 0xf5, 0xa9, 0x37, 0x35, 0x7b, - 0xb7, 0x5a, 0x53, 0xf4, 0xd7, 0x9a, 0xe8, 0xd8, 0xb1, 0xd6, 0xf4, 0xac, - 0xb4, 0xd6, 0xac, 0x58, 0x77, 0xaf, 0x35, 0x73, 0xd9, 0x7b, 0xd7, 0x9a, - 0x71, 0x87, 0xf7, 0x08, 0xb9, 0x54, 0xf0, 0x5a, 0xa8, 0x69, 0x66, 0x7c, - 0x11, 0xdd, 0xc6, 0x17, 0xd1, 0x69, 0xb7, 0x7c, 0x8e, 0x38, 0xa6, 0xdd, - 0x72, 0x8b, 0x6b, 0xa0, 0x0d, 0xae, 0x81, 0x0c, 0xe4, 0xd2, 0x7e, 0xce, - 0xc8, 0x7d, 0xc2, 0xbe, 0x1c, 0x04, 0x27, 0xb3, 0x1f, 0x8b, 0x19, 0x3f, - 0xa0, 0xf5, 0x3e, 0x05, 0x3f, 0xe4, 0xbc, 0xc2, 0x3e, 0xfb, 0x7f, 0xe2, - 0x15, 0xb2, 0x07, 0xc0, 0x0f, 0x36, 0xea, 0xcd, 0x46, 0x47, 0xd9, 0x02, - 0x5f, 0x48, 0x39, 0xe7, 0x33, 0xf6, 0x53, 0xbe, 0x50, 0x3e, 0x51, 0x78, - 0x2c, 0xd2, 0xbb, 0x3e, 0x63, 0x01, 0xe7, 0x23, 0x8f, 0x73, 0x22, 0xf3, - 0xef, 0x4d, 0xf9, 0xae, 0x17, 0xa2, 0x2f, 0xc2, 0x9e, 0x33, 0x0e, 0xe6, - 0xb5, 0x43, 0xeb, 0x36, 0xe4, 0x18, 0x0b, 0xe5, 0x3b, 0xce, 0x3d, 0xe9, - 0xf9, 0x84, 0x6b, 0xe1, 0xff, 0x16, 0x1b, 0x17, 0xef, 0x82, 0x8d, 0x37, - 0x33, 0x6c, 0xfc, 0xf2, 0x1e, 0xd8, 0xb8, 0xf8, 0x05, 0xb1, 0xe1, 0x3a, - 0x1f, 0xa3, 0x5e, 0x7a, 0xcf, 0x63, 0x7c, 0x48, 0xf9, 0xb1, 0xbf, 0x53, - 0x3e, 0x09, 0x6c, 0xe3, 0xd5, 0x9b, 0x32, 0xce, 0x72, 0x89, 0xfe, 0xd6, - 0xad, 0x5c, 0x32, 0xfe, 0x6a, 0x8a, 0x8b, 0xf1, 0xb7, 0xa4, 0x3c, 0xb7, - 0x03, 0x0e, 0xb8, 0x56, 0xbe, 0x0a, 0x1e, 0x68, 0xd1, 0xff, 0xa2, 0x56, - 0x66, 0xce, 0xae, 0xda, 0x47, 0xdb, 0xf9, 0xbe, 0xe7, 0x7b, 0x5e, 0xa0, - 0xb3, 0x62, 0x17, 0xfc, 0xb5, 0x9f, 0x5a, 0xaf, 0x9b, 0x7c, 0x7e, 0x00, - 0x1e, 0x1e, 0x37, 0x39, 0x56, 0x71, 0x56, 0xc4, 0x73, 0x7f, 0x3d, 0x0d, - 0x3c, 0xfa, 0xbc, 0x76, 0xb5, 0xee, 0x3e, 0xae, 0xff, 0x1e, 0x4a, 0x92, - 0x3b, 0xf2, 0xc8, 0xb6, 0x73, 0xb3, 0x81, 0x73, 0x73, 0x5d, 0xe9, 0xe0, - 0xb3, 0x55, 0xea, 0xbf, 0x13, 0xea, 0xac, 0x7c, 0x53, 0x9e, 0x53, 0xe7, - 0xe5, 0xd1, 0x02, 0x0d, 0xce, 0x67, 0x58, 0x61, 0x5f, 0x0c, 0xab, 0x7a, - 0x82, 0x31, 0xd5, 0x42, 0xbe, 0x5d, 0x82, 0x3f, 0x1a, 0x2a, 0x16, 0xb0, - 0xf6, 0xcc, 0x1f, 0x2d, 0xf8, 0xa3, 0x9e, 0xa4, 0x31, 0xf1, 0xe5, 0x9e, - 0x1d, 0xfe, 0x88, 0x7c, 0x6a, 0x2f, 0x9a, 0x38, 0x6f, 0x5f, 0x49, 0x54, - 0xfe, 0x5c, 0x68, 0xb5, 0xa9, 0xf9, 0x60, 0xed, 0x38, 0xd7, 0x6d, 0x5c, - 0x77, 0xcd, 0x2c, 0x55, 0xd1, 0xd7, 0xb3, 0x29, 0x84, 0x4f, 0xbe, 0x7d, - 0x90, 0x16, 0x8d, 0x1a, 0xe3, 0x17, 0xef, 0x09, 0x35, 0xc3, 0x83, 0xa8, - 0xa5, 0x92, 0xb1, 0x45, 0xbd, 0x36, 0x06, 0x1c, 0x35, 0x29, 0x80, 0x9d, - 0x01, 0x74, 0xcf, 0xb5, 0x6d, 0x7b, 0xb9, 0xcd, 0x67, 0xa4, 0x26, 0xf1, - 0x19, 0xbc, 0xdb, 0xbb, 0x0e, 0x7d, 0x03, 0xcf, 0xe0, 0xcc, 0xea, 0xc4, - 0xc0, 0xd5, 0xcb, 0x89, 0x45, 0xad, 0x12, 0xdf, 0x51, 0x30, 0x57, 0x96, - 0xa1, 0xe3, 0x99, 0x42, 0x8a, 0xcb, 0x32, 0xf4, 0x70, 0xcc, 0x10, 0xe6, - 0x63, 0xff, 0xe5, 0x58, 0x2b, 0xf7, 0xd5, 0xee, 0x85, 0xec, 0xbc, 0x4a, - 0xca, 0x07, 0xec, 0xdf, 0xd0, 0x7b, 0xbe, 0x90, 0xdf, 0xc7, 0xb4, 0x10, - 0xf3, 0x8d, 0x7d, 0x8c, 0x43, 0x0d, 0x78, 0xc3, 0x98, 0x84, 0xfb, 0x90, - 0x57, 0xf6, 0x21, 0x37, 0x97, 0x8a, 0xaa, 0x6d, 0x26, 0xc7, 0xb2, 0xf1, - 0xba, 0x1a, 0xc7, 0x39, 0x21, 0x4e, 0xd4, 0x59, 0x41, 0x8b, 0x3a, 0xe4, - 0x34, 0x7c, 0x9c, 0x81, 0x50, 0x5b, 0xac, 0x24, 0x9c, 0xcf, 0xf7, 0xd9, - 0xba, 0xe2, 0xb9, 0x4d, 0xc8, 0xe0, 0x79, 0x83, 0xf4, 0x86, 0xcf, 0xf7, - 0x07, 0xd9, 0xdd, 0x46, 0x89, 0x86, 0x21, 0x0f, 0xbb, 0xc6, 0xd8, 0xae, - 0xa0, 0xa1, 0x6a, 0x11, 0xd6, 0xbd, 0x5f, 0x4f, 0xef, 0x5c, 0x7e, 0x93, - 0xcd, 0x65, 0x83, 0x5f, 0x08, 0xe7, 0x1d, 0x9f, 0xf3, 0xda, 0xd7, 0x0c, - 0xba, 0x4e, 0x8a, 0x23, 0xc5, 0x37, 0x90, 0xef, 0x0e, 0x42, 0x26, 0x50, - 0xfc, 0x92, 0x9e, 0x19, 0x72, 0x99, 0x8a, 0xb1, 0x5d, 0xc7, 0x77, 0xcc, - 0xed, 0xef, 0x01, 0x62, 0xab, 0x9a, 0xcd, 0xd7, 0x8f, 0xd3, 0x4d, 0xe0, - 0x74, 0xb3, 0xb0, 0x75, 0xee, 0x28, 0x15, 0x30, 0x8e, 0x6d, 0x64, 0x2e, - 0x61, 0x99, 0x4f, 0xac, 0xed, 0x7a, 0x2a, 0x3b, 0xe8, 0xf8, 0x53, 0x9f, - 0x8e, 0x12, 0xaf, 0x4d, 0x34, 0xd2, 0xf3, 0xb3, 0xfa, 0x6b, 0xc0, 0xcf, - 0x38, 0x6f, 0x3c, 0xa0, 0x63, 0x1d, 0x5c, 0x7f, 0xd5, 0x55, 0x3f, 0x0e, - 0x56, 0xdb, 0xf4, 0xfe, 0x30, 0x9b, 0x67, 0x5f, 0x1a, 0x0f, 0x1e, 0xda, - 0x64, 0xb3, 0xcf, 0x76, 0x6b, 0x87, 0x79, 0x91, 0xd8, 0xbd, 0x19, 0x8d, - 0xf1, 0x66, 0xd4, 0x38, 0x07, 0xe3, 0x79, 0x0b, 0x1f, 0x8c, 0xd5, 0xcf, - 0xc7, 0xa8, 0xf5, 0x05, 0x31, 0xfa, 0x46, 0x9b, 0xb9, 0x22, 0xc5, 0x68, - 0xe3, 0x0e, 0x8c, 0xa2, 0x06, 0x2a, 0xe5, 0xf8, 0xe4, 0x78, 0xc9, 0xf1, - 0x99, 0x3f, 0xf3, 0xfd, 0x08, 0x38, 0x38, 0xe3, 0xb6, 0x18, 0xdc, 0x16, - 0xa9, 0x1c, 0xe7, 0x96, 0x23, 0x4a, 0xe3, 0x78, 0x19, 0x71, 0x1c, 0x19, - 0x9c, 0xf3, 0x38, 0x86, 0x59, 0x8e, 0xe3, 0x98, 0xe5, 0x46, 0x32, 0x39, - 0xb4, 0x88, 0xe7, 0x28, 0x8b, 0xe7, 0x16, 0x78, 0x37, 0xca, 0xe2, 0xb9, - 0x85, 0x18, 0x5e, 0xc9, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0xdf, 0xdb, 0x19, - 0x55, 0x95, 0x8b, 0x9d, 0x3a, 0x78, 0x6d, 0x45, 0xe9, 0x6c, 0x62, 0x9d, - 0xb0, 0xb1, 0x93, 0xc7, 0xc5, 0x1d, 0xf7, 0x5b, 0x58, 0xcf, 0xad, 0xbc, - 0x32, 0x8b, 0xbc, 0x72, 0x0e, 0x79, 0xa5, 0xdb, 0x77, 0xbf, 0x75, 0x56, - 0xe5, 0x95, 0x27, 0x8b, 0x79, 0x5e, 0xe9, 0x66, 0x79, 0xa5, 0xab, 0xf2, - 0xca, 0x13, 0x45, 0xce, 0x2b, 0x31, 0x05, 0xc5, 0xfe, 0xbc, 0x12, 0x6f, - 0xcb, 0x2b, 0xb9, 0x2c, 0xf7, 0xef, 0x94, 0x57, 0x72, 0x9f, 0x71, 0x6e, - 0xb1, 0x72, 0x5e, 0xbd, 0x2d, 0x9f, 0xe4, 0x63, 0xd8, 0x56, 0xe6, 0x25, - 0xe6, 0xe0, 0xb4, 0xae, 0xbf, 0x92, 0xe4, 0xb1, 0x74, 0x0c, 0xf3, 0xe0, - 0xbd, 0xb3, 0x53, 0x2c, 0xd9, 0x59, 0x2c, 0x0d, 0xa7, 0x32, 0x9d, 0xfe, - 0x78, 0x3a, 0x56, 0xdc, 0x1e, 0x4f, 0xb9, 0x9e, 0x3c, 0x9e, 0x52, 0x9d, - 0x1f, 0x1a, 0x65, 0xae, 0x07, 0x70, 0x96, 0x76, 0xfd, 0x39, 0xf4, 0x5e, - 0xe8, 0x4d, 0xa3, 0xae, 0x36, 0xe9, 0x6a, 0xce, 0x37, 0xea, 0xbe, 0x07, - 0x6d, 0x2f, 0xb7, 0xb5, 0xb8, 0xf5, 0xad, 0x8b, 0xda, 0xfa, 0x7d, 0xf0, - 0xc8, 0x79, 0xf5, 0xfd, 0x33, 0x79, 0xb5, 0x84, 0x33, 0xb0, 0x97, 0x8f, - 0x7b, 0x1d, 0xf3, 0xb9, 0xe2, 0x2c, 0x9e, 0x5e, 0xee, 0xdd, 0x82, 0xf9, - 0x8a, 0xc7, 0x7d, 0xff, 0x44, 0x0e, 0x41, 0x5d, 0xbe, 0x35, 0x96, 0xcf, - 0x38, 0x1e, 0xd6, 0xec, 0xd0, 0xa5, 0x6d, 0xe7, 0x9c, 0xf4, 0x7c, 0x83, - 0x75, 0xa3, 0x3e, 0xe1, 0x3a, 0x25, 0xfc, 0x8a, 0x4e, 0x2f, 0xd1, 0xb7, - 0x7c, 0xee, 0xd3, 0x69, 0xf6, 0x31, 0x29, 0x5f, 0x40, 0xcd, 0xf2, 0xf4, - 0xb6, 0x9a, 0xa5, 0x48, 0xe3, 0x07, 0xfa, 0xcf, 0x87, 0x37, 0xe5, 0xf8, - 0xa4, 0x7b, 0x36, 0xa0, 0x40, 0x9b, 0x5d, 0xe7, 0x5a, 0x76, 0xab, 0x76, - 0x25, 0x1a, 0xbd, 0x21, 0xf5, 0x49, 0xce, 0x85, 0x57, 0x33, 0x5f, 0xe1, - 0xdb, 0x99, 0x1b, 0xe0, 0xd6, 0x48, 0xdd, 0xf1, 0x06, 0xeb, 0x3c, 0x0f, - 0xbf, 0xa3, 0x4d, 0xb8, 0xbe, 0xb9, 0xdb, 0xbd, 0xab, 0x89, 0x7d, 0x71, - 0x9d, 0xa3, 0x06, 0xa9, 0xbb, 0x8b, 0x25, 0xdf, 0xfd, 0x59, 0x8b, 0x52, - 0x9e, 0x88, 0xfc, 0x05, 0xd8, 0x02, 0x9c, 0x8b, 0x45, 0xec, 0xcd, 0x24, - 0x78, 0xc9, 0x75, 0x0e, 0xe8, 0x42, 0x61, 0x7f, 0x19, 0xba, 0x8d, 0x03, - 0x5c, 0x3f, 0x7e, 0x2a, 0x97, 0x7b, 0x2a, 0x07, 0xfb, 0x8c, 0x91, 0x7a, - 0xb2, 0x5b, 0xe7, 0x36, 0x48, 0xf8, 0xb9, 0x80, 0x79, 0x9c, 0xbb, 0xe0, - 0xa7, 0x24, 0xa2, 0x33, 0x8e, 0x98, 0xed, 0x38, 0x62, 0xae, 0xa3, 0x03, - 0xdd, 0xb6, 0x4d, 0xbb, 0xb0, 0x27, 0xc8, 0xc1, 0xf4, 0x00, 0x6c, 0xb9, - 0xe0, 0x88, 0x3a, 0x6a, 0xc1, 0x1f, 0x18, 0xae, 0x78, 0x9a, 0x3e, 0xc1, - 0x1a, 0x6f, 0xc8, 0xf4, 0xde, 0xc5, 0x11, 0xd1, 0xd6, 0xdc, 0x37, 0x30, - 0x37, 0xdb, 0xc4, 0x31, 0xca, 0xf9, 0x72, 0x5e, 0x5b, 0x80, 0x8f, 0x8e, - 0xac, 0x6b, 0xe0, 0x35, 0xce, 0x97, 0x23, 0xd9, 0xfd, 0x12, 0xf6, 0x07, - 0xeb, 0xbf, 0x74, 0x47, 0xad, 0x99, 0xd7, 0x94, 0xe9, 0xdd, 0x69, 0x3c, - 0xc3, 0xf3, 0x13, 0x6c, 0x99, 0x98, 0xba, 0xa0, 0xce, 0x3d, 0xd3, 0xa8, - 0xf1, 0xb8, 0x95, 0xa8, 0x83, 0xf8, 0xae, 0x8b, 0x6b, 0x27, 0x89, 0xf8, - 0x4f, 0x9f, 0x63, 0x3e, 0x13, 0xcd, 0xb0, 0x0e, 0x3e, 0x1b, 0x71, 0xfc, - 0xfc, 0x1b, 0x2f, 0xf3, 0x0a, 0xbd, 0x68, 0x18, 0x00, 0x00, 0x00 }; - -static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 }; + 0x1f, 0x8b, 0x08, 0x08, 0xdb, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x58, 0x5d, 0x6c, + 0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xbb, 0x13, 0x77, 0xed, 0xbd, 0x49, 0x97, + 0x6a, 0x13, 0xb9, 0x74, 0xc6, 0x1e, 0x3b, 0x8b, 0x1c, 0x35, 0x93, 0xb0, + 0x24, 0x16, 0x5a, 0xd1, 0xc9, 0xcc, 0xae, 0x6b, 0xe5, 0x29, 0x86, 0xbc, + 0xf1, 0xb2, 0xac, 0xed, 0x46, 0x54, 0x48, 0x4d, 0x51, 0x84, 0x22, 0x81, + 0x94, 0x65, 0x76, 0x53, 0x40, 0x5a, 0x65, 0xc1, 0xa0, 0x04, 0x21, 0x84, + 0x22, 0x9b, 0x66, 0x91, 0x58, 0x3c, 0x4d, 0xe9, 0x6b, 0x94, 0xbc, 0x90, + 0x96, 0x17, 0x9e, 0x4b, 0x9e, 0xac, 0x02, 0x12, 0x0f, 0xa8, 0x8a, 0x78, + 0x40, 0x15, 0x0d, 0x1e, 0xbe, 0x33, 0x3f, 0x9b, 0x5d, 0xd7, 0x29, 0x79, + 0xa8, 0x84, 0xa5, 0xf1, 0xcc, 0xfd, 0x39, 0xf7, 0xe7, 0x7c, 0xdf, 0x77, + 0xee, 0xb9, 0x5b, 0x92, 0x69, 0x82, 0xd2, 0xbf, 0x49, 0x3c, 0x97, 0xbe, + 0x71, 0xf1, 0xd2, 0xe2, 0x8b, 0x27, 0x4d, 0x3a, 0x71, 0xe2, 0x45, 0xe9, + 0x19, 0x43, 0xa6, 0xcf, 0xe0, 0x4f, 0x21, 0x12, 0xd9, 0xf8, 0xfc, 0x90, + 0x21, 0x57, 0x6f, 0x4e, 0x7b, 0x36, 0x19, 0x4a, 0xd5, 0x79, 0x61, 0xd5, + 0x26, 0x72, 0x07, 0x0b, 0xa6, 0x4f, 0xff, 0x89, 0x5a, 0x45, 0x95, 0xb8, + 0xfe, 0xf9, 0xea, 0xa3, 0xe3, 0x77, 0x4e, 0x5b, 0x0f, 0x6f, 0x2a, 0x64, + 0x88, 0x6a, 0xc3, 0x10, 0xf3, 0x64, 0x4c, 0xc3, 0xe6, 0x97, 0x47, 0x57, + 0x34, 0x9a, 0xca, 0xc6, 0x12, 0x14, 0xf4, 0x0c, 0xaa, 0x77, 0x31, 0x8e, + 0x7d, 0x59, 0xf2, 0x43, 0x55, 0xf2, 0x6f, 0x18, 0x24, 0x57, 0x5d, 0xc9, + 0x0b, 0x6d, 0xb4, 0x49, 0xe4, 0x39, 0x39, 0x72, 0x45, 0x14, 0x7d, 0xd3, + 0x91, 0x49, 0xb6, 0x77, 0xa3, 0xd9, 0xb9, 0x25, 0xc9, 0xeb, 0x2f, 0x4b, + 0x7e, 0xdf, 0xe3, 0x7d, 0x63, 0x1d, 0x4b, 0x92, 0xdb, 0xe7, 0x77, 0xd5, + 0xf0, 0xbb, 0x53, 0xd4, 0x28, 0x52, 0x41, 0xb6, 0xd9, 0xd6, 0x24, 0xdf, + 0x59, 0x28, 0x29, 0x34, 0x8b, 0xe7, 0x00, 0xad, 0x3b, 0x94, 0xf7, 0x1c, + 0x52, 0x15, 0x5b, 0x26, 0xbf, 0x28, 0xd1, 0xaf, 0x2b, 0x1a, 0x9e, 0xb3, + 0x52, 0xad, 0xbf, 0x96, 0x8e, 0x53, 0xa4, 0x36, 0xd6, 0xd2, 0x2c, 0xf2, + 0xda, 0x12, 0x7b, 0xcf, 0x59, 0x10, 0x32, 0xcd, 0xe2, 0x99, 0xc4, 0x77, + 0x13, 0xfd, 0x34, 0xf2, 0x2a, 0x7b, 0xdb, 0x0e, 0xe0, 0x1b, 0xeb, 0xc4, + 0x58, 0x5e, 0xbc, 0x0e, 0x13, 0xeb, 0xb0, 0xa9, 0xd3, 0x5b, 0xc6, 0x3e, + 0xe6, 0x4a, 0x4d, 0xd2, 0xa9, 0x13, 0xaf, 0x7d, 0x92, 0x02, 0xa1, 0x50, + 0x70, 0x4c, 0x23, 0xf7, 0x9c, 0x8a, 0xf2, 0x21, 0x6a, 0x09, 0x09, 0x7d, + 0x3a, 0x29, 0x7e, 0x39, 0xb4, 0xeb, 0xa8, 0x2f, 0x50, 0x50, 0x3c, 0x28, + 0xc9, 0xd5, 0xef, 0xa1, 0x7e, 0x4e, 0x34, 0xe9, 0xbb, 0x78, 0x4b, 0x28, + 0x1f, 0xe4, 0xf1, 0x50, 0x96, 0x48, 0xb1, 0x49, 0x78, 0xa1, 0x49, 0xed, + 0x30, 0xb3, 0xe5, 0xfa, 0xa4, 0xae, 0x15, 0xee, 0xc5, 0x0e, 0xfd, 0x7a, + 0x75, 0x6a, 0x08, 0x6a, 0xa9, 0x55, 0xf4, 0xe9, 0xd9, 0xa2, 0x06, 0x9c, + 0xdc, 0x18, 0xcf, 0x97, 0xb8, 0x9e, 0xff, 0x50, 0x6f, 0x92, 0x52, 0xb5, + 0x85, 0x4f, 0x5f, 0xa6, 0xa4, 0x8d, 0xf7, 0x29, 0x63, 0x6f, 0xa7, 0xd2, + 0x72, 0x51, 0x78, 0x37, 0xbe, 0x48, 0x6e, 0xec, 0x1f, 0x03, 0xdf, 0x02, + 0x7b, 0xd4, 0x81, 0x75, 0xe0, 0xca, 0xd4, 0x2a, 0x19, 0x64, 0x2d, 0xae, + 0xa1, 0xe5, 0x6f, 0x5d, 0x05, 0x7e, 0x67, 0xdc, 0xd4, 0xd4, 0x8e, 0x71, + 0xfe, 0x23, 0xd6, 0xd9, 0x12, 0x06, 0xf0, 0x6e, 0x9c, 0x8f, 0xa2, 0x37, + 0x9d, 0x28, 0xd2, 0xab, 0x76, 0xf9, 0x16, 0x2d, 0x94, 0x34, 0x9a, 0x17, + 0x78, 0xc3, 0x8f, 0x36, 0x7c, 0xa5, 0x65, 0xeb, 0xc9, 0x78, 0x86, 0xbf, + 0xcb, 0x12, 0x96, 0x42, 0x1f, 0x74, 0xdf, 0x63, 0x7f, 0x94, 0x97, 0x62, + 0x9b, 0x28, 0xda, 0x5c, 0xfc, 0x34, 0x9b, 0xef, 0xa7, 0x36, 0x51, 0x54, + 0xaf, 0xf0, 0xbc, 0x16, 0xf6, 0xcc, 0x5c, 0x25, 0xaa, 0x0f, 0x1c, 0xa3, + 0xd9, 0xc5, 0xfa, 0x6c, 0xbc, 0x07, 0x25, 0xec, 0xc1, 0x2a, 0x9b, 0x92, + 0x41, 0x81, 0x1d, 0xbd, 0x00, 0x7e, 0xb8, 0xbe, 0x6d, 0xbd, 0xef, 0x2b, + 0x05, 0xda, 0x72, 0xf2, 0xd4, 0x09, 0x4b, 0x14, 0x84, 0x1d, 0xf2, 0x42, + 0x19, 0x73, 0x14, 0x68, 0xd3, 0x7e, 0x18, 0xd5, 0x1d, 0x07, 0x7e, 0x21, + 0xb6, 0x2b, 0xd5, 0x69, 0x1a, 0xed, 0x0b, 0x62, 0x8d, 0x1c, 0x60, 0x21, + 0xc3, 0x37, 0xb3, 0xf1, 0x77, 0x10, 0x3a, 0x68, 0xa7, 0x96, 0x5c, 0xb1, + 0x44, 0x40, 0x56, 0xc9, 0x53, 0x48, 0xc8, 0x55, 0x81, 0x3e, 0x2d, 0xaa, + 0x85, 0x06, 0xed, 0x28, 0x97, 0x63, 0x7e, 0xb7, 0x7b, 0x3b, 0xd1, 0x9d, + 0xa3, 0x25, 0xba, 0x1b, 0x16, 0xe9, 0x76, 0x48, 0x72, 0xd3, 0x01, 0x37, + 0x8a, 0x82, 0xde, 0x0a, 0x47, 0xf7, 0xf2, 0x1b, 0xec, 0x25, 0x38, 0xa2, + 0x40, 0x83, 0xab, 0xce, 0x3d, 0x30, 0xc8, 0x02, 0x46, 0x2d, 0xec, 0x3d, + 0x7b, 0xf3, 0xbe, 0x76, 0xa6, 0x57, 0x6d, 0xeb, 0x87, 0x3e, 0xa3, 0x76, + 0x4d, 0x43, 0xed, 0x5e, 0x7f, 0x0c, 0x30, 0x86, 0xa0, 0xab, 0xd0, 0x93, + 0x0c, 0xbf, 0xcc, 0x6c, 0x1b, 0xd4, 0xef, 0xe6, 0xc8, 0xdc, 0x54, 0xa9, + 0xd9, 0x2b, 0x92, 0x33, 0x6f, 0x99, 0x24, 0xcb, 0x45, 0x99, 0x54, 0x9a, + 0xd9, 0x8c, 0x68, 0x09, 0xeb, 0xb8, 0x6f, 0xff, 0x48, 0xa7, 0xa9, 0xc0, + 0xd1, 0x89, 0xfb, 0x18, 0x34, 0x73, 0xcb, 0x90, 0xfc, 0x1e, 0xef, 0x83, + 0x7d, 0x6e, 0xa4, 0x3e, 0x57, 0x25, 0xef, 0x46, 0x8e, 0x66, 0x37, 0xfe, + 0x11, 0x79, 0x36, 0x7c, 0x0d, 0x9e, 0xaf, 0x56, 0xbe, 0xa0, 0xd0, 0x04, + 0xea, 0x36, 0xb9, 0xed, 0x61, 0x5a, 0xcf, 0x63, 0x44, 0x91, 0xe7, 0x3c, + 0x4b, 0x1e, 0xf3, 0xff, 0x3c, 0xdb, 0xe4, 0x68, 0x66, 0x83, 0x75, 0x83, + 0xf7, 0x26, 0x97, 0x79, 0x6d, 0x07, 0xa8, 0x89, 0x1d, 0x35, 0xcb, 0x45, + 0xf8, 0x41, 0x8e, 0x35, 0xd2, 0xc4, 0x8e, 0x65, 0x7b, 0x02, 0x6f, 0x9e, + 0xef, 0xac, 0x92, 0xf0, 0x9d, 0xe3, 0x46, 0x9e, 0x7c, 0xe0, 0xab, 0x62, + 0x3d, 0x6b, 0x34, 0x57, 0x5a, 0x8f, 0xdb, 0x50, 0x37, 0xe0, 0x36, 0xb1, + 0xa7, 0x0d, 0xe5, 0x41, 0xb6, 0x06, 0x70, 0xda, 0x6e, 0x63, 0x16, 0x2d, + 0xde, 0x6b, 0xdd, 0xe1, 0xfe, 0xdc, 0xb7, 0x55, 0xd6, 0xc8, 0x2a, 0x6f, + 0x62, 0xf4, 0x7e, 0x17, 0xfb, 0xbd, 0xce, 0xb1, 0xc8, 0x36, 0xff, 0x4a, + 0xdc, 0x7f, 0x16, 0x7b, 0x9e, 0x5b, 0x6c, 0x73, 0xdb, 0x40, 0x23, 0x7b, + 0xa3, 0x25, 0x54, 0xf8, 0x5f, 0x86, 0xf3, 0xfd, 0x1f, 0xff, 0x2b, 0xd2, + 0xaa, 0xe0, 0x74, 0xa5, 0x00, 0x7c, 0x2c, 0xb3, 0x0d, 0xbd, 0xdb, 0x18, + 0x37, 0x70, 0x14, 0xd8, 0x25, 0x38, 0x71, 0xbf, 0xa5, 0x6e, 0x44, 0xed, + 0x78, 0xae, 0x2b, 0x3c, 0x17, 0x62, 0x92, 0xbd, 0xf8, 0x07, 0x70, 0xa3, + 0x49, 0x79, 0x9a, 0xdf, 0xce, 0xd3, 0x85, 0x41, 0x9e, 0x66, 0xae, 0xe9, + 0xf0, 0x43, 0x14, 0x75, 0x2a, 0xac, 0x51, 0xe0, 0x6d, 0x73, 0x3f, 0xab, + 0xa4, 0xc8, 0xbc, 0x0e, 0xb4, 0x6f, 0x13, 0xad, 0x0d, 0x74, 0xf8, 0x4d, + 0x1d, 0x19, 0x5b, 0xa6, 0x97, 0x7f, 0x46, 0xf4, 0xf2, 0x80, 0x6d, 0x79, + 0xfc, 0xc4, 0xa6, 0x89, 0x3d, 0xcb, 0xc0, 0xfc, 0xc2, 0x40, 0x46, 0xbc, + 0x40, 0x3c, 0xed, 0x7b, 0x88, 0x93, 0x35, 0x3c, 0x4b, 0x88, 0x9d, 0x8c, + 0x0d, 0xc7, 0x91, 0x5d, 0xe0, 0xb3, 0x8c, 0xb6, 0xb3, 0xa8, 0x4b, 0xf4, + 0xae, 0xd8, 0x3a, 0xd5, 0x9c, 0x49, 0x6a, 0x67, 0xb1, 0x4a, 0x70, 0xac, + 0x3a, 0x08, 0x4e, 0x1d, 0x40, 0xfc, 0xf9, 0x9d, 0x32, 0x1e, 0xab, 0x10, + 0xd3, 0x8a, 0x87, 0x11, 0x9b, 0xfa, 0xa8, 0xe7, 0xf1, 0x6e, 0xe1, 0x7d, + 0x00, 0xe5, 0xc3, 0xe8, 0x3b, 0x1a, 0xa7, 0x32, 0xbb, 0x27, 0xc5, 0x28, + 0xf0, 0x6e, 0xc3, 0x40, 0x7f, 0x13, 0xba, 0x61, 0x7f, 0xe7, 0x10, 0x3f, + 0xd8, 0xe7, 0x39, 0xf8, 0x54, 0xc7, 0xdc, 0x82, 0x66, 0xb7, 0xa9, 0xa5, + 0xa4, 0xf1, 0xcb, 0x1f, 0xc6, 0xaf, 0x52, 0xcc, 0x83, 0x20, 0x14, 0xb0, + 0x61, 0xfd, 0x66, 0x7a, 0x65, 0xec, 0xc8, 0xf5, 0xa0, 0x65, 0x4f, 0x89, + 0xa2, 0x55, 0xa7, 0x40, 0x4d, 0xe0, 0xee, 0x42, 0xc3, 0x4d, 0x68, 0xd8, + 0x1f, 0xd1, 0xb0, 0xff, 0x3f, 0x35, 0x0c, 0x7d, 0x42, 0x23, 0xb7, 0xc1, + 0xa9, 0xb7, 0x7a, 0xfb, 0xe9, 0x99, 0xb5, 0xcc, 0x9a, 0x36, 0xe9, 0xce, + 0xd1, 0xa7, 0xd5, 0x74, 0x49, 0x7e, 0x4a, 0x4d, 0xb7, 0x58, 0xd3, 0x2a, + 0x6b, 0xba, 0xb8, 0x57, 0xd3, 0xd3, 0x18, 0x23, 0xd1, 0xe6, 0x19, 0xb5, + 0x48, 0xda, 0x3c, 0xf0, 0xd8, 0xc8, 0x93, 0x72, 0xed, 0x31, 0xef, 0x98, + 0xcb, 0xfe, 0x00, 0xff, 0xb6, 0x35, 0xb4, 0x49, 0xe3, 0xf5, 0x88, 0x81, + 0x6a, 0xd5, 0x2a, 0xad, 0xc5, 0x7d, 0x54, 0xd2, 0xe1, 0xff, 0xd7, 0x8f, + 0x5a, 0xa6, 0x29, 0x8f, 0x6a, 0x1f, 0xea, 0xdf, 0x88, 0xae, 0x68, 0x55, + 0x9e, 0xa7, 0x65, 0x82, 0xf3, 0xe6, 0x4f, 0x80, 0x55, 0xbb, 0xcb, 0x7c, + 0xb7, 0x45, 0x3d, 0xe6, 0x19, 0xca, 0xd0, 0x84, 0x06, 0xde, 0xe6, 0xd0, + 0x4f, 0xdd, 0x48, 0x74, 0x74, 0x1b, 0xe3, 0x6e, 0x75, 0x99, 0x67, 0x06, + 0xe9, 0xd7, 0xed, 0xd2, 0x85, 0x38, 0x06, 0xcf, 0x8a, 0x25, 0x62, 0x0d, + 0xf2, 0xb9, 0x88, 0xf6, 0x41, 0x8e, 0x94, 0x58, 0xf7, 0x13, 0xa9, 0xee, + 0x9f, 0x87, 0xaf, 0x26, 0x50, 0x66, 0xed, 0x1f, 0x4e, 0xb5, 0x3f, 0x85, + 0x37, 0xd7, 0xad, 0xa8, 0x09, 0x87, 0xc0, 0xc7, 0x0d, 0xc6, 0x37, 0x8f, + 0x58, 0xc7, 0xf3, 0xff, 0x33, 0x5a, 0xb5, 0x19, 0x63, 0xdb, 0xfc, 0x01, + 0xcd, 0x41, 0x7f, 0xa8, 0xdf, 0xe6, 0xbe, 0x6c, 0x93, 0xf5, 0x15, 0x69, + 0xdf, 0x0f, 0xf7, 0xf4, 0x45, 0xfd, 0x36, 0xf7, 0x63, 0x7d, 0x1c, 0x22, + 0xe5, 0x3a, 0x9f, 0xdb, 0x1e, 0xeb, 0x03, 0x76, 0x35, 0xd4, 0x71, 0x6e, + 0xc1, 0xf6, 0x7c, 0x86, 0xf3, 0x3a, 0x39, 0xef, 0xe0, 0x73, 0x7e, 0xcf, + 0x79, 0x3e, 0xd4, 0xc8, 0x19, 0xf0, 0xfe, 0x3b, 0xea, 0x27, 0x35, 0xb2, + 0x02, 0x4d, 0x5c, 0x54, 0x13, 0x8d, 0xbc, 0x86, 0xf7, 0x19, 0x94, 0x57, + 0xf6, 0x68, 0x24, 0xb3, 0x7b, 0xf2, 0x39, 0x1e, 0xf4, 0x4a, 0xf1, 0x99, + 0xcb, 0xf3, 0x29, 0x1b, 0xd4, 0xd2, 0x52, 0x3d, 0xd4, 0x87, 0x7a, 0x98, + 0x40, 0xcc, 0xc8, 0xa5, 0x5c, 0xc7, 0xdb, 0xfe, 0x48, 0xf1, 0x1d, 0x4b, + 0xb4, 0x89, 0xb5, 0x31, 0x7a, 0x9e, 0xfd, 0xbf, 0xf4, 0x41, 0xe0, 0x51, + 0x3c, 0x37, 0x72, 0x11, 0x3e, 0x17, 0xa2, 0xe8, 0x15, 0x07, 0xed, 0x59, + 0x4e, 0x12, 0x63, 0x9f, 0xc3, 0xd9, 0xcb, 0x78, 0x20, 0x0f, 0xb4, 0x67, + 0xa1, 0x07, 0x8e, 0x05, 0xbb, 0xd1, 0x96, 0xed, 0xa1, 0xae, 0x06, 0xff, + 0x33, 0x26, 0xcb, 0xd2, 0x52, 0xdf, 0x60, 0x3b, 0xe8, 0x6d, 0xbf, 0x5c, + 0x4c, 0x87, 0xae, 0x1e, 0xe3, 0xc4, 0x3c, 0x6a, 0x8e, 0xe0, 0xd4, 0x88, + 0x71, 0xda, 0x19, 0xe2, 0xd4, 0x4c, 0x71, 0x6a, 0xc6, 0x38, 0x3d, 0x48, + 0x71, 0xfa, 0xf3, 0x13, 0x70, 0xda, 0x79, 0x0a, 0x9c, 0x0c, 0xda, 0xb2, + 0x4b, 0x38, 0x6f, 0xf5, 0x38, 0x77, 0xbd, 0xef, 0xec, 0x97, 0x7b, 0xb1, + 0xdf, 0xc7, 0xb0, 0x8a, 0x18, 0xab, 0x2d, 0x1a, 0xcd, 0x43, 0x2c, 0xf3, + 0x1e, 0x15, 0x70, 0x6e, 0xe4, 0xe9, 0xea, 0x9e, 0x5c, 0x24, 0x00, 0x4e, + 0xb5, 0x14, 0xa7, 0xab, 0xc0, 0xa9, 0x96, 0xe2, 0xb4, 0x3e, 0x82, 0xd3, + 0xfa, 0x18, 0x4e, 0x1c, 0x53, 0x2a, 0xc6, 0x7a, 0x37, 0xc3, 0x28, 0xc3, + 0x47, 0xa7, 0x9b, 0x62, 0x0a, 0xfb, 0x3f, 0x4e, 0xed, 0x9f, 0xaa, 0x9c, + 0xff, 0x02, 0xbb, 0x97, 0x54, 0x39, 0x3e, 0x17, 0xf8, 0xfb, 0x71, 0xbe, + 0x82, 0xb9, 0x5c, 0xcf, 0xe1, 0x3d, 0x21, 0xcf, 0xb5, 0x47, 0x63, 0xd1, + 0x07, 0x88, 0x45, 0x5c, 0xc7, 0xfd, 0x54, 0xa9, 0x06, 0xcd, 0x2b, 0xc8, + 0xe1, 0xfd, 0x61, 0x0e, 0x9f, 0xf8, 0xe1, 0x6a, 0x9a, 0xc3, 0x6f, 0xd9, + 0x9c, 0xc3, 0x9f, 0xd0, 0x68, 0x62, 0x39, 0xc5, 0x93, 0x79, 0x3d, 0x89, + 0xb6, 0xb3, 0x31, 0xee, 0x6d, 0xc4, 0xf2, 0x55, 0xf8, 0xa0, 0x19, 0xf3, + 0x13, 0x79, 0x57, 0xca, 0x5d, 0xe4, 0xbb, 0xe4, 0x87, 0x09, 0x4f, 0x3f, + 0xdb, 0x5c, 0xec, 0xef, 0x88, 0xd9, 0x46, 0x43, 0xc5, 0x1d, 0xe0, 0x6e, + 0x18, 0xc7, 0xea, 0x73, 0x41, 0x97, 0x5a, 0x47, 0xaa, 0x57, 0x22, 0xe0, + 0xee, 0x7e, 0xfd, 0x34, 0x9f, 0x39, 0xf9, 0x45, 0xaf, 0x82, 0xfa, 0x81, + 0x41, 0xc8, 0x83, 0x70, 0xa7, 0xa1, 0x96, 0x77, 0x5a, 0x42, 0xbe, 0x83, + 0x32, 0x6c, 0x82, 0x70, 0xba, 0x21, 0x57, 0x4b, 0xe0, 0x43, 0x8b, 0x5c, + 0xac, 0xd3, 0x0d, 0xe3, 0x7b, 0x4d, 0x43, 0xa9, 0x1a, 0xc8, 0x37, 0xc9, + 0xc0, 0x99, 0x0f, 0x9f, 0x98, 0x46, 0x7b, 0x80, 0x9c, 0x08, 0x79, 0x80, + 0xb7, 0x08, 0xbf, 0x1c, 0x03, 0x76, 0xa1, 0x0a, 0xdb, 0x6f, 0xe9, 0xc9, + 0x9d, 0x88, 0xc8, 0x8b, 0xfd, 0xf5, 0x71, 0xca, 0x91, 0x38, 0xe7, 0x92, + 0x6a, 0x3d, 0x32, 0x9b, 0x0e, 0xb8, 0x8e, 0x33, 0xa5, 0x13, 0x72, 0x5e, + 0x7d, 0xcc, 0x90, 0xaf, 0x71, 0x3c, 0x7f, 0x00, 0x1f, 0xe2, 0x7b, 0x9b, + 0xcf, 0x19, 0x85, 0x73, 0x73, 0xdc, 0x7d, 0xca, 0x88, 0x37, 0x34, 0x89, + 0xd8, 0x87, 0xd8, 0x3b, 0xcd, 0x58, 0xb9, 0xc9, 0x19, 0xc4, 0xe3, 0x1d, + 0x97, 0x93, 0x79, 0xfe, 0xa4, 0x25, 0x1c, 0xc6, 0x7d, 0x07, 0xfe, 0x5b, + 0xed, 0x39, 0x1c, 0x73, 0x3f, 0xaf, 0xd0, 0x43, 0x8a, 0x39, 0x29, 0x4e, + 0x20, 0x16, 0x9f, 0x86, 0x8d, 0x1b, 0xeb, 0x31, 0xc9, 0xbd, 0x32, 0x9b, + 0x0f, 0xf7, 0x8c, 0xf1, 0x17, 0x65, 0xbc, 0xec, 0x82, 0xd3, 0x95, 0x74, + 0xbe, 0x51, 0x8e, 0x2c, 0x20, 0xe5, 0x79, 0xa0, 0x0d, 0xf3, 0xb7, 0xa2, + 0x8e, 0x7e, 0xbc, 0x46, 0xd6, 0x25, 0xdb, 0x1c, 0xd1, 0xc6, 0xc7, 0x99, + 0xdd, 0x67, 0x8c, 0xea, 0xc8, 0x18, 0x45, 0xde, 0x9b, 0x68, 0x3a, 0xcf, + 0xa4, 0xf7, 0x0c, 0x8e, 0x2d, 0x02, 0x3a, 0x95, 0x9f, 0x93, 0xb1, 0x0f, + 0x0f, 0x7b, 0xf6, 0xe3, 0xfa, 0x5f, 0xe9, 0xe3, 0xe3, 0xfe, 0x56, 0x4d, + 0xca, 0xc7, 0x12, 0x6e, 0xda, 0x78, 0x87, 0x0f, 0x46, 0xd6, 0xae, 0xed, + 0x33, 0xef, 0xd7, 0x38, 0x5d, 0x43, 0xbc, 0x21, 0x57, 0xc1, 0x1d, 0xcc, + 0x27, 0x7c, 0x87, 0xaf, 0x67, 0x3e, 0x04, 0x6f, 0xe8, 0x5c, 0x3b, 0xe5, + 0x8b, 0x9c, 0xf0, 0x85, 0xf3, 0xba, 0xc5, 0x55, 0xf0, 0xa5, 0x0d, 0xbe, + 0xc0, 0xae, 0xa1, 0x55, 0xa7, 0xc1, 0x05, 0x8e, 0x4d, 0x28, 0x87, 0xcc, + 0x1d, 0xe6, 0x0a, 0xf3, 0xe6, 0x31, 0x5f, 0x5e, 0xe9, 0x1a, 0xc6, 0xe6, + 0xa7, 0x70, 0xe5, 0x8d, 0x98, 0x2b, 0xcc, 0xd9, 0x24, 0x7e, 0x74, 0x80, + 0x55, 0x90, 0xc6, 0x8f, 0x00, 0xf1, 0xa3, 0xc6, 0xf9, 0x4f, 0x1c, 0x0b, + 0x12, 0xfd, 0xac, 0x41, 0x3f, 0x35, 0x85, 0xf3, 0x23, 0xd6, 0x0e, 0xdb, + 0xb1, 0x7e, 0xd8, 0xae, 0x90, 0xda, 0x8d, 0xc7, 0x91, 0x76, 0xcf, 0x32, + 0xb3, 0x38, 0xd2, 0x86, 0x76, 0x3a, 0xa9, 0x8e, 0xda, 0xa9, 0x8e, 0xd0, + 0xa7, 0xa5, 0x54, 0xf8, 0x4c, 0xb0, 0x4c, 0x1f, 0xf1, 0xa3, 0x13, 0x8f, + 0xd9, 0xa2, 0xe4, 0x2e, 0xc3, 0xda, 0xe6, 0xb8, 0x3b, 0x12, 0x6f, 0xd3, + 0x7b, 0x6e, 0x23, 0xbe, 0xe7, 0x7e, 0x45, 0x1f, 0x8f, 0xb7, 0x38, 0x6b, + 0xe2, 0x7b, 0xee, 0x29, 0x9d, 0xef, 0xb9, 0x01, 0x7d, 0x49, 0x1f, 0xbd, + 0xe7, 0x06, 0x63, 0xf7, 0xdc, 0xcc, 0x96, 0xeb, 0xf7, 0x8b, 0xbb, 0x99, + 0x4f, 0x38, 0xf6, 0x32, 0x9f, 0xf6, 0xcb, 0x15, 0xb3, 0x3e, 0x1c, 0x93, + 0x58, 0xef, 0x1c, 0xcb, 0x92, 0xdc, 0xec, 0x6e, 0x98, 0xe9, 0xe2, 0x55, + 0xcc, 0x83, 0x72, 0x6f, 0x3f, 0x5d, 0x18, 0xa9, 0x2e, 0x26, 0x13, 0x9b, + 0xde, 0xa8, 0x36, 0x5e, 0xd5, 0xc7, 0xb5, 0x91, 0x8d, 0x93, 0x69, 0x23, + 0x19, 0x73, 0x47, 0x29, 0xe1, 0x0c, 0x2c, 0x23, 0x1e, 0x09, 0xbe, 0xa3, + 0x21, 0x5e, 0x54, 0xf3, 0xb8, 0xa7, 0x14, 0x78, 0xec, 0x76, 0xf8, 0x2c, + 0x35, 0x8a, 0x8c, 0x0b, 0xaf, 0xff, 0x61, 0x7c, 0x7f, 0xc0, 0xba, 0x0b, + 0x01, 0xff, 0xfe, 0xf1, 0x09, 0x3e, 0xbe, 0x06, 0x3e, 0x66, 0xfb, 0x19, + 0xad, 0xbf, 0x34, 0x52, 0x5f, 0x4e, 0x31, 0x4f, 0x7c, 0x7e, 0x2f, 0xd5, + 0xc8, 0x26, 0x72, 0xb7, 0xfb, 0xc8, 0x8b, 0xde, 0x44, 0xfc, 0x0e, 0x06, + 0x1f, 0x47, 0xf7, 0x8a, 0x2a, 0x75, 0x86, 0x36, 0xbf, 0xc0, 0xba, 0x2d, + 0x71, 0x13, 0x5f, 0x6f, 0x0c, 0xb2, 0xb1, 0xb9, 0x9d, 0xeb, 0xfe, 0x8d, + 0xf3, 0x19, 0x79, 0xdf, 0xb0, 0xef, 0xfb, 0x11, 0xe7, 0xbb, 0x77, 0x81, + 0xc5, 0x3b, 0xe1, 0x34, 0xfd, 0x1e, 0x1c, 0x7b, 0x3b, 0xce, 0x79, 0x93, + 0x5c, 0x17, 0xfe, 0xc3, 0x99, 0xc7, 0x67, 0xbd, 0xf7, 0x39, 0x99, 0x2e, + 0xd3, 0x57, 0x1d, 0xae, 0x93, 0xa9, 0x7e, 0x2a, 0x8a, 0x2e, 0xe2, 0xdc, + 0x5f, 0x19, 0x3b, 0xf7, 0x71, 0x07, 0x3c, 0xc9, 0xf9, 0x7f, 0x96, 0xf3, + 0xef, 0x46, 0x33, 0xf3, 0xd6, 0x4d, 0x97, 0x5c, 0xa9, 0xde, 0xe7, 0x7c, + 0x6c, 0x98, 0x8b, 0x11, 0x1d, 0x7a, 0x14, 0xc9, 0xf3, 0x7c, 0x36, 0xbd, + 0x9b, 0xfa, 0x1c, 0x6d, 0x37, 0x1e, 0xe1, 0x1e, 0x53, 0x8b, 0x7f, 0x17, + 0x72, 0xfb, 0x3c, 0x0f, 0x97, 0xf1, 0x0e, 0x39, 0x47, 0x78, 0xd2, 0x6f, + 0x35, 0x2a, 0xf0, 0xb5, 0xcc, 0x75, 0x85, 0xe2, 0x7b, 0x21, 0xee, 0x6e, + 0x3f, 0x6f, 0x53, 0x12, 0x3b, 0x6a, 0xce, 0x39, 0xac, 0x05, 0x98, 0x88, + 0x06, 0x30, 0x9e, 0x47, 0xac, 0xb2, 0xcc, 0x93, 0x72, 0xf2, 0x5b, 0xd5, + 0x1a, 0xc6, 0x56, 0x4e, 0x72, 0x2e, 0xf9, 0x51, 0xb4, 0x36, 0x88, 0xcf, + 0x44, 0x87, 0xb9, 0xe6, 0x87, 0x07, 0x65, 0x7e, 0xbb, 0x21, 0x7f, 0xeb, + 0x98, 0xc7, 0x7c, 0x02, 0x0f, 0x8b, 0xa2, 0x76, 0xc3, 0x14, 0xf5, 0x9e, + 0x29, 0x96, 0x7a, 0x32, 0x54, 0x52, 0xc8, 0xd1, 0x14, 0xe7, 0x08, 0x3a, + 0xd1, 0x73, 0x58, 0xcb, 0x2d, 0x53, 0xf8, 0xc8, 0xa3, 0xbe, 0xad, 0x58, + 0x62, 0x85, 0x76, 0xb1, 0xc7, 0x47, 0x51, 0x72, 0xa7, 0x35, 0x45, 0x6d, + 0x38, 0xf7, 0x23, 0xcc, 0xcd, 0x6b, 0x62, 0x2d, 0xf3, 0x79, 0xb6, 0x2c, + 0x9d, 0x83, 0x8f, 0xce, 0xf7, 0x77, 0x11, 0x43, 0xf9, 0x3c, 0xcb, 0x23, + 0xe6, 0x59, 0x26, 0x5f, 0xf6, 0xef, 0x62, 0xff, 0xef, 0xf4, 0x80, 0x0f, + 0x72, 0xc7, 0xb7, 0x87, 0x79, 0x1a, 0x63, 0x58, 0x06, 0x17, 0xd9, 0x3e, + 0x8a, 0x82, 0xc5, 0x38, 0x47, 0xc1, 0x5a, 0xe6, 0xca, 0xb7, 0x90, 0xa7, + 0xd7, 0x69, 0xa1, 0x5c, 0x8f, 0xdf, 0x11, 0x72, 0x12, 0xfe, 0x5d, 0xc0, + 0x12, 0x4d, 0x7c, 0xd7, 0xd2, 0xef, 0x80, 0x73, 0xf8, 0x45, 0x1e, 0x83, + 0x73, 0x79, 0xd6, 0xe1, 0x7f, 0x01, 0x17, 0xc6, 0xf1, 0xb2, 0x84, 0x14, + 0x00, 0x00, 0x00 }; +static u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b09FwBss[(0x250/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b09FwSbss[(0x34/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_09 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, .start_addr = 0x08000860, .text_addr = 0x08000800, - .text_len = 0x1864, + .text_len = 0x1480, .text_index = 0x0, .gz_text = bnx2_TPAT_b09FwText, .gz_text_len = sizeof(bnx2_TPAT_b09FwText), - .data_addr = 0x08002080, + .data_addr = 0x08001ca0, .data_len = 0x0, .data_index = 0x0, .data = bnx2_TPAT_b09FwData, - .sbss_addr = 0x08002088, - .sbss_len = 0x2c, + .sbss_addr = 0x08001ca0, + .sbss_len = 0x34, .sbss_index = 0x0, .sbss = bnx2_TPAT_b09FwSbss, - .bss_addr = 0x080020c0, - .bss_len = 0x850, + .bss_addr = 0x08001ce0, + .bss_len = 0x250, .bss_index = 0x0, .bss = bnx2_TPAT_b09FwBss, @@ -3279,769 +3308,732 @@ static struct fw_info bnx2_tpat_fw_09 = { }; static u8 bnx2_TXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c, - 0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1, - 0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42, - 0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48, - 0xd1, 0x6c, 0x68, 0x95, 0x49, 0x94, 0x54, 0xe3, 0x62, 0x41, 0x52, 0xf1, - 0xb6, 0xce, 0x54, 0x9b, 0x78, 0x5a, 0x4d, 0xeb, 0xad, 0x11, 0x90, 0xfa, - 0xe7, 0x85, 0x04, 0xda, 0x62, 0x44, 0x7f, 0xc8, 0x07, 0x18, 0x80, 0x24, - 0x6f, 0xf2, 0x44, 0x28, 0x9b, 0x7f, 0xfd, 0xd0, 0xac, 0x50, 0x4a, 0xd6, - 0xba, 0x9b, 0xb4, 0xa3, 0xed, 0x66, 0x67, 0x3b, 0xd3, 0x2f, 0x1c, 0x49, - 0xf6, 0x7a, 0x77, 0x67, 0x36, 0xda, 0x6e, 0xb6, 0xab, 0xb6, 0xb2, 0xd1, - 0xdf, 0xef, 0xbe, 0xf7, 0x28, 0x90, 0xa6, 0x6c, 0xcb, 0xb3, 0xed, 0x94, - 0x33, 0x18, 0xe0, 0xdd, 0x77, 0xdf, 0xb9, 0xe7, 0x9e, 0x73, 0xee, 0x39, - 0xe7, 0x77, 0xee, 0x7d, 0x0c, 0x8b, 0x74, 0x89, 0xf7, 0xf7, 0x00, 0x3e, - 0x91, 0x43, 0x87, 0x9f, 0xd9, 0x3e, 0xb2, 0xfd, 0x13, 0xf8, 0xf9, 0x09, - 0x31, 0x02, 0x06, 0x6f, 0xbe, 0x69, 0x88, 0x64, 0xff, 0x42, 0x3e, 0xf0, - 0x1f, 0x1e, 0x37, 0x7d, 0xfa, 0xfc, 0x48, 0x50, 0x4f, 0x4c, 0xec, 0x4a, - 0x5a, 0x12, 0x34, 0x12, 0xb2, 0x6f, 0xca, 0x12, 0xb1, 0x9d, 0xa1, 0x48, - 0x4a, 0xde, 0x6a, 0xe6, 0x43, 0x01, 0x61, 0xfb, 0x47, 0x12, 0x77, 0x9e, - 0xfb, 0xc9, 0xa7, 0xa3, 0xb7, 0xca, 0x86, 0x04, 0xcd, 0x44, 0x56, 0xcc, - 0x01, 0x09, 0xf6, 0xe1, 0x99, 0x6f, 0x3f, 0x6a, 0x18, 0xd2, 0xb3, 0xca, - 0xab, 0xcc, 0x95, 0x56, 0x9a, 0x3f, 0x79, 0x34, 0x2c, 0xbf, 0x57, 0x0f, - 0xc9, 0xf7, 0xea, 0xa6, 0x5c, 0xac, 0x07, 0xb4, 0xf1, 0x92, 0x29, 0xb3, - 0xa5, 0x69, 0xfd, 0x48, 0x31, 0x2f, 0xa9, 0x7a, 0x56, 0x2f, 0x2c, 0x98, - 0x3d, 0xc9, 0xf3, 0x39, 0x7d, 0x76, 0xa1, 0xb7, 0x27, 0x75, 0x7e, 0x5a, - 0x2f, 0x14, 0xc3, 0x3d, 0xc9, 0xba, 0xd9, 0x93, 0x5a, 0x0c, 0xe1, 0xba, - 0xb7, 0x27, 0xb9, 0x18, 0x9d, 0x17, 0xd9, 0x8a, 0x3e, 0xe1, 0x9e, 0x54, - 0x29, 0x9a, 0x15, 0xe9, 0x8f, 0xbf, 0x2a, 0x7d, 0x3d, 0xa9, 0xfa, 0x3f, - 0xd1, 0x1b, 0xa6, 0x26, 0x85, 0x5f, 0x15, 0x33, 0x9c, 0xb8, 0xd5, 0x7c, - 0xc8, 0xd2, 0xc4, 0xb4, 0x6e, 0x37, 0xb7, 0x58, 0x41, 0xc9, 0x9d, 0xee, - 0x14, 0x5b, 0xcd, 0xc9, 0x94, 0xdc, 0xe2, 0x90, 0xb9, 0x2c, 0x6d, 0x62, - 0x87, 0xfc, 0xeb, 0x66, 0x33, 0x19, 0xff, 0x32, 0xe5, 0x8a, 0x71, 0xa4, - 0x67, 0xbc, 0x2e, 0x92, 0x2c, 0x05, 0x25, 0x19, 0x7f, 0xab, 0xe9, 0x3e, - 0x13, 0xc4, 0x98, 0x81, 0x9e, 0xb1, 0x52, 0xb3, 0x99, 0x8e, 0x83, 0x7e, - 0xdc, 0x7f, 0xb6, 0x4d, 0xca, 0x21, 0xbb, 0x3c, 0x1b, 0xff, 0x6f, 0xba, - 0xab, 0x13, 0xce, 0x91, 0xd7, 0xb6, 0xe8, 0x56, 0x5e, 0x72, 0x21, 0x29, - 0x17, 0xe2, 0x9f, 0x92, 0x13, 0xf1, 0x30, 0xe6, 0x17, 0x94, 0x63, 0x71, - 0xc8, 0xd1, 0x3a, 0xac, 0x25, 0xeb, 0xd1, 0x48, 0x56, 0x9e, 0x97, 0xe4, - 0x62, 0xbf, 0x99, 0x16, 0x8c, 0x6d, 0x35, 0x3f, 0x9a, 0x8c, 0x63, 0xbc, - 0xe1, 0xff, 0xd5, 0xb4, 0x43, 0xd1, 0x6c, 0x59, 0x06, 0xa5, 0x50, 0xea, - 0x8f, 0xff, 0x4c, 0x34, 0x09, 0x5a, 0x62, 0x4f, 0x59, 0x26, 0xe4, 0x16, - 0x1d, 0x4c, 0x19, 0x4d, 0xd9, 0x83, 0xf1, 0x93, 0x16, 0xee, 0xd7, 0x65, - 0xb3, 0x6e, 0xb5, 0x4b, 0xc1, 0x94, 0x50, 0x97, 0x3c, 0x22, 0x85, 0xd3, - 0x68, 0x8f, 0xdb, 0xbd, 0x3a, 0x9e, 0xc9, 0x8c, 0xb0, 0x4d, 0x34, 0x23, - 0x11, 0x33, 0x53, 0xe0, 0xa8, 0xe2, 0x0c, 0x62, 0xfc, 0x98, 0xdd, 0xa9, - 0x99, 0xb2, 0x62, 0x06, 0xa4, 0xea, 0xc4, 0xec, 0xb0, 0xd6, 0x2e, 0xc7, - 0x62, 0x5d, 0x90, 0x69, 0x18, 0xb4, 0xe5, 0x9b, 0x7a, 0x22, 0x16, 0xce, - 0x41, 0x51, 0x3a, 0x64, 0x35, 0x07, 0x7e, 0xe6, 0xe2, 0x59, 0x2d, 0x55, - 0xff, 0x8a, 0x96, 0x3c, 0xbf, 0x5f, 0xdb, 0x75, 0x1e, 0x7d, 0xea, 0xe7, - 0x3c, 0xbb, 0x0b, 0x83, 0x37, 0x1d, 0xcf, 0xb2, 0x1d, 0x3c, 0x2b, 0xde, - 0xd1, 0x06, 0x5d, 0x36, 0x26, 0x43, 0x3d, 0x49, 0xa5, 0x4b, 0xf2, 0xa6, - 0x4b, 0x6e, 0x42, 0x93, 0x5e, 0xcb, 0x96, 0xe0, 0x27, 0xa1, 0xcf, 0x45, - 0xe8, 0x72, 0x31, 0x22, 0x47, 0x4a, 0x12, 0xd2, 0x85, 0x63, 0x65, 0xf5, - 0xaa, 0x43, 0x7b, 0x80, 0x6e, 0xa1, 0xfb, 0x82, 0xc3, 0x67, 0xa1, 0xc3, - 0x52, 0x1a, 0xf2, 0xc9, 0x60, 0xec, 0x7d, 0xda, 0x9e, 0xea, 0xa4, 0x96, - 0x81, 0x9d, 0x14, 0x4e, 0x0f, 0x41, 0x77, 0xd1, 0xc8, 0x8a, 0x6c, 0x96, - 0x82, 0x65, 0x45, 0xbe, 0x2c, 0xdd, 0x72, 0x6c, 0xd1, 0x92, 0x23, 0x8b, - 0x21, 0xc9, 0x9b, 0x51, 0xb3, 0x26, 0x7d, 0xd9, 0x4d, 0x89, 0x1e, 0x79, - 0xfe, 0x74, 0x34, 0x53, 0x96, 0x7e, 0xfb, 0x75, 0xdc, 0xcf, 0x9d, 0xa4, - 0x4e, 0x25, 0x9f, 0x8a, 0x1b, 0x92, 0x85, 0x4d, 0x18, 0xd6, 0x1f, 0x81, - 0xff, 0xe6, 0x73, 0xc9, 0x78, 0x34, 0x2c, 0xa2, 0x4b, 0xea, 0x0b, 0xfd, - 0xe6, 0x6e, 0x89, 0x9a, 0x19, 0xca, 0x3f, 0x3e, 0x04, 0x3d, 0xfc, 0x77, - 0xca, 0x1e, 0xb4, 0xa8, 0xe3, 0xa1, 0xf0, 0x31, 0xe8, 0x32, 0xab, 0x74, - 0xdc, 0x83, 0xf1, 0x03, 0x9e, 0xed, 0xf4, 0x48, 0xbe, 0x7a, 0xc3, 0x93, - 0x43, 0x8f, 0xcc, 0x57, 0xbb, 0xa5, 0x00, 0x1d, 0x16, 0xc4, 0x92, 0xc2, - 0xf9, 0x3f, 0xf7, 0xda, 0x2d, 0x99, 0x3b, 0xff, 0x32, 0xec, 0xe1, 0xb0, - 0xb6, 0xbf, 0xfe, 0x0b, 0xcd, 0xb3, 0x1f, 0xd8, 0x5f, 0x50, 0xec, 0x89, - 0xa0, 0x9c, 0xab, 0xbb, 0xf6, 0x57, 0xc1, 0x1a, 0xb3, 0x4d, 0x1b, 0xb6, - 0xf4, 0xc6, 0x6a, 0x9f, 0x73, 0xf5, 0x3e, 0x3c, 0x1b, 0x94, 0x23, 0x75, - 0xf6, 0xcf, 0xc3, 0xc6, 0x82, 0xb2, 0xf4, 0x68, 0xb7, 0x64, 0xd1, 0x5e, - 0x58, 0x14, 0x3b, 0x19, 0xd7, 0xf1, 0x4c, 0x0f, 0xe6, 0xb2, 0x15, 0x9f, - 0x2e, 0x99, 0xaa, 0x76, 0xd8, 0x86, 0x15, 0x92, 0xa9, 0x3a, 0xf5, 0x8f, - 0xef, 0x92, 0x6f, 0x03, 0x94, 0x2f, 0xdb, 0xf9, 0x1c, 0xdb, 0x4d, 0xb4, - 0xb7, 0xb6, 0xd1, 0xb6, 0x37, 0x53, 0xa6, 0x83, 0x82, 0xb6, 0x5c, 0x29, - 0x66, 0xee, 0xe7, 0x77, 0x9d, 0xf6, 0xd0, 0x6a, 0x0b, 0x01, 0xf4, 0x87, - 0x1e, 0xab, 0x18, 0xeb, 0xf4, 0x9d, 0x66, 0xdb, 0x08, 0xae, 0x2d, 0x2c, - 0xaa, 0x2e, 0x8e, 0x1d, 0x00, 0x5f, 0xba, 0x64, 0xab, 0x8a, 0xb7, 0x08, - 0x6d, 0xc0, 0x9d, 0x47, 0x9f, 0xcc, 0x2e, 0x76, 0xf7, 0xa4, 0x17, 0xd9, - 0x9e, 0x0c, 0x1b, 0x98, 0xe7, 0x54, 0x5c, 0x1a, 0x73, 0x71, 0xbd, 0x3f, - 0x00, 0xbe, 0xa6, 0xb1, 0xe0, 0x30, 0x0f, 0x8f, 0xc7, 0x06, 0xee, 0xf7, - 0xca, 0xd4, 0x79, 0xf6, 0xe5, 0x18, 0x85, 0x2d, 0xba, 0x24, 0xc0, 0x1b, - 0x3e, 0x56, 0x14, 0xf7, 0x3b, 0x31, 0x4e, 0x37, 0x6c, 0x27, 0x83, 0x31, - 0x9b, 0x8f, 0x27, 0xe3, 0xbd, 0x92, 0x5d, 0xed, 0x2b, 0xb0, 0x3b, 0xf6, - 0x1f, 0x5c, 0xd7, 0x17, 0xf2, 0x3d, 0x0f, 0x9a, 0x8b, 0x9d, 0x90, 0x21, - 0xdb, 0x75, 0xf0, 0xdc, 0x01, 0x1e, 0x82, 0x98, 0x4f, 0x3f, 0xd6, 0x43, - 0x07, 0xe8, 0x6f, 0xc2, 0x9c, 0x3a, 0x65, 0xfa, 0x74, 0x2f, 0x74, 0x61, - 0xa2, 0x6f, 0x50, 0x9e, 0x2f, 0x45, 0x61, 0x03, 0xec, 0x0f, 0x1d, 0x2c, - 0x46, 0xc3, 0x55, 0xb1, 0x65, 0x2e, 0xde, 0x01, 0xfb, 0x6a, 0x36, 0x67, - 0x60, 0x1f, 0xdf, 0x51, 0xfe, 0x62, 0xc8, 0x1c, 0xd3, 0x24, 0xdf, 0x91, - 0x38, 0x0c, 0x7e, 0xa2, 0x4f, 0x89, 0xf0, 0x7a, 0x87, 0xc6, 0x35, 0x0b, - 0x39, 0x72, 0x6c, 0xf8, 0xa4, 0xad, 0x90, 0x21, 0xfd, 0x56, 0x1f, 0xec, - 0x39, 0xac, 0xfc, 0xc9, 0xd8, 0x86, 0xfe, 0x24, 0x3a, 0x51, 0xc6, 0x58, - 0x85, 0xf3, 0x01, 0xfa, 0xb0, 0x51, 0x2c, 0x57, 0x79, 0x00, 0x6b, 0x6f, - 0x56, 0xd9, 0xc7, 0x09, 0xce, 0xb7, 0xf9, 0xf9, 0x38, 0xf9, 0xe2, 0x7c, - 0x6d, 0x3c, 0x4b, 0x1b, 0x8c, 0x1e, 0xb6, 0xd5, 0xf8, 0x27, 0xbc, 0xf1, - 0x5d, 0xde, 0x0b, 0xa5, 0x1e, 0x2d, 0xa5, 0x78, 0xf0, 0xe9, 0x88, 0x2c, - 0x9f, 0xec, 0x37, 0xf7, 0xc0, 0x86, 0xe9, 0xa7, 0x96, 0x2f, 0x50, 0xc7, - 0xa0, 0x31, 0x42, 0x1d, 0x9b, 0x8a, 0xbf, 0xe4, 0x22, 0xd7, 0x9e, 0xf4, - 0x19, 0x42, 0x1f, 0x01, 0x9f, 0x8b, 0xb5, 0x38, 0xeb, 0xad, 0xc5, 0x9c, - 0x43, 0xfb, 0x7b, 0x06, 0xcf, 0xea, 0x32, 0x16, 0xa3, 0x7f, 0x78, 0x5e, - 0x52, 0xf0, 0x91, 0xd0, 0xa3, 0x54, 0x31, 0x97, 0x4a, 0xa9, 0xd5, 0x6f, - 0xc1, 0xb6, 0x86, 0xff, 0xae, 0xe9, 0xfa, 0x43, 0xfa, 0x06, 0xfa, 0x9a, - 0x82, 0xa9, 0x43, 0x72, 0x3a, 0x9c, 0x21, 0x74, 0x13, 0x4f, 0x1a, 0xd1, - 0x4c, 0x16, 0x7c, 0x4d, 0x59, 0x4d, 0xb1, 0x1e, 0x13, 0x44, 0x0c, 0xf4, - 0xa9, 0xcb, 0x4e, 0xdf, 0x3f, 0x2d, 0x3b, 0xbe, 0x2e, 0xa8, 0x57, 0xea, - 0xc1, 0xf7, 0x11, 0x01, 0xb9, 0x0c, 0xdf, 0x35, 0x57, 0xea, 0x96, 0x06, - 0x78, 0xba, 0xe2, 0xf8, 0xb6, 0x66, 0x78, 0xb6, 0xc6, 0x67, 0xba, 0xf1, - 0x7c, 0x00, 0x7e, 0x4d, 0xf2, 0x46, 0x02, 0xbf, 0x8b, 0xa4, 0xc9, 0x36, - 0xdf, 0xce, 0xb9, 0x66, 0xa2, 0x76, 0x59, 0xda, 0x25, 0x13, 0x43, 0xfc, - 0x58, 0xd4, 0x31, 0x56, 0x1f, 0x7c, 0x79, 0x40, 0x0e, 0x96, 0x42, 0xf2, - 0xd5, 0x12, 0xe7, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xb1, 0x09, 0x9d, - 0x8f, 0xc3, 0xe7, 0x65, 0xb4, 0x31, 0xf8, 0x9f, 0xdd, 0xd5, 0xaf, 0x68, - 0xe9, 0xf3, 0x59, 0x6d, 0xbc, 0xbe, 0x5f, 0xcb, 0x9c, 0x9f, 0xd4, 0x76, - 0xb5, 0xf8, 0x22, 0xd1, 0xde, 0xdd, 0x17, 0x9d, 0x38, 0xcd, 0x31, 0xfb, - 0xe3, 0x1b, 0xfb, 0xa2, 0x5f, 0x6a, 0xad, 0xbe, 0xa8, 0x1f, 0xbe, 0x28, - 0x03, 0x5f, 0x34, 0x7e, 0xdf, 0xbe, 0xa8, 0x5d, 0xdf, 0xd8, 0x17, 0x75, - 0xeb, 0x77, 0x7d, 0x11, 0x63, 0xcf, 0xbf, 0xc6, 0xb5, 0x29, 0xdb, 0x76, - 0xfa, 0x72, 0x0e, 0xc3, 0x0f, 0x6f, 0x82, 0xac, 0xbb, 0xb8, 0x76, 0x22, - 0x05, 0xd8, 0xfd, 0x34, 0xc6, 0xfa, 0x4d, 0xd8, 0xfb, 0xb6, 0x98, 0x65, - 0x3e, 0xa1, 0xc6, 0x7d, 0xa7, 0xce, 0xc7, 0x56, 0x75, 0x4e, 0x1e, 0xdf, - 0x53, 0xe7, 0xb6, 0xab, 0x73, 0xea, 0xba, 0x53, 0x66, 0xd4, 0xb8, 0x4d, - 0x09, 0x3c, 0x26, 0xf0, 0x2a, 0xf2, 0x59, 0x23, 0x11, 0x05, 0x3d, 0x1d, - 0xe3, 0x53, 0x5f, 0x31, 0xf0, 0x20, 0xd0, 0x6f, 0xb7, 0xf2, 0x45, 0xbb, - 0xa0, 0xf7, 0x65, 0xe7, 0xfe, 0x74, 0x95, 0x69, 0xd1, 0xd5, 0x9e, 0x35, - 0xba, 0xea, 0x90, 0xe1, 0x98, 0xaf, 0xa3, 0xcd, 0x92, 0x8c, 0x51, 0x67, - 0xf7, 0xa3, 0xab, 0x7f, 0xaa, 0xff, 0xfd, 0xe8, 0xea, 0xb7, 0xee, 0xa1, - 0xab, 0x7f, 0xb5, 0x4e, 0x57, 0x96, 0xf9, 0x82, 0x46, 0xda, 0x8c, 0x1f, - 0xf4, 0x47, 0xcd, 0x8f, 0x4e, 0x31, 0x7f, 0xa8, 0x73, 0x4d, 0xfb, 0x79, - 0x07, 0xd7, 0xf3, 0xa5, 0xa6, 0x61, 0x59, 0x90, 0x1d, 0xd7, 0x34, 0xe5, - 0x16, 0x35, 0x3f, 0x4f, 0xfe, 0x11, 0x3b, 0xa6, 0x10, 0x6b, 0x5c, 0x1e, - 0xda, 0xa5, 0xbc, 0xc5, 0xed, 0x3f, 0x55, 0x6a, 0xfe, 0x42, 0x4f, 0xbc, - 0xdd, 0x4c, 0x8e, 0x58, 0x5e, 0x1c, 0x08, 0xca, 0xd7, 0xaa, 0xd1, 0xac, - 0xad, 0x75, 0x4b, 0xfe, 0x41, 0xc4, 0x9e, 0x12, 0xfd, 0xd7, 0xd6, 0x7b, - 0xc4, 0xe8, 0x3e, 0x2f, 0x46, 0x57, 0xc1, 0x2b, 0xf3, 0xab, 0xef, 0xbe, - 0xd5, 0x08, 0xf1, 0x3b, 0x66, 0xee, 0x93, 0x2f, 0x73, 0x8e, 0x88, 0xf7, - 0x8c, 0xfb, 0x16, 0x73, 0x9e, 0x7c, 0x20, 0xd1, 0x25, 0xf9, 0x2d, 0x5c, - 0x8f, 0xf4, 0x73, 0xf4, 0x5d, 0xed, 0x1e, 0xdf, 0x7e, 0x8e, 0xa4, 0x78, - 0x33, 0x30, 0x65, 0xf4, 0x41, 0x3e, 0x54, 0xe2, 0x3c, 0xde, 0xf2, 0xec, - 0x89, 0xb9, 0x82, 0xb4, 0xb9, 0xbe, 0x61, 0x2f, 0x72, 0x01, 0xda, 0x81, - 0xaf, 0x73, 0xea, 0x9b, 0x39, 0x82, 0x44, 0x74, 0x8b, 0x39, 0x82, 0x98, - 0x46, 0x62, 0x9f, 0x66, 0x43, 0xf7, 0x36, 0x74, 0x6f, 0x43, 0xf7, 0x36, - 0x74, 0x9f, 0xac, 0x1f, 0xc6, 0x3d, 0x95, 0x87, 0x80, 0x17, 0x97, 0x7e, - 0xda, 0xa5, 0x0f, 0x3e, 0xb7, 0x4a, 0x4e, 0xe9, 0x84, 0xf3, 0x45, 0xae, - 0xa1, 0xfc, 0xf5, 0xb8, 0xe6, 0xfa, 0x6b, 0xd2, 0xcb, 0xe0, 0xf9, 0xdb, - 0x98, 0xa7, 0xad, 0xeb, 0xd6, 0x5d, 0x99, 0xcc, 0xb5, 0xc8, 0x64, 0xd6, - 0xa1, 0x8c, 0xd8, 0x9f, 0x3e, 0x77, 0x5a, 0xaf, 0xac, 0xca, 0x65, 0x2f, - 0x78, 0xe8, 0xe0, 0xdc, 0xbd, 0x79, 0x90, 0x7e, 0xaf, 0x47, 0xff, 0x6f, - 0xd1, 0x87, 0xfe, 0x75, 0xa3, 0x71, 0x39, 0x26, 0x73, 0xc6, 0x77, 0x9b, - 0x0f, 0x72, 0x66, 0xac, 0x81, 0xef, 0x21, 0x96, 0x5f, 0x44, 0x2c, 0x59, - 0x31, 0x22, 0xf2, 0x93, 0x47, 0xaf, 0x21, 0x97, 0x96, 0xfc, 0xc3, 0x89, - 0x66, 0x24, 0x90, 0x78, 0xab, 0x39, 0x37, 0x82, 0x18, 0x97, 0x88, 0x86, - 0x93, 0xc6, 0xb0, 0x5c, 0xaa, 0x0f, 0xca, 0x8f, 0xea, 0x96, 0xfc, 0xb0, - 0x1e, 0x91, 0x1f, 0x20, 0xe6, 0x7f, 0xbf, 0xde, 0x9a, 0x73, 0x47, 0x68, - 0x4f, 0x3d, 0xe9, 0xfa, 0x46, 0xb9, 0x7f, 0x13, 0x34, 0xde, 0x82, 0x9d, - 0x04, 0xb2, 0xc8, 0xf5, 0x19, 0xbf, 0x26, 0x0e, 0x15, 0x9f, 0x6b, 0x82, - 0xb7, 0x6c, 0x5b, 0xc2, 0xca, 0xeb, 0x7a, 0xf7, 0xa8, 0xf9, 0x29, 0xb4, - 0x39, 0xa3, 0x81, 0x6a, 0xb1, 0x53, 0xe5, 0x8b, 0xd0, 0x91, 0xd8, 0xf5, - 0x60, 0xb0, 0x56, 0xbc, 0x85, 0x7e, 0xcd, 0xe6, 0xa1, 0xf8, 0x6f, 0xed, - 0x30, 0xff, 0x81, 0x85, 0x35, 0xdd, 0xf9, 0x25, 0x23, 0xb1, 0x49, 0x66, - 0x43, 0xdf, 0x6f, 0x98, 0x03, 0x7d, 0x59, 0x3d, 0x11, 0x94, 0x74, 0x91, - 0x6b, 0x2a, 0x24, 0xb3, 0x55, 0x28, 0xff, 0x3c, 0xd7, 0x85, 0x3c, 0x3b, - 0x17, 0xef, 0x86, 0xed, 0xff, 0x9a, 0xe1, 0xae, 0x03, 0x18, 0x50, 0x75, - 0x50, 0xf2, 0xe0, 0x37, 0x5f, 0x7f, 0xcb, 0xc3, 0x0e, 0xf0, 0x2a, 0x5b, - 0x21, 0xf8, 0xc4, 0x70, 0xda, 0x76, 0xfe, 0x30, 0x88, 0xb6, 0xe0, 0x56, - 0xeb, 0xce, 0x26, 0x7c, 0x3f, 0x10, 0xb2, 0x88, 0x4d, 0x24, 0xf3, 0x05, - 0x7c, 0xff, 0x4a, 0x42, 0x36, 0xf7, 0xe2, 0x7b, 0x4b, 0x02, 0x26, 0x99, - 0x60, 0xcc, 0xd5, 0x5a, 0x62, 0xae, 0x68, 0x69, 0xc8, 0x6e, 0x0e, 0x73, - 0x4f, 0x43, 0x9e, 0x5f, 0xac, 0x07, 0xb5, 0xd4, 0xe9, 0x47, 0xc0, 0x87, - 0x9f, 0x3b, 0x23, 0x3f, 0x33, 0x97, 0xb7, 0x04, 0xe4, 0x16, 0x7c, 0x5c, - 0x12, 0x7e, 0xcc, 0x46, 0x6e, 0xb1, 0x03, 0xcb, 0x35, 0xfa, 0x5f, 0xbf, - 0x20, 0x5f, 0xf3, 0x78, 0x6b, 0x93, 0x05, 0x65, 0xa3, 0x6c, 0xcf, 0x67, - 0xfe, 0xcd, 0xc0, 0xdd, 0xf6, 0x17, 0x57, 0xdb, 0xcb, 0x99, 0x7f, 0xb8, - 0xda, 0xde, 0xdb, 0xe6, 0xf2, 0x3f, 0xaa, 0x4d, 0xd4, 0xf7, 0x78, 0x6d, - 0xb7, 0xa1, 0xb3, 0x66, 0x93, 0xb9, 0x45, 0x01, 0xd8, 0x24, 0x1d, 0xa7, - 0x2f, 0xbe, 0x1f, 0x5f, 0xbb, 0xc6, 0xcf, 0x9a, 0x49, 0x83, 0xb6, 0x10, - 0x14, 0x97, 0x26, 0xef, 0x77, 0x20, 0x7f, 0xbf, 0x8d, 0xdf, 0x8c, 0xa3, - 0x7e, 0x6e, 0xce, 0x3e, 0x7c, 0xfe, 0xcd, 0x7b, 0xd8, 0x4b, 0x08, 0xf6, - 0xf2, 0xff, 0xab, 0x5d, 0x5c, 0xba, 0x1f, 0xbb, 0xc0, 0x9f, 0xb2, 0x0b, - 0xd5, 0xff, 0xd2, 0xea, 0x5a, 0x09, 0x43, 0x3e, 0x8c, 0x07, 0x83, 0xd0, - 0xf1, 0x66, 0x99, 0xb5, 0xc8, 0x8f, 0x15, 0xc9, 0xc1, 0x5f, 0x9e, 0x58, - 0x17, 0xbb, 0xbb, 0x10, 0x0f, 0x8e, 0x9f, 0x8e, 0x8e, 0x32, 0x1e, 0xc4, - 0xe0, 0x1b, 0x93, 0xef, 0x88, 0x07, 0x37, 0x8c, 0xd6, 0x78, 0x60, 0x20, - 0x1e, 0xec, 0x7a, 0x97, 0x78, 0x70, 0xe2, 0x1d, 0xf1, 0x40, 0x83, 0x6c, - 0x38, 0xbf, 0xbf, 0x35, 0xfc, 0x78, 0x50, 0x58, 0x13, 0x0f, 0x7c, 0x5d, - 0x59, 0x0a, 0x0b, 0xdc, 0xd5, 0x5b, 0x97, 0xa7, 0x2b, 0x09, 0x06, 0x12, - 0x8d, 0xcc, 0x9c, 0xf5, 0xb0, 0xb4, 0xc1, 0xe7, 0x5e, 0xaa, 0x8f, 0x40, - 0x67, 0x97, 0x30, 0xf7, 0x68, 0x9c, 0x89, 0x65, 0x5b, 0x82, 0xeb, 0xe1, - 0xcd, 0x08, 0x30, 0xe2, 0x6e, 0xe0, 0xbe, 0xdd, 0x67, 0xd5, 0xfa, 0x78, - 0x33, 0xea, 0x61, 0xf7, 0x6d, 0xc0, 0xee, 0x78, 0x3e, 0x00, 0x4c, 0xc8, - 0xf6, 0x2b, 0x66, 0x12, 0x7a, 0xaa, 0x3a, 0xf6, 0xee, 0x02, 0x3e, 0x73, - 0xaa, 0xef, 0xad, 0x08, 0xfb, 0x76, 0x24, 0x12, 0xd1, 0x3f, 0xc3, 0x77, - 0x7b, 0x22, 0xbc, 0xed, 0xaa, 0x45, 0xba, 0x87, 0xa2, 0x67, 0x15, 0x8d, - 0x80, 0x14, 0xd4, 0xb3, 0x91, 0x6d, 0x7c, 0xf6, 0x18, 0x62, 0xf6, 0x51, - 0xc7, 0x94, 0x23, 0x4e, 0x76, 0x77, 0x0e, 0x1f, 0x62, 0xd5, 0x4b, 0x25, - 0xde, 0x1f, 0xc5, 0xfd, 0x80, 0x30, 0x97, 0xfc, 0x2a, 0xfa, 0x1c, 0x44, - 0x9f, 0x19, 0xc7, 0xd7, 0x05, 0xef, 0x37, 0x32, 0x29, 0xdc, 0x9f, 0x29, - 0x36, 0x32, 0xe9, 0x22, 0xf3, 0xd6, 0xa1, 0xf0, 0x11, 0xc8, 0x33, 0x8b, - 0x5c, 0xcd, 0x96, 0xe8, 0x60, 0x5e, 0x9e, 0xee, 0x1c, 0x07, 0x4e, 0x3a, - 0x87, 0x1c, 0xc2, 0x9e, 0x8c, 0xc6, 0xcb, 0xf2, 0xe1, 0xce, 0xe4, 0x69, - 0xe4, 0x0b, 0xf1, 0xed, 0x90, 0x61, 0x23, 0xa3, 0xc7, 0x04, 0xb6, 0x1e, - 0x87, 0x5f, 0x1e, 0xd1, 0x53, 0xc5, 0x7e, 0x73, 0x56, 0x1e, 0x95, 0x86, - 0x19, 0x0d, 0x8f, 0xcb, 0x26, 0x49, 0x05, 0xd0, 0x6f, 0xf0, 0x43, 0x92, - 0x0d, 0x53, 0xd6, 0x0f, 0xc2, 0xdf, 0x6b, 0xd2, 0x61, 0xb5, 0xc6, 0x9e, - 0x5b, 0x10, 0x6f, 0x2e, 0x40, 0x9f, 0xdd, 0x61, 0x75, 0x7a, 0x3a, 0xd9, - 0x24, 0xcb, 0xef, 0xe8, 0x77, 0xbb, 0xa5, 0x5f, 0x6b, 0xfb, 0xdb, 0x68, - 0xdf, 0x84, 0x9c, 0xb3, 0x91, 0x09, 0xc4, 0x20, 0x7f, 0xcc, 0xa1, 0x0d, - 0x76, 0x72, 0x15, 0xf3, 0x61, 0x1c, 0x2c, 0x94, 0x99, 0xf7, 0x18, 0x52, - 0x36, 0x71, 0xcf, 0x69, 0x36, 0x2b, 0x16, 0xf8, 0xbd, 0x40, 0x9e, 0x83, - 0x32, 0xee, 0x0c, 0x88, 0x5d, 0xa3, 0x1c, 0xa2, 0xf0, 0x4a, 0x0f, 0x77, - 0xa5, 0x16, 0xa3, 0x76, 0x1e, 0x14, 0x8d, 0x0b, 0x7d, 0x5d, 0x49, 0xe4, - 0x39, 0xfa, 0x85, 0x48, 0x57, 0x0a, 0x36, 0x6b, 0x5c, 0x78, 0xa8, 0x2b, - 0x7d, 0x9a, 0x7c, 0x19, 0xc8, 0x73, 0x3e, 0x0a, 0x9c, 0xdf, 0x94, 0xdf, - 0x45, 0x2e, 0x5b, 0x18, 0x44, 0x0e, 0x80, 0xd5, 0xaf, 0x83, 0xef, 0xbc, - 0x29, 0xc1, 0xae, 0xc4, 0xab, 0xe0, 0x6f, 0x18, 0xb2, 0xd9, 0x84, 0x3e, - 0x06, 0xda, 0x07, 0x58, 0x13, 0x68, 0x69, 0xb7, 0xba, 0x10, 0x4f, 0x11, - 0xbb, 0x24, 0x98, 0x1c, 0xe9, 0x06, 0xfd, 0x2b, 0x01, 0xe6, 0x82, 0xc1, - 0xd8, 0x6a, 0xfb, 0x37, 0xdd, 0xf6, 0x41, 0xf0, 0xc2, 0xe7, 0x88, 0x09, - 0x24, 0x38, 0x35, 0x62, 0x82, 0x07, 0xf6, 0x0d, 0xa9, 0xbe, 0xe9, 0x45, - 0xda, 0x40, 0x23, 0x53, 0xb1, 0x1e, 0x91, 0xd4, 0xc2, 0x56, 0x19, 0x5f, - 0xe8, 0x95, 0x5d, 0x0b, 0xc4, 0x30, 0xac, 0x69, 0x60, 0x2a, 0xc0, 0x18, - 0xfa, 0x05, 0xe6, 0x76, 0xd1, 0xf0, 0x41, 0xe9, 0x0f, 0x7f, 0x15, 0xeb, - 0x60, 0xca, 0x8a, 0x45, 0x66, 0xb1, 0xc6, 0x02, 0x8a, 0x4e, 0xd8, 0x1f, - 0x93, 0x36, 0xba, 0x66, 0xdc, 0xf4, 0xe2, 0xbd, 0xe8, 0x62, 0xe1, 0x5c, - 0x08, 0xaf, 0xa3, 0xfb, 0x57, 0x1e, 0x5d, 0x13, 0x74, 0xfb, 0x40, 0x93, - 0x73, 0x7c, 0xa8, 0x73, 0xec, 0xb4, 0xd8, 0x1d, 0xe0, 0x2f, 0x1d, 0x7b, - 0x58, 0x66, 0x41, 0xe7, 0xe8, 0x02, 0xfd, 0xa4, 0x6c, 0xc5, 0x67, 0xb8, - 0x4d, 0x62, 0x83, 0xe7, 0x81, 0x73, 0xc6, 0x14, 0x0d, 0x17, 0x73, 0xe8, - 0x17, 0x12, 0xc0, 0xa9, 0x1f, 0x07, 0x3f, 0xcc, 0xb1, 0x38, 0xe7, 0x00, - 0xe6, 0x9b, 0xc0, 0x3a, 0x64, 0x7d, 0x85, 0xeb, 0x1b, 0xbf, 0xcf, 0x87, - 0x3b, 0x53, 0xa7, 0xdb, 0xb1, 0xee, 0xe4, 0x11, 0x43, 0xc5, 0x7e, 0xea, - 0xc5, 0xea, 0x4c, 0x96, 0x14, 0xdf, 0x9d, 0xa9, 0x12, 0x65, 0x14, 0xef, - 0x4c, 0x97, 0x28, 0x23, 0x01, 0x3f, 0x71, 0xd8, 0x64, 0x40, 0x22, 0x5b, - 0xa8, 0xc7, 0x43, 0xe8, 0xf7, 0x57, 0x01, 0xe2, 0xb8, 0xa4, 0xc5, 0xdf, - 0xf0, 0xb5, 0x17, 0x0e, 0xa3, 0x2f, 0x7f, 0x6f, 0x07, 0xdd, 0xfe, 0xc1, - 0x82, 0xb4, 0x0f, 0xce, 0xc0, 0x4f, 0xe8, 0x23, 0xc0, 0x91, 0xca, 0xce, - 0x9b, 0xc0, 0xd8, 0x3b, 0x30, 0x1f, 0xac, 0x8d, 0x98, 0x25, 0xd3, 0xf3, - 0x94, 0xab, 0x7c, 0x08, 0x73, 0xc0, 0xfc, 0x63, 0xf0, 0x2d, 0x9c, 0x03, - 0xc7, 0x16, 0xe4, 0x36, 0x4b, 0x92, 0x9b, 0x0f, 0x2a, 0x2c, 0x6b, 0x9b, - 0x1c, 0x5f, 0xd3, 0xf4, 0x44, 0x17, 0x74, 0xcc, 0xb9, 0xcd, 0x81, 0xb7, - 0x67, 0x10, 0xff, 0xa2, 0x0a, 0x43, 0x19, 0x17, 0xb8, 0x56, 0x46, 0xb1, - 0x4e, 0xc8, 0xbf, 0x67, 0x7b, 0x5a, 0x03, 0x3e, 0x45, 0xf9, 0x7f, 0xe4, - 0xea, 0x09, 0xf8, 0x91, 0x51, 0xf9, 0x7d, 0xf8, 0x92, 0x1f, 0xd7, 0xe3, - 0xc8, 0x1b, 0x86, 0x91, 0x37, 0x0c, 0x22, 0x6f, 0xb0, 0x90, 0x37, 0x44, - 0x90, 0x37, 0xf4, 0x21, 0x6f, 0x08, 0x23, 0x3e, 0x88, 0x1c, 0xad, 0xe7, - 0x61, 0x63, 0x0d, 0xf8, 0x41, 0x33, 0x68, 0xd7, 0x43, 0xc1, 0x64, 0x3d, - 0x1c, 0x4c, 0xd5, 0x03, 0x98, 0xd3, 0x01, 0x8e, 0x89, 0xf9, 0xe5, 0x3b, - 0xc7, 0x4a, 0xc3, 0x88, 0x39, 0x36, 0xfc, 0x52, 0x1a, 0xf1, 0x36, 0x2e, - 0x47, 0xf0, 0xcc, 0xf2, 0x7c, 0x04, 0xcf, 0x34, 0x25, 0x1d, 0x6f, 0x93, - 0x59, 0x33, 0x0e, 0x1a, 0x5b, 0x94, 0x9d, 0x22, 0xdf, 0x6a, 0x83, 0x9d, - 0x4a, 0xae, 0xc8, 0x7c, 0xab, 0x0f, 0xf4, 0x3a, 0x11, 0x97, 0xe9, 0x1f, - 0xe8, 0x0b, 0xec, 0xdd, 0x5f, 0xb2, 0xb8, 0xe6, 0xba, 0xb4, 0xe4, 0xe9, - 0xbc, 0x10, 0x6b, 0x22, 0x0e, 0xc2, 0x2e, 0xd8, 0x36, 0x81, 0xe7, 0xf8, - 0xfb, 0x6d, 0xcf, 0xef, 0x7f, 0x24, 0x28, 0x30, 0xde, 0x4b, 0x8c, 0xf9, - 0x16, 0xe8, 0x39, 0xad, 0xeb, 0xb5, 0xa6, 0x8b, 0xe5, 0xdf, 0x67, 0xfd, - 0x8d, 0x35, 0xc7, 0xd7, 0xc0, 0x73, 0xbf, 0xb9, 0x8c, 0x1c, 0xd9, 0xde, - 0xbf, 0x82, 0xdf, 0xad, 0xfd, 0xeb, 0xe8, 0xaf, 0xda, 0x82, 0x66, 0x22, - 0xce, 0x7c, 0x18, 0x3e, 0x73, 0x10, 0xfe, 0xf1, 0x56, 0x46, 0x5f, 0xba, - 0x89, 0x79, 0x42, 0x9e, 0xc5, 0x5b, 0x99, 0xc0, 0xc0, 0xb5, 0xe6, 0x8b, - 0xc0, 0x37, 0x63, 0x4b, 0x23, 0x92, 0x5a, 0xea, 0x0f, 0x5f, 0x96, 0xce, - 0xdb, 0xb6, 0x5c, 0x6b, 0xce, 0x3a, 0xd1, 0xe3, 0xb6, 0x10, 0x6f, 0x99, - 0x52, 0x01, 0xa9, 0x6d, 0x3b, 0x3b, 0x88, 0x19, 0x2f, 0x8a, 0x1e, 0x91, - 0xe4, 0x29, 0x5b, 0x46, 0x76, 0xfa, 0xb9, 0xfb, 0x9d, 0x0e, 0xe9, 0x42, - 0xdb, 0x52, 0x04, 0x7d, 0x88, 0x53, 0x39, 0xef, 0x2c, 0xe6, 0xac, 0xb9, - 0xcf, 0x78, 0xf5, 0xc9, 0x42, 0x09, 0x73, 0xaf, 0xdf, 0xca, 0x5c, 0x3e, - 0x05, 0xec, 0x0e, 0x1d, 0x25, 0x4f, 0xb1, 0xae, 0xb0, 0x09, 0x72, 0x1a, - 0x83, 0xad, 0xd0, 0x06, 0xfa, 0xf1, 0x6c, 0x53, 0xbe, 0x11, 0xa7, 0x5d, - 0xbc, 0x04, 0x59, 0x82, 0x56, 0xc0, 0x9f, 0x0f, 0x70, 0xde, 0x3c, 0xe5, - 0x17, 0x46, 0x6e, 0xce, 0xb1, 0x25, 0xd8, 0x99, 0x58, 0x9f, 0x77, 0xdf, - 0xca, 0x2c, 0x9f, 0x02, 0xfd, 0x01, 0xd6, 0xde, 0xe0, 0xb3, 0x8b, 0xac, - 0x1d, 0x32, 0x27, 0xdd, 0x05, 0x3d, 0xed, 0x55, 0xb5, 0xb8, 0x64, 0x35, - 0x2e, 0xd6, 0x49, 0xfa, 0x2c, 0x89, 0x18, 0xd6, 0x7e, 0xe4, 0xaf, 0x62, - 0xea, 0x89, 0x49, 0xdc, 0xa3, 0x3c, 0x35, 0xe4, 0x1c, 0xb8, 0x7f, 0x61, - 0x45, 0xe9, 0xc4, 0x80, 0xee, 0x72, 0x3b, 0x99, 0x84, 0xc9, 0xbc, 0x91, - 0x80, 0x2f, 0x1c, 0xe1, 0x1c, 0xd4, 0xd8, 0xc8, 0xc7, 0xb9, 0xfe, 0x30, - 0x67, 0xd8, 0x55, 0x4b, 0x5e, 0xae, 0xfe, 0x66, 0x4b, 0x47, 0x60, 0xd3, - 0x92, 0x6f, 0x43, 0x3e, 0x90, 0x1c, 0xc1, 0x6f, 0x38, 0x81, 0xa3, 0xd0, - 0xe7, 0xd9, 0x11, 0xd6, 0x3f, 0x5f, 0x02, 0xb6, 0x27, 0xdf, 0xb1, 0xc8, - 0x11, 0xb5, 0x86, 0x71, 0xed, 0x30, 0x97, 0xdb, 0x24, 0x97, 0xd5, 0xfc, - 0x1e, 0x22, 0xf6, 0x80, 0x9e, 0xee, 0x67, 0x7e, 0xe3, 0xf7, 0x39, 0x3f, - 0x97, 0x3e, 0x63, 0x57, 0xd2, 0x8a, 0x48, 0xaa, 0x78, 0xa9, 0x19, 0xb0, - 0x2c, 0x60, 0x67, 0x57, 0x8f, 0x29, 0x27, 0x08, 0x3e, 0x58, 0x6b, 0xdb, - 0xa9, 0x74, 0x09, 0x3e, 0x68, 0x3b, 0xf9, 0x60, 0x62, 0xb3, 0x9c, 0x9b, - 0xef, 0x91, 0xca, 0xfc, 0xcf, 0xa5, 0x3a, 0xdf, 0x25, 0xe7, 0xe7, 0x9b, - 0x72, 0x35, 0xae, 0x7c, 0x93, 0xd5, 0xae, 0xd6, 0xb5, 0x3c, 0xec, 0xd6, - 0x61, 0x62, 0xa3, 0xd7, 0xe5, 0x79, 0x39, 0x57, 0x76, 0x79, 0xcf, 0xb4, - 0xf0, 0x7e, 0x15, 0xb6, 0xf6, 0xaa, 0x45, 0xfe, 0x47, 0xa4, 0x52, 0x24, - 0xef, 0xfb, 0x14, 0xef, 0xbb, 0x56, 0x79, 0x97, 0xac, 0x61, 0x91, 0xff, - 0x8d, 0x78, 0xef, 0x90, 0xec, 0x56, 0xf2, 0x1f, 0xc1, 0xb3, 0xef, 0xb4, - 0xbf, 0x8a, 0x73, 0xad, 0xb9, 0x5c, 0x6c, 0x53, 0x3c, 0x1b, 0x89, 0x11, - 0xc8, 0xe7, 0x5a, 0xb3, 0xe1, 0x70, 0x1d, 0xe1, 0xb7, 0xf3, 0x2f, 0xe0, - 0xab, 0x7a, 0x55, 0xce, 0x92, 0x9b, 0xec, 0xee, 0x4c, 0x2e, 0x8e, 0x42, - 0xb7, 0x9d, 0x6a, 0x1d, 0xc2, 0x6d, 0x40, 0x67, 0xff, 0x1e, 0xfd, 0xbf, - 0xcd, 0xf5, 0xa6, 0xe4, 0x92, 0x86, 0x5c, 0x0a, 0xc5, 0xf1, 0x76, 0xe0, - 0x27, 0x8c, 0xd3, 0xc8, 0x64, 0x1d, 0x3e, 0xd3, 0x07, 0xdf, 0xc6, 0xef, - 0xf7, 0x6d, 0x0f, 0x79, 0xf8, 0x5c, 0xe8, 0x1c, 0x79, 0x05, 0xd7, 0xf3, - 0x48, 0x03, 0x31, 0x36, 0x36, 0x58, 0x51, 0xfb, 0x10, 0x71, 0x85, 0x85, - 0x67, 0x9d, 0x6f, 0xe3, 0xe3, 0x8e, 0x37, 0x56, 0xe7, 0x98, 0x6b, 0xe7, - 0x54, 0x70, 0x1a, 0xc8, 0xdf, 0x2d, 0xd0, 0xe5, 0xb8, 0x79, 0x31, 0x12, - 0x06, 0xc6, 0x65, 0x5b, 0x37, 0x7c, 0x4c, 0x04, 0x3e, 0x6b, 0x18, 0xbe, - 0x9f, 0x6b, 0x99, 0x7e, 0xde, 0xe7, 0x7d, 0x18, 0x34, 0xe9, 0x7f, 0x87, - 0x31, 0x67, 0xe6, 0xd8, 0xf4, 0x9f, 0x88, 0x27, 0xb5, 0x70, 0x57, 0xf2, - 0xb4, 0x5b, 0x1b, 0x74, 0x7f, 0xf3, 0xbe, 0x04, 0x1f, 0x49, 0x44, 0xcb, - 0x79, 0xe4, 0x7e, 0x29, 0xac, 0xd1, 0xa4, 0x85, 0x3c, 0xbb, 0x16, 0x7d, - 0x85, 0x98, 0x5b, 0xa7, 0x0c, 0x96, 0x28, 0x27, 0xd6, 0xa9, 0x4c, 0xc9, - 0x57, 0xbe, 0x0b, 0x79, 0x04, 0x65, 0x8b, 0x95, 0x85, 0x4f, 0x01, 0xff, - 0x98, 0xfb, 0x5c, 0x89, 0xb5, 0xc8, 0x7e, 0xc4, 0x31, 0x03, 0x42, 0x40, - 0x4e, 0xb5, 0x64, 0xc8, 0x67, 0x03, 0x43, 0xc8, 0x01, 0x9f, 0x45, 0xdf, - 0x80, 0xe4, 0x97, 0x18, 0x0f, 0x02, 0x32, 0xb7, 0x24, 0x72, 0xfd, 0x14, - 0xfd, 0x8a, 0xfa, 0x83, 0xcc, 0x1b, 0x99, 0x69, 0x62, 0xed, 0x79, 0xfa, - 0x18, 0xfa, 0x89, 0x07, 0xa1, 0x8b, 0xd8, 0x4b, 0xdf, 0x40, 0x6c, 0x9a, - 0x2d, 0xf6, 0xc3, 0x67, 0x4a, 0x43, 0x87, 0x4c, 0x11, 0xd3, 0x98, 0xa3, - 0x6f, 0x50, 0x77, 0xf4, 0x6b, 0x8e, 0x41, 0x29, 0x9c, 0x62, 0xbd, 0x31, - 0x08, 0x5e, 0x98, 0xb7, 0x1a, 0x2a, 0x0f, 0x7a, 0x50, 0xf9, 0x56, 0x7e, - 0x07, 0x5a, 0xc6, 0x8d, 0x1d, 0xdf, 0xa6, 0xd3, 0x8f, 0x3d, 0x22, 0xf6, - 0xc4, 0xa1, 0xce, 0x5d, 0xa5, 0x76, 0x29, 0xf7, 0xd2, 0x2e, 0xa9, 0xff, - 0xac, 0x4e, 0x5f, 0x8b, 0x3c, 0x0c, 0xf4, 0x58, 0x23, 0x08, 0xa0, 0x5f, - 0xc8, 0xeb, 0x47, 0xb9, 0xfe, 0xb6, 0x4c, 0xed, 0xfc, 0x3b, 0xf0, 0xe5, - 0xfa, 0xb5, 0xdc, 0x4e, 0xf8, 0xdb, 0x09, 0x5d, 0x1e, 0xfb, 0x54, 0x1a, - 0xcf, 0x32, 0x16, 0xde, 0xf2, 0xf0, 0x38, 0xdb, 0x58, 0xa3, 0x45, 0x9e, - 0x7e, 0xce, 0xc4, 0x77, 0xaf, 0xe4, 0xcf, 0x05, 0x21, 0x07, 0xe4, 0xc4, - 0x15, 0x97, 0x16, 0xf3, 0xde, 0xe3, 0xd0, 0x91, 0x7e, 0x32, 0x28, 0x6d, - 0x27, 0x7b, 0x25, 0xf0, 0xad, 0x2e, 0x69, 0xff, 0xd6, 0x80, 0x18, 0xdf, - 0x62, 0x2d, 0x29, 0x1a, 0x39, 0xaa, 0xea, 0x58, 0x69, 0x39, 0x86, 0xf8, - 0xa5, 0x23, 0x16, 0x2b, 0x3b, 0x35, 0xb7, 0x8a, 0x81, 0xc4, 0x55, 0x7f, - 0xc1, 0x96, 0xaf, 0xef, 0xfc, 0x85, 0xaa, 0xa3, 0x26, 0x47, 0x70, 0xfd, - 0x72, 0x06, 0xd8, 0x44, 0x83, 0xad, 0x34, 0x32, 0xd7, 0x1e, 0xf5, 0x73, - 0xcb, 0x41, 0x55, 0x93, 0xff, 0xfa, 0x4e, 0x37, 0xb7, 0x9c, 0x45, 0x6e, - 0x99, 0x56, 0xb9, 0x25, 0xfc, 0x6b, 0x80, 0xfd, 0xb6, 0x8a, 0x8e, 0xb1, - 0x72, 0xc2, 0x5c, 0xfd, 0xa3, 0x62, 0x1f, 0xc0, 0xba, 0x38, 0x23, 0xf3, - 0x7a, 0x42, 0x53, 0x34, 0x8d, 0x17, 0xe8, 0xa7, 0xe8, 0xbf, 0x68, 0xe3, - 0xac, 0x69, 0xa1, 0xed, 0x65, 0xfa, 0x28, 0xd7, 0xb6, 0xc7, 0x5a, 0x7c, - 0xdd, 0x5c, 0xa9, 0x0e, 0x1d, 0x22, 0xa7, 0xb7, 0xda, 0x30, 0x7f, 0xc4, - 0x74, 0x8b, 0xd7, 0x9c, 0x3f, 0x7c, 0x67, 0x28, 0xa4, 0xae, 0x0b, 0x65, - 0xb7, 0x86, 0xe1, 0xd2, 0x67, 0xfe, 0x01, 0x1f, 0x53, 0x27, 0x1f, 0x1c, - 0xb7, 0x4f, 0x8c, 0x33, 0x21, 0x09, 0x9c, 0xa1, 0xfd, 0x45, 0x23, 0x69, - 0xc8, 0x6f, 0xce, 0x22, 0x06, 0x3c, 0x04, 0x6c, 0xf4, 0x88, 0xe8, 0xe7, - 0x06, 0xb1, 0x76, 0xa2, 0xe1, 0xb2, 0xc4, 0xc4, 0xa8, 0x04, 0xe5, 0x8d, - 0x53, 0xd1, 0x08, 0xed, 0xe5, 0x2c, 0xe2, 0xd5, 0x91, 0x7a, 0xe7, 0xed, - 0x86, 0xe2, 0x82, 0x6d, 0xdf, 0x08, 0x00, 0x3b, 0x0c, 0xda, 0x7a, 0xb7, - 0xdc, 0x80, 0xbe, 0xb3, 0xaa, 0xed, 0x11, 0xd0, 0x05, 0x0f, 0x67, 0x58, - 0x1b, 0x24, 0xdd, 0xa3, 0xa0, 0x49, 0xda, 0x8d, 0xcc, 0x32, 0x73, 0xd3, - 0x53, 0xb4, 0xdd, 0x5e, 0xd8, 0x1d, 0xae, 0xeb, 0xed, 0x92, 0x9d, 0x8c, - 0x88, 0x7e, 0x6a, 0x8f, 0xf4, 0xef, 0xd4, 0xdd, 0xf9, 0xa8, 0x39, 0xb2, - 0x8d, 0x35, 0xe7, 0x11, 0xb5, 0x1e, 0xf5, 0x25, 0xd8, 0xcc, 0x3e, 0xea, - 0x18, 0xb1, 0x1f, 0x71, 0x8c, 0x7e, 0xcc, 0x40, 0x1c, 0x4b, 0xd5, 0x5d, - 0xbd, 0x97, 0xf7, 0x6d, 0x95, 0x63, 0x67, 0x68, 0x4f, 0xb8, 0xb7, 0x6a, - 0x53, 0xfe, 0xde, 0x10, 0xef, 0x59, 0x72, 0xfc, 0x45, 0xe6, 0x1e, 0xcc, - 0x39, 0x98, 0x67, 0x45, 0xc3, 0xbb, 0x30, 0x1f, 0xfd, 0x31, 0xfa, 0x03, - 0x5d, 0xd9, 0x6e, 0x0e, 0x3e, 0xba, 0x50, 0xa7, 0xde, 0x86, 0xb9, 0x7f, - 0x66, 0x32, 0x5f, 0xb3, 0xc3, 0xae, 0xbc, 0x0b, 0x68, 0x9b, 0x85, 0xef, - 0x4f, 0x39, 0x6d, 0xb2, 0x32, 0x69, 0x43, 0xf7, 0x5f, 0x02, 0x5f, 0x07, - 0x3a, 0x59, 0x23, 0x58, 0x99, 0x4c, 0xe3, 0xfa, 0x80, 0xca, 0xd1, 0x8c, - 0xc7, 0x6c, 0xd0, 0xd8, 0xca, 0x75, 0xe4, 0xe9, 0x29, 0xae, 0x17, 0xe6, - 0x1f, 0xd3, 0x67, 0xe1, 0xb3, 0xc7, 0xe3, 0x8c, 0xf1, 0xdc, 0x4b, 0xe8, - 0x00, 0x1f, 0xdd, 0x0a, 0x57, 0xe8, 0xd6, 0x4e, 0xbd, 0x50, 0xa6, 0x9f, - 0xcf, 0x87, 0xdb, 0x85, 0x78, 0xc4, 0xd4, 0x2b, 0x16, 0x75, 0xa2, 0xc9, - 0x65, 0xb5, 0xef, 0x20, 0x92, 0x76, 0x0e, 0x61, 0xac, 0xb8, 0x5e, 0x2d, - 0xef, 0xd4, 0xf3, 0x65, 0x43, 0x56, 0x42, 0xe4, 0x3b, 0xa2, 0xf2, 0xf8, - 0x9d, 0xca, 0xd6, 0x8a, 0x88, 0x25, 0xb0, 0x99, 0xf8, 0x87, 0x31, 0xae, - 0x6a, 0x83, 0x4d, 0x51, 0xf7, 0xd4, 0xbb, 0xf2, 0x91, 0x9e, 0xee, 0x37, - 0x8a, 0x99, 0x45, 0xf8, 0x5f, 0xd6, 0x2f, 0x3a, 0xbc, 0x5a, 0xe3, 0x4b, - 0x5e, 0x3e, 0xf4, 0x8c, 0x30, 0x4f, 0x99, 0x2b, 0x91, 0x97, 0x22, 0xfc, - 0xe1, 0x46, 0xb6, 0x44, 0x39, 0xba, 0x3e, 0xe5, 0x10, 0xec, 0x42, 0x5f, - 0x32, 0x3d, 0x1b, 0xe0, 0xdf, 0x28, 0xee, 0x31, 0x06, 0xe0, 0xbb, 0xde, - 0x86, 0xf5, 0xbe, 0x17, 0x32, 0xa2, 0x6e, 0xa0, 0xbf, 0x25, 0xee, 0xbb, - 0x42, 0x7f, 0x4b, 0x57, 0xde, 0xb6, 0x7b, 0xe9, 0xf3, 0x46, 0xe4, 0x18, - 0xfc, 0xe8, 0xd1, 0x45, 0xf2, 0x93, 0xf6, 0x70, 0xd9, 0x30, 0x64, 0x42, - 0x1f, 0x3f, 0x2c, 0x6f, 0xd4, 0x7e, 0xa0, 0x70, 0xe0, 0xb6, 0x9d, 0x0d, - 0x99, 0x86, 0x7f, 0x98, 0x71, 0x20, 0x7f, 0x33, 0x82, 0xf5, 0x19, 0x56, - 0xfe, 0x71, 0xe6, 0xfd, 0xe5, 0x24, 0x01, 0x37, 0x66, 0x7f, 0xf6, 0x3e, - 0x63, 0xf6, 0x03, 0xc0, 0x61, 0xef, 0x8b, 0xbe, 0xe1, 0xd2, 0xff, 0x33, - 0xe8, 0xea, 0xd7, 0x55, 0xfd, 0x22, 0xb7, 0x73, 0x2b, 0x65, 0xfa, 0x5e, - 0xcf, 0xe9, 0xee, 0x73, 0x9f, 0xbb, 0x4f, 0xbe, 0x4c, 0xa9, 0x01, 0x2b, - 0xe4, 0x55, 0x1c, 0x65, 0xae, 0xd8, 0xe6, 0xe9, 0x6f, 0x10, 0x18, 0x9a, - 0x74, 0x7d, 0xdf, 0xdb, 0x21, 0xf9, 0x5e, 0x3f, 0xff, 0x84, 0xcf, 0x5e, - 0x6d, 0xf7, 0xf3, 0x59, 0x3e, 0xbf, 0x92, 0x41, 0xfe, 0x0c, 0x1b, 0x60, - 0x2c, 0x60, 0x5b, 0x5c, 0xf9, 0xa1, 0x77, 0xe7, 0x9b, 0xf5, 0x0b, 0xf2, - 0xbd, 0x5b, 0xf1, 0x9d, 0x56, 0x7c, 0xb3, 0x06, 0xb9, 0x5f, 0x4b, 0x9d, - 0x67, 0x1d, 0xd2, 0xaf, 0x3b, 0x92, 0x1e, 0xb0, 0x01, 0xf4, 0xfd, 0x63, - 0xd0, 0xfd, 0x11, 0xf4, 0xfa, 0xc3, 0x12, 0xb0, 0x41, 0x09, 0xd8, 0xa0, - 0x04, 0x6c, 0x50, 0x02, 0x36, 0x28, 0x85, 0xbd, 0x3a, 0x8b, 0x4d, 0x6c, - 0xff, 0x3e, 0x6d, 0xd7, 0xaf, 0x6d, 0xac, 0xb7, 0x4b, 0xb7, 0xb6, 0x99, - 0xaa, 0xfb, 0x18, 0x39, 0xc8, 0x5a, 0x2b, 0xb0, 0x9a, 0x5f, 0xf7, 0xf0, - 0x62, 0x44, 0x8d, 0xfb, 0x5e, 0x88, 0x11, 0x35, 0x1b, 0xeb, 0x66, 0x28, - 0x6c, 0x00, 0x1b, 0x1a, 0x12, 0xc6, 0x6f, 0x13, 0xbe, 0x17, 0xb4, 0x86, - 0xfb, 0xb1, 0x92, 0xda, 0x55, 0x5d, 0xef, 0x88, 0xaa, 0x3b, 0x58, 0x32, - 0x5b, 0xf6, 0x73, 0xb7, 0x98, 0x8c, 0xcd, 0x13, 0x6f, 0xca, 0x16, 0x3d, - 0x01, 0x1d, 0x38, 0xc4, 0x88, 0xdc, 0x27, 0xe4, 0xf8, 0xb1, 0xc1, 0x2a, - 0xc6, 0x2c, 0x58, 0x2e, 0x7f, 0x47, 0x9c, 0xbb, 0xcf, 0xec, 0x82, 0x7f, - 0xce, 0x14, 0x23, 0x32, 0x5e, 0x74, 0x31, 0x01, 0xf2, 0x9f, 0x75, 0xf5, - 0xe5, 0x5b, 0xd0, 0xc3, 0xad, 0xcc, 0x94, 0xb5, 0x6a, 0x1b, 0x91, 0xcb, - 0x71, 0xca, 0x98, 0xfa, 0xdf, 0xab, 0xf6, 0x29, 0x76, 0x55, 0xdd, 0xbd, - 0xa4, 0x71, 0x65, 0x0b, 0x01, 0xfa, 0x19, 0xd0, 0x89, 0xbb, 0x6b, 0x18, - 0x76, 0x91, 0x73, 0x7c, 0xb9, 0xb4, 0xe2, 0x91, 0x2f, 0x6a, 0x62, 0x6d, - 0xd4, 0xfe, 0x1b, 0x2d, 0xed, 0xab, 0xf7, 0x3d, 0x7e, 0xe1, 0xfb, 0x56, - 0x6b, 0x0d, 0xf4, 0x53, 0x77, 0xdb, 0x81, 0xdd, 0x24, 0xa0, 0xee, 0xc3, - 0x87, 0xd7, 0x42, 0x92, 0xaa, 0x59, 0x92, 0x2e, 0xb3, 0x1f, 0xeb, 0x17, - 0xf4, 0x47, 0x7f, 0x22, 0x29, 0xe4, 0xab, 0xd9, 0x50, 0x34, 0x6e, 0xcb, - 0x7f, 0x96, 0xe5, 0x85, 0x7c, 0x84, 0xe7, 0x0a, 0xf2, 0x13, 0x1a, 0x9e, - 0xfb, 0x19, 0xae, 0xc9, 0xb3, 0x25, 0x33, 0x45, 0xc6, 0x9d, 0xa1, 0x70, - 0x0d, 0xf7, 0xb2, 0x93, 0xac, 0xd9, 0x7c, 0x07, 0x36, 0x19, 0x8d, 0x94, - 0xa1, 0xef, 0x2b, 0x45, 0x8e, 0x07, 0x6c, 0x54, 0x64, 0x5d, 0xc7, 0xbf, - 0xff, 0x27, 0xc0, 0x81, 0xf0, 0xd5, 0x21, 0xaf, 0x8f, 0x9a, 0xab, 0x6d, - 0x06, 0x60, 0xe3, 0x0d, 0xcf, 0xdf, 0x56, 0x8a, 0x6e, 0x1d, 0xe5, 0x2c, - 0xf9, 0x70, 0xfe, 0x77, 0xb3, 0x11, 0x42, 0x0e, 0xb4, 0x3a, 0xc7, 0xab, - 0xa4, 0x6f, 0xc2, 0xdd, 0xca, 0x51, 0xc7, 0x97, 0x05, 0xef, 0xb3, 0x8d, - 0x67, 0x27, 0x9a, 0xcd, 0xb3, 0xd6, 0x07, 0xad, 0x99, 0xf5, 0x6d, 0x4f, - 0x5a, 0xf9, 0xdd, 0x15, 0x27, 0xef, 0xd5, 0xcc, 0xbe, 0xbd, 0xc3, 0xad, - 0x99, 0xd5, 0x76, 0xac, 0xad, 0x99, 0x59, 0xdb, 0xdd, 0x9a, 0xd9, 0xfc, - 0xee, 0x02, 0x3e, 0x6e, 0xcd, 0x2c, 0xbb, 0xdd, 0xad, 0x99, 0x95, 0xb7, - 0xbb, 0x35, 0x33, 0x67, 0x87, 0x5b, 0x33, 0xfb, 0xf9, 0xf6, 0xb5, 0x35, - 0xb3, 0x1f, 0xec, 0x58, 0x5b, 0x33, 0xbb, 0xb8, 0x3b, 0x87, 0xcf, 0xdd, - 0x9a, 0xd9, 0xcf, 0x76, 0xdc, 0xbb, 0x66, 0xf6, 0x9a, 0x8f, 0xd7, 0x31, - 0x9f, 0x11, 0xcc, 0x21, 0x0e, 0xbc, 0x3e, 0x0c, 0xbc, 0xfe, 0x6e, 0x75, - 0xfe, 0x00, 0xe6, 0x39, 0xe8, 0xc5, 0x83, 0x0f, 0x82, 0xdb, 0x47, 0xbc, - 0x67, 0x6d, 0xe4, 0xbb, 0x11, 0x2f, 0x57, 0x21, 0x76, 0xdf, 0xec, 0xe5, - 0x6c, 0xff, 0xa8, 0xf3, 0xee, 0xb9, 0x97, 0xd6, 0xef, 0x0f, 0x21, 0xf5, - 0xf6, 0xf1, 0x3c, 0xe7, 0x95, 0x47, 0xee, 0x47, 0x39, 0xd8, 0xe8, 0x3f, - 0xbf, 0xfb, 0x1b, 0x16, 0x31, 0xfe, 0x73, 0x58, 0xab, 0xf6, 0x16, 0x43, - 0x9d, 0x01, 0x60, 0x8c, 0x3a, 0x2e, 0x29, 0xf4, 0x4f, 0xa9, 0xfe, 0xd7, - 0x5a, 0xfa, 0xaf, 0xa0, 0x3f, 0xe9, 0x46, 0xff, 0x1d, 0x3e, 0x2f, 0x29, - 0xfb, 0xb6, 0x5c, 0x0c, 0x9f, 0x2e, 0xf9, 0x78, 0x2b, 0xe0, 0x61, 0xe7, - 0x46, 0xc6, 0x76, 0x3e, 0x8f, 0x67, 0xa2, 0x17, 0x6d, 0xb9, 0xa9, 0xf0, - 0xbb, 0x91, 0x88, 0x5e, 0xcc, 0xaa, 0x7c, 0xad, 0x91, 0xc9, 0x39, 0x7e, - 0xfe, 0x8d, 0x1c, 0x6a, 0x80, 0x39, 0x0c, 0xec, 0x7d, 0x69, 0x10, 0x71, - 0xac, 0x35, 0xc7, 0x66, 0x5e, 0xad, 0x7b, 0x79, 0xb5, 0x29, 0x9f, 0xd9, - 0xd9, 0x8a, 0xcd, 0x2f, 0xee, 0xfe, 0xc7, 0x0a, 0x9b, 0x6f, 0x42, 0x6e, - 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7a, 0x01, 0xf3, - 0x19, 0xc6, 0x46, 0xe6, 0x37, 0x21, 0x7c, 0x78, 0x26, 0xc9, 0xc7, 0xe8, - 0xed, 0x9e, 0x7f, 0x67, 0x5e, 0xe4, 0x63, 0x95, 0xe4, 0x26, 0x37, 0x37, - 0xda, 0xa4, 0xb9, 0xf9, 0x67, 0xc4, 0xeb, 0x13, 0x58, 0xc5, 0xc2, 0x81, - 0x55, 0x2c, 0xbc, 0x66, 0x1f, 0x4b, 0xd4, 0xf9, 0x27, 0xb5, 0x1f, 0xc6, - 0xfd, 0xb1, 0x46, 0xe6, 0xca, 0x80, 0x68, 0x7a, 0x82, 0xfb, 0x64, 0xc0, - 0x3a, 0x16, 0xf7, 0xcd, 0xe8, 0x3b, 0xf7, 0x69, 0xa9, 0x2a, 0xe3, 0x0f, - 0xf1, 0x91, 0xbf, 0x17, 0xee, 0xeb, 0x89, 0xb2, 0x63, 0xdb, 0x1f, 0x6b, - 0xc8, 0x79, 0xe3, 0xed, 0xd6, 0x53, 0xe0, 0x25, 0x83, 0x6f, 0x5f, 0xa6, - 0x9f, 0x55, 0xb1, 0xaf, 0x03, 0xb6, 0x7b, 0xa4, 0x44, 0xec, 0xba, 0x59, - 0x6a, 0x1e, 0x7e, 0x3d, 0x37, 0xef, 0x62, 0xd7, 0xc0, 0x5a, 0xec, 0x1a, - 0x5f, 0x16, 0x97, 0xc7, 0x5d, 0x1b, 0xf2, 0x48, 0xbc, 0x4a, 0xfe, 0x18, - 0x77, 0xf6, 0xc2, 0xff, 0x35, 0x80, 0x69, 0x19, 0x73, 0x18, 0x6f, 0x22, - 0xc0, 0xf6, 0xf7, 0xe2, 0x4f, 0xb5, 0x1d, 0xea, 0xb0, 0x82, 0xf8, 0x4c, - 0xc3, 0x7f, 0x4c, 0xe0, 0x99, 0x8c, 0xcc, 0x9e, 0xfe, 0x1a, 0xe6, 0x36, - 0x2d, 0x57, 0xe6, 0x27, 0xc1, 0xdf, 0x73, 0x32, 0x17, 0xcf, 0xc3, 0x8f, - 0x70, 0xcf, 0x83, 0xb8, 0xad, 0xdf, 0xfb, 0x9e, 0xd6, 0xcf, 0x5a, 0x51, - 0xe2, 0x46, 0xa9, 0x16, 0xe9, 0x83, 0xb9, 0x67, 0xc8, 0xbd, 0x61, 0xda, - 0x0f, 0xeb, 0x27, 0xc8, 0x5d, 0x99, 0xc3, 0x9e, 0xe2, 0xf8, 0x6b, 0x75, - 0xb2, 0xec, 0x10, 0x7f, 0x35, 0x32, 0x8d, 0x25, 0xe2, 0xc7, 0xf7, 0x8b, - 0x25, 0xa9, 0x07, 0xe2, 0xc9, 0xfb, 0xc1, 0x91, 0xd1, 0x79, 0x60, 0xc8, - 0x57, 0x1a, 0x7a, 0x2b, 0x8e, 0x74, 0x31, 0x64, 0x72, 0x29, 0x0b, 0x9a, - 0x71, 0x85, 0x95, 0x91, 0xc7, 0xc1, 0xed, 0xf5, 0xe3, 0xd9, 0x7e, 0xe4, - 0xe4, 0x2e, 0x66, 0x4c, 0x01, 0x33, 0xfe, 0x06, 0x30, 0xe3, 0xac, 0x74, - 0x76, 0x11, 0x33, 0xda, 0x1e, 0x66, 0x4c, 0xc3, 0x9e, 0x73, 0x6b, 0xec, - 0x59, 0x53, 0xb5, 0x28, 0xde, 0xcb, 0x01, 0xf3, 0xa5, 0x4e, 0x45, 0xef, - 0x03, 0x27, 0x6a, 0x12, 0x52, 0xe7, 0x52, 0x02, 0x2d, 0x34, 0x7d, 0x3c, - 0xb8, 0x4d, 0xe1, 0xbc, 0xdd, 0xa5, 0x4d, 0xc8, 0x51, 0x14, 0xee, 0xf3, - 0xf6, 0x4b, 0x03, 0xeb, 0xf6, 0x90, 0x03, 0x2d, 0x7b, 0xc8, 0x77, 0xf1, - 0x21, 0x9e, 0xf3, 0x6a, 0x7d, 0x6d, 0xf0, 0x05, 0xff, 0x13, 0x3c, 0x71, - 0x7d, 0x71, 0x2d, 0x68, 0xee, 0x7a, 0x59, 0x83, 0x13, 0xff, 0x7a, 0x1d, - 0x4e, 0x44, 0xec, 0x3a, 0x17, 0x92, 0x24, 0x30, 0xa2, 0xbd, 0x44, 0x5a, - 0x5c, 0xd3, 0xc3, 0xd2, 0x8e, 0xf9, 0x75, 0x9c, 0xea, 0x05, 0x36, 0xea, - 0x92, 0x20, 0x30, 0x52, 0x9b, 0xc2, 0x48, 0x03, 0xc4, 0x32, 0x83, 0x33, - 0xc0, 0x36, 0xb5, 0x55, 0x9c, 0x14, 0x8d, 0xff, 0x01, 0xf4, 0xf2, 0x94, - 0xf2, 0x3d, 0x69, 0x39, 0x01, 0x5f, 0xda, 0xbe, 0x04, 0x7c, 0x77, 0xce, - 0xc5, 0x4f, 0x6d, 0xeb, 0xf0, 0xd3, 0xc1, 0x0d, 0xf1, 0x93, 0xaa, 0xdf, - 0x8f, 0x52, 0x26, 0x37, 0x1c, 0xb7, 0x7e, 0x7f, 0xdd, 0x71, 0xeb, 0xf7, - 0x37, 0x9c, 0xd6, 0xfa, 0xfd, 0x47, 0xa4, 0x60, 0x46, 0xed, 0x15, 0x59, - 0x57, 0xbf, 0x9f, 0x60, 0x3d, 0xdc, 0xe9, 0x72, 0xeb, 0xf4, 0x5d, 0x5e, - 0xfd, 0x3e, 0x2a, 0x85, 0x35, 0xed, 0xa6, 0xbc, 0x69, 0xf9, 0xf5, 0xfb, - 0xef, 0xa2, 0xad, 0x1b, 0x63, 0xac, 0xad, 0xdd, 0x5f, 0x77, 0x58, 0xbb, - 0x0f, 0xb1, 0x9f, 0x57, 0xbb, 0x67, 0x3f, 0xe4, 0xf2, 0x0e, 0xeb, 0xf6, - 0x8f, 0x40, 0x16, 0x5b, 0x21, 0x87, 0x5e, 0x69, 0x3f, 0x13, 0x66, 0x1f, - 0x55, 0xaf, 0x5f, 0x71, 0x42, 0x78, 0xce, 0xad, 0xab, 0xcf, 0xc0, 0xae, - 0x0e, 0xae, 0xd6, 0xeb, 0xdd, 0x31, 0x6e, 0x3a, 0x6b, 0xe9, 0xaf, 0xa5, - 0xd3, 0xe7, 0xd1, 0x09, 0x81, 0x4e, 0x78, 0x1d, 0x9d, 0xbb, 0xf5, 0xf9, - 0x9b, 0x8e, 0x5b, 0x9b, 0x4f, 0x9f, 0x16, 0xbb, 0x1d, 0xbe, 0xf9, 0xe2, - 0xc0, 0xc3, 0x1e, 0x8d, 0xd5, 0xda, 0x3c, 0x7d, 0x08, 0x70, 0x7b, 0x4c, - 0x9d, 0xbd, 0x9a, 0xf9, 0x7f, 0x50, 0x9b, 0x67, 0x5d, 0xde, 0xdd, 0x5f, - 0xe1, 0xfa, 0x04, 0x3e, 0x7f, 0xd1, 0xad, 0xc9, 0x8f, 0x95, 0xfc, 0x5a, - 0x3b, 0xf3, 0x47, 0xff, 0x5c, 0x54, 0x7f, 0xe4, 0x88, 0xd0, 0x56, 0xc8, - 0x1f, 0xe9, 0x76, 0xcb, 0x94, 0xc2, 0x47, 0xb0, 0xa9, 0xd8, 0xbd, 0x31, - 0x72, 0xe5, 0x94, 0x8f, 0x91, 0x43, 0x0a, 0x23, 0x57, 0x96, 0x7c, 0x8c, - 0x9c, 0xbc, 0x07, 0x46, 0x6e, 0x76, 0xb9, 0x71, 0x20, 0x28, 0x79, 0x85, - 0x91, 0xef, 0x75, 0x96, 0x8c, 0xf7, 0xba, 0x88, 0x07, 0xc4, 0x3d, 0x5f, - 0xd0, 0x7b, 0x8f, 0xb5, 0xe6, 0xe3, 0x66, 0xc6, 0xfe, 0xad, 0x32, 0x71, - 0xe6, 0x2e, 0x6e, 0x76, 0xb1, 0x71, 0x34, 0x72, 0x48, 0xc5, 0x44, 0xe0, - 0x84, 0x3a, 0xeb, 0xdf, 0xc4, 0xbe, 0x8c, 0x39, 0x01, 0x85, 0xcf, 0x72, - 0x45, 0xe6, 0x01, 0x6c, 0x23, 0x16, 0xee, 0xe4, 0x31, 0x2b, 0x2f, 0x26, - 0xf9, 0x58, 0xd3, 0x3f, 0xd7, 0xc2, 0x3d, 0x86, 0x37, 0x8d, 0xa4, 0x85, - 0x76, 0xc7, 0xcf, 0x15, 0xe2, 0xea, 0x3c, 0x50, 0x12, 0x58, 0x72, 0x6a, - 0x15, 0x4b, 0xd2, 0x57, 0xfc, 0xf4, 0x6d, 0xdb, 0xa4, 0x5f, 0xf3, 0xb1, - 0x22, 0x72, 0xa2, 0x12, 0xd7, 0xb6, 0x8f, 0x15, 0x5d, 0x9c, 0x98, 0x72, - 0x1a, 0xc0, 0xcb, 0x01, 0x19, 0x03, 0x4e, 0x6f, 0x7c, 0x89, 0x35, 0x28, - 0x1f, 0x1b, 0xd9, 0xf8, 0x6e, 0xad, 0x49, 0xf1, 0xba, 0x5d, 0xed, 0x05, - 0x5e, 0x1e, 0x08, 0xb6, 0xb4, 0x3f, 0x0b, 0xff, 0x8d, 0xfc, 0x08, 0xd8, - 0xc4, 0xc5, 0x44, 0x3b, 0xa0, 0x83, 0x91, 0x7b, 0x60, 0xa2, 0xf5, 0x31, - 0x8a, 0x31, 0xf3, 0x6e, 0x8c, 0x4a, 0xd7, 0xe9, 0xcf, 0xef, 0xc6, 0xa8, - 0x7b, 0xc7, 0x50, 0xb6, 0x61, 0x76, 0x56, 0x06, 0x9f, 0x69, 0x29, 0xac, - 0x8b, 0x51, 0x73, 0x1f, 0x20, 0x46, 0xb9, 0xf8, 0xc0, 0xe5, 0xfb, 0xf7, - 0x21, 0x9b, 0x1f, 0x43, 0xa6, 0x3f, 0x02, 0xe6, 0xfa, 0x21, 0xe6, 0xf5, - 0x03, 0xe0, 0xa1, 0xef, 0x97, 0xd6, 0x9f, 0x07, 0x19, 0x15, 0xe6, 0x87, - 0x2e, 0x66, 0x72, 0x31, 0xfd, 0x0c, 0x56, 0x57, 0xad, 0xd8, 0xc8, 0x4c, - 0x15, 0x87, 0xcc, 0x69, 0x77, 0x1f, 0x35, 0x92, 0x95, 0xa7, 0x3b, 0x53, - 0x8b, 0x8c, 0x19, 0xea, 0x3a, 0xcc, 0xfa, 0x25, 0xb1, 0x43, 0x55, 0xe5, - 0x99, 0x03, 0x52, 0xae, 0xb9, 0x78, 0x6b, 0x6e, 0xd1, 0xa5, 0x31, 0xe5, - 0xe1, 0xad, 0x9c, 0x87, 0xb7, 0xb2, 0xb5, 0xe5, 0x48, 0x00, 0xfd, 0xe7, - 0xe2, 0x6b, 0x31, 0xd6, 0x8c, 0x87, 0xb1, 0xa6, 0x3f, 0x20, 0xc6, 0xe2, - 0x58, 0x39, 0x3c, 0x33, 0x3e, 0x1f, 0x91, 0x5d, 0x90, 0xf3, 0x58, 0x91, - 0xfa, 0xe2, 0x19, 0xb2, 0xf7, 0xd2, 0x19, 0xf5, 0xe5, 0xea, 0x2a, 0x10, - 0xdb, 0xa7, 0x8d, 0x43, 0x57, 0x63, 0xef, 0xa9, 0x2b, 0x31, 0xdf, 0x18, - 0x09, 0xe2, 0xf3, 0xf7, 0xa5, 0x2b, 0xce, 0x83, 0xfa, 0x5a, 0x8f, 0xc5, - 0xee, 0x07, 0x93, 0xad, 0xc5, 0x63, 0xb6, 0xc2, 0x63, 0xed, 0x5e, 0x1f, - 0xd9, 0x33, 0x0e, 0x5d, 0xfe, 0x27, 0xf4, 0xf9, 0x99, 0xd5, 0x2d, 0x3f, - 0x85, 0xff, 0xfe, 0x43, 0xe8, 0xe4, 0x3f, 0x22, 0x57, 0x78, 0xcd, 0xea, - 0x93, 0x3f, 0x40, 0xdb, 0x5d, 0x9c, 0xc3, 0xfe, 0xc1, 0xc7, 0x92, 0xd6, - 0x35, 0xe0, 0x93, 0x6b, 0x1e, 0x3e, 0x79, 0x3a, 0x99, 0xb4, 0x26, 0x59, - 0x37, 0x87, 0x9c, 0x0f, 0xa4, 0xa6, 0x14, 0x36, 0xf1, 0x31, 0xc9, 0xed, - 0x34, 0xc7, 0x9f, 0x75, 0x56, 0x80, 0x7d, 0x56, 0x3c, 0xec, 0x73, 0x60, - 0xcc, 0xc5, 0x3e, 0xc1, 0xcf, 0x50, 0xff, 0x2e, 0xee, 0x59, 0xb1, 0x93, - 0x18, 0xa7, 0x0a, 0x4c, 0x52, 0x71, 0x0e, 0x48, 0xbe, 0xbe, 0x57, 0x7d, - 0x8e, 0x94, 0xec, 0x68, 0x1b, 0xe4, 0xc4, 0xda, 0xeb, 0x49, 0xae, 0x4a, - 0x27, 0x6a, 0x16, 0xf1, 0x9d, 0x75, 0xa2, 0xe1, 0xdf, 0xf1, 0xae, 0x9f, - 0xf7, 0xae, 0x4f, 0x78, 0xd7, 0xc7, 0x11, 0x87, 0x8f, 0xa9, 0x58, 0xca, - 0x76, 0xb6, 0x41, 0xc9, 0x0e, 0x68, 0x01, 0x7b, 0x9c, 0x1d, 0xfe, 0x8b, - 0x66, 0x59, 0xe9, 0x98, 0xf4, 0x27, 0xf0, 0x39, 0x8e, 0xcf, 0x34, 0x3e, - 0xfb, 0xf1, 0xc9, 0xe3, 0xb3, 0x2a, 0x53, 0x2d, 0x55, 0x9a, 0x84, 0x8d, - 0x0c, 0x4a, 0xaa, 0xfe, 0x12, 0xf4, 0xf8, 0x1c, 0x74, 0x7b, 0x58, 0x0a, - 0xd5, 0x3f, 0x95, 0xd9, 0x79, 0x4d, 0xba, 0x2c, 0xe8, 0xb4, 0x0a, 0x5b, - 0x9e, 0x77, 0xf7, 0x13, 0x3b, 0x13, 0x7b, 0xd1, 0xb7, 0x29, 0x4f, 0xc5, - 0x9f, 0x13, 0xfd, 0xb1, 0x39, 0xf4, 0x13, 0xbd, 0x30, 0xfc, 0x31, 0xb5, - 0x6f, 0x56, 0x8d, 0xbb, 0x32, 0xde, 0x65, 0xd9, 0x51, 0xe8, 0x7c, 0xf0, - 0x18, 0x68, 0x27, 0xd5, 0xd9, 0xd8, 0x8c, 0x1c, 0x3d, 0xbd, 0xbc, 0xc5, - 0xf5, 0xad, 0x51, 0xf3, 0x26, 0xf5, 0x8e, 0x79, 0xd8, 0xf0, 0x85, 0x19, - 0xd8, 0xfb, 0x41, 0x27, 0xa0, 0x8d, 0x21, 0xde, 0x8c, 0x39, 0x37, 0x55, - 0xbc, 0x81, 0xef, 0xca, 0xc4, 0x4e, 0x86, 0x70, 0xcd, 0xb3, 0x45, 0x88, - 0x8b, 0xea, 0x6c, 0xe5, 0x32, 0xf0, 0x8d, 0xa6, 0xea, 0x80, 0xb3, 0xab, - 0xfb, 0x43, 0x86, 0xf2, 0x5b, 0xb1, 0x98, 0x2e, 0xb9, 0x11, 0xe2, 0xdc, - 0xbd, 0x2a, 0x36, 0xd5, 0x8a, 0xf6, 0x43, 0xcc, 0x15, 0x6f, 0x08, 0xe3, - 0xdc, 0xe3, 0xe8, 0xd7, 0x07, 0x7f, 0x8c, 0x7b, 0x75, 0xda, 0x27, 0xe7, - 0xca, 0x67, 0xa6, 0xa5, 0x5a, 0x1e, 0xc5, 0x7c, 0xbd, 0x1c, 0x49, 0xe5, - 0x12, 0x11, 0xd8, 0xa3, 0xbf, 0x17, 0xe5, 0xd6, 0x4f, 0xaa, 0x8e, 0x8f, - 0x29, 0xba, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xee, 0x9f, 0xa9, 0xbd, - 0xb3, 0x82, 0x33, 0x0a, 0x39, 0x25, 0xd1, 0xce, 0x5a, 0x35, 0x7e, 0x97, - 0x75, 0x55, 0x13, 0x58, 0x31, 0x66, 0xa4, 0x56, 0x6e, 0x82, 0x5f, 0xc4, - 0xdc, 0x2d, 0x33, 0x52, 0x29, 0x4f, 0xcb, 0x2b, 0xe5, 0x9f, 0x77, 0x03, - 0x53, 0x41, 0xa6, 0xe4, 0xbf, 0x5b, 0xee, 0x9e, 0xbf, 0xf5, 0xdb, 0x21, - 0xcf, 0xd3, 0xf9, 0xb0, 0x9b, 0xe7, 0xe6, 0x55, 0x2d, 0xc6, 0xfd, 0xb6, - 0xf5, 0x29, 0x2b, 0x1a, 0x9e, 0x45, 0xcf, 0x83, 0x0b, 0xb4, 0xcd, 0xfc, - 0xf8, 0x9c, 0xb5, 0x43, 0xae, 0xc6, 0x37, 0xcb, 0x72, 0x5c, 0xe5, 0xc5, - 0xc4, 0x0f, 0x58, 0xeb, 0x51, 0xb3, 0x21, 0x7b, 0xe4, 0x28, 0xd6, 0xed, - 0xd5, 0xf8, 0xd3, 0xb0, 0xd3, 0x67, 0x61, 0x0b, 0xac, 0x01, 0x1c, 0x62, - 0xae, 0x25, 0x0d, 0x55, 0x23, 0x6b, 0x36, 0xc7, 0xd5, 0x19, 0xee, 0x76, - 0x59, 0x56, 0x58, 0xcc, 0xad, 0x9d, 0x2f, 0x4f, 0xba, 0x6b, 0xc4, 0x50, - 0x76, 0xff, 0xc7, 0xe0, 0xc7, 0x84, 0xed, 0xb6, 0xa9, 0x3e, 0x46, 0xa2, - 0xc3, 0xeb, 0xa3, 0xf4, 0xdb, 0xd2, 0xe7, 0x95, 0x44, 0xd2, 0xda, 0xff, - 0x89, 0xa4, 0x75, 0x73, 0xb7, 0x5b, 0x6f, 0x89, 0x9a, 0xb6, 0xc6, 0xf7, - 0x52, 0xdc, 0xf5, 0x98, 0xc1, 0xba, 0xba, 0xb4, 0x8a, 0xa1, 0x61, 0xa4, - 0x2f, 0x5f, 0x81, 0x7e, 0x03, 0xd2, 0x7e, 0xb2, 0xf9, 0xf8, 0x54, 0x7c, - 0x28, 0x72, 0x50, 0x78, 0x02, 0x8b, 0x79, 0x75, 0x34, 0x9e, 0x95, 0x2b, - 0x88, 0x93, 0x77, 0x88, 0x1d, 0x06, 0x2f, 0xcb, 0x9d, 0xc7, 0x93, 0xf1, - 0x51, 0xad, 0x32, 0x89, 0xac, 0xe5, 0xe5, 0x49, 0xc6, 0xd9, 0x43, 0x22, - 0xc0, 0x97, 0x27, 0x47, 0x24, 0x5d, 0x54, 0xef, 0xa9, 0xf0, 0x9c, 0xad, - 0x36, 0x0d, 0xf9, 0xe1, 0xf9, 0x09, 0x06, 0x46, 0xdd, 0xea, 0x8f, 0xa4, - 0xe5, 0x69, 0xd6, 0xc0, 0x24, 0xb7, 0x20, 0xdb, 0x92, 0xf0, 0xab, 0xf6, - 0x44, 0xbb, 0x4c, 0xd7, 0x1a, 0x99, 0xfe, 0x53, 0xcf, 0x82, 0xc6, 0x14, - 0x68, 0xed, 0x45, 0x6e, 0x92, 0x45, 0xac, 0xa6, 0x7c, 0xe9, 0xbb, 0x9f, - 0x81, 0x8c, 0x3e, 0xc2, 0x3d, 0xe5, 0xd1, 0xac, 0x44, 0x27, 0xf2, 0x8a, - 0xee, 0x5b, 0x5a, 0x6e, 0xf8, 0x57, 0x10, 0xeb, 0x02, 0xb2, 0x2b, 0x26, - 0xfa, 0xde, 0x58, 0xe0, 0xed, 0x29, 0x8b, 0x6d, 0x41, 0xb6, 0xe9, 0x68, - 0x0b, 0xfc, 0x7a, 0x2c, 0xa8, 0x27, 0x63, 0xd1, 0x51, 0x9e, 0x8f, 0x36, - 0xac, 0x29, 0xee, 0x4d, 0x3c, 0x20, 0x5d, 0x7b, 0xa5, 0xe7, 0x42, 0x74, - 0xf4, 0x06, 0x78, 0x09, 0x28, 0x5f, 0x3f, 0x25, 0xba, 0xd7, 0xde, 0xbd, - 0xda, 0x1e, 0xf0, 0xda, 0xf7, 0x4a, 0xd7, 0x85, 0x21, 0xf3, 0x75, 0x99, - 0x01, 0x4d, 0x43, 0xae, 0x23, 0xd7, 0xb1, 0x06, 0xa6, 0x60, 0x8b, 0x4f, - 0x92, 0x97, 0xfd, 0xc0, 0x1a, 0x58, 0x1b, 0xc8, 0xbf, 0xad, 0x0f, 0xcb, - 0x57, 0xcd, 0x4e, 0xc9, 0xa9, 0x5c, 0x37, 0xe0, 0xd6, 0x52, 0x61, 0xef, - 0x8f, 0x0e, 0x1c, 0xec, 0x71, 0xeb, 0x05, 0xdc, 0xef, 0x18, 0x46, 0xdb, - 0x9d, 0xe6, 0x39, 0x8b, 0x6d, 0xbc, 0x77, 0xa7, 0x59, 0xb5, 0x86, 0xcc, - 0x94, 0x16, 0xf4, 0xf6, 0xbd, 0x0f, 0xa9, 0xb9, 0xe7, 0xcb, 0xfd, 0x66, - 0x45, 0x1e, 0xd5, 0x52, 0x0f, 0x22, 0x5e, 0x38, 0xd3, 0xe8, 0x7b, 0x87, - 0xe7, 0x29, 0x54, 0x7d, 0xbf, 0x22, 0xfe, 0x35, 0xe9, 0x0c, 0x99, 0xe3, - 0xea, 0xd9, 0x21, 0xf3, 0xa8, 0xd6, 0xfa, 0x6c, 0x58, 0x1b, 0x5f, 0xf3, - 0x6c, 0x97, 0x92, 0x91, 0x61, 0xb9, 0x7d, 0x66, 0xcb, 0x7b, 0xe5, 0x79, - 0x87, 0xfd, 0xee, 0x34, 0x53, 0xd6, 0x03, 0xda, 0xd1, 0x07, 0xe9, 0x0b, - 0xd9, 0xf7, 0xf6, 0xba, 0x71, 0x78, 0x7d, 0xaf, 0x31, 0x9a, 0xb2, 0x76, - 0x8c, 0x4d, 0xaa, 0xcf, 0x55, 0xd5, 0x27, 0xa0, 0x64, 0xbd, 0x76, 0x9c, - 0xbf, 0x91, 0xb5, 0xe3, 0x74, 0xad, 0xce, 0x79, 0x16, 0x34, 0x8f, 0xa1, - 0x6f, 0xd1, 0xe9, 0x0f, 0x57, 0xe5, 0x76, 0x33, 0x67, 0xbd, 0x29, 0x57, - 0x57, 0x69, 0xff, 0x12, 0xd7, 0xad, 0x3c, 0xfd, 0xd2, 0xe3, 0x91, 0xbf, - 0xd9, 0xf6, 0x2f, 0x95, 0xbc, 0x1f, 0xb0, 0xfa, 0xf7, 0x57, 0xb4, 0xe8, - 0xe8, 0x5f, 0x0a, 0x75, 0xf5, 0xcf, 0x94, 0xaf, 0xf9, 0x18, 0xf4, 0xb4, - 0xed, 0x05, 0xac, 0xdd, 0xe1, 0xa4, 0xea, 0x73, 0xdd, 0xda, 0x2b, 0xdb, - 0x4e, 0xf6, 0x9b, 0xd7, 0xe5, 0x33, 0x92, 0x0e, 0xf1, 0x1a, 0x39, 0x94, - 0xc5, 0xf7, 0x52, 0x3e, 0xc1, 0xbc, 0x00, 0xba, 0xec, 0x1f, 0xfc, 0x4b, - 0x79, 0x56, 0x8e, 0x96, 0xe6, 0xe0, 0x7b, 0xa6, 0x64, 0xf0, 0x05, 0xfa, - 0x9f, 0xbc, 0xe9, 0xd6, 0x6a, 0xdc, 0x98, 0x98, 0xf2, 0x62, 0xe2, 0x9c, - 0xf2, 0x73, 0xaf, 0x79, 0xe7, 0x22, 0xfa, 0x07, 0xcf, 0xe1, 0xd9, 0x57, - 0x94, 0x0f, 0xf8, 0x3d, 0xa9, 0x62, 0x2d, 0x44, 0x5e, 0xde, 0x2c, 0x0f, - 0x3c, 0x41, 0x9b, 0x44, 0x06, 0xf0, 0xb1, 0x36, 0xf5, 0x1e, 0x8c, 0x6e, - 0x75, 0x88, 0x6c, 0xa1, 0xfd, 0x5c, 0x86, 0xad, 0x4d, 0xb9, 0x7b, 0x5f, - 0x6b, 0xae, 0xa3, 0x13, 0x2b, 0xf2, 0x1f, 0x94, 0x1d, 0x7e, 0xfc, 0x82, - 0xfb, 0x3d, 0x7c, 0x01, 0xe9, 0x72, 0x6c, 0xaf, 0x6c, 0xbf, 0xe0, 0xda, - 0xdd, 0xec, 0xfc, 0xb3, 0x4a, 0xbe, 0x53, 0x4a, 0xbe, 0x4d, 0x99, 0x89, - 0x53, 0xf6, 0x9c, 0x13, 0xcf, 0x4f, 0xba, 0x32, 0xf9, 0x9c, 0x67, 0x47, - 0xfd, 0x2f, 0xf0, 0x3d, 0x35, 0xca, 0x88, 0x7c, 0xcf, 0xf4, 0x70, 0x3f, - 0x76, 0xdb, 0x05, 0xce, 0xb7, 0x6f, 0xcd, 0x7c, 0x4f, 0xc0, 0xc7, 0x0e, - 0x0c, 0xb8, 0x73, 0x7e, 0x6d, 0xfe, 0xfd, 0xcf, 0xf9, 0x77, 0x57, 0xe7, - 0x6c, 0x48, 0x55, 0xe5, 0xb9, 0xb1, 0xcd, 0xd2, 0x95, 0x93, 0x06, 0xec, - 0xe3, 0xcf, 0x85, 0x67, 0xc6, 0xc9, 0x8b, 0x3b, 0xee, 0xb2, 0x43, 0x9e, - 0xfc, 0x39, 0x90, 0xaf, 0x29, 0x4f, 0x7f, 0xe4, 0xe3, 0xd9, 0x0d, 0xef, - 0x5d, 0x97, 0x46, 0x66, 0x10, 0x6d, 0xba, 0xd2, 0xe1, 0x98, 0xb7, 0xde, - 0xf6, 0x8a, 0xae, 0x74, 0x98, 0x5c, 0xd5, 0xe1, 0x0d, 0xe8, 0xb0, 0x2a, - 0x9f, 0xc6, 0x9c, 0xb0, 0xbe, 0x5f, 0x18, 0x32, 0x67, 0x64, 0xab, 0xd2, - 0xbf, 0x35, 0x00, 0x9f, 0xea, 0xe9, 0xb2, 0xfd, 0x3e, 0x74, 0xf9, 0xba, - 0x28, 0x7d, 0xaa, 0x73, 0x44, 0x55, 0x45, 0x87, 0xbe, 0x8d, 0x73, 0x6b, - 0x57, 0x3e, 0x81, 0x3c, 0xaa, 0xb3, 0x01, 0x13, 0xae, 0x7e, 0xd5, 0x9a, - 0xf7, 0xf4, 0x9b, 0x9d, 0xa0, 0x0e, 0x7f, 0xad, 0xc7, 0xd5, 0x67, 0x87, - 0xea, 0x73, 0x2a, 0x36, 0xaa, 0xd6, 0xbb, 0x35, 0xf0, 0xe9, 0x1e, 0xea, - 0xf4, 0x79, 0xc7, 0xfd, 0x2e, 0x22, 0xce, 0x9d, 0x72, 0xde, 0x4b, 0xaf, - 0xae, 0x4e, 0xc7, 0xc4, 0x5d, 0x57, 0xeb, 0xf5, 0xa9, 0x5f, 0x08, 0x28, - 0x1b, 0x1e, 0x83, 0x0c, 0x8f, 0x97, 0x1e, 0xf4, 0xec, 0xde, 0x9d, 0xf3, - 0xc0, 0xfb, 0x9c, 0xf3, 0x91, 0x62, 0xbf, 0xf9, 0x26, 0xee, 0x8d, 0x63, - 0xce, 0x33, 0xd2, 0x26, 0x29, 0x6f, 0xce, 0x91, 0xd5, 0x39, 0xfb, 0x3c, - 0xba, 0xfd, 0x52, 0xcc, 0x63, 0x1d, 0xfa, 0xaf, 0x7f, 0xab, 0xde, 0x37, - 0xb9, 0x59, 0xa4, 0xdf, 0x06, 0x56, 0x0a, 0xf5, 0xca, 0xf5, 0x5a, 0x44, - 0xae, 0x13, 0x83, 0x8c, 0xe0, 0xdb, 0x99, 0xf3, 0x62, 0x78, 0x50, 0x5e, - 0x2f, 0x6e, 0xc4, 0xc7, 0xb0, 0xdc, 0x28, 0xfa, 0xbc, 0x10, 0x0b, 0x33, - 0x5f, 0x98, 0x92, 0x37, 0xe6, 0xfb, 0xa5, 0x31, 0x81, 0xb8, 0x3f, 0x40, - 0x99, 0x0c, 0x99, 0x7b, 0xd4, 0x7b, 0x48, 0x77, 0x9a, 0x97, 0x2d, 0xd0, - 0x5f, 0x68, 0xca, 0x41, 0xee, 0x67, 0xf3, 0x77, 0xed, 0x21, 0x69, 0x30, - 0xa7, 0x18, 0xe8, 0x95, 0xca, 0x02, 0xf2, 0xf9, 0x22, 0xe9, 0x53, 0x6e, - 0x7b, 0xd5, 0xef, 0x71, 0x8c, 0xf7, 0x39, 0xbe, 0x1f, 0x10, 0xa2, 0x6e, - 0xee, 0x34, 0x97, 0x2d, 0xee, 0x67, 0x4e, 0x49, 0x0d, 0xfa, 0xfb, 0xe7, - 0x31, 0xee, 0xb7, 0xe7, 0xd4, 0xf9, 0xdb, 0x4a, 0x6d, 0x02, 0xb9, 0xc3, - 0x9d, 0xe6, 0x9c, 0x75, 0x56, 0xe9, 0xad, 0x56, 0x7e, 0xc2, 0x6b, 0xe7, - 0x35, 0xef, 0x35, 0x32, 0xdb, 0x06, 0x98, 0xaf, 0x3e, 0x81, 0x7c, 0x81, - 0xb9, 0xea, 0x04, 0xf0, 0x1a, 0x65, 0x12, 0x91, 0xd9, 0x22, 0x69, 0x49, - 0x68, 0x13, 0xf2, 0xfb, 0x9c, 0x8c, 0x83, 0x9f, 0x08, 0x72, 0x7b, 0xc6, - 0x87, 0x47, 0x65, 0x39, 0xe4, 0xc6, 0x01, 0x9e, 0xfb, 0x5a, 0x46, 0x6c, - 0x58, 0x5e, 0x8d, 0x0d, 0x5b, 0x71, 0xdd, 0xc8, 0xc4, 0x07, 0xfe, 0x06, - 0xf4, 0x59, 0xb7, 0x61, 0x6c, 0x18, 0x45, 0x7f, 0xb6, 0xf5, 0xca, 0xec, - 0x02, 0x92, 0x08, 0xe4, 0x2c, 0x15, 0xe1, 0x99, 0x8e, 0xac, 0x9c, 0xaa, - 0xf5, 0x87, 0x2f, 0x6b, 0x69, 0x75, 0xf6, 0x23, 0x36, 0xc0, 0xf3, 0x2c, - 0xbd, 0x52, 0x5b, 0x90, 0x88, 0x91, 0x78, 0x52, 0x9c, 0x9a, 0x8b, 0xd9, - 0xe7, 0x34, 0x9e, 0x69, 0xb1, 0xa5, 0xb6, 0xb6, 0x8f, 0x89, 0xdc, 0x57, - 0xbe, 0xe3, 0xf5, 0x49, 0xab, 0x3e, 0x7f, 0xdd, 0xc3, 0x3d, 0xb4, 0x9a, - 0xd3, 0x03, 0x1e, 0xc8, 0xdb, 0xc3, 0xad, 0xe3, 0x46, 0xee, 0x8e, 0xcb, - 0x31, 0x91, 0xcd, 0x6c, 0xb1, 0x31, 0xee, 0x4d, 0x3c, 0xf3, 0x24, 0xf8, - 0xb8, 0x63, 0xe8, 0xd6, 0x93, 0x52, 0xa8, 0xad, 0x1f, 0xa3, 0x95, 0x07, - 0x3e, 0x43, 0xfa, 0x1c, 0xe7, 0x00, 0xf8, 0xbb, 0xa3, 0xe9, 0xd6, 0x01, - 0xc8, 0xd2, 0x1d, 0xc3, 0x38, 0x13, 0x35, 0x7f, 0x2a, 0x03, 0xa2, 0x9f, - 0xd3, 0x94, 0xfc, 0xf5, 0xca, 0x30, 0x16, 0x48, 0x46, 0xba, 0x96, 0x26, - 0xc5, 0x58, 0x62, 0x0d, 0xe1, 0xb5, 0xce, 0xb4, 0xda, 0xbf, 0xdd, 0x84, - 0xf5, 0x2d, 0x76, 0xc0, 0x62, 0xbd, 0x80, 0xf5, 0xe0, 0x9f, 0x6e, 0x96, - 0x1e, 0xd6, 0x0b, 0x98, 0x37, 0xec, 0xc7, 0x37, 0x73, 0x87, 0x4b, 0x4d, - 0xe4, 0x7a, 0x9b, 0x19, 0x5f, 0x73, 0x35, 0xde, 0x8f, 0x46, 0x44, 0x78, - 0x8f, 0x7e, 0xa3, 0x57, 0xda, 0xbe, 0x35, 0x08, 0x5f, 0xf1, 0x34, 0xb0, - 0x37, 0xe8, 0x9e, 0x1c, 0x90, 0x80, 0x7b, 0x66, 0x42, 0xd5, 0x5b, 0xde, - 0x58, 0x88, 0x7a, 0xef, 0x73, 0xc9, 0xb6, 0xcb, 0x71, 0xd6, 0x44, 0xfb, - 0x58, 0xf3, 0x41, 0x3f, 0xd1, 0x97, 0x91, 0x9f, 0x5e, 0xaf, 0x59, 0x9b, - 0x79, 0x7e, 0xf3, 0x86, 0x83, 0x6b, 0x62, 0xff, 0x90, 0xc2, 0x98, 0xde, - 0x3d, 0xfe, 0x46, 0xbe, 0xf4, 0x8e, 0x77, 0x13, 0x98, 0x4f, 0x4d, 0x7a, - 0x67, 0xe7, 0x1a, 0x99, 0xa3, 0x6b, 0x72, 0xaa, 0x41, 0x55, 0xef, 0x6d, - 0x38, 0x16, 0xfc, 0xe3, 0x08, 0xec, 0x93, 0x6b, 0xa0, 0xa9, 0x3d, 0x01, - 0x6c, 0x16, 0xe9, 0x55, 0x39, 0xd1, 0xf1, 0x27, 0xc4, 0xb5, 0x77, 0x58, - 0x99, 0xf2, 0x65, 0x8d, 0xb2, 0x9b, 0x83, 0x2c, 0x97, 0x33, 0xf2, 0x47, - 0xce, 0x15, 0x55, 0x6b, 0x9d, 0x47, 0x5e, 0x12, 0x38, 0xa5, 0x72, 0xb2, - 0x16, 0x7c, 0x0b, 0xbf, 0xf7, 0xe2, 0xd7, 0xb1, 0x16, 0xa3, 0xea, 0x8c, - 0x82, 0x7e, 0xae, 0xd9, 0x4c, 0xc1, 0x7f, 0xe8, 0x96, 0x65, 0x16, 0x10, - 0x0f, 0x53, 0xea, 0x9c, 0x0b, 0xd7, 0xf1, 0x6f, 0x2b, 0xff, 0x2c, 0x15, - 0xc8, 0xe6, 0x4c, 0x04, 0x74, 0x34, 0x65, 0x9f, 0x86, 0xd2, 0xc3, 0x13, - 0x0a, 0xf3, 0x1a, 0xe7, 0xe0, 0xb0, 0x96, 0x06, 0x44, 0xce, 0x65, 0x64, - 0x0e, 0x6b, 0x38, 0xb0, 0x44, 0x1d, 0x50, 0xb6, 0x93, 0xd2, 0x06, 0xd9, - 0x1f, 0x01, 0xf6, 0x30, 0x4e, 0x51, 0xc6, 0x61, 0xac, 0x8b, 0x5e, 0x09, - 0x9c, 0x81, 0x8c, 0x4f, 0x01, 0x23, 0x2c, 0xb4, 0xcb, 0xf7, 0x6a, 0xbe, - 0x4c, 0x2f, 0xf1, 0x5c, 0xbf, 0x3e, 0x35, 0xd2, 0x47, 0x1c, 0x25, 0xd5, - 0xda, 0x9c, 0xcc, 0x9d, 0x66, 0xce, 0x3e, 0xa9, 0xce, 0x0c, 0x04, 0xd4, - 0x99, 0x15, 0x37, 0x67, 0x76, 0xbf, 0x5d, 0x8c, 0x59, 0x15, 0xee, 0xb5, - 0x09, 0x6c, 0x67, 0x18, 0xe3, 0x6e, 0x24, 0x5f, 0x37, 0x57, 0x1d, 0x07, - 0xbf, 0x97, 0xe7, 0xa3, 0x99, 0xbc, 0xc4, 0x79, 0x76, 0x7a, 0xc2, 0xc6, - 0xfc, 0x97, 0xe1, 0x3f, 0xe7, 0x4a, 0x3c, 0x27, 0x5d, 0xc0, 0x0a, 0xcb, - 0xc8, 0xe5, 0x22, 0x73, 0xc6, 0x8f, 0x43, 0x6f, 0xbc, 0x2e, 0x8c, 0x1a, - 0xf0, 0x03, 0x2b, 0xea, 0xdd, 0xcf, 0xa8, 0xdd, 0x40, 0x0e, 0x1b, 0xd1, - 0xf6, 0x43, 0xd7, 0x79, 0xb3, 0xcd, 0xb3, 0x07, 0x9e, 0xc5, 0x3f, 0x0b, - 0x3f, 0x7a, 0x5e, 0xf8, 0x4e, 0xd6, 0xed, 0x26, 0xf3, 0xa5, 0xab, 0xf0, - 0x7b, 0x99, 0x58, 0x06, 0x36, 0x94, 0x0f, 0x77, 0x80, 0xe7, 0xdf, 0xc4, - 0xbd, 0x9c, 0xc3, 0x71, 0xa2, 0xf1, 0x15, 0x29, 0x44, 0x02, 0x32, 0x14, - 0xb9, 0x22, 0x9b, 0xe1, 0xc9, 0x34, 0x79, 0xdd, 0x8a, 0x8e, 0x8a, 0xa6, - 0xe8, 0x0d, 0xee, 0x86, 0x0d, 0xde, 0x84, 0xbf, 0x6b, 0xf7, 0x72, 0xfd, - 0x54, 0x91, 0x18, 0xea, 0x59, 0x75, 0xb6, 0xe0, 0xaa, 0xc5, 0x3a, 0x20, - 0xdf, 0xc5, 0xfe, 0x1f, 0x6a, 0x8c, 0xbb, 0x7b, 0x77, 0xac, 0x43, 0x93, - 0x3f, 0x77, 0x8e, 0xbb, 0x2c, 0x97, 0x47, 0xd2, 0x69, 0x6b, 0xa1, 0x73, - 0xd9, 0xa3, 0x73, 0xd6, 0xa3, 0x53, 0xf1, 0xe8, 0x5c, 0x5d, 0xa5, 0xb3, - 0x07, 0x76, 0xd0, 0x6c, 0x9e, 0x00, 0xde, 0x48, 0xc6, 0x9b, 0xcd, 0x34, - 0xf2, 0xb2, 0xd9, 0xe1, 0x69, 0xb5, 0xe7, 0xaa, 0x27, 0x46, 0xc7, 0x93, - 0x96, 0x2b, 0x7f, 0x58, 0x81, 0x4c, 0xc3, 0x1e, 0xf3, 0xe2, 0x62, 0x75, - 0xee, 0x07, 0xba, 0xfb, 0x85, 0x5d, 0xf0, 0x03, 0x4f, 0x23, 0x96, 0x5c, - 0x1c, 0x3f, 0x6f, 0x49, 0x7e, 0xdb, 0x27, 0x75, 0xd8, 0x7b, 0x0f, 0xdf, - 0x27, 0x35, 0xa5, 0xeb, 0xe2, 0x78, 0xb5, 0xf6, 0x34, 0xf2, 0x23, 0xf6, - 0xdf, 0x4e, 0x0c, 0xb6, 0xab, 0x52, 0x8b, 0xec, 0x3a, 0xcb, 0xfd, 0x21, - 0xf4, 0xab, 0xd4, 0xba, 0x21, 0xf7, 0x6e, 0x55, 0x57, 0xb9, 0x52, 0x0c, - 0x41, 0x8f, 0x26, 0x6c, 0x3e, 0x84, 0xb6, 0x30, 0xec, 0xa0, 0x0f, 0xed, - 0x3f, 0xc7, 0xda, 0x8e, 0xa0, 0x7d, 0xa5, 0x73, 0x5c, 0xe1, 0x58, 0x4b, - 0xce, 0x39, 0x37, 0x11, 0x73, 0xdf, 0x84, 0x1f, 0x1d, 0x44, 0x9f, 0x61, - 0xf4, 0xf9, 0x14, 0xc6, 0xe1, 0x3b, 0xcd, 0x1b, 0xf1, 0xd4, 0x00, 0x4f, - 0x7a, 0x0b, 0x4f, 0x0d, 0xf0, 0x03, 0xdf, 0x79, 0x92, 0x35, 0xe8, 0x61, - 0x39, 0x5a, 0xe4, 0x19, 0x29, 0xbe, 0x17, 0x6f, 0x4a, 0x00, 0x98, 0xb4, - 0xed, 0x64, 0x34, 0xdc, 0x50, 0xb5, 0x1e, 0xda, 0xd6, 0x50, 0xbc, 0x2a, - 0x2a, 0xce, 0x44, 0x8e, 0x22, 0x7e, 0xdd, 0x74, 0xba, 0xe5, 0x75, 0x6f, - 0xac, 0x15, 0xe1, 0xfe, 0xe5, 0xda, 0xb1, 0x8e, 0x95, 0xae, 0x8d, 0xbf, - 0x6a, 0x19, 0xde, 0xbc, 0x7a, 0x31, 0xd6, 0xaf, 0xa2, 0xef, 0xb5, 0xf1, - 0xcb, 0xb5, 0x8d, 0xfa, 0xde, 0x44, 0xdf, 0xb6, 0x96, 0xbe, 0x37, 0xd1, - 0xaf, 0x1b, 0x71, 0xb0, 0x5b, 0xcd, 0x69, 0x16, 0x7c, 0x5d, 0x2f, 0xaa, - 0xf7, 0xb4, 0x21, 0x77, 0x8e, 0x69, 0x12, 0x53, 0x67, 0xdc, 0x5a, 0x49, - 0xd4, 0x8c, 0x68, 0xef, 0xa8, 0xf7, 0x28, 0x1b, 0x18, 0xb3, 0x80, 0x7b, - 0xe7, 0x27, 0xb4, 0x54, 0x35, 0x87, 0x98, 0xf5, 0x30, 0xf1, 0x53, 0xdc, - 0x46, 0xcc, 0xac, 0x80, 0x5e, 0xad, 0xd8, 0xe0, 0x79, 0x6a, 0xd8, 0xc5, - 0x2d, 0xe2, 0xec, 0x87, 0x0d, 0x75, 0xae, 0x21, 0xad, 0x6a, 0x76, 0x95, - 0xa2, 0x98, 0xc9, 0x11, 0x9e, 0x65, 0xf8, 0x0c, 0xd6, 0xe5, 0x57, 0xd0, - 0x96, 0x44, 0x7c, 0x3c, 0xa0, 0x25, 0xcf, 0x8f, 0xe3, 0xfa, 0x49, 0x5c, - 0xc3, 0x1f, 0x2f, 0x64, 0x71, 0xff, 0x49, 0x5c, 0x4f, 0x6b, 0xa9, 0x7a, - 0x16, 0xd7, 0x4f, 0xe1, 0x7a, 0xca, 0x64, 0x9e, 0xf2, 0xaa, 0x95, 0xd1, - 0x6c, 0xd0, 0xb2, 0xcf, 0x8f, 0xe3, 0xd3, 0x4a, 0x8f, 0xf7, 0xa0, 0xa7, - 0x22, 0xf7, 0xda, 0x62, 0xe0, 0x69, 0x9f, 0x96, 0xae, 0x76, 0x81, 0xc6, - 0x00, 0x9e, 0xa7, 0x4d, 0xed, 0xf7, 0xc6, 0x67, 0xcd, 0xe9, 0x63, 0xaa, - 0xe6, 0x64, 0x24, 0x32, 0xc0, 0xc9, 0x87, 0x91, 0x07, 0x68, 0x92, 0xb6, - 0x9e, 0x93, 0x42, 0x1c, 0x7e, 0xa5, 0x6a, 0x48, 0x2a, 0x94, 0xc7, 0xef, - 0xbc, 0x24, 0x47, 0x71, 0xbf, 0x4a, 0x5b, 0x60, 0xbf, 0x3f, 0x95, 0x42, - 0x99, 0xb8, 0x9f, 0x75, 0x26, 0xd6, 0xa6, 0x58, 0x5f, 0xca, 0x41, 0x06, - 0x21, 0xda, 0xef, 0x06, 0x35, 0x31, 0xf7, 0x8c, 0x34, 0xe2, 0xb2, 0x96, - 0xac, 0x72, 0xdf, 0xaf, 0x91, 0xb9, 0x6c, 0xf1, 0xfd, 0xb1, 0x69, 0xee, - 0x23, 0x16, 0x8c, 0x04, 0xeb, 0x23, 0xaa, 0xbe, 0x1e, 0x77, 0xf7, 0x07, - 0x5b, 0xcf, 0xa4, 0xf8, 0xeb, 0x85, 0xe3, 0x7e, 0x0d, 0xcf, 0xbb, 0xf5, - 0xac, 0x54, 0xfd, 0x9d, 0xba, 0xe0, 0x3b, 0x00, 0xe7, 0xa0, 0x8b, 0xcb, - 0x2a, 0x37, 0xe6, 0x1e, 0xee, 0xbb, 0xe5, 0x54, 0xc8, 0x61, 0x8a, 0xac, - 0x91, 0xf9, 0xfb, 0x76, 0xbe, 0x1c, 0xd7, 0xf3, 0x4a, 0x3e, 0x67, 0x40, - 0x53, 0xe2, 0xf4, 0xbb, 0xd9, 0x10, 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf3, - 0x2e, 0xdf, 0xe4, 0x99, 0xf2, 0x38, 0x0c, 0xff, 0xc9, 0xf7, 0x2b, 0x9e, - 0x93, 0x5c, 0x9c, 0x35, 0x1e, 0x03, 0xb1, 0x31, 0x8f, 0xdf, 0x77, 0xe5, - 0x37, 0xeb, 0xc9, 0x2f, 0x57, 0xfe, 0x2f, 0x4a, 0x87, 0x15, 0x8b, 0xe3, - 0xf9, 0xb5, 0x8f, 0xbd, 0x4a, 0x77, 0x15, 0x75, 0x7e, 0xd7, 0x97, 0x81, - 0x5f, 0xbf, 0xdb, 0xd8, 0xf6, 0xc6, 0x2d, 0xf2, 0xf6, 0x10, 0xcf, 0x43, - 0x0c, 0xda, 0x42, 0xfe, 0x39, 0x0f, 0xc6, 0x30, 0x7f, 0xaf, 0xd5, 0x9f, - 0x83, 0x3f, 0xcf, 0xfb, 0x95, 0x0f, 0xf9, 0xfd, 0xe4, 0x16, 0xe9, 0xca, - 0x98, 0x86, 0xc5, 0xd8, 0xf0, 0xb8, 0xb7, 0x3f, 0xf0, 0x7f, 0x43, 0xce, - 0xae, 0x2c, 0x02, 0x09, 0x99, 0xf5, 0xde, 0xbf, 0xde, 0xc0, 0x1e, 0xd6, - 0xef, 0x35, 0x37, 0x32, 0x67, 0xad, 0xbb, 0xf3, 0xae, 0x6c, 0x30, 0xef, - 0x8a, 0x37, 0xef, 0xea, 0x7d, 0xf2, 0x5b, 0x99, 0xb7, 0x31, 0x67, 0xda, - 0xdc, 0x46, 0xf6, 0x28, 0xea, 0xdd, 0xb0, 0x15, 0x23, 0x18, 0xb4, 0x9d, - 0x7b, 0xd5, 0x50, 0x99, 0x57, 0xbb, 0x76, 0x79, 0x16, 0xb1, 0xb0, 0x5c, - 0x76, 0x73, 0xec, 0xb2, 0xc3, 0x5a, 0xf6, 0xbb, 0xf1, 0xc0, 0x77, 0xb9, - 0xbe, 0xa8, 0xce, 0xbb, 0xcc, 0x3a, 0x6e, 0xdd, 0xab, 0x5c, 0x6e, 0x8d, - 0xa9, 0x0f, 0x32, 0x9e, 0x0e, 0xe6, 0x65, 0x82, 0xef, 0x94, 0xe3, 0xfa, - 0x11, 0xb9, 0xb2, 0xa0, 0xf6, 0xac, 0xbc, 0xbd, 0x21, 0xee, 0xf9, 0xa8, - 0xfd, 0x6f, 0xf8, 0xb5, 0x49, 0xe5, 0xd7, 0x97, 0x17, 0xd4, 0x3d, 0x17, - 0x2b, 0x39, 0x13, 0xf0, 0xfb, 0xc8, 0x25, 0xac, 0x07, 0xa4, 0x80, 0x9c, - 0xfb, 0xac, 0x75, 0x78, 0x0b, 0x71, 0x0e, 0x69, 0x2d, 0x83, 0xd6, 0xe5, - 0x05, 0xd9, 0xc2, 0x33, 0x25, 0x65, 0xb5, 0xcf, 0xe6, 0xd6, 0xc5, 0xa7, - 0xc5, 0xff, 0x7f, 0x1d, 0x41, 0x2f, 0x16, 0xf2, 0x5c, 0x0b, 0xdf, 0x73, - 0xa6, 0xaf, 0x40, 0x1e, 0x34, 0xc1, 0x7d, 0x9c, 0x66, 0xd3, 0xad, 0x9b, - 0x37, 0xb1, 0x2e, 0xda, 0xf8, 0x0e, 0x05, 0xfe, 0x0e, 0xc3, 0x7e, 0xb0, - 0x4e, 0x56, 0xdb, 0x79, 0xcd, 0xdc, 0xc3, 0xbf, 0x66, 0x60, 0xfb, 0x3f, - 0xe8, 0xf3, 0x49, 0x14, 0x38, 0x46, 0x00, 0x00, 0x00 }; - -static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = { + 0x1f, 0x8b, 0x08, 0x08, 0x51, 0xfe, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x7b, 0x7f, 0x70, + 0x1b, 0xe7, 0x99, 0xde, 0xbb, 0x0b, 0x80, 0x04, 0x29, 0x8a, 0x5a, 0x31, + 0x30, 0x83, 0x38, 0xb4, 0x8d, 0x15, 0x17, 0x34, 0x6d, 0xf2, 0x1c, 0x58, + 0xe5, 0xf9, 0xd8, 0x06, 0xb5, 0xd7, 0xc0, 0x92, 0xa2, 0x63, 0x26, 0x47, + 0xbb, 0xcc, 0x9d, 0x92, 0x51, 0x7d, 0x28, 0x48, 0x29, 0x6e, 0xe3, 0xb4, + 0xaa, 0xe3, 0x3f, 0x34, 0x4d, 0x5b, 0xc3, 0x00, 0x25, 0xcb, 0x2e, 0x44, + 0xd0, 0x16, 0x63, 0xa5, 0x33, 0x37, 0x53, 0x18, 0x80, 0x28, 0xe7, 0xba, + 0x24, 0xdc, 0xe4, 0x2e, 0xe9, 0x1f, 0xc9, 0x99, 0xa5, 0x6c, 0xc5, 0x6d, + 0xae, 0x33, 0xbe, 0x3f, 0xda, 0xa6, 0x37, 0xd7, 0x19, 0x8d, 0xfc, 0x23, + 0xce, 0x8f, 0xb9, 0xb8, 0x69, 0x7a, 0x56, 0x5b, 0xd9, 0xe8, 0xf3, 0x7c, + 0xbb, 0x4b, 0x82, 0x32, 0x15, 0x5b, 0xd7, 0x76, 0xa6, 0x9c, 0xc1, 0x10, + 0xfb, 0xed, 0xb7, 0xdf, 0xf7, 0xfe, 0x7e, 0xdf, 0xe7, 0xfd, 0x16, 0x71, + 0x91, 0x6e, 0xf1, 0xff, 0x76, 0xe3, 0x93, 0x38, 0x7a, 0xec, 0xb1, 0x3b, + 0xc6, 0xef, 0xd8, 0x2f, 0x72, 0xe7, 0x9d, 0xb2, 0x2b, 0xaa, 0xf3, 0xe6, + 0xdb, 0x21, 0x91, 0xdc, 0x4f, 0xe5, 0xaf, 0xfc, 0x87, 0xc7, 0x8d, 0x60, + 0x7d, 0x7e, 0x24, 0xaa, 0xa7, 0x5f, 0xcc, 0x64, 0x2c, 0x89, 0x86, 0xd2, + 0x33, 0x9f, 0x9d, 0xb3, 0x44, 0x6c, 0x77, 0x24, 0x91, 0x95, 0xf7, 0x5a, + 0x85, 0x58, 0x58, 0x38, 0x7e, 0x53, 0xfa, 0xca, 0xe3, 0xdf, 0xff, 0x2d, + 0xf3, 0x9d, 0x6a, 0x48, 0xa2, 0x46, 0x3a, 0x27, 0xc6, 0x90, 0x44, 0x07, + 0xf0, 0xcc, 0xef, 0xdf, 0x3a, 0xa5, 0x4b, 0x6f, 0xb0, 0x56, 0x5c, 0x16, + 0x2a, 0x6f, 0xb7, 0xbe, 0x7f, 0x6b, 0x4c, 0xfe, 0x55, 0xd3, 0x90, 0x17, + 0x9b, 0x61, 0x6d, 0xb2, 0xd2, 0x23, 0xa5, 0x8a, 0x2b, 0xc7, 0xcb, 0x05, + 0xc9, 0x36, 0x5f, 0x90, 0xe2, 0xb2, 0xd1, 0x9b, 0x39, 0xf7, 0x07, 0x52, + 0x5a, 0xee, 0xeb, 0xcd, 0x9e, 0x73, 0xa5, 0x58, 0x8e, 0xf7, 0x66, 0x9a, + 0x46, 0x6f, 0xf6, 0x4c, 0x0c, 0xd7, 0x7d, 0xbd, 0x99, 0x33, 0x66, 0x41, + 0xa4, 0x1f, 0x73, 0xe2, 0xbd, 0xd9, 0x8a, 0x99, 0x13, 0x19, 0x4c, 0xbd, + 0x22, 0x03, 0xbd, 0xd9, 0x66, 0x4d, 0x5b, 0x37, 0x34, 0x29, 0xfe, 0x86, + 0x18, 0xbd, 0xe9, 0xcb, 0xad, 0x4f, 0x58, 0x86, 0xec, 0xb5, 0x64, 0xcf, + 0x1e, 0x4b, 0x9e, 0x88, 0xa7, 0xa3, 0x92, 0x3f, 0xdd, 0x25, 0xb6, 0xe2, + 0xc9, 0x90, 0xfc, 0x99, 0x11, 0x63, 0x43, 0x22, 0x62, 0xc7, 0x82, 0xeb, + 0x56, 0x2b, 0x93, 0xfa, 0x02, 0xe5, 0x8a, 0xbd, 0xa4, 0x77, 0xb2, 0x29, + 0x92, 0xa9, 0x44, 0x25, 0x93, 0x7a, 0xaf, 0xe5, 0x3d, 0x13, 0xc5, 0xbe, + 0xe1, 0xde, 0x89, 0x4a, 0xab, 0xe5, 0xa4, 0xb0, 0x47, 0x2a, 0x78, 0x36, + 0x22, 0xd5, 0x98, 0x5d, 0x2d, 0xa5, 0x4c, 0xdd, 0xd3, 0x09, 0x79, 0xe4, + 0xb5, 0x2d, 0xba, 0xf5, 0xdb, 0x92, 0x8f, 0x49, 0xb5, 0x98, 0xba, 0x4b, + 0x9e, 0x4e, 0x19, 0x72, 0x12, 0xeb, 0x3d, 0x95, 0x82, 0x1c, 0xad, 0x63, + 0x5a, 0xa6, 0x69, 0xc6, 0x45, 0x7b, 0x5a, 0x32, 0x67, 0x06, 0x8d, 0xac, + 0x60, 0x6f, 0xab, 0x75, 0x4b, 0x26, 0x85, 0xfd, 0x46, 0xff, 0x67, 0xcb, + 0x8e, 0x99, 0xb9, 0xaa, 0x0c, 0x48, 0xb1, 0x32, 0x98, 0xfa, 0x13, 0xd1, + 0xa4, 0xd3, 0xa2, 0x7c, 0x5a, 0x72, 0x3f, 0xf6, 0xcd, 0x58, 0x18, 0x6f, + 0x8a, 0xad, 0x27, 0x23, 0xf2, 0x0f, 0x0c, 0x33, 0x91, 0x09, 0xf5, 0x4b, + 0xf1, 0x74, 0x27, 0xe8, 0xb4, 0xfb, 0x74, 0xcc, 0x3d, 0x30, 0x26, 0xb1, + 0x5d, 0x22, 0x5a, 0x28, 0x9d, 0xc4, 0xba, 0x22, 0x45, 0x77, 0x00, 0xcf, + 0x26, 0xc7, 0x7f, 0x2a, 0x7b, 0x24, 0xb1, 0x37, 0x2c, 0x25, 0xb7, 0x1b, + 0x72, 0x34, 0xa0, 0x83, 0xe4, 0xf8, 0x5f, 0x40, 0x29, 0xba, 0x95, 0x8c, + 0x1f, 0x93, 0x9c, 0x96, 0x6d, 0x76, 0x48, 0x29, 0x19, 0x95, 0x05, 0xd0, + 0xb1, 0x90, 0xfa, 0xa2, 0x96, 0x39, 0x77, 0x50, 0xcb, 0x9e, 0xc3, 0xbc, + 0x66, 0xdd, 0xb7, 0x35, 0x03, 0xeb, 0xe8, 0x52, 0x4c, 0x1e, 0xc4, 0xbd, + 0xa8, 0xcc, 0x61, 0xde, 0x1c, 0x78, 0x2a, 0x35, 0xf7, 0xc8, 0xfa, 0x6c, + 0xac, 0x37, 0x03, 0x1d, 0x16, 0x71, 0xff, 0xb7, 0x67, 0x34, 0x31, 0x2c, + 0x5b, 0x7e, 0x3c, 0x06, 0x1d, 0x9e, 0x81, 0xfe, 0xce, 0xc4, 0xe5, 0x78, + 0x45, 0x62, 0xba, 0x24, 0xe3, 0x79, 0x79, 0x41, 0xea, 0x2e, 0xf5, 0x0f, + 0x7d, 0x42, 0xdf, 0x45, 0x97, 0xcf, 0x41, 0x6f, 0x15, 0x07, 0xf2, 0x98, + 0x02, 0x0d, 0x0f, 0x6a, 0xf7, 0xd7, 0x67, 0xb5, 0x03, 0xcd, 0x1f, 0x6b, + 0xd2, 0x7d, 0x4c, 0xfb, 0x5c, 0xf3, 0x88, 0xe6, 0xcb, 0x1e, 0xba, 0x8b, + 0x8a, 0x3d, 0x13, 0x95, 0x95, 0xa6, 0xa7, 0xbb, 0x1a, 0xec, 0xd3, 0x36, + 0x6c, 0xe8, 0xe1, 0x6f, 0x6f, 0xce, 0x59, 0x69, 0xc6, 0x64, 0x01, 0xb4, + 0x1d, 0x6f, 0x72, 0xfe, 0xef, 0x41, 0x3f, 0x51, 0x71, 0x6f, 0xed, 0x91, + 0x1c, 0xc6, 0x8b, 0x67, 0xc4, 0xce, 0xa4, 0x74, 0x3c, 0xd3, 0x2b, 0x21, + 0xab, 0x1f, 0x9f, 0x6e, 0x99, 0xab, 0x77, 0xda, 0x21, 0x2b, 0x26, 0x73, + 0x4d, 0xca, 0x10, 0xff, 0x2b, 0x81, 0x1c, 0x49, 0x2b, 0xc7, 0xf9, 0x1c, + 0xc7, 0x0d, 0x8c, 0xb7, 0x8f, 0xd1, 0x2e, 0x7a, 0x41, 0x8f, 0x39, 0x2c, + 0x18, 0xcb, 0x57, 0x92, 0xc6, 0xe7, 0xf8, 0xbf, 0x49, 0xd9, 0x06, 0x32, + 0x0d, 0x63, 0xae, 0x2e, 0xf9, 0x3a, 0xf6, 0x39, 0x7d, 0xa5, 0x15, 0x19, + 0xc3, 0xb5, 0xf5, 0x4b, 0xc8, 0x92, 0xfb, 0x86, 0x41, 0x93, 0x2e, 0xb9, + 0x3a, 0xd7, 0xe2, 0x7d, 0x81, 0xee, 0x8b, 0x7b, 0x75, 0x19, 0x86, 0x7e, + 0x4d, 0xec, 0xd3, 0x85, 0x39, 0x3d, 0x90, 0x1f, 0x78, 0x3d, 0x87, 0xef, + 0xe0, 0x5d, 0xb7, 0x74, 0x3c, 0xdf, 0x29, 0x73, 0x29, 0xda, 0x0b, 0xe9, + 0xdc, 0x85, 0xb5, 0xbb, 0x64, 0xfe, 0x34, 0xe5, 0x01, 0xbb, 0xaa, 0xc4, + 0xa4, 0x74, 0xc6, 0x34, 0x1c, 0x31, 0x21, 0x1b, 0x1b, 0xf3, 0x3a, 0x25, + 0x67, 0xb4, 0x5a, 0x13, 0xa9, 0x11, 0xe3, 0x9b, 0xca, 0xce, 0x47, 0x8c, + 0xa4, 0x26, 0x85, 0x8e, 0xf4, 0x10, 0x64, 0x6b, 0x1e, 0x14, 0xe1, 0xf5, + 0x0f, 0xc4, 0x9e, 0xa5, 0xff, 0xc4, 0xb8, 0x17, 0xfc, 0xa9, 0x1f, 0xf4, + 0xd3, 0xe7, 0x06, 0xa0, 0x97, 0xb8, 0xf2, 0x83, 0x89, 0x1d, 0xfd, 0xc0, + 0x9c, 0xaa, 0x82, 0xdf, 0xe2, 0xb9, 0x30, 0xfd, 0x2f, 0x05, 0x73, 0x93, + 0x5d, 0x56, 0x14, 0xb6, 0x40, 0x5a, 0xc6, 0xb1, 0x7e, 0xab, 0xf5, 0xd9, + 0x94, 0x47, 0x53, 0xf1, 0x8c, 0x8d, 0x67, 0xc3, 0x90, 0xbb, 0xf9, 0x70, + 0x42, 0xed, 0x3f, 0xee, 0xef, 0x6f, 0xc8, 0x1c, 0xe8, 0x2e, 0x56, 0x42, + 0x92, 0x35, 0xb8, 0xc6, 0x9f, 0x71, 0x3c, 0xe7, 0xad, 0x05, 0xbb, 0x3d, + 0x35, 0x68, 0xdc, 0x07, 0x5f, 0xa2, 0x8f, 0x15, 0x57, 0x29, 0x63, 0xac, + 0x33, 0x46, 0x19, 0x1b, 0x8a, 0xc6, 0xcc, 0x19, 0xda, 0x91, 0x0c, 0x84, + 0x84, 0x76, 0x8e, 0x98, 0x01, 0xbb, 0x2a, 0xf9, 0x76, 0x95, 0x77, 0xa9, + 0xff, 0xbb, 0x7d, 0xff, 0xd4, 0x65, 0x28, 0x49, 0x7b, 0x7f, 0x5a, 0xb2, + 0xf0, 0xf1, 0x39, 0xec, 0x54, 0x07, 0x4f, 0xb5, 0xca, 0x20, 0x64, 0x15, + 0xf8, 0x1d, 0xf4, 0x3b, 0xfa, 0x6e, 0x2b, 0x88, 0x05, 0xc5, 0x0a, 0x7d, + 0xa6, 0x68, 0xe8, 0x52, 0xc0, 0x07, 0x76, 0x63, 0x99, 0xc3, 0x99, 0x90, + 0x39, 0x93, 0x03, 0x6d, 0xb0, 0x7b, 0xc9, 0xdc, 0x49, 0x7b, 0xc6, 0x9c, + 0xa6, 0xec, 0x0f, 0xfc, 0xac, 0xe6, 0x52, 0x4f, 0xdd, 0xd8, 0x37, 0xa0, + 0x29, 0x8c, 0x31, 0xae, 0x13, 0x85, 0xcd, 0x07, 0x36, 0x43, 0xfb, 0x33, + 0xed, 0x75, 0xe9, 0x90, 0xe1, 0x24, 0x62, 0xd9, 0x19, 0x1d, 0xfa, 0x1b, + 0x40, 0x4c, 0x09, 0xcb, 0x11, 0xc8, 0xea, 0x4b, 0x15, 0xd2, 0xe7, 0xc0, + 0xef, 0x10, 0xdb, 0xce, 0x4c, 0xc2, 0xcf, 0xa6, 0xb4, 0x09, 0xf8, 0xc4, + 0x67, 0xea, 0xa4, 0xa9, 0x25, 0xf4, 0x4b, 0xe7, 0x5c, 0x4e, 0x9b, 0x6c, + 0x1e, 0xd4, 0xa6, 0xce, 0xd1, 0x4f, 0xe8, 0x23, 0xa6, 0xf1, 0x80, 0x78, + 0x3c, 0x14, 0x9b, 0xaf, 0x68, 0xf4, 0xd5, 0xe2, 0xa9, 0x2e, 0xd0, 0xb1, + 0x0b, 0xf4, 0x18, 0xf0, 0x3d, 0xd8, 0x97, 0x65, 0xce, 0xd0, 0x66, 0x9c, + 0xa4, 0x95, 0xf8, 0xe7, 0xf2, 0x41, 0x39, 0x4c, 0x6c, 0xca, 0x61, 0x04, + 0x32, 0xd9, 0x2e, 0x87, 0x85, 0x0f, 0xca, 0xc1, 0x2e, 0x40, 0x0e, 0x0b, + 0x88, 0x43, 0x0b, 0x4d, 0xf2, 0xdc, 0x12, 0xfd, 0x4e, 0x81, 0x75, 0xca, + 0xbd, 0x7a, 0x9a, 0x36, 0x4a, 0x3f, 0x49, 0x26, 0x4a, 0x58, 0xa1, 0xe1, + 0xf6, 0x28, 0xdf, 0x98, 0x54, 0xb2, 0xf8, 0x30, 0x7e, 0xc9, 0xdf, 0x16, + 0xcf, 0x53, 0x75, 0xc6, 0x1b, 0xd8, 0x79, 0xd2, 0x32, 0xbe, 0x20, 0x5b, + 0x7c, 0xdf, 0xb7, 0xc5, 0x37, 0xf6, 0x09, 0x62, 0x10, 0x79, 0x0e, 0xe2, + 0x31, 0x6d, 0xe5, 0xa5, 0x56, 0xc8, 0xb2, 0xa0, 0x03, 0xda, 0x0b, 0x69, + 0x30, 0x8d, 0xcf, 0x0a, 0xfe, 0x23, 0x2e, 0xd0, 0x97, 0x72, 0x6a, 0x5e, + 0x87, 0xe4, 0xf6, 0x7a, 0xf3, 0xe7, 0x2a, 0xad, 0x5f, 0xe8, 0xe9, 0xf7, + 0x5b, 0x99, 0x31, 0xcb, 0xf7, 0xf1, 0xa8, 0x7c, 0xb9, 0x6e, 0xe6, 0x12, + 0x5a, 0x8f, 0x14, 0x6e, 0x40, 0x5c, 0xa9, 0xd0, 0x3f, 0xfa, 0xaf, 0x11, + 0xcb, 0x06, 0xfc, 0x58, 0xf6, 0x13, 0xc8, 0x9e, 0xb9, 0xe7, 0xf0, 0xfb, + 0xeb, 0x31, 0xfe, 0x4f, 0x1a, 0x33, 0xf2, 0x05, 0xe6, 0x9b, 0x3d, 0xba, + 0x8a, 0xdf, 0x16, 0x73, 0x41, 0x21, 0x9c, 0xee, 0x96, 0xc2, 0x5e, 0x29, + 0x84, 0xd2, 0xf4, 0x23, 0xfa, 0x46, 0x87, 0x4f, 0x77, 0x90, 0x3b, 0xf8, + 0x77, 0x4c, 0x17, 0x8b, 0x73, 0x90, 0x27, 0x2a, 0xe4, 0xe3, 0xbd, 0x40, + 0x27, 0x78, 0x46, 0x22, 0x9e, 0xcd, 0x4d, 0x23, 0x66, 0x52, 0xa6, 0xed, + 0xf6, 0xc2, 0x58, 0x2a, 0x09, 0xdd, 0x62, 0x2c, 0x15, 0x23, 0x94, 0x7e, + 0x50, 0xb3, 0xeb, 0x5f, 0xd4, 0x6c, 0xc8, 0xce, 0x86, 0xec, 0x6c, 0xc8, + 0x2e, 0x03, 0xd9, 0x65, 0x9b, 0xa4, 0x87, 0xb4, 0x78, 0xeb, 0x3b, 0xde, + 0xfa, 0xa0, 0xb3, 0x5f, 0xf2, 0xca, 0xc7, 0xc9, 0x2f, 0x62, 0xb2, 0x8a, + 0x07, 0x93, 0x9a, 0x17, 0x0f, 0xb8, 0xde, 0x14, 0x9e, 0xbf, 0x1b, 0x79, + 0xce, 0xd6, 0x75, 0x6b, 0x4b, 0x26, 0x0b, 0x6d, 0x32, 0x29, 0xb9, 0x94, + 0x11, 0xe7, 0xd3, 0x97, 0x5d, 0xe8, 0x3d, 0x90, 0xcb, 0x34, 0x68, 0xe8, + 0x24, 0xef, 0x3e, 0x1f, 0x5c, 0xbf, 0xcf, 0x5f, 0xff, 0xd3, 0x58, 0x93, + 0xbe, 0xbb, 0xd3, 0xbe, 0xdc, 0x93, 0xb9, 0xf4, 0xd7, 0xf1, 0x83, 0x5a, + 0x02, 0x31, 0xfa, 0x45, 0xf8, 0xda, 0xc5, 0x50, 0x5c, 0xbe, 0x7f, 0xeb, + 0x6b, 0xa8, 0x2f, 0xa4, 0x70, 0x63, 0xba, 0x95, 0x08, 0xa7, 0xdf, 0x6b, + 0x2d, 0x8c, 0x21, 0x7e, 0xa6, 0xcd, 0x78, 0x26, 0x34, 0x2a, 0x2f, 0x35, + 0x87, 0xe5, 0x3b, 0x4d, 0x4b, 0xfe, 0xa8, 0x99, 0x90, 0x3f, 0x6c, 0x0e, + 0xc8, 0xb7, 0x9b, 0x71, 0xf9, 0x56, 0x33, 0xa8, 0x45, 0xe2, 0xb4, 0xa5, + 0x5e, 0xa7, 0xb9, 0x53, 0x3d, 0x04, 0x3b, 0xc7, 0x5a, 0x99, 0xb1, 0x70, + 0x2e, 0x94, 0x56, 0x35, 0xc2, 0xcc, 0xd1, 0xf2, 0xe3, 0x2d, 0xdd, 0xb2, + 0x0a, 0xba, 0xde, 0x33, 0x6e, 0xdc, 0x25, 0x39, 0x3d, 0x8d, 0x31, 0x77, + 0x3c, 0xec, 0x94, 0xbb, 0x90, 0x5f, 0xa2, 0xa8, 0x65, 0x06, 0xa4, 0x80, + 0x75, 0x0b, 0xcd, 0x56, 0x6b, 0x29, 0xf5, 0x0f, 0x3f, 0x65, 0xfc, 0x8d, + 0x7f, 0xd9, 0x29, 0xbd, 0xdf, 0x5e, 0x37, 0x86, 0xfe, 0xbb, 0x5f, 0x0f, + 0xa1, 0xc6, 0xea, 0x57, 0x8b, 0xe7, 0xb4, 0xf4, 0xa8, 0x93, 0x70, 0x37, + 0x70, 0x5f, 0xa2, 0xfd, 0xd6, 0xcf, 0x51, 0x85, 0xc8, 0xee, 0x98, 0xc5, + 0x9a, 0x6b, 0x26, 0xfb, 0x79, 0xfc, 0xff, 0x58, 0x5a, 0xf6, 0xf4, 0xe1, + 0xff, 0xde, 0x34, 0x4c, 0x2a, 0xcd, 0x98, 0xac, 0xb5, 0xc5, 0x64, 0xd1, + 0x1c, 0xe4, 0xdf, 0x05, 0xf0, 0xe4, 0x40, 0x1e, 0xbf, 0xd3, 0x8c, 0x6a, + 0xd9, 0xd3, 0xfd, 0x52, 0xaa, 0x33, 0xaf, 0x71, 0x5e, 0xd4, 0xaf, 0x7b, + 0x78, 0xdd, 0x81, 0x6b, 0x41, 0xae, 0xf9, 0x94, 0x48, 0xaf, 0xf9, 0xa3, + 0xcf, 0x4b, 0xdd, 0xaf, 0x5b, 0x22, 0xb2, 0xac, 0x6c, 0x8c, 0xe3, 0xaf, + 0x65, 0xbf, 0x36, 0xb4, 0x35, 0xfe, 0xec, 0xe6, 0xf8, 0x3b, 0xd9, 0x4f, + 0x6f, 0x8e, 0x77, 0x87, 0x3d, 0x1e, 0xc6, 0xb5, 0x99, 0x66, 0xc1, 0x1f, + 0xbb, 0x0c, 0xb9, 0xb7, 0x5a, 0x0b, 0xc8, 0x3d, 0x45, 0xeb, 0x32, 0xea, + 0x24, 0xc6, 0x9f, 0xeb, 0x89, 0x37, 0xdb, 0x62, 0x8d, 0x91, 0x09, 0x51, + 0x9f, 0x51, 0xf1, 0xd6, 0xe4, 0xfd, 0x4e, 0xc4, 0x9d, 0xcb, 0xf8, 0xce, + 0x3c, 0x17, 0xc4, 0x3c, 0xce, 0xe1, 0xf3, 0x6f, 0x5f, 0x43, 0xe7, 0x31, + 0xe8, 0xfc, 0xff, 0x1b, 0xdd, 0xe2, 0x4f, 0xe9, 0x56, 0xc5, 0x9d, 0x97, + 0xb6, 0xd9, 0x2c, 0xe9, 0xef, 0xf6, 0x69, 0x96, 0x68, 0x38, 0x6d, 0x38, + 0x0b, 0xd6, 0x8d, 0x12, 0x41, 0x0d, 0x4b, 0x9b, 0x2d, 0x35, 0xbf, 0x8b, + 0xe7, 0x99, 0x27, 0x25, 0x1a, 0x49, 0xd3, 0x2e, 0xd6, 0x07, 0x32, 0xd6, + 0x31, 0xa7, 0xe6, 0x1e, 0x73, 0xce, 0x2a, 0x3b, 0x59, 0xbf, 0xc9, 0xab, + 0xcd, 0x7f, 0x74, 0x13, 0x6a, 0x73, 0x3c, 0xcf, 0x98, 0xcb, 0xf1, 0x46, + 0x4f, 0xc6, 0x62, 0x0e, 0x5a, 0x72, 0x8a, 0xf8, 0x2c, 0xa8, 0xb9, 0xaf, + 0x0e, 0x70, 0x6e, 0x67, 0x3a, 0x76, 0xd3, 0x8f, 0xf1, 0xbf, 0x23, 0xfd, + 0xce, 0x4d, 0x17, 0x2c, 0xae, 0x3b, 0x75, 0xd3, 0x59, 0xb5, 0x46, 0x18, + 0xf1, 0x8c, 0xf3, 0x2e, 0xdf, 0xc4, 0x67, 0x9f, 0x44, 0x1c, 0x3f, 0xe1, + 0x42, 0x97, 0xee, 0x8b, 0x4e, 0x1e, 0x9f, 0x39, 0xd2, 0x54, 0xe1, 0x7d, + 0xe3, 0xe6, 0x8c, 0x15, 0x56, 0xf9, 0xf6, 0x4b, 0x98, 0x73, 0x04, 0x73, + 0x0e, 0xbb, 0x01, 0x3f, 0xea, 0xbe, 0x93, 0xc5, 0xfd, 0xc3, 0x65, 0xc3, + 0x71, 0xca, 0xe6, 0x38, 0x6a, 0x8e, 0xf8, 0x71, 0xe4, 0xe3, 0x1c, 0x72, + 0xa0, 0x2d, 0xe6, 0x70, 0x41, 0xd2, 0x5d, 0x93, 0xa8, 0xe5, 0x56, 0x90, + 0x4f, 0x50, 0x87, 0xa4, 0xaa, 0x32, 0xd8, 0x95, 0x39, 0xad, 0xc3, 0x3e, + 0xef, 0x80, 0xbd, 0x1a, 0x8e, 0x9e, 0x44, 0x5c, 0x47, 0xdc, 0x5c, 0xa8, + 0x58, 0x5a, 0xb6, 0x3c, 0x68, 0x94, 0xe4, 0x56, 0x59, 0x37, 0xcc, 0xf8, + 0xa4, 0xec, 0x92, 0x6c, 0x18, 0xf3, 0x86, 0x3f, 0x2e, 0xb9, 0xb8, 0x86, + 0xd8, 0x70, 0x03, 0xe2, 0x16, 0xeb, 0xe4, 0xf6, 0x18, 0xfa, 0x0b, 0x11, + 0xeb, 0x8b, 0x21, 0xc6, 0x9e, 0x4e, 0x8b, 0x75, 0x3f, 0xe7, 0xed, 0x92, + 0x8d, 0x0f, 0xcc, 0x7b, 0xb7, 0x6d, 0x5e, 0xfb, 0xf8, 0x7b, 0x18, 0xdf, + 0x25, 0x17, 0x41, 0x47, 0x38, 0x39, 0x26, 0x25, 0xf0, 0x10, 0x39, 0xd5, + 0x6a, 0x5d, 0x00, 0x3f, 0x3a, 0xf8, 0x2f, 0x56, 0x59, 0x0b, 0x84, 0xa4, + 0x6a, 0xe0, 0x9e, 0xdb, 0x6a, 0xd5, 0x10, 0x46, 0xf5, 0x55, 0xd2, 0x1c, + 0x95, 0x49, 0x77, 0x48, 0xec, 0x06, 0xe5, 0x60, 0xc2, 0xeb, 0xfe, 0xac, + 0x2b, 0x7b, 0x86, 0x39, 0x13, 0x16, 0xb1, 0xfa, 0xe7, 0x5d, 0x19, 0xe4, + 0x3e, 0x7d, 0xf5, 0x62, 0x57, 0x16, 0x7a, 0x0f, 0xad, 0xfe, 0xe7, 0x2e, + 0xe7, 0x34, 0xe9, 0x0a, 0x21, 0xf7, 0xdd, 0x22, 0x45, 0xa3, 0x25, 0xdf, + 0x44, 0x8d, 0x50, 0x1c, 0x46, 0x2e, 0x83, 0x17, 0xe8, 0xa0, 0xbb, 0x60, + 0x48, 0xb4, 0x3b, 0xfd, 0x7d, 0xd0, 0x37, 0x06, 0xd9, 0xec, 0xc2, 0x9c, + 0x10, 0xc6, 0x87, 0xf0, 0xbf, 0x7d, 0xfc, 0x8d, 0x2e, 0xe4, 0x05, 0xc4, + 0x60, 0x89, 0x66, 0xc6, 0x7a, 0xb0, 0xfe, 0xf7, 0x30, 0x8e, 0x09, 0xc9, + 0xcd, 0xf1, 0x27, 0xbc, 0xf1, 0xb7, 0x41, 0x0b, 0x9f, 0x63, 0x8d, 0x22, + 0xd1, 0xb9, 0x31, 0x03, 0x34, 0x70, 0x6e, 0x4c, 0xcd, 0x75, 0xce, 0xd0, + 0x06, 0x0c, 0xa7, 0x66, 0xdd, 0x2c, 0xd9, 0xe5, 0x7e, 0x99, 0x5c, 0xee, + 0x93, 0x03, 0xcb, 0xe6, 0x4c, 0x95, 0xd8, 0x0f, 0x3c, 0x0b, 0xea, 0x30, + 0x7d, 0x55, 0x20, 0x01, 0x33, 0x7e, 0x44, 0x06, 0xe3, 0x5f, 0x92, 0x5f, + 0xb6, 0x90, 0xef, 0x91, 0xeb, 0x7b, 0x24, 0xac, 0xd6, 0x89, 0x07, 0x7b, + 0xd2, 0x46, 0xb7, 0xed, 0xeb, 0x9c, 0xb9, 0xd6, 0xba, 0x70, 0xfe, 0xd5, + 0xf8, 0x55, 0xeb, 0xfe, 0x85, 0xbf, 0xae, 0x81, 0x75, 0x07, 0xb0, 0x26, + 0x79, 0x34, 0xbb, 0x26, 0x4e, 0x8b, 0xdd, 0x09, 0xfa, 0x9c, 0xe4, 0x8d, + 0xc0, 0x86, 0xfd, 0x72, 0x62, 0x99, 0xf1, 0x42, 0xfa, 0xf1, 0x19, 0x8d, + 0x48, 0x72, 0xf8, 0x1c, 0xea, 0xae, 0x09, 0xb5, 0x86, 0x57, 0x93, 0xe9, + 0xab, 0x29, 0xd4, 0xc4, 0x3f, 0x05, 0x3d, 0xac, 0x15, 0xc8, 0x73, 0x18, + 0xfc, 0xa6, 0x50, 0x8b, 0x11, 0x47, 0xb5, 0x1e, 0xcf, 0xa4, 0xf0, 0xfd, + 0x5c, 0xa2, 0x2b, 0x8b, 0x98, 0x08, 0xff, 0xbe, 0x39, 0xa4, 0x72, 0x18, + 0xf5, 0x32, 0xda, 0x45, 0x3c, 0x83, 0xe7, 0xa1, 0x27, 0xca, 0x68, 0xbc, + 0xcb, 0xa9, 0x50, 0x46, 0x02, 0x7a, 0x2c, 0xd8, 0x64, 0x58, 0x61, 0x29, + 0x7d, 0xd5, 0xc6, 0xbc, 0xb7, 0x42, 0xac, 0x77, 0x33, 0x16, 0xbf, 0x23, + 0xe6, 0xac, 0x4e, 0x61, 0x2e, 0xbf, 0xdf, 0x85, 0x75, 0x07, 0x87, 0x8b, + 0xd2, 0x31, 0x7c, 0x18, 0xf1, 0x4e, 0x1f, 0x1b, 0x01, 0x6d, 0xb4, 0xf3, + 0x16, 0xb0, 0xc0, 0x6f, 0x81, 0x1f, 0xf8, 0x46, 0xd2, 0x92, 0xf9, 0x25, + 0xca, 0x55, 0x3e, 0x0e, 0x1e, 0xc0, 0x7f, 0x12, 0x71, 0x8d, 0x3c, 0x70, + 0x6f, 0x41, 0x8e, 0xbe, 0x5b, 0xf2, 0x4b, 0x51, 0x55, 0xeb, 0xdb, 0x06, + 0xf7, 0xd7, 0x34, 0x3d, 0xdd, 0x0d, 0x1d, 0x93, 0xb7, 0x1c, 0x68, 0x7b, + 0x0c, 0x79, 0x80, 0xbc, 0x91, 0x2f, 0xfa, 0xca, 0x28, 0xfc, 0x84, 0xf4, + 0xfb, 0xb6, 0xa7, 0xad, 0x23, 0xa6, 0xa8, 0x38, 0x98, 0xca, 0x20, 0xb0, + 0xbd, 0xd4, 0x1c, 0x97, 0x3f, 0x6e, 0x8e, 0xc9, 0x77, 0x9b, 0x29, 0xe4, + 0xc0, 0x51, 0xe4, 0xc0, 0x61, 0xe4, 0x40, 0x0b, 0x39, 0x30, 0x81, 0x1c, + 0x38, 0x80, 0x1c, 0x18, 0x47, 0x9c, 0x14, 0x39, 0xa1, 0xf2, 0x6d, 0x2c, + 0x0a, 0xcc, 0x1d, 0xb5, 0x9b, 0x0e, 0x78, 0x99, 0xc1, 0x5e, 0xb3, 0xe0, + 0xeb, 0x50, 0xd7, 0x44, 0x65, 0x1c, 0x31, 0xd7, 0x42, 0x3c, 0x4a, 0x20, + 0xdf, 0x8c, 0x01, 0x6b, 0x89, 0x6c, 0x2c, 0x25, 0x10, 0x13, 0x5b, 0xe2, + 0x00, 0x13, 0x97, 0x8c, 0x14, 0x9e, 0xdd, 0xab, 0xec, 0x33, 0x94, 0xbe, + 0x3b, 0x2c, 0xdd, 0xa3, 0x92, 0x2f, 0x9f, 0xc4, 0x58, 0x1c, 0xeb, 0x75, + 0x21, 0x2f, 0x31, 0x2e, 0x30, 0x06, 0x2c, 0x39, 0xbf, 0x6b, 0xd1, 0xd7, + 0xba, 0xb5, 0xcc, 0xe9, 0x82, 0x30, 0x96, 0x23, 0x0f, 0xc0, 0x1e, 0x38, + 0x36, 0x89, 0xe7, 0xf8, 0xfd, 0x2f, 0xfd, 0x98, 0xf9, 0xb1, 0x4e, 0x81, + 0xd1, 0xbe, 0xc4, 0x9c, 0x67, 0x61, 0x3d, 0xb7, 0xdd, 0x4f, 0x9f, 0x47, + 0xad, 0x14, 0xdc, 0x27, 0xae, 0x66, 0x3f, 0xe1, 0x24, 0x68, 0x1e, 0x04, + 0xbe, 0x47, 0x6d, 0x75, 0xb0, 0x8a, 0xef, 0xed, 0xf3, 0x5d, 0xcc, 0x57, + 0x63, 0x51, 0x23, 0x6d, 0xb1, 0x9e, 0x43, 0xac, 0x3c, 0x86, 0xb8, 0x68, + 0x3b, 0xfa, 0x5a, 0x03, 0x7c, 0x42, 0x8e, 0x65, 0xdb, 0x09, 0x0f, 0xbd, + 0xd6, 0x7a, 0xd6, 0x1a, 0x96, 0x89, 0xb5, 0x31, 0xc9, 0xae, 0x0d, 0xc6, + 0xcf, 0x4b, 0xd7, 0x65, 0x5b, 0x5e, 0x6b, 0x95, 0x5c, 0xf3, 0xa4, 0x0d, + 0xbb, 0xdc, 0xb7, 0xdf, 0x90, 0x1a, 0x30, 0xdc, 0xbe, 0xfd, 0x9d, 0xac, + 0xe9, 0x5f, 0x14, 0x3d, 0x21, 0x99, 0x45, 0x5b, 0xc6, 0xf6, 0x07, 0xb5, + 0xe7, 0x2f, 0x3b, 0xa4, 0x1b, 0x63, 0x6b, 0x09, 0xcc, 0x61, 0xdd, 0xaf, + 0xfa, 0x27, 0xe0, 0x59, 0xf3, 0x9e, 0x51, 0x39, 0x8f, 0x98, 0x19, 0xbc, + 0x37, 0x6d, 0xe7, 0xfc, 0x22, 0x70, 0x0d, 0xe4, 0x99, 0x59, 0x24, 0xee, + 0xda, 0x05, 0x39, 0x45, 0x60, 0x23, 0xd4, 0xfd, 0x20, 0x9e, 0x6d, 0xc9, + 0x57, 0x53, 0xb4, 0x87, 0xc7, 0x20, 0x4b, 0xac, 0x15, 0x0e, 0xf8, 0xf9, + 0x9a, 0xcc, 0x2d, 0x51, 0x7e, 0x71, 0xd4, 0x96, 0xdc, 0x5b, 0xa2, 0x5d, + 0xe9, 0xab, 0xeb, 0x46, 0xdb, 0xd9, 0x58, 0xc4, 0xfa, 0x43, 0xc4, 0xd8, + 0x88, 0xd5, 0x65, 0xf6, 0x06, 0x58, 0x53, 0x1d, 0x80, 0x4e, 0xa6, 0x15, + 0xe6, 0xce, 0xd4, 0x53, 0x62, 0x9d, 0x62, 0xac, 0x92, 0x44, 0xc8, 0x22, + 0xbe, 0x17, 0x43, 0x4f, 0xcf, 0xe2, 0x1e, 0xe5, 0xc9, 0x5a, 0x1f, 0xf7, + 0x57, 0xff, 0xa3, 0xd2, 0x49, 0x08, 0xba, 0xcb, 0xef, 0x67, 0x11, 0x22, + 0x4b, 0xa1, 0x34, 0x62, 0xe0, 0x18, 0x79, 0x50, 0x7b, 0xa3, 0x9e, 0xa4, + 0xdf, 0x81, 0x67, 0xd8, 0x46, 0x5b, 0x5d, 0xa9, 0xfe, 0x4a, 0x95, 0x08, + 0x6c, 0x59, 0x0a, 0x91, 0x34, 0x78, 0x1a, 0xc3, 0x77, 0x38, 0xff, 0x09, + 0xe8, 0xf3, 0x2c, 0x9e, 0x5f, 0x00, 0x5f, 0x1b, 0x65, 0xd2, 0x9d, 0x4c, + 0x1c, 0x57, 0xbe, 0x8b, 0x6b, 0x97, 0xb5, 0xcc, 0xd7, 0xe4, 0xbc, 0xe2, + 0xef, 0x13, 0xac, 0x9d, 0xa1, 0xa7, 0xeb, 0xe1, 0x6f, 0xf2, 0x3a, 0xf9, + 0xf3, 0xd6, 0x67, 0xce, 0xca, 0x58, 0x09, 0xc9, 0x96, 0x5f, 0x6a, 0x85, + 0x2d, 0x2b, 0x3e, 0xef, 0xeb, 0x31, 0xeb, 0x46, 0x41, 0x07, 0xfb, 0x00, + 0xfb, 0x95, 0x2e, 0x41, 0x07, 0x6d, 0xa7, 0x10, 0x4d, 0x3f, 0x2e, 0x2b, + 0x4b, 0xff, 0x54, 0x6a, 0x4b, 0x05, 0xa9, 0x2f, 0xfd, 0x23, 0x39, 0xb7, + 0xd4, 0x92, 0x0b, 0x29, 0x15, 0x93, 0xac, 0x0e, 0xe5, 0xcf, 0x72, 0xa3, + 0x87, 0x07, 0x93, 0xe3, 0x97, 0x20, 0xc0, 0x95, 0xaa, 0x47, 0xfb, 0x54, + 0x1b, 0xed, 0x17, 0x60, 0x6b, 0xaf, 0x58, 0xa4, 0x7f, 0x4c, 0x6a, 0x65, + 0xd2, 0xfe, 0xa0, 0xa2, 0xfd, 0xc0, 0x26, 0xed, 0x92, 0x0b, 0x59, 0xa4, + 0x7f, 0x27, 0xda, 0x81, 0xf3, 0xfb, 0x49, 0x7f, 0x02, 0xcf, 0x7e, 0xd0, + 0xfe, 0x6a, 0xee, 0x6b, 0xad, 0x8d, 0x72, 0x44, 0xd1, 0x1c, 0x4a, 0x8f, + 0x41, 0x3e, 0xaf, 0xb5, 0xd6, 0x5d, 0xfa, 0x11, 0xbe, 0xbb, 0xf7, 0x20, + 0x46, 0xf5, 0x61, 0xaf, 0x5e, 0xc9, 0xcf, 0x46, 0x11, 0x27, 0xc7, 0xa1, + 0xdb, 0x2e, 0xe5, 0x87, 0x08, 0x17, 0xd0, 0xd9, 0x34, 0xe6, 0x1f, 0xa2, + 0xbf, 0x29, 0xb9, 0x38, 0x90, 0x4b, 0xb1, 0x9c, 0x8e, 0xa0, 0xfe, 0xc7, + 0x3e, 0x86, 0x93, 0x73, 0xf9, 0xcc, 0x00, 0x62, 0x1a, 0xff, 0x7f, 0x64, + 0x7b, 0x28, 0x20, 0xd6, 0x42, 0xe7, 0x3d, 0x90, 0x1f, 0xe8, 0x18, 0x9b, + 0x41, 0x6e, 0x4d, 0x0e, 0xd7, 0x54, 0x7f, 0x91, 0x71, 0xe5, 0x28, 0xf2, + 0xe9, 0x21, 0x7c, 0xbc, 0xfd, 0x26, 0x9a, 0xdc, 0x73, 0x3b, 0x4f, 0x45, + 0x77, 0x7d, 0x2f, 0x01, 0x52, 0xa6, 0xc9, 0x7d, 0x0b, 0x12, 0x4a, 0x87, + 0xb0, 0x2f, 0xc7, 0x7a, 0x10, 0x63, 0x06, 0xa2, 0xd9, 0xe6, 0xcf, 0x31, + 0x4e, 0x5f, 0x66, 0x7c, 0x0f, 0x68, 0x1f, 0xc5, 0x9a, 0x8c, 0xbb, 0x63, + 0xe0, 0x99, 0x35, 0x26, 0xe3, 0x26, 0xf2, 0x48, 0xe3, 0x47, 0xcc, 0x2d, + 0xf8, 0x3e, 0xe0, 0x7f, 0xe7, 0x7d, 0x89, 0xde, 0x9c, 0x36, 0xab, 0x05, + 0x31, 0xb1, 0x27, 0x74, 0x6e, 0xc5, 0xa5, 0xd8, 0x30, 0x5f, 0x20, 0x66, + 0xd4, 0x29, 0x83, 0x35, 0xca, 0x89, 0xfd, 0x27, 0xd4, 0x7f, 0xb5, 0xe7, + 0x21, 0x8f, 0xa8, 0xec, 0xb5, 0x0e, 0x22, 0xa6, 0x80, 0xfe, 0xca, 0x18, + 0x78, 0x63, 0x8f, 0x66, 0x10, 0xf9, 0x2b, 0x04, 0x21, 0xa0, 0x96, 0x5a, + 0x0b, 0xc9, 0xbd, 0xe1, 0x11, 0xa3, 0x28, 0x8f, 0x46, 0x58, 0x36, 0x17, + 0xd6, 0x98, 0x07, 0xc2, 0xb2, 0xb0, 0x26, 0x72, 0x69, 0x91, 0x71, 0x45, + 0xfd, 0x41, 0xe6, 0x86, 0x33, 0x8f, 0x3c, 0x5b, 0x5a, 0x62, 0x8c, 0x61, + 0x9c, 0xb8, 0x01, 0xba, 0x48, 0x7e, 0xe3, 0xab, 0xc8, 0x49, 0xa5, 0xf2, + 0x20, 0x62, 0xa6, 0xac, 0xeb, 0x90, 0x29, 0x72, 0x19, 0x6b, 0xd4, 0x1d, + 0xfa, 0x32, 0x41, 0x4f, 0x26, 0x2a, 0xc5, 0x45, 0xf6, 0x63, 0xa2, 0xa0, + 0x85, 0x35, 0x76, 0x48, 0xd5, 0x3f, 0x37, 0xa8, 0xd8, 0xca, 0xff, 0xe1, + 0xb6, 0x7d, 0x93, 0x27, 0xf7, 0xe9, 0x8c, 0x63, 0x37, 0x8b, 0x3d, 0x63, + 0x77, 0x1d, 0xa8, 0x74, 0x48, 0xb5, 0x8f, 0x76, 0x49, 0xfd, 0xbf, 0xa0, + 0x62, 0xed, 0x02, 0x78, 0x2a, 0x2e, 0x12, 0xe3, 0x86, 0x31, 0x2f, 0xe6, + 0xcf, 0xa3, 0x5c, 0xff, 0x89, 0xcc, 0xed, 0x7f, 0x17, 0x74, 0x79, 0x71, + 0x2d, 0xbf, 0x1f, 0xf1, 0x76, 0x46, 0x97, 0x3b, 0xef, 0x1a, 0xc7, 0xb3, + 0xcc, 0x81, 0xef, 0xf8, 0x78, 0x92, 0x63, 0xec, 0x61, 0x81, 0xbe, 0x15, + 0x03, 0xff, 0xfb, 0xa4, 0xb0, 0x12, 0x85, 0x1c, 0x90, 0x4b, 0x6b, 0xde, + 0x5a, 0xac, 0x77, 0x4f, 0x42, 0x47, 0xfa, 0xa9, 0xa8, 0x44, 0x4e, 0xf5, + 0x49, 0xf8, 0xeb, 0xdd, 0xd2, 0xf1, 0xf5, 0x21, 0x09, 0x7d, 0xdd, 0x64, + 0x4e, 0x4f, 0x9c, 0x80, 0xbe, 0xe6, 0x65, 0x5c, 0x9e, 0x44, 0xde, 0x62, + 0x5e, 0x57, 0x76, 0x6a, 0xf4, 0x4b, 0x08, 0x05, 0xab, 0xfe, 0x8c, 0x2d, + 0x8f, 0xee, 0xff, 0x85, 0xea, 0x33, 0x01, 0xc3, 0x8b, 0xfe, 0xfc, 0x94, + 0xd8, 0xcd, 0x77, 0x21, 0x6b, 0xc3, 0x79, 0xed, 0xd6, 0xa0, 0xa6, 0x1c, + 0x56, 0xfd, 0xc2, 0x47, 0xf7, 0x7b, 0x35, 0x25, 0xf0, 0xb8, 0xe6, 0xa8, + 0x9a, 0x12, 0xf1, 0x35, 0xcc, 0x79, 0xfd, 0xa2, 0x63, 0xaf, 0xbc, 0x0c, + 0x42, 0x4f, 0xb7, 0x88, 0x7d, 0x08, 0x7e, 0xf1, 0x9c, 0x2c, 0xe9, 0x69, + 0x4d, 0xad, 0x19, 0x7a, 0x86, 0x71, 0x8a, 0xf1, 0x8b, 0x36, 0x9e, 0x4c, + 0x14, 0x61, 0x7f, 0xa1, 0xe7, 0x19, 0xa3, 0x3c, 0xdb, 0x9e, 0x68, 0x8b, + 0x75, 0x0b, 0x95, 0x7b, 0xa0, 0x43, 0xd4, 0xf2, 0x16, 0xe2, 0x9c, 0x81, + 0x5c, 0x6e, 0xf1, 0xda, 0xeb, 0xe1, 0xe5, 0x63, 0x31, 0x75, 0x5d, 0xac, + 0x7a, 0x18, 0xdc, 0x5b, 0x9f, 0x75, 0x07, 0x62, 0x4c, 0x93, 0x74, 0x70, + 0xdf, 0x01, 0x09, 0x3d, 0x17, 0x93, 0xf0, 0x73, 0xb4, 0x3f, 0x33, 0xe1, + 0x40, 0x7e, 0x0b, 0x16, 0x31, 0xd0, 0x0a, 0xb0, 0xc5, 0xcd, 0xa2, 0xaf, + 0x0c, 0xc0, 0x77, 0xcc, 0x78, 0x55, 0x92, 0x12, 0xaa, 0x45, 0xe5, 0xad, + 0x45, 0x33, 0x41, 0x7b, 0x39, 0x6b, 0x61, 0xbc, 0xd9, 0x75, 0x79, 0x5d, + 0x51, 0xc1, 0xb1, 0x2f, 0x87, 0x80, 0x19, 0x86, 0x6d, 0xbd, 0x47, 0x5e, + 0x87, 0xbe, 0x73, 0x6a, 0xec, 0x66, 0xac, 0x0b, 0x1a, 0x9e, 0x33, 0xc1, + 0x03, 0xd7, 0xfd, 0x1e, 0xd6, 0x54, 0xf8, 0xca, 0xd9, 0x60, 0x4d, 0xba, + 0x48, 0xdb, 0xed, 0x83, 0xdd, 0xe1, 0xba, 0xd9, 0x21, 0xb9, 0xd9, 0x84, + 0xe8, 0x8b, 0x9f, 0x91, 0xc1, 0xfd, 0xba, 0xc7, 0x8f, 0xe2, 0x91, 0x63, + 0xec, 0xc7, 0xdd, 0xae, 0xfc, 0x51, 0x5f, 0x83, 0xcd, 0x3c, 0x48, 0x1d, + 0x23, 0xf7, 0x23, 0x8f, 0x31, 0x8e, 0x85, 0x90, 0xc7, 0xb2, 0x4d, 0x4f, + 0xef, 0xd5, 0x07, 0xfb, 0xe5, 0xc9, 0xe7, 0x68, 0x4f, 0xb8, 0xb7, 0x69, + 0x53, 0x41, 0x0f, 0x98, 0xf7, 0x2c, 0x39, 0xf9, 0x6c, 0x50, 0x73, 0xb0, + 0xbe, 0x32, 0xe3, 0x07, 0xc0, 0x8f, 0x7e, 0x27, 0xe3, 0x81, 0xae, 0x6c, + 0x37, 0x6f, 0x59, 0x5e, 0xdd, 0x51, 0x49, 0xb0, 0x2f, 0x6e, 0xb0, 0x4e, + 0xb3, 0xe3, 0x9e, 0xbc, 0x8b, 0x18, 0x2b, 0x35, 0x67, 0x11, 0xa3, 0x23, + 0x72, 0x71, 0xd6, 0x86, 0xee, 0x3f, 0x0b, 0xba, 0x0e, 0x75, 0x11, 0x23, + 0x5f, 0x9c, 0x75, 0x70, 0x7d, 0x48, 0xd5, 0x66, 0xa1, 0x3b, 0x61, 0xc7, + 0xcd, 0x7e, 0xfa, 0x91, 0xaf, 0xa7, 0x84, 0x56, 0x5c, 0x32, 0xb5, 0x12, + 0x62, 0xf6, 0x64, 0x8a, 0x39, 0xbe, 0x53, 0xf5, 0x4d, 0xd9, 0xaf, 0xc9, + 0x2b, 0xbc, 0xb0, 0x4f, 0x2b, 0x56, 0x19, 0xe7, 0x0b, 0xf1, 0x0e, 0x21, + 0x0e, 0x11, 0xad, 0x66, 0x51, 0x27, 0x9a, 0x9c, 0x57, 0xbd, 0x58, 0x11, + 0xc7, 0x3d, 0x42, 0x19, 0x68, 0xf5, 0xea, 0x3e, 0xad, 0x50, 0x0d, 0xc9, + 0xc5, 0x18, 0xe9, 0x4e, 0xa8, 0xfa, 0x7d, 0xbf, 0xb2, 0xb5, 0x1e, 0xe4, + 0x12, 0xd8, 0x4c, 0xea, 0x93, 0xd8, 0x57, 0x8d, 0xc1, 0xa6, 0xa8, 0x7b, + 0xea, 0x5d, 0xc5, 0x48, 0x5f, 0xf7, 0x3b, 0xe5, 0x4c, 0xd0, 0x51, 0x26, + 0x7e, 0xef, 0xf4, 0xf1, 0xfb, 0xa2, 0x5f, 0x0f, 0x3d, 0x26, 0xac, 0x53, + 0x16, 0x2a, 0xa4, 0x05, 0xf1, 0xd6, 0xdd, 0xc9, 0x96, 0x28, 0x47, 0x2f, + 0xa6, 0x1c, 0x45, 0x1d, 0xa3, 0xaf, 0x19, 0xbe, 0x0d, 0xf0, 0x6f, 0x14, + 0xf7, 0xbc, 0x5a, 0xaa, 0xd8, 0x8c, 0xc0, 0xdf, 0xa7, 0x21, 0x23, 0xea, + 0x06, 0xfa, 0x5b, 0xe3, 0x99, 0x0a, 0xf4, 0xb7, 0xf6, 0xf2, 0xfb, 0x76, + 0x1f, 0x63, 0xde, 0xb0, 0x3c, 0x89, 0xf1, 0x13, 0x67, 0x48, 0xcf, 0xb8, + 0x8f, 0xc7, 0x12, 0x90, 0x09, 0x63, 0xfc, 0xa8, 0xbc, 0xd5, 0x70, 0x14, + 0xfe, 0xdb, 0xb7, 0x7f, 0x46, 0xe6, 0xdd, 0x59, 0xe0, 0x3f, 0xc8, 0xdf, + 0x48, 0xc0, 0x3f, 0xe3, 0x2a, 0x3e, 0x1e, 0xfe, 0x68, 0x35, 0x49, 0xd8, + 0xcb, 0xd9, 0xf7, 0x5e, 0x67, 0xce, 0xde, 0x0d, 0xfc, 0xf5, 0x91, 0xd6, + 0x0f, 0x79, 0xeb, 0xff, 0x17, 0xe8, 0xea, 0x73, 0xd8, 0x23, 0x0a, 0xfa, + 0xfa, 0x29, 0xd3, 0x0f, 0x7b, 0x4e, 0xf7, 0x9e, 0xbb, 0xff, 0x3a, 0xe9, + 0x32, 0xa4, 0x01, 0x8c, 0x50, 0x50, 0x79, 0x94, 0xb5, 0x62, 0xc4, 0xd7, + 0xdf, 0x31, 0x60, 0x67, 0xae, 0x1b, 0xc4, 0xde, 0x4e, 0x29, 0xf4, 0x05, + 0xf5, 0x27, 0x62, 0xf6, 0xe6, 0x78, 0x50, 0xcf, 0xf2, 0xf9, 0x94, 0x93, + 0x2f, 0xb3, 0x4f, 0xc8, 0x5c, 0xc0, 0x31, 0x65, 0x87, 0x1f, 0x42, 0xb7, + 0x09, 0xcf, 0x20, 0xdd, 0xf7, 0x29, 0xba, 0x1d, 0x45, 0x37, 0xfd, 0x8b, + 0x67, 0x3a, 0xec, 0xa3, 0x05, 0x7d, 0x33, 0xae, 0x07, 0x4c, 0x00, 0x7d, + 0x7f, 0x17, 0x3a, 0xfe, 0x4e, 0x05, 0x98, 0xa0, 0x02, 0x4c, 0x80, 0x3d, + 0xbe, 0x0d, 0x1d, 0x7f, 0xab, 0x02, 0x4c, 0x50, 0x89, 0xfb, 0x3d, 0x0a, + 0x9b, 0x98, 0xfe, 0x23, 0xda, 0x6e, 0xd0, 0x93, 0xb9, 0xda, 0x2e, 0x39, + 0xce, 0xf9, 0x01, 0x36, 0x8e, 0xc2, 0x8e, 0x78, 0x6e, 0x11, 0xf4, 0x3b, + 0xfc, 0x1c, 0xd1, 0xe0, 0xb9, 0x00, 0x72, 0x44, 0x83, 0xe7, 0x18, 0x23, + 0xf1, 0x10, 0x30, 0x61, 0x48, 0xe2, 0xc2, 0x5e, 0xef, 0xdc, 0x18, 0xd6, + 0x1a, 0x1d, 0x84, 0x27, 0x75, 0xa8, 0xbe, 0xd6, 0x71, 0xd5, 0x6f, 0x40, + 0x5c, 0xa8, 0x06, 0xb5, 0x5b, 0x52, 0x26, 0x96, 0x88, 0x33, 0x65, 0xaf, + 0x9e, 0x86, 0x0e, 0x5c, 0x62, 0xc3, 0xcd, 0xbe, 0xf4, 0x70, 0x1d, 0x7b, + 0x16, 0x2d, 0x8f, 0xbe, 0xe3, 0xee, 0xd6, 0x33, 0x07, 0x10, 0x9f, 0xa7, + 0xca, 0x09, 0x99, 0x2c, 0x7b, 0x98, 0x00, 0xf5, 0xcf, 0x55, 0xfd, 0x51, + 0x9b, 0x7a, 0x80, 0xfe, 0x36, 0x6d, 0x23, 0x71, 0x3e, 0x45, 0x19, 0x53, + 0xff, 0xd3, 0xaa, 0x67, 0x7d, 0xa0, 0xee, 0xf5, 0xe5, 0x27, 0x95, 0x2d, + 0x84, 0x19, 0x67, 0xa8, 0x3f, 0xcf, 0x87, 0x61, 0x17, 0x79, 0x37, 0x90, + 0x4b, 0x3b, 0x1e, 0xf9, 0xbc, 0x26, 0xd6, 0x4e, 0xe3, 0xb9, 0xb6, 0xf1, + 0xcd, 0xfb, 0x3e, 0xbd, 0x88, 0x7d, 0x9b, 0x3d, 0x06, 0xc6, 0xa9, 0xad, + 0xf1, 0x10, 0xea, 0x87, 0xb0, 0xba, 0x8f, 0x18, 0xde, 0x88, 0x49, 0xb6, + 0x61, 0x89, 0x53, 0xe5, 0x3c, 0xf6, 0x2d, 0x18, 0x8f, 0x9e, 0x90, 0xec, + 0x52, 0xaf, 0xe4, 0x62, 0x66, 0xca, 0x96, 0xbf, 0x27, 0x1b, 0xcb, 0x85, + 0x04, 0xcf, 0x0d, 0x0b, 0x33, 0x1a, 0x9e, 0x7b, 0x18, 0xd7, 0xa4, 0xd9, + 0x92, 0xc3, 0x65, 0xe6, 0x9d, 0x91, 0x78, 0x03, 0xf7, 0x72, 0xb3, 0xec, + 0xd5, 0x54, 0x61, 0x93, 0x66, 0xa2, 0x8a, 0x78, 0xf0, 0x72, 0x99, 0xfb, + 0x01, 0x1b, 0x95, 0xd9, 0xcf, 0x09, 0xee, 0x3f, 0x01, 0x1c, 0x88, 0x58, + 0x1d, 0xf3, 0xe7, 0x28, 0x5e, 0x6d, 0x23, 0x2c, 0x81, 0xae, 0x3b, 0x65, + 0xdd, 0x8f, 0xbb, 0xb5, 0xb2, 0xd7, 0x47, 0x39, 0x4b, 0x7a, 0xdc, 0xff, + 0xd5, 0x5a, 0x8f, 0xa1, 0x16, 0xda, 0xe4, 0xf5, 0x8f, 0xb9, 0x8f, 0x81, + 0xb0, 0x2b, 0x27, 0xdc, 0x40, 0x26, 0xbc, 0xcf, 0x31, 0x9e, 0x8d, 0xb6, + 0x5a, 0x67, 0xad, 0xf6, 0x9e, 0xdf, 0xf5, 0xf4, 0xcc, 0xde, 0xb8, 0x2d, + 0x63, 0xbd, 0xe6, 0xa0, 0x26, 0xf6, 0x7b, 0x66, 0x87, 0x46, 0xbc, 0x9e, + 0xd9, 0xfc, 0xc8, 0xf6, 0x9e, 0xd9, 0xcf, 0x6f, 0xf3, 0x7a, 0x66, 0x17, + 0x9d, 0x22, 0x3e, 0x5e, 0xcf, 0x6c, 0xf8, 0x76, 0xaf, 0x67, 0xf6, 0xf0, + 0xed, 0x5e, 0xcf, 0xec, 0x91, 0x11, 0xaf, 0x67, 0xf6, 0xfb, 0xb7, 0x6f, + 0xef, 0x99, 0x3d, 0x36, 0xb2, 0xbd, 0x67, 0x26, 0x13, 0xc8, 0x77, 0x13, + 0x5b, 0x3d, 0xb3, 0xf2, 0xc8, 0xb5, 0x7b, 0x66, 0xaf, 0x06, 0x78, 0x1d, + 0xfc, 0x8c, 0x81, 0x87, 0x14, 0xf0, 0xfa, 0x28, 0xf0, 0xfa, 0xaf, 0xeb, + 0x59, 0x87, 0xc1, 0xe7, 0xcd, 0x7e, 0x5e, 0xb8, 0x1e, 0xdc, 0x7e, 0xbb, + 0xff, 0x8c, 0xa0, 0xde, 0x4d, 0xf8, 0xb5, 0x0a, 0xb1, 0xfb, 0x1e, 0xbf, + 0x66, 0xfb, 0x6b, 0xd1, 0xad, 0xf3, 0xec, 0xf6, 0xff, 0x37, 0xa0, 0xf4, + 0x0e, 0xf0, 0x3c, 0xf9, 0x79, 0x0d, 0xb5, 0x1f, 0xf9, 0x47, 0xa2, 0xef, + 0xbe, 0xe8, 0x7c, 0xd5, 0x22, 0xc6, 0x7f, 0x1c, 0xbe, 0x6a, 0xef, 0x0d, + 0xc9, 0x3a, 0xfc, 0x96, 0x39, 0xea, 0xa4, 0x64, 0x31, 0x3f, 0xab, 0xe6, + 0x27, 0x26, 0xb6, 0xe6, 0xa7, 0x26, 0xbe, 0xaa, 0x6a, 0x52, 0xf3, 0x5f, + 0xe3, 0xf3, 0x0d, 0x65, 0xdf, 0x96, 0x87, 0xe1, 0x9d, 0x4a, 0x80, 0xb7, + 0xc2, 0x3e, 0x76, 0x36, 0x1c, 0xdb, 0x9d, 0xc0, 0x33, 0xe6, 0x8b, 0xb6, + 0x34, 0x14, 0x7e, 0x0f, 0xa5, 0xcd, 0x17, 0x73, 0xaa, 0x5e, 0x33, 0x9c, + 0xbc, 0x1b, 0xd4, 0xdf, 0xa8, 0xa1, 0x86, 0x06, 0xd5, 0xf9, 0x9b, 0xbe, + 0x36, 0x8c, 0x3c, 0xd6, 0x5e, 0x63, 0xb3, 0xae, 0xd6, 0xfd, 0xba, 0xda, + 0x90, 0xbb, 0xf7, 0xb7, 0x63, 0x73, 0x99, 0xf8, 0x5b, 0x0a, 0x9b, 0xef, + 0x42, 0x6d, 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7e, + 0x01, 0xeb, 0x19, 0xe6, 0x46, 0xd6, 0x37, 0x31, 0x7c, 0xf8, 0xbe, 0x41, + 0x80, 0xd1, 0x3b, 0xfc, 0xf8, 0xce, 0xba, 0x28, 0xc0, 0x2a, 0x77, 0x75, + 0x7b, 0xb5, 0xd1, 0x2e, 0xcd, 0xab, 0x3f, 0x13, 0xfe, 0x9c, 0xf0, 0x26, + 0x16, 0x0e, 0x6f, 0x62, 0xe1, 0x6d, 0xe7, 0x30, 0xa2, 0xde, 0x6d, 0x50, + 0xe7, 0x39, 0x3c, 0xdf, 0x11, 0x4d, 0x4f, 0xf3, 0x8c, 0x07, 0x38, 0xc7, + 0xe2, 0x99, 0x0f, 0x7d, 0xe9, 0x41, 0x2d, 0x5b, 0x37, 0x10, 0xef, 0x99, + 0x7f, 0x90, 0x6b, 0xcb, 0xc1, 0xd9, 0x62, 0xa0, 0x27, 0xca, 0x8e, 0x63, + 0x7f, 0xaa, 0xa1, 0xe6, 0x4d, 0x45, 0xac, 0x43, 0xa0, 0x65, 0x0a, 0xff, + 0x03, 0x99, 0xde, 0xa3, 0x72, 0x5f, 0x27, 0x6c, 0xf6, 0x78, 0x85, 0xd8, + 0xf5, 0x71, 0x69, 0xf8, 0xf8, 0x75, 0x65, 0xc9, 0xc3, 0xae, 0xe1, 0xed, + 0xd8, 0x35, 0xb5, 0x21, 0x1e, 0x8d, 0x07, 0x76, 0xa4, 0xd1, 0x70, 0x5e, + 0x19, 0x22, 0x66, 0x25, 0x9d, 0xcc, 0x3d, 0xd3, 0x88, 0x81, 0xcc, 0x39, + 0xcc, 0x37, 0xc4, 0xa5, 0xd7, 0xa2, 0x4f, 0x8d, 0x1d, 0xed, 0xb0, 0xa2, + 0xf8, 0xcc, 0x83, 0x8e, 0x19, 0x3c, 0x93, 0x96, 0x85, 0xd3, 0x5f, 0xd1, + 0x9c, 0xfa, 0x3c, 0xe8, 0x99, 0x42, 0xae, 0xa3, 0x2d, 0x15, 0x0c, 0xcf, + 0x8e, 0xd6, 0x11, 0xf7, 0x5d, 0xc6, 0x02, 0xd4, 0xae, 0xa8, 0x47, 0xca, + 0x8c, 0xbd, 0x3c, 0xeb, 0x0a, 0x62, 0x2e, 0xfb, 0x26, 0xa8, 0x59, 0x59, + 0xbb, 0x2e, 0x72, 0xdf, 0xed, 0xba, 0xa8, 0xb9, 0xc4, 0x5d, 0x86, 0xb3, + 0xbe, 0x46, 0xdc, 0xf8, 0x51, 0x31, 0xa4, 0xe1, 0xbc, 0x3c, 0x44, 0x1c, + 0x79, 0x3d, 0xf8, 0xd1, 0x84, 0x34, 0xcd, 0x17, 0xd6, 0xf5, 0x76, 0xfc, + 0xe8, 0x61, 0xc7, 0xcc, 0xda, 0x41, 0xac, 0xc9, 0xda, 0x8c, 0x38, 0xd1, + 0x44, 0x98, 0x1b, 0xc4, 0xb3, 0x83, 0xe0, 0xc7, 0xc3, 0x8a, 0x59, 0x60, + 0xc5, 0xbf, 0x03, 0xac, 0x58, 0x92, 0xf7, 0xa2, 0xc4, 0x8a, 0xb6, 0x8f, + 0x15, 0x1d, 0xd8, 0x71, 0x7e, 0x9b, 0x1d, 0x6b, 0xaa, 0x07, 0xc5, 0x7b, + 0x79, 0x60, 0xbd, 0xec, 0xa2, 0x79, 0x1d, 0xf8, 0x50, 0x93, 0x98, 0x3a, + 0xaf, 0x0f, 0xb7, 0xad, 0x19, 0xe0, 0xc0, 0x7d, 0x0a, 0xdf, 0xdd, 0x57, + 0xd9, 0x85, 0xda, 0x44, 0xe1, 0x3d, 0xff, 0x9c, 0x2f, 0x7c, 0xd5, 0xd9, + 0x67, 0xb8, 0xed, 0xec, 0x73, 0x0b, 0x17, 0xe2, 0x39, 0xbf, 0xc7, 0x17, + 0x81, 0xde, 0xfe, 0x07, 0x69, 0x82, 0x5f, 0xd1, 0x07, 0x34, 0xcf, 0x4f, + 0xb6, 0xe1, 0xc3, 0xff, 0x7a, 0x15, 0x3e, 0x44, 0xce, 0x5a, 0x89, 0x49, + 0x06, 0xd8, 0xd0, 0x5e, 0xe3, 0x5a, 0xf4, 0xe5, 0x51, 0xe9, 0x00, 0x7f, + 0x9d, 0x8b, 0x7d, 0xc0, 0x44, 0xdd, 0x12, 0x05, 0x36, 0x8a, 0x28, 0x6c, + 0x34, 0x44, 0x0c, 0x33, 0x7c, 0x18, 0x98, 0xa6, 0xb1, 0x89, 0x8f, 0xcc, + 0xd4, 0x0f, 0xa0, 0x97, 0x87, 0x95, 0xad, 0x8c, 0xcb, 0x53, 0x88, 0x9d, + 0x1d, 0x6b, 0xc0, 0x75, 0x2b, 0x1e, 0x6e, 0x8a, 0x5c, 0x85, 0x9b, 0x8e, + 0xec, 0x88, 0x9b, 0x54, 0xbf, 0x7e, 0x9c, 0x32, 0x79, 0xdd, 0xf5, 0xfa, + 0xf5, 0x97, 0x5c, 0xaf, 0x5f, 0xff, 0xba, 0xdb, 0xde, 0xaf, 0xbf, 0x49, + 0x8a, 0x86, 0x69, 0x5f, 0x94, 0xab, 0xfa, 0xf5, 0x33, 0xec, 0x7f, 0x57, + 0xbb, 0xbc, 0xbe, 0x7c, 0xb7, 0xdf, 0xaf, 0x37, 0xa5, 0xb8, 0x6d, 0xdc, + 0x90, 0xb7, 0xad, 0xa0, 0x5f, 0xff, 0x2f, 0x30, 0xd6, 0x83, 0x3d, 0xb6, + 0xf7, 0xea, 0x2f, 0xb9, 0xec, 0xd5, 0xc7, 0x38, 0xcf, 0xef, 0xd5, 0x73, + 0x1e, 0x6a, 0x78, 0x97, 0x7d, 0xfa, 0x9b, 0x21, 0x8b, 0x7e, 0xc8, 0xa1, + 0x4f, 0x3a, 0x9e, 0x8b, 0x73, 0x8e, 0xea, 0xcf, 0x5f, 0x74, 0x63, 0x78, + 0xce, 0xeb, 0xa3, 0x1f, 0x86, 0x5d, 0x1d, 0xd9, 0xec, 0xcf, 0x7b, 0x7b, + 0xbc, 0xe1, 0x6e, 0x5f, 0x7f, 0xfb, 0x3a, 0x03, 0xfe, 0x3a, 0x31, 0xac, + 0x13, 0xbf, 0x6a, 0x9d, 0xad, 0x7e, 0xfc, 0x1b, 0xae, 0xd7, 0x8b, 0x77, + 0x4e, 0x8b, 0xdd, 0x81, 0x98, 0xfc, 0xe2, 0xd0, 0x8d, 0xfe, 0x1a, 0x9b, + 0xbd, 0x78, 0xc6, 0x0e, 0xe0, 0x75, 0xc6, 0x0f, 0x3e, 0xff, 0xff, 0xbe, + 0x17, 0xcf, 0x3e, 0xbc, 0x77, 0x9e, 0x42, 0xff, 0x04, 0x2e, 0x7f, 0xd6, + 0xeb, 0xc1, 0x4f, 0x54, 0x82, 0xde, 0x3a, 0xeb, 0xc6, 0xe0, 0xbd, 0x8c, + 0xc1, 0xc4, 0x71, 0xa1, 0xad, 0x90, 0x3e, 0xae, 0xdb, 0x23, 0x73, 0x0a, + 0x17, 0xc1, 0xa6, 0x92, 0xd7, 0xc6, 0xc6, 0xb5, 0xc5, 0x00, 0x1b, 0xc7, + 0x14, 0x36, 0xae, 0xad, 0x05, 0xd8, 0x38, 0x73, 0x0d, 0x6c, 0xfc, 0xdf, + 0xba, 0xbc, 0xf8, 0x1f, 0x95, 0x82, 0xc2, 0xc6, 0xd7, 0x7a, 0xc7, 0x86, + 0xf7, 0xba, 0x89, 0x03, 0xc4, 0x3b, 0x17, 0xef, 0xbb, 0x86, 0xaf, 0x05, + 0x78, 0x99, 0xb9, 0xbe, 0x5f, 0x66, 0x9e, 0xdb, 0xc2, 0xcb, 0x1e, 0x26, + 0x36, 0x13, 0x47, 0x55, 0x2e, 0x04, 0x3e, 0x68, 0xb2, 0xef, 0x7d, 0x48, + 0xd9, 0x6e, 0xa9, 0x32, 0xab, 0x70, 0x59, 0x1e, 0xb5, 0x6d, 0x51, 0xe1, + 0x60, 0x62, 0xe0, 0x2e, 0x91, 0xbe, 0x20, 0x17, 0x05, 0x18, 0x33, 0xec, + 0xc7, 0x67, 0x9e, 0x29, 0xbc, 0x1d, 0xca, 0x10, 0x03, 0xbb, 0x41, 0x8d, + 0x40, 0x39, 0x0f, 0x23, 0x76, 0x19, 0xbe, 0xac, 0x3c, 0x9f, 0xdd, 0xb7, + 0xff, 0x87, 0xef, 0xdb, 0x06, 0xe3, 0x5a, 0x80, 0x11, 0x51, 0x03, 0x55, + 0xc6, 0xd5, 0xbb, 0x0e, 0x1e, 0x46, 0xf4, 0xf0, 0x61, 0xd6, 0x9d, 0x01, + 0x4e, 0x9e, 0x95, 0x09, 0xe0, 0xf3, 0xf5, 0xdf, 0x65, 0xef, 0x29, 0xc0, + 0x44, 0x36, 0xfe, 0xb7, 0xf7, 0xa2, 0x78, 0xdd, 0xa1, 0xce, 0xfe, 0xce, + 0x0f, 0x45, 0xdb, 0xc6, 0xff, 0x3e, 0xe2, 0x37, 0xea, 0xa1, 0x0a, 0x73, + 0x1d, 0xb1, 0xd0, 0x6f, 0x40, 0x07, 0x63, 0xd7, 0xc0, 0x42, 0x57, 0xe7, + 0x26, 0xe6, 0xcb, 0xad, 0xbc, 0xe4, 0x6c, 0xe6, 0x25, 0xee, 0xf1, 0xeb, + 0x72, 0x27, 0xc7, 0x6c, 0x23, 0x62, 0x4d, 0xe1, 0x33, 0x8f, 0x7c, 0xbd, + 0x3d, 0x37, 0xcd, 0x5d, 0x47, 0x6e, 0x9a, 0x50, 0xb9, 0x89, 0xf4, 0xa2, + 0x9e, 0x83, 0x4c, 0xbe, 0x0b, 0x59, 0x7e, 0x07, 0xb4, 0xff, 0x11, 0xf8, + 0xf9, 0x43, 0x60, 0xac, 0x6f, 0x03, 0x63, 0x7d, 0xab, 0xd2, 0xfe, 0x0e, + 0xc3, 0xb8, 0xb0, 0x0e, 0xf4, 0xea, 0x66, 0x0f, 0xc3, 0x1f, 0x86, 0x57, + 0x35, 0xca, 0x86, 0x33, 0x57, 0x1e, 0x31, 0xe6, 0xbd, 0xf3, 0xd2, 0x44, + 0x4e, 0xd2, 0x88, 0x11, 0xcc, 0x15, 0xea, 0x3a, 0xce, 0x7e, 0x25, 0xb1, + 0x42, 0x5d, 0xd5, 0x93, 0x43, 0x52, 0x6d, 0x78, 0xf8, 0x6a, 0xe1, 0x8c, + 0xb7, 0xc6, 0x9c, 0x8f, 0xaf, 0xf2, 0x3e, 0xbe, 0xca, 0x35, 0x36, 0x12, + 0xac, 0xcf, 0x17, 0x52, 0xdb, 0x31, 0xd5, 0x61, 0x1f, 0x53, 0xcd, 0xff, + 0x15, 0x31, 0x15, 0xf7, 0xca, 0xe3, 0x99, 0xc9, 0xa5, 0x84, 0x1c, 0x80, + 0x7c, 0x27, 0xca, 0xd4, 0x93, 0x69, 0xc3, 0x6e, 0x3e, 0x44, 0x57, 0x8e, + 0xd2, 0x4b, 0x28, 0xe9, 0xe9, 0x69, 0x12, 0x7a, 0x9a, 0xf8, 0xb5, 0xf5, + 0x8d, 0x1a, 0x33, 0xde, 0x1c, 0x8b, 0xe2, 0xf3, 0x7f, 0xaa, 0x23, 0xd2, + 0x4f, 0x3d, 0x5d, 0x8d, 0xb9, 0xae, 0x07, 0x7b, 0x6d, 0xc7, 0x5d, 0xb6, + 0xc2, 0x5d, 0x1d, 0xfe, 0x9c, 0x99, 0x89, 0x49, 0xe8, 0xf0, 0xdf, 0x63, + 0xce, 0x9f, 0xc0, 0xb7, 0x7e, 0x88, 0x78, 0xfd, 0xef, 0xa0, 0x8b, 0x7f, + 0x8b, 0xda, 0xe0, 0x55, 0xe4, 0x9f, 0x1f, 0x60, 0x6c, 0x0b, 0xc7, 0xa8, + 0x33, 0xfa, 0xd1, 0x8c, 0x95, 0x98, 0x28, 0xba, 0x89, 0x09, 0x0f, 0x7f, + 0xfc, 0xea, 0x6f, 0x66, 0xac, 0x29, 0xbe, 0xc3, 0x00, 0xf9, 0xfe, 0xf9, + 0xdd, 0x73, 0x0a, 0x7b, 0x04, 0x98, 0x23, 0x67, 0x73, 0xff, 0x92, 0x9b, + 0x9a, 0xa8, 0xe1, 0xe3, 0x61, 0x9b, 0xef, 0xd9, 0x1e, 0xb6, 0x59, 0xfa, + 0xeb, 0xd4, 0xbb, 0x87, 0x6b, 0x1e, 0x4e, 0xd3, 0xaf, 0xeb, 0xc0, 0x1c, + 0x35, 0xf8, 0x64, 0xa1, 0x69, 0xab, 0xcf, 0xf1, 0x8a, 0x6d, 0x46, 0x20, + 0x1f, 0xf6, 0x58, 0x4f, 0xd1, 0x0b, 0x5d, 0xd3, 0x28, 0x13, 0x81, 0xba, + 0x66, 0xfc, 0x9f, 0xf9, 0xd7, 0x4f, 0xfb, 0xd7, 0x4f, 0xf9, 0xd7, 0x27, + 0x91, 0x77, 0x9f, 0x54, 0xb9, 0x93, 0xe3, 0x1c, 0x83, 0x72, 0x5d, 0xac, + 0x85, 0xf5, 0xce, 0x8e, 0xfe, 0xb4, 0x55, 0x8d, 0x79, 0xfe, 0x5c, 0x68, + 0x3a, 0xf8, 0xfc, 0x63, 0x7c, 0x0e, 0xe2, 0x33, 0x8d, 0xcf, 0x63, 0xf8, + 0x6c, 0xca, 0x54, 0xcb, 0x56, 0xa8, 0xa3, 0x61, 0xc9, 0x62, 0xbc, 0x88, + 0x3a, 0x34, 0x93, 0x7a, 0x44, 0x8a, 0xf5, 0x92, 0x94, 0x96, 0x34, 0xe9, + 0xb6, 0xd2, 0x52, 0xaa, 0x1f, 0x93, 0xe3, 0x4b, 0xde, 0xb9, 0x61, 0x57, + 0xda, 0xc6, 0xdc, 0x96, 0x3c, 0x9c, 0x7a, 0x5c, 0xf4, 0x3b, 0x8f, 0x61, + 0x9e, 0xe8, 0xc5, 0xd1, 0xdb, 0xd4, 0xf9, 0x58, 0x3d, 0xe5, 0xc9, 0xf8, + 0x80, 0x65, 0x9b, 0xc8, 0x5b, 0xc3, 0x4f, 0x62, 0xed, 0x8c, 0x7a, 0x3f, + 0x30, 0x2d, 0x27, 0x4e, 0x6f, 0xec, 0xf5, 0x62, 0xa9, 0x69, 0xbc, 0x81, + 0x4d, 0xeb, 0xe0, 0xc3, 0x46, 0xec, 0x9b, 0x82, 0x9d, 0x1f, 0x71, 0xc3, + 0xda, 0x04, 0x62, 0xe0, 0x84, 0xab, 0x6a, 0x3d, 0xc4, 0x2a, 0xc3, 0x49, + 0x9e, 0x8a, 0xe1, 0x9a, 0xef, 0xd0, 0x20, 0x0f, 0x2a, 0x5b, 0xd9, 0x00, + 0x8e, 0xd1, 0x54, 0xbf, 0xaf, 0xb4, 0x79, 0x0e, 0xa4, 0xfa, 0xff, 0x4e, + 0x32, 0xa9, 0x4b, 0x7e, 0x8c, 0x38, 0xd6, 0x56, 0xb9, 0xa8, 0x51, 0xb6, + 0x3f, 0xc1, 0xda, 0xf0, 0x75, 0x61, 0x5e, 0xbb, 0x07, 0xf3, 0x06, 0x10, + 0x7f, 0x71, 0xaf, 0x09, 0x5e, 0x4e, 0x93, 0x57, 0x3e, 0x83, 0xda, 0xb6, + 0xfa, 0x49, 0xbd, 0xb8, 0xe4, 0xd7, 0x44, 0xaa, 0x76, 0x48, 0x48, 0x7d, + 0xf3, 0xcc, 0xc9, 0xeb, 0x93, 0xd4, 0xdd, 0x00, 0x3b, 0xf4, 0x60, 0x0e, + 0xeb, 0x08, 0xc8, 0xc8, 0x3b, 0x27, 0x53, 0x67, 0x64, 0x45, 0xf7, 0x93, + 0x7a, 0x69, 0x29, 0x83, 0x71, 0xf6, 0xa4, 0xf1, 0xbd, 0xaa, 0x2b, 0xec, + 0x7f, 0x31, 0x74, 0x58, 0x1a, 0xd5, 0x16, 0xe8, 0x45, 0x8e, 0xdd, 0x7b, + 0x58, 0x6a, 0xd5, 0x79, 0x79, 0xa1, 0xba, 0xb1, 0x0b, 0xd8, 0x09, 0x32, + 0x25, 0xfd, 0x3d, 0x3e, 0xfd, 0x54, 0x41, 0x30, 0x0e, 0x79, 0x9e, 0x2e, + 0xc4, 0xbd, 0xba, 0x96, 0xb8, 0xed, 0x24, 0xdf, 0x1b, 0x8c, 0xf3, 0x3d, + 0xbe, 0x23, 0xcb, 0xb4, 0xc9, 0x8b, 0xf7, 0x2e, 0x58, 0x9f, 0x92, 0x0b, + 0xa9, 0x3d, 0xb2, 0x91, 0x52, 0xf5, 0x2f, 0xf1, 0x01, 0x7c, 0xdb, 0x34, + 0xd6, 0xe5, 0x6e, 0x39, 0x01, 0x3f, 0xbd, 0x90, 0xca, 0xa9, 0xf3, 0x9b, + 0xe3, 0x4d, 0x62, 0xfb, 0x79, 0xd6, 0x54, 0xb2, 0xae, 0x7a, 0x60, 0xad, + 0xd6, 0x64, 0x8a, 0xb1, 0xa7, 0x43, 0x36, 0x14, 0xd6, 0xf2, 0x7a, 0xe3, + 0x1b, 0xb3, 0x9e, 0x6f, 0x84, 0x94, 0xbd, 0xff, 0x1b, 0xd0, 0x71, 0x0c, + 0x36, 0x1b, 0x51, 0x73, 0x42, 0xe9, 0x4e, 0x7f, 0x8e, 0xc2, 0x66, 0x6d, + 0x73, 0xc6, 0xc7, 0x33, 0x96, 0xf1, 0xa9, 0x8c, 0x35, 0x36, 0xe1, 0xf5, + 0x53, 0x4c, 0xc3, 0xd6, 0x2e, 0xb6, 0x82, 0xf7, 0x4d, 0xa6, 0xe0, 0x4f, + 0x2f, 0x6d, 0x62, 0x63, 0x18, 0xe7, 0xf3, 0x0b, 0xd0, 0x6b, 0x58, 0x3a, + 0x4e, 0xb5, 0xee, 0x99, 0x4b, 0x8d, 0x24, 0x8e, 0x08, 0xdf, 0x30, 0x62, + 0xfd, 0x6c, 0x82, 0xda, 0x05, 0xe4, 0xc3, 0x2b, 0xc4, 0x08, 0xc3, 0xe7, + 0xe5, 0xca, 0x3d, 0x99, 0xd4, 0x7e, 0xad, 0x36, 0x8b, 0xea, 0xe4, 0xf9, + 0x29, 0xe6, 0xd3, 0xa3, 0xec, 0x7d, 0x86, 0x4e, 0xbd, 0xad, 0x39, 0x65, + 0xf5, 0x8e, 0x39, 0xf4, 0xd2, 0xd2, 0xe6, 0x21, 0x37, 0x3c, 0x3f, 0xc3, + 0x04, 0xa8, 0x5b, 0x83, 0x09, 0x47, 0x72, 0xec, 0x71, 0x49, 0x7e, 0x59, + 0xf6, 0x65, 0x10, 0x47, 0xed, 0x99, 0x0e, 0x99, 0x6f, 0x18, 0xce, 0xe0, + 0xe2, 0x51, 0xac, 0x31, 0x87, 0xb5, 0xa6, 0x51, 0x83, 0xcc, 0x22, 0x27, + 0x53, 0xae, 0x8c, 0xd5, 0x0f, 0x43, 0x46, 0x37, 0xf1, 0xcc, 0x78, 0x3c, + 0x27, 0xe6, 0x4c, 0x41, 0xad, 0xfb, 0x9e, 0x96, 0x1f, 0xfd, 0x18, 0x72, + 0x5a, 0x58, 0x0e, 0x24, 0x45, 0x9f, 0x4e, 0x86, 0xdf, 0x9f, 0xb3, 0x38, + 0x16, 0xe5, 0x98, 0x8e, 0xb1, 0xf0, 0xe7, 0x92, 0x51, 0x3d, 0x93, 0x34, + 0xc7, 0xd9, 0xef, 0x0d, 0x59, 0x73, 0x12, 0x7a, 0xbe, 0xb7, 0x47, 0xba, + 0xa7, 0xa5, 0x77, 0xd5, 0x1c, 0x7f, 0x1d, 0xb4, 0x84, 0x55, 0x6c, 0x9f, + 0x13, 0xdd, 0x1f, 0xef, 0xd9, 0x1c, 0x0f, 0xfb, 0xe3, 0xd3, 0xd2, 0xbd, + 0x3a, 0x62, 0xbc, 0x29, 0x87, 0xb1, 0x66, 0x48, 0x2e, 0xa1, 0xa6, 0xb1, + 0x86, 0xe6, 0xe0, 0x73, 0x0f, 0x91, 0x96, 0x83, 0xc0, 0x14, 0xf0, 0x09, + 0xd4, 0xd9, 0xd6, 0x27, 0xe5, 0x4b, 0x46, 0x97, 0xe4, 0x55, 0x4d, 0x1b, + 0xf6, 0x7a, 0xa5, 0xb0, 0xf3, 0x5b, 0x87, 0xa6, 0x77, 0x7b, 0xfd, 0x00, + 0x9e, 0x67, 0x8c, 0x62, 0xec, 0x4a, 0x6b, 0xc5, 0xe2, 0x18, 0xef, 0x5d, + 0x69, 0xd5, 0xad, 0x11, 0x23, 0xab, 0x45, 0xfd, 0x73, 0xed, 0x79, 0xc5, + 0x7b, 0xa1, 0x3a, 0x68, 0xd4, 0xe4, 0x16, 0x2d, 0x7b, 0x03, 0xf2, 0x83, + 0xfb, 0x19, 0xcc, 0xbd, 0xd2, 0xca, 0x58, 0xf3, 0xaa, 0x7f, 0x5f, 0x93, + 0xe0, 0x9a, 0xeb, 0x8c, 0x18, 0x93, 0xea, 0xd9, 0x11, 0xe3, 0x84, 0xd6, + 0xfe, 0xac, 0xa1, 0x4d, 0x6e, 0x7b, 0xb6, 0x5b, 0xc9, 0x28, 0x64, 0x79, + 0x73, 0x4a, 0xd5, 0x69, 0x79, 0xda, 0xe5, 0xbc, 0x2b, 0xad, 0xac, 0x15, + 0xd1, 0x4e, 0xdc, 0xc0, 0x18, 0xc8, 0xb9, 0x97, 0xaf, 0xda, 0x87, 0xd7, + 0xd7, 0xda, 0xe3, 0x5d, 0xd9, 0xbe, 0xc7, 0x2e, 0x35, 0xe7, 0x82, 0x9a, + 0x13, 0x56, 0xb2, 0xde, 0xbe, 0xcf, 0xcf, 0x64, 0xfb, 0x3e, 0xdd, 0x9b, + 0x3c, 0x97, 0xb0, 0xe6, 0x93, 0x98, 0x5b, 0x76, 0x07, 0xe3, 0x75, 0xb9, + 0xdc, 0xca, 0x5b, 0x17, 0xe5, 0xc2, 0xe6, 0xda, 0xbf, 0xc2, 0x75, 0x3b, + 0x4d, 0xbf, 0xf2, 0x69, 0xe4, 0x77, 0x8e, 0x3d, 0xaa, 0xe4, 0xbd, 0xdb, + 0x1a, 0x3c, 0x58, 0xd3, 0xcc, 0xf1, 0x9f, 0x09, 0x75, 0x75, 0x44, 0xc5, + 0x98, 0xdb, 0xa0, 0xa7, 0x7d, 0xcf, 0xc0, 0x67, 0x47, 0x6d, 0x35, 0xe7, + 0x92, 0x35, 0x2d, 0xfb, 0x4e, 0x0d, 0x1a, 0x97, 0x10, 0xdb, 0x9c, 0x18, + 0xaf, 0x51, 0x2b, 0x59, 0x7c, 0x27, 0xfe, 0x4e, 0xd6, 0x01, 0xd0, 0xe5, + 0xe0, 0xf0, 0xcf, 0xe4, 0xa8, 0x9c, 0xa8, 0x1c, 0x43, 0x2e, 0x9c, 0x93, + 0xe1, 0x67, 0x90, 0x37, 0x2a, 0x05, 0x3c, 0x49, 0x9f, 0xf5, 0x72, 0xe0, + 0x9c, 0x7a, 0xcf, 0xfc, 0x24, 0xea, 0x64, 0xd8, 0x6e, 0x79, 0x70, 0x78, + 0x05, 0xcf, 0xbc, 0xa0, 0x70, 0xa8, 0x2b, 0x0d, 0xf8, 0x40, 0xe2, 0xf9, + 0x3d, 0xb2, 0xfb, 0x01, 0xda, 0x22, 0x32, 0xfd, 0x6d, 0x11, 0xf5, 0xee, + 0xbd, 0x6e, 0x75, 0x8a, 0xec, 0xa5, 0xdd, 0x34, 0x61, 0x63, 0x73, 0xde, + 0x99, 0xd6, 0xb6, 0x6b, 0x73, 0xe6, 0xa2, 0xac, 0x2a, 0xfb, 0xbb, 0x7d, + 0xd5, 0xfb, 0x3f, 0xba, 0x8a, 0x72, 0x38, 0x39, 0x2d, 0x77, 0xac, 0x7a, + 0xf6, 0x56, 0x5a, 0x3a, 0xaa, 0xe4, 0x3a, 0xa7, 0xe4, 0xda, 0x92, 0xc3, + 0x29, 0xca, 0x9c, 0xbc, 0xf0, 0xbd, 0x40, 0x4f, 0x16, 0xf7, 0xfb, 0xf6, + 0x33, 0xf8, 0x0c, 0x7f, 0x57, 0x42, 0xd9, 0xb0, 0xee, 0xbe, 0x7f, 0x37, + 0xcf, 0x59, 0xf7, 0xad, 0x92, 0xcf, 0x1b, 0xb7, 0xf1, 0xf9, 0x14, 0x62, + 0xea, 0xd0, 0x90, 0xc7, 0xeb, 0xab, 0x4b, 0x1f, 0xce, 0xeb, 0x37, 0x37, + 0x79, 0x0d, 0x49, 0x43, 0xd5, 0xaf, 0x5d, 0xbd, 0xd2, 0x8d, 0xa8, 0x07, + 0x7b, 0xf8, 0x09, 0xf6, 0x9a, 0x12, 0xd2, 0xe0, 0xed, 0xb7, 0xe1, 0x92, + 0x96, 0x80, 0x76, 0xd2, 0x73, 0x9f, 0xaf, 0x2f, 0xee, 0x7f, 0x74, 0xc7, + 0x7b, 0x97, 0xc4, 0x70, 0x86, 0x31, 0xa6, 0x2b, 0x9d, 0x65, 0x7d, 0xff, + 0x9a, 0x16, 0x5d, 0xe9, 0xcc, 0xde, 0xd4, 0xd9, 0xeb, 0xd0, 0x59, 0x5d, + 0x7e, 0x13, 0xbc, 0xc0, 0x9f, 0x9f, 0x19, 0x31, 0x0e, 0x13, 0x5b, 0x18, + 0x5c, 0x0f, 0x31, 0xd4, 0xd7, 0x5d, 0xc7, 0x47, 0xd0, 0xdd, 0x9b, 0xa2, + 0xf4, 0x07, 0x7e, 0x90, 0x7f, 0xd4, 0xf3, 0x8c, 0x61, 0xe4, 0xa9, 0x43, + 0xf9, 0x3e, 0x69, 0x53, 0x67, 0xfc, 0x33, 0x9e, 0x3e, 0x95, 0x6f, 0xfb, + 0xfa, 0xcc, 0xcd, 0x50, 0x67, 0xe6, 0x6e, 0x4f, 0x7f, 0x9d, 0x6a, 0xce, + 0x62, 0x32, 0xa1, 0xfc, 0xda, 0x1a, 0xba, 0x65, 0x37, 0x75, 0xf8, 0xb4, + 0xeb, 0xfd, 0x2f, 0xbb, 0xd3, 0xb2, 0xe8, 0x7e, 0x98, 0x1e, 0x3d, 0x1d, + 0x4e, 0x88, 0xe7, 0x3f, 0x57, 0xeb, 0x4f, 0x5f, 0x0d, 0x2b, 0x5b, 0x9d, + 0x80, 0xec, 0x4e, 0x56, 0x3e, 0xe6, 0xdb, 0xb7, 0xc7, 0xeb, 0xd0, 0x87, + 0xf0, 0x7a, 0xb8, 0x3c, 0x68, 0xbc, 0x8d, 0xb5, 0x26, 0x15, 0x86, 0x8b, + 0x88, 0xe3, 0xf3, 0x9a, 0xd8, 0xe4, 0x35, 0xa0, 0xcd, 0x9b, 0x97, 0x65, + 0x5d, 0xea, 0x32, 0x3e, 0x3d, 0xaa, 0xde, 0xbf, 0x7f, 0xa3, 0xcc, 0xb8, + 0x0c, 0xcc, 0x13, 0xeb, 0x93, 0x4b, 0x8d, 0x84, 0x5c, 0x22, 0x96, 0x18, + 0xc3, 0x7f, 0xf7, 0x98, 0x9f, 0x9b, 0xa3, 0xf2, 0x66, 0xb9, 0xbd, 0x56, + 0x1c, 0x95, 0xd7, 0xcb, 0x41, 0xbd, 0x48, 0x2c, 0xcb, 0xfc, 0x3f, 0x27, + 0x6f, 0x2d, 0x0d, 0xca, 0xfa, 0x0c, 0xf2, 0xf8, 0x10, 0x65, 0x30, 0x62, + 0x7c, 0x46, 0xfd, 0xbe, 0xe2, 0x4a, 0xeb, 0xbc, 0x85, 0x75, 0x97, 0x5b, + 0x72, 0x84, 0xe7, 0xd0, 0xfc, 0xde, 0xf8, 0x04, 0x56, 0xe1, 0xbc, 0x3e, + 0xa9, 0x2d, 0xa3, 0x2e, 0x2f, 0x73, 0x5d, 0xca, 0x69, 0x5a, 0x7d, 0x9f, + 0xc4, 0x3e, 0xf7, 0xf3, 0xbd, 0xf4, 0x18, 0x75, 0x71, 0xa5, 0xb5, 0x61, + 0xf1, 0x1c, 0x72, 0x4e, 0x1a, 0xd0, 0xd7, 0x97, 0x93, 0x3c, 0x27, 0xcf, + 0x0b, 0x7f, 0x9f, 0x52, 0x6b, 0xcc, 0xa0, 0x16, 0xb8, 0xd2, 0x5a, 0xb0, + 0x9e, 0x52, 0x7a, 0x6a, 0x54, 0x1f, 0xf0, 0xc7, 0x79, 0xcd, 0x7b, 0x86, + 0xb3, 0x6f, 0x88, 0xf5, 0xe7, 0x03, 0xc8, 0xff, 0xac, 0x3d, 0x89, 0xb7, + 0x28, 0x8b, 0x04, 0x6a, 0x5c, 0xae, 0xc5, 0xdf, 0x04, 0x25, 0x87, 0xf3, + 0x32, 0x09, 0x7a, 0x80, 0xcb, 0x5c, 0xc6, 0xfd, 0x5b, 0x65, 0x23, 0xe6, + 0xc5, 0x77, 0xbe, 0xaf, 0xb5, 0x81, 0x98, 0xbf, 0xb1, 0x19, 0xf3, 0xfb, + 0x71, 0x6d, 0x38, 0xa9, 0xa1, 0xff, 0x84, 0xf5, 0xd9, 0x77, 0x61, 0xcc, + 0x1f, 0xc7, 0x7c, 0x8e, 0xf5, 0x49, 0x69, 0x59, 0x6c, 0xf6, 0x99, 0x6a, + 0xc2, 0x77, 0x31, 0x72, 0xb2, 0xd8, 0x18, 0x8c, 0x9f, 0xd7, 0x1c, 0xf5, + 0xce, 0x46, 0x72, 0x88, 0x7d, 0xb7, 0x3e, 0x69, 0x2c, 0x4b, 0x22, 0x94, + 0x7e, 0x48, 0xdc, 0x86, 0x87, 0xb9, 0x17, 0x34, 0xf6, 0xdf, 0x6c, 0x69, + 0x6c, 0x9f, 0x63, 0x84, 0xd2, 0x87, 0xe4, 0x0f, 0xfc, 0x39, 0x8e, 0x9a, + 0xf3, 0x1f, 0x76, 0xf3, 0xec, 0xab, 0xe1, 0xf6, 0x82, 0x06, 0xd2, 0x76, + 0x63, 0xfb, 0xbe, 0x89, 0xad, 0x7d, 0xb9, 0x27, 0x6a, 0x98, 0xbd, 0x36, + 0xf6, 0x7d, 0x15, 0xcf, 0x3c, 0x04, 0x3a, 0xae, 0x84, 0x74, 0xeb, 0x21, + 0x29, 0x36, 0xae, 0xde, 0xa3, 0x9d, 0x06, 0x3e, 0xc3, 0xf5, 0xb9, 0xcf, + 0x21, 0xd0, 0x77, 0x45, 0xd3, 0xad, 0x43, 0x90, 0xa5, 0xb7, 0x47, 0xe8, + 0x39, 0xd3, 0xf8, 0xa1, 0x0c, 0x89, 0xbe, 0xa2, 0x29, 0xf9, 0xeb, 0xb5, + 0x51, 0x38, 0xc4, 0x94, 0x74, 0xaf, 0xcd, 0x4a, 0x68, 0x8d, 0x3d, 0x00, + 0xda, 0x22, 0xf5, 0xb8, 0x0b, 0x7e, 0x2c, 0x76, 0xd8, 0x22, 0xde, 0x67, + 0x1f, 0x77, 0xb5, 0x57, 0x7a, 0x89, 0xf7, 0x59, 0x0f, 0x1c, 0xc4, 0x7f, + 0xd6, 0x04, 0x2f, 0xb5, 0x32, 0xa9, 0x77, 0x54, 0xde, 0xcc, 0x37, 0x78, + 0xdf, 0x4c, 0x88, 0xf0, 0x1e, 0xe3, 0x43, 0x9f, 0x44, 0xbe, 0x3e, 0x8c, + 0x98, 0x90, 0x03, 0x76, 0xc6, 0xba, 0xa7, 0x86, 0x24, 0xec, 0xbd, 0xeb, + 0xa0, 0xfa, 0x25, 0x6f, 0x2d, 0x9b, 0xfe, 0xef, 0x53, 0x64, 0xdf, 0xf9, + 0x14, 0x7b, 0x9a, 0x03, 0xb0, 0x53, 0xd6, 0x23, 0xa2, 0x6f, 0xa0, 0xde, + 0xbc, 0xd4, 0x88, 0xf6, 0xf2, 0x7d, 0xcb, 0xd7, 0x5d, 0x5c, 0x13, 0xbb, + 0xc7, 0x14, 0x56, 0xf4, 0xef, 0xf1, 0x3b, 0xea, 0xa0, 0x6d, 0x98, 0x32, + 0x01, 0x4c, 0xc9, 0x3a, 0x69, 0xca, 0x7f, 0xe7, 0xcd, 0x70, 0x4e, 0x6c, + 0xab, 0x95, 0x86, 0x65, 0x03, 0x38, 0x6b, 0xdd, 0xb5, 0x10, 0x07, 0xdf, + 0xd6, 0xea, 0x65, 0xf5, 0xbb, 0x34, 0xed, 0x01, 0x60, 0xac, 0x44, 0x9f, + 0xaa, 0x75, 0x4e, 0x3e, 0x20, 0x9e, 0xbd, 0xc3, 0xca, 0x54, 0xcc, 0x5a, + 0xaf, 0x7a, 0xb5, 0xc5, 0x46, 0x75, 0x4a, 0xfe, 0xd4, 0x5d, 0x50, 0xbd, + 0xd2, 0x25, 0xd4, 0x1b, 0xe1, 0x45, 0x55, 0x6b, 0xb5, 0xe1, 0x54, 0xc4, + 0xb7, 0x67, 0x8f, 0xc0, 0x07, 0x4d, 0xf5, 0x6e, 0x81, 0xbe, 0xd2, 0x6a, + 0x65, 0x11, 0x2f, 0x74, 0xcb, 0x32, 0x8a, 0xc8, 0x73, 0x59, 0xf5, 0x7e, + 0x0a, 0xfd, 0xf7, 0xf7, 0x54, 0x1c, 0x96, 0x1a, 0x64, 0xf3, 0x5c, 0x02, + 0xeb, 0x68, 0xca, 0x3e, 0x43, 0x4a, 0x0f, 0x0f, 0x28, 0xec, 0x1a, 0x5a, + 0x41, 0x80, 0x5a, 0x1b, 0x12, 0x59, 0x81, 0xbf, 0xc2, 0x77, 0xc3, 0x6b, + 0xd4, 0x01, 0x65, 0x3b, 0x2b, 0x11, 0xc8, 0x9e, 0x58, 0x22, 0xb4, 0x48, + 0x19, 0xc7, 0x61, 0x17, 0x5c, 0x07, 0x32, 0xe6, 0xbb, 0x2c, 0xcb, 0x1d, + 0xf2, 0x4c, 0xc3, 0xf4, 0xdf, 0x3d, 0x7f, 0x89, 0xef, 0xa3, 0xeb, 0x73, + 0x63, 0x03, 0xc4, 0x4f, 0x52, 0x6a, 0x00, 0x63, 0x9c, 0x66, 0x0d, 0xce, + 0x18, 0x50, 0x88, 0x47, 0x94, 0xaf, 0xb3, 0x06, 0xf6, 0x7c, 0x9f, 0xf8, + 0x3a, 0x62, 0x11, 0xdb, 0x8e, 0x62, 0x8f, 0x9d, 0xe4, 0xea, 0xd5, 0x9e, + 0x93, 0xa0, 0xf3, 0xfc, 0x92, 0x39, 0x55, 0x90, 0x14, 0xdf, 0x71, 0x9e, + 0xb1, 0xc1, 0xf7, 0x06, 0xe2, 0xe4, 0x42, 0x85, 0xef, 0x33, 0x17, 0xe1, + 0x59, 0x53, 0x72, 0xbe, 0xcc, 0x1a, 0xf0, 0x76, 0xe8, 0x8b, 0xd7, 0xc5, + 0xf1, 0x10, 0xfc, 0xff, 0xa2, 0xc1, 0xdf, 0x91, 0xf1, 0x77, 0x41, 0x66, + 0x2a, 0xa1, 0x1d, 0x84, 0x8e, 0x0b, 0x46, 0xc4, 0xb7, 0x03, 0xa7, 0x4c, + 0x8c, 0x35, 0x62, 0x9c, 0xc3, 0xf7, 0x97, 0xdd, 0xcb, 0x2d, 0xd6, 0x3f, + 0x17, 0x10, 0xe7, 0xa6, 0x92, 0x53, 0xb0, 0x9d, 0x42, 0xbc, 0x13, 0xb4, + 0xfe, 0x5d, 0xdc, 0xcb, 0xbb, 0xdc, 0xc7, 0x4c, 0x5d, 0x94, 0x22, 0x30, + 0xfd, 0x48, 0xe2, 0x65, 0xd9, 0x83, 0x3a, 0x55, 0x93, 0x37, 0x2d, 0x73, + 0x5c, 0x34, 0xb5, 0xde, 0xf0, 0x7d, 0xb0, 0xbd, 0x37, 0x10, 0xdf, 0x3a, + 0xfc, 0xda, 0x3d, 0x5b, 0x26, 0x16, 0x3a, 0xaa, 0xde, 0x05, 0xb8, 0x60, + 0xb1, 0x7f, 0xc7, 0xdf, 0x44, 0xfe, 0xa5, 0xda, 0x63, 0xeb, 0x8c, 0x8d, + 0xfd, 0x63, 0xd2, 0xe7, 0xf1, 0x78, 0xc0, 0xf2, 0x68, 0xe4, 0x3a, 0x91, + 0xb6, 0x75, 0xce, 0xfb, 0xeb, 0x9c, 0xf5, 0xd7, 0xa9, 0xf9, 0xeb, 0x5c, + 0xd8, 0x5c, 0xe7, 0x6e, 0xe8, 0xbf, 0xd5, 0x7a, 0x0a, 0xf8, 0x21, 0x93, + 0x6a, 0xb5, 0x1c, 0xd4, 0x59, 0xa5, 0xd1, 0x79, 0x75, 0x46, 0xaa, 0xa7, + 0xbf, 0x71, 0x6f, 0xc6, 0x2a, 0xc4, 0xc3, 0x0a, 0x7b, 0xa0, 0x92, 0x82, + 0x1d, 0x16, 0xc4, 0xc3, 0xdc, 0x3c, 0xb7, 0xf3, 0xce, 0xf5, 0xba, 0xa1, + 0xc3, 0x1c, 0x72, 0x86, 0x91, 0x39, 0x67, 0x49, 0x61, 0xdf, 0x6f, 0xea, + 0xb0, 0xf3, 0x5e, 0xe4, 0x87, 0x9f, 0xc0, 0x66, 0x8c, 0x4c, 0xbd, 0x91, + 0x43, 0xbd, 0xc3, 0xf9, 0x77, 0x40, 0x8f, 0x85, 0x4c, 0xad, 0x51, 0xc8, + 0x9c, 0xe5, 0x79, 0x0e, 0xe6, 0xd5, 0x1a, 0x3d, 0x90, 0x7b, 0x8f, 0xea, + 0x8b, 0xbc, 0x5c, 0x8e, 0x31, 0x06, 0xc1, 0xd6, 0x63, 0x18, 0x8b, 0xab, + 0xdf, 0x68, 0xd5, 0xdd, 0x65, 0xf8, 0x74, 0x02, 0xe3, 0xd5, 0xae, 0x49, + 0x85, 0x47, 0x2d, 0x59, 0x71, 0x7f, 0xa5, 0x15, 0xcb, 0x97, 0xb5, 0x52, + 0x79, 0x18, 0x73, 0x46, 0xf9, 0x5b, 0x9f, 0x3d, 0xc0, 0x49, 0x53, 0xd5, + 0x1d, 0x69, 0x4a, 0x80, 0x26, 0xbd, 0x8d, 0xa6, 0x04, 0xe8, 0x41, 0xcc, + 0x3c, 0xc5, 0xde, 0xf1, 0xa8, 0x9c, 0x28, 0xf3, 0x9d, 0x26, 0xfe, 0x46, + 0xd5, 0x90, 0x30, 0xb0, 0x65, 0xe4, 0x94, 0x19, 0x5f, 0x57, 0xbd, 0x1a, + 0x73, 0xb8, 0x2e, 0x23, 0xa9, 0xba, 0xa8, 0xfc, 0x92, 0x38, 0x81, 0x7c, + 0xf5, 0x86, 0xdb, 0x23, 0x6f, 0xfa, 0x7b, 0x5d, 0x14, 0x9e, 0x33, 0x6e, + 0xdf, 0xeb, 0xc9, 0x4a, 0x2a, 0xf3, 0x8a, 0x15, 0xf2, 0xf9, 0xea, 0xc3, + 0x5e, 0x7b, 0x30, 0x37, 0x95, 0x39, 0xdf, 0xd8, 0x69, 0xae, 0x83, 0xb9, + 0x91, 0xb6, 0xb9, 0x0e, 0xe6, 0xf5, 0x20, 0xef, 0xf5, 0x28, 0x9e, 0x4a, + 0xa0, 0xeb, 0x52, 0x99, 0x3c, 0xf1, 0x0c, 0x82, 0x7b, 0x1a, 0xc4, 0xc6, + 0x53, 0xe2, 0x9f, 0xd9, 0xf2, 0xf7, 0x7a, 0x57, 0xf5, 0x6b, 0x94, 0x0d, + 0x4c, 0x58, 0x3c, 0x9b, 0x99, 0xd1, 0xb2, 0xf5, 0x3c, 0x72, 0xd5, 0x8d, + 0xc4, 0x43, 0x29, 0x1b, 0xb9, 0x92, 0xe7, 0x3c, 0x8d, 0x72, 0x81, 0xef, + 0x3d, 0xc3, 0x2e, 0xde, 0x21, 0x5e, 0xbe, 0x31, 0xa4, 0xde, 0x43, 0x70, + 0xfc, 0x73, 0x20, 0x31, 0x32, 0x63, 0x7c, 0xf7, 0xe0, 0x6e, 0xa9, 0x2f, + 0x7f, 0x11, 0x63, 0x19, 0xe4, 0xc5, 0x43, 0x5a, 0xe6, 0xdc, 0x24, 0xae, + 0x1f, 0xc2, 0x35, 0xe2, 0xf0, 0x72, 0x0e, 0xf7, 0x1f, 0xc2, 0xf5, 0xbc, + 0x96, 0x6d, 0xe6, 0x70, 0xfd, 0x30, 0xae, 0x27, 0x48, 0x9b, 0xf3, 0x8a, + 0x35, 0xa5, 0xd9, 0x58, 0xcb, 0x3e, 0x37, 0x89, 0x4f, 0xfb, 0x7a, 0xbc, + 0x07, 0x3d, 0x95, 0x79, 0x3e, 0x96, 0x04, 0x4d, 0x0f, 0x6a, 0x4e, 0xbd, + 0x1b, 0x6b, 0x0c, 0xe1, 0x79, 0xda, 0x54, 0xfb, 0x39, 0xd4, 0x6d, 0xaa, + 0x67, 0x14, 0x4a, 0xa7, 0x81, 0x77, 0x1f, 0x41, 0xde, 0xd7, 0xc4, 0xb1, + 0x1e, 0x97, 0x62, 0x2a, 0x2d, 0x0b, 0xf5, 0x90, 0x64, 0x63, 0x05, 0x7c, + 0x2f, 0x48, 0x66, 0x1c, 0xf7, 0xeb, 0xb4, 0x05, 0xce, 0x2b, 0x49, 0xb1, + 0x4a, 0xfc, 0xce, 0x7e, 0xd1, 0x57, 0xc0, 0x37, 0xfb, 0x44, 0x79, 0xc8, + 0x20, 0x46, 0xfb, 0xdd, 0xa1, 0xa7, 0xe5, 0xbd, 0xd3, 0x8c, 0x7c, 0xac, + 0x65, 0xea, 0xfe, 0x59, 0x9d, 0xc5, 0xdf, 0x2b, 0xb1, 0x47, 0x25, 0xc5, + 0x50, 0x9a, 0x7d, 0x0e, 0xd5, 0x17, 0x4f, 0x79, 0x67, 0x7a, 0xed, 0xef, + 0x90, 0x04, 0xfe, 0xc2, 0x7d, 0xbf, 0x82, 0xe7, 0xbd, 0xbe, 0x54, 0xb6, + 0xf9, 0x41, 0x5d, 0xf0, 0x5d, 0xfd, 0x15, 0xe8, 0xe2, 0xfc, 0x87, 0xf6, + 0xb9, 0xd8, 0xe3, 0x9a, 0x47, 0x2c, 0x62, 0x7f, 0x2c, 0x90, 0xdf, 0xd5, + 0x34, 0x92, 0xbe, 0xc3, 0x58, 0x4b, 0x52, 0x8c, 0xb3, 0xb9, 0x58, 0x42, + 0xd5, 0xbe, 0x1b, 0x4b, 0xf2, 0xc4, 0x16, 0xbd, 0xa4, 0x95, 0x72, 0x78, + 0x04, 0xf5, 0x1a, 0x7f, 0xff, 0xf0, 0xb8, 0xe4, 0x53, 0xec, 0xd1, 0x84, + 0x90, 0x0b, 0x0b, 0xf8, 0xbe, 0x25, 0xb7, 0x92, 0x2f, 0xb7, 0x7c, 0xf5, + 0x5b, 0x4a, 0x77, 0x35, 0x8b, 0xfb, 0x05, 0xbd, 0x8b, 0x69, 0xa5, 0xb3, + 0x9a, 0x7a, 0xcf, 0x36, 0xe0, 0x3d, 0xe8, 0xbf, 0xed, 0x6c, 0x73, 0x93, + 0x16, 0x69, 0xfb, 0x38, 0xdf, 0x5b, 0x18, 0xb6, 0x85, 0xf4, 0x93, 0x0f, + 0xe6, 0xac, 0xe0, 0x5c, 0x34, 0xe0, 0x21, 0xe0, 0xf3, 0xa3, 0xca, 0x85, + 0x74, 0xee, 0x31, 0xa4, 0x7b, 0xca, 0x08, 0x59, 0xcc, 0x01, 0x9f, 0xf6, + 0xfb, 0xf8, 0xff, 0x37, 0xe5, 0xea, 0xf1, 0x1e, 0x86, 0xa8, 0xfc, 0xdf, + 0x8b, 0xee, 0xa0, 0xf7, 0xab, 0xcf, 0x80, 0x0d, 0xe7, 0xac, 0xb5, 0xc5, + 0x67, 0x6d, 0x07, 0x3e, 0x6b, 0x3e, 0x9f, 0x1f, 0x7e, 0x4e, 0xea, 0xd1, + 0x59, 0x5b, 0xb2, 0xc1, 0x23, 0x6d, 0x6a, 0x27, 0x7b, 0xe3, 0x6f, 0x9c, + 0xd4, 0xef, 0xad, 0xa2, 0xb6, 0x7b, 0xad, 0x5e, 0x27, 0xeb, 0x64, 0xcf, + 0xee, 0xce, 0x22, 0xd7, 0x55, 0xab, 0x5e, 0xcd, 0x5c, 0x75, 0xd9, 0x6b, + 0xde, 0x69, 0x6f, 0x0d, 0x34, 0xff, 0x8e, 0x7a, 0xef, 0xa4, 0xe4, 0x7a, + 0x7d, 0xa9, 0x6a, 0xb5, 0x3d, 0x57, 0xde, 0xc0, 0x3c, 0x39, 0x5c, 0x90, + 0x19, 0xe8, 0x31, 0x89, 0xeb, 0x9b, 0xe5, 0xe5, 0x65, 0x75, 0x86, 0xe4, + 0x9f, 0xd5, 0xf0, 0x0c, 0x46, 0x9d, 0x43, 0x23, 0x5e, 0xcd, 0xaa, 0x78, + 0xbd, 0xb1, 0xac, 0xee, 0xa9, 0xdf, 0x3c, 0xd4, 0xdd, 0x19, 0xc4, 0x73, + 0xd4, 0x06, 0xd6, 0x6e, 0x29, 0xa2, 0x86, 0x3e, 0x6b, 0xcd, 0x18, 0xc4, + 0x29, 0x5c, 0x6b, 0x03, 0x6b, 0x9d, 0x5f, 0x96, 0xbd, 0x7c, 0xa7, 0xa3, + 0xaa, 0xce, 0xbd, 0xbc, 0x7e, 0xf5, 0xbc, 0x04, 0xbf, 0xd7, 0x8d, 0xfa, + 0x39, 0x8e, 0xef, 0x95, 0xf0, 0xb7, 0xa7, 0x8c, 0x01, 0xa8, 0x6b, 0x66, + 0x0a, 0x58, 0xaf, 0xd5, 0xf2, 0xfa, 0xd9, 0x2d, 0xd8, 0x7d, 0x84, 0xbf, + 0x65, 0xc0, 0xdf, 0x23, 0xb0, 0x13, 0xf8, 0xc1, 0xe6, 0x38, 0xaf, 0x59, + 0x4b, 0x04, 0xd7, 0x4c, 0x58, 0xff, 0x1b, 0xed, 0xcc, 0xfa, 0xa1, 0x98, + 0x41, 0x00, 0x00, 0x00 }; +static u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = { 0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010, 0x00000030, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00008002, 0x00000000, @@ -4051,42 +4043,42 @@ static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { - 0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c, - 0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000, +static u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { + 0x08003be8, 0x08003c14, 0x08003c5c, 0x08003c5c, 0x08003ae8, 0x08003b14, + 0x08003b14, 0x08003c5c, 0x08003c5c, 0x08003c5c, 0x08003b7c, 0x00000000, 0x00000000 }; -static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 }; -static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 }; +static u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 }; +static u32 bnx2_TXP_b09FwSbss[(0x80/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_09 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + .ver_major = 0x1, + .ver_minor = 0x0, + .ver_fix = 0x0, .start_addr = 0x08000060, .text_addr = 0x08000000, - .text_len = 0x4634, + .text_len = 0x4194, .text_index = 0x0, .gz_text = bnx2_TXP_b09FwText, .gz_text_len = sizeof(bnx2_TXP_b09FwText), - .data_addr = 0x08004680, + .data_addr = 0x080041e0, .data_len = 0xd0, .data_index = 0x0, .data = bnx2_TXP_b09FwData, - .sbss_addr = 0x08004750, - .sbss_len = 0x8c, + .sbss_addr = 0x080042b0, + .sbss_len = 0x80, .sbss_index = 0x0, .sbss = bnx2_TXP_b09FwSbss, - .bss_addr = 0x080047e0, + .bss_addr = 0x08004330, .bss_len = 0xa20, .bss_index = 0x0, .bss = bnx2_TXP_b09FwBss, - .rodata_addr = 0x08004638, + .rodata_addr = 0x08004198, .rodata_len = 0x30, .rodata_index = 0x0, .rodata = bnx2_TXP_b09FwRodata, diff --git a/trunk/drivers/net/bonding/bond_3ad.c b/trunk/drivers/net/bonding/bond_3ad.c index 7e03f41ae2c2..3fb354d9c515 100644 --- a/trunk/drivers/net/bonding/bond_3ad.c +++ b/trunk/drivers/net/bonding/bond_3ad.c @@ -884,8 +884,8 @@ static int ad_lacpdu_send(struct port *port) } skb->dev = slave->dev; - skb_reset_mac_header(skb); - skb->network_header = skb->mac_header + ETH_HLEN; + skb->mac.raw = skb->data; + skb->nh.raw = skb->data + ETH_HLEN; skb->protocol = PKT_TYPE_LACPDU; skb->priority = TC_PRIO_CONTROL; @@ -928,8 +928,8 @@ static int ad_marker_send(struct port *port, struct marker *marker) skb_reserve(skb, 16); skb->dev = slave->dev; - skb_reset_mac_header(skb); - skb->network_header = skb->mac_header + ETH_HLEN; + skb->mac.raw = skb->data; + skb->nh.raw = skb->data + ETH_HLEN; skb->protocol = PKT_TYPE_LACPDU; marker_header = (struct marker_header *)skb_put(skb, length); diff --git a/trunk/drivers/net/bonding/bond_alb.c b/trunk/drivers/net/bonding/bond_alb.c index 92c3b6f6a8e7..217a2eedee0a 100644 --- a/trunk/drivers/net/bonding/bond_alb.c +++ b/trunk/drivers/net/bonding/bond_alb.c @@ -104,15 +104,10 @@ struct arp_pkt { }; #pragma pack() -static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb) -{ - return (struct arp_pkt *)skb_network_header(skb); -} - /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 _simple_hash(const u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; @@ -618,7 +613,7 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct arp_pkt *arp = arp_pkt(skb); + struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *assigned_slave; struct rlb_client_info *client_info; u32 hash_index = 0; @@ -706,7 +701,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon */ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { - struct arp_pkt *arp = arp_pkt(skb); + struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; if (arp->op_code == __constant_htons(ARPOP_REPLY)) { @@ -895,8 +890,8 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) data = skb_put(skb, size); memcpy(data, &pkt, size); - skb_reset_mac_header(skb); - skb->network_header = skb->mac_header + ETH_HLEN; + skb->mac.raw = data; + skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; @@ -1268,10 +1263,10 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) int hash_size = 0; int do_tx_balance = 1; u32 hash_index = 0; - const u8 *hash_start = NULL; + u8 *hash_start = NULL; int res = 1; - skb_reset_mac_header(skb); + skb->mac.raw = (unsigned char *)skb->data; eth_data = eth_hdr(skb); /* make sure that the curr_active_slave and the slaves list do @@ -1285,18 +1280,15 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } switch (ntohs(skb->protocol)) { - case ETH_P_IP: { - const struct iphdr *iph = ip_hdr(skb); - + case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (iph->daddr == ip_bcast) || - (iph->protocol == IPPROTO_IGMP)) { + (skb->nh.iph->daddr == ip_bcast) || + (skb->nh.iph->protocol == IPPROTO_IGMP)) { do_tx_balance = 0; break; } - hash_start = (char *)&(iph->daddr); - hash_size = sizeof(iph->daddr); - } + hash_start = (char*)&(skb->nh.iph->daddr); + hash_size = sizeof(skb->nh.iph->daddr); break; case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { @@ -1304,8 +1296,8 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } - hash_start = (char *)&(ipv6_hdr(skb)->daddr); - hash_size = sizeof(ipv6_hdr(skb)->daddr); + hash_start = (char*)&(skb->nh.ipv6h->daddr); + hash_size = sizeof(skb->nh.ipv6h->daddr); break; case ETH_P_IPX: if (ipx_hdr(skb)->ipx_checksum != diff --git a/trunk/drivers/net/bonding/bond_main.c b/trunk/drivers/net/bonding/bond_main.c index 724bce51f936..e4724d874e7c 100644 --- a/trunk/drivers/net/bonding/bond_main.c +++ b/trunk/drivers/net/bonding/bond_main.c @@ -1360,6 +1360,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_undo_flags; } + if (slave_dev->get_stats == NULL) { + printk(KERN_NOTICE DRV_NAME + ": %s: the driver for slave device %s does not provide " + "get_stats function, network statistics will be " + "inaccurate.\n", bond_dev->name, slave_dev->name); + } + new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); if (!new_slave) { res = -ENOMEM; @@ -2517,7 +2524,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack (2 * sizeof(u32))))) goto out_unlock; - arp = arp_hdr(skb); + arp = skb->nh.arph; if (arp->ar_hln != dev->addr_len || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || @@ -3469,7 +3476,7 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, struct net_device *bond_dev, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; - struct iphdr *iph = ip_hdr(skb); + struct iphdr *iph = skb->nh.iph; u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; @@ -3633,32 +3640,35 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { - sstats = slave->dev->get_stats(slave->dev); - stats->rx_packets += sstats->rx_packets; - stats->rx_bytes += sstats->rx_bytes; - stats->rx_errors += sstats->rx_errors; - stats->rx_dropped += sstats->rx_dropped; - - stats->tx_packets += sstats->tx_packets; - stats->tx_bytes += sstats->tx_bytes; - stats->tx_errors += sstats->tx_errors; - stats->tx_dropped += sstats->tx_dropped; - - stats->multicast += sstats->multicast; - stats->collisions += sstats->collisions; - - stats->rx_length_errors += sstats->rx_length_errors; - stats->rx_over_errors += sstats->rx_over_errors; - stats->rx_crc_errors += sstats->rx_crc_errors; - stats->rx_frame_errors += sstats->rx_frame_errors; - stats->rx_fifo_errors += sstats->rx_fifo_errors; - stats->rx_missed_errors += sstats->rx_missed_errors; - - stats->tx_aborted_errors += sstats->tx_aborted_errors; - stats->tx_carrier_errors += sstats->tx_carrier_errors; - stats->tx_fifo_errors += sstats->tx_fifo_errors; - stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; - stats->tx_window_errors += sstats->tx_window_errors; + if (slave->dev->get_stats) { + sstats = slave->dev->get_stats(slave->dev); + + stats->rx_packets += sstats->rx_packets; + stats->rx_bytes += sstats->rx_bytes; + stats->rx_errors += sstats->rx_errors; + stats->rx_dropped += sstats->rx_dropped; + + stats->tx_packets += sstats->tx_packets; + stats->tx_bytes += sstats->tx_bytes; + stats->tx_errors += sstats->tx_errors; + stats->tx_dropped += sstats->tx_dropped; + + stats->multicast += sstats->multicast; + stats->collisions += sstats->collisions; + + stats->rx_length_errors += sstats->rx_length_errors; + stats->rx_over_errors += sstats->rx_over_errors; + stats->rx_crc_errors += sstats->rx_crc_errors; + stats->rx_frame_errors += sstats->rx_frame_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_missed_errors += sstats->rx_missed_errors; + + stats->tx_aborted_errors += sstats->tx_aborted_errors; + stats->tx_carrier_errors += sstats->tx_carrier_errors; + stats->tx_fifo_errors += sstats->tx_fifo_errors; + stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; + stats->tx_window_errors += sstats->tx_window_errors; + } } read_unlock_bh(&bond->lock); diff --git a/trunk/drivers/net/cassini.c b/trunk/drivers/net/cassini.c index 4aec747d9e43..c8126484c2be 100644 --- a/trunk/drivers/net/cassini.c +++ b/trunk/drivers/net/cassini.c @@ -1995,6 +1995,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc, return -1; *skbref = skb; + skb->dev = cp->dev; skb_reserve(skb, swivel); p = skb->data; @@ -2821,8 +2822,10 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, ctrl = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { - const u64 csum_start_off = skb_transport_offset(skb); - const u64 csum_stuff_off = csum_start_off + skb->csum_offset; + u64 csum_start_off, csum_stuff_off; + + csum_start_off = (u64) (skb->h.raw - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = TX_DESC_CSUM_EN | CAS_BASE(TX_DESC_CSUM_START, csum_start_off) | @@ -2846,8 +2849,8 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, ctrl | TX_DESC_SOF, 0); entry = TX_DESC_NEXT(ring, entry); - skb_copy_from_linear_data_offset(skb, len - tabort, - tx_tiny_buf(cp, ring, entry), tabort); + memcpy(tx_tiny_buf(cp, ring, entry), skb->data + + len - tabort, tabort); mapping = tx_tiny_map(cp, ring, entry, tentry); cas_write_txd(cp, ring, entry, mapping, tabort, ctrl, (nr_frags == 0)); diff --git a/trunk/drivers/net/chelsio/Makefile b/trunk/drivers/net/chelsio/Makefile index 743ad8b41b5e..382d23f810ab 100644 --- a/trunk/drivers/net/chelsio/Makefile +++ b/trunk/drivers/net/chelsio/Makefile @@ -4,6 +4,8 @@ obj-$(CONFIG_CHELSIO_T1) += cxgb.o -cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o +cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ mv88x201x.o my3126.o $(cxgb-y) + + diff --git a/trunk/drivers/net/chelsio/common.h b/trunk/drivers/net/chelsio/common.h index 8ba702c8b560..787f2f2820fe 100644 --- a/trunk/drivers/net/chelsio/common.h +++ b/trunk/drivers/net/chelsio/common.h @@ -322,9 +322,9 @@ struct board_info { unsigned char mdio_mdiinv; unsigned char mdio_mdc; unsigned char mdio_phybaseaddr; - const struct gmac *gmac; - const struct gphy *gphy; - const struct mdio_ops *mdio_ops; + struct gmac *gmac; + struct gphy *gphy; + struct mdio_ops *mdio_ops; const char *desc; }; diff --git a/trunk/drivers/net/chelsio/cphy.h b/trunk/drivers/net/chelsio/cphy.h index 79d855e267e0..cf9143499882 100644 --- a/trunk/drivers/net/chelsio/cphy.h +++ b/trunk/drivers/net/chelsio/cphy.h @@ -100,7 +100,7 @@ struct cphy { u32 elmer_gpo; - const struct cphy_ops *ops; /* PHY operations */ + struct cphy_ops *ops; /* PHY operations */ int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr, int reg_addr, unsigned int *val); int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr, @@ -136,7 +136,7 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg, /* Convenience initializer */ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, int phy_addr, struct cphy_ops *phy_ops, - const struct mdio_ops *mdio_ops) + struct mdio_ops *mdio_ops) { phy->adapter = adapter; phy->addr = phy_addr; @@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, struct gphy { /* Construct a PHY instance with the given PHY address */ struct cphy *(*create)(adapter_t *adapter, int phy_addr, - const struct mdio_ops *mdio_ops); + struct mdio_ops *mdio_ops); /* * Reset the PHY chip. This resets the whole PHY chip, not individual @@ -160,9 +160,11 @@ struct gphy { int (*reset)(adapter_t *adapter); }; -extern const struct gphy t1_my3126_ops; -extern const struct gphy t1_mv88e1xxx_ops; -extern const struct gphy t1_vsc8244_ops; -extern const struct gphy t1_mv88x201x_ops; +extern struct gphy t1_my3126_ops; +extern struct gphy t1_mv88e1xxx_ops; +extern struct gphy t1_vsc8244_ops; +extern struct gphy t1_xpak_ops; +extern struct gphy t1_mv88x201x_ops; +extern struct gphy t1_dummy_phy_ops; #endif /* _CXGB_CPHY_H_ */ diff --git a/trunk/drivers/net/chelsio/gmac.h b/trunk/drivers/net/chelsio/gmac.h index d42337457cf7..006a2eb2d362 100644 --- a/trunk/drivers/net/chelsio/gmac.h +++ b/trunk/drivers/net/chelsio/gmac.h @@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_instance; struct cmac { struct cmac_statistics stats; adapter_t *adapter; - const struct cmac_ops *ops; + struct cmac_ops *ops; cmac_instance *instance; }; @@ -136,7 +136,11 @@ struct gmac { int (*reset)(adapter_t *); }; -extern const struct gmac t1_pm3393_ops; -extern const struct gmac t1_vsc7326_ops; +extern struct gmac t1_pm3393_ops; +extern struct gmac t1_chelsio_mac_ops; +extern struct gmac t1_vsc7321_ops; +extern struct gmac t1_vsc7326_ops; +extern struct gmac t1_ixf1010_ops; +extern struct gmac t1_dummy_mac_ops; #endif /* _CXGB_GMAC_H_ */ diff --git a/trunk/drivers/net/chelsio/ixf1010.c b/trunk/drivers/net/chelsio/ixf1010.c new file mode 100644 index 000000000000..10b2a9a19006 --- /dev/null +++ b/trunk/drivers/net/chelsio/ixf1010.c @@ -0,0 +1,505 @@ +/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */ +#include "gmac.h" +#include "elmer0.h" + +/* Update fast changing statistics every 15 seconds */ +#define STATS_TICK_SECS 15 +/* 30 minutes for full statistics update */ +#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) + +/* + * The IXF1010 can handle frames up to 16383 bytes but it's optimized for + * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this. + * This length includes ethernet header and FCS. + */ +#define MAX_FRAME_SIZE 0x2667 + +/* MAC registers */ +enum { + /* Per-port registers */ + REG_MACADDR_LOW = 0, + REG_MACADDR_HIGH = 0x4, + REG_FDFC_TYPE = 0xC, + REG_FC_TX_TIMER_VALUE = 0x1c, + REG_IPG_RX_TIME1 = 0x28, + REG_IPG_RX_TIME2 = 0x2c, + REG_IPG_TX_TIME = 0x30, + REG_PAUSE_THRES = 0x38, + REG_MAX_FRAME_SIZE = 0x3c, + REG_RGMII_SPEED = 0x40, + REG_FC_ENABLE = 0x48, + REG_DISCARD_CTRL_FRAMES = 0x54, + REG_DIVERSE_CONFIG = 0x60, + REG_RX_FILTER = 0x64, + REG_MC_ADDR_LOW = 0x68, + REG_MC_ADDR_HIGH = 0x6c, + + REG_RX_OCTETS_OK = 0x80, + REG_RX_OCTETS_BAD = 0x84, + REG_RX_UC_PKTS = 0x88, + REG_RX_MC_PKTS = 0x8c, + REG_RX_BC_PKTS = 0x90, + REG_RX_FCS_ERR = 0xb0, + REG_RX_TAGGED = 0xb4, + REG_RX_DATA_ERR = 0xb8, + REG_RX_ALIGN_ERR = 0xbc, + REG_RX_LONG_ERR = 0xc0, + REG_RX_JABBER_ERR = 0xc4, + REG_RX_PAUSE_FRAMES = 0xc8, + REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc, + REG_RX_VERY_LONG_ERR = 0xd0, + REG_RX_RUNT_ERR = 0xd4, + REG_RX_SHORT_ERR = 0xd8, + REG_RX_SYMBOL_ERR = 0xe4, + + REG_TX_OCTETS_OK = 0x100, + REG_TX_OCTETS_BAD = 0x104, + REG_TX_UC_PKTS = 0x108, + REG_TX_MC_PKTS = 0x10c, + REG_TX_BC_PKTS = 0x110, + REG_TX_EXCESSIVE_LEN_DROP = 0x14c, + REG_TX_UNDERRUN = 0x150, + REG_TX_TAGGED = 0x154, + REG_TX_PAUSE_FRAMES = 0x15C, + + /* Global registers */ + REG_PORT_ENABLE = 0x1400, + + REG_JTAG_ID = 0x1430, + + RX_FIFO_HIGH_WATERMARK_BASE = 0x1600, + RX_FIFO_LOW_WATERMARK_BASE = 0x1628, + RX_FIFO_FRAMES_REMOVED_BASE = 0x1650, + + REG_RX_ERR_DROP = 0x167c, + REG_RX_FIFO_OVERFLOW_EVENT = 0x1680, + + TX_FIFO_HIGH_WATERMARK_BASE = 0x1800, + TX_FIFO_LOW_WATERMARK_BASE = 0x1828, + TX_FIFO_XFER_THRES_BASE = 0x1850, + + REG_TX_FIFO_OVERFLOW_EVENT = 0x1878, + REG_TX_FIFO_OOS_EVENT = 0x1884, + + TX_FIFO_FRAMES_REMOVED_BASE = 0x1888, + + REG_SPI_RX_BURST = 0x1c00, + REG_SPI_RX_TRAINING = 0x1c04, + REG_SPI_RX_CALENDAR = 0x1c08, + REG_SPI_TX_SYNC = 0x1c0c +}; + +enum { /* RMON registers */ + REG_RxOctetsTotalOK = 0x80, + REG_RxOctetsBad = 0x84, + REG_RxUCPkts = 0x88, + REG_RxMCPkts = 0x8c, + REG_RxBCPkts = 0x90, + REG_RxJumboPkts = 0xac, + REG_RxFCSErrors = 0xb0, + REG_RxDataErrors = 0xb8, + REG_RxAlignErrors = 0xbc, + REG_RxLongErrors = 0xc0, + REG_RxJabberErrors = 0xc4, + REG_RxPauseMacControlCounter = 0xc8, + REG_RxVeryLongErrors = 0xd0, + REG_RxRuntErrors = 0xd4, + REG_RxShortErrors = 0xd8, + REG_RxSequenceErrors = 0xe0, + REG_RxSymbolErrors = 0xe4, + + REG_TxOctetsTotalOK = 0x100, + REG_TxOctetsBad = 0x104, + REG_TxUCPkts = 0x108, + REG_TxMCPkts = 0x10c, + REG_TxBCPkts = 0x110, + REG_TxJumboPkts = 0x12C, + REG_TxTotalCollisions = 0x134, + REG_TxExcessiveLengthDrop = 0x14c, + REG_TxUnderrun = 0x150, + REG_TxCRCErrors = 0x158, + REG_TxPauseFrames = 0x15c +}; + +enum { + DIVERSE_CONFIG_PAD_ENABLE = 0x80, + DIVERSE_CONFIG_CRC_ADD = 0x40 +}; + +#define MACREG_BASE 0 +#define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg)) + +struct _cmac_instance { + u32 mac_base; + u32 index; + u32 version; + u32 ticks; +}; + +static void disable_port(struct cmac *mac) +{ + u32 val; + + t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val); + val &= ~(1 << mac->instance->index); + t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); +} + +/* + * Read the current values of the RMON counters and add them to the cumulative + * port statistics. The HW RMON counters are cleared by this operation. + */ +static void port_stats_update(struct cmac *mac) +{ + static struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { + +#define HW_STAT(name, stat_name) \ + { REG_##name, \ + (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxOctetsTotalOK, RxOctetsOK), + HW_STAT(RxOctetsBad, RxOctetsBad), + HW_STAT(RxUCPkts, RxUnicastFramesOK), + HW_STAT(RxMCPkts, RxMulticastFramesOK), + HW_STAT(RxBCPkts, RxBroadcastFramesOK), + HW_STAT(RxJumboPkts, RxJumboFramesOK), + HW_STAT(RxFCSErrors, RxFCSErrors), + HW_STAT(RxAlignErrors, RxAlignErrors), + HW_STAT(RxLongErrors, RxFrameTooLongErrors), + HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors), + HW_STAT(RxPauseMacControlCounter, RxPauseFrames), + HW_STAT(RxDataErrors, RxDataErrors), + HW_STAT(RxJabberErrors, RxJabberErrors), + HW_STAT(RxRuntErrors, RxRuntErrors), + HW_STAT(RxShortErrors, RxRuntErrors), + HW_STAT(RxSequenceErrors, RxSequenceErrors), + HW_STAT(RxSymbolErrors, RxSymbolErrors), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxOctetsTotalOK, TxOctetsOK), + HW_STAT(TxOctetsBad, TxOctetsBad), + HW_STAT(TxUCPkts, TxUnicastFramesOK), + HW_STAT(TxMCPkts, TxMulticastFramesOK), + HW_STAT(TxBCPkts, TxBroadcastFramesOK), + HW_STAT(TxJumboPkts, TxJumboFramesOK), + HW_STAT(TxPauseFrames, TxPauseFrames), + HW_STAT(TxExcessiveLengthDrop, TxLengthErrors), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxCRCErrors, TxFCSErrors) + }, *p = hw_stats; + u64 *stats = (u64 *) &mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { + u32 val; + + t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val); + stats[p->offset] += val; + } +} + +/* No-op interrupt operation as this MAC does not support interrupts */ +static int mac_intr_op(struct cmac *mac) +{ + return 0; +} + +/* Expect MAC address to be in network byte order. */ +static int mac_set_address(struct cmac *mac, u8 addr[6]) +{ + u32 addr_lo, addr_hi; + + addr_lo = addr[2]; + addr_lo = (addr_lo << 8) | addr[3]; + addr_lo = (addr_lo << 8) | addr[4]; + addr_lo = (addr_lo << 8) | addr[5]; + + addr_hi = addr[0]; + addr_hi = (addr_hi << 8) | addr[1]; + + t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo); + t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi); + return 0; +} + +static int mac_get_address(struct cmac *mac, u8 addr[6]) +{ + u32 addr_lo, addr_hi; + + t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo); + t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi); + + addr[0] = (u8) (addr_hi >> 8); + addr[1] = (u8) addr_hi; + addr[2] = (u8) (addr_lo >> 24); + addr[3] = (u8) (addr_lo >> 16); + addr[4] = (u8) (addr_lo >> 8); + addr[5] = (u8) addr_lo; + return 0; +} + +/* This is intended to reset a port, not the whole MAC */ +static int mac_reset(struct cmac *mac) +{ + return 0; +} + +static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) +{ + u32 val, new_mode; + adapter_t *adapter = mac->adapter; + u32 addr_lo, addr_hi; + u8 *addr; + + t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val); + new_mode = val & ~7; + if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0) + new_mode |= 1; /* only set if version > 0 due to erratum */ + if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm) + && t1_rx_mode_mc_cnt(rm) <= 1) + new_mode |= 2; + if (new_mode != val) + t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode); + switch (t1_rx_mode_mc_cnt(rm)) { + case 0: + t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0); + t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0); + break; + case 1: + addr = t1_get_next_mcaddr(rm); + addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | + addr[5]; + addr_hi = (addr[0] << 8) | addr[1]; + t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo); + t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi); + break; + default: + break; + } + return 0; +} + +static int mac_set_mtu(struct cmac *mac, int mtu) +{ + /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ + if (mtu > (MAX_FRAME_SIZE - 14 - 4)) + return -EINVAL; + t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), + mtu + 14 + 4); + return 0; +} + +static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, + int fc) +{ + u32 val; + + if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000) + return -1; + if (duplex >= 0 && duplex != DUPLEX_FULL) + return -1; + + if (speed >= 0) { + val = speed == SPEED_100 ? 1 : 2; + t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val); + } + + t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); + val &= ~3; + if (fc & PAUSE_RX) + val |= 1; + if (fc & PAUSE_TX) + val |= 2; + t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val); + return 0; +} + +static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex, + int *fc) +{ + u32 val; + + if (duplex) + *duplex = DUPLEX_FULL; + if (speed) { + t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED), + &val); + *speed = (val & 2) ? SPEED_1000 : SPEED_100; + } + if (fc) { + t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); + *fc = 0; + if (val & 1) + *fc |= PAUSE_RX; + if (val & 2) + *fc |= PAUSE_TX; + } + return 0; +} + +static void enable_port(struct cmac *mac) +{ + u32 val; + u32 index = mac->instance->index; + adapter_t *adapter = mac->adapter; + + t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val); + val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE; + t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val); + if (mac->instance->version > 0) + t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3); + else /* Don't enable unicast address filtering due to IXF1010 bug */ + t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2); + + t1_tpi_read(adapter, REG_RX_ERR_DROP, &val); + val |= (1 << index); + t1_tpi_write(adapter, REG_RX_ERR_DROP, val); + + /* + * Clear the port RMON registers by adding their current values to the + * cumulatice port stats and then clearing the stats. Really. + */ + port_stats_update(mac); + memset(&mac->stats, 0, sizeof(struct cmac_statistics)); + mac->instance->ticks = 0; + + t1_tpi_read(adapter, REG_PORT_ENABLE, &val); + val |= (1 << index); + t1_tpi_write(adapter, REG_PORT_ENABLE, val); + + index <<= 2; + if (is_T2(adapter)) { + /* T204: set the Fifo water level & threshold */ + t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); + t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); + t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600); + t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0); + t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100); + } else { + /* + * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around + * Underrun problem. Intel has blessed this solution. + */ + t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400); + } +} + +/* IXF1010 ports do not have separate enables for TX and RX */ +static int mac_enable(struct cmac *mac, int which) +{ + if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) + enable_port(mac); + return 0; +} + +static int mac_disable(struct cmac *mac, int which) +{ + if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) + disable_port(mac); + return 0; +} + +#define RMON_UPDATE(mac, name, stat_name) \ + t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ + (mac)->stats.stat_name += val; + +/* + * This function is called periodically to accumulate the current values of the + * RMON counters into the port statistics. Since the counters are only 32 bits + * some of them can overflow in less than a minute at GigE speeds, so this + * function should be called every 30 seconds or so. + * + * To cut down on reading costs we update only the octet counters at each tick + * and do a full update at major ticks, which can be every 30 minutes or more. + */ +static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, + int flag) +{ + if (flag == MAC_STATS_UPDATE_FULL || + MAJOR_UPDATE_TICKS <= mac->instance->ticks) { + port_stats_update(mac); + mac->instance->ticks = 0; + } else { + u32 val; + + RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); + RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); + mac->instance->ticks++; + } + return &mac->stats; +} + +static void mac_destroy(struct cmac *mac) +{ + kfree(mac); +} + +static struct cmac_ops ixf1010_ops = { + .destroy = mac_destroy, + .reset = mac_reset, + .interrupt_enable = mac_intr_op, + .interrupt_disable = mac_intr_op, + .interrupt_clear = mac_intr_op, + .enable = mac_enable, + .disable = mac_disable, + .set_mtu = mac_set_mtu, + .set_rx_mode = mac_set_rx_mode, + .set_speed_duplex_fc = mac_set_speed_duplex_fc, + .get_speed_duplex_fc = mac_get_speed_duplex_fc, + .statistics_update = mac_update_statistics, + .macaddress_get = mac_get_address, + .macaddress_set = mac_set_address, +}; + +static int ixf1010_mac_reset(adapter_t *adapter) +{ + u32 val; + + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + if ((val & 1) != 0) { + val &= ~1; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(2); + } + val |= 1; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(2); + + t1_tpi_write(adapter, REG_PORT_ENABLE, 0); + return 0; +} + +static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index) +{ + struct cmac *mac; + u32 val; + + if (index > 9) + return NULL; + + mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); + if (!mac) + return NULL; + + mac->ops = &ixf1010_ops; + mac->instance = (cmac_instance *)(mac + 1); + + mac->instance->mac_base = MACREG_BASE + (index * 0x200); + mac->instance->index = index; + mac->adapter = adapter; + mac->instance->ticks = 0; + + t1_tpi_read(adapter, REG_JTAG_ID, &val); + mac->instance->version = val >> 28; + return mac; +} + +struct gmac t1_ixf1010_ops = { + STATS_TICK_SECS, + ixf1010_mac_create, + ixf1010_mac_reset +}; diff --git a/trunk/drivers/net/chelsio/mac.c b/trunk/drivers/net/chelsio/mac.c index 1d972825eac3..6af39dc70459 100644 --- a/trunk/drivers/net/chelsio/mac.c +++ b/trunk/drivers/net/chelsio/mac.c @@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t *adapter, int index) return mac; } -const struct gmac t1_chelsio_mac_ops = { +struct gmac t1_chelsio_mac_ops = { .create = mac_create }; diff --git a/trunk/drivers/net/chelsio/mv88e1xxx.c b/trunk/drivers/net/chelsio/mv88e1xxx.c index 0632be0d6494..5867e3b0a887 100644 --- a/trunk/drivers/net/chelsio/mv88e1xxx.c +++ b/trunk/drivers/net/chelsio/mv88e1xxx.c @@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = { }; static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, - const struct mdio_ops *mdio_ops) + struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); @@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t* adapter) return 0; } -const struct gphy t1_mv88e1xxx_ops = { - .create = mv88e1xxx_phy_create, - .reset = mv88e1xxx_phy_reset +struct gphy t1_mv88e1xxx_ops = { + mv88e1xxx_phy_create, + mv88e1xxx_phy_reset }; diff --git a/trunk/drivers/net/chelsio/mv88x201x.c b/trunk/drivers/net/chelsio/mv88x201x.c index cd856041af34..c8e89480d906 100644 --- a/trunk/drivers/net/chelsio/mv88x201x.c +++ b/trunk/drivers/net/chelsio/mv88x201x.c @@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = { }; static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, - const struct mdio_ops *mdio_ops) + struct mdio_ops *mdio_ops) { u32 val; struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); @@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t *adapter) return 0; } -const struct gphy t1_mv88x201x_ops = { - .create = mv88x201x_phy_create, - .reset = mv88x201x_phy_reset +struct gphy t1_mv88x201x_ops = { + mv88x201x_phy_create, + mv88x201x_phy_reset }; diff --git a/trunk/drivers/net/chelsio/my3126.c b/trunk/drivers/net/chelsio/my3126.c index 040acd29995a..87dde3e60046 100644 --- a/trunk/drivers/net/chelsio/my3126.c +++ b/trunk/drivers/net/chelsio/my3126.c @@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = { }; static struct cphy *my3126_phy_create(adapter_t *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) + int phy_addr, struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); @@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * adapter) return 0; } -const struct gphy t1_my3126_ops = { - .create = my3126_phy_create, - .reset = my3126_phy_reset +struct gphy t1_my3126_ops = { + my3126_phy_create, + my3126_phy_reset }; diff --git a/trunk/drivers/net/chelsio/pm3393.c b/trunk/drivers/net/chelsio/pm3393.c index 678778a8d133..69129edeefd6 100644 --- a/trunk/drivers/net/chelsio/pm3393.c +++ b/trunk/drivers/net/chelsio/pm3393.c @@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * adapter) return successful_reset ? 0 : 1; } -const struct gmac t1_pm3393_ops = { - .stats_update_period = STATS_TICK_SECS, - .create = pm3393_mac_create, - .reset = pm3393_mac_reset, +struct gmac t1_pm3393_ops = { + STATS_TICK_SECS, + pm3393_mac_create, + pm3393_mac_reset }; diff --git a/trunk/drivers/net/chelsio/sge.c b/trunk/drivers/net/chelsio/sge.c index e4f874a70fe5..326d4a665123 100644 --- a/trunk/drivers/net/chelsio/sge.c +++ b/trunk/drivers/net/chelsio/sge.c @@ -1062,7 +1062,7 @@ static inline struct sk_buff *get_packet(struct pci_dev *pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(ce->skb, skb->data, len); + memcpy(skb->data, ce->skb->data, len); pci_dma_sync_single_for_device(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), @@ -1379,11 +1379,12 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) } __skb_pull(skb, sizeof(*p)); + skb->dev = adapter->port[p->iff].dev; skb->dev->last_rx = jiffies; st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id()); st->rx_packets++; - skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); + skb->protocol = eth_type_trans(skb, skb->dev); if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { @@ -1865,14 +1866,14 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) ++st->tx_tso; - eth_type = skb_network_offset(skb) == ETH_HLEN ? + eth_type = skb->nh.raw - skb->data == ETH_HLEN ? CPL_ETH_II : CPL_ETH_II_VLAN; hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr)); hdr->opcode = CPL_TX_PKT_LSO; hdr->ip_csum_dis = hdr->l4_csum_dis = 0; - hdr->ip_hdr_words = ip_hdr(skb)->ihl; - hdr->tcp_hdr_words = tcp_hdr(skb)->doff; + hdr->ip_hdr_words = skb->nh.iph->ihl; + hdr->tcp_hdr_words = skb->h.th->doff; hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type, skb_shinfo(skb)->gso_size)); hdr->len = htonl(skb->len - sizeof(*hdr)); @@ -1912,7 +1913,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(adapter->flags & UDP_CSUM_CAPABLE) && skb->ip_summed == CHECKSUM_PARTIAL && - ip_hdr(skb)->protocol == IPPROTO_UDP) { + skb->nh.iph->protocol == IPPROTO_UDP) { if (unlikely(skb_checksum_help(skb))) { pr_debug("%s: unable to do udp checksum\n", dev->name); dev_kfree_skb_any(skb); @@ -1925,7 +1926,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if ((unlikely(!adapter->sge->espibug_skb[dev->if_port]))) { if (skb->protocol == htons(ETH_P_ARP) && - arp_hdr(skb)->ar_op == htons(ARPOP_REQUEST)) { + skb->nh.arph->ar_op == htons(ARPOP_REQUEST)) { adapter->sge->espibug_skb[dev->if_port] = skb; /* We want to re-use this skb later. We * simply bump the reference count and it @@ -2095,14 +2096,10 @@ static void espibug_workaround_t204(unsigned long data) 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 }; - skb_copy_to_linear_data_offset(skb, - sizeof(struct cpl_tx_pkt), - ch_mac_addr, - ETH_ALEN); - skb_copy_to_linear_data_offset(skb, - skb->len - 10, - ch_mac_addr, - ETH_ALEN); + memcpy(skb->data + sizeof(struct cpl_tx_pkt), + ch_mac_addr, ETH_ALEN); + memcpy(skb->data + skb->len - 10, + ch_mac_addr, ETH_ALEN); skb->cb[0] = 0xff; } @@ -2129,14 +2126,10 @@ static void espibug_workaround(unsigned long data) if (!skb->cb[0]) { u8 ch_mac_addr[ETH_ALEN] = {0x0, 0x7, 0x43, 0x0, 0x0, 0x0}; - skb_copy_to_linear_data_offset(skb, - sizeof(struct cpl_tx_pkt), - ch_mac_addr, - ETH_ALEN); - skb_copy_to_linear_data_offset(skb, - skb->len - 10, - ch_mac_addr, - ETH_ALEN); + memcpy(skb->data + sizeof(struct cpl_tx_pkt), + ch_mac_addr, ETH_ALEN); + memcpy(skb->data + skb->len - 10, ch_mac_addr, + ETH_ALEN); skb->cb[0] = 0xff; } diff --git a/trunk/drivers/net/chelsio/subr.c b/trunk/drivers/net/chelsio/subr.c index 7de9a611e1f7..c2522cdfab37 100644 --- a/trunk/drivers/net/chelsio/subr.c +++ b/trunk/drivers/net/chelsio/subr.c @@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, } #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR) -static const struct mdio_ops mi1_mdio_ops = { - .init = mi1_mdio_init, - .read = mi1_mdio_read, - .write = mi1_mdio_write +static struct mdio_ops mi1_mdio_ops = { + mi1_mdio_init, + mi1_mdio_read, + mi1_mdio_write }; #endif @@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, return 0; } -static const struct mdio_ops mi1_mdio_ext_ops = { - .init = mi1_mdio_init, - .read = mi1_mdio_ext_read, - .write = mi1_mdio_ext_write +static struct mdio_ops mi1_mdio_ext_ops = { + mi1_mdio_init, + mi1_mdio_ext_read, + mi1_mdio_ext_write }; enum { @@ -392,136 +392,63 @@ enum { CH_BRD_N204_4CU, }; -static const struct board_info t1_board[] = { - { - .board = CHBT_BOARD_CHT110, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T1, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_MY3126, - .clock_core = 125000000, - .clock_mc3 = 150000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 1, - .mdio_mdiinv = 1, - .mdio_mdc = 1, - .mdio_phybaseaddr = 1, - .gmac = &t1_pm3393_ops, - .gphy = &t1_my3126_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T110 1x10GBase-CX4 TOE", - }, - - { - .board = CHBT_BOARD_N110, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, - .chip_term = CHBT_TERM_T1, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio N110 1x10GBaseX NIC", - }, - - { - .board = CHBT_BOARD_N210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio N210 1x10GBaseX NIC", - }, - - { - .board = CHBT_BOARD_CHT210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .clock_mc3 = 133000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T210 1x10GBaseX TOE", - }, - - { - .board = CHBT_BOARD_CHT210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_MY3126, - .clock_core = 125000000, - .clock_mc3 = 133000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 1, - .mdio_mdiinv = 1, - .mdio_mdc = 1, - .mdio_phybaseaddr = 1, - .gmac = &t1_pm3393_ops, - .gphy = &t1_my3126_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T210 1x10GBase-CX4 TOE", - }, +static struct board_info t1_board[] = { + +{ CHBT_BOARD_CHT110, 1/*ports#*/, + SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1, + CHBT_MAC_PM3393, CHBT_PHY_MY3126, + 125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/, + 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, + 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, + &t1_my3126_ops, &mi1_mdio_ext_ops, + "Chelsio T110 1x10GBase-CX4 TOE" }, + +{ CHBT_BOARD_N110, 1/*ports#*/, + SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1, + CHBT_MAC_PM3393, CHBT_PHY_88X2010, + 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, + 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, + 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, + &t1_mv88x201x_ops, &mi1_mdio_ext_ops, + "Chelsio N110 1x10GBaseX NIC" }, + +{ CHBT_BOARD_N210, 1/*ports#*/, + SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2, + CHBT_MAC_PM3393, CHBT_PHY_88X2010, + 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, + 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, + 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, + &t1_mv88x201x_ops, &mi1_mdio_ext_ops, + "Chelsio N210 1x10GBaseX NIC" }, + +{ CHBT_BOARD_CHT210, 1/*ports#*/, + SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, + CHBT_MAC_PM3393, CHBT_PHY_88X2010, + 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, + 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, + 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, + &t1_mv88x201x_ops, &mi1_mdio_ext_ops, + "Chelsio T210 1x10GBaseX TOE" }, + +{ CHBT_BOARD_CHT210, 1/*ports#*/, + SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, + CHBT_MAC_PM3393, CHBT_PHY_MY3126, + 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, + 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, + 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, + &t1_my3126_ops, &mi1_mdio_ext_ops, + "Chelsio T210 1x10GBase-CX4 TOE" }, #ifdef CONFIG_CHELSIO_T1_1G - { - .board = CHBT_BOARD_CHN204, - .port_number = 4, - .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | - SUPPORTED_PAUSE | SUPPORTED_TP, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_VSC7321, - .chip_phy = CHBT_PHY_88E1111, - .clock_core = 100000000, - .espi_nports = 4, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 0, - .mdio_phybaseaddr = 4, - .gmac = &t1_vsc7326_ops, - .gphy = &t1_mv88e1xxx_ops, - .mdio_ops = &mi1_mdio_ops, - .desc = "Chelsio N204 4x100/1000BaseT NIC", - }, +{ CHBT_BOARD_CHN204, 4/*ports#*/, + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111, + 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, + 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, + 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops, + &t1_mv88e1xxx_ops, &mi1_mdio_ops, + "Chelsio N204 4x100/1000BaseT NIC" }, #endif }; diff --git a/trunk/drivers/net/chelsio/vsc7326.c b/trunk/drivers/net/chelsio/vsc7326.c index 99b51f61fe77..534ffa0f616e 100644 --- a/trunk/drivers/net/chelsio/vsc7326.c +++ b/trunk/drivers/net/chelsio/vsc7326.c @@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *adapter) return 0; } -const struct gmac t1_vsc7326_ops = { +struct gmac t1_vsc7326_ops = { .stats_update_period = STATS_TICK_SECS, .create = vsc7326_mac_create, .reset = vsc7326_mac_reset, diff --git a/trunk/drivers/net/chelsio/vsc8244.c b/trunk/drivers/net/chelsio/vsc8244.c new file mode 100644 index 000000000000..251d4859c91d --- /dev/null +++ b/trunk/drivers/net/chelsio/vsc8244.c @@ -0,0 +1,367 @@ +/* + * This file is part of the Chelsio T2 Ethernet driver. + * + * Copyright (C) 2005 Chelsio Communications. All rights reserved. + * + * 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 LICENSE file included in this + * release for licensing terms and conditions. + */ + +#include "common.h" +#include "cphy.h" +#include "elmer0.h" + +#ifndef ADVERTISE_PAUSE_CAP +# define ADVERTISE_PAUSE_CAP 0x400 +#endif +#ifndef ADVERTISE_PAUSE_ASYM +# define ADVERTISE_PAUSE_ASYM 0x800 +#endif + +/* Gigabit MII registers */ +#ifndef MII_CTRL1000 +# define MII_CTRL1000 9 +#endif + +#ifndef ADVERTISE_1000FULL +# define ADVERTISE_1000FULL 0x200 +# define ADVERTISE_1000HALF 0x100 +#endif + +/* VSC8244 PHY specific registers. */ +enum { + VSC8244_INTR_ENABLE = 25, + VSC8244_INTR_STATUS = 26, + VSC8244_AUX_CTRL_STAT = 28, +}; + +enum { + VSC_INTR_RX_ERR = 1 << 0, + VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ + VSC_INTR_CABLE = 1 << 2, /* cable impairment */ + VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ + VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ + VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ + VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ + VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ + VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ + VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ + VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ + VSC_INTR_LINK_CHG = 1 << 13, /* link change */ + VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ +}; + +#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ + VSC_INTR_NEG_DONE) +#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ + VSC_INTR_ENABLE) + +/* PHY specific auxiliary control & status register fields */ +#define S_ACSR_ACTIPHY_TMR 0 +#define M_ACSR_ACTIPHY_TMR 0x3 +#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) + +#define S_ACSR_SPEED 3 +#define M_ACSR_SPEED 0x3 +#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) + +#define S_ACSR_DUPLEX 5 +#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) + +#define S_ACSR_ACTIPHY 6 +#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) + +/* + * Reset the PHY. This PHY completes reset immediately so we never wait. + */ +static int vsc8244_reset(struct cphy *cphy, int wait) +{ + int err; + unsigned int ctl; + + err = simple_mdio_read(cphy, MII_BMCR, &ctl); + if (err) + return err; + + ctl &= ~BMCR_PDOWN; + ctl |= BMCR_RESET; + return simple_mdio_write(cphy, MII_BMCR, ctl); +} + +static int vsc8244_intr_enable(struct cphy *cphy) +{ + simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK); + + /* Enable interrupts through Elmer */ + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer |= ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + + return 0; +} + +static int vsc8244_intr_disable(struct cphy *cphy) +{ + simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0); + + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer &= ~ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + + return 0; +} + +static int vsc8244_intr_clear(struct cphy *cphy) +{ + u32 val; + u32 elmer; + + /* Clear PHY interrupts by reading the register. */ + simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val); + + if (t1_is_asic(cphy->adapter)) { + t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); + elmer |= ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); + } + + return 0; +} + +/* + * Force the PHY speed and duplex. This also disables auto-negotiation, except + * for 1Gb/s, where auto-negotiation is mandatory. + */ +static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + unsigned int ctl; + + err = simple_mdio_read(phy, MII_BMCR, &ctl); + if (err) + return err; + + if (speed >= 0) { + ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + if (speed == SPEED_100) + ctl |= BMCR_SPEED100; + else if (speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + } + if (duplex >= 0) { + ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); + if (duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + } + if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ + ctl |= BMCR_ANENABLE; + return simple_mdio_write(phy, MII_BMCR, ctl); +} + +int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits) +{ + int ret; + unsigned int val; + + ret = mdio_read(phy, mmd, reg, &val); + if (!ret) + ret = mdio_write(phy, mmd, reg, val | bits); + return ret; +} + +static int vsc8244_autoneg_enable(struct cphy *cphy) +{ + return t1_mdio_set_bits(cphy, 0, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART); +} + +static int vsc8244_autoneg_restart(struct cphy *cphy) +{ + return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART); +} + +static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map) +{ + int err; + unsigned int val = 0; + + err = simple_mdio_read(phy, MII_CTRL1000, &val); + if (err) + return err; + + val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + if (advertise_map & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000HALF; + if (advertise_map & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000FULL; + + err = simple_mdio_write(phy, MII_CTRL1000, val); + if (err) + return err; + + val = 1; + if (advertise_map & ADVERTISED_10baseT_Half) + val |= ADVERTISE_10HALF; + if (advertise_map & ADVERTISED_10baseT_Full) + val |= ADVERTISE_10FULL; + if (advertise_map & ADVERTISED_100baseT_Half) + val |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + val |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_PAUSE) + val |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_ASYM_PAUSE) + val |= ADVERTISE_PAUSE_ASYM; + return simple_mdio_write(phy, MII_ADVERTISE, val); +} + +static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = simple_mdio_read(cphy, MII_BMCR, &bmcr); + if (!err) + err = simple_mdio_read(cphy, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = simple_mdio_read(cphy, MII_BMSR, &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status); + if (err) + return err; + + dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + sp = G_ACSR_SPEED(status); + if (sp == 0) + sp = SPEED_10; + else if (sp == 1) + sp = SPEED_100; + else + sp = SPEED_1000; + + if (fc && dplx == DUPLEX_FULL) { + err = simple_mdio_read(cphy, MII_LPA, &lpa); + if (!err) + err = simple_mdio_read(cphy, MII_ADVERTISE, + &adv); + if (err) + return err; + + if (lpa & adv & ADVERTISE_PAUSE_CAP) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_CAP) && + (lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_CAP)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +static int vsc8244_intr_handler(struct cphy *cphy) +{ + unsigned int cause; + int err, cphy_cause = 0; + + err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause); + if (err) + return err; + + cause &= INTR_MASK; + if (cause & CFG_CHG_INTR_MASK) + cphy_cause |= cphy_cause_link_change; + if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) + cphy_cause |= cphy_cause_fifo_error; + return cphy_cause; +} + +static void vsc8244_destroy(struct cphy *cphy) +{ + kfree(cphy); +} + +static struct cphy_ops vsc8244_ops = { + .destroy = vsc8244_destroy, + .reset = vsc8244_reset, + .interrupt_enable = vsc8244_intr_enable, + .interrupt_disable = vsc8244_intr_disable, + .interrupt_clear = vsc8244_intr_clear, + .interrupt_handler = vsc8244_intr_handler, + .autoneg_enable = vsc8244_autoneg_enable, + .autoneg_restart = vsc8244_autoneg_restart, + .advertise = vsc8244_advertise, + .set_speed_duplex = vsc8244_set_speed_duplex, + .get_link_status = vsc8244_get_link_status +}; + +static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, + struct mdio_ops *mdio_ops) +{ + struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); + + if (!cphy) + return NULL; + + cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops); + + return cphy; +} + + +static int vsc8244_phy_reset(adapter_t* adapter) +{ + return 0; +} + +struct gphy t1_vsc8244_ops = { + vsc8244_phy_create, + vsc8244_phy_reset +}; + + diff --git a/trunk/drivers/net/chelsio/vsc8244_reg.h b/trunk/drivers/net/chelsio/vsc8244_reg.h new file mode 100644 index 000000000000..d3c1829055cb --- /dev/null +++ b/trunk/drivers/net/chelsio/vsc8244_reg.h @@ -0,0 +1,172 @@ +/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */ +#ifndef CHELSIO_MV8E1XXX_H +#define CHELSIO_MV8E1XXX_H + +#ifndef BMCR_SPEED1000 +# define BMCR_SPEED1000 0x40 +#endif + +#ifndef ADVERTISE_PAUSE +# define ADVERTISE_PAUSE 0x400 +#endif +#ifndef ADVERTISE_PAUSE_ASYM +# define ADVERTISE_PAUSE_ASYM 0x800 +#endif + +/* Gigabit MII registers */ +#define MII_GBMR 1 /* 1000Base-T mode register */ +#define MII_GBCR 9 /* 1000Base-T control register */ +#define MII_GBSR 10 /* 1000Base-T status register */ + +/* 1000Base-T control register fields */ +#define GBCR_ADV_1000HALF 0x100 +#define GBCR_ADV_1000FULL 0x200 +#define GBCR_PREFER_MASTER 0x400 +#define GBCR_MANUAL_AS_MASTER 0x800 +#define GBCR_MANUAL_CONFIG_ENABLE 0x1000 + +/* 1000Base-T status register fields */ +#define GBSR_LP_1000HALF 0x400 +#define GBSR_LP_1000FULL 0x800 +#define GBSR_REMOTE_OK 0x1000 +#define GBSR_LOCAL_OK 0x2000 +#define GBSR_LOCAL_MASTER 0x4000 +#define GBSR_MASTER_FAULT 0x8000 + +/* Vitesse PHY interrupt status bits. */ +#if 0 +#define VSC8244_INTR_JABBER 0x0001 +#define VSC8244_INTR_POLARITY_CHNG 0x0002 +#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 +#define VSC8244_INTR_DOWNSHIFT 0x0020 +#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 +#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 +#define VSC8244_INTR_FALSE_CARRIER 0x0100 +#define VSC8244_INTR_SYMBOL_ERROR 0x0200 +#define VSC8244_INTR_LINK_CHNG 0x0400 +#define VSC8244_INTR_AUTONEG_DONE 0x0800 +#define VSC8244_INTR_PAGE_RECV 0x1000 +#define VSC8244_INTR_DUPLEX_CHNG 0x2000 +#define VSC8244_INTR_SPEED_CHNG 0x4000 +#define VSC8244_INTR_AUTONEG_ERR 0x8000 +#else +//#define VSC8244_INTR_JABBER 0x0001 +//#define VSC8244_INTR_POLARITY_CHNG 0x0002 +//#define VSC8244_INTR_BIT2 0x0004 +//#define VSC8244_INTR_BIT3 0x0008 +#define VSC8244_INTR_RX_ERR 0x0001 +#define VSC8244_INTR_MASTER_SLAVE 0x0002 +#define VSC8244_INTR_CABLE_IMPAIRED 0x0004 +#define VSC8244_INTR_FALSE_CARRIER 0x0008 +//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 +//#define VSC8244_INTR_DOWNSHIFT 0x0020 +//#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 +//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 +#define VSC8244_INTR_BIT4 0x0010 +#define VSC8244_INTR_FIFO_RX 0x0020 +#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040 +#define VSC8244_INTR_LOCK_LOST 0x0080 +//#define VSC8244_INTR_FALSE_CARRIER 0x0100 +//#define VSC8244_INTR_SYMBOL_ERROR 0x0200 +//#define VSC8244_INTR_LINK_CHNG 0x0400 +//#define VSC8244_INTR_AUTONEG_DONE 0x0800 +#define VSC8244_INTR_SYMBOL_ERROR 0x0100 +#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200 +#define VSC8244_INTR_AUTONEG_DONE 0x0400 +#define VSC8244_INTR_AUTONEG_ERR 0x0800 +//#define VSC8244_INTR_PAGE_RECV 0x1000 +//#define VSC8244_INTR_DUPLEX_CHNG 0x2000 +//#define VSC8244_INTR_SPEED_CHNG 0x4000 +//#define VSC8244_INTR_AUTONEG_ERR 0x8000 +#define VSC8244_INTR_DUPLEX_CHNG 0x1000 +#define VSC8244_INTR_LINK_CHNG 0x2000 +#define VSC8244_INTR_SPEED_CHNG 0x4000 +#define VSC8244_INTR_STATUS 0x8000 +#endif + + +/* Vitesse PHY specific registers. */ +#define VSC8244_SPECIFIC_CNTRL_REGISTER 16 +#define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c +#define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19 +#define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a +#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20 +#define VSC8244_RECV_ERR_CNTR_REGISTER 21 +#define VSC8244_RES_REGISTER 22 +#define VSC8244_GLOBAL_STATUS_REGISTER 23 +#define VSC8244_LED_CONTROL_REGISTER 24 +#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25 +#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26 +#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27 +#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28 +#define VSC8244_EXTENDED_ADDR_REGISTER 29 +#define VSC8244_EXTENDED_REGISTER 30 + +/* PHY specific control register fields */ +#define S_PSCR_MDI_XOVER_MODE 5 +#define M_PSCR_MDI_XOVER_MODE 0x3 +#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE) +#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE) + +/* Extended PHY specific control register fields */ +#define S_DOWNSHIFT_ENABLE 8 +#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE) + +#define S_DOWNSHIFT_CNT 9 +#define M_DOWNSHIFT_CNT 0x7 +#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT) +#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT) + +/* PHY specific status register fields */ +#define S_PSSR_JABBER 0 +#define V_PSSR_JABBER (1 << S_PSSR_JABBER) + +#define S_PSSR_POLARITY 1 +#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY) + +#define S_PSSR_RX_PAUSE 2 +#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE) + +#define S_PSSR_TX_PAUSE 3 +#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE) + +#define S_PSSR_ENERGY_DETECT 4 +#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT) + +#define S_PSSR_DOWNSHIFT_STATUS 5 +#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS) + +#define S_PSSR_MDI 6 +#define V_PSSR_MDI (1 << S_PSSR_MDI) + +#define S_PSSR_CABLE_LEN 7 +#define M_PSSR_CABLE_LEN 0x7 +#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN) +#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN) + +//#define S_PSSR_LINK 10 +//#define S_PSSR_LINK 13 +#define S_PSSR_LINK 2 +#define V_PSSR_LINK (1 << S_PSSR_LINK) + +//#define S_PSSR_STATUS_RESOLVED 11 +//#define S_PSSR_STATUS_RESOLVED 10 +#define S_PSSR_STATUS_RESOLVED 15 +#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED) + +#define S_PSSR_PAGE_RECEIVED 12 +#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED) + +//#define S_PSSR_DUPLEX 13 +//#define S_PSSR_DUPLEX 12 +#define S_PSSR_DUPLEX 5 +#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX) + +//#define S_PSSR_SPEED 14 +//#define S_PSSR_SPEED 14 +#define S_PSSR_SPEED 3 +#define M_PSSR_SPEED 0x3 +#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED) +#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED) + +#endif diff --git a/trunk/drivers/net/cris/eth_v10.c b/trunk/drivers/net/cris/eth_v10.c index 5bdf5ca85a65..8eb571276000 100644 --- a/trunk/drivers/net/cris/eth_v10.c +++ b/trunk/drivers/net/cris/eth_v10.c @@ -1348,8 +1348,7 @@ e100_rx(struct net_device *dev) #ifdef ETHDEBUG printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb)); + skb->head, skb->data, skb->tail, skb->end); printk("copying packet to 0x%x.\n", skb_data_ptr); #endif @@ -1376,6 +1375,7 @@ e100_rx(struct net_device *dev) myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data)); } + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* Send the packet to the upper layers */ diff --git a/trunk/drivers/net/cs89x0.c b/trunk/drivers/net/cs89x0.c index 9774bb1b3e80..4612f71a7106 100644 --- a/trunk/drivers/net/cs89x0.c +++ b/trunk/drivers/net/cs89x0.c @@ -1004,6 +1004,7 @@ dma_rx(struct net_device *dev) return; } skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; if (bp + length > lp->end_dma_buff) { int semi_cnt = lp->end_dma_buff - bp; @@ -1701,6 +1702,7 @@ net_rx(struct net_device *dev) return; } skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1); if (length & 1) diff --git a/trunk/drivers/net/cxgb3/cxgb3_offload.c b/trunk/drivers/net/cxgb3/cxgb3_offload.c index ebcf35e4cf5b..199e5066acf3 100644 --- a/trunk/drivers/net/cxgb3/cxgb3_offload.c +++ b/trunk/drivers/net/cxgb3/cxgb3_offload.c @@ -783,7 +783,7 @@ static int do_trace(struct t3cdev *dev, struct sk_buff *skb) skb->protocol = htons(0xffff); skb->dev = dev->lldev; skb_pull(skb, sizeof(*p)); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; netif_receive_skb(skb); return 0; } diff --git a/trunk/drivers/net/cxgb3/sge.c b/trunk/drivers/net/cxgb3/sge.c index 3666586a4831..027ab2c3825c 100644 --- a/trunk/drivers/net/cxgb3/sge.c +++ b/trunk/drivers/net/cxgb3/sge.c @@ -661,7 +661,7 @@ static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) if (skb) { __skb_put(skb, IMMED_PKT_SIZE); - skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE); + memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE); } return skb; } @@ -897,11 +897,11 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, d->flit[2] = 0; cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); hdr->cntrl = htonl(cntrl); - eth_type = skb_network_offset(skb) == ETH_HLEN ? + eth_type = skb->nh.raw - skb->data == ETH_HLEN ? CPL_ETH_II : CPL_ETH_II_VLAN; tso_info |= V_LSO_ETH_TYPE(eth_type) | - V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) | - V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff); + V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) | + V_LSO_TCPHDR_WORDS(skb->h.th->doff); hdr->lso_info = htonl(tso_info); flits = 3; } else { @@ -913,8 +913,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, if (skb->len <= WR_LEN - sizeof(*cpl)) { q->sdesc[pidx].skb = NULL; if (!skb->data_len) - skb_copy_from_linear_data(skb, &d->flit[2], - skb->len); + memcpy(&d->flit[2], skb->data, skb->len); else skb_copy_bits(skb, 0, &d->flit[2], skb->len); @@ -1320,19 +1319,16 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, /* Only TX_DATA builds SGLs */ from = (struct work_request_hdr *)skb->data; - memcpy(&d->flit[1], &from[1], - skb_transport_offset(skb) - sizeof(*from)); + memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from)); - flits = skb_transport_offset(skb) / 8; + flits = (skb->h.raw - skb->data) / 8; sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; - sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb), - skb->tail - skb->transport_header, + sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw, adap->pdev); if (need_skb_unmap()) { setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); skb->destructor = deferred_unmap_destructor; - ((struct unmap_info *)skb->cb)->len = (skb->tail - - skb->transport_header); + ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw; } write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, @@ -1353,8 +1349,8 @@ static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) if (skb->len <= WR_LEN && cnt == 0) return 1; /* packet fits as immediate data */ - flits = skb_transport_offset(skb) / 8; /* headers */ - if (skb->tail != skb->transport_header) + flits = (skb->h.raw - skb->data) / 8; /* headers */ + if (skb->tail != skb->h.raw) cnt++; return flits_to_desc(flits + sgl_len(cnt)); } @@ -1624,9 +1620,7 @@ static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, unsigned int gather_idx) { rq->offload_pkts++; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb_reset_transport_header(skb); + skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data; if (rq->polling) { rx_gather[gather_idx++] = skb; @@ -1690,8 +1684,9 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, struct port_info *pi; skb_pull(skb, sizeof(*p) + pad); + skb->dev = adap->port[p->iff]; skb->dev->last_rx = jiffies; - skb->protocol = eth_type_trans(skb, adap->port[p->iff]); + skb->protocol = eth_type_trans(skb, skb->dev); pi = netdev_priv(skb->dev); if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff && !p->fragment) { @@ -1722,11 +1717,11 @@ static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p, { skb->len = len; if (len <= SKB_DATA_SIZE) { - skb_copy_to_linear_data(skb, p->va, len); + memcpy(skb->data, p->va, len); skb->tail += len; put_page(p->frag.page); } else { - skb_copy_to_linear_data(skb, p->va, SKB_DATA_SIZE); + memcpy(skb->data, p->va, SKB_DATA_SIZE); skb_shinfo(skb)->frags[0].page = p->frag.page; skb_shinfo(skb)->frags[0].page_offset = p->frag.page_offset + SKB_DATA_SIZE; @@ -1772,7 +1767,7 @@ static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, __skb_put(skb, len); pci_dma_sync_single_for_cpu(adap->pdev, mapping, len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(sd->t.skb, skb->data, len); + memcpy(skb->data, sd->t.skb->data, len); pci_dma_sync_single_for_device(adap->pdev, mapping, len, PCI_DMA_FROMDEVICE); } else if (!drop_thres) diff --git a/trunk/drivers/net/de600.c b/trunk/drivers/net/de600.c index dae97b860daa..e547ce14eefe 100644 --- a/trunk/drivers/net/de600.c +++ b/trunk/drivers/net/de600.c @@ -359,6 +359,7 @@ static void de600_rx_intr(struct net_device *dev) } /* else */ + skb->dev = dev; skb_reserve(skb,2); /* Align */ /* 'skb->data' points to the start of sk_buff data area. */ diff --git a/trunk/drivers/net/de620.c b/trunk/drivers/net/de620.c index dc4892426174..b6ad0cb50552 100644 --- a/trunk/drivers/net/de620.c +++ b/trunk/drivers/net/de620.c @@ -697,6 +697,7 @@ static int de620_rx_intr(struct net_device *dev) } else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ + skb->dev = dev; /* skb->data points to the start of sk_buff data area */ buffer = skb_put(skb,size); /* copy the packet into the buffer */ diff --git a/trunk/drivers/net/declance.c b/trunk/drivers/net/declance.c index 95d854e2295c..9f7e1db8ce62 100644 --- a/trunk/drivers/net/declance.c +++ b/trunk/drivers/net/declance.c @@ -616,6 +616,7 @@ static int lance_rx(struct net_device *dev) } lp->stats.rx_bytes += len; + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ diff --git a/trunk/drivers/net/defxx.c b/trunk/drivers/net/defxx.c index 571d82f8008c..07d2731c1aa8 100644 --- a/trunk/drivers/net/defxx.c +++ b/trunk/drivers/net/defxx.c @@ -3091,13 +3091,13 @@ static void dfx_rcv_queue_process( { /* Receive buffer allocated, pass receive packet up */ - skb_copy_to_linear_data(skb, - p_buff + RCV_BUFF_K_PADDING, - pkt_len + 3); + memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); } skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ + skb->dev = bp->dev; /* pass up device pointer */ + skb->protocol = fddi_type_trans(skb, bp->dev); bp->rcv_total_bytes += skb->len; netif_rx(skb); diff --git a/trunk/drivers/net/depca.c b/trunk/drivers/net/depca.c index 183497020bfc..5113eef755b9 100644 --- a/trunk/drivers/net/depca.c +++ b/trunk/drivers/net/depca.c @@ -1044,6 +1044,7 @@ static int depca_rx(struct net_device *dev) unsigned char *buf; skb_reserve(skb, 2); /* 16 byte align the IP header */ buf = skb_put(skb, pkt_len); + skb->dev = dev; if (entry < lp->rx_old) { /* Wrapped buffer */ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len); @@ -1490,9 +1491,8 @@ static void __init depca_platform_probe (void) depca_io_ports[i].device = pldev; if (platform_device_add(pldev)) { - depca_io_ports[i].device = NULL; - pldev->dev.platform_data = NULL; platform_device_put(pldev); + depca_io_ports[i].device = NULL; continue; } diff --git a/trunk/drivers/net/dgrs.c b/trunk/drivers/net/dgrs.c index df62c0232f36..a79520295fd0 100644 --- a/trunk/drivers/net/dgrs.c +++ b/trunk/drivers/net/dgrs.c @@ -503,6 +503,7 @@ dgrs_rcv_frame( /* discarding the frame */ goto out; } + skb->dev = devN; skb_reserve(skb, 2); /* Align IP header */ again: @@ -741,7 +742,7 @@ static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN) } amt = min_t(unsigned int, len, rbdp->size - count); - skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt); + memcpy( (char *) S2H(rbdp->buf) + count, skb->data + i, amt); i += amt; count += amt; len -= amt; diff --git a/trunk/drivers/net/dl2k.c b/trunk/drivers/net/dl2k.c index 74ec64a1625d..9d446a0fe0bf 100644 --- a/trunk/drivers/net/dl2k.c +++ b/trunk/drivers/net/dl2k.c @@ -504,6 +504,7 @@ rio_timer (unsigned long data) break; } np->rx_skbuff[entry] = skb; + skb->dev = dev; /* 16 byte align the IP header */ skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = @@ -574,6 +575,7 @@ alloc_list (struct net_device *dev) dev->name); break; } + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve (skb, 2); /* 16 byte align the IP header. */ /* Rubicon now supports 40 bits of addressing space. */ np->rx_ring[i].fraginfo = @@ -864,6 +866,7 @@ receive_packet (struct net_device *dev) DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->dev = dev; /* 16 byte align the IP header */ skb_reserve (skb, 2); eth_copy_and_sum (skb, @@ -907,6 +910,7 @@ receive_packet (struct net_device *dev) break; } np->rx_skbuff[entry] = skb; + skb->dev = dev; /* 16 byte align the IP header */ skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = diff --git a/trunk/drivers/net/dm9000.c b/trunk/drivers/net/dm9000.c index 8cc1174e7f64..615d2b14efa7 100644 --- a/trunk/drivers/net/dm9000.c +++ b/trunk/drivers/net/dm9000.c @@ -954,6 +954,7 @@ dm9000_rx(struct net_device *dev) /* Move data from DM9000 */ if (GoodPacket && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { + skb->dev = dev; skb_reserve(skb, 2); rdptr = (u8 *) skb_put(skb, RxLen - 4); diff --git a/trunk/drivers/net/e100.c b/trunk/drivers/net/e100.c index 61696637a21e..0cefef5e3f06 100644 --- a/trunk/drivers/net/e100.c +++ b/trunk/drivers/net/e100.c @@ -159,7 +159,7 @@ #define DRV_NAME "e100" #define DRV_EXT "-NAPI" -#define DRV_VERSION "3.5.17-k4"DRV_EXT +#define DRV_VERSION "3.5.17-k2"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" #define PFX DRV_NAME ": " @@ -174,13 +174,10 @@ MODULE_VERSION(DRV_VERSION); static int debug = 3; static int eeprom_bad_csum_allow = 0; -static int use_io = 0; module_param(debug, int, 0); module_param(eeprom_bad_csum_allow, int, 0); -module_param(use_io, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums"); -MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); #define DPRINTK(nlevel, klevel, fmt, args...) \ (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ @@ -285,6 +282,12 @@ enum scb_status { rus_mask = 0x3C, }; +enum ru_state { + RU_SUSPENDED = 0, + RU_RUNNING = 1, + RU_UNINITIALIZED = -1, +}; + enum scb_stat_ack { stat_ack_not_ours = 0x00, stat_ack_sw_gen = 0x04, @@ -526,6 +529,7 @@ struct nic { struct rx *rx_to_use; struct rx *rx_to_clean; struct rfd blank_rfd; + enum ru_state ru_running; spinlock_t cb_lock ____cacheline_aligned; spinlock_t cmd_lock; @@ -587,7 +591,7 @@ static inline void e100_write_flush(struct nic *nic) { /* Flush previous PCI writes through intermediate bridges * by doing a benign read */ - (void)ioread8(&nic->csr->scb.status); + (void)readb(&nic->csr->scb.status); } static void e100_enable_irq(struct nic *nic) @@ -595,7 +599,7 @@ static void e100_enable_irq(struct nic *nic) unsigned long flags; spin_lock_irqsave(&nic->cmd_lock, flags); - iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi); + writeb(irq_mask_none, &nic->csr->scb.cmd_hi); e100_write_flush(nic); spin_unlock_irqrestore(&nic->cmd_lock, flags); } @@ -605,7 +609,7 @@ static void e100_disable_irq(struct nic *nic) unsigned long flags; spin_lock_irqsave(&nic->cmd_lock, flags); - iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi); + writeb(irq_mask_all, &nic->csr->scb.cmd_hi); e100_write_flush(nic); spin_unlock_irqrestore(&nic->cmd_lock, flags); } @@ -614,11 +618,11 @@ static void e100_hw_reset(struct nic *nic) { /* Put CU and RU into idle with a selective reset to get * device off of PCI bus */ - iowrite32(selective_reset, &nic->csr->port); + writel(selective_reset, &nic->csr->port); e100_write_flush(nic); udelay(20); /* Now fully reset device */ - iowrite32(software_reset, &nic->csr->port); + writel(software_reset, &nic->csr->port); e100_write_flush(nic); udelay(20); /* Mask off our interrupt line - it's unmasked after reset */ @@ -635,7 +639,7 @@ static int e100_self_test(struct nic *nic) nic->mem->selftest.signature = 0; nic->mem->selftest.result = 0xFFFFFFFF; - iowrite32(selftest | dma_addr, &nic->csr->port); + writel(selftest | dma_addr, &nic->csr->port); e100_write_flush(nic); /* Wait 10 msec for self-test to complete */ msleep(10); @@ -673,23 +677,23 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) for(j = 0; j < 3; j++) { /* Chip select */ - iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); for(i = 31; i >= 0; i--) { ctrl = (cmd_addr_data[j] & (1 << i)) ? eecs | eedi : eecs; - iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); - iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); } /* Wait 10 msec for cmd to complete */ msleep(10); /* Chip deselect */ - iowrite8(0, &nic->csr->eeprom_ctrl_lo); + writeb(0, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); } }; @@ -705,21 +709,21 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) cmd_addr_data = ((op_read << *addr_len) | addr) << 16; /* Chip select */ - iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); /* Bit-bang to read word from eeprom */ for(i = 31; i >= 0; i--) { ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; - iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); - iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); /* Eeprom drives a dummy zero to EEDO after receiving * complete address. Use this to adjust addr_len. */ - ctrl = ioread8(&nic->csr->eeprom_ctrl_lo); + ctrl = readb(&nic->csr->eeprom_ctrl_lo); if(!(ctrl & eedo) && i > 16) { *addr_len -= (i - 16); i = 17; @@ -729,7 +733,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) } /* Chip deselect */ - iowrite8(0, &nic->csr->eeprom_ctrl_lo); + writeb(0, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); return le16_to_cpu(data); @@ -800,7 +804,7 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) /* Previous command is accepted when SCB clears */ for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { - if(likely(!ioread8(&nic->csr->scb.cmd_lo))) + if(likely(!readb(&nic->csr->scb.cmd_lo))) break; cpu_relax(); if(unlikely(i > E100_WAIT_SCB_FAST)) @@ -812,8 +816,8 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) } if(unlikely(cmd != cuc_resume)) - iowrite32(dma_addr, &nic->csr->scb.gen_ptr); - iowrite8(cmd, &nic->csr->scb.cmd_lo); + writel(dma_addr, &nic->csr->scb.gen_ptr); + writeb(cmd, &nic->csr->scb.cmd_lo); err_unlock: spin_unlock_irqrestore(&nic->cmd_lock, flags); @@ -891,7 +895,7 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) */ spin_lock_irqsave(&nic->mdio_lock, flags); for (i = 100; i; --i) { - if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready) + if (readl(&nic->csr->mdi_ctrl) & mdi_ready) break; udelay(20); } @@ -901,11 +905,11 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) spin_unlock_irqrestore(&nic->mdio_lock, flags); return 0; /* No way to indicate timeout error */ } - iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); + writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); for (i = 0; i < 100; i++) { udelay(20); - if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready) + if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) break; } spin_unlock_irqrestore(&nic->mdio_lock, flags); @@ -947,7 +951,7 @@ static void e100_get_defaults(struct nic *nic) ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); /* Template for a freshly allocated RFD */ - nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s); + nic->blank_rfd.command = cpu_to_le16(cb_el); nic->blank_rfd.rbd = 0xFFFFFFFF; nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); @@ -1314,7 +1318,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, } /* ack any interupts, something could have been set */ - iowrite8(~0, &nic->csr->scb.stat_ack); + writeb(~0, &nic->csr->scb.stat_ack); /* if the command failed, or is not OK, notify and return */ if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { @@ -1576,7 +1580,7 @@ static void e100_watchdog(unsigned long data) * accidentally, due to hardware that shares a register between the * interrupt mask bit and the SW Interrupt generation bit */ spin_lock_irq(&nic->cmd_lock); - iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); + writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); e100_write_flush(nic); spin_unlock_irq(&nic->cmd_lock); @@ -1742,11 +1746,19 @@ static int e100_alloc_cbs(struct nic *nic) return 0; } -static inline void e100_start_receiver(struct nic *nic) +static inline void e100_start_receiver(struct nic *nic, struct rx *rx) { - /* Start if RFA is non-NULL */ - if(nic->rx_to_clean->skb) - e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr); + if(!nic->rxs) return; + if(RU_SUSPENDED != nic->ru_running) return; + + /* handle init time starts */ + if(!rx) rx = nic->rxs; + + /* (Re)start RU if suspended or idle and RFA is non-NULL */ + if(rx->skb) { + e100_exec_cmd(nic, ruc_start, rx->dma_addr); + nic->ru_running = RU_RUNNING; + } } #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) @@ -1757,7 +1769,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) /* Align, init, and map the RFD. */ skb_reserve(rx->skb, NET_IP_ALIGN); - skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd)); + memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd)); rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); @@ -1775,7 +1787,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) put_unaligned(cpu_to_le32(rx->dma_addr), (u32 *)&prev_rfd->link); wmb(); - prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s); + prev_rfd->command &= ~cpu_to_le16(cb_el); pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, sizeof(struct rfd), PCI_DMA_TODEVICE); } @@ -1813,6 +1825,10 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, pci_unmap_single(nic->pdev, rx->dma_addr, RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + /* this allows for a fast restart without re-enabling interrupts */ + if(le16_to_cpu(rfd->command) & cb_el) + nic->ru_running = RU_SUSPENDED; + /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); skb_put(skb, actual_size); @@ -1843,18 +1859,45 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, unsigned int work_to_do) { struct rx *rx; + int restart_required = 0; + struct rx *rx_to_start = NULL; + + /* are we already rnr? then pay attention!!! this ensures that + * the state machine progression never allows a start with a + * partially cleaned list, avoiding a race between hardware + * and rx_to_clean when in NAPI mode */ + if(RU_SUSPENDED == nic->ru_running) + restart_required = 1; /* Indicate newly arrived packets */ for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { - if(e100_rx_indicate(nic, rx, work_done, work_to_do)) + int err = e100_rx_indicate(nic, rx, work_done, work_to_do); + if(-EAGAIN == err) { + /* hit quota so have more work to do, restart once + * cleanup is complete */ + restart_required = 0; + break; + } else if(-ENODATA == err) break; /* No more to clean */ } + /* save our starting point as the place we'll restart the receiver */ + if(restart_required) + rx_to_start = nic->rx_to_clean; + /* Alloc new skbs to refill list */ for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { if(unlikely(e100_rx_alloc_skb(nic, rx))) break; /* Better luck next time (see watchdog) */ } + + if(restart_required) { + // ack the rnr? + writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); + e100_start_receiver(nic, rx_to_start); + if(work_done) + (*work_done)++; + } } static void e100_rx_clean_list(struct nic *nic) @@ -1862,6 +1905,8 @@ static void e100_rx_clean_list(struct nic *nic) struct rx *rx; unsigned int i, count = nic->params.rfds.count; + nic->ru_running = RU_UNINITIALIZED; + if(nic->rxs) { for(rx = nic->rxs, i = 0; i < count; rx++, i++) { if(rx->skb) { @@ -1883,6 +1928,7 @@ static int e100_rx_alloc_list(struct nic *nic) unsigned int i, count = nic->params.rfds.count; nic->rx_to_use = nic->rx_to_clean = NULL; + nic->ru_running = RU_UNINITIALIZED; if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC))) return -ENOMEM; @@ -1897,6 +1943,7 @@ static int e100_rx_alloc_list(struct nic *nic) } nic->rx_to_use = nic->rx_to_clean = nic->rxs; + nic->ru_running = RU_SUSPENDED; return 0; } @@ -1905,7 +1952,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id) { struct net_device *netdev = dev_id; struct nic *nic = netdev_priv(netdev); - u8 stat_ack = ioread8(&nic->csr->scb.stat_ack); + u8 stat_ack = readb(&nic->csr->scb.stat_ack); DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); @@ -1914,7 +1961,11 @@ static irqreturn_t e100_intr(int irq, void *dev_id) return IRQ_NONE; /* Ack interrupt(s) */ - iowrite8(stat_ack, &nic->csr->scb.stat_ack); + writeb(stat_ack, &nic->csr->scb.stat_ack); + + /* We hit Receive No Resource (RNR); restart RU after cleaning */ + if(stat_ack & stat_ack_rnr) + nic->ru_running = RU_SUSPENDED; if(likely(netif_rx_schedule_prep(netdev))) { e100_disable_irq(nic); @@ -2007,7 +2058,7 @@ static int e100_up(struct nic *nic) if((err = e100_hw_init(nic))) goto err_clean_cbs; e100_set_multicast_list(nic->netdev); - e100_start_receiver(nic); + e100_start_receiver(nic, NULL); mod_timer(&nic->watchdog, jiffies); if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, nic->netdev->name, nic->netdev))) @@ -2056,7 +2107,7 @@ static void e100_tx_timeout_task(struct work_struct *work) struct net_device *netdev = nic->netdev; DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", - ioread8(&nic->csr->scb.status)); + readb(&nic->csr->scb.status)); e100_down(netdev_priv(netdev)); e100_up(netdev_priv(netdev)); } @@ -2088,7 +2139,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, BMCR_LOOPBACK); - e100_start_receiver(nic); + e100_start_receiver(nic, NULL); if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) { err = -ENOMEM; @@ -2179,9 +2230,9 @@ static void e100_get_regs(struct net_device *netdev, int i; regs->version = (1 << 24) | nic->rev_id; - buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 | - ioread8(&nic->csr->scb.cmd_lo) << 16 | - ioread16(&nic->csr->scb.status); + buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | + readb(&nic->csr->scb.cmd_lo) << 16 | + readw(&nic->csr->scb.status); for(i = E100_PHY_REGS; i >= 0; i--) buff[1 + E100_PHY_REGS - i] = mdio_read(netdev, nic->mii.phy_id, i); @@ -2553,10 +2604,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); - if (use_io) - DPRINTK(PROBE, INFO, "using i/o access mode\n"); - - nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr)); + nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); if(!nic->csr) { DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); err = -ENOMEM; @@ -2603,16 +2651,11 @@ static int __devinit e100_probe(struct pci_dev *pdev, memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); - if (!is_valid_ether_addr(netdev->perm_addr)) { - if (!eeprom_bad_csum_allow) { - DPRINTK(PROBE, ERR, "Invalid MAC address from " - "EEPROM, aborting.\n"); - err = -EAGAIN; - goto err_out_free; - } else { - DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, " - "you MUST configure one.\n"); - } + if(!is_valid_ether_addr(netdev->perm_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; } /* Wol magic packet can be enabled from eeprom */ @@ -2633,7 +2676,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", - (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq, + (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); @@ -2642,7 +2685,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, err_out_free: e100_free(nic); err_out_iounmap: - pci_iounmap(pdev, nic->csr); + iounmap(nic->csr); err_out_free_res: pci_release_regions(pdev); err_out_disable_pdev: diff --git a/trunk/drivers/net/e1000/e1000.h b/trunk/drivers/net/e1000/e1000.h index a9ea67e75c1b..dd4b728ac4b5 100644 --- a/trunk/drivers/net/e1000/e1000.h +++ b/trunk/drivers/net/e1000/e1000.h @@ -155,6 +155,9 @@ struct e1000_adapter; /* Number of packet split data buffers (not including the header buffer) */ #define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1 +/* only works for sizes that are powers of 2 */ +#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct e1000_buffer { diff --git a/trunk/drivers/net/e1000/e1000_ethtool.c b/trunk/drivers/net/e1000/e1000_ethtool.c index bb08375b5f13..6777887295f5 100644 --- a/trunk/drivers/net/e1000/e1000_ethtool.c +++ b/trunk/drivers/net/e1000/e1000_ethtool.c @@ -654,11 +654,14 @@ e1000_set_ringparam(struct net_device *netdev, e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_tx_ring *txdr, *tx_old; struct e1000_rx_ring *rxdr, *rx_old; - int i, err; + int i, err, tx_ring_size, rx_ring_size; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; + rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; + while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) msleep(1); @@ -669,11 +672,11 @@ e1000_set_ringparam(struct net_device *netdev, rx_old = adapter->rx_ring; err = -ENOMEM; - txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL); + txdr = kzalloc(tx_ring_size, GFP_KERNEL); if (!txdr) goto err_alloc_tx; - rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL); + rxdr = kzalloc(rx_ring_size, GFP_KERNEL); if (!rxdr) goto err_alloc_rx; @@ -683,12 +686,12 @@ e1000_set_ringparam(struct net_device *netdev, rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); - rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); + E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD)); - txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); for (i = 0; i < adapter->num_tx_queues; i++) txdr[i].count = txdr->count; @@ -739,7 +742,7 @@ e1000_set_ringparam(struct net_device *netdev, uint32_t pat, value; \ uint32_t test[] = \ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ - for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ + for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ value = E1000_READ_REG(&adapter->hw, R); \ if (value != (test[pat] & W & M)) { \ @@ -1050,24 +1053,23 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; - int i, ret_val; + int size, i, ret_val; /* Setup Tx descriptor ring and Tx buffers */ if (!txdr->count) txdr->count = E1000_DEFAULT_TXD; - if (!(txdr->buffer_info = kcalloc(txdr->count, - sizeof(struct e1000_buffer), - GFP_KERNEL))) { + size = txdr->count * sizeof(struct e1000_buffer); + if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 1; goto err_nomem; } + memset(txdr->buffer_info, 0, size); txdr->size = txdr->count * sizeof(struct e1000_tx_desc); - txdr->size = ALIGN(txdr->size, 4096); - if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, - &txdr->dma))) { + E1000_ROUNDUP(txdr->size, 4096); + if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { ret_val = 2; goto err_nomem; } @@ -1114,12 +1116,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) if (!rxdr->count) rxdr->count = E1000_DEFAULT_RXD; - if (!(rxdr->buffer_info = kcalloc(rxdr->count, - sizeof(struct e1000_buffer), - GFP_KERNEL))) { + size = rxdr->count * sizeof(struct e1000_buffer); + if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 4; goto err_nomem; } + memset(rxdr->buffer_info, 0, size); rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { diff --git a/trunk/drivers/net/e1000/e1000_main.c b/trunk/drivers/net/e1000/e1000_main.c index 3a03a74c0609..b28a915bd980 100644 --- a/trunk/drivers/net/e1000/e1000_main.c +++ b/trunk/drivers/net/e1000/e1000_main.c @@ -409,22 +409,26 @@ e1000_release_hw_control(struct e1000_adapter *adapter) { uint32_t ctrl_ext; uint32_t swsm; + uint32_t extcnf; /* Let firmware taken over control of h/w */ switch (adapter->hw.mac_type) { - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm & ~E1000_SWSM_DRV_LOAD); - break; case e1000_82571: case e1000_82572: case e1000_80003es2lan: - case e1000_ich8lan: ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); break; + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm & ~E1000_SWSM_DRV_LOAD); + case e1000_ich8lan: + extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + extcnf & ~E1000_CTRL_EXT_DRV_LOAD); + break; default: break; } @@ -446,22 +450,27 @@ e1000_get_hw_control(struct e1000_adapter *adapter) { uint32_t ctrl_ext; uint32_t swsm; + uint32_t extcnf; /* Let firmware know the driver has taken over */ switch (adapter->hw.mac_type) { - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm | E1000_SWSM_DRV_LOAD); - break; case e1000_82571: case e1000_82572: case e1000_80003es2lan: - case e1000_ich8lan: ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); break; + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm | E1000_SWSM_DRV_LOAD); + break; + case e1000_ich8lan: + extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL); + E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL, + extcnf | E1000_EXTCNF_CTRL_SWFLAG); + break; default: break; } @@ -513,15 +522,14 @@ e1000_release_manageability(struct e1000_adapter *adapter) } } -/** - * e1000_configure - configure the hardware for RX and TX - * @adapter = private board structure - **/ -static void e1000_configure(struct e1000_adapter *adapter) +int +e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; int i; + /* hardware has been reset, we need to reload some things */ + e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -540,20 +548,14 @@ static void e1000_configure(struct e1000_adapter *adapter) } adapter->tx_queue_len = netdev->tx_queue_len; -} - -int e1000_up(struct e1000_adapter *adapter) -{ - /* hardware has been reset, we need to reload some things */ - e1000_configure(adapter); - - clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(adapter->netdev); + netif_poll_enable(netdev); #endif e1000_irq_enable(adapter); + clear_bit(__E1000_DOWN, &adapter->flags); + /* fire a link change interrupt to start the watchdog */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); return 0; @@ -638,15 +640,15 @@ e1000_down(struct e1000_adapter *adapter) * reschedule our watchdog timer */ set_bit(__E1000_DOWN, &adapter->flags); -#ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); -#endif e1000_irq_disable(adapter); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); +#ifdef CONFIG_E1000_NAPI + netif_poll_disable(netdev); +#endif netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; @@ -748,9 +750,9 @@ e1000_reset(struct e1000_adapter *adapter) VLAN_TAG_SIZE; min_tx_space = min_rx_space; min_tx_space *= 2; - min_tx_space = ALIGN(min_tx_space, 1024); + E1000_ROUNDUP(min_tx_space, 1024); min_tx_space >>= 10; - min_rx_space = ALIGN(min_rx_space, 1024); + E1000_ROUNDUP(min_rx_space, 1024); min_rx_space >>= 10; /* If current Tx allocation is less than the min Tx FIFO size, @@ -1354,27 +1356,31 @@ e1000_sw_init(struct e1000_adapter *adapter) static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) { - adapter->tx_ring = kcalloc(adapter->num_tx_queues, - sizeof(struct e1000_tx_ring), GFP_KERNEL); + int size; + + size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; + adapter->tx_ring = kmalloc(size, GFP_KERNEL); if (!adapter->tx_ring) return -ENOMEM; + memset(adapter->tx_ring, 0, size); - adapter->rx_ring = kcalloc(adapter->num_rx_queues, - sizeof(struct e1000_rx_ring), GFP_KERNEL); + size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; + adapter->rx_ring = kmalloc(size, GFP_KERNEL); if (!adapter->rx_ring) { kfree(adapter->tx_ring); return -ENOMEM; } + memset(adapter->rx_ring, 0, size); #ifdef CONFIG_E1000_NAPI - adapter->polling_netdev = kcalloc(adapter->num_rx_queues, - sizeof(struct net_device), - GFP_KERNEL); + size = sizeof(struct net_device) * adapter->num_rx_queues; + adapter->polling_netdev = kmalloc(size, GFP_KERNEL); if (!adapter->polling_netdev) { kfree(adapter->tx_ring); kfree(adapter->rx_ring); return -ENOMEM; } + memset(adapter->polling_netdev, 0, size); #endif return E1000_SUCCESS; @@ -1404,17 +1410,21 @@ e1000_open(struct net_device *netdev) return -EBUSY; /* allocate transmit descriptors */ - err = e1000_setup_all_tx_resources(adapter); - if (err) + if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* allocate receive descriptors */ - err = e1000_setup_all_rx_resources(adapter); - if (err) + if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + e1000_power_up_phy(adapter); + if ((err = e1000_up(adapter))) + goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { @@ -1427,33 +1437,12 @@ e1000_open(struct net_device *netdev) e1000_check_mng_mode(&adapter->hw)) e1000_get_hw_control(adapter); - /* before we allocate an interrupt, we must be ready to handle it. - * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt - * as soon as we call pci_request_irq, so we have to setup our - * clean_rx handler before we do so. */ - e1000_configure(adapter); - - err = e1000_request_irq(adapter); - if (err) - goto err_req_irq; - - /* From here on the code is the same as e1000_up() */ - clear_bit(__E1000_DOWN, &adapter->flags); - -#ifdef CONFIG_E1000_NAPI - netif_poll_enable(netdev); -#endif - - e1000_irq_enable(adapter); - - /* fire a link status change interrupt to start the watchdog */ - E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); - return E1000_SUCCESS; -err_req_irq: - e1000_release_hw_control(adapter); +err_up: e1000_power_down_phy(adapter); + e1000_free_irq(adapter); +err_req_irq: e1000_free_all_rx_resources(adapter); err_setup_rx: e1000_free_all_tx_resources(adapter); @@ -1556,7 +1545,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, /* round up to nearest 4K */ txdr->size = txdr->count * sizeof(struct e1000_tx_desc); - txdr->size = ALIGN(txdr->size, 4096); + E1000_ROUNDUP(txdr->size, 4096); txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if (!txdr->desc) { @@ -1770,18 +1759,18 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, } memset(rxdr->buffer_info, 0, size); - rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page), - GFP_KERNEL); + size = sizeof(struct e1000_ps_page) * rxdr->count; + rxdr->ps_page = kmalloc(size, GFP_KERNEL); if (!rxdr->ps_page) { vfree(rxdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } + memset(rxdr->ps_page, 0, size); - rxdr->ps_page_dma = kcalloc(rxdr->count, - sizeof(struct e1000_ps_page_dma), - GFP_KERNEL); + size = sizeof(struct e1000_ps_page_dma) * rxdr->count; + rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); if (!rxdr->ps_page_dma) { vfree(rxdr->buffer_info); kfree(rxdr->ps_page); @@ -1789,6 +1778,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } + memset(rxdr->ps_page_dma, 0, size); if (adapter->hw.mac_type <= e1000_82547_rev_2) desc_len = sizeof(struct e1000_rx_desc); @@ -1798,7 +1788,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, /* Round up to nearest 4K */ rxdr->size = rxdr->count * desc_len; - rxdr->size = ALIGN(rxdr->size, 4096); + E1000_ROUNDUP(rxdr->size, 4096); rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); @@ -2662,7 +2652,7 @@ e1000_watchdog(unsigned long data) netif_carrier_on(netdev); netif_wake_queue(netdev); - mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); + mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); adapter->smartspeed = 0; } else { /* make sure the receive unit is started */ @@ -2679,7 +2669,7 @@ e1000_watchdog(unsigned long data) DPRINTK(LINK, INFO, "NIC Link is Down\n"); netif_carrier_off(netdev); netif_stop_queue(netdev); - mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); + mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); /* 80003ES2LAN workaround-- * For packet buffer work-around on link down event; @@ -2731,7 +2721,7 @@ e1000_watchdog(unsigned long data) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); } enum latency_range { @@ -2897,30 +2887,33 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, return err; } - hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->gso_size; if (skb->protocol == htons(ETH_P_IP)) { - struct iphdr *iph = ip_hdr(skb); - iph->tot_len = 0; - iph->check = 0; - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, + IPPROTO_TCP, + 0); cmd_length = E1000_TXD_CMD_IP; - ipcse = skb_transport_offset(skb) - 1; + ipcse = skb->h.raw - skb->data - 1; } else if (skb->protocol == htons(ETH_P_IPV6)) { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + skb->nh.ipv6h->payload_len = 0; + skb->h.th->check = + ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + 0, + IPPROTO_TCP, + 0); ipcse = 0; } - ipcss = skb_network_offset(skb); - ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data; - tucss = skb_transport_offset(skb); - tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + ipcss = skb->nh.raw - skb->data; + ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; + tucss = skb->h.raw - skb->data; + tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | @@ -2961,7 +2954,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, uint8_t css; if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { - css = skb_transport_offset(skb); + css = skb->h.raw - skb->data; i = tx_ring->next_to_use; buffer_info = &tx_ring->buffer_info[i]; @@ -2969,8 +2962,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, context_desc->lower_setup.ip_config = 0; context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = - css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); @@ -3170,7 +3162,7 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb) uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; - skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR); + E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); if (adapter->link_duplex != HALF_DUPLEX) goto no_fifo_stall_required; @@ -3304,7 +3296,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* TSO Workaround for 82571/2/3 Controllers -- if skb->data * points to just header, pull a few bytes of payload from * frags into skb->data */ - hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { switch (adapter->hw.mac_type) { unsigned int pull_size; @@ -3315,7 +3307,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * NOTE: this is a TSO only workaround * if end byte alignment not correct move us * into the next dword */ - if ((unsigned long)(skb_tail_pointer(skb) - 1) & 4) + if ((unsigned long)(skb->tail - 1) & 4) break; /* fall through */ case e1000_82571: @@ -3371,9 +3363,12 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) (adapter->hw.mac_type == e1000_82573)) e1000_transfer_dhcp_info(adapter, skb); - if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) + local_irq_save(flags); + if (!spin_trylock(&tx_ring->tx_lock)) { /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); return NETDEV_TX_LOCKED; + } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ @@ -4232,12 +4227,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); - skb_copy_to_linear_data_offset(new_skb, - -NET_IP_ALIGN, - (skb->data - - NET_IP_ALIGN), - (length + - NET_IP_ALIGN)); + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + length + NET_IP_ALIGN); /* save the skb in buffer_info as good */ buffer_info->skb = skb; skb = new_skb; @@ -4399,7 +4391,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, PCI_DMA_FROMDEVICE); vaddr = kmap_atomic(ps_page->ps_page[0], KM_SKB_DATA_SOFTIRQ); - memcpy(skb_tail_pointer(skb), vaddr, l1); + memcpy(skb->tail, vaddr, l1); kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); pci_dma_sync_single_for_device(pdev, ps_page_dma->ps_page_dma[0], diff --git a/trunk/drivers/net/e1000/e1000_param.c b/trunk/drivers/net/e1000/e1000_param.c index f485874a63f5..f8862e203ac9 100644 --- a/trunk/drivers/net/e1000/e1000_param.c +++ b/trunk/drivers/net/e1000/e1000_param.c @@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_TxDescriptors > bd) { tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt, adapter); - tx_ring->count = ALIGN(tx_ring->count, + E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); } else { tx_ring->count = opt.def; @@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_RxDescriptors > bd) { rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt, adapter); - rx_ring->count = ALIGN(rx_ring->count, + E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); } else { rx_ring->count = opt.def; diff --git a/trunk/drivers/net/eepro.c b/trunk/drivers/net/eepro.c index 39654e1e2bed..b4463094c93a 100644 --- a/trunk/drivers/net/eepro.c +++ b/trunk/drivers/net/eepro.c @@ -1591,6 +1591,7 @@ eepro_rx(struct net_device *dev) break; } + skb->dev = dev; skb_reserve(skb,2); if (lp->version == LAN595) diff --git a/trunk/drivers/net/eepro100.c b/trunk/drivers/net/eepro100.c index 6c267c38df97..e28bb1e38f8d 100644 --- a/trunk/drivers/net/eepro100.c +++ b/trunk/drivers/net/eepro100.c @@ -1793,6 +1793,7 @@ speedo_rx(struct net_device *dev) copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], @@ -1804,9 +1805,8 @@ speedo_rx(struct net_device *dev) eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); #else - skb_copy_from_linear_data(sp->rx_skbuff[entry], - skb_put(skb, pkt_len), - pkt_len); + memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data, + pkt_len); #endif pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD) + pkt_len, diff --git a/trunk/drivers/net/eexpress.c b/trunk/drivers/net/eexpress.c index 7934ea37f944..3868b8031266 100644 --- a/trunk/drivers/net/eexpress.c +++ b/trunk/drivers/net/eexpress.c @@ -115,7 +115,6 @@ #include #include #include -#include #include #include @@ -557,7 +556,7 @@ static void unstick_cu(struct net_device *dev) if (lp->started) { - if (time_after(jiffies, dev->trans_start + 50)) + if ((jiffies - dev->trans_start)>50) { if (lp->tx_link==lp->last_tx_restart) { @@ -613,7 +612,7 @@ static void unstick_cu(struct net_device *dev) } else { - if (time_after(jiffies, lp->init_time + 10)) + if ((jiffies-lp->init_time)>10) { unsigned short status = scb_status(dev); printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n", @@ -777,7 +776,7 @@ static unsigned short eexp_start_irq(struct net_device *dev, static void eexp_cmd_clear(struct net_device *dev) { unsigned long int oldtime = jiffies; - while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10))); + while (scb_rdcmd(dev) && ((jiffies-oldtime)<10)); if (scb_rdcmd(dev)) { printk("%s: command didn't clear\n", dev->name); } @@ -977,6 +976,7 @@ static void eexp_hw_rx_pio(struct net_device *dev) lp->stats.rx_dropped++; break; } + skb->dev = dev; skb_reserve(skb, 2); outw(pbuf+10, ioaddr+READ_PTR); insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1); @@ -1650,7 +1650,7 @@ eexp_set_multicast(struct net_device *dev) #endif oj = jiffies; while ((SCB_CUstat(scb_status(dev)) == 2) && - (time_before(jiffies, oj + 2000))); + ((jiffies-oj) < 2000)); if (SCB_CUstat(scb_status(dev)) == 2) printk("%s: warning, CU didn't stop\n", dev->name); lp->started &= ~(STARTED_CU); diff --git a/trunk/drivers/net/ehea/ehea.h b/trunk/drivers/net/ehea/ehea.h index 602872dbe15f..42295d61ecd8 100644 --- a/trunk/drivers/net/ehea/ehea.h +++ b/trunk/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0058" +#define DRV_VERSION "EHEA_0046" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) @@ -78,7 +78,10 @@ #define EHEA_RQ2_PKT_SIZE 1522 #define EHEA_L_PKT_SIZE 256 /* low latency */ +#define EHEA_POLL_MAX_RWQE 1000 + /* Send completion signaling */ +#define EHEA_SIG_IV_LONG 1 /* Protection Domain Identifier */ #define EHEA_PD_ID 0xaabcdeff @@ -105,7 +108,11 @@ #define EHEA_CACHE_LINE 128 /* Memory Regions */ +#define EHEA_MR_MAX_TX_PAGES 20 +#define EHEA_MR_TX_DATA_PN 3 #define EHEA_MR_ACC_CTRL 0x00800000 +#define EHEA_RWQES_PER_MR_RQ2 10 +#define EHEA_RWQES_PER_MR_RQ3 10 #define EHEA_WATCH_DOG_TIMEOUT 10*HZ @@ -304,7 +311,6 @@ struct ehea_cq { * Memory Region */ struct ehea_mr { - struct ehea_adapter *adapter; u64 handle; u64 vaddr; u32 lkey; @@ -313,12 +319,17 @@ struct ehea_mr { /* * Port state information */ -struct port_stats { +struct port_state { + int poll_max_processed; int poll_receive_errors; + int ehea_poll; int queue_stopped; - int err_tcp_cksum; - int err_ip_cksum; - int err_frame_crc; + int min_swqe_avail; + u64 sqc_stop_sum; + int pkt_send; + int pkt_xmit; + int send_tasklet; + int nwqe; }; #define EHEA_IRQ_NAME_SIZE 20 @@ -337,7 +348,6 @@ struct ehea_q_skb_arr { * Port resources */ struct ehea_port_res { - struct port_stats p_stats; struct ehea_mr send_mr; /* send memory region */ struct ehea_mr recv_mr; /* receive memory region */ spinlock_t xmit_lock; @@ -347,8 +357,9 @@ struct ehea_port_res { struct ehea_qp *qp; struct ehea_cq *send_cq; struct ehea_cq *recv_cq; - struct ehea_eq *eq; - struct net_device *d_netdev; + struct ehea_eq *send_eq; + struct ehea_eq *recv_eq; + spinlock_t send_lock; struct ehea_q_skb_arr rq1_skba; struct ehea_q_skb_arr rq2_skba; struct ehea_q_skb_arr rq3_skba; @@ -358,18 +369,21 @@ struct ehea_port_res { int swqe_refill_th; atomic_t swqe_avail; int swqe_ll_count; + int swqe_count; u32 swqe_id_counter; u64 tx_packets; + struct tasklet_struct send_comp_task; + spinlock_t recv_lock; + struct port_state p_state; u64 rx_packets; u32 poll_counter; }; -#define EHEA_MAX_PORTS 16 struct ehea_adapter { u64 handle; - struct ibmebus_dev *ebus_dev; - struct ehea_port *port[EHEA_MAX_PORTS]; + u8 num_ports; + struct ehea_port *port[16]; struct ehea_eq *neq; /* notification event queue */ struct workqueue_struct *ehea_wq; struct tasklet_struct neq_tasklet; @@ -392,7 +406,7 @@ struct ehea_port { struct net_device *netdev; struct net_device_stats stats; struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; - struct of_device ofdev; /* Open Firmware Device */ + struct device_node *of_dev_node; /* Open Firmware Device Node */ struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ struct vlan_group *vgrp; struct ehea_eq *qp_eq; @@ -401,9 +415,7 @@ struct ehea_port { char int_aff_name[EHEA_IRQ_NAME_SIZE]; int allmulti; /* Indicates IFF_ALLMULTI state */ int promisc; /* Indicates IFF_PROMISC state */ - int num_tx_qps; int num_add_tx_qps; - int num_mcs; int resets; u64 mac_addr; u32 logical_port_id; diff --git a/trunk/drivers/net/ehea/ehea_ethtool.c b/trunk/drivers/net/ehea/ehea_ethtool.c index decec8cfe96b..9f57c2e78ced 100644 --- a/trunk/drivers/net/ehea/ehea_ethtool.c +++ b/trunk/drivers/net/ehea/ehea_ethtool.c @@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_device *dev) static void ehea_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1); + strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1); } static u32 ehea_get_msglevel(struct net_device *dev) @@ -166,23 +166,33 @@ static u32 ehea_get_rx_csum(struct net_device *dev) } static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { + {"poll_max_processed"}, + {"queue_stopped"}, + {"min_swqe_avail"}, + {"poll_receive_err"}, + {"pkt_send"}, + {"pkt_xmit"}, + {"send_tasklet"}, + {"ehea_poll"}, + {"nwqe"}, + {"swqe_available_0"}, {"sig_comp_iv"}, {"swqe_refill_th"}, {"port resets"}, - {"Receive errors"}, - {"TCP cksum errors"}, - {"IP cksum errors"}, - {"Frame cksum errors"}, - {"num SQ stopped"}, - {"SQ stopped"}, - {"PR0 free_swqes"}, - {"PR1 free_swqes"}, - {"PR2 free_swqes"}, - {"PR3 free_swqes"}, - {"PR4 free_swqes"}, - {"PR5 free_swqes"}, - {"PR6 free_swqes"}, - {"PR7 free_swqes"}, + {"rxo"}, + {"rx64"}, + {"rx65"}, + {"rx128"}, + {"rx256"}, + {"rx512"}, + {"rx1024"}, + {"txo"}, + {"tx64"}, + {"tx65"}, + {"tx128"}, + {"tx256"}, + {"tx512"}, + {"tx1024"}, }; static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -201,44 +211,63 @@ static int ehea_get_stats_count(struct net_device *dev) static void ehea_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - int i, k, tmp; + u64 hret; + int i; struct ehea_port *port = netdev_priv(dev); + struct ehea_adapter *adapter = port->adapter; + struct ehea_port_res *pr = &port->port_res[0]; + struct port_state *p_state = &pr->p_state; + struct hcp_ehea_port_cb6 *cb6; for (i = 0; i < ehea_get_stats_count(dev); i++) data[i] = 0; + i = 0; + data[i++] = p_state->poll_max_processed; + data[i++] = p_state->queue_stopped; + data[i++] = p_state->min_swqe_avail; + data[i++] = p_state->poll_receive_errors; + data[i++] = p_state->pkt_send; + data[i++] = p_state->pkt_xmit; + data[i++] = p_state->send_tasklet; + data[i++] = p_state->ehea_poll; + data[i++] = p_state->nwqe; + data[i++] = atomic_read(&port->port_res[0].swqe_avail); data[i++] = port->sig_comp_iv; data[i++] = port->port_res[0].swqe_refill_th; data[i++] = port->resets; - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp += port->port_res[k].p_stats.poll_receive_errors; - data[i++] = tmp; - - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp += port->port_res[k].p_stats.err_tcp_cksum; - data[i++] = tmp; - - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp += port->port_res[k].p_stats.err_ip_cksum; - data[i++] = tmp; - - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp += port->port_res[k].p_stats.err_frame_crc; - data[i++] = tmp; - - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp += port->port_res[k].p_stats.queue_stopped; - data[i++] = tmp; - - for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) - tmp |= port->port_res[k].queue_stopped; - data[i++] = tmp; - - for (k = 0; k < 8; k++) - data[i++] = atomic_read(&port->port_res[k].swqe_avail); + cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb6) { + ehea_error("no mem for cb6"); + return; + } + hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id, + H_PORT_CB6, H_PORT_CB6_ALL, cb6); + if (netif_msg_hw(port)) + ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats"); + + if (hret == H_SUCCESS) { + data[i++] = cb6->rxo; + data[i++] = cb6->rx64; + data[i++] = cb6->rx65; + data[i++] = cb6->rx128; + data[i++] = cb6->rx256; + data[i++] = cb6->rx512; + data[i++] = cb6->rx1024; + data[i++] = cb6->txo; + data[i++] = cb6->tx64; + data[i++] = cb6->tx65; + data[i++] = cb6->tx128; + data[i++] = cb6->tx256; + data[i++] = cb6->tx512; + data[i++] = cb6->tx1024; + } else + ehea_error("query_ehea_port failed"); + + kfree(cb6); } const struct ethtool_ops ehea_ethtool_ops = { diff --git a/trunk/drivers/net/ehea/ehea_main.c b/trunk/drivers/net/ehea/ehea_main.c index c7a5614e66c0..0e4042bc0a48 100644 --- a/trunk/drivers/net/ehea/ehea_main.c +++ b/trunk/drivers/net/ehea/ehea_main.c @@ -51,18 +51,13 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1; static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; static int sq_entries = EHEA_DEF_ENTRIES_SQ; -static int use_mcs = 0; -static int num_tx_qps = EHEA_NUM_TX_QP; module_param(msg_level, int, 0); module_param(rq1_entries, int, 0); module_param(rq2_entries, int, 0); module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); -module_param(use_mcs, int, 0); -module_param(num_tx_qps, int, 0); -MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); MODULE_PARM_DESC(msg_level, "msg_level"); MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " "[2^x - 1], x = [6..14]. Default = " @@ -76,29 +71,6 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 " MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " "[2^x - 1], x = [6..14]. Default = " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); -MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); - -static int port_name_cnt = 0; - -static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, - const struct of_device_id *id); - -static int __devexit ehea_remove(struct ibmebus_dev *dev); - -static struct of_device_id ehea_device_table[] = { - { - .name = "lhea", - .compatible = "IBM,lhea", - }, - {}, -}; - -static struct ibmebus_driver ehea_driver = { - .name = "ehea", - .id_table = ehea_device_table, - .probe = ehea_probe_adapter, - .remove = ehea_remove, -}; void ehea_dump(void *adr, int len, char *msg) { int x; @@ -225,7 +197,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); if (!skb) { ehea_error("%s: no mem for skb/%d wqes filled", - pr->port->netdev->name, i); + dev->name, i); q_skba->os_skbs = fill_wqes - i; ret = -ENOMEM; break; @@ -349,13 +321,6 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, { struct sk_buff *skb; - if (cqe->status & EHEA_CQE_STAT_ERR_TCP) - pr->p_stats.err_tcp_cksum++; - if (cqe->status & EHEA_CQE_STAT_ERR_IP) - pr->p_stats.err_ip_cksum++; - if (cqe->status & EHEA_CQE_STAT_ERR_CRC) - pr->p_stats.err_frame_crc++; - if (netif_msg_rx_err(pr->port)) { ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr); ehea_dump(cqe, sizeof(*cqe), "CQE"); @@ -380,11 +345,10 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } -static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, - struct ehea_port_res *pr, - int *budget) +static int ehea_poll(struct net_device *dev, int *budget) { - struct ehea_port *port = pr->port; + struct ehea_port *port = netdev_priv(dev); + struct ehea_port_res *pr = &port->port_res[0]; struct ehea_qp *qp = pr->qp; struct ehea_cqe *cqe; struct sk_buff *skb; @@ -395,12 +359,14 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, int skb_arr_rq2_len = pr->rq2_skba.len; int skb_arr_rq3_len = pr->rq3_skba.len; int processed, processed_rq1, processed_rq2, processed_rq3; - int wqe_index, last_wqe_index, rq, my_quota, port_reset; + int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset; processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; last_wqe_index = 0; my_quota = min(*budget, dev->quota); + my_quota = min(my_quota, EHEA_POLL_MAX_RWQE); + /* rq0 is low latency RQ */ cqe = ehea_poll_rq1(qp, &wqe_index); while ((my_quota > 0) && cqe) { ehea_inc_rq1(qp); @@ -420,14 +386,13 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, if (unlikely(!skb)) { if (netif_msg_rx_err(port)) ehea_error("LL rq1: skb=NULL"); - - skb = netdev_alloc_skb(port->netdev, + skb = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb) break; } - skb_copy_to_linear_data(skb, ((char*)cqe) + 64, - cqe->num_bytes_transfered - 4); + memcpy(skb->data, ((char*)cqe) + 64, + cqe->num_bytes_transfered - 4); ehea_fill_skb(dev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, @@ -437,7 +402,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq2: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, @@ -447,7 +412,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq3: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq3++; } @@ -456,8 +421,9 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, cqe->vlan_tag); else netif_receive_skb(skb); - } else { - pr->p_stats.poll_receive_errors++; + + } else { /* Error occured */ + pr->p_state.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, &processed_rq2, &processed_rq3); @@ -467,32 +433,72 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, cqe = ehea_poll_rq1(qp, &wqe_index); } - pr->rx_packets += processed; + dev->quota -= processed; *budget -= processed; + pr->p_state.ehea_poll += 1; + pr->rx_packets += processed; + ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); - cqe = ehea_poll_rq1(qp, &wqe_index); - return cqe; + intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF); + + if (!cqe || intreq) { + netif_rx_complete(dev); + ehea_reset_cq_ep(pr->recv_cq); + ehea_reset_cq_n1(pr->recv_cq); + cqe = hw_qeit_get_valid(&qp->hw_rqueue1); + if (!cqe || intreq) + return 0; + if (!netif_rx_reschedule(dev, my_quota)) + return 0; + } + return 1; } -static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) +void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) { struct sk_buff *skb; + int index, max_index_mask, i; + + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); + max_index_mask = pr->sq_skba.len - 1; + for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) { + skb = pr->sq_skba.arr[index]; + if (likely(skb)) { + dev_kfree_skb(skb); + pr->sq_skba.arr[index] = NULL; + } else { + ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d", + cqe->wr_id, i, index); + } + index--; + index &= max_index_mask; + } +} + +#define MAX_SENDCOMP_QUOTA 400 +void ehea_send_irq_tasklet(unsigned long data) +{ + struct ehea_port_res *pr = (struct ehea_port_res*)data; struct ehea_cq *send_cq = pr->send_cq; struct ehea_cqe *cqe; - int quota = my_quota; + int quota = MAX_SENDCOMP_QUOTA; int cqe_counter = 0; int swqe_av = 0; - int index; unsigned long flags; - cqe = ehea_poll_cq(send_cq); - while(cqe && (quota > 0)) { - ehea_inc_cq(send_cq); - + do { + cqe = ehea_poll_cq(send_cq); + if (!cqe) { + ehea_reset_cq_ep(send_cq); + ehea_reset_cq_n1(send_cq); + cqe = ehea_poll_cq(send_cq); + if (!cqe) + break; + } cqe_counter++; rmb(); if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { @@ -508,25 +514,17 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) ehea_dump(cqe, sizeof(*cqe), "CQE"); if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) - == EHEA_SWQE2_TYPE)) { - - index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); - skb = pr->sq_skba.arr[index]; - dev_kfree_skb(skb); - pr->sq_skba.arr[index] = NULL; - } + == EHEA_SWQE2_TYPE)) + free_sent_skbs(cqe, pr); swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); quota--; - - cqe = ehea_poll_cq(send_cq); - }; + } while (quota > 0); ehea_update_feca(send_cq, cqe_counter); atomic_add(swqe_av, &pr->swqe_avail); spin_lock_irqsave(&pr->netif_queue, flags); - if (pr->queue_stopped && (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th)) { netif_wake_queue(pr->port->netdev); @@ -534,55 +532,22 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) } spin_unlock_irqrestore(&pr->netif_queue, flags); - return cqe; + if (unlikely(cqe)) + tasklet_hi_schedule(&pr->send_comp_task); } -#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 - -static int ehea_poll(struct net_device *dev, int *budget) +static irqreturn_t ehea_send_irq_handler(int irq, void *param) { - struct ehea_port_res *pr = dev->priv; - struct ehea_cqe *cqe; - struct ehea_cqe *cqe_skb = NULL; - int force_irq, wqe_index; - - cqe = ehea_poll_rq1(pr->qp, &wqe_index); - cqe_skb = ehea_poll_cq(pr->send_cq); - - force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); - - if ((!cqe && !cqe_skb) || force_irq) { - pr->poll_counter = 0; - netif_rx_complete(dev); - ehea_reset_cq_ep(pr->recv_cq); - ehea_reset_cq_ep(pr->send_cq); - ehea_reset_cq_n1(pr->recv_cq); - ehea_reset_cq_n1(pr->send_cq); - cqe = ehea_poll_rq1(pr->qp, &wqe_index); - cqe_skb = ehea_poll_cq(pr->send_cq); - - if (!cqe && !cqe_skb) - return 0; - - if (!netif_rx_reschedule(dev, dev->quota)) - return 0; - } - - cqe = ehea_proc_rwqes(dev, pr, budget); - cqe_skb = ehea_proc_cqes(pr, 300); - - if (cqe || cqe_skb) - pr->poll_counter++; - - return 1; + struct ehea_port_res *pr = param; + tasklet_hi_schedule(&pr->send_comp_task); + return IRQ_HANDLED; } static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - - netif_rx_schedule(pr->d_netdev); - + struct ehea_port *port = pr->port; + netif_rx_schedule(port->netdev); return IRQ_HANDLED; } @@ -615,7 +580,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, { int i; - for (i = 0; i < EHEA_MAX_PORTS; i++) + for (i = 0; i < adapter->num_ports; i++) if (adapter->port[i]) if (adapter->port[i]->logical_port_id == logical_port) return adapter->port[i]; @@ -685,25 +650,19 @@ int ehea_sense_port_attr(struct ehea_port *port) } port->autoneg = 1; - port->num_mcs = cb0->num_default_qps; /* Number of default QPs */ - if (use_mcs) - port->num_def_qps = cb0->num_default_qps; - else - port->num_def_qps = 1; + port->num_def_qps = cb0->num_default_qps; if (!port->num_def_qps) { ret = -EINVAL; goto out_free; } - port->num_tx_qps = num_tx_qps; - - if (port->num_def_qps >= port->num_tx_qps) + if (port->num_def_qps >= EHEA_NUM_TX_QP) port->num_add_tx_qps = 0; else - port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps; + port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps; ret = 0; out_free: @@ -923,6 +882,23 @@ static int ehea_reg_interrupts(struct net_device *dev) struct ehea_port_res *pr; int i, ret; + for (i = 0; i < port->num_def_qps; i++) { + pr = &port->port_res[i]; + snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1 + , "%s-recv%d", dev->name, i); + ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1, + ehea_recv_irq_handler, + IRQF_DISABLED, pr->int_recv_name, pr); + if (ret) { + ehea_error("failed registering irq for ehea_recv_int:" + "port_res_nr:%d, ist=%X", i, + pr->recv_eq->attr.ist1); + goto out_free_seq; + } + if (netif_msg_ifup(port)) + ehea_info("irq_handle 0x%X for funct ehea_recv_int %d " + "registered", pr->recv_eq->attr.ist1, i); + } snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", dev->name); @@ -940,41 +916,41 @@ static int ehea_reg_interrupts(struct net_device *dev) ehea_info("irq_handle 0x%X for function qp_aff_irq_handler " "registered", port->qp_eq->attr.ist1); - for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, - "%s-queue%d", dev->name, i); - ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1, - ehea_recv_irq_handler, + "%s-send%d", dev->name, i); + ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1, + ehea_send_irq_handler, IRQF_DISABLED, pr->int_send_name, pr); if (ret) { - ehea_error("failed registering irq for ehea_queue " + ehea_error("failed registering irq for ehea_send " "port_res_nr:%d, ist=%X", i, - pr->eq->attr.ist1); + pr->send_eq->attr.ist1); goto out_free_req; } if (netif_msg_ifup(port)) - ehea_info("irq_handle 0x%X for function ehea_queue_int " - "%d registered", pr->eq->attr.ist1, i); + ehea_info("irq_handle 0x%X for function ehea_send_int " + "%d registered", pr->send_eq->attr.ist1, i); } out: return ret; - out_free_req: while (--i >= 0) { - u32 ist = port->port_res[i].eq->attr.ist1; + u32 ist = port->port_res[i].send_eq->attr.ist1; ibmebus_free_irq(NULL, ist, &port->port_res[i]); } - out_free_qpeq: ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port); i = port->num_def_qps; - +out_free_seq: + while (--i >= 0) { + u32 ist = port->port_res[i].recv_eq->attr.ist1; + ibmebus_free_irq(NULL, ist, &port->port_res[i]); + } goto out; - } static void ehea_free_interrupts(struct net_device *dev) @@ -984,13 +960,21 @@ static void ehea_free_interrupts(struct net_device *dev) int i; /* send */ - for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; - ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr); + ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr); if (netif_msg_intr(port)) ehea_info("free send irq for res %d with handle 0x%X", - i, pr->eq->attr.ist1); + i, pr->send_eq->attr.ist1); + } + + /* receive */ + for (i = 0; i < port->num_def_qps; i++) { + pr = &port->port_res[i]; + ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr); + if (netif_msg_intr(port)) + ehea_info("free recv irq for res %d with handle 0x%X", + i, pr->recv_eq->attr.ist1); } /* associated events */ @@ -1019,13 +1003,8 @@ static int ehea_configure_port(struct ehea_port *port) PXLY_RC_VLAN_FILTER) | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); - for (i = 0; i < port->num_mcs; i++) - if (use_mcs) - cb0->default_qpn_arr[i] = - port->port_res[i].qp->init_attr.qp_nr; - else - cb0->default_qpn_arr[i] = - port->port_res[0].qp->init_attr.qp_nr; + for (i = 0; i < port->num_def_qps; i++) + cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; if (netif_msg_ifup(port)) ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); @@ -1048,35 +1027,52 @@ static int ehea_configure_port(struct ehea_port *port) return ret; } -int ehea_gen_smrs(struct ehea_port_res *pr) +static int ehea_gen_smrs(struct ehea_port_res *pr) { - int ret; + u64 hret; struct ehea_adapter *adapter = pr->port->adapter; - ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr); - if (ret) + hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, + adapter->mr.vaddr, EHEA_MR_ACC_CTRL, + adapter->pd, &pr->send_mr); + if (hret != H_SUCCESS) goto out; - ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr); - if (ret) - goto out_free; + hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, + adapter->mr.vaddr, EHEA_MR_ACC_CTRL, + adapter->pd, &pr->recv_mr); + if (hret != H_SUCCESS) + goto out_freeres; return 0; -out_free: - ehea_rem_mr(&pr->send_mr); +out_freeres: + hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); + if (hret != H_SUCCESS) + ehea_error("failed freeing SMR"); out: - ehea_error("Generating SMRS failed\n"); return -EIO; } -int ehea_rem_smrs(struct ehea_port_res *pr) +static int ehea_rem_smrs(struct ehea_port_res *pr) { - if ((ehea_rem_mr(&pr->send_mr)) - || (ehea_rem_mr(&pr->recv_mr))) - return -EIO; - else - return 0; + struct ehea_adapter *adapter = pr->port->adapter; + int ret = 0; + u64 hret; + + hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); + if (hret != H_SUCCESS) { + ret = -EIO; + ehea_error("failed freeing send SMR for pr=%p", pr); + } + + hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle); + if (hret != H_SUCCESS) { + ret = -EIO; + ehea_error("failed freeing recv SMR for pr=%p", pr); + } + + return ret; } static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) @@ -1107,17 +1103,25 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, memset(pr, 0, sizeof(struct ehea_port_res)); pr->port = port; + spin_lock_init(&pr->send_lock); + spin_lock_init(&pr->recv_lock); spin_lock_init(&pr->xmit_lock); spin_lock_init(&pr->netif_queue); - pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); - if (!pr->eq) { - ehea_error("create_eq failed (eq)"); + pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); + if (!pr->recv_eq) { + ehea_error("create_eq failed (recv_eq)"); + goto out_free; + } + + pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); + if (!pr->send_eq) { + ehea_error("create_eq failed (send_eq)"); goto out_free; } pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, - pr->eq->fw_handle, + pr->recv_eq->fw_handle, port->logical_port_id); if (!pr->recv_cq) { ehea_error("create_cq failed (cq_recv)"); @@ -1125,7 +1129,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, } pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, - pr->eq->fw_handle, + pr->send_eq->fw_handle, port->logical_port_id); if (!pr->send_cq) { ehea_error("create_cq failed (cq_send)"); @@ -1190,20 +1194,11 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, ret = -EIO; goto out_free; } - + tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet, + (unsigned long)pr); atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); kfree(init_attr); - - pr->d_netdev = alloc_netdev(0, "", ether_setup); - if (!pr->d_netdev) - goto out_free; - pr->d_netdev->priv = pr; - pr->d_netdev->weight = 64; - pr->d_netdev->poll = ehea_poll; - set_bit(__LINK_STATE_START, &pr->d_netdev->state); - strcpy(pr->d_netdev->name, port->netdev->name); - ret = 0; goto out; @@ -1216,7 +1211,8 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, ehea_destroy_qp(pr->qp); ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->eq); + ehea_destroy_eq(pr->send_eq); + ehea_destroy_eq(pr->recv_eq); out: return ret; } @@ -1225,14 +1221,13 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) { int ret, i; - free_netdev(pr->d_netdev); - ret = ehea_destroy_qp(pr->qp); if (!ret) { ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->eq); + ehea_destroy_eq(pr->send_eq); + ehea_destroy_eq(pr->recv_eq); for (i = 0; i < pr->rq1_skba.len; i++) if (pr->rq1_skba.arr[i]) @@ -1267,8 +1262,8 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) static inline void write_ip_start_end(struct ehea_swqe *swqe, const struct sk_buff *skb) { - swqe->ip_start = skb_network_offset(skb); - swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1); + swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data)); + swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1); } static inline void write_tcp_offset_end(struct ehea_swqe *swqe, @@ -1305,13 +1300,13 @@ static void write_swqe2_TSO(struct sk_buff *skb, /* copy only eth/ip/tcp headers to immediate data and * the rest of skb->data to sg1entry */ - headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); + headersize = ETH_HLEN + (skb->nh.iph->ihl * 4) + (skb->h.th->doff * 4); skb_data_size = skb->len - skb->data_len; if (skb_data_size >= headersize) { /* copy immediate data */ - skb_copy_from_linear_data(skb, imm_data, headersize); + memcpy(imm_data, skb->data, headersize); swqe->immediate_data_length = headersize; if (skb_data_size > headersize) { @@ -1342,7 +1337,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb, */ if (skb_data_size >= SWQE2_MAX_IMM) { /* copy immediate data */ - skb_copy_from_linear_data(skb, imm_data, SWQE2_MAX_IMM); + memcpy(imm_data, skb->data, SWQE2_MAX_IMM); swqe->immediate_data_length = SWQE2_MAX_IMM; @@ -1355,7 +1350,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb, swqe->descriptors++; } } else { - skb_copy_from_linear_data(skb, imm_data, skb_data_size); + memcpy(imm_data, skb->data, skb_data_size); swqe->immediate_data_length = skb_data_size; } } @@ -1693,7 +1688,6 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, struct ehea_swqe *swqe, u32 lkey) { if (skb->protocol == htons(ETH_P_IP)) { - const struct iphdr *iph = ip_hdr(skb); /* IPv4 */ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IP_CHECKSUM @@ -1703,15 +1697,15 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, write_ip_start_end(swqe, skb); - if (iph->protocol == IPPROTO_UDP) { - if ((iph->frag_off & IP_MF) || - (iph->frag_off & IP_OFFSET)) + if (skb->nh.iph->protocol == IPPROTO_UDP) { + if ((skb->nh.iph->frag_off & IP_MF) || + (skb->nh.iph->frag_off & IP_OFFSET)) /* IP fragment, so don't change cs */ swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM; else write_udp_offset_end(swqe, skb); - } else if (iph->protocol == IPPROTO_TCP) { + } else if (skb->nh.iph->protocol == IPPROTO_TCP) { write_tcp_offset_end(swqe, skb); } @@ -1737,11 +1731,10 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, int i; if (skb->protocol == htons(ETH_P_IP)) { - const struct iphdr *iph = ip_hdr(skb); /* IPv4 */ write_ip_start_end(swqe, skb); - if (iph->protocol == IPPROTO_TCP) { + if (skb->nh.iph->protocol == IPPROTO_TCP) { swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IP_CHECKSUM | EHEA_SWQE_TCP_CHECKSUM @@ -1749,9 +1742,9 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, write_tcp_offset_end(swqe, skb); - } else if (iph->protocol == IPPROTO_UDP) { - if ((iph->frag_off & IP_MF) || - (iph->frag_off & IP_OFFSET)) + } else if (skb->nh.iph->protocol == IPPROTO_UDP) { + if ((skb->nh.iph->frag_off & IP_MF) || + (skb->nh.iph->frag_off & IP_OFFSET)) /* IP fragment, so don't change cs */ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT; @@ -1777,11 +1770,10 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, /* copy (immediate) data */ if (nfrags == 0) { /* data is in a single piece */ - skb_copy_from_linear_data(skb, imm_data, skb->len); + memcpy(imm_data, skb->data, skb->len); } else { /* first copy data from the skb->data buffer ... */ - skb_copy_from_linear_data(skb, imm_data, - skb->len - skb->data_len); + memcpy(imm_data, skb->data, skb->len - skb->data_len); imm_data += skb->len - skb->data_len; /* ... then copy data from the fragments */ @@ -1797,22 +1789,6 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, dev_kfree_skb(skb); } -static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps) -{ - struct tcphdr *tcp; - u32 tmp; - - if ((skb->protocol == htons(ETH_P_IP)) && - (skb->nh.iph->protocol == IPPROTO_TCP)) { - tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4)); - tmp = (tcp->source + (tcp->dest << 16)) % 31; - tmp += skb->nh.iph->daddr % 31; - return tmp % num_qps; - } - else - return 0; -} - static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); @@ -1820,17 +1796,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; u32 lkey; int swqe_index; - struct ehea_port_res *pr; - - pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)]; + struct ehea_port_res *pr = &port->port_res[0]; - if (!spin_trylock(&pr->xmit_lock)) - return NETDEV_TX_BUSY; - - if (pr->queue_stopped) { - spin_unlock(&pr->xmit_lock); - return NETDEV_TX_BUSY; - } + spin_lock(&pr->xmit_lock); swqe = ehea_get_swqe(pr->qp, &swqe_index); memset(swqe, 0, SWQE_HEADER_SIZE); @@ -1853,7 +1821,6 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE) | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter) - | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1) | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index); pr->sq_skba.arr[pr->sq_skba.index] = skb; @@ -1862,7 +1829,14 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) lkey = pr->send_mr.lkey; ehea_xmit2(skb, dev, swqe, lkey); - swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; + + if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) { + swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL, + EHEA_SIG_IV_LONG); + swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; + pr->swqe_count = 0; + } else + pr->swqe_count += 1; } pr->swqe_id_counter += 1; @@ -1882,7 +1856,6 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { spin_lock_irqsave(&pr->netif_queue, flags); if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { - pr->p_stats.queue_stopped++; netif_stop_queue(dev); pr->queue_stopped = 1; } @@ -2084,7 +2057,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps, } pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; - pr_cfg.max_entries_scq = sq_entries * 2; + pr_cfg.max_entries_scq = sq_entries; pr_cfg.max_entries_sq = sq_entries; pr_cfg.max_entries_rq1 = rq1_entries; pr_cfg.max_entries_rq2 = rq2_entries; @@ -2133,28 +2106,6 @@ static int ehea_clean_all_portres(struct ehea_port *port) return ret; } -static void ehea_remove_adapter_mr (struct ehea_adapter *adapter) -{ - int i; - - for (i=0; i < EHEA_MAX_PORTS; i++) - if (adapter->port[i]) - return; - - ehea_rem_mr(&adapter->mr); -} - -static int ehea_add_adapter_mr (struct ehea_adapter *adapter) -{ - int i; - - for (i=0; i < EHEA_MAX_PORTS; i++) - if (adapter->port[i]) - return 0; - - return ehea_reg_kernel_mr(adapter, &adapter->mr); -} - static int ehea_up(struct net_device *dev) { int ret, i; @@ -2254,10 +2205,8 @@ static int ehea_down(struct net_device *dev) ehea_drop_multicast_list(dev); ehea_free_interrupts(dev); - for (i = 0; i < port->num_def_qps; i++) - while (test_bit(__LINK_STATE_RX_SCHED, - &port->port_res[i].d_netdev->state)) - msleep(1); + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) + tasklet_kill(&port->port_res[i].send_comp_task); ehea_broadcast_reg_helper(port, H_DEREG_BCMC); ret = ehea_clean_all_portres(port); @@ -2324,6 +2273,8 @@ static void ehea_tx_watchdog(struct net_device *dev) int ehea_sense_adapter_attr(struct ehea_adapter *adapter) { struct hcp_query_ehea *cb; + struct device_node *lhea_dn = NULL; + struct device_node *eth_dn = NULL; u64 hret; int ret; @@ -2340,6 +2291,18 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) goto out_herr; } + /* Determine the number of available logical ports + * by counting the child nodes of the lhea OFDT entry + */ + adapter->num_ports = 0; + lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); + do { + eth_dn = of_get_next_child(lhea_dn, eth_dn); + if (eth_dn) + adapter->num_ports++; + } while ( eth_dn ); + of_node_put(lhea_dn); + adapter->max_mc_mac = cb->max_mc_mac - 1; ret = 0; @@ -2349,188 +2312,79 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) return ret; } -int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) +static int ehea_setup_single_port(struct ehea_port *port, + struct device_node *dn) { - struct hcp_ehea_port_cb4 *cb4; + int ret; u64 hret; - int ret = 0; + struct net_device *dev = port->netdev; + struct ehea_adapter *adapter = port->adapter; + struct hcp_ehea_port_cb4 *cb4; + u32 *dn_log_port_id; + int jumbo = 0; - *jumbo = 0; + sema_init(&port->port_lock, 1); + port->state = EHEA_PORT_DOWN; + port->sig_comp_iv = sq_entries / 10; - /* (Try to) enable *jumbo frames */ - cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!cb4) { - ehea_error("no mem for cb4"); - ret = -ENOMEM; + if (!dn) { + ehea_error("bad device node: dn=%p", dn); + ret = -EINVAL; goto out; - } else { - hret = ehea_h_query_ehea_port(port->adapter->handle, - port->logical_port_id, - H_PORT_CB4, - H_PORT_CB4_JUMBO, cb4); - if (hret == H_SUCCESS) { - if (cb4->jumbo_frame) - *jumbo = 1; - else { - cb4->jumbo_frame = 1; - hret = ehea_h_modify_ehea_port(port->adapter-> - handle, - port-> - logical_port_id, - H_PORT_CB4, - H_PORT_CB4_JUMBO, - cb4); - if (hret == H_SUCCESS) - *jumbo = 1; - } - } else - ret = -EINVAL; - - kfree(cb4); - } -out: - return ret; -} - -static ssize_t ehea_show_port_id(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); - return sprintf(buf, "0x%X", port->logical_port_id); -} - -static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id, - NULL); - -static void __devinit logical_port_release(struct device *dev) -{ - struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); - of_node_put(port->ofdev.node); -} - -static int ehea_driver_sysfs_add(struct device *dev, - struct device_driver *driver) -{ - int ret; - - ret = sysfs_create_link(&driver->kobj, &dev->kobj, - kobject_name(&dev->kobj)); - if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &driver->kobj, - "driver"); - if (ret) - sysfs_remove_link(&driver->kobj, - kobject_name(&dev->kobj)); - } - return ret; -} - -static void ehea_driver_sysfs_remove(struct device *dev, - struct device_driver *driver) -{ - struct device_driver *drv = driver; - - if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); - sysfs_remove_link(&dev->kobj, "driver"); } -} -static struct device *ehea_register_port(struct ehea_port *port, - struct device_node *dn) -{ - int ret; + port->of_dev_node = dn; - port->ofdev.node = of_node_get(dn); - port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; - port->ofdev.dev.bus = &ibmebus_bus_type; + /* Determine logical port id */ + dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL); - sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++); - port->ofdev.dev.release = logical_port_release; - - ret = of_device_register(&port->ofdev); - if (ret) { - ehea_error("failed to register device. ret=%d", ret); + if (!dn_log_port_id) { + ehea_error("bad device node: dn_log_port_id=%p", + dn_log_port_id); + ret = -EINVAL; goto out; } - - ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); - if (ret) { - ehea_error("failed to register attributes, ret=%d", ret); - goto out_unreg_of_dev; - } - - ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver); - if (ret) { - ehea_error("failed to register sysfs driver link"); - goto out_rem_dev_file; - } - - return &port->ofdev.dev; - -out_rem_dev_file: - device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); -out_unreg_of_dev: - of_device_unregister(&port->ofdev); -out: - return NULL; -} - -static void ehea_unregister_port(struct ehea_port *port) -{ - ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver); - device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); - of_device_unregister(&port->ofdev); -} - -struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, - u32 logical_port_id, - struct device_node *dn) -{ - int ret; - struct net_device *dev; - struct ehea_port *port; - struct device *port_dev; - int jumbo; - - /* allocate memory for the port structures */ - dev = alloc_etherdev(sizeof(struct ehea_port)); - - if (!dev) { - ehea_error("no mem for net_device"); - ret = -ENOMEM; - goto out_err; - } - - port = netdev_priv(dev); - - sema_init(&port->port_lock, 1); - port->state = EHEA_PORT_DOWN; - port->sig_comp_iv = sq_entries / 10; - - port->adapter = adapter; - port->netdev = dev; - port->logical_port_id = logical_port_id; - - port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); + port->logical_port_id = *dn_log_port_id; port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); if (!port->mc_list) { ret = -ENOMEM; - goto out_free_ethdev; + goto out; } INIT_LIST_HEAD(&port->mc_list->list); ret = ehea_sense_port_attr(port); if (ret) - goto out_free_mc_list; + goto out; - port_dev = ehea_register_port(port, dn); - if (!port_dev) - goto out_free_mc_list; + /* Enable Jumbo frames */ + cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb4) { + ehea_error("no mem for cb4"); + } else { + hret = ehea_h_query_ehea_port(adapter->handle, + port->logical_port_id, + H_PORT_CB4, + H_PORT_CB4_JUMBO, cb4); - SET_NETDEV_DEV(dev, port_dev); + if (hret == H_SUCCESS) { + if (cb4->jumbo_frame) + jumbo = 1; + else { + cb4->jumbo_frame = 1; + hret = ehea_h_modify_ehea_port(adapter->handle, + port-> + logical_port_id, + H_PORT_CB4, + H_PORT_CB4_JUMBO, + cb4); + if (hret == H_SUCCESS) + jumbo = 1; + } + } + kfree(cb4); + } /* initialize net_device structure */ SET_MODULE_OWNER(dev); @@ -2563,225 +2417,84 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, ret = register_netdev(dev); if (ret) { ehea_error("register_netdev failed. ret=%d", ret); - goto out_unreg_port; + goto out_free; } - ret = ehea_get_jumboframe_status(port, &jumbo); - if (ret) - ehea_error("failed determining jumbo frame status for %s", - port->netdev->name); - ehea_info("%s: Jumbo frames are %sabled", dev->name, jumbo == 1 ? "en" : "dis"); - return port; - -out_unreg_port: - ehea_unregister_port(port); - -out_free_mc_list: - kfree(port->mc_list); - -out_free_ethdev: - free_netdev(dev); - -out_err: - ehea_error("setting up logical port with id=%d failed, ret=%d", - logical_port_id, ret); - return NULL; -} + port->netdev = dev; + ret = 0; + goto out; -static void ehea_shutdown_single_port(struct ehea_port *port) -{ - unregister_netdev(port->netdev); - ehea_unregister_port(port); +out_free: kfree(port->mc_list); - free_netdev(port->netdev); +out: + return ret; } static int ehea_setup_ports(struct ehea_adapter *adapter) { - struct device_node *lhea_dn; - struct device_node *eth_dn = NULL; - - u32 *dn_log_port_id; - int i = 0; - - lhea_dn = adapter->ebus_dev->ofdev.node; - while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - - dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", - NULL); - if (!dn_log_port_id) { - ehea_error("bad device node: eth_dn name=%s", - eth_dn->full_name); - continue; - } - - if (ehea_add_adapter_mr(adapter)) { - ehea_error("creating MR failed"); - of_node_put(eth_dn); - return -EIO; - } - - adapter->port[i] = ehea_setup_single_port(adapter, - *dn_log_port_id, - eth_dn); - if (adapter->port[i]) - ehea_info("%s -> logical port id #%d", - adapter->port[i]->netdev->name, - *dn_log_port_id); - else - ehea_remove_adapter_mr(adapter); - - i++; - }; - - return 0; -} - -static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, - u32 logical_port_id) -{ - struct device_node *lhea_dn; - struct device_node *eth_dn = NULL; - u32 *dn_log_port_id; - - lhea_dn = adapter->ebus_dev->ofdev.node; - while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - - dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", - NULL); - if (dn_log_port_id) - if (*dn_log_port_id == logical_port_id) - return eth_dn; - }; - - return NULL; -} - -static ssize_t ehea_probe_port(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ehea_adapter *adapter = dev->driver_data; + int ret; + int port_setup_ok = 0; struct ehea_port *port; - struct device_node *eth_dn = NULL; + struct device_node *dn = NULL; + struct net_device *dev; int i; - u32 logical_port_id; - - sscanf(buf, "%X", &logical_port_id); - - port = ehea_get_port(adapter, logical_port_id); - - if (port) { - ehea_info("adding port with logical port id=%d failed. port " - "already configured as %s.", logical_port_id, - port->netdev->name); - return -EINVAL; - } - - eth_dn = ehea_get_eth_dn(adapter, logical_port_id); - - if (!eth_dn) { - ehea_info("no logical port with id %d found", logical_port_id); - return -EINVAL; - } - - if (ehea_add_adapter_mr(adapter)) { - ehea_error("creating MR failed"); - return -EIO; - } - - port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); - - of_node_put(eth_dn); + /* get port properties for all ports */ + for (i = 0; i < adapter->num_ports; i++) { - if (port) { - for (i=0; i < EHEA_MAX_PORTS; i++) - if (!adapter->port[i]) { - adapter->port[i] = port; - break; - } - - ehea_info("added %s (logical port id=%d)", port->netdev->name, - logical_port_id); - } else { - ehea_remove_adapter_mr(adapter); - return -EIO; - } - - return (ssize_t) count; -} - -static ssize_t ehea_remove_port(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ehea_adapter *adapter = dev->driver_data; - struct ehea_port *port; - int i; - u32 logical_port_id; - - sscanf(buf, "%X", &logical_port_id); + if (adapter->port[i]) + continue; /* port already up and running */ - port = ehea_get_port(adapter, logical_port_id); + /* allocate memory for the port structures */ + dev = alloc_etherdev(sizeof(struct ehea_port)); - if (port) { - ehea_info("removed %s (logical port id=%d)", port->netdev->name, - logical_port_id); + if (!dev) { + ehea_error("no mem for net_device"); + break; + } - ehea_shutdown_single_port(port); + port = netdev_priv(dev); + port->adapter = adapter; + port->netdev = dev; + adapter->port[i] = port; + port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); - for (i=0; i < EHEA_MAX_PORTS; i++) - if (adapter->port[i] == port) { - adapter->port[i] = NULL; - break; - } - } else { - ehea_error("removing port with logical port id=%d failed. port " - "not configured.", logical_port_id); - return -EINVAL; + dn = of_find_node_by_name(dn, "ethernet"); + ret = ehea_setup_single_port(port, dn); + if (ret) { + /* Free mem for this port struct. The others will be + processed on rollback */ + free_netdev(dev); + adapter->port[i] = NULL; + ehea_error("eHEA port %d setup failed, ret=%d", i, ret); + } } - ehea_remove_adapter_mr(adapter); - - return (ssize_t) count; -} + of_node_put(dn); -static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port); -static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port); + /* Check for succesfully set up ports */ + for (i = 0; i < adapter->num_ports; i++) + if (adapter->port[i]) + port_setup_ok++; -int ehea_create_device_sysfs(struct ibmebus_dev *dev) -{ - int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port); - if (ret) - goto out; + if (port_setup_ok) + ret = 0; /* At least some ports are setup correctly */ + else + ret = -EINVAL; - ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port); -out: return ret; } -void ehea_remove_device_sysfs(struct ibmebus_dev *dev) -{ - device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port); - device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port); -} - -static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, - const struct of_device_id *id) +static int __devinit ehea_probe(struct ibmebus_dev *dev, + const struct of_device_id *id) { struct ehea_adapter *adapter; u64 *adapter_handle; int ret; - if (!dev || !dev->ofdev.node) { - ehea_error("Invalid ibmebus device probed"); - return -EINVAL; - } - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); if (!adapter) { ret = -ENOMEM; @@ -2789,8 +2502,6 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, goto out; } - adapter->ebus_dev = dev; - adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", NULL); if (adapter_handle) @@ -2807,21 +2518,26 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, dev->ofdev.dev.driver_data = adapter; + ret = ehea_reg_mr_adapter(adapter); + if (ret) { + dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n"); + goto out_free_ad; + } /* initialize adapter and ports */ /* get adapter properties */ ret = ehea_sense_adapter_attr(adapter); if (ret) { dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); - goto out_free_ad; + goto out_free_res; } + dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports); adapter->neq = ehea_create_eq(adapter, EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); if (!adapter->neq) { - ret = -EIO; dev_err(&dev->ofdev.dev, "NEQ creation failed"); - goto out_free_ad; + goto out_free_res; } tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet, @@ -2836,27 +2552,18 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, } adapter->ehea_wq = create_workqueue("ehea_wq"); - if (!adapter->ehea_wq) { - ret = -EIO; + if (!adapter->ehea_wq) goto out_free_irq; - } - - ret = ehea_create_device_sysfs(dev); - if (ret) - goto out_kill_wq; ret = ehea_setup_ports(adapter); if (ret) { dev_err(&dev->ofdev.dev, "setup_ports failed"); - goto out_rem_dev_sysfs; + goto out_kill_wq; } ret = 0; goto out; -out_rem_dev_sysfs: - ehea_remove_device_sysfs(dev); - out_kill_wq: destroy_workqueue(adapter->ehea_wq); @@ -2866,32 +2573,45 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, out_kill_eq: ehea_destroy_eq(adapter->neq); +out_free_res: + ehea_h_free_resource(adapter->handle, adapter->mr.handle); + out_free_ad: kfree(adapter); out: return ret; } +static void ehea_shutdown_single_port(struct ehea_port *port) +{ + unregister_netdev(port->netdev); + kfree(port->mc_list); + free_netdev(port->netdev); +} + static int __devexit ehea_remove(struct ibmebus_dev *dev) { struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; + u64 hret; int i; - for (i = 0; i < EHEA_MAX_PORTS; i++) + for (i = 0; i < adapter->num_ports; i++) if (adapter->port[i]) { ehea_shutdown_single_port(adapter->port[i]); adapter->port[i] = NULL; } - - ehea_remove_device_sysfs(dev); - destroy_workqueue(adapter->ehea_wq); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); tasklet_kill(&adapter->neq_tasklet); ehea_destroy_eq(adapter->neq); - ehea_remove_adapter_mr(adapter); + + hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle); + if (hret) { + dev_err(&dev->ofdev.dev, "free_resource_mr failed"); + return -EIO; + } kfree(adapter); return 0; } @@ -2924,6 +2644,21 @@ static int check_module_parm(void) return ret; } +static struct of_device_id ehea_device_table[] = { + { + .name = "lhea", + .compatible = "IBM,lhea", + }, + {}, +}; + +static struct ibmebus_driver ehea_driver = { + .name = "ehea", + .id_table = ehea_device_table, + .probe = ehea_probe, + .remove = ehea_remove, +}; + int __init ehea_module_init(void) { int ret; diff --git a/trunk/drivers/net/ehea/ehea_phyp.c b/trunk/drivers/net/ehea/ehea_phyp.c index 95c4a7f9cc88..bc3c00547264 100644 --- a/trunk/drivers/net/ehea/ehea_phyp.c +++ b/trunk/drivers/net/ehea/ehea_phyp.c @@ -478,14 +478,12 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) 0, 0, 0, 0, 0, 0); /* R7-R12 */ } -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, - u64 force_bit) +u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) { return ehea_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle, /* R4 */ res_handle, /* R5 */ - force_bit, - 0, 0, 0, 0); /* R7-R10 */ + 0, 0, 0, 0, 0); /* R6-R10 */ } u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, diff --git a/trunk/drivers/net/ehea/ehea_phyp.h b/trunk/drivers/net/ehea/ehea_phyp.h index d17a45a7e717..90acddb068a1 100644 --- a/trunk/drivers/net/ehea/ehea_phyp.h +++ b/trunk/drivers/net/ehea/ehea_phyp.h @@ -414,11 +414,7 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle); -#define FORCE_FREE 1 -#define NORMAL_FREE 0 - -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, - u64 force_bit); +u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle); u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u64 length, const u32 access_ctrl, diff --git a/trunk/drivers/net/ehea/ehea_qmr.c b/trunk/drivers/net/ehea/ehea_qmr.c index f24a8862977d..96ff3b679996 100644 --- a/trunk/drivers/net/ehea/ehea_qmr.c +++ b/trunk/drivers/net/ehea/ehea_qmr.c @@ -197,7 +197,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, hw_queue_dtor(&cq->hw_queue); out_freeres: - ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE); + ehea_h_free_resource(adapter->handle, cq->fw_handle); out_freemem: kfree(cq); @@ -206,38 +206,25 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, return NULL; } -u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force) -{ - u64 hret; - u64 adapter_handle = cq->adapter->handle; - - /* deregister all previous registered pages */ - hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force); - if (hret != H_SUCCESS) - return hret; - - hw_queue_dtor(&cq->hw_queue); - kfree(cq); - - return hret; -} - int ehea_destroy_cq(struct ehea_cq *cq) { - u64 hret; + u64 adapter_handle, hret; + if (!cq) return 0; - if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) { - ehea_error_data(cq->adapter, cq->fw_handle); - hret = ehea_destroy_cq_res(cq, FORCE_FREE); - } + adapter_handle = cq->adapter->handle; + /* deregister all previous registered pages */ + hret = ehea_h_free_resource(adapter_handle, cq->fw_handle); if (hret != H_SUCCESS) { ehea_error("destroy CQ failed"); return -EIO; } + hw_queue_dtor(&cq->hw_queue); + kfree(cq); + return 0; } @@ -310,7 +297,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter, hw_queue_dtor(&eq->hw_queue); out_freeres: - ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE); + ehea_h_free_resource(adapter->handle, eq->fw_handle); out_freemem: kfree(eq); @@ -329,41 +316,27 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq) return eqe; } -u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force) +int ehea_destroy_eq(struct ehea_eq *eq) { u64 hret; unsigned long flags; + if (!eq) + return 0; + spin_lock_irqsave(&eq->spinlock, flags); - hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force); + hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle); spin_unlock_irqrestore(&eq->spinlock, flags); - if (hret != H_SUCCESS) - return hret; + if (hret != H_SUCCESS) { + ehea_error("destroy_eq failed"); + return -EIO; + } hw_queue_dtor(&eq->hw_queue); kfree(eq); - return hret; -} - -int ehea_destroy_eq(struct ehea_eq *eq) -{ - u64 hret; - if (!eq) - return 0; - - if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) { - ehea_error_data(eq->adapter, eq->fw_handle); - hret = ehea_destroy_eq_res(eq, FORCE_FREE); - } - - if (hret != H_SUCCESS) { - ehea_error("destroy EQ failed"); - return -EIO; - } - return 0; } @@ -498,56 +471,41 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter, out_freeres: ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); - ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE); + ehea_h_free_resource(adapter->handle, qp->fw_handle); out_freemem: kfree(qp); return NULL; } -u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force) +int ehea_destroy_qp(struct ehea_qp *qp) { - u64 hret; - struct ehea_qp_init_attr *qp_attr = &qp->init_attr; - - - ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); - hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force); - if (hret != H_SUCCESS) - return hret; - - hw_queue_dtor(&qp->hw_squeue); - hw_queue_dtor(&qp->hw_rqueue1); - - if (qp_attr->rq_count > 1) - hw_queue_dtor(&qp->hw_rqueue2); - if (qp_attr->rq_count > 2) - hw_queue_dtor(&qp->hw_rqueue3); - kfree(qp); + u64 hret; + struct ehea_qp_init_attr *qp_attr = &qp->init_attr; - return hret; -} + if (!qp) + return 0; -int ehea_destroy_qp(struct ehea_qp *qp) -{ - u64 hret; - if (!qp) - return 0; + ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); + hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); + if (hret != H_SUCCESS) { + ehea_error("destroy_qp failed"); + return -EIO; + } - if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) { - ehea_error_data(qp->adapter, qp->fw_handle); - hret = ehea_destroy_qp_res(qp, FORCE_FREE); - } + hw_queue_dtor(&qp->hw_squeue); + hw_queue_dtor(&qp->hw_rqueue1); - if (hret != H_SUCCESS) { - ehea_error("destroy QP failed"); - return -EIO; - } + if (qp_attr->rq_count > 1) + hw_queue_dtor(&qp->hw_rqueue2); + if (qp_attr->rq_count > 2) + hw_queue_dtor(&qp->hw_rqueue3); + kfree(qp); - return 0; + return 0; } -int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) +int ehea_reg_mr_adapter(struct ehea_adapter *adapter) { int i, k, ret; u64 hret, pt_abs, start, end, nr_pages; @@ -568,14 +526,14 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, acc_ctrl, adapter->pd, - &mr->handle, &mr->lkey); + &adapter->mr.handle, &adapter->mr.lkey); if (hret != H_SUCCESS) { ehea_error("alloc_resource_mr failed"); ret = -EIO; goto out; } - mr->vaddr = KERNELBASE; + adapter->mr.vaddr = KERNELBASE; k = 0; while (nr_pages > 0) { @@ -587,7 +545,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) EHEA_PAGESIZE))); hret = ehea_h_register_rpage_mr(adapter->handle, - mr->handle, 0, + adapter->mr.handle, 0, 0, (u64)pt_abs, num_pages); nr_pages -= num_pages; @@ -596,68 +554,34 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) (k * EHEA_PAGESIZE))); hret = ehea_h_register_rpage_mr(adapter->handle, - mr->handle, 0, + adapter->mr.handle, 0, 0, abs_adr,1); nr_pages--; } if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) { ehea_h_free_resource(adapter->handle, - mr->handle, FORCE_FREE); - ehea_error("register_rpage_mr failed"); + adapter->mr.handle); + ehea_error("register_rpage_mr failed: hret = %lX", + hret); ret = -EIO; goto out; } } if (hret != H_SUCCESS) { - ehea_h_free_resource(adapter->handle, mr->handle, - FORCE_FREE); - ehea_error("register_rpage failed for last page"); + ehea_h_free_resource(adapter->handle, adapter->mr.handle); + ehea_error("register_rpage failed for last page: hret = %lX", + hret); ret = -EIO; goto out; } - - mr->adapter = adapter; ret = 0; out: kfree(pt); return ret; } -int ehea_rem_mr(struct ehea_mr *mr) -{ - u64 hret; - - if (!mr || !mr->adapter) - return -EINVAL; - - hret = ehea_h_free_resource(mr->adapter->handle, mr->handle, - FORCE_FREE); - if (hret != H_SUCCESS) { - ehea_error("destroy MR failed"); - return -EIO; - } - - return 0; -} - -int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, - struct ehea_mr *shared_mr) -{ - u64 hret; - - hret = ehea_h_register_smr(adapter->handle, old_mr->handle, - old_mr->vaddr, EHEA_MR_ACC_CTRL, - adapter->pd, shared_mr); - if (hret != H_SUCCESS) - return -EIO; - - shared_mr->adapter = adapter; - - return 0; -} - void print_error_data(u64 *data) { int length; @@ -673,14 +597,6 @@ void print_error_data(u64 *data) ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " "port=%lX", resource, data[6], data[12], data[22]); - if (type == 0x4) /* Completion Queue */ - ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource, - data[6]); - - if (type == 0x3) /* Event Queue */ - ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource, - data[6]); - ehea_dump(data, length, "error data"); } diff --git a/trunk/drivers/net/ehea/ehea_qmr.h b/trunk/drivers/net/ehea/ehea_qmr.h index c0eb3e03a102..1ff60983504d 100644 --- a/trunk/drivers/net/ehea/ehea_qmr.h +++ b/trunk/drivers/net/ehea/ehea_qmr.h @@ -142,8 +142,6 @@ struct ehea_rwqe { #define EHEA_CQE_STAT_ERR_MASK 0x721F #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F #define EHEA_CQE_STAT_ERR_TCP 0x4000 -#define EHEA_CQE_STAT_ERR_IP 0x2000 -#define EHEA_CQE_STAT_ERR_CRC 0x1000 struct ehea_cqe { u64 wr_id; /* work request ID from WQE */ @@ -322,11 +320,6 @@ static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index) return hw_qeit_get_valid(queue); } -static inline void ehea_inc_cq(struct ehea_cq *cq) -{ - hw_qeit_inc(&cq->hw_queue); -} - static inline void ehea_inc_rq1(struct ehea_qp *qp) { hw_qeit_inc(&qp->hw_rqueue1); @@ -334,7 +327,7 @@ static inline void ehea_inc_rq1(struct ehea_qp *qp) static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq) { - return hw_qeit_get_valid(&my_cq->hw_queue); + return hw_qeit_get_inc_valid(&my_cq->hw_queue); } #define EHEA_CQ_REGISTER_ORIG 0 @@ -363,12 +356,7 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd, int ehea_destroy_qp(struct ehea_qp *qp); -int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr); - -int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, - struct ehea_mr *shared_mr); - -int ehea_rem_mr(struct ehea_mr *mr); +int ehea_reg_mr_adapter(struct ehea_adapter *adapter); void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); diff --git a/trunk/drivers/net/epic100.c b/trunk/drivers/net/epic100.c index 4e3f14c9c717..3a6a83d3ee1c 100644 --- a/trunk/drivers/net/epic100.c +++ b/trunk/drivers/net/epic100.c @@ -934,6 +934,7 @@ static void epic_init_ring(struct net_device *dev) ep->rx_skbuff[i] = skb; if (skb == NULL) break; + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1198,6 +1199,7 @@ static int epic_rx(struct net_device *dev, int budget) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(ep->pci_dev, ep->rx_ring[entry].bufaddr, @@ -1234,6 +1236,7 @@ static int epic_rx(struct net_device *dev, int budget) skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz); if (skb == NULL) break; + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); diff --git a/trunk/drivers/net/eth16i.c b/trunk/drivers/net/eth16i.c index 04abf59e5007..93283e386f3a 100644 --- a/trunk/drivers/net/eth16i.c +++ b/trunk/drivers/net/eth16i.c @@ -1175,6 +1175,7 @@ static void eth16i_rx(struct net_device *dev) break; } + skb->dev = dev; skb_reserve(skb,2); /* diff --git a/trunk/drivers/net/ewrk3.c b/trunk/drivers/net/ewrk3.c index cb0792c187ba..714ea1176ec7 100644 --- a/trunk/drivers/net/ewrk3.c +++ b/trunk/drivers/net/ewrk3.c @@ -993,6 +993,7 @@ static int ewrk3_rx(struct net_device *dev) if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) { unsigned char *p; + skb->dev = dev; skb_reserve(skb, 2); /* Align to 16 bytes */ p = skb_put(skb, pkt_len); diff --git a/trunk/drivers/net/fealnx.c b/trunk/drivers/net/fealnx.c index abe9b089c610..38a13f440530 100644 --- a/trunk/drivers/net/fealnx.c +++ b/trunk/drivers/net/fealnx.c @@ -1719,6 +1719,7 @@ static int netdev_rx(struct net_device *dev) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, np->cur_rx->buffer, diff --git a/trunk/drivers/net/fec.c b/trunk/drivers/net/fec.c index 255b09124e11..6764281b4531 100644 --- a/trunk/drivers/net/fec.c +++ b/trunk/drivers/net/fec.c @@ -647,6 +647,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; } else { + skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, data, pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); diff --git a/trunk/drivers/net/fec_8xx/fec_main.c b/trunk/drivers/net/fec_8xx/fec_main.c index 88efe9731bab..77f747a5afa7 100644 --- a/trunk/drivers/net/fec_8xx/fec_main.c +++ b/trunk/drivers/net/fec_8xx/fec_main.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -550,9 +551,7 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) skbn = dev_alloc_skb(pkt_len + 2); if (skbn != NULL) { skb_reserve(skbn, 2); /* align IP header */ - skb_copy_from_linear_data(skb - skbn->data, - pkt_len); + memcpy(skbn->data, skb->data, pkt_len); /* swap */ skbt = skb; skb = skbn; @@ -562,6 +561,7 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) skbn = dev_alloc_skb(ENET_RX_FRSIZE); if (skbn != NULL) { + skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); received++; diff --git a/trunk/drivers/net/fec_8xx/fec_mii.c b/trunk/drivers/net/fec_8xx/fec_mii.c index b3fa0d6a159c..e79700abf7b6 100644 --- a/trunk/drivers/net/fec_8xx/fec_mii.c +++ b/trunk/drivers/net/fec_8xx/fec_mii.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/forcedeth.c b/trunk/drivers/net/forcedeth.c index 7a018027fcc0..d04214e4e581 100644 --- a/trunk/drivers/net/forcedeth.c +++ b/trunk/drivers/net/forcedeth.c @@ -1385,12 +1385,11 @@ static int nv_alloc_rx(struct net_device *dev) while (np->put_rx.orig != less_rx) { struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); if (skb) { + skb->dev = dev; np->put_rx_ctx->skb = skb; - np->put_rx_ctx->dma = pci_map_single(np->pci_dev, - skb->data, - skb_tailroom(skb), - PCI_DMA_FROMDEVICE); - np->put_rx_ctx->dma_len = skb_tailroom(skb); + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma); wmb(); np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); @@ -1417,12 +1416,11 @@ static int nv_alloc_rx_optimized(struct net_device *dev) while (np->put_rx.ex != less_rx) { struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); if (skb) { + skb->dev = dev; np->put_rx_ctx->skb = skb; - np->put_rx_ctx->dma = pci_map_single(np->pci_dev, - skb->data, - skb_tailroom(skb), - PCI_DMA_FROMDEVICE); - np->put_rx_ctx->dma_len = skb_tailroom(skb); + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32; np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF; wmb(); @@ -1606,9 +1604,8 @@ static void nv_drain_rx(struct net_device *dev) wmb(); if (np->rx_skb[i].skb) { pci_unmap_single(np->pci_dev, np->rx_skb[i].dma, - (skb_end_pointer(np->rx_skb[i].skb) - - np->rx_skb[i].skb->data), - PCI_DMA_FROMDEVICE); + np->rx_skb[i].skb->end-np->rx_skb[i].skb->data, + PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skb[i].skb); np->rx_skb[i].skb = NULL; } @@ -4379,12 +4376,11 @@ static int nv_loopback_test(struct net_device *dev) ret = 0; goto out; } - test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data, - skb_tailroom(tx_skb), - PCI_DMA_FROMDEVICE); pkt_data = skb_put(tx_skb, pkt_len); for (i = 0; i < pkt_len; i++) pkt_data[i] = (u8)(i & 0xff); + test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data, + tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr); @@ -4441,7 +4437,7 @@ static int nv_loopback_test(struct net_device *dev) } pci_unmap_page(np->pci_dev, test_dma_addr, - (skb_end_pointer(tx_skb) - tx_skb->data), + tx_skb->end-tx_skb->data, PCI_DMA_TODEVICE); dev_kfree_skb_any(tx_skb); out: diff --git a/trunk/drivers/net/fs_enet/fs_enet-main.c b/trunk/drivers/net/fs_enet/fs_enet-main.c index a4a2a0ea43d3..4a05c14bf7ec 100644 --- a/trunk/drivers/net/fs_enet/fs_enet-main.c +++ b/trunk/drivers/net/fs_enet/fs_enet-main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -159,8 +160,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) skbn = dev_alloc_skb(pkt_len + 2); if (skbn != NULL) { skb_reserve(skbn, 2); /* align IP header */ - skb_copy_from_linear_data(skb, - skbn->data, pkt_len); + memcpy(skbn->data, skb->data, pkt_len); /* swap */ skbt = skb; skb = skbn; @@ -170,6 +170,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) skbn = dev_alloc_skb(ENET_RX_FRSIZE); if (skbn != NULL) { + skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); received++; @@ -293,8 +294,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) skbn = dev_alloc_skb(pkt_len + 2); if (skbn != NULL) { skb_reserve(skbn, 2); /* align IP header */ - skb_copy_from_linear_data(skb, - skbn->data, pkt_len); + memcpy(skbn->data, skb->data, pkt_len); /* swap */ skbt = skb; skb = skbn; @@ -304,6 +304,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) skbn = dev_alloc_skb(ENET_RX_FRSIZE); if (skbn != NULL) { + skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); received++; @@ -515,6 +516,7 @@ void fs_init_bds(struct net_device *dev) break; } fep->rx_skbuff[i] = skb; + skb->dev = dev; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), diff --git a/trunk/drivers/net/fs_enet/mac-fcc.c b/trunk/drivers/net/fs_enet/mac-fcc.c index 5603121132cd..8545e84fc9a0 100644 --- a/trunk/drivers/net/fs_enet/mac-fcc.c +++ b/trunk/drivers/net/fs_enet/mac-fcc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/fs_enet/mac-fec.c b/trunk/drivers/net/fs_enet/mac-fec.c index 04b4f80a1cde..cdcfb96f360f 100644 --- a/trunk/drivers/net/fs_enet/mac-fec.c +++ b/trunk/drivers/net/fs_enet/mac-fec.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/fs_enet/mac-scc.c b/trunk/drivers/net/fs_enet/mac-scc.c index d0f28981b55a..65925b5a224f 100644 --- a/trunk/drivers/net/fs_enet/mac-scc.c +++ b/trunk/drivers/net/fs_enet/mac-scc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/fs_enet/mii-bitbang.c b/trunk/drivers/net/fs_enet/mii-bitbang.c index d3840108ffbd..f91447837fd4 100644 --- a/trunk/drivers/net/fs_enet/mii-bitbang.c +++ b/trunk/drivers/net/fs_enet/mii-bitbang.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/fs_enet/mii-fec.c b/trunk/drivers/net/fs_enet/mii-fec.c index 0a563a83016f..235b177fb9ac 100644 --- a/trunk/drivers/net/fs_enet/mii-fec.c +++ b/trunk/drivers/net/fs_enet/mii-fec.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/gianfar.c b/trunk/drivers/net/gianfar.c index b666a0cc0642..d981d4c41dd3 100644 --- a/trunk/drivers/net/gianfar.c +++ b/trunk/drivers/net/gianfar.c @@ -942,18 +942,18 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb) /* Tell the controller what the protocol is */ /* And provide the already calculated phcs */ - if (ip_hdr(skb)->protocol == IPPROTO_UDP) { + if (skb->nh.iph->protocol == IPPROTO_UDP) { flags |= TXFCB_UDP; - fcb->phcs = udp_hdr(skb)->check; + fcb->phcs = skb->h.uh->check; } else - fcb->phcs = udp_hdr(skb)->check; + fcb->phcs = skb->h.th->check; /* l3os is the distance between the start of the * frame (skb->data) and the start of the IP hdr. * l4os is the distance between the start of the * l3 hdr and the l4 hdr */ - fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN); - fcb->l4os = skb_network_header_len(skb); + fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN); + fcb->l4os = (u16)(skb->h.raw - skb->nh.raw); fcb->flags = flags; } @@ -1295,6 +1295,8 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) */ skb_reserve(skb, alignamount); + skb->dev = dev; + bdp->bufPtr = dma_map_single(NULL, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); diff --git a/trunk/drivers/net/hamachi.c b/trunk/drivers/net/hamachi.c index 2521b111b3a5..c3c0d67fc383 100644 --- a/trunk/drivers/net/hamachi.c +++ b/trunk/drivers/net/hamachi.c @@ -1568,6 +1568,7 @@ static int hamachi_rx(struct net_device *dev) printk(KERN_ERR "%s: rx_copybreak non-zero " "not good with RX_CHECKSUM\n", dev->name); #endif + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(hmp->pci_dev, hmp->rx_ring[entry].addr, diff --git a/trunk/drivers/net/hamradio/baycom_ser_fdx.c b/trunk/drivers/net/hamradio/baycom_ser_fdx.c index 17ac6975d70d..59214e74b9cf 100644 --- a/trunk/drivers/net/hamradio/baycom_ser_fdx.c +++ b/trunk/drivers/net/hamradio/baycom_ser_fdx.c @@ -75,14 +75,12 @@ #include #include #include +#include +#include #include #include #include -#include -#include -#include - /* --------------------------------------------------------------------- */ #define BAYCOM_DEBUG @@ -415,18 +413,11 @@ static int ser12_open(struct net_device *dev) if (!dev || !bc) return -ENXIO; - if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT || - dev->irq < 2 || dev->irq > NR_IRQS) { - printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) " - "or irq (2 <= irq <= %d)\n", - 0xffff-SER12_EXTENT, NR_IRQS); + if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || + dev->irq < 2 || dev->irq > 15) return -ENXIO; - } - if (bc->baud < 300 || bc->baud > 4800) { - printk(KERN_INFO "baycom_ser_fdx: invalid baudrate " - "(300...4800)\n"); + if (bc->baud < 300 || bc->baud > 4800) return -EINVAL; - } if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", dev->base_addr); diff --git a/trunk/drivers/net/hamradio/bpqether.c b/trunk/drivers/net/hamradio/bpqether.c index 656f2789c9ba..d2542697e298 100644 --- a/trunk/drivers/net/hamradio/bpqether.c +++ b/trunk/drivers/net/hamradio/bpqether.c @@ -282,7 +282,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) } skb->protocol = ax25_type_trans(skb, dev); - skb_reset_network_header(skb); + skb->nh.raw = skb->data; dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); bpq->stats.tx_packets++; bpq->stats.tx_bytes+=skb->len; diff --git a/trunk/drivers/net/hamradio/dmascc.c b/trunk/drivers/net/hamradio/dmascc.c index 3be8c5047599..0fbb414b5a4d 100644 --- a/trunk/drivers/net/hamradio/dmascc.c +++ b/trunk/drivers/net/hamradio/dmascc.c @@ -930,7 +930,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) /* Transfer data to DMA buffer */ i = priv->tx_head; - skb_copy_from_linear_data_offset(skb, 1, priv->tx_buf[i], skb->len - 1); + memcpy(priv->tx_buf[i], skb->data + 1, skb->len - 1); priv->tx_len[i] = skb->len - 1; /* Clear interrupts while we touch our circular buffers */ diff --git a/trunk/drivers/net/hamradio/hdlcdrv.c b/trunk/drivers/net/hamradio/hdlcdrv.c index b33adc6a340b..f5a17ad9d3d6 100644 --- a/trunk/drivers/net/hamradio/hdlcdrv.c +++ b/trunk/drivers/net/hamradio/hdlcdrv.c @@ -317,9 +317,7 @@ void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s) dev_kfree_skb_irq(skb); break; } - skb_copy_from_linear_data_offset(skb, 1, - s->hdlctx.buffer, - pkt_len); + memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); dev_kfree_skb_irq(skb); s->hdlctx.bp = s->hdlctx.buffer; append_crc_ccitt(s->hdlctx.buffer, pkt_len); diff --git a/trunk/drivers/net/hamradio/yam.c b/trunk/drivers/net/hamradio/yam.c index 467559debfd6..ee3ea4fa729f 100644 --- a/trunk/drivers/net/hamradio/yam.c +++ b/trunk/drivers/net/hamradio/yam.c @@ -638,9 +638,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp) dev_kfree_skb_any(skb); break; } - skb_copy_from_linear_data_offset(skb, 1, - yp->tx_buf, - yp->tx_len); + memcpy(yp->tx_buf, skb->data + 1, yp->tx_len); dev_kfree_skb_any(skb); yp->tx_count = 0; yp->tx_crcl = 0x21; diff --git a/trunk/drivers/net/hp100.c b/trunk/drivers/net/hp100.c index 8118a6750b61..7dc5185aa2c0 100644 --- a/trunk/drivers/net/hp100.c +++ b/trunk/drivers/net/hp100.c @@ -1816,6 +1816,7 @@ static void hp100_rx(struct net_device *dev) u_char *ptr; skb_reserve(skb,2); + skb->dev = dev; /* ptr to start of the sk_buff data area */ skb_put(skb, pkt_len); diff --git a/trunk/drivers/net/ibm_emac/ibm_emac_core.c b/trunk/drivers/net/ibm_emac/ibm_emac_core.c index 50035ebd4f52..dd8ad8746825 100644 --- a/trunk/drivers/net/ibm_emac/ibm_emac_core.c +++ b/trunk/drivers/net/ibm_emac/ibm_emac_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1337,7 +1338,7 @@ static inline int emac_rx_sg_append(struct ocp_enet_private *dev, int slot) dev_kfree_skb(dev->rx_sg_skb); dev->rx_sg_skb = NULL; } else { - cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb), + cacheable_memcpy(dev->rx_sg_skb->tail, dev->rx_skb[slot]->data, len); skb_put(dev->rx_sg_skb, len); emac_recycle_rx_skb(dev, slot, len); @@ -1397,6 +1398,7 @@ static int emac_poll_rx(void *param, int budget) skb_put(skb, len); push_packet: + skb->dev = dev->ndev; skb->protocol = eth_type_trans(skb, dev->ndev); emac_rx_csum(dev, skb, ctrl); diff --git a/trunk/drivers/net/ibmlana.c b/trunk/drivers/net/ibmlana.c index fe85d6fcba33..3f946c811511 100644 --- a/trunk/drivers/net/ibmlana.c +++ b/trunk/drivers/net/ibmlana.c @@ -601,6 +601,7 @@ static void irqrx_handler(struct net_device *dev) /* set up skb fields */ + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; diff --git a/trunk/drivers/net/ibmveth.c b/trunk/drivers/net/ibmveth.c index 3bec0f733f01..458db0538a9a 100644 --- a/trunk/drivers/net/ibmveth.c +++ b/trunk/drivers/net/ibmveth.c @@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); -static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); +static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); static struct kobj_type ktype_veth_pool; #ifdef CONFIG_PROC_FS @@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) } } -static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) +static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) { ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); @@ -798,6 +798,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) skb_reserve(skb, offset); skb_put(skb, length); + skb->dev = netdev; skb->protocol = eth_type_trans(skb, netdev); netif_receive_skb(skb); /* send it up */ @@ -953,16 +954,14 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n", dev->unit_address); - mac_addr_p = (unsigned char *) vio_get_attribute(dev, - VETH_MAC_ADDR, NULL); + mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0); if(!mac_addr_p) { printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR " "attribute\n", __FILE__, __LINE__); return 0; } - mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev, - VETH_MCAST_FILTER_SIZE, NULL); + mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0); if(!mcastFilterSize_p) { printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " "VETH_MCAST_FILTER_SIZE attribute\n", diff --git a/trunk/drivers/net/ioc3-eth.c b/trunk/drivers/net/ioc3-eth.c index f749e07c6425..4ad780719a84 100644 --- a/trunk/drivers/net/ioc3-eth.c +++ b/trunk/drivers/net/ioc3-eth.c @@ -633,6 +633,8 @@ static inline void ioc3_rx(struct ioc3_private *ip) ip->rx_skbs[rx_entry] = NULL; /* Poison */ + new_skb->dev = priv_netdev(ip); + /* Because we reserve afterwards. */ skb_put(new_skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) new_skb->data; @@ -938,6 +940,7 @@ static void ioc3_alloc_rings(struct net_device *dev) } ip->rx_skbs[i] = skb; + skb->dev = dev; /* Because we reserve afterwards. */ skb_put(skb, (1664 + RX_OFFSET)); @@ -1393,9 +1396,9 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) * manually. */ if (skb->ip_summed == CHECKSUM_PARTIAL) { - const struct iphdr *ih = ip_hdr(skb); - const int proto = ntohs(ih->protocol); + int proto = ntohs(skb->nh.iph->protocol); unsigned int csoff; + struct iphdr *ih = skb->nh.iph; uint32_t csum, ehsum; uint16_t *eh; @@ -1422,11 +1425,11 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) csoff = ETH_HLEN + (ih->ihl << 2); if (proto == IPPROTO_UDP) { csoff += offsetof(struct udphdr, check); - udp_hdr(skb)->check = csum; + skb->h.uh->check = csum; } if (proto == IPPROTO_TCP) { csoff += offsetof(struct tcphdr, check); - tcp_hdr(skb)->check = csum; + skb->h.th->check = csum; } w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); @@ -1443,7 +1446,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (len <= 104) { /* Short packet, let's copy it directly into the ring. */ - skb_copy_from_linear_data(skb, desc->data, skb->len); + memcpy(desc->data, skb->data, skb->len); if (len < ETH_ZLEN) { /* Very short packet, pad with zeros at the end. */ memset(desc->data + len, 0, ETH_ZLEN - len); diff --git a/trunk/drivers/net/irda/ali-ircc.c b/trunk/drivers/net/irda/ali-ircc.c index f9c889c0dd07..cebf8c374bc5 100644 --- a/trunk/drivers/net/irda/ali-ircc.c +++ b/trunk/drivers/net/irda/ali-ircc.c @@ -1472,8 +1472,9 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->stats.tx_bytes += skb->len; - skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, - skb->len); + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); + self->tx_fifo.len++; self->tx_fifo.free++; @@ -1923,7 +1924,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) /* Copy frame without CRC, CRC is removed by hardware*/ skb_put(skb, len); - skb_copy_to_linear_data(skb, self->rx_buff.data, len); + memcpy(skb->data, self->rx_buff.data, len); /* Move to next frame */ self->rx_buff.data += len; @@ -1931,7 +1932,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); self->netdev->last_rx = jiffies; diff --git a/trunk/drivers/net/irda/au1k_ir.c b/trunk/drivers/net/irda/au1k_ir.c index 4dbdfaaf37bf..37914dc5b90e 100644 --- a/trunk/drivers/net/irda/au1k_ir.c +++ b/trunk/drivers/net/irda/au1k_ir.c @@ -526,7 +526,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) if (aup->speed == 4000000) { /* FIR */ - skb_copy_from_linear_data(skb, pDB->vaddr, skb->len); + memcpy((void *)pDB->vaddr, skb->data, skb->len); ptxd->count_0 = skb->len & 0xff; ptxd->count_1 = (skb->len >> 8) & 0xff; @@ -604,9 +604,9 @@ static int au1k_irda_rx(struct net_device *dev) skb_put(skb, count); else skb_put(skb, count-2); - skb_copy_to_linear_data(skb, pDB->vaddr, count - 2); + memcpy(skb->data, (void *)pDB->vaddr, count-2); skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); prxd->count_0 = 0; diff --git a/trunk/drivers/net/irda/donauboe.c b/trunk/drivers/net/irda/donauboe.c index 3ca47bf6dfec..11af0ae7510e 100644 --- a/trunk/drivers/net/irda/donauboe.c +++ b/trunk/drivers/net/irda/donauboe.c @@ -1119,7 +1119,7 @@ dumpbufs(skb->data,skb->len,'>'); else { len = skb->len; - skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len); + memcpy (self->tx_bufs[self->txs], skb->data, len); } self->ring->tx[self->txs].len = len & 0x0fff; @@ -1282,11 +1282,11 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); skb_reserve (skb, 1); skb_put (skb, len); - skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs], - len); + memcpy (skb->data, self->rx_bufs[self->rxs], len); + self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons (ETH_P_IRDA); } else diff --git a/trunk/drivers/net/irda/irda-usb.c b/trunk/drivers/net/irda/irda-usb.c index 0ac240ca905b..1d510bdc9b84 100644 --- a/trunk/drivers/net/irda/irda-usb.c +++ b/trunk/drivers/net/irda/irda-usb.c @@ -441,7 +441,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) goto drop; } - skb_copy_from_linear_data(skb, self->tx_buff + self->header_length, skb->len); + memcpy(self->tx_buff + self->header_length, skb->data, skb->len); /* Change setting for next frame */ if (self->capability & IUC_STIR421X) { @@ -902,7 +902,7 @@ static void irda_usb_receive(struct urb *urb) if(docopy) { /* Copy packet, so we can recycle the original */ - skb_copy_from_linear_data(skb, newskb->data, urb->actual_length); + memcpy(newskb->data, skb->data, urb->actual_length); /* Deliver this new skb */ dataskb = newskb; /* And hook the old skb to the URB @@ -921,7 +921,7 @@ static void irda_usb_receive(struct urb *urb) /* Ask the networking layer to queue the packet for the IrDA stack */ dataskb->dev = self->netdev; - skb_reset_mac_header(dataskb); + dataskb->mac.raw = dataskb->data; dataskb->protocol = htons(ETH_P_IRDA); len = dataskb->len; netif_rx(dataskb); diff --git a/trunk/drivers/net/irda/mcs7780.c b/trunk/drivers/net/irda/mcs7780.c index 0de867288a47..f0c61f3b2a82 100644 --- a/trunk/drivers/net/irda/mcs7780.c +++ b/trunk/drivers/net/irda/mcs7780.c @@ -200,14 +200,14 @@ static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs) /* Setup a communication between mcs7780 and agilent chip. */ static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs) { - IRDA_WARNING("This transceiver type is not supported yet.\n"); + IRDA_WARNING("This transceiver type is not supported yet."); return 1; } /* Setup a communication between mcs7780 and sharp chip. */ static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs) { - IRDA_WARNING("This transceiver type is not supported yet.\n"); + IRDA_WARNING("This transceiver type is not supported yet."); return 1; } @@ -279,7 +279,7 @@ static inline int mcs_setup_transceiver(struct mcs_cb *mcs) break; default: - IRDA_WARNING("Unknown transceiver type: %d\n", + IRDA_WARNING("Unknown transceiver type: %d", mcs->transceiver_type); ret = 1; } @@ -318,7 +318,7 @@ static inline int mcs_setup_transceiver(struct mcs_cb *mcs) return ret; error: - IRDA_ERROR("%s\n", msg); + IRDA_ERROR("%s", msg); return ret; } @@ -353,7 +353,7 @@ static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) buf[0] = len & 0xff; buf[1] = (len >> 8) & 0xff; /* copy the data into the tx buffer. */ - skb_copy_from_linear_data(skb, buf + 2, skb->len); + memcpy(buf+2, skb->data, skb->len); /* put the fcs in the last four bytes in little endian order. */ buf[len - 4] = fcs & 0xff; buf[len - 3] = (fcs >> 8) & 0xff; @@ -377,7 +377,7 @@ static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf) buf[0] = len & 0xff; buf[1] = (len >> 8) & 0xff; /* copy the data */ - skb_copy_from_linear_data(skb, buf + 2, skb->len); + memcpy(buf+2, skb->data, skb->len); /* put the fcs in last two bytes in little endian order. */ buf[len - 2] = fcs & 0xff; buf[len - 1] = (fcs >> 8) & 0xff; @@ -426,9 +426,9 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) } skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, buf, new_len); + memcpy(skb->data, buf, new_len); skb_put(skb, new_len); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); skb->dev = mcs->netdev; @@ -479,9 +479,9 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, buf, new_len); + memcpy(skb->data, buf, new_len); skb_put(skb, new_len); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); skb->dev = mcs->netdev; @@ -587,7 +587,7 @@ static int mcs_speed_change(struct mcs_cb *mcs) } while(cnt++ < 100 && (rval & MCS_IRINTX)); if(cnt >= 100) { - IRDA_ERROR("unable to change speed\n"); + IRDA_ERROR("unable to change speed"); ret = -EIO; goto error; } @@ -638,7 +638,7 @@ static int mcs_speed_change(struct mcs_cb *mcs) default: ret = 1; - IRDA_WARNING("Unknown transceiver type: %d\n", + IRDA_WARNING("Unknown transceiver type: %d", mcs->transceiver_type); } if (unlikely(ret)) @@ -733,7 +733,7 @@ static int mcs_net_open(struct net_device *netdev) sprintf(hwname, "usb#%d", mcs->usbdev->devnum); mcs->irlap = irlap_open(netdev, &mcs->qos, hwname); if (!mcs->irlap) { - IRDA_ERROR("mcs7780: irlap_open failed\n"); + IRDA_ERROR("mcs7780: irlap_open failed"); goto error2; } @@ -862,7 +862,7 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) mcs->out_buf, wraplen, mcs_send_irq, mcs); if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) { - IRDA_ERROR("failed tx_urb: %d\n", ret); + IRDA_ERROR("failed tx_urb: %d", ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -897,7 +897,7 @@ static int mcs_probe(struct usb_interface *intf, if (!ndev) goto error1; - IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); + IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.", udev->devnum); /* what is it realy for? */ SET_MODULE_OWNER(ndev); @@ -905,7 +905,7 @@ static int mcs_probe(struct usb_interface *intf, ret = usb_reset_configuration(udev); if (ret != 0) { - IRDA_ERROR("mcs7780: usb reset configuration failed\n"); + IRDA_ERROR("mcs7780: usb reset configuration failed"); goto error2; } @@ -950,7 +950,7 @@ static int mcs_probe(struct usb_interface *intf, if (ret != 0) goto error2; - IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s\n", + IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s", ndev->name); mcs->transceiver_type = transceiver_type; @@ -981,7 +981,7 @@ static void mcs_disconnect(struct usb_interface *intf) free_netdev(mcs->netdev); usb_set_intfdata(intf, NULL); - IRDA_DEBUG(0, "MCS7780 now disconnected.\n"); + IRDA_DEBUG(0, "MCS7780 now disconnected."); } /* Module insertion */ @@ -992,7 +992,7 @@ static int __init mcs_init(void) /* register this driver with the USB subsystem */ result = usb_register(&mcs_driver); if (result) - IRDA_ERROR("usb_register failed. Error number %d\n", result); + IRDA_ERROR("usb_register failed. Error number %d", result); return result; } diff --git a/trunk/drivers/net/irda/nsc-ircc.c b/trunk/drivers/net/irda/nsc-ircc.c index d96c89751a71..29b5ccd29d0b 100644 --- a/trunk/drivers/net/irda/nsc-ircc.c +++ b/trunk/drivers/net/irda/nsc-ircc.c @@ -1466,8 +1466,9 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) self->stats.tx_bytes += skb->len; - skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, - skb->len); + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); + self->tx_fifo.len++; self->tx_fifo.free++; @@ -1868,14 +1869,10 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) /* Copy frame without CRC */ if (self->io.speed < 4000000) { skb_put(skb, len-2); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 2); + memcpy(skb->data, self->rx_buff.data, len-2); } else { skb_put(skb, len-4); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 4); + memcpy(skb->data, self->rx_buff.data, len-4); } /* Move to next frame */ @@ -1884,7 +1881,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); self->netdev->last_rx = jiffies; diff --git a/trunk/drivers/net/irda/pxaficp_ir.c b/trunk/drivers/net/irda/pxaficp_ir.c index fb196fd91855..2272156af31e 100644 --- a/trunk/drivers/net/irda/pxaficp_ir.c +++ b/trunk/drivers/net/irda/pxaficp_ir.c @@ -386,12 +386,12 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in /* Align IP header to 20 bytes */ skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, si->dma_rx_buff, len); + memcpy(skb->data, si->dma_rx_buff, len); skb_put(skb, len); /* Feed it to IrLAP */ skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); @@ -484,7 +484,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long mtt = irda_get_mtt(skb); si->dma_tx_buff_len = skb->len; - skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); + memcpy(si->dma_tx_buff, skb->data, skb->len); if (mtt) while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) diff --git a/trunk/drivers/net/irda/sa1100_ir.c b/trunk/drivers/net/irda/sa1100_ir.c index 056639f72bec..937372d00398 100644 --- a/trunk/drivers/net/irda/sa1100_ir.c +++ b/trunk/drivers/net/irda/sa1100_ir.c @@ -504,7 +504,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev skb_put(skb, len); skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); si->stats.rx_packets++; si->stats.rx_bytes += len; diff --git a/trunk/drivers/net/irda/smsc-ircc2.c b/trunk/drivers/net/irda/smsc-ircc2.c index 198bf3bfa70f..31c623381ea8 100644 --- a/trunk/drivers/net/irda/smsc-ircc2.c +++ b/trunk/drivers/net/irda/smsc-ircc2.c @@ -315,7 +315,6 @@ static struct smsc_chip __initdata lpc_chips_flat[] = { /* Base address 0x2E or 0x4E */ { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 }, - { "47N227", KEY55_1|FIR|SERx4, 0x7a, 0x00 }, { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 }, { NULL } }; @@ -1162,7 +1161,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) self->new_speed = speed; } - skb_copy_from_linear_data(skb, self->tx_buff.head, skb->len); + memcpy(self->tx_buff.head, skb->data, skb->len); self->tx_buff.len = skb->len; self->tx_buff.data = self->tx_buff.head; @@ -1413,7 +1412,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) self->stats.rx_bytes += len; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); } diff --git a/trunk/drivers/net/irda/stir4200.c b/trunk/drivers/net/irda/stir4200.c index 755aa444a4dd..20d306fea4cb 100644 --- a/trunk/drivers/net/irda/stir4200.c +++ b/trunk/drivers/net/irda/stir4200.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -348,7 +349,7 @@ static void fir_eof(struct stir_cb *stir) } skb_reserve(nskb, 1); skb = nskb; - skb_copy_to_linear_data(nskb, rx_buff->data, len); + memcpy(nskb->data, rx_buff->data, len); } else { nskb = dev_alloc_skb(rx_buff->truesize); if (unlikely(!nskb)) { @@ -363,7 +364,7 @@ static void fir_eof(struct stir_cb *stir) skb_put(skb, len); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); skb->dev = stir->netdev; diff --git a/trunk/drivers/net/irda/via-ircc.c b/trunk/drivers/net/irda/via-ircc.c index ff5358574d0a..c3ed9b3067e5 100644 --- a/trunk/drivers/net/irda/via-ircc.c +++ b/trunk/drivers/net/irda/via-ircc.c @@ -925,8 +925,8 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, self->tx_fifo.tail += skb->len; self->stats.tx_bytes += skb->len; - skb_copy_from_linear_data(skb, - self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); self->tx_fifo.len++; self->tx_fifo.free++; //F01 if (self->tx_fifo.len == 1) { @@ -1125,7 +1125,7 @@ static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); return TRUE; @@ -1189,7 +1189,7 @@ F01_E */ skb_reserve(skb, 1); skb_put(skb, len - 4); - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); + memcpy(skb->data, self->rx_buff.data, len - 4); IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __FUNCTION__, len - 4, self->rx_buff.data); @@ -1198,7 +1198,7 @@ F01_E */ self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); @@ -1234,7 +1234,7 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase) } skb_reserve(skb, 1); skb_put(skb, len - 4 + 1); - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4 + 1); + memcpy(skb->data, self->rx_buff.data, len - 4 + 1); st_fifo->tail++; st_fifo->len++; if (st_fifo->tail > MAX_RX_WINDOW) @@ -1244,7 +1244,7 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase) self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); if (st_fifo->len < (MAX_RX_WINDOW + 2)) { @@ -1303,7 +1303,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) } skb_reserve(skb, 1); skb_put(skb, len - 4); - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); + memcpy(skb->data, self->rx_buff.data, len - 4); IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __FUNCTION__, len - 4, st_fifo->head); @@ -1313,7 +1313,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); } //while diff --git a/trunk/drivers/net/irda/vlsi_ir.c b/trunk/drivers/net/irda/vlsi_ir.c index c4be973867a6..3457e9d8b667 100644 --- a/trunk/drivers/net/irda/vlsi_ir.c +++ b/trunk/drivers/net/irda/vlsi_ir.c @@ -595,7 +595,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) rd->skb = NULL; skb->dev = ndev; memcpy(skb_put(skb,len), rd->buf, len); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; if (in_interrupt()) netif_rx(skb); else @@ -993,7 +993,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) goto drop; } else - skb_copy_from_linear_data(skb, rd->buf, len); + memcpy(rd->buf, skb->data, len); } rd->skb = skb; /* remember skb for tx-complete stats */ diff --git a/trunk/drivers/net/irda/w83977af_ir.c b/trunk/drivers/net/irda/w83977af_ir.c index 5182e800cc18..4212657fa4f9 100644 --- a/trunk/drivers/net/irda/w83977af_ir.c +++ b/trunk/drivers/net/irda/w83977af_ir.c @@ -529,7 +529,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Decide if we should use PIO or DMA transfer */ if (self->io.speed > PIO_MAX_SPEED) { self->tx_buff.data = self->tx_buff.head; - skb_copy_from_linear_data(skb, self->tx_buff.data, skb->len); + memcpy(self->tx_buff.data, skb->data, skb->len); self->tx_buff.len = skb->len; mtt = irda_get_mtt(skb); @@ -908,14 +908,10 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) /* Copy frame without CRC */ if (self->io.speed < 4000000) { skb_put(skb, len-2); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 2); + memcpy(skb->data, self->rx_buff.data, len-2); } else { skb_put(skb, len-4); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 4); + memcpy(skb->data, self->rx_buff.data, len-4); } /* Move to next frame */ @@ -923,7 +919,7 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) self->stats.rx_packets++; skb->dev = self->netdev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); self->netdev->last_rx = jiffies; diff --git a/trunk/drivers/net/iseries_veth.c b/trunk/drivers/net/iseries_veth.c index 347d50cd77d4..0e9ba3c3faf7 100644 --- a/trunk/drivers/net/iseries_veth.c +++ b/trunk/drivers/net/iseries_veth.c @@ -1540,6 +1540,7 @@ static void veth_receive(struct veth_lpar_connection *cnx, } skb_put(skb, length); + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); /* send it up */ diff --git a/trunk/drivers/net/ixgb/ixgb.h b/trunk/drivers/net/ixgb/ixgb.h index c8e90861f869..cf30a1059ce0 100644 --- a/trunk/drivers/net/ixgb/ixgb.h +++ b/trunk/drivers/net/ixgb/ixgb.h @@ -111,6 +111,9 @@ struct ixgb_adapter; /* How many Rx Buffers do we bundle into one write to the hardware ? */ #define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */ +/* only works for sizes that are powers of 2 */ +#define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgb_buffer { diff --git a/trunk/drivers/net/ixgb/ixgb_ethtool.c b/trunk/drivers/net/ixgb/ixgb_ethtool.c index afde84868bea..d6628bd9590a 100644 --- a/trunk/drivers/net/ixgb/ixgb_ethtool.c +++ b/trunk/drivers/net/ixgb/ixgb_ethtool.c @@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *netdev, rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD); - rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); + IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD); txdr->count = min(txdr->count,(uint32_t)MAX_TXD); - txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); + IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); if(netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ diff --git a/trunk/drivers/net/ixgb/ixgb_main.c b/trunk/drivers/net/ixgb/ixgb_main.c index 6d2b059371f1..afc2ec72529e 100644 --- a/trunk/drivers/net/ixgb/ixgb_main.c +++ b/trunk/drivers/net/ixgb/ixgb_main.c @@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) /* round up to nearest 4K */ txdr->size = txdr->count * sizeof(struct ixgb_tx_desc); - txdr->size = ALIGN(txdr->size, 4096); + IXGB_ROUNDUP(txdr->size, 4096); txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if(!txdr->desc) { @@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) /* Round up to nearest 4K */ rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc); - rxdr->size = ALIGN(rxdr->size, 4096); + IXGB_ROUNDUP(rxdr->size, 4096); rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); @@ -1182,27 +1182,24 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) if (likely(skb_is_gso(skb))) { struct ixgb_buffer *buffer_info; - struct iphdr *iph; - if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) return err; } - hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->gso_size; - iph = ip_hdr(skb); - iph->tot_len = 0; - iph->check = 0; - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, 0); - ipcss = skb_network_offset(skb); - ipcso = (void *)&(iph->check) - (void *)skb->data; - ipcse = skb_transport_offset(skb) - 1; - tucss = skb_transport_offset(skb); - tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, IPPROTO_TCP, 0); + ipcss = skb->nh.raw - skb->data; + ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; + ipcse = skb->h.raw - skb->data - 1; + tucss = skb->h.raw - skb->data; + tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; i = adapter->tx_ring.next_to_use; @@ -1246,7 +1243,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) { struct ixgb_buffer *buffer_info; - css = skb_transport_offset(skb); + css = skb->h.raw - skb->data; cso = css + skb->csum_offset; i = adapter->tx_ring.next_to_use; @@ -2017,12 +2014,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); - skb_copy_to_linear_data_offset(new_skb, - -NET_IP_ALIGN, - (skb->data - - NET_IP_ALIGN), - (length + - NET_IP_ALIGN)); + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + length + NET_IP_ALIGN); /* save the skb in buffer_info as good */ buffer_info->skb = skb; skb = new_skb; diff --git a/trunk/drivers/net/ixgb/ixgb_osdep.h b/trunk/drivers/net/ixgb/ixgb_osdep.h index 9e04a6b3ae0d..8434d752fd81 100644 --- a/trunk/drivers/net/ixgb/ixgb_osdep.h +++ b/trunk/drivers/net/ixgb/ixgb_osdep.h @@ -34,6 +34,7 @@ #define _IXGB_OSDEP_H_ #include +#include #include #include #include diff --git a/trunk/drivers/net/ixgb/ixgb_param.c b/trunk/drivers/net/ixgb/ixgb_param.c index 5d5ddabf4360..b27442a121f2 100644 --- a/trunk/drivers/net/ixgb/ixgb_param.c +++ b/trunk/drivers/net/ixgb/ixgb_param.c @@ -245,6 +245,8 @@ ixgb_validate_option(int *value, struct ixgb_option *opt) return -1; } +#define LIST_LEN(l) (sizeof(l) / sizeof(l[0])) + /** * ixgb_check_options - Range Checking for Command Line Parameters * @adapter: board private structure @@ -282,7 +284,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) } else { tx_ring->count = opt.def; } - tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); + IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); } { /* Receive Descriptor Count */ struct ixgb_option opt = { @@ -301,7 +303,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) } else { rx_ring->count = opt.def; } - rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); + IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); } { /* Receive Checksum Offload Enable */ struct ixgb_option opt = { @@ -333,7 +335,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) .name = "Flow Control", .err = "reading default settings from EEPROM", .def = ixgb_fc_tx_pause, - .arg = { .l = { .nr = ARRAY_SIZE(fc_list), + .arg = { .l = { .nr = LIST_LEN(fc_list), .p = fc_list }} }; diff --git a/trunk/drivers/net/ixp2000/ixpdev.c b/trunk/drivers/net/ixp2000/ixpdev.c index 6683afc02aaa..a4eccb11d677 100644 --- a/trunk/drivers/net/ixp2000/ixpdev.c +++ b/trunk/drivers/net/ixp2000/ixpdev.c @@ -110,10 +110,11 @@ static int ixpdev_rx(struct net_device *dev, int *budget) skb = dev_alloc_skb(desc->pkt_length + 2); if (likely(skb != NULL)) { + skb->dev = nds[desc->channel]; skb_reserve(skb, 2); eth_copy_and_sum(skb, buf, desc->pkt_length, 0); skb_put(skb, desc->pkt_length); - skb->protocol = eth_type_trans(skb, nds[desc->channel]); + skb->protocol = eth_type_trans(skb, skb->dev); skb->dev->last_rx = jiffies; diff --git a/trunk/drivers/net/jazzsonic.c b/trunk/drivers/net/jazzsonic.c index 75f6f441e876..d34afb52ea7f 100644 --- a/trunk/drivers/net/jazzsonic.c +++ b/trunk/drivers/net/jazzsonic.c @@ -88,23 +88,6 @@ static unsigned short known_revisions[] = 0xffff /* end of list */ }; -static int jazzsonic_open(struct net_device* dev) -{ - if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { - printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return -EAGAIN; - } - return sonic_open(dev); -} - -static int jazzsonic_close(struct net_device* dev) -{ - int err; - err = sonic_close(dev); - free_irq(dev->irq, dev); - return err; -} - static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; @@ -186,8 +169,8 @@ static int __init sonic_probe1(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = jazzsonic_open; - dev->stop = jazzsonic_close; + dev->open = sonic_open; + dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; @@ -277,6 +260,8 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); +#define SONIC_IRQ_FLAG IRQF_DISABLED + #include "sonic.c" static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) @@ -284,11 +269,11 @@ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); struct sonic_local* lp = netdev_priv(dev); - unregister_netdev(dev); + unregister_netdev (dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); release_region (dev->base_addr, SONIC_MEM_SIZE); - free_netdev(dev); + free_netdev (dev); return 0; } diff --git a/trunk/drivers/net/lance.c b/trunk/drivers/net/lance.c index 0fe96c85828b..a3843320dbe1 100644 --- a/trunk/drivers/net/lance.c +++ b/trunk/drivers/net/lance.c @@ -988,7 +988,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) if (lance_debug > 5) printk("%s: bouncing a high-memory packet (%#x).\n", dev->name, (u32)isa_virt_to_bus(skb->data)); - skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len); + memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); lp->tx_ring[entry].base = ((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; dev_kfree_skb(skb); @@ -1184,6 +1184,7 @@ lance_rx(struct net_device *dev) } break; } + skb->dev = dev; skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, diff --git a/trunk/drivers/net/lasi_82596.c b/trunk/drivers/net/lasi_82596.c index 6b49fc4bd1a1..452863d5d498 100644 --- a/trunk/drivers/net/lasi_82596.c +++ b/trunk/drivers/net/lasi_82596.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include @@ -800,6 +801,7 @@ static inline int i596_rx(struct net_device *dev) lp->stats.rx_dropped++; } else { + skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); diff --git a/trunk/drivers/net/lib8390.c b/trunk/drivers/net/lib8390.c index 5c86e737f954..e726c06b8dc6 100644 --- a/trunk/drivers/net/lib8390.c +++ b/trunk/drivers/net/lib8390.c @@ -722,6 +722,7 @@ static void ei_receive(struct net_device *dev) else { skb_reserve(skb,2); /* IP headers on 16 byte boundaries */ + skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); diff --git a/trunk/drivers/net/loopback.c b/trunk/drivers/net/loopback.c index 6ba6ed2b480a..2b739fd584f1 100644 --- a/trunk/drivers/net/loopback.c +++ b/trunk/drivers/net/loopback.c @@ -75,9 +75,8 @@ static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #ifdef LOOPBACK_TSO static void emulate_large_send_offload(struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); - struct tcphdr *th = (struct tcphdr *)(skb_network_header(skb) + - (iph->ihl * 4)); + struct iphdr *iph = skb->nh.iph; + struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4)); unsigned int doffset = (iph->ihl + th->doff) * 4; unsigned int mtu = skb_shinfo(skb)->gso_size + doffset; unsigned int offset = 0; @@ -91,11 +90,10 @@ static void emulate_large_send_offload(struct sk_buff *skb) if (!nskb) break; skb_reserve(nskb, 32); - skb_set_mac_header(nskb, -ETH_HLEN); - skb_reset_network_header(nskb); - iph = ip_hdr(nskb); - skb_copy_to_linear_data(nskb, skb_network_header(skb), - doffset); + nskb->mac.raw = nskb->data - 14; + nskb->nh.raw = nskb->data; + iph = nskb->nh.iph; + memcpy(nskb->data, skb->nh.raw, doffset); if (skb_copy_bits(skb, doffset + offset, nskb->data + doffset, @@ -110,7 +108,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); nskb->pkt_type = skb->pkt_type; - th = (struct tcphdr *)(skb_network_header(nskb) + iph->ihl * 4); + th = (struct tcphdr*)(nskb->nh.raw + iph->ihl*4); iph->tot_len = htons(frag_size + doffset); iph->id = htons(id); iph->check = 0; @@ -139,6 +137,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) skb_orphan(skb); skb->protocol = eth_type_trans(skb,dev); + skb->dev = dev; #ifndef LOOPBACK_MUST_CHECKSUM skb->ip_summed = CHECKSUM_UNNECESSARY; #endif @@ -146,7 +145,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef LOOPBACK_TSO if (skb_is_gso(skb)) { BUG_ON(skb->protocol != htons(ETH_P_IP)); - BUG_ON(ip_hdr(skb)->protocol != IPPROTO_TCP); + BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); emulate_large_send_offload(skb); return 0; @@ -164,9 +163,11 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static struct net_device_stats loopback_stats; + static struct net_device_stats *get_stats(struct net_device *dev) { - struct net_device_stats *stats = &dev->stats; + struct net_device_stats *stats = &loopback_stats; unsigned long bytes = 0; unsigned long packets = 0; int i; @@ -206,6 +207,7 @@ static const struct ethtool_ops loopback_ethtool_ops = { struct net_device loopback_dev = { .name = "lo", .get_stats = &get_stats, + .priv = &loopback_stats, .mtu = (16 * 1024) + 20 + 20 + 12, .hard_start_xmit = loopback_xmit, .hard_header = eth_header, diff --git a/trunk/drivers/net/lp486e.c b/trunk/drivers/net/lp486e.c index 5fc18da1873d..177c502f7385 100644 --- a/trunk/drivers/net/lp486e.c +++ b/trunk/drivers/net/lp486e.c @@ -676,6 +676,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, return 1; } + skb->dev = dev; memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len); skb->protocol = eth_type_trans(skb,dev); diff --git a/trunk/drivers/net/mac8390.c b/trunk/drivers/net/mac8390.c index 90b0c3ed4bb6..a12bb64e3694 100644 --- a/trunk/drivers/net/mac8390.c +++ b/trunk/drivers/net/mac8390.c @@ -14,8 +14,6 @@ /* 2001-05-15: support for Cabletron ported from old daynaport driver * and fixed access to Sonic Sys card which masquerades as a Farallon * by rayk@knightsmanor.org */ -/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */ -/* 2003-12-26: Make sure Asante cards always work. */ #include #include @@ -63,21 +61,25 @@ static char version[] = #define DAYNA_8390_BASE 0x80000 #define DAYNA_8390_MEM 0x00000 +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 + #define CABLETRON_8390_BASE 0x90000 #define CABLETRON_8390_MEM 0x00000 -#define INTERLAN_8390_BASE 0xE0000 -#define INTERLAN_8390_MEM 0xD0000 - enum mac8390_type { MAC8390_NONE = -1, MAC8390_APPLE, MAC8390_ASANTE, - MAC8390_FARALLON, + MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */ MAC8390_CABLETRON, MAC8390_DAYNA, MAC8390_INTERLAN, MAC8390_KINETICS, + MAC8390_FOCUS, + MAC8390_SONICSYS, + MAC8390_DAYNA2, + MAC8390_DAYNA3, }; static const char * cardname[] = { @@ -88,6 +90,10 @@ static const char * cardname[] = { "dayna", "interlan", "kinetics", + "focus", + "sonic systems", + "dayna2", + "dayna_lc", }; static int word16[] = { @@ -98,6 +104,10 @@ static int word16[] = { 0, /* dayna */ 1, /* interlan */ 0, /* kinetics */ + 1, /* focus (??) */ + 1, /* sonic systems */ + 1, /* dayna2 */ + 1, /* dayna-lc */ }; /* on which cards do we use NuBus resources? */ @@ -109,12 +119,10 @@ static int useresources[] = { 0, /* dayna */ 0, /* interlan */ 0, /* kinetics */ -}; - -enum mac8390_access { - ACCESS_UNKNOWN = 0, - ACCESS_32, - ACCESS_16, + 0, /* focus (??) */ + 1, /* sonic systems */ + 1, /* dayna2 */ + 1, /* dayna-lc */ }; extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); @@ -126,9 +134,8 @@ static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, static int mac8390_open(struct net_device * dev); static int mac8390_close(struct net_device * dev); static void mac8390_no_reset(struct net_device *dev); -static void interlan_reset(struct net_device *dev); -/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/ +/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/ static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct net_device * dev, int count, @@ -165,93 +172,23 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count); enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) { - switch (dev->dr_sw) { - case NUBUS_DRSW_3COM: - switch (dev->dr_hw) { - case NUBUS_DRHW_APPLE_SONIC_NB: - case NUBUS_DRHW_APPLE_SONIC_LC: - case NUBUS_DRHW_SONNET: - return MAC8390_NONE; - break; - default: - return MAC8390_APPLE; - break; - } - break; - - case NUBUS_DRSW_APPLE: - switch (dev->dr_hw) { - case NUBUS_DRHW_ASANTE_LC: - return MAC8390_NONE; - break; - case NUBUS_DRHW_CABLETRON: - return MAC8390_CABLETRON; - break; - default: - return MAC8390_APPLE; - break; - } - break; - - case NUBUS_DRSW_ASANTE: - return MAC8390_ASANTE; - break; - - case NUBUS_DRSW_TECHWORKS: - case NUBUS_DRSW_DAYNA2: - case NUBUS_DRSW_DAYNA_LC: - if (dev->dr_hw == NUBUS_DRHW_CABLETRON) - return MAC8390_CABLETRON; - else - return MAC8390_APPLE; - break; - - case NUBUS_DRSW_FARALLON: - return MAC8390_FARALLON; - break; - - case NUBUS_DRSW_KINETICS: - switch (dev->dr_hw) { - case NUBUS_DRHW_INTERLAN: - return MAC8390_INTERLAN; - break; - default: - return MAC8390_KINETICS; - break; - } - break; - - case NUBUS_DRSW_DAYNA: - // These correspond to Dayna Sonic cards - // which use the macsonic driver - if (dev->dr_hw == NUBUS_DRHW_SMC9194 || - dev->dr_hw == NUBUS_DRHW_INTERLAN ) - return MAC8390_NONE; - else - return MAC8390_DAYNA; - break; - } + if (dev->dr_sw == NUBUS_DRSW_ASANTE) + return MAC8390_ASANTE; + if (dev->dr_sw == NUBUS_DRSW_FARALLON) + return MAC8390_FARALLON; + if (dev->dr_sw == NUBUS_DRSW_KINETICS) + return MAC8390_KINETICS; + if (dev->dr_sw == NUBUS_DRSW_DAYNA) + return MAC8390_DAYNA; + if (dev->dr_sw == NUBUS_DRSW_DAYNA2) + return MAC8390_DAYNA2; + if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC) + return MAC8390_DAYNA3; + if (dev->dr_hw == NUBUS_DRHW_CABLETRON) + return MAC8390_CABLETRON; return MAC8390_NONE; } -enum mac8390_access __init mac8390_testio(volatile unsigned long membase) -{ - unsigned long outdata = 0xA5A0B5B0; - unsigned long indata = 0x00000000; - /* Try writing 32 bits */ - memcpy((char *)membase, (char *)&outdata, 4); - /* Now compare them */ - if (memcmp((char *)&outdata, (char *)membase, 4) == 0) - return ACCESS_32; - /* Write 16 bit output */ - word_memcpy_tocard((char *)membase, (char *)&outdata, 4); - /* Now read it back */ - word_memcpy_fromcard((char *)&indata, (char *)membase, 4); - if (outdata == indata) - return ACCESS_16; - return ACCESS_UNKNOWN; -} - int __init mac8390_memsize(unsigned long membase) { unsigned long flags; @@ -350,6 +287,14 @@ struct net_device * __init mac8390_probe(int unit) continue; } else { nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); + /* Some Sonic Sys cards masquerade as Farallon */ + if (cardtype == MAC8390_FARALLON && + dev->dev_addr[0] == 0x0 && + dev->dev_addr[1] == 0x40 && + dev->dev_addr[2] == 0x10) { + /* This is really Sonic Sys card */ + cardtype = MAC8390_SONICSYS; + } } if (useresources[cardtype] == 1) { @@ -389,17 +334,6 @@ struct net_device * __init mac8390_probe(int unit) dev->mem_start + mac8390_memsize(dev->mem_start); break; - case MAC8390_INTERLAN: - dev->base_addr = - (int)(ndev->board->slot_addr + - INTERLAN_8390_BASE); - dev->mem_start = - (int)(ndev->board->slot_addr + - INTERLAN_8390_MEM); - dev->mem_end = - dev->mem_start + - mac8390_memsize(dev->mem_start); - break; case MAC8390_CABLETRON: dev->base_addr = (int)(ndev->board->slot_addr + @@ -422,8 +356,8 @@ struct net_device * __init mac8390_probe(int unit) default: printk(KERN_ERR "Card type %s is" - " unsupported, sorry\n", - ndev->board->name); + " unsupported, sorry\n", + cardname[cardtype]); continue; } } @@ -504,7 +438,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd 24, 26, 28, 30 }; - int access_bitmode = 0; + int access_bitmode; /* Now fill in our stuff */ dev->open = &mac8390_open; @@ -534,47 +468,29 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Fill in model-specific information and functions */ switch(type) { - case MAC8390_FARALLON: - case MAC8390_APPLE: - switch(mac8390_testio(dev->mem_start)) { - case ACCESS_UNKNOWN: - printk("Don't know how to access card memory!\n"); - return -ENODEV; - break; - - case ACCESS_16: - /* 16 bit card, register map is reversed */ - ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; - - case ACCESS_32: - /* 32 bit card, register map is reversed */ - ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - access_bitmode = 1; - break; - } - break; - - case MAC8390_ASANTE: - /* Some Asante cards pass the 32 bit test - * but overwrite system memory when run at 32 bit. - * so we run them all at 16 bit. - */ + case MAC8390_SONICSYS: + /* 16 bit card, register map is reversed */ ei_status.reset_8390 = &mac8390_no_reset; ei_status.block_input = &slow_sane_block_input; ei_status.block_output = &slow_sane_block_output; ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; + access_bitmode = 0; + break; + case MAC8390_FARALLON: + case MAC8390_APPLE: + case MAC8390_ASANTE: + case MAC8390_DAYNA2: + case MAC8390_DAYNA3: + /* 32 bit card, register map is reversed */ + /* sane */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + access_bitmode = 1; break; - case MAC8390_CABLETRON: /* 16 bit card, register map is short forward */ ei_status.reset_8390 = &mac8390_no_reset; @@ -582,30 +498,21 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd ei_status.block_output = &slow_sane_block_output; ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ei_status.reg_offset = fwrd2_offsets; + access_bitmode = 0; break; - case MAC8390_DAYNA: case MAC8390_KINETICS: - /* 16 bit memory, register map is forward */ + /* 16 bit memory */ /* dayna and similar */ ei_status.reset_8390 = &mac8390_no_reset; ei_status.block_input = &dayna_block_input; ei_status.block_output = &dayna_block_output; ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; + access_bitmode = 0; break; - - case MAC8390_INTERLAN: - /* 16 bit memory, register map is forward */ - ei_status.reset_8390 = &interlan_reset; - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = fwrd4_offsets; - break; - default: - printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name); + printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); return -ENODEV; } @@ -623,9 +530,9 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd printk(":"); } } - printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", - dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, - dev->mem_start, access_bitmode?32:16); + printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n", + dev->irq, dev->mem_start, dev->mem_end-1, + access_bitmode?32:16); return 0; } @@ -654,18 +561,6 @@ static void mac8390_no_reset(struct net_device *dev) return; } -static void interlan_reset(struct net_device *dev) -{ - unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); - if (ei_debug > 1) - printk("Need to reset the NS8390 t=%lu...", jiffies); - ei_status.txing = 0; - target[0xC0000] = 0; - if (ei_debug > 1) - printk("reset complete\n"); - return; -} - /* dayna_memcpy_fromio/dayna_memcpy_toio */ /* directly from daynaport.c by Alan Cox */ static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) diff --git a/trunk/drivers/net/mac89x0.c b/trunk/drivers/net/mac89x0.c index 26a3b45a4a34..e960138011c0 100644 --- a/trunk/drivers/net/mac89x0.c +++ b/trunk/drivers/net/mac89x0.c @@ -128,7 +128,7 @@ struct net_local { extern void reset_chip(struct net_device *dev); #endif static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_rx(struct net_device *dev); @@ -374,39 +374,56 @@ net_open(struct net_device *dev) static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); - unsigned long flags; + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + dev->tbusy=0; + dev->trans_start = jiffies; + } - if (net_debug > 3) - printk("%s: sent %d byte packet of type %x\n", - dev->name, skb->len, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) - | skb->data[ETH_ALEN+ETH_ALEN+1]); + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + struct net_local *lp = netdev_priv(dev); + unsigned long flags; - /* keep the upload from being interrupted, since we - ask the chip to start transmitting before the - whole packet has been completely uploaded. */ - local_irq_save(flags); - netif_stop_queue(dev); + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + local_irq_save(flags); - /* initiate a transmit sequence */ - writereg(dev, PP_TxCMD, lp->send_cmd); - writereg(dev, PP_TxLength, skb->len); + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); - /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { - /* Gasp! It hasn't. But that shouldn't happen since - we're waiting for TxOk, so return 1 and requeue this packet. */ - local_irq_restore(flags); - return 1; - } + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ + local_irq_restore(flags); + return 1; + } - /* Write the contents of the packet */ - skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame), - skb->len+1); + /* Write the contents of the packet */ + memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); - local_irq_restore(flags); - dev->trans_start = jiffies; + local_irq_restore(flags); + dev->trans_start = jiffies; + } dev_kfree_skb (skb); return 0; @@ -424,6 +441,9 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) printk ("net_interrupt(): irq %d for unknown device.\n", irq); return IRQ_NONE; } + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; ioaddr = dev->base_addr; lp = netdev_priv(dev); @@ -444,7 +464,8 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) break; case ISQ_TRANSMITTER_EVENT: lp->stats.tx_packets++; - netif_wake_queue(dev); + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ if ((status & TX_OK) == 0) lp->stats.tx_errors++; if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; @@ -458,7 +479,8 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) That shouldn't happen since we only ever load one packet. Shrug. Do the right thing anyway. */ - netif_wake_queue(dev); + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ } if (status & TX_UNDERRUN) { if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); @@ -475,6 +497,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) break; } } + dev->interrupt = 0; return IRQ_HANDLED; } @@ -507,9 +530,9 @@ net_rx(struct net_device *dev) return; } skb_put(skb, length); + skb->dev = dev; - skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame), - length); + memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", dev->name, length, @@ -588,6 +611,8 @@ static void set_multicast_list(struct net_device *dev) static int set_mac_address(struct net_device *dev, void *addr) { int i; + if (dev->start) + return -EBUSY; printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); diff --git a/trunk/drivers/net/macb.c b/trunk/drivers/net/macb.c index 0e04f7ac3f2e..2e9571bf0736 100644 --- a/trunk/drivers/net/macb.c +++ b/trunk/drivers/net/macb.c @@ -357,6 +357,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, } skb_reserve(skb, RX_OFFSET); + skb->dev = bp->dev; skb->ip_summed = CHECKSUM_NONE; skb_put(skb, len); @@ -367,10 +368,9 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, BUG_ON(frag != last_frag); frag_len = len - offset; } - skb_copy_to_linear_data_offset(skb, offset, - (bp->rx_buffers + - (RX_BUFFER_SIZE * frag)), - frag_len); + memcpy(skb->data + offset, + bp->rx_buffers + (RX_BUFFER_SIZE * frag), + frag_len); offset += RX_BUFFER_SIZE; bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED); wmb(); @@ -576,8 +576,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) int i; dev_dbg(&bp->pdev->dev, "start_xmit: len %u head %p data %p tail %p end %p\n", - skb->len, skb->head, skb->data, - skb_tail_pointer(skb), skb_end_pointer(skb)); + skb->len, skb->head, skb->data, skb->tail, skb->end); dev_dbg(&bp->pdev->dev, "data:"); for (i = 0; i < 16; i++) diff --git a/trunk/drivers/net/mace.c b/trunk/drivers/net/mace.c index b3bd62394958..9ec24f0d5d68 100644 --- a/trunk/drivers/net/mace.c +++ b/trunk/drivers/net/mace.c @@ -939,6 +939,7 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) else /* Ethernet header; mace includes FCS */ nb -= 8; skb_put(skb, nb); + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); mp->stats.rx_bytes += skb->len; netif_rx(skb); diff --git a/trunk/drivers/net/macmace.c b/trunk/drivers/net/macmace.c index fef3193121f9..5d541e873041 100644 --- a/trunk/drivers/net/macmace.c +++ b/trunk/drivers/net/macmace.c @@ -12,11 +12,6 @@ * Copyright (C) 1998 Alan Cox * * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver - * - * Copyright (C) 2007 Finn Thain - * - * Converted to DMA API, converted to unified driver model, - * sync'd some routines with mace.c and fixed various bugs. */ @@ -28,9 +23,8 @@ #include #include #include -#include -#include #include +#include #include #include #include @@ -38,20 +32,13 @@ #include #include "mace.h" -static char mac_mace_string[] = "macmace"; -static struct platform_device *mac_mace_device; - -#define N_TX_BUFF_ORDER 0 -#define N_TX_RING (1 << N_TX_BUFF_ORDER) -#define N_RX_BUFF_ORDER 3 -#define N_RX_RING (1 << N_RX_BUFF_ORDER) - +#define N_TX_RING 1 +#define N_RX_RING 8 +#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE) #define TX_TIMEOUT HZ -#define MACE_BUFF_SIZE 0x800 - -/* Chip rev needs workaround on HW & multicast addr change */ -#define BROKEN_ADDRCHG_REV 0x0941 +/* Bits in transmit DMA status */ +#define TX_DMA_ERR 0x80 /* The MACE is simply wired down on a Mac68K box */ @@ -60,46 +47,40 @@ static struct platform_device *mac_mace_device; struct mace_data { volatile struct mace *mace; - unsigned char *tx_ring; - dma_addr_t tx_ring_phys; - unsigned char *rx_ring; - dma_addr_t rx_ring_phys; + volatile unsigned char *tx_ring; + volatile unsigned char *tx_ring_phys; + volatile unsigned char *rx_ring; + volatile unsigned char *rx_ring_phys; int dma_intr; struct net_device_stats stats; int rx_slot, rx_tail; int tx_slot, tx_sloti, tx_count; - int chipid; - struct device *device; }; struct mace_frame { - u8 rcvcnt; - u8 pad1; - u8 rcvsts; - u8 pad2; - u8 rntpc; - u8 pad3; - u8 rcvcc; - u8 pad4; - u32 pad5; - u32 pad6; + u16 len; + u16 status; + u16 rntpc; + u16 rcvcc; + u32 pad1; + u32 pad2; u8 data[1]; /* And frame continues.. */ }; #define PRIV_BYTES sizeof(struct mace_data) +extern void psc_debug_dump(void); + static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); -static void mace_reset(struct net_device *dev); static irqreturn_t mace_interrupt(int irq, void *dev_id); static irqreturn_t mace_dma_intr(int irq, void *dev_id); static void mace_tx_timeout(struct net_device *dev); -static void __mace_set_address(struct net_device *dev, void *addr); /* * Load a receive DMA channel with a base address and ring length @@ -107,7 +88,7 @@ static void __mace_set_address(struct net_device *dev, void *addr); static void mace_load_rxdma_base(struct net_device *dev, int set) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; psc_write_word(PSC_ENETRD_CMD + set, 0x0100); psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); @@ -122,7 +103,7 @@ static void mace_load_rxdma_base(struct net_device *dev, int set) static void mace_rxdma_reset(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mace = mp->mace; u8 maccc = mace->maccc; @@ -149,7 +130,7 @@ static void mace_rxdma_reset(struct net_device *dev) static void mace_txdma_reset(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mace = mp->mace; u8 maccc; @@ -187,7 +168,7 @@ static void mace_dma_off(struct net_device *dev) * model of Macintrash has a MACE (AV macintoshes) */ -static int __devinit mace_probe(struct platform_device *pdev) +struct net_device *mace_probe(int unit) { int j; struct mace_data *mp; @@ -198,28 +179,24 @@ static int __devinit mace_probe(struct platform_device *pdev) int err; if (found || macintosh_config->ether_type != MAC_ETHER_MACE) - return -ENODEV; + return ERR_PTR(-ENODEV); found = 1; /* prevent 'finding' one on every device probe */ dev = alloc_etherdev(PRIV_BYTES); if (!dev) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - mp = netdev_priv(dev); - - mp->device = &pdev->dev; - SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; dev->irq = IRQ_MAC_MACE; mp->dma_intr = IRQ_MAC_MACE_DMA; - mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo; - /* * The PROM contains 8 bytes which total 0xFF when XOR'd * together. Due to the usual peculiar apple brain damage @@ -240,7 +217,7 @@ static int __devinit mace_probe(struct platform_device *pdev) if (checksum != 0xFF) { free_netdev(dev); - return -ENODEV; + return ERR_PTR(-ENODEV); } memset(&mp->stats, 0, sizeof(mp->stats)); @@ -260,98 +237,22 @@ static int __devinit mace_probe(struct platform_device *pdev) err = register_netdev(dev); if (!err) - return 0; + return dev; free_netdev(dev); - return err; -} - -/* - * Reset the chip. - */ - -static void mace_reset(struct net_device *dev) -{ - struct mace_data *mp = netdev_priv(dev); - volatile struct mace *mb = mp->mace; - int i; - - /* soft-reset the chip */ - i = 200; - while (--i) { - mb->biucc = SWRST; - if (mb->biucc & SWRST) { - udelay(10); - continue; - } - break; - } - if (!i) { - printk(KERN_ERR "macmace: cannot reset chip!\n"); - return; - } - - mb->maccc = 0; /* turn off tx, rx */ - mb->imr = 0xFF; /* disable all intrs for now */ - i = mb->ir; - - mb->biucc = XMTSP_64; - mb->utr = RTRD; - mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU; - - mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ - mb->rcvfc = 0; - - /* load up the hardware address */ - __mace_set_address(dev, dev->dev_addr); - - /* clear the multicast filter */ - if (mp->chipid == BROKEN_ADDRCHG_REV) - mb->iac = LOGADDR; - else { - mb->iac = ADDRCHG | LOGADDR; - while ((mb->iac & ADDRCHG) != 0) - ; - } - for (i = 0; i < 8; ++i) - mb->ladrf = 0; - - /* done changing address */ - if (mp->chipid != BROKEN_ADDRCHG_REV) - mb->iac = 0; - - mb->plscc = PORTSEL_AUI; + return ERR_PTR(err); } /* * Load the address on a mace controller. */ -static void __mace_set_address(struct net_device *dev, void *addr) -{ - struct mace_data *mp = netdev_priv(dev); - volatile struct mace *mb = mp->mace; - unsigned char *p = addr; - int i; - - /* load up the hardware address */ - if (mp->chipid == BROKEN_ADDRCHG_REV) - mb->iac = PHYADDR; - else { - mb->iac = ADDRCHG | PHYADDR; - while ((mb->iac & ADDRCHG) != 0) - ; - } - for (i = 0; i < 6; ++i) - mb->padr = dev->dev_addr[i] = p[i]; - if (mp->chipid != BROKEN_ADDRCHG_REV) - mb->iac = 0; -} - static int mace_set_address(struct net_device *dev, void *addr) { - struct mace_data *mp = netdev_priv(dev); + unsigned char *p = addr; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; + int i; unsigned long flags; u8 maccc; @@ -359,10 +260,15 @@ static int mace_set_address(struct net_device *dev, void *addr) maccc = mb->maccc; - __mace_set_address(dev, addr); + /* load up the hardware address */ + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0); - mb->maccc = maccc; + for (i = 0; i < 6; ++i) { + mb->padr = dev->dev_addr[i] = p[i]; + } + mb->maccc = maccc; local_irq_restore(flags); return 0; @@ -375,11 +281,31 @@ static int mace_set_address(struct net_device *dev, void *addr) static int mace_open(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; +#if 0 + int i; - /* reset the chip */ - mace_reset(dev); + i = 200; + while (--i) { + mb->biucc = SWRST; + if (mb->biucc & SWRST) { + udelay(10); + continue; + } + break; + } + if (!i) { + printk(KERN_ERR "%s: software reset failed!!\n", dev->name); + return -EAGAIN; + } +#endif + + mb->biucc = XMTSP_64; + mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST; + mb->xmtfc = AUTO_PAD_XMIT; + mb->plscc = PORTSEL_AUI; + /* mb->utr = RTRD; */ if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); @@ -393,22 +319,26 @@ static int mace_open(struct net_device *dev) /* Allocate the DMA ring buffers */ - mp->tx_ring = dma_alloc_coherent(mp->device, - N_TX_RING * MACE_BUFF_SIZE, - &mp->tx_ring_phys, GFP_KERNEL); - if (mp->tx_ring == NULL) { - printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name); - goto out1; - } + mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES); + mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0); - mp->rx_ring = dma_alloc_coherent(mp->device, - N_RX_RING * MACE_BUFF_SIZE, - &mp->rx_ring_phys, GFP_KERNEL); - if (mp->rx_ring == NULL) { - printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name); - goto out2; + if (mp->tx_ring==NULL || mp->rx_ring==NULL) { + if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES); + if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0); + free_irq(dev->irq, dev); + free_irq(mp->dma_intr, dev); + printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name); + return -ENOMEM; } + mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring); + mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring); + + /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ + + kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER); + kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH); + mace_dma_off(dev); /* Not sure what these do */ @@ -418,22 +348,34 @@ static int mace_open(struct net_device *dev) psc_write_word(PSC_ENETWR_CTL, 0x0400); psc_write_word(PSC_ENETRD_CTL, 0x0400); - mace_rxdma_reset(dev); - mace_txdma_reset(dev); +#if 0 + /* load up the hardware address */ + + mb->iac = ADDRCHG | PHYADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i]; + + /* clear the multicast filter */ + mb->iac = ADDRCHG | LOGADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = 0; + + mb->plscc = PORTSEL_GPSI + ENPLSIO; - /* turn it on! */ mb->maccc = ENXMT | ENRCV; - /* enable all interrupts except receive interrupts */ mb->imr = RCVINT; - return 0; +#endif -out2: - dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, - mp->tx_ring, mp->tx_ring_phys); -out1: - free_irq(dev->irq, dev); - free_irq(mp->dma_intr, dev); - return -ENOMEM; + mace_rxdma_reset(dev); + mace_txdma_reset(dev); + + return 0; } /* @@ -442,13 +384,19 @@ static int mace_open(struct net_device *dev) static int mace_close(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; mb->maccc = 0; /* disable rx and tx */ mb->imr = 0xFF; /* disable all irqs */ mace_dma_off(dev); /* disable rx and tx dma */ + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); + + free_pages((u32) mp->rx_ring, N_RX_PAGES); + free_pages((u32) mp->tx_ring, 0); + return 0; } @@ -458,26 +406,22 @@ static int mace_close(struct net_device *dev) static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); - unsigned long flags; + struct mace_data *mp = (struct mace_data *) dev->priv; - /* Stop the queue since there's only the one buffer */ + /* Stop the queue if the buffer is full */ - local_irq_save(flags); - netif_stop_queue(dev); if (!mp->tx_count) { - printk(KERN_ERR "macmace: tx queue running but no free buffers.\n"); - local_irq_restore(flags); - return NETDEV_TX_BUSY; + netif_stop_queue(dev); + return 1; } mp->tx_count--; - local_irq_restore(flags); mp->stats.tx_packets++; mp->stats.tx_bytes += skb->len; /* We need to copy into our xmit buffer to take care of alignment and caching issues */ - skb_copy_from_linear_data(skb, mp->tx_ring, skb->len); + + memcpy((void *) mp->tx_ring, skb->data, skb->len); /* load the Tx DMA and fire it off */ @@ -489,26 +433,23 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - dev->trans_start = jiffies; - return NETDEV_TX_OK; + return 0; } static struct net_device_stats *mace_stats(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); - return &mp->stats; + struct mace_data *p = (struct mace_data *) dev->priv; + return &p->stats; } static void mace_set_multicast(struct net_device *dev) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; int i, j; u32 crc; u8 maccc; - unsigned long flags; - local_irq_save(flags); maccc = mb->maccc; mb->maccc &= ~PROM; @@ -533,122 +474,116 @@ static void mace_set_multicast(struct net_device *dev) } } - if (mp->chipid == BROKEN_ADDRCHG_REV) - mb->iac = LOGADDR; - else { - mb->iac = ADDRCHG | LOGADDR; - while ((mb->iac & ADDRCHG) != 0) - ; - } - for (i = 0; i < 8; ++i) + mb->iac = ADDRCHG | LOGADDR; + while (mb->iac & ADDRCHG); + + for (i = 0; i < 8; ++i) { mb->ladrf = multicast_filter[i]; - if (mp->chipid != BROKEN_ADDRCHG_REV) - mb->iac = 0; + } } mb->maccc = maccc; - local_irq_restore(flags); } +/* + * Miscellaneous interrupts are handled here. We may end up + * having to bash the chip on the head for bad errors + */ + static void mace_handle_misc_intrs(struct mace_data *mp, int intr) { volatile struct mace *mb = mp->mace; static int mace_babbles, mace_jabbers; - if (intr & MPCO) + if (intr & MPCO) { mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ - if (intr & RNTPCO) + } + mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + + if (intr & RNTPCO) { mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ - if (intr & CERR) + } + mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + + if (intr & CERR) { ++mp->stats.tx_heartbeat_errors; - if (intr & BABBLE) - if (mace_babbles++ < 4) - printk(KERN_DEBUG "macmace: babbling transmitter\n"); - if (intr & JABBER) - if (mace_jabbers++ < 4) - printk(KERN_DEBUG "macmace: jabbering transceiver\n"); + } + if (intr & BABBLE) { + if (mace_babbles++ < 4) { + printk(KERN_DEBUG "mace: babbling transmitter\n"); + } + } + if (intr & JABBER) { + if (mace_jabbers++ < 4) { + printk(KERN_DEBUG "mace: jabbering transceiver\n"); + } + } } -static irqreturn_t mace_interrupt(int irq, void *dev_id) +/* + * A transmit error has occurred. (We kick the transmit side from + * the DMA completion) + */ + +static void mace_xmit_error(struct net_device *dev) { - struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; - int intr, fs; - unsigned int flags; + u8 xmtfs, xmtrc; - /* don't want the dma interrupt handler to fire */ - local_irq_save(flags); + xmtfs = mb->xmtfs; + xmtrc = mb->xmtrc; - intr = mb->ir; /* read interrupt register */ - mace_handle_misc_intrs(mp, intr); - - if (intr & XMTINT) { - fs = mb->xmtfs; - if ((fs & XMTSV) == 0) { - printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs); - mace_reset(dev); - /* - * XXX mace likes to hang the machine after a xmtfs error. - * This is hard to reproduce, reseting *may* help - */ + if (xmtfs & XMTSV) { + if (xmtfs & UFLO) { + printk("%s: DMA underrun.\n", dev->name); + mp->stats.tx_errors++; + mp->stats.tx_fifo_errors++; + mace_txdma_reset(dev); } - /* dma should have finished */ - if (!mp->tx_count) { - printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs); - } - /* Update stats */ - if (fs & (UFLO|LCOL|LCAR|RTRY)) { - ++mp->stats.tx_errors; - if (fs & LCAR) - ++mp->stats.tx_carrier_errors; - else if (fs & (UFLO|LCOL|RTRY)) { - ++mp->stats.tx_aborted_errors; - if (mb->xmtfs & UFLO) { - printk(KERN_ERR "%s: DMA underrun.\n", dev->name); - mp->stats.tx_fifo_errors++; - mace_txdma_reset(dev); - } - } + if (xmtfs & RTRY) { + mp->stats.collisions++; } } +} - if (mp->tx_count) - netif_wake_queue(dev); - - local_irq_restore(flags); +/* + * A receive interrupt occurred. + */ - return IRQ_HANDLED; +static void mace_recv_interrupt(struct net_device *dev) +{ +/* struct mace_data *mp = (struct mace_data *) dev->priv; */ +// volatile struct mace *mb = mp->mace; } -static void mace_tx_timeout(struct net_device *dev) +/* + * Process the chip interrupt + */ + +static irqreturn_t mace_interrupt(int irq, void *dev_id) { - struct mace_data *mp = netdev_priv(dev); + struct net_device *dev = (struct net_device *) dev_id; + struct mace_data *mp = (struct mace_data *) dev->priv; volatile struct mace *mb = mp->mace; - unsigned long flags; + u8 ir; - local_irq_save(flags); - - /* turn off both tx and rx and reset the chip */ - mb->maccc = 0; - printk(KERN_ERR "macmace: transmit timeout - resetting\n"); - mace_txdma_reset(dev); - mace_reset(dev); - - /* restart rx dma */ - mace_rxdma_reset(dev); - - mp->tx_count = N_TX_RING; - netif_wake_queue(dev); + ir = mb->ir; + mace_handle_misc_intrs(mp, ir); - /* turn it on! */ - mb->maccc = ENXMT | ENRCV; - /* enable all interrupts except receive interrupts */ - mb->imr = RCVINT; + if (ir & XMTINT) { + mace_xmit_error(dev); + } + if (ir & RCVINT) { + mace_recv_interrupt(dev); + } + return IRQ_HANDLED; +} - local_irq_restore(flags); +static void mace_tx_timeout(struct net_device *dev) +{ +/* struct mace_data *mp = (struct mace_data *) dev->priv; */ +// volatile struct mace *mb = mp->mace; } /* @@ -657,39 +592,41 @@ static void mace_tx_timeout(struct net_device *dev) static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) { - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; struct sk_buff *skb; - unsigned int frame_status = mf->rcvsts; - if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { + if (mf->status & RS_OFLO) { + printk("%s: fifo overflow.\n", dev->name); + mp->stats.rx_errors++; + mp->stats.rx_fifo_errors++; + } + if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) mp->stats.rx_errors++; - if (frame_status & RS_OFLO) { - printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); - mp->stats.rx_fifo_errors++; - } - if (frame_status & RS_CLSN) - mp->stats.collisions++; - if (frame_status & RS_FRAMERR) - mp->stats.rx_frame_errors++; - if (frame_status & RS_FCSERR) - mp->stats.rx_crc_errors++; - } else { - unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); - skb = dev_alloc_skb(frame_length + 2); - if (!skb) { - mp->stats.rx_dropped++; - return; - } - skb_reserve(skb, 2); - memcpy(skb_put(skb, frame_length), mf->data, frame_length); - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - mp->stats.rx_packets++; - mp->stats.rx_bytes += frame_length; + if (mf->status&RS_CLSN) { + mp->stats.collisions++; + } + if (mf->status&RS_FRAMERR) { + mp->stats.rx_frame_errors++; } + if (mf->status&RS_FCSERR) { + mp->stats.rx_crc_errors++; + } + + skb = dev_alloc_skb(mf->len+2); + if (!skb) { + mp->stats.rx_dropped++; + return; + } + skb_reserve(skb,2); + memcpy(skb_put(skb, mf->len), mf->data, mf->len); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + mp->stats.rx_packets++; + mp->stats.rx_bytes += mf->len; } /* @@ -699,7 +636,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) static irqreturn_t mace_dma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = netdev_priv(dev); + struct mace_data *mp = (struct mace_data *) dev->priv; int left, head; u16 status; u32 baka; @@ -726,8 +663,7 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id) /* Loop through the ring buffer and process new packages */ while (mp->rx_tail < head) { - mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring - + (mp->rx_tail * MACE_BUFF_SIZE))); + mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800))); mp->rx_tail++; } @@ -754,76 +690,9 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id) psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); mp->tx_sloti ^= 0x10; mp->tx_count++; + netif_wake_queue(dev); } return IRQ_HANDLED; } MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Macintosh MACE ethernet driver"); - -static int __devexit mac_mace_device_remove (struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct mace_data *mp = netdev_priv(dev); - - unregister_netdev(dev); - - free_irq(dev->irq, dev); - free_irq(IRQ_MAC_MACE_DMA, dev); - - dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE, - mp->rx_ring, mp->rx_ring_phys); - dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, - mp->tx_ring, mp->tx_ring_phys); - - free_netdev(dev); - - return 0; -} - -static struct platform_driver mac_mace_driver = { - .probe = mace_probe, - .remove = __devexit_p(mac_mace_device_remove), - .driver = { - .name = mac_mace_string, - }, -}; - -static int __init mac_mace_init_module(void) -{ - int err; - - if ((err = platform_driver_register(&mac_mace_driver))) { - printk(KERN_ERR "Driver registration failed\n"); - return err; - } - - mac_mace_device = platform_device_alloc(mac_mace_string, 0); - if (!mac_mace_device) - goto out_unregister; - - if (platform_device_add(mac_mace_device)) { - platform_device_put(mac_mace_device); - mac_mace_device = NULL; - } - - return 0; - -out_unregister: - platform_driver_unregister(&mac_mace_driver); - - return -ENOMEM; -} - -static void __exit mac_mace_cleanup_module(void) -{ - platform_driver_unregister(&mac_mace_driver); - - if (mac_mace_device) { - platform_device_unregister(mac_mace_device); - mac_mace_device = NULL; - } -} - -module_init(mac_mace_init_module); -module_exit(mac_mace_cleanup_module); diff --git a/trunk/drivers/net/macsonic.c b/trunk/drivers/net/macsonic.c index e9ecdbf352ae..8ca57a0a4c11 100644 --- a/trunk/drivers/net/macsonic.c +++ b/trunk/drivers/net/macsonic.c @@ -130,46 +130,6 @@ static inline void bit_reverse_addr(unsigned char addr[6]) addr[i] = bitrev8(addr[i]); } -static irqreturn_t macsonic_interrupt(int irq, void *dev_id) -{ - irqreturn_t result; - unsigned long flags; - - local_irq_save(flags); - result = sonic_interrupt(irq, dev_id); - local_irq_restore(flags); - return result; -} - -static int macsonic_open(struct net_device* dev) -{ - if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { - printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return -EAGAIN; - } - /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes - * in at priority level 3. However, we sometimes get the level 2 inter- - * rupt as well, which must prevent re-entrance of the sonic handler. - */ - if (dev->irq == IRQ_AUTO_3) - if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { - printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9); - free_irq(dev->irq, dev); - return -EAGAIN; - } - return sonic_open(dev); -} - -static int macsonic_close(struct net_device* dev) -{ - int err; - err = sonic_close(dev); - free_irq(dev->irq, dev); - if (dev->irq == IRQ_AUTO_3) - free_irq(IRQ_NUBUS_9, dev); - return err; -} - int __init macsonic_init(struct net_device* dev) { struct sonic_local* lp = netdev_priv(dev); @@ -200,8 +160,8 @@ int __init macsonic_init(struct net_device* dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = macsonic_open; - dev->stop = macsonic_close; + dev->open = sonic_open; + dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; @@ -442,7 +402,7 @@ int __init macsonic_ident(struct nubus_dev* ndev) ndev->dr_sw == NUBUS_DRSW_DAYNA) return MACSONIC_DAYNA; - if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC && + if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC && ndev->dr_sw == 0) { /* huh? */ return MACSONIC_APPLE16; } @@ -562,7 +522,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) return macsonic_init(dev); } -static int __init mac_sonic_probe(struct platform_device *pdev) +static int __init mac_sonic_probe(struct platform_device *device) { struct net_device *dev; struct sonic_local *lp; @@ -574,8 +534,8 @@ static int __init mac_sonic_probe(struct platform_device *pdev) return -ENOMEM; lp = netdev_priv(dev); - lp->device = &pdev->dev; - SET_NETDEV_DEV(dev, &pdev->dev); + lp->device = &device->dev; + SET_NETDEV_DEV(dev, &device->dev); SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ @@ -612,17 +572,19 @@ MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); +#define SONIC_IRQ_FLAG IRQ_FLG_FAST + #include "sonic.c" -static int __devexit mac_sonic_device_remove (struct platform_device *pdev) +static int __devexit mac_sonic_device_remove (struct platform_device *device) { - struct net_device *dev = platform_get_drvdata(pdev); + struct net_device *dev = platform_get_drvdata(device); struct sonic_local* lp = netdev_priv(dev); - unregister_netdev(dev); + unregister_netdev (dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); - free_netdev(dev); + free_netdev (dev); return 0; } @@ -645,8 +607,9 @@ static int __init mac_sonic_init_module(void) } mac_sonic_device = platform_device_alloc(mac_sonic_string, 0); - if (!mac_sonic_device) + if (!mac_sonic_device) { goto out_unregister; + } if (platform_device_add(mac_sonic_device)) { platform_device_put(mac_sonic_device); diff --git a/trunk/drivers/net/meth.c b/trunk/drivers/net/meth.c index 0343ea12b299..7e69ca6edd91 100644 --- a/trunk/drivers/net/meth.c +++ b/trunk/drivers/net/meth.c @@ -421,6 +421,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) /* Write metadata, and then pass to the receive level */ skb_put(skb_c, len); priv->rx_skbs[priv->rx_write] = skb; + skb_c->dev = dev; skb_c->protocol = eth_type_trans(skb_c, dev); dev->last_rx = jiffies; priv->stats.rx_packets++; @@ -608,7 +609,7 @@ static void meth_tx_short_prepare(struct meth_private *priv, desc->header.raw = METH_TX_CMD_INT_EN | (len-1) | ((128-len) << 16); /* maybe I should set whole thing to 0 first... */ - skb_copy_from_linear_data(skb, desc->data.dt + (120 - len), skb->len); + memcpy(desc->data.dt + (120 - len), skb->data, skb->len); if (skb->len < len) memset(desc->data.dt + 120 - len + skb->len, 0, len-skb->len); } @@ -626,8 +627,8 @@ static void meth_tx_1page_prepare(struct meth_private *priv, /* unaligned part */ if (unaligned_len) { - skb_copy_from_linear_data(skb, desc->data.dt + (120 - unaligned_len), - unaligned_len); + memcpy(desc->data.dt + (120 - unaligned_len), + skb->data, unaligned_len); desc->header.raw |= (128 - unaligned_len) << 16; } @@ -652,8 +653,8 @@ static void meth_tx_2page_prepare(struct meth_private *priv, desc->header.raw = METH_TX_CMD_INT_EN | TX_CATBUF1 | TX_CATBUF2| (skb->len - 1); /* unaligned part */ if (unaligned_len){ - skb_copy_from_linear_data(skb, desc->data.dt + (120 - unaligned_len), - unaligned_len); + memcpy(desc->data.dt + (120 - unaligned_len), + skb->data, unaligned_len); desc->header.raw |= (128 - unaligned_len) << 16; } diff --git a/trunk/drivers/net/mii.c b/trunk/drivers/net/mii.c index 92056051f269..2912a34f597b 100644 --- a/trunk/drivers/net/mii.c +++ b/trunk/drivers/net/mii.c @@ -33,13 +33,6 @@ #include #include -/** - * mii_ethtool_gset - get settings that are specified in @ecmd - * @mii: MII interface - * @ecmd: requested ethtool_cmd - * - * Returns 0 for success, negative on error. - */ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; @@ -121,13 +114,6 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } -/** - * mii_ethtool_sset - set settings that are specified in @ecmd - * @mii: MII interface - * @ecmd: requested ethtool_cmd - * - * Returns 0 for success, negative on error. - */ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; @@ -221,10 +207,6 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return 0; } -/** - * mii_check_gmii_support - check if the MII supports Gb interfaces - * @mii: the MII interface - */ int mii_check_gmii_support(struct mii_if_info *mii) { int reg; @@ -239,12 +221,6 @@ int mii_check_gmii_support(struct mii_if_info *mii) return 0; } -/** - * mii_link_ok - is link status up/ok - * @mii: the MII interface - * - * Returns 1 if the MII reports link status up/ok, 0 otherwise. - */ int mii_link_ok (struct mii_if_info *mii) { /* first, a dummy read, needed to latch some MII phys */ @@ -254,12 +230,6 @@ int mii_link_ok (struct mii_if_info *mii) return 0; } -/** - * mii_nway_restart - restart NWay (autonegotiation) for this interface - * @mii: the MII interface - * - * Returns 0 on success, negative on error. - */ int mii_nway_restart (struct mii_if_info *mii) { int bmcr; @@ -277,14 +247,6 @@ int mii_nway_restart (struct mii_if_info *mii) return r; } -/** - * mii_check_link - check MII link status - * @mii: MII interface - * - * If the link status changed (previous != current), call - * netif_carrier_on() if current link status is Up or call - * netif_carrier_off() if current link status is Down. - */ void mii_check_link (struct mii_if_info *mii) { int cur_link = mii_link_ok(mii); @@ -296,15 +258,6 @@ void mii_check_link (struct mii_if_info *mii) netif_carrier_off(mii->dev); } -/** - * mii_check_media - check the MII interface for a duplex change - * @mii: the MII interface - * @ok_to_print: OK to print link up/down messages - * @init_media: OK to save duplex mode in @mii - * - * Returns 1 if the duplex mode changed, 0 if not. - * If the media type is forced, always returns 0. - */ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, unsigned int init_media) @@ -373,16 +326,6 @@ unsigned int mii_check_media (struct mii_if_info *mii, return 0; /* duplex did not change */ } -/** - * generic_mii_ioctl - main MII ioctl interface - * @mii_if: the MII interface - * @mii_data: MII ioctl data structure - * @cmd: MII ioctl command - * @duplex_chg_out: pointer to @duplex_changed status if there was no - * ioctl error - * - * Returns 0 on success, negative on error. - */ int generic_mii_ioctl(struct mii_if_info *mii_if, struct mii_ioctl_data *mii_data, int cmd, unsigned int *duplex_chg_out) diff --git a/trunk/drivers/net/mipsnet.c b/trunk/drivers/net/mipsnet.c index 638a279ec505..f42b9e201937 100644 --- a/trunk/drivers/net/mipsnet.c +++ b/trunk/drivers/net/mipsnet.c @@ -26,6 +26,8 @@ struct mipsnet_priv { struct net_device_stats stats; }; +static struct platform_device *mips_plat_dev; + static char mipsnet_string[] = "mipsnet"; /* @@ -99,6 +101,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) return -EFAULT; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -295,17 +298,64 @@ static struct device_driver mipsnet_driver = { .remove = __devexit_p(mipsnet_device_remove), }; +static void mipsnet_platform_release(struct device *device) +{ + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device(device); + kfree(pldev); +} + static int __init mipsnet_init_module(void) { + struct platform_device *pldev; int err; printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); - err = driver_register(&mipsnet_driver); - if (err) + if (driver_register(&mipsnet_driver)) { printk(KERN_ERR "Driver registration failed\n"); + err = -ENODEV; + goto out; + } + + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unregister_driver; + } + + memset (pldev, 0, sizeof (*pldev)); + pldev->name = mipsnet_string; + pldev->id = 0; + pldev->dev.release = mipsnet_platform_release; + if (platform_device_register(pldev)) { + err = -ENODEV; + goto out_free_pldev; + } + + if (!pldev->dev.driver) { + /* + * The driver was not bound to this device, there was + * no hardware at this address. Unregister it, as the + * release fuction will take care of freeing the + * allocated structure + */ + platform_device_unregister (pldev); + } + + mips_plat_dev = pldev; + + return 0; + +out_free_pldev: + kfree(pldev); + +out_unregister_driver: + driver_unregister(&mipsnet_driver); +out: return err; } diff --git a/trunk/drivers/net/mv643xx_eth.c b/trunk/drivers/net/mv643xx_eth.c index 1799eee88db7..8015a7c5b0c9 100644 --- a/trunk/drivers/net/mv643xx_eth.c +++ b/trunk/drivers/net/mv643xx_eth.c @@ -51,8 +51,8 @@ #include "mv643xx_eth.h" /* Static function declarations */ -static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr); -static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr); +static void eth_port_uc_addr_get(struct net_device *dev, + unsigned char *MacAddr); static void eth_port_set_multicast_list(struct net_device *); static void mv643xx_eth_port_enable_tx(unsigned int port_num, unsigned int queues); @@ -434,6 +434,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) * received packet */ skb_put(skb, pkt_info.byte_cnt - 4); + skb->dev = dev; if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1161,15 +1162,15 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | ETH_GEN_IP_V_4_CHECKSUM | - ip_hdr(skb)->ihl << ETH_TX_IHL_SHIFT; + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; - switch (ip_hdr(skb)->protocol) { + switch (skb->nh.iph->protocol) { case IPPROTO_UDP: cmd_sts |= ETH_UDP_FRAME; - desc->l4i_chk = udp_hdr(skb)->check; + desc->l4i_chk = skb->h.uh->check; break; case IPPROTO_TCP: - desc->l4i_chk = tcp_hdr(skb)->check; + desc->l4i_chk = skb->h.th->check; break; default: BUG(); @@ -1381,7 +1382,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) port_num = mp->port_num = pd->port_number; /* set default config values */ - eth_port_uc_addr_get(port_num, dev->dev_addr); + eth_port_uc_addr_get(dev, dev->dev_addr); mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; @@ -1839,9 +1840,26 @@ static void eth_port_start(struct net_device *dev) } /* - * eth_port_uc_addr_set - Write a MAC address into the port's hw registers + * eth_port_uc_addr_set - This function Set the port Unicast address. + * + * DESCRIPTION: + * This function Set the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char * p_addr Address to be set + * + * OUTPUT: + * Set MAC address low and high registers. also calls + * eth_port_set_filter_table_entry() to set the unicast + * table with the proper information. + * + * RETURN: + * N/A. + * */ -static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr) +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr) { unsigned int mac_h; unsigned int mac_l; @@ -1851,24 +1869,40 @@ static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr) mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | (p_addr[3] << 0); - mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l); - mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h); + mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); + mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); - /* Accept frames with this address */ - table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num); + /* Accept frames of this address */ + table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num); eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f); } /* - * eth_port_uc_addr_get - Read the MAC address from the port's hw registers + * eth_port_uc_addr_get - This function retrieves the port Unicast address + * (MAC address) from the ethernet hw registers. + * + * DESCRIPTION: + * This function retrieves the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char *MacAddr pointer where the MAC address is stored + * + * OUTPUT: + * Copy the MAC address to the location pointed to by MacAddr + * + * RETURN: + * N/A. + * */ -static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr) +static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr) { + struct mv643xx_private *mp = netdev_priv(dev); unsigned int mac_h; unsigned int mac_l; - mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num)); - mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num)); + mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num)); + mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num)); p_addr[0] = (mac_h >> 24) & 0xff; p_addr[1] = (mac_h >> 16) & 0xff; diff --git a/trunk/drivers/net/mv643xx_eth.h b/trunk/drivers/net/mv643xx_eth.h index 82f8c0cbfb64..7d4e90cf49e8 100644 --- a/trunk/drivers/net/mv643xx_eth.h +++ b/trunk/drivers/net/mv643xx_eth.h @@ -346,6 +346,10 @@ static void eth_port_init(struct mv643xx_private *mp); static void eth_port_reset(unsigned int eth_port_num); static void eth_port_start(struct net_device *dev); +/* Port MAC address routines */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr); + /* PHY and MIB routines */ static void ethernet_phy_reset(unsigned int eth_port_num); diff --git a/trunk/drivers/net/myri10ge/myri10ge.c b/trunk/drivers/net/myri10ge/myri10ge.c index 16e3c4315e82..f8efe0e70a6b 100644 --- a/trunk/drivers/net/myri10ge/myri10ge.c +++ b/trunk/drivers/net/myri10ge/myri10ge.c @@ -879,7 +879,7 @@ myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va, * skb_pull() (for ether_pad and eth_type_trans()) requires * the beginning of the packet in skb_headlen(), move it * manually */ - skb_copy_to_linear_data(skb, va, hlen); + memcpy(skb->data, va, hlen); skb_shinfo(skb)->frags[0].page_offset += hlen; skb_shinfo(skb)->frags[0].size -= hlen; skb->data_len -= hlen; @@ -1020,6 +1020,7 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, skb_shinfo(skb)->nr_frags = 0; } skb->protocol = eth_type_trans(skb, dev); + skb->dev = dev; if (mgp->csum_flag) { if ((skb->protocol == htons(ETH_P_IP)) || @@ -2029,7 +2030,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) odd_flag = 0; flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { - cksum_offset = skb_transport_offset(skb); + cksum_offset = (skb->h.raw - skb->data); pseudo_hdr_offset = cksum_offset + skb->csum_offset; /* If the headers are excessively large, then we must * fall back to a software checksum */ @@ -2054,7 +2055,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) * send loop that we are still in the * header portion of the TSO packet. * TSO header must be at most 134 bytes long */ - cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb)); + cum_len = -((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); /* for TSO, pseudo_hdr_offset holds mss. * The firmware figures out where to put diff --git a/trunk/drivers/net/myri_sbus.c b/trunk/drivers/net/myri_sbus.c index 13444da93273..ee26ef52289f 100644 --- a/trunk/drivers/net/myri_sbus.c +++ b/trunk/drivers/net/myri_sbus.c @@ -368,7 +368,7 @@ static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev) struct ethhdr *eth; unsigned char *rawp; - skb_set_mac_header(skb, MYRI_PAD_LEN); + skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN); skb_pull(skb, dev->hard_header_len); eth = eth_hdr(skb); @@ -502,7 +502,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) copy_skb->dev = dev; DRX(("resv_and_put ")); skb_put(copy_skb, len); - skb_copy_from_linear_data(skb, copy_skb->data, len); + memcpy(copy_skb->data, skb->data, len); /* Reuse original ring buffer. */ DRX(("reuse ")); diff --git a/trunk/drivers/net/natsemi.c b/trunk/drivers/net/natsemi.c index a8d7ff2c96ac..349b96a3ec4c 100644 --- a/trunk/drivers/net/natsemi.c +++ b/trunk/drivers/net/natsemi.c @@ -2289,6 +2289,7 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { + skb->dev = dev; /* 16 byte align the IP header */ skb_reserve(skb, RX_OFFSET); pci_dma_sync_single_for_cpu(np->pci_dev, diff --git a/trunk/drivers/net/netx-eth.c b/trunk/drivers/net/netx-eth.c index 2b8da0a54998..a53644f6a29b 100644 --- a/trunk/drivers/net/netx-eth.c +++ b/trunk/drivers/net/netx-eth.c @@ -168,6 +168,7 @@ static void netx_eth_receive(struct net_device *ndev) FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); ndev->last_rx = jiffies; + skb->dev = ndev; skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); priv->stats.rx_packets++; diff --git a/trunk/drivers/net/netxen/netxen_nic.h b/trunk/drivers/net/netxen/netxen_nic.h index ad6688eab265..dd8ce35332fe 100644 --- a/trunk/drivers/net/netxen/netxen_nic.h +++ b/trunk/drivers/net/netxen/netxen_nic.h @@ -64,9 +64,9 @@ #include "netxen_nic_hw.h" #define _NETXEN_NIC_LINUX_MAJOR 3 -#define _NETXEN_NIC_LINUX_MINOR 4 -#define _NETXEN_NIC_LINUX_SUBVERSION 2 -#define NETXEN_NIC_LINUX_VERSIONID "3.4.2" +#define _NETXEN_NIC_LINUX_MINOR 3 +#define _NETXEN_NIC_LINUX_SUBVERSION 3 +#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" #define NUM_FLASH_SECTORS (64) #define FLASH_SECTOR_SIZE (64 * 1024) @@ -131,8 +131,8 @@ extern struct workqueue_struct *netxen_workq; #define FIRST_PAGE_GROUP_START 0 #define FIRST_PAGE_GROUP_END 0x100000 -#define SECOND_PAGE_GROUP_START 0x6000000 -#define SECOND_PAGE_GROUP_END 0x68BC000 +#define SECOND_PAGE_GROUP_START 0x4000000 +#define SECOND_PAGE_GROUP_END 0x66BC000 #define THIRD_PAGE_GROUP_START 0x70E4000 #define THIRD_PAGE_GROUP_END 0x8000000 @@ -205,8 +205,6 @@ enum { #define MAX_CMD_DESCRIPTORS 1024 #define MAX_RCV_DESCRIPTORS 16384 -#define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4) -#define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4) #define MAX_JUMBO_RCV_DESCRIPTORS 1024 #define MAX_LRO_RCV_DESCRIPTORS 64 #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS @@ -232,9 +230,7 @@ enum { (((index) + (count)) & ((length) - 1)) #define MPORT_SINGLE_FUNCTION_MODE 0x1111 -#define MPORT_MULTI_FUNCTION_MODE 0x2222 -#include "netxen_nic_phan_reg.h" extern unsigned long long netxen_dma_mask; extern unsigned long last_schedule_time; @@ -304,8 +300,6 @@ struct netxen_ring_ctx { #define netxen_set_cmd_desc_port(cmd_desc, var) \ ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) -#define netxen_set_cmd_desc_ctxid(cmd_desc, var) \ - ((cmd_desc)->port_ctxid |= ((var) & 0xF0)) #define netxen_set_cmd_desc_flags(cmd_desc, val) \ ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \ @@ -448,7 +442,7 @@ struct status_desc { /* Bit pattern: 0-6 lro_count indicates frag sequence, 7 last_frag indicates last frag */ u8 lro; -} __attribute__ ((aligned(16))); +} __attribute__ ((aligned(8))); enum { NETXEN_RCV_PEG_0 = 0, @@ -709,8 +703,10 @@ extern char netxen_nic_driver_name[]; #else #define DPRINTK(klevel, fmt, args...) do { \ printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\ - (adapter != NULL && adapter->netdev != NULL) ? \ - adapter->netdev->name : NULL, \ + (adapter != NULL && \ + adapter->port[0] != NULL && \ + adapter->port[0]->netdev != NULL) ? \ + adapter->port[0]->netdev->name : NULL, \ ## args); } while(0) #endif @@ -726,18 +722,6 @@ struct netxen_skb_frag { u32 length; }; -#define _netxen_set_bits(config_word, start, bits, val) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\ - unsigned long long __tvalue = (val); \ - (config_word) &= ~__tmask; \ - (config_word) |= (((__tvalue) << (start)) & __tmask); \ -} - -#define _netxen_clear_bits(config_word, start, bits) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \ - (config_word) &= ~__tmask; \ -} - /* Following defines are for the state of the buffers */ #define NETXEN_BUFFER_FREE 0 #define NETXEN_BUFFER_BUSY 1 @@ -782,8 +766,6 @@ struct netxen_hardware_context { void __iomem *pci_base0; void __iomem *pci_base1; void __iomem *pci_base2; - unsigned long first_page_group_end; - unsigned long first_page_group_start; void __iomem *db_base; unsigned long db_len; @@ -798,7 +780,6 @@ struct netxen_hardware_context { struct pci_dev *cmd_desc_pdev; dma_addr_t cmd_desc_phys_addr; struct netxen_adapter *adapter; - int pci_func; }; #define RCV_RING_LRO RCV_DESC_LRO @@ -807,27 +788,17 @@ struct netxen_hardware_context { #define ETHERNET_FCS_SIZE 4 struct netxen_adapter_stats { - u64 rcvdbadskb; - u64 xmitcalled; - u64 xmitedframes; - u64 xmitfinished; - u64 badskblen; - u64 nocmddescriptor; - u64 polled; - u64 uphappy; - u64 updropped; - u64 uplcong; - u64 uphcong; - u64 upmcong; - u64 updunno; - u64 skbfreed; - u64 txdropped; - u64 txnullskb; - u64 csummed; - u64 no_rcv; - u64 rxbytes; - u64 txbytes; - u64 ints; + u64 ints; + u64 hostints; + u64 otherints; + u64 process_rcv; + u64 process_xmit; + u64 noxmitdone; + u64 xmitcsummed; + u64 post_called; + u64 posted; + u64 lastposted; + u64 goodskbposts; }; /* @@ -875,20 +846,13 @@ struct netxen_dummy_dma { struct netxen_adapter { struct netxen_hardware_context ahw; - - struct netxen_adapter *master; - struct net_device *netdev; - struct pci_dev *pdev; - struct net_device_stats net_stats; - unsigned char mac_addr[ETH_ALEN]; - int mtu; - int portnum; - + int port_count; /* Number of configured ports */ + int active_ports; /* Number of open ports */ + struct netxen_port *port[NETXEN_MAX_PORTS]; /* ptr to each port */ spinlock_t tx_lock; spinlock_t lock; struct work_struct watchdog_task; struct timer_list watchdog_timer; - struct work_struct tx_timeout_task; u32 curr_window; @@ -911,15 +875,6 @@ struct netxen_adapter { u32 temp; struct netxen_adapter_stats stats; - - u16 portno; - u16 link_speed; - u16 link_duplex; - u16 state; - u16 link_autoneg; - int rcsum; - int status; - spinlock_t stats_lock; struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ @@ -936,23 +891,65 @@ struct netxen_adapter { struct netxen_ring_ctx *ctx_desc; struct pci_dev *ctx_desc_pdev; dma_addr_t ctx_desc_phys_addr; - int (*enable_phy_interrupts) (struct netxen_adapter *); - int (*disable_phy_interrupts) (struct netxen_adapter *); + int (*enable_phy_interrupts) (struct netxen_adapter *, int); + int (*disable_phy_interrupts) (struct netxen_adapter *, int); void (*handle_phy_intr) (struct netxen_adapter *); - int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); - int (*set_mtu) (struct netxen_adapter *, int); - int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t); - int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t); - int (*phy_read) (struct netxen_adapter *, long reg, u32 *); - int (*phy_write) (struct netxen_adapter *, long reg, u32 val); + int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t); + int (*set_mtu) (struct netxen_port *, int); + int (*set_promisc) (struct netxen_adapter *, int, + netxen_niu_prom_mode_t); + int (*unset_promisc) (struct netxen_adapter *, int, + netxen_niu_prom_mode_t); + int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *); + int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val); int (*init_port) (struct netxen_adapter *, int); void (*init_niu) (struct netxen_adapter *); - int (*stop_port) (struct netxen_adapter *); + int (*stop_port) (struct netxen_adapter *, int); }; /* netxen_adapter structure */ /* Max number of xmit producer threads that can run simultaneously */ #define MAX_XMIT_PRODUCERS 16 +struct netxen_port_stats { + u64 rcvdbadskb; + u64 xmitcalled; + u64 xmitedframes; + u64 xmitfinished; + u64 badskblen; + u64 nocmddescriptor; + u64 polled; + u64 uphappy; + u64 updropped; + u64 uplcong; + u64 uphcong; + u64 upmcong; + u64 updunno; + u64 skbfreed; + u64 txdropped; + u64 txnullskb; + u64 csummed; + u64 no_rcv; + u64 rxbytes; + u64 txbytes; +}; + +struct netxen_port { + struct netxen_adapter *adapter; + + u16 portnum; /* GBE port number */ + u16 link_speed; + u16 link_duplex; + u16 link_autoneg; + + int flags; + + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + struct netxen_port_stats stats; + struct work_struct tx_timeout_task; +}; + #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ ((adapter)->ahw.pci_base0 + (off)) #define PCI_OFFSET_SECOND_RANGE(adapter, off) \ @@ -990,26 +987,32 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter, return NULL; } -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter); +int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter, + int port); +int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, + int port); +int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port); +int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port); +int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port); +int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port); void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter); void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter); void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, long enable); void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, long enable); -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, +int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg, __u32 * readval); -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, +int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy, long reg, __u32 val); /* Functions available from netxen_nic_hw.c */ -int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); -int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); +int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu); +int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu); void netxen_nic_init_niu_gb(struct netxen_adapter *adapter); void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw); void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); @@ -1024,7 +1027,6 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, int data); -int netxen_nic_erase_pxe(struct netxen_adapter *adapter); /* Functions from netxen_nic_init.c */ void netxen_free_adapter_offload(struct netxen_adapter *adapter); @@ -1049,8 +1051,11 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr); /* Functions from netxen_nic_isr.c */ void netxen_nic_isr_other(struct netxen_adapter *adapter); -void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link); -void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable); +void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port, + u32 link); +void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port, + u32 enable); +void netxen_nic_stop_all_ports(struct netxen_adapter *adapter); void netxen_initialize_adapter_sw(struct netxen_adapter *adapter); void netxen_initialize_adapter_hw(struct netxen_adapter *adapter); void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr, @@ -1105,7 +1110,6 @@ static inline void netxen_nic_enable_int(struct netxen_adapter *adapter) if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { mask = 0xbff; - writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_TARGET_MASK)); } @@ -1170,5 +1174,4 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, extern struct ethtool_ops netxen_nic_ethtool_ops; -extern int physical_port[]; /* physical port # from virtual port.*/ #endif /* __NETXEN_NIC_H_ */ diff --git a/trunk/drivers/net/netxen/netxen_nic_ethtool.c b/trunk/drivers/net/netxen/netxen_nic_ethtool.c index 16fabb377488..ee1b5a24cbe7 100644 --- a/trunk/drivers/net/netxen/netxen_nic_ethtool.c +++ b/trunk/drivers/net/netxen/netxen_nic_ethtool.c @@ -40,8 +40,8 @@ #include #include -#include "netxen_nic.h" #include "netxen_nic_hw.h" +#include "netxen_nic.h" #include "netxen_nic_phan_reg.h" struct netxen_nic_stats { @@ -50,8 +50,8 @@ struct netxen_nic_stats { int stat_offset; }; -#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \ - offsetof(struct netxen_adapter, m) +#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \ + offsetof(struct netxen_port, m) #define NETXEN_NIC_PORT_WINDOW 0x10000 #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF @@ -100,7 +100,8 @@ static int netxen_nic_get_eeprom_len(struct net_device *dev) static void netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; u32 fw_major = 0; u32 fw_minor = 0; u32 fw_build = 0; @@ -114,7 +115,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB)); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); - strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + strncpy(drvinfo->bus_info, pci_name(port->pdev), 32); drvinfo->n_stats = NETXEN_NIC_STATS_LEN; drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN; drvinfo->regdump_len = NETXEN_NIC_REGS_LEN; @@ -124,7 +125,8 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) static int netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg; /* read which mode */ @@ -144,8 +146,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->port = PORT_TP; if (netif_running(dev)) { - ecmd->speed = adapter->link_speed; - ecmd->duplex = adapter->link_duplex; + ecmd->speed = port->link_speed; + ecmd->duplex = port->link_duplex; } else return -EIO; /* link absent */ } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { @@ -163,7 +165,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else return -EIO; - ecmd->phy_address = adapter->portnum; + ecmd->phy_address = port->portnum; ecmd->transceiver = XCVR_EXTERNAL; switch ((netxen_brdtype_t) boardinfo->board_type) { @@ -177,7 +179,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->port = PORT_TP; ecmd->autoneg = (boardinfo->board_type == NETXEN_BRDTYPE_P2_SB31_10G_CX4) ? - (AUTONEG_DISABLE) : (adapter->link_autoneg); + (AUTONEG_DISABLE) : (port->link_autoneg); break; case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: @@ -204,22 +206,23 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; __u32 status; /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { /* autonegotiation */ if (adapter->phy_write - && adapter->phy_write(adapter, + && adapter->phy_write(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, ecmd->autoneg) != 0) return -EIO; else - adapter->link_autoneg = ecmd->autoneg; + port->link_autoneg = ecmd->autoneg; if (adapter->phy_read - && adapter->phy_read(adapter, + && adapter->phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) != 0) return -EIO; @@ -242,13 +245,13 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->duplex == DUPLEX_FULL) netxen_set_phy_duplex(status); if (adapter->phy_write - && adapter->phy_write(adapter, + && adapter->phy_write(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, *((int *)&status)) != 0) return -EIO; else { - adapter->link_speed = ecmd->speed; - adapter->link_duplex = ecmd->duplex; + port->link_speed = ecmd->speed; + port->link_duplex = ecmd->duplex; } } else return -EOPNOTSUPP; @@ -357,14 +360,15 @@ static struct netxen_niu_regs niu_registers[] = { static void netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; __u32 mode, *regs_buff = p; void __iomem *addr; int i, window; memset(p, 0, NETXEN_NIC_REGS_LEN); regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | - (adapter->pdev)->device; + (port->pdev)->device; /* which mode */ NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, ®s_buff[0]); mode = regs_buff[0]; @@ -379,8 +383,7 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) { /* GB: port specific registers */ if (mode == 0 && i >= 19) - window = physical_port[adapter->portnum] * - NETXEN_NIC_PORT_WINDOW; + window = port->portnum * NETXEN_NIC_PORT_WINDOW; NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode]. reg[i - 3] + window, @@ -392,14 +395,15 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) static u32 netxen_nic_test_link(struct net_device *dev) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; __u32 status; int val; /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { if (adapter->phy_read - && adapter->phy_read(adapter, + && adapter->phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) != 0) return -EIO; @@ -418,15 +422,15 @@ static int netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; int offset; int ret; if (eeprom->len == 0) return -EINVAL; - eeprom->magic = (adapter->pdev)->vendor | - ((adapter->pdev)->device << 16); + eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16); offset = eeprom->offset; ret = netxen_rom_fast_read_words(adapter, offset, bytes, @@ -441,7 +445,8 @@ static int netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; int offset = eeprom->offset; static int flash_start; static int ready_to_flash; @@ -511,7 +516,8 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, static void netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; int i; ring->rx_pending = 0; @@ -535,45 +541,19 @@ static void netxen_nic_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; __u32 val; - int port = physical_port[adapter->portnum]; if (adapter->ahw.board_type == NETXEN_NIC_GBE) { - if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) - return; /* get flow control settings */ - netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port), - &val); + netxen_nic_read_w0(adapter, + NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), + &val); pause->rx_pause = netxen_gb_get_rx_flowctl(val); - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); - switch (port) { - case 0: - pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); - break; - case 1: - pause->tx_pause = !(netxen_gb_get_gb1_mask(val)); - break; - case 2: - pause->tx_pause = !(netxen_gb_get_gb2_mask(val)); - break; - case 3: - default: - pause->tx_pause = !(netxen_gb_get_gb3_mask(val)); - break; - } - } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { - if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) - return; - pause->rx_pause = 1; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); - if (port == 0) - pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); - else - pause->tx_pause = !(netxen_xg_get_xg1_mask(val)); - } else { - printk(KERN_ERR"%s: Unknown board type: %x\n", - netxen_nic_driver_name, adapter->ahw.board_type); + pause->tx_pause = netxen_gb_get_tx_flowctl(val); + /* get autoneg settings */ + pause->autoneg = port->link_autoneg; } } @@ -581,76 +561,42 @@ static int netxen_nic_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; __u32 val; - int port = physical_port[adapter->portnum]; + unsigned int autoneg; + /* read mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { - if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) - return -EIO; /* set flow control */ netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), &val); - + NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), + (u32 *) & val); + if (pause->tx_pause) + netxen_gb_tx_flowctl(val); + else + netxen_gb_unset_tx_flowctl(val); if (pause->rx_pause) netxen_gb_rx_flowctl(val); else netxen_gb_unset_rx_flowctl(val); - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - val); + netxen_nic_write_w0(adapter, + NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), + *&val); /* set autoneg */ - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); - switch (port) { - case 0: - if (pause->tx_pause) - netxen_gb_unset_gb0_mask(val); - else - netxen_gb_set_gb0_mask(val); - break; - case 1: - if (pause->tx_pause) - netxen_gb_unset_gb1_mask(val); - else - netxen_gb_set_gb1_mask(val); - break; - case 2: - if (pause->tx_pause) - netxen_gb_unset_gb2_mask(val); - else - netxen_gb_set_gb2_mask(val); - break; - case 3: - default: - if (pause->tx_pause) - netxen_gb_unset_gb3_mask(val); - else - netxen_gb_set_gb3_mask(val); - break; - } - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); - } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { - if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) + autoneg = pause->autoneg; + if (adapter->phy_write + && adapter->phy_write(adapter, port->portnum, + NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, + autoneg) != 0) return -EIO; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); - if (port == 0) { - if (pause->tx_pause) - netxen_xg_unset_xg0_mask(val); - else - netxen_xg_set_xg0_mask(val); - } else { - if (pause->tx_pause) - netxen_xg_unset_xg1_mask(val); - else - netxen_xg_set_xg1_mask(val); + else { + port->link_autoneg = pause->autoneg; + return 0; } - netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); - } else { - printk(KERN_ERR "%s: Unknown board type: %x\n", - netxen_nic_driver_name, - adapter->ahw.board_type); - } - return 0; + } else + return -EOPNOTSUPP; } static int netxen_nic_reg_test(struct net_device *dev) @@ -681,12 +627,23 @@ static void netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data) { - memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN); - if ((data[0] = netxen_nic_reg_test(dev))) - eth_test->flags |= ETH_TEST_FL_FAILED; - /* link test */ - if ((data[1] = (u64) netxen_nic_test_link(dev))) - eth_test->flags |= ETH_TEST_FL_FAILED; + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */ + /* link test */ + if ((data[1] = (u64) netxen_nic_test_link(dev))) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* register tests */ + if ((data[0] = netxen_nic_reg_test(dev))) + eth_test->flags |= ETH_TEST_FL_FAILED; + } else { /* online tests */ + /* register tests */ + if((data[0] = netxen_nic_reg_test(dev))) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* link test */ + if ((data[1] = (u64) netxen_nic_test_link(dev))) + eth_test->flags |= ETH_TEST_FL_FAILED; + } } static void @@ -718,13 +675,12 @@ static void netxen_nic_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data) { - struct netxen_adapter *adapter = netdev_priv(dev); + struct netxen_port *port = netdev_priv(dev); int index; for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { char *p = - (char *)adapter + - netxen_nic_gstrings_stats[index].stat_offset; + (char *)port + netxen_nic_gstrings_stats[index].stat_offset; data[index] = (netxen_nic_gstrings_stats[index].sizeof_stat == sizeof(u64)) ? *(u64 *) p : *(u32 *) p; diff --git a/trunk/drivers/net/netxen/netxen_nic_hdr.h b/trunk/drivers/net/netxen/netxen_nic_hdr.h index 608e37b349b4..fe8b675f9e72 100644 --- a/trunk/drivers/net/netxen/netxen_nic_hdr.h +++ b/trunk/drivers/net/netxen/netxen_nic_hdr.h @@ -467,8 +467,6 @@ enum { #define NETXEN_PCI_OCM1 (0x05100000UL) #define NETXEN_PCI_OCM1_MAX (0x051fffffUL) #define NETXEN_PCI_CRBSPACE (0x06000000UL) -#define NETXEN_PCI_128MB_SIZE (0x08000000UL) -#define NETXEN_PCI_32MB_SIZE (0x02000000UL) #define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM) @@ -486,7 +484,6 @@ enum { /* 10 seconds before we give up */ #define NETXEN_NIU_PHY_WAITMAX 50 #define NETXEN_NIU_MAX_GBE_PORTS 4 -#define NETXEN_NIU_MAX_XG_PORTS 2 #define NETXEN_NIU_MODE (NETXEN_CRB_NIU + 0x00000) @@ -530,7 +527,6 @@ enum { #define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098) #define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc) #define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128) -#define NETXEN_NIU_GB_PAUSE_CTL (NETXEN_CRB_NIU + 0x0030c) #define NETXEN_NIU_FULL_LEVEL_XG (NETXEN_CRB_NIU + 0x00450) @@ -653,19 +649,11 @@ enum { #define PCIX_MS_WINDOW (0x10204) #define PCIX_SN_WINDOW (0x10208) #define PCIX_CRB_WINDOW (0x10210) -#define PCIX_CRB_WINDOW_F0 (0x10210) -#define PCIX_CRB_WINDOW_F1 (0x10230) -#define PCIX_CRB_WINDOW_F2 (0x10250) -#define PCIX_CRB_WINDOW_F3 (0x10270) #define PCIX_TARGET_STATUS (0x10118) #define PCIX_TARGET_MASK (0x10128) #define PCIX_MSI_F0 (0x13000) -#define PCIX_MSI_F1 (0x13004) -#define PCIX_MSI_F2 (0x13008) -#define PCIX_MSI_F3 (0x1300c) -#define PCIX_MSI_F(i) (0x13000+((i)*4)) #define PCIX_PS_MEM_SPACE (0x90000) diff --git a/trunk/drivers/net/netxen/netxen_nic_hw.c b/trunk/drivers/net/netxen/netxen_nic_hw.c index baff17a24d63..6537574a9cda 100644 --- a/trunk/drivers/net/netxen/netxen_nic_hw.c +++ b/trunk/drivers/net/netxen/netxen_nic_hw.c @@ -33,225 +33,8 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#define DEFINE_GLOBAL_RECV_CRB #include "netxen_nic_phan_reg.h" - -#include - -struct netxen_recv_crb recv_crb_registers[] = { - /* - * Instance 0. - */ - { - /* rcv_desc_crb: */ - { - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x100), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x104), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x108), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x10c), - - }, - /* Jumbo frames */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x110), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x114), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x118), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x11c), - }, - /* LRO */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x120), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x124), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x128), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x12c), - } - }, - /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x130), - /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x134), - /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x138), - /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x13c), - /* crb_status_ring_size */ - NETXEN_NIC_REG(0x140), - - }, - /* - * Instance 1, - */ - { - /* rcv_desc_crb: */ - { - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x144), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x148), - /* crb_globalrcv_ring: */ - NETXEN_NIC_REG(0x14c), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x150), - - }, - /* Jumbo frames */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x154), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x158), - /* crb_globalrcv_ring: */ - NETXEN_NIC_REG(0x15c), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x160), - }, - /* LRO */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x164), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x168), - /* crb_globalrcv_ring: */ - NETXEN_NIC_REG(0x16c), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x170), - } - - }, - /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x174), - /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x178), - /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x17c), - /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x180), - /* crb_status_ring_size */ - NETXEN_NIC_REG(0x184), - }, - /* - * Instance 2, - */ - { - { - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x1d8), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x1dc), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x1f0), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x1f4), - }, - /* Jumbo frames */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x1f8), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x1fc), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x200), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x204), - }, - /* LRO */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x208), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x20c), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x210), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x214), - } - }, - /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x218), - /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x21c), - /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x220), - /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x224), - /* crb_status_ring_size */ - NETXEN_NIC_REG(0x228), - }, - /* - * Instance 3, - */ - { - { - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x22c), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x230), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x234), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x238), - }, - /* Jumbo frames */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x23c), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x240), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x244), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x248), - }, - /* LRO */ - { - /* crb_rcv_producer_offset: */ - NETXEN_NIC_REG(0x24c), - /* crb_rcv_consumer_offset: */ - NETXEN_NIC_REG(0x250), - /* crb_gloablrcv_ring: */ - NETXEN_NIC_REG(0x254), - /* crb_rcv_ring_size */ - NETXEN_NIC_REG(0x258), - } - }, - /* crb_rcvstatus_ring: */ - NETXEN_NIC_REG(0x25c), - /* crb_rcv_status_producer: */ - NETXEN_NIC_REG(0x260), - /* crb_rcv_status_consumer: */ - NETXEN_NIC_REG(0x264), - /* crb_rcvpeg_state: */ - NETXEN_NIC_REG(0x268), - /* crb_status_ring_size */ - NETXEN_NIC_REG(0x26c), - }, -}; - -u64 ctx_addr_sig_regs[][3] = { - {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, - {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, - {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, - {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} -}; - - /* PCI Windowing for DDR regions. */ #define ADDR_IN_RANGE(addr, low, high) \ @@ -285,7 +68,8 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; struct sockaddr *addr = p; if (netif_running(netdev)) @@ -298,7 +82,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); if (adapter->macaddr_set) - adapter->macaddr_set(adapter, addr->sa_data); + adapter->macaddr_set(port, addr->sa_data); return 0; } @@ -308,19 +92,56 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) */ void netxen_nic_set_multi(struct net_device *netdev) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; struct dev_mc_list *mc_ptr; + __u32 netxen_mac_addr_cntl_data = 0; mc_ptr = netdev->mc_list; if (netdev->flags & IFF_PROMISC) { if (adapter->set_promisc) adapter->set_promisc(adapter, + port->portnum, NETXEN_NIU_PROMISC_MODE); } else { - if (adapter->unset_promisc) + if (adapter->unset_promisc && + adapter->ahw.boardcfg.board_type + != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) adapter->unset_promisc(adapter, + port->portnum, NETXEN_NIU_NON_PROMISC_MODE); } + if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { + netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03); + netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data); + netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data); + netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data); + netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data); + } else { + netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); + netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01); + netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02); + netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03); + } + writel(netxen_mac_addr_cntl_data, + NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG)); + if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { + writel(netxen_mac_addr_cntl_data, + NETXEN_CRB_NORMALIZE(adapter, + NETXEN_MULTICAST_ADDR_HI_0)); + } else { + writel(netxen_mac_addr_cntl_data, + NETXEN_CRB_NORMALIZE(adapter, + NETXEN_MULTICAST_ADDR_HI_1)); + } + netxen_mac_addr_cntl_data = 0; + writel(netxen_mac_addr_cntl_data, + NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR)); } /* @@ -329,7 +150,8 @@ void netxen_nic_set_multi(struct net_device *netdev) */ int netxen_nic_change_mtu(struct net_device *netdev, int mtu) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE; if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) { @@ -339,7 +161,7 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu) } if (adapter->set_mtu) - adapter->set_mtu(adapter, mtu); + adapter->set_mtu(port, mtu); netdev->mtu = mtu; return 0; @@ -356,9 +178,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) void *addr; int loops = 0, err = 0; int ctx, ring; + u32 card_cmdring = 0; struct netxen_recv_context *recv_ctx; struct netxen_rcv_desc_ctx *rcv_desc; - int func_id = adapter->portnum; DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE, PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE)); @@ -367,6 +189,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE, pci_base_offset(adapter, NETXEN_CAM_RAM_BASE)); + /* Window 1 call */ + card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING)); + + DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n", + card_cmdring); for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n"); @@ -400,7 +227,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) (dma_addr_t *) & adapter->ctx_desc_phys_addr, &adapter->ctx_desc_pdev); - printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n", + printk("ctx_desc_phys_addr: 0x%llx\n", (unsigned long long) adapter->ctx_desc_phys_addr); if (addr == NULL) { DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); @@ -409,7 +236,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) } memset(addr, 0, sizeof(struct netxen_ring_ctx)); adapter->ctx_desc = (struct netxen_ring_ctx *)addr; - adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum); adapter->ctx_desc->cmd_consumer_offset = cpu_to_le64(adapter->ctx_desc_phys_addr + sizeof(struct netxen_ring_ctx)); @@ -421,7 +247,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) adapter->max_tx_desc_count, (dma_addr_t *) & hw->cmd_desc_phys_addr, &adapter->ahw.cmd_desc_pdev); - printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n", + printk("cmd_desc_phys_addr: 0x%llx\n", (unsigned long long) hw->cmd_desc_phys_addr); if (addr == NULL) { @@ -480,11 +306,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) /* Window = 1 */ writel(lower32(adapter->ctx_desc_phys_addr), - NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id))); + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO)); writel(upper32(adapter->ctx_desc_phys_addr), - NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id))); - writel(NETXEN_CTX_SIGNATURE | func_id, - NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id))); + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI)); + writel(NETXEN_CTX_SIGNATURE, + NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG)); return err; } @@ -511,6 +337,10 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) adapter->ahw.cmd_desc_phys_addr); adapter->ahw.cmd_desc_head = NULL; } + /* Special handling: there are 2 ports on this board */ + if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { + adapter->ahw.max_ports = 2; + } for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { recv_ctx = &adapter->recv_ctx[ctx]; @@ -541,20 +371,22 @@ void netxen_tso_check(struct netxen_adapter *adapter, struct cmd_desc_type0 *desc, struct sk_buff *skb) { if (desc->mss) { - desc->total_hdr_length = (sizeof(struct ethhdr) + - ip_hdrlen(skb) + tcp_hdrlen(skb)); + desc->total_hdr_length = sizeof(struct ethhdr) + + ((skb->nh.iph)->ihl * sizeof(u32)) + + ((skb->h.th)->doff * sizeof(u32)); netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (ip_hdr(skb)->protocol == IPPROTO_TCP) { + if (skb->nh.iph->protocol == IPPROTO_TCP) { netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT); - } else if (ip_hdr(skb)->protocol == IPPROTO_UDP) { + } else if (skb->nh.iph->protocol == IPPROTO_UDP) { netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT); } else { return; } } - desc->tcp_hdr_offset = skb_transport_offset(skb); - desc->ip_hdr_offset = skb_network_offset(skb); + adapter->stats.xmitcsummed++; + desc->tcp_hdr_offset = skb->h.raw - skb->data; + desc->ip_hdr_offset = skb->nh.raw - skb->data; } int netxen_is_flash_supported(struct netxen_adapter *adapter) @@ -642,30 +474,7 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) if (adapter->curr_window == wndw) return; - switch(adapter->ahw.pci_func) { - case 0: - offset = PCI_OFFSET_SECOND_RANGE(adapter, - NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); - break; - case 1: - offset = PCI_OFFSET_SECOND_RANGE(adapter, - NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1)); - break; - case 2: - offset = PCI_OFFSET_SECOND_RANGE(adapter, - NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2)); - break; - case 3: - offset = PCI_OFFSET_SECOND_RANGE(adapter, - NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3)); - break; - default: - printk(KERN_INFO "Changing the window for PCI function" - "%d\n", adapter->ahw.pci_func); - offset = PCI_OFFSET_SECOND_RANGE(adapter, - NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); - break; - } + /* * Move the CRB window. * We need to write to the "direct access" region of PCI @@ -674,6 +483,9 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) * register address is received by PCI. The direct region bypasses * the CRB bus. */ + offset = + PCI_OFFSET_SECOND_RANGE(adapter, + NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); if (wndw & 0x1) wndw = NETXEN_WINDOW_ONE; @@ -691,10 +503,7 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) count++; } - if (wndw == NETXEN_WINDOW_ONE) - adapter->curr_window = 1; - else - adapter->curr_window = 0; + adapter->curr_window = wndw; } void netxen_load_firmware(struct netxen_adapter *adapter) @@ -939,17 +748,6 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter, return addr; } -int -netxen_nic_erase_pxe(struct netxen_adapter *adapter) -{ - if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) { - printk(KERN_ERR "%s: erase pxe failed\n", - netxen_nic_driver_name); - return -1; - } - return 0; -} - int netxen_nic_get_board_info(struct netxen_adapter *adapter) { int rv = 0; @@ -1011,29 +809,43 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) /* NIU access sections */ -int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu) +int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu) { + struct netxen_adapter *adapter = port->adapter; netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MAX_FRAME_SIZE( - physical_port[adapter->portnum]), new_mtu); + NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum), + new_mtu); return 0; } -int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu) +int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu) { + struct netxen_adapter *adapter = port->adapter; new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE; - if (physical_port[adapter->portnum] == 0) - netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, - new_mtu); - else - netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, - new_mtu); + if (port->portnum == 0) + netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); + else if (port->portnum == 1) + netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu); return 0; } void netxen_nic_init_niu_gb(struct netxen_adapter *adapter) { - netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]); + int portno; + for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) + netxen_niu_gbe_init_port(adapter, portno); +} + +void netxen_nic_stop_all_ports(struct netxen_adapter *adapter) +{ + int port_nr; + struct netxen_port *port; + + for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) { + port = adapter->port[port_nr]; + if (adapter->stop_port) + adapter->stop_port(adapter, port->portnum); + } } void @@ -1052,8 +864,9 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, } } -void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) +void netxen_nic_set_link_parameters(struct netxen_port *port) { + struct netxen_adapter *adapter = port->adapter; __u32 status; __u32 autoneg; __u32 mode; @@ -1062,47 +875,47 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ if (adapter->phy_read && adapter-> - phy_read(adapter, + phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) == 0) { if (netxen_get_phy_link(status)) { switch (netxen_get_phy_speed(status)) { case 0: - adapter->link_speed = SPEED_10; + port->link_speed = SPEED_10; break; case 1: - adapter->link_speed = SPEED_100; + port->link_speed = SPEED_100; break; case 2: - adapter->link_speed = SPEED_1000; + port->link_speed = SPEED_1000; break; default: - adapter->link_speed = -1; + port->link_speed = -1; break; } switch (netxen_get_phy_duplex(status)) { case 0: - adapter->link_duplex = DUPLEX_HALF; + port->link_duplex = DUPLEX_HALF; break; case 1: - adapter->link_duplex = DUPLEX_FULL; + port->link_duplex = DUPLEX_FULL; break; default: - adapter->link_duplex = -1; + port->link_duplex = -1; break; } if (adapter->phy_read && adapter-> - phy_read(adapter, + phy_read(adapter, port->portnum, NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, &autoneg) != 0) - adapter->link_autoneg = autoneg; + port->link_autoneg = autoneg; } else goto link_down; } else { link_down: - adapter->link_speed = -1; - adapter->link_duplex = -1; + port->link_speed = -1; + port->link_duplex = -1; } } } @@ -1116,7 +929,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) char brd_name[NETXEN_MAX_SHORT_NAME]; struct netxen_new_user_info user_info; int i, addr = USER_START; - __le32 *ptr32; + u32 *ptr32; struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); if (board_info->magic != NETXEN_BDINFO_MAGIC) { @@ -1142,6 +955,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) netxen_nic_driver_name); return; } + *ptr32 = le32_to_cpu(*ptr32); ptr32++; addr += sizeof(u32); } diff --git a/trunk/drivers/net/netxen/netxen_nic_hw.h b/trunk/drivers/net/netxen/netxen_nic_hw.h index 245bf13c7ba2..ab1112eb1b0d 100644 --- a/trunk/drivers/net/netxen/netxen_nic_hw.h +++ b/trunk/drivers/net/netxen/netxen_nic_hw.h @@ -6,12 +6,12 @@ * 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, @@ -87,7 +87,7 @@ struct netxen_adapter; *(u32 *)Y = readl((void __iomem*) addr); struct netxen_port; -void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); +void netxen_nic_set_link_parameters(struct netxen_port *port); void netxen_nic_flash_print(struct netxen_adapter *adapter); int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); @@ -220,69 +220,6 @@ typedef enum { _netxen_crb_get_bit(config_word, 1) #define netxen_get_gb_mii_mgmt_notvalid(config_word) \ _netxen_crb_get_bit(config_word, 2) -/* - * NIU XG Pause Ctl Register - * - * Bit 0 : xg0_mask => 1:disable tx pause frames - * Bit 1 : xg0_request => 1:request single pause frame - * Bit 2 : xg0_on_off => 1:request is pause on, 0:off - * Bit 3 : xg1_mask => 1:disable tx pause frames - * Bit 4 : xg1_request => 1:request single pause frame - * Bit 5 : xg1_on_off => 1:request is pause on, 0:off - */ - -#define netxen_xg_set_xg0_mask(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_xg_set_xg1_mask(config_word) \ - ((config_word) |= 1 << 3) - -#define netxen_xg_get_xg0_mask(config_word) \ - _netxen_crb_get_bit((config_word), 0) -#define netxen_xg_get_xg1_mask(config_word) \ - _netxen_crb_get_bit((config_word), 3) - -#define netxen_xg_unset_xg0_mask(config_word) \ - ((config_word) &= ~(1 << 0)) -#define netxen_xg_unset_xg1_mask(config_word) \ - ((config_word) &= ~(1 << 3)) - -/* - * NIU XG Pause Ctl Register - * - * Bit 0 : xg0_mask => 1:disable tx pause frames - * Bit 1 : xg0_request => 1:request single pause frame - * Bit 2 : xg0_on_off => 1:request is pause on, 0:off - * Bit 3 : xg1_mask => 1:disable tx pause frames - * Bit 4 : xg1_request => 1:request single pause frame - * Bit 5 : xg1_on_off => 1:request is pause on, 0:off - */ -#define netxen_gb_set_gb0_mask(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_gb_set_gb1_mask(config_word) \ - ((config_word) |= 1 << 2) -#define netxen_gb_set_gb2_mask(config_word) \ - ((config_word) |= 1 << 4) -#define netxen_gb_set_gb3_mask(config_word) \ - ((config_word) |= 1 << 6) - -#define netxen_gb_get_gb0_mask(config_word) \ - _netxen_crb_get_bit((config_word), 0) -#define netxen_gb_get_gb1_mask(config_word) \ - _netxen_crb_get_bit((config_word), 2) -#define netxen_gb_get_gb2_mask(config_word) \ - _netxen_crb_get_bit((config_word), 4) -#define netxen_gb_get_gb3_mask(config_word) \ - _netxen_crb_get_bit((config_word), 6) - -#define netxen_gb_unset_gb0_mask(config_word) \ - ((config_word) &= ~(1 << 0)) -#define netxen_gb_unset_gb1_mask(config_word) \ - ((config_word) &= ~(1 << 2)) -#define netxen_gb_unset_gb2_mask(config_word) \ - ((config_word) &= ~(1 << 4)) -#define netxen_gb_unset_gb3_mask(config_word) \ - ((config_word) &= ~(1 << 6)) - /* * PHY-Specific MII control/status registers. @@ -515,21 +452,21 @@ typedef enum { ((config) |= (((val) & 0x0f) << 28)) /* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, netxen_niu_prom_mode_t mode); int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - netxen_niu_prom_mode_t mode); + int port, netxen_niu_prom_mode_t mode); /* get/set the MAC address for a given MAC */ -int netxen_niu_macaddr_get(struct netxen_adapter *adapter, +int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port, netxen_ethernet_macaddr_t * addr); -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, +int netxen_niu_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr); /* XG versons */ -int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, +int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port, netxen_ethernet_macaddr_t * addr); -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, +int netxen_niu_xg_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr); /* Generic enable for GbE ports. Will detect the speed of the link. */ @@ -538,8 +475,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); /* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); +int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port); -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port); #endif /* __NETXEN_NIC_HW_H_ */ diff --git a/trunk/drivers/net/netxen/netxen_nic_init.c b/trunk/drivers/net/netxen/netxen_nic_init.c index cf0e96adfe44..eff965dc5fff 100644 --- a/trunk/drivers/net/netxen/netxen_nic_init.c +++ b/trunk/drivers/net/netxen/netxen_nic_init.c @@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_adapter *adapter) return err; } /* Window 1 call */ - writel(MPORT_MULTI_FUNCTION_MODE, + writel(MPORT_SINGLE_FUNCTION_MODE, NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE)); writel(PHAN_INITIALIZE_ACK, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); @@ -226,6 +226,7 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) adapter->unset_promisc = netxen_niu_set_promiscuous_mode; adapter->phy_read = netxen_niu_gbe_phy_read; adapter->phy_write = netxen_niu_gbe_phy_write; + adapter->init_port = netxen_niu_gbe_init_port; adapter->init_niu = netxen_nic_init_niu_gb; adapter->stop_port = netxen_niu_disable_gbe_port; break; @@ -276,8 +277,8 @@ u32 netxen_decode_crb_addr(u32 addr) return (pci_base + offset); } -static long rom_max_timeout = 100; -static long rom_lock_timeout = 10000; +static long rom_max_timeout = 10000; +static long rom_lock_timeout = 1000000; static long rom_write_timeout = 700; static inline int rom_lock(struct netxen_adapter *adapter) @@ -437,9 +438,9 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, for (addridx = addr; addridx < (addr + size); addridx += 4) { ret = do_rom_fast_read(adapter, addridx, (int *)bytes); + *(int *)bytes = cpu_to_le32(*(int *)bytes); if (ret != 0) break; - *(int *)bytes = cpu_to_le32(*(int *)bytes); bytes += 4; } @@ -498,6 +499,7 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, int data; data = le32_to_cpu((*(u32*)bytes)); + ret = do_rom_fast_write(adapter, addridx, data); if (ret < 0) return ret; @@ -951,8 +953,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) if (!pegtune_val) { val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); - while (val != PHAN_INITIALIZE_COMPLETE && - val != PHAN_INITIALIZE_ACK && loops < 200000) { + while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) { udelay(100); schedule(); val = @@ -989,7 +990,9 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter) static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) { - struct net_device *netdev = adapter->netdev; + int port_num; + struct netxen_port *port; + struct net_device *netdev; uint32_t temp, temp_state, temp_val; int rv = 0; @@ -1003,9 +1006,14 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) "%s: Device temperature %d degrees C exceeds" " maximum allowed. Hardware has been shut down.\n", netxen_nic_driver_name, temp_val); + for (port_num = 0; port_num < adapter->ahw.max_ports; + port_num++) { + port = adapter->port[port_num]; + netdev = port->netdev; - netif_carrier_off(netdev); - netif_stop_queue(netdev); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } rv = 1; } else if (temp_state == NX_TEMP_WARN) { if (adapter->temp == NX_TEMP_NORMAL) { @@ -1029,22 +1037,28 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) void netxen_watchdog_task(struct work_struct *work) { + int port_num; + struct netxen_port *port; struct net_device *netdev; struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, watchdog_task); - if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter)) + if (netxen_nic_check_temp(adapter)) return; - netdev = adapter->netdev; - if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) { - printk(KERN_INFO "%s port %d, %s carrier is now ok\n", - netxen_nic_driver_name, adapter->portnum, netdev->name); - netif_carrier_on(netdev); - } + for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { + port = adapter->port[port_num]; + netdev = port->netdev; - if (netif_queue_stopped(netdev)) - netif_wake_queue(netdev); + if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) { + printk(KERN_INFO "%s port %d, %s carrier is now ok\n", + netxen_nic_driver_name, port_num, netdev->name); + netif_carrier_on(netdev); + } + + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); + } if (adapter->handle_phy_intr) adapter->handle_phy_intr(adapter); @@ -1060,8 +1074,9 @@ void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, struct status_desc *desc) { - struct pci_dev *pdev = adapter->pdev; - struct net_device *netdev = adapter->netdev; + struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)]; + struct pci_dev *pdev = port->pdev; + struct net_device *netdev = port->netdev; int index = netxen_get_sts_refhandle(desc); struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); struct netxen_rx_buffer *buffer; @@ -1111,9 +1126,10 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, skb = (struct sk_buff *)buffer->skb; if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { - adapter->stats.csummed++; + port->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } + skb->dev = netdev; if (desc_ctx == RCV_DESC_LRO_CTXID) { /* True length was only available on the last pkt */ skb_put(skb, buffer->lro_length); @@ -1131,27 +1147,27 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, */ switch (ret) { case NET_RX_SUCCESS: - adapter->stats.uphappy++; + port->stats.uphappy++; break; case NET_RX_CN_LOW: - adapter->stats.uplcong++; + port->stats.uplcong++; break; case NET_RX_CN_MOD: - adapter->stats.upmcong++; + port->stats.upmcong++; break; case NET_RX_CN_HIGH: - adapter->stats.uphcong++; + port->stats.uphcong++; break; case NET_RX_DROP: - adapter->stats.updropped++; + port->stats.updropped++; break; default: - adapter->stats.updunno++; + port->stats.updunno++; break; } @@ -1163,13 +1179,14 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, /* * We just consumed one buffer so post a buffer. */ + adapter->stats.post_called++; buffer->skb = NULL; buffer->state = NETXEN_BUFFER_FREE; buffer->lro_current_frags = 0; buffer->lro_expected_frags = 0; - adapter->stats.no_rcv++; - adapter->stats.rxbytes += length; + port->stats.no_rcv++; + port->stats.rxbytes += length; } /* Process Receive status ring */ @@ -1210,6 +1227,7 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) /* update the consumer index in phantom */ if (count) { + adapter->stats.process_rcv++; recv_ctx->status_rx_consumer = consumer; recv_ctx->status_rx_producer = producer; @@ -1232,10 +1250,13 @@ int netxen_process_cmd_ring(unsigned long data) int count1 = 0; int count2 = 0; struct netxen_cmd_buffer *buffer; + struct netxen_port *port; /* port #1 */ + struct netxen_port *nport; struct pci_dev *pdev; struct netxen_skb_frag *frag; u32 i; struct sk_buff *skb = NULL; + int p; int done; spin_lock(&adapter->tx_lock); @@ -1256,6 +1277,7 @@ int netxen_process_cmd_ring(unsigned long data) } adapter->proc_cmd_buf_counter++; + adapter->stats.process_xmit++; /* * Not needed - does not seem to be used anywhere. * adapter->cmd_consumer = consumer; @@ -1264,7 +1286,8 @@ int netxen_process_cmd_ring(unsigned long data) while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) { buffer = &adapter->cmd_buf_arr[last_consumer]; - pdev = adapter->pdev; + port = adapter->port[buffer->port]; + pdev = port->pdev; frag = &buffer->frag_array[0]; skb = buffer->skb; if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) { @@ -1277,23 +1300,24 @@ int netxen_process_cmd_ring(unsigned long data) PCI_DMA_TODEVICE); } - adapter->stats.skbfreed++; + port->stats.skbfreed++; dev_kfree_skb_any(skb); skb = NULL; } else if (adapter->proc_cmd_buf_counter == 1) { - adapter->stats.txnullskb++; + port->stats.txnullskb++; } - if (unlikely(netif_queue_stopped(adapter->netdev) - && netif_carrier_ok(adapter->netdev)) - && ((jiffies - adapter->netdev->trans_start) > - adapter->netdev->watchdog_timeo)) { - SCHEDULE_WORK(&adapter->tx_timeout_task); + if (unlikely(netif_queue_stopped(port->netdev) + && netif_carrier_ok(port->netdev)) + && ((jiffies - port->netdev->trans_start) > + port->netdev->watchdog_timeo)) { + SCHEDULE_WORK(&port->tx_timeout_task); } last_consumer = get_next_index(last_consumer, adapter->max_tx_desc_count); count1++; } + adapter->stats.noxmitdone += count1; count2 = 0; spin_lock(&adapter->tx_lock); @@ -1313,10 +1337,13 @@ int netxen_process_cmd_ring(unsigned long data) } } if (count1 || count2) { - if (netif_queue_stopped(adapter->netdev) - && (adapter->flags & NETXEN_NETDEV_STATUS)) { - netif_wake_queue(adapter->netdev); - adapter->flags &= ~NETXEN_NETDEV_STATUS; + for (p = 0; p < adapter->ahw.max_ports; p++) { + nport = adapter->port[p]; + if (netif_queue_stopped(nport->netdev) + && (nport->flags & NETXEN_NETDEV_STATUS)) { + netif_wake_queue(nport->netdev); + nport->flags &= ~NETXEN_NETDEV_STATUS; + } } } /* @@ -1362,6 +1389,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) netxen_ctx_msg msg = 0; dma_addr_t dma; + adapter->stats.post_called++; rcv_desc = &recv_ctx->rcv_desc[ringid]; producer = rcv_desc->producer; @@ -1414,6 +1442,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) if (count) { rcv_desc->begin_alloc = index; rcv_desc->rcv_pending += count; + adapter->stats.lastposted = count; + adapter->stats.posted += count; rcv_desc->producer = producer; if (rcv_desc->rcv_free >= 32) { rcv_desc->rcv_free = 0; @@ -1421,8 +1451,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) writel((producer - 1) & (rcv_desc->max_rx_desc_count - 1), NETXEN_CRB_NORMALIZE(adapter, - recv_crb_registers[ - adapter->portnum]. + recv_crb_registers[0]. rcv_desc_crb[ringid]. crb_rcv_producer_offset)); /* @@ -1435,7 +1464,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) ((producer - 1) & (rcv_desc-> max_rx_desc_count - 1))); - netxen_set_msg_ctxid(msg, adapter->portnum); + netxen_set_msg_ctxid(msg, 0); netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); writel(msg, DB_NORMALIZE(adapter, @@ -1457,6 +1486,7 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, int count = 0; int index = 0; + adapter->stats.post_called++; rcv_desc = &recv_ctx->rcv_desc[ringid]; producer = rcv_desc->producer; @@ -1503,6 +1533,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, if (count) { rcv_desc->begin_alloc = index; rcv_desc->rcv_pending += count; + adapter->stats.lastposted = count; + adapter->stats.posted += count; rcv_desc->producer = producer; if (rcv_desc->rcv_free >= 32) { rcv_desc->rcv_free = 0; @@ -1510,8 +1542,7 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, writel((producer - 1) & (rcv_desc->max_rx_desc_count - 1), NETXEN_CRB_NORMALIZE(adapter, - recv_crb_registers[ - adapter->portnum]. + recv_crb_registers[0]. rcv_desc_crb[ringid]. crb_rcv_producer_offset)); wmb(); @@ -1532,7 +1563,13 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter) void netxen_nic_clear_stats(struct netxen_adapter *adapter) { + struct netxen_port *port; + int port_num; + memset(&adapter->stats, 0, sizeof(adapter->stats)); - return; + for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { + port = adapter->port[port_num]; + memset(&port->stats, 0, sizeof(port->stats)); + } } diff --git a/trunk/drivers/net/netxen/netxen_nic_isr.c b/trunk/drivers/net/netxen/netxen_nic_isr.c index b213b062eb56..be366e48007c 100644 --- a/trunk/drivers/net/netxen/netxen_nic_isr.c +++ b/trunk/drivers/net/netxen/netxen_nic_isr.c @@ -6,12 +6,12 @@ * 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, @@ -40,35 +40,35 @@ */ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) { - struct netxen_adapter *adapter = netdev_priv(netdev); - struct net_device_stats *stats = &adapter->net_stats; + struct netxen_port *port = netdev_priv(netdev); + struct net_device_stats *stats = &port->net_stats; memset(stats, 0, sizeof(*stats)); /* total packets received */ - stats->rx_packets = adapter->stats.no_rcv; + stats->rx_packets = port->stats.no_rcv; /* total packets transmitted */ - stats->tx_packets = adapter->stats.xmitedframes + - adapter->stats.xmitfinished; + stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished; /* total bytes received */ - stats->rx_bytes = adapter->stats.rxbytes; + stats->rx_bytes = port->stats.rxbytes; /* total bytes transmitted */ - stats->tx_bytes = adapter->stats.txbytes; + stats->tx_bytes = port->stats.txbytes; /* bad packets received */ - stats->rx_errors = adapter->stats.rcvdbadskb; + stats->rx_errors = port->stats.rcvdbadskb; /* packet transmit problems */ - stats->tx_errors = adapter->stats.nocmddescriptor; + stats->tx_errors = port->stats.nocmddescriptor; /* no space in linux buffers */ - stats->rx_dropped = adapter->stats.updropped; + stats->rx_dropped = port->stats.updropped; /* no space available in linux */ - stats->tx_dropped = adapter->stats.txdropped; + stats->tx_dropped = port->stats.txdropped; return stats; } -void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) +void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno, + u32 link) { - struct net_device *netdev = adapter->netdev; + struct net_device *netdev = (adapter->port[portno])->netdev; if (link) netif_carrier_on(netdev); @@ -76,13 +76,15 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) netif_carrier_off(netdev); } -void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) +void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, + u32 enable) { __u32 int_src; + struct netxen_port *port; /* This should clear the interrupt source */ if (adapter->phy_read) - adapter->phy_read(adapter, + adapter->phy_read(adapter, portno, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, &int_src); if (int_src == 0) { @@ -90,7 +92,9 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) return; } if (adapter->disable_phy_interrupts) - adapter->disable_phy_interrupts(adapter); + adapter->disable_phy_interrupts(adapter, portno); + + port = adapter->port[portno]; if (netxen_get_phy_int_jabber(int_src)) DPRINTK(INFO, "Jabber interrupt \n"); @@ -111,57 +115,64 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); if (adapter->phy_read - && adapter->phy_read(adapter, + && adapter->phy_read(adapter, portno, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) == 0) { if (netxen_get_phy_int_link_status_changed(int_src)) { if (netxen_get_phy_link(status)) { - printk(KERN_INFO "%s: %s Link UP\n", + netxen_niu_gbe_init_port(adapter, + portno); + printk("%s: %s Link UP\n", netxen_nic_driver_name, - adapter->netdev->name); + port->netdev->name); } else { - printk(KERN_INFO "%s: %s Link DOWN\n", + printk("%s: %s Link DOWN\n", netxen_nic_driver_name, - adapter->netdev->name); + port->netdev->name); } - netxen_indicate_link_status(adapter, + netxen_indicate_link_status(adapter, portno, netxen_get_phy_link (status)); } } } if (adapter->enable_phy_interrupts) - adapter->enable_phy_interrupts(adapter); + adapter->enable_phy_interrupts(adapter, portno); } void netxen_nic_isr_other(struct netxen_adapter *adapter) { - int portno = adapter->portnum; + u32 portno; u32 val, linkup, qg_linksup; /* verify the offset */ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); - val = val >> physical_port[adapter->portnum]; if (val == adapter->ahw.qg_linksup) return; qg_linksup = adapter->ahw.qg_linksup; adapter->ahw.qg_linksup = val; DPRINTK(INFO, "link update 0x%08x\n", val); + for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) { + linkup = val & 1; + if (linkup != (qg_linksup & 1)) { + printk(KERN_INFO "%s: %s PORT %d link %s\n", + adapter->port[portno]->netdev->name, + netxen_nic_driver_name, portno, + ((linkup == 0) ? "down" : "up")); + netxen_indicate_link_status(adapter, portno, linkup); + if (linkup) + netxen_nic_set_link_parameters(adapter-> + port[portno]); - linkup = val & 1; + } + val = val >> 1; + qg_linksup = qg_linksup >> 1; + } - if (linkup != (qg_linksup & 1)) { - printk(KERN_INFO "%s: %s PORT %d link %s\n", - adapter->netdev->name, - netxen_nic_driver_name, portno, - ((linkup == 0) ? "down" : "up")); - netxen_indicate_link_status(adapter, linkup); - if (linkup) - netxen_nic_set_link_parameters(adapter); + adapter->stats.otherints++; - } } void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) @@ -171,28 +182,26 @@ void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) { - struct net_device *netdev = adapter->netdev; - u32 val, val1; + struct net_device *netdev = adapter->port[0]->netdev; + u32 val; /* WINDOW = 1 */ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); - val >>= (physical_port[adapter->portnum] * 8); - val1 = val & 0xff; - if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) { + if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) { printk(KERN_INFO "%s: %s NIC Link is down\n", netxen_nic_driver_name, netdev->name); adapter->ahw.xg_linkup = 0; /* read twice to clear sticky bits */ /* WINDOW = 0 */ - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); + netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val); + netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val); if ((val & 0xffb) != 0xffb) { printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n", - netxen_nic_driver_name, val1); + netxen_nic_driver_name, val); } - } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) { + } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) { printk(KERN_INFO "%s: %s NIC Link is up\n", netxen_nic_driver_name, netdev->name); adapter->ahw.xg_linkup = 1; diff --git a/trunk/drivers/net/netxen/netxen_nic_main.c b/trunk/drivers/net/netxen/netxen_nic_main.c index 4e32bb678ea9..7d2525e76abb 100644 --- a/trunk/drivers/net/netxen/netxen_nic_main.c +++ b/trunk/drivers/net/netxen/netxen_nic_main.c @@ -36,11 +36,11 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" +#define DEFINE_GLOBAL_RECV_CRB #include "netxen_nic_phan_reg.h" #include #include -#include MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_LICENSE("GPL"); @@ -76,8 +76,6 @@ static void netxen_nic_poll_controller(struct net_device *netdev); #endif static irqreturn_t netxen_intr(int irq, void *data); -int physical_port[] = {0, 1, 2, 3}; - /* PCI Device ID Table */ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { {PCI_DEVICE(0x4040, 0x0001)}, @@ -95,67 +93,6 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); struct workqueue_struct *netxen_workq; static void netxen_watchdog(unsigned long); -static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer) -{ - switch (adapter->portnum) { - case 0: - writel(crb_producer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_PRODUCER_OFFSET)); - return; - case 1: - writel(crb_producer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_PRODUCER_OFFSET_1)); - return; - case 2: - writel(crb_producer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_PRODUCER_OFFSET_2)); - return; - case 3: - writel(crb_producer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_PRODUCER_OFFSET_3)); - return; - default: - printk(KERN_WARNING "We tried to update " - "CRB_CMD_PRODUCER_OFFSET for invalid " - "PCI function id %d\n", - adapter->portnum); - return; - } -} - -static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, - u32 crb_consumer) -{ - switch (adapter->portnum) { - case 0: - writel(crb_consumer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_CONSUMER_OFFSET)); - return; - case 1: - writel(crb_consumer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_CONSUMER_OFFSET_1)); - return; - case 2: - writel(crb_consumer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_CONSUMER_OFFSET_2)); - return; - case 3: - writel(crb_consumer, NETXEN_CRB_NORMALIZE - (adapter, CRB_CMD_CONSUMER_OFFSET_3)); - return; - default: - printk(KERN_WARNING "We tried to update " - "CRB_CMD_PRODUCER_OFFSET for invalid " - "PCI function id %d\n", - adapter->portnum); - return; - } -} - -#define ADAPTER_LIST_SIZE 12 -int netxen_cards_found; - /* * netxen_nic_probe() * @@ -173,30 +110,26 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev = NULL; struct netxen_adapter *adapter = NULL; + struct netxen_port *port = NULL; void __iomem *mem_ptr0 = NULL; void __iomem *mem_ptr1 = NULL; void __iomem *mem_ptr2 = NULL; - unsigned long first_page_group_end; - unsigned long first_page_group_start; - u8 __iomem *db_ptr = NULL; unsigned long mem_base, mem_len, db_base, db_len; - int pci_using_dac, i = 0, err; + int pci_using_dac, i, err; int ring; struct netxen_recv_context *recv_ctx = NULL; struct netxen_rcv_desc_ctx *rcv_desc = NULL; struct netxen_cmd_buffer *cmd_buf_arr = NULL; u64 mac_addr[FLASH_NUM_PORTS + 1]; int valid_mac = 0; - u32 val; - int pci_func_id = PCI_FUNC(pdev->devfn); printk(KERN_INFO "%s \n", netxen_nic_driver_string); - - if (pdev->class != 0x020000) { - printk(KERN_ERR"NetXen function %d, class %x will not" - "be enabled.\n",pci_func_id, pdev->class); + /* In current scheme, we use only PCI function 0 */ + if (PCI_FUNC(pdev->devfn) != 0) { + DPRINTK(ERR, "NetXen function %d will not be enabled.\n", + PCI_FUNC(pdev->devfn)); return -ENODEV; } if ((err = pci_enable_device(pdev))) @@ -223,52 +156,18 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_using_dac = 0; } - - netdev = alloc_etherdev(sizeof(struct netxen_adapter)); - if(!netdev) { - printk(KERN_ERR"%s: Failed to allocate memory for the " - "device block.Check system memory resource" - " usage.\n", netxen_nic_driver_name); - goto err_out_free_res; - } - - SET_MODULE_OWNER(netdev); - SET_NETDEV_DEV(netdev, &pdev->dev); - - adapter = netdev->priv; - memset(adapter, 0 , sizeof(struct netxen_adapter)); - - adapter->ahw.pdev = pdev; - adapter->ahw.pci_func = pci_func_id; - spin_lock_init(&adapter->tx_lock); - spin_lock_init(&adapter->lock); - /* remap phys address */ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ mem_len = pci_resource_len(pdev, 0); /* 128 Meg of memory */ - if (mem_len == NETXEN_PCI_128MB_SIZE) { - mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); - mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, - SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, - THIRD_PAGE_GROUP_SIZE); - first_page_group_start = FIRST_PAGE_GROUP_START; - first_page_group_end = FIRST_PAGE_GROUP_END; - } else if (mem_len == NETXEN_PCI_32MB_SIZE) { - mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); - first_page_group_start = 0; - first_page_group_end = 0; - } else { - err = -EIO; - goto err_out_free_netdev; - } + mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); + mem_ptr1 = + ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE); + mem_ptr2 = + ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); - if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) || - (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { + if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { DPRINTK(ERR, "Cannot remap adapter memory aborting.:" "0 -> %p, 1 -> %p, 2 -> %p\n", @@ -298,87 +197,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.first_page_group_start = first_page_group_start; - adapter->ahw.first_page_group_end = first_page_group_end; - adapter->ahw.pci_base1 = mem_ptr1; - adapter->ahw.pci_base2 = mem_ptr2; - adapter->ahw.db_base = db_ptr; - adapter->ahw.db_len = db_len; - - adapter->netdev = netdev; - adapter->pdev = pdev; - adapter->portnum = pci_func_id; - - netdev->open = netxen_nic_open; - netdev->stop = netxen_nic_close; - netdev->hard_start_xmit = netxen_nic_xmit_frame; - netdev->get_stats = netxen_nic_get_stats; - netdev->set_multicast_list = netxen_nic_set_multi; - netdev->set_mac_address = netxen_nic_set_mac; - netdev->change_mtu = netxen_nic_change_mtu; - netdev->tx_timeout = netxen_tx_timeout; - netdev->watchdog_timeo = HZ; - - netxen_nic_change_mtu(netdev, netdev->mtu); - - SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->poll = netxen_nic_poll; - netdev->weight = NETXEN_NETDEV_WEIGHT; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = netxen_nic_poll_controller; -#endif - /* ScatterGather support */ - netdev->features = NETIF_F_SG; - netdev->features |= NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_TSO; - - if (pci_using_dac) - netdev->features |= NETIF_F_HIGHDMA; - - if (pci_enable_msi(pdev)) { - adapter->flags &= ~NETXEN_NIC_MSI_ENABLED; - printk(KERN_WARNING "%s: unable to allocate MSI interrupt" - " error\n", netxen_nic_driver_name); - } else - adapter->flags |= NETXEN_NIC_MSI_ENABLED; - - netdev->irq = pdev->irq; - INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); - - /* - * Set the CRB window to invalid. If any register in window 0 is - * accessed it should set the window to 0 and then reset it to 1. - */ - adapter->curr_window = 255; - - /* initialize the adapter */ - netxen_initialize_adapter_hw(adapter); - -#ifdef CONFIG_PPC - if ((adapter->ahw.boardcfg.board_type == - NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) && - (pci_func_id == 2)) - goto err_out_free_adapter; -#endif /* CONFIG_PPC */ - - /* - * Adapter in our case is quad port so initialize it before - * initializing the ports - */ +/* + * Allocate a adapter structure which will manage all the initialization + * as well as the common resources for all ports... + * all the ports will have pointer to this adapter as well as Adapter + * will have pointers of all the ports structures. + */ - netxen_initialize_adapter_ops(adapter); + /* One adapter structure for all 4 ports.... */ + adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL); + if (adapter == NULL) { + printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n", + netxen_nic_driver_name, + (int)sizeof(struct netxen_adapter)); + err = -ENOMEM; + goto err_out_dbunmap; + } - adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST; - if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) || - (adapter->ahw.boardcfg.board_type == - NETXEN_BRDTYPE_P2_SB31_2G)) - adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; - else - adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; + adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS; + adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS; adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS; + pci_set_drvdata(pdev, adapter); + cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE); if (cmd_buf_arr == NULL) { printk(KERN_ERR @@ -388,7 +230,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_adapter; } memset(cmd_buf_arr, 0, TX_RINGSIZE); - adapter->cmd_buf_arr = cmd_buf_arr; for (i = 0; i < MAX_RCV_CTX; ++i) { recv_ctx = &adapter->recv_ctx[i]; @@ -436,21 +277,34 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } + adapter->cmd_buf_arr = cmd_buf_arr; + adapter->ahw.pci_base0 = mem_ptr0; + adapter->ahw.pci_base1 = mem_ptr1; + adapter->ahw.pci_base2 = mem_ptr2; + adapter->ahw.db_base = db_ptr; + adapter->ahw.db_len = db_len; + spin_lock_init(&adapter->tx_lock); + spin_lock_init(&adapter->lock); netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */ - - /* Mezz cards have PCI function 0,2,3 enabled */ - if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) - && (pci_func_id >= 2)) - adapter->portnum = pci_func_id - 2; - #ifdef CONFIG_IA64 - if(adapter->portnum == 0) { - netxen_pinit_from_rom(adapter, 0); - udelay(500); - netxen_load_firmware(adapter); - } + netxen_pinit_from_rom(adapter, 0); + udelay(500); + netxen_load_firmware(adapter); #endif + /* + * Set the CRB window to invalid. If any register in window 0 is + * accessed it should set the window to 0 and then reset it to 1. + */ + adapter->curr_window = 255; + /* + * Adapter in our case is quad port so initialize it before + * initializing the ports + */ + netxen_initialize_adapter_hw(adapter); /* initialize the adapter */ + + netxen_initialize_adapter_ops(adapter); + init_timer(&adapter->watchdog_timer); adapter->ahw.xg_linkup = 0; adapter->watchdog_timer.function = &netxen_watchdog; @@ -460,12 +314,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->proc_cmd_buf_counter = 0; adapter->ahw.revision_id = nx_p2_id; - /* make sure Window == 1 */ - netxen_nic_pci_change_crbwindow(adapter, 1); - - netxen_nic_update_cmd_producer(adapter, 0); - netxen_nic_update_cmd_consumer(adapter, 0); - writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); + if (pci_enable_msi(pdev)) { + adapter->flags &= ~NETXEN_NIC_MSI_ENABLED; + printk(KERN_WARNING "%s: unable to allocate MSI interrupt" + " error\n", netxen_nic_driver_name); + } else + adapter->flags |= NETXEN_NIC_MSI_ENABLED; if (netxen_is_flash_supported(adapter) == 0 && netxen_get_flash_mac_addr(adapter, mac_addr) == 0) @@ -473,118 +327,153 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else valid_mac = 0; - if (valid_mac) { - unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum]; - netdev->dev_addr[0] = *(p + 5); - netdev->dev_addr[1] = *(p + 4); - netdev->dev_addr[2] = *(p + 3); - netdev->dev_addr[3] = *(p + 2); - netdev->dev_addr[4] = *(p + 1); - netdev->dev_addr[5] = *(p + 0); - - memcpy(netdev->perm_addr, netdev->dev_addr, - netdev->addr_len); - if (!is_valid_ether_addr(netdev->perm_addr)) { - printk(KERN_ERR "%s: Bad MAC address " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - netxen_nic_driver_name, - netdev->dev_addr[0], - netdev->dev_addr[1], - netdev->dev_addr[2], - netdev->dev_addr[3], - netdev->dev_addr[4], - netdev->dev_addr[5]); - } else { - if (adapter->macaddr_set) - adapter->macaddr_set(adapter, - netdev->dev_addr); - } + /* + * Initialize all the CRB registers here. + */ + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET)); + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET)); + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); + + /* do this before waking up pegs so that we have valid dummy dma addr */ + err = netxen_initialize_adapter_offload(adapter); + if (err) { + goto err_out_free_dev; } - if (adapter->portnum == 0) { - err = netxen_initialize_adapter_offload(adapter); - if (err) - goto err_out_free_rx_buffer; - val = readl(NETXEN_CRB_NORMALIZE(adapter, - NETXEN_CAM_RAM(0x1fc))); - if (val == 0x55555555) { - /* This is the first boot after power up */ - val = readl(NETXEN_CRB_NORMALIZE(adapter, - NETXEN_ROMUSB_GLB_SW_RESET)); - printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val); - if (val != 0x80000f) { - /* clear the register for future unloads/loads */ - writel(0, NETXEN_CRB_NORMALIZE(adapter, - NETXEN_CAM_RAM(0x1fc))); - printk(KERN_ERR "ERROR in NetXen HW init sequence.\n"); - err = -ENODEV; + /* Unlock the HW, prompting the boot sequence */ + writel(1, + NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); + + /* Handshake with the card before we register the devices. */ + netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); + + /* initialize the all the ports */ + adapter->active_ports = 0; + + for (i = 0; i < adapter->ahw.max_ports; i++) { + netdev = alloc_etherdev(sizeof(struct netxen_port)); + if (!netdev) { + printk(KERN_ERR "%s: could not allocate netdev for port" + " %d\n", netxen_nic_driver_name, i + 1); goto err_out_free_dev; - } + } - /* clear the register for future unloads/loads */ - writel(0, NETXEN_CRB_NORMALIZE(adapter, - NETXEN_CAM_RAM(0x1fc))); + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + port = netdev_priv(netdev); + port->netdev = netdev; + port->pdev = pdev; + port->adapter = adapter; + port->portnum = i; /* Gigabit port number from 0-3 */ + + netdev->open = netxen_nic_open; + netdev->stop = netxen_nic_close; + netdev->hard_start_xmit = netxen_nic_xmit_frame; + netdev->get_stats = netxen_nic_get_stats; + netdev->set_multicast_list = netxen_nic_set_multi; + netdev->set_mac_address = netxen_nic_set_mac; + netdev->change_mtu = netxen_nic_change_mtu; + netdev->tx_timeout = netxen_tx_timeout; + netdev->watchdog_timeo = HZ; + + netxen_nic_change_mtu(netdev, netdev->mtu); + + SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); + netdev->poll = netxen_nic_poll; + netdev->weight = NETXEN_NETDEV_WEIGHT; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = netxen_nic_poll_controller; +#endif + /* ScatterGather support */ + netdev->features = NETIF_F_SG; + netdev->features |= NETIF_F_IP_CSUM; + netdev->features |= NETIF_F_TSO; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + if (valid_mac) { + unsigned char *p = (unsigned char *)&mac_addr[i]; + netdev->dev_addr[0] = *(p + 5); + netdev->dev_addr[1] = *(p + 4); + netdev->dev_addr[2] = *(p + 3); + netdev->dev_addr[3] = *(p + 2); + netdev->dev_addr[4] = *(p + 1); + netdev->dev_addr[5] = *(p + 0); + + memcpy(netdev->perm_addr, netdev->dev_addr, + netdev->addr_len); + if (!is_valid_ether_addr(netdev->perm_addr)) { + printk(KERN_ERR "%s: Bad MAC address " + "%02x:%02x:%02x:%02x:%02x:%02x.\n", + netxen_nic_driver_name, + netdev->dev_addr[0], + netdev->dev_addr[1], + netdev->dev_addr[2], + netdev->dev_addr[3], + netdev->dev_addr[4], + netdev->dev_addr[5]); + } else { + if (adapter->macaddr_set) + adapter->macaddr_set(port, + netdev->dev_addr); + } } - printk(KERN_INFO "State: 0x%0x\n", - readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE))); + INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task); + netif_carrier_off(netdev); + netif_stop_queue(netdev); - /* - * Tell the hardware our version number. - */ - i = (_NETXEN_NIC_LINUX_MAJOR << 16) - | ((_NETXEN_NIC_LINUX_MINOR << 8)) - | (_NETXEN_NIC_LINUX_SUBVERSION); - writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION)); - - /* Unlock the HW, prompting the boot sequence */ - writel(1, - NETXEN_CRB_NORMALIZE(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); - /* Handshake with the card before we register the devices. */ - netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); + if ((err = register_netdev(netdev))) { + printk(KERN_ERR "%s: register_netdev failed port #%d" + " aborting\n", netxen_nic_driver_name, i + 1); + err = -EIO; + free_netdev(netdev); + goto err_out_free_dev; + } + adapter->port_count++; + adapter->port[i] = port; } - + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); + netxen_pinit_from_rom(adapter, 0); + udelay(500); + netxen_load_firmware(adapter); + netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); /* - * See if the firmware gave us a virtual-physical port mapping. + * delay a while to ensure that the Pegs are up & running. + * Otherwise, we might see some flaky behaviour. */ - i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum))); - if (i != 0x55555555) - physical_port[adapter->portnum] = i; - - netif_carrier_off(netdev); - netif_stop_queue(netdev); - - if ((err = register_netdev(netdev))) { - printk(KERN_ERR "%s: register_netdev failed port #%d" - " aborting\n", netxen_nic_driver_name, - adapter->portnum); - err = -EIO; - goto err_out_free_dev; - } - - pci_set_drvdata(pdev, adapter); + udelay(100); switch (adapter->ahw.board_type) { - case NETXEN_NIC_GBE: - printk(KERN_INFO "%s: QUAD GbE board initialized\n", - netxen_nic_driver_name); - break; + case NETXEN_NIC_GBE: + printk("%s: QUAD GbE board initialized\n", + netxen_nic_driver_name); + break; - case NETXEN_NIC_XGBE: - printk(KERN_INFO "%s: XGbE board initialized\n", - netxen_nic_driver_name); - break; + case NETXEN_NIC_XGBE: + printk("%s: XGbE board initialized\n", netxen_nic_driver_name); + break; } adapter->driver_mismatch = 0; return 0; -err_out_free_dev: - if (adapter->portnum == 0) - netxen_free_adapter_offload(adapter); + err_out_free_dev: + if (adapter->flags & NETXEN_NIC_MSI_ENABLED) + pci_disable_msi(pdev); + for (i = 0; i < adapter->port_count; i++) { + port = adapter->port[i]; + if ((port) && (port->netdev)) { + unregister_netdev(port->netdev); + free_netdev(port->netdev); + } + } -err_out_free_rx_buffer: + netxen_free_adapter_offload(adapter); + + err_out_free_rx_buffer: for (i = 0; i < MAX_RCV_CTX; ++i) { recv_ctx = &adapter->recv_ctx[i]; for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { @@ -597,16 +486,15 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } vfree(cmd_buf_arr); -err_out_free_adapter: - if (adapter->flags & NETXEN_NIC_MSI_ENABLED) - pci_disable_msi(pdev); - + err_out_free_adapter: pci_set_drvdata(pdev, NULL); + kfree(adapter); + err_out_dbunmap: if (db_ptr) iounmap(db_ptr); -err_out_iounmap: + err_out_iounmap: if (mem_ptr0) iounmap(mem_ptr0); if (mem_ptr1) @@ -614,13 +502,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (mem_ptr2) iounmap(mem_ptr2); -err_out_free_netdev: - free_netdev(netdev); - -err_out_free_res: + err_out_free_res: pci_release_regions(pdev); - -err_out_disable_pdev: + err_out_disable_pdev: pci_disable_device(pdev); return err; } @@ -628,7 +512,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void __devexit netxen_nic_remove(struct pci_dev *pdev) { struct netxen_adapter *adapter; - struct net_device *netdev; + struct netxen_port *port; struct netxen_rx_buffer *buffer; struct netxen_recv_context *recv_ctx; struct netxen_rcv_desc_ctx *rcv_desc; @@ -639,35 +523,39 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if (adapter == NULL) return; - netdev = adapter->netdev; - - netxen_nic_disable_int(adapter); if (adapter->irq) free_irq(adapter->irq, adapter); - - if (adapter->stop_port) - adapter->stop_port(adapter); + netxen_nic_stop_all_ports(adapter); + /* leave the hw in the same state as reboot */ + writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); + netxen_pinit_from_rom(adapter, 0); + udelay(500); + netxen_load_firmware(adapter); + netxen_free_adapter_offload(adapter); + + mdelay(1000); /* Delay for a while to drain the DMA engines */ + for (i = 0; i < adapter->port_count; i++) { + port = adapter->port[i]; + if ((port) && (port->netdev)) { + unregister_netdev(port->netdev); + free_netdev(port->netdev); + } + } if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) pci_disable_msi(pdev); - - if (adapter->portnum == 0) - netxen_free_adapter_offload(adapter); - - if (adapter->irq) - free_irq(adapter->irq, adapter); - if(adapter->portnum == 0) { - /* leave the hw in the same state as reboot */ - writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); - netxen_pinit_from_rom(adapter, 0); - udelay(500); - netxen_load_firmware(adapter); - netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); - } - if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) netxen_free_hw_resources(adapter); + iounmap(adapter->ahw.db_base); + iounmap(adapter->ahw.pci_base0); + iounmap(adapter->ahw.pci_base1); + iounmap(adapter->ahw.pci_base2); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) { recv_ctx = &adapter->recv_ctx[ctxid]; for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { @@ -686,20 +574,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) } } - unregister_netdev(netdev); - vfree(adapter->cmd_buf_arr); - - iounmap(adapter->ahw.db_base); - iounmap(adapter->ahw.pci_base0); - iounmap(adapter->ahw.pci_base1); - iounmap(adapter->ahw.pci_base2); - - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - - free_netdev(netdev); + kfree(adapter); } /* @@ -708,7 +584,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) */ static int netxen_nic_open(struct net_device *netdev) { - struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; int err = 0; int ctx, ring; @@ -719,6 +596,8 @@ static int netxen_nic_open(struct net_device *netdev) return -EIO; } netxen_nic_flash_print(adapter); + if (adapter->init_niu) + adapter->init_niu(adapter); /* setup all the resources for the Phantom... */ /* this include the descriptors for rcv, tx, and status */ @@ -729,14 +608,21 @@ static int netxen_nic_open(struct net_device *netdev) err); return err; } + if (adapter->init_port + && adapter->init_port(adapter, port->portnum) != 0) { + printk(KERN_ERR "%s: Failed to initialize port %d\n", + netxen_nic_driver_name, port->portnum); + netxen_free_hw_resources(adapter); + return -EIO; + } for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) netxen_post_rx_buffers(adapter, ctx, ring); } adapter->irq = adapter->ahw.pdev->irq; - err = request_irq(adapter->ahw.pdev->irq, netxen_intr, - SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, - adapter); + err = request_irq(adapter->ahw.pdev->irq, &netxen_intr, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, + netdev->name, adapter); if (err) { printk(KERN_ERR "request_irq failed with: %d\n", err); netxen_free_hw_resources(adapter); @@ -745,28 +631,23 @@ static int netxen_nic_open(struct net_device *netdev) adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; } - if (!adapter->driver_mismatch) - mod_timer(&adapter->watchdog_timer, jiffies); + adapter->active_ports++; + if (adapter->active_ports == 1) { + if (!adapter->driver_mismatch) + mod_timer(&adapter->watchdog_timer, jiffies); - netxen_nic_enable_int(adapter); + netxen_nic_enable_int(adapter); + } /* Done here again so that even if phantom sw overwrote it, * we set it */ if (adapter->macaddr_set) - adapter->macaddr_set(adapter, netdev->dev_addr); - if (adapter->init_port - && adapter->init_port(adapter, adapter->portnum) != 0) { - del_timer_sync(&adapter->watchdog_timer); - printk(KERN_ERR "%s: Failed to initialize port %d\n", - netxen_nic_driver_name, adapter->portnum); - return -EIO; - } - - netxen_nic_set_link_parameters(adapter); + adapter->macaddr_set(port, netdev->dev_addr); + netxen_nic_set_link_parameters(port); netxen_nic_set_multi(netdev); if (adapter->set_mtu) - adapter->set_mtu(adapter, netdev->mtu); + adapter->set_mtu(port, netdev->mtu); if (!adapter->driver_mismatch) netif_start_queue(netdev); @@ -779,7 +660,8 @@ static int netxen_nic_open(struct net_device *netdev) */ static int netxen_nic_close(struct net_device *netdev) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; int i, j; struct netxen_cmd_buffer *cmd_buff; struct netxen_skb_frag *buffrag; @@ -787,39 +669,47 @@ static int netxen_nic_close(struct net_device *netdev) netif_carrier_off(netdev); netif_stop_queue(netdev); - cmd_buff = adapter->cmd_buf_arr; - for (i = 0; i < adapter->max_tx_desc_count; i++) { - buffrag = cmd_buff->frag_array; - if (buffrag->dma) { - pci_unmap_single(adapter->pdev, buffrag->dma, - buffrag->length, PCI_DMA_TODEVICE); - buffrag->dma = (u64) NULL; - } - for (j = 0; j < cmd_buff->frag_count; j++) { - buffrag++; + adapter->active_ports--; + + if (!adapter->active_ports) { + netxen_nic_disable_int(adapter); + cmd_buff = adapter->cmd_buf_arr; + for (i = 0; i < adapter->max_tx_desc_count; i++) { + buffrag = cmd_buff->frag_array; if (buffrag->dma) { - pci_unmap_page(adapter->pdev, buffrag->dma, - buffrag->length, - PCI_DMA_TODEVICE); + pci_unmap_single(port->pdev, buffrag->dma, + buffrag->length, + PCI_DMA_TODEVICE); buffrag->dma = (u64) NULL; } + for (j = 0; j < cmd_buff->frag_count; j++) { + buffrag++; + if (buffrag->dma) { + pci_unmap_page(port->pdev, + buffrag->dma, + buffrag->length, + PCI_DMA_TODEVICE); + buffrag->dma = (u64) NULL; + } + } + /* Free the skb we received in netxen_nic_xmit_frame */ + if (cmd_buff->skb) { + dev_kfree_skb_any(cmd_buff->skb); + cmd_buff->skb = NULL; + } + cmd_buff++; } - /* Free the skb we received in netxen_nic_xmit_frame */ - if (cmd_buff->skb) { - dev_kfree_skb_any(cmd_buff->skb); - cmd_buff->skb = NULL; - } - cmd_buff++; + FLUSH_SCHEDULED_WORK(); + del_timer_sync(&adapter->watchdog_timer); } - FLUSH_SCHEDULED_WORK(); - del_timer_sync(&adapter->watchdog_timer); return 0; } static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; struct netxen_hardware_context *hw = &adapter->ahw; unsigned int first_seg_len = skb->len - skb->data_len; struct netxen_skb_frag *buffrag; @@ -837,12 +727,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) u32 last_cmd_consumer = 0; int no_of_desc; - adapter->stats.xmitcalled++; + port->stats.xmitcalled++; frag_count = skb_shinfo(skb)->nr_frags + 1; if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); - adapter->stats.badskblen++; + port->stats.badskblen++; return NETDEV_TX_OK; } @@ -851,7 +741,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) "too large, can handle only %d frags\n", netxen_nic_driver_name, netdev->name, frag_count, MAX_BUFFERS_PER_CMD); - adapter->stats.txdropped++; + port->stats.txdropped++; if ((++dropped_packet & 0xff) == 0xff) printk("%s: %s droppped packets = %d\n", netxen_nic_driver_name, netdev->name, @@ -868,7 +758,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) */ retry_getting_window: spin_lock_bh(&adapter->tx_lock); - if (adapter->total_threads >= MAX_XMIT_PRODUCERS) { + if (adapter->total_threads == MAX_XMIT_PRODUCERS) { spin_unlock_bh(&adapter->tx_lock); /* * Yield CPU @@ -888,8 +778,9 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb_shinfo(skb)->gso_size > 0) { no_of_desc++; - if ((ip_hdrlen(skb) + tcp_hdrlen(skb) + - sizeof(struct ethhdr)) > + if (((skb->nh.iph)->ihl * sizeof(u32)) + + ((skb->h.th)->doff * sizeof(u32)) + + sizeof(struct ethhdr) > (sizeof(struct cmd_desc_type0) - 2)) { no_of_desc++; } @@ -901,8 +792,15 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if ((k + no_of_desc) >= ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count : last_cmd_consumer)) { + port->stats.nocmddescriptor++; + DPRINTK(ERR, "No command descriptors available," + " producer = %d, consumer = %d count=%llu," + " dropping packet\n", producer, + adapter->last_cmd_consumer, + port->stats.nocmddescriptor); + netif_stop_queue(netdev); - adapter->flags |= NETXEN_NETDEV_STATUS; + port->flags |= NETXEN_NETDEV_STATUS; spin_unlock_bh(&adapter->tx_lock); return NETDEV_TX_BUSY; } @@ -930,17 +828,16 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pbuf->skb = skb; pbuf->cmd = TX_ETHER_PKT; pbuf->frag_count = frag_count; - pbuf->port = adapter->portnum; + pbuf->port = port->portnum; buffrag = &pbuf->frag_array[0]; - buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len, + buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len, PCI_DMA_TODEVICE); buffrag->length = first_seg_len; netxen_set_cmd_desc_totallength(hwdesc, skb->len); netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT); - netxen_set_cmd_desc_port(hwdesc, adapter->portnum); - netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum); + netxen_set_cmd_desc_port(hwdesc, port->portnum); hwdesc->buffer1_length = cpu_to_le16(first_seg_len); hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); @@ -963,7 +860,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) offset = frag->page_offset; temp_len = len; - temp_dma = pci_map_page(adapter->pdev, frag->page, offset, + temp_dma = pci_map_page(port->pdev, frag->page, offset, len, PCI_DMA_TODEVICE); buffrag++; @@ -1023,36 +920,26 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* copy the next 64 bytes - should be enough except * for pathological case */ - skb_copy_from_linear_data_offset(skb, first_hdr_len, - hwdesc, - (hdr_len - - first_hdr_len)); + memcpy((void *)hwdesc, (void *)(skb->data) + + first_hdr_len, hdr_len - first_hdr_len); producer = get_next_index(producer, max_tx_desc_count); } } - - i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]); - - hw->cmd_desc_head[saved_producer].flags_opcode = - cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode); - hw->cmd_desc_head[saved_producer].num_of_buffers_total_length = - cpu_to_le32(hw->cmd_desc_head[saved_producer]. - num_of_buffers_total_length); - spin_lock_bh(&adapter->tx_lock); - adapter->stats.txbytes += i; - + port->stats.txbytes += + netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]); /* Code to update the adapter considering how many producer threads are currently working */ if ((--adapter->num_threads) == 0) { /* This is the last thread */ u32 crb_producer = adapter->cmd_producer; - netxen_nic_update_cmd_producer(adapter, crb_producer); + writel(crb_producer, + NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET)); wmb(); adapter->total_threads = 0; } - adapter->stats.xmitfinished++; + port->stats.xmitfinished++; spin_unlock_bh(&adapter->tx_lock); netdev->trans_start = jiffies; @@ -1072,26 +959,27 @@ static void netxen_watchdog(unsigned long v) static void netxen_tx_timeout(struct net_device *netdev) { - struct netxen_adapter *adapter = (struct netxen_adapter *) - netdev_priv(netdev); - SCHEDULE_WORK(&adapter->tx_timeout_task); + struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); + + SCHEDULE_WORK(&port->tx_timeout_task); } static void netxen_tx_timeout_task(struct work_struct *work) { - struct netxen_adapter *adapter = - container_of(work, struct netxen_adapter, tx_timeout_task); + struct netxen_port *port = + container_of(work, struct netxen_port, tx_timeout_task); + struct net_device *netdev = port->netdev; unsigned long flags; printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", - netxen_nic_driver_name, adapter->netdev->name); - - spin_lock_irqsave(&adapter->lock, flags); - netxen_nic_close(adapter->netdev); - netxen_nic_open(adapter->netdev); - spin_unlock_irqrestore(&adapter->lock, flags); - adapter->netdev->trans_start = jiffies; - netif_wake_queue(adapter->netdev); + netxen_nic_driver_name, netdev->name); + + spin_lock_irqsave(&port->adapter->lock, flags); + netxen_nic_close(netdev); + netxen_nic_open(netdev); + spin_unlock_irqrestore(&port->adapter->lock, flags); + netdev->trans_start = jiffies; + netif_wake_queue(netdev); } static int @@ -1100,16 +988,17 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) u32 ret = 0; DPRINTK(INFO, "Entered handle ISR\n"); + adapter->stats.ints++; if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { int count = 0; u32 mask; - u32 our_int = 0; - our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); - /* not our interrupt */ - if ((our_int & (0x80 << adapter->portnum)) == 0) + mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR)); + if ((mask & 0x80) == 0) { + /* not our interrupt */ return ret; + } netxen_nic_disable_int(adapter); /* Window = 0 or 1 */ do { @@ -1121,6 +1010,7 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) printk("Could not disable interrupt completely\n"); } + adapter->stats.hostints++; if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { if (netif_rx_schedule_prep(netdev)) { @@ -1154,24 +1044,33 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) irqreturn_t netxen_intr(int irq, void *data) { struct netxen_adapter *adapter; + struct netxen_port *port; struct net_device *netdev; + int i; if (unlikely(!irq)) { return IRQ_NONE; /* Not our interrupt */ } adapter = (struct netxen_adapter *)data; - netdev = adapter->netdev; - /* process our status queue (for all 4 ports) */ - if (netif_running(netdev)) - netxen_handle_int(adapter, netdev); + for (i = 0; i < adapter->ahw.max_ports; i++) { + port = adapter->port[i]; + netdev = port->netdev; + + /* process our status queue (for all 4 ports) */ + if (netif_running(netdev)) { + netxen_handle_int(adapter, netdev); + break; + } + } return IRQ_HANDLED; } static int netxen_nic_poll(struct net_device *netdev, int *budget) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; int work_to_do = min(*budget, netdev->quota); int done = 1; int ctx; @@ -1179,6 +1078,7 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) int work_done = 0; DPRINTK(INFO, "polling for %d descriptors\n", *budget); + port->stats.polled++; work_done = 0; for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { @@ -1222,7 +1122,8 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev) { - struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_port *port = netdev_priv(netdev); + struct netxen_adapter *adapter = port->adapter; disable_irq(adapter->irq); netxen_intr(adapter->irq, adapter); enable_irq(adapter->irq); diff --git a/trunk/drivers/net/netxen/netxen_nic_niu.c b/trunk/drivers/net/netxen/netxen_nic_niu.c index cef90a78351e..d5d95074e569 100644 --- a/trunk/drivers/net/netxen/netxen_nic_niu.c +++ b/trunk/drivers/net/netxen/netxen_nic_niu.c @@ -88,13 +88,12 @@ static inline int phy_unlock(struct netxen_adapter *adapter) * -1 on error * */ -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, - __u32 * readval) +int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, + long reg, __u32 * readval) { long timeout = 0; long result = 0; long restore = 0; - long phy = physical_port[adapter->portnum]; __u32 address; __u32 command; __u32 status; @@ -184,13 +183,12 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, * -1 on error * */ -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, - __u32 val) +int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, + long phy, long reg, __u32 val) { long timeout = 0; long result = 0; long restore = 0; - long phy = physical_port[adapter->portnum]; __u32 address; __u32 command; __u32 status; @@ -260,13 +258,15 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, return result; } -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter, + int port) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); return 0; } -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, + int port) { int result = 0; __u32 enable = 0; @@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) netxen_set_phy_int_speed_changed(enable); if (0 != - netxen_niu_gbe_phy_write(adapter, + netxen_niu_gbe_phy_write(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, enable)) result = -EIO; @@ -283,34 +283,38 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) return result; } -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); return 0; } -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter, + int port) { int result = 0; if (0 != - netxen_niu_gbe_phy_write(adapter, + netxen_niu_gbe_phy_write(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) result = -EIO; return result; } -int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); return 0; } -int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) +int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter, + int port) { int result = 0; if (0 != - netxen_niu_gbe_phy_write(adapter, + netxen_niu_gbe_phy_write(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, -EIO)) result = -EIO; @@ -351,9 +355,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, 0x5); } - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) + if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); } @@ -389,9 +393,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, 0x5); } - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) + if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); } @@ -400,11 +404,11 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int result = 0; __u32 status; if (adapter->disable_phy_interrupts) - adapter->disable_phy_interrupts(adapter); + adapter->disable_phy_interrupts(adapter, port); mdelay(2); if (0 == - netxen_niu_gbe_phy_read(adapter, + netxen_niu_gbe_phy_read(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status)) { if (netxen_get_phy_link(status)) { @@ -435,13 +439,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | NETXEN_GB_MAC_ENABLE_TX_RX | NETXEN_GB_MAC_PAUSED_FRMS); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) + if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) + if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); result = -1; @@ -454,18 +458,26 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { - u32 reg; - u32 portnum = physical_port[adapter->portnum]; + u32 reg = 0, ret = 0; - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5); - netxen_nic_hw_read_wx(adapter, - NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), ®, 4); - reg = (reg & ~0x2000UL); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg); + if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XG1_CONFIG_0, 0x5); + /* XXX hack for Mez cards: both ports in promisc mode */ + netxen_nic_hw_read_wx(adapter, + NETXEN_NIU_XGE_CONFIG_1, ®, 4); + reg = (reg | 0x2000UL); + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XGE_CONFIG_1, reg); + reg = 0; + netxen_nic_hw_read_wx(adapter, + NETXEN_NIU_XG1_CONFIG_1, ®, 4); + reg = (reg | 0x2000UL); + netxen_crb_writelit_adapter(adapter, + NETXEN_NIU_XG1_CONFIG_1, reg); + } - return 0; + return ret; } /* @@ -486,7 +498,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, * The read of the PHY INT status will clear the pending * interrupt status */ - if (netxen_niu_gbe_phy_read(adapter, + if (netxen_niu_gbe_phy_read(adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, &int_src) != 0) result = -EINVAL; @@ -523,7 +535,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, printk(KERN_INFO PFX "speed_changed or link status changed"); if (netxen_niu_gbe_phy_read - (adapter, + (adapter, port, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) == 0) { if (netxen_get_phy_speed(status) == 2) { @@ -569,11 +581,10 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, * Note that the passed-in value must already be in network byte order. */ int netxen_niu_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr) + int phy, netxen_ethernet_macaddr_t * addr) { u32 stationhigh; u32 stationlow; - int phy = physical_port[adapter->portnum]; u8 val[8]; if (addr == NULL) @@ -599,12 +610,13 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter, * Set the station MAC address. * Note that the passed-in value must already be in network byte order. */ -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, +int netxen_niu_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr) { u8 temp[4]; u32 val; - int phy = physical_port[adapter->portnum]; + struct netxen_adapter *adapter = port->adapter; + int phy = port->portnum; unsigned char mac_addr[6]; int i; @@ -622,7 +634,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) return -2; - netxen_niu_macaddr_get(adapter, + netxen_niu_macaddr_get(adapter, phy, (netxen_ethernet_macaddr_t *) mac_addr); if (memcmp(mac_addr, addr, 6) == 0) break; @@ -630,7 +642,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, if (i == 10) { printk(KERN_ERR "%s: cannot set Mac addr for %s\n", - netxen_nic_driver_name, adapter->netdev->name); + netxen_nic_driver_name, port->netdev->name); printk(KERN_ERR "MAC address set: " "%02x:%02x:%02x:%02x:%02x:%02x.\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); @@ -723,13 +735,13 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, } /* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) +int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) { __u32 mac_cfg0; - u32 port = physical_port[adapter->portnum]; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; + mac_cfg0 = 0; netxen_gb_soft_reset(mac_cfg0); if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), @@ -739,13 +751,13 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) } /* Disable an XG interface */ -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) { __u32 mac_cfg; - u32 port = physical_port[adapter->portnum]; if (port != 0) return -EINVAL; + mac_cfg = 0; netxen_xg_soft_reset(mac_cfg); if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0, @@ -755,11 +767,10 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) } /* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, netxen_niu_prom_mode_t mode) { __u32 reg; - u32 port = physical_port[adapter->portnum]; if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; @@ -813,50 +824,25 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, * Set the MAC address for an XG port * Note that the passed-in value must already be in network byte order. */ -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, +int netxen_niu_xg_macaddr_set(struct netxen_port *port, netxen_ethernet_macaddr_t addr) { - int phy = physical_port[adapter->portnum]; u8 temp[4]; u32 val; - - if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) - return -EIO; + struct netxen_adapter *adapter = port->adapter; temp[0] = temp[1] = 0; - switch (phy) { - case 0: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, - &val, 4)) - return -EIO; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, - &val, 4)) - return -EIO; - break; - - case 1: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, - &val, 4)) + memcpy(temp + 2, addr, 2); + val = le32_to_cpu(*(__le32 *)temp); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, + &val, 4)) return -EIO; - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, - &val, 4)) + memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); + val = le32_to_cpu(*(__le32 *)temp); + if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, + &val, 4)) return -EIO; - break; - - default: - printk(KERN_ERR "Unknown port %d\n", phy); - break; - } return 0; } @@ -865,10 +851,9 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, * Return the current station MAC address. * Note that the passed-in value must already be in network byte order. */ -int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, +int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, netxen_ethernet_macaddr_t * addr) { - int phy = physical_port[adapter->portnum]; u32 stationhigh; u32 stationlow; u8 val[8]; @@ -893,24 +878,21 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, } int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - netxen_niu_prom_mode_t mode) + int port, netxen_niu_prom_mode_t mode) { __u32 reg; - u32 port = physical_port[adapter->portnum]; - if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) + if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EINVAL; - if (netxen_nic_hw_read_wx(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) - return -EIO; + if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, ®, 4)) + return -EIO; if (mode == NETXEN_NIU_PROMISC_MODE) reg = (reg | 0x2000UL); else reg = (reg & ~0x2000UL); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg); return 0; } diff --git a/trunk/drivers/net/netxen/netxen_nic_phan_reg.h b/trunk/drivers/net/netxen/netxen_nic_phan_reg.h index 9457fc7249c8..0c7c94328b7f 100644 --- a/trunk/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/trunk/drivers/net/netxen/netxen_nic_phan_reg.h @@ -100,21 +100,8 @@ #define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) -#define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) -#define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) - -// 1c0 to 1cc used for signature reg -#define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) -#define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) -#define CRB_V2P_0 NETXEN_NIC_REG(0x290) -#define CRB_V2P_1 NETXEN_NIC_REG(0x294) -#define CRB_V2P_2 NETXEN_NIC_REG(0x298) -#define CRB_V2P_3 NETXEN_NIC_REG(0x29c) -#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) -#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) - /* used for ethtool tests */ #define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) @@ -152,13 +139,128 @@ struct netxen_recv_crb { }; #if defined(DEFINE_GLOBAL_RECV_CRB) +struct netxen_recv_crb recv_crb_registers[] = { + /* + * Instance 0. + */ + { + /* rcv_desc_crb: */ + { + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x100), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x104), + /* crb_gloablrcv_ring: */ + NETXEN_NIC_REG(0x108), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x10c), + + }, + /* Jumbo frames */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x110), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x114), + /* crb_gloablrcv_ring: */ + NETXEN_NIC_REG(0x118), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x11c), + }, + /* LRO */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x120), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x124), + /* crb_gloablrcv_ring: */ + NETXEN_NIC_REG(0x128), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x12c), + } + }, + /* crb_rcvstatus_ring: */ + NETXEN_NIC_REG(0x130), + /* crb_rcv_status_producer: */ + NETXEN_NIC_REG(0x134), + /* crb_rcv_status_consumer: */ + NETXEN_NIC_REG(0x138), + /* crb_rcvpeg_state: */ + NETXEN_NIC_REG(0x13c), + /* crb_status_ring_size */ + NETXEN_NIC_REG(0x140), + + }, + /* + * Instance 1, + */ + { + /* rcv_desc_crb: */ + { + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x144), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x148), + /* crb_globalrcv_ring: */ + NETXEN_NIC_REG(0x14c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x150), + + }, + /* Jumbo frames */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x154), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x158), + /* crb_globalrcv_ring: */ + NETXEN_NIC_REG(0x15c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x160), + }, + /* LRO */ + { + /* crb_rcv_producer_offset: */ + NETXEN_NIC_REG(0x164), + /* crb_rcv_consumer_offset: */ + NETXEN_NIC_REG(0x168), + /* crb_globalrcv_ring: */ + NETXEN_NIC_REG(0x16c), + /* crb_rcv_ring_size */ + NETXEN_NIC_REG(0x170), + } + + }, + /* crb_rcvstatus_ring: */ + NETXEN_NIC_REG(0x174), + /* crb_rcv_status_producer: */ + NETXEN_NIC_REG(0x178), + /* crb_rcv_status_consumer: */ + NETXEN_NIC_REG(0x17c), + /* crb_rcvpeg_state: */ + NETXEN_NIC_REG(0x180), + /* crb_status_ring_size */ + NETXEN_NIC_REG(0x184), + + }, +}; + +u64 ctx_addr_sig_regs[][3] = { + {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, + {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, + {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, + {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} +}; + #else extern struct netxen_recv_crb recv_crb_registers[]; extern u64 ctx_addr_sig_regs[][3]; +#define CRB_CTX_ADDR_REG_LO (ctx_addr_sig_regs[0][0]) +#define CRB_CTX_ADDR_REG_HI (ctx_addr_sig_regs[0][2]) +#define CRB_CTX_SIGNATURE_REG (ctx_addr_sig_regs[0][1]) #endif /* DEFINE_GLOBAL_RECEIVE_CRB */ -#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0]) -#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2]) -#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1]) /* * Temperature control. diff --git a/trunk/drivers/net/ni5010.c b/trunk/drivers/net/ni5010.c index 3d5b4232f65f..8be0d030d6f4 100644 --- a/trunk/drivers/net/ni5010.c +++ b/trunk/drivers/net/ni5010.c @@ -562,6 +562,7 @@ static void ni5010_rx(struct net_device *dev) return; } + skb->dev = dev; skb_reserve(skb, 2); /* Read packet into buffer */ diff --git a/trunk/drivers/net/ni52.c b/trunk/drivers/net/ni52.c index 8dbd6d1900b5..a6f4b24b0176 100644 --- a/trunk/drivers/net/ni52.c +++ b/trunk/drivers/net/ni52.c @@ -934,6 +934,7 @@ static void ni52_rcv_int(struct net_device *dev) skb = (struct sk_buff *) dev_alloc_skb(totlen+2); if(skb != NULL) { + skb->dev = dev; skb_reserve(skb,2); skb_put(skb,totlen); eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0); @@ -1182,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) else #endif { - skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len); + memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); len = skb->len; if (len < ETH_ZLEN) { len = ETH_ZLEN; diff --git a/trunk/drivers/net/ni65.c b/trunk/drivers/net/ni65.c index 3818edf0ac18..1578f4d98498 100644 --- a/trunk/drivers/net/ni65.c +++ b/trunk/drivers/net/ni65.c @@ -610,6 +610,7 @@ static void *ni65_alloc_mem(struct net_device *dev,char *what,int size,int type) printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what); return NULL; } + skb->dev = dev; skb_reserve(skb,2+16); skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ ptr = skb->data; @@ -1093,6 +1094,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) if(skb) { skb_reserve(skb,2); + skb->dev = dev; #ifdef RCV_VIA_SKB if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) { skb_put(skb,len); @@ -1176,9 +1178,8 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) if( (unsigned long) (skb->data + skb->len) > 0x1000000) { #endif - skb_copy_from_linear_data(skb, p->tmdbounce[p->tmdbouncenum], - skb->len > T_BUF_SIZE ? T_BUF_SIZE : - skb->len); + memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, + (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); if (len > skb->len) memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len); dev_kfree_skb (skb); diff --git a/trunk/drivers/net/ns83820.c b/trunk/drivers/net/ns83820.c index 6a32338623f1..9ec6e9e54f47 100644 --- a/trunk/drivers/net/ns83820.c +++ b/trunk/drivers/net/ns83820.c @@ -607,6 +607,7 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp) res &= 0xf; skb_reserve(skb, res); + skb->dev = ndev; if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); @@ -1156,9 +1157,9 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) extsts = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { extsts |= EXTSTS_IPPKT; - if (IPPROTO_TCP == ip_hdr(skb)->protocol) + if (IPPROTO_TCP == skb->nh.iph->protocol) extsts |= EXTSTS_TCPPKT; - else if (IPPROTO_UDP == ip_hdr(skb)->protocol) + else if (IPPROTO_UDP == skb->nh.iph->protocol) extsts |= EXTSTS_UDPPKT; } diff --git a/trunk/drivers/net/pasemi_mac.c b/trunk/drivers/net/pasemi_mac.c index 76fe9dd8e841..d670ac74824f 100644 --- a/trunk/drivers/net/pasemi_mac.c +++ b/trunk/drivers/net/pasemi_mac.c @@ -334,6 +334,8 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) break; } + skb->dev = dev; + dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_FROMDEVICE); @@ -729,18 +731,16 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; if (skb->ip_summed == CHECKSUM_PARTIAL) { - const unsigned char *nh = skb_network_header(skb); - - switch (ip_hdr(skb)->protocol) { + switch (skb->nh.iph->protocol) { case IPPROTO_TCP: dflags |= XCT_MACTX_CSUM_TCP; - dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); - dflags |= XCT_MACTX_IPO(nh - skb->data); + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); break; case IPPROTO_UDP: dflags |= XCT_MACTX_CSUM_UDP; - dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); - dflags |= XCT_MACTX_IPO(nh - skb->data); + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); break; } } diff --git a/trunk/drivers/net/pci-skeleton.c b/trunk/drivers/net/pci-skeleton.c index df8998b4f37e..6ca4e4fa6b88 100644 --- a/trunk/drivers/net/pci-skeleton.c +++ b/trunk/drivers/net/pci-skeleton.c @@ -1344,7 +1344,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) tp->tx_info[entry].skb = skb; /* tp->tx_info[entry].mapping = 0; */ - skb_copy_from_linear_data(skb, tp->tx_buf[entry], skb->len); + memcpy (tp->tx_buf[entry], skb->data, skb->len); /* Note: the chip doesn't have auto-pad! */ NETDRV_W32 (TxStatus0 + (entry * sizeof(u32)), @@ -1565,6 +1565,7 @@ static void netdrv_rx_interrupt (struct net_device *dev, skb = dev_alloc_skb (pkt_size + 2); if (skb) { + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); diff --git a/trunk/drivers/net/pcmcia/3c574_cs.c b/trunk/drivers/net/pcmcia/3c574_cs.c index 2b395ee21f75..c7bd9c1c7f31 100644 --- a/trunk/drivers/net/pcmcia/3c574_cs.c +++ b/trunk/drivers/net/pcmcia/3c574_cs.c @@ -1056,6 +1056,7 @@ static int el3_rx(struct net_device *dev, int worklimit) DEBUG(3, " Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), ((pkt_len+3)>>2)); diff --git a/trunk/drivers/net/pcmcia/3c589_cs.c b/trunk/drivers/net/pcmcia/3c589_cs.c index 143ae2ff309e..461e8274ef69 100644 --- a/trunk/drivers/net/pcmcia/3c589_cs.c +++ b/trunk/drivers/net/pcmcia/3c589_cs.c @@ -883,6 +883,7 @@ static int el3_rx(struct net_device *dev) DEBUG(3, " Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { + skb->dev = dev; skb_reserve(skb, 2); insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), (pkt_len+3)>>2); diff --git a/trunk/drivers/net/pcmcia/axnet_cs.c b/trunk/drivers/net/pcmcia/axnet_cs.c index 808fae1577e0..6139048f8117 100644 --- a/trunk/drivers/net/pcmcia/axnet_cs.c +++ b/trunk/drivers/net/pcmcia/axnet_cs.c @@ -1136,7 +1136,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) ei_block_output(dev, length, skb->data, output_page); else { memset(packet, 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, packet, skb->len); + memcpy(packet, skb->data, skb->len); ei_block_output(dev, length, packet, output_page); } @@ -1496,6 +1496,7 @@ static void ei_receive(struct net_device *dev) else { skb_reserve(skb,2); /* IP headers on 16 byte boundaries */ + skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); diff --git a/trunk/drivers/net/pcmcia/fmvj18x_cs.c b/trunk/drivers/net/pcmcia/fmvj18x_cs.c index 3f93d4933235..0d7de617e535 100644 --- a/trunk/drivers/net/pcmcia/fmvj18x_cs.c +++ b/trunk/drivers/net/pcmcia/fmvj18x_cs.c @@ -999,6 +999,7 @@ static void fjn_rx(struct net_device *dev) lp->stats.rx_dropped++; break; } + skb->dev = dev; skb_reserve(skb, 2); insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), diff --git a/trunk/drivers/net/pcmcia/nmclan_cs.c b/trunk/drivers/net/pcmcia/nmclan_cs.c index 73da611fd536..3b707747a811 100644 --- a/trunk/drivers/net/pcmcia/nmclan_cs.c +++ b/trunk/drivers/net/pcmcia/nmclan_cs.c @@ -1182,10 +1182,12 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) skb = dev_alloc_skb(pkt_len+2); if (skb != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1); if (pkt_len & 1) - *(skb_tail_pointer(skb) - 1) = inb(ioaddr + AM2150_RCV); + *(skb->tail-1) = inb(ioaddr + AM2150_RCV); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ diff --git a/trunk/drivers/net/pcmcia/smc91c92_cs.c b/trunk/drivers/net/pcmcia/smc91c92_cs.c index 7912dbd14251..2561f76033ea 100644 --- a/trunk/drivers/net/pcmcia/smc91c92_cs.c +++ b/trunk/drivers/net/pcmcia/smc91c92_cs.c @@ -1669,6 +1669,7 @@ static void smc_rx(struct net_device *dev) (packet_length+1)>>1); skb->protocol = eth_type_trans(skb, dev); + skb->dev = dev; netif_rx(skb); dev->last_rx = jiffies; smc->stats.rx_packets++; diff --git a/trunk/drivers/net/pcmcia/xirc2ps_cs.c b/trunk/drivers/net/pcmcia/xirc2ps_cs.c index 809ec440b8eb..5879e7c36988 100644 --- a/trunk/drivers/net/pcmcia/xirc2ps_cs.c +++ b/trunk/drivers/net/pcmcia/xirc2ps_cs.c @@ -1226,6 +1226,7 @@ xirc2ps_interrupt(int irq, void *dev_id) (pktlen+1)>>1); } skb->protocol = eth_type_trans(skb, dev); + skb->dev = dev; netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; diff --git a/trunk/drivers/net/pcnet32.c b/trunk/drivers/net/pcnet32.c index 9c171a7390e2..4d94ba7899bf 100644 --- a/trunk/drivers/net/pcnet32.c +++ b/trunk/drivers/net/pcnet32.c @@ -253,12 +253,12 @@ struct pcnet32_access { * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { - struct pcnet32_init_block *init_block; + struct pcnet32_init_block init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ struct pcnet32_rx_head *rx_ring; struct pcnet32_tx_head *tx_ring; - dma_addr_t init_dma_addr;/* DMA address of beginning of the init block, - returned by pci_alloc_consistent */ + dma_addr_t dma_addr;/* DMA address of beginning of this + object, returned by pci_alloc_consistent */ struct pci_dev *pci_dev; const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ @@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, static void pcnet32_purge_rx_ring(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int i; /* free all allocated skbuffs */ @@ -681,7 +681,7 @@ static void pcnet32_poll_controller(struct net_device *dev) static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; @@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; @@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct net_device *dev, static u32 pcnet32_get_link(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; int r; @@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_device *dev) static u32 pcnet32_get_msglevel(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; return lp->msg_enable; } static void pcnet32_set_msglevel(struct net_device *dev, u32 value) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; lp->msg_enable = value; } static int pcnet32_nway_reset(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; @@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net_device *dev) static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; ering->tx_max_pending = TX_MAX_RING_SIZE; ering->tx_pending = lp->tx_ring_size; @@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct net_device *dev, static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; unsigned int size; ulong ioaddr = dev->base_addr; @@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struct net_device *dev) static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *test, u64 * data) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int rc; if (test->flags == ETH_TEST_FL_OFFLINE) { @@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev, static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; /* access to registers */ ulong ioaddr = dev->base_addr; /* card base I/O address */ struct sk_buff *skb; /* sk buff */ @@ -1047,7 +1047,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) static void pcnet32_led_blink_callback(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev) static int pcnet32_phys_id(struct net_device *dev, u32 data) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags, int can_sleep) { int csr5; - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; int ticks; @@ -1206,6 +1206,7 @@ static void pcnet32_rx_entry(struct net_device *dev, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->data, @@ -1257,7 +1258,7 @@ static void pcnet32_rx_entry(struct net_device *dev, static int pcnet32_rx(struct net_device *dev, int quota) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int entry = lp->cur_rx & lp->rx_mod_mask; struct pcnet32_rx_head *rxp = &lp->rx_ring[entry]; int npackets = 0; @@ -1282,7 +1283,7 @@ static int pcnet32_rx(struct net_device *dev, int quota) static int pcnet32_tx(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned int dirty_tx = lp->dirty_tx; int delta; int must_restart = 0; @@ -1381,7 +1382,7 @@ static int pcnet32_tx(struct net_device *dev) #ifdef CONFIG_PCNET32_NAPI static int pcnet32_poll(struct net_device *dev, int *budget) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int quota = min(dev->quota, *budget); unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -1428,7 +1429,7 @@ static int pcnet32_poll(struct net_device *dev, int *budget) #define PCNET32_MAX_PHYS 32 static int pcnet32_get_regs_len(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int j = lp->phycount * PCNET32_REGS_PER_PHY; return ((PCNET32_NUM_REGS + j) * sizeof(u16)); @@ -1439,7 +1440,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, { int i, csr0; u16 *buff = ptr; - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1592,6 +1593,7 @@ static int __devinit pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { struct pcnet32_private *lp; + dma_addr_t lp_dma_addr; int i, media; int fdx, mii, fset, dxsuflo; int chip_version; @@ -1713,7 +1715,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dxsuflo = 1; } - dev = alloc_etherdev(sizeof(*lp)); + dev = alloc_etherdev(0); if (!dev) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Memory allocation failed.\n"); @@ -1804,22 +1806,25 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } dev->base_addr = ioaddr; - lp = netdev_priv(dev); /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ - if ((lp->init_block = - pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) { + if ((lp = + pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); ret = -ENOMEM; goto err_free_netdev; } + + memset(lp, 0, sizeof(*lp)); + lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; spin_lock_init(&lp->lock); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); + dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ @@ -1866,21 +1871,23 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block->tlen_rlen = + lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) - lp->init_block->phys_addr[i] = dev->dev_addr[i]; - lp->init_block->filter[0] = 0x00000000; - lp->init_block->filter[1] = 0x00000000; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); - a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); - a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); + a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, + init_block)) & 0xffff); + a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, + init_block)) >> 16); if (pdev) { /* use the IRQ provided by PCI */ dev->irq = pdev->irq; @@ -1986,8 +1993,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) err_free_ring: pcnet32_free_ring(dev); err_free_consistent: - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), - lp->init_block, lp->init_dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); err_free_netdev: free_netdev(dev); err_release_region: @@ -1998,7 +2004,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* if any allocation fails, caller must also call pcnet32_free_ring */ static int pcnet32_alloc_ring(struct net_device *dev, char *name) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * @@ -2065,7 +2071,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name) static void pcnet32_free_ring(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; kfree(lp->tx_skbuff); lp->tx_skbuff = NULL; @@ -2098,7 +2104,7 @@ static void pcnet32_free_ring(struct net_device *dev) static int pcnet32_open(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 val; int i; @@ -2129,7 +2135,8 @@ static int pcnet32_open(struct net_device *dev) "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), (u32) (lp->rx_ring_dma_addr), - (u32) (lp->init_dma_addr)); + (u32) (lp->dma_addr + + offsetof(struct pcnet32_private, init_block))); /* set/reset autoselect bit */ val = lp->a.read_bcr(ioaddr, 2) & ~2; @@ -2268,7 +2275,7 @@ static int pcnet32_open(struct net_device *dev) } #endif - lp->init_block->mode = + lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); pcnet32_load_multicast(dev); @@ -2278,8 +2285,12 @@ static int pcnet32_open(struct net_device *dev) } /* Re-initialize the PCNET32, and start it when done. */ - lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); - lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); + lp->a.write_csr(ioaddr, 1, (lp->dma_addr + + offsetof(struct pcnet32_private, + init_block)) & 0xffff); + lp->a.write_csr(ioaddr, 2, + (lp->dma_addr + + offsetof(struct pcnet32_private, init_block)) >> 16); lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT); @@ -2306,7 +2317,8 @@ static int pcnet32_open(struct net_device *dev) printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, - (u32) (lp->init_dma_addr), + (u32) (lp->dma_addr + + offsetof(struct pcnet32_private, init_block)), lp->a.read_csr(ioaddr, CSR0)); spin_unlock_irqrestore(&lp->lock, flags); @@ -2344,7 +2356,7 @@ static int pcnet32_open(struct net_device *dev) static void pcnet32_purge_tx_ring(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int i; for (i = 0; i < lp->tx_ring_size; i++) { @@ -2364,7 +2376,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev) /* Initialize the PCNET32 Rx and Tx rings. */ static int pcnet32_init_ring(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int i; lp->tx_full = 0; @@ -2406,12 +2418,12 @@ static int pcnet32_init_ring(struct net_device *dev) lp->tx_dma_addr[i] = 0; } - lp->init_block->tlen_rlen = + lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) - lp->init_block->phys_addr[i] = dev->dev_addr[i]; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -2422,7 +2434,7 @@ static int pcnet32_init_ring(struct net_device *dev) */ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; int i; @@ -2452,7 +2464,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) static void pcnet32_tx_timeout(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr, flags; spin_lock_irqsave(&lp->lock, flags); @@ -2493,7 +2505,7 @@ static void pcnet32_tx_timeout(struct net_device *dev) static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 status; int entry; @@ -2558,7 +2570,7 @@ pcnet32_interrupt(int irq, void *dev_id) int boguscnt = max_interrupt_work; ioaddr = dev->base_addr; - lp = netdev_priv(dev); + lp = dev->priv; spin_lock(&lp->lock); @@ -2640,7 +2652,7 @@ pcnet32_interrupt(int irq, void *dev_id) static int pcnet32_close(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; del_timer_sync(&lp->watchdog_timer); @@ -2681,7 +2693,7 @@ static int pcnet32_close(struct net_device *dev) static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -2695,8 +2707,8 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); - volatile struct pcnet32_init_block *ib = lp->init_block; + struct pcnet32_private *lp = dev->priv; + volatile struct pcnet32_init_block *ib = &lp->init_block; volatile u16 *mcast_table = (u16 *) & ib->filter; struct dev_mc_list *dmi = dev->mc_list; unsigned long ioaddr = dev->base_addr; @@ -2745,7 +2757,7 @@ static void pcnet32_load_multicast(struct net_device *dev) static void pcnet32_set_multicast_list(struct net_device *dev) { unsigned long ioaddr = dev->base_addr, flags; - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int csr15, suspended; spin_lock_irqsave(&lp->lock, flags); @@ -2756,12 +2768,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev) if (netif_msg_hw(lp)) printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - lp->init_block->mode = + lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); } else { - lp->init_block->mode = + lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); pcnet32_load_multicast(dev); @@ -2784,7 +2796,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) /* This routine assumes that the lp->lock is held */ static int mdio_read(struct net_device *dev, int phy_id, int reg_num) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 val_out; @@ -2800,7 +2812,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num) /* This routine assumes that the lp->lock is held */ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; if (!lp->mii) @@ -2812,7 +2824,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int rc; unsigned long flags; @@ -2830,7 +2842,7 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int pcnet32_check_otherphy(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; struct mii_if_info mii = lp->mii_if; u16 bmcr; int i; @@ -2877,7 +2889,7 @@ static int pcnet32_check_otherphy(struct net_device *dev) static void pcnet32_check_media(struct net_device *dev, int verbose) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; int curr_link; int prev_link = netif_carrier_ok(dev) ? 1 : 0; u32 bcr9; @@ -2933,7 +2945,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) static void pcnet32_watchdog(struct net_device *dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unsigned long flags; /* Print the link status if it has changed */ @@ -2949,13 +2961,12 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct pcnet32_private *lp = netdev_priv(dev); + struct pcnet32_private *lp = dev->priv; unregister_netdev(dev); pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), - lp->init_block, lp->init_dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(dev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -3030,13 +3041,12 @@ static void __exit pcnet32_cleanup_module(void) struct net_device *next_dev; while (pcnet32_dev) { - struct pcnet32_private *lp = netdev_priv(pcnet32_dev); + struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), - lp->init_block, lp->init_dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); free_netdev(pcnet32_dev); pcnet32_dev = next_dev; } diff --git a/trunk/drivers/net/phy/fixed.c b/trunk/drivers/net/phy/fixed.c index 68c99b4c5255..66da91bb1388 100644 --- a/trunk/drivers/net/phy/fixed.c +++ b/trunk/drivers/net/phy/fixed.c @@ -276,15 +276,21 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) artificially, we are binding the driver here by hand; it will be the same for all the fixed phys anyway. */ + down_write(&phydev->dev.bus->subsys.rwsem); + phydev->dev.driver = &fixed_mdio_driver.driver; err = phydev->dev.driver->probe(&phydev->dev); if(err < 0) { printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); + up_write(&phydev->dev.bus->subsys.rwsem); goto probe_fail; } err = device_bind_driver(&phydev->dev); + + up_write(&phydev->dev.bus->subsys.rwsem); + if (err) goto probe_fail; diff --git a/trunk/drivers/net/phy/mdio_bus.c b/trunk/drivers/net/phy/mdio_bus.c index fc4aee96cdfd..b31ce278bf35 100644 --- a/trunk/drivers/net/phy/mdio_bus.c +++ b/trunk/drivers/net/phy/mdio_bus.c @@ -35,14 +35,10 @@ #include #include -/** - * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus - * @bus: target mii_bus +/* mdiobus_register * - * Description: Called by a bus driver to bring up all the PHYs - * on a given bus, and attach them to the bus. - * - * Returns 0 on success or < 0 on error. + * description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus */ int mdiobus_register(struct mii_bus *bus) { @@ -118,13 +114,10 @@ void mdiobus_unregister(struct mii_bus *bus) } EXPORT_SYMBOL(mdiobus_unregister); -/** - * mdio_bus_match - determine if given PHY driver supports the given PHY device - * @dev: target PHY device - * @drv: given PHY driver +/* mdio_bus_match * - * Description: Given a PHY device, and a PHY driver, return 1 if - * the driver supports the device. Otherwise, return 0. + * description: Given a PHY device, and a PHY driver, return 1 if + * the driver supports the device. Otherwise, return 0 */ static int mdio_bus_match(struct device *dev, struct device_driver *drv) { diff --git a/trunk/drivers/net/phy/phy.c b/trunk/drivers/net/phy/phy.c index eed433d6056a..c94a1fb3a4be 100644 --- a/trunk/drivers/net/phy/phy.c +++ b/trunk/drivers/net/phy/phy.c @@ -39,9 +39,7 @@ #include #include -/** - * phy_print_status - Convenience function to print out the current phy status - * @phydev: the phy_device struct +/* Convenience function to print out the current phy status */ void phy_print_status(struct phy_device *phydev) { @@ -57,15 +55,10 @@ void phy_print_status(struct phy_device *phydev) EXPORT_SYMBOL(phy_print_status); -/** - * phy_read - Convenience function for reading a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to read - * - * NOTE: MUST NOT be called from interrupt context, +/* Convenience functions for reading/writing a given PHY + * register. They MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ + * to conclude the operation. */ int phy_read(struct phy_device *phydev, u16 regnum) { int retval; @@ -79,16 +72,6 @@ int phy_read(struct phy_device *phydev, u16 regnum) } EXPORT_SYMBOL(phy_read); -/** - * phy_write - Convenience function for writing a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to write - * @val: value to write to @regnum - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ int phy_write(struct phy_device *phydev, u16 regnum, u16 val) { int err; @@ -102,15 +85,7 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val) } EXPORT_SYMBOL(phy_write); -/** - * phy_clear_interrupt - Ack the phy device's interrupt - * @phydev: the phy_device struct - * - * If the @phydev driver has an ack_interrupt function, call it to - * ack and clear the phy device's interrupt. - * - * Returns 0 on success on < 0 on error. - */ + int phy_clear_interrupt(struct phy_device *phydev) { int err = 0; @@ -121,13 +96,7 @@ int phy_clear_interrupt(struct phy_device *phydev) return err; } -/** - * phy_config_interrupt - configure the PHY device for the requested interrupts - * @phydev: the phy_device struct - * @interrupts: interrupt flags to configure for this @phydev - * - * Returns 0 on success on < 0 on error. - */ + int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) { int err = 0; @@ -140,11 +109,9 @@ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) } -/** - * phy_aneg_done - return auto-negotiation status - * @phydev: target phy_device struct +/* phy_aneg_done * - * Description: Reads the status register and returns 0 either if + * description: Reads the status register and returns 0 either if * auto-negotiation is incomplete, or if there was an error. * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. */ @@ -206,12 +173,9 @@ static const struct phy_setting settings[] = { #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) -/** - * phy_find_setting - find a PHY settings array entry that matches speed & duplex - * @speed: speed to match - * @duplex: duplex to match +/* phy_find_setting * - * Description: Searches the settings array for the setting which + * description: Searches the settings array for the setting which * matches the desired speed and duplex, and returns the index * of that setting. Returns the index of the last setting if * none of the others match. @@ -228,12 +192,11 @@ static inline int phy_find_setting(int speed, int duplex) return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } -/** - * phy_find_valid - find a PHY setting that matches the requested features mask - * @idx: The first index in settings[] to search - * @features: A mask of the valid settings +/* phy_find_valid + * idx: The first index in settings[] to search + * features: A mask of the valid settings * - * Description: Returns the index of the first valid setting less + * description: Returns the index of the first valid setting less * than or equal to the one pointed to by idx, as determined by * the mask in features. Returns the index of the last setting * if nothing else matches. @@ -246,13 +209,11 @@ static inline int phy_find_valid(int idx, u32 features) return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } -/** - * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex - * @phydev: the target phy_device struct +/* phy_sanitize_settings * - * Description: Make sure the PHY is set to supported speeds and + * description: Make sure the PHY is set to supported speeds and * duplexes. Drop down by one in this order: 1000/FULL, - * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. + * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF */ void phy_sanitize_settings(struct phy_device *phydev) { @@ -271,17 +232,16 @@ void phy_sanitize_settings(struct phy_device *phydev) } EXPORT_SYMBOL(phy_sanitize_settings); -/** - * phy_ethtool_sset - generic ethtool sset function, handles all the details - * @phydev: target phy_device struct - * @cmd: ethtool_cmd +/* phy_ethtool_sset: + * A generic ethtool sset function. Handles all the details * * A few notes about parameter checking: * - We don't set port or transceiver, so we don't care what they * were set to. * - phy_start_aneg() will make sure forced settings are sane, and * choose the next best ones from the ones selected, so we don't - * care if ethtool tries to give us bad values. + * care if ethtool tries to give us bad values + * */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -344,15 +304,9 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) } EXPORT_SYMBOL(phy_ethtool_gset); -/** - * phy_mii_ioctl - generic PHY MII ioctl interface - * @phydev: the phy_device struct - * @mii_data: MII ioctl data - * @cmd: ioctl cmd to execute - * - * Note that this function is currently incompatible with the +/* Note that this function is currently incompatible with the * PHYCONTROL layer. It changes registers without regard to - * current state. Use at own risk. + * current state. Use at own risk */ int phy_mii_ioctl(struct phy_device *phydev, struct mii_ioctl_data *mii_data, int cmd) @@ -382,12 +336,6 @@ int phy_mii_ioctl(struct phy_device *phydev, phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; - if ((!phydev->autoneg) && - (val & BMCR_SPEED1000)) - phydev->speed = SPEED_1000; - else if ((!phydev->autoneg) && - (val & BMCR_SPEED100)) - phydev->speed = SPEED_100; break; case MII_ADVERTISE: phydev->advertising = val; @@ -410,14 +358,13 @@ int phy_mii_ioctl(struct phy_device *phydev, return 0; } -/** - * phy_start_aneg - start auto-negotiation for this PHY device - * @phydev: the phy_device struct +/* phy_start_aneg * - * Description: Sanitizes the settings (if we're not autonegotiating - * them), and then calls the driver's config_aneg function. - * If the PHYCONTROL Layer is operating, we change the state to - * reflect the beginning of Auto-negotiation or forcing. + * description: Sanitizes the settings (if we're not + * autonegotiating them), and then calls the driver's + * config_aneg function. If the PHYCONTROL Layer is operating, + * we change the state to reflect the beginning of + * Auto-negotiation or forcing. */ int phy_start_aneg(struct phy_device *phydev) { @@ -453,19 +400,15 @@ EXPORT_SYMBOL(phy_start_aneg); static void phy_change(struct work_struct *work); static void phy_timer(unsigned long data); -/** - * phy_start_machine - start PHY state machine tracking - * @phydev: the phy_device struct - * @handler: callback function for state change notifications +/* phy_start_machine: * - * Description: The PHY infrastructure can run a state machine + * description: The PHY infrastructure can run a state machine * which tracks whether the PHY is starting up, negotiating, * etc. This function starts the timer which tracks the state - * of the PHY. If you want to be notified when the state changes, - * pass in the callback @handler, otherwise, pass NULL. If you + * of the PHY. If you want to be notified when the state + * changes, pass in the callback, otherwise, pass NULL. If you * want to maintain your own state machine, do not call this - * function. - */ + * function. */ void phy_start_machine(struct phy_device *phydev, void (*handler)(struct net_device *)) { @@ -477,11 +420,9 @@ void phy_start_machine(struct phy_device *phydev, mod_timer(&phydev->phy_timer, jiffies + HZ); } -/** - * phy_stop_machine - stop the PHY state machine tracking - * @phydev: target phy_device struct +/* phy_stop_machine * - * Description: Stops the state machine timer, sets the state to UP + * description: Stops the state machine timer, sets the state to UP * (unless it wasn't up yet). This function must be called BEFORE * phy_detach. */ @@ -497,14 +438,12 @@ void phy_stop_machine(struct phy_device *phydev) phydev->adjust_state = NULL; } -/** - * phy_force_reduction - reduce PHY speed/duplex settings by one step - * @phydev: target phy_device struct +/* phy_force_reduction * - * Description: Reduces the speed/duplex settings by one notch, - * in this order-- - * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. - * The function bottoms out at 10/HALF. + * description: Reduces the speed/duplex settings by + * one notch. The order is so: + * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, + * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. */ static void phy_force_reduction(struct phy_device *phydev) { @@ -525,9 +464,7 @@ static void phy_force_reduction(struct phy_device *phydev) } -/** - * phy_error - enter HALTED state for this PHY device - * @phydev: target phy_device struct +/* phy_error: * * Moves the PHY to the HALTED state in response to a read * or write error, and tells the controller the link is down. @@ -541,12 +478,9 @@ void phy_error(struct phy_device *phydev) spin_unlock(&phydev->lock); } -/** - * phy_interrupt - PHY interrupt handler - * @irq: interrupt line - * @phy_dat: phy_device pointer +/* phy_interrupt * - * Description: When a PHY interrupt occurs, the handler disables + * description: When a PHY interrupt occurs, the handler disables * interrupts, and schedules a work task to clear the interrupt. */ static irqreturn_t phy_interrupt(int irq, void *phy_dat) @@ -567,10 +501,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) return IRQ_HANDLED; } -/** - * phy_enable_interrupts - Enable the interrupts from the PHY side - * @phydev: target phy_device struct - */ +/* Enable the interrupts from the PHY side */ int phy_enable_interrupts(struct phy_device *phydev) { int err; @@ -586,10 +517,7 @@ int phy_enable_interrupts(struct phy_device *phydev) } EXPORT_SYMBOL(phy_enable_interrupts); -/** - * phy_disable_interrupts - Disable the PHY interrupts from the PHY side - * @phydev: target phy_device struct - */ +/* Disable the PHY interrupts from the PHY side */ int phy_disable_interrupts(struct phy_device *phydev) { int err; @@ -615,15 +543,13 @@ int phy_disable_interrupts(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disable_interrupts); -/** - * phy_start_interrupts - request and enable interrupts for a PHY device - * @phydev: target phy_device struct +/* phy_start_interrupts * - * Description: Request the interrupt for the given PHY. - * If this fails, then we set irq to PHY_POLL. + * description: Request the interrupt for the given PHY. If + * this fails, then we set irq to PHY_POLL. * Otherwise, we enable the interrupts in the PHY. + * Returns 0 on success. * This should only be called with a valid IRQ number. - * Returns 0 on success or < 0 on error. */ int phy_start_interrupts(struct phy_device *phydev) { @@ -648,10 +574,6 @@ int phy_start_interrupts(struct phy_device *phydev) } EXPORT_SYMBOL(phy_start_interrupts); -/** - * phy_stop_interrupts - disable interrupts from a PHY device - * @phydev: target phy_device struct - */ int phy_stop_interrupts(struct phy_device *phydev) { int err; @@ -674,10 +596,7 @@ int phy_stop_interrupts(struct phy_device *phydev) EXPORT_SYMBOL(phy_stop_interrupts); -/** - * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes - * @work: work_struct that describes the work to be done - */ +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ static void phy_change(struct work_struct *work) { int err; @@ -711,10 +630,7 @@ static void phy_change(struct work_struct *work) phy_error(phydev); } -/** - * phy_stop - Bring down the PHY link, and stop checking the status - * @phydev: target phy_device struct - */ +/* Bring down the PHY link, and stop checking the status. */ void phy_stop(struct phy_device *phydev) { spin_lock(&phydev->lock); @@ -743,11 +659,9 @@ void phy_stop(struct phy_device *phydev) } -/** - * phy_start - start or restart a PHY device - * @phydev: target phy_device struct +/* phy_start * - * Description: Indicates the attached device's readiness to + * description: Indicates the attached device's readiness to * handle PHY-related work. Used during startup to start the * PHY, and after a call to phy_stop() to resume operation. * Also used to indicate the MDIO bus has cleared an error diff --git a/trunk/drivers/net/phy/phy_device.c b/trunk/drivers/net/phy/phy_device.c index a8b74cdab1ea..7d5b6d1838c8 100644 --- a/trunk/drivers/net/phy/phy_device.c +++ b/trunk/drivers/net/phy/phy_device.c @@ -74,13 +74,11 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) } EXPORT_SYMBOL(phy_device_create); -/** - * get_phy_device - reads the specified PHY device and returns its @phy_device struct - * @bus: the target MII bus - * @addr: PHY address on the MII bus +/* get_phy_device * - * Description: Reads the ID registers of the PHY at @addr on the - * @bus, then allocates and returns the phy_device to represent it. + * description: Reads the ID registers of the PHY at addr on the + * bus, then allocates and returns the phy_device to + * represent it. */ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) { @@ -114,33 +112,23 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } -/** - * phy_prepare_link - prepares the PHY layer to monitor link status - * @phydev: target phy_device struct - * @handler: callback function for link status change notifications +/* phy_prepare_link: * - * Description: Tells the PHY infrastructure to handle the + * description: Tells the PHY infrastructure to handle the * gory details on monitoring link status (whether through * polling or an interrupt), and to call back to the * connected device driver when the link status changes. * If you want to monitor your own link state, don't call - * this function. - */ + * this function */ void phy_prepare_link(struct phy_device *phydev, void (*handler)(struct net_device *)) { phydev->adjust_link = handler; } -/** - * phy_connect - connect an ethernet device to a PHY device - * @dev: the network device to connect - * @phy_id: the PHY device to connect - * @handler: callback function for state change notifications - * @flags: PHY device's dev_flags - * @interface: PHY device's interface +/* phy_connect: * - * Description: Convenience function for connecting ethernet + * description: Convenience function for connecting ethernet * devices to PHY devices. The default behavior is for * the PHY infrastructure to handle everything, and only notify * the connected driver when the link status changes. If you @@ -170,10 +158,6 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, } EXPORT_SYMBOL(phy_connect); -/** - * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device - * @phydev: target phy_device struct - */ void phy_disconnect(struct phy_device *phydev) { if (phydev->irq > 0) @@ -187,25 +171,21 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -static int phy_compare_id(struct device *dev, void *data) -{ - return strcmp((char *)data, dev->bus_id) ? 0 : 1; -} - -/** - * phy_attach - attach a network device to a particular PHY device - * @dev: network device to attach - * @phy_id: PHY device to attach - * @flags: PHY device's dev_flags - * @interface: PHY device's interface +/* phy_attach: * - * Description: Called by drivers to attach to a particular PHY + * description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up * to the phy_driver. If no driver is attached, then the * genphy_driver is used. The phy_device is given a ptr to * the attaching device, and given a callback for link status - * change. The phy_device is returned to the attaching driver. + * change. The phy_device is returned to the attaching + * driver. */ +static int phy_compare_id(struct device *dev, void *data) +{ + return strcmp((char *)data, dev->bus_id) ? 0 : 1; +} + struct phy_device *phy_attach(struct net_device *dev, const char *phy_id, u32 flags, phy_interface_t interface) { @@ -228,12 +208,16 @@ struct phy_device *phy_attach(struct net_device *dev, * exist, and we should use the genphy driver. */ if (NULL == d->driver) { int err; + down_write(&d->bus->subsys.rwsem); d->driver = &genphy_driver.driver; err = d->driver->probe(d); + if (err >= 0) err = device_bind_driver(d); + up_write(&d->bus->subsys.rwsem); + if (err) return ERR_PTR(err); } @@ -266,10 +250,6 @@ struct phy_device *phy_attach(struct net_device *dev, } EXPORT_SYMBOL(phy_attach); -/** - * phy_detach - detach a PHY device from its network device - * @phydev: target phy_device struct - */ void phy_detach(struct phy_device *phydev) { phydev->attached_dev = NULL; @@ -278,21 +258,22 @@ void phy_detach(struct phy_device *phydev) * was using the generic driver), we unbind the device * from the generic driver so that there's a chance a * real driver could be loaded */ - if (phydev->dev.driver == &genphy_driver.driver) + if (phydev->dev.driver == &genphy_driver.driver) { + down_write(&phydev->dev.bus->subsys.rwsem); device_release_driver(&phydev->dev); + up_write(&phydev->dev.bus->subsys.rwsem); + } } EXPORT_SYMBOL(phy_detach); /* Generic PHY support and helper functions */ -/** - * genphy_config_advert - sanitize and advertise auto-negotation parameters - * @phydev: target phy_device struct +/* genphy_config_advert * - * Description: Writes MII_ADVERTISE with the appropriate values, + * description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise - * what is supported. + * what is supported */ int genphy_config_advert(struct phy_device *phydev) { @@ -354,14 +335,11 @@ int genphy_config_advert(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_advert); -/** - * genphy_setup_forced - configures/forces speed/duplex from @phydev - * @phydev: target phy_device struct +/* genphy_setup_forced * - * Description: Configures MII_BMCR to force speed/duplex + * description: Configures MII_BMCR to force speed/duplex * to the values in phydev. Assumes that the values are valid. - * Please see phy_sanitize_settings(). - */ + * Please see phy_sanitize_settings() */ int genphy_setup_forced(struct phy_device *phydev) { int ctl = BMCR_RESET; @@ -390,10 +368,7 @@ int genphy_setup_forced(struct phy_device *phydev) } -/** - * genphy_restart_aneg - Enable and Restart Autonegotiation - * @phydev: target phy_device struct - */ +/* Enable and Restart Autonegotiation */ int genphy_restart_aneg(struct phy_device *phydev) { int ctl; @@ -414,13 +389,11 @@ int genphy_restart_aneg(struct phy_device *phydev) } -/** - * genphy_config_aneg - restart auto-negotiation or write BMCR - * @phydev: target phy_device struct +/* genphy_config_aneg * - * Description: If auto-negotiation is enabled, we configure the + * description: If auto-negotiation is enabled, we configure the * advertising, and then restart auto-negotiation. If it is not - * enabled, then we write the BMCR. + * enabled, then we write the BMCR */ int genphy_config_aneg(struct phy_device *phydev) { @@ -440,13 +413,11 @@ int genphy_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_aneg); -/** - * genphy_update_link - update link status in @phydev - * @phydev: target phy_device struct +/* genphy_update_link * - * Description: Update the value in phydev->link to reflect the + * description: Update the value in phydev->link to reflect the * current link value. In order to do this, we need to read - * the status register twice, keeping the second value. + * the status register twice, keeping the second value */ int genphy_update_link(struct phy_device *phydev) { @@ -473,11 +444,9 @@ int genphy_update_link(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_update_link); -/** - * genphy_read_status - check the link status and update current link state - * @phydev: target phy_device struct +/* genphy_read_status * - * Description: Check the link, then figure out the current state + * description: Check the link, then figure out the current state * by comparing what we advertise with what the link partner * advertises. Start by checking the gigabit possibilities, * then move on to 10/100. @@ -617,11 +586,9 @@ static int genphy_config_init(struct phy_device *phydev) } -/** - * phy_probe - probe and init a PHY device - * @dev: device to probe and init +/* phy_probe * - * Description: Take care of setting up the phy_device structure, + * description: Take care of setting up the phy_device structure, * set the state to READY (the driver's init function should * set it to STARTING if needed). */ @@ -683,10 +650,6 @@ static int phy_remove(struct device *dev) return 0; } -/** - * phy_driver_register - register a phy_driver with the PHY layer - * @new_driver: new phy_driver to register - */ int phy_driver_register(struct phy_driver *new_driver) { int retval; diff --git a/trunk/drivers/net/plip.c b/trunk/drivers/net/plip.c index 8754cf3356b0..6bb085f54437 100644 --- a/trunk/drivers/net/plip.c +++ b/trunk/drivers/net/plip.c @@ -546,7 +546,7 @@ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) struct ethhdr *eth; unsigned char *rawp; - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); eth = eth_hdr(skb); diff --git a/trunk/drivers/net/ppp_async.c b/trunk/drivers/net/ppp_async.c index caabbc408c34..933e2f3c77aa 100644 --- a/trunk/drivers/net/ppp_async.c +++ b/trunk/drivers/net/ppp_async.c @@ -802,9 +802,9 @@ process_input_packet(struct asyncppp *ap) /* check for address/control and protocol compression */ p = skb->data; - if (p[0] == PPP_ALLSTATIONS) { + if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { /* chop off address/control */ - if (p[1] != PPP_UI || skb->len < 3) + if (skb->len < 3) goto err; p = skb_pull(skb, 2); } diff --git a/trunk/drivers/net/ppp_generic.c b/trunk/drivers/net/ppp_generic.c index 6d596ca50cfd..ef58e4128782 100644 --- a/trunk/drivers/net/ppp_generic.c +++ b/trunk/drivers/net/ppp_generic.c @@ -88,6 +88,8 @@ struct ppp_file { #define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) #define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) +#define ROUNDUP(n, x) (((n) + (x) - 1) / (x)) + /* * Data structure describing one ppp unit. * A ppp unit corresponds to a ppp network interface device @@ -1295,7 +1297,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) */ fragsize = len; if (nfree > 1) - fragsize = DIV_ROUND_UP(fragsize, nfree); + fragsize = ROUNDUP(fragsize, nfree); /* nbigger channels get fragsize bytes, the rest get fragsize-1, except if nbigger==0, then they all get fragsize. */ nbigger = len % nfree; @@ -1683,7 +1685,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb_pull_rcsum(skb, 2); skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; netif_rx(skb); ppp->dev->last_rx = jiffies; } diff --git a/trunk/drivers/net/ppp_synctty.c b/trunk/drivers/net/ppp_synctty.c index 5918fab38349..b6f0e9a25e26 100644 --- a/trunk/drivers/net/ppp_synctty.c +++ b/trunk/drivers/net/ppp_synctty.c @@ -594,8 +594,7 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) return NULL; } skb_reserve(npkt,2); - skb_copy_from_linear_data(skb, - skb_put(npkt, skb->len), skb->len); + memcpy(skb_put(npkt,skb->len), skb->data, skb->len); kfree_skb(skb); skb = npkt; } diff --git a/trunk/drivers/net/pppoe.c b/trunk/drivers/net/pppoe.c index 6f98834e6ace..ebfa2967cd68 100644 --- a/trunk/drivers/net/pppoe.c +++ b/trunk/drivers/net/pppoe.c @@ -207,7 +207,7 @@ static inline struct pppox_sock *get_item(unsigned long sid, static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) { - struct net_device *dev; + struct net_device *dev = NULL; int ifindex; dev = dev_get_by_name(sp->sa_addr.pppoe.dev); @@ -218,6 +218,20 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); } +static inline int set_item(struct pppox_sock *po) +{ + int i; + + if (!po) + return -EINVAL; + + write_lock_bh(&pppoe_hash_lock); + i = __set_item(po); + write_unlock_bh(&pppoe_hash_lock); + + return i; +} + static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex) { struct pppox_sock *ret; @@ -241,53 +255,54 @@ static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int static void pppoe_flush_dev(struct net_device *dev) { int hash; + BUG_ON(dev == NULL); - write_lock_bh(&pppoe_hash_lock); + read_lock_bh(&pppoe_hash_lock); for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) { struct pppox_sock *po = item_hash_table[hash]; while (po != NULL) { - struct sock *sk = sk_pppox(po); - if (po->pppoe_dev != dev) { - po = po->next; - continue; - } - po->pppoe_dev = NULL; - dev_put(dev); + if (po->pppoe_dev == dev) { + struct sock *sk = sk_pppox(po); + sock_hold(sk); + po->pppoe_dev = NULL; - /* We always grab the socket lock, followed by the - * pppoe_hash_lock, in that order. Since we should - * hold the sock lock while doing any unbinding, - * we need to release the lock we're holding. - * Hold a reference to the sock so it doesn't disappear - * as we're jumping between locks. - */ + /* We hold a reference to SK, now drop the + * hash table lock so that we may attempt + * to lock the socket (which can sleep). + */ + read_unlock_bh(&pppoe_hash_lock); - sock_hold(sk); + lock_sock(sk); - write_unlock_bh(&pppoe_hash_lock); - lock_sock(sk); + if (sk->sk_state & + (PPPOX_CONNECTED | PPPOX_BOUND)) { + pppox_unbind_sock(sk); + dev_put(dev); + sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); + } - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { - pppox_unbind_sock(sk); - sk->sk_state = PPPOX_ZOMBIE; - sk->sk_state_change(sk); - } + release_sock(sk); - release_sock(sk); - sock_put(sk); + sock_put(sk); - /* Restart scan at the beginning of this hash chain. - * While the lock was dropped the chain contents may - * have changed. - */ - write_lock_bh(&pppoe_hash_lock); - po = item_hash_table[hash]; + read_lock_bh(&pppoe_hash_lock); + + /* Now restart from the beginning of this + * hash chain. We always NULL out pppoe_dev + * so we are guaranteed to make forward + * progress. + */ + po = item_hash_table[hash]; + continue; + } + po = po->next; } } - write_unlock_bh(&pppoe_hash_lock); + read_unlock_bh(&pppoe_hash_lock); } static int pppoe_device_event(struct notifier_block *this, @@ -329,10 +344,10 @@ static struct notifier_block pppoe_notifier = { static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) { struct pppox_sock *po = pppox_sk(sk); - struct pppox_sock *relay_po; + struct pppox_sock *relay_po = NULL; if (sk->sk_state & PPPOX_BOUND) { - struct pppoe_hdr *ph = pppoe_hdr(skb); + struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; int len = ntohs(ph->length); skb_pull_rcsum(skb, sizeof(struct pppoe_hdr)); if (pskb_trim_rcsum(skb, len)) @@ -386,7 +401,7 @@ static int pppoe_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; - ph = pppoe_hdr(skb); + ph = (struct pppoe_hdr *) skb->nh.raw; po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po != NULL) @@ -418,7 +433,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; - ph = pppoe_hdr(skb); + ph = (struct pppoe_hdr *) skb->nh.raw; if (ph->code != PADT_CODE) goto abort; @@ -499,49 +514,36 @@ static int pppoe_release(struct socket *sock) { struct sock *sk = sock->sk; struct pppox_sock *po; + int error = 0; if (!sk) return 0; - lock_sock(sk); - if (sock_flag(sk, SOCK_DEAD)){ - release_sock(sk); + if (sock_flag(sk, SOCK_DEAD)) return -EBADF; - } pppox_unbind_sock(sk); /* Signal the death of the socket. */ sk->sk_state = PPPOX_DEAD; - - /* Write lock on hash lock protects the entire "po" struct from - * concurrent updates via pppoe_flush_dev. The "po" struct should - * be considered part of the hash table contents, thus protected - * by the hash table lock */ - write_lock_bh(&pppoe_hash_lock); - po = pppox_sk(sk); if (po->pppoe_pa.sid) { - __delete_item(po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); + delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); } - if (po->pppoe_dev) { + if (po->pppoe_dev) dev_put(po->pppoe_dev); - po->pppoe_dev = NULL; - } - write_unlock_bh(&pppoe_hash_lock); + po->pppoe_dev = NULL; sock_orphan(sk); sock->sk = NULL; skb_queue_purge(&sk->sk_receive_queue); - release_sock(sk); sock_put(sk); - return 0; + return error; } @@ -597,18 +599,14 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, po->pppoe_dev = dev; po->pppoe_ifindex = dev->ifindex; - write_lock_bh(&pppoe_hash_lock); - if (!(dev->flags & IFF_UP)){ - write_unlock_bh(&pppoe_hash_lock); + if (!(dev->flags & IFF_UP)) goto err_put; - } memcpy(&po->pppoe_pa, &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); - error = __set_item(po); - write_unlock_bh(&pppoe_hash_lock); + error = set_item(po); if (error < 0) goto err_put; @@ -764,10 +762,10 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd, static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { - struct sk_buff *skb; + struct sk_buff *skb = NULL; struct sock *sk = sock->sk; struct pppox_sock *po = pppox_sk(sk); - int error; + int error = 0; struct pppoe_hdr hdr; struct pppoe_hdr *ph; struct net_device *dev; @@ -801,7 +799,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, /* Reserve space for headers. */ skb_reserve(skb, dev->hard_header_len); - skb_reset_network_header(skb); + skb->nh.raw = skb->data; skb->dev = dev; @@ -871,8 +869,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) goto abort; skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr)); - skb_copy_from_linear_data(skb, skb_put(skb2, skb->len), - skb->len); + memcpy(skb_put(skb2, skb->len), skb->data, skb->len); } else { /* Make a clone so as to not disturb the original skb, * give dev_queue_xmit something it can free. @@ -887,7 +884,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); skb2->protocol = __constant_htons(ETH_P_PPP_SES); - skb_reset_network_header(skb2); + skb2->nh.raw = skb2->data; skb2->dev = dev; @@ -932,8 +929,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len, int flags) { struct sock *sk = sock->sk; - struct sk_buff *skb; + struct sk_buff *skb = NULL; int error = 0; + int len; + struct pppoe_hdr *ph = NULL; if (sk->sk_state & PPPOX_BOUND) { error = -EIO; @@ -943,21 +942,26 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &error); - if (error < 0) + if (error < 0) { goto end; + } m->msg_namelen = 0; if (skb) { - struct pppoe_hdr *ph = pppoe_hdr(skb); - const int len = ntohs(ph->length); + error = 0; + ph = (struct pppoe_hdr *) skb->nh.raw; + len = ntohs(ph->length); error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len); - if (error == 0) - error = len; + if (error < 0) + goto do_skb_free; + error = len; } - kfree_skb(skb); +do_skb_free: + if (skb) + kfree_skb(skb); end: return error; } @@ -987,7 +991,7 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) static __inline__ struct pppox_sock *pppoe_get_idx(loff_t pos) { - struct pppox_sock *po; + struct pppox_sock *po = NULL; int i = 0; for (; i < PPPOE_HASH_SIZE; i++) { diff --git a/trunk/drivers/net/pppox.c b/trunk/drivers/net/pppox.c index f3e47d0c2b3c..9315046b3f55 100644 --- a/trunk/drivers/net/pppox.c +++ b/trunk/drivers/net/pppox.c @@ -31,7 +31,6 @@ #include #include #include -#include #include @@ -59,7 +58,7 @@ void pppox_unbind_sock(struct sock *sk) { /* Clear connection to ppp device, if attached. */ - if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) { + if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE)) { ppp_unregister_channel(&pppox_sk(sk)->chan); sk->sk_state = PPPOX_DEAD; } @@ -115,13 +114,6 @@ static int pppox_create(struct socket *sock, int protocol) goto out; rc = -EPROTONOSUPPORT; -#ifdef CONFIG_KMOD - if (!pppox_protos[protocol]) { - char buffer[32]; - sprintf(buffer, "pppox-proto-%d", protocol); - request_module(buffer); - } -#endif if (!pppox_protos[protocol] || !try_module_get(pppox_protos[protocol]->owner)) goto out; diff --git a/trunk/drivers/net/qla3xxx.c b/trunk/drivers/net/qla3xxx.c index d8766c0e8255..a8246eb2f8d9 100755 --- a/trunk/drivers/net/qla3xxx.c +++ b/trunk/drivers/net/qla3xxx.c @@ -39,7 +39,7 @@ #define DRV_NAME "qla3xxx" #define DRV_STRING "QLogic ISP3XXX Network Driver" -#define DRV_VERSION "v2.03.00-k4" +#define DRV_VERSION "v2.03.00-k3" #define PFX DRV_NAME " " static const char ql3xxx_driver_name[] = DRV_NAME; @@ -71,30 +71,6 @@ static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl); -/* - * These are the known PHY's which are used - */ -typedef enum { - PHY_TYPE_UNKNOWN = 0, - PHY_VITESSE_VSC8211, - PHY_AGERE_ET1011C, - MAX_PHY_DEV_TYPES -} PHY_DEVICE_et; - -typedef struct { - PHY_DEVICE_et phyDevice; - u32 phyIdOUI; - u16 phyIdModel; - char *name; -} PHY_DEVICE_INFO_t; - -static const PHY_DEVICE_INFO_t PHY_DEVICES[] = - {{PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"}, - {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"}, - {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"}, -}; - - /* * Caller must take hw_lock. */ @@ -686,7 +662,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev) } static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, - u16 regAddr, u16 value, u32 phyAddr) + u16 regAddr, u16 value, u32 mac_index) { struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -704,7 +680,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, } ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, - phyAddr | regAddr); + PHYAddr[mac_index] | regAddr); ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value); @@ -725,7 +701,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, } static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, - u16 * value, u32 phyAddr) + u16 * value, u32 mac_index) { struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -744,7 +720,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, } ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, - phyAddr | regAddr); + PHYAddr[mac_index] | regAddr); ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, (MAC_MII_CONTROL_RC << 16)); @@ -874,31 +850,28 @@ static void ql_petbi_start_neg(struct ql3_adapter *qdev) } -static void ql_petbi_reset_ex(struct ql3_adapter *qdev) +static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index) { ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET, - PHYAddr[qdev->mac_index]); + mac_index); } -static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev) +static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) { u16 reg; /* Enable Auto-negotiation sense */ - ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, - PHYAddr[qdev->mac_index]); + ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, mac_index); reg |= PETBI_TBI_AUTO_SENSE; - ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, - PHYAddr[qdev->mac_index]); + ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index); ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, - PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, - PHYAddr[qdev->mac_index]); + PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index); ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG | PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000, - PHYAddr[qdev->mac_index]); + mac_index); } static void ql_petbi_init(struct ql3_adapter *qdev) @@ -907,10 +880,10 @@ static void ql_petbi_init(struct ql3_adapter *qdev) ql_petbi_start_neg(qdev); } -static void ql_petbi_init_ex(struct ql3_adapter *qdev) +static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index) { - ql_petbi_reset_ex(qdev); - ql_petbi_start_neg_ex(qdev); + ql_petbi_reset_ex(qdev, mac_index); + ql_petbi_start_neg_ex(qdev, mac_index); } static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) @@ -923,128 +896,33 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE; } -static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) -{ - printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name); - /* power down device bit 11 = 1 */ - ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr); - /* enable diagnostic mode bit 2 = 1 */ - ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr); - /* 1000MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr); - /* 1000MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr); - /* 100MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr); - /* 100MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr); - /* 10MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr); - /* 10MB amplitude adjust (see Agere errata) */ - ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr); - /* point to hidden reg 0x2806 */ - ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr); - /* Write new PHYAD w/bit 5 set */ - ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr); - /* - * Disable diagnostic mode bit 2 = 0 - * Power up device bit 11 = 0 - * Link up (on) and activity (blink) - */ - ql_mii_write_reg(qdev, 0x12, 0x840a); - ql_mii_write_reg(qdev, 0x00, 0x1140); - ql_mii_write_reg(qdev, 0x1c, 0xfaf0); -} - -static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, - u16 phyIdReg0, u16 phyIdReg1) -{ - PHY_DEVICE_et result = PHY_TYPE_UNKNOWN; - u32 oui; - u16 model; - int i; - - if (phyIdReg0 == 0xffff) { - return result; - } - - if (phyIdReg1 == 0xffff) { - return result; - } - - /* oui is split between two registers */ - oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10); - - model = (phyIdReg1 & PHY_MODEL_MASK) >> 4; - - /* Scan table for this PHY */ - for(i = 0; i < MAX_PHY_DEV_TYPES; i++) { - if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel)) - { - result = PHY_DEVICES[i].phyDevice; - - printk(KERN_INFO "%s: Phy: %s\n", - qdev->ndev->name, PHY_DEVICES[i].name); - - break; - } - } - - return result; -} - static int ql_phy_get_speed(struct ql3_adapter *qdev) { u16 reg; - switch(qdev->phyType) { - case PHY_AGERE_ET1011C: - { - if (ql_mii_read_reg(qdev, 0x1A, ®) < 0) - return 0; - - reg = (reg >> 8) & 3; - break; - } - default: if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) return 0; reg = (((reg & 0x18) >> 3) & 3); - } - switch(reg) { - case 2: + if (reg == 2) return SPEED_1000; - case 1: + else if (reg == 1) return SPEED_100; - case 0: + else if (reg == 0) return SPEED_10; - default: + else return -1; - } } static int ql_is_full_dup(struct ql3_adapter *qdev) { u16 reg; - switch(qdev->phyType) { - case PHY_AGERE_ET1011C: - { - if (ql_mii_read_reg(qdev, 0x1A, ®)) - return 0; - - return ((reg & 0x0080) && (reg & 0x1000)) != 0; - } - case PHY_VITESSE_VSC8211: - default: - { - if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) - return 0; - return (reg & PHY_AUX_DUPLEX_STAT) != 0; - } - } + if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) + return 0; + + return (reg & PHY_AUX_DUPLEX_STAT) != 0; } static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) @@ -1057,73 +935,6 @@ static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) return (reg & PHY_NEG_PAUSE) != 0; } -static int PHY_Setup(struct ql3_adapter *qdev) -{ - u16 reg1; - u16 reg2; - bool agereAddrChangeNeeded = false; - u32 miiAddr = 0; - int err; - - /* Determine the PHY we are using by reading the ID's */ - err = ql_mii_read_reg(qdev, PHY_ID_0_REG, ®1); - if(err != 0) { - printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n", - qdev->ndev->name); - return err; - } - - err = ql_mii_read_reg(qdev, PHY_ID_1_REG, ®2); - if(err != 0) { - printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n", - qdev->ndev->name); - return err; - } - - /* Check if we have a Agere PHY */ - if ((reg1 == 0xffff) || (reg2 == 0xffff)) { - - /* Determine which MII address we should be using - determined by the index of the card */ - if (qdev->mac_index == 0) { - miiAddr = MII_AGERE_ADDR_1; - } else { - miiAddr = MII_AGERE_ADDR_2; - } - - err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, ®1, miiAddr); - if(err != 0) { - printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", - qdev->ndev->name); - return err; - } - - err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, ®2, miiAddr); - if(err != 0) { - printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", - qdev->ndev->name); - return err; - } - - /* We need to remember to initialize the Agere PHY */ - agereAddrChangeNeeded = true; - } - - /* Determine the particular PHY we have on board to apply - PHY specific initializations */ - qdev->phyType = getPhyType(qdev, reg1, reg2); - - if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) { - /* need this here so address gets changed */ - phyAgereSpecificInit(qdev, miiAddr); - } else if (qdev->phyType == PHY_TYPE_UNKNOWN) { - printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name); - return -EIO; - } - - return 0; -} - /* * Caller holds hw_lock. */ @@ -1394,14 +1205,15 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev) /* * Caller holds hw_lock. */ -static int ql_this_adapter_controls_port(struct ql3_adapter *qdev) +static int ql_this_adapter_controls_port(struct ql3_adapter *qdev, + u32 mac_index) { struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; u32 bitToCheck = 0; u32 temp; - switch (qdev->mac_index) { + switch (mac_index) { case 0: bitToCheck = PORT_STATUS_F1_ENABLED; break; @@ -1426,96 +1238,27 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev) } } -static void ql_phy_reset_ex(struct ql3_adapter *qdev) +static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index) { - ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, - PHYAddr[qdev->mac_index]); + ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index); } -static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) +static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) { u16 reg; - u16 portConfiguration; - - if(qdev->phyType == PHY_AGERE_ET1011C) { - /* turn off external loopback */ - ql_mii_write_reg(qdev, 0x13, 0x0000); - } - - if(qdev->mac_index == 0) - portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration; - else - portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration; - - /* Some HBA's in the field are set to 0 and they need to - be reinterpreted with a default value */ - if(portConfiguration == 0) - portConfiguration = PORT_CONFIG_DEFAULT; - - /* Set the 1000 advertisements */ - ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, - PHYAddr[qdev->mac_index]); - reg &= ~PHY_GIG_ALL_PARAMS; - - if(portConfiguration & - PORT_CONFIG_FULL_DUPLEX_ENABLED & - PORT_CONFIG_1000MB_SPEED) { - reg |= PHY_GIG_ADV_1000F; - } - - if(portConfiguration & - PORT_CONFIG_HALF_DUPLEX_ENABLED & - PORT_CONFIG_1000MB_SPEED) { - reg |= PHY_GIG_ADV_1000H; - } - ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, - PHYAddr[qdev->mac_index]); + ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, + PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index); - /* Set the 10/100 & pause negotiation advertisements */ - ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, ®, - PHYAddr[qdev->mac_index]); - reg &= ~PHY_NEG_ALL_PARAMS; - - if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED) - reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE; - - if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) { - if(portConfiguration & PORT_CONFIG_100MB_SPEED) - reg |= PHY_NEG_ADV_100F; - - if(portConfiguration & PORT_CONFIG_10MB_SPEED) - reg |= PHY_NEG_ADV_10F; - } - - if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) { - if(portConfiguration & PORT_CONFIG_100MB_SPEED) - reg |= PHY_NEG_ADV_100H; - - if(portConfiguration & PORT_CONFIG_10MB_SPEED) - reg |= PHY_NEG_ADV_10H; - } - - if(portConfiguration & - PORT_CONFIG_1000MB_SPEED) { - reg |= 1; - } - - ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, - PHYAddr[qdev->mac_index]); - - ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, PHYAddr[qdev->mac_index]); - - ql_mii_write_reg_ex(qdev, CONTROL_REG, - reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG, - PHYAddr[qdev->mac_index]); + ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, mac_index); + ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG, + mac_index); } -static void ql_phy_init_ex(struct ql3_adapter *qdev) +static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index) { - ql_phy_reset_ex(qdev); - PHY_Setup(qdev); - ql_phy_start_neg_ex(qdev); + ql_phy_reset_ex(qdev, mac_index); + ql_phy_start_neg_ex(qdev, mac_index); } /* @@ -1552,17 +1295,14 @@ static int ql_port_start(struct ql3_adapter *qdev) { if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * - 2) << 7)) { - printk(KERN_ERR "%s: Could not get hw lock for GIO\n", - qdev->ndev->name); + 2) << 7)) return -1; - } if (ql_is_fiber(qdev)) { ql_petbi_init(qdev); } else { /* Copper port */ - ql_phy_init_ex(qdev); + ql_phy_init_ex(qdev, qdev->mac_index); } ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); @@ -1713,7 +1453,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev) */ static void ql_get_phy_owner(struct ql3_adapter *qdev) { - if (ql_this_adapter_controls_port(qdev)) + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) set_bit(QL_LINK_MASTER,&qdev->flags); else clear_bit(QL_LINK_MASTER,&qdev->flags); @@ -1727,11 +1467,11 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev) ql_mii_enable_scan_mode(qdev); if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { - if (ql_this_adapter_controls_port(qdev)) - ql_petbi_init_ex(qdev); + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) + ql_petbi_init_ex(qdev, qdev->mac_index); } else { - if (ql_this_adapter_controls_port(qdev)) - ql_phy_init_ex(qdev); + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) + ql_phy_init_ex(qdev, qdev->mac_index); } } @@ -1884,23 +1624,6 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value) qdev->msg_enable = value; } -static void ql_get_pauseparam(struct net_device *ndev, - struct ethtool_pauseparam *pause) -{ - struct ql3_adapter *qdev = netdev_priv(ndev); - struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; - - u32 reg; - if(qdev->mac_index == 0) - reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg); - else - reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg); - - pause->autoneg = ql_get_auto_cfg_status(qdev); - pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2; - pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1; -} - static const struct ethtool_ops ql3xxx_ethtool_ops = { .get_settings = ql_get_settings, .get_drvinfo = ql_get_drvinfo, @@ -1908,7 +1631,6 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = ql_get_msglevel, .set_msglevel = ql_set_msglevel, - .get_pauseparam = ql_get_pauseparam, }; static int ql_populate_free_queue(struct ql3_adapter *qdev) @@ -2093,14 +1815,14 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, atomic_inc(&qdev->tx_count); } -static void ql_get_sbuf(struct ql3_adapter *qdev) +void ql_get_sbuf(struct ql3_adapter *qdev) { if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) qdev->small_buf_index = 0; qdev->small_buf_release_cnt++; } -static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) +struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) { struct ql_rcv_buf_cb *lrg_buf_cb = NULL; lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index]; @@ -2151,6 +1873,7 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, pci_unmap_len(lrg_buf_cb2, maplen), PCI_DMA_FROMDEVICE); prefetch(skb->data); + skb->dev = qdev->ndev; skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, qdev->ndev); @@ -2205,8 +1928,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, * Copy the ethhdr from first buffer to second. This * is necessary for 3022 IP completions. */ - skb_copy_from_linear_data_offset(skb1, VLAN_ID_LEN, - skb_push(skb2, size), size); + memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); } else { u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum); if (checksum & @@ -2224,6 +1946,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, skb2->ip_summed = CHECKSUM_UNNECESSARY; } } + skb2->dev = qdev->ndev; skb2->protocol = eth_type_trans(skb2, qdev->ndev); netif_receive_skb(skb2); @@ -3352,7 +3075,6 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) goto out; } - PHY_Setup(qdev); ql_init_scan_mode(qdev); ql_get_phy_owner(qdev); diff --git a/trunk/drivers/net/qla3xxx.h b/trunk/drivers/net/qla3xxx.h index 4a832c46c274..0203f88f0544 100755 --- a/trunk/drivers/net/qla3xxx.h +++ b/trunk/drivers/net/qla3xxx.h @@ -293,16 +293,6 @@ struct net_rsp_iocb { #define MII_SCAN_REGISTER 0x00000001 -#define PHY_ID_0_REG 2 -#define PHY_ID_1_REG 3 - -#define PHY_OUI_1_MASK 0xfc00 -#define PHY_MODEL_MASK 0x03f0 - -/* Address for the Agere Phy */ -#define MII_AGERE_ADDR_1 0x00001000 -#define MII_AGERE_ADDR_2 0x00001100 - /* 32-bit ispControlStatus */ enum { ISP_CONTROL_NP_MASK = 0x0003, @@ -799,7 +789,6 @@ enum { PHY_CTRL_LOOPBACK = 0x4000, PETBI_CONTROL_REG = 0x00, - PETBI_CTRL_ALL_PARAMS = 0x7140, PETBI_CTRL_SOFT_RESET = 0x8000, PETBI_CTRL_AUTO_NEG = 0x1000, PETBI_CTRL_RESTART_NEG = 0x0200, @@ -822,23 +811,6 @@ enum { PETBI_EXPANSION_REG = 0x06, PETBI_EXP_PAGE_RX = 0x0002, - PHY_GIG_CONTROL = 9, - PHY_GIG_ENABLE_MAN = 0x1000, /* Enable Master/Slave Manual Config*/ - PHY_GIG_SET_MASTER = 0x0800, /* Set Master (slave if clear)*/ - PHY_GIG_ALL_PARAMS = 0x0300, - PHY_GIG_ADV_1000F = 0x0200, - PHY_GIG_ADV_1000H = 0x0100, - - PHY_NEG_ADVER = 4, - PHY_NEG_ALL_PARAMS = 0x0fe0, - PHY_NEG_ASY_PAUSE = 0x0800, - PHY_NEG_SYM_PAUSE = 0x0400, - PHY_NEG_ADV_SPEED = 0x01e0, - PHY_NEG_ADV_100F = 0x0100, - PHY_NEG_ADV_100H = 0x0080, - PHY_NEG_ADV_10F = 0x0040, - PHY_NEG_ADV_10H = 0x0020, - PETBI_TBI_CTRL = 0x11, PETBI_TBI_RESET = 0x8000, PETBI_TBI_AUTO_SENSE = 0x0100, @@ -854,7 +826,8 @@ enum { PHY_AUX_RESET_STICK = 0x0002, PHY_NEG_PAUSE = 0x0400, PHY_CTRL_SOFT_RESET = 0x8000, - PHY_CTRL_AUTO_NEG = 0x1000, + PHY_NEG_ADVER = 4, + PHY_NEG_ADV_SPEED = 0x01e0, PHY_CTRL_RESTART_NEG = 0x0200, }; enum { @@ -919,7 +892,6 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16, u16 pauseThreshold_mac; u16 resumeThreshold_mac; u16 portConfiguration; -#define PORT_CONFIG_DEFAULT 0xf700 #define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000 #define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000 #define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000 @@ -1287,7 +1259,6 @@ struct ql3_adapter { struct delayed_work tx_timeout_work; u32 max_frame_size; u32 device_id; - u16 phyType; }; #endif /* _QLA3XXX_H_ */ diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 45876a854f00..6a77b8a92245 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -2284,7 +2284,7 @@ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) return LargeSend | ((mss & MSSMask) << MSSShift); } if (skb->ip_summed == CHECKSUM_PARTIAL) { - const struct iphdr *ip = ip_hdr(skb); + const struct iphdr *ip = skb->nh.iph; if (ip->protocol == IPPROTO_TCP) return IPCS | TCPCS; @@ -2586,6 +2586,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, pci_action(tp->pci_dev, le64_to_cpu(desc->addr), tp->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->dev = dev; skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); diff --git a/trunk/drivers/net/rionet.c b/trunk/drivers/net/rionet.c index df6b73872fdb..b7ff484af3e1 100644 --- a/trunk/drivers/net/rionet.c +++ b/trunk/drivers/net/rionet.c @@ -115,6 +115,7 @@ static int rionet_rx_clean(struct net_device *ndev) rnet->rx_skb[i]->data = data; skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); + rnet->rx_skb[i]->dev = ndev; rnet->rx_skb[i]->protocol = eth_type_trans(rnet->rx_skb[i], ndev); error = netif_rx(rnet->rx_skb[i]); diff --git a/trunk/drivers/net/rrunner.c b/trunk/drivers/net/rrunner.c index 25c73d47daad..d81536f90df6 100644 --- a/trunk/drivers/net/rrunner.c +++ b/trunk/drivers/net/rrunner.c @@ -1029,6 +1029,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) goto defer; } } + skb->dev = dev; skb->protocol = hippi_type_trans(skb, dev); netif_rx(skb); /* send it up */ @@ -1451,7 +1452,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) } skb_reserve(new_skb, 8); skb_put(new_skb, len); - skb_copy_from_linear_data(skb, new_skb->data, len); + memcpy(new_skb->data, skb->data, len); dev_kfree_skb(skb); skb = new_skb; } diff --git a/trunk/drivers/net/s2io-regs.h b/trunk/drivers/net/s2io-regs.h index 4cb710bbe729..33fb7f3b7041 100644 --- a/trunk/drivers/net/s2io-regs.h +++ b/trunk/drivers/net/s2io-regs.h @@ -1,6 +1,6 @@ /************************************************************************ * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2007 Neterion Inc. + * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. diff --git a/trunk/drivers/net/s2io.c b/trunk/drivers/net/s2io.c index 290e1c1f30c6..46ebf141ee5a 100644 --- a/trunk/drivers/net/s2io.c +++ b/trunk/drivers/net/s2io.c @@ -1,6 +1,6 @@ /************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2007 Neterion Inc. + * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.22.1" +#define DRV_VERSION "2.0.17.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct net_device *dev, } /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ -static int vlan_strip_flag; +int vlan_strip_flag; /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) @@ -394,6 +394,7 @@ static const u64 fix_mac[] = { END_SIGN }; +MODULE_AUTHOR("Raghavendra Koushik "); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); @@ -515,7 +516,7 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->fifos[i].list_info = kmalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { - DBG_PRINT(INFO_DBG, + DBG_PRINT(ERR_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } @@ -541,9 +542,9 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, + DBG_PRINT(ERR_DBG, "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + DBG_PRINT(ERR_DBG, "failed for TxDL\n"); return -ENOMEM; } /* If we got a zero DMA address(can happen on @@ -560,9 +561,9 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, + DBG_PRINT(ERR_DBG, "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + DBG_PRINT(ERR_DBG, "failed for TxDL\n"); return -ENOMEM; } } @@ -2186,7 +2187,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \ /* skb_shinfo(skb)->frag_list will have L4 data payload */ skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE); if (skb_shinfo(skb)->frag_list == NULL) { - DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name); + DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name); return -ENOMEM ; } frag_list = skb_shinfo(skb)->frag_list; @@ -2194,7 +2195,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \ frag_list->next = NULL; tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1); frag_list->data = tmp; - skb_reset_tail_pointer(frag_list); + frag_list->tail = tmp; /* Buffer-2 receives L4 data payload */ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, @@ -2241,7 +2242,6 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) struct buffAdd *ba; unsigned long flags; struct RxD_t *first_rxdp = NULL; - u64 Buffer0_ptr = 0, Buffer1_ptr = 0; mac_control = &nic->mac_control; config = &nic->config; @@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) /* allocate skb */ skb = dev_alloc_skb(size); if(!skb) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); + DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); if (first_rxdp) { wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; @@ -2342,21 +2342,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) * payload */ - /* save the buffer pointers to avoid frequent dma mapping */ - Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr; - Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr; memset(rxdp, 0, sizeof(struct RxD3)); - /* restore the buffer pointers for dma sync*/ - ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr; - ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr; - ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = (u64)(unsigned long) skb->data; tmp += ALIGN_SIZE; tmp &= ~ALIGN_SIZE; skb->data = (void *) (unsigned long)tmp; - skb_reset_tail_pointer(skb); + skb->tail = (void *) (unsigned long)tmp; if (!(((struct RxD3*)rxdp)->Buffer0_ptr)) ((struct RxD3*)rxdp)->Buffer0_ptr = @@ -2580,8 +2573,8 @@ static int s2io_poll(struct net_device *dev, int *budget) for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); + DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); break; } } @@ -2597,8 +2590,8 @@ static int s2io_poll(struct net_device *dev, int *budget) for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); + DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); break; } } @@ -2647,8 +2640,8 @@ static void s2io_netpoll(struct net_device *dev) for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); + DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n"); break; } } @@ -3314,7 +3307,6 @@ static void s2io_reset(struct s2io_nic * sp) u16 subid, pci_cmd; int i; u16 val16; - unsigned long long reset_cnt = 0; DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", __FUNCTION__, sp->dev->name); @@ -3380,11 +3372,6 @@ static void s2io_reset(struct s2io_nic * sp) /* Reset device statistics maintained by OS */ memset(&sp->stats, 0, sizeof (struct net_device_stats)); - /* save reset count */ - reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt; - memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); - /* restore reset count */ - sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt; /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; @@ -3672,7 +3659,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), GFP_KERNEL); if (nic->entries == NULL) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); return -ENOMEM; } memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); @@ -3681,7 +3668,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), GFP_KERNEL); if (nic->s2io_entries == NULL) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); kfree(nic->entries); return -ENOMEM; } @@ -4032,7 +4019,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); DBG_PRINT(INTR_DBG, "PANIC levels\n"); if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "Out of memory in %s", + DBG_PRINT(ERR_DBG, "Out of memory in %s", __FUNCTION__); clear_bit(0, (&sp->tasklet_status)); return -1; @@ -4042,8 +4029,8 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) tasklet_schedule(&sp->task); } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name); - DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); + DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name); + DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); } return 0; } @@ -4292,7 +4279,9 @@ static void s2io_updt_stats(struct s2io_nic *sp) if (cnt == 5) break; /* Updt failed */ } while(1); - } + } else { + memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); + } } /** @@ -5960,12 +5949,12 @@ static void s2io_tasklet(unsigned long dev_addr) for (i = 0; i < config->rx_ring_num; i++) { ret = fill_rx_buffers(sp, i); if (ret == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s: Out of ", + DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); DBG_PRINT(ERR_DBG, "memory in tasklet\n"); break; } else if (ret == -EFILL) { - DBG_PRINT(INFO_DBG, + DBG_PRINT(ERR_DBG, "%s: Rx Ring %d is full\n", dev->name, i); break; @@ -6076,8 +6065,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); + DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); return -ENOMEM ; } /* storing the mapped addr in a temp variable @@ -6099,7 +6088,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", + DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", dev->name); return -ENOMEM; } @@ -6126,7 +6115,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", + DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", dev->name); return -ENOMEM; } @@ -6627,6 +6616,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) /* Updating statistics */ rxdp->Host_Control = 0; + sp->rx_pkt_count++; sp->stats.rx_packets++; if (sp->rxd_mode == RXD_MODE_1) { int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); @@ -7262,7 +7252,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto register_failed; } s2io_vpd_read(sp); - DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n"); + DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, sp->product_name, get_xena_rev_id(sp->pdev)); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, diff --git a/trunk/drivers/net/s2io.h b/trunk/drivers/net/s2io.h index a656d18b33df..803137ca4b6c 100644 --- a/trunk/drivers/net/s2io.h +++ b/trunk/drivers/net/s2io.h @@ -1,6 +1,6 @@ /************************************************************************ * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2007 Neterion Inc. + * Copyright(c) 2002-2005 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. @@ -760,6 +760,7 @@ struct s2io_nic { #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; int high_dma_flag; @@ -793,6 +794,11 @@ struct s2io_nic { u16 all_multi_pos; u16 promisc_flg; + u16 tx_pkt_count; + u16 rx_pkt_count; + u16 tx_err_count; + u16 rx_err_count; + /* Id timer, used to blink NIC to physically identify NIC. */ struct timer_list id_timer; diff --git a/trunk/drivers/net/saa9730.c b/trunk/drivers/net/saa9730.c index ad94358ece89..143958f1ef0a 100644 --- a/trunk/drivers/net/saa9730.c +++ b/trunk/drivers/net/saa9730.c @@ -688,6 +688,7 @@ static int lan_saa9730_rx(struct net_device *dev) } else { lp->stats.rx_bytes += len; lp->stats.rx_packets++; + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ eth_copy_and_sum(skb, diff --git a/trunk/drivers/net/sb1000.c b/trunk/drivers/net/sb1000.c index 1de3eec1a792..b9fa4fbb1398 100644 --- a/trunk/drivers/net/sb1000.c +++ b/trunk/drivers/net/sb1000.c @@ -834,7 +834,7 @@ printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[3 goto dropped_frame; } skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16]; insw(ioaddr, skb_put(skb, NewDatagramDataSize), NewDatagramDataSize / 2); diff --git a/trunk/drivers/net/sb1250-mac.c b/trunk/drivers/net/sb1250-mac.c index 132e2148b21c..103c3174ab54 100644 --- a/trunk/drivers/net/sb1250-mac.c +++ b/trunk/drivers/net/sb1250-mac.c @@ -95,28 +95,19 @@ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS)); #endif #ifdef CONFIG_SBMAC_COALESCE -static int int_pktcnt_tx = 255; -module_param(int_pktcnt_tx, int, S_IRUGO); -MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count"); +static int int_pktcnt = 0; +module_param(int_pktcnt, int, S_IRUGO); +MODULE_PARM_DESC(int_pktcnt, "Packet count"); -static int int_timeout_tx = 255; -module_param(int_timeout_tx, int, S_IRUGO); -MODULE_PARM_DESC(int_timeout_tx, "TX timeout value"); - -static int int_pktcnt_rx = 64; -module_param(int_pktcnt_rx, int, S_IRUGO); -MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count"); - -static int int_timeout_rx = 64; -module_param(int_timeout_rx, int, S_IRUGO); -MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); +static int int_timeout = 0; +module_param(int_timeout, int, S_IRUGO); +MODULE_PARM_DESC(int_timeout, "Timeout value"); #endif #include #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) #include #include -#define R_MAC_DMA_OODPKTLOST_RX R_MAC_DMA_OODPKTLOST #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include #include @@ -164,8 +155,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) -#define SBMAC_MAX_TXDESCR 256 -#define SBMAC_MAX_RXDESCR 256 +#define SBMAC_MAX_TXDESCR 32 +#define SBMAC_MAX_RXDESCR 32 #define ETHER_ALIGN 2 #define ETHER_ADDR_LEN 6 @@ -194,10 +185,10 @@ typedef struct sbmacdma_s { * associated with it. */ - struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ - int sbdma_channel; /* channel number */ + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ + int sbdma_channel; /* channel number */ int sbdma_txdir; /* direction (1=transmit) */ - int sbdma_maxdescr; /* total # of descriptors in ring */ + int sbdma_maxdescr; /* total # of descriptors in ring */ #ifdef CONFIG_SBMAC_COALESCE int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/ int sbdma_int_timeout; /* # usec rx/tx interrupt */ @@ -206,16 +197,13 @@ typedef struct sbmacdma_s { volatile void __iomem *sbdma_config0; /* DMA config register 0 */ volatile void __iomem *sbdma_config1; /* DMA config register 1 */ volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ - volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ + volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ volatile void __iomem *sbdma_curdscr; /* current descriptor address */ - volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */ - /* * This stuff is for maintenance of the ring */ - sbdmadscr_t *sbdma_dscrtable_unaligned; sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ @@ -298,8 +286,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); static void sbdma_emptyring(sbmacdma_t *d); static void sbdma_fillring(sbmacdma_t *d); -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll); -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll); +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d); +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d); static int sbmac_initctx(struct sbmac_softc *s); static void sbmac_channel_start(struct sbmac_softc *s); static void sbmac_channel_stop(struct sbmac_softc *s); @@ -320,8 +308,6 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); -static int sbmac_poll(struct net_device *poll_dev, int *budget); - static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); static int sbmac_mii_probe(struct net_device *dev); @@ -693,10 +679,6 @@ static void sbdma_initctx(sbmacdma_t *d, int txrx, int maxdescr) { -#ifdef CONFIG_SBMAC_COALESCE - int int_pktcnt, int_timeout; -#endif - /* * Save away interesting stuff in the structure */ @@ -746,11 +728,6 @@ static void sbdma_initctx(sbmacdma_t *d, s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); d->sbdma_curdscr = s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); - if (d->sbdma_txdir) - d->sbdma_oodpktlost = NULL; - else - d->sbdma_oodpktlost = - s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX); /* * Allocate memory for the ring @@ -758,7 +735,6 @@ static void sbdma_initctx(sbmacdma_t *d, d->sbdma_maxdescr = maxdescr; - d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = (sbdmadscr_t *) kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); @@ -789,14 +765,12 @@ static void sbdma_initctx(sbmacdma_t *d, * Setup Rx/Tx DMA coalescing defaults */ - int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx; if ( int_pktcnt ) { d->sbdma_int_pktcnt = int_pktcnt; } else { d->sbdma_int_pktcnt = 1; } - int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx; if ( int_timeout ) { d->sbdma_int_timeout = int_timeout; } else { @@ -959,6 +933,9 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) } sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN); + + /* mark skbuff owned by our device */ + sb_new->dev = d->sbdma_eth->sbm_dev; } else { sb_new = sb; @@ -1151,63 +1128,32 @@ static void sbdma_fillring(sbmacdma_t *d) } } -#ifdef CONFIG_NET_POLL_CONTROLLER -static void sbmac_netpoll(struct net_device *netdev) -{ - struct sbmac_softc *sc = netdev_priv(netdev); - int irq = sc->sbm_dev->irq; - - __raw_writeq(0, sc->sbm_imr); - - sbmac_intr(irq, netdev, NULL); - -#ifdef CONFIG_SBMAC_COALESCE - __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), - sc->sbm_imr); -#else - __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | - (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); -#endif -} -#endif /********************************************************************** - * SBDMA_RX_PROCESS(sc,d,work_to_do,poll) + * SBDMA_RX_PROCESS(sc,d) * * Process "completed" receive buffers on the specified DMA channel. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. * * Input parameters: - * sc - softc structure - * d - DMA channel context - * work_to_do - no. of packets to process before enabling interrupt - * again (for NAPI) - * poll - 1: using polling (for NAPI) + * sc - softc structure + * d - DMA channel context * * Return value: * nothing ********************************************************************* */ -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, - int work_to_do, int poll) +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) { int curidx; int hwidx; sbdmadscr_t *dsc; struct sk_buff *sb; int len; - int work_done = 0; - int dropped = 0; - prefetch(d); - -again: - /* Check if the HW dropped any frames */ - sc->sbm_stats.rx_fifo_errors - += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff; - __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost); - - while (work_to_do-- > 0) { + for (;;) { /* * figure out where we are (as an index) and where * the hardware is (also as an index) @@ -1219,12 +1165,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) */ - dsc = d->sbdma_remptr; - curidx = dsc - d->sbdma_dscrtable; - - prefetch(dsc); - prefetch(&d->sbdma_ctxtable[curidx]); - + curidx = d->sbdma_remptr - d->sbdma_dscrtable; hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); @@ -1235,12 +1176,13 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, */ if (curidx == hwidx) - goto done; + break; /* * Otherwise, get the packet's sk_buff ptr back */ + dsc = &(d->sbdma_dscrtable[curidx]); sb = d->sbdma_ctxtable[curidx]; d->sbdma_ctxtable[curidx] = NULL; @@ -1252,7 +1194,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, * receive ring. */ - if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) { + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { /* * Add a new buffer to replace the old one. If we fail @@ -1260,14 +1202,9 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, * packet and put it right back on the receive ring. */ - if (unlikely (sbdma_add_rcvbuffer(d,NULL) == - -ENOBUFS)) { - sc->sbm_stats.rx_dropped++; + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { + sc->sbm_stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ - /* No point in continuing at the moment */ - printk(KERN_ERR "dropped packet (1)\n"); - d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - goto done; } else { /* * Set length into the packet @@ -1279,6 +1216,8 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, * receive ring. Pass the buffer to * the kernel */ + sc->sbm_stats.rx_bytes += len; + sc->sbm_stats.rx_packets++; sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); /* Check hw IPv4/TCP checksum if supported */ if (sc->rx_hw_checksum == ENABLE) { @@ -1290,22 +1229,8 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, sb->ip_summed = CHECKSUM_NONE; } } - prefetch(sb->data); - prefetch((const void *)(((char *)sb->data)+32)); - if (poll) - dropped = netif_receive_skb(sb); - else - dropped = netif_rx(sb); - - if (dropped == NET_RX_DROP) { - sc->sbm_stats.rx_dropped++; - d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - goto done; - } - else { - sc->sbm_stats.rx_bytes += len; - sc->sbm_stats.rx_packets++; - } + + netif_rx(sb); } } else { /* @@ -1322,16 +1247,12 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, */ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - work_done++; - } - if (!poll) { - work_to_do = 32; - goto again; /* collect fifo drop statistics again */ + } -done: - return work_done; } + + /********************************************************************** * SBDMA_TX_PROCESS(sc,d) * @@ -1343,30 +1264,22 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, * * Input parameters: * sc - softc structure - * d - DMA channel context - * poll - 1: using polling (for NAPI) + * d - DMA channel context * * Return value: * nothing ********************************************************************* */ -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) { int curidx; int hwidx; sbdmadscr_t *dsc; struct sk_buff *sb; unsigned long flags; - int packets_handled = 0; spin_lock_irqsave(&(sc->sbm_lock), flags); - if (d->sbdma_remptr == d->sbdma_addptr) - goto end_unlock; - - hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); - for (;;) { /* * figure out where we are (as an index) and where @@ -1380,6 +1293,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) */ curidx = d->sbdma_remptr - d->sbdma_dscrtable; + hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); /* * If they're the same, that means we've processed all @@ -1417,8 +1332,6 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); - packets_handled++; - } /* @@ -1427,10 +1340,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) * watermark on the transmit queue. */ - if (packets_handled) - netif_wake_queue(d->sbdma_eth->sbm_dev); + netif_wake_queue(d->sbdma_eth->sbm_dev); -end_unlock: spin_unlock_irqrestore(&(sc->sbm_lock), flags); } @@ -1504,9 +1415,9 @@ static int sbmac_initctx(struct sbmac_softc *s) static void sbdma_uninitctx(struct sbmacdma_s *d) { - if (d->sbdma_dscrtable_unaligned) { - kfree(d->sbdma_dscrtable_unaligned); - d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL; + if (d->sbdma_dscrtable) { + kfree(d->sbdma_dscrtable); + d->sbdma_dscrtable = NULL; } if (d->sbdma_ctxtable) { @@ -1704,9 +1615,15 @@ static void sbmac_channel_start(struct sbmac_softc *s) #endif #ifdef CONFIG_SBMAC_COALESCE + /* + * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0 + */ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); #else + /* + * Accept any kind of interrupt on TX and RX DMA channel 0 + */ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); #endif @@ -2139,46 +2056,57 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) uint64_t isr; int handled = 0; - /* - * Read the ISR (this clears the bits in the real - * register, except for counter addr) - */ + for (;;) { - isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; + /* + * Read the ISR (this clears the bits in the real + * register, except for counter addr) + */ - if (isr == 0) - return IRQ_RETVAL(0); - handled = 1; + isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; - /* - * Transmits on channel 0 - */ + if (isr == 0) + break; - if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { - sbdma_tx_process(sc,&(sc->sbm_txdma), 0); -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) { - if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) - __netif_schedule(dev); - } -#endif - } + handled = 1; + + /* + * Transmits on channel 0 + */ - if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { - if (netif_rx_schedule_prep(dev)) { - __raw_writeq(0, sc->sbm_imr); - __netif_rx_schedule(dev); - /* Depend on the exit from poll to reenable intr */ + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { + sbdma_tx_process(sc,&(sc->sbm_txdma)); } - else { - /* may leave some packets behind */ - sbdma_rx_process(sc,&(sc->sbm_rxdma), - SBMAC_MAX_RXDESCR * 2, 0); + + /* + * Receives on channel 0 + */ + + /* + * It's important to test all the bits (or at least the + * EOP_SEEN bit) when deciding to do the RX process + * particularly when coalescing, to make sure we + * take care of the following: + * + * If you have some packets waiting (have been received + * but no interrupt) and get a TX interrupt before + * the RX timer or counter expires, reading the ISR + * above will clear the timer and counter, and you + * won't get another interrupt until a packet shows + * up to start the timer again. Testing + * EOP_SEEN here takes care of this case. + * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0) + */ + + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { + sbdma_rx_process(sc,&(sc->sbm_rxdma)); } } return IRQ_RETVAL(handled); } + /********************************************************************** * SBMAC_START_TX(skb,dev) * @@ -2308,6 +2236,8 @@ static void sbmac_setmulti(struct sbmac_softc *sc) } } + + #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) /********************************************************************** * SBMAC_PARSE_XDIGIT(str) @@ -2470,13 +2400,8 @@ static int sbmac_init(struct net_device *dev, int idx) dev->do_ioctl = sbmac_mii_ioctl; dev->tx_timeout = sbmac_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = sbmac_poll; - dev->weight = 16; dev->change_mtu = sb1250_change_mtu; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sbmac_netpoll; -#endif /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); @@ -2874,39 +2799,7 @@ static int sbmac_close(struct net_device *dev) return 0; } -static int sbmac_poll(struct net_device *dev, int *budget) -{ - int work_to_do; - int work_done; - struct sbmac_softc *sc = netdev_priv(dev); - - work_to_do = min(*budget, dev->quota); - work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1); - if (work_done > work_to_do) - printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n", - sc->sbm_dev->name, *budget, dev->quota, work_done); - - sbdma_tx_process(sc, &(sc->sbm_txdma), 1); - - *budget -= work_done; - dev->quota -= work_done; - - if (work_done < work_to_do) { - netif_rx_complete(dev); - -#ifdef CONFIG_SBMAC_COALESCE - __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | - ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), - sc->sbm_imr); -#else - __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | - (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); -#endif - } - - return (work_done >= work_to_do); -} #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) static void @@ -2993,7 +2886,7 @@ sbmac_init_module(void) /* * The R_MAC_ETHERNET_ADDR register will be set to some nonzero - * value for us by the firmware if we are going to use this MAC. + * value for us by the firmware if we're going to use this MAC. * If we find a zero, skip this MAC. */ diff --git a/trunk/drivers/net/sc92031.c b/trunk/drivers/net/sc92031.c index 5b7284c955dc..c32c21af3fdd 100644 --- a/trunk/drivers/net/sc92031.c +++ b/trunk/drivers/net/sc92031.c @@ -814,6 +814,7 @@ static void _sc92031_rx_tasklet(struct net_device *dev) memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); } + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; netif_rx(skb); diff --git a/trunk/drivers/net/seeq8005.c b/trunk/drivers/net/seeq8005.c index 4bce7c4f373c..0d6c95c7aedf 100644 --- a/trunk/drivers/net/seeq8005.c +++ b/trunk/drivers/net/seeq8005.c @@ -550,6 +550,7 @@ static void seeq8005_rx(struct net_device *dev) lp->stats.rx_dropped++; break; } + skb->dev = dev; skb_reserve(skb, 2); /* align data on 16 byte */ buf = skb_put(skb,pkt_len); diff --git a/trunk/drivers/net/sgiseeq.c b/trunk/drivers/net/sgiseeq.c index 1fc77300b055..52ed522a234c 100644 --- a/trunk/drivers/net/sgiseeq.c +++ b/trunk/drivers/net/sgiseeq.c @@ -318,6 +318,7 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp skb = dev_alloc_skb(len + 2); if (skb) { + skb->dev = dev; skb_reserve(skb, 2); skb_put(skb, len); @@ -534,7 +535,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) * entry and the HPC got to the end of the chain before we * added this new entry and restarted it. */ - skb_copy_from_linear_data(skb, (char *)(long)td->buf_vaddr, skblen); + memcpy((char *)(long)td->buf_vaddr, skb->data, skblen); if (len != skblen) memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen); td->tdma.cntinfo = (len & HPCDMA_BCNT) | @@ -624,7 +625,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) -static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) +static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) { struct sgiseeq_init_block *sr; struct sgiseeq_private *sp; @@ -650,9 +651,7 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) #define EADDR_NVOFS 250 for (i = 0; i < 3; i++) { - unsigned short tmp = has_eeprom ? - ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) : - ip22_nvram_read(EADDR_NVOFS / 2+i); + unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i); dev->dev_addr[2 * i] = tmp >> 8; dev->dev_addr[2 * i + 1] = tmp & 0xff; @@ -680,11 +679,6 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); - /* Setup PIO and DMA transfer timing */ - sp->hregs->pconfig = 0x161; - sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | - HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; - /* Setup PIO and DMA transfer timing */ sp->hregs->pconfig = 0x161; sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | @@ -736,23 +730,8 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) static int __init sgiseeq_probe(void) { - unsigned int tmp, ret1, ret2 = 0; - /* On board adapter on 1st HPC is always present */ - ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0); - /* Let's see if second HPC is there */ - if (!(ip22_is_fullhouse()) && - get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) { - sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | - SGIMC_GIOPAR_EXP164 | - SGIMC_GIOPAR_HPC264; - hpc3c1->pbus_piocfg[0][0] = 0x3ffff; - /* interrupt/config register on Challenge S Mezz board */ - hpc3c1->pbus_extregs[0][0] = 0x30; - ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1); - } - - return (ret1 & ret2) ? ret1 : 0; + return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); } static void __exit sgiseeq_exit(void) diff --git a/trunk/drivers/net/sis190.c b/trunk/drivers/net/sis190.c index bc8de48da313..34463ce6f132 100644 --- a/trunk/drivers/net/sis190.c +++ b/trunk/drivers/net/sis190.c @@ -632,6 +632,7 @@ static int sis190_rx_interrupt(struct net_device *dev, pci_action(tp->pci_dev, le32_to_cpu(desc->addr), tp->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->dev = dev; skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); diff --git a/trunk/drivers/net/sis900.c b/trunk/drivers/net/sis900.c index 2cb2e156c758..b3750f284279 100644 --- a/trunk/drivers/net/sis900.c +++ b/trunk/drivers/net/sis900.c @@ -1160,6 +1160,7 @@ sis900_init_rx_ring(struct net_device *net_dev) buffer */ break; } + skb->dev = net_dev; sis_priv->rx_skbuff[i] = skb; sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev, @@ -1753,25 +1754,6 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; } else { struct sk_buff * skb; - struct sk_buff * rx_skb; - - pci_unmap_single(sis_priv->pci_dev, - sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - - /* refill the Rx buffer, what if there is not enought - * memory for new socket buffer ?? */ - if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { - /* - * Not enough memory to refill the buffer - * so we need to recycle the old one so - * as to avoid creating a memory hole - * in the rx ring - */ - skb = sis_priv->rx_skbuff[entry]; - sis_priv->stats.rx_dropped++; - goto refill_rx_ring; - } /* This situation should never happen, but due to some unknow bugs, it is possible that @@ -1786,11 +1768,14 @@ static int sis900_rx(struct net_device *net_dev) break; } + pci_unmap_single(sis_priv->pci_dev, + sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); /* give the socket buffer to upper layers */ - rx_skb = sis_priv->rx_skbuff[entry]; - skb_put(rx_skb, rx_size); - rx_skb->protocol = eth_type_trans(rx_skb, net_dev); - netif_rx(rx_skb); + skb = sis_priv->rx_skbuff[entry]; + skb_put(skb, rx_size); + skb->protocol = eth_type_trans(skb, net_dev); + netif_rx(skb); /* some network statistics */ if ((rx_status & BCAST) == MCAST) @@ -1798,13 +1783,33 @@ static int sis900_rx(struct net_device *net_dev) net_dev->last_rx = jiffies; sis_priv->stats.rx_bytes += rx_size; sis_priv->stats.rx_packets++; - sis_priv->dirty_rx++; -refill_rx_ring: + + /* refill the Rx buffer, what if there is not enought + * memory for new socket buffer ?? */ + if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { + /* not enough memory for skbuff, this makes a + * "hole" on the buffer ring, it is not clear + * how the hardware will react to this kind + * of degenerated buffer */ + if (netif_msg_rx_status(sis_priv)) + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + net_dev->name); + sis_priv->rx_skbuff[entry] = NULL; + /* reset buffer descriptor state */ + sis_priv->rx_ring[entry].cmdsts = 0; + sis_priv->rx_ring[entry].bufptr = 0; + sis_priv->stats.rx_dropped++; + sis_priv->cur_rx++; + break; + } + skb->dev = net_dev; sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = pci_map_single(sis_priv->pci_dev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + sis_priv->dirty_rx++; } sis_priv->cur_rx++; entry = sis_priv->cur_rx % NUM_RX_DESC; @@ -1831,6 +1836,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->stats.rx_dropped++; break; } + skb->dev = net_dev; sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = diff --git a/trunk/drivers/net/sk98lin/skge.c b/trunk/drivers/net/sk98lin/skge.c index bf218621db16..e94ab256b540 100644 --- a/trunk/drivers/net/sk98lin/skge.c +++ b/trunk/drivers/net/sk98lin/skge.c @@ -1562,10 +1562,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxd->pMBuf = pMessage; if (pMessage->ip_summed == CHECKSUM_PARTIAL) { - u16 hdrlen = skb_transport_offset(pMessage); + u16 hdrlen = pMessage->h.raw - pMessage->data; u16 offset = hdrlen + pMessage->csum_offset; - if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) && + if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { pTxd->TBControl = BMU_TCP_CHECK; @@ -1681,7 +1681,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ ** Does the HW need to evaluate checksum for TCP or UDP packets? */ if (pMessage->ip_summed == CHECKSUM_PARTIAL) { - u16 hdrlen = skb_transport_offset(pMessage); + u16 hdrlen = pMessage->h.raw - pMessage->data; u16 offset = hdrlen + pMessage->csum_offset; Control = BMU_STFWD; @@ -1691,7 +1691,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ ** opcode for udp is not working in the hardware yet ** (Revision 2.0) */ - if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) && + if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) && (pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipId == CHIP_ID_YUKON)) { Control |= BMU_TCP_CHECK; @@ -2127,7 +2127,7 @@ SK_U64 PhysAddr; (dma_addr_t) PhysAddr, FrameLength, PCI_DMA_FROMDEVICE); - skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength); + memcpy(pNewMsg->data, pMsg, FrameLength); pci_dma_sync_single_for_device(pAC->PciDev, (dma_addr_t) PhysAddr, @@ -2193,6 +2193,7 @@ SK_U64 PhysAddr; SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, FrameLength, pRxPort->PortIndex); + pMsg->dev = pAC->dev[pRxPort->PortIndex]; pMsg->protocol = eth_type_trans(pMsg, pAC->dev[pRxPort->PortIndex]); netif_rx(pMsg); @@ -2245,6 +2246,7 @@ SK_U64 PhysAddr; (IFF_PROMISC | IFF_ALLMULTI)) != 0 || (ForRlmt & SK_RLMT_RX_PROTOCOL) == SK_RLMT_RX_PROTOCOL) { + pMsg->dev = pAC->dev[pRxPort->PortIndex]; pMsg->protocol = eth_type_trans(pMsg, pAC->dev[pRxPort->PortIndex]); netif_rx(pMsg); @@ -5123,12 +5125,7 @@ static int skge_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) { - printk(KERN_WARNING "sk98lin: unable to enable device %s " - "in resume\n", dev->name); - goto err_out; - } + pci_enable_device(pdev); pci_set_master(pdev); if (pAC->GIni.GIMacsFound == 2) ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); @@ -5136,8 +5133,10 @@ static int skge_resume(struct pci_dev *pdev) ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev); if (ret) { printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq); - ret = -EBUSY; - goto err_out_disable_pdev; + pAC->AllocFlag &= ~SK_ALLOC_IRQ; + dev->irq = 0; + pci_disable_device(pdev); + return -EBUSY; } netif_device_attach(dev); @@ -5154,13 +5153,6 @@ static int skge_resume(struct pci_dev *pdev) } return 0; - -err_out_disable_pdev: - pci_disable_device(pdev); -err_out: - pAC->AllocFlag &= ~SK_ALLOC_IRQ; - dev->irq = 0; - return ret; } #else #define skge_suspend NULL diff --git a/trunk/drivers/net/skfp/h/lnkstat.h b/trunk/drivers/net/skfp/h/lnkstat.h new file mode 100644 index 000000000000..c73dcd96a40f --- /dev/null +++ b/trunk/drivers/net/skfp/h/lnkstat.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Definition of the Error Log Structure + * This structure will be copied into the Error Log buffer + * during the NDIS General Request ReadErrorLog by the MAC Driver + */ + +struct s_error_log { + + /* + * place holder for token ring adapter error log (zeros) + */ + u_char reserved_0 ; /* byte 0 inside Error Log */ + u_char reserved_1 ; /* byte 1 */ + u_char reserved_2 ; /* byte 2 */ + u_char reserved_3 ; /* byte 3 */ + u_char reserved_4 ; /* byte 4 */ + u_char reserved_5 ; /* byte 5 */ + u_char reserved_6 ; /* byte 6 */ + u_char reserved_7 ; /* byte 7 */ + u_char reserved_8 ; /* byte 8 */ + u_char reserved_9 ; /* byte 9 */ + u_char reserved_10 ; /* byte 10 */ + u_char reserved_11 ; /* byte 11 */ + u_char reserved_12 ; /* byte 12 */ + u_char reserved_13 ; /* byte 13 */ + + /* + * FDDI link statistics + */ +/* + * smt error low + */ +#define SMT_ERL_AEB (1<<15) /* A elast. buffer */ +#define SMT_ERL_BLC (1<<14) /* B link error condition */ +#define SMT_ERL_ALC (1<<13) /* A link error condition */ +#define SMT_ERL_NCC (1<<12) /* not copied condition */ +#define SMT_ERL_FEC (1<<11) /* frame error condition */ + +/* + * smt event low + */ +#define SMT_EVL_NCE (1<<5) + + u_short smt_error_low ; /* byte 14/15 */ + u_short smt_error_high ; /* byte 16/17 */ + u_short smt_event_low ; /* byte 18/19 */ + u_short smt_event_high ; /* byte 20/21 */ + u_short connection_policy_violation ; /* byte 22/23 */ + u_short port_event ; /* byte 24/25 */ + u_short set_count_low ; /* byte 26/27 */ + u_short set_count_high ; /* byte 28/29 */ + u_short aci_id_code ; /* byte 30/31 */ + u_short purge_frame_counter ; /* byte 32/33 */ + + /* + * CMT and RMT state machines + */ + u_short ecm_state ; /* byte 34/35 */ + u_short pcm_a_state ; /* byte 36/37 */ + u_short pcm_b_state ; /* byte 38/39 */ + u_short cfm_state ; /* byte 40/41 */ + u_short rmt_state ; /* byte 42/43 */ + + u_short not_used[30] ; /* byte 44-103 */ + + u_short ucode_version_level ; /* byte 104/105 */ + + u_short not_used_1 ; /* byte 106/107 */ + u_short not_used_2 ; /* byte 108/109 */ +} ; diff --git a/trunk/drivers/net/skfp/skfddi.c b/trunk/drivers/net/skfp/skfddi.c index a7ef6c8b7721..9733a11c6146 100644 --- a/trunk/drivers/net/skfp/skfddi.c +++ b/trunk/drivers/net/skfp/skfddi.c @@ -1680,6 +1680,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, rxd->rxd_os.skb = NULL; skb_trim(skb, len); skb->protocol = fddi_type_trans(skb, bp->dev); + skb->dev = bp->dev; /* pass up device pointer */ netif_rx(skb); bp->dev->last_rx = jiffies; @@ -1937,7 +1938,7 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc, } skb_reserve(skb, 3); skb_put(skb, len); - skb_copy_to_linear_data(skb, look_ahead, len); + memcpy(skb->data, look_ahead, len); // deliver frame to system skb->protocol = fddi_type_trans(skb, smc->os.dev); diff --git a/trunk/drivers/net/skge.c b/trunk/drivers/net/skge.c index 21afe108d3cb..d476a3cc2e94 100644 --- a/trunk/drivers/net/skge.c +++ b/trunk/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.11" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -2621,7 +2621,6 @@ static int skge_down(struct net_device *dev) static inline int skge_avail(const struct skge_ring *ring) { - smp_mb(); return ((ring->to_clean > ring->to_use) ? 0 : ring->count) + (ring->to_clean - ring->to_use) - 1; } @@ -2655,12 +2654,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) td->dma_hi = map >> 32; if (skb->ip_summed == CHECKSUM_PARTIAL) { - const int offset = skb_transport_offset(skb); + int offset = skb->h.raw - skb->data; /* This seems backwards, but it is what the sk98lin * does. Looks like hardware is wrong? */ - if (ipip_hdr(skb)->protocol == IPPROTO_UDP + if (skb->h.ipiph->protocol == IPPROTO_UDP && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) control = BMU_TCP_CHECK; else @@ -2710,8 +2709,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) dev->name, e - skge->tx_ring.start, skb->len); skge->tx_ring.to_use = e->next; - smp_wmb(); - if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) { pr_debug("%s: transmit queue full\n", dev->name); netif_stop_queue(dev); @@ -2729,6 +2726,8 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, { struct pci_dev *pdev = skge->hw->pdev; + BUG_ON(!e->skb); + /* skb header vs. fragment */ if (control & BMU_STF) pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), @@ -2746,6 +2745,7 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, dev_kfree_skb(e->skb); } + e->skb = NULL; } /* Free all buffers in transmit ring */ @@ -2950,7 +2950,7 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, pci_dma_sync_single_for_cpu(skge->hw->pdev, pci_unmap_addr(e, mapaddr), len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(e->skb, skb->data, len); + memcpy(skb->data, e->skb->data, len); pci_dma_sync_single_for_device(skge->hw->pdev, pci_unmap_addr(e, mapaddr), len, PCI_DMA_FROMDEVICE); @@ -3017,29 +3017,21 @@ static void skge_tx_done(struct net_device *dev) skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); + netif_tx_lock(dev); for (e = ring->to_clean; e != ring->to_use; e = e->next) { - u32 control = ((const struct skge_tx_desc *) e->desc)->control; + struct skge_tx_desc *td = e->desc; - if (control & BMU_OWN) + if (td->control & BMU_OWN) break; - skge_tx_free(skge, e, control); + skge_tx_free(skge, e, td->control); } skge->tx_ring.to_clean = e; - /* Can run lockless until we need to synchronize to restart queue. */ - smp_mb(); - - if (unlikely(netif_queue_stopped(dev) && - skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { - netif_tx_lock(dev); - if (unlikely(netif_queue_stopped(dev) && - skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { - netif_wake_queue(dev); + if (skge_avail(&skge->tx_ring) > TX_LOW_WATER) + netif_wake_queue(dev); - } - netif_tx_unlock(dev); - } + netif_tx_unlock(dev); } static int skge_poll(struct net_device *dev, int *budget) diff --git a/trunk/drivers/net/skge.h b/trunk/drivers/net/skge.h index edd71468220c..86467ae74d45 100644 --- a/trunk/drivers/net/skge.h +++ b/trunk/drivers/net/skge.h @@ -232,6 +232,7 @@ enum { IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT + | IS_NO_STAT_M1 | IS_NO_STAT_M2 | IS_RAM_RD_PAR | IS_RAM_WR_PAR | IS_M1_PAR_ERR | IS_M2_PAR_ERR | IS_R1_PAR_ERR | IS_R2_PAR_ERR, @@ -2446,15 +2447,15 @@ enum pause_status { struct skge_port { + u32 msg_enable; struct skge_hw *hw; struct net_device *netdev; int port; - u32 msg_enable; struct skge_ring tx_ring; + struct skge_ring rx_ring; - struct skge_ring rx_ring ____cacheline_aligned_in_smp; - unsigned int rx_buf_size; + struct net_device_stats net_stats; struct timer_list link_timer; enum pause_control flow_control; @@ -2470,8 +2471,7 @@ struct skge_port { void *mem; /* PCI memory for rings */ dma_addr_t dma; unsigned long mem_size; - - struct net_device_stats net_stats; + unsigned int rx_buf_size; }; diff --git a/trunk/drivers/net/sky2.c b/trunk/drivers/net/sky2.c index 238c2ca34da6..ac36152c68bf 100644 --- a/trunk/drivers/net/sky2.c +++ b/trunk/drivers/net/sky2.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -1392,8 +1391,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Check for TCP Segmentation Offload */ mss = skb_shinfo(skb)->gso_size; if (mss != 0) { - mss += tcp_optlen(skb); /* TCP options */ - mss += ip_hdrlen(skb) + sizeof(struct tcphdr); + mss += ((skb->h.th->doff - 5) * 4); /* TCP options */ + mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); mss += ETH_HLEN; if (mss != sky2->tx_last_mss) { @@ -1421,14 +1420,14 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Handle TCP checksum offload */ if (skb->ip_summed == CHECKSUM_PARTIAL) { - const unsigned offset = skb_transport_offset(skb); + unsigned offset = skb->h.raw - skb->data; u32 tcpsum; tcpsum = offset << 16; /* sum start */ tcpsum |= offset + skb->csum_offset; /* sum write */ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; - if (ip_hdr(skb)->protocol == IPPROTO_UDP) + if (skb->nh.iph->protocol == IPPROTO_UDP) ctrl |= UDPTCP; if (tcpsum != sky2->tx_tcpsum) { @@ -1971,7 +1970,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(re->skb, skb->data, length); + memcpy(skb->data, re->skb->data, length); skb->ip_summed = re->skb->ip_summed; skb->csum = re->skb->csum; pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, diff --git a/trunk/drivers/net/slip.c b/trunk/drivers/net/slip.c index 65bd20fac820..2f4b1de7a2b4 100644 --- a/trunk/drivers/net/slip.c +++ b/trunk/drivers/net/slip.c @@ -363,7 +363,7 @@ sl_bump(struct slip *sl) } skb->dev = sl->dev; memcpy(skb_put(skb,count), sl->rbuff, count); - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; skb->protocol=htons(ETH_P_IP); netif_rx(skb); sl->dev->last_rx = jiffies; diff --git a/trunk/drivers/net/smc911x.c b/trunk/drivers/net/smc911x.c index 81f24847c963..c95614131980 100644 --- a/trunk/drivers/net/smc911x.c +++ b/trunk/drivers/net/smc911x.c @@ -499,9 +499,10 @@ static inline void smc911x_rcv(struct net_device *dev) SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); SMC_PULL_DATA(data, pkt_len+2+3); - DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); + DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,); PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); dev->last_rx = jiffies; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; @@ -1306,6 +1307,7 @@ smc911x_rx_dma_irq(int dma, void *data) lp->current_rx_skb = NULL; PRINT_PKT(skb->data, skb->len); dev->last_rx = jiffies; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; diff --git a/trunk/drivers/net/smc9194.c b/trunk/drivers/net/smc9194.c index 36c1ebadbf20..bd6e84506c29 100644 --- a/trunk/drivers/net/smc9194.c +++ b/trunk/drivers/net/smc9194.c @@ -1262,6 +1262,7 @@ static void smc_rcv(struct net_device *dev) skb_reserve( skb, 2 ); /* 16 bit alignment */ + skb->dev = dev; data = skb_put( skb, packet_length); #ifdef USE_32_BIT diff --git a/trunk/drivers/net/smc91x.c b/trunk/drivers/net/smc91x.c index 01cc3c742c38..49f4b7712ebf 100644 --- a/trunk/drivers/net/smc91x.c +++ b/trunk/drivers/net/smc91x.c @@ -568,6 +568,7 @@ static inline void smc_rcv(struct net_device *dev) PRINT_PKT(data, packet_len - 4); dev->last_rx = jiffies; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; diff --git a/trunk/drivers/net/sonic.c b/trunk/drivers/net/sonic.c index 8069f3e32d83..ed7aa0a5acca 100644 --- a/trunk/drivers/net/sonic.c +++ b/trunk/drivers/net/sonic.c @@ -50,6 +50,29 @@ static int sonic_open(struct net_device *dev) if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); + /* + * We don't need to deal with auto-irq stuff since we + * hardwire the sonic interrupt. + */ +/* + * XXX Horrible work around: We install sonic_interrupt as fast interrupt. + * This means that during execution of the handler interrupt are disabled + * covering another bug otherwise corrupting data. This doesn't mean + * this glue works ok under all situations. + * + * Note (dhd): this also appears to prevent lockups on the Macintrash + * when more than one Ethernet card is installed (knock on wood) + * + * Note (fthain): whether the above is still true is anyones guess. Certainly + * the buffer handling algorithms will not tolerate re-entrance without some + * mutual exclusion added. Anyway, the memcpy has now been eliminated from the + * rx code to make this a faster "fast interrupt". + */ + if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { + printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); + return -EAGAIN; + } + for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); if (skb == NULL) { @@ -62,6 +85,7 @@ static int sonic_open(struct net_device *dev) dev->name); return -ENOMEM; } + skb->dev = dev; /* align IP header unless DMA requires otherwise */ if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2) skb_reserve(skb, 2); @@ -146,6 +170,8 @@ static int sonic_close(struct net_device *dev) } } + free_irq(dev->irq, dev); /* release the IRQ */ + return 0; } @@ -153,13 +179,8 @@ static void sonic_tx_timeout(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); int i; - /* - * put the Sonic into software-reset mode and - * disable all interrupts before releasing DMA buffers - */ + /* Stop the interrupts for this */ SONIC_WRITE(SONIC_IMR, 0); - SONIC_WRITE(SONIC_ISR, 0x7fff); - SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* We could resend the original skbs. Easier to re-initialise. */ for (i = 0; i < SONIC_NUM_TDS; i++) { if(lp->tx_laddr[i]) { @@ -430,6 +451,7 @@ static void sonic_rx(struct net_device *dev) lp->stats.rx_dropped++; break; } + new_skb->dev = dev; /* provide 16 byte IP header alignment unless DMA requires otherwise */ if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2) skb_reserve(new_skb, 2); diff --git a/trunk/drivers/net/spider_net.c b/trunk/drivers/net/spider_net.c index 230da14b1b68..e3019d52c30f 100644 --- a/trunk/drivers/net/spider_net.c +++ b/trunk/drivers/net/spider_net.c @@ -720,7 +720,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, spin_unlock_irqrestore(&chain->lock, flags); if (skb->protocol == htons(ETH_P_IP) && skb->ip_summed == CHECKSUM_PARTIAL) - switch (ip_hdr(skb)->protocol) { + switch (skb->nh.iph->protocol) { case IPPROTO_TCP: hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP; break; @@ -990,6 +990,7 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, netdev = card->netdev; skb = descr->skb; + skb->dev = netdev; skb_put(skb, hwdescr->valid_size); /* the card seems to add 2 bytes of junk in front diff --git a/trunk/drivers/net/starfire.c b/trunk/drivers/net/starfire.c index 9d6e454a8f98..8bba2e3da7e1 100644 --- a/trunk/drivers/net/starfire.c +++ b/trunk/drivers/net/starfire.c @@ -1452,6 +1452,7 @@ static int __netdev_rx(struct net_device *dev, int *quota) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_info[entry].mapping, diff --git a/trunk/drivers/net/sun3_82586.c b/trunk/drivers/net/sun3_82586.c index a123ea87893b..4757aa647c7a 100644 --- a/trunk/drivers/net/sun3_82586.c +++ b/trunk/drivers/net/sun3_82586.c @@ -775,6 +775,7 @@ static void sun3_82586_rcv_int(struct net_device *dev) skb = (struct sk_buff *) dev_alloc_skb(totlen+2); if(skb != NULL) { + skb->dev = dev; skb_reserve(skb,2); skb_put(skb,totlen); eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0); @@ -1023,11 +1024,10 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) { len = skb->len; if (len < ETH_ZLEN) { - memset((void *)p->xmit_cbuffs[p->xmit_count], 0, - ETH_ZLEN); + memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); len = ETH_ZLEN; } - skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len); + memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); #if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS diff --git a/trunk/drivers/net/sun3lance.c b/trunk/drivers/net/sun3lance.c index 791e081fdc15..7bee45b42a2c 100644 --- a/trunk/drivers/net/sun3lance.c +++ b/trunk/drivers/net/sun3lance.c @@ -629,7 +629,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) head->length = (-len) | 0xf000; head->misc = 0; - skb_copy_from_linear_data(skb, PKTBUF_ADDR(head), skb->len); + memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); if (len != skb->len) memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len); @@ -851,9 +851,10 @@ static int lance_rx( struct net_device *dev ) } + skb->dev = dev; skb_reserve( skb, 2 ); /* 16 byte align */ skb_put( skb, pkt_len ); /* Make room */ -// skb_copy_to_linear_data(skb, PKTBUF_ADDR(head), pkt_len); +// memcpy( skb->data, PKTBUF_ADDR(head), pkt_len ); eth_copy_and_sum(skb, PKTBUF_ADDR(head), pkt_len, 0); diff --git a/trunk/drivers/net/sunbmac.c b/trunk/drivers/net/sunbmac.c index 2ad8d58dee3b..18f88853e1e5 100644 --- a/trunk/drivers/net/sunbmac.c +++ b/trunk/drivers/net/sunbmac.c @@ -855,6 +855,7 @@ static void bigmac_rx(struct bigmac *bp) drops++; goto drop_it; } + copy_skb->dev = bp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, diff --git a/trunk/drivers/net/sundance.c b/trunk/drivers/net/sundance.c index f51ba31970aa..c06ecc8002b9 100644 --- a/trunk/drivers/net/sundance.c +++ b/trunk/drivers/net/sundance.c @@ -1308,6 +1308,7 @@ static void rx_poll(unsigned long data) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, desc->frag[0].addr, diff --git a/trunk/drivers/net/sungem.c b/trunk/drivers/net/sungem.c index 5da73212ac91..08ea61db46fe 100644 --- a/trunk/drivers/net/sungem.c +++ b/trunk/drivers/net/sungem.c @@ -64,9 +64,11 @@ #include #include -#ifdef CONFIG_SPARC +#ifdef __sparc__ #include -#include +#include +#include +#include #endif #ifdef CONFIG_PPC_PMAC @@ -843,10 +845,11 @@ static int gem_rx(struct gem *gp, int work_to_do) goto drop_it; } + copy_skb->dev = gp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); pci_dma_sync_single_for_cpu(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, copy_skb->data, len); + memcpy(copy_skb->data, skb->data, len); pci_dma_sync_single_for_device(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ @@ -1026,8 +1029,10 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) ctrl = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { - const u64 csum_start_off = skb_transport_offset(skb); - const u64 csum_stuff_off = csum_start_off + skb->csum_offset; + u64 csum_start_off, csum_stuff_off; + + csum_start_off = (u64) (skb->h.raw - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; ctrl = (TXDCTRL_CENAB | (csum_start_off << 15) | @@ -2844,7 +2849,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return rc; } -#if (!defined(CONFIG_SPARC) && !defined(CONFIG_PPC_PMAC)) +#if (!defined(__sparc__) && !defined(CONFIG_PPC_PMAC)) /* Fetch MAC address from vital product data of PCI ROM. */ static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr) { @@ -2899,19 +2904,36 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) static int __devinit gem_get_device_address(struct gem *gp) { -#if defined(CONFIG_SPARC) || defined(CONFIG_PPC_PMAC) +#if defined(__sparc__) || defined(CONFIG_PPC_PMAC) struct net_device *dev = gp->dev; +#endif + +#if defined(__sparc__) + struct pci_dev *pdev = gp->pdev; + struct pcidev_cookie *pcp = pdev->sysdata; + int use_idprom = 1; + + if (pcp != NULL) { + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + use_idprom = 0; + memcpy(dev->dev_addr, addr, 6); + } + } + if (use_idprom) + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); +#elif defined(CONFIG_PPC_PMAC) const unsigned char *addr; addr = get_property(gp->of_node, "local-mac-address", NULL); if (addr == NULL) { -#ifdef CONFIG_SPARC - addr = idprom->id_ethaddr; -#else printk("\n"); printk(KERN_ERR "%s: can't get mac-address\n", dev->name); return -1; -#endif } memcpy(dev->dev_addr, addr, 6); #else @@ -3069,7 +3091,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* On Apple, we want a reference to the Open Firmware device-tree * node. We use it for clock control. */ -#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC) +#ifdef CONFIG_PPC_PMAC gp->of_node = pci_device_to_OF_node(pdev); #endif diff --git a/trunk/drivers/net/sungem.h b/trunk/drivers/net/sungem.h index 58cf87c5751e..a70067c85cc9 100644 --- a/trunk/drivers/net/sungem.h +++ b/trunk/drivers/net/sungem.h @@ -1025,7 +1025,7 @@ struct gem { struct pci_dev *pdev; struct net_device *dev; -#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC) +#ifdef CONFIG_PPC_PMAC struct device_node *of_node; #endif }; diff --git a/trunk/drivers/net/sunhme.c b/trunk/drivers/net/sunhme.c index 51c3fe2108a3..ef671739cfea 100644 --- a/trunk/drivers/net/sunhme.c +++ b/trunk/drivers/net/sunhme.c @@ -55,6 +55,9 @@ #ifdef CONFIG_PCI #include +#ifdef CONFIG_SPARC +#include +#endif #endif #include "sunhme.h" @@ -2055,10 +2058,11 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) goto drop_it; } + copy_skb->dev = dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, copy_skb->data, len); + memcpy(copy_skb->data, skb->data, len); hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); /* Reuse original ring buffer. */ @@ -2266,8 +2270,10 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_flags = TXFLAG_OWN; if (skb->ip_summed == CHECKSUM_PARTIAL) { - const u32 csum_start_off = skb_transport_offset(skb); - const u32 csum_stuff_off = csum_start_off + skb->csum_offset; + u32 csum_start_off, csum_stuff_off; + + csum_start_off = (u32) (skb->h.raw - skb->data); + csum_stuff_off = csum_start_off + skb->csum_offset; tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | @@ -2698,7 +2704,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev->dev_addr[i] = macaddr[i]; macaddr[5]++; } else { - const unsigned char *addr; + unsigned char *addr; int len; addr = of_get_property(dp, "local-mac-address", &len); @@ -2980,7 +2986,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, { struct quattro *qp = NULL; #ifdef CONFIG_SPARC - struct device_node *dp; + struct pcidev_cookie *pcp; #endif struct happy_meal *hp; struct net_device *dev; @@ -2992,8 +2998,13 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC - dp = pci_device_to_OF_node(pdev); - strcpy(prom_name, dp->name); + pcp = pdev->sysdata; + if (pcp == NULL) { + printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n"); + return -ENODEV; + } + + strcpy(prom_name, pcp->prom_node->name); #else if (is_quattro_p(pdev)) strcpy(prom_name, "SUNW,qfe"); @@ -3070,11 +3081,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, macaddr[5]++; } else { #ifdef CONFIG_SPARC - const unsigned char *addr; + unsigned char *addr; int len; if (qfe_slot != -1 && - (addr = of_get_property(dp, + (addr = of_get_property(pcp->prom_node, "local-mac-address", &len)) != NULL && len == 6) { memcpy(dev->dev_addr, addr, 6); @@ -3094,7 +3105,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, hp->tcvregs = (hpreg_base + 0x7000UL); #ifdef CONFIG_SPARC - hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff); + hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff); if (hp->hm_revision == 0xff) { unsigned char prev; @@ -3289,7 +3300,7 @@ static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_devic { struct sbus_dev *sdev = to_sbus_device(&dev->dev); struct device_node *dp = dev->node; - const char *model = of_get_property(dp, "model", NULL); + char *model = of_get_property(dp, "model", NULL); int is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) @@ -3303,7 +3314,7 @@ static int __devexit hme_sbus_remove(struct of_device *dev) struct happy_meal *hp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = hp->dev; - unregister_netdev(net_dev); + unregister_netdevice(net_dev); /* XXX qfe parent interrupt... */ diff --git a/trunk/drivers/net/sunlance.c b/trunk/drivers/net/sunlance.c index 42722530ab24..5b00d79b5573 100644 --- a/trunk/drivers/net/sunlance.c +++ b/trunk/drivers/net/sunlance.c @@ -547,6 +547,7 @@ static void lance_rx_dvma(struct net_device *dev) lp->stats.rx_bytes += len; + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ eth_copy_and_sum(skb, @@ -720,6 +721,7 @@ static void lance_rx_pio(struct net_device *dev) lp->stats.rx_bytes += len; + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ lance_piocopy_to_skb(skb, &(ib->rx_buf[entry][0]), len); @@ -1143,7 +1145,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lance_init_block *ib = lp->init_block_mem; ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - skb_copy_from_linear_data(skb, &ib->tx_buf [entry][0], skblen); + memcpy((char *)&ib->tx_buf [entry][0], skb->data, skblen); if (len != skblen) memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); ib->btx_ring [entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN); @@ -1548,7 +1550,7 @@ static int __exit sunlance_sun4_remove(void) struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev); struct net_device *net_dev = lp->dev; - unregister_netdev(net_dev); + unregister_netdevice(net_dev); lance_free_hwresources(lp); @@ -1588,7 +1590,7 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev) struct lance_private *lp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = lp->dev; - unregister_netdev(net_dev); + unregister_netdevice(net_dev); lance_free_hwresources(lp); diff --git a/trunk/drivers/net/sunqe.c b/trunk/drivers/net/sunqe.c index fa70e0b78af7..7874eb1ef043 100644 --- a/trunk/drivers/net/sunqe.c +++ b/trunk/drivers/net/sunqe.c @@ -437,6 +437,7 @@ static void qe_rx(struct sunqe *qep) drops++; qep->net_stats.rx_dropped++; } else { + skb->dev = qep->dev; skb_reserve(skb, 2); skb_put(skb, len); eth_copy_and_sum(skb, (unsigned char *) this_qbuf, @@ -592,7 +593,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Avoid a race... */ qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE; - skb_copy_from_linear_data(skb, txbuf, len); + memcpy(txbuf, skb->data, len); qep->qe_block->qe_txd[entry].tx_addr = txbuf_dvma; qep->qe_block->qe_txd[entry].tx_flags = @@ -844,8 +845,6 @@ static int __init qec_ether_init(struct sbus_dev *sdev) if (!dev) return -ENOMEM; - memcpy(dev->dev_addr, idprom->id_ethaddr, 6); - qe = netdev_priv(dev); i = of_getintprop_default(sdev->ofdev.node, "channel#", -1); @@ -961,7 +960,7 @@ static int __devexit qec_sbus_remove(struct of_device *dev) struct sunqe *qp = dev_get_drvdata(&dev->dev); struct net_device *net_dev = qp->dev; - unregister_netdev(net_dev); + unregister_netdevice(net_dev); sbus_iounmap(qp->qcregs, CREG_REG_SIZE); sbus_iounmap(qp->mregs, MREGS_REG_SIZE); diff --git a/trunk/drivers/net/tc35815.c b/trunk/drivers/net/tc35815.c index f1e2dfc795a2..e3a7e3ceab77 100644 --- a/trunk/drivers/net/tc35815.c +++ b/trunk/drivers/net/tc35815.c @@ -1,34 +1,35 @@ -/* - * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. +/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com * * Based on skelton.c by Donald Becker. + * Copyright (C) 2000-2001 Toshiba Corporation * - * This driver is a replacement of older and less maintained version. - * This is a header of the older version: - * ---------- - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ahennessy@mvista.com - * Copyright (C) 2000-2001 Toshiba Corporation - * static const char *version = - * "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; - * ---------- + * 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 file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * (C) Copyright TOSHIBA CORPORATION 2004-2005 - * All Rights Reserved. + * 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. */ -#ifdef TC35815_NAPI -#define DRV_VERSION "1.35-NAPI" -#else -#define DRV_VERSION "1.35" -#endif -static const char *version = "tc35815.c:v" DRV_VERSION "\n"; -#define MODNAME "tc35815" +static const char *version = + "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; #include #include @@ -39,7 +40,6 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include -#include #include #include #include @@ -47,47 +47,36 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include -#include -#include +#include +#include +#include + +#include #include +#include #include +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ +static const char* cardname = "TC35815CF"; +#define TC35815_PROC_ENTRY "net/tc35815" + +#define TC35815_MODULE_NAME "TC35815CF" +#define TX_TIMEOUT (4*HZ) + /* First, a few definitions that the brave might change. */ -#define GATHER_TXINT /* On-Demand Tx Interrupt */ -#define WORKAROUND_LOSTCAR -#define WORKAROUND_100HALF_PROMISC -/* #define TC35815_USE_PACKEDBUFFER */ - -typedef enum { - TC35815CF = 0, - TC35815_NWU, - TC35815_TX4939, -} board_t; - -/* indexed by board_t, above */ -static const struct { - const char *name; -} board_info[] __devinitdata = { - { "TOSHIBA TC35815CF 10/100BaseTX" }, - { "TOSHIBA TC35815 with Wake on LAN" }, - { "TOSHIBA TC35815/TX4939" }, -}; +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef TC35815_DEBUG +#define TC35815_DEBUG 1 +#endif +static unsigned int tc35815_debug = TC35815_DEBUG; -static const struct pci_device_id tc35815_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF }, - {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU }, - {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 }, - {0,} -}; -MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); +#define GATHER_TXINT /* On-Demand Tx Interrupt */ -/* see MODULE_PARM_DESC */ -static struct tc35815_options { - int speed; - int duplex; - int doforce; -} options; +#define vtonocache(p) KSEG1ADDR(virt_to_phys(p)) /* * Registers @@ -130,11 +119,6 @@ struct tc35815_regs { * Bit assignments */ /* DMA_Ctl bit asign ------------------------------------------------------- */ -#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ -#define DMA_RxAlign_1 0x00400000 -#define DMA_RxAlign_2 0x00800000 -#define DMA_RxAlign_3 0x00c00000 -#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ #define DMA_IntMask 0x00040000 /* 1:Interupt mask */ #define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ #define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ @@ -285,6 +269,42 @@ struct tc35815_regs { #define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */ +/* MII register offsets */ +#define MII_CONTROL 0x0000 +#define MII_STATUS 0x0001 +#define MII_PHY_ID0 0x0002 +#define MII_PHY_ID1 0x0003 +#define MII_ANAR 0x0004 +#define MII_ANLPAR 0x0005 +#define MII_ANER 0x0006 +/* MII Control register bit definitions. */ +#define MIICNTL_FDX 0x0100 +#define MIICNTL_RST_AUTO 0x0200 +#define MIICNTL_ISOLATE 0x0400 +#define MIICNTL_PWRDWN 0x0800 +#define MIICNTL_AUTO 0x1000 +#define MIICNTL_SPEED 0x2000 +#define MIICNTL_LPBK 0x4000 +#define MIICNTL_RESET 0x8000 +/* MII Status register bit significance. */ +#define MIISTAT_EXT 0x0001 +#define MIISTAT_JAB 0x0002 +#define MIISTAT_LINK 0x0004 +#define MIISTAT_CAN_AUTO 0x0008 +#define MIISTAT_FAULT 0x0010 +#define MIISTAT_AUTO_DONE 0x0020 +#define MIISTAT_CAN_T 0x0800 +#define MIISTAT_CAN_T_FDX 0x1000 +#define MIISTAT_CAN_TX 0x2000 +#define MIISTAT_CAN_TX_FDX 0x4000 +#define MIISTAT_CAN_T4 0x8000 +/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */ +#define MII_AN_TX_FDX 0x0100 +#define MII_AN_TX_HDX 0x0080 +#define MII_AN_10_FDX 0x0040 +#define MII_AN_10_HDX 0x0020 + + /* * Descriptors */ @@ -332,51 +352,32 @@ struct BDesc { #ifdef NO_CHECK_CARRIER #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ - Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ - Tx_En) /* maybe 0x7b01 */ + Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ + Tx_En) /* maybe 0x7d01 */ #else #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ - Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ - Tx_En) /* maybe 0x7b01 */ + Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ + Tx_En) /* maybe 0x7f01 */ #endif #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ + #define INT_EN_CMD (Int_NRAbtEn | \ - Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ + Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ Int_STargAbtEn | \ Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/ -#define DMA_CTL_CMD DMA_BURST_SIZE -#define HAVE_DMA_RXALIGN(lp) likely((lp)->boardtype != TC35815CF) /* Tuning parameters */ #define DMA_BURST_SIZE 32 #define TX_THRESHOLD 1024 -#define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/ -#define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */ -/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */ -#ifdef TC35815_USE_PACKEDBUFFER #define FD_PAGE_NUM 2 -#define RX_BUF_NUM 8 /* >= 2 */ +#define FD_PAGE_ORDER 1 +/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */ +#define RX_BUF_PAGES 8 /* >= 2 */ #define RX_FD_NUM 250 /* >= 32 */ #define TX_FD_NUM 128 -#define RX_BUF_SIZE PAGE_SIZE -#else /* TC35815_USE_PACKEDBUFFER */ -#define FD_PAGE_NUM 4 -#define RX_BUF_NUM 128 /* < 256 */ -#define RX_FD_NUM 256 /* >= 32 */ -#define TX_FD_NUM 128 -#if RX_CTL_CMD & Rx_LongEn -#define RX_BUF_SIZE PAGE_SIZE -#elif RX_CTL_CMD & Rx_StripCRC -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ -#else -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ -#endif -#endif /* TC35815_USE_PACKEDBUFFER */ -#define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ -#define NAPI_WEIGHT 16 struct TxFD { struct FDesc fd; @@ -391,27 +392,18 @@ struct RxFD { struct FrFD { struct FDesc fd; - struct BDesc bd[RX_BUF_NUM]; + struct BDesc bd[RX_BUF_PAGES]; }; -#define tc_readl(addr) readl(addr) -#define tc_writel(d, addr) writel(d, addr) - -#define TC35815_TX_TIMEOUT msecs_to_jiffies(400) +extern unsigned long tc_readl(volatile __u32 *addr); +extern void tc_writel(unsigned long data, volatile __u32 *addr); -/* Timer state engine. */ -enum tc35815_timer_state { - arbwait = 0, /* Waiting for auto negotiation to complete. */ - lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ - ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ - asleep = 3, /* Time inactive. */ - lcheck = 4, /* Check link status. */ -}; +dma_addr_t priv_dma_handle; /* Information that need to be kept for each board. */ struct tc35815_local { - struct pci_dev *pci_dev; + struct net_device *next_module; /* statistics */ struct net_device_stats stats; @@ -419,372 +411,216 @@ struct tc35815_local { int max_tx_qlen; int tx_ints; int rx_ints; - int tx_underrun; } lstats; - /* Tx control lock. This protects the transmit buffer ring - * state along with the "tx full" state of the driver. This - * means all netif_queue flow control actions are protected - * by this lock as well. - */ - spinlock_t lock; - - int phy_addr; + int tbusy; + int option; +#define TC35815_OPT_AUTO 0x00 +#define TC35815_OPT_10M 0x01 +#define TC35815_OPT_100M 0x02 +#define TC35815_OPT_FULLDUP 0x04 + int linkspeed; /* 10 or 100 */ int fullduplex; - unsigned short saved_lpa; - struct timer_list timer; - enum tc35815_timer_state timer_state; /* State of auto-neg timer. */ - unsigned int timer_ticks; /* Number of clicks at each state */ /* * Transmitting: Batch Mode. * 1 BD in 1 TxFD. - * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER) + * Receiving: Packing Mode. * 1 circular FD for Free Buffer List. - * RX_BUF_NUM BD in Free Buffer FD. + * RX_BUG_PAGES BD in Free Buffer FD. * One Free Buffer BD has PAGE_SIZE data buffer. - * Or Non-Packing Mode. - * 1 circular FD for Free Buffer List. - * RX_BUF_NUM BD in Free Buffer FD. - * One Free Buffer BD has ETH_FRAME_LEN data buffer. */ - void * fd_buf; /* for TxFD, RxFD, FrFD */ - dma_addr_t fd_buf_dma; + struct pci_dev *pdev; + dma_addr_t fd_buf_dma_handle; + void * fd_buf; /* for TxFD, TxFD, FrFD */ struct TxFD *tfd_base; - unsigned int tfd_start; - unsigned int tfd_end; + int tfd_start; + int tfd_end; struct RxFD *rfd_base; struct RxFD *rfd_limit; struct RxFD *rfd_cur; struct FrFD *fbl_ptr; -#ifdef TC35815_USE_PACKEDBUFFER unsigned char fbl_curid; - void * data_buf[RX_BUF_NUM]; /* packing */ - dma_addr_t data_buf_dma[RX_BUF_NUM]; - struct { - struct sk_buff *skb; - dma_addr_t skb_dma; - } tx_skbs[TX_FD_NUM]; -#else - unsigned int fbl_count; - struct { - struct sk_buff *skb; - dma_addr_t skb_dma; - } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM]; -#endif - struct mii_if_info mii; - unsigned short mii_id[2]; - u32 msg_enable; - board_t boardtype; + dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; + void * data_buf[RX_BUF_PAGES]; /* packing */ + spinlock_t lock; }; -static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt) -{ - return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf); -} -#ifdef DEBUG -static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) -{ - return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma)); -} -#endif -#ifdef TC35815_USE_PACKEDBUFFER -static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) -{ - int i; - for (i = 0; i < RX_BUF_NUM; i++) { - if (bus >= lp->data_buf_dma[i] && - bus < lp->data_buf_dma[i] + PAGE_SIZE) - return (void *)((u8 *)lp->data_buf[i] + - (bus - lp->data_buf_dma[i])); - } - return NULL; -} - -#define TC35815_DMA_SYNC_ONDEMAND -static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) -{ -#ifdef TC35815_DMA_SYNC_ONDEMAND - void *buf; - /* pci_map + pci_dma_sync will be more effective than - * pci_alloc_consistent on some archs. */ - if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL) - return NULL; - *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(*dma_handle)) { - free_page((unsigned long)buf); - return NULL; - } - return buf; -#else - return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle); -#endif -} - -static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle) -{ -#ifdef TC35815_DMA_SYNC_ONDEMAND - pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE); - free_page((unsigned long)buf); -#else - pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle); -#endif -} -#else /* TC35815_USE_PACKEDBUFFER */ -static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, - struct pci_dev *hwdev, - dma_addr_t *dma_handle) -{ - struct sk_buff *skb; - skb = dev_alloc_skb(RX_BUF_SIZE); - if (!skb) - return NULL; - skb->dev = dev; - *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(*dma_handle)) { - dev_kfree_skb_any(skb); - return NULL; - } - skb_reserve(skb, 2); /* make IP header 4byte aligned */ - return skb; -} - -static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle) -{ - pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(skb); -} -#endif /* TC35815_USE_PACKEDBUFFER */ - /* Index to functions, as function prototypes. */ +static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq); + static int tc35815_open(struct net_device *dev); static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t tc35815_interrupt(int irq, void *dev_id); -#ifdef TC35815_NAPI -static int tc35815_rx(struct net_device *dev, int limit); -static int tc35815_poll(struct net_device *dev, int *budget); -#else +static void tc35815_tx_timeout(struct net_device *dev); +static irqreturn_t tc35815_interrupt(int irq, void *dev_id); static void tc35815_rx(struct net_device *dev); -#endif static void tc35815_txdone(struct net_device *dev); static int tc35815_close(struct net_device *dev); static struct net_device_stats *tc35815_get_stats(struct net_device *dev); static void tc35815_set_multicast_list(struct net_device *dev); -static void tc35815_tx_timeout(struct net_device *dev); -static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#ifdef CONFIG_NET_POLL_CONTROLLER -static void tc35815_poll_controller(struct net_device *dev); -#endif -static const struct ethtool_ops tc35815_ethtool_ops; -/* Example routines you must write ;->. */ static void tc35815_chip_reset(struct net_device *dev); static void tc35815_chip_init(struct net_device *dev); -static void tc35815_find_phy(struct net_device *dev); static void tc35815_phy_chip_init(struct net_device *dev); -#ifdef DEBUG -static void panic_queues(struct net_device *dev); -#endif - -static void tc35815_timer(unsigned long data); -static void tc35815_start_auto_negotiation(struct net_device *dev, - struct ethtool_cmd *ep); -static int tc_mdio_read(struct net_device *dev, int phy_id, int location); -static void tc_mdio_write(struct net_device *dev, int phy_id, int location, - int val); +/* A list of all installed tc35815 devices. */ +static struct net_device *root_tc35815_dev = NULL; -static void __devinit tc35815_init_dev_addr (struct net_device *dev) -{ - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int i; +/* + * PCI device identifiers for "new style" Linux PCI Device Drivers + */ +static struct pci_device_id tc35815_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; - /* dev_addr will be overwritten on NETDEV_REGISTER event */ - while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) - ; - for (i = 0; i < 6; i += 2) { - unsigned short data; - tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); - while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) - ; - data = tc_readl(&tr->PROM_Data); - dev->dev_addr[i] = data & 0xff; - dev->dev_addr[i+1] = data >> 8; - } -} +MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); -static int __devinit tc35815_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +int +tc35815_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - void __iomem *ioaddr = NULL; - struct net_device *dev; - struct tc35815_local *lp; - int rc; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - - static int printed_version; - if (!printed_version++) { - printk(version); - dev_printk(KERN_DEBUG, &pdev->dev, - "speed:%d duplex:%d doforce:%d\n", - options.speed, options.duplex, options.doforce); - } - - if (!pdev->irq) { - dev_warn(&pdev->dev, "no IRQ assigned.\n"); - return -ENODEV; - } + int err = 0; + int ret; + unsigned long pci_memaddr; + unsigned int pci_irq_line; - /* dev zeroed in alloc_etherdev */ - dev = alloc_etherdev (sizeof (*lp)); - if (dev == NULL) { - dev_err(&pdev->dev, "unable to alloc new ethernet\n"); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); - lp = dev->priv; + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); - /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); - if (rc) - goto err_out; + err = pci_enable_device(pdev); + if (err) + return err; - mmio_start = pci_resource_start (pdev, 1); - mmio_end = pci_resource_end (pdev, 1); - mmio_flags = pci_resource_flags (pdev, 1); - mmio_len = pci_resource_len (pdev, 1); + pci_memaddr = pci_resource_start (pdev, 1); - /* set this immediately, we need to know before - * we talk to the chip directly */ + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); - /* make sure PCI base addr 1 is MMIO */ - if (!(mmio_flags & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); - rc = -ENODEV; + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + ret = -ENODEV; goto err_out; } - - /* check for weird/broken PCI region reporting */ - if ((mmio_len < sizeof(struct tc35815_regs))) { - dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); - rc = -ENODEV; + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + ret = -ENODEV; goto err_out; } - rc = pci_request_regions (pdev, MODNAME); - if (rc) + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + if (ret) goto err_out; - pci_set_master (pdev); + pci_set_master(pdev); - /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, mmio_len); - if (ioaddr == NULL) { - dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); - rc = -EIO; - goto err_out_free_res; - } + return 0; - /* Initialize the device structure. */ - dev->open = tc35815_open; - dev->hard_start_xmit = tc35815_send_packet; - dev->stop = tc35815_close; - dev->get_stats = tc35815_get_stats; - dev->set_multicast_list = tc35815_set_multicast_list; - dev->do_ioctl = tc35815_ioctl; - dev->ethtool_ops = &tc35815_ethtool_ops; - dev->tx_timeout = tc35815_tx_timeout; - dev->watchdog_timeo = TC35815_TX_TIMEOUT; -#ifdef TC35815_NAPI - dev->poll = tc35815_poll; - dev->weight = NAPI_WEIGHT; -#endif -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = tc35815_poll_controller; -#endif +err_out: + pci_disable_device(pdev); + return ret; +} + +static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) +{ + static unsigned version_printed = 0; + int i, ret; + struct tc35815_local *lp; + struct tc35815_regs *tr; + struct net_device *dev; - dev->irq = pdev->irq; - dev->base_addr = (unsigned long) ioaddr; + /* Allocate a new 'dev' if needed. */ + dev = alloc_etherdev(sizeof(struct tc35815_local)); + if (dev == NULL) + return -ENOMEM; - /* dev->priv/lp zeroed and aligned in alloc_etherdev */ + /* + * alloc_etherdev allocs and zeros dev->priv + */ lp = dev->priv; - spin_lock_init(&lp->lock); - lp->pci_dev = pdev; - lp->boardtype = ent->driver_data; - lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK; - pci_set_drvdata(pdev, dev); + if (tc35815_debug && version_printed++ == 0) + printk(KERN_DEBUG "%s", version); + + /* Fill in the 'dev' fields. */ + dev->irq = irq; + dev->base_addr = (unsigned long)ioremap(base_addr, + sizeof(struct tc35815_regs)); + if (!dev->base_addr) { + ret = -ENOMEM; + goto err_out; + } + tr = (struct tc35815_regs*)dev->base_addr; - /* Soft reset the chip. */ tc35815_chip_reset(dev); - /* Retrieve the ethernet address. */ - tc35815_init_dev_addr(dev); - - rc = register_netdev (dev); - if (rc) - goto err_out_unmap; - - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - printk(KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", - dev->name, - board_info[ent->driver_data].name, - dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], - dev->irq); - - setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev); - lp->mii.dev = dev; - lp->mii.mdio_read = tc_mdio_read; - lp->mii.mdio_write = tc_mdio_write; - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - tc35815_find_phy(dev); - lp->mii.phy_id = lp->phy_addr; - lp->mii.full_duplex = 0; - lp->mii.force_media = 0; + /* Retrieve and print the ethernet address. */ + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + for (i = 0; i < 6; i += 2) { + unsigned short data; + tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + data = tc_readl(&tr->PROM_Data); + dev->dev_addr[i] = data & 0xff; + dev->dev_addr[i+1] = data >> 8; + } - return 0; + /* Initialize the device structure. */ + lp->pdev = pdev; + lp->next_module = root_tc35815_dev; + root_tc35815_dev = dev; -err_out_unmap: - iounmap(ioaddr); -err_out_free_res: - pci_release_regions (pdev); -err_out: - free_netdev (dev); - return rc; -} + spin_lock_init(&lp->lock); + if (dev->mem_start > 0) { + lp->option = dev->mem_start; + if ((lp->option & TC35815_OPT_10M) && + (lp->option & TC35815_OPT_100M)) { + /* if both speed speficied, auto select. */ + lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); + } + } + //XXX fixme + lp->option |= TC35815_OPT_10M; -static void __devexit tc35815_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - unsigned long mmio_addr; + /* do auto negotiation */ + tc35815_phy_chip_init(dev); - mmio_addr = dev->base_addr; + dev->open = tc35815_open; + dev->stop = tc35815_close; + dev->tx_timeout = tc35815_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->hard_start_xmit = tc35815_send_packet; + dev->get_stats = tc35815_get_stats; + dev->set_multicast_list = tc35815_set_multicast_list; + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); - unregister_netdev (dev); + ret = register_netdev(dev); + if (ret) + goto err_out_iounmap; - if (mmio_addr) { - iounmap ((void __iomem *)mmio_addr); - pci_release_regions (pdev); - } + printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", + dev->name, cardname, base_addr, irq); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); - free_netdev (dev); + return 0; - pci_set_drvdata (pdev, NULL); +err_out_iounmap: + iounmap((void *) dev->base_addr); +err_out: + free_netdev(dev); + return ret; } + static int tc35815_init_queues(struct net_device *dev) { @@ -793,64 +629,44 @@ tc35815_init_queues(struct net_device *dev) unsigned long fd_addr; if (!lp->fd_buf) { - BUG_ON(sizeof(struct FDesc) + - sizeof(struct BDesc) * RX_BUF_NUM + - sizeof(struct FDesc) * RX_FD_NUM + - sizeof(struct TxFD) * TX_FD_NUM > - PAGE_SIZE * FD_PAGE_NUM); + if (sizeof(struct FDesc) + + sizeof(struct BDesc) * RX_BUF_PAGES + + sizeof(struct FDesc) * RX_FD_NUM + + sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { + printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); + return -ENOMEM; + } - if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0) + if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) return -ENOMEM; - for (i = 0; i < RX_BUF_NUM; i++) { -#ifdef TC35815_USE_PACKEDBUFFER - if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) { - while (--i >= 0) { - free_rxbuf_page(lp->pci_dev, - lp->data_buf[i], - lp->data_buf_dma[i]); - lp->data_buf[i] = NULL; - } - pci_free_consistent(lp->pci_dev, - PAGE_SIZE * FD_PAGE_NUM, - lp->fd_buf, - lp->fd_buf_dma); - lp->fd_buf = NULL; - return -ENOMEM; - } -#else - lp->rx_skbs[i].skb = - alloc_rxbuf_skb(dev, lp->pci_dev, - &lp->rx_skbs[i].skb_dma); - if (!lp->rx_skbs[i].skb) { + for (i = 0; i < RX_BUF_PAGES; i++) { + if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) { while (--i >= 0) { - free_rxbuf_skb(lp->pci_dev, - lp->rx_skbs[i].skb, - lp->rx_skbs[i].skb_dma); - lp->rx_skbs[i].skb = NULL; + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; } - pci_free_consistent(lp->pci_dev, - PAGE_SIZE * FD_PAGE_NUM, - lp->fd_buf, - lp->fd_buf_dma); - lp->fd_buf = NULL; + free_page((unsigned long)lp->fd_buf); + lp->fd_buf = 0; return -ENOMEM; } +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM); #endif } - printk(KERN_DEBUG "%s: FD buf %p DataBuf", - dev->name, lp->fd_buf); -#ifdef TC35815_USE_PACKEDBUFFER - printk(" DataBuf"); - for (i = 0; i < RX_BUF_NUM; i++) - printk(" %p", lp->data_buf[i]); +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); #endif - printk("\n"); } else { - for (i = 0; i < FD_PAGE_NUM; i++) { - clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE)); - } + memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM); +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); +#endif } +#ifdef __mips__ + fd_addr = (unsigned long)vtonocache(lp->fd_buf); +#else fd_addr = (unsigned long)lp->fd_buf; +#endif /* Free Descriptors (for Receive) */ lp->rfd_base = (struct RxFD *)fd_addr; @@ -859,66 +675,34 @@ tc35815_init_queues(struct net_device *dev) lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); } lp->rfd_cur = lp->rfd_base; - lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1); + lp->rfd_limit = (struct RxFD *)(fd_addr - + sizeof(struct FDesc) - + sizeof(struct BDesc) * 30); /* Transmit Descriptors */ lp->tfd_base = (struct TxFD *)fd_addr; fd_addr += sizeof(struct TxFD) * TX_FD_NUM; for (i = 0; i < TX_FD_NUM; i++) { - lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1])); - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); + lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); } - lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0])); + lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); lp->tfd_start = 0; lp->tfd_end = 0; /* Buffer List (for Receive) */ lp->fbl_ptr = (struct FrFD *)fd_addr; - lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr)); - lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD); -#ifndef TC35815_USE_PACKEDBUFFER - /* - * move all allocated skbs to head of rx_skbs[] array. - * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in - * tc35815_rx() had failed. - */ - lp->fbl_count = 0; - for (i = 0; i < RX_BUF_NUM; i++) { - if (lp->rx_skbs[i].skb) { - if (i != lp->fbl_count) { - lp->rx_skbs[lp->fbl_count].skb = - lp->rx_skbs[i].skb; - lp->rx_skbs[lp->fbl_count].skb_dma = - lp->rx_skbs[i].skb_dma; - } - lp->fbl_count++; - } - } -#endif - for (i = 0; i < RX_BUF_NUM; i++) { -#ifdef TC35815_USE_PACKEDBUFFER - lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]); -#else - if (i >= lp->fbl_count) { - lp->fbl_ptr->bd[i].BuffData = 0; - lp->fbl_ptr->bd[i].BDCtl = 0; - continue; - } - lp->fbl_ptr->bd[i].BuffData = - cpu_to_le32(lp->rx_skbs[i].skb_dma); -#endif + lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); + lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); + for (i = 0; i < RX_BUF_PAGES; i++) { + lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); /* BDID is index of FrFD.bd[] */ lp->fbl_ptr->bd[i].BDCtl = - cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | - RX_BUF_SIZE); + cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); } -#ifdef TC35815_USE_PACKEDBUFFER lp->fbl_curid = 0; -#endif - printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n", - dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr); return 0; } @@ -929,25 +713,11 @@ tc35815_clear_queues(struct net_device *dev) int i; for (i = 0; i < TX_FD_NUM; i++) { - u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); - struct sk_buff *skb = - fdsystem != 0xffffffff ? - lp->tx_skbs[fdsystem].skb : NULL; -#ifdef DEBUG - if (lp->tx_skbs[i].skb != skb) { - printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); - panic_queues(dev); - } -#else - BUG_ON(lp->tx_skbs[i].skb != skb); -#endif - if (skb) { - pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); - lp->tx_skbs[i].skb = NULL; - lp->tx_skbs[i].skb_dma = 0; + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) dev_kfree_skb_any(skb); - } - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); } tc35815_init_queues(dev); @@ -961,53 +731,28 @@ tc35815_free_queues(struct net_device *dev) if (lp->tfd_base) { for (i = 0; i < TX_FD_NUM; i++) { - u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); - struct sk_buff *skb = - fdsystem != 0xffffffff ? - lp->tx_skbs[fdsystem].skb : NULL; -#ifdef DEBUG - if (lp->tx_skbs[i].skb != skb) { - printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); - panic_queues(dev); - } -#else - BUG_ON(lp->tx_skbs[i].skb != skb); -#endif - if (skb) { - dev_kfree_skb(skb); - pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); - lp->tx_skbs[i].skb = NULL; - lp->tx_skbs[i].skb_dma = 0; - } - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) + dev_kfree_skb_any(skb); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); } } + lp->rfd_base = NULL; lp->rfd_base = NULL; lp->rfd_limit = NULL; lp->rfd_cur = NULL; lp->fbl_ptr = NULL; - for (i = 0; i < RX_BUF_NUM; i++) { -#ifdef TC35815_USE_PACKEDBUFFER - if (lp->data_buf[i]) { - free_rxbuf_page(lp->pci_dev, - lp->data_buf[i], lp->data_buf_dma[i]); - lp->data_buf[i] = NULL; - } -#else - if (lp->rx_skbs[i].skb) { - free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb, - lp->rx_skbs[i].skb_dma); - lp->rx_skbs[i].skb = NULL; - } -#endif - } - if (lp->fd_buf) { - pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, - lp->fd_buf, lp->fd_buf_dma); - lp->fd_buf = NULL; + for (i = 0; i < RX_BUF_PAGES; i++) { + if (lp->data_buf[i]) + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; } + if (lp->fd_buf) + __free_pages(lp->fd_buf, FD_PAGE_ORDER); + lp->fd_buf = NULL; } static void @@ -1047,7 +792,6 @@ dump_rxfd(struct RxFD *fd) return bd_count; } -#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER) static void dump_frfd(struct FrFD *fd) { @@ -1058,22 +802,20 @@ dump_frfd(struct FrFD *fd) le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); printk("BD: "); - for (i = 0; i < RX_BUF_NUM; i++) + for (i = 0; i < RX_BUF_PAGES; i++) printk(" %08x %08x", le32_to_cpu(fd->bd[i].BuffData), le32_to_cpu(fd->bd[i].BDCtl)); printk("\n"); } -#endif -#ifdef DEBUG static void panic_queues(struct net_device *dev) { struct tc35815_local *lp = dev->priv; int i; - printk("TxFD base %p, start %u, end %u\n", + printk("TxFD base %p, start %d, end %d\n", lp->tfd_base, lp->tfd_start, lp->tfd_end); printk("RxFD base %p limit %p cur %p\n", lp->rfd_base, lp->rfd_limit, lp->rfd_cur); @@ -1087,13 +829,31 @@ panic_queues(struct net_device *dev) dump_frfd(lp->fbl_ptr); panic("%s: Illegal queue state.", dev->name); } + +#if 0 +static void print_buf(char *add, int length) +{ + int i; + int len = length; + + printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); + + if (len > 100) + len = 100; + for (i = 0; i < len; i++) { + printk(" %2.2X", (unsigned char) add[i]); + if (!(i % 16)) + printk("\n"); + } + printk("\n"); +} #endif static void print_eth(char *add) { int i; - printk("print_eth(%p)\n", add); + printk("print_eth(%08x)\n", (unsigned int) add); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i + 6]); printk(" =>"); @@ -1102,73 +862,6 @@ static void print_eth(char *add) printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); } -static int tc35815_tx_full(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end); -} - -static void tc35815_restart(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - int do_phy_reset = 1; - del_timer(&lp->timer); /* Kill if running */ - - if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) { - /* Resetting PHY cause problem on some chip... (SEEQ 80221) */ - do_phy_reset = 0; - } - if (do_phy_reset) { - int timeout; - tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET); - timeout = 100; - while (--timeout) { - if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET)) - break; - udelay(1); - } - if (!timeout) - printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); - } - - tc35815_chip_reset(dev); - tc35815_clear_queues(dev); - tc35815_chip_init(dev); - /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ - tc35815_set_multicast_list(dev); -} - -static void tc35815_tx_timeout(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", - dev->name, tc_readl(&tr->Tx_Stat)); - - /* Try to restart the adaptor. */ - spin_lock_irq(&lp->lock); - tc35815_restart(dev); - spin_unlock_irq(&lp->lock); - - lp->stats.tx_errors++; - - /* If we have space available to accept new transmit - * requests, wake up the queueing layer. This would - * be the case if the chipset_init() call above just - * flushes out the tx queue and empties it. - * - * If instead, the tx queue is retained then the - * netif_wake_queue() call should be placed in the - * TX completion interrupt handler of the driver instead - * of here. - */ - if (!tc35815_tx_full(dev)) - netif_wake_queue(dev); -} - /* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. @@ -1181,16 +874,16 @@ static int tc35815_open(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. */ - if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) { + + if (dev->irq == 0 || + request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) { return -EAGAIN; } - del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); if (tc35815_init_queues(dev) != 0) { @@ -1199,119 +892,138 @@ tc35815_open(struct net_device *dev) } /* Reset the hardware here. Don't forget to set the station address. */ - spin_lock_irq(&lp->lock); tc35815_chip_init(dev); - spin_unlock_irq(&lp->lock); - /* We are now ready to accept transmit requeusts from - * the queueing layer of the networking. - */ + lp->tbusy = 0; netif_start_queue(dev); return 0; } -/* This will only be invoked if your driver is _not_ in XOFF state. - * What this means is that you need not check it, and that this - * invariant will hold if you make sure that the netif_*_queue() - * calls are done at the proper times. - */ -static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +static void tc35815_tx_timeout(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct TxFD *txfd; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; unsigned long flags; - /* If some error occurs while trying to transmit this - * packet, you should return '1' from this function. - * In such a case you _may not_ do anything to the - * SKB, it is still owned by the network queueing - * layer when an error is returned. This means you - * may not modify any SKB fields, you may not free - * the SKB, etc. - */ - - /* This is the most common case for modern hardware. - * The spinlock protects this code from the TX complete - * hardware interrupt handler. Queue flow control is - * thus managed under this lock as well. - */ spin_lock_irqsave(&lp->lock, flags); + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + spin_unlock_irqrestore(&lp->lock, flags); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} - /* failsafe... (handle txdone now if half of FDs are used) */ - if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM > - TX_FD_NUM / 2) - tc35815_txdone(dev); - - if (netif_msg_pktdata(lp)) - print_eth(skb->data); -#ifdef DEBUG - if (lp->tx_skbs[lp->tfd_start].skb) { - printk("%s: tx_skbs conflict.\n", dev->name); - panic_queues(dev); - } -#else - BUG_ON(lp->tx_skbs[lp->tfd_start].skb); +static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; + + if (netif_queue_stopped(dev)) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, lp->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + dev_kfree_skb_any(skb); + } else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; + unsigned long flags; + lp->stats.tx_bytes += skb->len; + + +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)buf, length); #endif - lp->tx_skbs[lp->tfd_start].skb = skb; - lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - - /*add to ring */ - txfd = &lp->tfd_base[lp->tfd_start]; - txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma); - txfd->bd.BDCtl = cpu_to_le32(skb->len); - txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start); - txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); - - if (lp->tfd_start == lp->tfd_end) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - /* Start DMA Transmitter. */ - txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); + + spin_lock_irqsave(&lp->lock, flags); + + /* failsafe... */ + if (lp->tfd_start != lp->tfd_end) + tc35815_txdone(dev); + + + txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf)); + + txfd->bd.BDCtl = cpu_to_le32(length); + txfd->fd.FDSystem = cpu_to_le32((__u32)skb); + txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); + + if (lp->tfd_start == lp->tfd_end) { + /* Start DMA Transmitter. */ + txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); #ifdef GATHER_TXINT - txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); + txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); #endif - if (netif_msg_tx_queued(lp)) { - printk("%s: starting TxFD.\n", dev->name); - dump_txfd(txfd); - } - tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); - } else { - txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); - if (netif_msg_tx_queued(lp)) { - printk("%s: queueing TxFD.\n", dev->name); - dump_txfd(txfd); + if (tc35815_debug > 2) { + printk("%s: starting TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + } else { + txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); + if (tc35815_debug > 2) { + printk("%s: queueing TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } } - } - lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; + lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; - dev->trans_start = jiffies; + dev->trans_start = jiffies; - /* If we just used up the very last entry in the - * TX ring on this device, tell the queueing - * layer to send no more. - */ - if (tc35815_tx_full(dev)) { - if (netif_msg_tx_queued(lp)) - printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); - netif_stop_queue(dev); + if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) { + /* we can send another packet */ + lp->tbusy = 0; + netif_start_queue(dev); + } else { + netif_stop_queue(dev); + if (tc35815_debug > 1) + printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); + } + spin_unlock_irqrestore(&lp->lock, flags); } - /* When the TX completion hw interrupt arrives, this - * is when the transmit statistics are updated. - */ - - spin_unlock_irqrestore(&lp->lock, flags); return 0; } #define FATAL_ERROR_INT \ (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) -static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status) +static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) { static int count; printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", dev->name, status); + if (status & Int_IntPCI) printk(" IntPCI"); if (status & Int_DmParErr) @@ -1321,170 +1033,110 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status) printk("\n"); if (count++ > 100) panic("%s: Too many fatal errors.", dev->name); - printk(KERN_WARNING "%s: Resetting ...\n", dev->name); + printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname); /* Try to restart the adaptor. */ - tc35815_restart(dev); -} - -#ifdef TC35815_NAPI -static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit) -#else -static int tc35815_do_interrupt(struct net_device *dev, u32 status) -#endif -{ - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int ret = -1; - - /* Fatal errors... */ - if (status & FATAL_ERROR_INT) { - tc35815_fatal_error_interrupt(dev, status); - return 0; - } - /* recoverable errors */ - if (status & Int_IntFDAEx) { - /* disable FDAEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Free Descriptor Area Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; - ret = 0; - } - if (status & Int_IntBLEx) { - /* disable BLEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Buffer List Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; - ret = 0; - } - if (status & Int_IntExBD) { - printk(KERN_WARNING - "%s: Excessive Buffer Descriptiors (%#x).\n", - dev->name, status); - lp->stats.rx_length_errors++; - ret = 0; - } - - /* normal notification */ - if (status & Int_IntMacRx) { - /* Got a packet(s). */ -#ifdef TC35815_NAPI - ret = tc35815_rx(dev, limit); -#else - tc35815_rx(dev); - ret = 0; -#endif - lp->lstats.rx_ints++; - } - if (status & Int_IntMacTx) { - /* Transmit complete. */ - lp->lstats.tx_ints++; - tc35815_txdone(dev); - netif_wake_queue(dev); - ret = 0; - } - return ret; + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); } /* * The typical workload of the driver: - * Handle the network interface interrupts. + * Handle the network interface interrupts. */ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; -#ifdef TC35815_NAPI - u32 dmactl = tc_readl(&tr->DMA_Ctl); - - if (!(dmactl & DMA_IntMask)) { - /* disable interrupts */ - tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); - else { - printk(KERN_ERR "%s: interrupt taken in poll\n", - dev->name); - BUG(); - } - (void)tc_readl(&tr->Int_Src); /* flush */ - return IRQ_HANDLED; + struct tc35815_regs *tr; + struct tc35815_local *lp; + int status, boguscount = 0; + int handled = 0; + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); + return IRQ_NONE; } - return IRQ_NONE; -#else - struct tc35815_local *lp = dev->priv; - int handled; - u32 status; - - spin_lock(&lp->lock); - status = tc_readl(&tr->Int_Src); - tc_writel(status, &tr->Int_Src); /* write to clear */ - handled = tc35815_do_interrupt(dev, status); - (void)tc_readl(&tr->Int_Src); /* flush */ - spin_unlock(&lp->lock); - return IRQ_RETVAL(handled >= 0); -#endif /* TC35815_NAPI */ -} -#ifdef CONFIG_NET_POLL_CONTROLLER -static void tc35815_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - tc35815_interrupt(dev->irq, dev); - enable_irq(dev->irq); + tr = (struct tc35815_regs*)dev->base_addr; + lp = dev->priv; + + do { + status = tc_readl(&tr->Int_Src); + if (status == 0) + break; + handled = 1; + tc_writel(status, &tr->Int_Src); /* write to clear */ + + /* Fatal errors... */ + if (status & FATAL_ERROR_INT) { + tc35815_fatal_error_interrupt(dev, status); + break; + } + /* recoverable errors */ + if (status & Int_IntFDAEx) { + /* disable FDAEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Free Descriptor Area Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntBLEx) { + /* disable BLEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Buffer List Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntExBD) { + printk(KERN_WARNING + "%s: Excessive Buffer Descriptiors (%#x).\n", + dev->name, status); + lp->stats.rx_length_errors++; + } + /* normal notification */ + if (status & Int_IntMacRx) { + /* Got a packet(s). */ + lp->lstats.rx_ints++; + tc35815_rx(dev); + } + if (status & Int_IntMacTx) { + lp->lstats.tx_ints++; + tc35815_txdone(dev); + } + } while (++boguscount < 20) ; + + return IRQ_RETVAL(handled); } -#endif /* We have a good packet(s), get it/them out of the buffers. */ -#ifdef TC35815_NAPI -static int -tc35815_rx(struct net_device *dev, int limit) -#else static void tc35815_rx(struct net_device *dev) -#endif { struct tc35815_local *lp = dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned int fdctl; int i; int buf_free_count = 0; int fd_free_count = 0; -#ifdef TC35815_NAPI - int received = 0; -#endif while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); int pkt_len = fdctl & FD_FDLength_MASK; - int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; -#ifdef DEBUG struct RxFD *next_rfd; -#endif -#if (RX_CTL_CMD & Rx_StripCRC) == 0 - pkt_len -= 4; -#endif + int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; - if (netif_msg_rx_status(lp)) + if (tc35815_debug > 2) dump_rxfd(lp->rfd_cur); if (status & Rx_Good) { + /* Malloc up new buffer. */ struct sk_buff *skb; unsigned char *data; - int cur_bd; -#ifdef TC35815_USE_PACKEDBUFFER - int offset; -#endif + int cur_bd, offset; + + lp->stats.rx_bytes += pkt_len; -#ifdef TC35815_NAPI - if (--limit < 0) - break; -#endif -#ifdef TC35815_USE_PACKEDBUFFER - BUG_ON(bd_count > 2); skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", @@ -1493,6 +1145,7 @@ tc35815_rx(struct net_device *dev) break; } skb_reserve(skb, 2); /* 16 bit alignment */ + skb->dev = dev; data = skb_put(skb, pkt_len); @@ -1502,69 +1155,25 @@ tc35815_rx(struct net_device *dev) while (offset < pkt_len && cur_bd < bd_count) { int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & BD_BuffLength_MASK; - dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData); - void *rxbuf = rxbuf_bus_to_virt(lp, dma); - if (offset + len > pkt_len) - len = pkt_len - offset; -#ifdef TC35815_DMA_SYNC_ONDEMAND - pci_dma_sync_single_for_cpu(lp->pci_dev, - dma, len, - PCI_DMA_FROMDEVICE); + void *rxbuf = + bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData)); +#ifdef __mips__ + dma_cache_inv((unsigned long)rxbuf, len); #endif memcpy(data + offset, rxbuf, len); -#ifdef TC35815_DMA_SYNC_ONDEMAND - pci_dma_sync_single_for_device(lp->pci_dev, - dma, len, - PCI_DMA_FROMDEVICE); -#endif offset += len; cur_bd++; } -#else /* TC35815_USE_PACKEDBUFFER */ - BUG_ON(bd_count > 1); - cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl) - & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; -#ifdef DEBUG - if (cur_bd >= RX_BUF_NUM) { - printk("%s: invalid BDID.\n", dev->name); - panic_queues(dev); - } - BUG_ON(lp->rx_skbs[cur_bd].skb_dma != - (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3)); - if (!lp->rx_skbs[cur_bd].skb) { - printk("%s: NULL skb.\n", dev->name); - panic_queues(dev); - } -#else - BUG_ON(cur_bd >= RX_BUF_NUM); +#if 0 + print_buf(data,pkt_len); #endif - skb = lp->rx_skbs[cur_bd].skb; - prefetch(skb->data); - lp->rx_skbs[cur_bd].skb = NULL; - lp->fbl_count--; - pci_unmap_single(lp->pci_dev, - lp->rx_skbs[cur_bd].skb_dma, - RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (!HAVE_DMA_RXALIGN(lp)) - memmove(skb->data, skb->data - 2, pkt_len); - data = skb_put(skb, pkt_len); -#endif /* TC35815_USE_PACKEDBUFFER */ - if (netif_msg_pktdata(lp)) + if (tc35815_debug > 3) print_eth(data); skb->protocol = eth_type_trans(skb, dev); -#ifdef TC35815_NAPI - netif_receive_skb(skb); - received++; -#else netif_rx(skb); -#endif - dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; } else { lp->stats.rx_errors++; - printk(KERN_DEBUG "%s: Rx error (status %x)\n", - dev->name, status & Rx_Stat_Mask); /* WORKAROUND: LongErr and CRCErr means Overflow. */ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { status &= ~(Rx_LongErr|Rx_CRCErr); @@ -1581,150 +1190,63 @@ tc35815_rx(struct net_device *dev) int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); unsigned char id = (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; -#ifdef DEBUG - if (id >= RX_BUF_NUM) { + if (id >= RX_BUF_PAGES) { printk("%s: invalid BDID.\n", dev->name); panic_queues(dev); } -#else - BUG_ON(id >= RX_BUF_NUM); -#endif /* free old buffers */ -#ifdef TC35815_USE_PACKEDBUFFER - while (lp->fbl_curid != id) -#else - while (lp->fbl_count < RX_BUF_NUM) -#endif - { -#ifdef TC35815_USE_PACKEDBUFFER - unsigned char curid = lp->fbl_curid; -#else - unsigned char curid = - (id + 1 + lp->fbl_count) % RX_BUF_NUM; -#endif - struct BDesc *bd = &lp->fbl_ptr->bd[curid]; -#ifdef DEBUG - bdctl = le32_to_cpu(bd->BDCtl); + while (lp->fbl_curid != id) { + bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl); if (bdctl & BD_CownsBD) { printk("%s: Freeing invalid BD.\n", dev->name); panic_queues(dev); } -#endif /* pass BD to controler */ -#ifndef TC35815_USE_PACKEDBUFFER - if (!lp->rx_skbs[curid].skb) { - lp->rx_skbs[curid].skb = - alloc_rxbuf_skb(dev, - lp->pci_dev, - &lp->rx_skbs[curid].skb_dma); - if (!lp->rx_skbs[curid].skb) - break; /* try on next reception */ - bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma); - } -#endif /* TC35815_USE_PACKEDBUFFER */ /* Note: BDLength was modified by chip. */ - bd->BDCtl = cpu_to_le32(BD_CownsBD | - (curid << BD_RxBDID_SHIFT) | - RX_BUF_SIZE); -#ifdef TC35815_USE_PACKEDBUFFER - lp->fbl_curid = (curid + 1) % RX_BUF_NUM; - if (netif_msg_rx_status(lp)) { + lp->fbl_ptr->bd[lp->fbl_curid].BDCtl = + cpu_to_le32(BD_CownsBD | + (lp->fbl_curid << BD_RxBDID_SHIFT) | + PAGE_SIZE); + lp->fbl_curid = + (lp->fbl_curid + 1) % RX_BUF_PAGES; + if (tc35815_debug > 2) { printk("%s: Entering new FBD %d\n", dev->name, lp->fbl_curid); dump_frfd(lp->fbl_ptr); } -#else - lp->fbl_count++; -#endif buf_free_count++; } } /* put RxFD back to controller */ -#ifdef DEBUG - next_rfd = fd_bus_to_virt(lp, - le32_to_cpu(lp->rfd_cur->fd.FDNext)); + next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext)); +#ifdef __mips__ + next_rfd = (struct RxFD *)vtonocache(next_rfd); +#endif if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { printk("%s: RxFD FDNext invalid.\n", dev->name); panic_queues(dev); } -#endif for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { /* pass FD to controler */ -#ifdef DEBUG - lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); -#else - lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL); -#endif + lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */ lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); lp->rfd_cur++; fd_free_count++; } - if (lp->rfd_cur > lp->rfd_limit) - lp->rfd_cur = lp->rfd_base; -#ifdef DEBUG - if (lp->rfd_cur != next_rfd) - printk("rfd_cur = %p, next_rfd %p\n", - lp->rfd_cur, next_rfd); -#endif + + lp->rfd_cur = next_rfd; } /* re-enable BL/FDA Exhaust interrupts. */ if (fd_free_count) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 en, en_old = tc_readl(&tr->Int_En); - en = en_old | Int_FDAExEn; + tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En); if (buf_free_count) - en |= Int_BLExEn; - if (en != en_old) - tc_writel(en, &tr->Int_En); + tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En); } -#ifdef TC35815_NAPI - return received; -#endif } -#ifdef TC35815_NAPI -static int -tc35815_poll(struct net_device *dev, int *budget) -{ - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int limit = min(*budget, dev->quota); - int received = 0, handled; - u32 status; - - spin_lock(&lp->lock); - status = tc_readl(&tr->Int_Src); - do { - tc_writel(status, &tr->Int_Src); /* write to clear */ - - handled = tc35815_do_interrupt(dev, status, limit); - if (handled >= 0) { - received += handled; - limit -= handled; - if (limit <= 0) - break; - } - status = tc_readl(&tr->Int_Src); - } while (status); - spin_unlock(&lp->lock); - - dev->quota -= received; - *budget -= received; - if (limit <= 0) - return 1; - - netif_rx_complete(dev); - /* enable interrupts */ - tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); - return 0; -} -#endif - #ifdef NO_CHECK_CARRIER #define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) #else @@ -1743,17 +1265,9 @@ tc35815_check_tx_stat(struct net_device *dev, int status) if (status & Tx_TxColl_MASK) lp->stats.collisions += status & Tx_TxColl_MASK; -#ifndef NO_CHECK_CARRIER - /* TX4939 does not have NCarr */ - if (lp->boardtype == TC35815_TX4939) - status &= ~Tx_NCarr; -#ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if ((lp->timer_state != asleep && lp->timer_state != lcheck) - || lp->fullduplex) + if (lp->fullduplex) status &= ~Tx_NCarr; -#endif -#endif if (!(status & TX_STA_ERR)) { /* no error. */ @@ -1769,15 +1283,6 @@ tc35815_check_tx_stat(struct net_device *dev, int status) if (status & Tx_Under) { lp->stats.tx_fifo_errors++; msg = "Tx FIFO Underrun."; - if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) { - lp->lstats.tx_underrun++; - if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh); - msg = "Tx FIFO Underrun.Change Tx threshold to max."; - } - } } if (status & Tx_Defer) { lp->stats.tx_fifo_errors++; @@ -1801,19 +1306,18 @@ tc35815_check_tx_stat(struct net_device *dev, int status) lp->stats.tx_heartbeat_errors++; msg = "Signal Quality Error."; } - if (msg && netif_msg_tx_err(lp)) + if (msg) printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); } -/* This handles TX complete events posted by the device - * via interrupts. - */ static void tc35815_txdone(struct net_device *dev) { struct tc35815_local *lp = dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; struct TxFD *txfd; unsigned int fdctl; + int num_done = 0; txfd = &lp->tfd_base[lp->tfd_end]; while (lp->tfd_start != lp->tfd_end && @@ -1821,61 +1325,38 @@ tc35815_txdone(struct net_device *dev) int status = le32_to_cpu(txfd->fd.FDStat); struct sk_buff *skb; unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); - u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem); - if (netif_msg_tx_done(lp)) { + if (tc35815_debug > 2) { printk("%s: complete TxFD.\n", dev->name); dump_txfd(txfd); } tc35815_check_tx_stat(dev, status); - skb = fdsystem != 0xffffffff ? - lp->tx_skbs[fdsystem].skb : NULL; -#ifdef DEBUG - if (lp->tx_skbs[lp->tfd_end].skb != skb) { - printk("%s: tx_skbs mismatch.\n", dev->name); - panic_queues(dev); - } -#else - BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb); -#endif + skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem); if (skb) { - lp->stats.tx_bytes += skb->len; - pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE); - lp->tx_skbs[lp->tfd_end].skb = NULL; - lp->tx_skbs[lp->tfd_end].skb_dma = 0; -#ifdef TC35815_NAPI dev_kfree_skb_any(skb); -#else - dev_kfree_skb_irq(skb); -#endif } - txfd->fd.FDSystem = cpu_to_le32(0xffffffff); + txfd->fd.FDSystem = cpu_to_le32(0); + num_done++; lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; txfd = &lp->tfd_base[lp->tfd_end]; -#ifdef DEBUG - if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) { + if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) { printk("%s: TxFD FDNext invalid.\n", dev->name); panic_queues(dev); } -#endif if (fdnext & FD_Next_EOL) { /* DMA Transmitter has been stopping... */ if (lp->tfd_end != lp->tfd_start) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; struct TxFD* txhead = &lp->tfd_base[head]; int qlen = (lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM; -#ifdef DEBUG if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { printk("%s: TxFD FDCtl invalid.\n", dev->name); panic_queues(dev); } -#endif /* log max queue length */ if (lp->lstats.max_tx_qlen < qlen) lp->lstats.max_tx_qlen = qlen; @@ -1886,23 +1367,21 @@ tc35815_txdone(struct net_device *dev) #ifdef GATHER_TXINT txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); #endif - if (netif_msg_tx_queued(lp)) { + if (tc35815_debug > 2) { printk("%s: start TxFD on queue.\n", dev->name); dump_txfd(txfd); } - tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); } break; } } - /* If we had stopped the queue due to a "tx full" - * condition, and space has now been made available, - * wake up the queue. - */ - if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev)) - netif_wake_queue(dev); + if (num_done > 0 && lp->tbusy) { + lp->tbusy = 0; + netif_start_queue(dev); + } } /* The inverse routine to tc35815_open(). */ @@ -1910,18 +1389,18 @@ static int tc35815_close(struct net_device *dev) { struct tc35815_local *lp = dev->priv; + + lp->tbusy = 1; netif_stop_queue(dev); /* Flush the Tx and disable Rx here. */ - del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); free_irq(dev->irq, dev); tc35815_free_queues(dev); return 0; - } /* @@ -1931,29 +1410,29 @@ tc35815_close(struct net_device *dev) static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned long flags; + if (netif_running(dev)) { + spin_lock_irqsave(&lp->lock, flags); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); + spin_unlock_irqrestore(&lp->lock, flags); } return &lp->stats; } -static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr) +static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr) { - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; int cam_index = index * 6; - u32 cam_data; - u32 saved_addr; + unsigned long cam_data; + unsigned long saved_addr; saved_addr = tc_readl(&tr->CAM_Adr); - if (netif_msg_hw(lp)) { + if (tc35815_debug > 1) { int i; - printk(KERN_DEBUG "%s: CAM %d:", dev->name, index); + printk(KERN_DEBUG "%s: CAM %d:", cardname, index); for (i = 0; i < 6; i++) printk(" %02x", addr[i]); printk("\n"); @@ -1980,6 +1459,14 @@ static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned ch tc_writel(cam_data, &tr->CAM_Data); } + if (tc35815_debug > 2) { + int i; + for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { + tc_writel(i * 4, &tr->CAM_Adr); + printk("CAM 0x%x: %08lx", + i * 4, tc_readl(&tr->CAM_Data)); + } + } tc_writel(saved_addr, &tr->CAM_Adr); } @@ -1994,19 +1481,10 @@ static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned ch static void tc35815_set_multicast_list(struct net_device *dev) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; if (dev->flags&IFF_PROMISC) { -#ifdef WORKAROUND_100HALF_PROMISC - /* With some (all?) 100MHalf HUB, controller will hang - * if we enabled promiscuous mode before linkup... */ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS)) - return; -#endif /* Enable promiscuous mode */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); } @@ -2028,7 +1506,7 @@ tc35815_set_multicast_list(struct net_device *dev) if (!cur_addr) break; /* entry 0,1 is reserved. */ - tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr); + tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr); ena_bits |= CAM_Ena_Bit(i + 2); } tc_writel(ena_bits, &tr->CAM_Ena); @@ -2040,753 +1518,122 @@ tc35815_set_multicast_list(struct net_device *dev) } } -static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct tc35815_local *lp = dev->priv; - strcpy(info->driver, MODNAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, pci_name(lp->pci_dev)); -} - -static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct tc35815_local *lp = dev->priv; - spin_lock_irq(&lp->lock); - mii_ethtool_gset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct tc35815_local *lp = dev->priv; - int rc; -#if 1 /* use our negotiation method... */ - /* Verify the settings we care about. */ - if (cmd->autoneg != AUTONEG_ENABLE && - cmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || - (cmd->duplex != DUPLEX_HALF && - cmd->duplex != DUPLEX_FULL))) - return -EINVAL; - - /* Ok, do it to it. */ - spin_lock_irq(&lp->lock); - del_timer(&lp->timer); - tc35815_start_auto_negotiation(dev, cmd); - spin_unlock_irq(&lp->lock); - rc = 0; -#else - spin_lock_irq(&lp->lock); - rc = mii_ethtool_sset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); -#endif - return rc; -} - -static int tc35815_nway_reset(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int rc; - spin_lock_irq(&lp->lock); - rc = mii_nway_restart(&lp->mii); - spin_unlock_irq(&lp->lock); - return rc; -} - -static u32 tc35815_get_link(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int rc; - spin_lock_irq(&lp->lock); - rc = mii_link_ok(&lp->mii); - spin_unlock_irq(&lp->lock); - return rc; -} - -static u32 tc35815_get_msglevel(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - return lp->msg_enable; -} - -static void tc35815_set_msglevel(struct net_device *dev, u32 datum) -{ - struct tc35815_local *lp = dev->priv; - lp->msg_enable = datum; -} - -static int tc35815_get_stats_count(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - return sizeof(lp->lstats) / sizeof(int); -} - -static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) +static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) { struct tc35815_local *lp = dev->priv; - data[0] = lp->lstats.max_tx_qlen; - data[1] = lp->lstats.tx_ints; - data[2] = lp->lstats.rx_ints; - data[3] = lp->lstats.tx_underrun; -} - -static struct { - const char str[ETH_GSTRING_LEN]; -} ethtool_stats_keys[] = { - { "max_tx_qlen" }, - { "tx_ints" }, - { "rx_ints" }, - { "tx_underrun" }, -}; - -static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); -} - -static const struct ethtool_ops tc35815_ethtool_ops = { - .get_drvinfo = tc35815_get_drvinfo, - .get_settings = tc35815_get_settings, - .set_settings = tc35815_set_settings, - .nway_reset = tc35815_nway_reset, - .get_link = tc35815_get_link, - .get_msglevel = tc35815_get_msglevel, - .set_msglevel = tc35815_set_msglevel, - .get_strings = tc35815_get_strings, - .get_stats_count = tc35815_get_stats_count, - .get_ethtool_stats = tc35815_get_ethtool_stats, - .get_perm_addr = ethtool_op_get_perm_addr, -}; - -static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct tc35815_local *lp = dev->priv; - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irq(&lp->lock); - rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&lp->lock); + unsigned long data; + unsigned long flags; - return rc; -} + spin_lock_irqsave(&lp->lock, flags); -static int tc_mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 data; - tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA); + tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA); while (tc_readl(&tr->MD_CA) & MD_CA_Busy) ; data = tc_readl(&tr->MD_Data); - return data & 0xffff; -} - -static void tc_mdio_write(struct net_device *dev, int phy_id, int location, - int val) -{ - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - tc_writel(val, &tr->MD_Data); - tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA); - while (tc_readl(&tr->MD_CA) & MD_CA_Busy) - ; -} - -/* Auto negotiation. The scheme is very simple. We have a timer routine - * that keeps watching the auto negotiation process as it progresses. - * The DP83840 is first told to start doing it's thing, we set up the time - * and place the timer state machine in it's initial state. - * - * Here the timer peeks at the DP83840 status registers at each click to see - * if the auto negotiation has completed, we assume here that the DP83840 PHY - * will time out at some point and just tell us what (didn't) happen. For - * complete coverage we only allow so many of the ticks at this level to run, - * when this has expired we print a warning message and try another strategy. - * This "other" strategy is to force the interface into various speed/duplex - * configurations and we stop when we see a link-up condition before the - * maximum number of "peek" ticks have occurred. - * - * Once a valid link status has been detected we configure the BigMAC and - * the rest of the Happy Meal to speak the most efficient protocol we could - * get a clean link for. The priority for link configurations, highest first - * is: - * 100 Base-T Full Duplex - * 100 Base-T Half Duplex - * 10 Base-T Full Duplex - * 10 Base-T Half Duplex - * - * We start a new timer now, after a successful auto negotiation status has - * been detected. This timer just waits for the link-up bit to get set in - * the BMCR of the DP83840. When this occurs we print a kernel log message - * describing the link type in use and the fact that it is up. - * - * If a fatal error of some sort is signalled and detected in the interrupt - * service routine, and the chip is reset, or the link is ifconfig'd down - * and then back up, this entire process repeats itself all over again. - */ -/* Note: Above comments are come from sunhme driver. */ - -static int tc35815_try_next_permutation(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - - /* Downgrade from full to half duplex. Only possible via ethtool. */ - if (bmcr & BMCR_FULLDPLX) { - bmcr &= ~BMCR_FULLDPLX; - printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - return 0; - } - - /* Downgrade from 100 to 10. */ - if (bmcr & BMCR_SPEED100) { - bmcr &= ~BMCR_SPEED100; - printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - return 0; - } - - /* We've tried everything. */ - return -1; -} - -static void -tc35815_display_link_mode(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short lpa, bmcr; - char *speed = "", *duplex = ""; - - lpa = tc_mdio_read(dev, pid, MII_LPA); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) - speed = "100Mb/s"; - else - speed = "10Mb/s"; - if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) - duplex = "Full Duplex"; - else - duplex = "Half Duplex"; - - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Link is up at %s, %s.\n", - dev->name, speed, duplex); - printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); -} - -static void tc35815_display_forced_link_mode(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - char *speed = "", *duplex = ""; - - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_SPEED100) - speed = "100Mb/s"; - else - speed = "10Mb/s"; - if (bmcr & BMCR_FULLDPLX) - duplex = "Full Duplex.\n"; - else - duplex = "Half Duplex.\n"; - - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Link has been forced up at %s, %s", - dev->name, speed, duplex); + spin_unlock_irqrestore(&lp->lock, flags); + return data; } -static void tc35815_set_link_modes(struct net_device *dev) +static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int pid = lp->phy_addr; - unsigned short bmcr, lpa; - int speed; - - if (lp->timer_state == arbwait) { - lpa = tc_mdio_read(dev, pid, MII_LPA); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); - if (!(lpa & (LPA_10HALF | LPA_10FULL | - LPA_100HALF | LPA_100FULL))) { - /* fall back to 10HALF */ - printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n", - dev->name, lpa); - lpa = LPA_10HALF; - } - if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) - lp->fullduplex = 1; - else - lp->fullduplex = 0; - if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) - speed = 100; - else - speed = 10; - } else { - /* Forcing a link mode. */ - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_FULLDPLX) - lp->fullduplex = 1; - else - lp->fullduplex = 0; - if (bmcr & BMCR_SPEED100) - speed = 100; - else - speed = 10; - } - - tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl); - if (lp->fullduplex) { - tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); - } else { - tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl); - } - tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl); + unsigned long flags; - /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */ + spin_lock_irqsave(&lp->lock, flags); -#ifndef NO_CHECK_CARRIER - /* TX4939 does not have EnLCarr */ - if (lp->boardtype != TC35815_TX4939) { -#ifdef WORKAROUND_LOSTCAR - /* WORKAROUND: enable LostCrS only if half duplex operation */ - if (!lp->fullduplex && lp->boardtype != TC35815_TX4939) - tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl); -#endif - } -#endif - lp->mii.full_duplex = lp->fullduplex; + tc_writel(d, &tr->MD_Data); + tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + ; + spin_unlock_irqrestore(&lp->lock, flags); } -static void tc35815_timer(unsigned long data) +static void tc35815_phy_chip_init(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmsr, bmcr, lpa; - int restart_timer = 0; - - spin_lock_irq(&lp->lock); - - lp->timer_ticks++; - switch (lp->timer_state) { - case arbwait: - /* - * Only allow for 5 ticks, thats 10 seconds and much too - * long to wait for arbitration to complete. - */ - /* TC35815 need more times... */ - if (lp->timer_ticks >= 10) { - /* Enter force mode. */ - if (!options.doforce) { - printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," - " cable probblem?\n", dev->name); - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; - } - printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," - " trying force link mode\n", dev->name); - printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name, - tc_mdio_read(dev, pid, MII_BMCR), - tc_mdio_read(dev, pid, MII_BMSR)); - bmcr = BMCR_SPEED100; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* - * OK, seems we need do disable the transceiver - * for the first tick to make sure we get an - * accurate link state at the second tick. - */ - - lp->timer_state = ltrywait; - lp->timer_ticks = 0; - restart_timer = 1; - } else { - /* Anything interesting happen? */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - if (bmsr & BMSR_ANEGCOMPLETE) { - /* Just what we've been waiting for... */ - tc35815_set_link_modes(dev); - - /* - * Success, at least so far, advance our state - * engine. - */ - lp->timer_state = lupwait; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case lupwait: - /* - * Auto negotiation was successful and we are awaiting a - * link up status. I have decided to let this timer run - * forever until some sort of error is signalled, reporting - * a message to the user at 10 second intervals. - */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - if (bmsr & BMSR_LSTATUS) { - /* - * Wheee, it's up, display the link mode in use and put - * the timer to sleep. - */ - tc35815_display_link_mode(dev); - netif_carrier_on(dev); -#ifdef WORKAROUND_100HALF_PROMISC - /* delayed promiscuous enabling */ - if (dev->flags & IFF_PROMISC) - tc35815_set_multicast_list(dev); -#endif -#if 1 - lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); - lp->timer_state = lcheck; - restart_timer = 1; -#else - lp->timer_state = asleep; - restart_timer = 0; -#endif - } else { - if (lp->timer_ticks >= 10) { - printk(KERN_NOTICE "%s: Auto negotiation successful, link still " - "not completely up.\n", dev->name); - lp->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case ltrywait: - /* - * Making the timeout here too long can make it take - * annoyingly long to attempt all of the link mode - * permutations, but then again this is essentially - * error recovery code for the most part. - */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (lp->timer_ticks == 1) { - /* - * Re-enable transceiver, we'll re-enable the - * transceiver next tick, then check link state - * on the following tick. - */ - restart_timer = 1; - break; - } - if (lp->timer_ticks == 2) { - restart_timer = 1; - break; - } - if (bmsr & BMSR_LSTATUS) { - /* Force mode selection success. */ - tc35815_display_forced_link_mode(dev); - netif_carrier_on(dev); - tc35815_set_link_modes(dev); -#ifdef WORKAROUND_100HALF_PROMISC - /* delayed promiscuous enabling */ - if (dev->flags & IFF_PROMISC) - tc35815_set_multicast_list(dev); -#endif -#if 1 - lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); - lp->timer_state = lcheck; - restart_timer = 1; -#else - lp->timer_state = asleep; - restart_timer = 0; -#endif + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + static int first = 1; + unsigned short ctl; + + if (first) { + unsigned short id0, id1; + int count; + first = 0; + + /* first data written to the PHY will be an ID number */ + tc_phy_write(dev, 0, tr, 0, MII_CONTROL); /* ID:0 */ +#if 0 + tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Resetting PHY...", dev->name); + while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET) + ; + printk("\n"); + tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0, + MII_CONTROL); +#endif + id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0); + id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1); + printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name, + id0, id1); + if (lp->option & TC35815_OPT_10M) { + lp->linkspeed = 10; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + } else if (lp->option & TC35815_OPT_100M) { + lp->linkspeed = 100; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; } else { - if (lp->timer_ticks >= 4) { /* 6 seconds or so... */ - int ret; - - ret = tc35815_try_next_permutation(dev); - if (ret == -1) { - /* - * Aieee, tried them all, reset the - * chip and try all over again. - */ - printk(KERN_NOTICE "%s: Link down, " - "cable problem?\n", - dev->name); - - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; + /* auto negotiation */ + unsigned long neg_result; + tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Auto Negotiation...", dev->name); + count = 0; + while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) { + if (count++ > 5000) { + printk(" failed. Assume 10Mbps\n"); + lp->linkspeed = 10; + lp->fullduplex = 0; + goto done; } - lp->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; + if (count % 512 == 0) + printk("."); + mdelay(1); } - } - break; - - case lcheck: - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - lpa = tc_mdio_read(dev, pid, MII_LPA); - if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) { - printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name, - bmcr); - } else if ((lp->saved_lpa ^ lpa) & - (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) { - printk(KERN_NOTICE "%s: link status changed" - " (BMCR %x LPA %x->%x)\n", dev->name, - bmcr, lp->saved_lpa, lpa); - } else { - /* go on */ - restart_timer = 1; - break; - } - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; - - case asleep: - default: - /* Can't happens.... */ - printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " - "one anyways!\n", dev->name); - restart_timer = 0; - lp->timer_ticks = 0; - lp->timer_state = asleep; /* foo on you */ - break; - } - - if (restart_timer) { - lp->timer.expires = jiffies + msecs_to_jiffies(1200); - add_timer(&lp->timer); - } -out: - spin_unlock_irq(&lp->lock); -} - -static void tc35815_start_auto_negotiation(struct net_device *dev, - struct ethtool_cmd *ep) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmsr, bmcr, advertize; - int timeout; - - netif_carrier_off(dev); - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - advertize = tc_mdio_read(dev, pid, MII_ADVERTISE); - - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - if (options.speed || options.duplex) { - /* Advertise only specified configuration. */ - advertize &= ~(ADVERTISE_10HALF | - ADVERTISE_10FULL | - ADVERTISE_100HALF | - ADVERTISE_100FULL); - if (options.speed != 10) { - if (options.duplex != 1) - advertize |= ADVERTISE_100FULL; - if (options.duplex != 2) - advertize |= ADVERTISE_100HALF; - } - if (options.speed != 100) { - if (options.duplex != 1) - advertize |= ADVERTISE_10FULL; - if (options.duplex != 2) - advertize |= ADVERTISE_10HALF; - } - if (options.speed == 100) - bmcr |= BMCR_SPEED100; - else if (options.speed == 10) - bmcr &= ~BMCR_SPEED100; - if (options.duplex == 2) - bmcr |= BMCR_FULLDPLX; - else if (options.duplex == 1) - bmcr &= ~BMCR_FULLDPLX; - } else { - /* Advertise everything we can support. */ - if (bmsr & BMSR_10HALF) - advertize |= ADVERTISE_10HALF; - else - advertize &= ~ADVERTISE_10HALF; - if (bmsr & BMSR_10FULL) - advertize |= ADVERTISE_10FULL; - else - advertize &= ~ADVERTISE_10FULL; - if (bmsr & BMSR_100HALF) - advertize |= ADVERTISE_100HALF; - else - advertize &= ~ADVERTISE_100HALF; - if (bmsr & BMSR_100FULL) - advertize |= ADVERTISE_100FULL; + printk(" done.\n"); + neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR); + if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX)) + lp->linkspeed = 100; else - advertize &= ~ADVERTISE_100FULL; - } - - tc_mdio_write(dev, pid, MII_ADVERTISE, advertize); - - /* Enable Auto-Negotiation, this is usually on already... */ - bmcr |= BMCR_ANENABLE; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* Restart it to make sure it is going. */ - bmcr |= BMCR_ANRESTART; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr); - - /* BMCR_ANRESTART self clears when the process has begun. */ - timeout = 64; /* More than enough. */ - while (--timeout) { - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (!(bmcr & BMCR_ANRESTART)) - break; /* got it. */ - udelay(10); - } - if (!timeout) { - printk(KERN_ERR "%s: TC35815 would not start auto " - "negotiation BMCR=0x%04x\n", - dev->name, bmcr); - printk(KERN_NOTICE "%s: Performing force link " - "detection.\n", dev->name); - goto force_link; - } else { - printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name); - lp->timer_state = arbwait; - } - } else { -force_link: - /* Force the link up, trying first a particular mode. - * Either we are here at the request of ethtool or - * because the Happy Meal would not start to autoneg. - */ - - /* Disable auto-negotiation in BMCR, enable the duplex and - * speed setting, init the timer state machine, and fire it off. - */ - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - bmcr = BMCR_SPEED100; - } else { - if (ep->speed == SPEED_100) - bmcr = BMCR_SPEED100; + lp->linkspeed = 10; + if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX)) + lp->fullduplex = 1; else - bmcr = 0; - if (ep->duplex == DUPLEX_FULL) - bmcr |= BMCR_FULLDPLX; - } - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* OK, seems we need do disable the transceiver for the first - * tick to make sure we get an accurate link state at the - * second tick. - */ - lp->timer_state = ltrywait; - } - - del_timer(&lp->timer); - lp->timer_ticks = 0; - lp->timer.expires = jiffies + msecs_to_jiffies(1200); - add_timer(&lp->timer); -} - -static void tc35815_find_phy(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short id0; - - /* find MII phy */ - for (pid = 31; pid >= 0; pid--) { - id0 = tc_mdio_read(dev, pid, MII_BMSR); - if (id0 != 0xffff && id0 != 0x0000 && - (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */ - ) { - lp->phy_addr = pid; - break; + lp->fullduplex = 0; + done: + ; } } - if (pid < 0) { - printk(KERN_ERR "%s: No MII Phy found.\n", - dev->name); - lp->phy_addr = pid = 0; - } - lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1); - lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2); - if (netif_msg_hw(lp)) - printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name, - pid, lp->mii_id[0], lp->mii_id[1]); -} + ctl = 0; + if (lp->linkspeed == 100) + ctl |= MIICNTL_SPEED; + if (lp->fullduplex) + ctl |= MIICNTL_FDX; + tc_phy_write(dev, ctl, tr, 0, MII_CONTROL); -static void tc35815_phy_chip_init(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - struct ethtool_cmd ecmd, *ep; - - /* dis-isolate if needed. */ - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_ISOLATE) { - int count = 32; - printk(KERN_DEBUG "%s: unisolating...", dev->name); - tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE); - while (--count) { - if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE)) - break; - udelay(20); - } - printk(" %s.\n", count ? "done" : "failed"); - } - - if (options.speed && options.duplex) { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100; - ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL; - ep = &ecmd; - } else { - ep = NULL; + if (lp->fullduplex) { + tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); } - tc35815_start_auto_negotiation(dev, ep); } static void tc35815_chip_reset(struct net_device *dev) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int i; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + /* reset the controller */ tc_writel(MAC_Reset, &tr->MAC_Ctl); - udelay(4); /* 3200ns */ - i = 0; - while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) { - if (i++ > 100) { - printk(KERN_ERR "%s: MAC reset failed.\n", dev->name); - break; - } - mdelay(1); - } + while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) + ; + tc_writel(0, &tr->MAC_Ctl); /* initialize registers to default value */ @@ -2804,142 +1651,90 @@ static void tc35815_chip_reset(struct net_device *dev) tc_writel(0, &tr->CAM_Ena); (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ - /* initialize internal SRAM */ - tc_writel(DMA_TestMode, &tr->DMA_Ctl); - for (i = 0; i < 0x1000; i += 4) { - tc_writel(i, &tr->CAM_Adr); - tc_writel(0, &tr->CAM_Data); - } - tc_writel(0, &tr->DMA_Ctl); } static void tc35815_chip_init(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned long flags; unsigned long txctl = TX_CTL_CMD; tc35815_phy_chip_init(dev); /* load station address to CAM */ - tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr); + tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr); /* Enable CAM (broadcast and unicast) */ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); - /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */ - if (HAVE_DMA_RXALIGN(lp)) - tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl); - else - tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); -#ifdef TC35815_USE_PACKEDBUFFER + spin_lock_irqsave(&lp->lock, flags); + + tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); + tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ -#else - tc_writel(ETH_ZLEN, &tr->RxFragSize); -#endif tc_writel(0, &tr->TxPollCtr); /* Batch mode */ tc_writel(TX_THRESHOLD, &tr->TxThrsh); tc_writel(INT_EN_CMD, &tr->Int_En); /* set queues */ - tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas); + tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas); tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, &tr->FDA_Lim); /* * Activation method: - * First, enable the MAC Transmitter and the DMA Receive circuits. + * First, enable eht MAC Transmitter and the DMA Receive circuits. * Then enable the DMA Transmitter and the MAC Receive circuits. */ - tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ + tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ - /* start MAC transmitter */ -#ifndef NO_CHECK_CARRIER - /* TX4939 does not have EnLCarr */ - if (lp->boardtype == TC35815_TX4939) - txctl &= ~Tx_EnLCarr; -#ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if ((lp->timer_state != asleep && lp->timer_state != lcheck) || - lp->fullduplex) - txctl &= ~Tx_EnLCarr; -#endif -#endif /* !NO_CHECK_CARRIER */ + if (lp->fullduplex) + txctl = TX_CTL_CMD & ~Tx_EnLCarr; #ifdef GATHER_TXINT txctl &= ~Tx_EnComp; /* disable global tx completion int. */ #endif tc_writel(txctl, &tr->Tx_Ctl); -} - -#ifdef CONFIG_PM -static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct tc35815_local *lp = dev->priv; - unsigned long flags; - - pci_save_state(pdev); - if (!netif_running(dev)) - return 0; - netif_device_detach(dev); - spin_lock_irqsave(&lp->lock, flags); - del_timer(&lp->timer); /* Kill if running */ - tc35815_chip_reset(dev); +#if 0 /* No need to polling */ + tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ +#endif spin_unlock_irqrestore(&lp->lock, flags); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } -static int tc35815_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct tc35815_local *lp = dev->priv; - unsigned long flags; - - pci_restore_state(pdev); - if (!netif_running(dev)) - return 0; - pci_set_power_state(pdev, PCI_D0); - spin_lock_irqsave(&lp->lock, flags); - tc35815_restart(dev); - spin_unlock_irqrestore(&lp->lock, flags); - netif_device_attach(dev); - return 0; -} -#endif /* CONFIG_PM */ - -static struct pci_driver tc35815_pci_driver = { - .name = MODNAME, - .id_table = tc35815_pci_tbl, - .probe = tc35815_init_one, - .remove = __devexit_p(tc35815_remove_one), -#ifdef CONFIG_PM - .suspend = tc35815_suspend, - .resume = tc35815_resume, -#endif +static struct pci_driver tc35815_driver = { + .name = TC35815_MODULE_NAME, + .probe = tc35815_probe, + .remove = NULL, + .id_table = tc35815_pci_tbl, }; -module_param_named(speed, options.speed, int, 0); -MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps"); -module_param_named(duplex, options.duplex, int, 0); -MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full"); -module_param_named(doforce, options.doforce, int, 0); -MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed"); - static int __init tc35815_init_module(void) { - return pci_register_driver(&tc35815_pci_driver); + return pci_register_driver(&tc35815_driver); } static void __exit tc35815_cleanup_module(void) { - pci_unregister_driver(&tc35815_pci_driver); + struct net_device *next_dev; + + /* + * TODO: implement a tc35815_driver.remove hook, and + * move this code into that function. Then, delete + * all root_tc35815_dev list handling code. + */ + while (root_tc35815_dev) { + struct net_device *dev = root_tc35815_dev; + next_dev = ((struct tc35815_local *)dev->priv)->next_module; + iounmap((void *)(dev->base_addr)); + unregister_netdev(dev); + free_netdev(dev); + root_tc35815_dev = next_dev; + } + + pci_unregister_driver(&tc35815_driver); } module_init(tc35815_init_module); module_exit(tc35815_cleanup_module); - -MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c index 59d6e74a4a5f..256969e1300c 100644 --- a/trunk/drivers/net/tg3.c +++ b/trunk/drivers/net/tg3.c @@ -40,16 +40,16 @@ #include #include -#include #include #include #include #include -#ifdef CONFIG_SPARC +#ifdef CONFIG_SPARC64 #include -#include +#include +#include #endif #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) @@ -1300,11 +1300,9 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) msleep(1); } } - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) - tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | - WOL_DRV_STATE_SHUTDOWN | - WOL_DRV_WOL | - WOL_SET_MAGIC_PKT); + tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | + WOL_DRV_STATE_SHUTDOWN | + WOL_DRV_WOL | WOL_SET_MAGIC_PKT); pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); @@ -2595,8 +2593,10 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) { int current_link_up = 0; - if (!(mac_status & MAC_STATUS_PCS_SYNCED)) + if (!(mac_status & MAC_STATUS_PCS_SYNCED)) { + tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL; goto out; + } if (tp->link_config.autoneg == AUTONEG_ENABLE) { u32 flags; @@ -2614,6 +2614,7 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) tg3_setup_flow_control(tp, local_adv, remote_adv); + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; current_link_up = 1; } for (i = 0; i < 30; i++) { @@ -2636,6 +2637,7 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) } else { /* Forcing 1000FD link up. */ current_link_up = 1; + tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL; tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS)); udelay(40); @@ -3347,7 +3349,7 @@ static int tg3_rx(struct tg3 *tp, int budget) skb_reserve(copy_skb, 2); skb_put(copy_skb, len); pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, copy_skb->data, len); + memcpy(copy_skb->data, skb->data, len); pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ @@ -3893,7 +3895,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) entry = tp->tx_prod; base_flags = 0; mss = 0; - if ((mss = skb_shinfo(skb)->gso_size) != 0) { + if (skb->len > (tp->dev->mtu + ETH_HLEN) && + (mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len; if (skb_header_cloned(skb) && @@ -3905,20 +3908,20 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) mss |= (skb_headlen(skb) - ETH_HLEN) << 9; else { - struct iphdr *iph = ip_hdr(skb); - - tcp_opt_len = tcp_optlen(skb); - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); + tcp_opt_len = ((skb->h.th->doff - 5) * 4); + ip_tcp_len = (skb->nh.iph->ihl * 4) + + sizeof(struct tcphdr); - iph->check = 0; - iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); + skb->nh.iph->check = 0; + skb->nh.iph->tot_len = htons(mss + ip_tcp_len + + tcp_opt_len); mss |= (ip_tcp_len + tcp_opt_len) << 9; } base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); - tcp_hdr(skb)->check = 0; + skb->h.th->check = 0; } else if (skb->ip_summed == CHECKSUM_PARTIAL) @@ -4050,8 +4053,8 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; mss = 0; - if ((mss = skb_shinfo(skb)->gso_size) != 0) { - struct iphdr *iph; + if (skb->len > (tp->dev->mtu + ETH_HLEN) && + (mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len, hdr_len; if (skb_header_cloned(skb) && @@ -4060,8 +4063,8 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) goto out_unlock; } - tcp_opt_len = tcp_optlen(skb); - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); + tcp_opt_len = ((skb->h.th->doff - 5) * 4); + ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); hdr_len = ip_tcp_len + tcp_opt_len; if (unlikely((ETH_HLEN + hdr_len) > 80) && @@ -4071,31 +4074,34 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); - iph = ip_hdr(skb); - iph->check = 0; - iph->tot_len = htons(mss + hdr_len); + skb->nh.iph->check = 0; + skb->nh.iph->tot_len = htons(mss + hdr_len); if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { - tcp_hdr(skb)->check = 0; + skb->h.th->check = 0; base_flags &= ~TXD_FLAG_TCPUDP_CSUM; - } else - tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, - iph->daddr, 0, - IPPROTO_TCP, - 0); + } + else { + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, IPPROTO_TCP, 0); + } if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) { - if (tcp_opt_len || iph->ihl > 5) { + if (tcp_opt_len || skb->nh.iph->ihl > 5) { int tsflags; - tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2); + tsflags = ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)); mss |= (tsflags << 11); } } else { - if (tcp_opt_len || iph->ihl > 5) { + if (tcp_opt_len || skb->nh.iph->ihl > 5) { int tsflags; - tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2); + tsflags = ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)); base_flags |= tsflags << 12; } } @@ -5930,7 +5936,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp) /* tp->lock is held. */ -static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) +static void __tg3_set_mac_addr(struct tg3 *tp) { u32 addr_high, addr_low; int i; @@ -5942,8 +5948,6 @@ static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) (tp->dev->dev_addr[4] << 8) | (tp->dev->dev_addr[5] << 0)); for (i = 0; i < 4; i++) { - if (i == 1 && skip_mac_1) - continue; tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); } @@ -5970,7 +5974,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) { struct tg3 *tp = netdev_priv(dev); struct sockaddr *addr = p; - int err = 0, skip_mac_1 = 0; + int err = 0; if (!is_valid_ether_addr(addr->sa_data)) return -EINVAL; @@ -5981,21 +5985,22 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) return 0; if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { - u32 addr0_high, addr0_low, addr1_high, addr1_low; - - addr0_high = tr32(MAC_ADDR_0_HIGH); - addr0_low = tr32(MAC_ADDR_0_LOW); - addr1_high = tr32(MAC_ADDR_1_HIGH); - addr1_low = tr32(MAC_ADDR_1_LOW); + /* Reset chip so that ASF can re-init any MAC addresses it + * needs. + */ + tg3_netif_stop(tp); + tg3_full_lock(tp, 1); - /* Skip MAC addr 1 if ASF is using it. */ - if ((addr0_high != addr1_high || addr0_low != addr1_low) && - !(addr1_high == 0 && addr1_low == 0)) - skip_mac_1 = 1; + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + err = tg3_restart_hw(tp, 0); + if (!err) + tg3_netif_start(tp); + tg3_full_unlock(tp); + } else { + spin_lock_bh(&tp->lock); + __tg3_set_mac_addr(tp); + spin_unlock_bh(&tp->lock); } - spin_lock_bh(&tp->lock); - __tg3_set_mac_addr(tp, skip_mac_1); - spin_unlock_bh(&tp->lock); return err; } @@ -6312,7 +6317,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_jumbo_ptr); /* Initialize MAC address and backoff seed. */ - __tg3_set_mac_addr(tp, 0); + __tg3_set_mac_addr(tp); /* MTU + ethernet header + FCS + optional VLAN tag */ tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8); @@ -6343,7 +6348,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) { if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { + (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || + tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128; } else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) && !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) { @@ -6453,7 +6459,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL; - tp->grc_local_ctrl &= ~gpio_mask; tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ @@ -7033,7 +7038,11 @@ static int tg3_open(struct net_device *dev) if (err) return err; - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { + if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && + (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) && + (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) && + !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) && + (tp->pdev_peer == tp->pdev))) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ @@ -7392,7 +7401,9 @@ static int tg3_close(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tp->tg3_flags &= + ~(TG3_FLAG_INIT_COMPLETE | + TG3_FLAG_GOT_SERDES_FLOWCTL); tg3_full_unlock(tp); @@ -8027,10 +8038,7 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) - wol->supported = WAKE_MAGIC; - else - wol->supported = 0; + wol->supported = WAKE_MAGIC; wol->wolopts = 0; if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) wol->wolopts = WAKE_MAGIC; @@ -8044,7 +8052,8 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - !(tp->tg3_flags & TG3_FLAG_WOL_CAP)) + tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && + !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) return -EINVAL; spin_lock_bh(&tp->lock); @@ -9282,7 +9291,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) return; } } - tp->nvram_size = 0x80000; + tp->nvram_size = 0x20000; } static void __devinit tg3_get_nvram_info(struct tg3 *tp) @@ -9401,31 +9410,33 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) { - u32 nvcfg1, protect = 0; + u32 nvcfg1; nvcfg1 = tr32(NVRAM_CFG1); /* NVRAM protection for TPM */ - if (nvcfg1 & (1 << 27)) { + if (nvcfg1 & (1 << 27)) tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; - protect = 1; - } - nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; - switch (nvcfg1) { + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: case FLASH_5755VENDOR_ATMEL_FLASH_1: case FLASH_5755VENDOR_ATMEL_FLASH_2: case FLASH_5755VENDOR_ATMEL_FLASH_3: + case FLASH_5755VENDOR_ATMEL_FLASH_4: tp->nvram_jedecnum = JEDEC_ATMEL; tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; tp->tg3_flags2 |= TG3_FLG2_FLASH; tp->nvram_pagesize = 264; - if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1) - tp->nvram_size = (protect ? 0x3e200 : 0x80000); - else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2) - tp->nvram_size = (protect ? 0x1f200 : 0x40000); - else - tp->nvram_size = (protect ? 0x1f200 : 0x20000); break; case FLASH_5752VENDOR_ST_M45PE10: case FLASH_5752VENDOR_ST_M45PE20: @@ -9434,12 +9445,6 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; tp->tg3_flags2 |= TG3_FLG2_FLASH; tp->nvram_pagesize = 256; - if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) - tp->nvram_size = (protect ? 0x10000 : 0x20000); - else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20) - tp->nvram_size = (protect ? 0x10000 : 0x40000); - else - tp->nvram_size = (protect ? 0x20000 : 0x80000); break; } } @@ -9515,8 +9520,6 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) } tg3_enable_nvram_access(tp); - tp->nvram_size = 0; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tg3_get_5752_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) @@ -9528,8 +9531,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else tg3_get_nvram_info(tp); - if (tp->nvram_size == 0) - tg3_get_nvram_size(tp); + tg3_get_nvram_size(tp); tg3_disable_nvram_access(tp); tg3_nvram_unlock(tp); @@ -9996,8 +9998,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = PHY_ID_INVALID; tp->led_ctrl = LED_CTRL_MODE_PHY_1; - /* Assume an onboard device and WOL capable by default. */ - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP; + /* Assume an onboard device by default. */ + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) { @@ -10120,9 +10122,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } - if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && - !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) - tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL) + tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP; if (cfg2 & (1 << 17)) tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; @@ -10400,8 +10401,6 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) } } -static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); - static int __devinit tg3_get_invariants(struct tg3 *tp) { static struct pci_device_id write_reorder_chipsets[] = { @@ -10557,10 +10556,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff; tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) - tp->pdev_peer = tg3_find_peer(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -10574,14 +10569,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI; - if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX || - GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 && - tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 && - tp->pdev_peer == tp->pdev)) - tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { @@ -10683,6 +10670,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; + /* Back to back register writes can cause problems on this chip, + * the workaround is to read back all reg writes except those to + * mailbox regs. See tg3_write_indirect_reg32(). + * + * PCI Express 5750_A0 rev chips need this workaround too. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || + ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) + tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG; + if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) @@ -10706,19 +10704,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Various workaround register access methods */ if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) tp->write32 = tg3_write_indirect_reg32; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || - ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && - tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) { - /* - * Back to back register writes can cause problems on these - * chips, the workaround is to read back all reg writes - * except those to mailbox regs. - * - * See tg3_write_indirect_reg32(). - */ + else if (tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) tp->write32 = tg3_write_flush_reg32; - } - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { @@ -11001,20 +10988,24 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) return err; } -#ifdef CONFIG_SPARC +#ifdef CONFIG_SPARC64 static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp) { struct net_device *dev = tp->dev; struct pci_dev *pdev = tp->pdev; - struct device_node *dp = pci_device_to_OF_node(pdev); - const unsigned char *addr; - int len; - - addr = of_get_property(dp, "local-mac-address", &len); - if (addr && len == 6) { - memcpy(dev->dev_addr, addr, 6); - memcpy(dev->perm_addr, dev->dev_addr, 6); - return 0; + struct pcidev_cookie *pcp = pdev->sysdata; + + if (pcp != NULL) { + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, "local-mac-address", + &len); + if (addr && len == 6) { + memcpy(dev->dev_addr, addr, 6); + memcpy(dev->perm_addr, dev->dev_addr, 6); + return 0; + } } return -ENODEV; } @@ -11035,7 +11026,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) u32 hi, lo, mac_offset; int addr_ok = 0; -#ifdef CONFIG_SPARC +#ifdef CONFIG_SPARC64 if (!tg3_get_macaddr_sparc(tp)) return 0; #endif @@ -11907,6 +11898,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_pending = 63; } + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) + tp->pdev_peer = tg3_find_peer(tp); + err = tg3_get_device_address(tp); if (err) { printk(KERN_ERR PFX "Could not obtain valid ethernet address, " diff --git a/trunk/drivers/net/tg3.h b/trunk/drivers/net/tg3.h index dcdfc084966c..d515ed23841b 100644 --- a/trunk/drivers/net/tg3.h +++ b/trunk/drivers/net/tg3.h @@ -131,7 +131,6 @@ #define CHIPREV_ID_5752_A0_HW 0x5000 #define CHIPREV_ID_5752_A0 0x6000 #define CHIPREV_ID_5752_A1 0x6001 -#define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 @@ -2200,6 +2199,7 @@ struct tg3 { #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 #define TG3_FLAG_USE_MI_INTERRUPT 0x00000010 #define TG3_FLAG_ENABLE_ASF 0x00000020 +#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 #define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 #define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 @@ -2215,14 +2215,14 @@ struct tg3 { #define TG3_FLAG_PCI_32BIT 0x00080000 #define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 #define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000 -#define TG3_FLAG_WOL_CAP 0x00400000 +#define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 #define TG3_FLAG_IN_RESET_TASK 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 -#define TG3_FLAG_SUPPORT_MSI 0x20000000 +#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; diff --git a/trunk/drivers/net/tlan.c b/trunk/drivers/net/tlan.c index 106dc1ef0acb..f85f00251123 100644 --- a/trunk/drivers/net/tlan.c +++ b/trunk/drivers/net/tlan.c @@ -1112,7 +1112,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) if ( bbuf ) { tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); - skb_copy_from_linear_data(skb, tail_buffer, skb->len); + memcpy( tail_buffer, skb->data, skb->len ); } else { tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); TLan_StoreSKB(tail_list, skb); @@ -1577,6 +1577,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); else { head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb->dev = dev; skb_reserve(skb, 2); t = (void *) skb_put(skb, frameSize); @@ -1607,6 +1608,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); + new_skb->dev = dev; skb_reserve( new_skb, 2 ); t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); diff --git a/trunk/drivers/net/tokenring/3c359.c b/trunk/drivers/net/tokenring/3c359.c index e22a3f5333ef..7580bdeacadc 100644 --- a/trunk/drivers/net/tokenring/3c359.c +++ b/trunk/drivers/net/tokenring/3c359.c @@ -933,21 +933,20 @@ static void xl_rx(struct net_device *dev) return ; } + skb->dev = dev ; + while (xl_priv->rx_ring_tail != temp_ring_loc) { copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; frame_length -= copy_len ; pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail], - skb_put(skb, copy_len), - copy_len); + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; } /* Now we have found the last fragment */ pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail], - skb_put(skb,copy_len), frame_length); + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; /* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; @@ -968,6 +967,8 @@ static void xl_rx(struct net_device *dev) return ; } + skb->dev = dev ; + skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; skb_put(skb2, frame_length) ; diff --git a/trunk/drivers/net/tokenring/ibmtr.c b/trunk/drivers/net/tokenring/ibmtr.c index 1e8958ee2d0a..01d55315ee8c 100644 --- a/trunk/drivers/net/tokenring/ibmtr.c +++ b/trunk/drivers/net/tokenring/ibmtr.c @@ -1771,6 +1771,7 @@ static void tr_rx(struct net_device *dev) /*BMS again, if she comes in with few but leaves with many */ skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len); skb_put(skb, length); + skb->dev = dev; data = skb->data; rbuffer_len = ntohs(readw(rbuf + offsetof(struct rec_buf, buf_len))); rbufdata = rbuf + offsetof(struct rec_buf, data); diff --git a/trunk/drivers/net/tokenring/lanstreamer.c b/trunk/drivers/net/tokenring/lanstreamer.c index 5d849c089a3b..e999feb8c0bb 100644 --- a/trunk/drivers/net/tokenring/lanstreamer.c +++ b/trunk/drivers/net/tokenring/lanstreamer.c @@ -944,6 +944,8 @@ static void streamer_rx(struct net_device *dev) printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n", dev->name); streamer_priv->streamer_stats.rx_dropped++; } else { /* we allocated an skb OK */ + skb->dev = dev; + if (buffer_cnt == 1) { /* release the DMA mapping */ pci_unmap_single(streamer_priv->pci_dev, @@ -1605,11 +1607,10 @@ static void streamer_arb_cmd(struct net_device *dev) frame_data, buffer_len); } while (next_ptr && (buff_off = next_ptr)); - mac_frame->protocol = tr_type_trans(mac_frame, dev); #if STREAMER_NETWORK_MONITOR printk(KERN_WARNING "%s: Received MAC Frame, details: \n", dev->name); - mac_hdr = tr_hdr(mac_frame); + mac_hdr = (struct trh_hdr *) mac_frame->data; printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1], @@ -1621,6 +1622,8 @@ static void streamer_arb_cmd(struct net_device *dev) mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]); #endif + mac_frame->dev = dev; + mac_frame->protocol = tr_type_trans(mac_frame, dev); netif_rx(mac_frame); /* Now tell the card we have dealt with the received frame */ diff --git a/trunk/drivers/net/tokenring/madgemc.c b/trunk/drivers/net/tokenring/madgemc.c index f8f4d74f01f1..ed274d6909d0 100644 --- a/trunk/drivers/net/tokenring/madgemc.c +++ b/trunk/drivers/net/tokenring/madgemc.c @@ -23,6 +23,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/tokenring/olympic.c b/trunk/drivers/net/tokenring/olympic.c index 09b3cfb8e809..8f4ecc1109cb 100644 --- a/trunk/drivers/net/tokenring/olympic.c +++ b/trunk/drivers/net/tokenring/olympic.c @@ -814,6 +814,8 @@ static void olympic_rx(struct net_device *dev) olympic_priv->rx_ring_last_received += i ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; } else { + skb->dev = dev ; + /* Optimise based upon number of buffers used. If only one buffer is used we can simply swap the buffers around. If more than one then we must use the new buffer and copy the information @@ -845,9 +847,7 @@ static void olympic_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received], - skb_put(skb,length - 4), - length - 4); + memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; pci_dma_sync_single_for_device(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; @@ -864,9 +864,7 @@ static void olympic_rx(struct net_device *dev) olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); - skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received], - skb_put(skb, cpy_length), - cpy_length); + memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ; pci_dma_sync_single_for_device(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; @@ -1442,16 +1440,16 @@ static void olympic_arb_cmd(struct net_device *dev) next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr))); - mac_frame->protocol = tr_type_trans(mac_frame, dev); - if (olympic_priv->olympic_network_monitor) { struct trh_hdr *mac_hdr ; printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ; - mac_hdr = tr_hdr(mac_frame); + mac_hdr = (struct trh_hdr *)mac_frame->data ; printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; } - netif_rx(mac_frame); + mac_frame->dev = dev ; + mac_frame->protocol = tr_type_trans(mac_frame,dev); + netif_rx(mac_frame) ; dev->last_rx = jiffies; drop_frame: diff --git a/trunk/drivers/net/tokenring/smctr.c b/trunk/drivers/net/tokenring/smctr.c index 58d7e5d452fa..cec282a6f62d 100644 --- a/trunk/drivers/net/tokenring/smctr.c +++ b/trunk/drivers/net/tokenring/smctr.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -3888,13 +3889,14 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, /* Slide data into a sleek skb. */ skb_put(skb, skb->len); - skb_copy_to_linear_data(skb, rmf, skb->len); + memcpy(skb->data, rmf, skb->len); /* Update Counters */ tp->MacStat.rx_packets++; tp->MacStat.rx_bytes += skb->len; /* Kick the packet on up. */ + skb->dev = dev; skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; @@ -4474,13 +4476,14 @@ static int smctr_rx_frame(struct net_device *dev) if (skb) { skb_put(skb, rx_size); - skb_copy_to_linear_data(skb, pbuff, rx_size); + memcpy(skb->data, pbuff, rx_size); /* Update Counters */ tp->MacStat.rx_packets++; tp->MacStat.rx_bytes += skb->len; /* Kick the packet on up. */ + skb->dev = dev; skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; diff --git a/trunk/drivers/net/tokenring/tms380tr.c b/trunk/drivers/net/tokenring/tms380tr.c index 12bd294045a7..ea797ca2b988 100644 --- a/trunk/drivers/net/tokenring/tms380tr.c +++ b/trunk/drivers/net/tokenring/tms380tr.c @@ -644,7 +644,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device dmabuf = 0; i = tp->TplFree->TPLIndex; buf = tp->LocalTxBuffers[i]; - skb_copy_from_linear_data(skb, buf, length); + memcpy(buf, skb->data, length); newbuf = ((char *)buf - (char *)tp) + tp->dmabuffer; } else { @@ -2168,6 +2168,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) } else { + skb->dev = dev; skb_put(skb, tp->MaxPacketSize); rpl->SkbStat = SKB_DATA_COPY; ReceiveDataPtr = rpl->MData; @@ -2178,8 +2179,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) || rpl->SkbStat == SKB_DMA_DIRECT)) { if(rpl->SkbStat == SKB_DATA_COPY) - skb_copy_to_linear_data(skb, ReceiveDataPtr, - Length); + memcpy(skb->data, ReceiveDataPtr, Length); /* Deliver frame to system */ rpl->Skb = NULL; diff --git a/trunk/drivers/net/tsi108_eth.c b/trunk/drivers/net/tsi108_eth.c index 0bfc2c9c1c08..d92c5c597e16 100644 --- a/trunk/drivers/net/tsi108_eth.c +++ b/trunk/drivers/net/tsi108_eth.c @@ -788,6 +788,7 @@ static int tsi108_complete_rx(struct net_device *dev, int budget) printk(".\n"); } + skb->dev = dev; skb_put(skb, data->rxring[rx].len); skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); diff --git a/trunk/drivers/net/tulip/21142.c b/trunk/drivers/net/tulip/21142.c index 6c400ccd38b4..942b839ccc5b 100644 --- a/trunk/drivers/net/tulip/21142.c +++ b/trunk/drivers/net/tulip/21142.c @@ -14,6 +14,7 @@ */ +#include #include #include "tulip.h" diff --git a/trunk/drivers/net/tulip/de2104x.c b/trunk/drivers/net/tulip/de2104x.c index 861729806dc1..c82befa209a2 100644 --- a/trunk/drivers/net/tulip/de2104x.c +++ b/trunk/drivers/net/tulip/de2104x.c @@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number"); /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(CONFIG_SPARC) || defined(__ia64__) \ + || defined(__sparc__) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else @@ -435,6 +435,7 @@ static void de_rx (struct de_private *de) rx_work = 100; goto rx_next; } + copy_skb->dev = de->dev; if (!copying_skb) { pci_unmap_single(de->pdev, mapping, @@ -449,8 +450,8 @@ static void de_rx (struct de_private *de) } else { pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); - skb_copy_from_linear_data(skb, skb_put(copy_skb, len), - len); + memcpy(skb_put(copy_skb, len), skb->data, len); + pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ diff --git a/trunk/drivers/net/tulip/de4x5.c b/trunk/drivers/net/tulip/de4x5.c index 62143f92c231..4b3cd3d8b62a 100644 --- a/trunk/drivers/net/tulip/de4x5.c +++ b/trunk/drivers/net/tulip/de4x5.c @@ -1160,7 +1160,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id); lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); -#if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY) +#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY) lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN; #endif lp->rx_ring = dma_alloc_coherent(gendev, lp->dma_size, @@ -1175,7 +1175,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) ** Set up the RX descriptor ring (Intels) ** Allocate contiguous receive buffers, long word aligned (Alphas) */ -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY) +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) for (i=0; irx_ring[i].status = 0; lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); @@ -1252,7 +1252,11 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) mii_get_phy(dev); } +#ifndef __sparc_v9__ printk(" and requires IRQ%d (provided by %s).\n", dev->irq, +#else + printk(" and requires IRQ%x (provided by %s).\n", dev->irq, +#endif ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); } @@ -3623,13 +3627,14 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY) +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) struct sk_buff *ret; u_long i=0, tmp; p = dev_alloc_skb(IEEE802_3_SZ + DE4X5_ALIGN + 2); if (!p) return NULL; + p->dev = dev; tmp = virt_to_bus(p->data); i = ((tmp + DE4X5_ALIGN) & ~DE4X5_ALIGN) - tmp; skb_reserve(p, i); @@ -3650,6 +3655,7 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) p = dev_alloc_skb(len + 2); if (!p) return NULL; + p->dev = dev; skb_reserve(p, 2); /* Align */ if (index < lp->rx_old) { /* Wrapped buffer */ short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; diff --git a/trunk/drivers/net/tulip/dmfe.c b/trunk/drivers/net/tulip/dmfe.c index 4ed67ff0e81e..9aeac76184f3 100644 --- a/trunk/drivers/net/tulip/dmfe.c +++ b/trunk/drivers/net/tulip/dmfe.c @@ -55,6 +55,9 @@ TODO + Implement pci_driver::suspend() and pci_driver::resume() + power management methods. + Check on 64 bit boxes. Check and fix on big endian boxes. @@ -122,11 +125,6 @@ #define DM9801_NOISE_FLOOR 8 #define DM9802_NOISE_FLOOR 5 -#define DMFE_WOL_LINKCHANGE 0x20000000 -#define DMFE_WOL_SAMPLEPACKET 0x10000000 -#define DMFE_WOL_MAGICPACKET 0x08000000 - - #define DMFE_10MHF 0 #define DMFE_100MHF 1 #define DMFE_10MFD 4 @@ -253,7 +251,6 @@ struct dmfe_board_info { u8 wait_reset; /* Hardware failed, need to reset */ u8 dm910x_chk_mode; /* Operating mode check */ u8 first_in_callback; /* Flag to record state */ - u8 wol_mode; /* user WOL settings */ struct timer_list timer; /* System defined statistic counter */ @@ -434,7 +431,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, db->chip_id = ent->driver_data; db->ioaddr = pci_resource_start(pdev, 0); db->chip_revision = dev_rev; - db->wol_mode = 0; db->pdev = pdev; @@ -686,7 +682,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* transmit this packet */ txptr = db->tx_insert_ptr; - skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len); + memcpy(txptr->tx_buf_ptr, skb->data, skb->len); txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); /* Point to next transmit free descriptor */ @@ -992,14 +988,14 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) skb = newskb; /* size less than COPY_SIZE, allocate a rxlen SKB */ + skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - skb_copy_from_linear_data(rxptr->rx_skb_ptr, - skb_put(skb, rxlen), - rxlen); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen); dmfe_reuse_skb(db, rxptr->rx_skb_ptr); - } else + } else { + skb->dev = dev; skb_put(skb, rxlen); - + } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; @@ -1069,11 +1065,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) spin_unlock_irqrestore(&db->lock, flags); } -/* - * Ethtool interace - */ - -static void dmfe_ethtool_get_drvinfo(struct net_device *dev, +static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct dmfe_board_info *np = netdev_priv(dev); @@ -1087,35 +1079,9 @@ static void dmfe_ethtool_get_drvinfo(struct net_device *dev, dev->base_addr, dev->irq); } -static int dmfe_ethtool_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wolinfo) -{ - struct dmfe_board_info *db = netdev_priv(dev); - - if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | - WAKE_ARP | WAKE_MAGICSECURE)) - return -EOPNOTSUPP; - - db->wol_mode = wolinfo->wolopts; - return 0; -} - -static void dmfe_ethtool_get_wol(struct net_device *dev, - struct ethtool_wolinfo *wolinfo) -{ - struct dmfe_board_info *db = netdev_priv(dev); - - wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = db->wol_mode; - return; -} - - static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = dmfe_ethtool_get_drvinfo, + .get_drvinfo = netdev_get_drvinfo, .get_link = ethtool_op_get_link, - .set_wol = dmfe_ethtool_set_wol, - .get_wol = dmfe_ethtool_get_wol, }; /* @@ -2084,85 +2050,11 @@ static struct pci_device_id dmfe_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); -#ifdef CONFIG_PM -static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pci_dev); - struct dmfe_board_info *db = netdev_priv(dev); - u32 tmp; - - /* Disable upper layer interface */ - netif_device_detach(dev); - - /* Disable Tx/Rx */ - db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); - update_cr6(db->cr6_data, dev->base_addr); - - /* Disable Interrupt */ - outl(0, dev->base_addr + DCR7); - outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5); - - /* Fre RX buffers */ - dmfe_free_rxbuffer(db); - - /* Enable WOL */ - pci_read_config_dword(pci_dev, 0x40, &tmp); - tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET); - - if (db->wol_mode & WAKE_PHY) - tmp |= DMFE_WOL_LINKCHANGE; - if (db->wol_mode & WAKE_MAGIC) - tmp |= DMFE_WOL_MAGICPACKET; - - pci_write_config_dword(pci_dev, 0x40, tmp); - - pci_enable_wake(pci_dev, PCI_D3hot, 1); - pci_enable_wake(pci_dev, PCI_D3cold, 1); - - /* Power down device*/ - pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state)); - pci_save_state(pci_dev); - - return 0; -} - -static int dmfe_resume(struct pci_dev *pci_dev) -{ - struct net_device *dev = pci_get_drvdata(pci_dev); - u32 tmp; - - pci_restore_state(pci_dev); - pci_set_power_state(pci_dev, PCI_D0); - - /* Re-initilize DM910X board */ - dmfe_init_dm910x(dev); - - /* Disable WOL */ - pci_read_config_dword(pci_dev, 0x40, &tmp); - - tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET); - pci_write_config_dword(pci_dev, 0x40, tmp); - - pci_enable_wake(pci_dev, PCI_D3hot, 0); - pci_enable_wake(pci_dev, PCI_D3cold, 0); - - /* Restart upper layer interface */ - netif_device_attach(dev); - - return 0; -} -#else -#define dmfe_suspend NULL -#define dmfe_resume NULL -#endif - static struct pci_driver dmfe_driver = { .name = "dmfe", .id_table = dmfe_pci_tbl, .probe = dmfe_init_one, .remove = __devexit_p(dmfe_remove_one), - .suspend = dmfe_suspend, - .resume = dmfe_resume }; MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); diff --git a/trunk/drivers/net/tulip/interrupt.c b/trunk/drivers/net/tulip/interrupt.c index 9b08afbd1f65..e3488d7b8ede 100644 --- a/trunk/drivers/net/tulip/interrupt.c +++ b/trunk/drivers/net/tulip/interrupt.c @@ -192,6 +192,7 @@ int tulip_poll(struct net_device *dev, int *budget) to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(tp->pdev, tp->rx_buffers[entry].mapping, @@ -415,6 +416,7 @@ static int tulip_rx(struct net_device *dev) to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(tp->pdev, tp->rx_buffers[entry].mapping, @@ -673,7 +675,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) if (tp->link_change) (tp->link_change)(dev, csr5); } - if (csr5 & SystemError) { + if (csr5 & SytemError) { int error = (csr5 >> 23) & 7; /* oops, we hit a PCI error. The code produced corresponds * to the reason: @@ -743,7 +745,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) TxFIFOUnderflow | TxJabber | TPLnkFail | - SystemError )) != 0); + SytemError )) != 0); #else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); diff --git a/trunk/drivers/net/tulip/media.c b/trunk/drivers/net/tulip/media.c index b56256636543..20bd52b86993 100644 --- a/trunk/drivers/net/tulip/media.c +++ b/trunk/drivers/net/tulip/media.c @@ -44,10 +44,8 @@ static const unsigned char comet_miireg2offset[32] = { /* MII transceiver control section. Read and write the MII registers using software-generated serial - MDIO protocol. - See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions") - or DP83840A data sheet for more details. - */ + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location) { @@ -263,56 +261,24 @@ void tulip_select_media(struct net_device *dev, int startup) u16 *reset_sequence = &((u16*)(p+3))[init_length]; int reset_length = p[2 + init_length*2]; misc_info = reset_sequence + reset_length; - if (startup) { - int timeout = 10; /* max 1 ms */ + if (startup) for (i = 0; i < reset_length; i++) iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); - - /* flush posted writes */ - ioread32(ioaddr + CSR15); - - /* Sect 3.10.3 in DP83840A.pdf (p39) */ - udelay(500); - - /* Section 4.2 in DP83840A.pdf (p43) */ - /* and IEEE 802.3 "22.2.4.1.1 Reset" */ - while (timeout-- && - (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) - udelay(100); - } for (i = 0; i < init_length; i++) iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); - - ioread32(ioaddr + CSR15); /* flush posted writes */ } else { u8 *init_sequence = p + 2; u8 *reset_sequence = p + 3 + init_length; int reset_length = p[2 + init_length]; misc_info = (u16*)(reset_sequence + reset_length); if (startup) { - int timeout = 10; /* max 1 ms */ iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); for (i = 0; i < reset_length; i++) iowrite32(reset_sequence[i], ioaddr + CSR12); - - /* flush posted writes */ - ioread32(ioaddr + CSR12); - - /* Sect 3.10.3 in DP83840A.pdf (p39) */ - udelay(500); - - /* Section 4.2 in DP83840A.pdf (p43) */ - /* and IEEE 802.3 "22.2.4.1.1 Reset" */ - while (timeout-- && - (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) - udelay(100); } for (i = 0; i < init_length; i++) iowrite32(init_sequence[i], ioaddr + CSR12); - - ioread32(ioaddr + CSR12); /* flush posted writes */ } - tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff --git a/trunk/drivers/net/tulip/pnic.c b/trunk/drivers/net/tulip/pnic.c index be82a2effee3..85a521e0d052 100644 --- a/trunk/drivers/net/tulip/pnic.c +++ b/trunk/drivers/net/tulip/pnic.c @@ -15,6 +15,7 @@ */ #include +#include #include #include "tulip.h" diff --git a/trunk/drivers/net/tulip/pnic2.c b/trunk/drivers/net/tulip/pnic2.c index 4e4a879c3fa5..c31be0e377a8 100644 --- a/trunk/drivers/net/tulip/pnic2.c +++ b/trunk/drivers/net/tulip/pnic2.c @@ -76,6 +76,7 @@ +#include #include "tulip.h" #include diff --git a/trunk/drivers/net/tulip/timer.c b/trunk/drivers/net/tulip/timer.c index d2c1f42109b0..df326fe1cc8f 100644 --- a/trunk/drivers/net/tulip/timer.c +++ b/trunk/drivers/net/tulip/timer.c @@ -14,6 +14,7 @@ */ +#include #include "tulip.h" diff --git a/trunk/drivers/net/tulip/tulip.h b/trunk/drivers/net/tulip/tulip.h index 16f26a8364f0..25f25da76917 100644 --- a/trunk/drivers/net/tulip/tulip.h +++ b/trunk/drivers/net/tulip/tulip.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -133,7 +132,7 @@ enum pci_cfg_driver_reg { /* The bits in the CSR5 status registers, mostly interrupt sources. */ enum status_bits { TimerInt = 0x800, - SystemError = 0x2000, + SytemError = 0x2000, TPLnkFail = 0x1000, TPLnkPass = 0x10, NormalIntr = 0x10000, @@ -483,11 +482,8 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp) udelay(10); if (!i) - printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed" - " (CSR5 0x%x CSR6 0x%x)\n", - pci_name(tp->pdev), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n", + pci_name(tp->pdev)); } } diff --git a/trunk/drivers/net/tulip/tulip_core.c b/trunk/drivers/net/tulip/tulip_core.c index 041af63f2811..e3774a522372 100644 --- a/trunk/drivers/net/tulip/tulip_core.c +++ b/trunk/drivers/net/tulip/tulip_core.c @@ -17,11 +17,11 @@ #define DRV_NAME "tulip" #ifdef CONFIG_TULIP_NAPI -#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */ +#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */ #else -#define DRV_VERSION "1.1.15" +#define DRV_VERSION "1.1.14" #endif -#define DRV_RELDATE "Feb 27, 2007" +#define DRV_RELDATE "May 11, 2002" #include @@ -36,8 +36,8 @@ #include #include -#ifdef CONFIG_SPARC -#include +#ifdef __sparc__ +#include #endif static char version[] __devinitdata = @@ -67,7 +67,7 @@ const char * const medianame[32] = { /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(CONFIG_SPARC) || defined(__ia64__) \ + || defined(__sparc__) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else @@ -91,7 +91,7 @@ static int rx_copybreak = 100; static int csr0 = 0x01A00000 | 0xE000; #elif defined(__i386__) || defined(__powerpc__) || defined(__x86_64__) static int csr0 = 0x01A00000 | 0x8000; -#elif defined(CONFIG_SPARC) || defined(__hppa__) +#elif defined(__sparc__) || defined(__hppa__) /* The UltraSparc PCI controllers will disconnect at every 64-byte * crossing anyways so it makes no sense to tell Tulip to burst * any more than that. @@ -1315,7 +1315,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ if (tulip_uli_dm_quirk(pdev)) { csr0 &= ~0x01f100ff; -#if defined(CONFIG_SPARC) +#if defined(__sparc__) csr0 = (csr0 & ~0xff00) | 0xe000; #endif } @@ -1535,19 +1535,23 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, Many PCI BIOSes also incorrectly report the IRQ line, so we correct that here as well. */ if (sum == 0 || sum == 6*0xff) { -#if defined(CONFIG_SPARC) - struct device_node *dp = pci_device_to_OF_node(pdev); - const unsigned char *addr; - int len; +#if defined(__sparc__) + struct pcidev_cookie *pcp = pdev->sysdata; #endif eeprom_missing = 1; for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(CONFIG_SPARC) - addr = of_get_property(dp, "local-mac-address", &len); - if (addr && len == 6) - memcpy(dev->dev_addr, addr, 6); +#if defined(__sparc__) + if (pcp) { + unsigned char *addr; + int len; + + addr = of_get_property(pcp->prom_node, + "local-mac-address", &len); + if (addr && len == 6) + memcpy(dev->dev_addr, addr, 6); + } #endif #if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ if (last_irq) diff --git a/trunk/drivers/net/tulip/uli526x.c b/trunk/drivers/net/tulip/uli526x.c index ca2548eb7d63..229158e8e4be 100644 --- a/trunk/drivers/net/tulip/uli526x.c +++ b/trunk/drivers/net/tulip/uli526x.c @@ -583,7 +583,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* transmit this packet */ txptr = db->tx_insert_ptr; - skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len); + memcpy(txptr->tx_buf_ptr, skb->data, skb->len); txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); /* Point to next transmit free descriptor */ @@ -828,14 +828,14 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info ( (skb = dev_alloc_skb(rxlen + 2) ) != NULL) ) { /* size less than COPY_SIZE, allocate a rxlen SKB */ + skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), - skb_tail_pointer(rxptr->rx_skb_ptr), - rxlen); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); uli526x_reuse_skb(db, rxptr->rx_skb_ptr); - } else + } else { + skb->dev = dev; skb_put(skb, rxlen); - + } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; @@ -1177,10 +1177,7 @@ static void uli526x_reuse_skb(struct uli526x_board_info *db, struct sk_buff * sk if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { rxptr->rx_skb_ptr = skb; - rxptr->rdes2 = cpu_to_le32(pci_map_single(db->pdev, - skb_tail_pointer(skb), - RX_ALLOC_SIZE, - PCI_DMA_FROMDEVICE)); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; @@ -1344,10 +1341,7 @@ static void allocate_rx_buffer(struct uli526x_board_info *db) if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; rxptr->rx_skb_ptr = skb; /* FIXME (?) */ - rxptr->rdes2 = cpu_to_le32(pci_map_single(db->pdev, - skb_tail_pointer(skb), - RX_ALLOC_SIZE, - PCI_DMA_FROMDEVICE)); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = rxptr->next_rx_desc; diff --git a/trunk/drivers/net/tulip/winbond-840.c b/trunk/drivers/net/tulip/winbond-840.c index fa440706fb4a..002a05e0722f 100644 --- a/trunk/drivers/net/tulip/winbond-840.c +++ b/trunk/drivers/net/tulip/winbond-840.c @@ -813,6 +813,7 @@ static void init_rxtx_rings(struct net_device *dev) np->rx_skbuff[i] = skb; if (skb == NULL) break; + skb->dev = dev; /* Mark as being used by this device. */ np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data, np->rx_buf_sz,PCI_DMA_FROMDEVICE); @@ -902,7 +903,7 @@ static void init_registers(struct net_device *dev) } #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) i |= 0xE000; -#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) +#elif defined(__sparc__) || defined (CONFIG_PARISC) i |= 0x4800; #else #warning Processor architecture undefined @@ -1147,7 +1148,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) } /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError | + if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError | TimerInt | TxDied)) netdev_error(dev, intr_status); @@ -1228,6 +1229,7 @@ static int netdev_rx(struct net_device *dev) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, @@ -1276,6 +1278,7 @@ static int netdev_rx(struct net_device *dev) np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ np->rx_addr[entry] = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); diff --git a/trunk/drivers/net/tulip/xircom_cb.c b/trunk/drivers/net/tulip/xircom_cb.c index 985a1810ca59..61d313049dd0 100644 --- a/trunk/drivers/net/tulip/xircom_cb.c +++ b/trunk/drivers/net/tulip/xircom_cb.c @@ -411,9 +411,9 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) sometimes sends more than you ask it to. */ memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); - skb_copy_from_linear_data(skb, - &(card->tx_buffer[bufferoffsets[desc] / 4]), - skb->len); + memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len); + + /* FIXME: The specification tells us that the length we send HAS to be a multiple of 4 bytes. */ @@ -1207,6 +1207,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri card->stats.rx_dropped++; goto out; } + skb->dev = dev; skb_reserve(skb, 2); eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0); skb_put(skb, pkt_len); diff --git a/trunk/drivers/net/tulip/xircom_tulip_cb.c b/trunk/drivers/net/tulip/xircom_tulip_cb.c index f64172927377..a998c5d0ae9c 100644 --- a/trunk/drivers/net/tulip/xircom_tulip_cb.c +++ b/trunk/drivers/net/tulip/xircom_tulip_cb.c @@ -65,7 +65,7 @@ static int rx_copybreak = 100; static int csr0 = 0x01A00000 | 0xE000; #elif defined(__powerpc__) static int csr0 = 0x01B00000 | 0x8000; -#elif defined(CONFIG_SPARC) +#elif defined(__sparc__) static int csr0 = 0x01B00080 | 0x8000; #elif defined(__i386__) static int csr0 = 0x01A00000 | 0x8000; @@ -915,9 +915,7 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->tx_skbuff[entry] = skb; if (tp->chip_id == X3201_3) { - skb_copy_from_linear_data(skb, - tp->tx_aligned_skbuff[entry]->data, - skb->len); + memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len); tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data); } else tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data); @@ -1240,6 +1238,7 @@ xircom_rx(struct net_device *dev) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ #if ! defined(__alpha__) eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1), diff --git a/trunk/drivers/net/tun.c b/trunk/drivers/net/tun.c index a2c6caaaae93..5643d1e84ed6 100644 --- a/trunk/drivers/net/tun.c +++ b/trunk/drivers/net/tun.c @@ -18,10 +18,6 @@ /* * Changes: * - * Brian Braunstein 2007/03/23 - * Fixed hw address handling. Now net_device.dev_addr is kept consistent - * with tun.dev_addr when the address is set by this module. - * * Mike Kershaw 2005/08/14 * Add TUNSETLINK ioctl to set the link encapsulation * @@ -200,10 +196,7 @@ static void tun_net_init(struct net_device *dev) dev->set_multicast_list = tun_net_mclist; ether_setup(dev); - - /* random address already created for us by tun_set_iff, use it */ - memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) ); - + random_ether_addr(dev->dev_addr); dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */ break; } @@ -261,11 +254,11 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, return -EFAULT; } + skb->dev = tun->dev; switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->protocol = pi.proto; - skb->dev = tun->dev; break; case TUN_TAP_DEV: skb->protocol = eth_type_trans(skb, tun->dev); @@ -393,8 +386,8 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, * - we are multicast promiscous. * - we belong to the multicast group. */ - skb_copy_from_linear_data(skb, addr, min_t(size_t, sizeof addr, - skb->len)); + memcpy(addr, skb->data, + min_t(size_t, sizeof addr, skb->len)); bit_nr = ether_crc(sizeof addr, addr) >> 26; if ((tun->if_flags & IFF_PROMISC) || memcmp(addr, tun->dev_addr, sizeof addr) == 0 || @@ -643,7 +636,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, return 0; case SIOCGIFHWADDR: - /* Note: the actual net device's address may be different */ memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr, min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr)); if (copy_to_user( argp, &ifr, sizeof ifr)) @@ -651,24 +643,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, return 0; case SIOCSIFHWADDR: - { - /* try to set the actual net device's hw address */ - int ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); - - if (ret == 0) { - /** Set the character device's hardware address. This is used when - * filtering packets being sent from the network device to the character - * device. */ - memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data, - min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr)); - DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2], - tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]); - } - - return ret; - } + /** Set the character device's hardware address. This is used when + * filtering packets being sent from the network device to the character + * device. */ + memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data, + min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr)); + DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n", + tun->dev->name, + tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2], + tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]); + return 0; case SIOCADDMULTI: /** Add the specified group to the character device's multicast filter diff --git a/trunk/drivers/net/typhoon.c b/trunk/drivers/net/typhoon.c index f2dd7763cd0b..0d91d094edd9 100644 --- a/trunk/drivers/net/typhoon.c +++ b/trunk/drivers/net/typhoon.c @@ -1708,6 +1708,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, if(pkt_len < rx_copybreak && (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + new_skb->dev = tp->dev; skb_reserve(new_skb, 2); pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, PKT_BUF_SZ, diff --git a/trunk/drivers/net/ucc_geth.c b/trunk/drivers/net/ucc_geth.c index 16b9acdabbe8..639e1e6913bf 100644 --- a/trunk/drivers/net/ucc_geth.c +++ b/trunk/drivers/net/ucc_geth.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -42,13 +41,12 @@ #include #include "ucc_geth.h" -#include "ucc_geth_mii.h" +#include "ucc_geth_phy.h" #undef DEBUG -#define DRV_DESC "QE UCC Gigabit Ethernet Controller" +#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006" #define DRV_NAME "ucc_geth" -#define DRV_VERSION "1.1" #define ugeth_printk(level, format, arg...) \ printk(level format "\n", ## arg) @@ -75,13 +73,22 @@ static struct ucc_geth_info ugeth_primary_info = { .bd_mem_part = MEM_PART_SYSTEM, .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, .max_rx_buf_length = 1536, - /* adjusted at startup if max-speed 1000 */ +/* FIXME: should be changed in run time for 1G and 100M */ +#ifdef CONFIG_UGETH_HAS_GIGA + .urfs = UCC_GETH_URFS_GIGA_INIT, + .urfet = UCC_GETH_URFET_GIGA_INIT, + .urfset = UCC_GETH_URFSET_GIGA_INIT, + .utfs = UCC_GETH_UTFS_GIGA_INIT, + .utfet = UCC_GETH_UTFET_GIGA_INIT, + .utftt = UCC_GETH_UTFTT_GIGA_INIT, +#else .urfs = UCC_GETH_URFS_INIT, .urfet = UCC_GETH_URFET_INIT, .urfset = UCC_GETH_URFSET_INIT, .utfs = UCC_GETH_UTFS_INIT, .utfet = UCC_GETH_UTFET_INIT, .utftt = UCC_GETH_UTFTT_INIT, +#endif .ufpt = 256, .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, @@ -210,6 +217,70 @@ static struct list_head *dequeue(struct list_head *lh) } } +static int get_interface_details(enum enet_interface enet_interface, + enum enet_speed *speed, + int *r10m, + int *rmm, + int *rpm, + int *tbi, int *limited_to_full_duplex) +{ + /* Analyze enet_interface according to Interface Mode + Configuration table */ + switch (enet_interface) { + case ENET_10_MII: + *speed = ENET_SPEED_10BT; + break; + case ENET_10_RMII: + *speed = ENET_SPEED_10BT; + *r10m = 1; + *rmm = 1; + break; + case ENET_10_RGMII: + *speed = ENET_SPEED_10BT; + *rpm = 1; + *r10m = 1; + *limited_to_full_duplex = 1; + break; + case ENET_100_MII: + *speed = ENET_SPEED_100BT; + break; + case ENET_100_RMII: + *speed = ENET_SPEED_100BT; + *rmm = 1; + break; + case ENET_100_RGMII: + *speed = ENET_SPEED_100BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_GMII: + *speed = ENET_SPEED_1000BT; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RGMII: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_TBI: + *speed = ENET_SPEED_1000BT; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RTBI: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + default: + return -EINVAL; + break; + } + + return 0; +} + static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) { struct sk_buff *skb = NULL; @@ -687,6 +758,24 @@ static void dump_regs(struct ucc_geth_private *ugeth) ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", (u32) & ugeth->ug_regs->hafdup, in_be32(&ugeth->ug_regs->hafdup)); + ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcfg, + in_be32(&ugeth->ug_regs->miimng.miimcfg)); + ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcom, + in_be32(&ugeth->ug_regs->miimng.miimcom)); + ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimadd, + in_be32(&ugeth->ug_regs->miimng.miimadd)); + ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcon, + in_be32(&ugeth->ug_regs->miimng.miimcon)); + ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimstat, + in_be32(&ugeth->ug_regs->miimng.miimstat)); + ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimind, + in_be32(&ugeth->ug_regs->miimng.miimind)); ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", (u32) & ugeth->ug_regs->ifctl, in_be32(&ugeth->ug_regs->ifctl)); @@ -1336,6 +1425,27 @@ static int init_mac_station_addr_regs(u8 address_byte_0, return 0; } +static int init_mac_duplex_mode(int full_duplex, + int limited_to_full_duplex, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + /* some interfaces must work in full duplex mode */ + if ((full_duplex == 0) && (limited_to_full_duplex == 1)) + return -EINVAL; + + value = in_be32(maccfg2_register); + + if (full_duplex) + value |= MACCFG2_FDX; + else + value &= ~MACCFG2_FDX; + + out_be32(maccfg2_register, value); + return 0; +} + static int init_check_frame_length_mode(int length_check, volatile u32 *maccfg2_register) { @@ -1367,6 +1477,40 @@ static int init_preamble_length(u8 preamble_length, return 0; } +static int init_mii_management_configuration(int reset_mgmt, + int preamble_supress, + volatile u32 *miimcfg_register, + volatile u32 *miimind_register) +{ + unsigned int timeout = PHY_INIT_TIMEOUT; + u32 value = 0; + + value = in_be32(miimcfg_register); + if (reset_mgmt) { + value |= MIIMCFG_RESET_MANAGEMENT; + out_be32(miimcfg_register, value); + } + + value = 0; + + if (preamble_supress) + value |= MIIMCFG_NO_PREAMBLE; + + value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; + out_be32(miimcfg_register, value); + + /* Wait until the bus is free */ + while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) + cpu_relax(); + + if (timeout <= 0) { + ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); + return -ETIMEDOUT; + } + + return 0; +} + static int init_rx_parameters(int reject_broadcast, int receive_short_frames, int promiscuous, volatile u32 *upsmr_register) @@ -1426,8 +1570,10 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) struct ucc_geth_info *ug_info; struct ucc_geth *ug_regs; struct ucc_fast *uf_regs; - int ret_val; - u32 upsmr, maccfg2, tbiBaseAddress; + enum enet_speed speed; + int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = + 0, limited_to_full_duplex = 0; + u32 upsmr, maccfg2, utbipar, tbiBaseAddress; u16 value; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -1436,13 +1582,24 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) ug_regs = ugeth->ug_regs; uf_regs = ugeth->uccf->uf_regs; + /* Analyze enet_interface according to Interface Mode Configuration + table */ + ret_val = + get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, + &rpm, &tbi, &limited_to_full_duplex); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; + } + /* Set MACCFG2 */ maccfg2 = in_be32(&ug_regs->maccfg2); maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; - if ((ugeth->max_speed == SPEED_10) || - (ugeth->max_speed == SPEED_100)) + if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - else if (ugeth->max_speed == SPEED_1000) + else if (speed == ENET_SPEED_1000BT) maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; maccfg2 |= ug_info->padAndCrc; out_be32(&ug_regs->maccfg2, maccfg2); @@ -1450,39 +1607,54 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) /* Set UPSMR */ upsmr = in_be32(&uf_regs->upsmr); upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); - if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { + if (rpm) upsmr |= UPSMR_RPM; - switch (ugeth->max_speed) { - case SPEED_10: - upsmr |= UPSMR_R10M; - /* FALLTHROUGH */ - case SPEED_100: - if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) - upsmr |= UPSMR_RMM; - } - } - if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { + if (r10m) + upsmr |= UPSMR_R10M; + if (tbi) upsmr |= UPSMR_TBIM; - } + if (rmm) + upsmr |= UPSMR_RMM; out_be32(&uf_regs->upsmr, upsmr); + /* Set UTBIPAR */ + utbipar = in_be32(&ug_regs->utbipar); + utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; + if (tbi) + utbipar |= + (ug_info->phy_address + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + else + utbipar |= + (0x10 + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + out_be32(&ug_regs->utbipar, utbipar); + /* Disable autonegotiation in tbi mode, because by default it comes up in autonegotiation mode. */ /* Note that this depends on proper setting in utbipar register. */ - if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { + if (tbi) { tbiBaseAddress = in_be32(&ug_regs->utbipar); tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; - value = ugeth->phydev->bus->read(ugeth->phydev->bus, - (u8) tbiBaseAddress, ENET_TBI_MII_CR); + value = + ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR); value &= ~0x1000; /* Turn off autonegotiation */ - ugeth->phydev->bus->write(ugeth->phydev->bus, - (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); + ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR, value); + } + + ret_val = init_mac_duplex_mode(1, + limited_to_full_duplex, + &ug_regs->maccfg2); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; } init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); @@ -1504,88 +1676,76 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) * function converts those variables into the appropriate * register values, and can bring down the device if needed. */ - static void adjust_link(struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); struct ucc_geth *ug_regs; - struct ucc_fast *uf_regs; - struct phy_device *phydev = ugeth->phydev; - unsigned long flags; - int new_state = 0; + u32 tempval; + struct ugeth_mii_info *mii_info = ugeth->mii_info; ug_regs = ugeth->ug_regs; - uf_regs = ugeth->uccf->uf_regs; - spin_lock_irqsave(&ugeth->lock, flags); - - if (phydev->link) { - u32 tempval = in_be32(&ug_regs->maccfg2); - u32 upsmr = in_be32(&uf_regs->upsmr); + if (mii_info->link) { /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (phydev->duplex != ugeth->oldduplex) { - new_state = 1; - if (!(phydev->duplex)) + if (mii_info->duplex != ugeth->oldduplex) { + if (!(mii_info->duplex)) { + tempval = in_be32(&ug_regs->maccfg2); tempval &= ~(MACCFG2_FDX); - else + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Half Duplex", dev->name); + } else { + tempval = in_be32(&ug_regs->maccfg2); tempval |= MACCFG2_FDX; - ugeth->oldduplex = phydev->duplex; + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Full Duplex", dev->name); + } + + ugeth->oldduplex = mii_info->duplex; } - if (phydev->speed != ugeth->oldspeed) { - new_state = 1; - switch (phydev->speed) { - case SPEED_1000: - tempval = ((tempval & - ~(MACCFG2_INTERFACE_MODE_MASK)) | - MACCFG2_INTERFACE_MODE_BYTE); + if (mii_info->speed != ugeth->oldspeed) { + switch (mii_info->speed) { + case 1000: + ugeth->ug_info->enet_interface = ENET_1000_RGMII; break; - case SPEED_100: - case SPEED_10: - tempval = ((tempval & - ~(MACCFG2_INTERFACE_MODE_MASK)) | - MACCFG2_INTERFACE_MODE_NIBBLE); - /* if reduced mode, re-set UPSMR.R10M */ - if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || - (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { - if (phydev->speed == SPEED_10) - upsmr |= UPSMR_R10M; - else - upsmr &= ~(UPSMR_R10M); - } + case 100: + ugeth->ug_info->enet_interface = ENET_100_RGMII; + break; + case 10: + ugeth->ug_info->enet_interface = ENET_10_RGMII; break; default: - if (netif_msg_link(ugeth)) - ugeth_warn( - "%s: Ack! Speed (%d) is not 10/100/1000!", - dev->name, phydev->speed); + ugeth_warn + ("%s: Ack! Speed (%d) is not 10/100/1000!", + dev->name, mii_info->speed); break; } - ugeth->oldspeed = phydev->speed; - } + adjust_enet_interface(ugeth); + + ugeth_info("%s: Speed %dBT", dev->name, + mii_info->speed); - out_be32(&ug_regs->maccfg2, tempval); - out_be32(&uf_regs->upsmr, upsmr); + ugeth->oldspeed = mii_info->speed; + } if (!ugeth->oldlink) { - new_state = 1; + ugeth_info("%s: Link is up", dev->name); ugeth->oldlink = 1; + netif_carrier_on(dev); netif_schedule(dev); } - } else if (ugeth->oldlink) { - new_state = 1; + } else { + if (ugeth->oldlink) { + ugeth_info("%s: Link is down", dev->name); ugeth->oldlink = 0; ugeth->oldspeed = 0; ugeth->oldduplex = -1; + netif_carrier_off(dev); + } } - - if (new_state && netif_msg_link(ugeth)) - phy_print_status(phydev); - - spin_unlock_irqrestore(&ugeth->lock, flags); } /* Configure the PHY for dev. @@ -1593,40 +1753,102 @@ static void adjust_link(struct net_device *dev) */ static int init_phy(struct net_device *dev) { - struct ucc_geth_private *priv = netdev_priv(dev); - struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct phy_info *curphy; + struct ucc_mii_mng *mii_regs; + struct ugeth_mii_info *mii_info; + int err; - priv->oldlink = 0; - priv->oldspeed = 0; - priv->oldduplex = -1; + mii_regs = &ugeth->ug_regs->miimng; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, - priv->ug_info->phy_address); + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; - phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); + mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); - if (IS_ERR(phydev)) { - printk("%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); + if (NULL == mii_info) { + ugeth_err("%s: Could not allocate mii_info", dev->name); + return -ENOMEM; } - phydev->supported &= (ADVERTISED_10baseT_Half | + mii_info->mii_regs = mii_regs; + mii_info->speed = SPEED_1000; + mii_info->duplex = DUPLEX_FULL; + mii_info->pause = 0; + mii_info->link = 0; + + mii_info->advertising = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full); + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + mii_info->autoneg = 1; - if (priv->max_speed == SPEED_1000) - phydev->supported |= ADVERTISED_1000baseT_Full; + mii_info->mii_id = ugeth->ug_info->phy_address; - phydev->advertising = phydev->supported; + mii_info->dev = dev; - priv->phydev = phydev; + mii_info->mdio_read = &read_phy_reg; + mii_info->mdio_write = &write_phy_reg; + + spin_lock_init(&mii_info->mdio_lock); + + ugeth->mii_info = mii_info; + + spin_lock_irq(&ugeth->lock); + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + if (init_mii_management_configuration(1, + ugeth->ug_info-> + miiPreambleSupress, + &mii_regs->miimcfg, + &mii_regs->miimind)) { + ugeth_err("%s: The MII Bus is stuck!", dev->name); + err = -1; + goto bus_fail; + } + + spin_unlock_irq(&ugeth->lock); + + /* get info for this PHY */ + curphy = get_phy_info(ugeth->mii_info); + + if (curphy == NULL) { + ugeth_err("%s: No PHY found", dev->name); + err = -1; + goto no_phy; + } + + mii_info->phyinfo = curphy; + + /* Run the commands which initialize the PHY */ + if (curphy->init) { + err = curphy->init(ugeth->mii_info); + if (err) + goto phy_init_fail; + } return 0; + + phy_init_fail: + no_phy: + bus_fail: + kfree(mii_info); + + return err; } +#ifdef CONFIG_UGETH_TX_ON_DEMOND +static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) +{ + struct ucc_fastransmit_on_demand(ugeth->uccf); + return 0; +} +#endif static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) { @@ -2134,8 +2356,6 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) } for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { bd = ugeth->p_tx_bd_ring[i]; - if (!bd) - continue; for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { if (ugeth->tx_skbuff[i][j]) { dma_unmap_single(NULL, @@ -2267,7 +2487,6 @@ static void ucc_geth_set_multi(struct net_device *dev) static void ucc_geth_stop(struct ucc_geth_private *ugeth) { struct ucc_geth *ug_regs = ugeth->ug_regs; - struct phy_device *phydev = ugeth->phydev; u32 tempval; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -2276,7 +2495,8 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); /* Tell the kernel the link is down */ - phy_stop(phydev); + ugeth->mii_info->link = 0; + adjust_link(ugeth->dev); /* Mask all interrupts */ out_be32(ugeth->uccf->p_ucce, 0x00000000); @@ -2289,24 +2509,50 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); out_be32(&ug_regs->maccfg1, tempval); + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + /* Clear any pending interrupts */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY Interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_DISABLED); + } + free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); + } else { + del_timer_sync(&ugeth->phy_info_timer); + } + ucc_geth_memclean(ugeth); } -static int ucc_struct_init(struct ucc_geth_private *ugeth) +static int ucc_geth_startup(struct ucc_geth_private *ugeth) { + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + struct ucc_geth_init_pram *p_init_enet_pram; + struct ucc_fast_private *uccf; struct ucc_geth_info *ug_info; struct ucc_fast_info *uf_info; - int i; + struct ucc_fast *uf_regs; + struct ucc_geth *ug_regs; + int ret_val = -EINVAL; + u32 remoder = UCC_GETH_REMODER_INIT; + u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; + u32 ifstat, i, j, size, l2qt, l3qt, length; + u16 temoder = UCC_GETH_TEMODER_INIT; + u16 test; + u8 function_code = 0; + u8 *bd, *endOfRing; + u8 numThreadsRxNumerical, numThreadsTxNumerical; + + ugeth_vdbg("%s: IN", __FUNCTION__); ug_info = ugeth->ug_info; uf_info = &ug_info->uf_info; - /* Create CQs for hash tables */ - INIT_LIST_HEAD(&ugeth->group_hash_q); - INIT_LIST_HEAD(&ugeth->ind_hash_q); - if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || (uf_info->bd_mem_part == MEM_PART_MURAM))) { ugeth_err("%s: Bad memory partition value.", __FUNCTION__); @@ -2401,42 +2647,12 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) for (i = 0; i < ug_info->numQueuesTx; i++) uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); /* Initialize the general fast UCC block. */ - if (ucc_fast_init(uf_info, &ugeth->uccf)) { + if (ucc_fast_init(uf_info, &uccf)) { ugeth_err("%s: Failed to init uccf.", __FUNCTION__); ucc_geth_memclean(ugeth); return -ENOMEM; } - - ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); - - return 0; -} - -static int ucc_geth_startup(struct ucc_geth_private *ugeth) -{ - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - struct ucc_geth_init_pram *p_init_enet_pram; - struct ucc_fast_private *uccf; - struct ucc_geth_info *ug_info; - struct ucc_fast_info *uf_info; - struct ucc_fast *uf_regs; - struct ucc_geth *ug_regs; - int ret_val = -EINVAL; - u32 remoder = UCC_GETH_REMODER_INIT; - u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; - u32 ifstat, i, j, size, l2qt, l3qt, length; - u16 temoder = UCC_GETH_TEMODER_INIT; - u16 test; - u8 function_code = 0; - u8 *bd, *endOfRing; - u8 numThreadsRxNumerical, numThreadsTxNumerical; - - ugeth_vdbg("%s: IN", __FUNCTION__); - uccf = ugeth->uccf; - ug_info = ugeth->ug_info; - uf_info = &ug_info->uf_info; - uf_regs = uccf->uf_regs; - ug_regs = ugeth->ug_regs; + ugeth->uccf = uccf; switch (ug_info->numThreadsRx) { case UCC_GETH_NUM_OF_THREADS_1: @@ -2495,6 +2711,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) || (ug_info->vlanOperationNonTagged != UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); + uf_regs = uccf->uf_regs; + ug_regs = (struct ucc_geth *) (uccf->uf_regs); + ugeth->ug_regs = ug_regs; + init_default_reg_vals(&uf_regs->upsmr, &ug_regs->maccfg1, &ug_regs->maccfg2); @@ -2957,8 +3177,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) /* Size varies with number of Rx queues */ ugeth->rx_irq_coalescing_tbl_offset = qe_muram_alloc(ug_info->numQueuesRx * - sizeof(struct ucc_geth_rx_interrupt_coalescing_entry) - + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); + sizeof(struct ucc_geth_rx_interrupt_coalescing_entry), + UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { ugeth_err ("%s: Can not allocate DPRAM memory for" @@ -3139,6 +3359,13 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) for (j = 0; j < NUM_OF_PADDRS; j++) ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); + /* Create CQs for hash tables */ + if (ug_info->maxGroupAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->group_hash_q); + } + if (ug_info->maxIndAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->ind_hash_q); + } p_82xx_addr_filt = (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> p_rx_glbl_pram->addressfiltering; @@ -3335,9 +3562,6 @@ static void ucc_geth_timeout(struct net_device *dev) static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); -#ifdef CONFIG_UGETH_TX_ON_DEMAND - struct ucc_fast_private *uccf; -#endif u8 *bd; /* BD pointer */ u32 bd_status; u8 txQ = 0; @@ -3396,10 +3620,6 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); } -#ifdef CONFIG_UGETH_TX_ON_DEMAND - uccf = ugeth->uccf; - out_be16(uccf->p_utodr, UCC_FAST_TOD); -#endif spin_unlock_irq(&ugeth->lock); return 0; @@ -3415,6 +3635,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit ugeth_vdbg("%s: IN", __FUNCTION__); + spin_lock(&ugeth->lock); /* collect received buffers */ bd = ugeth->rxBd[rxQ]; @@ -3462,6 +3683,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit skb = get_new_skb(ugeth, bd); if (!skb) { ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); + spin_unlock(&ugeth->lock); ugeth->stats.rx_dropped++; break; } @@ -3482,6 +3704,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit } ugeth->rxBd[rxQ] = bd; + spin_unlock(&ugeth->lock); return howmany; } @@ -3533,38 +3756,23 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) static int ucc_geth_poll(struct net_device *dev, int *budget) { struct ucc_geth_private *ugeth = netdev_priv(dev); - struct ucc_geth_info *ug_info; - struct ucc_fast_private *uccf; int howmany; - u8 i; - int rx_work_limit; - register u32 uccm; - - ug_info = ugeth->ug_info; + int rx_work_limit = *budget; + u8 rxQ = 0; - rx_work_limit = *budget; if (rx_work_limit > dev->quota) rx_work_limit = dev->quota; - howmany = 0; - - for (i = 0; i < ug_info->numQueuesRx; i++) { - howmany += ucc_geth_rx(ugeth, i, rx_work_limit); - } + howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); dev->quota -= howmany; rx_work_limit -= howmany; *budget -= howmany; - if (rx_work_limit > 0) { + if (rx_work_limit >= 0) netif_rx_complete(dev); - uccf = ugeth->uccf; - uccm = in_be32(uccf->p_uccm); - uccm |= UCCE_RX_EVENTS; - out_be32(uccf->p_uccm, uccm); - } - return (rx_work_limit > 0) ? 0 : 1; + return (rx_work_limit < 0) ? 1 : 0; } #endif /* CONFIG_UGETH_NAPI */ @@ -3574,13 +3782,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) struct ucc_geth_private *ugeth = netdev_priv(dev); struct ucc_fast_private *uccf; struct ucc_geth_info *ug_info; - register u32 ucce; - register u32 uccm; -#ifndef CONFIG_UGETH_NAPI - register u32 rx_mask; -#endif - register u32 tx_mask; - u8 i; + register u32 ucce = 0; + register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; + register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; + register u8 i; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -3590,57 +3795,174 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) uccf = ugeth->uccf; ug_info = ugeth->ug_info; - /* read and clear events */ - ucce = (u32) in_be32(uccf->p_ucce); - uccm = (u32) in_be32(uccf->p_uccm); - ucce &= uccm; - out_be32(uccf->p_ucce, ucce); + do { + ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); + + /* clear event bits for next time */ + /* Side effect here is to mask ucce variable + for future processing below. */ + out_be32(uccf->p_ucce, ucce); /* Clear with ones, + but only bits in UCCM */ + + /* We ignore Tx interrupts because Tx confirmation is + done inside Tx routine */ - /* check for receive events that require processing */ - if (ucce & UCCE_RX_EVENTS) { -#ifdef CONFIG_UGETH_NAPI - if (netif_rx_schedule_prep(dev)) { - uccm &= ~UCCE_RX_EVENTS; - out_be32(uccf->p_uccm, uccm); - __netif_rx_schedule(dev); - } -#else - rx_mask = UCCE_RXBF_SINGLE_MASK; for (i = 0; i < ug_info->numQueuesRx; i++) { - if (ucce & rx_mask) - ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]); - ucce &= ~rx_mask; - rx_mask <<= 1; + if (ucce & bit_mask) + ucc_geth_rx(ugeth, i, + (int)ugeth->ug_info-> + bdRingLenRx[i]); + ucce &= ~bit_mask; + bit_mask <<= 1; } -#endif /* CONFIG_UGETH_NAPI */ - } - /* Tx event processing */ - if (ucce & UCCE_TX_EVENTS) { - spin_lock(&ugeth->lock); - tx_mask = UCCE_TXBF_SINGLE_MASK; for (i = 0; i < ug_info->numQueuesTx; i++) { if (ucce & tx_mask) ucc_geth_tx(dev, i); ucce &= ~tx_mask; tx_mask <<= 1; } - spin_unlock(&ugeth->lock); - } - /* Errors and other events */ - if (ucce & UCCE_OTHER) { + /* Exceptions */ if (ucce & UCCE_BSY) { + ugeth_vdbg("Got BUSY irq!!!!"); ugeth->stats.rx_errors++; + ucce &= ~UCCE_BSY; } - if (ucce & UCCE_TXE) { - ugeth->stats.tx_errors++; + if (ucce & UCCE_OTHER) { + ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", + ucce); + ugeth->stats.rx_errors++; + ucce &= ~ucce; } } + while (ucce); + + return IRQ_HANDLED; +} + +static irqreturn_t phy_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct ucc_geth_private *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupt */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); + + /* Schedule the phy change */ + schedule_work(&ugeth->tq); return IRQ_HANDLED; } +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void ugeth_phy_change(struct work_struct *work) +{ + struct ucc_geth_private *ugeth = + container_of(work, struct ucc_geth_private, tq); + struct net_device *dev = ugeth->dev; + struct ucc_geth *ug_regs; + int result = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_regs = ugeth->ug_regs; + + /* Delay to give the PHY a chance to change the + * register state */ + msleep(1); + + /* Update the link, speed, duplex */ + result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); + + /* Adjust the known status as long as the link + * isn't still coming up */ + if ((0 == result) || (ugeth->mii_info->link == 0)) + adjust_link(dev); + + /* Reenable interrupts, if needed */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); +} + +/* Called every so often on systems that don't interrupt + * the core for PHY changes */ +static void ugeth_phy_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct ucc_geth_private *ugeth = netdev_priv(dev); + + schedule_work(&ugeth->tq); + + mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); +} + +/* Keep trying aneg for some time + * If, after GFAR_AN_TIMEOUT seconds, it has not + * finished, we switch to forced. + * Either way, once the process has completed, we either + * request the interrupt, or switch the timer over to + * using ugeth_phy_timer to check status */ +static void ugeth_phy_startup_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); + static int secondary = UGETH_AN_TIMEOUT; + int result; + + /* Configure the Auto-negotiation */ + result = mii_info->phyinfo->config_aneg(mii_info); + + /* If autonegotiation failed to start, and + * we haven't timed out, reset the timer, and return */ + if (result && secondary--) { + mod_timer(&ugeth->phy_info_timer, jiffies + HZ); + return; + } else if (result) { + /* Couldn't start autonegotiation. + * Try switching to forced */ + mii_info->autoneg = 0; + result = mii_info->phyinfo->config_aneg(mii_info); + + /* Forcing failed! Give up */ + if (result) { + ugeth_err("%s: Forcing failed!", mii_info->dev->name); + return; + } + } + + /* Kill the timer so it can be restarted */ + del_timer_sync(&ugeth->phy_info_timer); + + /* Grab the PHY interrupt, if necessary/possible */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + if (request_irq(ugeth->ug_info->phy_interrupt, + phy_interrupt, IRQF_SHARED, + "phy_interrupt", mii_info->dev) < 0) { + ugeth_err("%s: Can't get IRQ %d (PHY)", + mii_info->dev->name, + ugeth->ug_info->phy_interrupt); + } else { + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); + return; + } + } + + /* Start the timer again, this time in order to + * handle a change in status */ + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_timer; + ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; + mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); +} + /* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) @@ -3657,12 +3979,6 @@ static int ucc_geth_open(struct net_device *dev) return -EINVAL; } - err = ucc_struct_init(ugeth); - if (err) { - ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); - return err; - } - err = ucc_geth_startup(ugeth); if (err) { ugeth_err("%s: Cannot configure net device, aborting.", @@ -3690,12 +4006,10 @@ static int ucc_geth_open(struct net_device *dev) err = init_phy(dev); if (err) { - ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); + ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); return err; } - - phy_start(ugeth->phydev); - +#ifndef CONFIG_UGETH_NAPI err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, "UCC Geth", dev); @@ -3705,6 +4019,15 @@ static int ucc_geth_open(struct net_device *dev) ucc_geth_stop(ugeth); return err; } +#endif /* CONFIG_UGETH_NAPI */ + + /* Set up the PHY change work queue */ + INIT_WORK(&ugeth->tq, ugeth_phy_change); + + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; + ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; + mod_timer(&ugeth->phy_info_timer, jiffies + HZ); err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { @@ -3727,8 +4050,11 @@ static int ucc_geth_close(struct net_device *dev) ucc_geth_stop(ugeth); - phy_disconnect(ugeth->phydev); - ugeth->phydev = NULL; + /* Shutdown the PHY */ + if (ugeth->mii_info->phyinfo->close) + ugeth->mii_info->phyinfo->close(ugeth->mii_info); + + kfree(ugeth->mii_info); netif_stop_queue(dev); @@ -3737,53 +4063,20 @@ static int ucc_geth_close(struct net_device *dev) const struct ethtool_ops ucc_geth_ethtool_ops = { }; -static phy_interface_t to_phy_interface(const char *interface_type) -{ - if (strcasecmp(interface_type, "mii") == 0) - return PHY_INTERFACE_MODE_MII; - if (strcasecmp(interface_type, "gmii") == 0) - return PHY_INTERFACE_MODE_GMII; - if (strcasecmp(interface_type, "tbi") == 0) - return PHY_INTERFACE_MODE_TBI; - if (strcasecmp(interface_type, "rmii") == 0) - return PHY_INTERFACE_MODE_RMII; - if (strcasecmp(interface_type, "rgmii") == 0) - return PHY_INTERFACE_MODE_RGMII; - if (strcasecmp(interface_type, "rgmii-id") == 0) - return PHY_INTERFACE_MODE_RGMII_ID; - if (strcasecmp(interface_type, "rtbi") == 0) - return PHY_INTERFACE_MODE_RTBI; - - return PHY_INTERFACE_MODE_MII; -} - static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) { struct device *device = &ofdev->dev; struct device_node *np = ofdev->node; - struct device_node *mdio; struct net_device *dev = NULL; struct ucc_geth_private *ugeth = NULL; struct ucc_geth_info *ug_info; struct resource res; struct device_node *phy; - int err, ucc_num, max_speed = 0; + int err, ucc_num, phy_interface; + static int mii_mng_configured = 0; const phandle *ph; const unsigned int *prop; const void *mac_addr; - phy_interface_t phy_interface; - static const int enet_to_speed[] = { - SPEED_10, SPEED_10, SPEED_10, - SPEED_100, SPEED_100, SPEED_100, - SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, - }; - static const phy_interface_t enet_to_phy_interface[] = { - PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, - PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, - PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, - PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, - PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, - }; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -3794,7 +4087,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info = &ugeth_info[ucc_num]; ug_info->uf_info.ucc_num = ucc_num; - prop = get_property(np, "rx-clock", NULL); ug_info->uf_info.rx_clock = *prop; prop = get_property(np, "tx-clock", NULL); @@ -3812,72 +4104,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma if (phy == NULL) return -ENODEV; - /* set the PHY address */ prop = get_property(phy, "reg", NULL); - if (prop == NULL) - return -1; ug_info->phy_address = *prop; - - /* get the phy interface type, or default to MII */ - prop = get_property(np, "interface-type", NULL); - if (!prop) { - /* handle interface property present in old trees */ - prop = get_property(phy, "interface", NULL); - if (prop != NULL) - phy_interface = enet_to_phy_interface[*prop]; - else - phy_interface = PHY_INTERFACE_MODE_MII; - } else { - phy_interface = to_phy_interface((const char *)prop); - } - - /* get speed, or derive from interface */ - prop = get_property(np, "max-speed", NULL); - if (!prop) { - /* handle interface property present in old trees */ - prop = get_property(phy, "interface", NULL); - if (prop != NULL) - max_speed = enet_to_speed[*prop]; - } else { - max_speed = *prop; - } - if (!max_speed) { - switch (phy_interface) { - case PHY_INTERFACE_MODE_GMII: - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_TBI: - case PHY_INTERFACE_MODE_RTBI: - max_speed = SPEED_1000; - break; - default: - max_speed = SPEED_100; - break; - } - } - - if (max_speed == SPEED_1000) { - ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; - ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; - ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; - ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; - ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; - ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; - } - - /* Set the bus id */ - mdio = of_get_parent(phy); - - if (mdio == NULL) - return -1; - - err = of_address_to_resource(mdio, 0, &res); - of_node_put(mdio); - - if (err) - return -1; - - ug_info->mdio_bus = res.start; + prop = get_property(phy, "interface", NULL); + ug_info->enet_interface = *prop; + ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); + ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? + 0:FSL_UGETH_BRD_HAS_PHY_INTR; printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, @@ -3889,6 +4122,43 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma return -ENODEV; } + /* FIXME: Work around for early chip rev. */ + /* There's a bug in initial chip rev(s) in the RGMII ac */ + /* timing. */ + /* The following compensates by writing to the reserved */ + /* QE Port Output Hold Registers (CPOH1?). */ + prop = get_property(phy, "interface", NULL); + phy_interface = *prop; + if ((phy_interface == ENET_1000_RGMII) || + (phy_interface == ENET_100_RGMII) || + (phy_interface == ENET_10_RGMII)) { + struct device_node *soc; + phys_addr_t immrbase = -1; + u32 *tmp_reg; + u32 tmp_val; + + soc = of_find_node_by_type(NULL, "soc"); + if (soc) { + unsigned int size; + const void *prop = get_property(soc, "reg", &size); + immrbase = of_translate_address(soc, prop); + of_node_put(soc); + }; + + tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); + tmp_val = in_be32(tmp_reg); + if (ucc_num == 1) + out_be32(tmp_reg, tmp_val | 0x00003000); + else if (ucc_num == 2) + out_be32(tmp_reg, tmp_val | 0x0c000000); + iounmap(tmp_reg); + } + + if (!mii_mng_configured) { + ucc_set_qe_mux_mii_mng(ucc_num); + mii_mng_configured = 1; + } + /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof(*ugeth)); @@ -3922,10 +4192,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->set_multicast_list = ucc_geth_set_multi; dev->ethtool_ops = &ucc_geth_ethtool_ops; - ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; - ugeth->phy_interface = phy_interface; - ugeth->max_speed = max_speed; - err = register_netdev(dev); if (err) { ugeth_err("%s: Cannot register net device, aborting.", @@ -3934,13 +4200,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma return err; } + ugeth->ug_info = ug_info; + ugeth->dev = dev; + mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(dev->dev_addr, mac_addr, 6); - ugeth->ug_info = ug_info; - ugeth->dev = dev; - return 0; } @@ -3976,30 +4242,19 @@ static struct of_platform_driver ucc_geth_driver = { static int __init ucc_geth_init(void) { - int i, ret; - - ret = uec_mdio_init(); - - if (ret) - return ret; + int i; printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); for (i = 0; i < 8; i++) memcpy(&(ugeth_info[i]), &ugeth_primary_info, sizeof(ugeth_primary_info)); - ret = of_register_platform_driver(&ucc_geth_driver); - - if (ret) - uec_mdio_exit(); - - return ret; + return of_register_platform_driver(&ucc_geth_driver); } static void __exit ucc_geth_exit(void) { of_unregister_platform_driver(&ucc_geth_driver); - uec_mdio_exit(); } module_init(ucc_geth_init); @@ -4007,5 +4262,4 @@ module_exit(ucc_geth_exit); MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION(DRV_DESC); -MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/ucc_geth.h b/trunk/drivers/net/ucc_geth.h index a29e1c3ca4b7..a66561253593 100644 --- a/trunk/drivers/net/ucc_geth.h +++ b/trunk/drivers/net/ucc_geth.h @@ -28,8 +28,6 @@ #include #include -#include "ucc_geth_mii.h" - #define NUM_TX_QUEUES 8 #define NUM_RX_QUEUES 8 #define NUM_BDS_IN_PREFETCHED_BDS 4 @@ -38,6 +36,15 @@ #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 +struct ucc_mii_mng { + u32 miimcfg; /* MII management configuration reg */ + u32 miimcom; /* MII management command reg */ + u32 miimadd; /* MII management address reg */ + u32 miimcon; /* MII management control reg */ + u32 miimstat; /* MII management status reg */ + u32 miimind; /* MII management indication reg */ +} __attribute__ ((packed)); + struct ucc_geth { struct ucc_fast uccf; @@ -46,7 +53,7 @@ struct ucc_geth { u32 ipgifg; /* interframe gap reg. */ u32 hafdup; /* half-duplex reg. */ u8 res1[0x10]; - u8 miimng[0x18]; /* MII management structure moved to _mii.h */ + struct ucc_mii_mng miimng; /* MII management structure */ u32 ifctl; /* interface control reg */ u32 ifstat; /* interface statux reg */ u32 macstnaddr1; /* mac station address part 1 reg */ @@ -205,9 +212,6 @@ struct ucc_geth { #define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ UCCE_RXC | UCCE_TXC | UCCE_TXE) -#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY) -#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE) - /* UCC GETH UPSMR (Protocol Specific Mode Register) */ #define UPSMR_ECM 0x04000000 /* Enable CAM Miss or @@ -377,6 +381,66 @@ struct ucc_geth { #define UCCS_MPD 0x01 /* Magic Packet Detected */ +/* UCC GETH MIIMCFG (MII Management Configuration Register) */ +#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset + management */ +#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble + suppress */ +#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide + << shift */ +#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by + 112 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by + 160 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by + 224 */ + +/* UCC GETH MIIMCOM (MII Management Command Register) */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ + +/* UCC GETH MIIMADD (MII Management Address Register) */ +#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address + << shift */ +#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register + << shift */ + +/* UCC GETH MIIMCON (MII Management Control Register) */ +#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control + << shift */ +#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status + << shift */ + +/* UCC GETH MIIMIND (MII Management Indicator Register) */ +#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ +#define MIIMIND_SCAN 0x00000002 /* Scan in + progress */ +#define MIIMIND_BUSY 0x00000001 + /* UCC GETH IFSTAT (Interface Status Register) */ #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive transmission @@ -867,7 +931,8 @@ struct ucc_geth_hardware_statistics { #define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */ #define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */ #define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */ -#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 64 +#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a + guess */ #define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */ #define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */ #define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This @@ -944,6 +1009,15 @@ struct ucc_geth_hardware_statistics { register */ #define UCC_GETH_MACCFG1_INIT 0 #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) +#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ + (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) + +/* Ethernet speed */ +enum enet_speed { + ENET_SPEED_10BT, /* 10 Base T */ + ENET_SPEED_100BT, /* 100 Base T */ + ENET_SPEED_1000BT /* 1000 Base T */ +}; /* Ethernet Address Type. */ enum enet_addr_type { @@ -952,6 +1026,22 @@ enum enet_addr_type { ENET_ADDR_TYPE_BROADCAST }; +/* TBI / MII Set Register */ +enum enet_tbi_mii_reg { + ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ + ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ + ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ + ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability + (ANLPBPA) */ + ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ + ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ + ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page + (ANLPANP) */ + ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ + ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ + ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ +}; + /* UCC GETH 82xx Ethernet Address Recognition Location */ enum ucc_geth_enet_address_recognition_location { UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station @@ -1149,7 +1239,8 @@ struct ucc_geth_info { u16 pausePeriod; u16 extensionField; u8 phy_address; - u32 mdio_bus; + u32 board_flags; + u32 phy_interrupt; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; @@ -1158,6 +1249,7 @@ struct ucc_geth_info { u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; u16 bdRingLenTx[NUM_TX_QUEUES]; u16 bdRingLenRx[NUM_RX_QUEUES]; + enum enet_interface enet_interface; enum ucc_geth_num_of_station_addresses numStationAddresses; enum qe_fltr_largest_external_tbl_lookup_key_size largestexternallookupkeysize; @@ -1234,11 +1326,9 @@ struct ucc_geth_private { /* index of the first skb which hasn't been transmitted yet. */ u16 skb_dirtytx[NUM_TX_QUEUES]; + struct work_struct tq; + struct timer_list phy_info_timer; struct ugeth_mii_info *mii_info; - struct phy_device *phydev; - phy_interface_t phy_interface; - int max_speed; - uint32_t msg_enable; int oldspeed; int oldduplex; int oldlink; diff --git a/trunk/drivers/net/ucc_geth_mii.c b/trunk/drivers/net/ucc_geth_mii.c deleted file mode 100644 index 73b5a538e8f4..000000000000 --- a/trunk/drivers/net/ucc_geth_mii.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * drivers/net/ucc_geth_mii.c - * - * Gianfar Ethernet Driver -- MIIM bus implementation - * Provides Bus interface for MIIM regs - * - * Author: Li Yang - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#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 "ucc_geth_mii.h" -#include "ucc_geth.h" - -#define DEBUG -#ifdef DEBUG -#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg) -#else -#define vdbg(format, arg...) do {} while(0) -#endif - -#define DRV_DESC "QE UCC Ethernet Controller MII Bus" -#define DRV_NAME "fsl-uec_mdio" - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the master UEC MIIM regs */ -int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) -{ - struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; - - /* Setting up the MII Mangement Address Register */ - out_be32(®s->miimadd, - (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); - - /* Setting up the MII Mangement Control Register with the value */ - out_be32(®s->miimcon, value); - - /* Wait till MII management write is complete */ - while ((in_be32(®s->miimind)) & MIIMIND_BUSY) - cpu_relax(); - - return 0; -} - -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; - u16 value; - - /* Setting up the MII Mangement Address Register */ - out_be32(®s->miimadd, - (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); - - /* Clear miimcom, perform an MII management read cycle */ - out_be32(®s->miimcom, 0); - out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); - - /* Wait till MII management write is complete */ - while ((in_be32(®s->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID)) - cpu_relax(); - - /* Read MII management status */ - value = in_be32(®s->miimstat); - - return value; -} - -/* Reset the MIIM registers, and wait for the bus to free */ -int uec_mdio_reset(struct mii_bus *bus) -{ - struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; - unsigned int timeout = PHY_INIT_TIMEOUT; - - spin_lock_bh(&bus->mdio_lock); - - /* Reset the management interface */ - out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); - - /* Setup the MII Mgmt clock speed */ - out_be32(®s->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112); - - /* Wait until the bus is free */ - while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) - cpu_relax(); - - spin_unlock_bh(&bus->mdio_lock); - - if (timeout <= 0) { - printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); - return -EBUSY; - } - - return 0; -} - -static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) -{ - struct device *device = &ofdev->dev; - struct device_node *np = ofdev->node, *tempnp = NULL; - struct device_node *child = NULL; - struct ucc_mii_mng __iomem *regs; - struct mii_bus *new_bus; - struct resource res; - int k, err = 0; - - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - - if (NULL == new_bus) - return -ENOMEM; - - new_bus->name = "UCC Ethernet Controller MII Bus"; - new_bus->read = &uec_mdio_read; - new_bus->write = &uec_mdio_write; - new_bus->reset = &uec_mdio_reset; - - memset(&res, 0, sizeof(res)); - - err = of_address_to_resource(np, 0, &res); - if (err) - goto reg_map_fail; - - new_bus->id = res.start; - - new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); - - if (NULL == new_bus->irq) { - err = -ENOMEM; - goto reg_map_fail; - } - - for (k = 0; k < 32; k++) - new_bus->irq[k] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = get_property(child, "reg", NULL); - new_bus->irq[*id] = irq; - } - } - - /* Set the base address */ - regs = ioremap(res.start, sizeof(struct ucc_mii_mng)); - - if (NULL == regs) { - err = -ENOMEM; - goto ioremap_fail; - } - - new_bus->priv = (void __force *)regs; - - new_bus->dev = device; - dev_set_drvdata(device, new_bus); - - /* Read MII management master from device tree */ - while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth")) - != NULL) { - struct resource tempres; - - err = of_address_to_resource(tempnp, 0, &tempres); - if (err) - goto bus_register_fail; - - /* if our mdio regs fall within this UCC regs range */ - if ((res.start >= tempres.start) && - (res.end <= tempres.end)) { - /* set this UCC to be the MII master */ - const u32 *id = get_property(tempnp, "device-id", NULL); - if (id == NULL) - goto bus_register_fail; - - ucc_set_qe_mux_mii_mng(*id - 1); - - /* assign the TBI an address which won't - * conflict with the PHYs */ - out_be32(®s->utbipar, UTBIPAR_INIT_TBIPA); - break; - } - } - - err = mdiobus_register(new_bus); - if (0 != err) { - printk(KERN_ERR "%s: Cannot register as MDIO bus\n", - new_bus->name); - goto bus_register_fail; - } - - return 0; - -bus_register_fail: - iounmap(regs); -ioremap_fail: - kfree(new_bus->irq); -reg_map_fail: - kfree(new_bus); - - return err; -} - -int uec_mdio_remove(struct of_device *ofdev) -{ - struct device *device = &ofdev->dev; - struct mii_bus *bus = dev_get_drvdata(device); - - mdiobus_unregister(bus); - - dev_set_drvdata(device, NULL); - - iounmap((void __iomem *)bus->priv); - bus->priv = NULL; - kfree(bus); - - return 0; -} - -static struct of_device_id uec_mdio_match[] = { - { - .type = "mdio", - .compatible = "ucc_geth_phy", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, uec_mdio_match); - -static struct of_platform_driver uec_mdio_driver = { - .name = DRV_NAME, - .probe = uec_mdio_probe, - .remove = uec_mdio_remove, - .match_table = uec_mdio_match, -}; - -int __init uec_mdio_init(void) -{ - return of_register_platform_driver(&uec_mdio_driver); -} - -void __exit uec_mdio_exit(void) -{ - of_unregister_platform_driver(&uec_mdio_driver); -} diff --git a/trunk/drivers/net/ucc_geth_mii.h b/trunk/drivers/net/ucc_geth_mii.h deleted file mode 100644 index 98430fe0bfc6..000000000000 --- a/trunk/drivers/net/ucc_geth_mii.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * drivers/net/ucc_geth_mii.h - * - * Gianfar Ethernet Driver -- MII Management Bus Implementation - * Driver for the MDIO bus controller in the Gianfar register space - * - * Author: Andy Fleming - * Maintainer: Kumar Gala - * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#ifndef __UEC_MII_H -#define __UEC_MII_H - -/* UCC GETH MIIMCFG (MII Management Configuration Register) */ -#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset - management */ -#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble - suppress */ -#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide - << shift */ -#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f - -/* UCC GETH MIIMCOM (MII Management Command Register) */ -#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ -#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ - -/* UCC GETH MIIMADD (MII Management Address Register) */ -#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address - << shift */ -#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register - << shift */ - -/* UCC GETH MIIMCON (MII Management Control Register) */ -#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control - << shift */ -#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status - << shift */ - -/* UCC GETH MIIMIND (MII Management Indicator Register) */ -#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ -#define MIIMIND_SCAN 0x00000002 /* Scan in - progress */ -#define MIIMIND_BUSY 0x00000001 - -/* Initial TBI Physical Address */ -#define UTBIPAR_INIT_TBIPA 0x1f - -struct ucc_mii_mng { - u32 miimcfg; /* MII management configuration reg */ - u32 miimcom; /* MII management command reg */ - u32 miimadd; /* MII management address reg */ - u32 miimcon; /* MII management control reg */ - u32 miimstat; /* MII management status reg */ - u32 miimind; /* MII management indication reg */ - u8 notcare[28]; /* Space holder */ - u32 utbipar; /* TBI phy address reg */ -} __attribute__ ((packed)); - -/* TBI / MII Set Register */ -enum enet_tbi_mii_reg { - ENET_TBI_MII_CR = 0x00, /* Control */ - ENET_TBI_MII_SR = 0x01, /* Status */ - ENET_TBI_MII_ANA = 0x04, /* AN advertisement */ - ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */ - ENET_TBI_MII_ANEX = 0x06, /* AN expansion */ - ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */ - ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */ - ENET_TBI_MII_EXST = 0x0F, /* Extended status */ - ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */ - ENET_TBI_MII_TBICON = 0x11 /* TBI control */ -}; - -int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); -int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); -int __init uec_mdio_init(void); -void __exit uec_mdio_exit(void); -#endif /* __UEC_MII_H */ diff --git a/trunk/drivers/net/ucc_geth_phy.c b/trunk/drivers/net/ucc_geth_phy.c new file mode 100644 index 000000000000..9373d895b9ec --- /dev/null +++ b/trunk/drivers/net/ucc_geth_phy.c @@ -0,0 +1,785 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" + +#define ugphy_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugphy_dbg(format, arg...) \ + ugphy_printk(KERN_DEBUG, format , ## arg) +#define ugphy_err(format, arg...) \ + ugphy_printk(KERN_ERR, format , ## arg) +#define ugphy_info(format, arg...) \ + ugphy_printk(KERN_INFO, format , ## arg) +#define ugphy_warn(format, arg...) \ + ugphy_printk(KERN_WARNING, format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugphy_vdbg ugphy_dbg +#else +#define ugphy_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static void config_genmii_advert(struct ugeth_mii_info *mii_info); +static void genmii_setup_forced(struct ugeth_mii_info *mii_info); +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); +static int gbit_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_update_link(struct ugeth_mii_info *mii_info); +static int genmii_read_status(struct ugeth_mii_info *mii_info); + +static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); + + return retval; +} + +static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); +} + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_mii_mng *mii_regs; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; + u32 tmp_reg; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + /* Stop the MII management read cycle */ + out_be32(&mii_regs->miimcom, 0); + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Setting up the MII Mangement Control Register with the value */ + out_be32(&mii_regs->miimcon, (u32) value); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + spin_unlock_irq(&ugeth->lock); + + udelay(10000); +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value. Clears miimcom first. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +int read_phy_reg(struct net_device *dev, int mii_id, int regnum) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_mii_mng *mii_regs; + enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; + u32 tmp_reg; + u16 value; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Perform an MII management read cycle */ + out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + udelay(10000); + + /* Read MII management status */ + value = (u16) in_be32(&mii_regs->miimstat); + out_be32(&mii_regs->miimcom, 0); + if (value == 0xffff) + ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", + mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); + + spin_unlock_irq(&ugeth->lock); + + return (value); +} + +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->phyinfo->ack_interrupt) + mii_info->phyinfo->ack_interrupt(mii_info); +} + +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + mii_info->interrupts = interrupts; + if (mii_info->phyinfo->config_intr) + mii_info->phyinfo->config_intr(mii_info); +} + +/* Writes MII_ADVERTISE with the appropriate values, after + * sanitizing advertise to make sure only supported features + * are advertised + */ +static void config_genmii_advert(struct ugeth_mii_info *mii_info) +{ + u32 advertise; + u16 adv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Only allow advertising what this PHY supports */ + mii_info->advertising &= mii_info->phyinfo->features; + advertise = mii_info->advertising; + + /* Setup standard advertisement */ + adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv); +} + +static void genmii_setup_forced(struct ugeth_mii_info *mii_info) +{ + u16 ctrl; + u32 features = mii_info->phyinfo->features; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + ctrl = ucc_geth_phy_read(mii_info, MII_BMCR); + + ctrl &= + ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + ctrl |= BMCR_RESET; + + switch (mii_info->speed) { + case SPEED_1000: + if (features & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + ctrl |= BMCR_SPEED1000; + break; + } + mii_info->speed = SPEED_100; + case SPEED_100: + if (features & (SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full)) { + ctrl |= BMCR_SPEED100; + break; + } + mii_info->speed = SPEED_10; + case SPEED_10: + if (features & (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full)) + break; + default: /* Unsupported speed! */ + ugphy_err("%s: Bad speed!", mii_info->dev->name); + break; + } + + ucc_geth_phy_write(mii_info, MII_BMCR, ctrl); +} + +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) +{ + u16 ctl; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + ctl = ucc_geth_phy_read(mii_info, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + ucc_geth_phy_write(mii_info, MII_BMCR, ctl); +} + +static int gbit_config_aneg(struct ugeth_mii_info *mii_info) +{ + u16 adv; + u32 advertise; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->autoneg) { + /* Configure the ADVERTISE register */ + config_genmii_advert(mii_info); + advertise = mii_info->advertising; + + adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL); + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + +static int genmii_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->autoneg) { + config_genmii_advert(mii_info); + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + +static int genmii_update_link(struct ugeth_mii_info *mii_info) +{ + u16 status; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Do a fake read */ + ucc_geth_phy_read(mii_info, MII_BMSR); + + /* Read link and autonegotiation status */ + status = ucc_geth_phy_read(mii_info, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + mii_info->link = 0; + else + mii_info->link = 1; + + /* If we are autonegotiating, and not done, + * return an error */ + if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return -EAGAIN; + + return 0; +} + +static int genmii_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + if (mii_info->autoneg) { + status = ucc_geth_phy_read(mii_info, MII_LPA); + + if (status & (LPA_10FULL | LPA_100FULL)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + if (status & (LPA_100FULL | LPA_100HALF)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + mii_info->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +static int marvell_init(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); + ucc_geth_phy_write(mii_info, 0x1b, + (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); + msleep(4000); + + return 0; +} + +static int marvell_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET); + + ucc_geth_phy_write(mii_info, 0x1d, 0x1f); + ucc_geth_phy_write(mii_info, 0x1e, 0x200c); + ucc_geth_phy_write(mii_info, 0x1d, 0x5); + ucc_geth_phy_write(mii_info, 0x1e, 0); + ucc_geth_phy_write(mii_info, 0x1e, 0x100); + + gbit_config_aneg(mii_info); + + return 0; +} + +static int marvell_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); + + /* Get the duplexity */ + if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + /* Get the speed */ + speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; + switch (speed) { + case MII_M1011_PHY_SPEC_STATUS_1000: + mii_info->speed = SPEED_1000; + break; + case MII_M1011_PHY_SPEC_STATUS_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + mii_info->pause = 0; + } + + return 0; +} + +static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + ucc_geth_phy_read(mii_info, MII_M1011_IEVENT); + + return 0; +} + +static int marvell_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + else + ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return 0; +} + +static int cis820x_init(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); + + return 0; +} + +static int cis820x_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + + status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); + if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + speed = status & MII_CIS8201_AUXCONSTAT_SPEED; + + switch (speed) { + case MII_CIS8201_AUXCONSTAT_GBIT: + mii_info->speed = SPEED_1000; + break; + case MII_CIS8201_AUXCONSTAT_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + } + + return 0; +} + +static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT); + + return 0; +} + +static int cis820x_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); + else + ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0); + + return 0; +} + +#define DM9161_DELAY 10 + +static int dm9161_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR); + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + } + + return 0; +} + +static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (0 == priv->resetdone) + return -EAGAIN; + + return 0; +} + +static void dm9161_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + struct dm9161_private *priv = mii_info->priv; + u16 status = ucc_geth_phy_read(mii_info, MII_BMSR); + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (status & BMSR_ANEGCOMPLETE) { + priv->resetdone = 1; + } else + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); +} + +static int dm9161_init(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Allocate the private data structure */ + priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); + + if (NULL == priv) + return -ENOMEM; + + mii_info->priv = priv; + + /* Reset is not done yet */ + priv->resetdone = 0; + + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); + + ucc_geth_phy_write(mii_info, MII_BMCR, + ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); + + config_genmii_advert(mii_info); + /* Start/Restart aneg */ + genmii_config_aneg(mii_info); + + /* Start a timer for DM9161_DELAY seconds to wait + * for the PHY to be ready */ + init_timer(&priv->timer); + priv->timer.function = &dm9161_timer; + priv->timer.data = (unsigned long)mii_info; + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); + + return 0; +} + +static void dm9161_close(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + del_timer_sync(&priv->timer); + kfree(priv); +} + +static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + ucc_geth_phy_read(mii_info, MII_DM9161_INTR); + + + return 0; +} + +static int dm9161_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + else + ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + + return 0; +} + +/* Cicada 820x */ +static struct phy_info phy_info_cis820x = { + .phy_id = 0x000fc440, + .name = "Cicada Cis8204", + .phy_id_mask = 0x000fffc0, + .features = MII_GBIT_FEATURES, + .init = &cis820x_init, + .config_aneg = &gbit_config_aneg, + .read_status = &cis820x_read_status, + .ack_interrupt = &cis820x_ack_interrupt, + .config_intr = &cis820x_config_intr, +}; + +static struct phy_info phy_info_dm9161 = { + .phy_id = 0x0181b880, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161E", + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .close = dm9161_close, +}; + +static struct phy_info phy_info_dm9161a = { + .phy_id = 0x0181b8a0, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161A", + .features = MII_BASIC_FEATURES, + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .ack_interrupt = dm9161_ack_interrupt, + .config_intr = dm9161_config_intr, + .close = dm9161_close, +}; + +static struct phy_info phy_info_marvell = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E11x1", + .features = MII_GBIT_FEATURES, + .init = &marvell_init, + .config_aneg = &marvell_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, +}; + +static struct phy_info phy_info_genmii = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .features = MII_BASIC_FEATURES, + .config_aneg = genmii_config_aneg, + .read_status = genmii_read_status, +}; + +static struct phy_info *phy_info[] = { + &phy_info_cis820x, + &phy_info_marvell, + &phy_info_dm9161, + &phy_info_dm9161a, + &phy_info_genmii, + NULL +}; + +/* Use the PHY ID registers to determine what type of PHY is attached + * to device dev. return a struct phy_info structure describing that PHY + */ +struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) +{ + u16 phy_reg; + u32 phy_ID; + int i; + struct phy_info *theInfo = NULL; + struct net_device *dev = mii_info->dev; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Grab the bits from PHYIR1, and put them in the upper half */ + phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1); + phy_ID = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2); + phy_ID |= (phy_reg & 0xffff); + + /* loop through all the known PHY types, and find one that */ + /* matches the ID we read from the PHY. */ + for (i = 0; phy_info[i]; i++) + if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ + theInfo = phy_info[i]; + break; + } + + /* This shouldn't happen, as we have generic PHY support */ + if (theInfo == NULL) { + ugphy_info("%s: PHY id %x is not supported!", dev->name, + phy_ID); + return NULL; + } else { + ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, + phy_ID); + } + + return theInfo; +} diff --git a/trunk/drivers/net/ucc_geth_phy.h b/trunk/drivers/net/ucc_geth_phy.h new file mode 100644 index 000000000000..f5740783670f --- /dev/null +++ b/trunk/drivers/net/ucc_geth_phy.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __UCC_GETH_PHY_H__ +#define __UCC_GETH_PHY_H__ + +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define UGETH_AN_TIMEOUT 2000 + +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL 0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 + +/* 88E1011 PHY Status Register */ +#define MII_M1011_PHY_SPEC_STATUS 0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 + +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 + +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 + +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MII_DM9161_SCSR 0x11 +#define MII_DM9161_SCSR_100F 0x8000 +#define MII_DM9161_SCSR_100H 0x4000 +#define MII_DM9161_SCSR_10F 0x2000 +#define MII_DM9161_SCSR_10H 0x1000 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +#define MII_READ_COMMAND 0x00000001 + +#define MII_INTERRUPT_DISABLED 0x0 +#define MII_INTERRUPT_ENABLED 0x1 +/* Taken from mii_if_info and sungem_phy.h */ +struct ugeth_mii_info { + /* Information about the PHY type */ + /* And management functions */ + struct phy_info *phyinfo; + + struct ucc_mii_mng *mii_regs; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + + /* The most recently read link state */ + int link; + + /* Enabled Interrupts */ + u32 interrupts; + + u32 advertising; + int autoneg; + int mii_id; + + /* private data pointer */ + /* For use by PHYs to maintain extra state */ + void *priv; + + /* Provided by host chip */ + struct net_device *dev; + + /* A lock to ensure that only one thing can read/write + * the MDIO bus at a time */ + spinlock_t mdio_lock; + + /* Provided by ethernet driver */ + int (*mdio_read) (struct net_device * dev, int mii_id, int reg); + void (*mdio_write) (struct net_device * dev, int mii_id, int reg, + int val); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY. During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is. The 32-bit result + * gotten from the PHY will be ANDed with phy_id_mask to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * There are 6 commands which take a ugeth_mii_info structure. + * Each PHY must declare config_aneg, and read_status. + */ +struct phy_info { + u32 phy_id; + char *name; + unsigned int phy_id_mask; + u32 features; + + /* Called to initialize the PHY */ + int (*init) (struct ugeth_mii_info * mii_info); + + /* Called to suspend the PHY for power */ + int (*suspend) (struct ugeth_mii_info * mii_info); + + /* Reconfigures autonegotiation (or disables it) */ + int (*config_aneg) (struct ugeth_mii_info * mii_info); + + /* Determines the negotiated speed and duplex */ + int (*read_status) (struct ugeth_mii_info * mii_info); + + /* Clears any pending interrupts */ + int (*ack_interrupt) (struct ugeth_mii_info * mii_info); + + /* Enables or disables interrupts */ + int (*config_intr) (struct ugeth_mii_info * mii_info); + + /* Clears up any memory if needed */ + void (*close) (struct ugeth_mii_info * mii_info); +}; + +struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); +int read_phy_reg(struct net_device *dev, int mii_id, int regnum); +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts); + +struct dm9161_private { + struct timer_list timer; + int resetdone; +}; + +#endif /* __UCC_GETH_PHY_H__ */ diff --git a/trunk/drivers/net/via-rhine.c b/trunk/drivers/net/via-rhine.c index adea290a9d5e..f3a972e74e9a 100644 --- a/trunk/drivers/net/via-rhine.c +++ b/trunk/drivers/net/via-rhine.c @@ -1486,6 +1486,7 @@ static int rhine_rx(struct net_device *dev, int limit) copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(rp->pdev, rp->rx_skbuff_dma[entry], diff --git a/trunk/drivers/net/via-velocity.c b/trunk/drivers/net/via-velocity.c index 25b75b615188..8e5d82051bd4 100644 --- a/trunk/drivers/net/via-velocity.c +++ b/trunk/drivers/net/via-velocity.c @@ -1339,8 +1339,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) skb_reserve(new_skb, 2); - skb_copy_from_linear_data(rx_skb[0], new_skb->data, - pkt_size); + memcpy(new_skb->data, rx_skb[0]->data, pkt_size); *rx_skb = new_skb; ret = 0; } @@ -1399,6 +1398,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) vptr->stats.multicast++; skb = rd_info->skb; + skb->dev = vptr->dev; pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1428,7 +1428,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len - 4); - skb->protocol = eth_type_trans(skb, vptr->dev); + skb->protocol = eth_type_trans(skb, skb->dev); stats->rx_bytes += pkt_len; netif_rx(skb); @@ -1928,7 +1928,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) if (pktlen < ETH_ZLEN) { /* Cannot occur until ZC support */ pktlen = ETH_ZLEN; - skb_copy_from_linear_data(skb, tdinfo->buf, skb->len); + memcpy(tdinfo->buf, skb->data, skb->len); memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len); tdinfo->skb = skb; tdinfo->skb_dma[0] = tdinfo->buf_dma; @@ -1944,7 +1944,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) int nfrags = skb_shinfo(skb)->nr_frags; tdinfo->skb = skb; if (nfrags > 6) { - skb_copy_from_linear_data(skb, tdinfo->buf, skb->len); + memcpy(tdinfo->buf, skb->data, skb->len); tdinfo->skb_dma[0] = tdinfo->buf_dma; td_ptr->tdesc0.pktsize = td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); @@ -2007,7 +2007,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) */ if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) && (skb->ip_summed == CHECKSUM_PARTIAL)) { - const struct iphdr *ip = ip_hdr(skb); + struct iphdr *ip = skb->nh.iph; if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; else if (ip->protocol == IPPROTO_UDP) diff --git a/trunk/drivers/net/wan/cosa.c b/trunk/drivers/net/wan/cosa.c index 23464735fa88..5b82e4fd0d73 100644 --- a/trunk/drivers/net/wan/cosa.c +++ b/trunk/drivers/net/wan/cosa.c @@ -773,7 +773,7 @@ static int sppp_rx_done(struct channel_data *chan) } chan->rx_skb->protocol = htons(ETH_P_WAN_PPP); chan->rx_skb->dev = chan->pppdev.dev; - skb_reset_mac_header(chan->rx_skb); + chan->rx_skb->mac.raw = chan->rx_skb->data; chan->stats.rx_packets++; chan->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); diff --git a/trunk/drivers/net/wan/cycx_x25.c b/trunk/drivers/net/wan/cycx_x25.c index 016b3ff3ea5e..a631d1c2fa14 100644 --- a/trunk/drivers/net/wan/cycx_x25.c +++ b/trunk/drivers/net/wan/cycx_x25.c @@ -834,7 +834,7 @@ static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) ++chan->ifstats.rx_packets; chan->ifstats.rx_bytes += pktlen; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; netif_rx(skb); dev->last_rx = jiffies; /* timestamp */ } diff --git a/trunk/drivers/net/wan/dlci.c b/trunk/drivers/net/wan/dlci.c index 66be20c292b6..736987559432 100644 --- a/trunk/drivers/net/wan/dlci.c +++ b/trunk/drivers/net/wan/dlci.c @@ -176,7 +176,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) if (process) { /* we've set up the protocol, so discard the header */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, header); dlp->stats.rx_bytes += skb->len; netif_rx(skb); diff --git a/trunk/drivers/net/wan/dscc4.c b/trunk/drivers/net/wan/dscc4.c index dca024471455..25021a7992a9 100644 --- a/trunk/drivers/net/wan/dscc4.c +++ b/trunk/drivers/net/wan/dscc4.c @@ -1904,8 +1904,7 @@ static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) struct TxFD *tx_fd = dpriv->tx_fd + last; skb->len = DUMMY_SKB_SIZE; - skb_copy_to_linear_data(skb, version, - strlen(version) % DUMMY_SKB_SIZE); + memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE); tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE); tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, DUMMY_SKB_SIZE, PCI_DMA_TODEVICE); diff --git a/trunk/drivers/net/wan/farsync.c b/trunk/drivers/net/wan/farsync.c index 58a53b6d9b42..c45d6a83339d 100644 --- a/trunk/drivers/net/wan/farsync.c +++ b/trunk/drivers/net/wan/farsync.c @@ -864,7 +864,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev) { skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; return htons(ETH_P_CUST); } diff --git a/trunk/drivers/net/wan/hdlc_cisco.c b/trunk/drivers/net/wan/hdlc_cisco.c index 9ec6cf2e510e..c9664fd8a917 100644 --- a/trunk/drivers/net/wan/hdlc_cisco.c +++ b/trunk/drivers/net/wan/hdlc_cisco.c @@ -37,16 +37,16 @@ struct hdlc_header { u8 address; u8 control; - __be16 protocol; + u16 protocol; }__attribute__ ((packed)); struct cisco_packet { - __be32 type; /* code */ - __be32 par1; - __be32 par2; - __be16 rel; /* reliability */ - __be32 time; + u32 type; /* code */ + u32 par1; + u32 par2; + u16 rel; /* reliability */ + u32 time; }__attribute__ ((packed)); #define CISCO_PACKET_LEN 18 #define CISCO_BIG_PACKET_LEN 20 @@ -97,7 +97,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, static void cisco_keepalive_send(struct net_device *dev, u32 type, - __be32 par1, __be32 par2) + u32 par1, u32 par2) { struct sk_buff *skb; struct cisco_packet *data; @@ -115,16 +115,16 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, data = (struct cisco_packet*)(skb->data + 4); data->type = htonl(type); - data->par1 = par1; - data->par2 = par2; - data->rel = __constant_htons(0xFFFF); + data->par1 = htonl(par1); + data->par2 = htonl(par2); + data->rel = 0xFFFF; /* we will need do_div here if 1000 % HZ != 0 */ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); skb_put(skb, sizeof(struct cisco_packet)); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; - skb_reset_network_header(skb); + skb->nh.raw = skb->data; dev_queue_xmit(skb); } @@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb) case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ in_dev = dev->ip_ptr; addr = 0; - mask = __constant_htonl(~0); /* is the mask correct? */ + mask = ~0; /* is the mask correct? */ if (in_dev != NULL) { struct in_ifaddr **ifap = &in_dev->ifa_list; @@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb) } /* switch(protocol) */ printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name, - ntohs(data->protocol)); + data->protocol); dev_kfree_skb_any(skb); return NET_RX_DROP; @@ -270,9 +270,8 @@ static void cisco_timer(unsigned long arg) netif_dormant_on(dev); } - cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, - htonl(++state(hdlc)->txseq), - htonl(state(hdlc)->rxseq)); + cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq, + state(hdlc)->rxseq); state(hdlc)->request_sent = 1; state(hdlc)->timer.expires = jiffies + state(hdlc)->settings.interval * HZ; diff --git a/trunk/drivers/net/wan/hdlc_fr.c b/trunk/drivers/net/wan/hdlc_fr.c index 15b6e07a4382..c6c3c757d6f1 100644 --- a/trunk/drivers/net/wan/hdlc_fr.c +++ b/trunk/drivers/net/wan/hdlc_fr.c @@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) struct sk_buff *skb = *skb_p; switch (skb->protocol) { - case __constant_htons(NLPID_CCITT_ANSI_LMI): + case __constant_ntohs(NLPID_CCITT_ANSI_LMI): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_CCITT_ANSI_LMI; break; - case __constant_htons(NLPID_CISCO_LMI): + case __constant_ntohs(NLPID_CISCO_LMI): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_CISCO_LMI; break; - case __constant_htons(ETH_P_IP): + case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IP; break; - case __constant_htons(ETH_P_IPV6): + case __constant_ntohs(ETH_P_IPV6): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IPV6; break; - case __constant_htons(ETH_P_802_3): + case __constant_ntohs(ETH_P_802_3): head_len = 10; if (skb_headroom(skb) < head_len) { struct sk_buff *skb2 = skb_realloc_headroom(skb, @@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) skb->data[5] = FR_PAD; skb->data[6] = FR_PAD; skb->data[7] = FR_PAD; - *(__be16*)(skb->data + 8) = skb->protocol; + *(u16*)(skb->data + 8) = skb->protocol; } dlci_to_q922(skb->data, dlci); @@ -533,7 +533,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI); fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI); } - data = skb_tail_pointer(skb); + data = skb->tail; data[i++] = LMI_CALLREF; data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY; if (lmi == LMI_ANSI) @@ -590,7 +590,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep) skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; - skb_reset_network_header(skb); + skb->nh.raw = skb->data; dev_queue_xmit(skb); } @@ -974,8 +974,8 @@ static int fr_rx(struct sk_buff *skb) } else if (skb->len > 10 && data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) { - u16 oui = ntohs(*(__be16*)(data + 6)); - u16 pid = ntohs(*(__be16*)(data + 8)); + u16 oui = ntohs(*(u16*)(data + 6)); + u16 pid = ntohs(*(u16*)(data + 8)); skb_pull(skb, 10); switch ((((u32)oui) << 16) | pid) { @@ -1011,6 +1011,7 @@ static int fr_rx(struct sk_buff *skb) stats->rx_bytes += skb->len; if (pvc->state.becn) stats->rx_compressed++; + skb->dev = dev; netif_rx(skb); return NET_RX_SUCCESS; } else { @@ -1127,7 +1128,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) memcpy(dev->dev_addr, "\x00\x01", 2); get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); } else { - *(__be16*)dev->dev_addr = htons(dlci); + *(u16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); } dev->hard_start_xmit = pvc_xmit; diff --git a/trunk/drivers/net/wan/hostess_sv11.c b/trunk/drivers/net/wan/hostess_sv11.c index 9ba3e4ee6ec7..a02c5fb40567 100644 --- a/trunk/drivers/net/wan/hostess_sv11.c +++ b/trunk/drivers/net/wan/hostess_sv11.c @@ -59,7 +59,7 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ skb_trim(skb, skb->len-2); skb->protocol=__constant_htons(ETH_P_WAN_PPP); - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; skb->dev=c->netdevice; /* * Send it to the PPP layer. We don't have time to process diff --git a/trunk/drivers/net/wan/lmc/lmc_main.c b/trunk/drivers/net/wan/lmc/lmc_main.c index ae132c1c5459..2b54f1bc3a0d 100644 --- a/trunk/drivers/net/wan/lmc/lmc_main.c +++ b/trunk/drivers/net/wan/lmc/lmc_main.c @@ -1636,7 +1636,7 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ if (nsb) { sc->lmc_rxq[i] = nsb; nsb->dev = dev; - sc->lmc_rxring[i].buffer1 = virt_to_bus(skb_tail_pointer(nsb)); + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); } sc->failed_recv_alloc = 1; goto skip_packet; @@ -1667,8 +1667,8 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ skb_put (skb, len); skb->protocol = lmc_proto_type(sc, skb); skb->protocol = htons(ETH_P_WAN_PPP); - skb_reset_mac_header(skb); - /* skb_reset_network_header(skb); */ + skb->mac.raw = skb->data; +// skb->nh.raw = skb->data; skb->dev = dev; lmc_proto_netif(sc, skb); @@ -1679,7 +1679,7 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ if (nsb) { sc->lmc_rxq[i] = nsb; nsb->dev = dev; - sc->lmc_rxring[i].buffer1 = virt_to_bus(skb_tail_pointer(nsb)); + sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); /* Transferred to 21140 below */ } else { @@ -1702,11 +1702,11 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ if(!nsb) { goto give_it_anyways; } - skb_copy_from_linear_data(skb, skb_put(nsb, len), len); + memcpy(skb_put(nsb, len), skb->data, len); nsb->protocol = lmc_proto_type(sc, skb); - skb_reset_mac_header(nsb); - /* skb_reset_network_header(nsb); */ + nsb->mac.raw = nsb->data; +// nsb->nh.raw = nsb->data; nsb->dev = dev; lmc_proto_netif(sc, nsb); } @@ -1932,7 +1932,7 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ sc->lmc_rxring[i].status = 0x80000000; /* used to be PKT_BUF_SZ now uses skb since we lose some to head room */ - sc->lmc_rxring[i].length = skb_tailroom(skb); + sc->lmc_rxring[i].length = skb->end - skb->data; /* use to be tail which is dumb since you're thinking why write * to the end of the packj,et but since there's nothing there tail == data diff --git a/trunk/drivers/net/wan/lmc/lmc_media.c b/trunk/drivers/net/wan/lmc/lmc_media.c index 574737b55f39..ae01555d24cf 100644 --- a/trunk/drivers/net/wan/lmc/lmc_media.c +++ b/trunk/drivers/net/wan/lmc/lmc_media.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/wan/lmc/lmc_proto.c b/trunk/drivers/net/wan/lmc/lmc_proto.c index 31e1799571ad..74876c0073e8 100644 --- a/trunk/drivers/net/wan/lmc/lmc_proto.c +++ b/trunk/drivers/net/wan/lmc/lmc_proto.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/net/wan/pc300_drv.c b/trunk/drivers/net/wan/pc300_drv.c index 999bf71937ca..62184dee377c 100644 --- a/trunk/drivers/net/wan/pc300_drv.c +++ b/trunk/drivers/net/wan/pc300_drv.c @@ -1755,17 +1755,17 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) skb->dev = dev; skb->protocol = htons(ETH_P_CUST); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; skb->len = 10 + skb_main->len; - skb_copy_to_linear_data(skb, dev->name, 5); + memcpy(skb->data, dev->name, 5); skb->data[5] = '['; skb->data[6] = rx_tx; skb->data[7] = ']'; skb->data[8] = ':'; skb->data[9] = ' '; - skb_copy_from_linear_data(skb_main, &skb->data[10], skb_main->len); + memcpy(&skb->data[10], skb_main->data, skb_main->len); netif_rx(skb); } diff --git a/trunk/drivers/net/wan/pc300_tty.c b/trunk/drivers/net/wan/pc300_tty.c index e24a7b095dd6..5873c346e7e9 100644 --- a/trunk/drivers/net/wan/pc300_tty.c +++ b/trunk/drivers/net/wan/pc300_tty.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -1002,17 +1003,17 @@ static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx) skb_put (skb, 10 + len); skb->dev = dev->dev; skb->protocol = htons(ETH_P_CUST); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; skb->len = 10 + len; - skb_copy_to_linear_data(skb, dev->dev->name, 5); + memcpy(skb->data,dev->dev->name,5); skb->data[5] = '['; skb->data[6] = rxtx; skb->data[7] = ']'; skb->data[8] = ':'; skb->data[9] = ' '; - skb_copy_to_linear_data_offset(skb, 10, buf, len); + memcpy(&skb->data[10], buf, len); netif_rx(skb); } diff --git a/trunk/drivers/net/wan/sbni.c b/trunk/drivers/net/wan/sbni.c index 35eded7ffb2d..fc5c0c611ffd 100644 --- a/trunk/drivers/net/wan/sbni.c +++ b/trunk/drivers/net/wan/sbni.c @@ -999,6 +999,11 @@ get_rx_buf( struct net_device *dev ) if( !skb ) return NULL; +#ifdef CONFIG_SBNI_MULTILINE + skb->dev = ((struct net_local *) dev->priv)->master; +#else + skb->dev = dev; +#endif skb_reserve( skb, 2 ); /* Align IP on longword boundaries */ return skb; } diff --git a/trunk/drivers/net/wan/sealevel.c b/trunk/drivers/net/wan/sealevel.c index 131358108c5a..70fb1b98b1dd 100644 --- a/trunk/drivers/net/wan/sealevel.c +++ b/trunk/drivers/net/wan/sealevel.c @@ -61,7 +61,7 @@ static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ skb_trim(skb, skb->len-2); skb->protocol=htons(ETH_P_WAN_PPP); - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; skb->dev=c->netdevice; /* * Send it to the PPP layer. We don't have time to process diff --git a/trunk/drivers/net/wan/syncppp.c b/trunk/drivers/net/wan/syncppp.c index 67fc67cfd452..218f7b574ab3 100644 --- a/trunk/drivers/net/wan/syncppp.c +++ b/trunk/drivers/net/wan/syncppp.c @@ -227,7 +227,7 @@ static void sppp_input (struct net_device *dev, struct sk_buff *skb) unsigned long flags; skb->dev=dev; - skb_reset_mac_header(skb); + skb->mac.raw=skb->data; if (dev->flags & IFF_RUNNING) { diff --git a/trunk/drivers/net/wan/z85230.c b/trunk/drivers/net/wan/z85230.c index 98ef400908b8..8b4540bfc1b0 100644 --- a/trunk/drivers/net/wan/z85230.c +++ b/trunk/drivers/net/wan/z85230.c @@ -1656,7 +1656,7 @@ static void z8530_rx_done(struct z8530_channel *c) else { skb_put(skb, ct); - skb_copy_to_linear_data(skb, rxb, ct); + memcpy(skb->data, rxb, ct); c->stats.rx_packets++; c->stats.rx_bytes+=ct; } @@ -1782,7 +1782,7 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) */ c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used]; c->tx_dma_used^=1; /* Flip temp buffer */ - skb_copy_from_linear_data(skb, c->tx_next_ptr, skb->len); + memcpy(c->tx_next_ptr, skb->data, skb->len); } else c->tx_next_ptr=skb->data; diff --git a/trunk/drivers/net/wireless/Kconfig b/trunk/drivers/net/wireless/Kconfig index c4b3dc291a5a..ece3d9c2dc61 100644 --- a/trunk/drivers/net/wireless/Kconfig +++ b/trunk/drivers/net/wireless/Kconfig @@ -2,21 +2,47 @@ # Wireless LAN device configuration # -menu "Wireless LAN" - -config WLAN_PRE80211 - bool "Wireless LAN (pre-802.11)" +menu "Wireless LAN (non-hamradio)" depends on NETDEVICES + +config NET_RADIO + bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions" + select WIRELESS_EXT ---help--- - Say Y if you have any pre-802.11 wireless LAN hardware. + Support for wireless LANs and everything having to do with radio, + but not with amateur radio or FM broadcasting. + + Saying Y here also enables the Wireless Extensions (creates + /proc/net/wireless and enables iwconfig access). The Wireless + Extension is a generic API allowing a driver to expose to the user + space configuration and statistics specific to common Wireless LANs. + The beauty of it is that a single set of tool can support all the + variations of Wireless LANs, regardless of their type (as long as + the driver supports Wireless Extension). Another advantage is that + these parameters may be changed on the fly without restarting the + driver (or Linux). If you wish to use Wireless Extensions with + wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch + the tools from + . - This option does not affect the kernel build, it only - lets you choose drivers. +config NET_WIRELESS_RTNETLINK + bool "Wireless Extension API over RtNetlink" + depends on NET_RADIO + ---help--- + Support the Wireless Extension API over the RtNetlink socket + in addition to the traditional ioctl interface (selected above). + + For now, few tools use this facility, but it might grow in the + future. The only downside is that it adds 4.5 kB to your kernel. + +# Note : the cards are obsolete (can't buy them anymore), but the drivers +# are not, as people are still using them... +comment "Obsolete Wireless cards support (pre-802.11)" + depends on NET_RADIO && (INET || ISA || PCMCIA) config STRIP tristate "STRIP (Metricom starmode radio IP)" - depends on INET && WLAN_PRE80211 - select WIRELESS_EXT + depends on NET_RADIO && INET ---help--- Say Y if you have a Metricom radio and intend to use Starmode Radio IP. STRIP is a radio protocol developed for the MosquitoNet project @@ -39,8 +65,7 @@ config STRIP config ARLAN tristate "Aironet Arlan 655 & IC2200 DS support" - depends on ISA && !64BIT && WLAN_PRE80211 - select WIRELESS_EXT + depends on NET_RADIO && ISA && !64BIT ---help--- Aironet makes Arlan, a class of wireless LAN adapters. These use the www.Telxon.com chip, which is also used on several similar cards. @@ -55,8 +80,7 @@ config ARLAN config WAVELAN tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" - depends on ISA && WLAN_PRE80211 - select WIRELESS_EXT + depends on NET_RADIO && ISA ---help--- The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is a Radio LAN (wireless Ethernet-like Local Area Network) using the @@ -83,8 +107,7 @@ config WAVELAN config PCMCIA_WAVELAN tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" - depends on PCMCIA && WLAN_PRE80211 - select WIRELESS_EXT + depends on NET_RADIO && PCMCIA help Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA (PC-card) wireless Ethernet networking card to your computer. This @@ -95,8 +118,7 @@ config PCMCIA_WAVELAN config PCMCIA_NETWAVE tristate "Xircom Netwave AirSurfer Pcmcia wireless support" - depends on PCMCIA && WLAN_PRE80211 - select WIRELESS_EXT + depends on NET_RADIO && PCMCIA help Say Y here if you intend to attach this type of PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -104,20 +126,12 @@ config PCMCIA_NETWAVE To compile this driver as a module, choose M here: the module will be called netwave_cs. If unsure, say N. - -config WLAN_80211 - bool "Wireless LAN (IEEE 802.11)" - depends on NETDEVICES - ---help--- - Say Y if you have any 802.11 wireless LAN hardware. - - This option does not affect the kernel build, it only - lets you choose drivers. +comment "Wireless 802.11 Frequency Hopping cards support" + depends on NET_RADIO && PCMCIA config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4MHz wireless support" - depends on PCMCIA && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && PCMCIA ---help--- Say Y here if you intend to attach an Aviator/Raytheon PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -127,10 +141,12 @@ config PCMCIA_RAYCS To compile this driver as a module, choose M here: the module will be called ray_cs. If unsure, say N. +comment "Wireless 802.11b ISA/PCI cards support" + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) + config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && PCI select FW_LOADER select IEEE80211 ---help--- @@ -184,8 +200,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && PCI select FW_LOADER select IEEE80211 ---help--- @@ -265,23 +280,9 @@ config IPW2200_DEBUG If you are not sure, say N here. -config LIBERTAS_USB - tristate "Marvell Libertas 8388 802.11a/b/g cards" - depends on NET_RADIO && USB - select FW_LOADER - ---help--- - A driver for Marvell Libertas 8388 USB devices. - -config LIBERTAS_USB_DEBUG - bool "Enable full debugging output in the Libertas USB module." - depends on LIBERTAS_USB - ---help--- - Debugging support. - config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) - select WIRELESS_EXT + depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) select CRYPTO ---help--- This is the standard Linux driver to support Cisco/Aironet ISA and @@ -298,8 +299,7 @@ config AIRO config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA) ---help--- A driver for 802.11b wireless cards based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast @@ -373,8 +373,7 @@ config PCI_HERMES config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && (PCI || PCMCIA) select FW_LOADER select CRC32 ---help--- @@ -395,9 +394,13 @@ config PCI_ATMEL Enable support for PCI and mini-PCI cards containing the Atmel at76c506 chip. +# If Pcmcia is compiled in, offer Pcmcia cards... +comment "Wireless 802.11b Pcmcia/Cardbus cards support" + depends on NET_RADIO && PCMCIA + config PCMCIA_HERMES tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES + depends on NET_RADIO && PCMCIA && HERMES ---help--- A driver for "Hermes" chipset based PCMCIA wireless adaptors, such as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -417,7 +420,7 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES + depends on NET_RADIO && PCMCIA && HERMES select FW_LOADER ---help--- @@ -431,8 +434,7 @@ config PCMCIA_SPECTRUM config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) select CRYPTO select CRYPTO_AES ---help--- @@ -456,8 +458,7 @@ config AIRO_CS config PCMCIA_ATMEL tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT + depends on NET_RADIO && ATMEL && PCMCIA select FW_LOADER select CRC32 ---help--- @@ -466,17 +467,17 @@ config PCMCIA_ATMEL config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO && EXPERIMENTAL && PCMCIA ---help--- A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. It has basic support for Linux wireless extensions and initial micro support for ethtool. +comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support" + depends on NET_RADIO && PCI config PRISM54 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' - depends on PCI && EXPERIMENTAL && WLAN_80211 - select WIRELESS_EXT + depends on PCI && NET_RADIO && EXPERIMENTAL select FW_LOADER ---help--- Enable PCI and Cardbus support for the following chipset based cards: @@ -522,8 +523,7 @@ config PRISM54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" - depends on USB && WLAN_80211 - select WIRELESS_EXT + depends on USB && NET_RADIO select FW_LOADER ---help--- Say Y if you want to use wireless LAN adapters based on the ZyDAS @@ -542,4 +542,11 @@ source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +# yes, this works even when no drivers are selected +config NET_WIRELESS + bool + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) + default y + endmenu + diff --git a/trunk/drivers/net/wireless/Makefile b/trunk/drivers/net/wireless/Makefile index d2124602263b..c613af17a159 100644 --- a/trunk/drivers/net/wireless/Makefile +++ b/trunk/drivers/net/wireless/Makefile @@ -43,4 +43,3 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_ZD1201) += zd1201.o -obj-$(CONFIG_LIBERTAS_USB) += libertas/ diff --git a/trunk/drivers/net/wireless/README b/trunk/drivers/net/wireless/README new file mode 100644 index 000000000000..0c274bf6d45e --- /dev/null +++ b/trunk/drivers/net/wireless/README @@ -0,0 +1,25 @@ + README + ------ + + This directory is mostly for Wireless LAN drivers, in their +various incarnations (ISA, PCI, Pcmcia...). + This separate directory is needed because a lot of driver work +on different bus (typically PCI + Pcmcia) and share 95% of the +code. This allow the code and the config options to be in one single +place instead of scattered all over the driver tree, which is never +100% satisfactory. + + Note : if you want more info on the topic of Wireless LANs, +you are kindly invited to have a look at the Wireless Howto : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + Some Wireless LAN drivers, like orinoco_cs, require the use of +Wireless Tools to be configured : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + + Special notes for distribution maintainers : + 1) wvlan_cs will be discontinued soon in favor of orinoco_cs + 2) Please add Wireless Tools support in your scripts + + Have fun... + + Jean diff --git a/trunk/drivers/net/wireless/airo.c b/trunk/drivers/net/wireless/airo.c index f21bbafcb728..2ada76a93cb6 100644 --- a/trunk/drivers/net/wireless/airo.c +++ b/trunk/drivers/net/wireless/airo.c @@ -1145,7 +1145,6 @@ static void airo_networks_free(struct airo_info *ai); struct airo_info { struct net_device_stats stats; struct net_device *dev; - struct list_head dev_list; /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we use the high bit to mark whether it is in use. */ #define MAX_FIDS 6 @@ -2361,21 +2360,6 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static LIST_HEAD(airo_devices); - -static void add_airo_dev(struct airo_info *ai) -{ - /* Upper layers already keep track of PCI devices, - * so we only need to remember our non-PCI cards. */ - if (!ai->pci) - list_add_tail(&ai->dev_list, &airo_devices); -} - -static void del_airo_dev(struct airo_info *ai) -{ - if (!ai->pci) - list_del(&ai->dev_list); -} static int airo_close(struct net_device *dev) { struct airo_info *ai = dev->priv; @@ -2397,6 +2381,8 @@ static int airo_close(struct net_device *dev) { return 0; } +static void del_airo_dev( struct net_device *dev ); + void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = dev->priv; @@ -2448,15 +2434,17 @@ void stop_airo_card( struct net_device *dev, int freeres ) } } crypto_free_cipher(ai->tfm); - del_airo_dev(ai); + del_airo_dev( dev ); free_netdev( dev ); } EXPORT_SYMBOL(stop_airo_card); +static int add_airo_dev( struct net_device *dev ); + static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) { - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); + memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); return ETH_ALEN; } @@ -2752,6 +2740,8 @@ static int airo_networks_allocate(struct airo_info *ai) static void airo_networks_free(struct airo_info *ai) { + if (!ai->networks) + return; kfree(ai->networks); ai->networks = NULL; } @@ -2826,10 +2816,12 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, if (IS_ERR(ai->airo_thread_task)) goto err_out_free; ai->tfm = NULL; - add_airo_dev(ai); + rc = add_airo_dev( dev ); + if (rc) + goto err_out_thr; if (airo_networks_allocate (ai)) - goto err_out_thr; + goto err_out_unlink; airo_networks_initialize (ai); /* The Airo-specific entries in the device structure. */ @@ -2945,8 +2937,9 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, free_irq(dev->irq, dev); err_out_nets: airo_networks_free(ai); +err_out_unlink: + del_airo_dev(dev); err_out_thr: - del_airo_dev(ai); set_bit(JOB_DIE, &ai->jobs); kthread_stop(ai->airo_thread_task); err_out_free: @@ -3418,12 +3411,14 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { OUT4500( apriv, EVACK, EV_RX); if (test_bit(FLAG_802_11, &apriv->flags)) { - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_OTHERHOST; skb->dev = apriv->wifidev; skb->protocol = htons(ETH_P_802_2); - } else + } else { + skb->dev = dev; skb->protocol = eth_type_trans(skb,dev); + } skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; @@ -3646,6 +3641,7 @@ static void mpi_receive_802_3(struct airo_info *ai) } #endif /* WIRELESS_SPY */ + skb->dev = ai->dev; skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, ai->dev); skb->dev->last_rx = jiffies; @@ -3753,7 +3749,7 @@ void mpi_receive_802_11 (struct airo_info *ai) wireless_spy_update(ai->dev, sa, &wstats); } #endif /* IW_WIRELESS_SPY */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_OTHERHOST; skb->dev = ai->wifidev; skb->protocol = htons(ETH_P_802_2); @@ -5542,6 +5538,11 @@ static int proc_close( struct inode *inode, struct file *file ) return 0; } +static struct net_device_list { + struct net_device *dev; + struct net_device_list *next; +} *airo_devices; + /* Since the card doesn't automatically switch to the right WEP mode, we will make it do it. If the card isn't associated, every secs we will switch WEP modes to see if that will help. If the card is @@ -5584,6 +5585,26 @@ static void timer_func( struct net_device *dev ) { apriv->expires = RUN_AT(HZ*3); } +static int add_airo_dev( struct net_device *dev ) { + struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL ); + if ( !node ) + return -ENOMEM; + + node->dev = dev; + node->next = airo_devices; + airo_devices = node; + + return 0; +} + +static void del_airo_dev( struct net_device *dev ) { + struct net_device_list **p = &airo_devices; + while( *p && ( (*p)->dev != dev ) ) + p = &(*p)->next; + if ( *p && (*p)->dev == dev ) + *p = (*p)->next; +} + #ifdef CONFIG_PCI static int __devinit airo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) @@ -5607,10 +5628,6 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, static void __devexit airo_pci_remove(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - - airo_print_info(dev->name, "Unregistering..."); - stop_airo_card(dev, 1); } static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) @@ -5736,11 +5753,9 @@ static int __init airo_init_module( void ) static void __exit airo_cleanup_module( void ) { - struct airo_info *ai; - while(!list_empty(&airo_devices)) { - ai = list_entry(airo_devices.next, struct airo_info, dev_list); - airo_print_info(ai->dev->name, "Unregistering..."); - stop_airo_card(ai->dev, 1); + while( airo_devices ) { + airo_print_info(airo_devices->dev->name, "Unregistering...\n"); + stop_airo_card( airo_devices->dev, 1 ); } #ifdef CONFIG_PCI pci_unregister_driver(&airo_driver); diff --git a/trunk/drivers/net/wireless/arlan-main.c b/trunk/drivers/net/wireless/arlan-main.c index 498e8486d125..4688e56b69c7 100644 --- a/trunk/drivers/net/wireless/arlan-main.c +++ b/trunk/drivers/net/wireless/arlan-main.c @@ -1500,6 +1500,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short break; } skb_reserve(skb, 2); + skb->dev = dev; skbtmp = skb_put(skb, pkt_len); memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); diff --git a/trunk/drivers/net/wireless/atmel.c b/trunk/drivers/net/wireless/atmel.c index 51a7db53afa5..23eba698aec5 100644 --- a/trunk/drivers/net/wireless/atmel.c +++ b/trunk/drivers/net/wireless/atmel.c @@ -827,14 +827,14 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->wep_is_on) frame_ctl |= IEEE80211_FCTL_PROTECTED; if (priv->operating_mode == IW_MODE_ADHOC) { - skb_copy_from_linear_data(skb, &header.addr1, 6); + memcpy(&header.addr1, skb->data, 6); memcpy(&header.addr2, dev->dev_addr, 6); memcpy(&header.addr3, priv->BSSID, 6); } else { frame_ctl |= IEEE80211_FCTL_TODS; memcpy(&header.addr1, priv->CurrentBSSID, 6); memcpy(&header.addr2, dev->dev_addr, 6); - skb_copy_from_linear_data(skb, &header.addr3, 6); + memcpy(&header.addr3, skb->data, 6); } if (priv->use_wpa) @@ -920,6 +920,7 @@ static void fast_rx_path(struct atmel_private *priv, memcpy(&skbp[6], header->addr2, 6); /* source address */ priv->dev->last_rx = jiffies; + skb->dev = priv->dev; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -1027,6 +1028,7 @@ static void frag_rx_path(struct atmel_private *priv, priv->rx_buf, priv->frag_len + 12); priv->dev->last_rx = jiffies; + skb->dev = priv->dev; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); diff --git a/trunk/drivers/net/wireless/bcm43xx/Kconfig b/trunk/drivers/net/wireless/bcm43xx/Kconfig index ce397e4284f4..533993f538fc 100644 --- a/trunk/drivers/net/wireless/bcm43xx/Kconfig +++ b/trunk/drivers/net/wireless/bcm43xx/Kconfig @@ -1,7 +1,6 @@ config BCM43XX tristate "Broadcom BCM43xx wireless support" - depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL - select WIRELESS_EXT + depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL select FW_LOADER select HW_RANDOM ---help--- diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx.h b/trunk/drivers/net/wireless/bcm43xx/bcm43xx.h index f8483c179e4c..95ff175d8f33 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -277,14 +277,11 @@ #define BCM43xx_SBTMSTATELOW_REJECT 0x02 #define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 -#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000 /* sbtmstatehigh state flags */ #define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001 #define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004 #define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020 -#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 -#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000 #define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 #define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000 #define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000 diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index e3d2e61a31ee..6e0dc76400e5 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -998,8 +998,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, assert(0); return; } - skb_copy_from_linear_data(skb, skb_put(bounce_skb, skb->len), - skb->len); + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); dev_kfree_skb_any(skb); skb = bounce_skb; } diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c index d2df6a0100a1..c947025d655f 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo * struct bcm43xx_private *bcm = bcm43xx_priv(dev); strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strncpy(info->version, utsname()->release, sizeof(info->version)); + strncpy(info->version, UTS_RELEASE, sizeof(info->version)); strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); } diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 5e96bca6730a..a38e7eec0e62 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1407,7 +1407,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); } else { if (connect_phy) - flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; + flags |= 0x20000000; bcm43xx_phy_connect(bcm, connect_phy); bcm43xx_core_enable(bcm, flags); bcm43xx_write16(bcm, 0x03E6, 0x0000); @@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, u32 sbtmstatelow; sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; + sbtmstatelow |= 0x20000000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); } err = wireless_core_up(bcm, 1); diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index b37f1e348700..72529a440f15 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (connect) { - if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL)) + if (!(flags & 0x00010000)) return -ENODEV; flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; + flags |= (0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); } else { - if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL)) + if (!(flags & 0x00020000)) return -ENODEV; flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; + flags &= ~(0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); } out: @@ -300,20 +300,16 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) if (phy->rev > 2) { bcm43xx_phy_write(bcm, 0x0422, 0x287A); - bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) - & 0x0FFF) | 0x3000); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); } - bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) - | 0x7874); + bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); bcm43xx_phy_write(bcm, 0x048E, 0x1C00); if (phy->rev == 1) { - bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) - & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); bcm43xx_phy_write(bcm, 0x048B, 0x005E); - bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) - & 0xFF00) | 0x001E); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); bcm43xx_phy_write(bcm, 0x048D, 0x0002); } @@ -339,8 +335,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) if (phy->rev == 1) { bcm43xx_phy_write(bcm, 0x0406, 0x4F19); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) - & 0xFC3F) | 0x0340); + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); bcm43xx_phy_write(bcm, 0x042C, 0x005A); bcm43xx_phy_write(bcm, 0x0427, 0x001A); diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.h index 73118364b552..1f321ef42be8 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.h +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_phy.h @@ -48,10 +48,6 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); local_irq_restore(flags); \ } while (0) -/* Card uses the loopback gain stuff */ -#define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->connected)) - u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); diff --git a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 6a109f4a1b71..4025dd0089d2 100644 --- a/trunk/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/trunk/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1343,110 +1343,11 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) return ret; } -#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) -static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd) -{ - struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 loop_or = 0; - u16 adj_loopback_gain = phy->loopback_gain[0]; - u8 loop; - u16 extern_lna_control; - - if (!phy->connected) - return 0; - if (!has_loopback_gain(phy)) { - if (phy->rev < 7 || !(bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA)) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0FB2; - case LPD(0, 0, 1): - return 0x00B2; - case LPD(1, 0, 1): - return 0x30B2; - case LPD(1, 0, 0): - return 0x30B3; - default: - assert(0); - } - } else { - switch (lpd) { - case LPD(0, 1, 1): - return 0x8FB2; - case LPD(0, 0, 1): - return 0x80B2; - case LPD(1, 0, 1): - return 0x20B2; - case LPD(1, 0, 0): - return 0x20B3; - default: - assert(0); - } - } - } else { - if (radio->revision == 8) - adj_loopback_gain += 0x003E; - else - adj_loopback_gain += 0x0026; - if (adj_loopback_gain >= 0x46) { - adj_loopback_gain -= 0x46; - extern_lna_control = 0x3000; - } else if (adj_loopback_gain >= 0x3A) { - adj_loopback_gain -= 0x3A; - extern_lna_control = 0x2000; - } else if (adj_loopback_gain >= 0x2E) { - adj_loopback_gain -= 0x2E; - extern_lna_control = 0x1000; - } else { - adj_loopback_gain -= 0x10; - extern_lna_control = 0x0000; - } - for (loop = 0; loop < 16; loop++) { - u16 tmp = adj_loopback_gain - 6 * loop; - if (tmp < 6) - break; - } - - loop_or = (loop << 8) | extern_lna_control; - if (phy->rev >= 7 && bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA) { - if (extern_lna_control) - loop_or |= 0x8000; - switch (lpd) { - case LPD(0, 1, 1): - return 0x8F92; - case LPD(0, 0, 1): - return (0x8092 | loop_or); - case LPD(1, 0, 1): - return (0x2092 | loop_or); - case LPD(1, 0, 0): - return (0x2093 | loop_or); - default: - assert(0); - } - } else { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0F92; - case LPD(0, 0, 1): - case LPD(1, 0, 1): - return (0x0092 | loop_or); - case LPD(1, 0, 0): - return (0x0093 | loop_or); - default: - assert(0); - } - } - } - return 0; -} - u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - u16 backup[21] = { 0 }; + u16 backup[19] = { 0 }; u16 ret; u16 i, j; u32 tmp1 = 0, tmp2 = 0; @@ -1472,36 +1373,19 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); backup[9] = bcm43xx_phy_read(bcm, 0x0802); bcm43xx_phy_write(bcm, 0x0814, - (bcm43xx_phy_read(bcm, 0x0814) - | 0x0003)); + (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); bcm43xx_phy_write(bcm, 0x0815, - (bcm43xx_phy_read(bcm, 0x0815) - & 0xFFFC)); + (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) - & 0x7FFF)); + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); bcm43xx_phy_write(bcm, 0x0802, (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); - if (phy->rev > 1) { /* loopback gain enabled */ - backup[19] = bcm43xx_phy_read(bcm, 0x080F); - backup[20] = bcm43xx_phy_read(bcm, 0x0810); - if (phy->rev >= 3) - bcm43xx_phy_write(bcm, 0x080F, 0xC020); - else - bcm43xx_phy_write(bcm, 0x080F, 0x8020); - bcm43xx_phy_write(bcm, 0x0810, 0x0000); - } - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); - if (phy->rev < 7 || !(bcm->sprom.boardflags - & BCM43xx_BFL_EXTLNA)) - bcm43xx_phy_write(bcm, 0x0811, 0x01B3); - else - bcm43xx_phy_write(bcm, 0x0811, 0x09B3); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); } - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, - (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); backup[10] = bcm43xx_phy_read(bcm, 0x0035); bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); @@ -1513,12 +1397,10 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x03E6, 0x0122); } else { if (phy->analog >= 2) - bcm43xx_phy_write(bcm, 0x0003, - (bcm43xx_phy_read(bcm, 0x0003) - & 0xFFBF) | 0x0040); + bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003) + & 0xFFBF) | 0x0040); bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, - (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) - | 0x2000)); + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); } ret = bcm43xx_radio_calibrationvalue(bcm); @@ -1526,25 +1408,16 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) if (phy->type == BCM43xx_PHYTYPE_B) bcm43xx_radio_write16(bcm, 0x0078, 0x0026); - if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); bcm43xx_phy_write(bcm, 0x002B, 0x1403); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(0, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); bcm43xx_radio_write16(bcm, 0x0051, (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); - if (radio->revision == 8) - bcm43xx_radio_write16(bcm, 0x0043, 0x001F); - else { - bcm43xx_radio_write16(bcm, 0x0052, 0x0000); - bcm43xx_radio_write16(bcm, 0x0043, - (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) - | 0x0009); - } + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009); bcm43xx_phy_write(bcm, 0x0058, 0x0000); for (i = 0; i < 16; i++) { @@ -1552,25 +1425,21 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0059, 0xC810); bcm43xx_phy_write(bcm, 0x0058, 0x000D); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); udelay(10); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); udelay(10); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 0))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); - udelay(20); + udelay(10); tmp1 += bcm43xx_phy_read(bcm, 0x002D); bcm43xx_phy_write(bcm, 0x0058, 0x0000); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); } @@ -1588,29 +1457,21 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0059, 0xC810); bcm43xx_phy_write(bcm, 0x0058, 0x000D); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); udelay(10); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); udelay(10); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 0))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); udelay(10); tmp2 += bcm43xx_phy_read(bcm, 0x002D); bcm43xx_phy_write(bcm, 0x0058, 0x0000); if (phy->connected) - bcm43xx_phy_write(bcm, 0x0812, - bcm43xx_get_812_value(bcm, - LPD(1, 0, 1))); + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); } tmp2++; @@ -1636,20 +1497,15 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0030, backup[2]); bcm43xx_write16(bcm, 0x03EC, backup[3]); } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); if (phy->connected) { - bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, - (bcm43xx_read16(bcm, - BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); bcm43xx_phy_write(bcm, 0x0811, backup[4]); bcm43xx_phy_write(bcm, 0x0812, backup[5]); bcm43xx_phy_write(bcm, 0x0814, backup[6]); bcm43xx_phy_write(bcm, 0x0815, backup[7]); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); bcm43xx_phy_write(bcm, 0x0802, backup[9]); - if (phy->rev > 1) { - bcm43xx_phy_write(bcm, 0x080F, backup[19]); - bcm43xx_phy_write(bcm, 0x0810, backup[20]); - } } } if (i >= 15) diff --git a/trunk/drivers/net/wireless/hostap/Kconfig b/trunk/drivers/net/wireless/hostap/Kconfig index 1fef33169fdd..308f773ad566 100644 --- a/trunk/drivers/net/wireless/hostap/Kconfig +++ b/trunk/drivers/net/wireless/hostap/Kconfig @@ -1,7 +1,6 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - depends on WLAN_80211 - select WIRELESS_EXT + depends on NET_RADIO select IEEE80211 select IEEE80211_CRYPT_WEP ---help--- diff --git a/trunk/drivers/net/wireless/hostap/hostap_80211_rx.c b/trunk/drivers/net/wireless/hostap/hostap_80211_rx.c index cbedc9ee740a..7e04dc94b3bc 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/trunk/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -167,7 +167,7 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d ret = skb->len - phdrlen; skb->dev = dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, hdrlen); if (prism_header) skb_pull(skb, phdrlen); @@ -933,14 +933,12 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, if (frag == 0) { /* copy first fragment (including full headers) into * beginning of the fragment cache skb */ - skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), - flen); + memcpy(skb_put(frag_skb, flen), skb->data, flen); } else { /* append frame payload to the end of the fragment * cache skb */ - skb_copy_from_linear_data_offset(skb, hdrlen, - skb_put(frag_skb, - flen), flen); + memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, + flen); } dev_kfree_skb(skb); skb = NULL; @@ -1046,9 +1044,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, skb->len >= ETH_HLEN + ETH_ALEN) { /* Non-standard frame: get addr4 from its bogus location after * the payload */ - skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN, - skb->data + ETH_ALEN, - ETH_ALEN); + memcpy(skb->data + ETH_ALEN, + skb->data + skb->len - ETH_ALEN, ETH_ALEN); skb_trim(skb, skb->len - ETH_ALEN); } @@ -1076,17 +1073,17 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, if (skb2 != NULL) { /* send to wireless media */ - skb2->dev = dev; skb2->protocol = __constant_htons(ETH_P_802_3); - skb_reset_mac_header(skb2); - skb_reset_network_header(skb2); - /* skb2->network_header += ETH_HLEN; */ + skb2->mac.raw = skb2->nh.raw = skb2->data; + /* skb2->nh.raw = skb2->data + ETH_HLEN; */ + skb2->dev = dev; dev_queue_xmit(skb2); } if (skb) { skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); + skb->dev = dev; netif_rx(skb); } diff --git a/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c b/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c index 246fac0e8001..4a5be70c0419 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -146,8 +146,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, * Addr4 = SA */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); + memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdr_len += ETH_ALEN; } else { /* bogus 4-addr format to workaround Prism2 station @@ -160,8 +159,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* SA from skb->data + ETH_ALEN will be added after * frame payload; use hdr.addr4 as a temporary buffer */ - skb_copy_from_linear_data_offset(skb, ETH_ALEN, - &hdr.addr4, ETH_ALEN); + memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); need_tailroom += ETH_ALEN; } @@ -176,27 +174,24 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) else memcpy(&hdr.addr1, local->bssid, ETH_ALEN); memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); + memcpy(&hdr.addr3, skb->data, ETH_ALEN); } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { fc |= IEEE80211_FCTL_FROMDS; /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); + memcpy(&hdr.addr1, skb->data, ETH_ALEN); memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3, - ETH_ALEN); + memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { fc |= IEEE80211_FCTL_TODS; /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ memcpy(&hdr.addr1, to_assoc_ap ? local->assoc_ap_addr : local->bssid, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); - skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); + memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(&hdr.addr3, skb->data, ETH_ALEN); } else if (local->iw_mode == IW_MODE_ADHOC) { /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ - skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); - skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, - ETH_ALEN); + memcpy(&hdr.addr1, skb->data, ETH_ALEN); + memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(&hdr.addr3, local->bssid, ETH_ALEN); } @@ -242,7 +237,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) iface->stats.tx_packets++; iface->stats.tx_bytes += skb->len; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; memset(meta, 0, sizeof(*meta)); meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; diff --git a/trunk/drivers/net/wireless/hostap/hostap_ap.c b/trunk/drivers/net/wireless/hostap/hostap_ap.c index 5b3abd54d0e5..efb8cf3bd8ad 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_ap.c +++ b/trunk/drivers/net/wireless/hostap/hostap_ap.c @@ -1,8 +1,8 @@ /* * Intersil Prism2 driver with Host AP (software access point) support * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen + * + * Copyright (c) 2002-2005, Jouni Malinen * * This file is to be included into hostap.c when S/W AP functionality is * compiled. @@ -982,8 +982,7 @@ static void prism2_send_mgmt(struct net_device *dev, meta->tx_cb_idx = tx_cb_idx; skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); + skb->mac.raw = skb->nh.raw = skb->data; dev_queue_xmit(skb); } #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -1277,8 +1276,8 @@ static char * ap_auth_make_challenge(struct ap_data *ap) return NULL; } - skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, - tmpbuf, WLAN_AUTH_CHALLENGE_LEN); + memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len, + WLAN_AUTH_CHALLENGE_LEN); dev_kfree_skb(skb); return tmpbuf; diff --git a/trunk/drivers/net/wireless/hostap/hostap_common.h b/trunk/drivers/net/wireless/hostap/hostap_common.h index b31e6a05f23c..01624005d808 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_common.h +++ b/trunk/drivers/net/wireless/hostap/hostap_common.h @@ -368,9 +368,9 @@ enum { #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 #define PRISM2_HOSTAPD_RID_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.rid.data) +((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -offsetof(struct prism2_hostapd_param, u.generic_elem.data) +((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() */ diff --git a/trunk/drivers/net/wireless/hostap/hostap_cs.c b/trunk/drivers/net/wireless/hostap/hostap_cs.c index ee1532b62e42..8d8f4b9b8b07 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_cs.c +++ b/trunk/drivers/net/wireless/hostap/hostap_cs.c @@ -22,7 +22,7 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static char *version = PRISM2_VERSION " (Jouni Malinen )"; static dev_info_t dev_info = "hostap_cs"; MODULE_AUTHOR("Jouni Malinen"); @@ -838,8 +838,6 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), - PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", - 0x2d858104), PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", 0x74c5e40d), PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", @@ -850,11 +848,6 @@ static struct pcmcia_device_id hostap_cs_ids[] = { "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", "Eval-RevA", 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), - /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ - PCMCIA_DEVICE_PROD_ID1234( - "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", - "A3", - 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52), PCMCIA_DEVICE_PROD_ID123( "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 0xe6ec52ce, 0x08649af2, 0x4b74baa0), diff --git a/trunk/drivers/net/wireless/hostap/hostap_hw.c b/trunk/drivers/net/wireless/hostap/hostap_hw.c index 959887b70ca7..3079378fb8cd 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_hw.c +++ b/trunk/drivers/net/wireless/hostap/hostap_hw.c @@ -3,8 +3,8 @@ * Intersil Prism2/2.5/3. * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen + * + * Copyright (c) 2002-2005, Jouni Malinen * * 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 @@ -1838,14 +1838,13 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) /* skb->data starts with txdesc->frame_control */ hdr_len = 24; - skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len); + memcpy(&txdesc.frame_control, skb->data, hdr_len); fc = le16_to_cpu(txdesc.frame_control); if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) && skb->len >= 30) { /* Addr4 */ - skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, - ETH_ALEN); + memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); hdr_len += ETH_ALEN; } @@ -2218,7 +2217,7 @@ static void hostap_tx_callback(local_info_t *local, memcpy(skb_put(skb, len), payload, len); skb->dev = local->dev; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; cb->func(skb, ok, cb->data); } diff --git a/trunk/drivers/net/wireless/hostap/hostap_main.c b/trunk/drivers/net/wireless/hostap/hostap_main.c index 4743426cf6ad..9077e6edde34 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_main.c +++ b/trunk/drivers/net/wireless/hostap/hostap_main.c @@ -3,8 +3,8 @@ * Intersil Prism2/2.5/3 - hostap.o module, common routines * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2005, Jouni Malinen + * + * Copyright (c) 2002-2005, Jouni Malinen * * 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 @@ -590,20 +590,20 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) { - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ + memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; } int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) { - const unsigned char *mac = skb_mac_header(skb); - - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, + if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) { + memcpy(haddr, skb->mac.raw + + sizeof(struct linux_wlan_ng_prism_hdr) + 10, ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, + } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */ + memcpy(haddr, skb->mac.raw + + sizeof(struct linux_wlan_ng_cap_hdr) + 10, ETH_ALEN); /* addr2 */ } return ETH_ALEN; @@ -1063,8 +1063,7 @@ int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, meta->iface = netdev_priv(dev); skb->dev = dev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); + skb->mac.raw = skb->nh.raw = skb->data; dev_queue_xmit(skb); return 0; diff --git a/trunk/drivers/net/wireless/hostap/hostap_pci.c b/trunk/drivers/net/wireless/hostap/hostap_pci.c index db4899ed4bb1..c4f6020baa9e 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_pci.c +++ b/trunk/drivers/net/wireless/hostap/hostap_pci.c @@ -20,7 +20,7 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static char *version = PRISM2_VERSION " (Jouni Malinen )"; static char *dev_info = "hostap_pci"; diff --git a/trunk/drivers/net/wireless/hostap/hostap_plx.c b/trunk/drivers/net/wireless/hostap/hostap_plx.c index f0fd5ecdb24d..e235e0647897 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_plx.c +++ b/trunk/drivers/net/wireless/hostap/hostap_plx.c @@ -23,7 +23,7 @@ #include "hostap_wlan.h" -static char *version = PRISM2_VERSION " (Jouni Malinen )"; +static char *version = PRISM2_VERSION " (Jouni Malinen )"; static char *dev_info = "hostap_plx"; diff --git a/trunk/drivers/net/wireless/ipw2100.c b/trunk/drivers/net/wireless/ipw2100.c index d51daf87450f..ad6e4a428355 100644 --- a/trunk/drivers/net/wireless/ipw2100.c +++ b/trunk/drivers/net/wireless/ipw2100.c @@ -28,8 +28,8 @@ Portions of this file are based on the Host AP project, Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - - Copyright (c) 2002-2003, Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c @@ -2416,9 +2416,8 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #ifdef IPW2100_RX_DEBUG /* Make a copy of the frame so we can dump it to the logs if * ieee80211_rx fails */ - skb_copy_from_linear_data(packet->skb, packet_data, - min_t(u32, status->frame_size, - IPW_RX_NIC_BUFFER_LENGTH)); + memcpy(packet_data, packet->skb->data, + min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH)); #endif if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { diff --git a/trunk/drivers/net/wireless/ipw2200.c b/trunk/drivers/net/wireless/ipw2200.c index 7cb2052a55a5..c878a2f3239c 100644 --- a/trunk/drivers/net/wireless/ipw2200.c +++ b/trunk/drivers/net/wireless/ipw2200.c @@ -1847,52 +1847,6 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, store_net_stats); -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - int len = 0, i; - - len = sprintf(&buf[len], - "Displaying %d channels in 2.4Ghz band " - "(802.11bg):\n", geo->bg_channels); - - for (i = 0; i < geo->bg_channels; i++) { - len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", - geo->bg[i].channel, - geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? - " (radar spectrum)" : "", - ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) - ? "" : ", IBSS", - geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? - "passive only" : "active/passive", - geo->bg[i].flags & IEEE80211_CH_B_ONLY ? - "B" : "B/G"); - } - - len += sprintf(&buf[len], - "Displaying %d channels in 5.2Ghz band " - "(802.11a):\n", geo->a_channels); - for (i = 0; i < geo->a_channels; i++) { - len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", - geo->a[i].channel, - geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? - " (radar spectrum)" : "", - ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) - ? "" : ", IBSS", - geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? - "passive only" : "active/passive"); - } - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); - static void notify_wx_assoc_event(struct ipw_priv *priv) { union iwreq_data wrqu; @@ -8179,7 +8133,7 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv, skb->dev = priv->ieee->dev; /* Point raw at the ieee80211_stats */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_80211_STATS); @@ -10401,7 +10355,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, rt_hdr->it_len = dst->len; - skb_copy_from_linear_data(src, skb_put(dst, len), len); + memcpy(skb_put(dst, len), src->data, len); if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) dev_kfree_skb_any(dst); @@ -11429,7 +11383,6 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_led.attr, &dev_attr_speed_scan.attr, &dev_attr_net_stats.attr, - &dev_attr_channels.attr, #ifdef CONFIG_IPW2200_PROMISCUOUS &dev_attr_rtap_iface.attr, &dev_attr_rtap_filter.attr, diff --git a/trunk/drivers/net/wireless/libertas/11d.c b/trunk/drivers/net/wireless/libertas/11d.c deleted file mode 100644 index e0ecc4d483bb..000000000000 --- a/trunk/drivers/net/wireless/libertas/11d.c +++ /dev/null @@ -1,754 +0,0 @@ -/** - * This file contains functions for 802.11D. - */ -#include -#include -#include - -#include "host.h" -#include "decl.h" -#include "11d.h" -#include "dev.h" -#include "wext.h" - -#define TX_PWR_DEFAULT 10 - -static struct region_code_mapping region_code_mapping[] = { - {"US ", 0x10}, /* US FCC */ - {"CA ", 0x10}, /* IC Canada */ - {"SG ", 0x10}, /* Singapore */ - {"EU ", 0x30}, /* ETSI */ - {"AU ", 0x30}, /* Australia */ - {"KR ", 0x30}, /* Republic Of Korea */ - {"ES ", 0x31}, /* Spain */ - {"FR ", 0x32}, /* France */ - {"JP ", 0x40}, /* Japan */ -}; - -/* Following 2 structure defines the supported channels */ -static struct chan_freq_power channel_freq_power_UN_BG[] = { - {1, 2412, TX_PWR_DEFAULT}, - {2, 2417, TX_PWR_DEFAULT}, - {3, 2422, TX_PWR_DEFAULT}, - {4, 2427, TX_PWR_DEFAULT}, - {5, 2432, TX_PWR_DEFAULT}, - {6, 2437, TX_PWR_DEFAULT}, - {7, 2442, TX_PWR_DEFAULT}, - {8, 2447, TX_PWR_DEFAULT}, - {9, 2452, TX_PWR_DEFAULT}, - {10, 2457, TX_PWR_DEFAULT}, - {11, 2462, TX_PWR_DEFAULT}, - {12, 2467, TX_PWR_DEFAULT}, - {13, 2472, TX_PWR_DEFAULT}, - {14, 2484, TX_PWR_DEFAULT} -}; - -static u8 wlan_region_2_code(u8 * region) -{ - u8 i; - u8 size = sizeof(region_code_mapping)/ - sizeof(struct region_code_mapping); - - for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) - region[i] = toupper(region[i]); - - for (i = 0; i < size; i++) { - if (!memcmp(region, region_code_mapping[i].region, - COUNTRY_CODE_LEN)) - return (region_code_mapping[i].code); - } - - /* default is US */ - return (region_code_mapping[0].code); -} - -static u8 *wlan_code_2_region(u8 code) -{ - u8 i; - u8 size = sizeof(region_code_mapping) - / sizeof(struct region_code_mapping); - for (i = 0; i < size; i++) { - if (region_code_mapping[i].code == code) - return (region_code_mapping[i].region); - } - /* default is US */ - return (region_code_mapping[0].region); -} - -/** - * @brief This function finds the nrchan-th chan after the firstchan - * @param band band - * @param firstchan first channel number - * @param nrchan number of channels - * @return the nrchan-th chan number -*/ -static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) -/*find the nrchan-th chan after the firstchan*/ -{ - u8 i; - struct chan_freq_power *cfp; - u8 cfp_no; - - cfp = channel_freq_power_UN_BG; - cfp_no = sizeof(channel_freq_power_UN_BG) / - sizeof(struct chan_freq_power); - - for (i = 0; i < cfp_no; i++) { - if ((cfp + i)->channel == firstchan) { - lbs_pr_debug(1, "firstchan found\n"); - break; - } - } - - if (i < cfp_no) { - /*if beyond the boundary */ - if (i + nrchan < cfp_no) { - *chan = (cfp + i + nrchan)->channel; - return 1; - } - } - - return 0; -} - -/** - * @brief This function Checks if chan txpwr is learned from AP/IBSS - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return TRUE; FALSE -*/ -static u8 wlan_channel_known_11d(u8 chan, - struct parsed_region_chan_11d * parsed_region_chan) -{ - struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; - u8 nr_chan = parsed_region_chan->nr_chan; - u8 i = 0; - - lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, - sizeof(struct chan_power_11d) * nr_chan); - - for (i = 0; i < nr_chan; i++) { - if (chan == chanpwr[i].chan) { - lbs_pr_debug(1, "11D: Found Chan:%d\n", chan); - return 1; - } - } - - lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan); - return 0; -} - -u32 libertas_chan_2_freq(u8 chan, u8 band) -{ - struct chan_freq_power *cf; - u16 cnt; - u16 i; - u32 freq = 0; - - cf = channel_freq_power_UN_BG; - cnt = - sizeof(channel_freq_power_UN_BG) / - sizeof(struct chan_freq_power); - - for (i = 0; i < cnt; i++) { - if (chan == cf[i].channel) - freq = cf[i].freq; - } - - return freq; -} - -static int generate_domain_info_11d(struct parsed_region_chan_11d - *parsed_region_chan, - struct wlan_802_11d_domain_reg * domaininfo) -{ - u8 nr_subband = 0; - - u8 nr_chan = parsed_region_chan->nr_chan; - u8 nr_parsedchan = 0; - - u8 firstchan = 0, nextchan = 0, maxpwr = 0; - - u8 i, flag = 0; - - memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, - COUNTRY_CODE_LEN); - - lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, - sizeof(struct parsed_region_chan_11d)); - - for (i = 0; i < nr_chan; i++) { - if (!flag) { - flag = 1; - nextchan = firstchan = - parsed_region_chan->chanpwr[i].chan; - maxpwr = parsed_region_chan->chanpwr[i].pwr; - nr_parsedchan = 1; - continue; - } - - if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 && - parsed_region_chan->chanpwr[i].pwr == maxpwr) { - nextchan++; - nr_parsedchan++; - } else { - domaininfo->subband[nr_subband].firstchan = firstchan; - domaininfo->subband[nr_subband].nrchan = - nr_parsedchan; - domaininfo->subband[nr_subband].maxtxpwr = maxpwr; - nr_subband++; - nextchan = firstchan = - parsed_region_chan->chanpwr[i].chan; - maxpwr = parsed_region_chan->chanpwr[i].pwr; - } - } - - if (flag) { - domaininfo->subband[nr_subband].firstchan = firstchan; - domaininfo->subband[nr_subband].nrchan = nr_parsedchan; - domaininfo->subband[nr_subband].maxtxpwr = maxpwr; - nr_subband++; - } - domaininfo->nr_subband = nr_subband; - - lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband); - lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, - COUNTRY_CODE_LEN + 1 + - sizeof(struct ieeetypes_subbandset) * nr_subband); - return 0; -} - -/** - * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS - * @param region_chan pointer to struct region_channel - * @param *parsed_region_chan pointer to parsed_region_chan_11d - * @return N/A -*/ -static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, - struct parsed_region_chan_11d * - parsed_region_chan) -{ - u8 i; - struct chan_freq_power *cfp; - - if (region_chan == NULL) { - lbs_pr_debug(1, "11D: region_chan is NULL\n"); - return; - } - - cfp = region_chan->CFP; - if (cfp == NULL) { - lbs_pr_debug(1, "11D: cfp equal NULL \n"); - return; - } - - parsed_region_chan->band = region_chan->band; - parsed_region_chan->region = region_chan->region; - memcpy(parsed_region_chan->countrycode, - wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); - - lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region, - parsed_region_chan->band); - - for (i = 0; i < region_chan->nrcfp; i++, cfp++) { - parsed_region_chan->chanpwr[i].chan = cfp->channel; - parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; - lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n", - parsed_region_chan->chanpwr[i].chan, - parsed_region_chan->chanpwr[i].pwr); - } - parsed_region_chan->nr_chan = region_chan->nrcfp; - - lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan); - - return; -} - -/** - * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS - * @param region region ID - * @param band band - * @param chan chan - * @return TRUE;FALSE -*/ -static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) -{ - struct chan_freq_power *cfp; - int cfp_no; - u8 idx; - - ENTER(); - - cfp = libertas_get_region_cfp_table(region, band, &cfp_no); - if (cfp == NULL) - return 0; - - for (idx = 0; idx < cfp_no; idx++) { - if (chan == (cfp + idx)->channel) { - /* If Mrvl Chip Supported? */ - if ((cfp + idx)->unsupported) { - return 0; - } else { - return 1; - } - } - } - - /*chan is not in the region table */ - LEAVE(); - return 0; -} - -/** - * @brief This function checks if chan txpwr is learned from AP/IBSS - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return 0 -*/ -static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* - countryinfo, - u8 band, - struct parsed_region_chan_11d * - parsed_region_chan) -{ - u8 nr_subband, nrchan; - u8 lastchan, firstchan; - u8 region; - u8 curchan = 0; - - u8 idx = 0; /*chan index in parsed_region_chan */ - - u8 j, i; - - ENTER(); - - /*validation Rules: - 1. valid region Code - 2. First Chan increment - 3. channel range no overlap - 4. channel is valid? - 5. channel is supported by region? - 6. Others - */ - - lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); - - if ((*(countryinfo->countrycode)) == 0 - || (countryinfo->len <= COUNTRY_CODE_LEN)) { - /* No region Info or Wrong region info: treat as No 11D info */ - LEAVE(); - return 0; - } - - /*Step1: check region_code */ - parsed_region_chan->region = region = - wlan_region_2_code(countryinfo->countrycode); - - lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region); - lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, - COUNTRY_CODE_LEN); - - parsed_region_chan->band = band; - - memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, - COUNTRY_CODE_LEN); - - nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); - - for (j = 0, lastchan = 0; j < nr_subband; j++) { - - if (countryinfo->subband[j].firstchan <= lastchan) { - /*Step2&3. Check First Chan Num increment and no overlap */ - lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n", - countryinfo->subband[j].firstchan, lastchan); - continue; - } - - firstchan = countryinfo->subband[j].firstchan; - nrchan = countryinfo->subband[j].nrchan; - - for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { - /*step4: channel is supported? */ - - if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { - /* Chan is not found in UN table */ - lbs_pr_debug(1, "chan is not supported: %d \n", i); - break; - } - - lastchan = curchan; - - if (wlan_region_chan_supported_11d - (region, band, curchan)) { - /*step5: Check if curchan is supported by mrvl in region */ - parsed_region_chan->chanpwr[idx].chan = curchan; - parsed_region_chan->chanpwr[idx].pwr = - countryinfo->subband[j].maxtxpwr; - idx++; - } else { - /*not supported and ignore the chan */ - lbs_pr_debug(1, - "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", - i, curchan, region, band); - } - } - - /*Step6: Add other checking if any */ - - } - - parsed_region_chan->nr_chan = idx; - - lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, - 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); - - LEAVE(); - return 0; -} - -/** - * @brief This function calculates the scan type for channels - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return PASSIVE if chan is unknown; ACTIVE if chan is known -*/ -u8 libertas_get_scan_type_11d(u8 chan, - struct parsed_region_chan_11d * parsed_region_chan) -{ - u8 scan_type = cmd_scan_type_passive; - - ENTER(); - - if (wlan_channel_known_11d(chan, parsed_region_chan)) { - lbs_pr_debug(1, "11D: Found and do Active Scan\n"); - scan_type = cmd_scan_type_active; - } else { - lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n"); - } - - LEAVE(); - return scan_type; - -} - -void libertas_init_11d(wlan_private * priv) -{ - priv->adapter->enable11d = 0; - memset(&(priv->adapter->parsed_region_chan), 0, - sizeof(struct parsed_region_chan_11d)); - return; -} - -static int wlan_enable_11d(wlan_private * priv, u8 flag) -{ - int ret; - - priv->adapter->enable11d = flag; - - /* send cmd to FW to enable/disable 11D function in FW */ - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, - OID_802_11D_ENABLE, - &priv->adapter->enable11d); - if (ret) - lbs_pr_debug(1, "11D: Fail to enable 11D \n"); - - return 0; -} - -/** - * @brief This function sets DOMAIN INFO to FW - * @param priv pointer to wlan_private - * @return 0; -1 -*/ -static int set_domain_info_11d(wlan_private * priv) -{ - int ret; - - if (!priv->adapter->enable11d) { - lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n"); - return 0; - } - - ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - if (ret) - lbs_pr_debug(1, "11D: Fail to dnld domain Info\n"); - - return ret; -} - -/** - * @brief This function setups scan channels - * @param priv pointer to wlan_private - * @param band band - * @return 0 -*/ -int libertas_set_universaltable(wlan_private * priv, u8 band) -{ - wlan_adapter *adapter = priv->adapter; - u16 size = sizeof(struct chan_freq_power); - u16 i = 0; - - memset(adapter->universal_channel, 0, - sizeof(adapter->universal_channel)); - - adapter->universal_channel[i].nrcfp = - sizeof(channel_freq_power_UN_BG) / size; - lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n", - adapter->universal_channel[i].nrcfp); - - adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; - adapter->universal_channel[i].valid = 1; - adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE; - adapter->universal_channel[i].band = band; - i++; - - return 0; -} - -/** - * @brief This function implements command CMD_802_11D_DOMAIN_INFO - * @param priv pointer to wlan_private - * @param cmd pointer to cmd buffer - * @param cmdno cmd ID - * @param cmdOption cmd action - * @return 0 -*/ -int libertas_cmd_802_11d_domain_info(wlan_private * priv, - struct cmd_ds_command *cmd, u16 cmdno, - u16 cmdoption) -{ - struct cmd_ds_802_11d_domain_info *pdomaininfo = - &cmd->params.domaininfo; - struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; - wlan_adapter *adapter = priv->adapter; - u8 nr_subband = adapter->domainreg.nr_subband; - - ENTER(); - - lbs_pr_debug(1, "nr_subband=%x\n", nr_subband); - - cmd->command = cpu_to_le16(cmdno); - pdomaininfo->action = cpu_to_le16(cmdoption); - if (cmdoption == cmd_act_get) { - cmd->size = - cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, - (int)(cmd->size)); - LEAVE(); - return 0; - } - - domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); - memcpy(domain->countrycode, adapter->domainreg.countrycode, - sizeof(domain->countrycode)); - - domain->header.len = - cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + - sizeof(domain->countrycode)); - - if (nr_subband) { - memcpy(domain->subband, adapter->domainreg.subband, - nr_subband * sizeof(struct ieeetypes_subbandset)); - - cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + - domain->header.len + - sizeof(struct mrvlietypesheader) + - S_DS_GEN); - } else { - cmd->size = - cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - } - - lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size)); - - LEAVE(); - - return 0; -} - -/** - * @brief This function implements private cmd: enable/disable 11D - * @param priv pointer to wlan_private - * @param wrq pointer to user data - * @return 0 or -1 - */ -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) -{ - int data = 0; - int *val; - - ENTER(); - data = SUBCMD_DATA(wrq); - - lbs_pr_debug(1, "enable 11D: %s\n", - (data == 1) ? "enable" : "Disable"); - - wlan_enable_11d(priv, data); - val = (int *)wrq->u.name; - *val = priv->adapter->enable11d; - - LEAVE(); - return 0; -} - -/** - * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to wlan_private - * @param resp pointer to command response buffer - * @return 0; -1 - */ -int libertas_ret_802_11d_domain_info(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11d_domain_info - *domaininfo = &resp->params.domaininforesp; - struct mrvlietypes_domainparamset *domain = &domaininfo->domain; - u16 action = le16_to_cpu(domaininfo->action); - s16 ret = 0; - u8 nr_subband = 0; - - ENTER(); - - lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, - (int)le16_to_cpu(resp->size)); - - nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset); - /* countrycode 3 bytes */ - - lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband); - - if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { - lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n"); - return -1; - } - - switch (action) { - case cmd_act_set: /*Proc Set action */ - break; - - case cmd_act_get: - break; - default: - lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action); - ret = -1; - break; - } - - LEAVE(); - return ret; -} - -/** - * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to wlan_private - * @return 0; -1 - */ -int libertas_parse_dnld_countryinfo_11d(wlan_private * priv) -{ - int ret; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - if (priv->adapter->enable11d) { - memset(&adapter->parsed_region_chan, 0, - sizeof(struct parsed_region_chan_11d)); - ret = parse_domain_info_11d(&adapter->pattemptedbssdesc-> - countryinfo, 0, - &adapter->parsed_region_chan); - - if (ret == -1) { - lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n"); - LEAVE(); - return ret; - } - - memset(&adapter->domainreg, 0, - sizeof(struct wlan_802_11d_domain_reg)); - generate_domain_info_11d(&adapter->parsed_region_chan, - &adapter->domainreg); - - ret = set_domain_info_11d(priv); - - if (ret) { - lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); - LEAVE(); - return ret; - } - } - LEAVE(); - return 0; -} - -/** - * @brief This function generates 11D info from user specified regioncode and download to FW - * @param priv pointer to wlan_private - * @return 0; -1 - */ -int libertas_create_dnld_countryinfo_11d(wlan_private * priv) -{ - int ret; - wlan_adapter *adapter = priv->adapter; - struct region_channel *region_chan; - u8 j; - - ENTER(); - lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band); - - if (priv->adapter->enable11d) { - /* update parsed_region_chan_11; dnld domaininf to FW */ - - for (j = 0; j < sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); j++) { - region_chan = &adapter->region_channel[j]; - - lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j, - region_chan->band); - - if (!region_chan || !region_chan->valid - || !region_chan->CFP) - continue; - if (region_chan->band != adapter->curbssparams.band) - continue; - break; - } - - if (j >= sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0])) { - lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n", - adapter->curbssparams.band); - LEAVE(); - return -1; - } - - memset(&adapter->parsed_region_chan, 0, - sizeof(struct parsed_region_chan_11d)); - wlan_generate_parsed_region_chan_11d(region_chan, - &adapter-> - parsed_region_chan); - - memset(&adapter->domainreg, 0, - sizeof(struct wlan_802_11d_domain_reg)); - generate_domain_info_11d(&adapter->parsed_region_chan, - &adapter->domainreg); - - ret = set_domain_info_11d(priv); - - if (ret) { - lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); - LEAVE(); - return ret; - } - - } - - LEAVE(); - return 0; -} diff --git a/trunk/drivers/net/wireless/libertas/11d.h b/trunk/drivers/net/wireless/libertas/11d.h deleted file mode 100644 index db2ebea9f231..000000000000 --- a/trunk/drivers/net/wireless/libertas/11d.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * This header file contains data structures and - * function declarations of 802.11d - */ -#ifndef _WLAN_11D_ -#define _WLAN_11D_ - -#include "types.h" -#include "defs.h" - -#define UNIVERSAL_REGION_CODE 0xff - -/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) - */ -#define MRVDRV_MAX_SUBBAND_802_11D 83 - -#define COUNTRY_CODE_LEN 3 -#define MAX_NO_OF_CHAN 40 - -struct cmd_ds_command; - -/** Data structure for Country IE*/ -struct ieeetypes_subbandset { - u8 firstchan; - u8 nrchan; - u8 maxtxpwr; -} __attribute__ ((packed)); - -struct ieeetypes_countryinfoset { - u8 element_id; - u8 len; - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; -}; - -struct ieeetypes_countryinfofullset { - u8 element_id; - u8 len; - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; -} __attribute__ ((packed)); - -struct mrvlietypes_domainparamset { - struct mrvlietypesheader header; - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11d_domain_info { - u16 action; - struct mrvlietypes_domainparamset domain; -} __attribute__ ((packed)); - -/** domain regulatory information */ -struct wlan_802_11d_domain_reg { - /** country Code*/ - u8 countrycode[COUNTRY_CODE_LEN]; - /** No. of subband*/ - u8 nr_subband; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; -}; - -struct chan_power_11d { - u8 chan; - u8 pwr; -} __attribute__ ((packed)); - -struct parsed_region_chan_11d { - u8 band; - u8 region; - s8 countrycode[COUNTRY_CODE_LEN]; - struct chan_power_11d chanpwr[MAX_NO_OF_CHAN]; - u8 nr_chan; -} __attribute__ ((packed)); - -struct region_code_mapping { - u8 region[COUNTRY_CODE_LEN]; - u8 code; -}; - -u8 libertas_get_scan_type_11d(u8 chan, - struct parsed_region_chan_11d *parsed_region_chan); - -u32 libertas_chan_2_freq(u8 chan, u8 band); - -enum state_11d libertas_get_state_11d(wlan_private * priv); - -void libertas_init_11d(wlan_private * priv); - -int libertas_set_universaltable(wlan_private * priv, u8 band); - -int libertas_cmd_802_11d_domain_info(wlan_private * priv, - struct cmd_ds_command *cmd, u16 cmdno, - u16 cmdOption); - -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); - -int libertas_ret_802_11d_domain_info(wlan_private * priv, - struct cmd_ds_command *resp); - -int libertas_parse_dnld_countryinfo_11d(wlan_private * priv); - -int libertas_create_dnld_countryinfo_11d(wlan_private * priv); - -#endif /* _WLAN_11D_ */ diff --git a/trunk/drivers/net/wireless/libertas/LICENSE b/trunk/drivers/net/wireless/libertas/LICENSE deleted file mode 100644 index 8862742213b9..000000000000 --- a/trunk/drivers/net/wireless/libertas/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ - Copyright (c) 2003-2006, Marvell International Ltd. - All Rights Reserved - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License 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 License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - diff --git a/trunk/drivers/net/wireless/libertas/Makefile b/trunk/drivers/net/wireless/libertas/Makefile deleted file mode 100644 index 19c935071d8e..000000000000 --- a/trunk/drivers/net/wireless/libertas/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# EXTRA_CFLAGS += -Wpacked - -usb8xxx-objs := main.o fw.o wext.o \ - rx.o tx.o cmd.o \ - cmdresp.o scan.o \ - join.o 11d.o \ - ioctl.o debugfs.o \ - ethtool.o assoc.o - -ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y) -EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG -endif - - -# This is needed to support the newer boot2 bootloader (v >= 3104) -EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND -usb8xxx-objs += if_bootcmd.o -usb8xxx-objs += if_usb.o - -obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o - diff --git a/trunk/drivers/net/wireless/libertas/README b/trunk/drivers/net/wireless/libertas/README deleted file mode 100644 index 688da4c784b1..000000000000 --- a/trunk/drivers/net/wireless/libertas/README +++ /dev/null @@ -1,1044 +0,0 @@ -================================================================================ - README for USB8388 - - (c) Copyright © 2003-2006, Marvell International Ltd. - All Rights Reserved - - This software file (the "File") is distributed by Marvell International - Ltd. under the terms of the GNU General Public License Version 2, June 1991 - (the "License"). You may use, redistribute and/or modify this File in - accordance with the terms and conditions of the License, a copy of which - is available along with the File in the license.txt file or by writing to - the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. - - THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - ARE EXPRESSLY DISCLAIMED. The License provides additional details about - this warranty disclaimer. -================================================================================ - -===================== -DRIVER LOADING -===================== - - o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/ - - o. Load driver by using the following command: - - insmod usb8388.ko [fw_name=usb8388.bin] - -===================== -IWPRIV COMMAND -===================== - -NAME - This manual describes the usage of private commands used in Marvell WLAN - Linux Driver. All the commands available in Wlanconfig will not be available - in the iwpriv. - -SYNOPSIS - iwpriv [sub-command] ... - - iwpriv ethX version - iwpriv ethX scantype [sub-command] - iwpriv ethX getSNR - iwpriv ethX getNF - iwpriv ethX getRSSI - iwpriv ethX setrxant - iwpriv ethX getrxant - iwpriv ethX settxant - iwpriv ethX gettxant - iwpriv ethX authalgs - iwpriv ethX pre-TBTT - iwpriv ethX 8021xauthalgs - iwpriv ethX encryptionmode - iwpriv ethX setregioncode - iwpriv ethX getregioncode - iwpriv ethX setbcnavg - iwpriv ethX getbcnavg - iwpriv ethX setdataavg - iwpriv ethX setlisteninter - iwpriv ethX getlisteninter - iwpriv ethX setmultipledtim - iwpriv ethX getmultipledtim - iwpriv ethX atimwindow - iwpriv ethX deauth - iwpriv ethX adhocstop - iwpriv ethX radioon - iwpriv ethX radiooff - iwpriv ethX reasso-on - iwpriv ethX reasso-off - iwpriv ethX scanmode [sub-command] - iwpriv ethX setwpaie - iwpriv ethX wlanidle-off - iwpriv ethX wlanidle-on - iwpriv ethX getcis - iwpriv ethX getlog - iwpriv ethX getadhocstatus - iwpriv ethX adhocgrate - -Version 4 Command: - iwpriv ethX inactvityto - iwpriv ethX sleeppd - iwpriv ethX enable11d - iwpriv ethX tpccfg - iwpriv ethX powercfg - iwpriv ethX setafc - iwpriv ethX getafc - -Version 5 Command: - iwpriv ethX ledgpio - iwpriv ethX scanprobes - iwpriv ethX lolisteninter - iwpriv ethX rateadapt - iwpriv ethX txcontrol - iwpriv ethX psnullinterval - iwpriv ethX prescan - iwpriv ethX getrxinfo - iwpriv ethX gettxrate - iwpriv ethX beaconinterval - -BT Commands: - The blinding table (BT) contains a list of mac addresses that should be - ignored by the firmware. It is primarily used for debugging and - testing networks. It can be edited and inspected with the following - commands: - - iwpriv ethX bt_reset - iwpriv ethX bt_add - iwpriv ethX bt_del - iwpriv ethX bt_list - -FWT Commands: - The forwarding table (FWT) is a feature used to manage mesh network - routing in the firmware. The FWT is essentially a routing table that - associates a destination mac address (da) with a next hop receiver - address (ra). The FWT can be inspected and edited with the following - iwpriv commands, which are described in greater detail below. - Eventually, the table will be automatically maintained by a custom - routing protocol. - - NOTE: FWT commands replace the previous DFT commands. What were the DFT - commands?, you might ask. They were an earlier API to the firmware that - implemented a simple MAC-layer forwarding mechanism. In the unlikely - event that you were using these commands, you must migrate to the new - FWT commands which can be used to achieve the same functionality. - - iwpriv ethX fwt_add [parameters] - iwpriv ethX fwt_del [parameters] - iwpriv ethX fwt_lookup [parameters] - iwpriv ethX fwt_list [parameters] - iwpriv ethX fwt_list_route [parameters] - iwpriv ethX fwt_list_neigh [parameters] - iwpriv ethX fwt_reset [parameters] - iwpriv ethX fwt_cleanup - iwpriv ethX fwt_time - -MESH Commands: - - The MESH commands are used to configure various features of the mesh - routing protocol. The following commands are supported: - - iwpriv ethX mesh_get_ttl - iwpriv ethX mesh_set_ttl ttl - -DESCRIPTION - Those commands are used to send additional commands to the Marvell WLAN - card via the Linux device driver. - - The ethX parameter specifies the network device that is to be used to - perform this command on. it could be eth0, eth1 etc. - -version - This is used to get the current version of the driver and the firmware. - -scantype - This command is used to set the scan type to be used by the driver in - the scan command. This setting will not be used while performing a scan - for a specific SSID, as it is always done with scan type being active. - - where the sub-commands are: - - active -- to set the scan type to active - passive -- to set the scan type to passive - get -- to get the scan type set in the driver - -getSNR - This command gets the average and non average value of Signal to Noise - Ratio of Beacon and Data. - - where value is:- - 0 -- Beacon non-average. - 1 -- Beacon average. - 2 -- Data non-average. - 3 -- Data average. - - If no value is given, all four values are returned in the order mentioned - above. - - Note: This command is available only when STA is connected. - -getRSSI - This command gets the average and non average value os Receive Signal - Strength of Beacon and Data. - - where value is:- - 0 -- Beacon non-average. - 1 -- Beacon average. - 2 -- Data non-average. - 3 -- Data average. - - Note: This command is available only when STA is connected. - -getNF - This command gets the average and non average value of Noise Floor of - Beacon and Data. - - where value is:- - 0 -- Beacon non-average. - 1 -- Beacon average. - 2 -- Data non-average. - 3 -- Data average. - - Note: This command is available only when STA is connected. - -setrxant - This command is used to set the mode for Rx antenna. - - The options that can be sent are:- - 1 -- Antenna 1. - 2 -- Antenna 2. - 0xFFFF -- Diversity. - - Usage: - iwpriv ethX setrxant 0x01: select Antenna 1. - -getrxant - This command is used to get the mode for Rx antenna. - - -settxant - This command is used to set the mode for Tx antenna. - The options that can be sent are:- - 1 -- Antenna 1. - 2 -- Antenna 2. - 0xFFFF -- Diversity. - Usage: - iwpriv ethX settxant 0x01: select Antenna 1. - -gettxant - This command is used to get the mode for Tx antenna. - -authalgs - This command is used by the WPA supplicant to set the authentication - algorithms in the station. - -8021xauthalgs - This command is used by the WPA supplicant to set the 8021.x authentication algorithm type - station. - - where values can be:- - 1 -- None - 2 -- LEAP - 4 -- TLS - 8 -- TTLs - 16 -- MD5 - - -encryptionmode - This command is used by the WPA supplicant to set the encryption algorithm. - - where values can be:- - 0 -- NONE - 1 -- WEP40 - 2 -- TKIP - 3 -- CCMP - 4 -- WEP104 - -pre-TBTT - This command is used to set pre-TBTT time period where value is in microseconds. - -setregioncode - This command is used to set the region code in the station. - where value is 'region code' for various regions like - USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ... - - Usage: - iwpriv ethX setregioncode 0x10: set region code to USA (0x10). - -getregioncode - This command is used to get the region code information set in the - station. - -setbcnavg - Set the weighting factor for calculating RSSI. - -getbcnavg - Get weighting factor for calculating RSSI. - -setdataavg - Set the weighting factor for calculating SNR. - -setlisteninter - This command is used to set the listen interval in the - station. - - where the value ranges between 1 - 255 - -getlisteninter - This command is used to get the listen interval value set in the - station. - -setmultipledtim - This command is used to set the multiple dtim value in the - station. - where the value is 1,2,3,4,5,0xfffe - 0xfffe means the firmware will use listen interval in association - command for waking up - -getmultipledtim - This command is used to get the multiple dtim value set in the station. - -atimwindow - This command is used to set the atim value in the - station. - - where the value ranges between 0 - 50 - -deauth - This command is used to send the de-authentication to the AP with which - the station is associated. This command is valid only when - station is in Infrastructure mode. - - Note: This command is available only when STA is connected. - -adhocstop - This command is used to stop beacon transmission from the station and - go into idle state in ad-hoc mode. - - Note: This command is available only when STA is connected. - -radioon - This command is used to turn on the RF antenna. - -radiooff - This command is sued to turn off the RF antenna. - -scanmode - This command is used to set the station to scan for either IBSS - networks or BSS networks or both BSS and IBSS networks. This - command can be used with sub commands, - - where the value for - bss -- Scan All the BSS networks. - ibss -- Scan All the IBSS networks. - any -- Scan both BSS and IBSS networks. - - - -setwpaie - This command is used by WPA supplicant to send the WPA-IE to the driver. - -wlanidle-off - This command is used to get into idle state. - - Note: This command is available only when STA is connected. - -wlanidle-on - This command is used to get off the idle state. - - Note: This command is available only when STA is connected. - - -getlog - This command is used to get the 802.11 statistics available in the - station. - - Note: This command is available only when STA is connected. - -getadhocstatus - This command is used to get the ad-hoc Network Status. - - The various status codes are: - AdhocStarted - AdhocJoined - AdhocIdle - InfraMode - AutoUnknownMode - - Note: This command is available only when STA is connected. - -adhocgrate - This command is used to enable(1) g_rate, Disable(0) g_rate - and request(2) the status which g_rate is disabled/enabled, - for Ad-hoc creator. - - where value is:- - 0 -- Disabled - 1 -- Enabled - 2 -- Get - -ledgpio - This command is used to set/get LEDs. - - iwpriv ethX ledgpio - will set the corresponding LED for the GPIO Line. - - iwpriv ethX ledgpio - will give u which LEDs are Enabled. - - Usage: - iwpriv eth1 ledgpio 1 0 2 1 3 4 - will enable - LED 1 -> GPIO 0 - LED 2 -> GPIO 1 - LED 3 -> GPIO 4 - - iwpriv eth1 ledgpio - shows LED information in the format as mentioned above. - - Note: LED0 is invalid - Note: Maximum Number of LEDs are 16. - -inactivityto - This command is used by the host to set/get the inactivity timeout value, - which specifies when WLAN device is put to sleep. - - Usage: - iwpriv ethX inactivityto [] - - where the parameter are: - timeout: timeout value in milliseconds. - - Example: - iwpriv eth1 inactivityto - "get the timeout value" - - iwpriv eth1 inactivityto X - "set timeout value to X ms" - - -sleeppd - This command is used to configure the sleep period of the WLAN device. - - Usage: - iwpriv ethX sleeppd [] - - where the parameter are: - Period: sleep period in milliseconds. Range 10~60. - - Example: - iwpriv eth1 sleeppd 10 - "set period as 10 ms" - iwpriv eth1 sleeppd - "get the sleep period configuration" - -enable11d - This command is used to control 11d - where value is:- - 1 -- Enabled - 0 -- Disabled - 2 -- Get - - - - -tpccfg - Enables or disables automatic transmit power control. - - The first parameter turns this feature on (1) or off (0). When turning - on, the user must also supply four more parameters in the following - order: - -UseSNR (Use SNR (in addition to PER) for TPC algorithm), - -P0 (P0 power level for TPC), - -P1 (P1 power level for TPC), - -P2 (P2 power level for TPC). - - Usage: - iwpriv ethX tpccfg: Get current configuration - iwpriv ethX tpccfg 0: disable auto TPC - iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR; - P0=0x05; P1=0x0a; P2=0x0d; - iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR; - P0=0x05; P1=0x0a; P2=0x0d. - -powercfg - Enables or disables power adaptation. - - The first parameter turns this feature on (1) or off (0). When turning - on, the user must also supply three more parameters in the following - order: - -P0 (P0 power level for Power Adaptation), - -P1 (P1 power level for Power Adaptation), - -P2 (P2 power level for Power Adaptation). - - Usage: - iwpriv ethX powercfg: Get current configuration - iwpriv ethX powercfg 0: disable power adaptation - iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation; - P0=0x0d; P1=0x0f; P2=0x12. - -getafc - This command returns automatic frequency control parameters. It returns - three integers: - -P0: automatic is on (1), or off (0), - -P1: current timing offset in PPM (part per million), and - -P2: current frequency offset in PPM. - -setafc - Set automatic frequency control options. - - The first parameter turns automatic on (1) or off (0). - The user must supply two more parameters in either case, in the following - order: - - When auto is on: - - -P0 (automatic adjustment frequency threshold in PPM), - -P1 (automatic adjustment period in beacon period), - - When auto is off: - - -P0 (manual adjustment timing offset in PPM), and - -P1 (manual adjustment frequency offset in PPM). - - Usage: - iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy - offset are 10 PPM. - - iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment, - frequency threshold 10 PPM, for every 10 beacon periods. - - - -scanprobes - This command sets number of probe requests per channel. - - Usage: - iwpriv ethX scanprobes 3 (set scan probes to 3) - iwpriv ethX scanprobes (get scan probes) - -lolisteninter - This command sets the value of listen interval. - - Usage: - iwpriv ethX lolisteninter 234 (set the lolisteninter to 234) - iwpriv ethX lolisteninter (get the lolisteninter value) - -rateadapt - This command sets the data rates bitmap. - Where - 0: Disable auto rate adapt - 1: Enable auto rate adapt - - - data rate bitmap - Bit Data rate - 0 1 Mbps - 1 2 Mbps - 2 5.5 Mbps - 3 11 Mbps - 4 Reserved - 5 6 Mbps - 6 9 Mbps - 7 12 Mbps - 8 18 Mbps - 9 24 Mbps - 10 36 Mbps - 11 48 Mbps - 12 54 Mbps - 12-15 Reserved - - Usage: - iwpriv ethX rateadapt - read the currect data rate setting - iwpriv ethX rateadapt 1 0x07 - enable auto data rate adapt and - data rates are 1Mbps, 2Mbsp and 5.5Mbps - - -txcontrol - This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis. - - Where value is: - if bit[4] == 1: - bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16 - Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv - - bit[12:8] - if bit[12] == 1, bit[11:8] specifies the Tx retry limit. - - bit[14:13] specifies per packet ack policy: - bit[14:13] - 1 0 use immediate ack policy for this packet - 1 1 use no ack policy for this packet - 0 x use the per-packet ack policy setting - - Usage: - iwpriv ethX txcontrol 0x7513 - Use no-ack policy, 5 retires for Tx, 11Mbps rate - - - -psnullinterval - This command is used to set/request NULL package interval for Power Save - under infrastructure mode. - - where value is:- - -1 -- Disabled - n>0 -- Set interval as n (seconds) - -prescan - This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap - - where value is:- - 0 -- Disabled - 1 -- Enabled - 2 -- Get - -getrxinfo - This command gets non average value of Signal to Noise Ratio of Data and rate index. - - The following table shows RateIndex and Rate - - RateIndex Data rate - 0 1 Mbps - 1 2 Mbps - 2 5.5 Mbps - 3 11 Mbps - 4 Reserved - 5 6 Mbps - 6 9 Mbps - 7 12 Mbps - 8 18 Mbps - 9 24 Mbps - 10 36 Mbps - 11 48 Mbps - 12 54 Mbps - 13-15 Reserved - -gettxrate - This command gets current Tx rate index of the first packet associated with Rate Adaptation. - - The following table shows RateIndex and Rate - - RateIndex Data rate - 0 1 Mbps - 1 2 Mbps - 2 5.5 Mbps - 3 11 Mbps - 4 Reserved - 5 6 Mbps - 6 9 Mbps - 7 12 Mbps - 8 18 Mbps - 9 24 Mbps - 10 36 Mbps - 11 48 Mbps - 12 54 Mbps - 13-15 Reserved - -bcninterval - This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc - beacon interval when no argument is given. The valid beacon interval is between 20 - 1000, - default beacon interval is 100. - - Usage: - iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100) - iwpriv ethX bcninterval (get adhoc beacon interval) - -fwt_add - This command is used to insert an entry into the FWT table. The list of - parameters must follow the following structure: - - iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr] - - The parameters between brackets are optional, but they must appear in - the order specified. For example, if you want to specify the metric, - you must also specify the dir, ssn, and dsn but you need not specify the - hopcount, expiration, sleepmode, or snr. Any unspecified parameters - will be assigned the defaults specified below. - - The different parameters are:- - da -- DA MAC address in the form 00:11:22:33:44:55 - ra -- RA MAC address in the form 00:11:22:33:44:55 - metric -- route metric (cost: smaller-metric routes are - preferred, default is 0) - dir -- direction (1 for direct, 0 for reverse, - default is 1) - ssn -- Source Sequence Number (time at the RA for - reverse routes. Default is 0) - dsn -- Destination Sequence Number (time at the DA - for direct routes. Default is 0) - hopcount -- hop count (currently unused, default is 0) - ttl -- TTL (Only used in reverse entries) - expiration -- entry expiration (in ticks, where a tick is - 1024us, or ~ 1ms. Use 0 for an indefinite - entry, default is 0) - sleepmode -- RA's sleep mode (currently unused, default is - 0) - snr -- SNR in the link to RA (currently unused, - default is 0) - - The command does not return anything. - -fwt_del - This command is used to remove an entry to the FWT table. The list of - parameters must follow the following structure: - - iwpriv ethX fwt_del da ra [dir] - - where the different parameters are:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - ra -- RA MAC address (in the form "00:11:22:33:44:55") - dir -- direction (1 for direct, 0 for reverse, - default is 1) - - The command does not return anything. - -fwt_lookup - This command is used to get the best route in the FWT table to a given - host. The only parameter is the MAC address of the host that is being - looked for. - - iwpriv ethX fwt_lookup da - - where:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - - The command returns an output string identical to the one returned by - fwt_list described below. - - -fwt_list - This command is used to list a route from the FWT table. The only - parameter is the index into the table. If you want to list all the - routes in a table, start with index=0, and keep listing until you get a - "(null)" string. Note that the indicies may change as the fwt is - updated. It is expected that most users will not use fwt_list directly, - but that a utility similar to the traditional route command will be used - to invoke fwt_list over and over. - - iwpriv ethX fwt_list index - - The output is a string of the following form: - - da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr - - where the different fields are:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - ra -- RA MAC address (in the form "00:11:22:33:44:55") - metric -- route metric (cost: smaller-metric routes are preferred) - dir -- direction (1 for direct, 0 for reverse) - ssn -- Source Sequence Number (time at the RA for reverse routes) - dsn -- Destination Sequence Number (time at the DA for direct routes) - hopcount -- hop count (currently unused) - ttl -- TTL (only used in reverse entries) - expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) - sleepmode -- RA's sleep mode (currently unused) - snr -- SNR in the link to RA (currently unused) - -fwt_list_route - This command is used to list a route from the FWT table. The only - parameter is the route ID. If you want to list all the routes in a - table, start with rid=0, and keep incrementing rid until you get a - "(null)" string. This function is similar to fwt_list. The only - difference is the output format. Also note that this command is meant - for debugging. It is expected that users will use fwt_lookup and - fwt_list. One important reason for this is that the route id may change - as the route table is altered. - - iwpriv ethX fwt_list_route rid - - The output is a string of the following form: - - da metric dir nid ssn dsn hopcount ttl expiration - - where the different fields are:- - da -- DA MAC address (in the form "00:11:22:33:44:55") - metric -- route metric (cost: smaller-metric routes are preferred) - dir -- direction (1 for direct, 0 for reverse) - nid -- Next-hop (neighbor) host ID (nid) - ssn -- Source Sequence Number (time at the RA for reverse routes) - dsn -- Destination Sequence Number (time at the DA for direct routes) - hopcount -- hop count (currently unused) - ttl -- TTL count (only used in reverse entries) - expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) - -fwt_list_neigh - This command is used to list a neighbor from the FWT table. The only - parameter is the neighbor ID. If you want to list all the neighbors in a - table, start with nid=0, and keep incrementing nid until you get a - "(null)" string. Note that the nid from a fwt_list_route command can be - used as an input to this command. Also note that this command is meant - mostly for debugging. It is expected that users will use fwt_lookup. - One important reason for this is that the neighbor id may change as the - neighbor table is altered. - - iwpriv ethX fwt_list_neigh nid - - The output is a string of the following form: - - ra sleepmode snr references - - where the different fields are:- - ra -- RA MAC address (in the form "00:11:22:33:44:55") - sleepmode -- RA's sleep mode (currently unused) - snr -- SNR in the link to RA (currently unused) - references -- RA's reference counter - -fwt_reset - This command is used to reset the FWT table, getting rid of all the - entries. There are no input parameters. - - iwpriv ethX fwt_reset - - The command does not return anything. - -fwt_cleanup - This command is used to perform user-based garbage recollection. The - FWT table is checked, and all the entries that are expired or invalid - are cleaned. Note that this is exported to the driver for debugging - purposes, as garbage collection is also fired by the firmware when in - space problems. There are no input parameters. - - iwpriv ethX fwt_cleanup - - The command does returns the number of invalid/expired routes deleted. - -fwt_time - This command returns a card's internal time representation. It is this - time that is used to represent the expiration times of FWT entries. The - number is not consistent from card to card; it is simply a timer count. - The fwt_time command is used to inspect the timer so that expiration - times reported by fwt_list can be properly interpreted. - - iwpriv ethX fwt_time - -mesh_get_ttl - - The mesh ttl is the number of hops a mesh packet can traverse before it - is dropped. This parameter is used to prevent infinite loops in the - mesh network. The value returned by this function is the ttl assigned - to all mesh packets. Currently there is no way to control the ttl on a - per packet or per socket basis. - - iwpriv ethX mesh_get_ttl - -mesh_set_ttl ttl - - Set the ttl. The argument must be between 0 and 255. - - iwpriv ethX mesh_set_ttl - -========================= -ETHTOOL -========================= - - -Use the -i option to retrieve version information from the driver. - -# ethtool -i eth0 -driver: libertas -version: COMM-USB8388-318.p4 -firmware-version: 5.110.7 -bus-info: - -Use the -e option to read the EEPROM contents of the card. - - Usage: - ethtool -e ethX [raw on|off] [offset N] [length N] - - -e retrieves and prints an EEPROM dump for the specified ethernet - device. When raw is enabled, then it dumps the raw EEPROM data - to stdout. The length and offset parameters allow dumping cer- - tain portions of the EEPROM. Default is to dump the entire EEP- - ROM. - -# ethtool -e eth0 offset 0 length 16 -Offset Values ------- ------ -0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00 - -======================== -DEBUGFS COMMANDS -======================== - -those commands are used via debugfs interface - -=========== -rdmac -rdbbp -rdrf - These commands are used to read the MAC, BBP and RF registers from the - card. These commands take one parameter that specifies the offset - location that is to be read. This parameter must be specified in - hexadecimal (its possible to preceed preceding the number with a "0x"). - - Path: /debugfs/libertas_wireless/ethX/registers/ - - Usage: - echo "0xa123" > rdmac ; cat rdmac - echo "0xa123" > rdbbp ; cat rdbbp - echo "0xa123" > rdrf ; cat rdrf -wrmac -wrbbp -wrrf - These commands are used to write the MAC, BBP and RF registers in the - card. These commands take two parameters that specify the offset - location and the value that is to be written. This parameters must - be specified in hexadecimal (its possible to preceed the number - with a "0x"). - - Usage: - echo "0xa123 0xaa" > wrmac - echo "0xa123 0xaa" > wrbbp - echo "0xa123 0xaa" > wrrf - -sleepparams - This command is used to set the sleepclock configurations - - Path: /debugfs/libertas_wireless/ethX/ - - Usage: - cat sleepparams: reads the current sleepclock configuration - - echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration. - - where: - p1 is Sleep clock error in ppm (0-65535) - p2 is Wakeup offset in usec (0-65535) - p3 is Clock stabilization time in usec (0-65535) - p4 is Control periodic calibration (0-2) - p5 is Control the use of external sleep clock (0-2) - p6 is reserved for debug (0-65535) - -subscribed_events - - The subscribed_events directory contains the interface for the - subscribed events API. - - Path: /debugfs/libertas_wireless/ethX/subscribed_events/ - - Each event is represented by a filename. Each filename consists of the - following three fields: - Value Frequency Subscribed - - To read the current values for a given event, do: - cat event - To set the current values, do: - echo "60 2 1" > event - - Frequency field specifies the reporting frequency for this event. - If it is set to 0, then the event is reported only once, and then - automatically unsubscribed. If it is set to 1, then the event is - reported every time it occurs. If it is set to N, then the event is - reported every Nth time it occurs. - - beacon_missed - Value field specifies the number of consecutive missing beacons which - triggers the LINK_LOSS event. This event is generated only once after - which the firmware resets its state. At initialization, the LINK_LOSS - event is subscribed by default. The default value of MissedBeacons is - 60. - - failure_count - Value field specifies the consecutive failure count threshold which - triggers the generation of the MAX_FAIL event. Once this event is - generated, the consecutive failure count is reset to 0. - At initialization, the MAX_FAIL event is NOT subscribed by - default. - - high_rssi - This event is generated when the average received RSSI in beacons goes - above a threshold, specified by Value. - - low_rssi - This event is generated when the average received RSSI in beacons goes - below a threshold, specified by Value. - - high_snr - This event is generated when the average received SNR in beacons goes - above a threshold, specified by Value. - - low_snr - This event is generated when the average received SNR in beacons goes - below a threshold, specified by Value. - -extscan - This command is used to do a specific scan. - - Path: /debugfs/libertas_wireless/ethX/ - - Usage: echo "SSID" > extscan - - Example: - echo "LINKSYS-AP" > extscan - - To see the results of use getscantable command. - -getscantable - - Display the current contents of the driver scan table (ie. get the - scan results). - - Path: /debugfs/libertas_wireless/ethX/ - - Usage: - cat getscantable - -setuserscan - Initiate a customized scan and retrieve the results - - - Path: /debugfs/libertas_wireless/ethX/ - - Usage: - echo "[ARGS]" > setuserscan - - where [ARGS]: - - chan=[chan#][band][mode] where band is [a,b,g] and mode is - blank for active or 'p' for passive - bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan - ssid="[SSID]" specify a SSID filter for the scan - keep=[0 or 1] keep the previous scan results (1), discard (0) - dur=[scan time] time to scan for each channel in milliseconds - probes=[#] number of probe requests to send on each chan - type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) - - Any combination of the above arguments can be supplied on the command line. - If the chan token is absent, a full channel scan will be completed by - the driver. If the dur or probes tokens are absent, the driver default - setting will be used. The bssid and ssid fields, if blank, - will produce an unfiltered scan. The type field will default to 3 (Any) - and the keep field will default to 0 (Discard). - - Examples: - 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: - echo "chan=1g,6g,11g" > setuserscan - - 2) Perform a passive scan on channel 11 for 20 ms: - echo "chan=11gp dur=20" > setuserscan - - 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on - channel 36 in the 'a' band: - - echo "chan=1g,6g,11g,36ap" > setuserscan - - 4) Perform an active scan on channel 6 and 36 for a specific SSID: - echo "chan=6g,36a ssid="TestAP"" > setuserscan - - 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep - the current scan table intact, update existing or append new scan data: - echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan - - 6) Scan channel 6, for all infrastructure networks, sending two probe - requests. Keep the previous scan table intact. Update any duplicate - BSSID/SSID matches with the new scan data: - echo "chan=6g type=1 probes=2 keep=1" > setuserscan - - All entries in the scan table (not just the new scan data when keep=1) - will be displayed upon completion by use of the getscantable ioctl. - -============================================================================== diff --git a/trunk/drivers/net/wireless/libertas/assoc.c b/trunk/drivers/net/wireless/libertas/assoc.c deleted file mode 100644 index b55c7f57aca8..000000000000 --- a/trunk/drivers/net/wireless/libertas/assoc.c +++ /dev/null @@ -1,588 +0,0 @@ -/* Copyright (C) 2006, Red Hat, Inc. */ - -#include -#include - -#include "assoc.h" -#include "join.h" -#include "decl.h" -#include "hostcmd.h" -#include "host.h" - - -static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -static int assoc_helper_essid(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - int i; - - ENTER(); - - lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid); - if (assoc_req->mode == wlan802_11infrastructure) { - if (adapter->prescan) { - libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1); - } - - i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, - NULL, wlan802_11infrastructure); - if (i >= 0) { - lbs_pr_debug(1, - "SSID found in scan list ... associating...\n"); - - ret = wlan_associate(priv, &adapter->scantable[i]); - if (ret == 0) { - memcpy(&assoc_req->bssid, - &adapter->scantable[i].macaddress, - ETH_ALEN); - } - } else { - lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n", - assoc_req->ssid.ssid); - } - } else if (assoc_req->mode == wlan802_11ibss) { - /* Scan for the network, do not save previous results. Stale - * scan data will cause us to join a non-existant adhoc network - */ - libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0); - - /* Search for the requested SSID in the scan table */ - i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL, - wlan802_11ibss); - if (i >= 0) { - lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret); - libertas_join_adhoc_network(priv, &adapter->scantable[i]); - } else { - /* else send START command */ - lbs_pr_debug(1, "SSID not found in list, so creating adhoc" - " with SSID '%s'\n", assoc_req->ssid.ssid); - libertas_start_adhoc_network(priv, &assoc_req->ssid); - } - memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN); - } - - LEAVE(); - return ret; -} - - -static int assoc_helper_bssid(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int i, ret = 0; - - ENTER(); - - lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n", - MAC_ARG(assoc_req->bssid)); - - /* Search for index position in list for requested MAC */ - i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid, - assoc_req->mode); - if (i < 0) { - lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, " - "cannot associate.\n", MAC_ARG(assoc_req->bssid)); - goto out; - } - - if (assoc_req->mode == wlan802_11infrastructure) { - ret = wlan_associate(priv, &adapter->scantable[i]); - lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret); - } else if (assoc_req->mode == wlan802_11ibss) { - libertas_join_adhoc_network(priv, &adapter->scantable[i]); - } - memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid, - sizeof(struct WLAN_802_11_SSID)); - -out: - LEAVE(); - return ret; -} - - -static int assoc_helper_associate(wlan_private *priv, - struct assoc_request * assoc_req) -{ - int ret = 0, done = 0; - - /* If we're given and 'any' BSSID, try associating based on SSID */ - - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN) - && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) { - ret = assoc_helper_bssid(priv, assoc_req); - done = 1; - if (ret) { - lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); - } - } - } - - if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - ret = assoc_helper_essid(priv, assoc_req); - if (ret) { - lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); - } - } - - return ret; -} - - -static int assoc_helper_mode(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - if (assoc_req->mode == adapter->inframode) { - LEAVE(); - return 0; - } - - if (assoc_req->mode == wlan802_11infrastructure) { - if (adapter->psstate != PS_STATE_FULL_POWER) - libertas_ps_wakeup(priv, cmd_option_waitforrsp); - adapter->psmode = wlan802_11powermodecam; - } - - adapter->inframode = assoc_req->mode; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - 0, cmd_option_waitforrsp, - OID_802_11_INFRASTRUCTURE_MODE, - (void *) assoc_req->mode); - - LEAVE(); - return ret; -} - - -static int assoc_helper_wep_keys(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int i; - int ret = 0; - - ENTER(); - - /* Set or remove WEP keys */ - if ( assoc_req->wep_keys[0].len - || assoc_req->wep_keys[1].len - || assoc_req->wep_keys[2].len - || assoc_req->wep_keys[3].len) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_add, - cmd_option_waitforrsp, - 0, assoc_req); - } else { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_remove, - cmd_option_waitforrsp, - 0, NULL); - } - - if (ret) - goto out; - - /* enable/disable the MAC's WEP packet filter */ - if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled) - adapter->currentpacketfilter |= cmd_act_mac_wep_enable; - else - adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; - ret = libertas_set_mac_packet_filter(priv); - if (ret) - goto out; - - mutex_lock(&adapter->lock); - - /* Copy WEP keys into adapter wep key fields */ - for (i = 0; i < 4; i++) { - memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); - } - adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; - - mutex_unlock(&adapter->lock); - -out: - LEAVE(); - return ret; -} - -static int assoc_helper_secinfo(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - memcpy(&adapter->secinfo, &assoc_req->secinfo, - sizeof(struct wlan_802_11_security)); - - ret = libertas_set_mac_packet_filter(priv); - - LEAVE(); - return ret; -} - - -static int assoc_helper_wpa_keys(wlan_private *priv, - struct assoc_request * assoc_req) -{ - int ret = 0; - - ENTER(); - - /* enable/Disable RSN */ - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_enable_rsn, - cmd_act_set, - cmd_option_waitforrsp, - 0, assoc_req); - if (ret) - goto out; - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_key_material, - cmd_act_set, - cmd_option_waitforrsp, - 0, assoc_req); - -out: - LEAVE(); - return ret; -} - - -static int assoc_helper_wpa_ie(wlan_private *priv, - struct assoc_request * assoc_req) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); - adapter->wpa_ie_len = assoc_req->wpa_ie_len; - } else { - memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN); - adapter->wpa_ie_len = 0; - } - - LEAVE(); - return ret; -} - - -static int should_deauth_infrastructure(wlan_adapter *adapter, - struct assoc_request * assoc_req) -{ - if (adapter->connect_status != libertas_connected) - return 0; - - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - lbs_pr_debug(1, "Deauthenticating due to new SSID in " - " configuration request.\n"); - return 1; - } - - if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { - if (adapter->secinfo.authmode != - assoc_req->secinfo.authmode) { - lbs_pr_debug(1, "Deauthenticating due to updated security " - "info in configuration request.\n"); - return 1; - } - } - - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - lbs_pr_debug(1, "Deauthenticating due to new BSSID in " - " configuration request.\n"); - return 1; - } - - /* FIXME: deal with 'auto' mode somehow */ - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { - if (assoc_req->mode != wlan802_11infrastructure) - return 1; - } - - return 0; -} - - -static int should_stop_adhoc(wlan_adapter *adapter, - struct assoc_request * assoc_req) -{ - if (adapter->connect_status != libertas_connected) - return 0; - - if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength) - return 1; - if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid, - sizeof(struct WLAN_802_11_SSID))) - return 1; - - /* FIXME: deal with 'auto' mode somehow */ - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { - if (assoc_req->mode != wlan802_11ibss) - return 1; - } - - return 0; -} - - -void wlan_association_worker(struct work_struct *work) -{ - wlan_private *priv = container_of(work, wlan_private, assoc_work.work); - wlan_adapter *adapter = priv->adapter; - struct assoc_request * assoc_req = NULL; - int ret = 0; - int find_any_ssid = 0; - - ENTER(); - - mutex_lock(&adapter->lock); - assoc_req = adapter->assoc_req; - adapter->assoc_req = NULL; - mutex_unlock(&adapter->lock); - - if (!assoc_req) { - LEAVE(); - return; - } - - lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n", - assoc_req->flags); - - /* If 'any' SSID was specified, find an SSID to associate with */ - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) - && !assoc_req->ssid.ssidlength) - find_any_ssid = 1; - - /* But don't use 'any' SSID if there's a valid locked BSSID to use */ - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN) - && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN)) - find_any_ssid = 0; - } - - if (find_any_ssid) { - enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; - - ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid, - assoc_req->mode, &new_mode); - if (ret) { - lbs_pr_debug(1, "Could not find best network\n"); - ret = -ENETUNREACH; - goto out; - } - - /* Ensure we switch to the mode of the AP */ - if (assoc_req->mode == wlan802_11autounknown) { - set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); - assoc_req->mode = new_mode; - } - } - - /* - * Check if the attributes being changing require deauthentication - * from the currently associated infrastructure access point. - */ - if (adapter->inframode == wlan802_11infrastructure) { - if (should_deauth_infrastructure(adapter, assoc_req)) { - ret = libertas_send_deauthentication(priv); - if (ret) { - lbs_pr_debug(1, "Deauthentication due to new " - "configuration request failed: %d\n", - ret); - } - } - } else if (adapter->inframode == wlan802_11ibss) { - if (should_stop_adhoc(adapter, assoc_req)) { - ret = libertas_stop_adhoc_network(priv); - if (ret) { - lbs_pr_debug(1, "Teardown of AdHoc network due to " - "new configuration request failed: %d\n", - ret); - } - - } - } - - /* Send the various configuration bits to the firmware */ - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { - ret = assoc_helper_mode(priv, assoc_req); - if (ret) { -lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); - goto out; - } - } - - if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) - || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { - ret = assoc_helper_wep_keys(priv, assoc_req); - if (ret) { -lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); - goto out; - } - } - - if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { - ret = assoc_helper_secinfo(priv, assoc_req); - if (ret) { -lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); - goto out; - } - } - - if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { - ret = assoc_helper_wpa_ie(priv, assoc_req); - if (ret) { -lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); - goto out; - } - } - - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) - || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { - ret = assoc_helper_wpa_keys(priv, assoc_req); - if (ret) { -lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); - goto out; - } - } - - /* SSID/BSSID should be the _last_ config option set, because they - * trigger the association attempt. - */ - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) - || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - int success = 1; - - ret = assoc_helper_associate(priv, assoc_req); - if (ret) { - lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n", - ret); - success = 0; - } - - if (adapter->connect_status != libertas_connected) { - lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, " - "not connected.\n"); - success = 0; - } - - if (success) { - lbs_pr_debug(1, "ASSOC: association attempt successful. " - "Associated to '%s' (" MAC_FMT ")\n", - assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid)); - libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, cmd_option_waitforrsp, 0, NULL); - - libertas_prepare_and_send_command(priv, - cmd_802_11_get_log, - 0, cmd_option_waitforrsp, 0, NULL); - } else { - - ret = -1; - } - } - -out: - if (ret) { - lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n", - ret); - } - kfree(assoc_req); - LEAVE(); -} - - -/* - * Caller MUST hold any necessary locks - */ -struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) -{ - struct assoc_request * assoc_req; - - if (!adapter->assoc_req) { - adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL); - if (!adapter->assoc_req) { - lbs_pr_info("Not enough memory to allocate association" - " request!\n"); - return NULL; - } - } - - /* Copy current configuration attributes to the association request, - * but don't overwrite any that are already set. - */ - assoc_req = adapter->assoc_req; - if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid, - adapter->curbssparams.ssid.ssidlength); - } - - if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) - assoc_req->channel = adapter->curbssparams.channel; - - if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) - assoc_req->mode = adapter->inframode; - - if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - memcpy(&assoc_req->bssid, adapter->curbssparams.bssid, - ETH_ALEN); - } - - if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { - int i; - for (i = 0; i < 4; i++) { - memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); - } - } - - if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) - assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx; - - if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, - sizeof(struct WLAN_802_11_KEY)); - } - - if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, - sizeof(struct WLAN_802_11_KEY)); - } - - if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { - memcpy(&assoc_req->secinfo, &adapter->secinfo, - sizeof(struct wlan_802_11_security)); - } - - if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie, - MAX_WPA_IE_LEN); - assoc_req->wpa_ie_len = adapter->wpa_ie_len; - } - - return assoc_req; -} - - diff --git a/trunk/drivers/net/wireless/libertas/assoc.h b/trunk/drivers/net/wireless/libertas/assoc.h deleted file mode 100644 index 2ffd82d99b34..000000000000 --- a/trunk/drivers/net/wireless/libertas/assoc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2006, Red Hat, Inc. */ - -#ifndef _WLAN_ASSOC_H_ -#define _WLAN_ASSOC_H_ - -#include "dev.h" - -void wlan_association_worker(struct work_struct *work); - -struct assoc_request * wlan_get_association_request(wlan_adapter *adapter); - -#define ASSOC_DELAY (HZ / 2) -static inline void wlan_postpone_association_work(wlan_private *priv) -{ - if (priv->adapter->surpriseremoved) - return; - cancel_delayed_work(&priv->assoc_work); - queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); -} - -static inline void wlan_cancel_association_work(wlan_private *priv) -{ - cancel_delayed_work(&priv->assoc_work); - if (priv->adapter->assoc_req) { - kfree(priv->adapter->assoc_req); - priv->adapter->assoc_req = NULL; - } -} - -#endif /* _WLAN_ASSOC_H */ diff --git a/trunk/drivers/net/wireless/libertas/cmd.c b/trunk/drivers/net/wireless/libertas/cmd.c deleted file mode 100644 index bfdac58b5c06..000000000000 --- a/trunk/drivers/net/wireless/libertas/cmd.c +++ /dev/null @@ -1,1958 +0,0 @@ -/** - * This file contains the handling of command. - * It prepares command and sends it to firmware when it is ready. - */ - -#include -#include "host.h" -#include "hostcmd.h" -#include "sbi.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "wext.h" - -static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); - -static u16 commands_allowed_in_ps[] = { - cmd_802_11_rssi, -}; - -/** - * @brief This function checks if the commans is allowed - * in PS mode not. - * - * @param command the command ID - * @return TRUE or FALSE - */ -static u8 is_command_allowed_in_ps(u16 command) -{ - int count = sizeof(commands_allowed_in_ps) - / sizeof(commands_allowed_in_ps[0]); - int i; - - for (i = 0; i < count; i++) { - if (command == cpu_to_le16(commands_allowed_in_ps[i])) - return 1; - } - - return 0; -} - -static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) -{ - struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_get_hw_spec); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); - memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_ps_mode(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; - u16 action = cmd_action; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_802_11_ps_mode); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + - S_DS_GEN); - psm->action = cpu_to_le16(cmd_action); - psm->multipledtim = 0; - switch (action) { - case cmd_subcmd_enter_ps: - lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n"); - lbs_pr_debug(1, "locallisteninterval = %d\n", - adapter->locallisteninterval); - - psm->locallisteninterval = - cpu_to_le16(adapter->locallisteninterval); - psm->nullpktinterval = - cpu_to_le16(adapter->nullpktinterval); - psm->multipledtim = - cpu_to_le16(priv->adapter->multipledtim); - break; - - case cmd_subcmd_exit_ps: - lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n"); - break; - - case cmd_subcmd_sleep_confirmed: - lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n"); - break; - - default: - break; - } - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - u16 *timeout = pdata_buf; - - cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) - + S_DS_GEN); - - cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action); - - if (cmd_action) - cmd->params.inactivity_timeout.timeout = - cpu_to_le16(*timeout); - else - cmd->params.inactivity_timeout.timeout = 0; - - return 0; -} - -static int wlan_cmd_802_11_sleep_params(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params; - - ENTER(); - - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + - S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_sleep_params); - - if (cmd_action == cmd_act_get) { - memset(&adapter->sp, 0, sizeof(struct sleep_params)); - memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); - sp->action = cpu_to_le16(cmd_action); - } else if (cmd_action == cmd_act_set) { - sp->action = cpu_to_le16(cmd_action); - sp->error = cpu_to_le16(adapter->sp.sp_error); - sp->offset = cpu_to_le16(adapter->sp.sp_offset); - sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime); - sp->calcontrol = (u8) adapter->sp.sp_calcontrol; - sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk; - sp->reserved = cpu_to_le16(adapter->sp.sp_reserved); - } - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_set_wep(wlan_private * priv, - struct cmd_ds_command *cmd, - u32 cmd_act, - void * pdata_buf) -{ - struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - struct assoc_request * assoc_req = pdata_buf; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_802_11_set_wep); - cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep)) - + S_DS_GEN); - - if (cmd_act == cmd_act_add) { - int i; - - if (!assoc_req) { - lbs_pr_debug(1, "Invalid association request!"); - ret = -1; - goto done; - } - - wep->action = cpu_to_le16(cmd_act_add); - - /* default tx key index */ - wep->keyindex = cpu_to_le16((u16) - (assoc_req->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); - - lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex); - - /* Copy key types and material to host command structure */ - for (i = 0; i < 4; i++) { - struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i]; - - switch (pkey->len) { - case KEY_LEN_WEP_40: - wep->keytype[i] = cmd_type_wep_40_bit; - memmove(&wep->keymaterial[i], pkey->key, - pkey->len); - break; - case KEY_LEN_WEP_104: - wep->keytype[i] = cmd_type_wep_104_bit; - memmove(&wep->keymaterial[i], pkey->key, - pkey->len); - break; - case 0: - break; - default: - lbs_pr_debug(1, "Invalid WEP key %d length of %d\n", - i, pkey->len); - ret = -1; - goto done; - break; - } - } - } else if (cmd_act == cmd_act_remove) { - /* ACT_REMOVE clears _all_ WEP keys */ - wep->action = cpu_to_le16(cmd_act_remove); - - /* default tx key index */ - wep->keyindex = cpu_to_le16((u16) - (adapter->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); - } - - ret = 0; - -done: - LEAVE(); - return ret; -} - -static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn; - wlan_adapter *adapter = priv->adapter; - - cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) + - S_DS_GEN); - penableRSN->action = cpu_to_le16(cmd_action); - if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { - penableRSN->enable = cpu_to_le16(cmd_enable_rsn); - } else { - penableRSN->enable = cpu_to_le16(cmd_disable_rsn); - } - - return 0; -} - - -static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, - struct WLAN_802_11_KEY * pkey) -{ - pkeyparamset->keytypeid = cpu_to_le16(pkey->type); - - if (pkey->flags & KEY_INFO_WPA_ENABLED) { - pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED); - } else { - pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED); - } - - if (pkey->flags & KEY_INFO_WPA_UNICAST) { - pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); - } else if (pkey->flags & KEY_INFO_WPA_MCAST) { - pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); - } - - pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); - pkeyparamset->keylen = cpu_to_le16(pkey->len); - memcpy(pkeyparamset->key, pkey->key, pkey->len); - pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) - + sizeof(pkeyparamset->keyinfo) - + sizeof(pkeyparamset->keylen) - + sizeof(pkeyparamset->key)); -} - -static int wlan_cmd_802_11_key_material(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, - u32 cmd_oid, void *pdata_buf) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_key_material *pkeymaterial = - &cmd->params.keymaterial; - int ret = 0; - int index = 0; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_802_11_key_material); - pkeymaterial->action = cpu_to_le16(cmd_action); - - if (cmd_action == cmd_act_get) { - cmd->size = cpu_to_le16( S_DS_GEN - + sizeof (pkeymaterial->action)); - ret = 0; - goto done; - } - - memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); - - if (adapter->wpa_unicast_key.len) { - set_one_wpa_key(&pkeymaterial->keyParamSet[index], - &adapter->wpa_unicast_key); - index++; - } - - if (adapter->wpa_mcast_key.len) { - set_one_wpa_key(&pkeymaterial->keyParamSet[index], - &adapter->wpa_mcast_key); - index++; - } - - cmd->size = cpu_to_le16( S_DS_GEN - + sizeof (pkeymaterial->action) - + index * sizeof(struct MrvlIEtype_keyParamSet)); - - ret = 0; - -done: - LEAVE(); - return ret; -} - -static int wlan_cmd_802_11_reset(wlan_private * priv, - struct cmd_ds_command *cmd, int cmd_action) -{ - struct cmd_ds_802_11_reset *reset = &cmd->params.reset; - - cmd->command = cpu_to_le16(cmd_802_11_reset); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); - reset->action = cpu_to_le16(cmd_action); - - return 0; -} - -static int wlan_cmd_802_11_get_log(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(cmd_802_11_get_log); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); - - return 0; -} - -static int wlan_cmd_802_11_get_stat(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(cmd_802_11_get_stat); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + - S_DS_GEN); - - return 0; -} - -static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, - struct cmd_ds_command *cmd, - int cmd_action, - int cmd_oid, void *pdata_buf) -{ - struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; - wlan_adapter *adapter = priv->adapter; - u8 ucTemp; - - ENTER(); - - lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); - - cmd->command = cpu_to_le16(cmd_802_11_snmp_mib); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) + - S_DS_GEN); - - switch (cmd_oid) { - case OID_802_11_INFRASTRUCTURE_MODE: - { - enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode = - (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf; - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); - pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i); - pSNMPMIB->bufsize = sizeof(u8); - if (mode == wlan802_11infrastructure) - ucTemp = SNMP_MIB_VALUE_INFRA; - else - ucTemp = SNMP_MIB_VALUE_ADHOC; - - memmove(pSNMPMIB->value, &ucTemp, sizeof(u8)); - - break; - } - - case OID_802_11D_ENABLE: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i); - - if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cmd_act_set; - pSNMPMIB->bufsize = sizeof(u16); - ulTemp = *(u32 *)pdata_buf; - *((unsigned short *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); - } - break; - } - - case OID_802_11_FRAGMENTATION_THRESHOLD: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i); - - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_set); - pSNMPMIB->bufsize = - cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *) pdata_buf); - *((unsigned short *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); - - } - - break; - } - - case OID_802_11_RTS_THRESHOLD: - { - - u32 ulTemp; - pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i); - - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_set); - pSNMPMIB->bufsize = - cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *) - pdata_buf); - *(unsigned short *)(pSNMPMIB->value) = - cpu_to_le16((u16) ulTemp); - - } - break; - } - case OID_802_11_TX_RETRYCOUNT: - pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i); - - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = - cpu_to_le16(cmd_act_set); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - *((unsigned short *)(pSNMPMIB->value)) = - cpu_to_le16((u16) adapter->txretrycount); - } - - break; - default: - break; - } - - lbs_pr_debug(1, - "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n", - cmd->command, cmd->size, cmd->seqnum, cmd->result); - - lbs_pr_debug(1, - "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n", - pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize, - *(u16 *) pSNMPMIB->value); - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_radio_control(wlan_private * priv, - struct cmd_ds_command *cmd, - int cmd_action) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_radio_control *pradiocontrol = - &cmd->params.radio; - - ENTER(); - - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + - S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_radio_control); - - pradiocontrol->action = cpu_to_le16(cmd_action); - - switch (adapter->preamble) { - case cmd_type_short_preamble: - pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case cmd_type_long_preamble: - pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); - break; - - case cmd_type_auto_preamble: - default: - pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; - } - - if (adapter->radioon) - pradiocontrol->control |= cpu_to_le16(TURN_ON_RF); - else - pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF); - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - - struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; - - ENTER(); - - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + - S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power); - prtp->action = cmd_action; - - lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size, - cmd->command, prtp->action); - - switch (cmd_action) { - case cmd_act_tx_power_opt_get: - prtp->action = cpu_to_le16(cmd_act_get); - prtp->currentlevel = 0; - break; - - case cmd_act_tx_power_opt_set_high: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = - cpu_to_le16(cmd_act_tx_power_index_high); - break; - - case cmd_act_tx_power_opt_set_mid: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = - cpu_to_le16(cmd_act_tx_power_index_mid); - break; - - case cmd_act_tx_power_opt_set_low: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); - break; - } - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; - - cmd->command = cpu_to_le16(cmd_802_11_rf_antenna); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + - S_DS_GEN); - - rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == cmd_act_set_rx) || - (cmd_action == cmd_act_set_tx)) { - rant->antennamode = - cpu_to_le16((u16) (*(u32 *) pdata_buf)); - } - - return 0; -} - -static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_802_11_rate_adapt_rateset - *rateadapt = &cmd->params.rateset; - wlan_adapter *adapter = priv->adapter; - - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) - + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset); - - ENTER(); - - rateadapt->action = cmd_action; - rateadapt->enablehwauto = adapter->enablehwauto; - rateadapt->bitmap = adapter->ratebitmap; - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_data_rate(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate; - wlan_adapter *adapter = priv->adapter; - u16 action = cmd_action; - - ENTER(); - - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + - S_DS_GEN); - - cmd->command = cpu_to_le16(cmd_802_11_data_rate); - - memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); - - pdatarate->action = cpu_to_le16(cmd_action); - - if (action == cmd_act_set_tx_fix_rate) { - pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); - lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n", - adapter->datarate); - } else if (action == cmd_act_set_tx_auto) { - lbs_pr_debug(1, "Setting FW for AUTO rate\n"); - } - - LEAVE(); - return 0; -} - -static int wlan_cmd_mac_multicast_adr(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; - wlan_adapter *adapter = priv->adapter; - - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + - S_DS_GEN); - cmd->command = cpu_to_le16(cmd_mac_multicast_adr); - - pMCastAdr->action = cpu_to_le16(cmd_action); - pMCastAdr->nr_of_adrs = - cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); - memcpy(pMCastAdr->maclist, adapter->multicastlist, - adapter->nr_of_multicastmacaddr * ETH_ALEN); - - return 0; -} - -static int wlan_cmd_802_11_rf_channel(wlan_private * priv, - struct cmd_ds_command *cmd, - int option, void *pdata_buf) -{ - struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; - - cmd->command = cpu_to_le16(cmd_802_11_rf_channel); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) - + S_DS_GEN); - - if (option == cmd_opt_802_11_rf_channel_set) { - rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); - } - - rfchan->action = cpu_to_le16(option); - - return 0; -} - -static int wlan_cmd_802_11_rssi(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - wlan_adapter *adapter = priv->adapter; - - cmd->command = cpu_to_le16(cmd_802_11_rssi); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); - cmd->params.rssi.N = priv->adapter->bcn_avg_factor; - - /* reset Beacon SNR/NF/RSSI values */ - adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0; - adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->NF[TYPE_BEACON][TYPE_AVG] = 0; - adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; - - return 0; -} - -static int wlan_cmd_reg_access(wlan_private * priv, - struct cmd_ds_command *cmdptr, - u8 cmd_action, void *pdata_buf) -{ - struct wlan_offset_value *offval; - - ENTER(); - - offval = (struct wlan_offset_value *)pdata_buf; - - switch (cmdptr->command) { - case cmd_mac_reg_access: - { - struct cmd_ds_mac_reg_access *macreg; - - cmdptr->size = - cpu_to_le16(sizeof - (struct cmd_ds_mac_reg_access) - + S_DS_GEN); - macreg = - (struct cmd_ds_mac_reg_access *)&cmdptr->params. - macreg; - - macreg->action = cpu_to_le16(cmd_action); - macreg->offset = cpu_to_le16((u16) offval->offset); - macreg->value = cpu_to_le32(offval->value); - - break; - } - - case cmd_bbp_reg_access: - { - struct cmd_ds_bbp_reg_access *bbpreg; - - cmdptr->size = - cpu_to_le16(sizeof - (struct cmd_ds_bbp_reg_access) - + S_DS_GEN); - bbpreg = - (struct cmd_ds_bbp_reg_access *)&cmdptr->params. - bbpreg; - - bbpreg->action = cpu_to_le16(cmd_action); - bbpreg->offset = cpu_to_le16((u16) offval->offset); - bbpreg->value = (u8) offval->value; - - break; - } - - case cmd_rf_reg_access: - { - struct cmd_ds_rf_reg_access *rfreg; - - cmdptr->size = - cpu_to_le16(sizeof - (struct cmd_ds_rf_reg_access) + - S_DS_GEN); - rfreg = - (struct cmd_ds_rf_reg_access *)&cmdptr->params. - rfreg; - - rfreg->action = cpu_to_le16(cmd_action); - rfreg->offset = cpu_to_le16((u16) offval->offset); - rfreg->value = (u8) offval->value; - - break; - } - - default: - break; - } - - LEAVE(); - return 0; -} - -static int wlan_cmd_802_11_mac_address(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - wlan_adapter *adapter = priv->adapter; - - cmd->command = cpu_to_le16(cmd_802_11_mac_address); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + - S_DS_GEN); - cmd->result = 0; - - cmd->params.macadd.action = cpu_to_le16(cmd_action); - - if (cmd_action == cmd_act_set) { - memcpy(cmd->params.macadd.macadd, - adapter->current_addr, ETH_ALEN); - lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); - } - - return 0; -} - -static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, - struct cmd_ds_command *cmd, - int cmd_action, void *pdata_buf) -{ - struct wlan_ioctl_regrdwr *ea = pdata_buf; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_802_11_eeprom_access); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + - S_DS_GEN); - cmd->result = 0; - - cmd->params.rdeeprom.action = cpu_to_le16(ea->action); - cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset); - cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); - cmd->params.rdeeprom.value = 0; - - return 0; -} - -static int wlan_cmd_bt_access(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_bt_access *bt_access = &cmd->params.bt; - lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action); - - cmd->command = cpu_to_le16(cmd_bt_access); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) - + S_DS_GEN); - cmd->result = 0; - bt_access->action = cpu_to_le16(cmd_action); - - switch (cmd_action) { - case cmd_act_bt_access_add: - memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); - lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); - break; - case cmd_act_bt_access_del: - memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); - lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); - break; - case cmd_act_bt_access_list: - bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); - break; - case cmd_act_bt_access_reset: - break; - default: - break; - } - return 0; -} - -static int wlan_cmd_fwt_access(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; - lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); - - cmd->command = cpu_to_le16(cmd_fwt_access); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) - + S_DS_GEN); - cmd->result = 0; - - if (pdata_buf) - memcpy(fwt_access, pdata_buf, sizeof(*fwt_access)); - else - memset(fwt_access, 0, sizeof(*fwt_access)); - - fwt_access->action = cpu_to_le16(cmd_action); - - return 0; -} - -static int wlan_cmd_mesh_access(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; - lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); - - cmd->command = cpu_to_le16(cmd_mesh_access); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) - + S_DS_GEN); - cmd->result = 0; - - if (pdata_buf) - memcpy(mesh_access, pdata_buf, sizeof(*mesh_access)); - else - memset(mesh_access, 0, sizeof(*mesh_access)); - - mesh_access->action = cpu_to_le16(cmd_action); - - return 0; -} - -void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) -{ - unsigned long flags; - struct cmd_ds_command *cmdptr; - - ENTER(); - - if (!cmdnode) { - lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n"); - goto done; - } - - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - if (!cmdptr) { - lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n"); - goto done; - } - - /* Exit_PS command needs to be queued in the header always. */ - if (cmdptr->command == cmd_802_11_ps_mode) { - struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; - if (psm->action == cmd_subcmd_exit_ps) { - if (adapter->psstate != PS_STATE_FULL_POWER) - addtail = 0; - } - } - - spin_lock_irqsave(&adapter->driver_lock, flags); - - if (addtail) - list_add_tail((struct list_head *)cmdnode, - &adapter->cmdpendingq); - else - list_add((struct list_head *)cmdnode, &adapter->cmdpendingq); - - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n", - (u32) cmdnode, - ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command); - -done: - LEAVE(); - return; -} - -/* - * TODO: Fix the issue when DownloadcommandToStation is being called the - * second time when the command timesout. All the cmdptr->xxx are in little - * endian and therefore all the comparissions will fail. - * For now - we are not performing the endian conversion the second time - but - * for PS and DEEP_SLEEP we need to worry - */ -static int DownloadcommandToStation(wlan_private * priv, - struct cmd_ctrl_node *cmdnode) -{ - unsigned long flags; - struct cmd_ds_command *cmdptr; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - u16 cmdsize; - u16 command; - - ENTER(); - - if (!adapter || !cmdnode) { - lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n", - (int)adapter, (int)cmdnode); - if (cmdnode) { - spin_lock_irqsave(&adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, cmdnode); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - } - ret = -1; - goto done; - } - - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - - - spin_lock_irqsave(&adapter->driver_lock, flags); - if (!cmdptr || !cmdptr->size) { - lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, " - "Not sending\n"); - __libertas_cleanup_and_insert_cmd(priv, cmdnode); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; - goto done; - } - - adapter->cur_cmd = cmdnode; - adapter->cur_cmd_retcode = 0; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n", - cmdptr->size); - - cmdsize = cmdptr->size; - - command = cpu_to_le16(cmdptr->command); - - cmdnode->cmdwaitqwoken = 0; - cmdsize = cpu_to_le16(cmdsize); - - ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); - - if (ret != 0) { - lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n"); - spin_lock_irqsave(&adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; - goto done; - } - - lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies); - lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); - - /* Setup the timer after transmit command */ - if (command == cmd_802_11_scan - || command == cmd_802_11_authenticate - || command == cmd_802_11_associate) - mod_timer(&adapter->command_timer, jiffies + (10*HZ)); - else - mod_timer(&adapter->command_timer, jiffies + (5*HZ)); - - ret = 0; - - done: - LEAVE(); - return ret; -} - -static int wlan_cmd_mac_control(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - struct cmd_ds_mac_control *mac = &cmd->params.macctrl; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_mac_control); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); - mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); - - lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n", - mac->action, cmd->size); - - LEAVE(); - return 0; -} - -/** - * This function inserts command node to cmdfreeq - * after cleans it. Requires adapter->driver_lock held. - */ -void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) -{ - wlan_adapter *adapter = priv->adapter; - - if (!ptempcmd) - goto done; - - cleanup_cmdnode(ptempcmd); - list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); -done: - return; -} - -void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, ptempcmd); - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); -} - -int libertas_set_radio_control(wlan_private * priv) -{ - int ret = 0; - - ENTER(); - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - - lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", - priv->adapter->radioon, priv->adapter->preamble); - - LEAVE(); - return ret; -} - -int libertas_set_mac_packet_filter(wlan_private * priv) -{ - int ret = 0; - - ENTER(); - - lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n", - priv->adapter->currentpacketfilter); - - /* Send MAC control command to station */ - ret = libertas_prepare_and_send_command(priv, - cmd_mac_control, 0, 0, 0, NULL); - - LEAVE(); - return ret; -} - -/** - * @brief This function prepare the command before send to firmware. - * - * @param priv A pointer to wlan_private structure - * @param cmd_no command number - * @param cmd_action command action: GET or SET - * @param wait_option wait option: wait response or not - * @param cmd_oid cmd oid: treated as sub command - * @param pdata_buf A pointer to informaion buffer - * @return 0 or -1 - */ -int libertas_prepare_and_send_command(wlan_private * priv, - u16 cmd_no, - u16 cmd_action, - u16 wait_option, u32 cmd_oid, void *pdata_buf) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmdnode; - struct cmd_ds_command *cmdptr; - unsigned long flags; - - ENTER(); - - if (!adapter) { - lbs_pr_debug(1, "PREP_CMD: adapter is Null\n"); - ret = -1; - goto done; - } - - if (adapter->surpriseremoved) { - lbs_pr_debug(1, "PREP_CMD: Card is Removed\n"); - ret = -1; - goto done; - } - - cmdnode = libertas_get_free_cmd_ctrl_node(priv); - - if (cmdnode == NULL) { - lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n"); - - /* Wake up main thread to execute next command */ - wake_up_interruptible(&priv->mainthread.waitq); - ret = -1; - goto done; - } - - libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf); - - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - - lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n", - (u32) cmdptr, cmd_no); - - if (!cmdptr) { - lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n"); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - ret = -1; - goto done; - } - - /* Set sequence number, command and INT option */ - adapter->seqnum++; - cmdptr->seqnum = cpu_to_le16(adapter->seqnum); - - cmdptr->command = cmd_no; - cmdptr->result = 0; - - switch (cmd_no) { - case cmd_get_hw_spec: - ret = wlan_cmd_hw_spec(priv, cmdptr); - break; - case cmd_802_11_ps_mode: - ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_scan: - ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); - break; - - case cmd_mac_control: - ret = wlan_cmd_mac_control(priv, cmdptr); - break; - - case cmd_802_11_associate: - case cmd_802_11_reassociate: - ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); - break; - - case cmd_802_11_deauthenticate: - ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); - break; - - case cmd_802_11_set_wep: - ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); - break; - - case cmd_802_11_ad_hoc_start: - ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); - break; - case cmd_code_dnld: - break; - - case cmd_802_11_reset: - ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_get_log: - ret = wlan_cmd_802_11_get_log(priv, cmdptr); - break; - - case cmd_802_11_authenticate: - ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); - break; - - case cmd_802_11_get_stat: - ret = wlan_cmd_802_11_get_stat(priv, cmdptr); - break; - - case cmd_802_11_snmp_mib: - ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, - cmd_action, cmd_oid, pdata_buf); - break; - - case cmd_mac_reg_access: - case cmd_bbp_reg_access: - case cmd_rf_reg_access: - ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case cmd_802_11_rf_channel: - ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, - cmd_action, pdata_buf); - break; - - case cmd_802_11_rf_tx_power: - ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, - cmd_action, pdata_buf); - break; - - case cmd_802_11_radio_control: - ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_rf_antenna: - ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, - cmd_action, pdata_buf); - break; - - case cmd_802_11_data_rate: - ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); - break; - case cmd_802_11_rate_adapt_rateset: - ret = wlan_cmd_802_11_rate_adapt_rateset(priv, - cmdptr, cmd_action); - break; - - case cmd_mac_multicast_adr: - ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_ad_hoc_join: - ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); - break; - - case cmd_802_11_rssi: - ret = wlan_cmd_802_11_rssi(priv, cmdptr); - break; - - case cmd_802_11_ad_hoc_stop: - ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); - break; - - case cmd_802_11_enable_rsn: - ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_key_material: - ret = wlan_cmd_802_11_key_material(priv, cmdptr, - cmd_action, cmd_oid, - pdata_buf); - break; - - case cmd_802_11_pairwise_tsc: - break; - case cmd_802_11_group_tsc: - break; - - case cmd_802_11_mac_address: - ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); - break; - - case cmd_802_11_eeprom_access: - ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, - cmd_action, pdata_buf); - break; - - case cmd_802_11_set_afc: - case cmd_802_11_get_afc: - - cmdptr->command = cpu_to_le16(cmd_no); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + - S_DS_GEN); - - memmove(&cmdptr->params.afc, - pdata_buf, sizeof(struct cmd_ds_802_11_afc)); - - ret = 0; - goto done; - - case cmd_802_11d_domain_info: - ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, - cmd_no, cmd_action); - break; - - case cmd_802_11_sleep_params: - ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); - break; - case cmd_802_11_inactivity_timeout: - ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, - cmd_action, pdata_buf); - libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); - break; - - case cmd_802_11_tpc_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + - S_DS_GEN); - - memmove(&cmdptr->params.tpccfg, - pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); - - ret = 0; - break; - case cmd_802_11_led_gpio_ctrl: - { - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio*) - cmdptr->params.ledgpio.data; - - memmove(&cmdptr->params.ledgpio, - pdata_buf, - sizeof(struct cmd_ds_802_11_led_ctrl)); - - cmdptr->command = - cpu_to_le16(cmd_802_11_led_gpio_ctrl); - -#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 - cmdptr->size = - cpu_to_le16(gpio->header.len + S_DS_GEN + - ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); - gpio->header.len = cpu_to_le16(gpio->header.len); - - ret = 0; - break; - } - case cmd_802_11_pwr_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + - S_DS_GEN); - memmove(&cmdptr->params.pwrcfg, pdata_buf, - sizeof(struct cmd_ds_802_11_pwr_cfg)); - - ret = 0; - break; - case cmd_bt_access: - ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case cmd_fwt_access: - ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case cmd_mesh_access: - ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case cmd_get_tsf: - cmdptr->command = cpu_to_le16(cmd_get_tsf); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_get_tsf) - + S_DS_GEN); - ret = 0; - break; - case cmd_802_11_tx_rate_query: - cmdptr->command = - cpu_to_le16(cmd_802_11_tx_rate_query); - cmdptr->size = - cpu_to_le16(sizeof(struct cmd_tx_rate_query) + - S_DS_GEN); - adapter->txrate = 0; - ret = 0; - break; - default: - lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no); - ret = -1; - break; - } - - /* return error, since the command preparation failed */ - if (ret != 0) { - lbs_pr_debug(1, "PREP_CMD: command preparation failed\n"); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - ret = -1; - goto done; - } - - cmdnode->cmdwaitqwoken = 0; - - libertas_queue_cmd(adapter, cmdnode, 1); - adapter->nr_cmd_pending++; - wake_up_interruptible(&priv->mainthread.waitq); - - if (wait_option & cmd_option_waitforrsp) { - lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n"); - might_sleep(); - wait_event_interruptible(cmdnode->cmdwait_q, - cmdnode->cmdwaitqwoken); - } - - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd_retcode) { - lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n", - adapter->cur_cmd_retcode); - adapter->cur_cmd_retcode = 0; - ret = -1; - } - spin_unlock_irqrestore(&adapter->driver_lock, flags); - -done: - LEAVE(); - return ret; -} - -/** - * @brief This function allocates the command buffer and link - * it to command free queue. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -int libertas_allocate_cmd_buffer(wlan_private * priv) -{ - int ret = 0; - u32 ulbufsize; - u32 i; - struct cmd_ctrl_node *tempcmd_array; - u8 *ptempvirtualaddr; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* Allocate and initialize cmdCtrlNode */ - ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; - - if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) { - lbs_pr_debug(1, - "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n"); - ret = -1; - goto done; - } - - adapter->cmd_array = tempcmd_array; - memset(adapter->cmd_array, 0, ulbufsize); - - /* Allocate and initialize command buffers */ - ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) { - lbs_pr_debug(1, - "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n"); - ret = -1; - goto done; - } - - memset(ptempvirtualaddr, 0, ulbufsize); - - /* Update command buffer virtual */ - tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr; - } - - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - init_waitqueue_head(&tempcmd_array[i].cmdwait_q); - libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]); - } - - ret = 0; - done: - LEAVE(); - return ret; -} - -/** - * @brief This function frees the command buffer. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -int libertas_free_cmd_buffer(wlan_private * priv) -{ - u32 ulbufsize; - unsigned int i; - struct cmd_ctrl_node *tempcmd_array; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* need to check if cmd array is allocated or not */ - if (adapter->cmd_array == NULL) { - lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n"); - goto done; - } - - tempcmd_array = adapter->cmd_array; - - /* Release shared memory buffers */ - ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - if (tempcmd_array[i].bufvirtualaddr) { - lbs_pr_debug(1, "Free all the array\n"); - kfree(tempcmd_array[i].bufvirtualaddr); - tempcmd_array[i].bufvirtualaddr = NULL; - } - } - - /* Release cmd_ctrl_node */ - if (adapter->cmd_array) { - lbs_pr_debug(1, "Free cmd_array\n"); - kfree(adapter->cmd_array); - adapter->cmd_array = NULL; - } - -done: - LEAVE(); - return 0; -} - -/** - * @brief This function gets a free command node if available in - * command free queue. - * - * @param priv A pointer to wlan_private structure - * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL - */ -struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) -{ - struct cmd_ctrl_node *tempnode; - wlan_adapter *adapter = priv->adapter; - unsigned long flags; - - if (!adapter) - return NULL; - - spin_lock_irqsave(&adapter->driver_lock, flags); - - if (!list_empty(&adapter->cmdfreeq)) { - tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; - list_del((struct list_head *)tempnode); - } else { - lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n"); - tempnode = NULL; - } - - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - if (tempnode) { - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n"); - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n", - tempnode); - cleanup_cmdnode(tempnode); - } - - return tempnode; -} - -/** - * @brief This function cleans command node. - * - * @param ptempnode A pointer to cmdCtrlNode structure - * @return n/a - */ -static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) -{ - if (!ptempnode) - return; - ptempnode->cmdwaitqwoken = 1; - wake_up_interruptible(&ptempnode->cmdwait_q); - ptempnode->status = 0; - ptempnode->cmd_oid = (u32) 0; - ptempnode->wait_option = 0; - ptempnode->pdata_buf = NULL; - - if (ptempnode->bufvirtualaddr != NULL) - memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); - return; -} - -/** - * @brief This function initializes the command node. - * - * @param priv A pointer to wlan_private structure - * @param ptempnode A pointer to cmd_ctrl_node structure - * @param cmd_oid cmd oid: treated as sub command - * @param wait_option wait option: wait response or not - * @param pdata_buf A pointer to informaion buffer - * @return 0 or -1 - */ -void libertas_set_cmd_ctrl_node(wlan_private * priv, - struct cmd_ctrl_node *ptempnode, - u32 cmd_oid, u16 wait_option, void *pdata_buf) -{ - ENTER(); - - if (!ptempnode) - return; - - ptempnode->cmd_oid = cmd_oid; - ptempnode->wait_option = wait_option; - ptempnode->pdata_buf = pdata_buf; - - LEAVE(); -} - -/** - * @brief This function executes next command in command - * pending queue. It will put fimware back to PS mode - * if applicable. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -int libertas_execute_next_command(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmdnode = NULL; - struct cmd_ds_command *cmdptr; - unsigned long flags; - int ret = 0; - - lbs_pr_debug(1, "libertas_execute_next_command\n"); - - spin_lock_irqsave(&adapter->driver_lock, flags); - - if (adapter->cur_cmd) { - lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n"); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; - goto done; - } - - if (!list_empty(&adapter->cmdpendingq)) { - cmdnode = (struct cmd_ctrl_node *) - adapter->cmdpendingq.next; - } - - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - if (cmdnode) { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: Got next command from cmdpendingq\n"); - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - - if (is_command_allowed_in_ps(cmdptr->command)) { - if ((adapter->psstate == PS_STATE_SLEEP) - || (adapter->psstate == PS_STATE_PRE_SLEEP) - ) { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n", - cmdptr->command, adapter->psstate); - ret = -1; - goto done; - } - lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command " - "0x%x in psstate %d\n", - cmdptr->command, adapter->psstate); - } else if (adapter->psstate != PS_STATE_FULL_POWER) { - /* - * 1. Non-PS command: - * Queue it. set needtowakeup to TRUE if current state - * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. - * 2. PS command but not Exit_PS: - * Ignore it. - * 3. PS command Exit_PS: - * Set needtowakeup to TRUE if current state is SLEEP, - * otherwise send this command down to firmware - * immediately. - */ - if (cmdptr->command != - cpu_to_le16(cmd_802_11_ps_mode)) { - /* Prepare to send Exit PS, - * this non PS command will be sent later */ - if ((adapter->psstate == PS_STATE_SLEEP) - || (adapter->psstate == PS_STATE_PRE_SLEEP) - ) { - /* w/ new scheme, it will not reach here. - since it is blocked in main_thread. */ - adapter->needtowakeup = 1; - } else - libertas_ps_wakeup(priv, 0); - - ret = 0; - goto done; - } else { - /* - * PS command. Ignore it if it is not Exit_PS. - * otherwise send it down immediately. - */ - struct cmd_ds_802_11_ps_mode *psm = - &cmdptr->params.psmode; - - lbs_pr_debug(1, - "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", - psm->action); - if (psm->action != - cpu_to_le16(cmd_subcmd_exit_ps)) { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); - list_del((struct list_head *)cmdnode); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - - ret = 0; - goto done; - } - - if ((adapter->psstate == PS_STATE_SLEEP) - || (adapter->psstate == PS_STATE_PRE_SLEEP) - ) { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); - list_del((struct list_head *)cmdnode); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - adapter->needtowakeup = 1; - - ret = 0; - goto done; - } - - lbs_pr_debug(1, - "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); - } - } - list_del((struct list_head *)cmdnode); - lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n", - cmdptr->command); - DownloadcommandToStation(priv, cmdnode); - } else { - /* - * check if in power save mode, if yes, put the device back - * to PS mode - */ - if ((adapter->psmode != wlan802_11powermodecam) && - (adapter->psstate == PS_STATE_FULL_POWER) && - (adapter->connect_status == libertas_connected)) { - if (adapter->secinfo.WPAenabled - || adapter->secinfo.WPA2enabled) { - /* check for valid WPA group keys */ - if (adapter->wpa_mcast_key.len - || adapter->wpa_unicast_key.len) { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: WPA enabled and GTK_SET" - " go back to PS_SLEEP"); - libertas_ps_sleep(priv, 0); - } - } else { - lbs_pr_debug(1, - "EXEC_NEXT_CMD: command PendQ is empty," - " go back to PS_SLEEP"); - libertas_ps_sleep(priv, 0); - } - } - } - - ret = 0; -done: - return ret; -} - -void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) -{ - union iwreq_data iwrq; - u8 buf[50]; - - ENTER(); - - memset(&iwrq, 0, sizeof(union iwreq_data)); - memset(buf, 0, sizeof(buf)); - - snprintf(buf, sizeof(buf) - 1, "%s", str); - - iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; - - /* Send Event to upper layer */ - lbs_pr_debug(1, "Event Indication string = %s\n", - (char *)buf); - lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length); - - lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str); - wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf); - - LEAVE(); - return; -} - -static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) -{ - unsigned long flags; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", - size); - - lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size); - - ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size); - priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; - - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->intcounter || adapter->currenttxskb) - lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n", - adapter->intcounter, adapter->currenttxskb); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - if (ret) { - lbs_pr_alert( - "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); - } else { - spin_lock_irqsave(&adapter->driver_lock, flags); - if (!adapter->intcounter) { - adapter->psstate = PS_STATE_SLEEP; - } else { - lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n", - adapter->intcounter); - } - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); - lbs_pr_debug(1, "+"); - } - - LEAVE(); - return ret; -} - -void libertas_ps_sleep(wlan_private * priv, int wait_option) -{ - - ENTER(); - - /* - * PS is currently supported only in Infrastructure mode - * Remove this check if it is to be supported in IBSS mode also - */ - - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_enter_ps, wait_option, 0, NULL); - - LEAVE(); - return; -} - -/** - * @brief This function sends Eixt_PS command to firmware. - * - * @param priv A pointer to wlan_private structure - * @param wait_option wait response or not - * @return n/a - */ -void libertas_ps_wakeup(wlan_private * priv, int wait_option) -{ - enum WLAN_802_11_POWER_MODE Localpsmode; - - ENTER(); - - Localpsmode = wlan802_11powermodecam; - - lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode); - - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_exit_ps, - wait_option, 0, &Localpsmode); - - LEAVE(); - return; -} - -/** - * @brief This function checks condition and prepares to - * send sleep confirm command to firmware if ok. - * - * @param priv A pointer to wlan_private structure - * @param psmode Power Saving mode - * @return n/a - */ -void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) -{ - unsigned long flags =0; - wlan_adapter *adapter = priv->adapter; - u8 allowed = 1; - - ENTER(); - - if (priv->wlan_dev.dnld_sent) { - allowed = 0; - lbs_pr_debug(1, "D"); - } - - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd) { - allowed = 0; - lbs_pr_debug(1, "C"); - } - if (adapter->intcounter > 0) { - allowed = 0; - lbs_pr_debug(1, "I%d", adapter->intcounter); - } - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - if (allowed) { - lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n"); - sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, - sizeof(struct PS_CMD_ConfirmSleep)); - } else { - lbs_pr_debug(1, "Sleep Confirm has been delayed\n"); - } - - LEAVE(); -} diff --git a/trunk/drivers/net/wireless/libertas/cmdresp.c b/trunk/drivers/net/wireless/libertas/cmdresp.c deleted file mode 100644 index cdb012c7e9cf..000000000000 --- a/trunk/drivers/net/wireless/libertas/cmdresp.c +++ /dev/null @@ -1,1031 +0,0 @@ -/** - * This file contains the handling of command - * responses as well as events generated by firmware. - */ -#include -#include -#include - -#include - -#include "host.h" -#include "sbi.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "wext.h" - -/** - * @brief This function handles disconnect event. it - * reports disconnect to upper layer, clean tx/rx packets, - * reset link state etc. - * - * @param priv A pointer to wlan_private structure - * @return n/a - */ -void libertas_mac_event_disconnected(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - union iwreq_data wrqu; - - if (adapter->connect_status != libertas_connected) - return; - - lbs_pr_debug(1, "Handles disconnect event.\n"); - - memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* - * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. - * It causes problem in the Supplicant - */ - - msleep_interruptible(1000); - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); - - /* Free Tx and Rx packets */ - kfree_skb(priv->adapter->currenttxskb); - priv->adapter->currenttxskb = NULL; - - /* report disconnect to upper layer */ - netif_stop_queue(priv->wlan_dev.netdev); - netif_carrier_off(priv->wlan_dev.netdev); - - /* reset SNR/NF/RSSI values */ - memset(adapter->SNR, 0x00, sizeof(adapter->SNR)); - memset(adapter->NF, 0x00, sizeof(adapter->NF)); - memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI)); - memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); - memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); - adapter->nextSNRNF = 0; - adapter->numSNRNF = 0; - adapter->rxpd_rate = 0; - lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n", - adapter->curbssparams.ssid.ssid, - adapter->curbssparams.ssid.ssidlength); - lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n", - adapter->previousssid.ssid, adapter->previousssid.ssidlength); - - /* reset internal flags */ - adapter->secinfo.WPAenabled = 0; - adapter->secinfo.WPA2enabled = 0; - adapter->wpa_ie_len = 0; - adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; - adapter->secinfo.Encryptionmode = CIPHER_NONE; - - adapter->connect_status = libertas_disconnected; - - /* - * memorize the previous SSID and BSSID - * it could be used for re-assoc - */ - memcpy(&adapter->previousssid, - &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID)); - memcpy(adapter->previousbssid, - adapter->curbssparams.bssid, ETH_ALEN); - - /* need to erase the current SSID and BSSID info */ - adapter->pattemptedbssdesc = NULL; - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); - - if (adapter->psstate != PS_STATE_FULL_POWER) { - /* make firmware to exit PS mode */ - lbs_pr_debug(1, "Disconnected, so exit PS mode.\n"); - libertas_ps_wakeup(priv, 0); - } -} - -/** - * @brief This function handles MIC failure event. - * - * @param priv A pointer to wlan_private structure - * @para event the event id - * @return n/a - */ -static void handle_mic_failureevent(wlan_private * priv, u32 event) -{ - char buf[50]; - - memset(buf, 0, sizeof(buf)); - - sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); - - if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { - strcat(buf, "unicast "); - } else { - strcat(buf, "multicast "); - } - - libertas_send_iwevcustom_event(priv, buf); -} - -static int wlan_ret_reg_access(wlan_private * priv, - u16 type, struct cmd_ds_command *resp) -{ - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - switch (type) { - case cmd_ret_mac_reg_access: - { - struct cmd_ds_mac_reg_access *reg; - - reg = - (struct cmd_ds_mac_reg_access *)&resp->params. - macreg; - - adapter->offsetvalue.offset = reg->offset; - adapter->offsetvalue.value = reg->value; - break; - } - - case cmd_ret_bbp_reg_access: - { - struct cmd_ds_bbp_reg_access *reg; - reg = - (struct cmd_ds_bbp_reg_access *)&resp->params. - bbpreg; - - adapter->offsetvalue.offset = reg->offset; - adapter->offsetvalue.value = reg->value; - break; - } - - case cmd_ret_rf_reg_access: - { - struct cmd_ds_rf_reg_access *reg; - reg = - (struct cmd_ds_rf_reg_access *)&resp->params. - rfreg; - - adapter->offsetvalue.offset = reg->offset; - adapter->offsetvalue.value = reg->value; - break; - } - - default: - LEAVE(); - return -1; - } - - LEAVE(); - return 0; -} - -static int wlan_ret_get_hw_spec(wlan_private * priv, - struct cmd_ds_command *resp) -{ - u32 i; - struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo); - - adapter->fwreleasenumber = hwspec->fwreleasenumber; - - lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n", - adapter->fwreleasenumber); - lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", - hwspec->permanentaddr[0], hwspec->permanentaddr[1], - hwspec->permanentaddr[2], hwspec->permanentaddr[3], - hwspec->permanentaddr[4], hwspec->permanentaddr[5]); - lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n", - hwspec->hwifversion, hwspec->version); - - adapter->regioncode = le16_to_cpu(hwspec->regioncode); - - for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { - /* use the region code to search for the index */ - if (adapter->regioncode == libertas_region_code_to_index[i]) { - adapter->regiontableindex = (u16) i; - break; - } - } - - /* if it's unidentified region code, use the default (USA) */ - if (i >= MRVDRV_MAX_REGION_CODE) { - adapter->regioncode = 0x10; - adapter->regiontableindex = 0; - lbs_pr_info( - "unidentified region code, use the default (USA)\n"); - } - - if (adapter->current_addr[0] == 0xff) { - memmove(adapter->current_addr, hwspec->permanentaddr, - ETH_ALEN); - } - - memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN); - memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); - - if (libertas_set_regiontable(priv, adapter->regioncode, 0)) { - ret = -1; - goto done; - } - - if (libertas_set_universaltable(priv, 0)) { - ret = -1; - goto done; - } - - done: - LEAVE(); - return ret; -} - -static int wlan_ret_802_11_sleep_params(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n" - " extsleepclk=%x\n", sp->error, sp->offset, - sp->stabletime, sp->calcontrol, sp->externalsleepclk); - adapter->sp.sp_error = le16_to_cpu(sp->error); - adapter->sp.sp_offset = le16_to_cpu(sp->offset); - adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime); - adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol); - adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk); - adapter->sp.sp_reserved = le16_to_cpu(sp->reserved); - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_stat(wlan_private * priv, - struct cmd_ds_command *resp) -{ -/* currently adapter->wlan802_11Stat is unused - - struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; - wlan_adapter *adapter = priv->adapter; - - // TODO Convert it to Big endian befor copy - memcpy(&adapter->wlan802_11Stat, - p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); -*/ - return 0; -} - -static int wlan_ret_802_11_snmp_mib(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; - u16 oid = le16_to_cpu(smib->oid); - u16 querytype = le16_to_cpu(smib->querytype); - - ENTER(); - - lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid, - querytype); - lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n", - le16_to_cpu(smib->bufsize)); - - if (querytype == cmd_act_get) { - switch (oid) { - case fragthresh_i: - priv->adapter->fragthsd = - le16_to_cpu(* - ((unsigned short *)(smib->value))); - lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n", - priv->adapter->fragthsd); - break; - case rtsthresh_i: - priv->adapter->rtsthsd = - le16_to_cpu(* - ((unsigned short *)(smib->value))); - lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n", - priv->adapter->rtsthsd); - break; - case short_retrylim_i: - priv->adapter->txretrycount = - le16_to_cpu(* - ((unsigned short *)(smib->value))); - lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n", - priv->adapter->rtsthsd); - break; - default: - break; - } - } - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_key_material(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_key_material *pkeymaterial = - &resp->params.keymaterial; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(pkeymaterial->action); - - ENTER(); - - /* Copy the returned key to driver private data */ - if (action == cmd_act_get) { - u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; - u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); - - while (buf_ptr < resp_end) { - struct MrvlIEtype_keyParamSet * pkeyparamset = - (struct MrvlIEtype_keyParamSet *) buf_ptr; - struct WLAN_802_11_KEY * pkey; - u16 key_info = le16_to_cpu(pkeyparamset->keyinfo); - u16 param_set_len = le16_to_cpu(pkeyparamset->length); - u8 * end; - u16 key_len = le16_to_cpu(pkeyparamset->keylen); - - end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) - + sizeof (pkeyparamset->length) - + param_set_len; - /* Make sure we don't access past the end of the IEs */ - if (end > resp_end) - break; - - if (key_info & KEY_INFO_WPA_UNICAST) - pkey = &adapter->wpa_unicast_key; - else if (key_info & KEY_INFO_WPA_MCAST) - pkey = &adapter->wpa_mcast_key; - else - break; - - /* Copy returned key into driver */ - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); - if (key_len > sizeof(pkey->key)) - break; - pkey->type = le16_to_cpu(pkeyparamset->keytypeid); - pkey->flags = le16_to_cpu(pkeyparamset->keyinfo); - pkey->len = le16_to_cpu(pkeyparamset->keylen); - memcpy(pkey->key, pkeyparamset->key, pkey->len); - - buf_ptr = end + 1; - } - } - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_mac_address(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN); - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); - - lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel); - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(pAntenna->action); - - if (action == cmd_act_get_rx) - adapter->rxantennamode = - le16_to_cpu(pAntenna->antennamode); - - if (action == cmd_act_get_tx) - adapter->txantennamode = - le16_to_cpu(pAntenna->antennamode); - - lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", - action, le16_to_cpu(pAntenna->antennamode)); - - return 0; -} - -static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rate_adapt_rateset *rates = - &resp->params.rateset; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (rates->action == cmd_act_get) { - adapter->enablehwauto = rates->enablehwauto; - adapter->ratebitmap = rates->bitmap; - } - - LEAVE(); - - return 0; -} - -static int wlan_ret_802_11_data_rate(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; - wlan_adapter *adapter = priv->adapter; - u8 dot11datarate; - - ENTER(); - - lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", - (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); - - dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cmd_act_get_tx_rate) { - memcpy(adapter->libertas_supported_rates, pdatarate->datarate, - sizeof(adapter->libertas_supported_rates)); - } - adapter->datarate = libertas_index_to_data_rate(dot11datarate); - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_rf_channel(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_channel *rfchannel = - &resp->params.rfchannel; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(rfchannel->action); - u16 newchannel = le16_to_cpu(rfchannel->currentchannel); - - ENTER(); - - if (action == cmd_opt_802_11_rf_channel_get - && adapter->curbssparams.channel != newchannel) { - lbs_pr_debug(1, "channel Switch: %d to %d\n", - adapter->curbssparams.channel, newchannel); - - /* Update the channel again */ - adapter->curbssparams.channel = newchannel; - } - - LEAVE(); - return 0; -} - -static int wlan_ret_802_11_rssi(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; - wlan_adapter *adapter = priv->adapter; - - /* store the non average value */ - adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); - adapter->NF[TYPE_BEACON][TYPE_NOAVG] = - le16_to_cpu(rssirsp->noisefloor); - - adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); - adapter->NF[TYPE_BEACON][TYPE_AVG] = - le16_to_cpu(rssirsp->avgnoisefloor); - - adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], - adapter->NF[TYPE_BEACON][TYPE_NOAVG]); - - adapter->RSSI[TYPE_BEACON][TYPE_AVG] = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); - - lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n", - adapter->RSSI[TYPE_BEACON][TYPE_AVG]); - - return 0; -} - -static int wlan_ret_802_11_eeprom_access(wlan_private * priv, - struct cmd_ds_command *resp) -{ - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_regrdwr *pbuf; - pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; - - lbs_pr_debug(1, "eeprom read len=%x\n", - le16_to_cpu(resp->params.rdeeprom.bytecount)); - if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { - pbuf->NOB = 0; - lbs_pr_debug(1, "eeprom read return length is too big\n"); - return -1; - } - pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); - if (pbuf->NOB > 0) { - - memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, - le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_dbg_hex("adapter", (char *)&pbuf->value, - le16_to_cpu(resp->params.rdeeprom.bytecount)); - } - return 0; -} - -static int wlan_ret_get_log(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_get_log *logmessage = - (struct cmd_ds_802_11_get_log *)&resp->params.glog; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* TODO Convert it to Big Endian before copy */ - memcpy(&adapter->logmsg, logmessage, - sizeof(struct cmd_ds_802_11_get_log)); - - LEAVE(); - return 0; -} - -static inline int handle_cmd_response(u16 respcmd, - struct cmd_ds_command *resp, - wlan_private *priv) -{ - int ret = 0; - unsigned long flags; - wlan_adapter *adapter = priv->adapter; - - switch (respcmd) { - case cmd_ret_mac_reg_access: - case cmd_ret_bbp_reg_access: - case cmd_ret_rf_reg_access: - ret = wlan_ret_reg_access(priv, respcmd, resp); - break; - - case cmd_ret_hw_spec_info: - ret = wlan_ret_get_hw_spec(priv, resp); - break; - - case cmd_ret_802_11_scan: - ret = libertas_ret_80211_scan(priv, resp); - break; - - case cmd_ret_802_11_get_log: - ret = wlan_ret_get_log(priv, resp); - break; - - case cmd_ret_802_11_associate: - case cmd_ret_802_11_reassociate: - ret = libertas_ret_80211_associate(priv, resp); - break; - - case cmd_ret_802_11_disassociate: - case cmd_ret_802_11_deauthenticate: - ret = libertas_ret_80211_disassociate(priv, resp); - break; - - case cmd_ret_802_11_ad_hoc_start: - case cmd_ret_802_11_ad_hoc_join: - ret = libertas_ret_80211_ad_hoc_start(priv, resp); - break; - - case cmd_ret_802_11_stat: - ret = wlan_ret_802_11_stat(priv, resp); - break; - - case cmd_ret_802_11_snmp_mib: - ret = wlan_ret_802_11_snmp_mib(priv, resp); - break; - - case cmd_ret_802_11_rf_tx_power: - ret = wlan_ret_802_11_rf_tx_power(priv, resp); - break; - - case cmd_ret_802_11_set_afc: - case cmd_ret_802_11_get_afc: - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, - &resp->params.afc, - sizeof(struct cmd_ds_802_11_afc)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - break; - case cmd_ret_802_11_rf_antenna: - ret = wlan_ret_802_11_rf_antenna(priv, resp); - break; - - case cmd_ret_mac_multicast_adr: - case cmd_ret_mac_control: - case cmd_ret_802_11_set_wep: - case cmd_ret_802_11_reset: - case cmd_ret_802_11_authenticate: - case cmd_ret_802_11_radio_control: - case cmd_ret_802_11_beacon_stop: - case cmd_ret_802_11_enable_rsn: - break; - - case cmd_ret_802_11_data_rate: - ret = wlan_ret_802_11_data_rate(priv, resp); - break; - case cmd_ret_802_11_rate_adapt_rateset: - ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); - break; - case cmd_ret_802_11_rf_channel: - ret = wlan_ret_802_11_rf_channel(priv, resp); - break; - - case cmd_ret_802_11_rssi: - ret = wlan_ret_802_11_rssi(priv, resp); - break; - - case cmd_ret_802_11_mac_address: - ret = wlan_ret_802_11_mac_address(priv, resp); - break; - - case cmd_ret_802_11_ad_hoc_stop: - ret = libertas_ret_80211_ad_hoc_stop(priv, resp); - break; - - case cmd_ret_802_11_key_material: - lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n"); - ret = wlan_ret_802_11_key_material(priv, resp); - break; - - case cmd_ret_802_11_eeprom_access: - ret = wlan_ret_802_11_eeprom_access(priv, resp); - break; - - case cmd_ret_802_11d_domain_info: - ret = libertas_ret_802_11d_domain_info(priv, resp); - break; - - case cmd_ret_802_11_sleep_params: - ret = wlan_ret_802_11_sleep_params(priv, resp); - break; - case cmd_ret_802_11_inactivity_timeout: - spin_lock_irqsave(&adapter->driver_lock, flags); - *((u16 *) adapter->cur_cmd->pdata_buf) = - le16_to_cpu(resp->params.inactivity_timeout.timeout); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - - case cmd_ret_802_11_tpc_cfg: - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, - &resp->params.tpccfg, - sizeof(struct cmd_ds_802_11_tpc_cfg)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - case cmd_ret_802_11_led_gpio_ctrl: - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, - &resp->params.ledgpio, - sizeof(struct cmd_ds_802_11_led_ctrl)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - case cmd_ret_802_11_pwr_cfg: - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, - &resp->params.pwrcfg, - sizeof(struct cmd_ds_802_11_pwr_cfg)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - break; - - case cmd_ret_get_tsf: - spin_lock_irqsave(&adapter->driver_lock, flags); - memcpy(priv->adapter->cur_cmd->pdata_buf, - &resp->params.gettsf.tsfvalue, sizeof(u64)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - case cmd_ret_bt_access: - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, - &resp->params.bt.addr1, 2 * ETH_ALEN); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - case cmd_ret_fwt_access: - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, - &resp->params.fwt, - sizeof(resp->params.fwt)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - break; - case cmd_ret_mesh_access: - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, - &resp->params.mesh, - sizeof(resp->params.mesh)); - break; - case cmd_rte_802_11_tx_rate_query: - priv->adapter->txrate = resp->params.txrate.txrate; - break; - default: - lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n", - resp->command); - break; - } - return ret; -} - -int libertas_process_rx_command(wlan_private * priv) -{ - u16 respcmd; - struct cmd_ds_command *resp; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - ulong flags; - u16 result; - - ENTER(); - - lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies); - - /* Now we got response from FW, cancel the command timer */ - del_timer(&adapter->command_timer); - - mutex_lock(&adapter->lock); - spin_lock_irqsave(&adapter->driver_lock, flags); - - if (!adapter->cur_cmd) { - lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd); - ret = -1; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - goto done; - } - resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); - - lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr, - priv->wlan_dev.upld_len); - - respcmd = le16_to_cpu(resp->command); - - result = le16_to_cpu(resp->result); - - lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd, - result, priv->wlan_dev.upld_len); - - if (!(respcmd & 0x8000)) { - lbs_pr_debug(1, "Invalid response to command!"); - adapter->cur_cmd_retcode = -1; - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; - goto done; - } - - /* Store the response code to cur_cmd_retcode. */ - adapter->cur_cmd_retcode = le16_to_cpu(resp->result); - - if (respcmd == cmd_ret_802_11_ps_mode) { - struct cmd_ds_802_11_ps_mode *psmode; - - psmode = &resp->params.psmode; - lbs_pr_debug(1, - "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", - resp->result, psmode->action); - psmode->action = cpu_to_le16(psmode->action); - - if (result) { - lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n", - resp->result); - if (adapter->inframode == wlan802_11ibss) { - /* - * We should not re-try enter-ps command in - * ad-hoc mode. It takes place in - * libertas_execute_next_command(). - */ - if (psmode->action == cmd_subcmd_enter_ps) - adapter->psmode = - wlan802_11powermodecam; - } - } else if (psmode->action == cmd_subcmd_enter_ps) { - adapter->needtowakeup = 0; - adapter->psstate = PS_STATE_AWAKE; - - lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n"); - if (adapter->connect_status != libertas_connected) { - /* - * When Deauth Event received before Enter_PS command - * response, We need to wake up the firmware. - */ - lbs_pr_debug(1, - "Disconnected, Going to invoke libertas_ps_wakeup\n"); - - mutex_unlock(&adapter->lock); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - libertas_ps_wakeup(priv, 0); - mutex_lock(&adapter->lock); - spin_lock_irqsave(&adapter->driver_lock, flags); - } - } else if (psmode->action == cmd_subcmd_exit_ps) { - adapter->needtowakeup = 0; - adapter->psstate = PS_STATE_FULL_POWER; - lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n"); - } else { - lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n", - psmode->action); - } - - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - ret = 0; - goto done; - } - - if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { - /* Copy the response back to response buffer */ - memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size); - - adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; - } - - /* If the command is not successful, cleanup and return failure */ - if ((result != 0 || !(respcmd & 0x8000))) { - lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n", - resp->command, resp->result); - /* - * Handling errors here - */ - switch (respcmd) { - case cmd_ret_hw_spec_info: - case cmd_ret_802_11_reset: - lbs_pr_debug(1, "CMD_RESP: Reset command failed\n"); - break; - - } - - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - ret = -1; - goto done; - } - - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - ret = handle_cmd_response(respcmd, resp, priv); - - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd) { - /* Clean up and Put current command back to cmdfreeq */ - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - WARN_ON(adapter->nr_cmd_pending > 128); - adapter->cur_cmd = NULL; - } - spin_unlock_irqrestore(&adapter->driver_lock, flags); - -done: - mutex_unlock(&adapter->lock); - LEAVE(); - return ret; -} - -int libertas_process_event(wlan_private * priv) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - u32 eventcause; - - spin_lock_irq(&adapter->driver_lock); - eventcause = adapter->eventcause; - spin_unlock_irq(&adapter->driver_lock); - - ENTER(); - - lbs_pr_debug(1, "EVENT Cause %x\n", eventcause); - - switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { - case MACREG_INT_CODE_LINK_SENSED: - lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n"); - break; - - case MACREG_INT_CODE_DEAUTHENTICATED: - lbs_pr_debug(1, "EVENT: Deauthenticated\n"); - libertas_mac_event_disconnected(priv); - break; - - case MACREG_INT_CODE_DISASSOCIATED: - lbs_pr_debug(1, "EVENT: Disassociated\n"); - libertas_mac_event_disconnected(priv); - break; - - case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: - lbs_pr_debug(1, "EVENT: Link lost\n"); - libertas_mac_event_disconnected(priv); - break; - - case MACREG_INT_CODE_PS_SLEEP: - lbs_pr_debug(1, "EVENT: SLEEP\n"); - lbs_pr_debug(1, "_"); - - /* handle unexpected PS SLEEP event */ - if (adapter->psstate == PS_STATE_FULL_POWER) { - lbs_pr_debug(1, - "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); - break; - } - adapter->psstate = PS_STATE_PRE_SLEEP; - - libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); - - break; - - case MACREG_INT_CODE_PS_AWAKE: - lbs_pr_debug(1, "EVENT: AWAKE \n"); - lbs_pr_debug(1, "|"); - - /* handle unexpected PS AWAKE event */ - if (adapter->psstate == PS_STATE_FULL_POWER) { - lbs_pr_debug(1, - "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); - break; - } - - adapter->psstate = PS_STATE_AWAKE; - - if (adapter->needtowakeup) { - /* - * wait for the command processing to finish - * before resuming sending - * adapter->needtowakeup will be set to FALSE - * in libertas_ps_wakeup() - */ - lbs_pr_debug(1, "Waking up...\n"); - libertas_ps_wakeup(priv, 0); - } - break; - - case MACREG_INT_CODE_MIC_ERR_UNICAST: - lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n"); - handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); - break; - - case MACREG_INT_CODE_MIC_ERR_MULTICAST: - lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n"); - handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); - break; - case MACREG_INT_CODE_MIB_CHANGED: - case MACREG_INT_CODE_INIT_DONE: - break; - - case MACREG_INT_CODE_ADHOC_BCN_LOST: - lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n"); - break; - - case MACREG_INT_CODE_RSSI_LOW: - lbs_pr_alert( "EVENT: RSSI_LOW\n"); - break; - case MACREG_INT_CODE_SNR_LOW: - lbs_pr_alert( "EVENT: SNR_LOW\n"); - break; - case MACREG_INT_CODE_MAX_FAIL: - lbs_pr_alert( "EVENT: MAX_FAIL\n"); - break; - case MACREG_INT_CODE_RSSI_HIGH: - lbs_pr_alert( "EVENT: RSSI_HIGH\n"); - break; - case MACREG_INT_CODE_SNR_HIGH: - lbs_pr_alert( "EVENT: SNR_HIGH\n"); - break; - - default: - lbs_pr_alert( "EVENT: unknown event id: %#x\n", - eventcause >> SBI_EVENT_CAUSE_SHIFT); - break; - } - - spin_lock_irq(&adapter->driver_lock); - adapter->eventcause = 0; - spin_unlock_irq(&adapter->driver_lock); - LEAVE(); - return ret; -} diff --git a/trunk/drivers/net/wireless/libertas/debugfs.c b/trunk/drivers/net/wireless/libertas/debugfs.c deleted file mode 100644 index 51dfd202f558..000000000000 --- a/trunk/drivers/net/wireless/libertas/debugfs.c +++ /dev/null @@ -1,1935 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "dev.h" -#include "decl.h" -#include "host.h" - -static struct dentry *libertas_dir = NULL; -static char *szStates[] = { - "Connected", - "Disconnected" -}; - -void libertas_debug_init(wlan_private * priv, struct net_device *dev); - -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t write_file_dummy(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static const size_t len = PAGE_SIZE; - -static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - size_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - ssize_t res; - - pos += snprintf(buf+pos, len-pos, "state = %s\n", - szStates[priv->adapter->connect_status]); - pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", - (u32) priv->adapter->regioncode); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - - free_page(addr); - return res; -} - - -static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - size_t pos = 0; - int numscansdone = 0, res; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - pos += snprintf(buf+pos, len-pos, - "---------------------------------------"); - pos += snprintf(buf+pos, len-pos, - "---------------------------------------\n"); - pos += snprintf(buf+pos, len-pos, - "# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); - pos += snprintf(buf+pos, len-pos, - "---------------------------------------"); - pos += snprintf(buf+pos, len-pos, - "---------------------------------------\n"); - - while (numscansdone < priv->adapter->numinscantable) { - struct bss_descriptor *pbssinfo; - u16 cap; - - pbssinfo = &priv->adapter->scantable[numscansdone]; - memcpy(&cap, &pbssinfo->cap, sizeof(cap)); - pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |", - numscansdone, pbssinfo->channel, pbssinfo->rssi, - pbssinfo->macaddress[0], pbssinfo->macaddress[1], - pbssinfo->macaddress[2], pbssinfo->macaddress[3], - pbssinfo->macaddress[4], pbssinfo->macaddress[5]); - pos += snprintf(buf+pos, len-pos, " %04x-", cap); - pos += snprintf(buf+pos, len-pos, "%c%c%c |", - pbssinfo->cap.ibss ? 'A' : 'I', - pbssinfo->cap.privacy ? 'P' : ' ', - pbssinfo->cap.spectrummgmt ? 'S' : ' '); - pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf); - pos += snprintf(buf+pos, len-pos, " %d |", - SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi)); - - pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid); - - numscansdone++; - } - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - - free_page(addr); - return res; -} - -static ssize_t libertas_sleepparams_write(struct file *file, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t buf_size, res; - int p1, p2, p3, p4, p5, p6; - struct sleep_params sp; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, user_buf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); - if (res != 6) { - res = -EFAULT; - goto out_unlock; - } - sp.sp_error = p1; - sp.sp_offset = p2; - sp.sp_stabletime = p3; - sp.sp_calcontrol = p4; - sp.sp_extsleepclk = p5; - sp.sp_reserved = p6; - - memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params)); - - res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - - if (!res) - res = count; - else - res = -EINVAL; - -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res; - size_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_get, - cmd_option_waitforrsp, 0, NULL); - if (res) { - res = -EFAULT; - goto out_unlock; - } - - pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error, - adapter->sp.sp_offset, adapter->sp.sp_stabletime, - adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk, - adapter->sp.sp_reserved); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - struct WLAN_802_11_SSID extscan_ssid; - union iwreq_data wrqu; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - - memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1); - extscan_ssid.ssidlength = strlen(buf)-1; - - libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1); - - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); - -out_unlock: - free_page(addr); - return count; -} - -static int libertas_parse_chan(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur) -{ - char *start, *end, *hold, *str; - int i = 0; - - start = strstr(buf, "chan="); - if (!start) - return -EINVAL; - start += 5; - end = strstr(start, " "); - if (!end) - end = buf + count; - hold = kzalloc((end - start)+1, GFP_KERNEL); - if (!hold) - return -ENOMEM; - strncpy(hold, start, end - start); - hold[(end-start)+1] = '\0'; - while(hold && (str = strsep(&hold, ","))) { - int chan; - char band, passive = 0; - sscanf(str, "%d%c%c", &chan, &band, &passive); - scan_cfg->chanlist[i].channumber = chan; - scan_cfg->chanlist[i].scantype = passive ? 1 : 0; - if (band == 'b' || band == 'g') - scan_cfg->chanlist[i].radiotype = 0; - else if (band == 'a') - scan_cfg->chanlist[i].radiotype = 1; - - scan_cfg->chanlist[i].scantime = dur; - i++; - } - - kfree(hold); - return i; -} - -static void libertas_parse_bssid(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - unsigned int mac[ETH_ALEN]; - int i; - - hold = strstr(buf, "bssid="); - if (!hold) - return; - hold += 6; - sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3, - mac+4, mac+5); - for(i=0;ispecificBSSID[i] = mac[i]; -} - -static void libertas_parse_ssid(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold, *end; - ssize_t size; - - hold = strstr(buf, "ssid="); - if (!hold) - return; - hold += 5; - end = strstr(hold, " "); - if (!end) - end = buf + count - 1; - - size = min(IW_ESSID_MAX_SIZE, end - hold); - strncpy(scan_cfg->specificSSID, hold, size); - - return; -} - -static void libertas_parse_keep(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "keep="); - if (!hold) - return; - hold += 5; - sscanf(hold, "%d", &val); - - if (val != 0) - val = 1; - - scan_cfg->keeppreviousscan = val; - return; -} - -static int libertas_parse_dur(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "dur="); - if (!hold) - return 0; - hold += 4; - sscanf(hold, "%d", &val); - - return val; -} - -static void libertas_parse_probes(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "probes="); - if (!hold) - return; - hold += 7; - sscanf(hold, "%d", &val); - - scan_cfg->numprobes = val; - - return; -} - -static void libertas_parse_type(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "type="); - if (!hold) - return; - hold += 5; - sscanf(hold, "%d", &val); - - /* type=1,2 or 3 */ - if (val < 1 || val > 3) - return; - - scan_cfg->bsstype = val; - - return; -} - -static ssize_t libertas_setuserscan(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - struct wlan_ioctl_user_scan_cfg *scan_cfg; - union iwreq_data wrqu; - int dur; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL); - if (!scan_cfg) - return -ENOMEM; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - - scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY; - - dur = libertas_parse_dur(buf, count, scan_cfg); - libertas_parse_chan(buf, count, scan_cfg, dur); - libertas_parse_bssid(buf, count, scan_cfg); - libertas_parse_ssid(buf, count, scan_cfg); - libertas_parse_keep(buf, count, scan_cfg); - libertas_parse_probes(buf, count, scan_cfg); - libertas_parse_type(buf, count, scan_cfg); - - wlan_scan_networks(priv, scan_cfg); - wait_event_interruptible(priv->adapter->cmd_pending, - !priv->adapter->nr_cmd_pending); - - memset(&wrqu, 0x00, sizeof(union iwreq_data)); - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); - -out_unlock: - free_page(addr); - kfree(scan_cfg); - return count; -} - -static int libertas_event_initcmd(wlan_private *priv, void **response_buf, - struct cmd_ctrl_node **cmdnode, - struct cmd_ds_command **cmd) -{ - u16 wait_option = cmd_option_waitforrsp; - - if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { - lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n"); - return -ENOMEM; - } - if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) { - lbs_pr_debug(1, "failed to allocate response buffer!\n"); - return -ENOMEM; - } - libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL); - init_waitqueue_head(&(*cmdnode)->cmdwait_q); - (*cmdnode)->pdata_buf = *response_buf; - (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; - (*cmdnode)->cmdwaitqwoken = 0; - *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; - (*cmd)->command = cmd_802_11_subscribe_event; - (*cmd)->seqnum = ++priv->adapter->seqnum; - (*cmd)->result = 0; - return 0; -} - -static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_rssithreshold *Lowrssi; - case TLV_TYPE_RSSI_LOW: - Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - Lowrssi->rssivalue, - Lowrssi->rssifreq, - (event->events & 0x0001)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static u16 libertas_get_events_bitmap(wlan_private *priv) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res; - u16 event_bitmap; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - return res; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - return 0; - } - - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - event_bitmap = event->events; - kfree(response_buf); - return event_bitmap; -} - -static ssize_t libertas_lowrssi_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_rssithreshold *rssi_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_rssithreshold)); - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); - rssi_threshold->header.type = cpu_to_le16(0x0104); - rssi_threshold->header.len = 2; - rssi_threshold->rssivalue = cpu_to_le16(value); - rssi_threshold->rssifreq = cpu_to_le16(freq); - event_bitmap |= subscribed ? 0x0001 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_snrthreshold *LowSnr; - case TLV_TYPE_SNR_LOW: - LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - LowSnr->snrvalue, - LowSnr->snrfreq, - (event->events & 0x0002)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static ssize_t libertas_lowsnr_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_snrthreshold *snr_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_snrthreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); - snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW); - snr_threshold->header.len = 2; - snr_threshold->snrvalue = cpu_to_le16(value); - snr_threshold->snrfreq = cpu_to_le16(freq); - event_bitmap |= subscribed ? 0x0002 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - res = count; - -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_failurecount *failcount; - case TLV_TYPE_FAILCOUNT: - failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - failcount->failvalue, - failcount->Failfreq, - (event->events & 0x0004)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_failurecount); - break; - } - } - - kfree(response_buf); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static ssize_t libertas_failcount_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_failurecount *failcount; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_failurecount)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - failcount = (struct mrvlietypes_failurecount *)(ptr); - failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); - failcount->header.len = 2; - failcount->failvalue = cpu_to_le16(value); - failcount->Failfreq = cpu_to_le16(freq); - event_bitmap |= subscribed ? 0x0004 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = (struct cmd_ds_command *)response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - free_page(addr); - kfree(response_buf); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - free_page(addr); - kfree(response_buf); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_beaconsmissed *bcnmiss; - case TLV_TYPE_BCNMISS: - bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d N/A %d\n", - bcnmiss->beaconmissed, - (event->events & 0x0008)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_beaconsmissed); - break; - } - } - - kfree(response_buf); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static ssize_t libertas_bcnmiss_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_beaconsmissed *bcnmiss; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_beaconsmissed)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr); - bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS); - bcnmiss->header.len = 2; - bcnmiss->beaconmissed = cpu_to_le16(value); - event_bitmap |= subscribed ? 0x0008 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - free_page(addr); - kfree(response_buf); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_rssithreshold *Highrssi; - case TLV_TYPE_RSSI_HIGH: - Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - Highrssi->rssivalue, - Highrssi->rssifreq, - (event->events & 0x0010)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static ssize_t libertas_highrssi_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_rssithreshold *rssi_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_rssithreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); - rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); - rssi_threshold->header.len = 2; - rssi_threshold->rssivalue = cpu_to_le16(value); - rssi_threshold->rssifreq = cpu_to_le16(freq); - event_bitmap |= subscribed ? 0x0010 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_get; - pcmdptr->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - while (cmd_len < pcmdptr->size) { - struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); - switch(header->type) { - struct mrvlietypes_snrthreshold *HighSnr; - case TLV_TYPE_SNR_HIGH: - HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - HighSnr->snrvalue, - HighSnr->snrfreq, - (event->events & 0x0020)?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static ssize_t libertas_highsnr_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_snrthreshold *snr_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cmd_act_set; - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_snrthreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); - snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH); - snr_threshold->header.len = 2; - snr_threshold->snrvalue = cpu_to_le16(value); - snr_threshold->snrfreq = cpu_to_le16(freq); - event_bitmap |= subscribed ? 0x0020 : 0x0; - event->events = event_bitmap; - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, - pcmdptr->result); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; - ssize_t pos = 0; - int ret; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - offval.offset = priv->mac_offset; - offval.value = 0; - - ret = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", - priv->mac_offset, adapter->offsetvalue.value); - - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return ret; -} - -static ssize_t libertas_rdmac_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - priv->mac_offset = simple_strtoul((char *)buf, NULL, 16); - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_wrmac_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - u32 offset, value; - struct wlan_offset_value offval; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%x %x", &offset, &value); - if (res != 2) { - res = -EFAULT; - goto out_unlock; - } - - offval.offset = offset; - offval.value = value; - res = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; - ssize_t pos = 0; - int ret; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - offval.offset = priv->bbp_offset; - offval.value = 0; - - ret = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", - priv->bbp_offset, adapter->offsetvalue.value); - - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - - return ret; -} - -static ssize_t libertas_rdbbp_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16); - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_wrbbp_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - u32 offset, value; - struct wlan_offset_value offval; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%x %x", &offset, &value); - if (res != 2) { - res = -EFAULT; - goto out_unlock; - } - - offval.offset = offset; - offval.value = value; - res = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; - ssize_t pos = 0; - int ret; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - offval.offset = priv->rf_offset; - offval.value = 0; - - ret = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", - priv->rf_offset, adapter->offsetvalue.value); - - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - - return ret; -} - -static ssize_t libertas_rdrf_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - priv->rf_offset = simple_strtoul((char *)buf, NULL, 16); - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_wrrf_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - - wlan_private *priv = file->private_data; - ssize_t res, buf_size; - u32 offset, value; - struct wlan_offset_value offval; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%x %x", &offset, &value); - if (res != 2) { - res = -EFAULT; - goto out_unlock; - } - - offval.offset = offset; - offval.value = value; - res = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); - mdelay(10); - - res = count; -out_unlock: - free_page(addr); - return res; -} - -#define FOPS(fread, fwrite) { \ - .owner = THIS_MODULE, \ - .open = open_file_generic, \ - .read = (fread), \ - .write = (fwrite), \ -} - -struct libertas_debugfs_files { - char *name; - int perm; - struct file_operations fops; -}; - -struct libertas_debugfs_files debugfs_files[] = { - { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), }, - { "getscantable", 0444, FOPS(libertas_getscantable, - write_file_dummy), }, - { "sleepparams", 0644, FOPS(libertas_sleepparams_read, - libertas_sleepparams_write), }, - { "extscan", 0600, FOPS(NULL, libertas_extscan), }, - { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), }, -}; - -struct libertas_debugfs_files debugfs_events_files[] = { - {"low_rssi", 0644, FOPS(libertas_lowrssi_read, - libertas_lowrssi_write), }, - {"low_snr", 0644, FOPS(libertas_lowsnr_read, - libertas_lowsnr_write), }, - {"failure_count", 0644, FOPS(libertas_failcount_read, - libertas_failcount_write), }, - {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read, - libertas_bcnmiss_write), }, - {"high_rssi", 0644, FOPS(libertas_highrssi_read, - libertas_highrssi_write), }, - {"high_snr", 0644, FOPS(libertas_highsnr_read, - libertas_highsnr_write), }, -}; - -struct libertas_debugfs_files debugfs_regs_files[] = { - {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), }, - {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), }, - {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), }, - {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), }, - {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), }, - {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), }, -}; - -void libertas_debugfs_init(void) -{ - if (!libertas_dir) - libertas_dir = debugfs_create_dir("libertas_wireless", NULL); - - return; -} - -void libertas_debugfs_remove(void) -{ - if (libertas_dir) - debugfs_remove(libertas_dir); - return; -} - -void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) -{ - int i; - struct libertas_debugfs_files *files; - if (!libertas_dir) - goto exit; - - priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir); - if (!priv->debugfs_dir) - goto exit; - - for (i=0; idebugfs_files[i] = debugfs_create_file(files->name, - files->perm, - priv->debugfs_dir, - priv, - &files->fops); - } - - priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); - if (!priv->events_dir) - goto exit; - - for (i=0; idebugfs_events_files[i] = debugfs_create_file(files->name, - files->perm, - priv->events_dir, - priv, - &files->fops); - } - - priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); - if (!priv->regs_dir) - goto exit; - - for (i=0; idebugfs_regs_files[i] = debugfs_create_file(files->name, - files->perm, - priv->regs_dir, - priv, - &files->fops); - } - -#ifdef PROC_DEBUG - libertas_debug_init(priv, dev); -#endif -exit: - return; -} - -void libertas_debugfs_remove_one(wlan_private *priv) -{ - int i; - - for(i=0; idebugfs_regs_files[i]); - - debugfs_remove(priv->regs_dir); - - for(i=0; idebugfs_events_files[i]); - - debugfs_remove(priv->events_dir); -#ifdef PROC_DEBUG - debugfs_remove(priv->debugfs_debug); -#endif - for(i=0; idebugfs_files[i]); -} - -/* debug entry */ - -#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n)) -#define item_addr(n) (offsetof(wlan_adapter, n)) - -struct debug_data { - char name[32]; - u32 size; - u32 addr; -}; - -/* To debug any member of wlan_adapter, simply add one line here. - */ -static struct debug_data items[] = { - {"intcounter", item_size(intcounter), item_addr(intcounter)}, - {"psmode", item_size(psmode), item_addr(psmode)}, - {"psstate", item_size(psstate), item_addr(psstate)}, -}; - -static int num_of_items = ARRAY_SIZE(items); - -/** - * @brief proc read function - * - * @param page pointer to buffer - * @param s read data starting position - * @param off offset - * @param cnt counter - * @param eof end of file flag - * @param data data to output - * @return number of output data - */ -static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - int val = 0; - size_t pos = 0; - ssize_t res; - char *p; - int i; - struct debug_data *d; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - p = buf; - - d = (struct debug_data *)file->private_data; - - for (i = 0; i < num_of_items; i++) { - if (d[i].size == 1) - val = *((u8 *) d[i].addr); - else if (d[i].size == 2) - val = *((u16 *) d[i].addr); - else if (d[i].size == 4) - val = *((u32 *) d[i].addr); - - pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); - } - - res = simple_read_from_buffer(userbuf, count, ppos, p, pos); - - free_page(addr); - return res; -} - -/** - * @brief proc write function - * - * @param f file pointer - * @param buf pointer to data buffer - * @param cnt data number to write - * @param data data to write - * @return number of data - */ -static int wlan_debugfs_write(struct file *f, const char __user *buf, - size_t cnt, loff_t *ppos) -{ - int r, i; - char *pdata; - char *p; - char *p0; - char *p1; - char *p2; - struct debug_data *d = (struct debug_data *)f->private_data; - - pdata = (char *)kmalloc(cnt, GFP_KERNEL); - if (pdata == NULL) - return 0; - - if (copy_from_user(pdata, buf, cnt)) { - lbs_pr_debug(1, "Copy from user failed\n"); - kfree(pdata); - return 0; - } - - p0 = pdata; - for (i = 0; i < num_of_items; i++) { - do { - p = strstr(p0, d[i].name); - if (p == NULL) - break; - p1 = strchr(p, '\n'); - if (p1 == NULL) - break; - p0 = p1++; - p2 = strchr(p, '='); - if (!p2) - break; - p2++; - r = simple_strtoul(p2, NULL, 0); - if (d[i].size == 1) - *((u8 *) d[i].addr) = (u8) r; - else if (d[i].size == 2) - *((u16 *) d[i].addr) = (u16) r; - else if (d[i].size == 4) - *((u32 *) d[i].addr) = (u32) r; - break; - } while (1); - } - kfree(pdata); - - return cnt; -} - -static struct file_operations libertas_debug_fops = { - .owner = THIS_MODULE, - .open = open_file_generic, - .write = wlan_debugfs_write, - .read = wlan_debugfs_read, -}; - -/** - * @brief create debug proc file - * - * @param priv pointer wlan_private - * @param dev pointer net_device - * @return N/A - */ -void libertas_debug_init(wlan_private * priv, struct net_device *dev) -{ - int i; - - if (!priv->debugfs_dir) - return; - - for (i = 0; i < num_of_items; i++) - items[i].addr += (u32) priv->adapter; - - priv->debugfs_debug = debugfs_create_file("debug", 0644, - priv->debugfs_dir, &items[0], - &libertas_debug_fops); -} - -/** - * @brief remove proc file - * - * @param priv pointer wlan_private - * @return N/A - */ -void libertas_debug_remove(wlan_private * priv) -{ - debugfs_remove(priv->debugfs_debug); -} diff --git a/trunk/drivers/net/wireless/libertas/debugfs.h b/trunk/drivers/net/wireless/libertas/debugfs.h deleted file mode 100644 index 880a11b95d26..000000000000 --- a/trunk/drivers/net/wireless/libertas/debugfs.h +++ /dev/null @@ -1,6 +0,0 @@ -void libertas_debugfs_init(void); -void libertas_debugfs_remove(void); - -void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev); -void libertas_debugfs_remove_one(wlan_private *priv); - diff --git a/trunk/drivers/net/wireless/libertas/decl.h b/trunk/drivers/net/wireless/libertas/decl.h deleted file mode 100644 index 606bdd002be7..000000000000 --- a/trunk/drivers/net/wireless/libertas/decl.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This file contains declaration referring to - * functions defined in other source files - */ - -#ifndef _WLAN_DECL_H_ -#define _WLAN_DECL_H_ - -#include "defs.h" - -/** Function Prototype Declaration */ -struct wlan_private; -struct sk_buff; -struct net_device; - -extern char *libertas_fw_name; - -void libertas_free_adapter(wlan_private * priv); -int libertas_set_mac_packet_filter(wlan_private * priv); - -int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); -void libertas_send_tx_feedback(wlan_private * priv); -u8 libertas_check_last_packet_indication(wlan_private * priv); - -int libertas_free_cmd_buffer(wlan_private * priv); -struct cmd_ctrl_node; -struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv); - -void libertas_set_cmd_ctrl_node(wlan_private * priv, - struct cmd_ctrl_node *ptempnode, - u32 cmd_oid, u16 wait_option, void *pdata_buf); - -int libertas_prepare_and_send_command(wlan_private * priv, - u16 cmd_no, - u16 cmd_action, - u16 wait_option, u32 cmd_oid, void *pdata_buf); - -void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail); - -int libertas_allocate_cmd_buffer(wlan_private * priv); -int libertas_execute_next_command(wlan_private * priv); -int libertas_process_event(wlan_private * priv); -void libertas_interrupt(struct net_device *); -int libertas_set_radio_control(wlan_private * priv); -u32 libertas_index_to_data_rate(u8 index); -u8 libertas_data_rate_to_index(u32 rate); -void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); - -int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); - -/** The proc fs interface */ -int libertas_process_rx_command(wlan_private * priv); -int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); -void libertas_cleanup_and_insert_cmd(wlan_private * priv, - struct cmd_ctrl_node *ptempcmd); -void __libertas_cleanup_and_insert_cmd(wlan_private * priv, - struct cmd_ctrl_node *ptempcmd); - -int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band); - -int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *); - -void libertas_ps_sleep(wlan_private * priv, int wait_option); -void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode); -void libertas_ps_wakeup(wlan_private * priv, int wait_option); - -void libertas_tx_runqueue(wlan_private *priv); - -extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel( - wlan_adapter * adapter, u8 band, u16 channel); - -extern void libertas_mac_event_disconnected(wlan_private * priv); - -void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); - -int reset_device(wlan_private *priv); -/* main.c */ -extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, - int *cfp_no); -wlan_private *wlan_add_card(void *card); -int wlan_remove_card(void *card); - -#endif /* _WLAN_DECL_H_ */ diff --git a/trunk/drivers/net/wireless/libertas/defs.h b/trunk/drivers/net/wireless/libertas/defs.h deleted file mode 100644 index fb1478c1b87d..000000000000 --- a/trunk/drivers/net/wireless/libertas/defs.h +++ /dev/null @@ -1,369 +0,0 @@ -/** - * This header file contains global constant/enum definitions, - * global variable declaration. - */ -#ifndef _WLAN_DEFS_H_ -#define _WLAN_DEFS_H_ - -#include - -extern unsigned int libertas_debug; - -#define DRV_NAME "usb8xxx" - -#define lbs_pr_info(format, args...) \ - printk(KERN_INFO DRV_NAME": " format, ## args) -#define lbs_pr_err(format, args...) \ - printk(KERN_ERR DRV_NAME": " format, ## args) -#define lbs_pr_alert(format, args...) \ - printk(KERN_ALERT DRV_NAME": " format, ## args) - -#ifdef DEBUG -#define lbs_pr_debug(level, format, args...) \ - do { if (libertas_debug >= level) \ - printk(KERN_INFO DRV_NAME": " format, ##args); } while (0) -#define lbs_dev_dbg(level, device, format, args...) \ - lbs_pr_debug(level, "%s: " format, \ - (device)->bus_id , ## args) - -static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) -{ - int i = 0; - - if (!libertas_debug) - return; - - printk(KERN_DEBUG "%s: ", prompt); - for (i = 1; i <= len; i++) { - printk(KERN_DEBUG "%02x ", (u8) * buf); - buf++; - } - printk("\n"); -} -#else -#define lbs_pr_debug(level, format, args...) do {} while (0) -#define lbs_dev_dbg(level, device, format, args...) do {} while (0) -#define lbs_dbg_hex(x,y,z) do {} while (0) -#endif - -#define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \ - __FUNCTION__, __FILE__, __LINE__) -#define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \ - __FUNCTION__, __FILE__, __LINE__) - -/** Buffer Constants */ - -/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical -* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas -* driver has more local TxPDs. Each TxPD on the host memory is associated -* with a Tx control node. The driver maintains 8 RxPD descriptors for -* station firmware to store Rx packet information. -* -* Current version of MAC has a 32x6 multicast address buffer. -* -* 802.11b can have up to 14 channels, the driver keeps the -* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. -*/ - -#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 -#define MRVDRV_NUM_OF_CMD_BUFFER 10 -#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) -#define MRVDRV_MAX_CHANNEL_SIZE 14 -#define MRVDRV_MAX_BSSID_LIST 64 -#define MRVDRV_ASSOCIATION_TIME_OUT 255 -#define MRVDRV_SNAP_HEADER_LEN 8 - -#define WLAN_UPLD_SIZE 2312 -#define DEV_NAME_LEN 32 - -/** Misc constants */ -/* This section defines 802.11 specific contants */ - -#define MRVDRV_MAX_BSS_DESCRIPTS 16 -#define MRVDRV_MAX_REGION_CODE 6 - -#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe -#define MRVDRV_MIN_MULTIPLE_DTIM 1 -#define MRVDRV_MAX_MULTIPLE_DTIM 5 -#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1 - -#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10 - -#define MRVDRV_CHANNELS_PER_SCAN 4 -#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 - -#define MRVDRV_DEBUG_RX_PATH 0x00000001 -#define MRVDRV_DEBUG_TX_PATH 0x00000002 - -#define MRVDRV_MIN_BEACON_INTERVAL 20 -#define MRVDRV_MAX_BEACON_INTERVAL 1000 -#define MRVDRV_BEACON_INTERVAL 100 - -/** TxPD status */ - -/* Station firmware use TxPD status field to report final Tx transmit -* result, Bit masks are used to present combined situations. -*/ - -#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 -#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 - -/** Tx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. - * TODO: change to proper mesh flag when MAC understands it. - */ -#define TxPD_CONTROL_WDS_FRAME (1<<17) -#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME - -/** RxPD status */ - -#define MRVDRV_RXPD_STATUS_OK 0x0001 - -/** RxPD status - Received packet types */ -/** Rx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. - * TODO: change to proper mesh flag when MAC understands it. - */ -#define RxPD_CONTROL_WDS_FRAME (0x40) -#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME - -/** RSSI-related defines */ -/* RSSI constants are used to implement 802.11 RSSI threshold -* indication. if the Rx packet signal got too weak for 5 consecutive -* times, miniport driver (driver) will report this event to wrapper -*/ - -#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) - -/** RTS/FRAG related defines */ -#define MRVDRV_RTS_MIN_VALUE 0 -#define MRVDRV_RTS_MAX_VALUE 2347 -#define MRVDRV_FRAG_MIN_VALUE 256 -#define MRVDRV_FRAG_MAX_VALUE 2346 - -/* This is for firmware specific length */ -#define EXTRA_LEN 36 - -#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ - (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) - -#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ - (ETH_FRAME_LEN + sizeof(struct rxpd) \ - + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) - -#define CMD_F_HOSTCMD (1 << 0) -#define FW_CAPINFO_WPA (1 << 0) - -/** WPA key LENGTH*/ -#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 - -#define KEY_LEN_WPA_AES 16 -#define KEY_LEN_WPA_TKIP 32 -#define KEY_LEN_WEP_104 13 -#define KEY_LEN_WEP_40 5 - -#define RF_ANTENNA_1 0x1 -#define RF_ANTENNA_2 0x2 -#define RF_ANTENNA_AUTO 0xFFFF - -#define BAND_B (0x01) -#define BAND_G (0x02) -#define ALL_802_11_BANDS (BAND_B | BAND_G) - -/** MACRO DEFINITIONS */ -#define CAL_NF(NF) ((s32)(-(s32)(NF))) -#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF))) -#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) - -#define DEFAULT_BCN_AVG_FACTOR 8 -#define DEFAULT_DATA_AVG_FACTOR 8 -#define AVG_SCALE 100 -#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \ - (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \ - ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ - AVG_SCALE)) / N)) - -#define B_SUPPORTED_RATES 8 -#define G_SUPPORTED_RATES 14 - -#define WLAN_SUPPORTED_RATES 14 - -#define MAX_LEDS 8 - -#define IS_MESH_FRAME(x) (x->cb[6]) -#define SET_MESH_FRAME(x) (x->cb[6]=1) -#define UNSET_MESH_FRAME(x) (x->cb[6]=0) - -/** Global Variable Declaration */ -typedef struct _wlan_private wlan_private; -typedef struct _wlan_adapter wlan_adapter; -extern const char libertas_driver_version[]; -extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; - -extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES]; - -extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_b[4]; - -/** ENUM definition*/ -/** SNRNF_TYPE */ -enum SNRNF_TYPE { - TYPE_BEACON = 0, - TYPE_RXPD, - MAX_TYPE_B -}; - -/** SNRNF_DATA*/ -enum SNRNF_DATA { - TYPE_NOAVG = 0, - TYPE_AVG, - MAX_TYPE_AVG -}; - -/** WLAN_802_11_AUTH_ALG*/ -enum WLAN_802_11_AUTH_ALG { - AUTH_ALG_OPEN_SYSTEM = 1, - AUTH_ALG_SHARED_KEY = 2, - AUTH_ALG_NETWORK_EAP = 8, -}; - -/** WLAN_802_1X_AUTH_ALG */ -enum WLAN_802_1X_AUTH_ALG { - WLAN_1X_AUTH_ALG_NONE = 1, - WLAN_1X_AUTH_ALG_LEAP = 2, - WLAN_1X_AUTH_ALG_TLS = 4, - WLAN_1X_AUTH_ALG_TTLS = 8, - WLAN_1X_AUTH_ALG_MD5 = 16, -}; - -/** WLAN_802_11_ENCRYPTION_MODE */ -enum WLAN_802_11_ENCRYPTION_MODE { - CIPHER_NONE, - CIPHER_WEP40, - CIPHER_TKIP, - CIPHER_CCMP, - CIPHER_WEP104, -}; - -/** WLAN_802_11_POWER_MODE */ -enum WLAN_802_11_POWER_MODE { - wlan802_11powermodecam, - wlan802_11powermodemax_psp, - wlan802_11Powermodefast_psp, - /*not a real mode, defined as an upper bound */ - wlan802_11powemodemax -}; - -/** PS_STATE */ -enum PS_STATE { - PS_STATE_FULL_POWER, - PS_STATE_AWAKE, - PS_STATE_PRE_SLEEP, - PS_STATE_SLEEP -}; - -/** DNLD_STATE */ -enum DNLD_STATE { - DNLD_RES_RECEIVED, - DNLD_DATA_SENT, - DNLD_CMD_SENT -}; - -/** WLAN_MEDIA_STATE */ -enum WLAN_MEDIA_STATE { - libertas_connected, - libertas_disconnected -}; - -/** WLAN_802_11_PRIVACY_FILTER */ -enum WLAN_802_11_PRIVACY_FILTER { - wlan802_11privfilteracceptall, - wlan802_11privfilter8021xWEP -}; - -/** mv_ms_type */ -enum mv_ms_type { - MVMS_DAT = 0, - MVMS_CMD = 1, - MVMS_TXDONE = 2, - MVMS_EVENT -}; - -/** WLAN_802_11_NETWORK_INFRASTRUCTURE */ -enum WLAN_802_11_NETWORK_INFRASTRUCTURE { - wlan802_11ibss, - wlan802_11infrastructure, - wlan802_11autounknown, - /*defined as upper bound */ - wlan802_11infrastructuremax -}; - -/** WLAN_802_11_AUTHENTICATION_MODE */ -enum WLAN_802_11_AUTHENTICATION_MODE { - wlan802_11authmodeopen = 0x00, - wlan802_11authmodeshared = 0x01, - wlan802_11authmodenetworkEAP = 0x80, -}; - -/** WLAN_802_11_WEP_STATUS */ -enum WLAN_802_11_WEP_STATUS { - wlan802_11WEPenabled, - wlan802_11WEPdisabled, -}; - -/** SNMP_MIB_INDEX_e */ -enum SNMP_MIB_INDEX_e { - desired_bsstype_i = 0, - op_rateset_i, - bcnperiod_i, - dtimperiod_i, - assocrsp_timeout_i, - rtsthresh_i, - short_retrylim_i, - long_retrylim_i, - fragthresh_i, - dot11d_i, - dot11h_i, - manufid_i, - prodID_i, - manuf_oui_i, - manuf_name_i, - manuf_prodname_i, - manuf_prodver_i, -}; - -/** KEY_TYPE_ID */ -enum KEY_TYPE_ID { - KEY_TYPE_ID_WEP = 0, - KEY_TYPE_ID_TKIP, - KEY_TYPE_ID_AES -}; - -/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ -enum KEY_INFO_WPA { - KEY_INFO_WPA_MCAST = 0x01, - KEY_INFO_WPA_UNICAST = 0x02, - KEY_INFO_WPA_ENABLED = 0x04 -}; - -/** SNMP_MIB_VALUE_e */ -enum SNMP_MIB_VALUE_e { - SNMP_MIB_VALUE_INFRA = 1, - SNMP_MIB_VALUE_ADHOC -}; - -/* Default values for fwt commands. */ -#define FWT_DEFAULT_METRIC 0 -#define FWT_DEFAULT_DIR 1 -#define FWT_DEFAULT_SSN 0xffffffff -#define FWT_DEFAULT_DSN 0 -#define FWT_DEFAULT_HOPCOUNT 0 -#define FWT_DEFAULT_TTL 0 -#define FWT_DEFAULT_EXPIRATION 0 -#define FWT_DEFAULT_SLEEPMODE 0 -#define FWT_DEFAULT_SNR 0 - -#endif /* _WLAN_DEFS_H_ */ diff --git a/trunk/drivers/net/wireless/libertas/dev.h b/trunk/drivers/net/wireless/libertas/dev.h deleted file mode 100644 index b1f876f9693b..000000000000 --- a/trunk/drivers/net/wireless/libertas/dev.h +++ /dev/null @@ -1,403 +0,0 @@ -/** - * This file contains definitions and data structures specific - * to Marvell 802.11 NIC. It contains the Device Information - * structure wlan_adapter. - */ -#ifndef _WLAN_DEV_H_ -#define _WLAN_DEV_H_ - -#include -#include -#include -#include - -#include "defs.h" -#include "scan.h" -#include "thread.h" - -extern struct ethtool_ops libertas_ethtool_ops; - -#define MAX_BSSID_PER_CHANNEL 16 - -#define NR_TX_QUEUE 3 - -/* For the extended Scan */ -#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \ - MRVDRV_MAX_CHANNEL_SIZE + 1 - -#define MAX_REGION_CHANNEL_NUM 2 - -/** Chan-freq-TxPower mapping table*/ -struct chan_freq_power { - /** channel Number */ - u16 channel; - /** frequency of this channel */ - u32 freq; - /** Max allowed Tx power level */ - u16 maxtxpower; - /** TRUE:channel unsupported; FLASE:supported*/ - u8 unsupported; -}; - -/** region-band mapping table*/ -struct region_channel { - /** TRUE if this entry is valid */ - u8 valid; - /** region code for US, Japan ... */ - u8 region; - /** band B/G/A, used for BAND_CONFIG cmd */ - u8 band; - /** Actual No. of elements in the array below */ - u8 nrcfp; - /** chan-freq-txpower mapping table*/ - struct chan_freq_power *CFP; -}; - -struct wlan_802_11_security { - u8 WPAenabled; - u8 WPA2enabled; - enum WLAN_802_11_WEP_STATUS WEPstatus; - enum WLAN_802_11_AUTHENTICATION_MODE authmode; - enum WLAN_802_1X_AUTH_ALG auth1xalg; - enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode; -}; - -/** Current Basic Service Set State Structure */ -struct current_bss_params { - struct bss_descriptor bssdescriptor; - /** bssid */ - u8 bssid[ETH_ALEN]; - /** ssid */ - struct WLAN_802_11_SSID ssid; - - /** band */ - u8 band; - /** channel */ - u8 channel; - /** number of rates supported */ - int numofrates; - /** supported rates*/ - u8 datarates[WLAN_SUPPORTED_RATES]; -}; - -/** sleep_params */ -struct sleep_params { - u16 sp_error; - u16 sp_offset; - u16 sp_stabletime; - u8 sp_calcontrol; - u8 sp_extsleepclk; - u16 sp_reserved; -}; - -/** Data structure for the Marvell WLAN device */ -typedef struct _wlan_dev { - /** device name */ - char name[DEV_NAME_LEN]; - /** card pointer */ - void *card; - /** IO port */ - u32 ioport; - /** Upload received */ - u32 upld_rcv; - /** Upload type */ - u32 upld_typ; - /** Upload length */ - u32 upld_len; - /** netdev pointer */ - struct net_device *netdev; - /* Upload buffer */ - u8 upld_buf[WLAN_UPLD_SIZE]; - /* Download sent: - bit0 1/0=data_sent/data_tx_done, - bit1 1/0=cmd_sent/cmd_tx_done, - all other bits reserved 0 */ - u8 dnld_sent; -} wlan_dev_t, *pwlan_dev_t; - -/* Mesh statistics */ -struct wlan_mesh_stats { - u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ - u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ - u32 fwd_drop_ttl; /* Fwd: TTL zero */ - u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ - u32 fwd_drop_noroute; /* Fwd: No route to Destination */ - u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ - u32 drop_blind; /* Rx: Dropped by blinding table */ -}; - -/** Private structure for the MV device */ -struct _wlan_private { - int open; - int mesh_open; - int infra_open; - - wlan_adapter *adapter; - wlan_dev_t wlan_dev; - - struct net_device_stats stats; - struct net_device *mesh_dev ; /* Virtual device */ - - struct iw_statistics wstats; - struct wlan_mesh_stats mstats; - struct dentry *debugfs_dir; - struct dentry *debugfs_debug; - struct dentry *debugfs_files[6]; - - struct dentry *events_dir; - struct dentry *debugfs_events_files[6]; - - struct dentry *regs_dir; - struct dentry *debugfs_regs_files[6]; - - u32 mac_offset; - u32 bbp_offset; - u32 rf_offset; - - const struct firmware *firmware; - struct device *hotplug_device; - - /** thread to service interrupts */ - struct wlan_thread mainthread; - - struct delayed_work assoc_work; - struct workqueue_struct *assoc_thread; -}; - -/** Association request - * - * Encapsulates all the options that describe a specific assocation request - * or configuration of the wireless card's radio, mode, and security settings. - */ -struct assoc_request { -#define ASSOC_FLAG_SSID 1 -#define ASSOC_FLAG_CHANNEL 2 -#define ASSOC_FLAG_MODE 3 -#define ASSOC_FLAG_BSSID 4 -#define ASSOC_FLAG_WEP_KEYS 5 -#define ASSOC_FLAG_WEP_TX_KEYIDX 6 -#define ASSOC_FLAG_WPA_MCAST_KEY 7 -#define ASSOC_FLAG_WPA_UCAST_KEY 8 -#define ASSOC_FLAG_SECINFO 9 -#define ASSOC_FLAG_WPA_IE 10 - unsigned long flags; - - struct WLAN_802_11_SSID ssid; - u8 channel; - enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode; - u8 bssid[ETH_ALEN]; - - /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; - u16 wep_tx_keyidx; - - /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; - - struct wlan_802_11_security secinfo; - - /** WPA Information Elements*/ -#define MAX_WPA_IE_LEN 64 - u8 wpa_ie[MAX_WPA_IE_LEN]; - u8 wpa_ie_len; -}; - -/** Wlan adapter data structure*/ -struct _wlan_adapter { - /** STATUS variables */ - u32 fwreleasenumber; - u32 fwcapinfo; - /* protected with big lock */ - - struct mutex lock; - - u8 tmptxbuf[WLAN_UPLD_SIZE]; - /* protected by hard_start_xmit serialization */ - - /** command-related variables */ - u16 seqnum; - /* protected by big lock */ - - struct cmd_ctrl_node *cmd_array; - /** Current command */ - struct cmd_ctrl_node *cur_cmd; - int cur_cmd_retcode; - /** command Queues */ - /** Free command buffers */ - struct list_head cmdfreeq; - /** Pending command buffers */ - struct list_head cmdpendingq; - - wait_queue_head_t cmd_pending; - u8 nr_cmd_pending; - /* command related variables protected by adapter->driver_lock */ - - /** Async and Sync Event variables */ - u32 intcounter; - u32 eventcause; - u8 nodename[16]; /* nickname */ - - /** spin locks */ - spinlock_t driver_lock; - - /** Timers */ - struct timer_list command_timer; - - /* TX queue used in PS mode */ - spinlock_t txqueue_lock; - struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; - unsigned int tx_queue_idx; - - u8 hisregcpy; - - /** current ssid/bssid related parameters*/ - struct current_bss_params curbssparams; - - enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; - - struct bss_descriptor *pattemptedbssdesc; - - struct WLAN_802_11_SSID previousssid; - u8 previousbssid[ETH_ALEN]; - - struct bss_descriptor *scantable; - u32 numinscantable; - - u8 scantype; - u32 scanmode; - - u16 beaconperiod; - u8 adhoccreate; - - /** capability Info used in Association, start, join */ - struct ieeetypes_capinfo capinfo; - - /** MAC address information */ - u8 current_addr[ETH_ALEN]; - u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; - u32 nr_of_multicastmacaddr; - - /** 802.11 statistics */ -// struct cmd_DS_802_11_GET_STAT wlan802_11Stat; - - u16 enablehwauto; - u16 ratebitmap; - /** control G rates */ - u8 adhoc_grate_enabled; - - u32 txantenna; - u32 rxantenna; - - u8 adhocchannel; - u32 fragthsd; - u32 rtsthsd; - - u32 datarate; - u8 is_datarate_auto; - - u16 listeninterval; - u16 prescan; - u8 txretrycount; - - /** Tx-related variables (for single packet tx) */ - struct sk_buff *currenttxskb; - u16 TxLockFlag; - - /** NIC Operation characteristics */ - u16 currentpacketfilter; - u32 connect_status; - u16 regioncode; - u16 regiontableindex; - u16 txpowerlevel; - - /** POWER MANAGEMENT AND PnP SUPPORT */ - u8 surpriseremoved; - u16 atimwindow; - - u16 psmode; /* Wlan802_11PowermodeCAM=disable - Wlan802_11PowermodeMAX_PSP=enable */ - u16 multipledtim; - u32 psstate; - u8 needtowakeup; - - struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; - u16 locallisteninterval; - u16 nullpktinterval; - - struct assoc_request * assoc_req; - - /** Encryption parameter */ - struct wlan_802_11_security secinfo; - - /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; - u16 wep_tx_keyidx; - - /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; - - /** WPA Information Elements*/ -#define MAX_WPA_IE_LEN 64 - u8 wpa_ie[MAX_WPA_IE_LEN]; - u8 wpa_ie_len; - - u16 rxantennamode; - u16 txantennamode; - - /** Requested Signal Strength*/ - u16 bcn_avg_factor; - u16 data_avg_factor; - u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; - u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; - u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; - u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; - u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; - u16 nextSNRNF; - u16 numSNRNF; - u16 rxpd_rate; - - u8 radioon; - u32 preamble; - - /** Multi bands Parameter*/ - u8 libertas_supported_rates[G_SUPPORTED_RATES]; - - /** Blue Tooth Co-existence Arbitration */ - - /** sleep_params */ - struct sleep_params sp; - - /** RF calibration data */ - -#define MAX_REGION_CHANNEL_NUM 2 - /** region channel data */ - struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; - - struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; - - /** 11D and Domain Regulatory Data */ - struct wlan_802_11d_domain_reg domainreg; - struct parsed_region_chan_11d parsed_region_chan; - - /** FSM variable for 11d support */ - u32 enable11d; - - /** MISCELLANEOUS */ - u8 *prdeeprom; - struct wlan_offset_value offsetvalue; - - struct cmd_ds_802_11_get_log logmsg; - u16 scanprobes; - - u32 pkttxctrl; - - u16 txrate; - u32 linkmode; - u32 radiomode; - u32 debugmode; - u8 fw_ready; -}; - -#endif /* _WLAN_DEV_H_ */ diff --git a/trunk/drivers/net/wireless/libertas/ethtool.c b/trunk/drivers/net/wireless/libertas/ethtool.c deleted file mode 100644 index 0064de542963..000000000000 --- a/trunk/drivers/net/wireless/libertas/ethtool.c +++ /dev/null @@ -1,184 +0,0 @@ - -#include -#include -#include - -#include "host.h" -#include "sbi.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "wext.h" -static const char * mesh_stat_strings[]= { - "drop_duplicate_bcast", - "drop_ttl_zero", - "drop_no_fwd_route", - "drop_no_buffers", - "fwded_unicast_cnt", - "fwded_bcast_cnt", - "drop_blind_table" -}; - -static void libertas_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - wlan_private *priv = (wlan_private *) dev->priv; - char fwver[32]; - - libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); - - strcpy(info->driver, "libertas"); - strcpy(info->version, libertas_driver_version); - strcpy(info->fw_version, fwver); -} - -/* All 8388 parts have 16KiB EEPROM size at the time of writing. - * In case that changes this needs fixing. - */ -#define LIBERTAS_EEPROM_LEN 16384 - -static int libertas_ethtool_get_eeprom_len(struct net_device *dev) -{ - return LIBERTAS_EEPROM_LEN; -} - -static int libertas_ethtool_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * bytes) -{ - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_regrdwr regctrl; - char *ptr; - int ret; - - regctrl.action = 0; - regctrl.offset = eeprom->offset; - regctrl.NOB = eeprom->len; - - if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) - return -EINVAL; - -// mutex_lock(&priv->mutex); - - adapter->prdeeprom = - (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); - if (!adapter->prdeeprom) - return -ENOMEM; - memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); - - /* +14 is for action, offset, and NOB in - * response */ - lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n", - regctrl.action, regctrl.offset, regctrl.NOB); - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_eeprom_access, - regctrl.action, - cmd_option_waitforrsp, 0, - ®ctrl); - - if (ret) { - if (adapter->prdeeprom) - kfree(adapter->prdeeprom); - LEAVE(); - return ret; - } - - mdelay(10); - - ptr = (char *)adapter->prdeeprom; - - /* skip the command header, but include the "value" u32 variable */ - ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; - - /* - * Return the result back to the user - */ - memcpy(bytes, ptr, eeprom->len); - - if (adapter->prdeeprom) - kfree(adapter->prdeeprom); -// mutex_unlock(&priv->mutex); - - return 0; -} - -static void libertas_ethtool_get_stats(struct net_device * dev, - struct ethtool_stats * stats, u64 * data) -{ - wlan_private *priv = dev->priv; - - ENTER(); - - stats->cmd = ETHTOOL_GSTATS; - BUG_ON(stats->n_stats != MESH_STATS_NUM); - - data[0] = priv->mstats.fwd_drop_rbt; - data[1] = priv->mstats.fwd_drop_ttl; - data[2] = priv->mstats.fwd_drop_noroute; - data[3] = priv->mstats.fwd_drop_nobuf; - data[4] = priv->mstats.fwd_unicast_cnt; - data[5] = priv->mstats.fwd_bcast_cnt; - data[6] = priv->mstats.drop_blind; - - LEAVE(); -} - -static int libertas_ethtool_get_stats_count(struct net_device * dev) -{ - int ret; - wlan_private *priv = dev->priv; - struct cmd_ds_mesh_access mesh_access; - - ENTER(); - /* Get Mesh Statistics */ - ret = libertas_prepare_and_send_command(priv, - cmd_mesh_access, cmd_act_mesh_get_stats, - cmd_option_waitforrsp, 0, &mesh_access); - - if (ret) { - LEAVE(); - return 0; - } - - priv->mstats.fwd_drop_rbt = mesh_access.data[0]; - priv->mstats.fwd_drop_ttl = mesh_access.data[1]; - priv->mstats.fwd_drop_noroute = mesh_access.data[2]; - priv->mstats.fwd_drop_nobuf = mesh_access.data[3]; - priv->mstats.fwd_unicast_cnt = mesh_access.data[4]; - priv->mstats.fwd_bcast_cnt = mesh_access.data[5]; - priv->mstats.drop_blind = mesh_access.data[6]; - - LEAVE(); - return MESH_STATS_NUM; -} - -static void libertas_ethtool_get_strings (struct net_device * dev, - u32 stringset, - u8 * s) -{ - int i; - - ENTER(); - switch (stringset) { - case ETH_SS_STATS: - for (i=0; i < MESH_STATS_NUM; i++) { - memcpy(s + i * ETH_GSTRING_LEN, - mesh_stat_strings[i], - ETH_GSTRING_LEN); - } - break; - } - LEAVE(); -} - -struct ethtool_ops libertas_ethtool_ops = { - .get_drvinfo = libertas_ethtool_get_drvinfo, - .get_eeprom = libertas_ethtool_get_eeprom, - .get_eeprom_len = libertas_ethtool_get_eeprom_len, - .get_stats_count = libertas_ethtool_get_stats_count, - .get_ethtool_stats = libertas_ethtool_get_stats, - .get_strings = libertas_ethtool_get_strings, -}; - diff --git a/trunk/drivers/net/wireless/libertas/fw.c b/trunk/drivers/net/wireless/libertas/fw.c deleted file mode 100644 index b194a4570791..000000000000 --- a/trunk/drivers/net/wireless/libertas/fw.c +++ /dev/null @@ -1,361 +0,0 @@ -/** - * This file contains the initialization for FW and HW - */ -#include -#include - -#include -#include -#include - -#include "host.h" -#include "sbi.h" -#include "defs.h" -#include "decl.h" -#include "dev.h" -#include "fw.h" -#include "wext.h" -#include "if_usb.h" - -char *libertas_fw_name = NULL; -module_param_named(fw_name, libertas_fw_name, charp, 0644); - -unsigned int libertas_debug = 0; -module_param(libertas_debug, int, 0); - -/** - * @brief This function checks the validity of Boot2/FW image. - * - * @param data pointer to image - * len image length - * @return 0 or -1 - */ -static int check_fwfile_format(u8 *data, u32 totlen) -{ - u8 bincmd, exit; - u32 blksize, offset, len; - int ret; - - ret = 1; - exit = len = 0; - - do { - bincmd = *data; - blksize = *(u32*)(data + offsetof(struct fwheader, datalength)); - switch (bincmd) { - case FW_HAS_DATA_TO_RECV: - offset = sizeof(struct fwheader) + blksize; - data += offset; - len += offset; - if (len >= totlen) - exit = 1; - break; - case FW_HAS_LAST_BLOCK: - exit = 1; - ret = 0; - break; - default: - exit = 1; - break; - } - } while (!exit); - - if (ret) - lbs_pr_err("bin file format check FAIL...\n"); - else - lbs_pr_debug(1, "bin file format check PASS...\n"); - - return ret; -} - -/** - * @brief This function downloads firmware image, gets - * HW spec from firmware and set basic parameters to - * firmware. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -static int wlan_setup_station_hw(wlan_private * priv) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if ((ret = request_firmware(&priv->firmware, libertas_fw_name, - priv->hotplug_device)) < 0) { - lbs_pr_err("request_firmware() failed, error code = %#x\n", - ret); - lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name); - goto done; - } - - if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) { - release_firmware(priv->firmware); - goto done; - } - - ret = libertas_sbi_prog_firmware(priv); - - release_firmware(priv->firmware); - - if (ret) { - lbs_pr_debug(1, "Bootloader in invalid state!\n"); - ret = -1; - goto done; - } - - /* - * Read MAC address from HW - */ - memset(adapter->current_addr, 0xff, ETH_ALEN); - - ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, - 0, cmd_option_waitforrsp, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - libertas_set_mac_packet_filter(priv); - - /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - cmd_act_get_tx_rate, - cmd_option_waitforrsp, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - ret = 0; -done: - LEAVE(); - - return (ret); -} - -static int wlan_allocate_adapter(wlan_private * priv) -{ - u32 ulbufsize; - wlan_adapter *adapter = priv->adapter; - - struct bss_descriptor *ptempscantable; - - /* Allocate buffer to store the BSSID list */ - ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; - if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) { - libertas_free_adapter(priv); - return -1; - } - - adapter->scantable = ptempscantable; - memset(adapter->scantable, 0, ulbufsize); - - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); - - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); - adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(cmd_802_11_ps_mode); - adapter->libertas_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; - adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(cmd_subcmd_sleep_confirmed); - - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->scanprobes = 0; - - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; - adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; - - /* ATIM params */ - adapter->atimwindow = 0; - - adapter->connect_status = libertas_disconnected; - memset(adapter->current_addr, 0xff, ETH_ALEN); - - /* scan type */ - adapter->scantype = cmd_scan_type_active; - - /* scan mode */ - adapter->scanmode = cmd_bss_type_any; - - /* 802.11 specific */ - adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); - adapter->wep_tx_keyidx = 0; - adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; - adapter->secinfo.authmode = wlan802_11authmodeopen; - adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; - adapter->secinfo.Encryptionmode = CIPHER_NONE; - adapter->inframode = wlan802_11infrastructure; - - adapter->assoc_req = NULL; - - adapter->numinscantable = 0; - adapter->pattemptedbssdesc = NULL; - mutex_init(&adapter->lock); - - adapter->prescan = 1; - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - cmd_act_mac_rx_on | cmd_act_mac_tx_on; - - adapter->radioon = RADIO_ON; - adapter->txantenna = RF_ANTENNA_2; - adapter->rxantenna = RF_ANTENNA_AUTO; - - adapter->is_datarate_auto = 1; - adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - - // set default value of capinfo. -#define SHORT_PREAMBLE_ALLOWED 1 - memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); - adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; - - adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; - - adapter->psmode = wlan802_11powermodecam; - adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; - - adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; - - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - adapter->locallisteninterval = 0; /* default value in firmware will be used */ - - adapter->datarate = 0; // Initially indicate the rate as auto - - adapter->adhoc_grate_enabled = 0; - - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; - adapter->pkttxctrl = 0; - - memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); - adapter->tx_queue_idx = 0; - spin_lock_init(&adapter->txqueue_lock); - - return; -} - -static void command_timer_fn(unsigned long data); - -int libertas_init_fw(wlan_private * priv) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; - - /* init adapter structure */ - wlan_init_adapter(priv); - - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); - - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; - } - - /* init 802.11d */ - libertas_init_11d(priv); - - ret = 0; -done: - LEAVE(); - return ret; -} - -void libertas_free_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_pr_debug(1, "Why double free adapter?:)\n"); - return; - } - - lbs_pr_debug(1, "Free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_pr_debug(1, "Free commandTimer\n"); - del_timer(&adapter->command_timer); - - lbs_pr_debug(1, "Free scantable\n"); - if (adapter->scantable) { - kfree(adapter->scantable); - adapter->scantable = NULL; - } - - lbs_pr_debug(1, "Free adapter\n"); - - /* Free the adapter object itself */ - kfree(adapter); - priv->adapter = NULL; -} - -/** - * This function handles the timeout of command sending. - * It will re-send the same command again. - */ -static void command_timer_fn(unsigned long data) -{ - wlan_private *priv = (wlan_private *)data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *ptempnode; - struct cmd_ds_command *cmd; - unsigned long flags; - - ptempnode = adapter->cur_cmd; - cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; - - lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command); - - if (!adapter->fw_ready) - return; - - if (ptempnode == NULL) { - lbs_pr_debug(1, "PTempnode Empty\n"); - return; - } - - spin_lock_irqsave(&adapter->driver_lock, flags); - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_pr_debug(1, "Re-sending same command as it timeout...!\n"); - libertas_queue_cmd(adapter, ptempnode, 0); - - wake_up_interruptible(&priv->mainthread.waitq); - - return; -} diff --git a/trunk/drivers/net/wireless/libertas/fw.h b/trunk/drivers/net/wireless/libertas/fw.h deleted file mode 100644 index 1f9ae267a9e0..000000000000 --- a/trunk/drivers/net/wireless/libertas/fw.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This header file contains FW interface related definitions. - */ -#ifndef _WLAN_FW_H_ -#define _WLAN_FW_H_ - -#ifndef DEV_NAME_LEN -#define DEV_NAME_LEN 32 -#endif - -int libertas_init_fw(wlan_private * priv); - -#endif /* _WLAN_FW_H_ */ diff --git a/trunk/drivers/net/wireless/libertas/host.h b/trunk/drivers/net/wireless/libertas/host.h deleted file mode 100644 index c0faaecaf5be..000000000000 --- a/trunk/drivers/net/wireless/libertas/host.h +++ /dev/null @@ -1,338 +0,0 @@ -/** - * This file contains definitions of WLAN commands. - */ - -#ifndef _HOST_H_ -#define _HOST_H_ - -/** PUBLIC DEFINITIONS */ -#define DEFAULT_AD_HOC_CHANNEL 6 -#define DEFAULT_AD_HOC_CHANNEL_A 36 - -/** IEEE 802.11 oids */ -#define OID_802_11_SSID 0x00008002 -#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 -#define OID_802_11_RTS_THRESHOLD 0x0000800A -#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D -#define OID_802_11_SUPPORTED_RATES 0x0000800E -#define OID_802_11_STATISTICS 0x00008012 -#define OID_802_11_TX_RETRYCOUNT 0x0000801D -#define OID_802_11D_ENABLE 0x00008020 - -#define cmd_option_waitforrsp 0x0002 - -/** Host command ID */ -#define cmd_code_dnld 0x0002 -#define cmd_get_hw_spec 0x0003 -#define cmd_eeprom_update 0x0004 -#define cmd_802_11_reset 0x0005 -#define cmd_802_11_scan 0x0006 -#define cmd_802_11_get_log 0x000b -#define cmd_mac_multicast_adr 0x0010 -#define cmd_802_11_authenticate 0x0011 -#define cmd_802_11_eeprom_access 0x0059 -#define cmd_802_11_associate 0x0050 -#define cmd_802_11_set_wep 0x0013 -#define cmd_802_11_get_stat 0x0014 -#define cmd_802_3_get_stat 0x0015 -#define cmd_802_11_snmp_mib 0x0016 -#define cmd_mac_reg_map 0x0017 -#define cmd_bbp_reg_map 0x0018 -#define cmd_mac_reg_access 0x0019 -#define cmd_bbp_reg_access 0x001a -#define cmd_rf_reg_access 0x001b -#define cmd_802_11_radio_control 0x001c -#define cmd_802_11_rf_channel 0x001d -#define cmd_802_11_rf_tx_power 0x001e -#define cmd_802_11_rssi 0x001f -#define cmd_802_11_rf_antenna 0x0020 - -#define cmd_802_11_ps_mode 0x0021 - -#define cmd_802_11_data_rate 0x0022 -#define cmd_rf_reg_map 0x0023 -#define cmd_802_11_deauthenticate 0x0024 -#define cmd_802_11_reassociate 0x0025 -#define cmd_802_11_disassociate 0x0026 -#define cmd_mac_control 0x0028 -#define cmd_802_11_ad_hoc_start 0x002b -#define cmd_802_11_ad_hoc_join 0x002c - -#define cmd_802_11_query_tkip_reply_cntrs 0x002e -#define cmd_802_11_enable_rsn 0x002f -#define cmd_802_11_pairwise_tsc 0x0036 -#define cmd_802_11_group_tsc 0x0037 -#define cmd_802_11_key_material 0x005e - -#define cmd_802_11_set_afc 0x003c -#define cmd_802_11_get_afc 0x003d - -#define cmd_802_11_ad_hoc_stop 0x0040 - -#define cmd_802_11_beacon_stop 0x0049 - -#define cmd_802_11_mac_address 0x004D -#define cmd_802_11_eeprom_access 0x0059 - -#define cmd_802_11_band_config 0x0058 - -#define cmd_802_11d_domain_info 0x005b - -#define cmd_802_11_sleep_params 0x0066 - -#define cmd_802_11_inactivity_timeout 0x0067 - -#define cmd_802_11_tpc_cfg 0x0072 -#define cmd_802_11_pwr_cfg 0x0073 - -#define cmd_802_11_led_gpio_ctrl 0x004e - -#define cmd_802_11_subscribe_event 0x0075 - -#define cmd_802_11_rate_adapt_rateset 0x0076 - -#define cmd_802_11_tx_rate_query 0x007f - -#define cmd_get_tsf 0x0080 - -#define cmd_bt_access 0x0087 -#define cmd_ret_bt_access 0x8087 - -#define cmd_fwt_access 0x0088 -#define cmd_ret_fwt_access 0x8088 - -#define cmd_mesh_access 0x0090 -#define cmd_ret_mesh_access 0x8090 - -/* For the IEEE Power Save */ -#define cmd_subcmd_enter_ps 0x0030 -#define cmd_subcmd_exit_ps 0x0031 -#define cmd_subcmd_sleep_confirmed 0x0034 -#define cmd_subcmd_full_powerdown 0x0035 -#define cmd_subcmd_full_powerup 0x0036 - -/* command RET code, MSB is set to 1 */ -#define cmd_ret_hw_spec_info 0x8003 -#define cmd_ret_eeprom_update 0x8004 -#define cmd_ret_802_11_reset 0x8005 -#define cmd_ret_802_11_scan 0x8006 -#define cmd_ret_802_11_get_log 0x800b -#define cmd_ret_mac_control 0x8028 -#define cmd_ret_mac_multicast_adr 0x8010 -#define cmd_ret_802_11_authenticate 0x8011 -#define cmd_ret_802_11_deauthenticate 0x8024 -#define cmd_ret_802_11_associate 0x8012 -#define cmd_ret_802_11_reassociate 0x8025 -#define cmd_ret_802_11_disassociate 0x8026 -#define cmd_ret_802_11_set_wep 0x8013 -#define cmd_ret_802_11_stat 0x8014 -#define cmd_ret_802_3_stat 0x8015 -#define cmd_ret_802_11_snmp_mib 0x8016 -#define cmd_ret_mac_reg_map 0x8017 -#define cmd_ret_bbp_reg_map 0x8018 -#define cmd_ret_rf_reg_map 0x8023 -#define cmd_ret_mac_reg_access 0x8019 -#define cmd_ret_bbp_reg_access 0x801a -#define cmd_ret_rf_reg_access 0x801b -#define cmd_ret_802_11_radio_control 0x801c -#define cmd_ret_802_11_rf_channel 0x801d -#define cmd_ret_802_11_rssi 0x801f -#define cmd_ret_802_11_rf_tx_power 0x801e -#define cmd_ret_802_11_rf_antenna 0x8020 -#define cmd_ret_802_11_ps_mode 0x8021 -#define cmd_ret_802_11_data_rate 0x8022 - -#define cmd_ret_802_11_ad_hoc_start 0x802B -#define cmd_ret_802_11_ad_hoc_join 0x802C - -#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e -#define cmd_ret_802_11_enable_rsn 0x802f -#define cmd_ret_802_11_pairwise_tsc 0x8036 -#define cmd_ret_802_11_group_tsc 0x8037 -#define cmd_ret_802_11_key_material 0x805e - -#define cmd_enable_rsn 0x0001 -#define cmd_disable_rsn 0x0000 - -#define cmd_act_set 0x0001 -#define cmd_act_get 0x0000 - -#define cmd_act_get_AES (cmd_act_get + 2) -#define cmd_act_set_AES (cmd_act_set + 2) -#define cmd_act_remove_aes (cmd_act_set + 3) - -#define cmd_ret_802_11_set_afc 0x803c -#define cmd_ret_802_11_get_afc 0x803d - -#define cmd_ret_802_11_ad_hoc_stop 0x8040 - -#define cmd_ret_802_11_beacon_stop 0x8049 - -#define cmd_ret_802_11_mac_address 0x804D -#define cmd_ret_802_11_eeprom_access 0x8059 - -#define cmd_ret_802_11_band_config 0x8058 - -#define cmd_ret_802_11_sleep_params 0x8066 - -#define cmd_ret_802_11_inactivity_timeout 0x8067 - -#define cmd_ret_802_11d_domain_info (0x8000 | \ - cmd_802_11d_domain_info) - -#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000) -#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000) - -#define cmd_ret_802_11_led_gpio_ctrl 0x804e - -#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000) - -#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000) - -#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000) - -#define cmd_ret_get_tsf 0x8080 - -/* Define action or option for cmd_802_11_set_wep */ -#define cmd_act_add 0x0002 -#define cmd_act_remove 0x0004 -#define cmd_act_use_default 0x0008 - -#define cmd_type_wep_40_bit 0x0001 -#define cmd_type_wep_104_bit 0x0002 - -#define cmd_NUM_OF_WEP_KEYS 4 - -#define cmd_WEP_KEY_INDEX_MASK 0x3fff - -/* Define action or option for cmd_802_11_reset */ -#define cmd_act_halt 0x0003 - -/* Define action or option for cmd_802_11_scan */ -#define cmd_bss_type_bss 0x0001 -#define cmd_bss_type_ibss 0x0002 -#define cmd_bss_type_any 0x0003 - -/* Define action or option for cmd_802_11_scan */ -#define cmd_scan_type_active 0x0000 -#define cmd_scan_type_passive 0x0001 - -#define cmd_scan_radio_type_bg 0 - -#define cmd_scan_probe_delay_time 0 - -/* Define action or option for cmd_mac_control */ -#define cmd_act_mac_rx_on 0x0001 -#define cmd_act_mac_tx_on 0x0002 -#define cmd_act_mac_loopback_on 0x0004 -#define cmd_act_mac_wep_enable 0x0008 -#define cmd_act_mac_int_enable 0x0010 -#define cmd_act_mac_multicast_enable 0x0020 -#define cmd_act_mac_broadcast_enable 0x0040 -#define cmd_act_mac_promiscuous_enable 0x0080 -#define cmd_act_mac_all_multicast_enable 0x0100 -#define cmd_act_mac_strict_protection_enable 0x0400 - -/* Define action or option for cmd_802_11_radio_control */ -#define cmd_type_auto_preamble 0x0001 -#define cmd_type_short_preamble 0x0002 -#define cmd_type_long_preamble 0x0003 - -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 - -/* Define action or option for CMD_802_11_RF_CHANNEL */ -#define cmd_opt_802_11_rf_channel_get 0x00 -#define cmd_opt_802_11_rf_channel_set 0x01 - -/* Define action or option for cmd_802_11_rf_tx_power */ -#define cmd_act_tx_power_opt_get 0x0000 -#define cmd_act_tx_power_opt_set_high 0x8007 -#define cmd_act_tx_power_opt_set_mid 0x8004 -#define cmd_act_tx_power_opt_set_low 0x8000 - -#define cmd_act_tx_power_index_high 0x0007 -#define cmd_act_tx_power_index_mid 0x0004 -#define cmd_act_tx_power_index_low 0x0000 - -/* Define action or option for cmd_802_11_data_rate */ -#define cmd_act_set_tx_auto 0x0000 -#define cmd_act_set_tx_fix_rate 0x0001 -#define cmd_act_get_tx_rate 0x0002 - -#define cmd_act_set_rx 0x0001 -#define cmd_act_set_tx 0x0002 -#define cmd_act_set_both 0x0003 -#define cmd_act_get_rx 0x0004 -#define cmd_act_get_tx 0x0008 -#define cmd_act_get_both 0x000c - -/* Define action or option for cmd_802_11_ps_mode */ -#define cmd_type_cam 0x0000 -#define cmd_type_max_psp 0x0001 -#define cmd_type_fast_psp 0x0002 - -/* Define action or option for cmd_bt_access */ -enum cmd_bt_access_opts { - /* The bt commands start at 5 instead of 1 because the old dft commands - * are mapped to 1-4. These old commands are no longer maintained and - * should not be called. - */ - cmd_act_bt_access_add = 5, - cmd_act_bt_access_del, - cmd_act_bt_access_list, - cmd_act_bt_access_reset -}; - -/* Define action or option for cmd_fwt_access */ -enum cmd_fwt_access_opts { - cmd_act_fwt_access_add = 1, - cmd_act_fwt_access_del, - cmd_act_fwt_access_lookup, - cmd_act_fwt_access_list, - cmd_act_fwt_access_list_route, - cmd_act_fwt_access_list_neighbor, - cmd_act_fwt_access_reset, - cmd_act_fwt_access_cleanup, - cmd_act_fwt_access_time, -}; - -/* Define action or option for cmd_mesh_access */ -enum cmd_mesh_access_opts { - cmd_act_mesh_get_ttl = 1, - cmd_act_mesh_set_ttl, - cmd_act_mesh_get_stats, - cmd_act_mesh_get_mpp, - cmd_act_mesh_set_mpp, -}; - -/** Card Event definition */ -#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000 -#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001 -#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002 -#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003 -#define MACREG_INT_CODE_LINK_SENSED 0x00000004 -#define MACREG_INT_CODE_CMD_FINISHED 0x00000005 -#define MACREG_INT_CODE_MIB_CHANGED 0x00000006 -#define MACREG_INT_CODE_INIT_DONE 0x00000007 -#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008 -#define MACREG_INT_CODE_DISASSOCIATED 0x00000009 -#define MACREG_INT_CODE_PS_AWAKE 0x0000000a -#define MACREG_INT_CODE_PS_SLEEP 0x0000000b -#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d -#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e -#define MACREG_INT_CODE_WM_AWAKE 0x0000000f -#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011 -#define MACREG_INT_CODE_RSSI_LOW 0x00000019 -#define MACREG_INT_CODE_SNR_LOW 0x0000001a -#define MACREG_INT_CODE_MAX_FAIL 0x0000001b -#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c -#define MACREG_INT_CODE_SNR_HIGH 0x0000001d - -#endif /* _HOST_H_ */ diff --git a/trunk/drivers/net/wireless/libertas/hostcmd.h b/trunk/drivers/net/wireless/libertas/hostcmd.h deleted file mode 100644 index f239e5d2435b..000000000000 --- a/trunk/drivers/net/wireless/libertas/hostcmd.h +++ /dev/null @@ -1,693 +0,0 @@ -/* - * This file contains the function prototypes, data structure - * and defines for all the host/station commands - */ -#ifndef __HOSTCMD__H -#define __HOSTCMD__H - -#include -#include "11d.h" -#include "types.h" - -/* 802.11-related definitions */ - -/* TxPD descriptor */ -struct txpd { - /* Current Tx packet status */ - u32 tx_status; - /* Tx control */ - u32 tx_control; - u32 tx_packet_location; - /* Tx packet length */ - u16 tx_packet_length; - /* First 2 byte of destination MAC address */ - u8 tx_dest_addr_high[2]; - /* Last 4 byte of destination MAC address */ - u8 tx_dest_addr_low[4]; - /* Pkt Priority */ - u8 priority; - /* Pkt Trasnit Power control */ - u8 powermgmt; - /* Amount of time the packet has been queued in the driver (units = 2ms) */ - u8 pktdelay_2ms; - /* reserved */ - u8 reserved1; -}; - -/* RxPD Descriptor */ -struct rxpd { - /* Current Rx packet status */ - u16 status; - - /* SNR */ - u8 snr; - - /* Tx control */ - u8 rx_control; - - /* Pkt length */ - u16 pkt_len; - - /* Noise Floor */ - u8 nf; - - /* Rx Packet Rate */ - u8 rx_rate; - - /* Pkt addr */ - u32 pkt_ptr; - - /* Next Rx RxPD addr */ - u32 next_rxpd_ptr; - - /* Pkt Priority */ - u8 priority; - u8 reserved[3]; -}; - -struct cmd_ctrl_node { - /* CMD link list */ - struct list_head list; - u32 status; - /* CMD ID */ - u32 cmd_oid; - /*CMD wait option: wait for finish or no wait */ - u16 wait_option; - /* command parameter */ - void *pdata_buf; - /*command data */ - u8 *bufvirtualaddr; - u16 cmdflags; - /* wait queue */ - u16 cmdwaitqwoken; - wait_queue_head_t cmdwait_q; -}; - -/* WLAN_802_11_KEY - * - * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES) - * is determined from the keylength field. - */ -struct WLAN_802_11_KEY { - u32 len; - u32 flags; /* KEY_INFO_* from wlan_defs.h */ - u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH]; - u16 type; /* KEY_TYPE_* from wlan_defs.h */ -}; - -struct IE_WPA { - u8 elementid; - u8 len; - u8 oui[4]; - u16 version; -}; - -struct WLAN_802_11_SSID { - /* SSID length */ - u32 ssidlength; - - /* SSID information field */ - u8 ssid[IW_ESSID_MAX_SIZE]; -}; - -struct WPA_SUPPLICANT { - u8 wpa_ie[256]; - u8 wpa_ie_len; -}; - -/* wlan_offset_value */ -struct wlan_offset_value { - u32 offset; - u32 value; -}; - -struct WLAN_802_11_FIXED_IEs { - u8 timestamp[8]; - u16 beaconinterval; - u16 capabilities; -}; - -struct WLAN_802_11_VARIABLE_IEs { - u8 elementid; - u8 length; - u8 data[1]; -}; - -/* Define general data structure */ -/* cmd_DS_GEN */ -struct cmd_ds_gen { - u16 command; - u16 size; - u16 seqnum; - u16 result; -}; - -#define S_DS_GEN sizeof(struct cmd_ds_gen) -/* - * Define data structure for cmd_get_hw_spec - * This structure defines the response for the GET_HW_SPEC command - */ -struct cmd_ds_get_hw_spec { - /* HW Interface version number */ - u16 hwifversion; - /* HW version number */ - u16 version; - /* Max number of TxPD FW can handle */ - u16 nr_txpd; - /* Max no of Multicast address */ - u16 nr_mcast_adr; - /* MAC address */ - u8 permanentaddr[6]; - - /* region Code */ - u16 regioncode; - - /* Number of antenna used */ - u16 nr_antenna; - - /* FW release number, example 0x1234=1.2.3.4 */ - u32 fwreleasenumber; - - /* Base Address of TxPD queue */ - u32 wcb_base; - /* Read Pointer of RxPd queue */ - u32 rxpd_rdptr; - - /* Write Pointer of RxPd queue */ - u32 rxpd_wrptr; - - /*FW/HW capability */ - u32 fwcapinfo; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_reset { - u16 action; -}; - -struct cmd_ds_802_11_subscribe_event { - u16 action; - u16 events; -}; - -/* - * This scan handle Country Information IE(802.11d compliant) - * Define data structure for cmd_802_11_scan - */ -struct cmd_ds_802_11_scan { - u8 bsstype; - u8 BSSID[ETH_ALEN]; - u8 tlvbuffer[1]; -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_chanlistparamset_t ChanListParamSet; - mrvlietypes_ratesparamset_t OpRateSet; -#endif -}; - -struct cmd_ds_802_11_scan_rsp { - u16 bssdescriptsize; - u8 nr_sets; - u8 bssdesc_and_tlvbuffer[1]; -}; - -struct cmd_ds_802_11_get_log { - u32 mcasttxframe; - u32 failed; - u32 retry; - u32 multiretry; - u32 framedup; - u32 rtssuccess; - u32 rtsfailure; - u32 ackfailure; - u32 rxfrag; - u32 mcastrxframe; - u32 fcserror; - u32 txframe; - u32 wepundecryptable; -}; - -struct cmd_ds_mac_control { - u16 action; - u16 reserved; -}; - -struct cmd_ds_mac_multicast_adr { - u16 action; - u16 nr_of_adrs; - u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; -}; - -struct cmd_ds_802_11_authenticate { - u8 macaddr[ETH_ALEN]; - u8 authtype; - u8 reserved[10]; -}; - -struct cmd_ds_802_11_deauthenticate { - u8 macaddr[6]; - u16 reasoncode; -}; - -struct cmd_ds_802_11_associate { - u8 peerstaaddr[6]; - struct ieeetypes_capinfo capinfo; - u16 listeninterval; - u16 bcnperiod; - u8 dtimperiod; - -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_phyparamset_t phyparamset; - mrvlietypes_ssparamset_t ssparamset; - mrvlietypes_ratesparamset_t ratesParamSet; -#endif -} __attribute__ ((packed)); - -struct cmd_ds_802_11_disassociate { - u8 destmacaddr[6]; - u16 reasoncode; -}; - -struct cmd_ds_802_11_associate_rsp { - struct ieeetypes_assocrsp assocRsp; -}; - -struct cmd_ds_802_11_ad_hoc_result { - u8 PAD[3]; - u8 BSSID[ETH_ALEN]; -}; - -struct cmd_ds_802_11_set_wep { - /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ - u16 action; - - /* key Index selected for Tx */ - u16 keyindex; - - /* 40, 128bit or TXWEP */ - u8 keytype[4]; - u8 keymaterial[4][16]; -}; - -struct cmd_ds_802_3_get_stat { - u32 xmitok; - u32 rcvok; - u32 xmiterror; - u32 rcverror; - u32 rcvnobuffer; - u32 rcvcrcerror; -}; - -struct cmd_ds_802_11_get_stat { - u32 txfragmentcnt; - u32 mcasttxframecnt; - u32 failedcnt; - u32 retrycnt; - u32 Multipleretrycnt; - u32 rtssuccesscnt; - u32 rtsfailurecnt; - u32 ackfailurecnt; - u32 frameduplicatecnt; - u32 rxfragmentcnt; - u32 mcastrxframecnt; - u32 fcserrorcnt; - u32 bcasttxframecnt; - u32 bcastrxframecnt; - u32 txbeacon; - u32 rxbeacon; - u32 wepundecryptable; -}; - -struct cmd_ds_802_11_snmp_mib { - u16 querytype; - u16 oid; - u16 bufsize; - u8 value[128]; -}; - -struct cmd_ds_mac_reg_map { - u16 buffersize; - u8 regmap[128]; - u16 reserved; -}; - -struct cmd_ds_bbp_reg_map { - u16 buffersize; - u8 regmap[128]; - u16 reserved; -}; - -struct cmd_ds_rf_reg_map { - u16 buffersize; - u8 regmap[64]; - u16 reserved; -}; - -struct cmd_ds_mac_reg_access { - u16 action; - u16 offset; - u32 value; -}; - -struct cmd_ds_bbp_reg_access { - u16 action; - u16 offset; - u8 value; - u8 reserved[3]; -}; - -struct cmd_ds_rf_reg_access { - u16 action; - u16 offset; - u8 value; - u8 reserved[3]; -}; - -struct cmd_ds_802_11_radio_control { - u16 action; - u16 control; -}; - -struct cmd_ds_802_11_sleep_params { - /* ACT_GET/ACT_SET */ - u16 action; - - /* Sleep clock error in ppm */ - u16 error; - - /* Wakeup offset in usec */ - u16 offset; - - /* Clock stabilization time in usec */ - u16 stabletime; - - /* control periodic calibration */ - u8 calcontrol; - - /* control the use of external sleep clock */ - u8 externalsleepclk; - - /* reserved field, should be set to zero */ - u16 reserved; -}; - -struct cmd_ds_802_11_inactivity_timeout { - /* ACT_GET/ACT_SET */ - u16 action; - - /* Inactivity timeout in msec */ - u16 timeout; -}; - -struct cmd_ds_802_11_rf_channel { - u16 action; - u16 currentchannel; - u16 rftype; - u16 reserved; - u8 channellist[32]; -}; - -struct cmd_ds_802_11_rssi { - /* weighting factor */ - u16 N; - - u16 reserved_0; - u16 reserved_1; - u16 reserved_2; -}; - -struct cmd_ds_802_11_rssi_rsp { - u16 SNR; - u16 noisefloor; - u16 avgSNR; - u16 avgnoisefloor; -}; - -struct cmd_ds_802_11_mac_address { - u16 action; - u8 macadd[ETH_ALEN]; -}; - -struct cmd_ds_802_11_rf_tx_power { - u16 action; - u16 currentlevel; -}; - -struct cmd_ds_802_11_rf_antenna { - u16 action; - - /* Number of antennas or 0xffff(diversity) */ - u16 antennamode; - -}; - -struct cmd_ds_802_11_ps_mode { - u16 action; - u16 nullpktinterval; - u16 multipledtim; - u16 reserved; - u16 locallisteninterval; -}; - -struct PS_CMD_ConfirmSleep { - u16 command; - u16 size; - u16 seqnum; - u16 result; - - u16 action; - u16 reserved1; - u16 multipledtim; - u16 reserved; - u16 locallisteninterval; -}; - -struct cmd_ds_802_11_data_rate { - u16 action; - u16 reserverd; - u8 datarate[G_SUPPORTED_RATES]; -}; - -struct cmd_ds_802_11_rate_adapt_rateset { - u16 action; - u16 enablehwauto; - u16 bitmap; -}; - -struct cmd_ds_802_11_ad_hoc_start { - u8 SSID[IW_ESSID_MAX_SIZE]; - u8 bsstype; - u16 beaconperiod; - u8 dtimperiod; - union IEEEtypes_ssparamset ssparamset; - union ieeetypes_phyparamset phyparamset; - u16 probedelay; - struct ieeetypes_capinfo cap; - u8 datarate[G_SUPPORTED_RATES]; - u8 tlv_memory_size_pad[100]; -} __attribute__ ((packed)); - -struct adhoc_bssdesc { - u8 BSSID[6]; - u8 SSID[32]; - u8 bsstype; - u16 beaconperiod; - u8 dtimperiod; - u8 timestamp[8]; - u8 localtime[8]; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; - u8 datarates[G_SUPPORTED_RATES]; - - /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the - * Adhoc join command and will cause a binary layout mismatch with - * the firmware - */ -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ad_hoc_join { - struct adhoc_bssdesc bssdescriptor; - u16 failtimeout; - u16 probedelay; - -} __attribute__ ((packed)); - -struct cmd_ds_802_11_enable_rsn { - u16 action; - u16 enable; -}; - -struct MrvlIEtype_keyParamSet { - /* type ID */ - u16 type; - - /* length of Payload */ - u16 length; - - /* type of key: WEP=0, TKIP=1, AES=2 */ - u16 keytypeid; - - /* key control Info specific to a keytypeid */ - u16 keyinfo; - - /* length of key */ - u16 keylen; - - /* key material of size keylen */ - u8 key[32]; -}; - -struct cmd_ds_802_11_key_material { - u16 action; - struct MrvlIEtype_keyParamSet keyParamSet[2]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_eeprom_access { - u16 action; - - /* multiple 4 */ - u16 offset; - u16 bytecount; - u8 value; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_tpc_cfg { - u16 action; - u8 enable; - s8 P0; - s8 P1; - s8 P2; - u8 usesnr; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_led_ctrl { - u16 action; - u16 numled; - u8 data[256]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_pwr_cfg { - u16 action; - u8 enable; - s8 PA_P0; - s8 PA_P1; - s8 PA_P2; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_afc { - u16 afc_auto; - union { - struct { - u16 threshold; - u16 period; - }; - struct { - s16 timing_offset; - s16 carrier_offset; - }; - }; -} __attribute__ ((packed)); - -struct cmd_tx_rate_query { - u16 txrate; -} __attribute__ ((packed)); - -struct cmd_ds_get_tsf { - __le64 tsfvalue; -} __attribute__ ((packed)); - -struct cmd_ds_bt_access { - u16 action; - u32 id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; -} __attribute__ ((packed)); - -struct cmd_ds_fwt_access { - u16 action; - u32 id; - u8 da[ETH_ALEN]; - u8 dir; - u8 ra[ETH_ALEN]; - u32 ssn; - u32 dsn; - u32 metric; - u8 hopcount; - u8 ttl; - u32 expiration; - u8 sleepmode; - u32 snr; - u32 references; -} __attribute__ ((packed)); - -#define MESH_STATS_NUM 7 -struct cmd_ds_mesh_access { - u16 action; - u32 data[MESH_STATS_NUM + 1]; /* last position reserved */ -} __attribute__ ((packed)); - -struct cmd_ds_command { - /* command header */ - u16 command; - u16 size; - u16 seqnum; - u16 result; - - /* command Body */ - union { - struct cmd_ds_get_hw_spec hwspec; - struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_scan scan; - struct cmd_ds_802_11_scan_rsp scanresp; - struct cmd_ds_mac_control macctrl; - struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_deauthenticate deauth; - struct cmd_ds_802_11_set_wep wep; - struct cmd_ds_802_11_ad_hoc_start ads; - struct cmd_ds_802_11_reset reset; - struct cmd_ds_802_11_ad_hoc_result result; - struct cmd_ds_802_11_get_log glog; - struct cmd_ds_802_11_authenticate auth; - struct cmd_ds_802_11_get_stat gstat; - struct cmd_ds_802_3_get_stat gstat_8023; - struct cmd_ds_802_11_snmp_mib smib; - struct cmd_ds_802_11_rf_tx_power txp; - struct cmd_ds_802_11_rf_antenna rant; - struct cmd_ds_802_11_data_rate drate; - struct cmd_ds_802_11_rate_adapt_rateset rateset; - struct cmd_ds_mac_multicast_adr madr; - struct cmd_ds_802_11_ad_hoc_join adj; - struct cmd_ds_802_11_radio_control radio; - struct cmd_ds_802_11_rf_channel rfchannel; - struct cmd_ds_802_11_rssi rssi; - struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_802_11_disassociate dassociate; - struct cmd_ds_802_11_mac_address macadd; - struct cmd_ds_802_11_enable_rsn enbrsn; - struct cmd_ds_802_11_key_material keymaterial; - struct cmd_ds_mac_reg_access macreg; - struct cmd_ds_bbp_reg_access bbpreg; - struct cmd_ds_rf_reg_access rfreg; - struct cmd_ds_802_11_eeprom_access rdeeprom; - - struct cmd_ds_802_11d_domain_info domaininfo; - struct cmd_ds_802_11d_domain_info domaininforesp; - - struct cmd_ds_802_11_sleep_params sleep_params; - struct cmd_ds_802_11_inactivity_timeout inactivity_timeout; - struct cmd_ds_802_11_tpc_cfg tpccfg; - struct cmd_ds_802_11_pwr_cfg pwrcfg; - struct cmd_ds_802_11_afc afc; - struct cmd_ds_802_11_led_ctrl ledgpio; - - struct cmd_tx_rate_query txrate; - struct cmd_ds_bt_access bt; - struct cmd_ds_fwt_access fwt; - struct cmd_ds_mesh_access mesh; - struct cmd_ds_get_tsf gettsf; - struct cmd_ds_802_11_subscribe_event subscribe_event; - } params; -} __attribute__ ((packed)); - -#endif diff --git a/trunk/drivers/net/wireless/libertas/if_bootcmd.c b/trunk/drivers/net/wireless/libertas/if_bootcmd.c deleted file mode 100644 index 567000c3e87b..000000000000 --- a/trunk/drivers/net/wireless/libertas/if_bootcmd.c +++ /dev/null @@ -1,38 +0,0 @@ -/** - * This file contains functions used in USB Boot command - * and Boot2/FW update - */ - -#include -#include -#include -#include - -#include "defs.h" -#include "dev.h" -#include "if_usb.h" - -/** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 - */ -int if_usb_issue_boot_command(wlan_private *priv, int ivalue) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - struct bootcmdstr sbootcmd; - int i; - - /* Prepare command */ - sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER; - sbootcmd.u8cmd_tag = ivalue; - for (i=0; i<11; i++) - sbootcmd.au8dumy[i]=0x00; - memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); - - /* Issue command */ - usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); - - return 0; -} diff --git a/trunk/drivers/net/wireless/libertas/if_usb.c b/trunk/drivers/net/wireless/libertas/if_usb.c deleted file mode 100644 index 695fb6a66ffe..000000000000 --- a/trunk/drivers/net/wireless/libertas/if_usb.c +++ /dev/null @@ -1,952 +0,0 @@ -/** - * This file contains functions used in USB interface module. - */ -#include -#include -#include -#include - -#include "host.h" -#include "sbi.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "if_usb.h" - -#define MESSAGE_HEADER_LEN 4 - -static const char usbdriver_name[] = "usb8xxx"; - -static struct usb_device_id if_usb_table[] = { - /* Enter the device signature inside */ - { - USB_DEVICE(USB8388_VID_1, USB8388_PID_1), - }, - { - USB_DEVICE(USB8388_VID_2, USB8388_PID_2), - }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, if_usb_table); - -static void if_usb_receive(struct urb *urb); -static void if_usb_receive_fwload(struct urb *urb); - -/** - * @brief call back function to handle the status of the URB - * @param urb pointer to urb structure - * @return N/A - */ -static void if_usb_write_bulk_callback(struct urb *urb) -{ - wlan_private *priv = (wlan_private *) (urb->context); - wlan_adapter *adapter = priv->adapter; - struct net_device *dev = priv->wlan_dev.netdev; - - /* handle the transmission complete validations */ - - if (urb->status != 0) { - /* print the failure status number for debug */ - lbs_pr_info("URB in failure status\n"); - } else { - lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n"); - lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n", - urb->actual_length); - priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; - /* Wake main thread if commands are pending */ - if (!adapter->cur_cmd) - wake_up_interruptible(&priv->mainthread.waitq); - if ((adapter->connect_status == libertas_connected)) - netif_wake_queue(dev); - } - - return; -} - -/** - * @brief free tx/rx urb, skb and rx buffer - * @param cardp pointer usb_card_rec - * @return N/A - */ -void if_usb_free(struct usb_card_rec *cardp) -{ - ENTER(); - - /* Unlink tx & rx urb */ - usb_kill_urb(cardp->tx_urb); - usb_kill_urb(cardp->rx_urb); - - usb_free_urb(cardp->tx_urb); - cardp->tx_urb = NULL; - - usb_free_urb(cardp->rx_urb); - cardp->rx_urb = NULL; - - kfree(cardp->bulk_out_buffer); - cardp->bulk_out_buffer = NULL; - - LEAVE(); - return; -} - -/** - * @brief sets the configuration values - * @param ifnum interface number - * @param id pointer to usb_device_id - * @return 0 on success, error code on failure - */ -static int if_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - wlan_private *pwlanpriv; - struct usb_card_rec *usb_cardp; - int i; - - udev = interface_to_usbdev(intf); - - usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); - if (!usb_cardp) { - lbs_pr_err("Out of memory allocating private data.\n"); - goto error; - } - - usb_cardp->udev = udev; - iface_desc = intf->cur_altsetting; - - lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" - " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", - udev->descriptor.bcdUSB, - udev->descriptor.bDeviceClass, - udev->descriptor.bDeviceSubClass, - udev->descriptor.bDeviceProtocol); - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - /* we found a bulk in endpoint */ - lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n", - endpoint->wMaxPacketSize); - if (! - (usb_cardp->rx_urb = - usb_alloc_urb(0, GFP_KERNEL))) { - lbs_dev_dbg(1, &udev->dev, - "Rx URB allocation failed\n"); - goto dealloc; - } - usb_cardp->rx_urb_recall = 0; - - usb_cardp->bulk_in_size = - endpoint->wMaxPacketSize; - usb_cardp->bulk_in_endpointAddr = - (endpoint-> - bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n", - endpoint->bEndpointAddress); - } - - if (((endpoint-> - bEndpointAddress & USB_ENDPOINT_DIR_MASK) == - USB_DIR_OUT) - && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - /* We found bulk out endpoint */ - if (! - (usb_cardp->tx_urb = - usb_alloc_urb(0, GFP_KERNEL))) { - lbs_dev_dbg(1,&udev->dev, - "Tx URB allocation failed\n"); - goto dealloc; - } - - usb_cardp->bulk_out_size = - endpoint->wMaxPacketSize; - lbs_dev_dbg(1, &udev->dev, - "Bulk out size is %d\n", - endpoint->wMaxPacketSize); - usb_cardp->bulk_out_endpointAddr = - endpoint->bEndpointAddress; - lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n", - endpoint->bEndpointAddress); - usb_cardp->bulk_out_buffer = - kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, - GFP_KERNEL); - - if (!usb_cardp->bulk_out_buffer) { - lbs_dev_dbg(1, &udev->dev, - "Could not allocate buffer\n"); - goto dealloc; - } - } - } - - - /* At this point wlan_add_card() will be called. Don't worry - * about keeping pwlanpriv around since it will be set on our - * usb device data in -> add() -> libertas_sbi_register_dev(). - */ - if (!(pwlanpriv = wlan_add_card(usb_cardp))) - goto dealloc; - - usb_get_dev(udev); - usb_set_intfdata(intf, usb_cardp); - - /* - * return card structure, which can be got back in the - * diconnect function as the ptr - * argument. - */ - return 0; - -dealloc: - if_usb_free(usb_cardp); - -error: - return -ENOMEM; -} - -/** - * @brief free resource and cleanup - * @param udev pointer to usb_device - * @param ptr pointer to usb_cardp - * @return N/A - */ -static void if_usb_disconnect(struct usb_interface *intf) -{ - struct usb_card_rec *cardp = usb_get_intfdata(intf); - wlan_private *priv = (wlan_private *) cardp->priv; - wlan_adapter *adapter = NULL; - - adapter = priv->adapter; - - /* - * Update Surprise removed to TRUE - */ - adapter->surpriseremoved = 1; - - /* card is removed and we can call wlan_remove_card */ - lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n"); - wlan_remove_card(cardp); - - /* Unlink and free urb */ - if_usb_free(cardp); - - usb_set_intfdata(intf, NULL); - usb_put_dev(interface_to_usbdev(intf)); - - return; -} - -/** - * @brief This function download FW - * @param priv pointer to wlan_private - * @return 0 - */ -static int if_prog_firmware(wlan_private * priv) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - struct FWData *fwdata; - struct fwheader *fwheader; - u8 *firmware = priv->firmware->data; - - fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); - - if (!fwdata) - return -1; - - fwheader = &fwdata->fwheader; - - if (!cardp->CRC_OK) { - cardp->totalbytes = cardp->fwlastblksent; - cardp->fwseqnum = cardp->lastseqnum - 1; - } - - lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n", - cardp->totalbytes); - - memcpy(fwheader, &firmware[cardp->totalbytes], - sizeof(struct fwheader)); - - cardp->fwlastblksent = cardp->totalbytes; - cardp->totalbytes += sizeof(struct fwheader); - - lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n"); - memcpy(fwdata->data, &firmware[cardp->totalbytes], - fwdata->fwheader.datalength); - - lbs_dev_dbg(2, &cardp->udev->dev, - "Data length = %d\n", fwdata->fwheader.datalength); - - cardp->fwseqnum = cardp->fwseqnum + 1; - - fwdata->seqnum = cardp->fwseqnum; - cardp->lastseqnum = fwdata->seqnum; - cardp->totalbytes += fwdata->fwheader.datalength; - - if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) { - lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n"); - lbs_dev_dbg(2, &cardp->udev->dev, - "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, - cardp->totalbytes); - memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); - - } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) { - lbs_dev_dbg(2, &cardp->udev->dev, - "Host has finished FW downloading\n"); - lbs_dev_dbg(2, &cardp->udev->dev, - "Donwloading FW JUMP BLOCK\n"); - memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); - cardp->fwfinalblk = 1; - } - - lbs_dev_dbg(2, &cardp->udev->dev, - "The firmware download is done size is %d\n", - cardp->totalbytes); - - kfree(fwdata); - - return 0; -} - -static int libertas_do_reset(wlan_private *priv) -{ - int ret; - struct usb_card_rec *cardp = priv->wlan_dev.card; - - ret = usb_reset_device(cardp->udev); - if (!ret) { - msleep(10); - reset_device(priv); - msleep(10); - } - return ret; -} - -/** - * @brief This function transfer the data to the device. - * @param priv pointer to wlan_private - * @param payload pointer to payload data - * @param nb data length - * @return 0 or -1 - */ -int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) -{ - /* pointer to card structure */ - struct usb_card_rec *cardp = priv->wlan_dev.card; - int ret = -1; - - /* check if device is removed */ - if (priv->adapter->surpriseremoved) { - lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n"); - goto tx_ret; - } - - usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, - usb_sndbulkpipe(cardp->udev, - cardp->bulk_out_endpointAddr), - payload, nb, if_usb_write_bulk_callback, priv); - - cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; - - if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { - /* transfer failed */ - lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n"); - ret = -1; - } else { - lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n"); - ret = 0; - } - -tx_ret: - return ret; -} - -static int __if_usb_submit_rx_urb(wlan_private * priv, - void (*callbackfn) - (struct urb *urb)) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - struct sk_buff *skb; - struct read_cb_info *rinfo = &cardp->rinfo; - int ret = -1; - - if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { - lbs_pr_err("No free skb\n"); - goto rx_ret; - } - - rinfo->skb = skb; - - /* Fill the receive configuration URB and initialise the Rx call back */ - usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, - usb_rcvbulkpipe(cardp->udev, - cardp->bulk_in_endpointAddr), - skb->tail + IPFIELD_ALIGN_OFFSET, - MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, - rinfo); - - cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; - - lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); - if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { - /* handle failure conditions */ - lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n"); - ret = -1; - } else { - lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n"); - ret = 0; - } - -rx_ret: - return ret; -} - -static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) -{ - return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); -} - -static inline int if_usb_submit_rx_urb(wlan_private * priv) -{ - return __if_usb_submit_rx_urb(priv, &if_usb_receive); -} - -static void if_usb_receive_fwload(struct urb *urb) -{ - struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; - struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; - struct fwsyncheader *syncfwheader; - struct bootcmdrespStr bootcmdresp; - - if (urb->status) { - lbs_dev_dbg(1, &cardp->udev->dev, - "URB status is failed during fw load\n"); - kfree_skb(skb); - return; - } - - if (cardp->bootcmdresp == 0) { - memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, - sizeof(bootcmdresp)); - if (cardp->udev->descriptor.bcdDevice < 0x3106) { - kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); - cardp->bootcmdresp = 1; - lbs_dev_dbg(1, &cardp->udev->dev, - "Received valid boot command response\n"); - return; - } - if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) { - lbs_pr_info( - "boot cmd response wrong magic number (0x%x)\n", - bootcmdresp.u32magicnumber); - } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { - lbs_pr_info( - "boot cmd response cmd_tag error (%d)\n", - bootcmdresp.u8cmd_tag); - } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { - lbs_pr_info( - "boot cmd response result error (%d)\n", - bootcmdresp.u8result); - } else { - cardp->bootcmdresp = 1; - lbs_dev_dbg(1, &cardp->udev->dev, - "Received valid boot command response\n"); - } - kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); - return; - } - - syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); - if (!syncfwheader) { - lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n"); - kfree_skb(skb); - return; - } - - memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, - sizeof(struct fwsyncheader)); - - if (!syncfwheader->cmd) { - lbs_dev_dbg(2, &cardp->udev->dev, - "FW received Blk with correct CRC\n"); - lbs_dev_dbg(2, &cardp->udev->dev, - "FW received Blk seqnum = %d\n", - syncfwheader->seqnum); - cardp->CRC_OK = 1; - } else { - lbs_dev_dbg(1, &cardp->udev->dev, - "FW received Blk with CRC error\n"); - cardp->CRC_OK = 0; - } - - kfree_skb(skb); - - if (cardp->fwfinalblk) { - cardp->fwdnldover = 1; - goto exit; - } - - if_prog_firmware(priv); - - if_usb_submit_rx_urb_fwload(priv); -exit: - kfree(syncfwheader); - - return; - -} - -#define MRVDRV_MIN_PKT_LEN 30 - -static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, - struct usb_card_rec *cardp, - wlan_private *priv) -{ - if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + - MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { - lbs_dev_dbg(1, &cardp->udev->dev, - "Packet length is Invalid\n"); - kfree_skb(skb); - return; - } - - skb_reserve(skb, IPFIELD_ALIGN_OFFSET); - skb_put(skb, recvlength); - skb_pull(skb, MESSAGE_HEADER_LEN); - libertas_process_rxed_packet(priv, skb); - priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); -} - -static inline void process_cmdrequest(int recvlength, u8 *recvbuff, - struct sk_buff *skb, - struct usb_card_rec *cardp, - wlan_private *priv) -{ - u8 *cmdbuf; - if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { - lbs_dev_dbg(1, &cardp->udev->dev, - "The receive buffer is too large\n"); - kfree_skb(skb); - return; - } - - if (!in_interrupt()) - BUG(); - - spin_lock(&priv->adapter->driver_lock); - /* take care of cur_cmd = NULL case by reading the - * data to clear the interrupt */ - if (!priv->adapter->cur_cmd) { - cmdbuf = priv->wlan_dev.upld_buf; - priv->adapter->hisregcpy &= ~his_cmdupldrdy; - } else - cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; - - cardp->usb_int_cause |= his_cmdupldrdy; - priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); - memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, - priv->wlan_dev.upld_len); - - kfree_skb(skb); - libertas_interrupt(priv->wlan_dev.netdev); - spin_unlock(&priv->adapter->driver_lock); - - lbs_dev_dbg(1, &cardp->udev->dev, - "Wake up main thread to handle cmd response\n"); - - return; -} - -/** - * @brief This function reads of the packet into the upload buff, - * wake up the main thread and initialise the Rx callack. - * - * @param urb pointer to struct urb - * @return N/A - */ -static void if_usb_receive(struct urb *urb) -{ - struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; - struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; - - int recvlength = urb->actual_length; - u8 *recvbuff = NULL; - u32 recvtype; - - ENTER(); - - if (recvlength) { - if (urb->status) { - lbs_dev_dbg(1, &cardp->udev->dev, - "URB status is failed\n"); - kfree_skb(skb); - goto setup_for_next; - } - - recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; - memcpy(&recvtype, recvbuff, sizeof(u32)); - lbs_dev_dbg(1, &cardp->udev->dev, - "Recv length = 0x%x\n", recvlength); - lbs_dev_dbg(1, &cardp->udev->dev, - "Receive type = 0x%X\n", recvtype); - recvtype = le32_to_cpu(recvtype); - lbs_dev_dbg(1, &cardp->udev->dev, - "Receive type after = 0x%X\n", recvtype); - } else if (urb->status) - goto rx_exit; - - - switch (recvtype) { - case CMD_TYPE_DATA: - process_cmdtypedata(recvlength, skb, cardp, priv); - break; - - case CMD_TYPE_REQUEST: - process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); - break; - - case CMD_TYPE_INDICATION: - /* Event cause handling */ - spin_lock(&priv->adapter->driver_lock); - cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN); - lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n", - cardp->usb_event_cause); - if (cardp->usb_event_cause & 0xffff0000) { - libertas_send_tx_feedback(priv); - break; - } - cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3; - cardp->usb_int_cause |= his_cardevent; - kfree_skb(skb); - libertas_interrupt(priv->wlan_dev.netdev); - spin_unlock(&priv->adapter->driver_lock); - goto rx_exit; - default: - kfree_skb(skb); - break; - } - -setup_for_next: - if_usb_submit_rx_urb(priv); -rx_exit: - LEAVE(); - return; -} - -/** - * @brief This function downloads data to FW - * @param priv pointer to wlan_private structure - * @param type type of data - * @param buf pointer to data buffer - * @param len number of bytes - * @return 0 or -1 - */ -int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) -{ - int ret = -1; - u32 tmp; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; - - lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type); - lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb); - - if (type == MVMS_CMD) { - tmp = cpu_to_le32(CMD_TYPE_REQUEST); - priv->wlan_dev.dnld_sent = DNLD_CMD_SENT; - memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, - MESSAGE_HEADER_LEN); - - } else { - tmp = cpu_to_le32(CMD_TYPE_DATA); - priv->wlan_dev.dnld_sent = DNLD_DATA_SENT; - memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, - MESSAGE_HEADER_LEN); - } - - memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); - - ret = - usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); - - return ret; -} - -/* called with adapter->driver_lock held */ -int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - - *ireg = cardp->usb_int_cause; - cardp->usb_int_cause = 0; - - lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg); - - return 0; -} - -int libertas_sbi_read_event_cause(wlan_private * priv) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - priv->adapter->eventcause = cardp->usb_event_cause; - /* Re-submit rx urb here to avoid event lost issue */ - if_usb_submit_rx_urb(priv); - return 0; -} - -int reset_device(wlan_private *priv) -{ - int ret; - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, - cmd_act_halt, 0, 0, NULL); - msleep_interruptible(10); - - return ret; -} - -int libertas_sbi_unregister_dev(wlan_private * priv) -{ - int ret = 0; - - /* Need to send a Reset command to device before USB resources freed - * and wlan_remove_card() called, then device can handle FW download - * again. - */ - if (priv) - reset_device(priv); - - return ret; -} - - -/** - * @brief This function register usb device and initialize parameter - * @param priv pointer to wlan_private - * @return 0 or -1 - */ -int libertas_sbi_register_dev(wlan_private * priv) -{ - - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; - ENTER(); - - cardp->priv = priv; - cardp->eth_dev = priv->wlan_dev.netdev; - priv->hotplug_device = &(cardp->udev->dev); - - SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev)); - - lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n", - cardp->udev); - - LEAVE(); - return 0; -} - - - -int libertas_sbi_prog_firmware(wlan_private * priv) -{ - struct usb_card_rec *cardp = priv->wlan_dev.card; - int i = 0; - static int reset_count = 10; - - ENTER(); - - cardp->rinfo.priv = priv; - -restart: - if (if_usb_submit_rx_urb_fwload(priv) < 0) { - lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n"); - LEAVE(); - return -1; - } - -#ifdef SUPPORT_BOOT_COMMAND - cardp->bootcmdresp = 0; - do { - int j = 0; - i++; - /* Issue Boot command = 1, Boot from Download-FW */ - if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); - /* wait for command response */ - do { - j++; - msleep_interruptible(100); - } while (cardp->bootcmdresp == 0 && j < 10); - } while (cardp->bootcmdresp == 0 && i < 5); - - if (cardp->bootcmdresp == 0) { - if (--reset_count >= 0) { - libertas_do_reset(priv); - goto restart; - } - return -1; - } -#endif - - i = 0; - priv->adapter->fw_ready = 0; - - cardp->totalbytes = 0; - cardp->fwlastblksent = 0; - cardp->CRC_OK = 1; - cardp->fwdnldover = 0; - cardp->fwseqnum = -1; - cardp->totalbytes = 0; - cardp->fwfinalblk = 0; - - if_prog_firmware(priv); - - do { - lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n"); - i++; - msleep_interruptible(100); - if (priv->adapter->surpriseremoved || i >= 20) - break; - } while (!cardp->fwdnldover); - - if (!cardp->fwdnldover) { - lbs_pr_info("failed to load fw, resetting device!\n"); - if (--reset_count >= 0) { - libertas_do_reset(priv); - goto restart; - } - - lbs_pr_info("FW download failure, time = %d ms\n", i * 100); - LEAVE(); - return -1; - } - - if_usb_submit_rx_urb(priv); - - /* Delay 200 ms to waiting for the FW ready */ - msleep_interruptible(200); - - priv->adapter->fw_ready = 1; - - LEAVE(); - return 0; -} - -/** - * @brief Given a usb_card_rec return its wlan_private - * @param card pointer to a usb_card_rec - * @return pointer to wlan_private - */ -wlan_private *libertas_sbi_get_priv(void *card) -{ - struct usb_card_rec *cardp = card; - return cardp->priv; -} - -#ifdef ENABLE_PM -int libertas_sbi_suspend(wlan_private * priv) -{ - return 0; -} - -int libertas_sbi_resume(wlan_private * priv) -{ - return 0; -} -#endif - -#ifdef CONFIG_PM -static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_card_rec *cardp = usb_get_intfdata(intf); - wlan_private *priv = cardp->priv; - - ENTER(); - - if (priv->adapter->psstate != PS_STATE_FULL_POWER) - return -1; - - netif_device_detach(cardp->eth_dev); - - /* Unlink tx & rx urb */ - usb_kill_urb(cardp->tx_urb); - usb_kill_urb(cardp->rx_urb); - - cardp->rx_urb_recall = 1; - - LEAVE(); - return 0; -} - -static int if_usb_resume(struct usb_interface *intf) -{ - struct usb_card_rec *cardp = usb_get_intfdata(intf); - - ENTER(); - - cardp->rx_urb_recall = 0; - - if_usb_submit_rx_urb(cardp->priv); - - netif_device_attach(cardp->eth_dev); - - LEAVE(); - return 0; -} -#else -#define if_usb_suspend NULL -#define if_usb_resume NULL -#endif - -static struct usb_driver if_usb_driver = { - /* driver name */ - .name = usbdriver_name, - /* probe function name */ - .probe = if_usb_probe, - /* disconnect function name */ - .disconnect = if_usb_disconnect, - /* device signature table */ - .id_table = if_usb_table, - .suspend = if_usb_suspend, - .resume = if_usb_resume, -}; - -/** - * @brief This function registers driver. - * @param add pointer to add_card callback function - * @param remove pointer to remove card callback function - * @param arg pointer to call back function parameter - * @return dummy success variable - */ -int libertas_sbi_register(void) -{ - /* - * API registers the Marvell USB driver - * to the USB system - */ - usb_register(&if_usb_driver); - - /* Return success to wlan layer */ - return 0; -} - -/** - * @brief This function removes usb driver. - * @return N/A - */ -void libertas_sbi_unregister(void) -{ - /* API unregisters the driver from USB subsystem */ - usb_deregister(&if_usb_driver); - return; -} diff --git a/trunk/drivers/net/wireless/libertas/if_usb.h b/trunk/drivers/net/wireless/libertas/if_usb.h deleted file mode 100644 index 785116720bc6..000000000000 --- a/trunk/drivers/net/wireless/libertas/if_usb.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This file contains definition for USB interface. - */ -#define CMD_TYPE_REQUEST 0xF00DFACE -#define CMD_TYPE_DATA 0xBEADC0DE -#define CMD_TYPE_INDICATION 0xBEEFFACE - -#define IPFIELD_ALIGN_OFFSET 2 - -#define USB8388_VID_1 0x1286 -#define USB8388_PID_1 0x2001 -#define USB8388_VID_2 0x05a3 -#define USB8388_PID_2 0x8388 - -#ifdef SUPPORT_BOOT_COMMAND -#define BOOT_CMD_FW_BY_USB 0x01 -#define BOOT_CMD_FW_IN_EEPROM 0x02 -#define BOOT_CMD_UPDATE_BOOT2 0x03 -#define BOOT_CMD_UPDATE_FW 0x04 -#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */ - -struct bootcmdstr -{ - u32 u32magicnumber; - u8 u8cmd_tag; - u8 au8dumy[11]; -}; - -#define BOOT_CMD_RESP_OK 0x0001 -#define BOOT_CMD_RESP_FAIL 0x0000 - -struct bootcmdrespStr -{ - u32 u32magicnumber; - u8 u8cmd_tag; - u8 u8result; - u8 au8dumy[2]; -}; -#endif /* SUPPORT_BOOT_COMMAND */ - -/* read callback private data */ -struct read_cb_info { - wlan_private *priv; - struct sk_buff *skb; -}; - -/** USB card description structure*/ -struct usb_card_rec { - struct net_device *eth_dev; - struct usb_device *udev; - struct urb *rx_urb, *tx_urb; - void *priv; - struct read_cb_info rinfo; - - int bulk_in_size; - u8 bulk_in_endpointAddr; - - u8 *bulk_out_buffer; - int bulk_out_size; - u8 bulk_out_endpointAddr; - - u8 CRC_OK; - u32 fwseqnum; - u32 lastseqnum; - u32 totalbytes; - u32 fwlastblksent; - u8 fwdnldover; - u8 fwfinalblk; - - u32 usb_event_cause; - u8 usb_int_cause; - - u8 rx_urb_recall; - - u8 bootcmdresp; -}; - -/** fwheader */ -struct fwheader { - u32 dnldcmd; - u32 baseaddr; - u32 datalength; - u32 CRC; -}; - -#define FW_MAX_DATA_BLK_SIZE 600 -/** FWData */ -struct FWData { - struct fwheader fwheader; - u32 seqnum; - u8 data[FW_MAX_DATA_BLK_SIZE]; -}; - -/** fwsyncheader */ -struct fwsyncheader { - u32 cmd; - u32 seqnum; -}; - -#define FW_HAS_DATA_TO_RECV 0x00000001 -#define FW_HAS_LAST_BLOCK 0x00000004 - -#define FW_DATA_XMIT_SIZE \ - sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32) - -int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); -void if_usb_free(struct usb_card_rec *cardp); -int if_usb_issue_boot_command(wlan_private *priv, int ivalue); - diff --git a/trunk/drivers/net/wireless/libertas/ioctl.c b/trunk/drivers/net/wireless/libertas/ioctl.c deleted file mode 100644 index 82b39642423a..000000000000 --- a/trunk/drivers/net/wireless/libertas/ioctl.c +++ /dev/null @@ -1,2500 +0,0 @@ -/** - * This file contains ioctl functions - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include "host.h" -#include "radiotap.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "wext.h" - -#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ - IW_ESSID_MAX_SIZE + \ - IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ - IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ - IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ - -#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) - -static int setrxantenna(wlan_private * priv, int mode) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2 - && mode != RF_ANTENNA_AUTO) { - return -EINVAL; - } - - adapter->rxantennamode = mode; - - lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, - cmd_act_set_rx, - cmd_option_waitforrsp, 0, - &adapter->rxantennamode); - return ret; -} - -static int settxantenna(wlan_private * priv, int mode) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2) - && (mode != RF_ANTENNA_AUTO)) { - return -EINVAL; - } - - adapter->txantennamode = mode; - - lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, - cmd_act_set_tx, - cmd_option_waitforrsp, 0, - &adapter->txantennamode); - - return ret; -} - -static int getrxantenna(wlan_private * priv, char *buf) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - // clear it, so we will know if the value - // returned below is correct or not. - adapter->rxantennamode = 0; - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, - cmd_act_get_rx, - cmd_option_waitforrsp, 0, NULL); - - if (ret) { - LEAVE(); - return ret; - } - - lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode); - - return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1; -} - -static int gettxantenna(wlan_private * priv, char *buf) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - // clear it, so we will know if the value - // returned below is correct or not. - adapter->txantennamode = 0; - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, - cmd_act_get_tx, - cmd_option_waitforrsp, 0, NULL); - - if (ret) { - LEAVE(); - return ret; - } - - lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode); - - return sprintf(buf, "0x%04x", adapter->txantennamode) + 1; -} - -static int wlan_set_region(wlan_private * priv, u16 region_code) -{ - int i; - - for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { - // use the region code to search for the index - if (region_code == libertas_region_code_to_index[i]) { - priv->adapter->regiontableindex = (u16) i; - priv->adapter->regioncode = region_code; - break; - } - } - - // if it's unidentified region code - if (i >= MRVDRV_MAX_REGION_CODE) { - lbs_pr_debug(1, "region Code not identified\n"); - LEAVE(); - return -1; - } - - if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { - LEAVE(); - return -EINVAL; - } - - return 0; -} - -/** - * @brief Get/Set Firmware wakeup method - * - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to user data - * @return 0--success, otherwise fail - */ -static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) -{ - wlan_adapter *adapter = priv->adapter; - int data; - ENTER(); - - if ((int)wrq->u.data.length == 0) { - if (copy_to_user - (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) { - lbs_pr_alert("copy_to_user failed!\n"); - return -EFAULT; - } - } else { - if ((int)wrq->u.data.length > 1) { - lbs_pr_alert("ioctl too many args!\n"); - return -EFAULT; - } - if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_alert("Copy from user failed\n"); - return -EFAULT; - } - - adapter->pkttxctrl = (u32) data; - } - - wrq->u.data.length = 1; - - LEAVE(); - return 0; -} - -/** - * @brief Get/Set NULL Package generation interval - * - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to user data - * @return 0--success, otherwise fail - */ -static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) -{ - wlan_adapter *adapter = priv->adapter; - int data; - ENTER(); - - if ((int)wrq->u.data.length == 0) { - data = adapter->nullpktinterval; - - if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { - lbs_pr_alert( "copy_to_user failed!\n"); - return -EFAULT; - } - } else { - if ((int)wrq->u.data.length > 1) { - lbs_pr_alert( "ioctl too many args!\n"); - return -EFAULT; - } - if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - - adapter->nullpktinterval = data; - } - - wrq->u.data.length = 1; - - LEAVE(); - return 0; -} - -static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) -{ - wlan_adapter *adapter = priv->adapter; - int data[2]; - ENTER(); - data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; - data[1] = adapter->rxpd_rate; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - wrq->u.data.length = 2; - LEAVE(); - return 0; -} - -static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - int data[4]; - - ENTER(); - memset(data, 0, sizeof(data)); - if (wrq->u.data.length) { - if (copy_from_user(data, wrq->u.data.pointer, - min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) - return -EFAULT; - } - if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { - if (adapter->connect_status == libertas_connected) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, - cmd_option_waitforrsp, - 0, NULL); - - if (ret) { - LEAVE(); - return ret; - } - } - } - - if (wrq->u.data.length == 0) { - data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; - data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; - data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; - data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) - return -EFAULT; - wrq->u.data.length = 4; - } else if (data[0] == 0) { - data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) - return -EFAULT; - wrq->u.data.length = 1; - } else if (data[0] == 1) { - data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) - return -EFAULT; - wrq->u.data.length = 1; - } else if (data[0] == 2) { - data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) - return -EFAULT; - wrq->u.data.length = 1; - } else if (data[0] == 3) { - data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) - return -EFAULT; - wrq->u.data.length = 1; - } else - return -ENOTSUPP; - - LEAVE(); - return 0; -} - -static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) -{ - int data; - wlan_adapter *adapter = priv->adapter; - - if (wrq->u.data.length > 0) { - if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) - return -EFAULT; - - lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data); - if ((data > MRVDRV_MAX_BEACON_INTERVAL) - || (data < MRVDRV_MIN_BEACON_INTERVAL)) - return -ENOTSUPP; - adapter->beaconperiod = data; - } - data = adapter->beaconperiod; - if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) - return -EFAULT; - - wrq->u.data.length = 1; - - return 0; -} - -static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - int temp; - int data = 0; - int *val; - - ENTER(); - data = SUBCMD_DATA(wrq); - if ((data == 0) || (data == 1)) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, cmd_option_waitforrsp, - 0, NULL); - if (ret) { - LEAVE(); - return ret; - } - } - - switch (data) { - case 0: - - temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], - adapter->NF[TYPE_BEACON][TYPE_NOAVG]); - break; - case 1: - temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG], - adapter->NF[TYPE_BEACON][TYPE_AVG]); - break; - case 2: - temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], - adapter->NF[TYPE_RXPD][TYPE_NOAVG]); - break; - case 3: - temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - break; - default: - return -ENOTSUPP; - } - val = (int *)wrq->u.name; - *val = temp; - - LEAVE(); - return 0; -} - -static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - int temp; - int data = 0; - int *val; - - data = SUBCMD_DATA(wrq); - if ((data == 0) || (data == 1)) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, cmd_option_waitforrsp, - 0, NULL); - - if (ret) { - LEAVE(); - return ret; - } - } - - switch (data) { - case 0: - temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG]; - break; - case 1: - temp = adapter->NF[TYPE_BEACON][TYPE_AVG]; - break; - case 2: - temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG]; - break; - case 3: - temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; - break; - default: - return -ENOTSUPP; - } - - temp = CAL_NF(temp); - - lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp); - val = (int *)wrq->u.name; - *val = temp; - return 0; -} - -static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) -{ - wlan_adapter *adapter = priv->adapter; - int *pdata; - struct iwreq *wrq = (struct iwreq *)req; - int ret = 0; - adapter->txrate = 0; - lbs_pr_debug(1, "wlan_get_txrate_ioctl\n"); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query, - cmd_act_get, cmd_option_waitforrsp, - 0, NULL); - if (ret) - return ret; - - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->txrate; - return 0; -} - -static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - char status[64]; - wlan_adapter *adapter = priv->adapter; - - memset(status, 0, sizeof(status)); - - switch (adapter->inframode) { - case wlan802_11ibss: - if (adapter->connect_status == libertas_connected) { - if (adapter->adhoccreate) - memcpy(&status, "AdhocStarted", sizeof(status)); - else - memcpy(&status, "AdhocJoined", sizeof(status)); - } else { - memcpy(&status, "AdhocIdle", sizeof(status)); - } - break; - case wlan802_11infrastructure: - memcpy(&status, "Inframode", sizeof(status)); - break; - default: - memcpy(&status, "AutoUnknownmode", sizeof(status)); - break; - } - - lbs_pr_debug(1, "status = %s\n", status); - wrq->u.data.length = strlen(status) + 1; - - if (wrq->u.data.pointer) { - if (copy_to_user(wrq->u.data.pointer, - &status, wrq->u.data.length)) - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief Set/Get WPA IE - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - - if (wrq->u.data.length) { - if (wrq->u.data.length > sizeof(adapter->wpa_ie)) { - lbs_pr_debug(1, "failed to copy WPA IE, too big \n"); - return -EFAULT; - } - if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer, - wrq->u.data.length)) { - lbs_pr_debug(1, "failed to copy WPA IE \n"); - return -EFAULT; - } - adapter->wpa_ie_len = wrq->u.data.length; - lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len, - adapter->wpa_ie[0]); - lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len); - if (adapter->wpa_ie[0] == WPA_IE) - adapter->secinfo.WPAenabled = 1; - else if (adapter->wpa_ie[0] == WPA2_IE) - adapter->secinfo.WPA2enabled = 1; - else { - adapter->secinfo.WPAenabled = 0; - adapter->secinfo.WPA2enabled = 0; - } - } else { - memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie)); - adapter->wpa_ie_len = wrq->u.data.length; - lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n", - adapter->wpa_ie_len, adapter->wpa_ie[0]); - adapter->secinfo.WPAenabled = 0; - adapter->secinfo.WPA2enabled = 0; - } - - // enable/disable RSN in firmware if WPA is enabled/disabled - // depending on variable adapter->secinfo.WPAenabled is set or not - ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, - cmd_act_set, cmd_option_waitforrsp, - 0, NULL); - - LEAVE(); - return ret; -} - -/** - * @brief Set Auto prescan - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to iwreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - int data; - wlan_adapter *adapter = priv->adapter; - int *val; - - data = SUBCMD_DATA(wrq); - lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); - adapter->prescan = data; - - val = (int *)wrq->u.name; - *val = data; - return 0; -} - -static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - u32 mdtim; - int idata; - int ret = -EINVAL; - - ENTER(); - - idata = SUBCMD_DATA(wrq); - mdtim = (u32) idata; - if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) - && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) - || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { - priv->adapter->multipledtim = mdtim; - ret = 0; - } - if (ret) - lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n"); - - LEAVE(); - return ret; -} - -/** - * @brief Set authentication mode - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) -{ - int alg; - struct iwreq *wrq = (struct iwreq *)req; - wlan_adapter *adapter = priv->adapter; - - if (wrq->u.data.flags == 0) { - //from iwpriv subcmd - alg = SUBCMD_DATA(wrq); - } else { - //from wpa_supplicant subcmd - if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - } - - lbs_pr_debug(1, "auth alg is %#x\n", alg); - - switch (alg) { - case AUTH_ALG_SHARED_KEY: - adapter->secinfo.authmode = wlan802_11authmodeshared; - break; - case AUTH_ALG_NETWORK_EAP: - adapter->secinfo.authmode = - wlan802_11authmodenetworkEAP; - break; - case AUTH_ALG_OPEN_SYSTEM: - default: - adapter->secinfo.authmode = wlan802_11authmodeopen; - break; - } - return 0; -} - -/** - * @brief Set 802.1x authentication mode - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) -{ - int alg; - struct iwreq *wrq = (struct iwreq *)req; - - if (wrq->u.data.flags == 0) { - //from iwpriv subcmd - alg = SUBCMD_DATA(wrq); - } else { - //from wpa_supplicant subcmd - if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - } - lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg); - priv->adapter->secinfo.auth1xalg = alg; - return 0; -} - -static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) -{ - int mode; - struct iwreq *wrq = (struct iwreq *)req; - - ENTER(); - - if (wrq->u.data.flags == 0) { - //from iwpriv subcmd - mode = SUBCMD_DATA(wrq); - } else { - //from wpa_supplicant subcmd - if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - } - lbs_pr_debug(1, "encryption mode is %#x\n", mode); - priv->adapter->secinfo.Encryptionmode = mode; - - LEAVE(); - return 0; -} - -static void adjust_mtu(wlan_private * priv) -{ - int mtu_increment = 0; - - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) - mtu_increment += sizeof(struct ieee80211_hdr_4addr); - - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) - mtu_increment += max(sizeof(struct tx_radiotap_hdr), - sizeof(struct rx_radiotap_hdr)); - priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN - - sizeof(struct ethhdr) - + mtu_increment; -} - -/** - * @brief Set Link-Layer Layer mode - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) -{ - int mode; - - mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; - - switch (mode) { - case WLAN_LINKMODE_802_3: - priv->adapter->linkmode = mode; - break; - case WLAN_LINKMODE_802_11: - priv->adapter->linkmode = mode; - break; - default: - lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n", - mode); - return -EINVAL; - break; - } - lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode); - - adjust_mtu(priv); - - return 0; -} - -/** - * @brief Set Radio header mode - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) -{ - int mode; - - mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; - - switch (mode) { - case WLAN_RADIOMODE_NONE: - priv->adapter->radiomode = mode; - break; - case WLAN_RADIOMODE_RADIOTAP: - priv->adapter->radiomode = mode; - break; - default: - lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n", - mode); - return -EINVAL; - } - lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode); - - adjust_mtu(priv); - return 0; -} - -/** - * @brief Set Debug header mode - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) -{ - priv->adapter->debugmode = (int)((struct ifreq *) - ((u8 *) req + 4))->ifr_data; - return 0; -} - -static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, - struct ifreq *req) -{ - int len; - char buf[8]; - struct iwreq *wrq = (struct iwreq *)req; - - lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n"); - len = getrxantenna(priv, buf); - - wrq->u.data.length = len; - if (wrq->u.data.pointer) { - if (copy_to_user(wrq->u.data.pointer, &buf, len)) { - lbs_pr_debug(1, "CopyToUser failed\n"); - return -EFAULT; - } - } - - return 0; -} - -static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, - struct ifreq *req) -{ - int len; - char buf[8]; - struct iwreq *wrq = (struct iwreq *)req; - - lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n"); - len = gettxantenna(priv, buf); - - wrq->u.data.length = len; - if (wrq->u.data.pointer) { - if (copy_to_user(wrq->u.data.pointer, &buf, len)) { - lbs_pr_debug(1, "CopyToUser failed\n"); - return -EFAULT; - } - } - return 0; -} - -/** - * @brief Get the MAC TSF value from the firmware - * - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to iwreq structure containing buffer - * space to store a TSF value retrieved from the firmware - * - * @return 0 if successful; IOCTL error code otherwise - */ -static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - u64 tsfval; - int ret; - - ret = libertas_prepare_and_send_command(priv, - cmd_get_tsf, - 0, cmd_option_waitforrsp, 0, &tsfval); - - lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval); - - if (ret != 0) { - lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n"); - ret = -EFAULT; - } else { - if (copy_to_user(wrq->u.data.pointer, - &tsfval, - min_t(size_t, wrq->u.data.length, - sizeof(tsfval))) != 0) { - - lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n"); - ret = -EFAULT; - } else { - ret = 0; - } - } - return ret; -} - -/** - * @brief Get/Set adapt rate - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to iwreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) -{ - int ret; - wlan_adapter *adapter = priv->adapter; - int data[2]; - - memset(data, 0, sizeof(data)); - if (!wrq->u.data.length) { - lbs_pr_debug(1, "Get ADAPT RATE SET\n"); - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rate_adapt_rateset, - cmd_act_get, - cmd_option_waitforrsp, 0, NULL); - data[0] = adapter->enablehwauto; - data[1] = adapter->ratebitmap; - if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } -#define GET_TWO_INT 2 - wrq->u.data.length = GET_TWO_INT; - } else { - lbs_pr_debug(1, "Set ADAPT RATE SET\n"); - if (wrq->u.data.length > 2) - return -EINVAL; - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * wrq->u.data.length)) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - - adapter->enablehwauto = data[0]; - adapter->ratebitmap = data[1]; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rate_adapt_rateset, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - } - return ret; -} - -/** - * @brief Get/Set inactivity timeout - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to iwreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) -{ - int ret; - int data = 0; - u16 timeout = 0; - - ENTER(); - if (wrq->u.data.length > 1) - return -ENOTSUPP; - - if (wrq->u.data.length == 0) { - /* Get */ - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_inactivity_timeout, - cmd_act_get, - cmd_option_waitforrsp, 0, - &timeout); - data = timeout; - if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - } else { - /* Set */ - if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - - timeout = data; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_inactivity_timeout, - cmd_act_set, - cmd_option_waitforrsp, 0, - &timeout); - } - - wrq->u.data.length = 1; - - LEAVE(); - return ret; -} - -static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - int ret; - char buf[GETLOG_BUFSIZE - 1]; - wlan_adapter *adapter = priv->adapter; - - lbs_pr_debug(1, " GET STATS\n"); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log, - 0, cmd_option_waitforrsp, 0, NULL); - - if (ret) { - return ret; - } - - if (wrq->u.data.pointer) { - sprintf(buf, "\n mcasttxframe %u failed %u retry %u " - "multiretry %u framedup %u " - "rtssuccess %u rtsfailure %u ackfailure %u\n" - "rxfrag %u mcastrxframe %u fcserror %u " - "txframe %u wepundecryptable %u ", - adapter->logmsg.mcasttxframe, - adapter->logmsg.failed, - adapter->logmsg.retry, - adapter->logmsg.multiretry, - adapter->logmsg.framedup, - adapter->logmsg.rtssuccess, - adapter->logmsg.rtsfailure, - adapter->logmsg.ackfailure, - adapter->logmsg.rxfrag, - adapter->logmsg.mcastrxframe, - adapter->logmsg.fcserror, - adapter->logmsg.txframe, - adapter->logmsg.wepundecryptable); - wrq->u.data.length = strlen(buf) + 1; - if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - } - - return 0; -} - -static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - u8 buf[12]; - u8 *option[] = { "active", "passive", "get", }; - int i, max_options = (sizeof(option) / sizeof(option[0])); - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - if (priv->adapter->enable11d) { - lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n"); - return -EFAULT; - } - - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), - wrq->u.data.length))) - return -EFAULT; - - lbs_pr_debug(1, "Scan type Option = %s\n", buf); - - buf[sizeof(buf) - 1] = '\0'; - - for (i = 0; i < max_options; i++) { - if (!strcmp(buf, option[i])) - break; - } - - switch (i) { - case 0: - adapter->scantype = cmd_scan_type_active; - break; - case 1: - adapter->scantype = cmd_scan_type_passive; - break; - case 2: - wrq->u.data.length = strlen(option[adapter->scantype]) + 1; - - if (copy_to_user(wrq->u.data.pointer, - option[adapter->scantype], - wrq->u.data.length)) { - lbs_pr_debug(1, "Copy to user failed\n"); - ret = -EFAULT; - } - - break; - default: - lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n"); - ret = -EINVAL; - break; - } - - return ret; -} - -static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - wlan_adapter *adapter = priv->adapter; - u8 buf[12]; - u8 *option[] = { "bss", "ibss", "any", "get" }; - int i, max_options = (sizeof(option) / sizeof(option[0])); - int ret = 0; - - ENTER(); - - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), - wrq->u.data.length))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - - lbs_pr_debug(1, "Scan mode Option = %s\n", buf); - - buf[sizeof(buf) - 1] = '\0'; - - for (i = 0; i < max_options; i++) { - if (!strcmp(buf, option[i])) - break; - } - - switch (i) { - - case 0: - adapter->scanmode = cmd_bss_type_bss; - break; - case 1: - adapter->scanmode = cmd_bss_type_ibss; - break; - case 2: - adapter->scanmode = cmd_bss_type_any; - break; - case 3: - - wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1; - - lbs_pr_debug(1, "Get Scan mode Option = %s\n", - option[adapter->scanmode - 1]); - - lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length); - - if (copy_to_user(wrq->u.data.pointer, - option[adapter->scanmode - 1], - wrq->u.data.length)) { - lbs_pr_debug(1, "Copy to user failed\n"); - ret = -EFAULT; - } - lbs_pr_debug(1, "GET Scan type Option after copy = %s\n", - (char *)wrq->u.data.pointer); - - break; - - default: - lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n"); - ret = -EINVAL; - break; - } - - LEAVE(); - return ret; -} - -/** - * @brief Get/Set Adhoc G Rate - * - * @param priv A pointer to wlan_private structure - * @param wrq A pointer to user data - * @return 0--success, otherwise fail - */ -static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) -{ - wlan_adapter *adapter = priv->adapter; - int data, data1; - int *val; - - ENTER(); - - data1 = SUBCMD_DATA(wrq); - switch (data1) { - case 0: - adapter->adhoc_grate_enabled = 0; - break; - case 1: - adapter->adhoc_grate_enabled = 1; - break; - case 2: - break; - default: - return -EINVAL; - } - data = adapter->adhoc_grate_enabled; - val = (int *)wrq->u.name; - *val = data; - LEAVE(); - return 0; -} - -static inline int hex2int(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - if (c >= 'A' && c <= 'F') - return (c - 'A' + 10); - return -1; -} - -/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") - into binary format (6 bytes). - - This function expects that each byte is represented with 2 characters - (e.g., 11:2:11:11:11:11 is invalid) - - */ -static char *eth_str2addr(char *ethstr, u8 * addr) -{ - int i, val, val2; - char *pos = ethstr; - - /* get rid of initial blanks */ - while (*pos == ' ' || *pos == '\t') - ++pos; - - for (i = 0; i < 6; i++) { - val = hex2int(*pos++); - if (val < 0) - return NULL; - val2 = hex2int(*pos++); - if (val2 < 0) - return NULL; - addr[i] = (val * 16 + val2) & 0xff; - - if (i < 5 && *pos++ != ':') - return NULL; - } - return pos; -} - -/* this writes xx:xx:xx:xx:xx:xx into ethstr - (ethstr must have space for 18 chars) */ -static int eth_addr2str(u8 * addr, char *ethstr) -{ - int i; - char *pos = ethstr; - - for (i = 0; i < 6; i++) { - sprintf(pos, "%02x", addr[i] & 0xff); - pos += 2; - if (i < 5) - *pos++ = ':'; - } - return 17; -} - -/** - * @brief Add an entry to the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char ethaddrs_str[18]; - char *pos; - u8 ethaddr[ETH_ALEN]; - - ENTER(); - if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, - sizeof(ethaddrs_str))) - return -EFAULT; - - if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { - lbs_pr_info("BT_ADD: Invalid MAC address\n"); - return -EINVAL; - } - - lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str); - LEAVE(); - return (libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_add, - cmd_option_waitforrsp, 0, ethaddr)); -} - -/** - * @brief Delete an entry from the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char ethaddrs_str[18]; - u8 ethaddr[ETH_ALEN]; - char *pos; - - ENTER(); - if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, - sizeof(ethaddrs_str))) - return -EFAULT; - - if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { - lbs_pr_info("Invalid MAC address\n"); - return -EINVAL; - } - - lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str); - - return (libertas_prepare_and_send_command(priv, - cmd_bt_access, - cmd_act_bt_access_del, - cmd_option_waitforrsp, 0, ethaddr)); - LEAVE(); - return 0; -} - -/** - * @brief Reset all entries from the BT table - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_reset_ioctl(wlan_private * priv) -{ - ENTER(); - - lbs_pr_alert( "BT: resetting\n"); - - return (libertas_prepare_and_send_command(priv, - cmd_bt_access, - cmd_act_bt_access_reset, - cmd_option_waitforrsp, 0, NULL)); - - LEAVE(); - return 0; -} - -/** - * @brief List an entry from the BT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) -{ - int pos; - char *addr1; - struct iwreq *wrq = (struct iwreq *)req; - /* used to pass id and store the bt entry returned by the FW */ - union { - int id; - char addr1addr2[2 * ETH_ALEN]; - } param; - static char outstr[64]; - char *pbuf = outstr; - int ret; - - ENTER(); - - if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -1; - } - param.id = simple_strtoul(outstr, NULL, 10); - pos = sprintf(pbuf, "%d: ", param.id); - pbuf += pos; - - ret = libertas_prepare_and_send_command(priv, cmd_bt_access, - cmd_act_bt_access_list, - cmd_option_waitforrsp, 0, - (char *)¶m); - - if (ret == 0) { - addr1 = param.addr1addr2; - - pos = sprintf(pbuf, "ignoring traffic from "); - pbuf += pos; - pos = eth_addr2str(addr1, pbuf); - pbuf += pos; - } else { - sprintf(pbuf, "(null)"); - pbuf += pos; - } - - wrq->u.data.length = strlen(outstr); - if (copy_to_user(wrq->u.data.pointer, (char *)outstr, - wrq->u.data.length)) { - lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n"); - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief Find the next parameter in an input string - * @param ptr A pointer to the input parameter string - * @return A pointer to the next parameter, or 0 if no parameters left. - */ -static char * next_param(char * ptr) -{ - if (!ptr) return NULL; - while (*ptr == ' ' || *ptr == '\t') ++ptr; - return (*ptr == '\0') ? NULL : ptr; -} - -/** - * @brief Add an entry to the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[128]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); - return -EINVAL; - } - - if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { - lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); - return -EINVAL; - } - - if ((ptr = next_param(ptr))) - fwt_access.metric = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.metric = FWT_DEFAULT_METRIC; - - if ((ptr = next_param(ptr))) - fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.dir = FWT_DEFAULT_DIR; - - if ((ptr = next_param(ptr))) - fwt_access.ssn = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.ssn = FWT_DEFAULT_SSN; - - if ((ptr = next_param(ptr))) - fwt_access.dsn = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.dsn = FWT_DEFAULT_DSN; - - if ((ptr = next_param(ptr))) - fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); - else - fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; - - if ((ptr = next_param(ptr))) - fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); - else - fwt_access.ttl = FWT_DEFAULT_TTL; - - if ((ptr = next_param(ptr))) - fwt_access.expiration = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.expiration = FWT_DEFAULT_EXPIRATION; - - if ((ptr = next_param(ptr))) - fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; - - if ((ptr = next_param(ptr))) - fwt_access.snr = - cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - else - fwt_access.snr = FWT_DEFAULT_SNR; - -#ifdef DEBUG - { - char ethaddr1_str[18], ethaddr2_str[18]; - eth_addr2str(fwt_access.da, ethaddr1_str); - eth_addr2str(fwt_access.ra, ethaddr2_str); - lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, - fwt_access.dir, ethaddr2_str); - lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", - fwt_access.ssn, fwt_access.dsn, fwt_access.metric, - fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, - fwt_access.sleepmode, fwt_access.snr); - } -#endif - - LEAVE(); - return (libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_add, - cmd_option_waitforrsp, 0, - (void *)&fwt_access)); -} - -/** - * @brief Delete an entry from the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); - return -EINVAL; - } - - if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { - lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); - return -EINVAL; - } - - if ((ptr = next_param(ptr))) - fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); - else - fwt_access.dir = FWT_DEFAULT_DIR; - -#ifdef DEBUG - { - char ethaddr1_str[18], ethaddr2_str[18]; - lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str); - eth_addr2str(fwt_access.da, ethaddr1_str); - eth_addr2str(fwt_access.ra, ethaddr2_str); - lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, - ethaddr2_str, fwt_access.dir); - } -#endif - - LEAVE(); - return (libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_del, - cmd_option_waitforrsp, 0, - (void *)&fwt_access)); -} - - -/** - * @brief Print route parameters - * @param fwt_access struct cmd_ds_fwt_access with route info - * @param buf destination buffer for route info - */ -static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) -{ - buf += sprintf(buf, " "); - buf += eth_addr2str(fwt_access.da, buf); - buf += sprintf(buf, " "); - buf += eth_addr2str(fwt_access.ra, buf); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); - buf += sprintf(buf, " %u", fwt_access.dir); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); - buf += sprintf(buf, " %u", fwt_access.hopcount); - buf += sprintf(buf, " %u", fwt_access.ttl); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); - buf += sprintf(buf, " %u", fwt_access.sleepmode); - buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr)); -} - -/** - * @brief Lookup an entry in the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - char *ptr; - static struct cmd_ds_fwt_access fwt_access; - static char out_str[128]; - int ret; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { - lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); - return -EINVAL; - } - -#ifdef DEBUG - { - char ethaddr1_str[18]; - lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str); - eth_addr2str(fwt_access.da, ethaddr1_str); - lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); - } -#endif - - ret = libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_lookup, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - print_route(fwt_access, out_str); - else - sprintf(out_str, "(null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n"); - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief Reset all entries from the FWT table - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_reset_ioctl(wlan_private * priv) -{ - lbs_pr_debug(1, "FWT: resetting\n"); - - return (libertas_prepare_and_send_command(priv, - cmd_fwt_access, - cmd_act_fwt_access_reset, - cmd_option_waitforrsp, 0, NULL)); -} - -/** - * @brief List an entry from the FWT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[8]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str); - lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list, - cmd_option_waitforrsp, 0, (void *)&fwt_access); - - if (ret == 0) - print_route(fwt_access, pbuf); - else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n"); - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief List an entry from the FRT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[64]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str); - lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list_route, - cmd_option_waitforrsp, 0, (void *)&fwt_access); - - if (ret == 0) { - pbuf += sprintf(pbuf, " "); - pbuf += eth_addr2str(fwt_access.da, pbuf); - pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric)); - pbuf += sprintf(pbuf, " %u", fwt_access.dir); - /* note that the firmware returns the nid in the id field */ - pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id)); - pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn)); - pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn)); - pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount); - pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl); - pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration)); - } else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n"); - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief List an entry from the FNT table - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct iwreq *wrq = (struct iwreq *)req; - char in_str[8]; - static struct cmd_ds_fwt_access fwt_access; - char *ptr = in_str; - static char out_str[128]; - char *pbuf = out_str; - int ret; - - ENTER(); - if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) - return -EFAULT; - - memset(&fwt_access, 0, sizeof(fwt_access)); - fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); - -#ifdef DEBUG - { - lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str); - lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); - } -#endif - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_list_neighbor, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) { - pbuf += sprintf(pbuf, " ra "); - pbuf += eth_addr2str(fwt_access.ra, pbuf); - pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); - pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); - pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); - } else - pbuf += sprintf(pbuf, " (null)"); - - wrq->u.data.length = strlen(out_str); - if (copy_to_user(wrq->u.data.pointer, (char *)out_str, - wrq->u.data.length)) { - lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n"); - return -EFAULT; - } - - LEAVE(); - return 0; -} - -/** - * @brief Cleans up the route (FRT) and neighbor (FNT) tables - * (Garbage Collection) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) -{ - static struct cmd_ds_fwt_access fwt_access; - int ret; - - ENTER(); - - lbs_pr_debug(1, "FWT: cleaning up\n"); - - memset(&fwt_access, 0, sizeof(fwt_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_cleanup, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); - else - return -EFAULT; - - LEAVE(); - return 0; -} - -/** - * @brief Gets firmware internal time (debug purposes) - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) -{ - static struct cmd_ds_fwt_access fwt_access; - int ret; - - ENTER(); - - lbs_pr_debug(1, "FWT: getting time\n"); - - memset(&fwt_access, 0, sizeof(fwt_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, - cmd_act_fwt_access_time, - cmd_option_waitforrsp, 0, - (void *)&fwt_access); - - if (ret == 0) - req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); - else - return -EFAULT; - - LEAVE(); - return 0; -} - -/** - * @brief Gets mesh ttl from firmware - * @param priv A pointer to wlan_private structure - * @param req A pointer to ifreq structure - * @return 0 --success, otherwise fail - */ -static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) -{ - struct cmd_ds_mesh_access mesh_access; - int ret; - - ENTER(); - - memset(&mesh_access, 0, sizeof(mesh_access)); - - ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, - cmd_act_mesh_get_ttl, - cmd_option_waitforrsp, 0, - (void *)&mesh_access); - - if (ret == 0) { - req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0])); - } - else - return -EFAULT; - - LEAVE(); - return 0; -} - -/** - * @brief Gets mesh ttl from firmware - * @param priv A pointer to wlan_private structure - * @param ttl New ttl value - * @return 0 --success, otherwise fail - */ -static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) -{ - struct cmd_ds_mesh_access mesh_access; - int ret; - - ENTER(); - - if( (ttl > 0xff) || (ttl < 0) ) - return -EINVAL; - - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = ttl; - - ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, - cmd_act_mesh_set_ttl, - cmd_option_waitforrsp, 0, - (void *)&mesh_access); - - if (ret != 0) - ret = -EFAULT; - - LEAVE(); - return ret; -} - -/** - * @brief ioctl function - entry point - * - * @param dev A pointer to net_device structure - * @param req A pointer to ifreq structure - * @param cmd command - * @return 0--success, otherwise fail - */ -int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - int subcmd = 0; - int idata = 0; - int *pdata; - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct iwreq *wrq = (struct iwreq *)req; - - ENTER(); - - lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); - switch (cmd) { - case WLANSCAN_TYPE: - lbs_pr_debug(1, "Scan type Ioctl\n"); - ret = wlan_scan_type_ioctl(priv, wrq); - break; - - case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ - switch (wrq->u.data.flags) { - case WLANDEAUTH: - lbs_pr_debug(1, "Deauth\n"); - libertas_send_deauth(priv); - break; - - case WLANADHOCSTOP: - lbs_pr_debug(1, "Adhoc stop\n"); - ret = libertas_do_adhocstop_ioctl(priv); - break; - - case WLANRADIOON: - wlan_radio_ioctl(priv, 1); - break; - - case WLANRADIOOFF: - wlan_radio_ioctl(priv, 0); - break; - case WLANWLANIDLEON: - libertas_idle_on(priv); - break; - case WLANWLANIDLEOFF: - libertas_idle_off(priv); - break; - case WLAN_SUBCMD_BT_RESET: /* bt_reset */ - wlan_bt_reset_ioctl(priv); - break; - case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ - wlan_fwt_reset_ioctl(priv); - break; - } /* End of switch */ - break; - - case WLANSETWPAIE: - ret = wlan_setwpaie_ioctl(priv, req); - break; - case WLAN_SETINT_GETINT: - /* The first 4 bytes of req->ifr_data is sub-ioctl number - * after 4 bytes sits the payload. - */ - subcmd = (int)req->ifr_data; //from iwpriv subcmd - switch (subcmd) { - case WLANNF: - ret = wlan_get_nf(priv, wrq); - break; - case WLANRSSI: - ret = wlan_get_rssi(priv, wrq); - break; - case WLANENABLE11D: - ret = libertas_cmd_enable_11d(priv, wrq); - break; - case WLANADHOCGRATE: - ret = wlan_do_set_grate_ioctl(priv, wrq); - break; - case WLAN_SUBCMD_SET_PRESCAN: - ret = wlan_subcmd_setprescan_ioctl(priv, wrq); - break; - } - break; - - case WLAN_SETONEINT_GETONEINT: - switch (wrq->u.data.flags) { - case WLAN_BEACON_INTERVAL: - ret = wlan_beacon_interval(priv, wrq); - break; - - case WLAN_LISTENINTRVL: - if (!wrq->u.data.length) { - int data; - lbs_pr_debug(1, "Get locallisteninterval value\n"); -#define GET_ONE_INT 1 - data = adapter->locallisteninterval; - if (copy_to_user(wrq->u.data.pointer, - &data, sizeof(int))) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = GET_ONE_INT; - } else { - int data; - if (copy_from_user - (&data, wrq->u.data.pointer, sizeof(int))) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - - lbs_pr_debug(1, "Set locallisteninterval = %d\n", - data); -#define MAX_U16_VAL 65535 - if (data > MAX_U16_VAL) { - lbs_pr_debug(1, "Exceeds U16 value\n"); - return -EINVAL; - } - adapter->locallisteninterval = data; - } - break; - case WLAN_TXCONTROL: - ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl - break; - - case WLAN_NULLPKTINTERVAL: - ret = wlan_null_pkt_interval(priv, wrq); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - break; - - case WLAN_SETONEINT_GETNONE: - /* The first 4 bytes of req->ifr_data is sub-ioctl number - * after 4 bytes sits the payload. - */ - subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd - - if (!subcmd) - subcmd = (int)req->ifr_data; //from iwpriv subcmd - - switch (subcmd) { - case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ - idata = SUBCMD_DATA(wrq); - ret = setrxantenna(priv, idata); - break; - case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ - idata = SUBCMD_DATA(wrq); - ret = settxantenna(priv, idata); - break; - case WLAN_SET_ATIM_WINDOW: - adapter->atimwindow = SUBCMD_DATA(wrq); - adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50); - break; - case WLANSETBCNAVG: - adapter->bcn_avg_factor = SUBCMD_DATA(wrq); - if (adapter->bcn_avg_factor == 0) - adapter->bcn_avg_factor = - DEFAULT_BCN_AVG_FACTOR; - if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) - adapter->bcn_avg_factor = - DEFAULT_BCN_AVG_FACTOR; - break; - case WLANSETDATAAVG: - adapter->data_avg_factor = SUBCMD_DATA(wrq); - if (adapter->data_avg_factor == 0) - adapter->data_avg_factor = - DEFAULT_DATA_AVG_FACTOR; - if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) - adapter->data_avg_factor = - DEFAULT_DATA_AVG_FACTOR; - break; - case WLANSETREGION: - idata = SUBCMD_DATA(wrq); - ret = wlan_set_region(priv, (u16) idata); - break; - - case WLAN_SET_LISTEN_INTERVAL: - idata = SUBCMD_DATA(wrq); - adapter->listeninterval = (u16) idata; - break; - - case WLAN_SET_MULTIPLE_DTIM: - ret = wlan_set_multiple_dtim_ioctl(priv, req); - break; - - case WLANSETAUTHALG: - ret = wlan_setauthalg_ioctl(priv, req); - break; - - case WLANSET8021XAUTHALG: - ret = wlan_set8021xauthalg_ioctl(priv, req); - break; - - case WLANSETENCRYPTIONMODE: - ret = wlan_setencryptionmode_ioctl(priv, req); - break; - - case WLAN_SET_LINKMODE: - ret = wlan_set_linkmode_ioctl(priv, req); - break; - - case WLAN_SET_RADIOMODE: - ret = wlan_set_radiomode_ioctl(priv, req); - break; - - case WLAN_SET_DEBUGMODE: - ret = wlan_set_debugmode_ioctl(priv, req); - break; - - case WLAN_SUBCMD_MESH_SET_TTL: - idata = SUBCMD_DATA(wrq); - ret = wlan_mesh_set_ttl_ioctl(priv, idata); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - break; - - case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ - /* - * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is - * in flags of iwreq structure, otherwise it will be in - * mode member of iwreq structure. - */ - switch ((int)wrq->u.data.flags) { - case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ - ret = wlan_subcmd_getrxantenna_ioctl(priv, req); - break; - - case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ - ret = wlan_subcmd_gettxantenna_ioctl(priv, req); - break; - - case WLAN_GET_TSF: - ret = wlan_get_tsf_ioctl(priv, wrq); - break; - } - break; - - case WLAN_SET128CHAR_GET128CHAR: - switch ((int)wrq->u.data.flags) { - - case WLANSCAN_MODE: - lbs_pr_debug(1, "Scan mode Ioctl\n"); - ret = wlan_scan_mode_ioctl(priv, wrq); - break; - - case WLAN_GET_ADHOC_STATUS: - ret = wlan_get_adhoc_status_ioctl(priv, wrq); - break; - case WLAN_SUBCMD_BT_ADD: - ret = wlan_bt_add_ioctl(priv, req); - break; - case WLAN_SUBCMD_BT_DEL: - ret = wlan_bt_del_ioctl(priv, req); - break; - case WLAN_SUBCMD_BT_LIST: - ret = wlan_bt_list_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_ADD: - ret = wlan_fwt_add_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_DEL: - ret = wlan_fwt_del_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LOOKUP: - ret = wlan_fwt_lookup_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: - ret = wlan_fwt_list_neighbor_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST: - ret = wlan_fwt_list_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_LIST_ROUTE: - ret = wlan_fwt_list_route_ioctl(priv, req); - break; - } - break; - - case WLAN_SETNONE_GETONEINT: - switch ((int)req->ifr_data) { - case WLANGETBCNAVG: - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->bcn_avg_factor; - break; - - case WLANGETREGION: - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->regioncode; - break; - - case WLAN_GET_LISTEN_INTERVAL: - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->listeninterval; - break; - - case WLAN_GET_LINKMODE: - req->ifr_data = (char *)((u32) adapter->linkmode); - break; - - case WLAN_GET_RADIOMODE: - req->ifr_data = (char *)((u32) adapter->radiomode); - break; - - case WLAN_GET_DEBUGMODE: - req->ifr_data = (char *)((u32) adapter->debugmode); - break; - - case WLAN_GET_MULTIPLE_DTIM: - pdata = (int *)wrq->u.name; - *pdata = (int)adapter->multipledtim; - break; - case WLAN_GET_TX_RATE: - ret = wlan_get_txrate_ioctl(priv, req); - break; - case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ - ret = wlan_fwt_cleanup_ioctl(priv, req); - break; - - case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ - ret = wlan_fwt_time_ioctl(priv, req); - break; - - case WLAN_SUBCMD_MESH_GET_TTL: - ret = wlan_mesh_get_ttl_ioctl(priv, req); - break; - - default: - ret = -EOPNOTSUPP; - - } - - break; - - case WLANGETLOG: - ret = wlan_do_getlog_ioctl(priv, wrq); - break; - - case WLAN_SET_GET_SIXTEEN_INT: - switch ((int)wrq->u.data.flags) { - case WLAN_TPCCFG: - { - int data[5]; - struct cmd_ds_802_11_tpc_cfg cfg; - memset(&cfg, 0, sizeof(cfg)); - if ((wrq->u.data.length > 1) - && (wrq->u.data.length != 5)) - return -1; - - if (wrq->u.data.length == 0) { - cfg.action = - cpu_to_le16 - (cmd_act_get); - } else { - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * 5)) { - lbs_pr_debug(1, - "Copy from user failed\n"); - return -EFAULT; - } - - cfg.action = - cpu_to_le16 - (cmd_act_set); - cfg.enable = data[0]; - cfg.usesnr = data[1]; - cfg.P0 = data[2]; - cfg.P1 = data[3]; - cfg.P2 = data[4]; - } - - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_tpc_cfg, - 0, - cmd_option_waitforrsp, - 0, (void *)&cfg); - - data[0] = cfg.enable; - data[1] = cfg.usesnr; - data[2] = cfg.P0; - data[3] = cfg.P1; - data[4] = cfg.P2; - if (copy_to_user - (wrq->u.data.pointer, data, - sizeof(int) * 5)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = 5; - } - break; - - case WLAN_POWERCFG: - { - int data[4]; - struct cmd_ds_802_11_pwr_cfg cfg; - memset(&cfg, 0, sizeof(cfg)); - if ((wrq->u.data.length > 1) - && (wrq->u.data.length != 4)) - return -1; - if (wrq->u.data.length == 0) { - cfg.action = - cpu_to_le16 - (cmd_act_get); - } else { - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * 4)) { - lbs_pr_debug(1, - "Copy from user failed\n"); - return -EFAULT; - } - - cfg.action = - cpu_to_le16 - (cmd_act_set); - cfg.enable = data[0]; - cfg.PA_P0 = data[1]; - cfg.PA_P1 = data[2]; - cfg.PA_P2 = data[3]; - } - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_pwr_cfg, - 0, - cmd_option_waitforrsp, - 0, (void *)&cfg); - data[0] = cfg.enable; - data[1] = cfg.PA_P0; - data[2] = cfg.PA_P1; - data[3] = cfg.PA_P2; - if (copy_to_user - (wrq->u.data.pointer, data, - sizeof(int) * 4)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = 4; - } - break; - case WLAN_AUTO_FREQ_SET: - { - int data[3]; - struct cmd_ds_802_11_afc afc; - memset(&afc, 0, sizeof(afc)); - if (wrq->u.data.length != 3) - return -1; - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * 3)) { - lbs_pr_debug(1, "Copy from user failed\n"); - return -EFAULT; - } - afc.afc_auto = data[0]; - - if (afc.afc_auto != 0) { - afc.threshold = data[1]; - afc.period = data[2]; - } else { - afc.timing_offset = data[1]; - afc.carrier_offset = data[2]; - } - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_set_afc, - 0, - cmd_option_waitforrsp, - 0, (void *)&afc); - } - break; - case WLAN_AUTO_FREQ_GET: - { - int data[3]; - struct cmd_ds_802_11_afc afc; - memset(&afc, 0, sizeof(afc)); - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_get_afc, - 0, - cmd_option_waitforrsp, - 0, (void *)&afc); - data[0] = afc.afc_auto; - data[1] = afc.timing_offset; - data[2] = afc.carrier_offset; - if (copy_to_user - (wrq->u.data.pointer, data, - sizeof(int) * 3)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = 3; - } - break; - case WLAN_SCANPROBES: - { - int data; - if (wrq->u.data.length > 0) { - if (copy_from_user - (&data, wrq->u.data.pointer, - sizeof(int))) { - lbs_pr_debug(1, - "Copy from user failed\n"); - return -EFAULT; - } - - adapter->scanprobes = data; - } else { - data = adapter->scanprobes; - if (copy_to_user - (wrq->u.data.pointer, &data, - sizeof(int))) { - lbs_pr_debug(1, - "Copy to user failed\n"); - return -EFAULT; - } - } - wrq->u.data.length = 1; - } - break; - case WLAN_LED_GPIO_CTRL: - { - int i; - int data[16]; - - struct cmd_ds_802_11_led_ctrl ctrl; - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio *) ctrl.data; - - memset(&ctrl, 0, sizeof(ctrl)); - if (wrq->u.data.length > MAX_LEDS * 2) - return -ENOTSUPP; - if ((wrq->u.data.length % 2) != 0) - return -ENOTSUPP; - if (wrq->u.data.length == 0) { - ctrl.action = - cpu_to_le16 - (cmd_act_get); - } else { - if (copy_from_user - (data, wrq->u.data.pointer, - sizeof(int) * - wrq->u.data.length)) { - lbs_pr_debug(1, - "Copy from user failed\n"); - return -EFAULT; - } - - ctrl.action = - cpu_to_le16 - (cmd_act_set); - ctrl.numled = cpu_to_le16(0); - gpio->header.type = - cpu_to_le16(TLV_TYPE_LED_GPIO); - gpio->header.len = wrq->u.data.length; - for (i = 0; i < wrq->u.data.length; - i += 2) { - gpio->ledpin[i / 2].led = - data[i]; - gpio->ledpin[i / 2].pin = - data[i + 1]; - } - } - ret = - libertas_prepare_and_send_command(priv, - cmd_802_11_led_gpio_ctrl, - 0, - cmd_option_waitforrsp, - 0, (void *)&ctrl); - for (i = 0; i < gpio->header.len; i += 2) { - data[i] = gpio->ledpin[i / 2].led; - data[i + 1] = gpio->ledpin[i / 2].pin; - } - if (copy_to_user(wrq->u.data.pointer, data, - sizeof(int) * - gpio->header.len)) { - lbs_pr_debug(1, "Copy to user failed\n"); - return -EFAULT; - } - - wrq->u.data.length = gpio->header.len; - } - break; - case WLAN_ADAPT_RATESET: - ret = wlan_adapt_rateset(priv, wrq); - break; - case WLAN_INACTIVITY_TIMEOUT: - ret = wlan_inactivity_timeout(priv, wrq); - break; - case WLANSNR: - ret = wlan_get_snr(priv, wrq); - break; - case WLAN_GET_RXINFO: - ret = wlan_get_rxinfo(priv, wrq); - } - break; - - default: - ret = -EINVAL; - break; - } - LEAVE(); - return ret; -} - - diff --git a/trunk/drivers/net/wireless/libertas/join.c b/trunk/drivers/net/wireless/libertas/join.c deleted file mode 100644 index 11682cbe752b..000000000000 --- a/trunk/drivers/net/wireless/libertas/join.c +++ /dev/null @@ -1,1055 +0,0 @@ -/** - * Functions implementing wlan infrastructure and adhoc join routines, - * IOCTL handlers as well as command preperation and response routines - * for sending adhoc start, adhoc join, and association commands - * to the firmware. - */ -#include -#include -#include - -#include - -#include "host.h" -#include "decl.h" -#include "join.h" -#include "dev.h" - -/** - * @brief This function finds out the common rates between rate1 and rate2. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param adapter A pointer to wlan_adapter structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer - * @param rate2 the buffer which keeps rate2 - * @param rate2_size the size of rate2 buffer. - * - * @return 0 or -1 - */ -static int get_common_rates(wlan_adapter * adapter, u8 * rate1, - int rate1_size, u8 * rate2, int rate2_size) -{ - u8 *ptr = rate1; - int ret = 0; - u8 tmp[30]; - int i; - - memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); - memset(rate1, 0, rate1_size); - - /* Mask the top bit of the original values */ - for (i = 0; tmp[i] && i < sizeof(tmp); i++) - tmp[i] &= 0x7F; - - for (i = 0; rate2[i] && i < rate2_size; i++) { - /* Check for Card Rate in tmp, excluding the top bit */ - if (strchr(tmp, rate2[i] & 0x7F)) { - /* values match, so copy the Card Rate to rate1 */ - *rate1++ = rate2[i]; - } - } - - lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); - lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); - lbs_dbg_hex("Common rates:", ptr, rate1_size); - lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate); - - if (!adapter->is_datarate_auto) { - while (*ptr) { - if ((*ptr & 0x7f) == adapter->datarate) { - ret = 0; - goto done; - } - ptr++; - } - lbs_pr_alert( "Previously set fixed data rate %#x isn't " - "compatible with the network.\n", adapter->datarate); - - ret = -1; - goto done; - } - - ret = 0; -done: - return ret; -} - -int libertas_send_deauth(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - if (adapter->inframode == wlan802_11infrastructure && - adapter->connect_status == libertas_connected) - ret = libertas_send_deauthentication(priv); - else - ret = -ENOTSUPP; - - return ret; -} - -int libertas_do_adhocstop_ioctl(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - if (adapter->inframode == wlan802_11ibss && - adapter->connect_status == libertas_connected) - ret = libertas_stop_adhoc_network(priv); - else - ret = -ENOTSUPP; - - return ret; -} - -/** - * @brief Associate to a specific BSS discovered in a scan - * - * @param priv A pointer to wlan_private structure - * @param pbssdesc Pointer to the BSS descriptor to associate with. - * - * @return 0-success, otherwise fail - */ -int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc) -{ - wlan_adapter *adapter = priv->adapter; - int ret; - - ENTER(); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, - 0, cmd_option_waitforrsp, - 0, pbssdesc->macaddress); - - if (ret) { - LEAVE(); - return ret; - } - - /* set preamble to firmware */ - if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble) - adapter->preamble = cmd_type_short_preamble; - else - adapter->preamble = cmd_type_long_preamble; - - libertas_set_radio_control(priv); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, - 0, cmd_option_waitforrsp, 0, pbssdesc); - - LEAVE(); - return ret; -} - -/** - * @brief Start an Adhoc Network - * - * @param priv A pointer to wlan_private structure - * @param adhocssid The ssid of the Adhoc Network - * @return 0--success, -1--fail - */ -int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - adapter->adhoccreate = 1; - - if (!adapter->capinfo.shortpreamble) { - lbs_pr_debug(1, "AdhocStart: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; - } else { - lbs_pr_debug(1, "AdhocStart: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; - } - - libertas_set_radio_control(priv); - - lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel); - lbs_pr_debug(1, "curbssparams.channel = %d\n", - adapter->curbssparams.channel); - lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, - 0, cmd_option_waitforrsp, 0, adhocssid); - - return ret; -} - -/** - * @brief Join an adhoc network found in a previous scan - * - * @param priv A pointer to wlan_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join - * - * @return 0--success, -1--fail - */ -int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n", - adapter->curbssparams.ssid.ssid); - lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n", - adapter->curbssparams.ssid.ssidlength); - lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid); - lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n", - pbssdesc->ssid.ssidlength); - - /* check if the requested SSID is already joined */ - if (adapter->curbssparams.ssid.ssidlength - && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid) - && (adapter->curbssparams.bssdescriptor.inframode == - wlan802_11ibss)) { - - lbs_pr_debug(1, - "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " - "not attempting to re-join"); - - return -1; - } - - /*Use shortpreamble only when both creator and card supports - short preamble */ - if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) { - lbs_pr_debug(1, "AdhocJoin: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; - } else { - lbs_pr_debug(1, "AdhocJoin: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; - } - - libertas_set_radio_control(priv); - - lbs_pr_debug(1, "curbssparams.channel = %d\n", - adapter->curbssparams.channel); - lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band); - - adapter->adhoccreate = 0; - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, - 0, cmd_option_waitforrsp, - OID_802_11_SSID, pbssdesc); - - return ret; -} - -int libertas_stop_adhoc_network(wlan_private * priv) -{ - return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, - 0, cmd_option_waitforrsp, 0, NULL); -} - -/** - * @brief Send Deauthentication Request - * - * @param priv A pointer to wlan_private structure - * @return 0--success, -1--fail - */ -int libertas_send_deauthentication(wlan_private * priv) -{ - return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, - 0, cmd_option_waitforrsp, 0, NULL); -} - -/** - * @brief Set Idle Off - * - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -int libertas_idle_off(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 }; - int i; - - ENTER(); - - if (adapter->connect_status == libertas_disconnected) { - if (adapter->inframode == wlan802_11infrastructure) { - if (memcmp(adapter->previousbssid, zeromac, - sizeof(zeromac)) != 0) { - - lbs_pr_debug(1, "Previous SSID = %s\n", - adapter->previousssid.ssid); - lbs_pr_debug(1, "Previous BSSID = " - "%02x:%02x:%02x:%02x:%02x:%02x:\n", - adapter->previousbssid[0], - adapter->previousbssid[1], - adapter->previousbssid[2], - adapter->previousbssid[3], - adapter->previousbssid[4], - adapter->previousbssid[5]); - - i = libertas_find_SSID_in_list(adapter, - &adapter->previousssid, - adapter->previousbssid, - adapter->inframode); - - if (i < 0) { - libertas_send_specific_BSSID_scan(priv, - adapter-> - previousbssid, - 1); - i = libertas_find_SSID_in_list(adapter, - &adapter-> - previousssid, - adapter-> - previousbssid, - adapter-> - inframode); - } - - if (i < 0) { - /* If the BSSID could not be found, try just the SSID */ - i = libertas_find_SSID_in_list(adapter, - &adapter-> - previousssid, NULL, - adapter-> - inframode); - } - - if (i < 0) { - libertas_send_specific_SSID_scan(priv, - &adapter-> - previousssid, - 1); - i = libertas_find_SSID_in_list(adapter, - &adapter-> - previousssid, NULL, - adapter-> - inframode); - } - - if (i >= 0) { - ret = - wlan_associate(priv, - &adapter-> - scantable[i]); - } - } - } else if (adapter->inframode == wlan802_11ibss) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_ad_hoc_start, - 0, - cmd_option_waitforrsp, - 0, &adapter->previousssid); - } - } - /* else it is connected */ - - lbs_pr_debug(1, "\nwlanidle is off"); - LEAVE(); - return ret; -} - -/** - * @brief Set Idle On - * - * @param priv A pointer to wlan_private structure - * @return 0 --success, otherwise fail - */ -int libertas_idle_on(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - if (adapter->connect_status == libertas_connected) { - if (adapter->inframode == wlan802_11infrastructure) { - lbs_pr_debug(1, "Previous SSID = %s\n", - adapter->previousssid.ssid); - memmove(&adapter->previousssid, - &adapter->curbssparams.ssid, - sizeof(struct WLAN_802_11_SSID)); - libertas_send_deauth(priv); - - } else if (adapter->inframode == wlan802_11ibss) { - ret = libertas_stop_adhoc_network(priv); - } - - } - - lbs_pr_debug(1, "\nwlanidle is on"); - - return ret; -} - -/** - * @brief This function prepares command of authenticate. - * - * @param priv A pointer to wlan_private structure - * @param cmd A pointer to cmd_ds_command structure - * @param pdata_buf Void cast of pointer to a BSSID to authenticate with - * - * @return 0 or -1 - */ -int libertas_cmd_80211_authenticate(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pdata_buf) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_authenticate *pauthenticate = - &cmd->params.auth; - u8 *bssid = pdata_buf; - - cmd->command = cpu_to_le16(cmd_802_11_authenticate); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) - + S_DS_GEN); - - pauthenticate->authtype = adapter->secinfo.authmode; - memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - - lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - - return 0; -} - -int libertas_cmd_80211_deauthenticate(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; - - ENTER(); - - cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); - - /* set AP MAC address */ - memmove(dauth->macaddr, adapter->curbssparams.bssid, - ETH_ALEN); - - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); - - LEAVE(); - return 0; -} - -int libertas_cmd_80211_associate(wlan_private * priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_associate *passo = &cmd->params.associate; - int ret = 0; - struct bss_descriptor *pbssdesc; - u8 *card_rates; - u8 *pos; - int card_rates_size; - u16 tmpcap; - struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_phyparamset *phy; - struct mrvlietypes_ssparamset *ss; - struct mrvlietypes_ratesparamset *rates; - struct mrvlietypes_rsnparamset *rsn; - - ENTER(); - - pbssdesc = pdata_buf; - pos = (u8 *) passo; - - if (!adapter) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(cmd_802_11_associate); - - /* Save so we know which BSS Desc to use in the response handler */ - adapter->pattemptedbssdesc = pbssdesc; - - memcpy(passo->peerstaaddr, - pbssdesc->macaddress, sizeof(passo->peerstaaddr)); - pos += sizeof(passo->peerstaaddr); - - /* set the listen interval */ - passo->listeninterval = adapter->listeninterval; - - pos += sizeof(passo->capinfo); - pos += sizeof(passo->listeninterval); - pos += sizeof(passo->bcnperiod); - pos += sizeof(passo->dtimperiod); - - ssid = (struct mrvlietypes_ssidparamset *) pos; - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); - ssid->header.len = pbssdesc->ssid.ssidlength; - memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len); - pos += sizeof(ssid->header) + ssid->header.len; - ssid->header.len = cpu_to_le16(ssid->header.len); - - phy = (struct mrvlietypes_phyparamset *) pos; - phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - phy->header.len = sizeof(phy->fh_ds.dsparamset); - memcpy(&phy->fh_ds.dsparamset, - &pbssdesc->phyparamset.dsparamset.currentchan, - sizeof(phy->fh_ds.dsparamset)); - pos += sizeof(phy->header) + phy->header.len; - phy->header.len = cpu_to_le16(phy->header.len); - - ss = (struct mrvlietypes_ssparamset *) pos; - ss->header.type = cpu_to_le16(TLV_TYPE_CF); - ss->header.len = sizeof(ss->cf_ibss.cfparamset); - pos += sizeof(ss->header) + ss->header.len; - ss->header.len = cpu_to_le16(ss->header.len); - - rates = (struct mrvlietypes_ratesparamset *) pos; - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - - memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - - if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, - card_rates, card_rates_size)) { - ret = -1; - goto done; - } - - rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); - adapter->curbssparams.numofrates = rates->header.len; - - pos += sizeof(rates->header) + rates->header.len; - rates->header.len = cpu_to_le16(rates->header.len); - - if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { - rsn = (struct mrvlietypes_rsnparamset *) pos; - rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */ - rsn->header.type = cpu_to_le16(rsn->header.type); - rsn->header.len = (u16) adapter->wpa_ie[1]; - memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len); - lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, - sizeof(rsn->header) + rsn->header.len); - pos += sizeof(rsn->header) + rsn->header.len; - rsn->header.len = cpu_to_le16(rsn->header.len); - } - - /* update curbssparams */ - adapter->curbssparams.channel = - (pbssdesc->phyparamset.dsparamset.currentchan); - - /* Copy the infra. association rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, &rates->rates, - min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len)); - - lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len); - - /* set IBSS field */ - if (pbssdesc->inframode == wlan802_11infrastructure) { -#define CAPINFO_ESS_MODE 1 - passo->capinfo.ess = CAPINFO_ESS_MODE; - } - - if (libertas_parse_dnld_countryinfo_11d(priv)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - - /* set the capability info at last */ - memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo)); - tmpcap &= CAPINFO_MASK; - lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - tmpcap, CAPINFO_MASK); - tmpcap = cpu_to_le16(tmpcap); - memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); - - done: - LEAVE(); - return ret; -} - -int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, - struct cmd_ds_command *cmd, void *pssid) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - int i; - u16 tmpcap; - struct bss_descriptor *pbssdesc; - struct WLAN_802_11_SSID *ssid = pssid; - - ENTER(); - - if (!adapter) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); - - pbssdesc = &adapter->curbssparams.bssdescriptor; - adapter->pattemptedbssdesc = pbssdesc; - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. adapter->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); - - memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength); - - lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID); - - memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength); - - pbssdesc->ssid.ssidlength = ssid->ssidlength; - - /* set the BSS type */ - adhs->bsstype = cmd_bss_type_ibss; - pbssdesc->inframode = wlan802_11ibss; - adhs->beaconperiod = adapter->beaconperiod; - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!adapter->adhocchannel); - - lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n", - adapter->adhocchannel); - - adapter->curbssparams.channel = adapter->adhocchannel; - - pbssdesc->channel = adapter->adhocchannel; - adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel; - - memcpy(&pbssdesc->phyparamset, - &adhs->phyparamset, sizeof(union ieeetypes_phyparamset)); - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow; - memcpy(&pbssdesc->ssparamset, - &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset)); - - /* set capability info */ - adhs->cap.ess = 0; - adhs->cap.ibss = 1; - pbssdesc->cap.ibss = 1; - - /* probedelay */ - adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); - - /* set up privacy in adapter->scantable[i] */ - if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { - -#define AD_HOC_CAP_PRIVACY_ON 1 - lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n"); - pbssdesc->privacy = wlan802_11privfilter8021xWEP; - adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; - } else { - lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting " - "privacy to ACCEPT ALL\n"); - pbssdesc->privacy = wlan802_11privfilteracceptall; - } - - memset(adhs->datarate, 0, sizeof(adhs->datarate)); - - if (adapter->adhoc_grate_enabled) { - memcpy(adhs->datarate, libertas_adhoc_rates_g, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); - } else { - memcpy(adhs->datarate, libertas_adhoc_rates_b, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); - } - - /* Find the last non zero */ - for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; - - adapter->curbssparams.numofrates = i; - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, - &adhs->datarate, adapter->curbssparams.numofrates); - - lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->datarate[0], adhs->datarate[1], - adhs->datarate[2], adhs->datarate[3]); - - lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (libertas_create_dnld_countryinfo_11d(priv)) { - lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) - + S_DS_GEN + cmdappendsize); - - memcpy(&tmpcap, &adhs->cap, sizeof(u16)); - tmpcap = cpu_to_le16(tmpcap); - memcpy(&adhs->cap, &tmpcap, sizeof(u16)); - - ret = 0; -done: - LEAVE(); - return ret; -} - -int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, - struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; - struct bss_descriptor *pbssdesc = pdata_buf; - int cmdappendsize = 0; - int ret = 0; - u8 *card_rates; - int card_rates_size; - u16 tmpcap; - int i; - - ENTER(); - - adapter->pattemptedbssdesc = pbssdesc; - - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); - - padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; - - padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod; - - memcpy(&padhocjoin->bssdescriptor.BSSID, - &pbssdesc->macaddress, ETH_ALEN); - - memcpy(&padhocjoin->bssdescriptor.SSID, - &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength); - - memcpy(&padhocjoin->bssdescriptor.phyparamset, - &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset)); - - memcpy(&padhocjoin->bssdescriptor.ssparamset, - &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset)); - - memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo)); - tmpcap &= CAPINFO_MASK; - - lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - tmpcap, CAPINFO_MASK); - memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, - sizeof(struct ieeetypes_capinfo)); - - /* information on BSSID descriptor passed to FW */ - lbs_pr_debug(1, - "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n", - padhocjoin->bssdescriptor.BSSID[0], - padhocjoin->bssdescriptor.BSSID[1], - padhocjoin->bssdescriptor.BSSID[2], - padhocjoin->bssdescriptor.BSSID[3], - padhocjoin->bssdescriptor.BSSID[4], - padhocjoin->bssdescriptor.BSSID[5], - padhocjoin->bssdescriptor.SSID); - - lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n", - (u32) padhocjoin->bssdescriptor.datarates); - - /* failtimeout */ - padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - padhocjoin->probedelay = - cpu_to_le16(cmd_scan_probe_delay_time); - - /* Copy Data rates from the rates recorded in scan response */ - memset(padhocjoin->bssdescriptor.datarates, 0, - sizeof(padhocjoin->bssdescriptor.datarates)); - memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates, - min(sizeof(padhocjoin->bssdescriptor.datarates), - sizeof(pbssdesc->datarates))); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - - adapter->curbssparams.channel = pbssdesc->channel; - - if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, - sizeof(padhocjoin->bssdescriptor.datarates), - card_rates, card_rates_size)) { - lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Find the last non zero */ - for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) - && padhocjoin->bssdescriptor.datarates[i]; i++) ; - - adapter->curbssparams.numofrates = i; - - /* - * Copy the adhoc joining rates to Current BSS State structure - */ - memcpy(adapter->curbssparams.datarates, - padhocjoin->bssdescriptor.datarates, - adapter->curbssparams.numofrates); - - padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(pbssdesc->atimwindow); - - if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { - padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; - } - - if (adapter->psmode == wlan802_11powermodemax_psp) { - /* wake up first */ - enum WLAN_802_11_POWER_MODE Localpsmode; - - Localpsmode = wlan802_11powermodecam; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_ps_mode, - cmd_act_set, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (libertas_parse_dnld_countryinfo_11d(priv)) { - ret = -1; - goto done; - } - - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) - + S_DS_GEN + cmdappendsize); - - memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap, - sizeof(struct ieeetypes_capinfo)); - tmpcap = cpu_to_le16(tmpcap); - - memcpy(&padhocjoin->bssdescriptor.cap, - &tmpcap, sizeof(struct ieeetypes_capinfo)); - - done: - LEAVE(); - return ret; -} - -int libertas_ret_80211_associate(wlan_private * priv, - struct cmd_ds_command *resp) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - union iwreq_data wrqu; - struct ieeetypes_assocrsp *passocrsp; - struct bss_descriptor *pbssdesc; - - ENTER(); - - passocrsp = (struct ieeetypes_assocrsp *) & resp->params; - - if (passocrsp->statuscode) { - - libertas_mac_event_disconnected(priv); - - lbs_pr_debug(1, - "ASSOC_RESP: Association failed, status code = %d\n", - passocrsp->statuscode); - - ret = -1; - goto done; - } - - lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, - le16_to_cpu(resp->size) - S_DS_GEN); - - /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; - - /* Set the attempted BSSID Index to current */ - pbssdesc = adapter->pattemptedbssdesc; - - lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid); - - /* Set the new SSID to current SSID */ - memcpy(&adapter->curbssparams.ssid, - &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); - - /* Set the new BSSID (AP's MAC address) to current BSSID */ - memcpy(adapter->curbssparams.bssid, - pbssdesc->macaddress, ETH_ALEN); - - /* Make a copy of current BSSID descriptor */ - memcpy(&adapter->curbssparams.bssdescriptor, - pbssdesc, sizeof(struct bss_descriptor)); - - lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n", - adapter->currentpacketfilter); - - adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; - adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; - - memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); - memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); - adapter->nextSNRNF = 0; - adapter->numSNRNF = 0; - - netif_carrier_on(priv->wlan_dev.netdev); - netif_wake_queue(priv->wlan_dev.netdev); - - lbs_pr_debug(1, "ASSOC_RESP: Associated \n"); - - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); - - done: - LEAVE(); - return ret; -} - -int libertas_ret_80211_disassociate(wlan_private * priv, - struct cmd_ds_command *resp) -{ - ENTER(); - - libertas_mac_event_disconnected(priv); - - LEAVE(); - return 0; -} - -int libertas_ret_80211_ad_hoc_start(wlan_private * priv, - struct cmd_ds_command *resp) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - u16 command = le16_to_cpu(resp->command); - u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; - union iwreq_data wrqu; - struct bss_descriptor *pbssdesc; - - ENTER(); - - padhocresult = &resp->params.result; - - lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command); - lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result); - - pbssdesc = adapter->pattemptedbssdesc; - - /* - * Join result code 0 --> SUCCESS - */ - if (result) { - lbs_pr_debug(1, "ADHOC_RESP failed\n"); - if (adapter->connect_status == libertas_connected) { - libertas_mac_event_disconnected(priv); - } - - memset(&adapter->curbssparams.bssdescriptor, - 0x00, sizeof(adapter->curbssparams.bssdescriptor)); - - LEAVE(); - return -1; - } - - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid); - - /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; - - if (command == cmd_ret_802_11_ad_hoc_start) { - /* Update the created network descriptor with the new BSSID */ - memcpy(pbssdesc->macaddress, - padhocresult->BSSID, ETH_ALEN); - } else { - - /* Make a copy of current BSSID descriptor, only needed for join since - * the current descriptor is already being used for adhoc start - */ - memmove(&adapter->curbssparams.bssdescriptor, - pbssdesc, sizeof(struct bss_descriptor)); - } - - /* Set the BSSID from the joined/started descriptor */ - memcpy(&adapter->curbssparams.bssid, - pbssdesc->macaddress, ETH_ALEN); - - /* Set the new SSID to current SSID */ - memcpy(&adapter->curbssparams.ssid, - &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); - - netif_carrier_on(priv->wlan_dev.netdev); - netif_wake_queue(priv->wlan_dev.netdev); - - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); - - lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel); - lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", - padhocresult->BSSID[0], padhocresult->BSSID[1], - padhocresult->BSSID[2], padhocresult->BSSID[3], - padhocresult->BSSID[4], padhocresult->BSSID[5]); - - LEAVE(); - return ret; -} - -int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, - struct cmd_ds_command *resp) -{ - ENTER(); - - libertas_mac_event_disconnected(priv); - - LEAVE(); - return 0; -} diff --git a/trunk/drivers/net/wireless/libertas/join.h b/trunk/drivers/net/wireless/libertas/join.h deleted file mode 100644 index 8efa2455af9a..000000000000 --- a/trunk/drivers/net/wireless/libertas/join.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ -/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ - -/** - * Interface for the wlan infrastructure and adhoc join routines - * - * Driver interface functions and type declarations for the join module - * implemented in wlan_join.c. Process all start/join requests for - * both adhoc and infrastructure networks - */ -#ifndef _WLAN_JOIN_H -#define _WLAN_JOIN_H - -#include "defs.h" - -struct cmd_ds_command; -extern int libertas_cmd_80211_authenticate(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, - struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pssid); -extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, - struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_associate(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, - struct cmd_ds_command *resp); -extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, - struct cmd_ds_command *resp); -extern int libertas_ret_80211_disassociate(wlan_private * priv, - struct cmd_ds_command *resp); -extern int libertas_ret_80211_associate(wlan_private * priv, - struct cmd_ds_command *resp); - -extern int libertas_idle_on(wlan_private * priv); -extern int libertas_idle_off(wlan_private * priv); - -extern int libertas_do_adhocstop_ioctl(wlan_private * priv); -extern int libertas_reassociation_thread(void *data); - -struct WLAN_802_11_SSID; -struct bss_descriptor; - -extern int libertas_start_adhoc_network(wlan_private * priv, - struct WLAN_802_11_SSID *adhocssid); -extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc); -extern int libertas_stop_adhoc_network(wlan_private * priv); - -extern int libertas_send_deauthentication(wlan_private * priv); -extern int libertas_send_deauth(wlan_private * priv); - -extern int libertas_do_adhocstop_ioctl(wlan_private * priv); - -int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc); - -#endif diff --git a/trunk/drivers/net/wireless/libertas/main.c b/trunk/drivers/net/wireless/libertas/main.c deleted file mode 100644 index dcbf102a057e..000000000000 --- a/trunk/drivers/net/wireless/libertas/main.c +++ /dev/null @@ -1,1258 +0,0 @@ -/** - * This file contains the major functions in WLAN - * driver. It includes init, exit, open, close and main - * thread etc.. - */ - -#include -#include -#include -#include -#include - -#include - -#include "host.h" -#include "sbi.h" -#include "decl.h" -#include "dev.h" -#include "fw.h" -#include "wext.h" -#include "debugfs.h" -#include "assoc.h" - -#ifdef ENABLE_PM -static struct pm_dev *wlan_pm_dev = NULL; -#endif - -#define WLAN_TX_PWR_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */ -#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */ - -/* Format { channel, frequency (MHz), maxtxpower } */ -/* band: 'B/G', region: USA FCC/Canada IC */ -static struct chan_freq_power channel_freq_power_US_BG[] = { - {1, 2412, WLAN_TX_PWR_US_DEFAULT}, - {2, 2417, WLAN_TX_PWR_US_DEFAULT}, - {3, 2422, WLAN_TX_PWR_US_DEFAULT}, - {4, 2427, WLAN_TX_PWR_US_DEFAULT}, - {5, 2432, WLAN_TX_PWR_US_DEFAULT}, - {6, 2437, WLAN_TX_PWR_US_DEFAULT}, - {7, 2442, WLAN_TX_PWR_US_DEFAULT}, - {8, 2447, WLAN_TX_PWR_US_DEFAULT}, - {9, 2452, WLAN_TX_PWR_US_DEFAULT}, - {10, 2457, WLAN_TX_PWR_US_DEFAULT}, - {11, 2462, WLAN_TX_PWR_US_DEFAULT} -}; - -/* band: 'B/G', region: Europe ETSI */ -static struct chan_freq_power channel_freq_power_EU_BG[] = { - {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, - {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, - {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, - {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, - {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, - {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, - {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, - {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, - {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, - {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, - {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, - {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, - {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT} -}; - -/* band: 'B/G', region: Spain */ -static struct chan_freq_power channel_freq_power_SPN_BG[] = { - {10, 2457, WLAN_TX_PWR_DEFAULT}, - {11, 2462, WLAN_TX_PWR_DEFAULT} -}; - -/* band: 'B/G', region: France */ -static struct chan_freq_power channel_freq_power_FR_BG[] = { - {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, - {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, - {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, - {13, 2472, WLAN_TX_PWR_FR_DEFAULT} -}; - -/* band: 'B/G', region: Japan */ -static struct chan_freq_power channel_freq_power_JPN_BG[] = { - {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, - {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, - {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, - {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, - {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, - {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, - {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, - {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, - {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, - {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, - {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, - {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, - {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, - {14, 2484, WLAN_TX_PWR_JP_DEFAULT} -}; - -/** - * the structure for channel, frequency and power - */ -struct region_cfp_table { - u8 region; - struct chan_freq_power *cfp_BG; - int cfp_no_BG; -}; - -/** - * the structure for the mapping between region and CFP - */ -static struct region_cfp_table region_cfp_table[] = { - {0x10, /*US FCC */ - channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), - } - , - {0x20, /*CANADA IC */ - channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), - } - , - {0x30, /*EU*/ channel_freq_power_EU_BG, - sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), - } - , - {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, - sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), - } - , - {0x32, /*FRANCE*/ channel_freq_power_FR_BG, - sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), - } - , - {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, - sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), - } - , -/*Add new region here */ -}; - -/** - * the rates supported by the card - */ -u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = - { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, - 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 -}; - -/** - * the rates supported - */ -u8 libertas_supported_rates[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; - -/** - * the rates supported for ad-hoc G mode - */ -u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; - -/** - * the rates supported for ad-hoc B mode - */ -u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; - -/** - * the global variable of a pointer to wlan_private - * structure variable - */ -static wlan_private *wlanpriv = NULL; - -#define MAX_DEVS 5 -static struct net_device *libertas_devs[MAX_DEVS]; -static int libertas_found = 0; - -/** - * the table to keep region code - */ -u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = - { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; - -static u8 *default_fw_name = "usb8388.bin"; - -/** - * Attributes exported through sysfs - */ - -/** - * @brief Get function for sysfs attribute libertas_mpp - */ -static ssize_t libertas_mpp_get(struct device * dev, - struct device_attribute *attr, char * buf) { - struct cmd_ds_mesh_access mesh_access; - - memset(&mesh_access, 0, sizeof(mesh_access)); - libertas_prepare_and_send_command(to_net_dev(dev)->priv, - cmd_mesh_access, - cmd_act_mesh_get_mpp, - cmd_option_waitforrsp, 0, (void *)&mesh_access); - - return snprintf(buf, 3, "%d\n", mesh_access.data[0]); -} - -/** - * @brief Set function for sysfs attribute libertas_mpp - */ -static ssize_t libertas_mpp_set(struct device * dev, - struct device_attribute *attr, const char * buf, size_t count) { - struct cmd_ds_mesh_access mesh_access; - - - memset(&mesh_access, 0, sizeof(mesh_access)); - sscanf(buf, "%d", &(mesh_access.data[0])); - libertas_prepare_and_send_command((to_net_dev(dev))->priv, - cmd_mesh_access, - cmd_act_mesh_set_mpp, - cmd_option_waitforrsp, 0, (void *)&mesh_access); - return strlen(buf); -} - -/** - * libertas_mpp attribute to be exported per mshX interface - * through sysfs (/sys/class/net/mshX/libertas-mpp) - */ -static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get, - libertas_mpp_set ); - -/** - * @brief Check if the device can be open and wait if necessary. - * - * @param dev A pointer to net_device structure - * @return 0 - * - * For USB adapter, on some systems the device open handler will be - * called before FW ready. Use the following flag check and wait - * function to work around the issue. - * - */ -static int pre_open_check(struct net_device *dev) { - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - int i = 0; - - while (!adapter->fw_ready && i < 20) { - i++; - msleep_interruptible(100); - } - if (!adapter->fw_ready) { - lbs_pr_info("FW not ready, pre_open_check() return failure\n"); - LEAVE(); - return -1; - } - - return 0; -} - -/** - * @brief This function opens the device - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int wlan_dev_open(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - - priv->open = 1; - - if (adapter->connect_status == libertas_connected) { - netif_carrier_on(priv->wlan_dev.netdev); - } else - netif_carrier_off(priv->wlan_dev.netdev); - - LEAVE(); - return 0; -} -/** - * @brief This function opens the mshX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int mesh_open(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv ; - - if(pre_open_check(dev) == -1) - return -1; - priv->mesh_open = 1 ; - netif_start_queue(priv->mesh_dev); - if (priv->infra_open == 0) - return wlan_dev_open(priv->wlan_dev.netdev) ; - return 0; -} - -/** - * @brief This function opens the ethX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int wlan_open(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv ; - - if(pre_open_check(dev) == -1) - return -1; - priv->infra_open = 1 ; - netif_wake_queue(priv->wlan_dev.netdev); - if (priv->open == 0) - return wlan_dev_open(priv->wlan_dev.netdev) ; - return 0; -} - -static int wlan_dev_close(struct net_device *dev) -{ - wlan_private *priv = dev->priv; - - ENTER(); - - netif_carrier_off(priv->wlan_dev.netdev); - priv->open = 0; - - LEAVE(); - return 0; -} - -/** - * @brief This function closes the mshX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int mesh_close(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) (dev->priv); - - priv->mesh_open = 0; - netif_stop_queue(priv->mesh_dev); - if (priv->infra_open == 0) - return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; - else - return 0; -} - -/** - * @brief This function closes the ethX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int wlan_close(struct net_device *dev) { - wlan_private *priv = (wlan_private *) dev->priv; - - netif_stop_queue(priv->wlan_dev.netdev); - priv->infra_open = 0; - if (priv->mesh_open == 0) - return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; - else - return 0; -} - - -#ifdef ENABLE_PM - -/** - * @brief This function is a callback function. it is called by - * kernel to enter or exit power saving mode. - * - * @param pmdev A pointer to pm_dev - * @param pmreq pm_request_t - * @param pmdata A pointer to pmdata - * @return 0 or -1 - */ -static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq, - void *pmdata) -{ - wlan_private *priv = wlanpriv; - wlan_adapter *adapter = priv->adapter; - struct net_device *dev = priv->wlan_dev.netdev; - - lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq); - - switch (pmreq) { - case PM_SUSPEND: - lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n"); - - /* in associated mode */ - if (adapter->connect_status == libertas_connected) { - if ((adapter->psstate != PS_STATE_SLEEP) - ) { - lbs_pr_debug(1, - "wlan_pm_callback: can't enter sleep mode\n"); - return -1; - } else { - - /* - * Detach the network interface - * if the network is running - */ - if (netif_running(dev)) { - netif_device_detach(dev); - lbs_pr_debug(1, - "netif_device_detach().\n"); - } - libertas_sbi_suspend(priv); - } - break; - } - - /* in non associated mode */ - - /* - * Detach the network interface - * if the network is running - */ - if (netif_running(dev)) - netif_device_detach(dev); - - /* - * Storing and restoring of the regs be taken care - * at the driver rest will be done at wlan driver - * this makes driver independent of the card - */ - - libertas_sbi_suspend(priv); - - break; - - case PM_RESUME: - /* in associated mode */ - if (adapter->connect_status == libertas_connected) { - { - /* - * Bring the inteface up first - * This case should not happen still ... - */ - libertas_sbi_resume(priv); - - /* - * Attach the network interface - * if the network is running - */ - if (netif_running(dev)) { - netif_device_attach(dev); - lbs_pr_debug(1, - "after netif_device_attach().\n"); - } - lbs_pr_debug(1, - "After netif attach, in associated mode.\n"); - } - break; - } - - /* in non associated mode */ - - /* - * Bring the inteface up first - * This case should not happen still ... - */ - - libertas_sbi_resume(priv); - - if (netif_running(dev)) - netif_device_attach(dev); - - lbs_pr_debug(1, "after netif attach, in NON associated mode.\n"); - break; - } - - return 0; -} -#endif /* ENABLE_PM */ - -static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - int ret = 0; - wlan_private *priv = dev->priv; - - ENTER(); - - if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) { - priv->stats.tx_dropped++; - goto done; - } - - netif_stop_queue(priv->wlan_dev.netdev); - - if (libertas_process_tx(priv, skb) == 0) - dev->trans_start = jiffies; -done: - LEAVE(); - return ret; -} - -/** - * @brief Mark mesh packets and handover them to wlan_hard_start_xmit - * - */ -static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - wlan_private *priv = dev->priv; - ENTER(); - SET_MESH_FRAME(skb); - LEAVE(); - - return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev); -} - -/** - * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit - * - */ -static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { - ENTER(); - UNSET_MESH_FRAME(skb); - LEAVE(); - return wlan_hard_start_xmit(skb, dev); -} - -static void wlan_tx_timeout(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv; - - ENTER(); - - lbs_pr_err("tx watch dog timeout!\n"); - - priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; - dev->trans_start = jiffies; - - if (priv->adapter->currenttxskb) { - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { - /* If we are here, we have not received feedback from - the previous packet. Assume TX_FAIL and move on. */ - priv->adapter->eventcause = 0x01000000; - libertas_send_tx_feedback(priv); - } else - wake_up_interruptible(&priv->mainthread.waitq); - } else if (priv->adapter->connect_status == libertas_connected) - netif_wake_queue(priv->wlan_dev.netdev); - - LEAVE(); -} - -/** - * @brief This function returns the network statistics - * - * @param dev A pointer to wlan_private structure - * @return A pointer to net_device_stats structure - */ -static struct net_device_stats *wlan_get_stats(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv; - - return &priv->stats; -} - -static int wlan_set_mac_address(struct net_device *dev, void *addr) -{ - int ret = 0; - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - struct sockaddr *phwaddr = addr; - - ENTER(); - - memset(adapter->current_addr, 0, ETH_ALEN); - - /* dev->dev_addr is 8 bytes */ - lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN); - - lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); - memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - - if (ret) { - lbs_pr_debug(1, "set mac address failed.\n"); - ret = -1; - goto done; - } - - lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN); - memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); - memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); - -done: - LEAVE(); - return ret; -} - -static int wlan_copy_multicast_address(wlan_adapter * adapter, - struct net_device *dev) -{ - int i = 0; - struct dev_mc_list *mcptr = dev->mc_list; - - for (i = 0; i < dev->mc_count; i++) { - memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); - mcptr = mcptr->next; - } - - return i; - -} - -static void wlan_set_multicast_list(struct net_device *dev) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int oldpacketfilter; - - ENTER(); - - oldpacketfilter = adapter->currentpacketfilter; - - if (dev->flags & IFF_PROMISC) { - lbs_pr_debug(1, "enable Promiscuous mode\n"); - adapter->currentpacketfilter |= - cmd_act_mac_promiscuous_enable; - adapter->currentpacketfilter &= - ~(cmd_act_mac_all_multicast_enable | - cmd_act_mac_multicast_enable); - } else { - /* Multicast */ - adapter->currentpacketfilter &= - ~cmd_act_mac_promiscuous_enable; - - if (dev->flags & IFF_ALLMULTI || dev->mc_count > - MRVDRV_MAX_MULTICAST_LIST_SIZE) { - lbs_pr_debug(1, "Enabling All Multicast!\n"); - adapter->currentpacketfilter |= - cmd_act_mac_all_multicast_enable; - adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; - } else { - adapter->currentpacketfilter &= - ~cmd_act_mac_all_multicast_enable; - - if (!dev->mc_count) { - lbs_pr_debug(1, "No multicast addresses - " - "disabling multicast!\n"); - adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; - } else { - int i; - - adapter->currentpacketfilter |= - cmd_act_mac_multicast_enable; - - adapter->nr_of_multicastmacaddr = - wlan_copy_multicast_address(adapter, dev); - - lbs_pr_debug(1, "Multicast addresses: %d\n", - dev->mc_count); - - for (i = 0; i < dev->mc_count; i++) { - lbs_pr_debug(1, "Multicast address %d:" - "%x %x %x %x %x %x\n", i, - adapter->multicastlist[i][0], - adapter->multicastlist[i][1], - adapter->multicastlist[i][2], - adapter->multicastlist[i][3], - adapter->multicastlist[i][4], - adapter->multicastlist[i][5]); - } - /* set multicast addresses to firmware */ - libertas_prepare_and_send_command(priv, - cmd_mac_multicast_adr, - cmd_act_set, 0, 0, - NULL); - } - } - } - - if (adapter->currentpacketfilter != oldpacketfilter) { - libertas_set_mac_packet_filter(priv); - } - - LEAVE(); -} - -/** - * @brief This function hanldes the major job in WLAN driver. - * it handles the event generated by firmware, rx data received - * from firmware and tx data sent from kernel. - * - * @param data A pointer to wlan_thread structure - * @return 0 - */ -static int wlan_service_main_thread(void *data) -{ - struct wlan_thread *thread = data; - wlan_private *priv = thread->priv; - wlan_adapter *adapter = priv->adapter; - wait_queue_t wait; - u8 ireg = 0; - - ENTER(); - - wlan_activate_thread(thread); - - init_waitqueue_entry(&wait, current); - - for (;;) { - lbs_pr_debug(1, "main-thread 111: intcounter=%d " - "currenttxskb=%p dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->wlan_dev.dnld_sent); - - add_wait_queue(&thread->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&adapter->driver_lock); - if ((adapter->psstate == PS_STATE_SLEEP) || - (!adapter->intcounter - && (priv->wlan_dev.dnld_sent || adapter->cur_cmd || - list_empty(&adapter->cmdpendingq)))) { - lbs_pr_debug(1, - "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", - adapter->connect_status, adapter->intcounter, - adapter->psmode, adapter->psstate); - spin_unlock_irq(&adapter->driver_lock); - schedule(); - } else - spin_unlock_irq(&adapter->driver_lock); - - - lbs_pr_debug(1, - "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", adapter->intcounter, - adapter->currenttxskb, priv->wlan_dev.dnld_sent); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&thread->waitq, &wait); - try_to_freeze(); - - lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->wlan_dev.dnld_sent); - - if (kthread_should_stop() - || adapter->surpriseremoved) { - lbs_pr_debug(1, - "main-thread: break from main thread: surpriseremoved=0x%x\n", - adapter->surpriseremoved); - break; - } - - - spin_lock_irq(&adapter->driver_lock); - if (adapter->intcounter) { - u8 int_status; - adapter->intcounter = 0; - int_status = libertas_sbi_get_int_status(priv, &ireg); - - if (int_status) { - lbs_pr_debug(1, - "main-thread: reading HOST_INT_STATUS_REG failed\n"); - spin_unlock_irq(&adapter->driver_lock); - continue; - } - adapter->hisregcpy |= ireg; - } - - lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->wlan_dev.dnld_sent); - - /* command response? */ - if (adapter->hisregcpy & his_cmdupldrdy) { - lbs_pr_debug(1, "main-thread: cmd response ready.\n"); - - adapter->hisregcpy &= ~his_cmdupldrdy; - spin_unlock_irq(&adapter->driver_lock); - libertas_process_rx_command(priv); - spin_lock_irq(&adapter->driver_lock); - } - - /* Any Card Event */ - if (adapter->hisregcpy & his_cardevent) { - lbs_pr_debug(1, "main-thread: Card Event Activity.\n"); - - adapter->hisregcpy &= ~his_cardevent; - - if (libertas_sbi_read_event_cause(priv)) { - lbs_pr_alert( - "main-thread: libertas_sbi_read_event_cause failed.\n"); - spin_unlock_irq(&adapter->driver_lock); - continue; - } - spin_unlock_irq(&adapter->driver_lock); - libertas_process_event(priv); - } else - spin_unlock_irq(&adapter->driver_lock); - - /* Check if we need to confirm Sleep Request received previously */ - if (adapter->psstate == PS_STATE_PRE_SLEEP) { - if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) { - if (adapter->connect_status == - libertas_connected) { - lbs_pr_debug(1, - "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " - "dnld_sent=%d cur_cmd=%p, confirm now\n", - adapter->intcounter, - adapter->currenttxskb, - priv->wlan_dev.dnld_sent, - adapter->cur_cmd); - - libertas_ps_confirm_sleep(priv, - (u16) adapter->psmode); - } else { - /* workaround for firmware sending - * deauth/linkloss event immediately - * after sleep request, remove this - * after firmware fixes it - */ - adapter->psstate = PS_STATE_AWAKE; - lbs_pr_alert( - "main-thread: ignore PS_SleepConfirm in non-connected state\n"); - } - } - } - - /* The PS state is changed during processing of Sleep Request - * event above - */ - if ((priv->adapter->psstate == PS_STATE_SLEEP) || - (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) - continue; - - /* Execute the next command */ - if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd) - libertas_execute_next_command(priv); - - /* Wake-up command waiters which can't sleep in - * libertas_prepare_and_send_command - */ - if (!adapter->nr_cmd_pending) - wake_up_all(&adapter->cmd_pending); - - libertas_tx_runqueue(priv); - } - - del_timer(&adapter->command_timer); - adapter->nr_cmd_pending = 0; - wake_up_all(&adapter->cmd_pending); - wlan_deactivate_thread(thread); - - LEAVE(); - return 0; -} - -/** - * @brief This function adds the card. it will probe the - * card, allocate the wlan_priv and initialize the device. - * - * @param card A pointer to card - * @return A pointer to wlan_private structure - */ -wlan_private *wlan_add_card(void *card) -{ - struct net_device *dev = NULL; - struct net_device *mesh_dev = NULL; - wlan_private *priv = NULL; - - ENTER(); - - /* Allocate an Ethernet device and register it */ - if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { - lbs_pr_alert( "Init ethernet device failed!\n"); - return NULL; - } - - priv = dev->priv; - - /* allocate buffer for wlan_adapter */ - if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) { - lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n"); - goto err_kmalloc; - } - - /* Allocate a virtual mesh device */ - if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { - lbs_pr_debug(1, "Init ethernet device failed!\n"); - return NULL; - } - - /* Both intervaces share the priv structure */ - mesh_dev->priv = priv; - - /* init wlan_adapter */ - memset(priv->adapter, 0, sizeof(wlan_adapter)); - - priv->wlan_dev.netdev = dev; - priv->wlan_dev.card = card; - priv->mesh_open = 0; - priv->infra_open = 0; - priv->mesh_dev = mesh_dev; - wlanpriv = priv; - - SET_MODULE_OWNER(dev); - SET_MODULE_OWNER(mesh_dev); - - /* Setup the OS Interface to our functions */ - dev->open = wlan_open; - dev->hard_start_xmit = wlan_pre_start_xmit; - dev->stop = wlan_close; - dev->do_ioctl = libertas_do_ioctl; - dev->set_mac_address = wlan_set_mac_address; - mesh_dev->open = mesh_open; - mesh_dev->hard_start_xmit = mesh_pre_start_xmit; - mesh_dev->stop = mesh_close; - mesh_dev->do_ioctl = libertas_do_ioctl; - memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr, - sizeof(wlanpriv->wlan_dev.netdev->dev_addr)); - -#define WLAN_WATCHDOG_TIMEOUT (5 * HZ) - - dev->tx_timeout = wlan_tx_timeout; - dev->get_stats = wlan_get_stats; - dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT; - dev->ethtool_ops = &libertas_ethtool_ops; - mesh_dev->get_stats = wlan_get_stats; - mesh_dev->ethtool_ops = &libertas_ethtool_ops; - -#ifdef WIRELESS_EXT - dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; - mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; -#endif -#define NETIF_F_DYNALLOC 16 - dev->features |= NETIF_F_DYNALLOC; - dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->set_multicast_list = wlan_set_multicast_list; - - INIT_LIST_HEAD(&priv->adapter->cmdfreeq); - INIT_LIST_HEAD(&priv->adapter->cmdpendingq); - - spin_lock_init(&priv->adapter->driver_lock); - init_waitqueue_head(&priv->adapter->cmd_pending); - priv->adapter->nr_cmd_pending = 0; - - lbs_pr_debug(1, "Starting kthread...\n"); - priv->mainthread.priv = priv; - wlan_create_thread(wlan_service_main_thread, - &priv->mainthread, "wlan_main_service"); - - priv->assoc_thread = - create_singlethread_workqueue("libertas_assoc"); - INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker); - - /* - * Register the device. Fillup the private data structure with - * relevant information from the card and request for the required - * IRQ. - */ - if (libertas_sbi_register_dev(priv) < 0) { - lbs_pr_info("failed to register wlan device!\n"); - goto err_registerdev; - } - - /* init FW and HW */ - if (libertas_init_fw(priv)) { - lbs_pr_debug(1, "Firmware Init failed\n"); - goto err_registerdev; - } - - if (register_netdev(dev)) { - lbs_pr_err("Cannot register network device!\n"); - goto err_init_fw; - } - - /* Register virtual mesh interface */ - if (register_netdev(mesh_dev)) { - lbs_pr_info("Cannot register mesh virtual interface!\n"); - goto err_init_fw; - } - - lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name); - - libertas_debugfs_init_one(priv, dev); - - if (libertas_found == MAX_DEVS) - goto err_init_fw; - libertas_devs[libertas_found] = dev; - libertas_found++; -#ifdef ENABLE_PM - if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback))) - lbs_pr_alert( "failed to register PM callback\n"); -#endif - if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp)) - goto err_create_file; - - LEAVE(); - return priv; - -err_create_file: - device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); -err_init_fw: - libertas_sbi_unregister_dev(priv); -err_registerdev: - destroy_workqueue(priv->assoc_thread); - /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->mainthread.waitq); - wlan_terminate_thread(&priv->mainthread); - kfree(priv->adapter); -err_kmalloc: - free_netdev(dev); - free_netdev(mesh_dev); - wlanpriv = NULL; - - LEAVE(); - return NULL; -} - -static void wake_pending_cmdnodes(wlan_private *priv) -{ - struct cmd_ctrl_node *cmdnode; - unsigned long flags; - - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { - cmdnode->cmdwaitqwoken = 1; - wake_up_interruptible(&cmdnode->cmdwait_q); - } - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); -} - - -int wlan_remove_card(void *card) -{ - wlan_private *priv = libertas_sbi_get_priv(card); - wlan_adapter *adapter; - struct net_device *dev; - struct net_device *mesh_dev; - union iwreq_data wrqu; - int i; - - ENTER(); - - if (!priv) { - LEAVE(); - return 0; - } - - adapter = priv->adapter; - - if (!adapter) { - LEAVE(); - return 0; - } - - dev = priv->wlan_dev.netdev; - mesh_dev = priv->mesh_dev; - - netif_stop_queue(mesh_dev); - netif_stop_queue(priv->wlan_dev.netdev); - netif_carrier_off(priv->wlan_dev.netdev); - - wake_pending_cmdnodes(priv); - - device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); - unregister_netdev(mesh_dev); - unregister_netdev(dev); - - cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->assoc_thread); - - if (adapter->psmode == wlan802_11powermodemax_psp) { - adapter->psmode = wlan802_11powermodecam; - libertas_ps_wakeup(priv, cmd_option_waitforrsp); - } - - memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); - -#ifdef ENABLE_PM - pm_unregister(wlan_pm_dev); -#endif - - adapter->surpriseremoved = 1; - - /* Stop the thread servicing the interrupts */ - wlan_terminate_thread(&priv->mainthread); - - libertas_debugfs_remove_one(priv); - - lbs_pr_debug(1, "Free adapter\n"); - libertas_free_adapter(priv); - - for (i = 0; iwlan_dev.netdev) { - libertas_devs[i] = libertas_devs[--libertas_found]; - libertas_devs[libertas_found] = NULL ; - break ; - } - } - - lbs_pr_debug(1, "Unregister finish\n"); - - priv->wlan_dev.netdev = NULL; - priv->mesh_dev = NULL ; - free_netdev(mesh_dev); - free_netdev(dev); - wlanpriv = NULL; - - LEAVE(); - return 0; -} - -/** - * @brief This function finds the CFP in - * region_cfp_table based on region and band parameter. - * - * @param region The region code - * @param band The band - * @param cfp_no A pointer to CFP number - * @return A pointer to CFP - */ -struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no) -{ - int i, end; - - ENTER(); - - end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); - - for (i = 0; i < end ; i++) { - lbs_pr_debug(1, "region_cfp_table[i].region=%d\n", - region_cfp_table[i].region); - if (region_cfp_table[i].region == region) { - *cfp_no = region_cfp_table[i].cfp_no_BG; - LEAVE(); - return region_cfp_table[i].cfp_BG; - } - } - - LEAVE(); - return NULL; -} - -int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) -{ - wlan_adapter *adapter = priv->adapter; - int i = 0; - - struct chan_freq_power *cfp; - int cfp_no; - - ENTER(); - - memset(adapter->region_channel, 0, sizeof(adapter->region_channel)); - - { - cfp = libertas_get_region_cfp_table(region, band, &cfp_no); - if (cfp != NULL) { - adapter->region_channel[i].nrcfp = cfp_no; - adapter->region_channel[i].CFP = cfp; - } else { - lbs_pr_debug(1, "wrong region code %#x in band B-G\n", - region); - return -1; - } - adapter->region_channel[i].valid = 1; - adapter->region_channel[i].region = region; - adapter->region_channel[i].band = band; - i++; - } - LEAVE(); - return 0; -} - -/** - * @brief This function handles the interrupt. it will change PS - * state if applicable. it will wake up main_thread to handle - * the interrupt event as well. - * - * @param dev A pointer to net_device structure - * @return n/a - */ -void libertas_interrupt(struct net_device *dev) -{ - wlan_private *priv = dev->priv; - - ENTER(); - - lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n", - priv->adapter->intcounter); - - priv->adapter->intcounter++; - - if (priv->adapter->psstate == PS_STATE_SLEEP) { - priv->adapter->psstate = PS_STATE_AWAKE; - netif_wake_queue(dev); - } - - wake_up_interruptible(&priv->mainthread.waitq); - - LEAVE(); -} - -static int wlan_init_module(void) -{ - int ret = 0; - - ENTER(); - - if (libertas_fw_name == NULL) { - libertas_fw_name = default_fw_name; - } - - libertas_debugfs_init(); - - if (libertas_sbi_register()) { - ret = -1; - libertas_debugfs_remove(); - goto done; - } - -done: - LEAVE(); - return ret; -} - -static void wlan_cleanup_module(void) -{ - int i; - - ENTER(); - - for (i = 0; ipriv; - reset_device(priv); - } - - libertas_sbi_unregister(); - libertas_debugfs_remove(); - - LEAVE(); -} - -module_init(wlan_init_module); -module_exit(wlan_cleanup_module); - -MODULE_DESCRIPTION("M-WLAN Driver"); -MODULE_AUTHOR("Marvell International Ltd."); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/wireless/libertas/radiotap.h b/trunk/drivers/net/wireless/libertas/radiotap.h deleted file mode 100644 index 5d118f40cfbc..000000000000 --- a/trunk/drivers/net/wireless/libertas/radiotap.h +++ /dev/null @@ -1,57 +0,0 @@ -#include - -struct tx_radiotap_hdr { - struct ieee80211_radiotap_header hdr; - u8 rate; - u8 txpower; - u8 rts_retries; - u8 data_retries; -#if 0 - u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; -#endif -} __attribute__ ((packed)); - -#define TX_RADIOTAP_PRESENT ( \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ - (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \ - (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ - 0) - -#define IEEE80211_FC_VERSION_MASK 0x0003 -#define IEEE80211_FC_TYPE_MASK 0x000c -#define IEEE80211_FC_TYPE_MGT 0x0000 -#define IEEE80211_FC_TYPE_CTL 0x0004 -#define IEEE80211_FC_TYPE_DATA 0x0008 -#define IEEE80211_FC_SUBTYPE_MASK 0x00f0 -#define IEEE80211_FC_TOFROMDS_MASK 0x0300 -#define IEEE80211_FC_TODS_MASK 0x0100 -#define IEEE80211_FC_FROMDS_MASK 0x0200 -#define IEEE80211_FC_NODS 0x0000 -#define IEEE80211_FC_TODS 0x0100 -#define IEEE80211_FC_FROMDS 0x0200 -#define IEEE80211_FC_DSTODS 0x0300 - -struct rx_radiotap_hdr { - struct ieee80211_radiotap_header hdr; - u8 flags; - u8 rate; - u16 chan_freq; - u16 chan_flags; - u8 antenna; - u8 antsignal; - u16 rx_flags; -#if 0 - u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18]; -#endif -} __attribute__ ((packed)); - -#define RX_RADIOTAP_PRESENT ( \ - (1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - (1 << IEEE80211_RADIOTAP_CHANNEL) | \ - (1 << IEEE80211_RADIOTAP_ANTENNA) | \ - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ - (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \ - 0) - diff --git a/trunk/drivers/net/wireless/libertas/rx.c b/trunk/drivers/net/wireless/libertas/rx.c deleted file mode 100644 index 7e3f78f092dc..000000000000 --- a/trunk/drivers/net/wireless/libertas/rx.c +++ /dev/null @@ -1,459 +0,0 @@ -/** - * This file contains the handling of RX in wlan driver. - */ -#include -#include - -#include "hostcmd.h" -#include "radiotap.h" -#include "decl.h" -#include "dev.h" -#include "wext.h" - -struct eth803hdr { - u8 dest_addr[6]; - u8 src_addr[6]; - u16 h803_len; -} __attribute__ ((packed)); - -struct rfc1042hdr { - u8 llc_dsap; - u8 llc_ssap; - u8 llc_ctrl; - u8 snap_oui[3]; - u16 snap_type; -} __attribute__ ((packed)); - -struct rxpackethdr { - struct rxpd rx_pd; - struct eth803hdr eth803_hdr; - struct rfc1042hdr rfc1042_hdr; -} __attribute__ ((packed)); - -struct rx80211packethdr { - struct rxpd rx_pd; - void *eth80211_hdr; -} __attribute__ ((packed)); - -static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb); - -/** - * @brief This function computes the avgSNR . - * - * @param priv A pointer to wlan_private structure - * @return avgSNR - */ -static u8 wlan_getavgsnr(wlan_private * priv) -{ - u8 i; - u16 temp = 0; - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF == 0) - return 0; - for (i = 0; i < adapter->numSNRNF; i++) - temp += adapter->rawSNR[i]; - return (u8) (temp / adapter->numSNRNF); - -} - -/** - * @brief This function computes the AvgNF - * - * @param priv A pointer to wlan_private structure - * @return AvgNF - */ -static u8 wlan_getavgnf(wlan_private * priv) -{ - u8 i; - u16 temp = 0; - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF == 0) - return 0; - for (i = 0; i < adapter->numSNRNF; i++) - temp += adapter->rawNF[i]; - return (u8) (temp / adapter->numSNRNF); - -} - -/** - * @brief This function save the raw SNR/NF to our internel buffer - * - * @param priv A pointer to wlan_private structure - * @param prxpd A pointer to rxpd structure of received packet - * @return n/a - */ -static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) -{ - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF < adapter->data_avg_factor) - adapter->numSNRNF++; - adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; - adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; - adapter->nextSNRNF++; - if (adapter->nextSNRNF >= adapter->data_avg_factor) - adapter->nextSNRNF = 0; - return; -} - -/** - * @brief This function computes the RSSI in received packet. - * - * @param priv A pointer to wlan_private structure - * @param prxpd A pointer to rxpd structure of received packet - * @return n/a - */ -static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) -{ - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf); - lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n", - adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - - adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; - adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; - wlan_save_rawSNRNF(priv, p_rx_pd); - - adapter->rxpd_rate = p_rx_pd->rx_rate; - - adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; - adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; - lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n", - adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - - adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = - CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], - adapter->NF[TYPE_RXPD][TYPE_NOAVG]); - - adapter->RSSI[TYPE_RXPD][TYPE_AVG] = - CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - - LEAVE(); -} - -int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) -{ - lbs_pr_debug(1, "skb->data=%p\n", skb->data); - - if(IS_MESH_FRAME(skb)) - skb->dev = priv->mesh_dev; - else - skb->dev = priv->wlan_dev.netdev; - skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev); - skb->ip_summed = CHECKSUM_UNNECESSARY; - - netif_rx(skb); - - return 0; -} - -/** - * @brief This function processes received packet and forwards it - * to kernel/upper layer - * - * @param priv A pointer to wlan_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 - */ -int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - struct rxpackethdr *p_rx_pkt; - struct rxpd *p_rx_pd; - - int hdrchop; - struct ethhdr *p_ethhdr; - - const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - - ENTER(); - - if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) - lbs_dbg_hex("RX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) - return process_rxed_802_11_packet(priv, skb); - - p_rx_pkt = (struct rxpackethdr *) skb->data; - p_rx_pd = &p_rx_pkt->rx_pd; - if (p_rx_pd->rx_control & RxPD_MESH_FRAME) - SET_MESH_FRAME(skb); - else - UNSET_MESH_FRAME(skb); - - lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, - min_t(unsigned int, skb->len, 100)); - - if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { - lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); - priv->stats.rx_length_errors++; - ret = 0; - goto done; - } - - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) { - lbs_pr_debug(1, "RX error: frame received with bad status\n"); - lbs_pr_alert("rxpd Not OK\n"); - priv->stats.rx_errors++; - ret = 0; - goto done; - } - - lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", - skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); - - lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, - sizeof(p_rx_pkt->eth803_hdr.dest_addr)); - lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, - sizeof(p_rx_pkt->eth803_hdr.src_addr)); - - if (memcmp(&p_rx_pkt->rfc1042_hdr, - rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { - /* - * Replace the 803 header and rfc1042 header (llc/snap) with an - * EthernetII header, keep the src/dst and snap_type (ethertype) - * - * The firmware only passes up SNAP frames converting - * all RX Data from 802.11 to 802.2/LLC/SNAP frames. - * - * To create the Ethernet II, just move the src, dst address right - * before the snap_type. - */ - p_ethhdr = (struct ethhdr *) - ((u8 *) & p_rx_pkt->eth803_hdr - + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) - - sizeof(p_rx_pkt->eth803_hdr.dest_addr) - - sizeof(p_rx_pkt->eth803_hdr.src_addr) - - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); - - memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, - sizeof(p_ethhdr->h_source)); - memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, - sizeof(p_ethhdr->h_dest)); - - /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header - * that was removed - */ - hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; - } else { - lbs_dbg_hex("RX Data: LLC/SNAP", - (u8 *) & p_rx_pkt->rfc1042_hdr, - sizeof(p_rx_pkt->rfc1042_hdr)); - - /* Chop off the rxpd */ - hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; - } - - /* Chop off the leading header bytes so the skb points to the start of - * either the reconstructed EthII frame or the 802.2/llc/snap frame - */ - skb_pull(skb, hdrchop); - - /* Take the data rate from the rxpd structure - * only if the rate is auto - */ - if (adapter->is_datarate_auto) - adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); - - wlan_compute_rssi(priv, p_rx_pd); - - lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); - if (libertas_upload_rx_packet(priv, skb)) { - lbs_pr_debug(1, "RX error: libertas_upload_rx_packet" - " returns failure\n"); - ret = -1; - goto done; - } - priv->stats.rx_bytes += skb->len; - priv->stats.rx_packets++; - - ret = 0; -done: - LEAVE(); - - return ret; -} - -/** - * @brief This function converts Tx/Rx rates from the Marvell WLAN format - * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) - * - * @param rate Input rate - * @return Output Rate (0 if invalid) - */ -static u8 convert_mv_rate_to_radiotap(u8 rate) -{ - switch (rate) { - case 0: /* 1 Mbps */ - return 2; - case 1: /* 2 Mbps */ - return 4; - case 2: /* 5.5 Mbps */ - return 11; - case 3: /* 11 Mbps */ - return 22; - case 4: /* 6 Mbps */ - return 12; - case 5: /* 9 Mbps */ - return 18; - case 6: /* 12 Mbps */ - return 24; - case 7: /* 18 Mbps */ - return 36; - case 8: /* 24 Mbps */ - return 48; - case 9: /* 36 Mbps */ - return 72; - case 10: /* 48 Mbps */ - return 96; - case 11: /* 54 Mbps */ - return 108; - } - lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate); - return 0; -} - -/** - * @brief This function processes a received 802.11 packet and forwards it - * to kernel/upper layer - * - * @param priv A pointer to wlan_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 - */ -static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - struct rx80211packethdr *p_rx_pkt; - struct rxpd *prxpd; - struct rx_radiotap_hdr radiotap_hdr; - struct rx_radiotap_hdr *pradiotap_hdr; - - ENTER(); - - p_rx_pkt = (struct rx80211packethdr *) skb->data; - prxpd = &p_rx_pkt->rx_pd; - - // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); - - if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { - lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); - priv->stats.rx_length_errors++; - ret = 0; - goto done; - } - - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) { - //lbs_pr_debug(1, "RX error: frame received with bad status\n"); - priv->stats.rx_errors++; - } - - lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", - skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); - - /* create the exported radio header */ - switch (priv->adapter->radiomode) { - case WLAN_RADIOMODE_NONE: - /* no radio header */ - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - break; - - case WLAN_RADIOMODE_RADIOTAP: - /* radiotap header */ - radiotap_hdr.hdr.it_version = 0; - /* XXX must check this value for pad */ - radiotap_hdr.hdr.it_pad = 0; - radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr); - radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; - /* unknown values */ - radiotap_hdr.flags = 0; - radiotap_hdr.chan_freq = 0; - radiotap_hdr.chan_flags = 0; - radiotap_hdr.antenna = 0; - /* known values */ - radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); - /* XXX must check no carryout */ - radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; - radiotap_hdr.rx_flags = 0; - if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) - radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; - //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); - - // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); - - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - - /* add space for the new radio header */ - if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && - pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, - GFP_ATOMIC)) { - lbs_pr_alert( "%s: couldn't pskb_expand_head\n", - __func__); - } - - pradiotap_hdr = - (struct rx_radiotap_hdr *)skb_push(skb, - sizeof(struct - rx_radiotap_hdr)); - memcpy(pradiotap_hdr, &radiotap_hdr, - sizeof(struct rx_radiotap_hdr)); - //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); - break; - - default: - /* unknown header */ - lbs_pr_alert( "Unknown radiomode (%i)\n", - priv->adapter->radiomode); - /* don't export any header */ - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - break; - } - - /* Take the data rate from the rxpd structure - * only if the rate is auto - */ - if (adapter->is_datarate_auto) { - adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); - } - - wlan_compute_rssi(priv, prxpd); - - lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); - - if (libertas_upload_rx_packet(priv, skb)) { - lbs_pr_debug(1, "RX error: libertas_upload_rx_packet " - "returns failure\n"); - ret = -1; - goto done; - } - - priv->stats.rx_bytes += skb->len; - priv->stats.rx_packets++; - - ret = 0; -done: - LEAVE(); - - skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ - - return (ret); -} diff --git a/trunk/drivers/net/wireless/libertas/sbi.h b/trunk/drivers/net/wireless/libertas/sbi.h deleted file mode 100644 index 59d3a59ccef0..000000000000 --- a/trunk/drivers/net/wireless/libertas/sbi.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file contains IF layer definitions. - */ - -#ifndef _SBI_H_ -#define _SBI_H_ - -#include - -#include "defs.h" - -/** INT status Bit Definition*/ -#define his_cmddnldrdy 0x01 -#define his_cardevent 0x02 -#define his_cmdupldrdy 0x04 - -#ifndef DEV_NAME_LEN -#define DEV_NAME_LEN 32 -#endif - -#define SBI_EVENT_CAUSE_SHIFT 3 - -/* Probe and Check if the card is present*/ -int libertas_sbi_register_dev(wlan_private * priv); -int libertas_sbi_unregister_dev(wlan_private *); -int libertas_sbi_get_int_status(wlan_private * priv, u8 *); -int libertas_sbi_register(void); -void libertas_sbi_unregister(void); -int libertas_sbi_prog_firmware(wlan_private *); - -int libertas_sbi_read_event_cause(wlan_private *); -int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); -wlan_private *libertas_sbi_get_priv(void *card); - -#ifdef ENABLE_PM -int libertas_sbi_suspend(wlan_private *); -int libertas_sbi_resume(wlan_private *); -#endif - -#endif /* _SBI_H */ diff --git a/trunk/drivers/net/wireless/libertas/scan.c b/trunk/drivers/net/wireless/libertas/scan.c deleted file mode 100644 index e18706238951..000000000000 --- a/trunk/drivers/net/wireless/libertas/scan.c +++ /dev/null @@ -1,2044 +0,0 @@ -/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ -/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ - -/** - * Functions implementing wlan scan IOCTL and firmware command APIs - * - * IOCTL handlers as well as command preperation and response routines - * for sending scan commands to the firmware. - */ -#include -#include -#include -#include - -#include -#include - -#include "host.h" -#include "decl.h" -#include "dev.h" -#include "scan.h" - -//! Approximate amount of data needed to pass a scan result back to iwlist -#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ - + IW_ESSID_MAX_SIZE \ - + IW_EV_UINT_LEN \ - + IW_EV_FREQ_LEN \ - + IW_EV_QUAL_LEN \ - + IW_ESSID_MAX_SIZE \ - + IW_EV_PARAM_LEN \ - + 40) /* 40 for WPAIE */ - -//! Memory needed to store a max sized channel List TLV for a firmware scan -#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ - + (MRVDRV_MAX_CHANNELS_PER_SCAN \ - * sizeof(struct chanscanparamset))) - -//! Memory needed to store a max number/size SSID TLV for a firmware scan -#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) - -//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max -#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ - + sizeof(struct mrvlietypes_numprobes) \ - + CHAN_TLV_MAX_SIZE \ - + SSID_TLV_MAX_SIZE) - -//! The maximum number of channels the firmware can scan per command -#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 - -/** - * @brief Number of channels to scan per firmware scan command issuance. - * - * Number restricted to prevent hitting the limit on the amount of scan data - * returned in a single firmware scan command. - */ -#define MRVDRV_CHANNELS_PER_SCAN_CMD 4 - -//! Scan time specified in the channel TLV for each channel for passive scans -#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 - -//! Scan time specified in the channel TLV for each channel for active scans -#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 - -//! Macro to enable/disable SSID checking before storing a scan table -#ifdef DISCARD_BAD_SSID -#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid) -#else -#define CHECK_SSID_IS_VALID(x) 1 -#endif - -/** - * @brief Check if a scanned network compatible with the driver settings - * - * WEP WPA WPA2 ad-hoc encrypt Network - * enabled enabled enabled AES mode privacy WPA WPA2 Compatible - * 0 0 0 0 NONE 0 0 0 yes No security - * 1 0 0 0 NONE 1 0 0 yes Static WEP - * 0 1 0 0 x 1x 1 x yes WPA - * 0 0 1 0 x 1x x 1 yes WPA2 - * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES - * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP - * - * - * @param adapter A pointer to wlan_adapter - * @param index Index in scantable to check against current driver settings - * @param mode Network mode: Infrastructure or IBSS - * - * @return Index in scantable, or error code if negative - */ -static int is_network_compatible(wlan_adapter * adapter, int index, int mode) -{ - ENTER(); - - if (adapter->scantable[index].inframode == mode) { - if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled - && adapter->scantable[index].wpa_supplicant.wpa_ie[0] != - WPA_IE - && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] != - WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE - && !adapter->scantable[index].privacy) { - /* no security */ - LEAVE(); - return index; - } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled - && adapter->scantable[index].privacy) { - /* static WEP enabled */ - LEAVE(); - return index; - } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled - && adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled - && (adapter->scantable[index].wpa_supplicant. - wpa_ie[0] - == WPA_IE) - /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && adapter->scantable[index].privacy */ - ) { - /* WPA enabled */ - lbs_pr_debug(1, - "is_network_compatible() WPA: index=%d wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " - "privacy=%#x\n", index, - adapter->scantable[index].wpa_supplicant. - wpa_ie[0], - adapter->scantable[index].wpa2_supplicant. - wpa_ie[0], - (adapter->secinfo.WEPstatus == - wlan802_11WEPenabled) ? "e" : "d", - (adapter->secinfo.WPAenabled) ? "e" : "d", - (adapter->secinfo.WPA2enabled) ? "e" : "d", - adapter->secinfo.Encryptionmode, - adapter->scantable[index].privacy); - LEAVE(); - return index; - } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled - && !adapter->secinfo.WPAenabled - && adapter->secinfo.WPA2enabled - && (adapter->scantable[index].wpa2_supplicant. - wpa_ie[0] - == WPA2_IE) - /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && adapter->scantable[index].privacy */ - ) { - /* WPA2 enabled */ - lbs_pr_debug(1, - "is_network_compatible() WPA2: index=%d wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " - "privacy=%#x\n", index, - adapter->scantable[index].wpa_supplicant. - wpa_ie[0], - adapter->scantable[index].wpa2_supplicant. - wpa_ie[0], - (adapter->secinfo.WEPstatus == - wlan802_11WEPenabled) ? "e" : "d", - (adapter->secinfo.WPAenabled) ? "e" : "d", - (adapter->secinfo.WPA2enabled) ? "e" : "d", - adapter->secinfo.Encryptionmode, - adapter->scantable[index].privacy); - LEAVE(); - return index; - } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled - && (adapter->scantable[index].wpa_supplicant. - wpa_ie[0] - != WPA_IE) - && (adapter->scantable[index].wpa2_supplicant. - wpa_ie[0] - != WPA2_IE) - && adapter->secinfo.Encryptionmode != CIPHER_NONE - && adapter->scantable[index].privacy) { - /* dynamic WEP enabled */ - lbs_pr_debug(1, - "is_network_compatible() dynamic WEP: index=%d " - "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n", - index, - adapter->scantable[index].wpa_supplicant. - wpa_ie[0], - adapter->scantable[index].wpa2_supplicant. - wpa_ie[0], adapter->secinfo.Encryptionmode, - adapter->scantable[index].privacy); - LEAVE(); - return index; - } - - /* security doesn't match */ - lbs_pr_debug(1, - "is_network_compatible() FAILED: index=%d wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n", - index, - adapter->scantable[index].wpa_supplicant.wpa_ie[0], - adapter->scantable[index].wpa2_supplicant.wpa_ie[0], - (adapter->secinfo.WEPstatus == - wlan802_11WEPenabled) ? "e" : "d", - (adapter->secinfo.WPAenabled) ? "e" : "d", - (adapter->secinfo.WPA2enabled) ? "e" : "d", - adapter->secinfo.Encryptionmode, - adapter->scantable[index].privacy); - LEAVE(); - return -ECONNREFUSED; - } - - /* mode doesn't match */ - LEAVE(); - return -ENETUNREACH; -} - -/** - * @brief This function validates a SSID as being able to be printed - * - * @param pssid SSID structure to validate - * - * @return TRUE or FALSE - */ -static u8 ssid_valid(struct WLAN_802_11_SSID *pssid) -{ - int ssididx; - - for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) { - if (!isprint(pssid->ssid[ssididx])) { - return 0; - } - } - - return 1; -} - -/** - * @brief Post process the scan table after a new scan command has completed - * - * Inspect each entry of the scan table and try to find an entry that - * matches our current associated/joined network from the scan. If - * one is found, update the stored copy of the bssdescriptor for our - * current network. - * - * Debug dump the current scan table contents if compiled accordingly. - * - * @param priv A pointer to wlan_private structure - * - * @return void - */ -static void wlan_scan_process_results(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int foundcurrent; - int i; - - foundcurrent = 0; - - if (adapter->connect_status == libertas_connected) { - /* try to find the current BSSID in the new scan list */ - for (i = 0; i < adapter->numinscantable; i++) { - if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, - &adapter->curbssparams.ssid) && - !memcmp(adapter->curbssparams.bssid, - adapter->scantable[i].macaddress, - ETH_ALEN)) { - foundcurrent = 1; - } - } - - if (foundcurrent) { - /* Make a copy of current BSSID descriptor */ - memcpy(&adapter->curbssparams.bssdescriptor, - &adapter->scantable[i], - sizeof(adapter->curbssparams.bssdescriptor)); - } - } - - for (i = 0; i < adapter->numinscantable; i++) { - lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, " - "RSSI[%03d], SSID[%s]\n", - i, - adapter->scantable[i].macaddress[0], - adapter->scantable[i].macaddress[1], - adapter->scantable[i].macaddress[2], - adapter->scantable[i].macaddress[3], - adapter->scantable[i].macaddress[4], - adapter->scantable[i].macaddress[5], - (s32) adapter->scantable[i].rssi, - adapter->scantable[i].ssid.ssid); - } -} - -/** - * @brief Create a channel list for the driver to scan based on region info - * - * Use the driver region/band information to construct a comprehensive list - * of channels to scan. This routine is used for any scan that is not - * provided a specific channel list to scan. - * - * @param priv A pointer to wlan_private structure - * @param scanchanlist Output parameter: resulting channel list to scan - * @param filteredscan Flag indicating whether or not a BSSID or SSID filter - * is being sent in the command to firmware. Used to - * increase the number of channels sent in a scan - * command and to disable the firmware channel scan - * filter. - * - * @return void - */ -static void wlan_scan_create_channel_list(wlan_private * priv, - struct chanscanparamset * scanchanlist, - u8 filteredscan) -{ - - wlan_adapter *adapter = priv->adapter; - struct region_channel *scanregion; - struct chan_freq_power *cfp; - int rgnidx; - int chanidx; - int nextchan; - u8 scantype; - - chanidx = 0; - - /* Set the default scan type to the user specified type, will later - * be changed to passive on a per channel basis if restricted by - * regulatory requirements (11d or 11h) - */ - scantype = adapter->scantype; - - for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { - if (priv->adapter->enable11d && - adapter->connect_status != libertas_connected) { - /* Scan all the supported chan for the first scan */ - if (!adapter->universal_channel[rgnidx].valid) - continue; - scanregion = &adapter->universal_channel[rgnidx]; - - /* clear the parsed_region_chan for the first scan */ - memset(&adapter->parsed_region_chan, 0x00, - sizeof(adapter->parsed_region_chan)); - } else { - if (!adapter->region_channel[rgnidx].valid) - continue; - scanregion = &adapter->region_channel[rgnidx]; - } - - for (nextchan = 0; - nextchan < scanregion->nrcfp; nextchan++, chanidx++) { - - cfp = scanregion->CFP + nextchan; - - if (priv->adapter->enable11d) { - scantype = - libertas_get_scan_type_11d(cfp->channel, - &adapter-> - parsed_region_chan); - } - - switch (scanregion->band) { - case BAND_B: - case BAND_G: - default: - scanchanlist[chanidx].radiotype = - cmd_scan_radio_type_bg; - break; - } - - if (scantype == cmd_scan_type_passive) { - scanchanlist[chanidx].maxscantime = - cpu_to_le16 - (MRVDRV_PASSIVE_SCAN_CHAN_TIME); - scanchanlist[chanidx].chanscanmode.passivescan = - 1; - } else { - scanchanlist[chanidx].maxscantime = - cpu_to_le16 - (MRVDRV_ACTIVE_SCAN_CHAN_TIME); - scanchanlist[chanidx].chanscanmode.passivescan = - 0; - } - - scanchanlist[chanidx].channumber = cfp->channel; - - if (filteredscan) { - scanchanlist[chanidx].chanscanmode. - disablechanfilt = 1; - } - } - } -} - -/** - * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds - * - * Application layer or other functions can invoke wlan_scan_networks - * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. - * This structure is used as the basis of one or many wlan_scan_cmd_config - * commands that are sent to the command processing module and sent to - * firmware. - * - * Create a wlan_scan_cmd_config based on the following user supplied - * parameters (if present): - * - SSID filter - * - BSSID filter - * - Number of Probes to be sent - * - channel list - * - * If the SSID or BSSID filter is not present, disable/clear the filter. - * If the number of probes is not set, use the adapter default setting - * Qualify the channel - * - * @param priv A pointer to wlan_private structure - * @param puserscanin NULL or pointer to scan configuration parameters - * @param ppchantlvout Output parameter: Pointer to the start of the - * channel TLV portion of the output scan config - * @param pscanchanlist Output parameter: Pointer to the resulting channel - * list to scan - * @param pmaxchanperscan Output parameter: Number of channels to scan for - * each issuance of the firmware scan command - * @param pfilteredscan Output parameter: Flag indicating whether or not - * a BSSID or SSID filter is being sent in the - * command to firmware. Used to increase the number - * of channels sent in a scan command and to - * disable the firmware channel scan filter. - * @param pscancurrentonly Output parameter: Flag indicating whether or not - * we are only scanning our current active channel - * - * @return resulting scan configuration - */ -static struct wlan_scan_cmd_config * -wlan_scan_setup_scan_config(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, - struct mrvlietypes_chanlistparamset ** ppchantlvout, - struct chanscanparamset * pscanchanlist, - int *pmaxchanperscan, - u8 * pfilteredscan, - u8 * pscancurrentonly) -{ - wlan_adapter *adapter = priv->adapter; - const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - struct mrvlietypes_numprobes *pnumprobestlv; - struct mrvlietypes_ssidparamset *pssidtlv; - struct wlan_scan_cmd_config * pscancfgout = NULL; - u8 *ptlvpos; - u16 numprobes; - u16 ssidlen; - int chanidx; - int scantype; - int scandur; - int channel; - int radiotype; - - pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); - if (pscancfgout == NULL) - goto out; - - /* The tlvbufferlen is calculated for each scan command. The TLVs added - * in this routine will be preserved since the routine that sends - * the command will append channelTLVs at *ppchantlvout. The difference - * between the *ppchantlvout and the tlvbuffer start will be used - * to calculate the size of anything we add in this routine. - */ - pscancfgout->tlvbufferlen = 0; - - /* Running tlv pointer. Assigned to ppchantlvout at end of function - * so later routines know where channels can be added to the command buf - */ - ptlvpos = pscancfgout->tlvbuffer; - - /* - * Set the initial scan paramters for progressive scanning. If a specific - * BSSID or SSID is used, the number of channels in the scan command - * will be increased to the absolute maximum - */ - *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD; - - /* Initialize the scan as un-filtered by firmware, set to TRUE below if - * a SSID or BSSID filter is sent in the command - */ - *pfilteredscan = 0; - - /* Initialize the scan as not being only on the current channel. If - * the channel list is customized, only contains one channel, and - * is the active channel, this is set true and data flow is not halted. - */ - *pscancurrentonly = 0; - - if (puserscanin) { - - /* Set the bss type scan filter, use adapter setting if unset */ - pscancfgout->bsstype = - (puserscanin->bsstype ? puserscanin->bsstype : adapter-> - scanmode); - - /* Set the number of probes to send, use adapter setting if unset */ - numprobes = (puserscanin->numprobes ? puserscanin->numprobes : - adapter->scanprobes); - - /* - * Set the BSSID filter to the incoming configuration, - * if non-zero. If not set, it will remain disabled (all zeros). - */ - memcpy(pscancfgout->specificBSSID, - puserscanin->specificBSSID, - sizeof(pscancfgout->specificBSSID)); - - ssidlen = strlen(puserscanin->specificSSID); - - if (ssidlen) { - pssidtlv = - (struct mrvlietypes_ssidparamset *) pscancfgout-> - tlvbuffer; - pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); - pssidtlv->header.len = cpu_to_le16(ssidlen); - memcpy(pssidtlv->ssid, puserscanin->specificSSID, - ssidlen); - ptlvpos += sizeof(pssidtlv->header) + ssidlen; - } - - /* - * The default number of channels sent in the command is low to - * ensure the response buffer from the firmware does not truncate - * scan results. That is not an issue with an SSID or BSSID - * filter applied to the scan results in the firmware. - */ - if (ssidlen || (memcmp(pscancfgout->specificBSSID, - &zeromac, sizeof(zeromac)) != 0)) { - *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; - *pfilteredscan = 1; - } - } else { - pscancfgout->bsstype = adapter->scanmode; - numprobes = adapter->scanprobes; - } - - /* If the input config or adapter has the number of Probes set, add tlv */ - if (numprobes) { - pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; - pnumprobestlv->header.type = - cpu_to_le16(TLV_TYPE_NUMPROBES); - pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes); - pnumprobestlv->numprobes = cpu_to_le16(numprobes); - - ptlvpos += - sizeof(pnumprobestlv->header) + pnumprobestlv->header.len; - - pnumprobestlv->header.len = - cpu_to_le16(pnumprobestlv->header.len); - } - - /* - * Set the output for the channel TLV to the address in the tlv buffer - * past any TLVs that were added in this fuction (SSID, numprobes). - * channel TLVs will be added past this for each scan command, preserving - * the TLVs that were previously added. - */ - *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; - - if (puserscanin && puserscanin->chanlist[0].channumber) { - - lbs_pr_debug(1, "Scan: Using supplied channel list\n"); - - for (chanidx = 0; - chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX - && puserscanin->chanlist[chanidx].channumber; chanidx++) { - - channel = puserscanin->chanlist[chanidx].channumber; - (pscanchanlist + chanidx)->channumber = channel; - - radiotype = puserscanin->chanlist[chanidx].radiotype; - (pscanchanlist + chanidx)->radiotype = radiotype; - - scantype = puserscanin->chanlist[chanidx].scantype; - - if (scantype == cmd_scan_type_passive) { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 1; - } else { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 0; - } - - if (puserscanin->chanlist[chanidx].scantime) { - scandur = - puserscanin->chanlist[chanidx].scantime; - } else { - if (scantype == cmd_scan_type_passive) { - scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; - } else { - scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; - } - } - - (pscanchanlist + chanidx)->minscantime = - cpu_to_le16(scandur); - (pscanchanlist + chanidx)->maxscantime = - cpu_to_le16(scandur); - } - - /* Check if we are only scanning the current channel */ - if ((chanidx == 1) && (puserscanin->chanlist[0].channumber - == - priv->adapter->curbssparams.channel)) { - *pscancurrentonly = 1; - lbs_pr_debug(1, "Scan: Scanning current channel only"); - } - - } else { - lbs_pr_debug(1, "Scan: Creating full region channel list\n"); - wlan_scan_create_channel_list(priv, pscanchanlist, - *pfilteredscan); - } - -out: - return pscancfgout; -} - -/** - * @brief Construct and send multiple scan config commands to the firmware - * - * Previous routines have created a wlan_scan_cmd_config with any requested - * TLVs. This function splits the channel TLV into maxchanperscan lists - * and sends the portion of the channel TLV along with the other TLVs - * to the wlan_cmd routines for execution in the firmware. - * - * @param priv A pointer to wlan_private structure - * @param maxchanperscan Maximum number channels to be included in each - * scan command sent to firmware - * @param filteredscan Flag indicating whether or not a BSSID or SSID - * filter is being used for the firmware command - * scan command sent to firmware - * @param pscancfgout Scan configuration used for this scan. - * @param pchantlvout Pointer in the pscancfgout where the channel TLV - * should start. This is past any other TLVs that - * must be sent down in each firmware command. - * @param pscanchanlist List of channels to scan in maxchanperscan segments - * - * @return 0 or error return otherwise - */ -static int wlan_scan_channel_list(wlan_private * priv, - int maxchanperscan, - u8 filteredscan, - struct wlan_scan_cmd_config * pscancfgout, - struct mrvlietypes_chanlistparamset * pchantlvout, - struct chanscanparamset * pscanchanlist) -{ - struct chanscanparamset *ptmpchan; - struct chanscanparamset *pstartchan; - u8 scanband; - int doneearly; - int tlvidx; - int ret = 0; - - ENTER(); - - if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) { - lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n", - pscancfgout, pchantlvout, pscanchanlist); - return -1; - } - - pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); - - /* Set the temp channel struct pointer to the start of the desired list */ - ptmpchan = pscanchanlist; - - /* Loop through the desired channel list, sending a new firmware scan - * commands for each maxchanperscan channels (or for 1,6,11 individually - * if configured accordingly) - */ - while (ptmpchan->channumber) { - - tlvidx = 0; - pchantlvout->header.len = 0; - scanband = ptmpchan->radiotype; - pstartchan = ptmpchan; - doneearly = 0; - - /* Construct the channel TLV for the scan command. Continue to - * insert channel TLVs until: - * - the tlvidx hits the maximum configured per scan command - * - the next channel to insert is 0 (end of desired channel list) - * - doneearly is set (controlling individual scanning of 1,6,11) - */ - while (tlvidx < maxchanperscan && ptmpchan->channumber - && !doneearly) { - - lbs_pr_debug(1, - "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", - ptmpchan->channumber, ptmpchan->radiotype, - ptmpchan->chanscanmode.passivescan, - ptmpchan->chanscanmode.disablechanfilt, - ptmpchan->maxscantime); - - /* Copy the current channel TLV to the command being prepared */ - memcpy(pchantlvout->chanscanparam + tlvidx, - ptmpchan, sizeof(pchantlvout->chanscanparam)); - - /* Increment the TLV header length by the size appended */ - pchantlvout->header.len += - sizeof(pchantlvout->chanscanparam); - - /* - * The tlv buffer length is set to the number of bytes of the - * between the channel tlv pointer and the start of the - * tlv buffer. This compensates for any TLVs that were appended - * before the channel list. - */ - pscancfgout->tlvbufferlen = ((u8 *) pchantlvout - - pscancfgout->tlvbuffer); - - /* Add the size of the channel tlv header and the data length */ - pscancfgout->tlvbufferlen += - (sizeof(pchantlvout->header) - + pchantlvout->header.len); - - /* Increment the index to the channel tlv we are constructing */ - tlvidx++; - - doneearly = 0; - - /* Stop the loop if the *current* channel is in the 1,6,11 set - * and we are not filtering on a BSSID or SSID. - */ - if (!filteredscan && (ptmpchan->channumber == 1 - || ptmpchan->channumber == 6 - || ptmpchan->channumber == 11)) { - doneearly = 1; - } - - /* Increment the tmp pointer to the next channel to be scanned */ - ptmpchan++; - - /* Stop the loop if the *next* channel is in the 1,6,11 set. - * This will cause it to be the only channel scanned on the next - * interation - */ - if (!filteredscan && (ptmpchan->channumber == 1 - || ptmpchan->channumber == 6 - || ptmpchan->channumber == 11)) { - doneearly = 1; - } - } - - /* Send the scan command to the firmware with the specified cfg */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0, - 0, 0, pscancfgout); - } - - LEAVE(); - return ret; -} - -/** - * @brief Internal function used to start a scan based on an input config - * - * Use the input user scan configuration information when provided in - * order to send the appropriate scan commands to firmware to populate or - * update the internal driver scan table - * - * @param priv A pointer to wlan_private structure - * @param puserscanin Pointer to the input configuration for the requested - * scan. - * - * @return 0 or < 0 if error - */ -int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin) -{ - wlan_adapter *adapter = priv->adapter; - struct mrvlietypes_chanlistparamset *pchantlvout; - struct chanscanparamset * scan_chan_list = NULL; - struct wlan_scan_cmd_config * scan_cfg = NULL; - u8 keeppreviousscan; - u8 filteredscan; - u8 scancurrentchanonly; - int maxchanperscan; - int ret; - - ENTER(); - - scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * - WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); - if (scan_chan_list == NULL) { - ret = -ENOMEM; - goto out; - } - - scan_cfg = wlan_scan_setup_scan_config(priv, - puserscanin, - &pchantlvout, - scan_chan_list, - &maxchanperscan, - &filteredscan, - &scancurrentchanonly); - if (scan_cfg == NULL) { - ret = -ENOMEM; - goto out; - } - - keeppreviousscan = 0; - - if (puserscanin) { - keeppreviousscan = puserscanin->keeppreviousscan; - } - - if (!keeppreviousscan) { - memset(adapter->scantable, 0x00, - sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST); - adapter->numinscantable = 0; - } - - /* Keep the data path active if we are only scanning our current channel */ - if (!scancurrentchanonly) { - netif_stop_queue(priv->wlan_dev.netdev); - netif_carrier_off(priv->wlan_dev.netdev); - } - - ret = wlan_scan_channel_list(priv, - maxchanperscan, - filteredscan, - scan_cfg, - pchantlvout, - scan_chan_list); - - /* Process the resulting scan table: - * - Remove any bad ssids - * - Update our current BSS information from scan data - */ - wlan_scan_process_results(priv); - - if (priv->adapter->connect_status == libertas_connected) { - netif_carrier_on(priv->wlan_dev.netdev); - netif_wake_queue(priv->wlan_dev.netdev); - } - -out: - if (scan_cfg) - kfree(scan_cfg); - - if (scan_chan_list) - kfree(scan_chan_list); - - LEAVE(); - return ret; -} - -/** - * @brief Inspect the scan response buffer for pointers to expected TLVs - * - * TLVs can be included at the end of the scan response BSS information. - * Parse the data in the buffer for pointers to TLVs that can potentially - * be passed back in the response - * - * @param ptlv Pointer to the start of the TLV buffer to parse - * @param tlvbufsize size of the TLV buffer - * @param ptsftlv Output parameter: Pointer to the TSF TLV if found - * - * @return void - */ -static -void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, - int tlvbufsize, - struct mrvlietypes_tsftimestamp ** ptsftlv) -{ - struct mrvlietypes_data *pcurrenttlv; - int tlvbufleft; - u16 tlvtype; - u16 tlvlen; - - pcurrenttlv = ptlv; - tlvbufleft = tlvbufsize; - *ptsftlv = NULL; - - lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); - lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); - - while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { - tlvtype = le16_to_cpu(pcurrenttlv->header.type); - tlvlen = le16_to_cpu(pcurrenttlv->header.len); - - switch (tlvtype) { - case TLV_TYPE_TSFTIMESTAMP: - *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv; - break; - - default: - lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n", - tlvtype); - /* Give up, this seems corrupted */ - return; - } /* switch */ - - tlvbufleft -= (sizeof(ptlv->header) + tlvlen); - pcurrenttlv = - (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen); - } /* while */ -} - -/** - * @brief Interpret a BSS scan response returned from the firmware - * - * Parse the various fixed fields and IEs passed back for a a BSS probe - * response or beacon from the scan command. Record information as needed - * in the scan table struct bss_descriptor for that entry. - * - * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry - * - * @return 0 or -1 - */ -static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, - u8 ** pbeaconinfo, int *bytesleft) -{ - enum ieeetypes_elementid elemID; - struct ieeetypes_fhparamset *pFH; - struct ieeetypes_dsparamset *pDS; - struct ieeetypes_cfparamset *pCF; - struct ieeetypes_ibssparamset *pibss; - struct ieeetypes_capinfo *pcap; - struct WLAN_802_11_FIXED_IEs fixedie; - u8 *pcurrentptr; - u8 *pRate; - u8 elemlen; - u8 bytestocopy; - u8 ratesize; - u16 beaconsize; - u8 founddatarateie; - int bytesleftforcurrentbeacon; - - struct WPA_SUPPLICANT *pwpa_supplicant; - struct WPA_SUPPLICANT *pwpa2_supplicant; - struct IE_WPA *pIe; - const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; - - struct ieeetypes_countryinfoset *pcountryinfo; - - ENTER(); - - founddatarateie = 0; - ratesize = 0; - beaconsize = 0; - - if (*bytesleft >= sizeof(beaconsize)) { - /* Extract & convert beacon size from the command buffer */ - memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize)); - beaconsize = le16_to_cpu(beaconsize); - *bytesleft -= sizeof(beaconsize); - *pbeaconinfo += sizeof(beaconsize); - } - - if (beaconsize == 0 || beaconsize > *bytesleft) { - - *pbeaconinfo += *bytesleft; - *bytesleft = 0; - - return -1; - } - - /* Initialize the current working beacon pointer for this BSS iteration */ - pcurrentptr = *pbeaconinfo; - - /* Advance the return beacon pointer past the current beacon */ - *pbeaconinfo += beaconsize; - *bytesleft -= beaconsize; - - bytesleftforcurrentbeacon = beaconsize; - - pwpa_supplicant = &pBSSEntry->wpa_supplicant; - pwpa2_supplicant = &pBSSEntry->wpa2_supplicant; - - memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN); - lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n", - pBSSEntry->macaddress[0], pBSSEntry->macaddress[1], - pBSSEntry->macaddress[2], pBSSEntry->macaddress[3], - pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]); - - pcurrentptr += ETH_ALEN; - bytesleftforcurrentbeacon -= ETH_ALEN; - - if (bytesleftforcurrentbeacon < 12) { - lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n"); - return -1; - } - - /* - * next 4 fields are RSSI, time stamp, beacon interval, - * and capability information - */ - - /* RSSI is 1 byte long */ - pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr)); - lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr); - pcurrentptr += 1; - bytesleftforcurrentbeacon -= 1; - - /* time stamp is 8 bytes long */ - memcpy(fixedie.timestamp, pcurrentptr, 8); - memcpy(pBSSEntry->timestamp, pcurrentptr, 8); - pcurrentptr += 8; - bytesleftforcurrentbeacon -= 8; - - /* beacon interval is 2 bytes long */ - memcpy(&fixedie.beaconinterval, pcurrentptr, 2); - pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; - - /* capability information is 2 bytes long */ - memcpy(&fixedie.capabilities, pcurrentptr, 2); - lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n", - fixedie.capabilities); - fixedie.capabilities = le16_to_cpu(fixedie.capabilities); - pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; - memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo)); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; - - /* rest of the current buffer are IE's */ - lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n", - bytesleftforcurrentbeacon); - - lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr, - bytesleftforcurrentbeacon); - - if (pcap->privacy) { - lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n"); - pBSSEntry->privacy = wlan802_11privfilter8021xWEP; - } else { - pBSSEntry->privacy = wlan802_11privfilteracceptall; - } - - if (pcap->ibss == 1) { - pBSSEntry->inframode = wlan802_11ibss; - } else { - pBSSEntry->inframode = wlan802_11infrastructure; - } - - /* process variable IE */ - while (bytesleftforcurrentbeacon >= 2) { - elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); - elemlen = *((u8 *) pcurrentptr + 1); - - if (bytesleftforcurrentbeacon < elemlen) { - lbs_pr_debug(1, "InterpretIE: error in processing IE, " - "bytes left < IE length\n"); - bytesleftforcurrentbeacon = 0; - continue; - } - - switch (elemID) { - - case SSID: - pBSSEntry->ssid.ssidlength = elemlen; - memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2), - elemlen); - lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid); - break; - - case SUPPORTED_RATES: - memcpy(pBSSEntry->datarates, (pcurrentptr + 2), - elemlen); - memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2), - elemlen); - ratesize = elemlen; - founddatarateie = 1; - break; - - case EXTRA_IE: - lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n"); - pBSSEntry->extra_ie = 1; - break; - - case FH_PARAM_SET: - pFH = (struct ieeetypes_fhparamset *) pcurrentptr; - memmove(&pBSSEntry->phyparamset.fhparamset, pFH, - sizeof(struct ieeetypes_fhparamset)); - pBSSEntry->phyparamset.fhparamset.dwelltime - = - le16_to_cpu(pBSSEntry->phyparamset.fhparamset. - dwelltime); - break; - - case DS_PARAM_SET: - pDS = (struct ieeetypes_dsparamset *) pcurrentptr; - - pBSSEntry->channel = pDS->currentchan; - - memcpy(&pBSSEntry->phyparamset.dsparamset, pDS, - sizeof(struct ieeetypes_dsparamset)); - break; - - case CF_PARAM_SET: - pCF = (struct ieeetypes_cfparamset *) pcurrentptr; - - memcpy(&pBSSEntry->ssparamset.cfparamset, pCF, - sizeof(struct ieeetypes_cfparamset)); - break; - - case IBSS_PARAM_SET: - pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; - pBSSEntry->atimwindow = - le32_to_cpu(pibss->atimwindow); - - memmove(&pBSSEntry->ssparamset.ibssparamset, pibss, - sizeof(struct ieeetypes_ibssparamset)); - - pBSSEntry->ssparamset.ibssparamset.atimwindow - = - le16_to_cpu(pBSSEntry->ssparamset.ibssparamset. - atimwindow); - break; - - /* Handle Country Info IE */ - case COUNTRY_INFO: - pcountryinfo = - (struct ieeetypes_countryinfoset *) pcurrentptr; - - if (pcountryinfo->len < - sizeof(pcountryinfo->countrycode) - || pcountryinfo->len > 254) { - lbs_pr_debug(1, "InterpretIE: 11D- Err " - "CountryInfo len =%d min=%d max=254\n", - pcountryinfo->len, - sizeof(pcountryinfo->countrycode)); - LEAVE(); - return -1; - } - - memcpy(&pBSSEntry->countryinfo, - pcountryinfo, pcountryinfo->len + 2); - lbs_dbg_hex("InterpretIE: 11D- CountryInfo:", - (u8 *) pcountryinfo, - (u32) (pcountryinfo->len + 2)); - break; - - case EXTENDED_SUPPORTED_RATES: - /* - * only process extended supported rate - * if data rate is already found. - * data rate IE should come before - * extended supported rate IE - */ - if (founddatarateie) { - if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) { - bytestocopy = - (WLAN_SUPPORTED_RATES - ratesize); - } else { - bytestocopy = elemlen; - } - - pRate = (u8 *) pBSSEntry->datarates; - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); - - pRate = (u8 *) pBSSEntry->libertas_supported_rates; - - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); - } - break; - - case VENDOR_SPECIFIC_221: -#define IE_ID_LEN_FIELDS_BYTES 2 - pIe = (struct IE_WPA *)pcurrentptr; - - if (!memcmp(pIe->oui, oui01, sizeof(oui01))) { - pwpa_supplicant->wpa_ie_len - = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, - sizeof(pwpa_supplicant->wpa_ie)); - memcpy(pwpa_supplicant->wpa_ie, - pcurrentptr, - pwpa_supplicant->wpa_ie_len); - lbs_dbg_hex("InterpretIE: Resp WPA_IE", - pwpa_supplicant->wpa_ie, elemlen); - } - break; - case WPA2_IE: - pIe = (struct IE_WPA *)pcurrentptr; - pwpa2_supplicant->wpa_ie_len - = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, - sizeof(pwpa2_supplicant->wpa_ie)); - memcpy(pwpa2_supplicant->wpa_ie, - pcurrentptr, pwpa2_supplicant->wpa_ie_len); - - lbs_dbg_hex("InterpretIE: Resp WPA2_IE", - pwpa2_supplicant->wpa_ie, elemlen); - break; - case TIM: - break; - - case CHALLENGE_TEXT: - break; - } - - pcurrentptr += elemlen + 2; - - /* need to account for IE ID and IE len */ - bytesleftforcurrentbeacon -= (elemlen + 2); - - } /* while (bytesleftforcurrentbeacon > 2) */ - - return 0; -} - -/** - * @brief Compare two SSIDs - * - * @param ssid1 A pointer to ssid to compare - * @param ssid2 A pointer to ssid to compare - * - * @return 0--ssid is same, otherwise is different - */ -int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2) -{ - if (!ssid1 || !ssid2) - return -1; - - if (ssid1->ssidlength != ssid2->ssidlength) - return -1; - - return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength); -} - -/** - * @brief This function finds a specific compatible BSSID in the scan list - * - * @param adapter A pointer to wlan_adapter - * @param bssid BSSID to find in the scan list - * @param mode Network mode: Infrastructure or IBSS - * - * @return index in BSSID list, or error return code (< 0) - */ -int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode) -{ - int ret = -ENETUNREACH; - int i; - - if (!bssid) - return -EFAULT; - - lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n", - adapter->numinscantable); - - /* Look through the scan table for a compatible match. The ret return - * variable will be equal to the index in the scan table (greater - * than zero) if the network is compatible. The loop will continue - * past a matched bssid that is not compatible in case there is an - * AP with multiple SSIDs assigned to the same BSSID - */ - for (i = 0; ret < 0 && i < adapter->numinscantable; i++) { - if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) { - switch (mode) { - case wlan802_11infrastructure: - case wlan802_11ibss: - ret = is_network_compatible(adapter, i, mode); - break; - default: - ret = i; - break; - } - } - } - - return ret; -} - -/** - * @brief This function finds ssid in ssid list. - * - * @param adapter A pointer to wlan_adapter - * @param ssid SSID to find in the list - * @param bssid BSSID to qualify the SSID selection (if provided) - * @param mode Network mode: Infrastructure or IBSS - * - * @return index in BSSID list - */ -int libertas_find_SSID_in_list(wlan_adapter * adapter, - struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode) -{ - int net = -ENETUNREACH; - u8 bestrssi = 0; - int i; - int j; - - lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable); - - for (i = 0; i < adapter->numinscantable; i++) { - if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) && - (!bssid || - !memcmp(adapter->scantable[i]. - macaddress, bssid, ETH_ALEN))) { - switch (mode) { - case wlan802_11infrastructure: - case wlan802_11ibss: - j = is_network_compatible(adapter, i, mode); - - if (j >= 0) { - if (bssid) { - return i; - } - - if (SCAN_RSSI - (adapter->scantable[i].rssi) - > bestrssi) { - bestrssi = - SCAN_RSSI(adapter-> - scantable[i]. - rssi); - net = i; - } - } else { - if (net == -ENETUNREACH) { - net = j; - } - } - break; - case wlan802_11autounknown: - default: - if (SCAN_RSSI(adapter->scantable[i].rssi) - > bestrssi) { - bestrssi = - SCAN_RSSI(adapter->scantable[i]. - rssi); - net = i; - } - break; - } - } - } - - return net; -} - -/** - * @brief This function finds the best SSID in the Scan List - * - * Search the scan table for the best SSID that also matches the current - * adapter network preference (infrastructure or adhoc) - * - * @param adapter A pointer to wlan_adapter - * - * @return index in BSSID list - */ -int libertas_find_best_SSID_in_list(wlan_adapter * adapter, - enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode) -{ - int bestnet = -ENETUNREACH; - u8 bestrssi = 0; - int i; - - ENTER(); - - lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable); - - for (i = 0; i < adapter->numinscantable; i++) { - switch (mode) { - case wlan802_11infrastructure: - case wlan802_11ibss: - if (is_network_compatible(adapter, i, mode) >= 0) { - if (SCAN_RSSI(adapter->scantable[i].rssi) > - bestrssi) { - bestrssi = - SCAN_RSSI(adapter->scantable[i]. - rssi); - bestnet = i; - } - } - break; - case wlan802_11autounknown: - default: - if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) { - bestrssi = - SCAN_RSSI(adapter->scantable[i].rssi); - bestnet = i; - } - break; - } - } - - LEAVE(); - return bestnet; -} - -/** - * @brief Find the AP with specific ssid in the scan list - * - * @param priv A pointer to wlan_private structure - * @param pSSID A pointer to AP's ssid - * - * @return 0--success, otherwise--fail - */ -int libertas_find_best_network_SSID(wlan_private * priv, - struct WLAN_802_11_SSID *pSSID, - enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, - enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - struct bss_descriptor *preqbssid; - int i; - - ENTER(); - - memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID)); - - wlan_scan_networks(priv, NULL); - if (adapter->surpriseremoved) - return -1; - wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); - - i = libertas_find_best_SSID_in_list(adapter, preferred_mode); - if (i < 0) { - ret = -1; - goto out; - } - - preqbssid = &adapter->scantable[i]; - memcpy(pSSID, &preqbssid->ssid, - sizeof(struct WLAN_802_11_SSID)); - *out_mode = preqbssid->inframode; - - if (!pSSID->ssidlength) { - ret = -1; - } - -out: - LEAVE(); - return ret; -} - -/** - * @brief Scan Network - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * - * @return 0 --success, otherwise fail - */ -int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - union iwreq_data wrqu; - - ENTER(); - - if (!wlan_scan_networks(priv, NULL)) { - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, - NULL); - } - - if (adapter->surpriseremoved) - return -1; - - LEAVE(); - return 0; -} - -/** - * @brief Send a scan command for all available channels filtered on a spec - * - * @param priv A pointer to wlan_private structure - * @param prequestedssid A pointer to AP's ssid - * @param keeppreviousscan Flag used to save/clear scan table before scan - * - * @return 0-success, otherwise fail - */ -int libertas_send_specific_SSID_scan(wlan_private * priv, - struct WLAN_802_11_SSID *prequestedssid, - u8 keeppreviousscan) -{ - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_user_scan_cfg scancfg; - - ENTER(); - - if (prequestedssid == NULL) { - return -1; - } - - memset(&scancfg, 0x00, sizeof(scancfg)); - - memcpy(scancfg.specificSSID, prequestedssid->ssid, - prequestedssid->ssidlength); - scancfg.keeppreviousscan = keeppreviousscan; - - wlan_scan_networks(priv, &scancfg); - if (adapter->surpriseremoved) - return -1; - wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); - - LEAVE(); - return 0; -} - -/** - * @brief scan an AP with specific BSSID - * - * @param priv A pointer to wlan_private structure - * @param bssid A pointer to AP's bssid - * @param keeppreviousscan Flag used to save/clear scan table before scan - * - * @return 0-success, otherwise fail - */ -int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan) -{ - struct wlan_ioctl_user_scan_cfg scancfg; - - ENTER(); - - if (bssid == NULL) { - return -1; - } - - memset(&scancfg, 0x00, sizeof(scancfg)); - memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID)); - scancfg.keeppreviousscan = keeppreviousscan; - - wlan_scan_networks(priv, &scancfg); - if (priv->adapter->surpriseremoved) - return -1; - wait_event_interruptible(priv->adapter->cmd_pending, - !priv->adapter->nr_cmd_pending); - - LEAVE(); - return 0; -} - -/** - * @brief Retrieve the scan table entries via wireless tools IOCTL call - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param dwrq A pointer to iw_point structure - * @param extra A pointer to extra data buf - * - * @return 0 --success, otherwise fail - */ -int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - char *current_ev = extra; - char *end_buf = extra + IW_SCAN_MAX_DATA; - struct chan_freq_power *cfp; - struct bss_descriptor *pscantable; - char *current_val; /* For rates */ - struct iw_event iwe; /* Temporary buffer */ - int i; - int j; - int rate; -#define PERFECT_RSSI ((u8)50) -#define WORST_RSSI ((u8)0) -#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) - u8 rssi; - - u8 buf[16 + 256 * 2]; - u8 *ptr; - - ENTER(); - - /* - * if there's either commands in the queue or one being - * processed return -EAGAIN for iwlist to retry later. - */ - if (adapter->nr_cmd_pending) - return -EAGAIN; - - if (adapter->connect_status == libertas_connected) - lbs_pr_debug(1, "Current ssid: %32s\n", - adapter->curbssparams.ssid.ssid); - - lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n", - adapter->numinscantable); - - /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. - * The new API using SIOCGIWSCAN is only limited by buffer size - * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes - * which is 4096. - */ - for (i = 0; i < adapter->numinscantable; i++) { - if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { - lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p " - "MAX_SCAN_CELL_SIZE=%d\n", - i, current_ev, end_buf, MAX_SCAN_CELL_SIZE); - break; - } - - pscantable = &adapter->scantable[i]; - - lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid); - - cfp = - libertas_find_cfp_by_band_and_channel(adapter, 0, - pscantable->channel); - if (!cfp) { - lbs_pr_debug(1, "Invalid channel number %d\n", - pscantable->channel); - continue; - } - - if (!ssid_valid(&adapter->scantable[i].ssid)) { - continue; - } - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, - &adapter->scantable[i].macaddress, ETH_ALEN); - - iwe.len = IW_EV_ADDR_LEN; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); - - //Add the ESSID - iwe.u.data.length = adapter->scantable[i].ssid.ssidlength; - - if (iwe.u.data.length > 32) { - iwe.u.data.length = 32; - } - - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - adapter->scantable[i].ssid. - ssid); - - //Add mode - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = adapter->scantable[i].inframode + 1; - iwe.len = IW_EV_UINT_LEN; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); - - //frequency - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = (long)cfp->freq * 100000; - iwe.u.freq.e = 1; - iwe.len = IW_EV_FREQ_LEN; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; - iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi); - - rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; - iwe.u.qual.qual = - (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * - (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / - (RSSI_DIFF * RSSI_DIFF); - if (iwe.u.qual.qual > 100) - iwe.u.qual.qual = 100; - else if (iwe.u.qual.qual < 1) - iwe.u.qual.qual = 0; - - if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { - iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; - } else { - iwe.u.qual.noise = - CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); - } - if ((adapter->inframode == wlan802_11ibss) && - !libertas_SSID_cmp(&adapter->curbssparams.ssid, - &adapter->scantable[i].ssid) - && adapter->adhoccreate) { - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, - cmd_option_waitforrsp, - 0, NULL); - - if (!ret) { - iwe.u.qual.level = - CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / - AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / - AVG_SCALE); - } - } - iwe.len = IW_EV_QUAL_LEN; - current_ev = - iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (adapter->scantable[i].privacy) { - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - } else { - iwe.u.data.flags = IW_ENCODE_DISABLED; - } - iwe.u.data.length = 0; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - adapter->scantable->ssid. - ssid); - - current_val = current_ev + IW_EV_LCP_LEN; - - iwe.cmd = SIOCGIWRATE; - - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - iwe.u.bitrate.value = 0; - - /* Bit rate given in 500 kb/s units (+ 0x80) */ - for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates); - j++) { - if (adapter->scantable[i].libertas_supported_rates[j] == 0) { - break; - } - rate = - (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) * - 500000; - if (rate > iwe.u.bitrate.value) { - iwe.u.bitrate.value = rate; - } - - iwe.u.bitrate.value = - (adapter->scantable[i].libertas_supported_rates[j] - & 0x7f) * 500000; - iwe.len = IW_EV_PARAM_LEN; - current_ev = - iwe_stream_add_value(current_ev, current_val, - end_buf, &iwe, iwe.len); - - } - if ((adapter->scantable[i].inframode == wlan802_11ibss) - && !libertas_SSID_cmp(&adapter->curbssparams.ssid, - &adapter->scantable[i].ssid) - && adapter->adhoccreate) { - iwe.u.bitrate.value = 22 * 500000; - } - iwe.len = IW_EV_PARAM_LEN; - current_ev = - iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, - iwe.len); - - /* Add new value to event */ - current_val = current_ev + IW_EV_LCP_LEN; - - if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) { - memset(&iwe, 0, sizeof(iwe)); - memset(buf, 0, sizeof(buf)); - memcpy(buf, adapter->scantable[i]. - wpa2_supplicant.wpa_ie, - adapter->scantable[i].wpa2_supplicant. - wpa_ie_len); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = adapter->scantable[i]. - wpa2_supplicant.wpa_ie_len; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - } - if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) { - memset(&iwe, 0, sizeof(iwe)); - memset(buf, 0, sizeof(buf)); - memcpy(buf, adapter->scantable[i]. - wpa_supplicant.wpa_ie, - adapter->scantable[i].wpa_supplicant. - wpa_ie_len); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = adapter->scantable[i]. - wpa_supplicant.wpa_ie_len; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - } - - - if (adapter->scantable[i].extra_ie != 0) { - memset(&iwe, 0, sizeof(iwe)); - memset(buf, 0, sizeof(buf)); - ptr = buf; - ptr += sprintf(ptr, "extra_ie"); - iwe.u.data.length = strlen(buf); - - lbs_pr_debug(1, "iwe.u.data.length %d\n", - iwe.u.data.length); - lbs_pr_debug(1, "BUF: %s \n", buf); - - iwe.cmd = IWEVCUSTOM; - iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; - current_ev = - iwe_stream_add_point(current_ev, end_buf, &iwe, - buf); - } - - current_val = current_ev + IW_EV_LCP_LEN; - - /* - * Check if we added any event - */ - if ((current_val - current_ev) > IW_EV_LCP_LEN) - current_ev = current_val; - } - - dwrq->length = (current_ev - extra); - dwrq->flags = 0; - - LEAVE(); - return 0; -} - -/** - * @brief Prepare a scan command to be sent to the firmware - * - * Use the wlan_scan_cmd_config sent to the command processing module in - * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command - * struct to send to firmware. - * - * The fixed fields specifying the BSS type and BSSID filters as well as a - * variable number/length of TLVs are sent in the command to firmware. - * - * @param priv A pointer to wlan_private structure - * @param cmd A pointer to cmd_ds_command structure to be sent to - * firmware with the cmd_DS_801_11_SCAN structure - * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used - * to set the fields/TLVs for the command sent to firmware - * - * @return 0 or -1 - * - * @sa wlan_scan_create_channel_list - */ -int libertas_cmd_80211_scan(wlan_private * priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct wlan_scan_cmd_config *pscancfg; - - ENTER(); - - pscancfg = pdata_buf; - - /* Set fixed field variables in scan command */ - pscan->bsstype = pscancfg->bsstype; - memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID)); - memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); - - cmd->command = cpu_to_le16(cmd_802_11_scan); - - /* size is equal to the sizeof(fixed portions) + the TLV len + header */ - cmd->size = cpu_to_le16(sizeof(pscan->bsstype) - + sizeof(pscan->BSSID) - + pscancfg->tlvbufferlen + S_DS_GEN); - - lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n", - cmd->command, cmd->size, cmd->seqnum); - LEAVE(); - return 0; -} - -/** - * @brief This function handles the command response of scan - * - * The response buffer for the scan command has the following - * memory layout: - * - * .-----------------------------------------------------------. - * | header (4 * sizeof(u16)): Standard command response hdr | - * .-----------------------------------------------------------. - * | bufsize (u16) : sizeof the BSS Description data | - * .-----------------------------------------------------------. - * | NumOfSet (u8) : Number of BSS Descs returned | - * .-----------------------------------------------------------. - * | BSSDescription data (variable, size given in bufsize) | - * .-----------------------------------------------------------. - * | TLV data (variable, size calculated using header->size, | - * | bufsize and sizeof the fixed fields above) | - * .-----------------------------------------------------------. - * - * @param priv A pointer to wlan_private structure - * @param resp A pointer to cmd_ds_command - * - * @return 0 or -1 - */ -int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_scan_rsp *pscan; - struct bss_descriptor newbssentry; - struct mrvlietypes_data *ptlv; - struct mrvlietypes_tsftimestamp *ptsftlv; - u8 *pbssinfo; - u16 scanrespsize; - int bytesleft; - int numintable; - int bssIdx; - int idx; - int tlvbufsize; - u64 tsfval; - - ENTER(); - - pscan = &resp->params.scanresp; - - if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) { - lbs_pr_debug(1, - "SCAN_RESP: Invalid number of AP returned (%d)!!\n", - pscan->nr_sets); - LEAVE(); - return -1; - } - - bytesleft = le16_to_cpu(pscan->bssdescriptsize); - lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft); - - scanrespsize = le16_to_cpu(resp->size); - lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n", - pscan->nr_sets); - - numintable = adapter->numinscantable; - pbssinfo = pscan->bssdesc_and_tlvbuffer; - - /* The size of the TLV buffer is equal to the entire command response - * size (scanrespsize) minus the fixed fields (sizeof()'s), the - * BSS Descriptions (bssdescriptsize as bytesLef) and the command - * response header (S_DS_GEN) - */ - tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) - + sizeof(pscan->nr_sets) - + S_DS_GEN); - - ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft); - - /* Search the TLV buffer space in the scan response for any valid TLVs */ - wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv); - - /* - * Process each scan response returned (pscan->nr_sets). Save - * the information in the newbssentry and then insert into the - * driver scan table either as an update to an existing entry - * or as an addition at the end of the table - */ - for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { - /* Zero out the newbssentry we are about to store info in */ - memset(&newbssentry, 0x00, sizeof(newbssentry)); - - /* Process the data fields and IEs returned for this BSS */ - if ((InterpretBSSDescriptionWithIE(&newbssentry, - &pbssinfo, - &bytesleft) == - 0) - && CHECK_SSID_IS_VALID(&newbssentry.ssid)) { - - lbs_pr_debug(1, - "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", - newbssentry.macaddress[0], - newbssentry.macaddress[1], - newbssentry.macaddress[2], - newbssentry.macaddress[3], - newbssentry.macaddress[4], - newbssentry.macaddress[5]); - - /* - * Search the scan table for the same bssid - */ - for (bssIdx = 0; bssIdx < numintable; bssIdx++) { - if (memcmp(newbssentry.macaddress, - adapter->scantable[bssIdx]. - macaddress, - sizeof(newbssentry.macaddress)) == - 0) { - /* - * If the SSID matches as well, it is a duplicate of - * this entry. Keep the bssIdx set to this - * entry so we replace the old contents in the table - */ - if ((newbssentry.ssid.ssidlength == - adapter->scantable[bssIdx].ssid. - ssidlength) - && - (memcmp - (newbssentry.ssid.ssid, - adapter->scantable[bssIdx].ssid. - ssid, - newbssentry.ssid.ssidlength) == - 0)) { - lbs_pr_debug(1, - "SCAN_RESP: Duplicate of index: %d\n", - bssIdx); - break; - } - } - } - /* - * If the bssIdx is equal to the number of entries in the table, - * the new entry was not a duplicate; append it to the scan - * table - */ - if (bssIdx == numintable) { - /* Range check the bssIdx, keep it limited to the last entry */ - if (bssIdx == MRVDRV_MAX_BSSID_LIST) { - bssIdx--; - } else { - numintable++; - } - } - - /* - * If the TSF TLV was appended to the scan results, save the - * this entries TSF value in the networktsf field. The - * networktsf is the firmware's TSF value at the time the - * beacon or probe response was received. - */ - if (ptsftlv) { - memcpy(&tsfval, &ptsftlv->tsftable[idx], - sizeof(tsfval)); - tsfval = le64_to_cpu(tsfval); - - memcpy(&newbssentry.networktsf, - &tsfval, sizeof(newbssentry.networktsf)); - } - - /* Copy the locally created newbssentry to the scan table */ - memcpy(&adapter->scantable[bssIdx], - &newbssentry, - sizeof(adapter->scantable[bssIdx])); - - } else { - - /* error parsing/interpreting the scan response, skipped */ - lbs_pr_debug(1, "SCAN_RESP: " - "InterpretBSSDescriptionWithIE returned ERROR\n"); - } - } - - lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", - pscan->nr_sets, numintable - adapter->numinscantable, - numintable); - - /* Update the total number of BSSIDs in the scan table */ - adapter->numinscantable = numintable; - - LEAVE(); - return 0; -} diff --git a/trunk/drivers/net/wireless/libertas/scan.h b/trunk/drivers/net/wireless/libertas/scan.h deleted file mode 100644 index d93aa7fa44fd..000000000000 --- a/trunk/drivers/net/wireless/libertas/scan.h +++ /dev/null @@ -1,216 +0,0 @@ -/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ -/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ - -/** - * Interface for the wlan network scan routines - * - * Driver interface functions and type declarations for the scan module - * implemented in wlan_scan.c. - */ -#ifndef _WLAN_SCAN_H -#define _WLAN_SCAN_H - -#include "hostcmd.h" - -/** - * @brief Maximum number of channels that can be sent in a setuserscan ioctl - * - * @sa wlan_ioctl_user_scan_cfg - */ -#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 - -//! Infrastructure BSS scan type in wlan_scan_cmd_config -#define WLAN_SCAN_BSS_TYPE_BSS 1 - -//! Adhoc BSS scan type in wlan_scan_cmd_config -#define WLAN_SCAN_BSS_TYPE_IBSS 2 - -//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter -#define WLAN_SCAN_BSS_TYPE_ANY 3 - -/** - * @brief Structure used internally in the wlan driver to configure a scan. - * - * Sent to the command processing module to configure the firmware - * scan command prepared by libertas_cmd_80211_scan. - * - * @sa wlan_scan_networks - * - */ -struct wlan_scan_cmd_config { - /** - * @brief BSS type to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. valid settings are: - * - * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) - * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) - * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) - */ - u8 bsstype; - - /** - * @brief Specific BSSID used to filter scan results in the firmware - */ - u8 specificBSSID[ETH_ALEN]; - - /** - * @brief length of TLVs sent in command starting at tlvBuffer - */ - int tlvbufferlen; - - /** - * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command - * - * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t - * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t - */ - u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here -}; - -/** - * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg - * - * Multiple instances of this structure are included in the IOCTL command - * to configure a instance of a scan on the specific channel. - */ -struct wlan_ioctl_user_scan_chan { - u8 channumber; //!< channel Number to scan - u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1 - u8 scantype; //!< Scan type: Active = 0, Passive = 1 - u16 scantime; //!< Scan duration in milliseconds; if 0 default used -}; - -/** - * @brief IOCTL input structure to configure an immediate scan cmd to firmware - * - * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies - * a number of parameters to be used in general for the scan as well - * as a channel list (wlan_ioctl_user_scan_chan) for each scan period - * desired. - * - * @sa libertas_set_user_scan_ioctl - */ -struct wlan_ioctl_user_scan_cfg { - - /** - * @brief Flag set to keep the previous scan table intact - * - * If set, the scan results will accumulate, replacing any previous - * matched entries for a BSS with the new scan data - */ - u8 keeppreviousscan; //!< Do not erase the existing scan results - - /** - * @brief BSS type to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. valid settings are: - * - * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) - * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) - * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) - */ - u8 bsstype; - - /** - * @brief Configure the number of probe requests for active chan scans - */ - u8 numprobes; - - /** - * @brief BSSID filter sent in the firmware command to limit the results - */ - u8 specificBSSID[ETH_ALEN]; - - /** - * @brief SSID filter sent in the firmware command to limit the results - */ - char specificSSID[IW_ESSID_MAX_SIZE + 1]; - - /** - * @brief Variable number (fixed maximum) of channels to scan up - */ - struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; -}; - -/** - * @brief Structure used to store information for each beacon/probe response - */ -struct bss_descriptor { - u8 macaddress[ETH_ALEN]; - - struct WLAN_802_11_SSID ssid; - - /* WEP encryption requirement */ - u32 privacy; - - /* receive signal strength in dBm */ - long rssi; - - u32 channel; - - u16 beaconperiod; - - u32 atimwindow; - - enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; - u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; - - int extra_ie; - - u8 timestamp[8]; //!< TSF value included in the beacon/probe response - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; - u8 datarates[WLAN_SUPPORTED_RATES]; - - __le64 networktsf; //!< TSF timestamp from the current firmware TSF - - struct ieeetypes_countryinfofullset countryinfo; - - struct WPA_SUPPLICANT wpa_supplicant; - struct WPA_SUPPLICANT wpa2_supplicant; - -}; - -extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, - struct WLAN_802_11_SSID *ssid2); -extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid, - u8 * bssid, int mode); -int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode); -extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode); - -int libertas_find_best_network_SSID(wlan_private * priv, - struct WLAN_802_11_SSID *pSSID, - enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, - enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode); - -extern int libertas_send_specific_SSID_scan(wlan_private * priv, - struct WLAN_802_11_SSID *prequestedssid, - u8 keeppreviousscan); -extern int libertas_send_specific_BSSID_scan(wlan_private * priv, - u8 * bssid, u8 keeppreviousscan); - -extern int libertas_cmd_80211_scan(wlan_private * priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -extern int libertas_ret_80211_scan(wlan_private * priv, - struct cmd_ds_command *resp); - -int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin); - -struct ifreq; - -struct iw_point; -struct iw_param; -struct iw_request_info; -extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra); -extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra); - -#endif /* _WLAN_SCAN_H */ diff --git a/trunk/drivers/net/wireless/libertas/thread.h b/trunk/drivers/net/wireless/libertas/thread.h deleted file mode 100644 index 207b8a6cc33d..000000000000 --- a/trunk/drivers/net/wireless/libertas/thread.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef __WLAN_THREAD_H_ -#define __WLAN_THREAD_H_ - -#include - -struct wlan_thread { - struct task_struct *task; - wait_queue_head_t waitq; - pid_t pid; - void *priv; -}; - -static inline void wlan_activate_thread(struct wlan_thread * thr) -{ - /** Record the thread pid */ - thr->pid = current->pid; - - /** Initialize the wait queue */ - init_waitqueue_head(&thr->waitq); -} - -static inline void wlan_deactivate_thread(struct wlan_thread * thr) -{ - ENTER(); - - thr->pid = 0; - - LEAVE(); -} - -static inline void wlan_create_thread(int (*wlanfunc) (void *), - struct wlan_thread * thr, char *name) -{ - thr->task = kthread_run(wlanfunc, thr, "%s", name); -} - -static inline int wlan_terminate_thread(struct wlan_thread * thr) -{ - ENTER(); - - /* Check if the thread is active or not */ - if (!thr->pid) { - printk(KERN_ERR "Thread does not exist\n"); - return -1; - } - kthread_stop(thr->task); - - LEAVE(); - return 0; -} - -#endif diff --git a/trunk/drivers/net/wireless/libertas/tx.c b/trunk/drivers/net/wireless/libertas/tx.c deleted file mode 100644 index 82d06223043e..000000000000 --- a/trunk/drivers/net/wireless/libertas/tx.c +++ /dev/null @@ -1,285 +0,0 @@ -/** - * This file contains the handling of TX in wlan driver. - */ -#include - -#include "hostcmd.h" -#include "radiotap.h" -#include "sbi.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "wext.h" - -/** - * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE - * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) - * - * @param rate Input rate - * @return Output Rate (0 if invalid) - */ -static u32 convert_radiotap_rate_to_mv(u8 rate) -{ - switch (rate) { - case 2: /* 1 Mbps */ - return 0 | (1 << 4); - case 4: /* 2 Mbps */ - return 1 | (1 << 4); - case 11: /* 5.5 Mbps */ - return 2 | (1 << 4); - case 22: /* 11 Mbps */ - return 3 | (1 << 4); - case 12: /* 6 Mbps */ - return 4 | (1 << 4); - case 18: /* 9 Mbps */ - return 5 | (1 << 4); - case 24: /* 12 Mbps */ - return 6 | (1 << 4); - case 36: /* 18 Mbps */ - return 7 | (1 << 4); - case 48: /* 24 Mbps */ - return 8 | (1 << 4); - case 72: /* 36 Mbps */ - return 9 | (1 << 4); - case 96: /* 48 Mbps */ - return 10 | (1 << 4); - case 108: /* 54 Mbps */ - return 11 | (1 << 4); - } - return 0; -} - -/** - * @brief This function processes a single packet and sends - * to IF layer - * - * @param priv A pointer to wlan_private structure - * @param skb A pointer to skb which includes TX packet - * @return 0 or -1 - */ -static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - struct txpd localtxpd; - struct txpd *plocaltxpd = &localtxpd; - u8 *p802x_hdr; - struct tx_radiotap_hdr *pradiotap_hdr; - u32 new_rate; - u8 *ptr = priv->adapter->tmptxbuf; - - ENTER(); - - if (priv->adapter->surpriseremoved) - return -1; - - if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - - if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { - lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n", - skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); - ret = -1; - goto done; - } - - memset(plocaltxpd, 0, sizeof(struct txpd)); - - plocaltxpd->tx_packet_length = skb->len; - - /* offset of actual data */ - plocaltxpd->tx_packet_location = sizeof(struct txpd); - - /* TxCtrl set by user or default */ - plocaltxpd->tx_control = adapter->pkttxctrl; - - p802x_hdr = skb->data; - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { - - /* locate radiotap header */ - pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; - - /* set txpd fields from the radiotap header */ - new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); - if (new_rate != 0) { - /* erase tx_control[4:0] */ - plocaltxpd->tx_control &= ~0x1f; - /* write new tx_control[4:0] */ - plocaltxpd->tx_control |= new_rate; - } - - /* skip the radiotap header */ - p802x_hdr += sizeof(struct tx_radiotap_hdr); - plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr); - - } - /* copy destination address from 802.3 or 802.11 header */ - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) - memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); - else - memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); - - lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); - - if (IS_MESH_FRAME(skb)) { - plocaltxpd->tx_control |= TxPD_MESH_FRAME; - } - - memcpy(ptr, plocaltxpd, sizeof(struct txpd)); - - ptr += sizeof(struct txpd); - - lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length); - memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length); - ret = libertas_sbi_host_to_card(priv, MVMS_DAT, - priv->adapter->tmptxbuf, - plocaltxpd->tx_packet_length + - sizeof(struct txpd)); - - if (ret) { - lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret); - goto done; - } - - lbs_pr_debug(1, "SendSinglePacket succeeds\n"); - - done: - if (!ret) { - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; - } else { - priv->stats.tx_dropped++; - priv->stats.tx_errors++; - } - - if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { - /* Keep the skb to echo it back once Tx feedback is - received from FW */ - skb_orphan(skb); - /* stop processing outgoing pkts */ - netif_stop_queue(priv->wlan_dev.netdev); - /* freeze any packets already in our queues */ - priv->adapter->TxLockFlag = 1; - } else { - dev_kfree_skb_any(skb); - priv->adapter->currenttxskb = NULL; - } - - LEAVE(); - return ret; -} - - -void libertas_tx_runqueue(wlan_private *priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - spin_lock(&adapter->txqueue_lock); - for (i = 0; i < adapter->tx_queue_idx; i++) { - struct sk_buff *skb = adapter->tx_queue_ps[i]; - spin_unlock(&adapter->txqueue_lock); - SendSinglePacket(priv, skb); - spin_lock(&adapter->txqueue_lock); - } - adapter->tx_queue_idx = 0; - spin_unlock(&adapter->txqueue_lock); -} - -static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) -{ - wlan_adapter *adapter = priv->adapter; - - spin_lock(&adapter->txqueue_lock); - - WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE); - adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; - if (adapter->tx_queue_idx == NR_TX_QUEUE) - netif_stop_queue(priv->wlan_dev.netdev); - else - netif_start_queue(priv->wlan_dev.netdev); - - spin_unlock(&adapter->txqueue_lock); -} - -/** - * @brief This function checks the conditions and sends packet to IF - * layer if everything is ok. - * - * @param priv A pointer to wlan_private structure - * @return n/a - */ -int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) -{ - int ret = -1; - - ENTER(); - - lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); - - if (priv->wlan_dev.dnld_sent) { - lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", - priv->wlan_dev.dnld_sent); - goto done; - } - - if ((priv->adapter->psstate == PS_STATE_SLEEP) || - (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) { - wlan_tx_queue(priv, skb); - return ret; - } - - priv->adapter->currenttxskb = skb; - - ret = SendSinglePacket(priv, skb); -done: - LEAVE(); - return ret; -} - -/** - * @brief This function sends to the host the last transmitted packet, - * filling the radiotap headers with transmission information. - * - * @param priv A pointer to wlan_private structure - * @param status A 32 bit value containing transmission status. - * - * @returns void - */ -void libertas_send_tx_feedback(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - struct tx_radiotap_hdr *radiotap_hdr; - u32 status = adapter->eventcause; - int txfail; - int try_count; - - if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || - adapter->currenttxskb == NULL) - return; - - radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; - - if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr, - min_t(unsigned int, adapter->currenttxskb->len, 100)); - - txfail = (status >> 24); - -#if 0 - /* The version of roofnet that we've tested does not use this yet - * But it may be used in the future. - */ - if (txfail) - radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL; -#endif - try_count = (status >> 16) & 0xff; - radiotap_hdr->data_retries = (try_count) ? - (1 + adapter->txretrycount - try_count) : 0; - libertas_upload_rx_packet(priv, adapter->currenttxskb); - adapter->currenttxskb = NULL; - priv->adapter->TxLockFlag = 0; - if (priv->adapter->connect_status == libertas_connected) - netif_wake_queue(priv->wlan_dev.netdev); -} diff --git a/trunk/drivers/net/wireless/libertas/types.h b/trunk/drivers/net/wireless/libertas/types.h deleted file mode 100644 index 09d62f8b1a16..000000000000 --- a/trunk/drivers/net/wireless/libertas/types.h +++ /dev/null @@ -1,289 +0,0 @@ -/** - * This header file contains definition for global types - */ -#ifndef _WLAN_TYPES_ -#define _WLAN_TYPES_ - -#include - -/** IEEE type definitions */ -enum ieeetypes_elementid { - SSID = 0, - SUPPORTED_RATES, - FH_PARAM_SET, - DS_PARAM_SET, - CF_PARAM_SET, - TIM, - IBSS_PARAM_SET, - COUNTRY_INFO = 7, - - CHALLENGE_TEXT = 16, - - EXTENDED_SUPPORTED_RATES = 50, - - VENDOR_SPECIFIC_221 = 221, - - WPA_IE = 221, - WPA2_IE = 48, - - EXTRA_IE = 133, -} __attribute__ ((packed)); - -#define CAPINFO_MASK (~(0xda00)) - -struct ieeetypes_capinfo { - u8 ess:1; - u8 ibss:1; - u8 cfpollable:1; - u8 cfpollrqst:1; - u8 privacy:1; - u8 shortpreamble:1; - u8 pbcc:1; - u8 chanagility:1; - u8 spectrummgmt:1; - u8 rsrvd3:1; - u8 shortslottime:1; - u8 apsd:1; - u8 rsvrd2:1; - u8 dsssofdm:1; - u8 rsrvd1:2; -} __attribute__ ((packed)); - -struct ieeetypes_cfparamset { - u8 elementid; - u8 len; - u8 cfpcnt; - u8 cfpperiod; - u16 cfpmaxduration; - u16 cfpdurationremaining; -} __attribute__ ((packed)); - - -struct ieeetypes_ibssparamset { - u8 elementid; - u8 len; - u16 atimwindow; -} __attribute__ ((packed)); - -union IEEEtypes_ssparamset { - struct ieeetypes_cfparamset cfparamset; - struct ieeetypes_ibssparamset ibssparamset; -} __attribute__ ((packed)); - -struct ieeetypes_fhparamset { - u8 elementid; - u8 len; - u16 dwelltime; - u8 hopset; - u8 hoppattern; - u8 hopindex; -} __attribute__ ((packed)); - -struct ieeetypes_dsparamset { - u8 elementid; - u8 len; - u8 currentchan; -} __attribute__ ((packed)); - -union ieeetypes_phyparamset { - struct ieeetypes_fhparamset fhparamset; - struct ieeetypes_dsparamset dsparamset; -} __attribute__ ((packed)); - -struct ieeetypes_assocrsp { - struct ieeetypes_capinfo capability; - u16 statuscode; - u16 aid; - u8 iebuffer[1]; -} __attribute__ ((packed)); - -/** TLV type ID definition */ -#define PROPRIETARY_TLV_BASE_ID 0x0100 - -/* Terminating TLV type */ -#define MRVL_TERMINATE_TLV_ID 0xffff - -#define TLV_TYPE_SSID 0x0000 -#define TLV_TYPE_RATES 0x0001 -#define TLV_TYPE_PHY_FH 0x0002 -#define TLV_TYPE_PHY_DS 0x0003 -#define TLV_TYPE_CF 0x0004 -#define TLV_TYPE_IBSS 0x0006 - -#define TLV_TYPE_DOMAIN 0x0007 - -#define TLV_TYPE_POWER_CAPABILITY 0x0021 - -#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) -#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) -#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) -#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) -#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) -#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) -#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) -#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8) -#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) -#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) -#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11) -#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) -#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) -#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14) -#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15) -#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) -#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17) -#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) -#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) -#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) -#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) - -/** TLV related data structures*/ -struct mrvlietypesheader { - u16 type; - u16 len; -} __attribute__ ((packed)); - -struct mrvlietypes_data { - struct mrvlietypesheader header; - u8 Data[1]; -} __attribute__ ((packed)); - -struct mrvlietypes_ratesparamset { - struct mrvlietypesheader header; - u8 rates[1]; -} __attribute__ ((packed)); - -struct mrvlietypes_ssidparamset { - struct mrvlietypesheader header; - u8 ssid[1]; -} __attribute__ ((packed)); - -struct mrvlietypes_wildcardssidparamset { - struct mrvlietypesheader header; - u8 MaxSsidlength; - u8 ssid[1]; -} __attribute__ ((packed)); - -struct chanscanmode { - u8 passivescan:1; - u8 disablechanfilt:1; - u8 reserved_2_7:6; -} __attribute__ ((packed)); - -struct chanscanparamset { - u8 radiotype; - u8 channumber; - struct chanscanmode chanscanmode; - u16 minscantime; - u16 maxscantime; -} __attribute__ ((packed)); - -struct mrvlietypes_chanlistparamset { - struct mrvlietypesheader header; - struct chanscanparamset chanscanparam[1]; -} __attribute__ ((packed)); - -struct cfparamset { - u8 cfpcnt; - u8 cfpperiod; - u16 cfpmaxduration; - u16 cfpdurationremaining; -} __attribute__ ((packed)); - -struct ibssparamset { - u16 atimwindow; -} __attribute__ ((packed)); - -struct mrvlietypes_ssparamset { - struct mrvlietypesheader header; - union { - struct cfparamset cfparamset[1]; - struct ibssparamset ibssparamset[1]; - } cf_ibss; -} __attribute__ ((packed)); - -struct fhparamset { - u16 dwelltime; - u8 hopset; - u8 hoppattern; - u8 hopindex; -} __attribute__ ((packed)); - -struct dsparamset { - u8 currentchan; -} __attribute__ ((packed)); - -struct mrvlietypes_phyparamset { - struct mrvlietypesheader header; - union { - struct fhparamset fhparamset[1]; - struct dsparamset dsparamset[1]; - } fh_ds; -} __attribute__ ((packed)); - -struct mrvlietypes_rsnparamset { - struct mrvlietypesheader header; - u8 rsnie[1]; -} __attribute__ ((packed)); - -struct mrvlietypes_tsftimestamp { - struct mrvlietypesheader header; - __le64 tsftable[1]; -} __attribute__ ((packed)); - -/** Local Power capability */ -struct mrvlietypes_powercapability { - struct mrvlietypesheader header; - s8 minpower; - s8 maxpower; -} __attribute__ ((packed)); - -struct mrvlietypes_rssithreshold { - struct mrvlietypesheader header; - u8 rssivalue; - u8 rssifreq; -} __attribute__ ((packed)); - -struct mrvlietypes_snrthreshold { - struct mrvlietypesheader header; - u8 snrvalue; - u8 snrfreq; -} __attribute__ ((packed)); - -struct mrvlietypes_failurecount { - struct mrvlietypesheader header; - u8 failvalue; - u8 Failfreq; -} __attribute__ ((packed)); - -struct mrvlietypes_beaconsmissed { - struct mrvlietypesheader header; - u8 beaconmissed; - u8 reserved; -} __attribute__ ((packed)); - -struct mrvlietypes_numprobes { - struct mrvlietypesheader header; - u16 numprobes; -} __attribute__ ((packed)); - -struct mrvlietypes_bcastprobe { - struct mrvlietypesheader header; - u16 bcastprobe; -} __attribute__ ((packed)); - -struct mrvlietypes_numssidprobe { - struct mrvlietypesheader header; - u16 numssidprobe; -} __attribute__ ((packed)); - -struct led_pin { - u8 led; - u8 pin; -} __attribute__ ((packed)); - -struct mrvlietypes_ledgpio { - struct mrvlietypesheader header; - struct led_pin ledpin[1]; -} __attribute__ ((packed)); - -#endif /* _WLAN_TYPES_ */ diff --git a/trunk/drivers/net/wireless/libertas/version.h b/trunk/drivers/net/wireless/libertas/version.h deleted file mode 100644 index e86f65ae79b8..000000000000 --- a/trunk/drivers/net/wireless/libertas/version.h +++ /dev/null @@ -1,8 +0,0 @@ -#define DRIVER_RELEASE_VERSION "320.p0" -const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION -#ifdef DEBUG - "-dbg" -#endif - ""; - - diff --git a/trunk/drivers/net/wireless/libertas/wext.c b/trunk/drivers/net/wireless/libertas/wext.c deleted file mode 100644 index 4a52336bc0f6..000000000000 --- a/trunk/drivers/net/wireless/libertas/wext.c +++ /dev/null @@ -1,2769 +0,0 @@ -/** - * This file contains ioctl functions - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "host.h" -#include "radiotap.h" -#include "decl.h" -#include "defs.h" -#include "dev.h" -#include "join.h" -#include "version.h" -#include "wext.h" -#include "assoc.h" - - -/** - * @brief Convert mw value to dbm value - * - * @param mw the value of mw - * @return the value of dbm - */ -static int mw_to_dbm(int mw) -{ - if (mw < 2) - return 0; - else if (mw < 3) - return 3; - else if (mw < 4) - return 5; - else if (mw < 6) - return 7; - else if (mw < 7) - return 8; - else if (mw < 8) - return 9; - else if (mw < 10) - return 10; - else if (mw < 13) - return 11; - else if (mw < 16) - return 12; - else if (mw < 20) - return 13; - else if (mw < 25) - return 14; - else if (mw < 32) - return 15; - else if (mw < 40) - return 16; - else if (mw < 50) - return 17; - else if (mw < 63) - return 18; - else if (mw < 79) - return 19; - else if (mw < 100) - return 20; - else - return 21; -} - -/** - * @brief Find the channel frequency power info with specific channel - * - * @param adapter A pointer to wlan_adapter structure - * @param band it can be BAND_A, BAND_G or BAND_B - * @param channel the channel for looking - * @return A pointer to struct chan_freq_power structure or NULL if not find. - */ -struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter, - u8 band, u16 channel) -{ - struct chan_freq_power *cfp = NULL; - struct region_channel *rc; - int count = sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); - int i, j; - - for (j = 0; !cfp && (j < count); j++) { - rc = &adapter->region_channel[j]; - - if (adapter->enable11d) - rc = &adapter->universal_channel[j]; - if (!rc->valid || !rc->CFP) - continue; - if (rc->band != band) - continue; - for (i = 0; i < rc->nrcfp; i++) { - if (rc->CFP[i].channel == channel) { - cfp = &rc->CFP[i]; - break; - } - } - } - - if (!cfp && channel) - lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find " - "cfp by band %d & channel %d\n", band, channel); - - return cfp; -} - -/** - * @brief Find the channel frequency power info with specific frequency - * - * @param adapter A pointer to wlan_adapter structure - * @param band it can be BAND_A, BAND_G or BAND_B - * @param freq the frequency for looking - * @return A pointer to struct chan_freq_power structure or NULL if not find. - */ -static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, - u8 band, u32 freq) -{ - struct chan_freq_power *cfp = NULL; - struct region_channel *rc; - int count = sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); - int i, j; - - for (j = 0; !cfp && (j < count); j++) { - rc = &adapter->region_channel[j]; - - if (adapter->enable11d) - rc = &adapter->universal_channel[j]; - if (!rc->valid || !rc->CFP) - continue; - if (rc->band != band) - continue; - for (i = 0; i < rc->nrcfp; i++) { - if (rc->CFP[i].freq == freq) { - cfp = &rc->CFP[i]; - break; - } - } - } - - if (!cfp && freq) - lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by " - "band %d & freq %d\n", band, freq); - - return cfp; -} - -static int updatecurrentchannel(wlan_private * priv) -{ - int ret; - - /* - ** the channel in f/w could be out of sync, get the current channel - */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_get, - cmd_option_waitforrsp, 0, NULL); - - lbs_pr_debug(1, "Current channel = %d\n", - priv->adapter->curbssparams.channel); - - return ret; -} - -static int setcurrentchannel(wlan_private * priv, int channel) -{ - lbs_pr_debug(1, "Set channel = %d\n", channel); - - /* - ** Current channel is not set to adhocchannel requested, set channel - */ - return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_set, - cmd_option_waitforrsp, 0, &channel)); -} - -static int changeadhocchannel(wlan_private * priv, int channel) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - adapter->adhocchannel = channel; - - updatecurrentchannel(priv); - - if (adapter->curbssparams.channel == adapter->adhocchannel) { - /* adhocchannel is set to the current channel already */ - LEAVE(); - return 0; - } - - lbs_pr_debug(1, "Updating channel from %d to %d\n", - adapter->curbssparams.channel, adapter->adhocchannel); - - setcurrentchannel(priv, adapter->adhocchannel); - - updatecurrentchannel(priv); - - if (adapter->curbssparams.channel != adapter->adhocchannel) { - lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n", - adapter->adhocchannel, adapter->curbssparams.channel); - LEAVE(); - return -1; - } - - if (adapter->connect_status == libertas_connected) { - int i; - struct WLAN_802_11_SSID curadhocssid; - - lbs_pr_debug(1, "channel Changed while in an IBSS\n"); - - /* Copy the current ssid */ - memcpy(&curadhocssid, &adapter->curbssparams.ssid, - sizeof(struct WLAN_802_11_SSID)); - - /* Exit Adhoc mode */ - lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n"); - ret = libertas_stop_adhoc_network(priv); - - if (ret) { - LEAVE(); - return ret; - } - /* Scan for the network, do not save previous results. Stale - * scan data will cause us to join a non-existant adhoc network - */ - libertas_send_specific_SSID_scan(priv, &curadhocssid, 0); - - // find out the BSSID that matches the current SSID - i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL, - wlan802_11ibss); - - if (i >= 0) { - lbs_pr_debug(1, "SSID found at %d in List," - "so join\n", i); - libertas_join_adhoc_network(priv, &adapter->scantable[i]); - } else { - // else send START command - lbs_pr_debug(1, "SSID not found in list, " - "so creating adhoc with ssid = %s\n", - curadhocssid.ssid); - libertas_start_adhoc_network(priv, &curadhocssid); - } // end of else (START command) - } - - LEAVE(); - return 0; -} - -/** - * @brief Set Radio On/OFF - * - * @param priv A pointer to wlan_private structure - * @option Radio Option - * @return 0 --success, otherwise fail - */ -int wlan_radio_ioctl(wlan_private * priv, u8 option) -{ - int ret = 0; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (adapter->radioon != option) { - lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off"); - adapter->radioon = option; - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); - } - - LEAVE(); - return ret; -} - -/** - * @brief Copy rates - * - * @param dest A pointer to Dest Buf - * @param src A pointer to Src Buf - * @param len The len of Src Buf - * @return Number of rates copyed - */ -static inline int copyrates(u8 * dest, int pos, u8 * src, int len) -{ - int i; - - for (i = 0; i < len && src[i]; i++, pos++) { - if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) - break; - dest[pos] = src[i]; - } - - return pos; -} - -/** - * @brief Get active data rates - * - * @param adapter A pointer to wlan_adapter structure - * @param rate The buf to return the active rates - * @return The number of rates - */ -static int get_active_data_rates(wlan_adapter * adapter, - u8* rates) -{ - int k = 0; - - ENTER(); - - if (adapter->connect_status != libertas_connected) { - if (adapter->inframode == wlan802_11infrastructure) { - //Infra. mode - lbs_pr_debug(1, "Infra\n"); - k = copyrates(rates, k, libertas_supported_rates, - sizeof(libertas_supported_rates)); - } else { - //ad-hoc mode - lbs_pr_debug(1, "Adhoc G\n"); - k = copyrates(rates, k, libertas_adhoc_rates_g, - sizeof(libertas_adhoc_rates_g)); - } - } else { - k = copyrates(rates, 0, adapter->curbssparams.datarates, - adapter->curbssparams.numofrates); - } - - LEAVE(); - - return k; -} - -static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, - char *cwrq, char *extra) -{ - const char *cp; - char comm[6] = { "COMM-" }; - char mrvl[6] = { "MRVL-" }; - int cnt; - - ENTER(); - - strcpy(cwrq, mrvl); - - cp = strstr(libertas_driver_version, comm); - if (cp == libertas_driver_version) //skip leading "COMM-" - cp = libertas_driver_version + strlen(comm); - else - cp = libertas_driver_version; - - cnt = strlen(mrvl); - cwrq += cnt; - while (cnt < 16 && (*cp != '-')) { - *cwrq++ = toupper(*cp++); - cnt++; - } - *cwrq = '\0'; - - LEAVE(); - - return 0; -} - -static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct chan_freq_power *cfp; - - ENTER(); - - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, - adapter->curbssparams.channel); - - if (!cfp) { - if (adapter->curbssparams.channel) - lbs_pr_debug(1, "Invalid channel=%d\n", - adapter->curbssparams.channel); - return -EINVAL; - } - - fwrq->m = (long)cfp->freq * 100000; - fwrq->e = 1; - - lbs_pr_debug(1, "freq=%u\n", fwrq->m); - - LEAVE(); - return 0; -} - -static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (adapter->connect_status == libertas_connected) { - memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); - } else { - memset(awrq->sa_data, 0, ETH_ALEN); - } - awrq->sa_family = ARPHRD_ETHER; - - LEAVE(); - return 0; -} - -static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* - * Check the size of the string - */ - - if (dwrq->length > 16) { - return -E2BIG; - } - - mutex_lock(&adapter->lock); - memset(adapter->nodename, 0, sizeof(adapter->nodename)); - memcpy(adapter->nodename, extra, dwrq->length); - mutex_unlock(&adapter->lock); - - LEAVE(); - return 0; -} - -static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* - * Get the Nick Name saved - */ - - mutex_lock(&adapter->lock); - strncpy(extra, adapter->nodename, 16); - mutex_unlock(&adapter->lock); - - extra[16] = '\0'; - - /* - * If none, we may want to get the one that was set - */ - - /* - * Push it out ! - */ - dwrq->length = strlen(extra) + 1; - - LEAVE(); - return 0; -} - -static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int rthr = vwrq->value; - - ENTER(); - - if (vwrq->disabled) { - adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; - } else { - if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) - return -EINVAL; - adapter->rtsthsd = rthr; - } - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, - OID_802_11_RTS_THRESHOLD, &rthr); - - LEAVE(); - return ret; -} - -static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - adapter->rtsthsd = 0; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, - OID_802_11_RTS_THRESHOLD, NULL); - if (ret) { - LEAVE(); - return ret; - } - - vwrq->value = adapter->rtsthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) - || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); - vwrq->fixed = 1; - - LEAVE(); - return 0; -} - -static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - int fthr = vwrq->value; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (vwrq->disabled) { - adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; - } else { - if (fthr < MRVDRV_FRAG_MIN_VALUE - || fthr > MRVDRV_FRAG_MAX_VALUE) - return -EINVAL; - adapter->fragthsd = fthr; - } - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, - OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); - LEAVE(); - return ret; -} - -static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - adapter->fragthsd = 0; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, - OID_802_11_FRAGMENTATION_THRESHOLD, NULL); - if (ret) { - LEAVE(); - return ret; - } - - vwrq->value = adapter->fragthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) - || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); - vwrq->fixed = 1; - - LEAVE(); - return ret; -} - -static int wlan_get_mode(struct net_device *dev, - struct iw_request_info *info, u32 * uwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - switch (adapter->inframode) { - case wlan802_11ibss: - *uwrq = IW_MODE_ADHOC; - break; - - case wlan802_11infrastructure: - *uwrq = IW_MODE_INFRA; - break; - - default: - case wlan802_11autounknown: - *uwrq = IW_MODE_AUTO; - break; - } - - LEAVE(); - return 0; -} - -static int wlan_get_txpow(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_get, - cmd_option_waitforrsp, 0, NULL); - - if (ret) { - LEAVE(); - return ret; - } - - lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel); - vwrq->value = adapter->txpowerlevel; - vwrq->fixed = 1; - if (adapter->radioon) { - vwrq->disabled = 0; - vwrq->flags = IW_TXPOW_DBM; - } else { - vwrq->disabled = 1; - } - - LEAVE(); - return 0; -} - -static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (vwrq->flags == IW_RETRY_LIMIT) { - /* The MAC has a 4-bit Total_Tx_Count register - Total_Tx_Count = 1 + Tx_Retry_Count */ -#define TX_RETRY_MIN 0 -#define TX_RETRY_MAX 14 - if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) - return -EINVAL; - - /* Adding 1 to convert retry count to try count */ - adapter->txretrycount = vwrq->value + 1; - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, - OID_802_11_TX_RETRYCOUNT, NULL); - - if (ret) { - LEAVE(); - return ret; - } - } else { - return -EOPNOTSUPP; - } - - LEAVE(); - return 0; -} - -static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - ENTER(); - adapter->txretrycount = 0; - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, - OID_802_11_TX_RETRYCOUNT, NULL); - if (ret) { - LEAVE(); - return ret; - } - vwrq->disabled = 0; - if (!vwrq->flags) { - vwrq->flags = IW_RETRY_LIMIT; - /* Subtract 1 to convert try count to retry count */ - vwrq->value = adapter->txretrycount - 1; - } - - LEAVE(); - return 0; -} - -static inline void sort_channels(struct iw_freq *freq, int num) -{ - int i, j; - struct iw_freq temp; - - for (i = 0; i < num; i++) - for (j = i + 1; j < num; j++) - if (freq[i].i > freq[j].i) { - temp.i = freq[i].i; - temp.m = freq[i].m; - - freq[i].i = freq[j].i; - freq[i].m = freq[j].m; - - freq[j].i = temp.i; - freq[j].m = temp.m; - } -} - -/* data rate listing - MULTI_BANDS: - abg a b b/g - Infra G(12) A(8) B(4) G(12) - Adhoc A+B(12) A(8) B(4) B(4) - - non-MULTI_BANDS: - b b/g - Infra B(4) G(12) - Adhoc B(4) B(4) - */ -/** - * @brief Get Range Info - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 --success, otherwise fail - */ -static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - int i, j; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct iw_range *range = (struct iw_range *)extra; - struct chan_freq_power *cfp; - u8 rates[WLAN_SUPPORTED_RATES]; - - u8 flag = 0; - - ENTER(); - - dwrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->min_nwid = 0; - range->max_nwid = 0; - - memset(rates, 0, sizeof(rates)); - range->num_bitrates = get_active_data_rates(adapter, rates); - - for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; - i++) { - range->bitrate[i] = (rates[i] & 0x7f) * 500000; - } - range->num_bitrates = i; - lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES, - range->num_bitrates); - - range->num_frequency = 0; - if (priv->adapter->enable11d && - adapter->connect_status == libertas_connected) { - u8 chan_no; - u8 band; - - struct parsed_region_chan_11d *parsed_region_chan = - &adapter->parsed_region_chan; - - if (parsed_region_chan == NULL) { - lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n"); - LEAVE(); - return 0; - } - band = parsed_region_chan->band; - lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band, - parsed_region_chan->nr_chan); - - for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && (i < parsed_region_chan->nr_chan); i++) { - chan_no = parsed_region_chan->chanpwr[i].chan; - lbs_pr_debug(1, "chan_no=%d\n", chan_no); - range->freq[range->num_frequency].i = (long)chan_no; - range->freq[range->num_frequency].m = - (long)libertas_chan_2_freq(chan_no, band) * 100000; - range->freq[range->num_frequency].e = 1; - range->num_frequency++; - } - flag = 1; - } - if (!flag) { - for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && (j < sizeof(adapter->region_channel) - / sizeof(adapter->region_channel[0])); j++) { - cfp = adapter->region_channel[j].CFP; - for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && adapter->region_channel[j].valid - && cfp - && (i < adapter->region_channel[j].nrcfp); i++) { - range->freq[range->num_frequency].i = - (long)cfp->channel; - range->freq[range->num_frequency].m = - (long)cfp->freq * 100000; - range->freq[range->num_frequency].e = 1; - cfp++; - range->num_frequency++; - } - } - } - - lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", - IW_MAX_FREQUENCIES, range->num_frequency); - - range->num_channels = range->num_frequency; - - sort_channels(&range->freq[0], range->num_frequency); - - /* - * Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface - */ - if (i > 2) - range->throughput = 5000 * 1000; - else - range->throughput = 1500 * 1000; - - range->min_rts = MRVDRV_RTS_MIN_VALUE; - range->max_rts = MRVDRV_RTS_MAX_VALUE; - range->min_frag = MRVDRV_FRAG_MIN_VALUE; - range->max_frag = MRVDRV_FRAG_MAX_VALUE; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = 4; - - range->min_pmp = 1000000; - range->max_pmp = 120000000; - range->min_pmt = 1000; - range->max_pmt = 1000000; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - - /* - * Minimum version we recommend - */ - range->we_version_source = 15; - - /* - * Version we are compiled with - */ - range->we_version_compiled = WIRELESS_EXT; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - - range->min_retry = TX_RETRY_MIN; - range->max_retry = TX_RETRY_MAX; - - /* - * Set the qual, level and noise range values - */ - range->max_qual.qual = 100; - range->max_qual.level = 0; - range->max_qual.noise = 0; - range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - - range->avg_qual.qual = 70; - /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ - range->avg_qual.level = 0; - range->avg_qual.noise = 0; - range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - - range->sensitivity = 0; - - /* - * Setup the supported power level ranges - */ - memset(range->txpower, 0, sizeof(range->txpower)); - range->txpower[0] = 5; - range->txpower[1] = 7; - range->txpower[2] = 9; - range->txpower[3] = 11; - range->txpower[4] = 13; - range->txpower[5] = 15; - range->txpower[6] = 17; - range->txpower[7] = 19; - - range->num_txpower = 8; - range->txpower_capa = IW_TXPOW_DBM; - range->txpower_capa |= IW_TXPOW_RANGE; - - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - - if (adapter->fwcapinfo & FW_CAPINFO_WPA) { - range->enc_capa = IW_ENC_CAPA_WPA - | IW_ENC_CAPA_WPA2 - | IW_ENC_CAPA_CIPHER_TKIP - | IW_ENC_CAPA_CIPHER_CCMP; - } - - LEAVE(); - return 0; -} - -static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - /* PS is currently supported only in Infrastructure mode - * Remove this check if it is to be supported in IBSS mode also - */ - - if (vwrq->disabled) { - adapter->psmode = wlan802_11powermodecam; - if (adapter->psstate != PS_STATE_FULL_POWER) { - libertas_ps_wakeup(priv, cmd_option_waitforrsp); - } - - return 0; - } - - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - lbs_pr_debug(1, - "Setting power timeout command is not supported\n"); - return -EINVAL; - } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - lbs_pr_debug(1, "Setting power period command is not supported\n"); - return -EINVAL; - } - - if (adapter->psmode != wlan802_11powermodecam) { - return 0; - } - - adapter->psmode = wlan802_11powermodemax_psp; - - if (adapter->connect_status == libertas_connected) { - libertas_ps_sleep(priv, cmd_option_waitforrsp); - } - - LEAVE(); - return 0; -} - -static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int mode; - - ENTER(); - - mode = adapter->psmode; - - if ((vwrq->disabled = (mode == wlan802_11powermodecam)) - || adapter->connect_status == libertas_disconnected) { - LEAVE(); - return 0; - } - - vwrq->value = 0; - - LEAVE(); - return 0; -} - -/* - * iwpriv settable callbacks - */ - -static const iw_handler wlan_private_handler[] = { - NULL, /* SIOCIWFIRSTPRIV */ -}; - -static const struct iw_priv_args wlan_private_args[] = { - /* - * { cmd, set_args, get_args, name } - */ - { - WLANSCAN_TYPE, - IW_PRIV_TYPE_CHAR | 8, - IW_PRIV_TYPE_CHAR | 8, - "scantype"}, - - { - WLAN_SETINT_GETINT, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - ""}, - { - WLANNF, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getNF"}, - { - WLANRSSI, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getRSSI"}, - { - WLANENABLE11D, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "enable11d"}, - { - WLANADHOCGRATE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "adhocgrate"}, - - { - WLAN_SUBCMD_SET_PRESCAN, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "prescan"}, - { - WLAN_SETONEINT_GETONEINT, - IW_PRIV_TYPE_INT | 1, - IW_PRIV_TYPE_INT | 1, - ""}, - { - WLAN_BEACON_INTERVAL, - IW_PRIV_TYPE_INT | 1, - IW_PRIV_TYPE_INT | 1, - "bcninterval"}, - { - WLAN_LISTENINTRVL, - IW_PRIV_TYPE_INT | 1, - IW_PRIV_TYPE_INT | 1, - "lolisteninter"}, - { - WLAN_TXCONTROL, - IW_PRIV_TYPE_INT | 1, - IW_PRIV_TYPE_INT | 1, - "txcontrol"}, - { - WLAN_NULLPKTINTERVAL, - IW_PRIV_TYPE_INT | 1, - IW_PRIV_TYPE_INT | 1, - "psnullinterval"}, - /* Using iwpriv sub-command feature */ - { - WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */ - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - ""}, - - { - WLAN_SUBCMD_SETRXANTENNA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setrxant"}, - { - WLAN_SUBCMD_SETTXANTENNA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "settxant"}, - { - WLANSETAUTHALG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "authalgs", - }, - { - WLANSET8021XAUTHALG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "8021xauthalgs", - }, - { - WLANSETENCRYPTIONMODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "encryptionmode", - }, - { - WLANSETREGION, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setregioncode"}, - { - WLAN_SET_LISTEN_INTERVAL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setlisteninter"}, - { - WLAN_SET_MULTIPLE_DTIM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setmultipledtim"}, - { - WLAN_SET_ATIM_WINDOW, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "atimwindow"}, - { - WLANSETBCNAVG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setbcnavg"}, - { - WLANSETDATAAVG, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "setdataavg"}, - { - WLAN_SET_LINKMODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "linkmode"}, - { - WLAN_SET_RADIOMODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "radiomode"}, - { - WLAN_SET_DEBUGMODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "debugmode"}, - { - WLAN_SUBCMD_MESH_SET_TTL, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, - "mesh_set_ttl"}, - { - WLAN_SETNONE_GETONEINT, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - ""}, - { - WLANGETREGION, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getregioncode"}, - { - WLAN_GET_LISTEN_INTERVAL, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getlisteninter"}, - { - WLAN_GET_MULTIPLE_DTIM, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getmultipledtim"}, - { - WLAN_GET_TX_RATE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "gettxrate"}, - { - WLANGETBCNAVG, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "getbcnavg"}, - { - WLAN_GET_LINKMODE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_linkmode"}, - { - WLAN_GET_RADIOMODE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_radiomode"}, - { - WLAN_GET_DEBUGMODE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_debugmode"}, - { - WLAN_SUBCMD_FWT_CLEANUP, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "fwt_cleanup"}, - { - WLAN_SUBCMD_FWT_TIME, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "fwt_time"}, - { - WLAN_SUBCMD_MESH_GET_TTL, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "mesh_get_ttl"}, - { - WLAN_SETNONE_GETTWELVE_CHAR, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | 12, - ""}, - { - WLAN_SUBCMD_GETRXANTENNA, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | 12, - "getrxant"}, - { - WLAN_SUBCMD_GETTXANTENNA, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | 12, - "gettxant"}, - { - WLAN_GET_TSF, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | 12, - "gettsf"}, - { - WLAN_SETNONE_GETNONE, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - ""}, - { - WLANDEAUTH, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "deauth"}, - { - WLANADHOCSTOP, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "adhocstop"}, - { - WLANRADIOON, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "radioon"}, - { - WLANRADIOOFF, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "radiooff"}, - { - WLANWLANIDLEON, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "wlanidle-on"}, - { - WLANWLANIDLEOFF, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "wlanidle-off"}, - { - WLAN_SUBCMD_FWT_RESET, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "fwt_reset"}, - { - WLAN_SUBCMD_BT_RESET, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_NONE, - "bt_reset"}, - { - WLAN_SET128CHAR_GET128CHAR, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - ""}, - /* BT Management */ - { - WLAN_SUBCMD_BT_ADD, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_add"}, - { - WLAN_SUBCMD_BT_DEL, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_del"}, - { - WLAN_SUBCMD_BT_LIST, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "bt_list"}, - /* FWT Management */ - { - WLAN_SUBCMD_FWT_ADD, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_add"}, - { - WLAN_SUBCMD_FWT_DEL, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_del"}, - { - WLAN_SUBCMD_FWT_LOOKUP, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_lookup"}, - { - WLAN_SUBCMD_FWT_LIST_NEIGHBOR, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list_neigh"}, - { - WLAN_SUBCMD_FWT_LIST, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list"}, - { - WLAN_SUBCMD_FWT_LIST_ROUTE, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "fwt_list_route"}, - { - WLANSCAN_MODE, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "scanmode"}, - { - WLAN_GET_ADHOC_STATUS, - IW_PRIV_TYPE_CHAR | 128, - IW_PRIV_TYPE_CHAR | 128, - "getadhocstatus"}, - { - WLAN_SETNONE_GETWORDCHAR, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | 128, - ""}, - { - WLANSETWPAIE, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24, - IW_PRIV_TYPE_NONE, - "setwpaie"}, - { - WLANGETLOG, - IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE, - "getlog"}, - { - WLAN_SET_GET_SIXTEEN_INT, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - ""}, - { - WLAN_TPCCFG, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "tpccfg"}, - { - WLAN_POWERCFG, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "powercfg"}, - { - WLAN_AUTO_FREQ_SET, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "setafc"}, - { - WLAN_AUTO_FREQ_GET, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "getafc"}, - { - WLAN_SCANPROBES, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "scanprobes"}, - { - WLAN_LED_GPIO_CTRL, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "ledgpio"}, - { - WLAN_ADAPT_RATESET, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "rateadapt"}, - { - WLAN_INACTIVITY_TIMEOUT, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "inactivityto"}, - { - WLANSNR, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "getSNR"}, - { - WLAN_GET_RATE, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "getrate"}, - { - WLAN_GET_RXINFO, - IW_PRIV_TYPE_INT | 16, - IW_PRIV_TYPE_INT | 16, - "getrxinfo"}, -}; - -static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) -{ - enum { - POOR = 30, - FAIR = 60, - GOOD = 80, - VERY_GOOD = 90, - EXCELLENT = 95, - PERFECT = 100 - }; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - u32 rssi_qual; - u32 tx_qual; - u32 quality = 0; - int stats_valid = 0; - u8 rssi; - u32 tx_retries; - - ENTER(); - - priv->wstats.status = adapter->inframode; - - /* If we're not associated, all quality values are meaningless */ - if (adapter->connect_status != libertas_connected) - goto out; - - /* Quality by RSSI */ - priv->wstats.qual.level = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], - adapter->NF[TYPE_BEACON][TYPE_NOAVG]); - - if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { - priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; - } else { - priv->wstats.qual.noise = - CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); - } - - lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level); - lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise); - - rssi = priv->wstats.qual.level - priv->wstats.qual.noise; - if (rssi < 15) - rssi_qual = rssi * POOR / 10; - else if (rssi < 20) - rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; - else if (rssi < 30) - rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; - else if (rssi < 40) - rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / - 10 + GOOD; - else - rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / - 10 + VERY_GOOD; - quality = rssi_qual; - - /* Quality by TX errors */ - priv->wstats.discard.retries = priv->stats.tx_errors; - - tx_retries = adapter->logmsg.retry; - - if (tx_retries > 75) - tx_qual = (90 - tx_retries) * POOR / 15; - else if (tx_retries > 70) - tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; - else if (tx_retries > 65) - tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; - else if (tx_retries > 50) - tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / - 15 + GOOD; - else - tx_qual = (50 - tx_retries) * - (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; - quality = min(quality, tx_qual); - - priv->wstats.discard.code = adapter->logmsg.wepundecryptable; - priv->wstats.discard.fragment = adapter->logmsg.fcserror; - priv->wstats.discard.retries = tx_retries; - priv->wstats.discard.misc = adapter->logmsg.ackfailure; - - /* Calculate quality */ - priv->wstats.qual.qual = max(quality, (u32)100); - priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - stats_valid = 1; - - /* update stats asynchronously for future calls */ - libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, - 0, 0, NULL); - libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0, - 0, 0, NULL); -out: - if (!stats_valid) { - priv->wstats.miss.beacon = 0; - priv->wstats.discard.retries = 0; - priv->wstats.qual.qual = 0; - priv->wstats.qual.level = 0; - priv->wstats.qual.noise = 0; - priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; - priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; - } - - LEAVE (); - return &priv->wstats; - - -} - -static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int rc = -EINPROGRESS; /* Call commit handler */ - struct chan_freq_power *cfp; - - ENTER(); - - /* - * If setting by frequency, convert to a channel - */ - if (fwrq->e == 1) { - - long f = fwrq->m / 100000; - int c = 0; - - cfp = find_cfp_by_band_and_freq(adapter, 0, f); - if (!cfp) { - lbs_pr_debug(1, "Invalid freq=%ld\n", f); - return -EINVAL; - } - - c = (int)cfp->channel; - - if (c < 0) - return -EINVAL; - - fwrq->e = 0; - fwrq->m = c; - } - - /* - * Setting by channel number - */ - if (fwrq->m > 1000 || fwrq->e > 0) { - rc = -EOPNOTSUPP; - } else { - int channel = fwrq->m; - - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel); - if (!cfp) { - rc = -EINVAL; - } else { - if (adapter->inframode == wlan802_11ibss) { - rc = changeadhocchannel(priv, channel); - /* If station is WEP enabled, send the - * command to set WEP in firmware - */ - if (adapter->secinfo.WEPstatus == - wlan802_11WEPenabled) { - lbs_pr_debug(1, "set_freq: WEP enabled\n"); - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_add, - cmd_option_waitforrsp, - 0, - NULL); - - if (ret) { - LEAVE(); - return ret; - } - - adapter->currentpacketfilter |= - cmd_act_mac_wep_enable; - - libertas_set_mac_packet_filter(priv); - } - } else { - rc = -EOPNOTSUPP; - } - } - } - - LEAVE(); - return rc; -} - -/** - * @brief use index to get the data rate - * - * @param index The index of data rate - * @return data rate or 0 - */ -u32 libertas_index_to_data_rate(u8 index) -{ - if (index >= sizeof(libertas_wlan_data_rates)) - index = 0; - - return libertas_wlan_data_rates[index]; -} - -/** - * @brief use rate to get the index - * - * @param rate data rate - * @return index or 0 - */ -u8 libertas_data_rate_to_index(u32 rate) -{ - u8 *ptr; - - if (rate) - if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, - sizeof(libertas_wlan_data_rates)))) - return (ptr - libertas_wlan_data_rates); - - return 0; -} - -static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - u32 data_rate; - u16 action; - int ret = 0; - u8 rates[WLAN_SUPPORTED_RATES]; - u8 *rate; - - ENTER(); - - lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value); - - if (vwrq->value == -1) { - action = cmd_act_set_tx_auto; // Auto - adapter->is_datarate_auto = 1; - adapter->datarate = 0; - } else { - if (vwrq->value % 100000) { - return -EINVAL; - } - - data_rate = vwrq->value / 500000; - - memset(rates, 0, sizeof(rates)); - get_active_data_rates(adapter, rates); - rate = rates; - while (*rate) { - lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate, - data_rate); - if ((*rate & 0x7f) == (data_rate & 0x7f)) - break; - rate++; - } - if (!*rate) { - lbs_pr_alert( "The fixed data rate 0x%X is out " - "of range.\n", data_rate); - return -EINVAL; - } - - adapter->datarate = data_rate; - action = cmd_act_set_tx_fix_rate; - adapter->is_datarate_auto = 0; - } - - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - action, cmd_option_waitforrsp, 0, NULL); - - LEAVE(); - return ret; -} - -static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (adapter->is_datarate_auto) { - vwrq->fixed = 0; - } else { - vwrq->fixed = 1; - } - - vwrq->value = adapter->datarate * 500000; - - LEAVE(); - return 0; -} - -static int wlan_set_mode(struct net_device *dev, - struct iw_request_info *info, u32 * uwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct assoc_request * assoc_req; - enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; - - ENTER(); - - switch (*uwrq) { - case IW_MODE_ADHOC: - lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n", - adapter->datarate); - new_mode = wlan802_11ibss; - adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; - break; - - case IW_MODE_INFRA: - lbs_pr_debug(1, "Wanted mode is Infrastructure\n"); - new_mode = wlan802_11infrastructure; - break; - - case IW_MODE_AUTO: - lbs_pr_debug(1, "Wanted mode is Auto\n"); - new_mode = wlan802_11autounknown; - break; - - default: - lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq); - return -EINVAL; - } - - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - } else { - assoc_req->mode = new_mode; - } - - if (ret == 0) { - set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); - wlan_postpone_association_work(priv); - } else { - wlan_cancel_association_work(priv); - } - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - - -/** - * @brief Get Encryption key - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 --success, otherwise fail - */ -static int wlan_get_encode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, u8 * extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - - ENTER(); - - lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n", - dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx); - - dwrq->flags = 0; - - /* Authentication method */ - switch (adapter->secinfo.authmode) { - case wlan802_11authmodeopen: - dwrq->flags = IW_ENCODE_OPEN; - break; - - case wlan802_11authmodeshared: - case wlan802_11authmodenetworkEAP: - dwrq->flags = IW_ENCODE_RESTRICTED; - break; - default: - dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; - break; - } - - if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) - || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { - dwrq->flags &= ~IW_ENCODE_DISABLED; - } else { - dwrq->flags |= IW_ENCODE_DISABLED; - } - - memset(extra, 0, 16); - - mutex_lock(&adapter->lock); - - /* Default to returning current transmit key */ - if (index < 0) - index = adapter->wep_tx_keyidx; - - if ((adapter->wep_keys[index].len) && - (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) { - memcpy(extra, adapter->wep_keys[index].key, - adapter->wep_keys[index].len); - dwrq->length = adapter->wep_keys[index].len; - - dwrq->flags |= (index + 1); - /* Return WEP enabled */ - dwrq->flags &= ~IW_ENCODE_DISABLED; - } else if ((adapter->secinfo.WPAenabled) - || (adapter->secinfo.WPA2enabled)) { - /* return WPA enabled */ - dwrq->flags &= ~IW_ENCODE_DISABLED; - } else { - dwrq->flags |= IW_ENCODE_DISABLED; - } - - mutex_unlock(&adapter->lock); - - dwrq->flags |= IW_ENCODE_NOKEY; - - lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n", - extra[0], extra[1], extra[2], - extra[3], extra[4], extra[5], dwrq->length); - - lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags); - - LEAVE(); - return 0; -} - -/** - * @brief Set Encryption key (internal) - * - * @param priv A pointer to private card structure - * @param key_material A pointer to key material - * @param key_length length of key material - * @param index key index to set - * @param set_tx_key Force set TX key (1 = yes, 0 = no) - * @return 0 --success, otherwise fail - */ -static int wlan_set_wep_key(struct assoc_request *assoc_req, - const char *key_material, - u16 key_length, - u16 index, - int set_tx_key) -{ - struct WLAN_802_11_KEY *pkey; - - ENTER(); - - /* Paranoid validation of key index */ - if (index > 3) { - LEAVE(); - return -EINVAL; - } - - /* validate max key length */ - if (key_length > KEY_LEN_WEP_104) { - LEAVE(); - return -EINVAL; - } - - pkey = &assoc_req->wep_keys[index]; - - if (key_length > 0) { - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); - pkey->type = KEY_TYPE_ID_WEP; - - /* Standardize the key length */ - pkey->len = (key_length > KEY_LEN_WEP_40) ? - KEY_LEN_WEP_104 : KEY_LEN_WEP_40; - memcpy(pkey->key, key_material, key_length); - } - - if (set_tx_key) { - /* Ensure the chosen key is valid */ - if (!pkey->len) { - lbs_pr_debug(1, "key not set, so cannot enable it\n"); - LEAVE(); - return -EINVAL; - } - assoc_req->wep_tx_keyidx = index; - } - - assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled; - - LEAVE(); - return 0; -} - -static int validate_key_index(u16 def_index, u16 raw_index, - u16 *out_index, u16 *is_default) -{ - if (!out_index || !is_default) - return -EINVAL; - - /* Verify index if present, otherwise use default TX key index */ - if (raw_index > 0) { - if (raw_index > 4) - return -EINVAL; - *out_index = raw_index - 1; - } else { - *out_index = def_index; - *is_default = 1; - } - return 0; -} - -static void disable_wep(struct assoc_request *assoc_req) -{ - int i; - - /* Set Open System auth mode */ - assoc_req->secinfo.authmode = wlan802_11authmodeopen; - - /* Clear WEP keys and mark WEP as disabled */ - assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; - for (i = 0; i < 4; i++) - assoc_req->wep_keys[i].len = 0; - - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); -} - -/** - * @brief Set Encryption key - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 --success, otherwise fail - */ -static int wlan_set_encode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct assoc_request * assoc_req; - u16 is_default = 0, index = 0, set_tx_key = 0; - - ENTER(); - - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - goto out; - } - - if (dwrq->flags & IW_ENCODE_DISABLED) { - disable_wep (assoc_req); - goto out; - } - - ret = validate_key_index(assoc_req->wep_tx_keyidx, - (dwrq->flags & IW_ENCODE_INDEX), - &index, &is_default); - if (ret) { - ret = -EINVAL; - goto out; - } - - /* If WEP isn't enabled, or if there is no key data but a valid - * index, set the TX key. - */ - if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) - || (dwrq->length == 0 && !is_default)) - set_tx_key = 1; - - ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); - if (ret) - goto out; - - if (dwrq->length) - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); - if (set_tx_key) - set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); - - if (dwrq->flags & IW_ENCODE_RESTRICTED) { - assoc_req->secinfo.authmode = wlan802_11authmodeshared; - } else if (dwrq->flags & IW_ENCODE_OPEN) { - assoc_req->secinfo.authmode = wlan802_11authmodeopen; - } - -out: - if (ret == 0) { - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - wlan_postpone_association_work(priv); - } else { - wlan_cancel_association_work(priv); - } - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - -/** - * @brief Get Extended Encryption key (WPA/802.1x and WEP) - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 on success, otherwise failure - */ -static int wlan_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, - char *extra) -{ - int ret = -EINVAL; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int index, max_key_len; - - ENTER(); - - max_key_len = dwrq->length - sizeof(*ext); - if (max_key_len < 0) - goto out; - - index = dwrq->flags & IW_ENCODE_INDEX; - if (index) { - if (index < 1 || index > 4) - goto out; - index--; - } else { - index = adapter->wep_tx_keyidx; - } - - if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY && - ext->alg != IW_ENCODE_ALG_WEP) { - if (index != 0 || adapter->inframode != wlan802_11infrastructure) - goto out; - } - - dwrq->flags = index + 1; - memset(ext, 0, sizeof(*ext)); - - if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) - && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) { - ext->alg = IW_ENCODE_ALG_NONE; - ext->key_len = 0; - dwrq->flags |= IW_ENCODE_DISABLED; - } else { - u8 *key = NULL; - - if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled) { - ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = adapter->wep_keys[index].len; - key = &adapter->wep_keys[index].key[0]; - } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) && - (adapter->secinfo.WPAenabled || - adapter->secinfo.WPA2enabled)) { - /* WPA */ - ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = 0; - } else { - goto out; - } - - if (ext->key_len > max_key_len) { - ret = -E2BIG; - goto out; - } - - if (ext->key_len) - memcpy(ext->key, key, ext->key_len); - else - dwrq->flags |= IW_ENCODE_NOKEY; - dwrq->flags |= IW_ENCODE_ENABLED; - } - ret = 0; - -out: - LEAVE(); - return ret; -} - -/** - * @brief Set Encryption key Extended (WPA/802.1x and WEP) - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 --success, otherwise fail - */ -static int wlan_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, - char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int alg = ext->alg; - struct assoc_request * assoc_req; - - ENTER(); - - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - goto out; - } - - if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { - disable_wep (assoc_req); - } else if (alg == IW_ENCODE_ALG_WEP) { - u16 is_default = 0, index, set_tx_key = 0; - - ret = validate_key_index(assoc_req->wep_tx_keyidx, - (dwrq->flags & IW_ENCODE_INDEX), - &index, &is_default); - if (ret) - goto out; - - /* If WEP isn't enabled, or if there is no key data but a valid - * index, or if the set-TX-key flag was passed, set the TX key. - */ - if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) - || (dwrq->length == 0 && !is_default) - || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) - set_tx_key = 1; - - /* Copy key to driver */ - ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index, - set_tx_key); - if (ret) - goto out; - - if (dwrq->flags & IW_ENCODE_RESTRICTED) { - assoc_req->secinfo.authmode = - wlan802_11authmodeshared; - } else if (dwrq->flags & IW_ENCODE_OPEN) { - assoc_req->secinfo.authmode = - wlan802_11authmodeopen; - } - - /* Mark the various WEP bits as modified */ - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - if (dwrq->length) - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); - if (set_tx_key) - set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); - - } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { - struct WLAN_802_11_KEY * pkey; - - /* validate key length */ - if (((alg == IW_ENCODE_ALG_TKIP) - && (ext->key_len != KEY_LEN_WPA_TKIP)) - || ((alg == IW_ENCODE_ALG_CCMP) - && (ext->key_len != KEY_LEN_WPA_AES))) { - lbs_pr_debug(1, "Invalid size %d for key of alg" - "type %d.\n", - ext->key_len, - alg); - ret = -EINVAL; - goto out; - } - - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - pkey = &assoc_req->wpa_mcast_key; - else - pkey = &assoc_req->wpa_unicast_key; - - memset(pkey, 0, sizeof (struct WLAN_802_11_KEY)); - memcpy(pkey->key, ext->key, ext->key_len); - pkey->len = ext->key_len; - pkey->flags = KEY_INFO_WPA_ENABLED; - - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - pkey->flags |= KEY_INFO_WPA_MCAST; - set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); - } else { - pkey->flags |= KEY_INFO_WPA_UNICAST; - set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); - } - - if (alg == IW_ENCODE_ALG_TKIP) - pkey->type = KEY_TYPE_ID_TKIP; - else if (alg == IW_ENCODE_ALG_CCMP) - pkey->type = KEY_TYPE_ID_AES; - - /* If WPA isn't enabled yet, do that now */ - if ( assoc_req->secinfo.WPAenabled == 0 - && assoc_req->secinfo.WPA2enabled == 0) { - assoc_req->secinfo.WPAenabled = 1; - assoc_req->secinfo.WPA2enabled = 1; - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - } - - disable_wep (assoc_req); - } - -out: - if (ret == 0) { - wlan_postpone_association_work(priv); - } else { - wlan_cancel_association_work(priv); - } - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - - -static int wlan_set_genie(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, - char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - struct assoc_request * assoc_req; - - ENTER(); - - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - goto out; - } - - if (dwrq->length > MAX_WPA_IE_LEN || - (dwrq->length && extra == NULL)) { - ret = -EINVAL; - goto out; - } - - if (dwrq->length) { - memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); - assoc_req->wpa_ie_len = dwrq->length; - } else { - memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie)); - assoc_req->wpa_ie_len = 0; - } - -out: - if (ret == 0) { - set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); - wlan_postpone_association_work(priv); - } else { - wlan_cancel_association_work(priv); - } - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - -static int wlan_get_genie(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, - char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - if (adapter->wpa_ie_len == 0) { - dwrq->length = 0; - LEAVE(); - return 0; - } - - if (dwrq->length < adapter->wpa_ie_len) { - LEAVE(); - return -E2BIG; - } - - dwrq->length = adapter->wpa_ie_len; - memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len); - - LEAVE(); - return 0; -} - - -static int wlan_set_auth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *dwrq, - char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct assoc_request * assoc_req; - int ret = 0; - int updated = 0; - - ENTER(); - - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - goto out; - } - - switch (dwrq->flags & IW_AUTH_INDEX) { - case IW_AUTH_TKIP_COUNTERMEASURES: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * libertas does not use these parameters - */ - break; - - case IW_AUTH_WPA_VERSION: - if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { - assoc_req->secinfo.WPAenabled = 0; - assoc_req->secinfo.WPA2enabled = 0; - } - if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { - assoc_req->secinfo.WPAenabled = 1; - assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; - assoc_req->secinfo.authmode = - wlan802_11authmodeopen; - } - if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { - assoc_req->secinfo.WPA2enabled = 1; - assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; - assoc_req->secinfo.authmode = - wlan802_11authmodeopen; - } - updated = 1; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - if (dwrq->value) { - adapter->currentpacketfilter |= - cmd_act_mac_strict_protection_enable; - } else { - adapter->currentpacketfilter &= - ~cmd_act_mac_strict_protection_enable; - } - updated = 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { - assoc_req->secinfo.authmode = - wlan802_11authmodeshared; - } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { - assoc_req->secinfo.authmode = - wlan802_11authmodeopen; - } else if (dwrq->value & IW_AUTH_ALG_LEAP) { - assoc_req->secinfo.authmode = - wlan802_11authmodenetworkEAP; - } else { - ret = -EINVAL; - } - updated = 1; - break; - - case IW_AUTH_WPA_ENABLED: - if (dwrq->value) { - if (!assoc_req->secinfo.WPAenabled && - !assoc_req->secinfo.WPA2enabled) { - assoc_req->secinfo.WPAenabled = 1; - assoc_req->secinfo.WPA2enabled = 1; - assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; - assoc_req->secinfo.authmode = - wlan802_11authmodeopen; - } - } else { - assoc_req->secinfo.WPAenabled = 0; - assoc_req->secinfo.WPA2enabled = 0; - } - updated = 1; - break; - - default: - ret = -EOPNOTSUPP; - break; - } - -out: - if (ret == 0) { - if (updated) - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - wlan_postpone_association_work(priv); - } else if (ret != -EOPNOTSUPP) { - wlan_cancel_association_work(priv); - } - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - -static int wlan_get_auth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *dwrq, - char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - - switch (dwrq->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - dwrq->value = 0; - if (adapter->secinfo.WPAenabled) - dwrq->value |= IW_AUTH_WPA_VERSION_WPA; - if (adapter->secinfo.WPA2enabled) - dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; - if (!dwrq->value) - dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - dwrq->value = 0; - if (adapter->currentpacketfilter & - cmd_act_mac_strict_protection_enable) - dwrq->value = 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - switch (adapter->secinfo.authmode) { - case wlan802_11authmodeshared: - dwrq->value = IW_AUTH_ALG_SHARED_KEY; - break; - case wlan802_11authmodeopen: - dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - case wlan802_11authmodenetworkEAP: - dwrq->value = IW_AUTH_ALG_LEAP; - break; - default: - break; - } - break; - - case IW_AUTH_WPA_ENABLED: - if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled) - dwrq->value = 1; - break; - - default: - LEAVE(); - return -EOPNOTSUPP; - } - - LEAVE(); - return 0; -} - - -static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - u16 dbm; - - ENTER(); - - if (vwrq->disabled) { - wlan_radio_ioctl(priv, RADIO_OFF); - return 0; - } - - adapter->preamble = cmd_type_auto_preamble; - - wlan_radio_ioctl(priv, RADIO_ON); - - if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - dbm = (u16) mw_to_dbm(vwrq->value); - } else - dbm = (u16) vwrq->value; - - /* auto tx power control */ - - if (vwrq->fixed == 0) - dbm = 0xffff; - - lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm); - - ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_set_low, - cmd_option_waitforrsp, 0, (void *)&dbm); - - LEAVE(); - return ret; -} - -static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - ENTER(); - /* - * Note : if dwrq->flags != 0, we should get the relevant SSID from - * the SSID list... - */ - - /* - * Get the current SSID - */ - if (adapter->connect_status == libertas_connected) { - memcpy(extra, adapter->curbssparams.ssid.ssid, - adapter->curbssparams.ssid.ssidlength); - extra[adapter->curbssparams.ssid.ssidlength] = '\0'; - } else { - memset(extra, 0, 32); - extra[adapter->curbssparams.ssid.ssidlength] = '\0'; - } - /* - * If none, we may want to get the one that was set - */ - - /* To make the driver backward compatible with WPA supplicant v0.2.4 */ - if (dwrq->length == 32) /* check with WPA supplicant buffer size */ - dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength, - IW_ESSID_MAX_SIZE); - else - dwrq->length = adapter->curbssparams.ssid.ssidlength + 1; - - dwrq->flags = 1; /* active */ - - LEAVE(); - return 0; -} - -static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - struct WLAN_802_11_SSID ssid; - struct assoc_request * assoc_req; - int ssid_len = dwrq->length; - - ENTER(); - - /* - * WE-20 and earlier NULL pad the end of the SSID and increment - * SSID length so it can be used like a string. WE-21 and later don't, - * but some userspace tools aren't able to cope with the change. - */ - if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0')) - ssid_len--; - - /* Check the size of the string */ - if (ssid_len > IW_ESSID_MAX_SIZE) { - ret = -E2BIG; - goto out; - } - - memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID)); - - if (!dwrq->flags || !ssid_len) { - /* "any" SSID requested; leave SSID blank */ - } else { - /* Specific SSID requested */ - memcpy(&ssid.ssid, extra, ssid_len); - ssid.ssidlength = ssid_len; - } - - lbs_pr_debug(1, "Requested new SSID = %s\n", - (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any"); - -out: - mutex_lock(&adapter->lock); - if (ret == 0) { - /* Get or create the current association request */ - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - ret = -ENOMEM; - } else { - /* Copy the SSID to the association request */ - memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID)); - set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); - wlan_postpone_association_work(priv); - } - } - - /* Cancel the association request if there was an error */ - if (ret != 0) { - wlan_cancel_association_work(priv); - } - - mutex_unlock(&adapter->lock); - - LEAVE(); - return ret; -} - -/** - * @brief Connect to the AP or Ad-hoc Network with specific bssid - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param awrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * @return 0 --success, otherwise fail - */ -static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - struct assoc_request * assoc_req; - int ret = 0; - - ENTER(); - - if (awrq->sa_family != ARPHRD_ETHER) - return -EINVAL; - - lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data)); - - mutex_lock(&adapter->lock); - - /* Get or create the current association request */ - assoc_req = wlan_get_association_request(adapter); - if (!assoc_req) { - wlan_cancel_association_work(priv); - ret = -ENOMEM; - } else { - /* Copy the BSSID to the association request */ - memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); - set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); - wlan_postpone_association_work(priv); - } - - mutex_unlock(&adapter->lock); - - return ret; -} - -void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen) -{ - union { - u32 l; - u8 c[4]; - } ver; - char fwver[32]; - - mutex_lock(&adapter->lock); - ver.l = adapter->fwreleasenumber; - mutex_unlock(&adapter->lock); - - if (ver.c[3] == 0) - sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]); - else - sprintf(fwver, "%u.%u.%u.p%u", - ver.c[2], ver.c[1], ver.c[0], ver.c[3]); - - snprintf(fwversion, maxlen, fwver); -} - - -/* - * iwconfig settable callbacks - */ -static const iw_handler wlan_handler[] = { - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) wlan_get_name, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ - (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ - (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ - (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL, /* SIOCSIWRANGE */ - (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ - (iw_handler) NULL, /* SIOCSIWPRIV */ - (iw_handler) NULL, /* SIOCGIWPRIV */ - (iw_handler) NULL, /* SIOCSIWSTATS */ - (iw_handler) NULL, /* SIOCGIWSTATS */ - iw_handler_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ - (iw_handler) wlan_set_wap, /* SIOCSIWAP */ - (iw_handler) wlan_get_wap, /* SIOCGIWAP */ - (iw_handler) NULL, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ - (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ - (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ - (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ - (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ - (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ - (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ - (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ - (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ - (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ - (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ - (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ - (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ - (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ - (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ - (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ - (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ - (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ - (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ - (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ - (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ - (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ - (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ - (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */ - (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ -}; - -struct iw_handler_def libertas_handler_def = { - .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), - .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(wlan_private_args) / - sizeof(struct iw_priv_args), - .standard = (iw_handler *) wlan_handler, - .private = (iw_handler *) wlan_private_handler, - .private_args = (struct iw_priv_args *)wlan_private_args, - .get_wireless_stats = wlan_get_wireless_stats, -}; diff --git a/trunk/drivers/net/wireless/libertas/wext.h b/trunk/drivers/net/wireless/libertas/wext.h deleted file mode 100644 index 39f367c38d90..000000000000 --- a/trunk/drivers/net/wireless/libertas/wext.h +++ /dev/null @@ -1,147 +0,0 @@ -/** - * This file contains definition for IOCTL call. - */ -#ifndef _WLAN_WEXT_H_ -#define _WLAN_WEXT_H_ - -#define SUBCMD_OFFSET 4 -#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) - -/** PRIVATE CMD ID */ -#define WLANIOCTL SIOCIWFIRSTPRIV - -#define WLANSETWPAIE (WLANIOCTL + 0) - -#define WLAN_SETINT_GETINT (WLANIOCTL + 7) -#define WLANNF 1 -#define WLANRSSI 2 -#define WLANENABLE11D 5 -#define WLANADHOCGRATE 6 -#define WLAN_SUBCMD_SET_PRESCAN 11 - -#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) -#define WLANDEAUTH 1 -#define WLANRADIOON 2 -#define WLANRADIOOFF 3 -#define WLANREMOVEADHOCAES 4 -#define WLANADHOCSTOP 5 -#define WLANCIPHERTEST 6 -#define WLANCRYPTOTEST 7 - -#define WLANWLANIDLEON 10 -#define WLANWLANIDLEOFF 11 -#define WLAN_SUBCMD_BT_RESET 13 -#define WLAN_SUBCMD_FWT_RESET 14 - -#define WLANGETLOG (WLANIOCTL + 9) -#define GETLOG_BUFSIZE 300 - -#define WLANSCAN_TYPE (WLANIOCTL + 11) - -#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15) -#define WLANGETREGION 1 -#define WLAN_GET_LISTEN_INTERVAL 2 -#define WLAN_GET_MULTIPLE_DTIM 3 -#define WLAN_GET_TX_RATE 4 -#define WLANGETBCNAVG 5 - -#define WLAN_GET_LINKMODE 6 -#define WLAN_GET_RADIOMODE 7 -#define WLAN_GET_DEBUGMODE 8 -#define WLAN_SUBCMD_FWT_CLEANUP 15 -#define WLAN_SUBCMD_FWT_TIME 16 -#define WLAN_SUBCMD_MESH_GET_TTL 17 - -#define WLANREGCFRDWR (WLANIOCTL + 18) - -#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19) -#define WLAN_SUBCMD_GETRXANTENNA 1 -#define WLAN_SUBCMD_GETTXANTENNA 2 -#define WLAN_GET_TSF 3 - -#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21) -#define WLANGETADHOCAES 1 - -#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23) -#define WLAN_BEACON_INTERVAL 1 -#define WLAN_LISTENINTRVL 4 - -#define WLAN_TXCONTROL 6 -#define WLAN_NULLPKTINTERVAL 7 - -#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24) -#define WLAN_SUBCMD_SETRXANTENNA 1 -#define WLAN_SUBCMD_SETTXANTENNA 2 -#define WLANSETAUTHALG 5 -#define WLANSET8021XAUTHALG 6 -#define WLANSETENCRYPTIONMODE 7 -#define WLANSETREGION 8 -#define WLAN_SET_LISTEN_INTERVAL 9 - -#define WLAN_SET_MULTIPLE_DTIM 10 -#define WLAN_SET_ATIM_WINDOW 11 -#define WLANSETBCNAVG 13 -#define WLANSETDATAAVG 14 -#define WLAN_SET_LINKMODE 15 -#define WLAN_SET_RADIOMODE 16 -#define WLAN_SET_DEBUGMODE 17 -#define WLAN_SUBCMD_MESH_SET_TTL 18 - -#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25) -#define WLANSCAN_MODE 6 - -#define WLAN_GET_ADHOC_STATUS 9 - -#define WLAN_SUBCMD_BT_ADD 18 -#define WLAN_SUBCMD_BT_DEL 19 -#define WLAN_SUBCMD_BT_LIST 20 -#define WLAN_SUBCMD_FWT_ADD 21 -#define WLAN_SUBCMD_FWT_DEL 22 -#define WLAN_SUBCMD_FWT_LOOKUP 23 -#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24 -#define WLAN_SUBCMD_FWT_LIST 25 -#define WLAN_SUBCMD_FWT_LIST_ROUTE 26 - -#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29) -#define WLAN_TPCCFG 1 -#define WLAN_POWERCFG 2 - -#define WLAN_AUTO_FREQ_SET 3 -#define WLAN_AUTO_FREQ_GET 4 -#define WLAN_LED_GPIO_CTRL 5 -#define WLAN_SCANPROBES 6 -#define WLAN_ADAPT_RATESET 8 -#define WLAN_INACTIVITY_TIMEOUT 9 -#define WLANSNR 10 -#define WLAN_GET_RATE 11 -#define WLAN_GET_RXINFO 12 - -#define WLANCMD52RDWR (WLANIOCTL + 30) -#define WLANCMD53RDWR (WLANIOCTL + 31) -#define CMD53BUFLEN 32 - -#define REG_MAC 0x19 -#define REG_BBP 0x1a -#define REG_RF 0x1b -#define REG_EEPROM 0x59 -#define WLAN_LINKMODE_802_3 0 -#define WLAN_LINKMODE_802_11 2 -#define WLAN_RADIOMODE_NONE 0 -#define WLAN_RADIOMODE_RADIOTAP 2 - -/** wlan_ioctl_regrdwr */ -struct wlan_ioctl_regrdwr { - /** Which register to access */ - u16 whichreg; - /** Read or Write */ - u16 action; - u32 offset; - u16 NOB; - u32 value; -}; - -extern struct iw_handler_def libertas_handler_def; -int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i); -int wlan_radio_ioctl(wlan_private * priv, u8 option); - -#endif /* _WLAN_WEXT_H_ */ diff --git a/trunk/drivers/net/wireless/netwave_cs.c b/trunk/drivers/net/wireless/netwave_cs.c index 45b00e13ab2b..a009ab517710 100644 --- a/trunk/drivers/net/wireless/netwave_cs.c +++ b/trunk/drivers/net/wireless/netwave_cs.c @@ -1283,6 +1283,7 @@ static int netwave_rx(struct net_device *dev) skb_reserve( skb, 2); /* Align IP on 16 byte */ skb_put( skb, rcvLen); + skb->dev = dev; /* Copy packet fragments to the skb data area */ ptr = (u_char*) skb->data; diff --git a/trunk/drivers/net/wireless/orinoco.c b/trunk/drivers/net/wireless/orinoco.c index 062286dc8e15..4e7f6cf51436 100644 --- a/trunk/drivers/net/wireless/orinoco.c +++ b/trunk/drivers/net/wireless/orinoco.c @@ -689,7 +689,7 @@ static void orinoco_stat_gather(struct net_device *dev, /* Note : gcc will optimise the whole section away if * WIRELESS_SPY is not defined... - Jean II */ if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, + orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, desc->signal, desc->silence); } } @@ -770,7 +770,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, /* Copy the 802.11 header to the skb */ memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; /* If any, copy the data from the card to the skb */ if (datalen > 0) { @@ -915,6 +915,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) memcpy(hdr->h_source, desc.addr2, ETH_ALEN); dev->last_rx = jiffies; + skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; if (fc & IEEE80211_FCTL_TODS) diff --git a/trunk/drivers/net/wireless/prism54/islpci_eth.c b/trunk/drivers/net/wireless/prism54/islpci_eth.c index dd070cccf324..b1122912ee2d 100644 --- a/trunk/drivers/net/wireless/prism54/islpci_eth.c +++ b/trunk/drivers/net/wireless/prism54/islpci_eth.c @@ -136,7 +136,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) printk("islpci_eth_transmit:wds_mac\n"); #endif memmove(skb->data + 6, src, skb->len); - skb_copy_to_linear_data(skb, wds_mac, 6); + memcpy(skb->data, wds_mac, 6); } else { memmove(skb->data, src, skb->len); } @@ -162,16 +162,13 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) skb_put(newskb, init_wds ? skb->len + 6 : skb->len); if (init_wds) { - skb_copy_from_linear_data(skb, - newskb->data + 6, - skb->len); - skb_copy_to_linear_data(newskb, wds_mac, 6); + memcpy(newskb->data + 6, skb->data, skb->len); + memcpy(newskb->data, wds_mac, 6); #ifdef ISLPCI_ETH_DEBUG printk("islpci_eth_transmit:wds_mac\n"); #endif } else - skb_copy_from_linear_data(skb, newskb->data, - skb->len); + memcpy(newskb->data, skb->data, skb->len); #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", @@ -306,7 +303,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) skb_pull(*skb, sizeof (struct rfmon_header)); (*skb)->protocol = htons(ETH_P_802_2); - skb_reset_mac_header(*skb); + (*skb)->mac.raw = (*skb)->data; (*skb)->pkt_type = PACKET_OTHERHOST; return 0; @@ -377,6 +374,10 @@ islpci_eth_receive(islpci_private *priv) DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); display_buffer((char *) skb->data, skb->len); #endif + + /* do some additional sk_buff and network layer parameters */ + skb->dev = ndev; + /* take care of monitor mode and spy monitoring. */ if (unlikely(priv->iw_mode == IW_MODE_MONITOR)) discard = islpci_monitor_rx(priv, &skb); @@ -397,10 +398,8 @@ islpci_eth_receive(islpci_private *priv) /* Update spy records */ wireless_spy_update(ndev, annex->addr2, &wstats); - skb_copy_from_linear_data(skb, - (skb->data + - sizeof(struct rfmon_header)), - 2 * ETH_ALEN); + memcpy(skb->data + sizeof (struct rfmon_header), + skb->data, 2 * ETH_ALEN); skb_pull(skb, sizeof (struct rfmon_header)); } skb->protocol = eth_type_trans(skb, ndev); diff --git a/trunk/drivers/net/wireless/ray_cs.c b/trunk/drivers/net/wireless/ray_cs.c index 3be624295a1f..47b2ccb6a633 100644 --- a/trunk/drivers/net/wireless/ray_cs.c +++ b/trunk/drivers/net/wireless/ray_cs.c @@ -2232,6 +2232,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i return; } skb_reserve( skb, 2); /* Align IP on 16 byte (TBD check this)*/ + skb->dev = dev; DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len); @@ -2242,8 +2243,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); /* Get source address */ #ifdef WIRELESS_SPY - skb_copy_from_linear_data_offset(skb, offsetof(struct mac_header, addr_2), - linksrcaddr, ETH_ALEN); + memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN); #endif /* Now, deal with encapsulation/translation/sniffer */ if (!sniffer) { diff --git a/trunk/drivers/net/wireless/strip.c b/trunk/drivers/net/wireless/strip.c index ef32a5c1e818..f5ce1c6063d8 100644 --- a/trunk/drivers/net/wireless/strip.c +++ b/trunk/drivers/net/wireless/strip.c @@ -1971,7 +1971,8 @@ static struct net_device *get_strip_dev(struct strip *strip_info) sizeof(zero_address))) { struct net_device *dev; read_lock_bh(&dev_base_lock); - for_each_netdev(dev) { + dev = dev_base; + while (dev) { if (dev->type == strip_info->dev->type && !memcmp(dev->dev_addr, &strip_info->true_dev_addr, @@ -1982,6 +1983,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info) read_unlock_bh(&dev_base_lock); return (dev); } + dev = dev->next; } read_unlock_bh(&dev_base_lock); } @@ -2007,7 +2009,7 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header * header, packetlen); skb->dev = get_strip_dev(strip_info); skb->protocol = header->protocol; - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; /* Having put a fake header on the front of the sk_buff for the */ /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ diff --git a/trunk/drivers/net/wireless/todo.txt b/trunk/drivers/net/wireless/todo.txt new file mode 100644 index 000000000000..32234018de72 --- /dev/null +++ b/trunk/drivers/net/wireless/todo.txt @@ -0,0 +1,15 @@ + Wireless Todo + ------------- + +1) Bring other kernel Wireless LAN drivers here + Completed + +2) Bring new Wireless LAN driver not yet in the kernel there + See my web page for details + In particular : HostAP + +3) Misc + o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete + o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete + + Jean II diff --git a/trunk/drivers/net/wireless/wavelan.c b/trunk/drivers/net/wireless/wavelan.c index 1cf090d60edc..2aa3c761dd83 100644 --- a/trunk/drivers/net/wireless/wavelan.c +++ b/trunk/drivers/net/wireless/wavelan.c @@ -2512,13 +2512,14 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) return; } + skb->dev = dev; + /* Copy the packet to the buffer. */ obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); skb->protocol = eth_type_trans(skb, dev); #ifdef DEBUG_RX_INFO - wv_packet_info(skb_mac_header(skb), sksize, dev->name, - "wv_packet_read"); + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); #endif /* DEBUG_RX_INFO */ /* Statistics-gathering and associated stuff. @@ -2554,7 +2555,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) /* Spying stuff */ #ifdef IW_WIRELESS_SPY - wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); #endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM @@ -2938,7 +2939,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) * need to pad. Jean II */ if (skb->len < ETH_ZLEN) { memset(data, 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, data, skb->len); + memcpy(data, skb->data, skb->len); /* Write packet on the card */ if(wv_packet_write(dev, data, ETH_ZLEN)) return 1; /* We failed */ diff --git a/trunk/drivers/net/wireless/wavelan_cs.c b/trunk/drivers/net/wireless/wavelan_cs.c index 67b867f837ca..b04239792f63 100644 --- a/trunk/drivers/net/wireless/wavelan_cs.c +++ b/trunk/drivers/net/wireless/wavelan_cs.c @@ -2884,12 +2884,14 @@ wv_packet_read(struct net_device * dev, return; } + skb->dev = dev; + skb_reserve(skb, 2); fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); skb->protocol = eth_type_trans(skb, dev); #ifdef DEBUG_RX_INFO - wv_packet_info(skb_mac_header(skb), sksize, dev->name, "wv_packet_read"); + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); #endif /* DEBUG_RX_INFO */ /* Statistics gathering & stuff associated. @@ -2923,7 +2925,7 @@ wv_packet_read(struct net_device * dev, #endif /* WAVELAN_ROAMING */ #ifdef WIRELESS_SPY - wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, stats); + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); #endif /* WIRELESS_SPY */ #ifdef HISTOGRAM wl_his_gather(dev, stats); diff --git a/trunk/drivers/net/wireless/zd1201.c b/trunk/drivers/net/wireless/zd1201.c index 935b144d9b56..6cb66a356c96 100644 --- a/trunk/drivers/net/wireless/zd1201.c +++ b/trunk/drivers/net/wireless/zd1201.c @@ -327,6 +327,7 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, 6), &data[datalen-8], 6); memcpy(skb_put(skb, 2), &data[datalen-24], 2); memcpy(skb_put(skb, len), data, len); + skb->dev = zd->dev; skb->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, zd->dev); zd->stats.rx_packets++; @@ -384,6 +385,7 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, 2), &data[6], 2); memcpy(skb_put(skb, len), data+8, len); } + skb->dev = zd->dev; skb->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, zd->dev); zd->stats.rx_packets++; @@ -807,10 +809,10 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) txbuf[4] = 0x00; txbuf[5] = 0x00; - skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); + memcpy(txbuf+6, skb->data+12, skb->len-12); if (pad) txbuf[skb->len-12+6]=0; - skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); + memcpy(txbuf+skb->len-12+6+pad, skb->data, 12); *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); txbuf[txbuflen-1] = 0; diff --git a/trunk/drivers/net/wireless/zd1211rw/Kconfig b/trunk/drivers/net/wireless/zd1211rw/Kconfig index d1ab24a95630..66ed55bc5460 100644 --- a/trunk/drivers/net/wireless/zd1211rw/Kconfig +++ b/trunk/drivers/net/wireless/zd1211rw/Kconfig @@ -1,7 +1,6 @@ config ZD1211RW tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL - select WIRELESS_EXT + depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL select FW_LOADER ---help--- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_chip.c b/trunk/drivers/net/wireless/zd1211rw/zd_chip.c index 95b4a2a26707..87ee3ee020fe 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_chip.c @@ -67,12 +67,11 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size) i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); - i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, + i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type, chip->patch_cck_gain ? 'g' : '-', chip->patch_cr157 ? '7' : '-', chip->patch_6m_band_edge ? '6' : '-', - chip->new_phy_layout ? 'N' : '-', - chip->al2230s_bit ? 'S' : '-'); + chip->new_phy_layout ? 'N' : '-'); return i; } @@ -115,7 +114,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr /* Allocate a single memory block for values and addresses. */ count16 = 2*count; a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), - GFP_KERNEL); + GFP_NOFS); if (!a16) { dev_dbg_f(zd_chip_dev(chip), "error ENOMEM in allocation of a16\n"); @@ -164,7 +163,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, /* Allocate a single memory block for values and addresses. */ count16 = 2*count; - ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL); + ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS); if (!ioreqs16) { r = -ENOMEM; dev_dbg_f(zd_chip_dev(chip), @@ -615,24 +614,16 @@ static int patch_cr157(struct zd_chip *chip) * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge * bit (for AL2230, AL2230S) */ -static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) -{ - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - if (!chip->patch_6m_band_edge) - return 0; - - return zd_rf_patch_6m_band_edge(&chip->rf, channel); -} - -/* Generic implementation of 6M band edge patching, used by most RFs via - * zd_rf_generic_patch_6m() */ -int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) +static int patch_6m_band_edge(struct zd_chip *chip, int channel) { struct zd_ioreq16 ioreqs[] = { { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, { CR47, 0x1e }, }; + if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge) + return 0; + /* FIXME: Channel 11 is not the edge for all regulatory domains. */ if (channel == 1 || channel == 11) ioreqs[0].value = 0x12; @@ -692,17 +683,17 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip) { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, - { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, - { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, - { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, - { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, - { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, - { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, - { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, + { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 }, + { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 }, + { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 }, + { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c }, + { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c }, + { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 }, + { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa }, + { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea }, + { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a }, + { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba }, /* Note: CR204 must lead the CR203 */ { CR204, 0x7d }, { }, diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_chip.h b/trunk/drivers/net/wireless/zd1211rw/zd_chip.h index ce0a5f6da0d2..e57ed75d9425 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/trunk/drivers/net/wireless/zd1211rw/zd_chip.h @@ -833,7 +833,6 @@ int zd_chip_enable_rx(struct zd_chip *chip); void zd_chip_disable_rx(struct zd_chip *chip); int zd_chip_enable_hwint(struct zd_chip *chip); int zd_chip_disable_hwint(struct zd_chip *chip); -int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel); int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, u8 rts_rate, int preamble); diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_mac.c b/trunk/drivers/net/wireless/zd1211rw/zd_mac.c index 6753d240c168..4c5f78eac349 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_mac.c @@ -156,8 +156,17 @@ void zd_mac_clear(struct zd_mac *mac) static int reset_mode(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; - return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); + struct zd_ioreq32 ioreqs[] = { + { CR_RX_FILTER, STA_RX_FILTER }, + { CR_SNIFFER_ON, 0U }, + }; + + if (ieee->iw_mode == IW_MODE_MONITOR) { + ioreqs[0].value = 0xffffffff; + ioreqs[1].value = 0x1; + } + + return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); } int zd_mac_open(struct net_device *netdev) @@ -965,14 +974,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, switch (ieee->iw_mode) { case IW_MODE_ADHOC: if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || - compare_ether_addr(hdr->addr3, ieee->bssid) != 0) + memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0) return 0; break; case IW_MODE_AUTO: case IW_MODE_INFRA: if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != IEEE80211_FCTL_FROMDS || - compare_ether_addr(hdr->addr2, ieee->bssid) != 0) + memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0) return 0; break; default: @@ -980,9 +989,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, return 0; } - return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 || + return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || (is_multicast_ether_addr(hdr->addr1) && - compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) || + memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || (netdev->flags & IFF_PROMISC); } @@ -1038,7 +1047,7 @@ static void update_qual_rssi(struct zd_mac *mac, hdr = (struct ieee80211_hdr_3addr *)buffer; if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) return; - if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0) + if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0) return; spin_lock_irqsave(&mac->lock, flags); diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_rf.c b/trunk/drivers/net/wireless/zd1211rw/zd_rf.c index 549c23bcd6cc..f50cff3db916 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_rf.c @@ -23,7 +23,7 @@ #include "zd_ieee80211.h" #include "zd_chip.h" -static const char * const rfs[] = { +static const char *rfs[] = { [0] = "unknown RF0", [1] = "unknown RF1", [UW2451_RF] = "UW2451_RF", @@ -34,7 +34,7 @@ static const char * const rfs[] = { [AL2210_RF] = "AL2210_RF", [MAXIM_NEW_RF] = "MAXIM_NEW_RF", [UW2453_RF] = "UW2453_RF", - [UNKNOWN_A_RF] = "UNKNOWN_A_RF", + [AL2230S_RF] = "AL2230S_RF", [RALINK_RF] = "RALINK_RF", [INTERSIL_RF] = "INTERSIL_RF", [RF2959_RF] = "RF2959_RF", @@ -154,17 +154,3 @@ int zd_switch_radio_off(struct zd_rf *rf) r = t; return r; } - -int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel) -{ - if (!rf->patch_6m_band_edge) - return 0; - - return rf->patch_6m_band_edge(rf, channel); -} - -int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel) -{ - return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel); -} - diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_rf.h b/trunk/drivers/net/wireless/zd1211rw/zd_rf.h index aa9cc105ce60..a57732eb69e1 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/trunk/drivers/net/wireless/zd1211rw/zd_rf.h @@ -26,7 +26,7 @@ #define AL2210_RF 0x7 #define MAXIM_NEW_RF 0x8 #define UW2453_RF 0x9 -#define UNKNOWN_A_RF 0xa +#define AL2230S_RF 0xa #define RALINK_RF 0xb #define INTERSIL_RF 0xc #define RF2959_RF 0xd @@ -47,13 +47,17 @@ struct zd_rf { u8 type; u8 channel; + /* + * Whether this RF should patch the 6M band edge + * (assuming E2P_POD agrees) + */ + u8 patch_6m_band_edge:1; /* RF-specific functions */ int (*init_hw)(struct zd_rf *rf); int (*set_channel)(struct zd_rf *rf, u8 channel); int (*switch_radio_on)(struct zd_rf *rf); int (*switch_radio_off)(struct zd_rf *rf); - int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel); }; const char *zd_rf_name(u8 type); @@ -68,9 +72,6 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel); int zd_switch_radio_on(struct zd_rf *rf); int zd_switch_radio_off(struct zd_rf *rf); -int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); -int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); - /* Functions for individual RF chips */ int zd_rf_init_rf2959(struct zd_rf *rf); diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/trunk/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 511392acfedf..5235a7827ac5 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -59,18 +59,6 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { { CR240, 0x57 }, { CR9, 0xe0 }, }; -static const struct zd_ioreq16 ioreqs_init_al2230s[] = { - { CR47, 0x1e }, /* MARK_002 */ - { CR106, 0x22 }, - { CR107, 0x2a }, /* MARK_002 */ - { CR109, 0x13 }, /* MARK_002 */ - { CR118, 0xf8 }, /* MARK_002 */ - { CR119, 0x12 }, { CR122, 0xe0 }, - { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ - { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ - { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ -}; - static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; @@ -102,7 +90,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); - static const struct zd_ioreq16 ioreqs_init[] = { + static const struct zd_ioreq16 ioreqs[] = { { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, @@ -129,9 +117,10 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, { CR253, 0xff }, - }; - static const struct zd_ioreq16 ioreqs_pll[] = { + /* These following happen separately in the vendor driver */ + { }, + /* shdnb(PLL_ON)=0 */ { CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ @@ -139,7 +128,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) { CR138, 0x28 }, { CR203, 0x06 }, }; - static const u32 rv1[] = { + static const u32 rv[] = { /* Channel 1 */ 0x03f790, 0x033331, @@ -148,9 +137,6 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0b3331, 0x03b812, 0x00fff3, - }; - - static const u32 rv2[] = { 0x000da4, 0x0f4dc5, /* fix freq shift, 0x04edc5 */ 0x0805b6, @@ -162,9 +148,8 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0bdffc, 0x00000d, 0x00500f, - }; - static const u32 rv3[] = { + /* These writes happen separately in the vendor driver */ 0x00d00f, 0x004c0f, 0x00540f, @@ -172,38 +157,11 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x00500f, }; - r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init)); - if (r) - return r; - - if (chip->al2230s_bit) { - r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, - ARRAY_SIZE(ioreqs_init_al2230s)); - if (r) - return r; - } - - r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS); - if (r) - return r; - - /* improve band edge for AL2230S */ - if (chip->al2230s_bit) - r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); - else - r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); - if (r) - return r; - - r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS); - if (r) - return r; - - r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll)); + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); if (r) return r; - r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS); + r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); if (r) return r; @@ -269,9 +227,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x481dc0, 0xcfff00, 0x25a000, - }; - static const u32 rv2[] = { /* To improve AL2230 yield, improve phase noise, 4713 */ 0x25a000, 0xa3b2f0, @@ -294,7 +250,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; - static const u32 rv3[] = { + static const u32 rv2[] = { /* To improve AL2230 yield, 4713 */ 0xf01b00, 0xf01e00, @@ -313,35 +269,16 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); if (r) return r; - - if (chip->al2230s_bit) { - r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, - ARRAY_SIZE(ioreqs_init_al2230s)); - if (r) - return r; - } - r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); if (r) return r; r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); - if (r) - return r; - - if (chip->al2230s_bit) - r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); - else - r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); - if (r) - return r; - - r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); if (r) return r; r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); if (r) return r; - r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3)); + r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); if (r) return r; r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); @@ -421,6 +358,12 @@ int zd_rf_init_al2230(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); + if (chip->al2230s_bit) { + dev_err(zd_chip_dev(chip), "AL2230S devices are not yet " + "supported by this driver.\n"); + return -ENODEV; + } + rf->switch_radio_off = al2230_switch_radio_off; if (chip->is_zd1211b) { rf->init_hw = zd1211b_al2230_init_hw; @@ -431,6 +374,6 @@ int zd_rf_init_al2230(struct zd_rf *rf) rf->set_channel = zd1211_al2230_set_channel; rf->switch_radio_on = zd1211_al2230_switch_radio_on; } - rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->patch_6m_band_edge = 1; return 0; } diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/trunk/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 5e5e9ddc6a74..a289f95187ec 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -51,52 +51,9 @@ static const u32 std_rv[] = { 0xd8c010, }; -static const u32 rv_init1[] = { - 0x3c9000, - 0xbfffff, - 0x700000, - 0xf15d58, -}; - -static const u32 rv_init2[] = { - 0xf15d59, - 0xf15d5c, - 0xf15d58, -}; - -static const struct zd_ioreq16 ioreqs_sw[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, -}; - -static int zd1211b_al7230b_finalize(struct zd_chip *chip) +static int al7230b_init_hw(struct zd_rf *rf) { - int r; - static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x04 }, - { }, - { CR240, 0x80 }, - }; - - r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); - if (r) - return r; - - if (chip->new_phy_layout) { - /* antenna selection? */ - r = zd_iowrite16_locked(chip, 0xe5, CR9); - if (r) - return r; - } - - return zd_iowrite16_locked(chip, 0x04, CR203); -} - -static int zd1211_al7230b_init_hw(struct zd_rf *rf) -{ - int r; + int i, r; struct zd_chip *chip = zd_rf_to_chip(rf); /* All of these writes are identical to AL2230 unless otherwise @@ -160,136 +117,39 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR251, 0x3f }, /* PLL_ON */ + /* PLL_ON */ + { CR251, 0x3f }, { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { CR38, 0x38 }, { CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); if (r) return r; - r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); - if (r) - return r; - - r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); - if (r) - return r; - - r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); + r = zd_rfwrite_cr_locked(chip, 0x09ec04); if (r) return r; - - r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); + r = zd_rfwrite_cr_locked(chip, 0x8cccc8); if (r) return r; - r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); - if (r) - return r; + for (i = 0; i < ARRAY_SIZE(std_rv); i++) { + r = zd_rfwrite_cr_locked(chip, std_rv[i]); + if (r) + return r; + } - r = zd_iowrite16_locked(chip, 0x06, CR203); + r = zd_rfwrite_cr_locked(chip, 0x3c9000); if (r) return r; - r = zd_iowrite16_locked(chip, 0x80, CR240); + r = zd_rfwrite_cr_locked(chip, 0xbfffff); if (r) return r; - - return 0; -} - -static int zd1211b_al7230b_init_hw(struct zd_rf *rf) -{ - int r; - struct zd_chip *chip = zd_rf_to_chip(rf); - - static const struct zd_ioreq16 ioreqs_1[] = { - { CR240, 0x57 }, { CR9, 0x9 }, - { }, - { CR10, 0x8b }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ - { CR20, 0x10 }, /* 4N25->Stone Request */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5613 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ - { CR47, 0x1e }, - - /* ZD1215 5610 */ - { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0A }, { CR89, 0x04 }, - { CR90, 0x58 }, /* 5112 */ - { CR91, 0x00 }, /* 5613 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, - { CR102, 0x27 }, - { CR106, 0x20 }, /* change to 0x24 for AL7230B */ - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR112, 0x1f }, - }; - - static const struct zd_ioreq16 ioreqs_new_phy[] = { - { CR107, 0x28 }, - { CR110, 0x1f }, /* 5127, 0x13->0x1f */ - { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, - { CR121, 0x6c }, /* 5613 */ - }; - - static const struct zd_ioreq16 ioreqs_old_phy[] = { - { CR107, 0x24 }, - { CR110, 0x13 }, /* 5127, 0x13->0x1f */ - { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, - { CR121, 0x6a }, /* 5613 */ - }; - - static const struct zd_ioreq16 ioreqs_2[] = { - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, - { CR117, 0xfa }, { CR120, 0x4f }, - { CR122, 0xfc }, /* E0->FCh at 4901 */ - { CR123, 0x57 }, /* 5613 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5613 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR130, 0x10 }, - { CR131, 0x00 }, /* 5112 */ - { CR137, 0x50 }, /* 5613 */ - { CR138, 0xa8 }, /* 5112 */ - { CR144, 0xac }, /* 5613 */ - { CR148, 0x40 }, /* 5112 */ - { CR149, 0x40 }, /* 4O07, 50->40 */ - { CR150, 0x1a }, /* 5112, 0C->1A */ - { CR252, 0x34 }, { CR253, 0x34 }, - { CR251, 0x2f }, /* PLL_OFF */ - }; - - static const struct zd_ioreq16 ioreqs_3[] = { - { CR251, 0x7f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, - }; - - r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); + r = zd_rfwrite_cr_locked(chip, 0x700000); if (r) return r; - - if (chip->new_phy_layout) - r = zd_iowrite16a_locked(chip, ioreqs_new_phy, - ARRAY_SIZE(ioreqs_new_phy)); - else - r = zd_iowrite16a_locked(chip, ioreqs_old_phy, - ARRAY_SIZE(ioreqs_old_phy)); + r = zd_rfwrite_cr_locked(chip, 0xf15d58); if (r) return r; @@ -297,36 +157,38 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf) if (r) return r; - r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); + r = zd_rfwrite_cr_locked(chip, 0xf15d59); if (r) return r; - - r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); + r = zd_rfwrite_cr_locked(chip, 0xf15d5c); if (r) return r; - - r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); + r = zd_rfwrite_cr_locked(chip, 0xf15d58); if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3)); + r = zd_iowrite16_locked(chip, 0x06, CR203); if (r) return r; - - r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); + r = zd_iowrite16_locked(chip, 0x80, CR240); if (r) return r; - return zd1211b_al7230b_finalize(chip); + return 0; } -static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) +static int al7230b_set_channel(struct zd_rf *rf, u8 channel) { - int r; + int i, r; const u32 *rv = chan_rv[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); - static const struct zd_ioreq16 ioreqs[] = { + struct zd_ioreq16 ioreqs_1[] = { + { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { CR38, 0x38 }, { CR136, 0xdf }, + }; + + struct zd_ioreq16 ioreqs_2[] = { /* PLL_ON */ { CR251, 0x3f }, { CR203, 0x06 }, { CR240, 0x08 }, @@ -341,52 +203,11 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); - if (r) - return r; - - r = zd_rfwrite_cr_locked(chip, 0x3c9000); - if (r) - return r; - r = zd_rfwrite_cr_locked(chip, 0xf15d58); - if (r) - return r; - - r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); - if (r) - return r; - - r = zd_rfwritev_cr_locked(chip, rv, 2); - if (r) - return r; - - r = zd_rfwrite_cr_locked(chip, 0x3c9000); - if (r) - return r; - - return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -} - -static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) -{ - int r; - const u32 *rv = chan_rv[channel-1]; - struct zd_chip *chip = zd_rf_to_chip(rf); - - r = zd_iowrite16_locked(chip, 0x57, CR240); - if (r) - return r; - r = zd_iowrite16_locked(chip, 0xe4, CR9); - if (r) - return r; - - /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); - if (r) - return r; - r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); - if (r) - return r; + for (i = 0; i < ARRAY_SIZE(std_rv); i++) { + r = zd_rfwrite_cr_locked(chip, std_rv[i]); + if (r) + return r; + } r = zd_rfwrite_cr_locked(chip, 0x3c9000); if (r) @@ -395,26 +216,24 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); if (r) return r; - r = zd_rfwritev_cr_locked(chip, rv, 2); - if (r) - return r; + for (i = 0; i < 2; i++) { + r = zd_rfwrite_cr_locked(chip, rv[i]); + if (r) + return r; + } r = zd_rfwrite_cr_locked(chip, 0x3c9000); if (r) return r; - r = zd_iowrite16_locked(chip, 0x7f, CR251); - if (r) - return r; - - return zd1211b_al7230b_finalize(chip); + return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); } -static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) +static int al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { @@ -425,17 +244,6 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } -static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) -{ - struct zd_chip *chip = zd_rf_to_chip(rf); - static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, - }; - - return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -} - static int al7230b_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); @@ -447,45 +255,20 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } -/* ZD1211B+AL7230B 6m band edge patching differs slightly from other - * configurations */ -static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) -{ - struct zd_chip *chip = zd_rf_to_chip(rf); - struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, - }; - - /* FIXME: Channel 11 is not the edge for all regulatory domains. */ - if (channel == 1) { - ioreqs[0].value = 0x0e; - ioreqs[1].value = 0x10; - } else if (channel == 11) { - ioreqs[0].value = 0x10; - ioreqs[1].value = 0x10; - } - - dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel); - return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -} - int zd_rf_init_al7230b(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); if (chip->is_zd1211b) { - rf->init_hw = zd1211b_al7230b_init_hw; - rf->switch_radio_on = zd1211b_al7230b_switch_radio_on; - rf->set_channel = zd1211b_al7230b_set_channel; - rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m; - } else { - rf->init_hw = zd1211_al7230b_init_hw; - rf->switch_radio_on = zd1211_al7230b_switch_radio_on; - rf->set_channel = zd1211_al7230b_set_channel; - rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + dev_err(zd_chip_dev(chip), "AL7230B is currently not " + "supported for ZD1211B devices\n"); + return -ENODEV; } + rf->init_hw = al7230b_init_hw; + rf->set_channel = al7230b_set_channel; + rf->switch_radio_on = al7230b_switch_radio_on; rf->switch_radio_off = al7230b_switch_radio_off; - + rf->patch_6m_band_edge = 1; return 0; } diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/trunk/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 2d736bdf707c..58247271cc24 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -21,7 +21,7 @@ #include "zd_usb.h" #include "zd_chip.h" -static const u32 rf2959_table[][2] = { +static u32 rf2959_table[][2] = { RF_CHANNEL( 1) = { 0x181979, 0x1e6666 }, RF_CHANNEL( 2) = { 0x181989, 0x1e6666 }, RF_CHANNEL( 3) = { 0x181999, 0x1e6666 }, @@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf) static int rf2959_set_channel(struct zd_rf *rf, u8 channel) { int i, r; - const u32 *rv = rf2959_table[channel-1]; + u32 *rv = rf2959_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); for (i = 0; i < 2; i++) { diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c index e04cffc8adf3..aac8a1c5ba08 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c @@ -52,7 +52,6 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, @@ -63,10 +62,6 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} @@ -417,7 +412,7 @@ int zd_usb_enable_int(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "\n"); - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_NOFS); if (!urb) { r = -ENOMEM; goto out; @@ -435,7 +430,7 @@ int zd_usb_enable_int(struct zd_usb *usb) /* TODO: make it a DMA buffer */ r = -ENOMEM; - transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL); + transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS); if (!transfer_buffer) { dev_dbg_f(zd_usb_dev(usb), "couldn't allocate transfer_buffer\n"); @@ -449,7 +444,7 @@ int zd_usb_enable_int(struct zd_usb *usb) intr->interval); dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); - r = usb_submit_urb(urb, GFP_KERNEL); + r = usb_submit_urb(urb, GFP_NOFS); if (r) { dev_dbg_f(zd_usb_dev(usb), "Couldn't submit urb. Error number %d\n", r); @@ -598,10 +593,10 @@ static struct urb *alloc_urb(struct zd_usb *usb) struct urb *urb; void *buffer; - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_NOFS); if (!urb) return NULL; - buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL, + buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS, &urb->transfer_dma); if (!buffer) { usb_free_urb(urb); @@ -634,7 +629,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "\n"); r = -ENOMEM; - urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); + urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS); if (!urbs) goto error; for (i = 0; i < URBS_COUNT; i++) { @@ -655,7 +650,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) spin_unlock_irq(&rx->lock); for (i = 0; i < URBS_COUNT; i++) { - r = usb_submit_urb(urbs[i], GFP_KERNEL); + r = usb_submit_urb(urbs[i], GFP_NOFS); if (r) goto error_submit; } @@ -1161,7 +1156,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, } req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); - req = kmalloc(req_len, GFP_KERNEL); + req = kmalloc(req_len, GFP_NOFS); if (!req) return -ENOMEM; req->id = cpu_to_le16(USB_REQ_READ_REGS); @@ -1224,7 +1219,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, req_len = sizeof(struct usb_req_write_regs) + count * sizeof(struct reg_data); - req = kmalloc(req_len, GFP_KERNEL); + req = kmalloc(req_len, GFP_NOFS); if (!req) return -ENOMEM; @@ -1304,7 +1299,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); - req = kmalloc(req_len, GFP_KERNEL); + req = kmalloc(req_len, GFP_NOFS); if (!req) return -ENOMEM; diff --git a/trunk/drivers/net/yellowfin.c b/trunk/drivers/net/yellowfin.c index 3f4a7cf9efea..2412ce4917f2 100644 --- a/trunk/drivers/net/yellowfin.c +++ b/trunk/drivers/net/yellowfin.c @@ -1137,6 +1137,7 @@ static int yellowfin_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) break; + skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0); skb_put(skb, pkt_len); diff --git a/trunk/drivers/net/znet.c b/trunk/drivers/net/znet.c index 4032e9f6f9b0..b24b0727108c 100644 --- a/trunk/drivers/net/znet.c +++ b/trunk/drivers/net/znet.c @@ -774,6 +774,7 @@ static void znet_rx(struct net_device *dev) znet->stats.rx_dropped++; break; } + skb->dev = dev; if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) { int semi_cnt = (znet->rx_end - znet->rx_cur)<<1; diff --git a/trunk/drivers/parisc/hppb.c b/trunk/drivers/parisc/hppb.c index a68b3b3761a2..9bb4db552f3c 100644 --- a/trunk/drivers/parisc/hppb.c +++ b/trunk/drivers/parisc/hppb.c @@ -22,6 +22,8 @@ #include #include +#include + struct hppb_card { unsigned long hpa; struct resource mmio_region; diff --git a/trunk/drivers/parisc/led.c b/trunk/drivers/parisc/led.c index 98be2880757d..d190c05d87ed 100644 --- a/trunk/drivers/parisc/led.c +++ b/trunk/drivers/parisc/led.c @@ -365,13 +365,15 @@ static __inline__ int led_get_net_activity(void) * for reading should be OK */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for (dev = dev_base; dev; dev = dev->next) { struct net_device_stats *stats; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) continue; if (LOOPBACK(in_dev->ifa_list->ifa_local)) continue; + if (!dev->get_stats) + continue; stats = dev->get_stats(dev); rx_total += stats->rx_packets; tx_total += stats->tx_packets; diff --git a/trunk/drivers/parisc/pdc_stable.c b/trunk/drivers/parisc/pdc_stable.c index 815e445c3125..ea1b7a63598e 100644 --- a/trunk/drivers/parisc/pdc_stable.c +++ b/trunk/drivers/parisc/pdc_stable.c @@ -520,17 +520,17 @@ static struct pdcspath_entry *pdcspath_entries[] = { /** * pdcs_size_read - Stable Storage size output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. */ static ssize_t -pdcs_size_read(struct kset *kset, char *buf) +pdcs_size_read(struct subsystem *entry, char *buf) { char *out = buf; - - if (!kset || !buf) + + if (!entry || !buf) return -EINVAL; - + /* show the size of the stable storage */ out += sprintf(out, "%ld\n", pdcs_size); @@ -539,17 +539,17 @@ pdcs_size_read(struct kset *kset, char *buf) /** * pdcs_auto_read - Stable Storage autoboot/search flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag */ static ssize_t -pdcs_auto_read(struct kset *kset, char *buf, int knob) +pdcs_auto_read(struct subsystem *entry, char *buf, int knob) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -565,40 +565,40 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob) /** * pdcs_autoboot_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. */ static inline ssize_t -pdcs_autoboot_read(struct kset *kset, char *buf) +pdcs_autoboot_read(struct subsystem *entry, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOBOOT); + return pdcs_auto_read(entry, buf, PF_AUTOBOOT); } /** * pdcs_autosearch_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. */ static inline ssize_t -pdcs_autosearch_read(struct kset *kset, char *buf) +pdcs_autosearch_read(struct subsystem *entry, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOSEARCH); + return pdcs_auto_read(entry, buf, PF_AUTOSEARCH); } /** * pdcs_timer_read - Stable Storage timer count output (in seconds). - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * * The value of the timer field correponds to a number of seconds in powers of 2. */ static ssize_t -pdcs_timer_read(struct kset *kset, char *buf) +pdcs_timer_read(struct subsystem *entry, char *buf) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -615,15 +615,15 @@ pdcs_timer_read(struct kset *kset, char *buf) /** * pdcs_osid_read - Stable Storage OS ID register output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. */ static ssize_t -pdcs_osid_read(struct kset *kset, char *buf) +pdcs_osid_read(struct subsystem *entry, char *buf) { char *out = buf; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; out += sprintf(out, "%s dependent data (0x%.4x)\n", @@ -634,18 +634,18 @@ pdcs_osid_read(struct kset *kset, char *buf) /** * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * * This can hold 16 bytes of OS-Dependent data. */ static ssize_t -pdcs_osdep1_read(struct kset *kset, char *buf) +pdcs_osdep1_read(struct subsystem *entry, char *buf) { char *out = buf; u32 result[4]; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK) @@ -661,18 +661,18 @@ pdcs_osdep1_read(struct kset *kset, char *buf) /** * pdcs_diagnostic_read - Stable Storage Diagnostic register output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * * I have NFC how to interpret the content of that register ;-). */ static ssize_t -pdcs_diagnostic_read(struct kset *kset, char *buf) +pdcs_diagnostic_read(struct subsystem *entry, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; /* get diagnostic */ @@ -686,18 +686,18 @@ pdcs_diagnostic_read(struct kset *kset, char *buf) /** * pdcs_fastsize_read - Stable Storage FastSize register output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * * This register holds the amount of system RAM to be tested during boot sequence. */ static ssize_t -pdcs_fastsize_read(struct kset *kset, char *buf) +pdcs_fastsize_read(struct subsystem *entry, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; /* get fast-size */ @@ -715,13 +715,13 @@ pdcs_fastsize_read(struct kset *kset, char *buf) /** * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output. - * @kset: An allocated and populated struct kset. We don't use it tho. + * @entry: An allocated and populated subsytem struct. We don't use it tho. * @buf: The output buffer to write to. * * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available. */ static ssize_t -pdcs_osdep2_read(struct kset *kset, char *buf) +pdcs_osdep2_read(struct subsystem *entry, char *buf) { char *out = buf; unsigned long size; @@ -733,7 +733,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf) size = pdcs_size - 224; - if (!kset || !buf) + if (!entry || !buf) return -EINVAL; for (i=0; ip_tcr, regs->p_ir)); dprintk((KERN_DEBUG "read status 0x%x\n", bits)); return bits; } @@ -147,7 +147,7 @@ static unsigned char control_sunbpp_to_pc(struct parport *p) if (value_or & P_OR_SLCT_IN) bits |= PARPORT_CONTROL_SELECT; - dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", value_tcr, value_or)); + dprintk((KERN_DEBUG "tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); dprintk((KERN_DEBUG "read control 0x%x\n", bits)); return bits; } @@ -165,8 +165,7 @@ static unsigned char parport_sunbpp_frob_control(struct parport *p, unsigned char value_tcr = sbus_readb(®s->p_tcr); unsigned char value_or = sbus_readb(®s->p_or); - dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", - value_tcr, value_or)); + dprintk((KERN_DEBUG "frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); if (mask & PARPORT_CONTROL_STROBE) { if (val & PARPORT_CONTROL_STROBE) { value_tcr &= ~P_TCR_DS; @@ -198,8 +197,7 @@ static unsigned char parport_sunbpp_frob_control(struct parport *p, sbus_writeb(value_or, ®s->p_or); sbus_writeb(value_tcr, ®s->p_tcr); - dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", - value_tcr, value_or)); + dprintk((KERN_DEBUG "frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); return parport_sunbpp_read_control(p); } diff --git a/trunk/drivers/pci/Kconfig b/trunk/drivers/pci/Kconfig index 7a1d6d512837..5ea5bc70cb82 100644 --- a/trunk/drivers/pci/Kconfig +++ b/trunk/drivers/pci/Kconfig @@ -1,14 +1,10 @@ # # PCI configuration # -config ARCH_SUPPORTS_MSI - bool - default n - config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI - depends on ARCH_SUPPORTS_MSI + depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64 help This allows device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to @@ -21,6 +17,31 @@ config PCI_MSI If you don't know what to do here, say N. +config PCI_MULTITHREAD_PROBE + bool "PCI Multi-threaded probe (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL && BROKEN + help + Say Y here if you want the PCI core to spawn a new thread for + every PCI device that is probed. This can cause a huge + speedup in boot times on multiprocessor machines, and even a + smaller speedup on single processor machines. + + But it can also cause lots of bad things to happen. A number + of PCI drivers cannot properly handle running in this way, + some will just not work properly at all, while others might + decide to blow up power supplies with a huge load all at once, + so use this option at your own risk. + + It is very unwise to use this option if you are not using a + boot process that can handle devices being created in any + order. A program that can create persistent block and network + device names (like udev) is a good idea if you wish to use + this option. + + Again, use this option at your own risk, you have been warned! + + When in doubt, say N. + config PCI_DEBUG bool "PCI Debugging" depends on PCI && DEBUG_KERNEL diff --git a/trunk/drivers/pci/bus.c b/trunk/drivers/pci/bus.c index 9e5ea074ad20..aadaa3c8096b 100644 --- a/trunk/drivers/pci/bus.c +++ b/trunk/drivers/pci/bus.c @@ -77,7 +77,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, * This adds a single pci device to the global * device list and adds sysfs and procfs entries */ -int pci_bus_add_device(struct pci_dev *dev) +int __devinit pci_bus_add_device(struct pci_dev *dev) { int retval; retval = device_add(&dev->dev); @@ -105,7 +105,7 @@ int pci_bus_add_device(struct pci_dev *dev) * * Call hotplug for each new devices. */ -void pci_bus_add_devices(struct pci_bus *bus) +void __devinit pci_bus_add_devices(struct pci_bus *bus) { struct pci_dev *dev; int retval; diff --git a/trunk/drivers/pci/hotplug/Kconfig b/trunk/drivers/pci/hotplug/Kconfig index 63d62752fb91..be92695a7833 100644 --- a/trunk/drivers/pci/hotplug/Kconfig +++ b/trunk/drivers/pci/hotplug/Kconfig @@ -2,7 +2,9 @@ # PCI Hotplug support # -menuconfig HOTPLUG_PCI +menu "PCI Hotplug Support" + +config HOTPLUG_PCI tristate "Support for PCI Hotplug (EXPERIMENTAL)" depends on PCI && EXPERIMENTAL && HOTPLUG ---help--- @@ -15,10 +17,9 @@ menuconfig HOTPLUG_PCI When in doubt, say N. -if HOTPLUG_PCI - config HOTPLUG_PCI_FAKE tristate "Fake PCI Hotplug driver" + depends on HOTPLUG_PCI help Say Y here if you want to use the fake PCI hotplug driver. It can be used to simulate PCI hotplug events if even if your system is @@ -41,7 +42,7 @@ config HOTPLUG_PCI_FAKE config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" - depends on X86 && PCI_BIOS + depends on HOTPLUG_PCI && X86 && PCI_BIOS help Say Y here if you have a motherboard with a Compaq PCI Hotplug controller. @@ -63,7 +64,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM config HOTPLUG_PCI_IBM tristate "IBM PCI Hotplug driver" - depends on X86_IO_APIC && X86 && PCI_BIOS + depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS help Say Y here if you have a motherboard with a IBM PCI Hotplug controller. @@ -75,6 +76,7 @@ config HOTPLUG_PCI_IBM config HOTPLUG_PCI_ACPI tristate "ACPI PCI Hotplug driver" + depends on HOTPLUG_PCI depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) help Say Y here if you have a system that supports PCI Hotplug using @@ -99,6 +101,7 @@ config HOTPLUG_PCI_ACPI_IBM config HOTPLUG_PCI_CPCI bool "CompactPCI Hotplug driver" + depends on HOTPLUG_PCI help Say Y here if you have a CompactPCI system card with CompactPCI hotswap support per the PICMG 2.1 specification. @@ -107,7 +110,7 @@ config HOTPLUG_PCI_CPCI config HOTPLUG_PCI_CPCI_ZT5550 tristate "Ziatech ZT5550 CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 help Say Y here if you have an Performance Technologies (formerly Intel, formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. @@ -119,7 +122,7 @@ config HOTPLUG_PCI_CPCI_ZT5550 config HOTPLUG_PCI_CPCI_GENERIC tristate "Generic port I/O CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 + depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86 help Say Y here if you have a CompactPCI system card that exposes the #ENUM hotswap signal as a bit in a system register that can be read through @@ -132,6 +135,7 @@ config HOTPLUG_PCI_CPCI_GENERIC config HOTPLUG_PCI_SHPC tristate "SHPC PCI Hotplug driver" + depends on HOTPLUG_PCI help Say Y here if you have a motherboard with a SHPC PCI Hotplug controller. @@ -143,7 +147,7 @@ config HOTPLUG_PCI_SHPC config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" - depends on PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE + depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE help Say Y here if you have a RPA system that supports PCI Hotplug. @@ -166,11 +170,12 @@ config HOTPLUG_PCI_RPA_DLPAR config HOTPLUG_PCI_SGI tristate "SGI PCI Hotplug Support" - depends on IA64_SGI_SN2 || IA64_GENERIC + depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) help Say Y here if you want to use the SGI Altix Hotplug Driver for PCI devices. When in doubt, say N. -endif # HOTPLUG_PCI +endmenu + diff --git a/trunk/drivers/pci/hotplug/acpiphp_ibm.c b/trunk/drivers/pci/hotplug/acpiphp_ibm.c index e7322c25d377..7f03881a8b68 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_ibm.c +++ b/trunk/drivers/pci/hotplug/acpiphp_ibm.c @@ -424,7 +424,7 @@ static int __init ibm_acpiphp_init(void) int retval = 0; acpi_status status; struct acpi_device *device; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; dbg("%s\n", __FUNCTION__); @@ -471,7 +471,7 @@ static int __init ibm_acpiphp_init(void) static void __exit ibm_acpiphp_exit(void) { acpi_status status; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj; dbg("%s\n", __FUNCTION__); diff --git a/trunk/drivers/pci/hotplug/cpcihp_zt5550.c b/trunk/drivers/pci/hotplug/cpcihp_zt5550.c index 41f6a8d79c81..1c12e9171097 100644 --- a/trunk/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/trunk/drivers/pci/hotplug/cpcihp_zt5550.c @@ -296,17 +296,13 @@ static struct pci_driver zt5550_hc_driver = { static int __init zt5550_init(void) { struct resource* r; - int rc; info(DRIVER_DESC " version: " DRIVER_VERSION); r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); if(!r) return -EBUSY; - rc = pci_register_driver(&zt5550_hc_driver); - if(rc < 0) - release_region(ENUM_PORT, 1); - return rc; + return pci_register_driver(&zt5550_hc_driver); } static void __exit diff --git a/trunk/drivers/pci/hotplug/fakephp.c b/trunk/drivers/pci/hotplug/fakephp.c index 027f6865d7e3..e27907c91d92 100644 --- a/trunk/drivers/pci/hotplug/fakephp.c +++ b/trunk/drivers/pci/hotplug/fakephp.c @@ -238,7 +238,7 @@ static void pci_rescan_bus(const struct pci_bus *bus) { unsigned int devfn; struct pci_dev *dev; - dev = alloc_pci_dev(); + dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) return; diff --git a/trunk/drivers/pci/hotplug/pci_hotplug_core.c b/trunk/drivers/pci/hotplug/pci_hotplug_core.c index 63f3bd1eecc4..f5d632e72323 100644 --- a/trunk/drivers/pci/hotplug/pci_hotplug_core.c +++ b/trunk/drivers/pci/hotplug/pci_hotplug_core.c @@ -62,7 +62,7 @@ static int debug; static LIST_HEAD(pci_hotplug_slot_list); -struct kset pci_hotplug_slots_subsys; +struct subsystem pci_hotplug_slots_subsys; static ssize_t hotplug_slot_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -764,7 +764,7 @@ static int __init pci_hotplug_init (void) { int result; - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); + kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); result = subsystem_register(&pci_hotplug_slots_subsys); if (result) { err("Register subsys with error %d\n", result); diff --git a/trunk/drivers/pci/hotplug/pciehp.h b/trunk/drivers/pci/hotplug/pciehp.h index ccc57627201e..d19fcae8a7c0 100644 --- a/trunk/drivers/pci/hotplug/pciehp.h +++ b/trunk/drivers/pci/hotplug/pciehp.h @@ -43,7 +43,6 @@ extern int pciehp_poll_mode; extern int pciehp_poll_time; extern int pciehp_debug; extern int pciehp_force; -extern struct workqueue_struct *pciehp_wq; #define dbg(format, arg...) \ do { \ @@ -71,16 +70,14 @@ struct slot { struct list_head slot_list; char name[SLOT_NAME_SIZE]; unsigned long last_emi_toggle; - struct delayed_work work; /* work for button event */ - struct mutex lock; }; struct event_info { u32 event_type; - struct slot *p_slot; - struct work_struct work; + u8 hp_slot; }; +#define MAX_EVENTS 10 struct controller { struct controller *next; struct mutex crit_sect; /* critical section mutex */ @@ -89,9 +86,11 @@ struct controller { int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; struct list_head slot_list; + struct event_info event_queue[MAX_EVENTS]; struct slot *slot; struct hpc_ops *hpc_ops; wait_queue_head_t queue; /* sleep & wake process */ + u8 next_event; u8 bus; u8 device; u8 function; @@ -150,17 +149,21 @@ struct controller { #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) #define EMI(cap) (cap & EMI_PRSN) -extern int pciehp_sysfs_enable_slot(struct slot *slot); -extern int pciehp_sysfs_disable_slot(struct slot *slot); +extern int pciehp_event_start_thread(void); +extern void pciehp_event_stop_thread(void); +extern int pciehp_enable_slot(struct slot *slot); +extern int pciehp_disable_slot(struct slot *slot); extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot); -extern void pciehp_queue_pushbutton_work(struct work_struct *work); int pcie_init(struct controller *ctrl, struct pcie_device *dev); +/* Global variables */ +extern struct controller *pciehp_ctrl_list; + static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot; diff --git a/trunk/drivers/pci/hotplug/pciehp_core.c b/trunk/drivers/pci/hotplug/pciehp_core.c index e5d3f0b4f45a..a92eda6e02f6 100644 --- a/trunk/drivers/pci/hotplug/pciehp_core.c +++ b/trunk/drivers/pci/hotplug/pciehp_core.c @@ -41,7 +41,7 @@ int pciehp_debug; int pciehp_poll_mode; int pciehp_poll_time; int pciehp_force; -struct workqueue_struct *pciehp_wq; +struct controller *pciehp_ctrl_list; #define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " @@ -62,6 +62,7 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing" #define PCIE_MODULE_NAME "pciehp" +static int pcie_start_thread (void); static int set_attention_status (struct hotplug_slot *slot, u8 value); static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); @@ -228,8 +229,6 @@ static int init_slots(struct controller *ctrl) slot->device = ctrl->slot_device_offset + i; slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot; - mutex_init(&slot->lock); - INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; @@ -287,9 +286,6 @@ static void cleanup_slots(struct controller *ctrl) if (EMI(ctrl->ctrlcap)) sysfs_remove_file(&slot->hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); - cancel_delayed_work(&slot->work); - flush_scheduled_work(); - flush_workqueue(pciehp_wq); pci_hp_deregister(slot->hotplug_slot); } } @@ -318,7 +314,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - return pciehp_sysfs_enable_slot(slot); + return pciehp_enable_slot(slot); } @@ -328,7 +324,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - return pciehp_sysfs_disable_slot(slot); + return pciehp_disable_slot(slot); } static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) @@ -470,6 +466,17 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); + /* Finish setting up the hot plug ctrl device */ + ctrl->next_event = 0; + + if (!pciehp_ctrl_list) { + pciehp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = pciehp_ctrl_list; + pciehp_ctrl_list = ctrl; + } + t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ @@ -489,14 +496,48 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ return -ENODEV; } -static void pciehp_remove (struct pcie_device *dev) + +static int pcie_start_thread(void) { - struct pci_dev *pdev = dev->port; - struct controller *ctrl = pci_get_drvdata(pdev); + int retval = 0; + + dbg("Initialize + Start the notification/polling mechanism \n"); + + retval = pciehp_event_start_thread(); + if (retval) { + dbg("pciehp_event_start_thread() failed\n"); + return retval; + } + + return retval; +} + +static void __exit unload_pciehpd(void) +{ + struct controller *ctrl; + struct controller *tctrl; + + ctrl = pciehp_ctrl_list; + + while (ctrl) { + cleanup_slots(ctrl); + + ctrl->hpc_ops->release_ctlr(ctrl); + + tctrl = ctrl; + ctrl = ctrl->next; + + kfree(tctrl); + } + + /* Stop the notification mechanism */ + pciehp_event_stop_thread(); - cleanup_slots(ctrl); - ctrl->hpc_ops->release_ctlr(ctrl); - kfree(ctrl); +} + +static void pciehp_remove (struct pcie_device *device) +{ + /* XXX - Needs to be adapted to device driver model */ } #ifdef CONFIG_PM @@ -544,18 +585,31 @@ static int __init pcied_init(void) pciehp_poll_mode = 1; #endif + retval = pcie_start_thread(); + if (retval) + goto error_hpc_init; + retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); if (retval) dbg("%s: Failure to register service\n", __FUNCTION__); + +error_hpc_init: + if (retval) { + pciehp_event_stop_thread(); + }; + return retval; } static void __exit pcied_cleanup(void) { dbg("unload_pciehpd()\n"); + unload_pciehpd(); + pcie_port_service_unregister(&hpdriver_portdrv); + info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff --git a/trunk/drivers/pci/hotplug/pciehp_ctrl.c b/trunk/drivers/pci/hotplug/pciehp_ctrl.c index 7f22caa70178..4283ef56dbd9 100644 --- a/trunk/drivers/pci/hotplug/pciehp_ctrl.c +++ b/trunk/drivers/pci/hotplug/pciehp_ctrl.c @@ -32,61 +32,92 @@ #include #include #include -#include #include "../pci.h" #include "pciehp.h" -static void interrupt_event_handler(struct work_struct *work); -static int pciehp_enable_slot(struct slot *p_slot); -static int pciehp_disable_slot(struct slot *p_slot); +static void interrupt_event_handler(struct controller *ctrl); -static int queue_interrupt_event(struct slot *p_slot, u32 event_type) -{ - struct event_info *info; - - info = kmalloc(sizeof(*info), GFP_ATOMIC); - if (!info) - return -ENOMEM; - - info->event_type = event_type; - info->p_slot = p_slot; - INIT_WORK(&info->work, interrupt_event_handler); +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ +static unsigned long surprise_rm_pending; /* = 0 */ - schedule_work(&info->work); - - return 0; +static inline char *slot_name(struct slot *p_slot) +{ + return p_slot->hotplug_slot->name; } u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) { struct slot *p_slot; - u32 event_type; + u8 rc = 0; + u8 getstatus; + struct event_info *taskInfo; /* Attention Button Change */ dbg("pciehp: Attention button interrupt received.\n"); - + + /* This is the structure that tells the worker thread what to do */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + + ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; + taskInfo->hp_slot = hp_slot; + + rc++; + /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%s)\n", p_slot->name); - event_type = INT_BUTTON_PRESS; + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_BUTTON_PRESS; + + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + /* Cancel if we are still blinking; this means that we press the + * attention again before the 5 sec. limit expires to cancel hot-add + * or hot-remove + */ + taskInfo->event_type = INT_BUTTON_CANCEL; + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + /* Ignore if the slot is on power-on or power-off state; this + * means that the previous attention button action to hot-add or + * hot-remove is undergoing + */ + taskInfo->event_type = INT_BUTTON_IGNORE; + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); + } - queue_interrupt_event(p_slot, event_type); + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ return 0; + } u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) { struct slot *p_slot; + u8 rc = 0; u8 getstatus; - u32 event_type; + struct event_info *taskInfo; /* Switch Change */ dbg("pciehp: Switch interrupt received.\n"); + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; + taskInfo->hp_slot = hp_slot; + + rc++; p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); @@ -94,30 +125,39 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) /* * Switch opened */ - info("Latch open on Slot(%s)\n", p_slot->name); - event_type = INT_SWITCH_OPEN; + info("Latch open on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - info("Latch close on Slot(%s)\n", p_slot->name); - event_type = INT_SWITCH_CLOSE; + info("Latch close on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_SWITCH_CLOSE; } - queue_interrupt_event(p_slot, event_type); + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ - return 1; + return rc; } u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) { struct slot *p_slot; - u32 event_type; - u8 presence_save; + u8 presence_save, rc = 0; + struct event_info *taskInfo; /* Presence Change */ dbg("pciehp: Presence/Notify input change.\n"); + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; + taskInfo->hp_slot = hp_slot; + + rc++; p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); /* Switch is open, assume a presence change @@ -128,49 +168,59 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) /* * Card Present */ - info("Card present on Slot(%s)\n", p_slot->name); - event_type = INT_PRESENCE_ON; + info("Card present on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%s)\n", p_slot->name); - event_type = INT_PRESENCE_OFF; + info("Card not present on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_PRESENCE_OFF; } - queue_interrupt_event(p_slot, event_type); + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ - return 1; + return rc; } u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) { struct slot *p_slot; - u32 event_type; + u8 rc = 0; + struct event_info *taskInfo; /* power fault */ dbg("pciehp: Power fault interrupt received.\n"); + /* this is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS; + taskInfo->hp_slot = hp_slot; + + rc++; p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { /* * power fault Cleared */ - info("Power fault cleared on Slot(%s)\n", p_slot->name); - event_type = INT_POWER_FAULT_CLEAR; + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { /* * power fault */ - info("Power fault on Slot(%s)\n", p_slot->name); - event_type = INT_POWER_FAULT; + info("Power fault on Slot(%s)\n", slot_name(p_slot)); + taskInfo->event_type = INT_POWER_FAULT; info("power fault bit %x set\n", hp_slot); } + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ - queue_interrupt_event(p_slot, event_type); - - return 1; + return rc; } /* The following routines constitute the bulk of the @@ -307,10 +357,13 @@ static int remove_board(struct slot *p_slot) return 0; } -struct power_work_info { - struct slot *p_slot; - struct work_struct work; -}; + +static void pushbutton_helper_thread(unsigned long data) +{ + pushbutton_pending = data; + + up(&event_semaphore); +} /** * pciehp_pushbutton_thread @@ -319,212 +372,274 @@ struct power_work_info { * Handles all pending events and exits. * */ -static void pciehp_power_thread(struct work_struct *work) +static void pciehp_pushbutton_thread(unsigned long slot) { - struct power_work_info *info = - container_of(work, struct power_work_info, work); - struct slot *p_slot = info->p_slot; - - mutex_lock(&p_slot->lock); - switch (p_slot->state) { - case POWEROFF_STATE: - mutex_unlock(&p_slot->lock); - dbg("%s: disabling bus:device(%x:%x)\n", - __FUNCTION__, p_slot->bus, p_slot->device); + struct slot *p_slot = (struct slot *) slot; + u8 getstatus; + + pushbutton_pending = 0; + + if (!p_slot) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return; + } + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = POWEROFF_STATE; + dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__, + p_slot->bus, p_slot->device); + pciehp_disable_slot(p_slot); - mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; - break; - case POWERON_STATE: - mutex_unlock(&p_slot->lock); + } else { + p_slot->state = POWERON_STATE; + dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, + p_slot->bus, p_slot->device); + if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - mutex_lock(&p_slot->lock); + p_slot->state = STATIC_STATE; - break; - default: - break; } - mutex_unlock(&p_slot->lock); - kfree(info); + return; } -void pciehp_queue_pushbutton_work(struct work_struct *work) +/** + * pciehp_surprise_rm_thread + * + * Scheduled procedure to handle blocking stuff for the surprise removal + * Handles all pending events and exits. + * + */ +static void pciehp_surprise_rm_thread(unsigned long slot) { - struct slot *p_slot = container_of(work, struct slot, work.work); - struct power_work_info *info; + struct slot *p_slot = (struct slot *) slot; + u8 getstatus; + + surprise_rm_pending = 0; - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - err("%s: Cannot allocate memory\n", __FUNCTION__); + if (!p_slot) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); return; } - info->p_slot = p_slot; - INIT_WORK(&info->work, pciehp_power_thread); - mutex_lock(&p_slot->lock); - switch (p_slot->state) { - case BLINKINGOFF_STATE: + p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (!getstatus) { p_slot->state = POWEROFF_STATE; - break; - case BLINKINGON_STATE: + dbg("%s: removing bus:device(%x:%x)\n", + __FUNCTION__, p_slot->bus, p_slot->device); + + pciehp_disable_slot(p_slot); + p_slot->state = STATIC_STATE; + } else { p_slot->state = POWERON_STATE; - break; - default: - goto out; + dbg("%s: adding bus:device(%x:%x)\n", + __FUNCTION__, p_slot->bus, p_slot->device); + + if (pciehp_enable_slot(p_slot) && + PWR_LED(p_slot->ctrl->ctrlcap)) + p_slot->hpc_ops->green_led_off(p_slot); + + p_slot->state = STATIC_STATE; } - queue_work(pciehp_wq, &info->work); - out: - mutex_unlock(&p_slot->lock); + + return; } + + +/* this is the main worker thread */ +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize("pciehpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished || signal_pending(current)) + break; + /* Do stuff here */ + if (pushbutton_pending) + pciehp_pushbutton_thread(pushbutton_pending); + else if (surprise_rm_pending) + pciehp_surprise_rm_thread(surprise_rm_pending); + else + for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + +int pciehp_event_start_thread(void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + init_MUTEX_LOCKED(&event_semaphore); + pid = kernel_thread(event_thread, NULL, 0); + + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + return 0; +} + + +void pciehp_event_stop_thread(void) +{ + event_finished = 1; + up(&event_semaphore); + down(&event_exit); +} + + static int update_slot_info(struct slot *slot) { struct hotplug_slot_info *info; + /* char buffer[SLOT_NAME_SIZE]; */ int result; - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); if (!info) return -ENOMEM; + /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */ + slot->hpc_ops->get_power_status(slot, &(info->power_status)); slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); + /* result = pci_hp_change_slot_info(buffer, info); */ result = pci_hp_change_slot_info(slot->hotplug_slot, info); kfree (info); return result; } -/* - * Note: This function must be called with slot->lock held - */ -static void handle_button_press_event(struct slot *p_slot) -{ - struct controller *ctrl = p_slot->ctrl; - u8 getstatus; - - switch (p_slot->state) { - case STATIC_STATE: - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { - p_slot->state = BLINKINGOFF_STATE; - info("PCI slot #%s - powering off due to button " - "press.\n", p_slot->name); - } else { - p_slot->state = BLINKINGON_STATE; - info("PCI slot #%s - powering on due to button " - "press.\n", p_slot->name); - } - /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->green_led_blink(p_slot); - if (ATTN_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - schedule_delayed_work(&p_slot->work, 5*HZ); - break; - case BLINKINGOFF_STATE: - case BLINKINGON_STATE: - /* - * Cancel if we are still blinking; this means that we - * press the attention again before the 5 sec. limit - * expires to cancel hot-add or hot-remove - */ - info("Button cancel on Slot(%s)\n", p_slot->name); - dbg("%s: button cancel\n", __FUNCTION__); - cancel_delayed_work(&p_slot->work); - if (p_slot->state == BLINKINGOFF_STATE) { - if (PWR_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->green_led_on(p_slot); - } else { - if (PWR_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->green_led_off(p_slot); - } - if (ATTN_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->set_attention_status(p_slot, 0); - info("PCI slot #%s - action canceled due to button press\n", - p_slot->name); - p_slot->state = STATIC_STATE; - break; - case POWEROFF_STATE: - case POWERON_STATE: - /* - * Ignore if the slot is on power-on or power-off state; - * this means that the previous attention button action - * to hot-add or hot-remove is undergoing - */ - info("Button ignore on Slot(%s)\n", p_slot->name); - update_slot_info(p_slot); - break; - default: - warn("Not a valid state\n"); - break; - } -} - -/* - * Note: This function must be called with slot->lock held - */ -static void handle_surprise_event(struct slot *p_slot) +static void interrupt_event_handler(struct controller *ctrl) { + int loop = 0; + int change = 1; + u8 hp_slot; u8 getstatus; - struct power_work_info *info; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - err("%s: Cannot allocate memory\n", __FUNCTION__); - return; - } - info->p_slot = p_slot; - INIT_WORK(&info->work, pciehp_power_thread); - - p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (!getstatus) - p_slot->state = POWEROFF_STATE; - else - p_slot->state = POWERON_STATE; - - queue_work(pciehp_wq, &info->work); -} - -static void interrupt_event_handler(struct work_struct *work) -{ - struct event_info *info = container_of(work, struct event_info, work); - struct slot *p_slot = info->p_slot; - struct controller *ctrl = p_slot->ctrl; + struct slot *p_slot; - mutex_lock(&p_slot->lock); - switch (info->event_type) { - case INT_BUTTON_PRESS: - handle_button_press_event(p_slot); - break; - case INT_POWER_FAULT: - if (!POWER_CTRL(ctrl->ctrlcap)) - break; - if (ATTN_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (PWR_LED(ctrl->ctrlcap)) - p_slot->hpc_ops->green_led_off(p_slot); - break; - case INT_PRESENCE_ON: - case INT_PRESENCE_OFF: - if (!HP_SUPR_RM(ctrl->ctrlcap)) - break; - dbg("Surprise Removal\n"); - update_slot_info(p_slot); - handle_surprise_event(p_slot); - break; - default: - update_slot_info(p_slot); - break; + while (change) { + change = 0; + + for (loop = 0; loop < MAX_EVENTS; loop++) { + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + switch (p_slot->state) { + case BLINKINGOFF_STATE: + if (PWR_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->green_led_on(p_slot); + + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); + break; + case BLINKINGON_STATE: + if (PWR_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->green_led_off(p_slot); + + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); + break; + default: + warn("Not a valid state\n"); + return; + } + info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); + p_slot->state = STATIC_STATE; + } + /* ***********Button Pressed (No action on 1st press...) */ + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + + if (ATTN_BUTTN(ctrl->ctrlcap)) { + dbg("Button pressed\n"); + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + /* slot is on */ + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); + } else { + /* slot is off */ + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); + } + + /* blink green LED and turn off amber */ + if (PWR_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->green_led_blink(p_slot); + + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + init_timer(&p_slot->task_event); + p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ + p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; + p_slot->task_event.data = (unsigned long) p_slot; + + add_timer(&p_slot->task_event); + } + } + /***********POWER FAULT********************/ + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + if (POWER_CTRL(ctrl->ctrlcap)) { + dbg("power fault\n"); + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 1); + + if (PWR_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->green_led_off(p_slot); + } + } + /***********SURPRISE REMOVAL********************/ + else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || + (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { + if (HP_SUPR_RM(ctrl->ctrlcap)) { + dbg("Surprise Removal\n"); + if (p_slot) { + surprise_rm_pending = (unsigned long) p_slot; + up(&event_semaphore); + update_slot_info(p_slot); + } + } + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } /* End of FOR loop */ } - mutex_unlock(&p_slot->lock); - - kfree(info); } int pciehp_enable_slot(struct slot *p_slot) @@ -538,7 +653,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { info("%s: no adapter on slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -546,7 +661,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -556,7 +671,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -591,7 +706,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -601,7 +716,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -611,7 +726,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __FUNCTION__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -624,66 +739,3 @@ int pciehp_disable_slot(struct slot *p_slot) return ret; } -int pciehp_sysfs_enable_slot(struct slot *p_slot) -{ - int retval = -ENODEV; - - mutex_lock(&p_slot->lock); - switch (p_slot->state) { - case BLINKINGON_STATE: - cancel_delayed_work(&p_slot->work); - case STATIC_STATE: - p_slot->state = POWERON_STATE; - mutex_unlock(&p_slot->lock); - retval = pciehp_enable_slot(p_slot); - mutex_lock(&p_slot->lock); - p_slot->state = STATIC_STATE; - break; - case POWERON_STATE: - info("Slot %s is already in powering on state\n", - p_slot->name); - break; - case BLINKINGOFF_STATE: - case POWEROFF_STATE: - info("Already enabled on slot %s\n", p_slot->name); - break; - default: - err("Not a valid state on slot %s\n", p_slot->name); - break; - } - mutex_unlock(&p_slot->lock); - - return retval; -} - -int pciehp_sysfs_disable_slot(struct slot *p_slot) -{ - int retval = -ENODEV; - - mutex_lock(&p_slot->lock); - switch (p_slot->state) { - case BLINKINGOFF_STATE: - cancel_delayed_work(&p_slot->work); - case STATIC_STATE: - p_slot->state = POWEROFF_STATE; - mutex_unlock(&p_slot->lock); - retval = pciehp_disable_slot(p_slot); - mutex_lock(&p_slot->lock); - p_slot->state = STATIC_STATE; - break; - case POWEROFF_STATE: - info("Slot %s is already in powering off state\n", - p_slot->name); - break; - case BLINKINGON_STATE: - case POWERON_STATE: - info("Already disabled on slot %s\n", p_slot->name); - break; - default: - err("Not a valid state on slot %s\n", p_slot->name); - break; - } - mutex_unlock(&p_slot->lock); - - return retval; -} diff --git a/trunk/drivers/pci/hotplug/pciehp_hpc.c b/trunk/drivers/pci/hotplug/pciehp_hpc.c index 9aac6a87eb53..fbc64aa2dd68 100644 --- a/trunk/drivers/pci/hotplug/pciehp_hpc.c +++ b/trunk/drivers/pci/hotplug/pciehp_hpc.c @@ -71,8 +71,6 @@ #define DBG_LEAVE_ROUTINE #endif /* DEBUG */ -static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); - struct ctrl_reg { u8 cap_id; u8 nxt_ptr; @@ -221,7 +219,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define EMI_STATE 0x0080 #define EMI_STATUS_BIT 7 +static spinlock_t hpc_event_lock; + DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ +static int ctlr_seq_num = 0; /* Controller sequence # */ static irqreturn_t pcie_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); @@ -655,13 +656,6 @@ static void hpc_release_ctlr(struct controller *ctrl) else free_irq(ctrl->pci_dev->irq, ctrl); - /* - * If this is the last controller to be released, destroy the - * pciehp work queue - */ - if (atomic_dec_and_test(&pciehp_num_controllers)) - destroy_workqueue(pciehp_wq); - DBG_LEAVE_ROUTINE } @@ -1158,6 +1152,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) int pcie_init(struct controller * ctrl, struct pcie_device *dev) { int rc; + static int first = 1; u16 temp_word; u16 cap_reg; u16 intr_enable = 0; @@ -1226,6 +1221,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); + if (first) { + spin_lock_init(&hpc_event_lock); + first = 0; + } + for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, @@ -1286,8 +1286,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", - __FUNCTION__, ctrl->pci_dev->irq, - atomic_read(&pciehp_num_controllers), rc); + __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); @@ -1297,18 +1296,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); - /* - * If this is the first controller to be initialized, - * initialize the pciehp work queue - */ - if (atomic_add_return(1, &pciehp_num_controllers) == 1) { - pciehp_wq = create_singlethread_workqueue("pciehpd"); - if (!pciehp_wq) { - rc = -ENOMEM; - goto abort_free_irq; - } - } - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); @@ -1362,6 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) goto abort_disable_intr; } + ctlr_seq_num++; ctrl->hpc_ops = &pciehp_hpc_ops; DBG_LEAVE_ROUTINE diff --git a/trunk/drivers/pci/hotplug/rpadlpar_core.c b/trunk/drivers/pci/hotplug/rpadlpar_core.c index bb3c101c2c5a..72383467a0d5 100644 --- a/trunk/drivers/pci/hotplug/rpadlpar_core.c +++ b/trunk/drivers/pci/hotplug/rpadlpar_core.c @@ -98,15 +98,7 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) return NULL; } -/** - * find_php_slot - return hotplug slot structure for device node - * - * This routine will return the hotplug slot structure - * for a given device node. Note that built-in PCI slots - * may be dlpar-able, but not hot-pluggable, so this routine - * will return NULL for built-in PCI slots. - */ -static struct slot *find_php_slot(struct device_node *dn) +static struct slot *find_slot(struct device_node *dn) { struct list_head *tmp, *n; struct slot *slot; @@ -232,9 +224,9 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn) if (!pcibios_find_pci_bus(dn)) return -EINVAL; - /* If pci slot is hotplugable, use hotplug to remove it */ - slot = find_php_slot(dn); + slot = find_slot(dn); if (slot) { + /* Remove hotplug slot */ if (rpaphp_deregister_slot(slot)) { printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", @@ -378,17 +370,22 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) if (!bus) return -EINVAL; - /* If pci slot is hotplugable, use hotplug to remove it */ - slot = find_php_slot(dn); + slot = find_slot(dn); if (slot) { + /* Remove hotplug slot */ if (rpaphp_deregister_slot(slot)) { printk(KERN_ERR "%s: unable to remove hotplug slot %s\n", __FUNCTION__, drc_name); return -EIO; } - } else - pcibios_remove_pci_devices(bus); + } else { + struct pci_dev *dev, *tmp; + list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + eeh_remove_bus_device(dev); + pci_remove_bus_device(dev); + } + } if (unmap_bus_range(bus)) { printk(KERN_ERR "%s: failed to unmap bus range\n", diff --git a/trunk/drivers/pci/hotplug/rpaphp.h b/trunk/drivers/pci/hotplug/rpaphp.h index c822a779653f..2e7accf0f734 100644 --- a/trunk/drivers/pci/hotplug/rpaphp.h +++ b/trunk/drivers/pci/hotplug/rpaphp.h @@ -83,15 +83,19 @@ struct slot { extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; extern struct list_head rpaphp_slot_head; +extern int num_slots; /* function prototypes */ /* rpaphp_pci.c */ -extern int rpaphp_enable_slot(struct slot *slot); +extern int rpaphp_enable_pci_slot(struct slot *slot); +extern int rpaphp_register_pci_slot(struct slot *slot); +extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); extern int rpaphp_get_sensor_state(struct slot *slot, int *state); /* rpaphp_core.c */ extern int rpaphp_add_slot(struct device_node *dn); +extern int rpaphp_remove_slot(struct slot *slot); extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, char **drc_name, char **drc_type, int *drc_power_domain); @@ -100,5 +104,7 @@ extern void dealloc_slot_struct(struct slot *slot); extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain); extern int rpaphp_register_slot(struct slot *slot); extern int rpaphp_deregister_slot(struct slot *slot); +extern int rpaphp_get_power_status(struct slot *slot, u8 * value); +extern int rpaphp_set_attention_status(struct slot *slot, u8 status); #endif /* _PPC64PHP_H */ diff --git a/trunk/drivers/pci/hotplug/rpaphp_core.c b/trunk/drivers/pci/hotplug/rpaphp_core.c index 847936fe327e..71a2cb8baa4a 100644 --- a/trunk/drivers/pci/hotplug/rpaphp_core.c +++ b/trunk/drivers/pci/hotplug/rpaphp_core.c @@ -39,7 +39,9 @@ #include "rpaphp.h" int debug; +static struct semaphore rpaphp_sem; LIST_HEAD(rpaphp_slot_head); +int num_slots; #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Linda Xie " @@ -53,6 +55,11 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); +static int rpaphp_get_attention_status(struct slot *slot) +{ + return slot->hotplug_slot->info->attention_status; +} + /** * set_attention_status - set attention LED * echo 0 > attention -- set LED OFF @@ -62,75 +69,79 @@ module_param(debug, bool, 0644); */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { - int rc; + int retval = 0; struct slot *slot = (struct slot *)hotplug_slot->private; + down(&rpaphp_sem); switch (value) { case 0: - case 1: - case 2: + retval = rpaphp_set_attention_status(slot, LED_OFF); + hotplug_slot->info->attention_status = 0; break; + case 1: default: - value = 1; + retval = rpaphp_set_attention_status(slot, LED_ON); + hotplug_slot->info->attention_status = 1; + break; + case 2: + retval = rpaphp_set_attention_status(slot, LED_ID); + hotplug_slot->info->attention_status = 2; break; } - - rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); - if (!rc) - hotplug_slot->info->attention_status = value; - - return rc; + up(&rpaphp_sem); + return retval; } /** * get_power_status - get power status of a slot * @hotplug_slot: slot to get status * @value: pointer to store status + * + * */ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) { - int retval, level; + int retval; struct slot *slot = (struct slot *)hotplug_slot->private; - retval = rtas_get_power_level (slot->power_domain, &level); - if (!retval) - *value = level; + down(&rpaphp_sem); + retval = rpaphp_get_power_status(slot, value); + up(&rpaphp_sem); return retval; } /** * get_attention_status - get attention LED status + * + * */ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) { + int retval = 0; struct slot *slot = (struct slot *)hotplug_slot->private; - *value = slot->hotplug_slot->info->attention_status; - return 0; + + down(&rpaphp_sem); + *value = rpaphp_get_attention_status(slot); + up(&rpaphp_sem); + return retval; } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) { struct slot *slot = (struct slot *)hotplug_slot->private; - int rc, state; - - rc = rpaphp_get_sensor_state(slot, &state); - - *value = NOT_VALID; - if (rc) - return rc; - - if (state == EMPTY) - *value = EMPTY; - else if (state == PRESENT) - *value = slot->state; + int retval = 0; - return 0; + down(&rpaphp_sem); + retval = rpaphp_get_pci_adapter_status(slot, 0, value); + up(&rpaphp_sem); + return retval; } static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { struct slot *slot = (struct slot *)hotplug_slot->private; + down(&rpaphp_sem); switch (slot->type) { case 1: case 2: @@ -161,6 +172,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe break; } + up(&rpaphp_sem); return 0; } @@ -253,14 +265,6 @@ static int is_php_type(char *drc_type) return 1; } -/** - * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0 - * - * This routine will return true only if the device node is - * a hotpluggable slot. This routine will return false - * for built-in pci slots (even when the built-in slots are - * dlparable.) - */ static int is_php_dn(struct device_node *dn, const int **indexes, const int **names, const int **types, const int **power_domains) { @@ -268,31 +272,24 @@ static int is_php_dn(struct device_node *dn, const int **indexes, int rc; rc = get_children_props(dn, indexes, names, &drc_types, power_domains); - if (rc < 0) - return 0; - - if (!is_php_type((char *) &drc_types[1])) - return 0; + if (rc >= 0) { + if (is_php_type((char *) &drc_types[1])) { + *types = drc_types; + return 1; + } + } - *types = drc_types; - return 1; + return 0; } /** - * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem. - * @dn device node of slot - * - * This subroutine will register a hotplugable slot with the - * PCI hotplug infrastructure. This routine is typicaly called - * during boot time, if the hotplug slots are present at boot time, - * or is called later, by the dlpar add code, if the slot is - * being dynamically added during runtime. - * - * If the device node points at an embedded (built-in) slot, this - * routine will just return without doing anything, since embedded - * slots cannot be hotplugged. + * rpaphp_add_slot -- add hotplug or dlpar slot * - * To remove a slot, it suffices to call rpaphp_deregister_slot() + * rpaphp not only registers PCI hotplug slots(HOTPLUG), + * but also logical DR slots(EMBEDDED). + * HOTPLUG slot: An adapter can be physically added/removed. + * EMBEDDED slot: An adapter can be logically removed/added + * from/to a partition with the slot. */ int rpaphp_add_slot(struct device_node *dn) { @@ -302,42 +299,34 @@ int rpaphp_add_slot(struct device_node *dn) const int *indexes, *names, *types, *power_domains; char *name, *type; - if (!dn->name || strcmp(dn->name, "pci")) - return 0; - - /* If this is not a hotplug slot, return without doing anything. */ - if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) - return 0; - dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name); /* register PCI devices */ - name = (char *) &names[1]; - type = (char *) &types[1]; - for (i = 0; i < indexes[0]; i++) { - - slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); - if (!slot) - return -ENOMEM; - - slot->type = simple_strtoul(type, NULL, 10); + if (dn->name != 0 && strcmp(dn->name, "pci") == 0) { + if (!is_php_dn(dn, &indexes, &names, &types, &power_domains)) + goto exit; + + name = (char *) &names[1]; + type = (char *) &types[1]; + for (i = 0; i < indexes[0]; i++, + name += (strlen(name) + 1), type += (strlen(type) + 1)) { + + if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name, + power_domains[i + 1]))) { + retval = -ENOMEM; + goto exit; + } + slot->type = simple_strtoul(type, NULL, 10); - dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", - indexes[i + 1], name, type); + dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", + indexes[i + 1], name, type); - retval = rpaphp_enable_slot(slot); - if (!retval) - retval = rpaphp_register_slot(slot); - - if (retval) - dealloc_slot_struct(slot); - - name += strlen(name) + 1; - type += strlen(type) + 1; + retval = rpaphp_register_pci_slot(slot); + } } - dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); - - /* XXX FIXME: reports a failure only if last entry in loop failed */ +exit: + dbg("%s - Exit: num_slots=%d rc[%d]\n", + __FUNCTION__, num_slots, retval); return retval; } @@ -365,6 +354,7 @@ static int __init rpaphp_init(void) struct device_node *dn = NULL; info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + init_MUTEX(&rpaphp_sem); while ((dn = of_find_node_by_name(dn, "pci"))) rpaphp_add_slot(dn); @@ -377,9 +367,8 @@ static void __exit rpaphp_exit(void) cleanup_slots(); } -static int enable_slot(struct hotplug_slot *hotplug_slot) +static int __enable_slot(struct slot *slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; int state; int retval; @@ -403,17 +392,46 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) return 0; } -static int disable_slot(struct hotplug_slot *hotplug_slot) +static int enable_slot(struct hotplug_slot *hotplug_slot) { + int retval; struct slot *slot = (struct slot *)hotplug_slot->private; + + down(&rpaphp_sem); + retval = __enable_slot(slot); + up(&rpaphp_sem); + + return retval; +} + +static int __disable_slot(struct slot *slot) +{ + struct pci_dev *dev, *tmp; + if (slot->state == NOT_CONFIGURED) return -EINVAL; - pcibios_remove_pci_devices(slot->bus); + list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) { + eeh_remove_bus_device(dev); + pci_remove_bus_device(dev); + } + slot->state = NOT_CONFIGURED; return 0; } +static int disable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = (struct slot *)hotplug_slot->private; + int retval; + + down(&rpaphp_sem); + retval = __disable_slot (slot); + up(&rpaphp_sem); + + return retval; +} + struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { .owner = THIS_MODULE, .enable_slot = enable_slot, diff --git a/trunk/drivers/pci/hotplug/rpaphp_pci.c b/trunk/drivers/pci/hotplug/rpaphp_pci.c index 54ca8650d511..6f6cbede5135 100644 --- a/trunk/drivers/pci/hotplug/rpaphp_pci.c +++ b/trunk/drivers/pci/hotplug/rpaphp_pci.c @@ -64,6 +64,75 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) return rc; } +/** + * get_pci_adapter_status - get the status of a slot + * + * 0-- slot is empty + * 1-- adapter is configured + * 2-- adapter is not configured + * 3-- not valid + */ +int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) +{ + struct pci_bus *bus; + int state, rc; + + *value = NOT_VALID; + rc = rpaphp_get_sensor_state(slot, &state); + if (rc) + goto exit; + + if (state == EMPTY) + *value = EMPTY; + else if (state == PRESENT) { + if (!is_init) { + /* at run-time slot->state can be changed by */ + /* config/unconfig adapter */ + *value = slot->state; + } else { + bus = pcibios_find_pci_bus(slot->dn); + if (bus && !list_empty(&bus->devices)) + *value = CONFIGURED; + else + *value = NOT_CONFIGURED; + } + } +exit: + return rc; +} + +static void print_slot_pci_funcs(struct pci_bus *bus) +{ + struct device_node *dn; + struct pci_dev *dev; + + dn = pci_bus_to_OF_node(bus); + if (!dn) + return; + + dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); + list_for_each_entry (dev, &bus->devices, bus_list) + dbg("\t%s\n", pci_name(dev)); + return; +} + +static int setup_pci_hotplug_slot_info(struct slot *slot) +{ + struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info; + + dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", + __FUNCTION__); + rpaphp_get_power_status(slot, &hotplug_slot_info->power_status); + rpaphp_get_pci_adapter_status(slot, 1, + &hotplug_slot_info->adapter_status); + if (hotplug_slot_info->adapter_status == NOT_VALID) { + err("%s: NOT_VALID: skip dn->full_name=%s\n", + __FUNCTION__, slot->dn->full_name); + return -EINVAL; + } + return 0; +} + static void set_slot_name(struct slot *slot) { struct pci_bus *bus = slot->bus; @@ -77,73 +146,69 @@ static void set_slot_name(struct slot *slot) bus->number); } -/** - * rpaphp_enable_slot - record slot state, config pci device - * - * Initialize values in the slot, and the hotplug_slot info - * structures to indicate if there is a pci card plugged into - * the slot. If the slot is not empty, run the pcibios routine - * to get pcibios stuff correctly set up. - */ -int rpaphp_enable_slot(struct slot *slot) +static int setup_pci_slot(struct slot *slot) { - int rc, level, state; + struct device_node *dn = slot->dn; struct pci_bus *bus; - struct hotplug_slot_info *info = slot->hotplug_slot->info; - - info->adapter_status = NOT_VALID; - slot->state = EMPTY; - - /* Find out if the power is turned on for the slot */ - rc = rtas_get_power_level(slot->power_domain, &level); - if (rc) - return rc; - info->power_status = level; - - /* Figure out if there is an adapter in the slot */ - rc = rpaphp_get_sensor_state(slot, &state); - if (rc) - return rc; - bus = pcibios_find_pci_bus(slot->dn); + BUG_ON(!dn); + bus = pcibios_find_pci_bus(dn); if (!bus) { - err("%s: no pci_bus for dn %s\n", __FUNCTION__, slot->dn->full_name); - return -EINVAL; + err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); + goto exit_rc; } - info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; set_slot_name(slot); - /* if there's an adapter in the slot, go add the pci devices */ - if (state == PRESENT) { - info->adapter_status = NOT_CONFIGURED; - slot->state = NOT_CONFIGURED; - - /* non-empty slot has to have child */ - if (!slot->dn->child) { - err("%s: slot[%s]'s device_node doesn't have child for adapter\n", - __FUNCTION__, slot->name); - return -EINVAL; + /* find slot's pci_dev if it's not empty */ + if (slot->hotplug_slot->info->adapter_status == EMPTY) { + slot->state = EMPTY; /* slot is empty */ + } else { + /* slot is occupied */ + if (!dn->child) { + /* non-empty slot has to have child */ + err("%s: slot[%s]'s device_node doesn't have child for adapter\n", + __FUNCTION__, slot->name); + goto exit_rc; } - if (list_empty(&bus->devices)) - pcibios_add_pci_devices(bus); + if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { + dbg("%s CONFIGURING pci adapter in slot[%s]\n", + __FUNCTION__, slot->name); + pcibios_add_pci_devices(slot->bus); - if (!list_empty(&bus->devices)) { - info->adapter_status = CONFIGURED; - slot->state = CONFIGURED; + } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { + err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", + __FUNCTION__, slot->name); + goto exit_rc; } - - if (debug) { - struct pci_dev *dev; - dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->dn->full_name); - list_for_each_entry (dev, &bus->devices, bus_list) - dbg("\t%s\n", pci_name(dev)); + print_slot_pci_funcs(slot->bus); + if (!list_empty(slot->pci_devs)) { + slot->state = CONFIGURED; + } else { + /* DLPAR add as opposed to + * boot time */ + slot->state = NOT_CONFIGURED; } } - return 0; +exit_rc: + dealloc_slot_struct(slot); + return -EINVAL; +} + +int rpaphp_register_pci_slot(struct slot *slot) +{ + int rc = -EINVAL; + + if (setup_pci_hotplug_slot_info(slot)) + goto exit_rc; + if (setup_pci_slot(slot)) + goto exit_rc; + rc = rpaphp_register_slot(slot); +exit_rc: + return rc; } diff --git a/trunk/drivers/pci/hotplug/rpaphp_slot.c b/trunk/drivers/pci/hotplug/rpaphp_slot.c index d4ee8723fcb3..3009193f0058 100644 --- a/trunk/drivers/pci/hotplug/rpaphp_slot.c +++ b/trunk/drivers/pci/hotplug/rpaphp_slot.c @@ -56,6 +56,7 @@ static struct hotplug_slot_attribute php_attr_location = { static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = (struct slot *) hotplug_slot->private; + dealloc_slot_struct(slot); } @@ -64,12 +65,12 @@ void dealloc_slot_struct(struct slot *slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); - kfree(slot->location); kfree(slot); + return; } -struct slot *alloc_slot_struct(struct device_node *dn, - int drc_index, char *drc_name, int power_domain) +struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, + int power_domain) { struct slot *slot; @@ -114,7 +115,7 @@ struct slot *alloc_slot_struct(struct device_node *dn, static int is_registered(struct slot *slot) { - struct slot *tmp_slot; + struct slot *tmp_slot; list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { if (!strcmp(tmp_slot->name, slot->name)) @@ -139,6 +140,8 @@ int rpaphp_deregister_slot(struct slot *slot) retval = pci_hp_deregister(php_slot); if (retval) err("Problem unregistering a slot %s\n", slot->name); + else + num_slots--; dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); return retval; @@ -157,13 +160,14 @@ int rpaphp_register_slot(struct slot *slot) /* should not try to register the same slot twice */ if (is_registered(slot)) { err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name); - return -EAGAIN; + retval = -EAGAIN; + goto register_fail; } retval = pci_hp_register(php_slot); if (retval) { err("pci_hp_register failed with error %d\n", retval); - return retval; + goto register_fail; } /* create "phy_location" file */ @@ -177,10 +181,43 @@ int rpaphp_register_slot(struct slot *slot) list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); info("Slot [%s](PCI location=%s) registered\n", slot->name, slot->location); + num_slots++; return 0; sysfs_fail: pci_hp_deregister(php_slot); +register_fail: + rpaphp_release_slot(php_slot); return retval; } +int rpaphp_get_power_status(struct slot *slot, u8 * value) +{ + int rc = 0, level; + + rc = rtas_get_power_level(slot->power_domain, &level); + if (rc < 0) { + err("failed to get power-level for slot(%s), rc=0x%x\n", + slot->location, rc); + return rc; + } + + dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", + __FUNCTION__, slot->name, slot->power_domain, level); + *value = level; + + return rc; +} + +int rpaphp_set_attention_status(struct slot *slot, u8 status) +{ + int rc; + + /* status: LED_OFF or LED_ON */ + rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); + if (rc < 0) + err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n", + slot->name, slot->location, slot->index, status, rc); + + return rc; +} diff --git a/trunk/drivers/pci/hotplug/shpchp.h b/trunk/drivers/pci/hotplug/shpchp.h index 37ed0884b972..01d31a1f697c 100644 --- a/trunk/drivers/pci/hotplug/shpchp.h +++ b/trunk/drivers/pci/hotplug/shpchp.h @@ -166,7 +166,7 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct slot *p_slot); extern void cleanup_slots(struct controller *ctrl); -extern void shpchp_queue_pushbutton_work(struct work_struct *work); +extern void queue_pushbutton_work(struct work_struct *work); extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); #ifdef CONFIG_ACPI diff --git a/trunk/drivers/pci/hotplug/shpchp_core.c b/trunk/drivers/pci/hotplug/shpchp_core.c index 80dec9796b31..5f4bc08a633a 100644 --- a/trunk/drivers/pci/hotplug/shpchp_core.c +++ b/trunk/drivers/pci/hotplug/shpchp_core.c @@ -136,7 +136,7 @@ static int init_slots(struct controller *ctrl) slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); mutex_init(&slot->lock); - INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); + INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work); /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; diff --git a/trunk/drivers/pci/hotplug/shpchp_ctrl.c b/trunk/drivers/pci/hotplug/shpchp_ctrl.c index 2c94d44279a3..b746bd265bc6 100644 --- a/trunk/drivers/pci/hotplug/shpchp_ctrl.c +++ b/trunk/drivers/pci/hotplug/shpchp_ctrl.c @@ -433,7 +433,7 @@ static void shpchp_pushbutton_thread(struct work_struct *work) kfree(info); } -void shpchp_queue_pushbutton_work(struct work_struct *work) +void queue_pushbutton_work(struct work_struct *work) { struct slot *p_slot = container_of(work, struct slot, work.work); struct pushbutton_work_info *info; diff --git a/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c index 9e1321d0d5e6..435c1958a7b7 100644 --- a/trunk/drivers/pci/msi.c +++ b/trunk/drivers/pci/msi.c @@ -24,8 +24,20 @@ #include "pci.h" #include "msi.h" +static struct kmem_cache* msi_cachep; + static int pci_msi_enable = 1; +static int msi_cache_init(void) +{ + msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!msi_cachep) + return -ENOMEM; + + return 0; +} + static void msi_set_enable(struct pci_dev *dev, int enable) { int pos; @@ -56,29 +68,6 @@ static void msix_set_enable(struct pci_dev *dev, int enable) } } -static void msix_flush_writes(unsigned int irq) -{ - struct msi_desc *entry; - - entry = get_irq_msi(irq); - BUG_ON(!entry || !entry->dev); - switch (entry->msi_attrib.type) { - case PCI_CAP_ID_MSI: - /* nothing to do */ - break; - case PCI_CAP_ID_MSIX: - { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; - readl(entry->mask_base + offset); - break; - } - default: - BUG(); - break; - } -} - static void msi_set_mask_bit(unsigned int irq, int flag) { struct msi_desc *entry; @@ -198,28 +187,41 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) void mask_msi_irq(unsigned int irq) { msi_set_mask_bit(irq, 1); - msix_flush_writes(irq); } void unmask_msi_irq(unsigned int irq) { msi_set_mask_bit(irq, 0); - msix_flush_writes(irq); } -static int msi_free_irqs(struct pci_dev* dev); +static int msi_free_irq(struct pci_dev* dev, int irq); + +static int msi_init(void) +{ + static int status = -ENOMEM; + + if (!status) + return status; + status = msi_cache_init(); + if (status < 0) { + pci_msi_enable = 0; + printk(KERN_WARNING "PCI: MSI cache init failed\n"); + return status; + } + + return status; +} static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; - entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL); + entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL); if (!entry) return NULL; - INIT_LIST_HEAD(&entry->list); - entry->irq = 0; + entry->link.tail = entry->link.head = 0; /* single message */ entry->dev = NULL; return entry; @@ -254,6 +256,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) static void __pci_restore_msix_state(struct pci_dev *dev) { int pos; + int irq, head, tail = 0; struct msi_desc *entry; u16 control; @@ -263,15 +266,18 @@ static void __pci_restore_msix_state(struct pci_dev *dev) /* route the table */ pci_intx(dev, 0); /* disable intx */ msix_set_enable(dev, 0); + irq = head = dev->first_msi_irq; + entry = get_irq_msi(irq); + pos = entry->msi_attrib.pos; + while (head != tail) { + entry = get_irq_msi(irq); + write_msi_msg(irq, &entry->msg); + msi_set_mask_bit(irq, entry->msi_attrib.masked); - list_for_each_entry(entry, &dev->msi_list, list) { - write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); + tail = entry->link.tail; + irq = tail; } - BUG_ON(list_empty(&dev->msi_list)); - entry = list_entry(dev->msi_list.next, struct msi_desc, list); - pos = entry->msi_attrib.pos; pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); control &= ~PCI_MSIX_FLAGS_MASKALL; control |= PCI_MSIX_FLAGS_ENABLE; @@ -297,7 +303,7 @@ void pci_restore_msi_state(struct pci_dev *dev) static int msi_capability_init(struct pci_dev *dev) { struct msi_desc *entry; - int pos, ret; + int pos, irq; u16 control; msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ @@ -334,21 +340,23 @@ static int msi_capability_init(struct pci_dev *dev) msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); } - list_add(&entry->list, &dev->msi_list); - /* Configure MSI capability structure */ - ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); - if (ret) { - msi_free_irqs(dev); - return ret; + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + return irq; } + entry->link.head = irq; + entry->link.tail = irq; + dev->first_msi_irq = irq; + set_irq_msi(irq, entry); /* Set MSI enabled bits */ pci_intx(dev, 0); /* disable intx */ msi_set_enable(dev, 1); dev->msi_enabled = 1; - dev->irq = entry->irq; + dev->irq = irq; return 0; } @@ -365,8 +373,8 @@ static int msi_capability_init(struct pci_dev *dev) static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { - struct msi_desc *entry; - int pos, i, j, nr_entries, ret; + struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; + int irq, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; u16 control; @@ -405,34 +413,44 @@ static int msix_capability_init(struct pci_dev *dev, entry->dev = dev; entry->mask_base = base; - list_add(&entry->list, &dev->msi_list); - } - - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); - if (ret) { - int avail = 0; - list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq != 0) { - avail++; - } + /* Configure MSI-X capability structure */ + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + break; } + entries[i].vector = irq; + if (!head) { + entry->link.head = irq; + entry->link.tail = irq; + head = entry; + } else { + entry->link.head = temp; + entry->link.tail = tail->link.tail; + tail->link.tail = irq; + head->link.head = irq; + } + temp = irq; + tail = entry; - msi_free_irqs(dev); - + set_irq_msi(irq, entry); + } + if (i != nvec) { + int avail = i - 1; + i--; + for (; i >= 0; i--) { + irq = (entries + i)->vector; + msi_free_irq(dev, irq); + (entries + i)->vector = 0; + } /* If we had some success report the number of irqs * we succeeded in setting up. */ - if (avail == 0) - avail = ret; + if (avail <= 0) + avail = -EBUSY; return avail; } - - i = 0; - list_for_each_entry(entry, &dev->msi_list, list) { - entries[i].vector = entry->irq; - set_irq_msi(entry->irq, entry); - i++; - } + dev->first_msi_irq = entries[0].vector; /* Set MSI-X enabled bits */ pci_intx(dev, 0); /* disable intx */ msix_set_enable(dev, 1); @@ -442,32 +460,21 @@ static int msix_capability_init(struct pci_dev *dev, } /** - * pci_msi_check_device - check whether MSI may be enabled on a device + * pci_msi_supported - check whether MSI may be enabled on device * @dev: pointer to the pci_dev data structure of MSI device function - * @nvec: how many MSIs have been requested ? - * @type: are we checking for MSI or MSI-X ? * * Look at global flags, the device itself, and its parent busses - * to determine if MSI/-X are supported for the device. If MSI/-X is - * supported return 0, else return an error code. + * to return 0 if MSI are supported for the device. **/ -static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) +static +int pci_msi_supported(struct pci_dev * dev) { struct pci_bus *bus; - int ret; /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable || !dev || dev->no_msi) return -EINVAL; - /* - * You can't ask to have 0 or less MSIs configured. - * a) it's stupid .. - * b) the list manipulation code assumes nvec >= 1. - */ - if (nvec < 1) - return -ERANGE; - /* Any bridge which does NOT route MSI transactions from it's * secondary bus to it's primary bus must set NO_MSI flag on * the secondary pci_bus. @@ -478,13 +485,6 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; - ret = arch_msi_check_device(dev, nvec, type); - if (ret) - return ret; - - if (!pci_find_capability(dev, type)) - return -EINVAL; - return 0; } @@ -500,12 +500,19 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) **/ int pci_enable_msi(struct pci_dev* dev) { - int status; + int pos, status; + + if (pci_msi_supported(dev) < 0) + return -EINVAL; - status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); - if (status) + status = msi_init(); + if (status < 0) return status; + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (!pos) + return -EINVAL; + WARN_ON(!!dev->msi_enabled); /* Check whether driver already requested for MSI-X irqs */ @@ -518,54 +525,69 @@ int pci_enable_msi(struct pci_dev* dev) status = msi_capability_init(dev); return status; } -EXPORT_SYMBOL(pci_enable_msi); void pci_disable_msi(struct pci_dev* dev) { struct msi_desc *entry; int default_irq; - if (!pci_msi_enable || !dev || !dev->msi_enabled) + if (!pci_msi_enable) + return; + if (!dev) + return; + + if (!dev->msi_enabled) return; msi_set_enable(dev, 0); pci_intx(dev, 1); /* enable intx */ dev->msi_enabled = 0; - BUG_ON(list_empty(&dev->msi_list)); - entry = list_entry(dev->msi_list.next, struct msi_desc, list); - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { + entry = get_irq_msi(dev->first_msi_irq); + if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { return; } - - default_irq = entry->msi_attrib.default_irq; - msi_free_irqs(dev); - - /* Restore dev->irq to its default pin-assertion irq */ - dev->irq = default_irq; + if (irq_has_action(dev->first_msi_irq)) { + printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " + "free_irq() on MSI irq %d\n", + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); + } else { + default_irq = entry->msi_attrib.default_irq; + msi_free_irq(dev, dev->first_msi_irq); + + /* Restore dev->irq to its default pin-assertion irq */ + dev->irq = default_irq; + } + dev->first_msi_irq = 0; } -EXPORT_SYMBOL(pci_disable_msi); -static int msi_free_irqs(struct pci_dev* dev) +static int msi_free_irq(struct pci_dev* dev, int irq) { - struct msi_desc *entry, *tmp; - - list_for_each_entry(entry, &dev->msi_list, list) - BUG_ON(irq_has_action(entry->irq)); - - arch_teardown_msi_irqs(dev); - - list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { - if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) { - if (list_is_last(&entry->list, &dev->msi_list)) - iounmap(entry->mask_base); + struct msi_desc *entry; + int head, entry_nr, type; + void __iomem *base; - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - } - list_del(&entry->list); - kfree(entry); + entry = get_irq_msi(irq); + if (!entry || entry->dev != dev) { + return -EINVAL; + } + type = entry->msi_attrib.type; + entry_nr = entry->msi_attrib.entry_nr; + head = entry->link.head; + base = entry->mask_base; + get_irq_msi(entry->link.head)->link.tail = entry->link.tail; + get_irq_msi(entry->link.tail)->link.head = entry->link.head; + + arch_teardown_msi_irq(irq); + kmem_cache_free(msi_cachep, entry); + + if (type == PCI_CAP_ID_MSIX) { + writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + + if (head == irq) + iounmap(base); } return 0; @@ -592,14 +614,17 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) int i, j; u16 control; - if (!entries) + if (!entries || pci_msi_supported(dev) < 0) return -EINVAL; - status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); - if (status) + status = msi_init(); + if (status < 0) return status; pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (!pos) + return -EINVAL; + pci_read_config_word(dev, msi_control_reg(pos), &control); nr_entries = multi_msix_capable(control); if (nvec > nr_entries) @@ -626,25 +651,41 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) status = msix_capability_init(dev, entries, nvec); return status; } -EXPORT_SYMBOL(pci_enable_msix); - -static void msix_free_all_irqs(struct pci_dev *dev) -{ - msi_free_irqs(dev); -} void pci_disable_msix(struct pci_dev* dev) { - if (!pci_msi_enable || !dev || !dev->msix_enabled) + int irq, head, tail = 0, warning = 0; + + if (!pci_msi_enable) + return; + if (!dev) + return; + + if (!dev->msix_enabled) return; msix_set_enable(dev, 0); pci_intx(dev, 1); /* enable intx */ dev->msix_enabled = 0; - msix_free_all_irqs(dev); + irq = head = dev->first_msi_irq; + while (head != tail) { + tail = get_irq_msi(irq)->link.tail; + if (irq_has_action(irq)) + warning = 1; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; + } + msi_free_irq(dev, irq); + if (warning) { + printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " + "free_irq() on all MSI-X irqs\n", + pci_name(dev)); + BUG_ON(warning > 0); + } + dev->first_msi_irq = 0; } -EXPORT_SYMBOL(pci_disable_msix); /** * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state @@ -660,11 +701,38 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) if (!pci_msi_enable || !dev) return; - if (dev->msi_enabled) - msi_free_irqs(dev); - - if (dev->msix_enabled) - msix_free_all_irqs(dev); + if (dev->msi_enabled) { + if (irq_has_action(dev->first_msi_irq)) { + printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " + "called without free_irq() on MSI irq %d\n", + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); + } else /* Release MSI irq assigned to this device */ + msi_free_irq(dev, dev->first_msi_irq); + } + if (dev->msix_enabled) { + int irq, head, tail = 0, warning = 0; + void __iomem *base = NULL; + + irq = head = dev->first_msi_irq; + while (head != tail) { + tail = get_irq_msi(irq)->link.tail; + base = get_irq_msi(irq)->mask_base; + if (irq_has_action(irq)) + warning = 1; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; + } + msi_free_irq(dev, irq); + if (warning) { + iounmap(base); + printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " + "called without free_irq() on all MSI-X irqs\n", + pci_name(dev)); + BUG_ON(warning > 0); + } + } } void pci_no_msi(void) @@ -672,53 +740,7 @@ void pci_no_msi(void) pci_msi_enable = 0; } -void pci_msi_init_pci_dev(struct pci_dev *dev) -{ - INIT_LIST_HEAD(&dev->msi_list); -} - - -/* Arch hooks */ - -int __attribute__ ((weak)) -arch_msi_check_device(struct pci_dev* dev, int nvec, int type) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ - struct msi_desc *entry; - int ret; - - list_for_each_entry(entry, &dev->msi_list, list) { - ret = arch_setup_msi_irq(dev, entry); - if (ret) - return ret; - } - - return 0; -} - -void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) -{ - return; -} - -void __attribute__ ((weak)) -arch_teardown_msi_irqs(struct pci_dev *dev) -{ - struct msi_desc *entry; - - list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq != 0) - arch_teardown_msi_irq(entry->irq); - } -} +EXPORT_SYMBOL(pci_enable_msi); +EXPORT_SYMBOL(pci_disable_msi); +EXPORT_SYMBOL(pci_enable_msix); +EXPORT_SYMBOL(pci_disable_msix); diff --git a/trunk/drivers/pci/pci-acpi.c b/trunk/drivers/pci/pci-acpi.c index b5ac810404c0..a064f36a0805 100644 --- a/trunk/drivers/pci/pci-acpi.c +++ b/trunk/drivers/pci/pci-acpi.c @@ -317,10 +317,6 @@ static int __init acpi_pci_init(void) { int ret; - if (acpi_gbl_FADT.boot_flags & BAF_MSI_NOT_SUPPORTED) { - printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); - pci_no_msi(); - } ret = register_acpi_bus_type(&acpi_pci_bus); if (ret) return 0; diff --git a/trunk/drivers/pci/pci-driver.c b/trunk/drivers/pci/pci-driver.c index 3bb7739d26a5..a3c1755b2f28 100644 --- a/trunk/drivers/pci/pci-driver.c +++ b/trunk/drivers/pci/pci-driver.c @@ -13,6 +13,20 @@ #include #include "pci.h" +/* + * Registration of PCI drivers and handling of hot-pluggable devices. + */ + +/* multithreaded probe logic */ +static int pci_multithread_probe = +#ifdef CONFIG_PCI_MULTITHREAD_PROBE + 1; +#else + 0; +#endif +__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644); + + /* * Dynamic device IDs are disabled for !CONFIG_HOTPLUG */ @@ -38,7 +52,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) { struct pci_dynid *dynid; struct pci_driver *pdrv = to_pci_driver(driver); - __u32 vendor, device, subvendor=PCI_ANY_ID, + __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, subdevice=PCI_ANY_ID, class=0, class_mask=0; unsigned long driver_data=0; int fields=0; @@ -47,7 +61,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) fields = sscanf(buf, "%x %x %x %x %x %x %lux", &vendor, &device, &subvendor, &subdevice, &class, &class_mask, &driver_data); - if (fields < 2) + if (fields < 0) return -EINVAL; dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); @@ -420,6 +434,11 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, drv->driver.mod_name = mod_name; drv->driver.kobj.ktype = &pci_driver_kobj_type; + if (pci_multithread_probe) + drv->driver.multithread_probe = pci_multithread_probe; + else + drv->driver.multithread_probe = drv->multithread_probe; + spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); diff --git a/trunk/drivers/pci/pci-sysfs.c b/trunk/drivers/pci/pci-sysfs.c index 284e83a527f9..cd913a2a416f 100644 --- a/trunk/drivers/pci/pci-sysfs.c +++ b/trunk/drivers/pci/pci-sysfs.c @@ -620,8 +620,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) goto err_bin_file; /* If the device has a ROM, try to expose it in sysfs. */ - if (pci_resource_len(pdev, PCI_ROM_RESOURCE) || - (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) { + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); if (rom_attr) { pdev->rom_attr = rom_attr; @@ -636,7 +635,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) goto err_rom; } else { retval = -ENOMEM; - goto err_resource_files; + goto err_bin_file; } } /* add platform-specific attributes */ @@ -646,8 +645,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) err_rom: kfree(rom_attr); -err_resource_files: - pci_remove_resource_files(pdev); err_bin_file: if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); @@ -698,4 +695,4 @@ static int __init pci_sysfs_init(void) return 0; } -late_initcall(pci_sysfs_init); +__initcall(pci_sysfs_init); diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index fd47ac0c4730..d3eab057b2d3 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; * Given a PCI bus, returns the highest PCI bus number present in the set * including the given PCI bus and its list of child PCI buses. */ -unsigned char pci_bus_max_busnr(struct pci_bus* bus) +unsigned char __devinit +pci_bus_max_busnr(struct pci_bus* bus) { struct list_head *tmp; unsigned char max, n; @@ -891,76 +891,31 @@ pci_disable_device(struct pci_dev *dev) } /** - * pcibios_set_pcie_reset_state - set reset state for device dev - * @dev: the PCI-E device reset - * @state: Reset state to enter into - * - * - * Sets the PCI-E reset state for the device. This is the default - * implementation. Architecture implementations can override this. - */ -int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev, - enum pcie_reset_state state) -{ - return -EINVAL; -} - -/** - * pci_set_pcie_reset_state - set reset state for device dev - * @dev: the PCI-E device reset - * @state: Reset state to enter into + * pci_enable_wake - enable device to generate PME# when suspended + * @dev: - PCI device to operate on + * @state: - Current state of device. + * @enable: - Flag to enable or disable generation + * + * Set the bits in the device's PM Capabilities to generate PME# when + * the system is suspended. * - * - * Sets the PCI reset state for the device. - */ -int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) -{ - return pcibios_set_pcie_reset_state(dev, state); -} - -/** - * pci_enable_wake - enable PCI device as wakeup event source - * @dev: PCI device affected - * @state: PCI state from which device will issue wakeup events - * @enable: True to enable event generation; false to disable - * - * This enables the device as a wakeup event source, or disables it. - * When such events involves platform-specific hooks, those hooks are - * called automatically by this routine. - * - * Devices with legacy power management (no standard PCI PM capabilities) - * always require such platform hooks. Depending on the platform, devices - * supporting the standard PCI PME# signal may require such platform hooks; - * they always update bits in config space to allow PME# generation. - * - * -EIO is returned if the device can't ever be a wakeup event source. - * -EINVAL is returned if the device can't generate wakeup events from - * the specified PCI state. Returns zero if the operation is successful. + * -EIO is returned if device doesn't have PM Capabilities. + * -EINVAL is returned if device supports it, but can't generate wake events. + * 0 if operation is successful. + * */ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { int pm; - int status; u16 value; - /* Note that drivers should verify device_may_wakeup(&dev->dev) - * before calling this function. Platform code should report - * errors when drivers try to enable wakeup on devices that - * can't issue wakeups, or on which wakeups were disabled by - * userspace updating the /sys/devices.../power/wakeup file. - */ - - status = call_platform_enable_wakeup(&dev->dev, enable); - /* find PCI PM capability in list */ pm = pci_find_capability(dev, PCI_CAP_ID_PM); - /* If device doesn't support PM Capabilities, but caller wants to - * disable wake events, it's a NOP. Otherwise fail unless the - * platform hooks handled this legacy device already. - */ - if (!pm) - return enable ? status : 0; + /* If device doesn't support PM Capabilities, but request is to disable + * wake events, it's a nop; otherwise fail */ + if (!pm) + return enable ? -EIO : 0; /* Check device's ability to generate PME# */ pci_read_config_word(dev,pm+PCI_PM_PMC,&value); @@ -969,14 +924,8 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ /* Check if it can generate PME# from requested state. */ - if (!value || !(value & (1 << state))) { - /* if it can't, revert what the platform hook changed, - * always reporting the base "EINVAL, can't PME#" error - */ - if (enable) - call_platform_enable_wakeup(&dev->dev, 0); + if (!value || !(value & (1 << state))) return enable ? -EINVAL : 0; - } pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); @@ -987,7 +936,7 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) value &= ~PCI_PM_CTRL_PME_ENABLE; pci_write_config_word(dev, pm + PCI_PM_CTRL, value); - + return 0; } @@ -1322,7 +1271,7 @@ pci_intx(struct pci_dev *pdev, int enable) /** * pci_msi_off - disables any msi or msix capabilities - * @dev: the PCI device to operate on + * @pdev: the PCI device to operate on * * If you want to use msi see pci_enable_msi and friends. * This is a lower level primitive that allows us to disable @@ -1454,5 +1403,4 @@ EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_save_state); EXPORT_SYMBOL(pci_restore_state); EXPORT_SYMBOL(pci_enable_wake); -EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index 3fec13d3add7..62ea04c8af64 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -47,10 +47,8 @@ extern unsigned int pci_pm_d3_delay; #ifdef CONFIG_PCI_MSI void pci_no_msi(void); -extern void pci_msi_init_pci_dev(struct pci_dev *dev); #else static inline void pci_no_msi(void) { } -static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index e48fcf089621..a4a96826d9e0 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -364,7 +364,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) } } -static struct pci_bus * pci_alloc_bus(void) +static struct pci_bus * __devinit pci_alloc_bus(void) { struct pci_bus *b; @@ -432,7 +432,7 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) return NULL; } -struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) +struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) { struct pci_bus *child; @@ -461,7 +461,7 @@ static void pci_enable_crs(struct pci_dev *dev) pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); } -static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) +static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) { struct pci_bus *parent = child->parent; @@ -477,7 +477,7 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) } } -unsigned int pci_scan_child_bus(struct pci_bus *bus); +unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); /* * If it's a bridge, configure it and scan the bus behind it. @@ -489,7 +489,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus); * them, we proceed to assigning numbers to the remaining buses in * order to avoid overlaps between old and new bus numbers. */ -int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) +int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); @@ -682,7 +682,34 @@ static void pci_read_irq(struct pci_dev *dev) dev->irq = irq; } -#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) +static void change_legacy_io_resource(struct pci_dev * dev, unsigned index, + unsigned start, unsigned end) +{ + unsigned base = start & PCI_BASE_ADDRESS_IO_MASK; + unsigned len = (end | ~PCI_BASE_ADDRESS_IO_MASK) - base + 1; + + /* + * Some X versions get confused when the BARs reported through + * /sys or /proc differ from those seen in config space, thus + * try to update the config space values, too. + */ + if (!(pci_resource_flags(dev, index) & IORESOURCE_IO)) + printk(KERN_WARNING "%s: cannot adjust BAR%u (not I/O)\n", + pci_name(dev), index); + else if (pci_resource_len(dev, index) != len) + printk(KERN_WARNING "%s: cannot adjust BAR%u (size %04X)\n", + pci_name(dev), index, (unsigned)pci_resource_len(dev, index)); + else { + printk(KERN_INFO "%s: trying to change BAR%u from %04X to %04X\n", + pci_name(dev), index, + (unsigned)pci_resource_start(dev, index), base); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + index * 4, base); + } + pci_resource_start(dev, index) = start; + pci_resource_end(dev, index) = end; + pci_resource_flags(dev, index) = + IORESOURCE_IO | IORESOURCE_PCI_FIXED | PCI_BASE_ADDRESS_SPACE_IO; +} /** * pci_setup_device - fill in class and map information of a device @@ -735,20 +762,12 @@ static int pci_setup_device(struct pci_dev * dev) u8 progif; pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 1) == 0) { - dev->resource[0].start = 0x1F0; - dev->resource[0].end = 0x1F7; - dev->resource[0].flags = LEGACY_IO_RESOURCE; - dev->resource[1].start = 0x3F6; - dev->resource[1].end = 0x3F6; - dev->resource[1].flags = LEGACY_IO_RESOURCE; + change_legacy_io_resource(dev, 0, 0x1F0, 0x1F7); + change_legacy_io_resource(dev, 1, 0x3F6, 0x3F6); } if ((progif & 4) == 0) { - dev->resource[2].start = 0x170; - dev->resource[2].end = 0x177; - dev->resource[2].flags = LEGACY_IO_RESOURCE; - dev->resource[3].start = 0x376; - dev->resource[3].end = 0x376; - dev->resource[3].flags = LEGACY_IO_RESOURCE; + change_legacy_io_resource(dev, 2, 0x170, 0x177); + change_legacy_io_resource(dev, 3, 0x376, 0x376); } } break; @@ -846,23 +865,6 @@ static void pci_release_bus_bridge_dev(struct device *dev) kfree(dev); } -struct pci_dev *alloc_pci_dev(void) -{ - struct pci_dev *dev; - - dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); - if (!dev) - return NULL; - - INIT_LIST_HEAD(&dev->global_list); - INIT_LIST_HEAD(&dev->bus_list); - - pci_msi_init_pci_dev(dev); - - return dev; -} -EXPORT_SYMBOL(alloc_pci_dev); - /* * Read the config data for a PCI device, sanity-check it * and fill in the dev structure... @@ -902,7 +904,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) return NULL; - dev = alloc_pci_dev(); + dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) return NULL; @@ -929,7 +931,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) return dev; } -void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) +void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { device_initialize(&dev->dev); dev->dev.release = pci_release_dev; @@ -952,7 +954,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) up_write(&pci_bus_sem); } -struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) +struct pci_dev * __devinit +pci_scan_single_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; @@ -974,7 +977,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) * discovered devices to the @bus->devices list. New devices * will have an empty dev->global_list head. */ -int pci_scan_slot(struct pci_bus *bus, int devfn) +int __devinit pci_scan_slot(struct pci_bus *bus, int devfn) { int func, nr = 0; int scan_all_fns; @@ -1007,7 +1010,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) return nr; } -unsigned int pci_scan_child_bus(struct pci_bus *bus) +unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) { unsigned int devfn, pass, max = bus->secondary; struct pci_dev *dev; @@ -1057,7 +1060,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) return max; } -struct pci_bus * pci_create_bus(struct device *parent, +struct pci_bus * __devinit pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { int error; @@ -1135,7 +1138,7 @@ struct pci_bus * pci_create_bus(struct device *parent, } EXPORT_SYMBOL_GPL(pci_create_bus); -struct pci_bus *pci_scan_bus_parented(struct device *parent, +struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index 147d86f8edbf..65d6f23ead41 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -1303,6 +1303,119 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic ); #endif +enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 }; +/* Defaults to combined */ +static enum ide_combined_type combined_mode; + +static int __init combined_setup(char *str) +{ + if (!strncmp(str, "ide", 3)) + combined_mode = IDE; + else if (!strncmp(str, "libata", 6)) + combined_mode = LIBATA; + else /* "combined" or anything else defaults to old behavior */ + combined_mode = COMBINED; + + return 1; +} +__setup("combined_mode=", combined_setup); + +#ifdef CONFIG_SATA_INTEL_COMBINED +static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev) +{ + u8 prog, comb, tmp; + int ich = 0; + + /* + * Narrow down to Intel SATA PCI devices. + */ + switch (pdev->device) { + /* PCI ids taken from drivers/scsi/ata_piix.c */ + case 0x24d1: + case 0x24df: + case 0x25a3: + case 0x25b0: + ich = 5; + break; + case 0x2651: + case 0x2652: + case 0x2653: + case 0x2680: /* ESB2 */ + ich = 6; + break; + case 0x27c0: + case 0x27c4: + ich = 7; + break; + case 0x2828: /* ICH8M */ + ich = 8; + break; + default: + /* we do not handle this PCI device */ + return; + } + + /* + * Read combined mode register. + */ + pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */ + + if (ich == 5) { + tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */ + if (tmp == 0x4) /* bits 10x */ + comb = (1 << 0); /* SATA port 0, PATA port 1 */ + else if (tmp == 0x6) /* bits 11x */ + comb = (1 << 2); /* PATA port 0, SATA port 1 */ + else + return; /* not in combined mode */ + } else { + WARN_ON((ich != 6) && (ich != 7) && (ich != 8)); + tmp &= 0x3; /* interesting bits 1:0 */ + if (tmp & (1 << 0)) + comb = (1 << 2); /* PATA port 0, SATA port 1 */ + else if (tmp & (1 << 1)) + comb = (1 << 0); /* SATA port 0, PATA port 1 */ + else + return; /* not in combined mode */ + } + + /* + * Read programming interface register. + * (Tells us if it's legacy or native mode) + */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); + + /* if SATA port is in native mode, we're ok. */ + if (prog & comb) + return; + + /* Don't reserve any so the IDE driver can get them (but only if + * combined_mode=ide). + */ + if (combined_mode == IDE) + return; + + /* Grab them both for libata if combined_mode=libata. */ + if (combined_mode == LIBATA) { + request_region(0x1f0, 8, "libata"); /* port 0 */ + request_region(0x170, 8, "libata"); /* port 1 */ + return; + } + + /* SATA port is in legacy mode. Reserve port so that + * IDE driver does not attempt to use it. If request_region + * fails, it will be obvious at boot time, so we don't bother + * checking return values. + */ + if (comb == (1 << 0)) + request_region(0x1f0, 8, "libata"); /* port 0 */ + else + request_region(0x170, 8, "libata"); /* port 1 */ +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined ); +#endif /* CONFIG_SATA_INTEL_COMBINED */ + + int pcie_mch_quirk; EXPORT_SYMBOL(pcie_mch_quirk); @@ -1648,8 +1761,6 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_msi); /* Go through the list of Hypertransport capabilities and * return 1 if a HT MSI capability is found and enabled */ diff --git a/trunk/drivers/pci/search.c b/trunk/drivers/pci/search.c index b137a27472c7..2dd8681d6b31 100644 --- a/trunk/drivers/pci/search.c +++ b/trunk/drivers/pci/search.c @@ -15,7 +15,8 @@ DECLARE_RWSEM(pci_bus_sem); -static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) +static struct pci_bus * +pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) { struct pci_bus* child; struct list_head *tmp; diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 5ec297d7a5b4..3554f3948814 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -36,7 +36,8 @@ #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -static void pbus_assign_resources_sorted(struct pci_bus *bus) +static void __devinit +pbus_assign_resources_sorted(struct pci_bus *bus) { struct pci_dev *dev; struct resource *res; @@ -219,7 +220,8 @@ pci_setup_bridge(struct pci_bus *bus) /* Check whether the bridge supports optional I/O and prefetchable memory ranges. If not, the respective base/limit registers must be read-only and read as 0. */ -static void pci_bridge_check_ranges(struct pci_bus *bus) +static void __devinit +pci_bridge_check_ranges(struct pci_bus *bus) { u16 io; u32 pmem; @@ -257,7 +259,8 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) bus resource of a given type. Note: we intentionally skip the bus resources which have already been assigned (that is, have non-NULL parent resource). */ -static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type) +static struct resource * __devinit +find_free_bus_resource(struct pci_bus *bus, unsigned long type) { int i; struct resource *r; @@ -278,7 +281,8 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon since these windows have 4K granularity and the IO ranges of non-bridge PCI devices are limited to 256 bytes. We must be careful with the ISA aliasing though. */ -static void pbus_size_io(struct pci_bus *bus) +static void __devinit +pbus_size_io(struct pci_bus *bus) { struct pci_dev *dev; struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); @@ -322,7 +326,8 @@ static void pbus_size_io(struct pci_bus *bus) /* Calculate the size of the bus and minimal alignment which guarantees that all child resources fit in this size. */ -static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) +static int __devinit +pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) { struct pci_dev *dev; unsigned long min_align, align, size; @@ -442,7 +447,8 @@ pci_bus_size_cardbus(struct pci_bus *bus) } } -void pci_bus_size_bridges(struct pci_bus *bus) +void __devinit +pci_bus_size_bridges(struct pci_bus *bus) { struct pci_dev *dev; unsigned long mask, prefmask; @@ -492,7 +498,8 @@ void pci_bus_size_bridges(struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_size_bridges); -void pci_bus_assign_resources(struct pci_bus *bus) +void __devinit +pci_bus_assign_resources(struct pci_bus *bus) { struct pci_bus *b; struct pci_dev *dev; diff --git a/trunk/drivers/pci/setup-res.c b/trunk/drivers/pci/setup-res.c index 6dfd86167e39..cb4ced3560e9 100644 --- a/trunk/drivers/pci/setup-res.c +++ b/trunk/drivers/pci/setup-res.c @@ -101,7 +101,8 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) new & ~PCI_REGION_FLAG_MASK); } -int pci_claim_resource(struct pci_dev *dev, int resource) +int __devinit +pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; struct resource *root = NULL; @@ -211,7 +212,8 @@ EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); #endif /* Sort resources by alignment */ -void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) +void __devinit +pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) { int i; diff --git a/trunk/drivers/pcmcia/cs.c b/trunk/drivers/pcmcia/cs.c index 50cad3a59a6c..ac004248324a 100644 --- a/trunk/drivers/pcmcia/cs.c +++ b/trunk/drivers/pcmcia/cs.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/pcmcia/socket_sysfs.c b/trunk/drivers/pcmcia/socket_sysfs.c index a2bb46526b56..ea5765c3bdc0 100644 --- a/trunk/drivers/pcmcia/socket_sysfs.c +++ b/trunk/drivers/pcmcia/socket_sysfs.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/pnp/card.c b/trunk/drivers/pnp/card.c index dd6384b1efce..91c047a7e635 100644 --- a/trunk/drivers/pnp/card.c +++ b/trunk/drivers/pnp/card.c @@ -311,6 +311,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char return NULL; found: + down_write(&dev->dev.bus->subsys.rwsem); dev->card_link = clink; dev->dev.driver = &drv->link.driver; if (pnp_bus_type.probe(&dev->dev)) @@ -318,11 +319,14 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char if (device_bind_driver(&dev->dev)) goto err_out; + up_write(&dev->dev.bus->subsys.rwsem); + return dev; err_out: dev->dev.driver = NULL; dev->card_link = NULL; + up_write(&dev->dev.bus->subsys.rwsem); return NULL; } @@ -336,9 +340,11 @@ void pnp_release_card_device(struct pnp_dev * dev) struct pnp_card_driver * drv = dev->card_link->driver; if (!drv) return; + down_write(&dev->dev.bus->subsys.rwsem); drv->link.remove = &card_remove; device_release_driver(&dev->dev); drv->link.remove = &card_remove_first; + up_write(&dev->dev.bus->subsys.rwsem); } /* diff --git a/trunk/drivers/ps3/ps3av.c b/trunk/drivers/ps3/ps3av.c index 1393e64335f9..d21e04ccb021 100644 --- a/trunk/drivers/ps3/ps3av.c +++ b/trunk/drivers/ps3/ps3av.c @@ -38,24 +38,7 @@ static int timeout = 5000; /* in msec ( 5 sec ) */ module_param(timeout, int, 0644); -static struct ps3av { - int available; - struct mutex mutex; - struct work_struct work; - struct completion done; - struct workqueue_struct *wq; - int open_count; - struct ps3_vuart_port_device *dev; - - int region; - struct ps3av_pkt_av_get_hw_conf av_hw_conf; - u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; - u32 opt_port[PS3AV_OPT_PORT_MAX]; - u32 head[PS3AV_HEAD_MAX]; - u32 audio_port; - int ps3av_mode; - int ps3av_mode_old; -} ps3av; +static struct ps3av ps3av; static struct ps3_vuart_port_device ps3av_dev = { .match_id = PS3_MATCH_ID_AV_SETTINGS @@ -176,7 +159,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) else printk(KERN_ERR "%s: failed event packet, cid:%08x size:%d\n", - __func__, hdr->cid, hdr->size); + __FUNCTION__, hdr->cid, hdr->size); return 1; /* receive event packet */ } return 0; @@ -198,7 +181,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res < 0) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_write() failed (result=%d)\n", - __func__, res); + __FUNCTION__, res); return res; } @@ -211,7 +194,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res != PS3AV_HDR_SIZE) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_read() failed (result=%d)\n", - __func__, res); + __FUNCTION__, res); return res; } @@ -221,7 +204,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res < 0) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_read() failed (result=%d)\n", - __func__, res); + __FUNCTION__, res); return res; } res += PS3AV_HDR_SIZE; /* total len */ @@ -231,7 +214,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", - __func__, recv_buf->cid); + __FUNCTION__, recv_buf->cid); return -EINVAL; } @@ -267,7 +250,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, struct ps3av_send_hdr *buf) { int res = 0; - static union { + union { struct ps3av_reply_hdr reply_hdr; u8 raw[PS3AV_BUF_SIZE]; } recv_buf; @@ -276,7 +259,8 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, BUG_ON(!ps3av.available); - mutex_lock(&ps3av.mutex); + if (down_interruptible(&ps3av.sem)) + return -ERESTARTSYS; table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); BUG_ON(!table); @@ -293,7 +277,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, if (res < 0) { printk(KERN_ERR "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", - __func__, res); + __FUNCTION__, res); goto err; } @@ -302,16 +286,16 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, usr_buf_size); if (res < 0) { printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", - __func__, res); + __FUNCTION__, res); goto err; } - mutex_unlock(&ps3av.mutex); + up(&ps3av.sem); return 0; err: - mutex_unlock(&ps3av.mutex); - printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); + up(&ps3av.sem); + printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res); return res; } @@ -456,7 +440,7 @@ static int ps3av_set_videomode(void) ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); /* wake up ps3avd to do the actual video mode setting */ - queue_work(ps3av.wq, &ps3av.work); + up(&ps3av.ping); return 0; } @@ -522,7 +506,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) if (res == PS3AV_STATUS_NO_SYNC_HEAD) printk(KERN_WARNING "%s: Command failed. Please try your request again. \n", - __func__); + __FUNCTION__); else if (res) dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); @@ -531,10 +515,18 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); } -static void ps3avd(struct work_struct *work) +static int ps3avd(void *p) { - ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old); - complete(&ps3av.done); + struct ps3av *info = p; + + daemonize("ps3avd"); + while (1) { + down(&info->ping); + ps3av_set_videomode_cont(info->ps3av_mode, + info->ps3av_mode_old); + up(&info->pong); + } + return 0; } static int ps3av_vid2table_id(int vid) @@ -715,7 +707,8 @@ int ps3av_set_video_mode(u32 id, int boot) size = ARRAY_SIZE(video_mode_table); if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { - dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id); + dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__, + id); return -EINVAL; } @@ -724,14 +717,15 @@ int ps3av_set_video_mode(u32 id, int boot) if ((id & PS3AV_MODE_MASK) == 0) { id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); if (id < 1) { - printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); + printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__, + id); return -EINVAL; } id |= option; } /* set videomode */ - wait_for_completion(&ps3av.done); + down(&ps3av.pong); ps3av.ps3av_mode_old = ps3av.ps3av_mode; ps3av.ps3av_mode = id; if (ps3av_set_videomode()) @@ -742,13 +736,6 @@ int ps3av_set_video_mode(u32 id, int boot) EXPORT_SYMBOL_GPL(ps3av_set_video_mode); -int ps3av_get_auto_mode(int boot) -{ - return ps3av_auto_videomode(&ps3av.av_hw_conf, boot); -} - -EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); - int ps3av_set_mode(u32 id, int boot) { int res; @@ -784,7 +771,7 @@ int ps3av_get_scanmode(int id) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); return -EINVAL; } return video_mode_table[id].interlace; @@ -799,7 +786,7 @@ int ps3av_get_refresh_rate(int id) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); return -EINVAL; } return video_mode_table[id].freq; @@ -815,7 +802,7 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); return -EINVAL; } *xres = video_mode_table[id].x; @@ -851,7 +838,7 @@ int ps3av_dev_open(void) status = lv1_gpu_open(0); if (status) { printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", - __func__, status); + __FUNCTION__, status); ps3av.open_count--; } } @@ -868,13 +855,13 @@ int ps3av_dev_close(void) mutex_lock(&ps3av.mutex); if (ps3av.open_count <= 0) { - printk(KERN_ERR "%s: GPU already closed\n", __func__); + printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__); status = -1; } else if (!--ps3av.open_count) { status = lv1_gpu_close(); if (status) printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", - __func__, status); + __FUNCTION__, status); } mutex_unlock(&ps3av.mutex); @@ -893,16 +880,13 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev) memset(&ps3av, 0, sizeof(ps3av)); + init_MUTEX(&ps3av.sem); + init_MUTEX_LOCKED(&ps3av.ping); + init_MUTEX(&ps3av.pong); mutex_init(&ps3av.mutex); ps3av.ps3av_mode = 0; ps3av.dev = dev; - - INIT_WORK(&ps3av.work, ps3avd); - init_completion(&ps3av.done); - complete(&ps3av.done); - ps3av.wq = create_singlethread_workqueue("ps3avd"); - if (!ps3av.wq) - return -ENOMEM; + kernel_thread(ps3avd, &ps3av, CLONE_KERNEL); ps3av.available = 1; switch (ps3_os_area_get_av_multi_out()) { @@ -924,7 +908,7 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev) /* init avsetting modules */ res = ps3av_cmd_init(); if (res < 0) - printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, + printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__, res); ps3av_get_hw_conf(&ps3av); @@ -942,8 +926,6 @@ static int ps3av_remove(struct ps3_vuart_port_device *dev) { if (ps3av.available) { ps3av_cmd_fin(); - if (ps3av.wq) - destroy_workqueue(ps3av.wq); ps3av.available = 0; } @@ -976,7 +958,7 @@ static int ps3av_module_init(void) if (error) { printk(KERN_ERR "%s: ps3_vuart_port_driver_register failed %d\n", - __func__, error); + __FUNCTION__, error); return error; } @@ -984,7 +966,7 @@ static int ps3av_module_init(void) if (error) printk(KERN_ERR "%s: ps3_vuart_port_device_register failed %d\n", - __func__, error); + __FUNCTION__, error); return error; } diff --git a/trunk/drivers/ps3/ps3av_cmd.c b/trunk/drivers/ps3/ps3av_cmd.c index 0145ea173c42..bc70e81f8cb0 100644 --- a/trunk/drivers/ps3/ps3av_cmd.c +++ b/trunk/drivers/ps3/ps3av_cmd.c @@ -395,7 +395,7 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt, video_mode->video_order = ps3av_video_fmt_table[video_fmt].order; pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n", - __func__, video_vid, video_mode->width, video_mode->height, + __FUNCTION__, video_vid, video_mode->width, video_mode->height, video_mode->pitch, video_mode->video_out_format, video_mode->video_format, video_mode->video_order); return sizeof(*video_mode); @@ -477,7 +477,7 @@ static u8 ps3av_cnv_mclk(u32 fs) if (ps3av_cnv_mclk_table[i].fs == fs) return ps3av_cnv_mclk_table[i].mclk; - printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs); + printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); return 0; } @@ -526,12 +526,13 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) d = 4; break; default: - printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid); + printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__, + video_vid); break; } if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K) - printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs); + printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); else ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; @@ -554,7 +555,8 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable) ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) | 0x01; } else - printk(KERN_ERR "%s failed, source:%x\n", __func__, source); + printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__, + source); return ret; } @@ -583,7 +585,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits) ret = PS3AV_CMD_AV_INPUTLEN_24; break; default: - printk(KERN_ERR "%s failed, word_bits:%x\n", __func__, + printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__, word_bits); break; } @@ -593,7 +595,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits) static u8 ps3av_cnv_layout(u32 num_of_ch) { if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) { - printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__, + printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__, num_of_ch); return 0; } @@ -862,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) res = get_status(avb); if (res) - pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__, + pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__, res); out: @@ -1011,7 +1013,7 @@ int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, return size; if (error != -EAGAIN) { printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", - __func__, error); + __FUNCTION__, error); return error; } msleep(POLLING_INTERVAL); diff --git a/trunk/drivers/ps3/vuart.c b/trunk/drivers/ps3/vuart.c index 7d7cab1d91b4..6c12744eeb9d 100644 --- a/trunk/drivers/ps3/vuart.c +++ b/trunk/drivers/ps3/vuart.c @@ -82,6 +82,14 @@ struct ports_bmp { u64 unused[3]; } __attribute__ ((aligned (32))); +/* redefine dev_dbg to do a syntax check */ + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) static void __attribute__ ((unused)) _dump_ports_bmp( const struct ports_bmp* bmp, const char* func, int line) diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index 977521013fe8..eb5dc62f0d9c 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -398,9 +398,6 @@ dasd_change_state(struct dasd_device *device) if (device->state == device->target) wake_up(&dasd_init_waitq); - - /* let user-space know that the device status changed */ - kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); } /* @@ -2174,51 +2171,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event) return ret; } -struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device, - void *rdc_buffer, - int rdc_buffer_size, char *magic) -{ - struct dasd_ccw_req *cqr; - struct ccw1 *ccw; - - cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device); - - if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Could not allocate RDC request"); - return cqr; - } - - ccw = cqr->cpaddr; - ccw->cmd_code = CCW_CMD_RDC; - ccw->cda = (__u32)(addr_t)rdc_buffer; - ccw->count = rdc_buffer_size; - - cqr->device = device; - cqr->expires = 10*HZ; - clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); - cqr->retries = 2; - cqr->buildclk = get_clock(); - cqr->status = DASD_CQR_FILLED; - return cqr; -} - - -int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, - void **rdc_buffer, int rdc_buffer_size) -{ - int ret; - struct dasd_ccw_req *cqr; - - cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size, - magic); - if (IS_ERR(cqr)) - return PTR_ERR(cqr); - - ret = dasd_sleep_on(cqr); - dasd_sfree_request(cqr, cqr->device); - return ret; -} static int __init dasd_init(void) diff --git a/trunk/drivers/s390/block/dasd_devmap.c b/trunk/drivers/s390/block/dasd_devmap.c index 6a89cefe99bb..ed70852cc915 100644 --- a/trunk/drivers/s390/block/dasd_devmap.c +++ b/trunk/drivers/s390/block/dasd_devmap.c @@ -19,7 +19,6 @@ #include #include -#include /* This is ugly... */ #define PRINTK_HEADER "dasd_devmap:" @@ -134,8 +133,6 @@ dasd_call_setup(char *str) __setup ("dasd=", dasd_call_setup); #endif /* #ifndef MODULE */ -#define DASD_IPLDEV "ipldev" - /* * Read a device busid/devno from a string. */ @@ -144,20 +141,6 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; - /* Interpret ipldev busid */ - if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) { - if (ipl_info.type != IPL_TYPE_CCW) { - MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw " - "device"); - return -EINVAL; - } - *id0 = 0; - *id1 = ipl_info.data.ccw.dev_id.ssid; - *devno = ipl_info.data.ccw.dev_id.devno; - *str += strlen(DASD_IPLDEV); - - return 0; - } /* check for leading '0x' */ old_style = 0; if ((*str)[0] == '0' && (*str)[1] == 'x') { @@ -845,46 +828,6 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); -static ssize_t -dasd_device_status_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct dasd_device *device; - ssize_t len; - - device = dasd_device_from_cdev(to_ccwdev(dev)); - if (!IS_ERR(device)) { - switch (device->state) { - case DASD_STATE_NEW: - len = snprintf(buf, PAGE_SIZE, "new\n"); - break; - case DASD_STATE_KNOWN: - len = snprintf(buf, PAGE_SIZE, "detected\n"); - break; - case DASD_STATE_BASIC: - len = snprintf(buf, PAGE_SIZE, "basic\n"); - break; - case DASD_STATE_UNFMT: - len = snprintf(buf, PAGE_SIZE, "unformatted\n"); - break; - case DASD_STATE_READY: - len = snprintf(buf, PAGE_SIZE, "ready\n"); - break; - case DASD_STATE_ONLINE: - len = snprintf(buf, PAGE_SIZE, "online\n"); - break; - default: - len = snprintf(buf, PAGE_SIZE, "no stat\n"); - break; - } - dasd_put_device(device); - } else - len = snprintf(buf, PAGE_SIZE, "unknown\n"); - return len; -} - -static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); - static ssize_t dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -996,7 +939,6 @@ static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); static struct attribute * dasd_attrs[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, - &dev_attr_status.attr, &dev_attr_alias.attr, &dev_attr_vendor.attr, &dev_attr_uid.attr, diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index c9583fbc2a7d..cecab2274a6e 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -450,81 +450,6 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) return 0; } -struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device, - void *rcd_buffer, - struct ciw *ciw, __u8 lpm) -{ - struct dasd_ccw_req *cqr; - struct ccw1 *ccw; - - cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device); - - if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Could not allocate RCD request"); - return cqr; - } - - ccw = cqr->cpaddr; - ccw->cmd_code = ciw->cmd; - ccw->cda = (__u32)(addr_t)rcd_buffer; - ccw->count = ciw->count; - - cqr->device = device; - cqr->expires = 10*HZ; - cqr->lpm = lpm; - clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); - cqr->retries = 2; - cqr->buildclk = get_clock(); - cqr->status = DASD_CQR_FILLED; - return cqr; -} - -static int dasd_eckd_read_conf_lpm(struct dasd_device *device, - void **rcd_buffer, - int *rcd_buffer_size, __u8 lpm) -{ - struct ciw *ciw; - char *rcd_buf = NULL; - int ret; - struct dasd_ccw_req *cqr; - - /* - * scan for RCD command in extended SenseID data - */ - ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); - if (!ciw || ciw->cmd == 0) { - ret = -EOPNOTSUPP; - goto out_error; - } - rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); - if (!rcd_buf) { - ret = -ENOMEM; - goto out_error; - } - cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); - if (IS_ERR(cqr)) { - ret = PTR_ERR(cqr); - goto out_error; - } - ret = dasd_sleep_on(cqr); - /* - * on success we update the user input parms - */ - dasd_sfree_request(cqr, cqr->device); - if (ret) - goto out_error; - - *rcd_buffer_size = ciw->count; - *rcd_buffer = rcd_buf; - return 0; -out_error: - kfree(rcd_buf); - *rcd_buffer = NULL; - *rcd_buffer_size = 0; - return ret; -} - static int dasd_eckd_read_conf(struct dasd_device *device) { @@ -544,8 +469,8 @@ dasd_eckd_read_conf(struct dasd_device *device) /* get configuration data per operational path */ for (lpm = 0x80; lpm; lpm>>= 1) { if (lpm & path_data->opm){ - rc = dasd_eckd_read_conf_lpm(device, &conf_data, - &conf_len, lpm); + rc = read_conf_data_lpm(device->cdev, &conf_data, + &conf_len, lpm); if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ MESSAGE(KERN_WARNING, "Read configuration data returned " @@ -714,7 +639,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); memset(rdc_data, 0, sizeof(rdc_data)); - rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); + rc = read_dev_chars(device->cdev, &rdc_data, 64); if (rc) DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned " diff --git a/trunk/drivers/s390/block/dasd_fba.c b/trunk/drivers/s390/block/dasd_fba.c index da16ead8aff2..be0909e39226 100644 --- a/trunk/drivers/s390/block/dasd_fba.c +++ b/trunk/drivers/s390/block/dasd_fba.c @@ -135,7 +135,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) } /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); - rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); + rc = read_dev_chars(device->cdev, &rdc_data, 32); if (rc) { DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned error %d", diff --git a/trunk/drivers/s390/block/dasd_int.h b/trunk/drivers/s390/block/dasd_int.h index 241294cba415..a2cc69e11410 100644 --- a/trunk/drivers/s390/block/dasd_int.h +++ b/trunk/drivers/s390/block/dasd_int.h @@ -509,8 +509,6 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); -int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); - /* externals in dasd_devmap.c */ extern int dasd_max_devindex; extern int dasd_probeonly; diff --git a/trunk/drivers/s390/char/Makefile b/trunk/drivers/s390/char/Makefile index c210784bdf46..293e667b50f2 100644 --- a/trunk/drivers/s390/char/Makefile +++ b/trunk/drivers/s390/char/Makefile @@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o sclp_config.o sclp_chp.o + sclp_info.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o @@ -29,6 +29,3 @@ obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o obj-$(CONFIG_MONREADER) += monreader.o obj-$(CONFIG_MONWRITER) += monwriter.o - -zcore_mod-objs := sclp_sdias.o zcore.o -obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o diff --git a/trunk/drivers/s390/char/con3215.c b/trunk/drivers/s390/char/con3215.c index 6000bdee4082..9a328f14a641 100644 --- a/trunk/drivers/s390/char/con3215.c +++ b/trunk/drivers/s390/char/con3215.c @@ -813,6 +813,12 @@ con3215_unblank(void) spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } +static int __init +con3215_consetup(struct console *co, char *options) +{ + return 0; +} + /* * The console structure for the 3215 console */ @@ -821,6 +827,7 @@ static struct console con3215 = { .write = con3215_write, .device = con3215_device, .unblank = con3215_unblank, + .setup = con3215_consetup, .flags = CON_PRINTBUFFER, }; diff --git a/trunk/drivers/s390/char/con3270.c b/trunk/drivers/s390/char/con3270.c index fd3479119eb4..8e7f2d7633d6 100644 --- a/trunk/drivers/s390/char/con3270.c +++ b/trunk/drivers/s390/char/con3270.c @@ -555,6 +555,12 @@ con3270_unblank(void) spin_unlock_irqrestore(&cp->view.lock, flags); } +static int __init +con3270_consetup(struct console *co, char *options) +{ + return 0; +} + /* * The console structure for the 3270 console */ @@ -563,6 +569,7 @@ static struct console con3270 = { .write = con3270_write, .device = con3270_device, .unblank = con3270_unblank, + .setup = con3270_consetup, .flags = CON_PRINTBUFFER, }; diff --git a/trunk/drivers/s390/char/sclp.c b/trunk/drivers/s390/char/sclp.c index fa62e6944057..f171de3b0b11 100644 --- a/trunk/drivers/s390/char/sclp.c +++ b/trunk/drivers/s390/char/sclp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -511,7 +510,7 @@ sclp_state_change_cb(struct evbuf_header *evbuf) } static struct sclp_register sclp_state_change_event = { - .receive_mask = EVTYP_STATECHANGE_MASK, + .receive_mask = EvTyp_StateChange_Mask, .receiver_fn = sclp_state_change_cb }; @@ -931,10 +930,3 @@ sclp_init(void) sclp_init_mask(1); return 0; } - -static __init int sclp_initcall(void) -{ - return sclp_init(); -} - -arch_initcall(sclp_initcall); diff --git a/trunk/drivers/s390/char/sclp.h b/trunk/drivers/s390/char/sclp.h index 87ac4a3ad49d..7d29ab45a6ed 100644 --- a/trunk/drivers/s390/char/sclp.h +++ b/trunk/drivers/s390/char/sclp.h @@ -19,37 +19,33 @@ #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) #define MAX_CONSOLE_PAGES 4 -#define EVTYP_OPCMD 0x01 -#define EVTYP_MSG 0x02 -#define EVTYP_STATECHANGE 0x08 -#define EVTYP_PMSGCMD 0x09 -#define EVTYP_CNTLPROGOPCMD 0x20 -#define EVTYP_CNTLPROGIDENT 0x0B -#define EVTYP_SIGQUIESCE 0x1D -#define EVTYP_VT220MSG 0x1A -#define EVTYP_CONFMGMDATA 0x04 -#define EVTYP_SDIAS 0x1C - -#define EVTYP_OPCMD_MASK 0x80000000 -#define EVTYP_MSG_MASK 0x40000000 -#define EVTYP_STATECHANGE_MASK 0x01000000 -#define EVTYP_PMSGCMD_MASK 0x00800000 -#define EVTYP_CTLPROGOPCMD_MASK 0x00000001 -#define EVTYP_CTLPROGIDENT_MASK 0x00200000 -#define EVTYP_SIGQUIESCE_MASK 0x00000008 -#define EVTYP_VT220MSG_MASK 0x00000040 -#define EVTYP_CONFMGMDATA_MASK 0x10000000 -#define EVTYP_SDIAS_MASK 0x00000010 - -#define GNRLMSGFLGS_DOM 0x8000 -#define GNRLMSGFLGS_SNDALRM 0x4000 -#define GNRLMSGFLGS_HOLDMSG 0x2000 - -#define LNTPFLGS_CNTLTEXT 0x8000 -#define LNTPFLGS_LABELTEXT 0x4000 -#define LNTPFLGS_DATATEXT 0x2000 -#define LNTPFLGS_ENDTEXT 0x1000 -#define LNTPFLGS_PROMPTTEXT 0x0800 +#define EvTyp_OpCmd 0x01 +#define EvTyp_Msg 0x02 +#define EvTyp_StateChange 0x08 +#define EvTyp_PMsgCmd 0x09 +#define EvTyp_CntlProgOpCmd 0x20 +#define EvTyp_CntlProgIdent 0x0B +#define EvTyp_SigQuiesce 0x1D +#define EvTyp_VT220Msg 0x1A + +#define EvTyp_OpCmd_Mask 0x80000000 +#define EvTyp_Msg_Mask 0x40000000 +#define EvTyp_StateChange_Mask 0x01000000 +#define EvTyp_PMsgCmd_Mask 0x00800000 +#define EvTyp_CtlProgOpCmd_Mask 0x00000001 +#define EvTyp_CtlProgIdent_Mask 0x00200000 +#define EvTyp_SigQuiesce_Mask 0x00000008 +#define EvTyp_VT220Msg_Mask 0x00000040 + +#define GnrlMsgFlgs_DOM 0x8000 +#define GnrlMsgFlgs_SndAlrm 0x4000 +#define GnrlMsgFlgs_HoldMsg 0x2000 + +#define LnTpFlgs_CntlText 0x8000 +#define LnTpFlgs_LabelText 0x4000 +#define LnTpFlgs_DataText 0x2000 +#define LnTpFlgs_EndText 0x1000 +#define LnTpFlgs_PromptText 0x0800 typedef unsigned int sclp_cmdw_t; @@ -60,15 +56,15 @@ typedef unsigned int sclp_cmdw_t; #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define GDS_ID_MDSMU 0x1310 -#define GDS_ID_MDSROUTEINFO 0x1311 -#define GDS_ID_AGUNWRKCORR 0x1549 -#define GDS_ID_SNACONDREPORT 0x1532 +#define GDS_ID_MDSRouteInfo 0x1311 +#define GDS_ID_AgUnWrkCorr 0x1549 +#define GDS_ID_SNACondReport 0x1532 #define GDS_ID_CPMSU 0x1212 -#define GDS_ID_ROUTTARGINSTR 0x154D -#define GDS_ID_OPREQ 0x8070 -#define GDS_ID_TEXTCMD 0x1320 +#define GDS_ID_RoutTargInstr 0x154D +#define GDS_ID_OpReq 0x8070 +#define GDS_ID_TextCmd 0x1320 -#define GDS_KEY_SELFDEFTEXTMSG 0x31 +#define GDS_KEY_SelfDefTextMsg 0x31 typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ diff --git a/trunk/drivers/s390/char/sclp_chp.c b/trunk/drivers/s390/char/sclp_chp.c deleted file mode 100644 index a66b914519b5..000000000000 --- a/trunk/drivers/s390/char/sclp_chp.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * drivers/s390/char/sclp_chp.c - * - * Copyright IBM Corp. 2007 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include - -#include "sclp.h" - -#define TAG "sclp_chp: " - -#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH 0x000f0001 -#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH 0x000e0001 -#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION 0x00030001 - -static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid) -{ - return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8; -} - -static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid) -{ - return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8; -} - -static void chp_callback(struct sclp_req *req, void *data) -{ - struct completion *completion = data; - - complete(completion); -} - -struct chp_cfg_sccb { - struct sccb_header header; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - -struct chp_cfg_data { - struct chp_cfg_sccb sccb; - struct sclp_req req; - struct completion completion; -} __attribute__((packed)); - -static int do_configure(sclp_cmdw_t cmd) -{ - struct chp_cfg_data *data; - int rc; - - /* Prepare sccb. */ - data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!data) - return -ENOMEM; - data->sccb.header.length = sizeof(struct chp_cfg_sccb); - data->req.command = cmd; - data->req.sccb = &(data->sccb); - data->req.status = SCLP_REQ_FILLED; - data->req.callback = chp_callback; - data->req.callback_data = &(data->completion); - init_completion(&data->completion); - - /* Perform sclp request. */ - rc = sclp_add_request(&(data->req)); - if (rc) - goto out; - wait_for_completion(&data->completion); - - /* Check response .*/ - if (data->req.status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "configure channel-path request failed " - "(status=0x%02x)\n", data->req.status); - rc = -EIO; - goto out; - } - switch (data->sccb.header.response_code) { - case 0x0020: - case 0x0120: - case 0x0440: - case 0x0450: - break; - default: - printk(KERN_WARNING TAG "configure channel-path failed " - "(cmd=0x%08x, response=0x%04x)\n", cmd, - data->sccb.header.response_code); - rc = -EIO; - break; - } -out: - free_page((unsigned long) data); - - return rc; -} - -/** - * sclp_chp_configure - perform configure channel-path sclp command - * @chpid: channel-path ID - * - * Perform configure channel-path command sclp command for specified chpid. - * Return 0 after command successfully finished, non-zero otherwise. - */ -int sclp_chp_configure(struct chp_id chpid) -{ - return do_configure(get_configure_cmdw(chpid)); -} - -/** - * sclp_chp_deconfigure - perform deconfigure channel-path sclp command - * @chpid: channel-path ID - * - * Perform deconfigure channel-path command sclp command for specified chpid - * and wait for completion. On success return 0. Return non-zero otherwise. - */ -int sclp_chp_deconfigure(struct chp_id chpid) -{ - return do_configure(get_deconfigure_cmdw(chpid)); -} - -struct chp_info_sccb { - struct sccb_header header; - u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; - u8 standby[SCLP_CHP_INFO_MASK_SIZE]; - u8 configured[SCLP_CHP_INFO_MASK_SIZE]; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - -struct chp_info_data { - struct chp_info_sccb sccb; - struct sclp_req req; - struct completion completion; -} __attribute__((packed)); - -/** - * sclp_chp_read_info - perform read channel-path information sclp command - * @info: resulting channel-path information data - * - * Perform read channel-path information sclp command and wait for completion. - * On success, store channel-path information in @info and return 0. Return - * non-zero otherwise. - */ -int sclp_chp_read_info(struct sclp_chp_info *info) -{ - struct chp_info_data *data; - int rc; - - /* Prepare sccb. */ - data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!data) - return -ENOMEM; - data->sccb.header.length = sizeof(struct chp_info_sccb); - data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION; - data->req.sccb = &(data->sccb); - data->req.status = SCLP_REQ_FILLED; - data->req.callback = chp_callback; - data->req.callback_data = &(data->completion); - init_completion(&data->completion); - - /* Perform sclp request. */ - rc = sclp_add_request(&(data->req)); - if (rc) - goto out; - wait_for_completion(&data->completion); - - /* Check response .*/ - if (data->req.status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "read channel-path info request failed " - "(status=0x%02x)\n", data->req.status); - rc = -EIO; - goto out; - } - if (data->sccb.header.response_code != 0x0010) { - printk(KERN_WARNING TAG "read channel-path info failed " - "(response=0x%04x)\n", data->sccb.header.response_code); - rc = -EIO; - goto out; - } - memcpy(info->recognized, data->sccb.recognized, - SCLP_CHP_INFO_MASK_SIZE); - memcpy(info->standby, data->sccb.standby, - SCLP_CHP_INFO_MASK_SIZE); - memcpy(info->configured, data->sccb.configured, - SCLP_CHP_INFO_MASK_SIZE); -out: - free_page((unsigned long) data); - - return rc; -} diff --git a/trunk/drivers/s390/char/sclp_config.c b/trunk/drivers/s390/char/sclp_config.c deleted file mode 100644 index 5322e5e54a98..000000000000 --- a/trunk/drivers/s390/char/sclp_config.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * drivers/s390/char/sclp_config.c - * - * Copyright IBM Corp. 2007 - * Author(s): Heiko Carstens - */ - -#include -#include -#include -#include -#include -#include "sclp.h" - -#define TAG "sclp_config: " - -struct conf_mgm_data { - u8 reserved; - u8 ev_qualifier; -} __attribute__((packed)); - -#define EV_QUAL_CAP_CHANGE 3 - -static struct work_struct sclp_cpu_capability_work; - -static void sclp_cpu_capability_notify(struct work_struct *work) -{ - int cpu; - struct sys_device *sysdev; - - printk(KERN_WARNING TAG "cpu capability changed.\n"); - lock_cpu_hotplug(); - for_each_online_cpu(cpu) { - sysdev = get_cpu_sysdev(cpu); - kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); - } - unlock_cpu_hotplug(); -} - -static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) -{ - struct conf_mgm_data *cdata; - - cdata = (struct conf_mgm_data *)(evbuf + 1); - if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE) - schedule_work(&sclp_cpu_capability_work); -} - -static struct sclp_register sclp_conf_register = -{ - .receive_mask = EVTYP_CONFMGMDATA_MASK, - .receiver_fn = sclp_conf_receiver_fn, -}; - -static int __init sclp_conf_init(void) -{ - int rc; - - INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); - - rc = sclp_register(&sclp_conf_register); - if (rc) { - printk(KERN_ERR TAG "failed to register (%d).\n", rc); - return rc; - } - - if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK)) { - printk(KERN_WARNING TAG "no configuration management.\n"); - sclp_unregister(&sclp_conf_register); - rc = -ENOSYS; - } - return rc; -} - -__initcall(sclp_conf_init); diff --git a/trunk/drivers/s390/char/sclp_cpi.c b/trunk/drivers/s390/char/sclp_cpi.c index 29fe2a5ec2fe..65aa2c85737f 100644 --- a/trunk/drivers/s390/char/sclp_cpi.c +++ b/trunk/drivers/s390/char/sclp_cpi.c @@ -46,7 +46,7 @@ struct cpi_sccb { /* Event type structure for write message and write priority message */ static struct sclp_register sclp_cpi_event = { - .send_mask = EVTYP_CTLPROGIDENT_MASK + .send_mask = EvTyp_CtlProgIdent_Mask }; MODULE_LICENSE("GPL"); @@ -201,7 +201,7 @@ cpi_module_init(void) "console.\n"); return -EINVAL; } - if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) { + if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) { printk(KERN_WARNING "cpi: no control program identification " "support\n"); sclp_unregister(&sclp_cpi_event); diff --git a/trunk/drivers/s390/char/sclp_quiesce.c b/trunk/drivers/s390/char/sclp_quiesce.c index 45ff25e787cb..baa8fe669ed2 100644 --- a/trunk/drivers/s390/char/sclp_quiesce.c +++ b/trunk/drivers/s390/char/sclp_quiesce.c @@ -43,7 +43,7 @@ sclp_quiesce_handler(struct evbuf_header *evbuf) } static struct sclp_register sclp_quiesce_event = { - .receive_mask = EVTYP_SIGQUIESCE_MASK, + .receive_mask = EvTyp_SigQuiesce_Mask, .receiver_fn = sclp_quiesce_handler }; diff --git a/trunk/drivers/s390/char/sclp_rw.c b/trunk/drivers/s390/char/sclp_rw.c index bbd5b8b66f42..2486783ea58e 100644 --- a/trunk/drivers/s390/char/sclp_rw.c +++ b/trunk/drivers/s390/char/sclp_rw.c @@ -30,7 +30,7 @@ /* Event type structure for write message and write priority message */ static struct sclp_register sclp_rw_event = { - .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK + .send_mask = EvTyp_Msg_Mask | EvTyp_PMsgCmd_Mask }; /* @@ -64,7 +64,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab) memset(sccb, 0, sizeof(struct write_sccb)); sccb->header.length = sizeof(struct write_sccb); sccb->msg_buf.header.length = sizeof(struct msg_buf); - sccb->msg_buf.header.type = EVTYP_MSG; + sccb->msg_buf.header.type = EvTyp_Msg; sccb->msg_buf.mdb.header.length = sizeof(struct mdb); sccb->msg_buf.mdb.header.type = 1; sccb->msg_buf.mdb.header.tag = 0xD4C4C240; /* ebcdic "MDB " */ @@ -114,7 +114,7 @@ sclp_initialize_mto(struct sclp_buffer *buffer, int max_len) memset(mto, 0, sizeof(struct mto)); mto->length = sizeof(struct mto); mto->type = 4; /* message text object */ - mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */ + mto->line_type_flags = LnTpFlgs_EndText; /* end text */ /* set pointer to first byte after struct mto. */ buffer->current_line = (char *) (mto + 1); @@ -215,7 +215,7 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count) case '\a': /* bell, one for several times */ /* set SCLP sound alarm bit in General Object */ buffer->sccb->msg_buf.mdb.go.general_msg_flags |= - GNRLMSGFLGS_SNDALRM; + GnrlMsgFlgs_SndAlrm; break; case '\t': /* horizontal tabulator */ /* check if new mto needs to be created */ @@ -452,12 +452,12 @@ sclp_emit_buffer(struct sclp_buffer *buffer, return -EIO; sccb = buffer->sccb; - if (sclp_rw_event.sclp_send_mask & EVTYP_MSG_MASK) + if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask) /* Use normal write message */ - sccb->msg_buf.header.type = EVTYP_MSG; - else if (sclp_rw_event.sclp_send_mask & EVTYP_PMSGCMD_MASK) + sccb->msg_buf.header.type = EvTyp_Msg; + else if (sclp_rw_event.sclp_send_mask & EvTyp_PMsgCmd_Mask) /* Use write priority message */ - sccb->msg_buf.header.type = EVTYP_PMSGCMD; + sccb->msg_buf.header.type = EvTyp_PMsgCmd; else return -ENOSYS; buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; diff --git a/trunk/drivers/s390/char/sclp_sdias.c b/trunk/drivers/s390/char/sclp_sdias.c deleted file mode 100644 index 52283daddaef..000000000000 --- a/trunk/drivers/s390/char/sclp_sdias.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Sclp "store data in absolut storage" - * - * Copyright IBM Corp. 2003,2007 - * Author(s): Michael Holzheu - */ - -#include -#include -#include -#include -#include "sclp.h" -#include "sclp_rw.h" - -#define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) -#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x ) - -#define SDIAS_RETRIES 300 -#define SDIAS_SLEEP_TICKS 50 - -#define EQ_STORE_DATA 0x0 -#define EQ_SIZE 0x1 -#define DI_FCP_DUMP 0x0 -#define ASA_SIZE_32 0x0 -#define ASA_SIZE_64 0x1 -#define EVSTATE_ALL_STORED 0x0 -#define EVSTATE_NO_DATA 0x3 -#define EVSTATE_PART_STORED 0x10 - -static struct debug_info *sdias_dbf; - -static struct sclp_register sclp_sdias_register = { - .send_mask = EVTYP_SDIAS_MASK, -}; - -struct sdias_evbuf { - struct evbuf_header hdr; - u8 event_qual; - u8 data_id; - u64 reserved2; - u32 event_id; - u16 reserved3; - u8 asa_size; - u8 event_status; - u32 reserved4; - u32 blk_cnt; - u64 asa; - u32 reserved5; - u32 fbn; - u32 reserved6; - u32 lbn; - u16 reserved7; - u16 dbs; -} __attribute__((packed)); - -struct sdias_sccb { - struct sccb_header hdr; - struct sdias_evbuf evbuf; -} __attribute__((packed)); - -static struct sdias_sccb sccb __attribute__((aligned(4096))); - -static int sclp_req_done; -static wait_queue_head_t sdias_wq; -static DEFINE_MUTEX(sdias_mutex); - -static void sdias_callback(struct sclp_req *request, void *data) -{ - struct sdias_sccb *sccb; - - sccb = (struct sdias_sccb *) request->sccb; - sclp_req_done = 1; - wake_up(&sdias_wq); /* Inform caller, that request is complete */ - TRACE("callback done\n"); -} - -static int sdias_sclp_send(struct sclp_req *req) -{ - int retries; - int rc; - - for (retries = SDIAS_RETRIES; retries; retries--) { - sclp_req_done = 0; - TRACE("add request\n"); - rc = sclp_add_request(req); - if (rc) { - /* not initiated, wait some time and retry */ - set_current_state(TASK_INTERRUPTIBLE); - TRACE("add request failed: rc = %i\n",rc); - schedule_timeout(SDIAS_SLEEP_TICKS); - continue; - } - /* initiated, wait for completion of service call */ - wait_event(sdias_wq, (sclp_req_done == 1)); - if (req->status == SCLP_REQ_FAILED) { - TRACE("sclp request failed\n"); - rc = -EIO; - continue; - } - TRACE("request done\n"); - break; - } - return rc; -} - -/* - * Get number of blocks (4K) available in the HSA - */ -int sclp_sdias_blk_count(void) -{ - struct sclp_req request; - int rc; - - mutex_lock(&sdias_mutex); - - memset(&sccb, 0, sizeof(sccb)); - memset(&request, 0, sizeof(request)); - - sccb.hdr.length = sizeof(sccb); - sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); - sccb.evbuf.hdr.type = EVTYP_SDIAS; - sccb.evbuf.event_qual = EQ_SIZE; - sccb.evbuf.data_id = DI_FCP_DUMP; - sccb.evbuf.event_id = 4712; - sccb.evbuf.dbs = 1; - - request.sccb = &sccb; - request.command = SCLP_CMDW_WRITE_EVENT_DATA; - request.status = SCLP_REQ_FILLED; - request.callback = sdias_callback; - - rc = sdias_sclp_send(&request); - if (rc) { - ERROR_MSG("sclp_send failed for get_nr_blocks\n"); - goto out; - } - if (sccb.hdr.response_code != 0x0020) { - TRACE("send failed: %x\n", sccb.hdr.response_code); - rc = -EIO; - goto out; - } - - switch (sccb.evbuf.event_status) { - case 0: - rc = sccb.evbuf.blk_cnt; - break; - default: - ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status); - rc = -EIO; - goto out; - } - TRACE("%i blocks\n", rc); -out: - mutex_unlock(&sdias_mutex); - return rc; -} - -/* - * Copy from HSA to absolute storage (not reentrant): - * - * @dest : Address of buffer where data should be copied - * @start_blk: Start Block (beginning with 1) - * @nr_blks : Number of 4K blocks to copy - * - * Return Value: 0 : Requested 'number' of blocks of data copied - * <0: ERROR - negative event status - */ -int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) -{ - struct sclp_req request; - int rc; - - mutex_lock(&sdias_mutex); - - memset(&sccb, 0, sizeof(sccb)); - memset(&request, 0, sizeof(request)); - - sccb.hdr.length = sizeof(sccb); - sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); - sccb.evbuf.hdr.type = EVTYP_SDIAS; - sccb.evbuf.hdr.flags = 0; - sccb.evbuf.event_qual = EQ_STORE_DATA; - sccb.evbuf.data_id = DI_FCP_DUMP; - sccb.evbuf.event_id = 4712; -#ifdef __s390x__ - sccb.evbuf.asa_size = ASA_SIZE_64; -#else - sccb.evbuf.asa_size = ASA_SIZE_32; -#endif - sccb.evbuf.event_status = 0; - sccb.evbuf.blk_cnt = nr_blks; - sccb.evbuf.asa = (unsigned long)dest; - sccb.evbuf.fbn = start_blk; - sccb.evbuf.lbn = 0; - sccb.evbuf.dbs = 1; - - request.sccb = &sccb; - request.command = SCLP_CMDW_WRITE_EVENT_DATA; - request.status = SCLP_REQ_FILLED; - request.callback = sdias_callback; - - rc = sdias_sclp_send(&request); - if (rc) { - ERROR_MSG("sclp_send failed: %x\n", rc); - goto out; - } - if (sccb.hdr.response_code != 0x0020) { - TRACE("copy failed: %x\n", sccb.hdr.response_code); - rc = -EIO; - goto out; - } - - switch (sccb.evbuf.event_status) { - case EVSTATE_ALL_STORED: - TRACE("all stored\n"); - case EVSTATE_PART_STORED: - TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); - break; - case EVSTATE_NO_DATA: - TRACE("no data\n"); - default: - ERROR_MSG("Error from SCLP while copying hsa. " - "Event status = %x\n", - sccb.evbuf.event_status); - rc = -EIO; - } -out: - mutex_unlock(&sdias_mutex); - return rc; -} - -int __init sdias_init(void) -{ - int rc; - - if (ipl_info.type != IPL_TYPE_FCP_DUMP) - return 0; - sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); - debug_register_view(sdias_dbf, &debug_sprintf_view); - debug_set_level(sdias_dbf, 6); - rc = sclp_register(&sclp_sdias_register); - if (rc) { - ERROR_MSG("sclp register failed\n"); - return rc; - } - init_waitqueue_head(&sdias_wq); - TRACE("init done\n"); - return 0; -} - -void __exit sdias_exit(void) -{ - debug_unregister(sdias_dbf); - sclp_unregister(&sclp_sdias_register); -} diff --git a/trunk/drivers/s390/char/sclp_tty.c b/trunk/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..076816b9d528 100644 --- a/trunk/drivers/s390/char/sclp_tty.c +++ b/trunk/drivers/s390/char/sclp_tty.c @@ -648,7 +648,7 @@ sclp_eval_textcmd(struct gds_subvector *start, subvec = start; while (subvec < end) { subvec = find_gds_subvector(subvec, end, - GDS_KEY_SELFDEFTEXTMSG); + GDS_KEY_SelfDefTextMsg); if (!subvec) break; sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1), @@ -664,7 +664,7 @@ sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end) vec = start; while (vec < end) { - vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD); + vec = find_gds_vector(vec, end, GDS_ID_TextCmd); if (!vec) break; sclp_eval_textcmd((struct gds_subvector *)(vec + 1), @@ -703,7 +703,7 @@ sclp_tty_state_change(struct sclp_register *reg) static struct sclp_register sclp_input_event = { - .receive_mask = EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK, + .receive_mask = EvTyp_OpCmd_Mask | EvTyp_PMsgCmd_Mask, .state_change_fn = sclp_tty_state_change, .receiver_fn = sclp_tty_receiver }; diff --git a/trunk/drivers/s390/char/sclp_vt220.c b/trunk/drivers/s390/char/sclp_vt220.c index 726334757bbf..f77dc33b5f8d 100644 --- a/trunk/drivers/s390/char/sclp_vt220.c +++ b/trunk/drivers/s390/char/sclp_vt220.c @@ -99,8 +99,8 @@ static void sclp_vt220_emit_current(void); /* Registration structure for our interest in SCLP event buffers */ static struct sclp_register sclp_vt220_register = { - .send_mask = EVTYP_VT220MSG_MASK, - .receive_mask = EVTYP_VT220MSG_MASK, + .send_mask = EvTyp_VT220Msg_Mask, + .receive_mask = EvTyp_VT220Msg_Mask, .state_change_fn = NULL, .receiver_fn = sclp_vt220_receiver_fn }; @@ -202,7 +202,7 @@ sclp_vt220_callback(struct sclp_req *request, void *data) static int __sclp_vt220_emit(struct sclp_vt220_request *request) { - if (!(sclp_vt220_register.sclp_send_mask & EVTYP_VT220MSG_MASK)) { + if (!(sclp_vt220_register.sclp_send_mask & EvTyp_VT220Msg_Mask)) { request->sclp_req.status = SCLP_REQ_FAILED; return -EIO; } @@ -284,7 +284,7 @@ sclp_vt220_initialize_page(void *page) sccb->header.length = sizeof(struct sclp_vt220_sccb); sccb->header.function_code = SCLP_NORMAL_WRITE; sccb->header.response_code = 0x0000; - sccb->evbuf.type = EVTYP_VT220MSG; + sccb->evbuf.type = EvTyp_VT220Msg; sccb->evbuf.length = sizeof(struct evbuf_header); return request; diff --git a/trunk/drivers/s390/char/tape.h b/trunk/drivers/s390/char/tape.h index 3b52f5c1dbef..bb4ff537729d 100644 --- a/trunk/drivers/s390/char/tape.h +++ b/trunk/drivers/s390/char/tape.h @@ -103,7 +103,6 @@ enum tape_op { TO_CRYPT_OFF, /* Disable encrpytion */ TO_KEKL_SET, /* Set KEK label */ TO_KEKL_QUERY, /* Query KEK label */ - TO_RDC, /* Read device characteristics */ TO_SIZE, /* #entries in tape_op_t */ }; diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c index 7e2b2ab49264..50f5edab83d7 100644 --- a/trunk/drivers/s390/char/tape_3590.c +++ b/trunk/drivers/s390/char/tape_3590.c @@ -788,7 +788,6 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) case TO_SIZE: case TO_KEKL_SET: case TO_KEKL_QUERY: - case TO_RDC: break; } return TAPE_IO_SUCCESS; @@ -1550,26 +1549,6 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, return TAPE_IO_STOP; } - -static int tape_3590_read_dev_chars(struct tape_device *device, - struct tape_3590_rdc_data *rdc_data) -{ - int rc; - struct tape_request *request; - - request = tape_alloc_request(1, sizeof(*rdc_data)); - if (IS_ERR(request)) - return PTR_ERR(request); - request->op = TO_RDC; - tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data), - request->cpdata); - rc = tape_do_io(device, request); - if (rc == 0) - memcpy(rdc_data, request->cpdata, sizeof(*rdc_data)); - tape_free_request(request); - return rc; -} - /* * Setup device function */ @@ -1578,7 +1557,7 @@ tape_3590_setup_device(struct tape_device *device) { int rc; struct tape_3590_disc_data *data; - struct tape_3590_rdc_data *rdc_data; + char *rdc_data; DBF_EVENT(6, "3590 device setup\n"); data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); @@ -1587,12 +1566,12 @@ tape_3590_setup_device(struct tape_device *device) data->read_back_op = READ_PREVIOUS; device->discdata = data; - rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA); + rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA); if (!rdc_data) { rc = -ENOMEM; goto fail_kmalloc; } - rc = tape_3590_read_dev_chars(device, rdc_data); + rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64); if (rc) { DBF_LH(3, "Read device characteristics failed!\n"); goto fail_kmalloc; @@ -1600,7 +1579,7 @@ tape_3590_setup_device(struct tape_device *device) rc = tape_std_assign(device); if (rc) goto fail_rdc_data; - if (rdc_data->data[31] == 0x13) { + if (rdc_data[31] == 0x13) { PRINT_INFO("Device has crypto support\n"); data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; tape_3592_disable_crypt(device); diff --git a/trunk/drivers/s390/char/tape_3590.h b/trunk/drivers/s390/char/tape_3590.h index 4534055f1376..aa5138807af1 100644 --- a/trunk/drivers/s390/char/tape_3590.h +++ b/trunk/drivers/s390/char/tape_3590.h @@ -129,10 +129,6 @@ struct tape_3590_med_sense { char pad2[116]; } __attribute__ ((packed)); -struct tape_3590_rdc_data { - char data[64]; -} __attribute__ ((packed)); - /* Datastructures for 3592 encryption support */ struct tape3592_kekl { diff --git a/trunk/drivers/s390/char/tape_core.c b/trunk/drivers/s390/char/tape_core.c index 2fae6338ee1c..e2a8a1a04bab 100644 --- a/trunk/drivers/s390/char/tape_core.c +++ b/trunk/drivers/s390/char/tape_core.c @@ -73,7 +73,7 @@ const char *tape_op_verbose[TO_SIZE] = [TO_DIS] = "DIS", [TO_ASSIGN] = "ASS", [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON", [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS", - [TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC", + [TO_KEKL_QUERY] = "KLQ", }; static int @@ -911,7 +911,6 @@ __tape_start_request(struct tape_device *device, struct tape_request *request) case TO_ASSIGN: case TO_UNASSIGN: case TO_READ_ATTMSG: - case TO_RDC: if (device->tape_state == TS_INIT) break; if (device->tape_state == TS_UNUSED) diff --git a/trunk/drivers/s390/char/vmlogrdr.c b/trunk/drivers/s390/char/vmlogrdr.c index a5a00e9ae4d0..b87d3b019936 100644 --- a/trunk/drivers/s390/char/vmlogrdr.c +++ b/trunk/drivers/s390/char/vmlogrdr.c @@ -125,7 +125,7 @@ static struct vmlogrdr_priv_t sys_ser[] = { .recording_name = "EREP", .minor_num = 0, .buffer_free = 1, - .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[0].priv_lock), + .priv_lock = SPIN_LOCK_UNLOCKED, .autorecording = 1, .autopurge = 1, }, @@ -134,7 +134,7 @@ static struct vmlogrdr_priv_t sys_ser[] = { .recording_name = "ACCOUNT", .minor_num = 1, .buffer_free = 1, - .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[1].priv_lock), + .priv_lock = SPIN_LOCK_UNLOCKED, .autorecording = 1, .autopurge = 1, }, @@ -143,7 +143,7 @@ static struct vmlogrdr_priv_t sys_ser[] = { .recording_name = "SYMPTOM", .minor_num = 2, .buffer_free = 1, - .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[2].priv_lock), + .priv_lock = SPIN_LOCK_UNLOCKED, .autorecording = 1, .autopurge = 1, } @@ -385,9 +385,6 @@ static int vmlogrdr_release (struct inode *inode, struct file *filp) struct vmlogrdr_priv_t * logptr = filp->private_data; - iucv_path_sever(logptr->path, NULL); - kfree(logptr->path); - logptr->path = NULL; if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) diff --git a/trunk/drivers/s390/char/zcore.c b/trunk/drivers/s390/char/zcore.c deleted file mode 100644 index 89d439316a53..000000000000 --- a/trunk/drivers/s390/char/zcore.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - * zcore module to export memory content and register sets for creating system - * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same - * dump format as s390 standalone dumps. - * - * For more information please refer to Documentation/s390/zfcpdump.txt - * - * Copyright IBM Corp. 2003,2007 - * Author(s): Michael Holzheu - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) -#define MSG(x...) printk( KERN_ALERT x ) -#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x ) - -#define TO_USER 0 -#define TO_KERNEL 1 - -enum arch_id { - ARCH_S390 = 0, - ARCH_S390X = 1, -}; - -/* dump system info */ - -struct sys_info { - enum arch_id arch; - unsigned long sa_base; - u32 sa_size; - int cpu_map[NR_CPUS]; - unsigned long mem_size; - union save_area lc_mask; -}; - -static struct sys_info sys_info; -static struct debug_info *zcore_dbf; -static int hsa_available; -static struct dentry *zcore_dir; -static struct dentry *zcore_file; - -/* - * Copy memory from HSA to kernel or user memory (not reentrant): - * - * @dest: Kernel or user buffer where memory should be copied to - * @src: Start address within HSA where data should be copied - * @count: Size of buffer, which should be copied - * @mode: Either TO_KERNEL or TO_USER - */ -static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) -{ - int offs, blk_num; - static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); - - if (count == 0) - return 0; - - /* copy first block */ - offs = 0; - if ((src % PAGE_SIZE) != 0) { - blk_num = src / PAGE_SIZE + 2; - if (sclp_sdias_copy(buf, blk_num, 1)) { - TRACE("sclp_sdias_copy() failed\n"); - return -EIO; - } - offs = min((PAGE_SIZE - (src % PAGE_SIZE)), count); - if (mode == TO_USER) { - if (copy_to_user((__force __user void*) dest, - buf + (src % PAGE_SIZE), offs)) - return -EFAULT; - } else - memcpy(dest, buf + (src % PAGE_SIZE), offs); - } - if (offs == count) - goto out; - - /* copy middle */ - for (; (offs + PAGE_SIZE) <= count; offs += PAGE_SIZE) { - blk_num = (src + offs) / PAGE_SIZE + 2; - if (sclp_sdias_copy(buf, blk_num, 1)) { - TRACE("sclp_sdias_copy() failed\n"); - return -EIO; - } - if (mode == TO_USER) { - if (copy_to_user((__force __user void*) dest + offs, - buf, PAGE_SIZE)) - return -EFAULT; - } else - memcpy(dest + offs, buf, PAGE_SIZE); - } - if (offs == count) - goto out; - - /* copy last block */ - blk_num = (src + offs) / PAGE_SIZE + 2; - if (sclp_sdias_copy(buf, blk_num, 1)) { - TRACE("sclp_sdias_copy() failed\n"); - return -EIO; - } - if (mode == TO_USER) { - if (copy_to_user((__force __user void*) dest + offs, buf, - PAGE_SIZE)) - return -EFAULT; - } else - memcpy(dest + offs, buf, count - offs); -out: - return 0; -} - -static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) -{ - return memcpy_hsa((void __force *) dest, src, count, TO_USER); -} - -static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) -{ - return memcpy_hsa(dest, src, count, TO_KERNEL); -} - -static int memcpy_real(void *dest, unsigned long src, size_t count) -{ - unsigned long flags; - int rc = -EFAULT; - register unsigned long _dest asm("2") = (unsigned long) dest; - register unsigned long _len1 asm("3") = (unsigned long) count; - register unsigned long _src asm("4") = src; - register unsigned long _len2 asm("5") = (unsigned long) count; - - if (count == 0) - return 0; - flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */ - asm volatile ( - "0: mvcle %1,%2,0x0\n" - "1: jo 0b\n" - " lhi %0,0x0\n" - "2:\n" - EX_TABLE(1b,2b) - : "+d" (rc) - : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2) - : "cc", "memory"); - __raw_local_irq_ssm(flags); - - return rc; -} - -static int memcpy_real_user(__user void *dest, unsigned long src, size_t count) -{ - static char buf[4096]; - int offs = 0, size; - - while (offs < count) { - size = min(sizeof(buf), count - offs); - if (memcpy_real(buf, src + offs, size)) - return -EFAULT; - if (copy_to_user(dest + offs, buf, size)) - return -EFAULT; - offs += size; - } - return 0; -} - -#ifdef __s390x__ -/* - * Convert s390x (64 bit) cpu info to s390 (32 bit) cpu info - */ -static void __init s390x_to_s390_regs(union save_area *out, union save_area *in, - int cpu) -{ - int i; - - for (i = 0; i < 16; i++) { - out->s390.gp_regs[i] = in->s390x.gp_regs[i] & 0x00000000ffffffff; - out->s390.acc_regs[i] = in->s390x.acc_regs[i]; - out->s390.ctrl_regs[i] = - in->s390x.ctrl_regs[i] & 0x00000000ffffffff; - } - /* locore for 31 bit has only space for fpregs 0,2,4,6 */ - out->s390.fp_regs[0] = in->s390x.fp_regs[0]; - out->s390.fp_regs[1] = in->s390x.fp_regs[2]; - out->s390.fp_regs[2] = in->s390x.fp_regs[4]; - out->s390.fp_regs[3] = in->s390x.fp_regs[6]; - memcpy(&(out->s390.psw[0]), &(in->s390x.psw[0]), 4); - out->s390.psw[1] |= 0x8; /* set bit 12 */ - memcpy(&(out->s390.psw[4]),&(in->s390x.psw[12]), 4); - out->s390.psw[4] |= 0x80; /* set (31bit) addressing bit */ - out->s390.pref_reg = in->s390x.pref_reg; - out->s390.timer = in->s390x.timer; - out->s390.clk_cmp = in->s390x.clk_cmp; -} - -static void __init s390x_to_s390_save_areas(void) -{ - int i = 1; - static union save_area tmp; - - while (zfcpdump_save_areas[i]) { - s390x_to_s390_regs(&tmp, zfcpdump_save_areas[i], i); - memcpy(zfcpdump_save_areas[i], &tmp, sizeof(tmp)); - i++; - } -} - -#endif /* __s390x__ */ - -static int __init init_cpu_info(enum arch_id arch) -{ - union save_area *sa; - - /* get info for boot cpu from lowcore, stored in the HSA */ - - sa = kmalloc(sizeof(*sa), GFP_KERNEL); - if (!sa) { - ERROR_MSG("kmalloc failed: %s: %i\n",__FUNCTION__, __LINE__); - return -ENOMEM; - } - if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { - ERROR_MSG("could not copy from HSA\n"); - kfree(sa); - return -EIO; - } - zfcpdump_save_areas[0] = sa; - -#ifdef __s390x__ - /* convert s390x regs to s390, if we are dumping an s390 Linux */ - - if (arch == ARCH_S390) - s390x_to_s390_save_areas(); -#endif - - return 0; -} - -static DEFINE_MUTEX(zcore_mutex); - -#define DUMP_VERSION 0x3 -#define DUMP_MAGIC 0xa8190173618f23fdULL -#define DUMP_ARCH_S390X 2 -#define DUMP_ARCH_S390 1 -#define HEADER_SIZE 4096 - -/* dump header dumped according to s390 crash dump format */ - -struct zcore_header { - u64 magic; - u32 version; - u32 header_size; - u32 dump_level; - u32 page_size; - u64 mem_size; - u64 mem_start; - u64 mem_end; - u32 num_pages; - u32 pad1; - u64 tod; - cpuid_t cpu_id; - u32 arch_id; - u32 build_arch; - char pad2[4016]; -} __attribute__((packed,__aligned__(16))); - -static struct zcore_header zcore_header = { - .magic = DUMP_MAGIC, - .version = DUMP_VERSION, - .header_size = 4096, - .dump_level = 0, - .page_size = PAGE_SIZE, - .mem_start = 0, -#ifdef __s390x__ - .build_arch = DUMP_ARCH_S390X, -#else - .build_arch = DUMP_ARCH_S390, -#endif -}; - -/* - * Copy lowcore info to buffer. Use map in order to copy only register parts. - * - * @buf: User buffer - * @sa: Pointer to save area - * @sa_off: Offset in save area to copy - * @len: Number of bytes to copy - */ -static int copy_lc(void __user *buf, void *sa, int sa_off, int len) -{ - int i; - char *lc_mask = (char*)&sys_info.lc_mask; - - for (i = 0; i < len; i++) { - if (!lc_mask[i + sa_off]) - continue; - if (copy_to_user(buf + i, sa + sa_off + i, 1)) - return -EFAULT; - } - return 0; -} - -/* - * Copy lowcores info to memory, if necessary - * - * @buf: User buffer - * @addr: Start address of buffer in dump memory - * @count: Size of buffer - */ -static int zcore_add_lc(char __user *buf, unsigned long start, size_t count) -{ - unsigned long end; - int i = 0; - - if (count == 0) - return 0; - - end = start + count; - while (zfcpdump_save_areas[i]) { - unsigned long cp_start, cp_end; /* copy range */ - unsigned long sa_start, sa_end; /* save area range */ - unsigned long prefix; - unsigned long sa_off, len, buf_off; - - if (sys_info.arch == ARCH_S390) - prefix = zfcpdump_save_areas[i]->s390.pref_reg; - else - prefix = zfcpdump_save_areas[i]->s390x.pref_reg; - - sa_start = prefix + sys_info.sa_base; - sa_end = prefix + sys_info.sa_base + sys_info.sa_size; - - if ((end < sa_start) || (start > sa_end)) - goto next; - cp_start = max(start, sa_start); - cp_end = min(end, sa_end); - - buf_off = cp_start - start; - sa_off = cp_start - sa_start; - len = cp_end - cp_start; - - TRACE("copy_lc for: %lx\n", start); - if (copy_lc(buf + buf_off, zfcpdump_save_areas[i], sa_off, len)) - return -EFAULT; -next: - i++; - } - return 0; -} - -/* - * Read routine for zcore character device - * First 4K are dump header - * Next 32MB are HSA Memory - * Rest is read from absolute Memory - */ -static ssize_t zcore_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long mem_start; /* Start address in memory */ - size_t mem_offs; /* Offset in dump memory */ - size_t hdr_count; /* Size of header part of output buffer */ - size_t size; - int rc; - - mutex_lock(&zcore_mutex); - - if (*ppos > (sys_info.mem_size + HEADER_SIZE)) { - rc = -EINVAL; - goto fail; - } - - count = min(count, (size_t) (sys_info.mem_size + HEADER_SIZE - *ppos)); - - /* Copy dump header */ - if (*ppos < HEADER_SIZE) { - size = min(count, (size_t) (HEADER_SIZE - *ppos)); - if (copy_to_user(buf, &zcore_header + *ppos, size)) { - rc = -EFAULT; - goto fail; - } - hdr_count = size; - mem_start = 0; - } else { - hdr_count = 0; - mem_start = *ppos - HEADER_SIZE; - } - - mem_offs = 0; - - /* Copy from HSA data */ - if (*ppos < (ZFCPDUMP_HSA_SIZE + HEADER_SIZE)) { - size = min((count - hdr_count), (size_t) (ZFCPDUMP_HSA_SIZE - - mem_start)); - rc = memcpy_hsa_user(buf + hdr_count, mem_start, size); - if (rc) - goto fail; - - mem_offs += size; - } - - /* Copy from real mem */ - size = count - mem_offs - hdr_count; - rc = memcpy_real_user(buf + hdr_count + mem_offs, mem_start + mem_offs, - size); - if (rc) - goto fail; - - /* - * Since s390 dump analysis tools like lcrash or crash - * expect register sets in the prefix pages of the cpus, - * we copy them into the read buffer, if necessary. - * buf + hdr_count: Start of memory part of output buffer - * mem_start: Start memory address to copy from - * count - hdr_count: Size of memory area to copy - */ - if (zcore_add_lc(buf + hdr_count, mem_start, count - hdr_count)) { - rc = -EFAULT; - goto fail; - } - *ppos += count; -fail: - mutex_unlock(&zcore_mutex); - return (rc < 0) ? rc : count; -} - -static int zcore_open(struct inode *inode, struct file *filp) -{ - if (!hsa_available) - return -ENODATA; - else - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; -} - -static int zcore_release(struct inode *inode, struct file *filep) -{ - diag308(DIAG308_REL_HSA, NULL); - hsa_available = 0; - return 0; -} - -static loff_t zcore_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t rc; - - mutex_lock(&zcore_mutex); - switch (orig) { - case 0: - file->f_pos = offset; - rc = file->f_pos; - break; - case 1: - file->f_pos += offset; - rc = file->f_pos; - break; - default: - rc = -EINVAL; - } - mutex_unlock(&zcore_mutex); - return rc; -} - -static struct file_operations zcore_fops = { - .owner = THIS_MODULE, - .llseek = zcore_lseek, - .read = zcore_read, - .open = zcore_open, - .release = zcore_release, -}; - - -static void __init set_s390_lc_mask(union save_area *map) -{ - memset(&map->s390.ext_save, 0xff, sizeof(map->s390.ext_save)); - memset(&map->s390.timer, 0xff, sizeof(map->s390.timer)); - memset(&map->s390.clk_cmp, 0xff, sizeof(map->s390.clk_cmp)); - memset(&map->s390.psw, 0xff, sizeof(map->s390.psw)); - memset(&map->s390.pref_reg, 0xff, sizeof(map->s390.pref_reg)); - memset(&map->s390.acc_regs, 0xff, sizeof(map->s390.acc_regs)); - memset(&map->s390.fp_regs, 0xff, sizeof(map->s390.fp_regs)); - memset(&map->s390.gp_regs, 0xff, sizeof(map->s390.gp_regs)); - memset(&map->s390.ctrl_regs, 0xff, sizeof(map->s390.ctrl_regs)); -} - -static void __init set_s390x_lc_mask(union save_area *map) -{ - memset(&map->s390x.fp_regs, 0xff, sizeof(map->s390x.fp_regs)); - memset(&map->s390x.gp_regs, 0xff, sizeof(map->s390x.gp_regs)); - memset(&map->s390x.psw, 0xff, sizeof(map->s390x.psw)); - memset(&map->s390x.pref_reg, 0xff, sizeof(map->s390x.pref_reg)); - memset(&map->s390x.fp_ctrl_reg, 0xff, sizeof(map->s390x.fp_ctrl_reg)); - memset(&map->s390x.tod_reg, 0xff, sizeof(map->s390x.tod_reg)); - memset(&map->s390x.timer, 0xff, sizeof(map->s390x.timer)); - memset(&map->s390x.clk_cmp, 0xff, sizeof(map->s390x.clk_cmp)); - memset(&map->s390x.acc_regs, 0xff, sizeof(map->s390x.acc_regs)); - memset(&map->s390x.ctrl_regs, 0xff, sizeof(map->s390x.ctrl_regs)); -} - -/* - * Initialize dump globals for a given architecture - */ -static int __init sys_info_init(enum arch_id arch) -{ - switch (arch) { - case ARCH_S390X: - MSG("DETECTED 'S390X (64 bit) OS'\n"); - sys_info.sa_base = SAVE_AREA_BASE_S390X; - sys_info.sa_size = sizeof(struct save_area_s390x); - set_s390x_lc_mask(&sys_info.lc_mask); - break; - case ARCH_S390: - MSG("DETECTED 'S390 (32 bit) OS'\n"); - sys_info.sa_base = SAVE_AREA_BASE_S390; - sys_info.sa_size = sizeof(struct save_area_s390); - set_s390_lc_mask(&sys_info.lc_mask); - break; - default: - ERROR_MSG("unknown architecture 0x%x.\n",arch); - return -EINVAL; - } - sys_info.arch = arch; - if (init_cpu_info(arch)) { - ERROR_MSG("get cpu info failed\n"); - return -ENOMEM; - } - sys_info.mem_size = real_memory_size; - - return 0; -} - -static int __init check_sdias(void) -{ - int rc, act_hsa_size; - - rc = sclp_sdias_blk_count(); - if (rc < 0) { - ERROR_MSG("Could not determine HSA size\n"); - return rc; - } - act_hsa_size = (rc - 1) * PAGE_SIZE; - if (act_hsa_size < ZFCPDUMP_HSA_SIZE) { - ERROR_MSG("HSA size too small: %i\n", act_hsa_size); - return -EINVAL; - } - return 0; -} - -static void __init zcore_header_init(int arch, struct zcore_header *hdr) -{ - if (arch == ARCH_S390X) - hdr->arch_id = DUMP_ARCH_S390X; - else - hdr->arch_id = DUMP_ARCH_S390; - hdr->mem_size = sys_info.mem_size; - hdr->mem_end = sys_info.mem_size; - hdr->num_pages = sys_info.mem_size / PAGE_SIZE; - hdr->tod = get_clock(); - get_cpu_id(&hdr->cpu_id); -} - -extern int sdias_init(void); - -static int __init zcore_init(void) -{ - unsigned char arch; - int rc; - - if (ipl_info.type != IPL_TYPE_FCP_DUMP) - return -ENODATA; - - zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long)); - debug_register_view(zcore_dbf, &debug_sprintf_view); - debug_set_level(zcore_dbf, 6); - - TRACE("devno: %x\n", ipl_info.data.fcp.dev_id.devno); - TRACE("wwpn: %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn); - TRACE("lun: %llx\n", (unsigned long long) ipl_info.data.fcp.lun); - - rc = sdias_init(); - if (rc) - goto fail; - - rc = check_sdias(); - if (rc) { - ERROR_MSG("Dump initialization failed\n"); - goto fail; - } - - rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1); - if (rc) { - ERROR_MSG("sdial memcpy for arch id failed\n"); - goto fail; - } - -#ifndef __s390x__ - if (arch == ARCH_S390X) { - ERROR_MSG("32 bit dumper can't dump 64 bit system!\n"); - rc = -EINVAL; - goto fail; - } -#endif - - rc = sys_info_init(arch); - if (rc) { - ERROR_MSG("arch init failed\n"); - goto fail; - } - - zcore_header_init(arch, &zcore_header); - - zcore_dir = debugfs_create_dir("zcore" , NULL); - if (!zcore_dir) { - rc = -ENOMEM; - goto fail; - } - zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL, - &zcore_fops); - if (!zcore_file) { - debugfs_remove(zcore_dir); - rc = -ENOMEM; - goto fail; - } - hsa_available = 1; - return 0; - -fail: - diag308(DIAG308_REL_HSA, NULL); - return rc; -} - -extern void sdias_exit(void); - -static void __exit zcore_exit(void) -{ - debug_unregister(zcore_dbf); - sdias_exit(); - diag308(DIAG308_REL_HSA, NULL); -} - -MODULE_AUTHOR("Copyright IBM Corp. 2003,2007"); -MODULE_DESCRIPTION("zcore module for zfcpdump support"); -MODULE_LICENSE("GPL"); - -subsys_initcall(zcore_init); -module_exit(zcore_exit); diff --git a/trunk/drivers/s390/cio/Makefile b/trunk/drivers/s390/cio/Makefile index cfaf77b320f5..c490c2a1c2fc 100644 --- a/trunk/drivers/s390/cio/Makefile +++ b/trunk/drivers/s390/cio/Makefile @@ -2,7 +2,7 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o +obj-y += airq.o blacklist.o chsc.o cio.o css.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o diff --git a/trunk/drivers/s390/cio/ccwgroup.c b/trunk/drivers/s390/cio/ccwgroup.c index e5ccda63e883..5aeb68e732b0 100644 --- a/trunk/drivers/s390/cio/ccwgroup.c +++ b/trunk/drivers/s390/cio/ccwgroup.c @@ -75,10 +75,8 @@ static void ccwgroup_ungroup_callback(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - mutex_lock(&gdev->reg_mutex); __ccwgroup_remove_symlinks(gdev); device_unregister(dev); - mutex_unlock(&gdev->reg_mutex); } static ssize_t @@ -175,8 +173,7 @@ ccwgroup_create(struct device *root, return -ENOMEM; atomic_set(&gdev->onoff, 0); - mutex_init(&gdev->reg_mutex); - mutex_lock(&gdev->reg_mutex); + for (i = 0; i < argc; i++) { gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); @@ -186,12 +183,12 @@ ccwgroup_create(struct device *root, || gdev->cdev[i]->id.driver_info != gdev->cdev[0]->id.driver_info) { rc = -EINVAL; - goto error; + goto free_dev; } /* Don't allow a device to belong to more than one group. */ if (gdev->cdev[i]->dev.driver_data) { rc = -EINVAL; - goto error; + goto free_dev; } gdev->cdev[i]->dev.driver_data = gdev; } @@ -206,8 +203,9 @@ ccwgroup_create(struct device *root, gdev->cdev[0]->dev.bus_id); rc = device_register(&gdev->dev); + if (rc) - goto error; + goto free_dev; get_device(&gdev->dev); rc = device_create_file(&gdev->dev, &dev_attr_ungroup); @@ -218,21 +216,27 @@ ccwgroup_create(struct device *root, rc = __ccwgroup_create_symlinks(gdev); if (!rc) { - mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); return 0; } device_remove_file(&gdev->dev, &dev_attr_ungroup); device_unregister(&gdev->dev); error: + for (i = 0; i < argc; i++) + if (gdev->cdev[i]) { + put_device(&gdev->cdev[i]->dev); + gdev->cdev[i]->dev.driver_data = NULL; + } + put_device(&gdev->dev); + return rc; +free_dev: for (i = 0; i < argc; i++) if (gdev->cdev[i]) { if (gdev->cdev[i]->dev.driver_data == gdev) gdev->cdev[i]->dev.driver_data = NULL; put_device(&gdev->cdev[i]->dev); } - mutex_unlock(&gdev->reg_mutex); - put_device(&gdev->dev); + kfree(gdev); return rc; } @@ -418,12 +422,8 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) get_driver(&cdriver->driver); while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, __ccwgroup_match_all))) { - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - - mutex_lock(&gdev->reg_mutex); - __ccwgroup_remove_symlinks(gdev); + __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); device_unregister(dev); - mutex_unlock(&gdev->reg_mutex); put_device(dev); } put_driver(&cdriver->driver); @@ -444,10 +444,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) if (cdev->dev.driver_data) { gdev = (struct ccwgroup_device *)cdev->dev.driver_data; if (get_device(&gdev->dev)) { - mutex_lock(&gdev->reg_mutex); if (device_is_registered(&gdev->dev)) return gdev; - mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); } return NULL; @@ -467,7 +465,6 @@ ccwgroup_remove_ccwdev(struct ccw_device *cdev) if (gdev) { __ccwgroup_remove_symlinks(gdev); device_unregister(&gdev->dev); - mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); } } diff --git a/trunk/drivers/s390/cio/chp.c b/trunk/drivers/s390/cio/chp.c deleted file mode 100644 index ac289e6eadfe..000000000000 --- a/trunk/drivers/s390/cio/chp.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * drivers/s390/cio/chp.c - * - * Copyright IBM Corp. 1999,2007 - * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) - * Arnd Bergmann (arndb@de.ibm.com) - * Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cio.h" -#include "css.h" -#include "ioasm.h" -#include "cio_debug.h" -#include "chp.h" - -#define to_channelpath(device) container_of(device, struct channel_path, dev) -#define CHP_INFO_UPDATE_INTERVAL 1*HZ - -enum cfg_task_t { - cfg_none, - cfg_configure, - cfg_deconfigure -}; - -/* Map for pending configure tasks. */ -static enum cfg_task_t chp_cfg_task[__MAX_CSSID + 1][__MAX_CHPID + 1]; -static DEFINE_MUTEX(cfg_lock); -static int cfg_busy; - -/* Map for channel-path status. */ -static struct sclp_chp_info chp_info; -static DEFINE_MUTEX(info_lock); - -/* Time after which channel-path status may be outdated. */ -static unsigned long chp_info_expires; - -/* Workqueue to perform pending configure tasks. */ -static struct workqueue_struct *chp_wq; -static struct work_struct cfg_work; - -/* Wait queue for configure completion events. */ -static wait_queue_head_t cfg_wait_queue; - -/* Return channel_path struct for given chpid. */ -static inline struct channel_path *chpid_to_chp(struct chp_id chpid) -{ - return css[chpid.cssid]->chps[chpid.id]; -} - -/* Set vary state for given chpid. */ -static void set_chp_logically_online(struct chp_id chpid, int onoff) -{ - chpid_to_chp(chpid)->state = onoff; -} - -/* On succes return 0 if channel-path is varied offline, 1 if it is varied - * online. Return -ENODEV if channel-path is not registered. */ -int chp_get_status(struct chp_id chpid) -{ - return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV); -} - -/** - * chp_get_sch_opm - return opm for subchannel - * @sch: subchannel - * - * Calculate and return the operational path mask (opm) based on the chpids - * used by the subchannel and the status of the associated channel-paths. - */ -u8 chp_get_sch_opm(struct subchannel *sch) -{ - struct chp_id chpid; - int opm; - int i; - - opm = 0; - chp_id_init(&chpid); - for (i=0; i < 8; i++) { - opm <<= 1; - chpid.id = sch->schib.pmcw.chpid[i]; - if (chp_get_status(chpid) != 0) - opm |= 1; - } - return opm; -} - -/** - * chp_is_registered - check if a channel-path is registered - * @chpid: channel-path ID - * - * Return non-zero if a channel-path with the given chpid is registered, - * zero otherwise. - */ -int chp_is_registered(struct chp_id chpid) -{ - return chpid_to_chp(chpid) != NULL; -} - -/* - * Function: s390_vary_chpid - * Varies the specified chpid online or offline - */ -static int s390_vary_chpid(struct chp_id chpid, int on) -{ - char dbf_text[15]; - int status; - - sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, - chpid.id); - CIO_TRACE_EVENT( 2, dbf_text); - - status = chp_get_status(chpid); - if (status < 0) { - printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n", - chpid.cssid, chpid.id); - return -EINVAL; - } - - if (!on && !status) { - printk(KERN_ERR "chpid %x.%02x is already offline\n", - chpid.cssid, chpid.id); - return -EINVAL; - } - - set_chp_logically_online(chpid, on); - chsc_chp_vary(chpid, on); - return 0; -} - -/* - * Channel measurement related functions - */ -static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, - loff_t off, size_t count) -{ - struct channel_path *chp; - unsigned int size; - - chp = to_channelpath(container_of(kobj, struct device, kobj)); - if (!chp->cmg_chars) - return 0; - - size = sizeof(struct cmg_chars); - - if (off > size) - return 0; - if (off + count > size) - count = size - off; - memcpy(buf, chp->cmg_chars + off, count); - return count; -} - -static struct bin_attribute chp_measurement_chars_attr = { - .attr = { - .name = "measurement_chars", - .mode = S_IRUSR, - .owner = THIS_MODULE, - }, - .size = sizeof(struct cmg_chars), - .read = chp_measurement_chars_read, -}; - -static void chp_measurement_copy_block(struct cmg_entry *buf, - struct channel_subsystem *css, - struct chp_id chpid) -{ - void *area; - struct cmg_entry *entry, reference_buf; - int idx; - - if (chpid.id < 128) { - area = css->cub_addr1; - idx = chpid.id; - } else { - area = css->cub_addr2; - idx = chpid.id - 128; - } - entry = area + (idx * sizeof(struct cmg_entry)); - do { - memcpy(buf, entry, sizeof(*entry)); - memcpy(&reference_buf, entry, sizeof(*entry)); - } while (reference_buf.values[0] != buf->values[0]); -} - -static ssize_t chp_measurement_read(struct kobject *kobj, char *buf, - loff_t off, size_t count) -{ - struct channel_path *chp; - struct channel_subsystem *css; - unsigned int size; - - chp = to_channelpath(container_of(kobj, struct device, kobj)); - css = to_css(chp->dev.parent); - - size = sizeof(struct cmg_entry); - - /* Only allow single reads. */ - if (off || count < size) - return 0; - chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid); - count = size; - return count; -} - -static struct bin_attribute chp_measurement_attr = { - .attr = { - .name = "measurement", - .mode = S_IRUSR, - .owner = THIS_MODULE, - }, - .size = sizeof(struct cmg_entry), - .read = chp_measurement_read, -}; - -void chp_remove_cmg_attr(struct channel_path *chp) -{ - device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); - device_remove_bin_file(&chp->dev, &chp_measurement_attr); -} - -int chp_add_cmg_attr(struct channel_path *chp) -{ - int ret; - - ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); - if (ret) - return ret; - ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); - if (ret) - device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); - return ret; -} - -/* - * Files for the channel path entries. - */ -static ssize_t chp_status_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct channel_path *chp = container_of(dev, struct channel_path, dev); - - if (!chp) - return 0; - return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") : - sprintf(buf, "offline\n")); -} - -static ssize_t chp_status_write(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct channel_path *cp = container_of(dev, struct channel_path, dev); - char cmd[10]; - int num_args; - int error; - - num_args = sscanf(buf, "%5s", cmd); - if (!num_args) - return count; - - if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) - error = s390_vary_chpid(cp->chpid, 1); - else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) - error = s390_vary_chpid(cp->chpid, 0); - else - error = -EINVAL; - - return error < 0 ? error : count; - -} - -static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); - -static ssize_t chp_configure_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct channel_path *cp; - int status; - - cp = container_of(dev, struct channel_path, dev); - status = chp_info_get_status(cp->chpid); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", status); -} - -static int cfg_wait_idle(void); - -static ssize_t chp_configure_write(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct channel_path *cp; - int val; - char delim; - - if (sscanf(buf, "%d %c", &val, &delim) != 1) - return -EINVAL; - if (val != 0 && val != 1) - return -EINVAL; - cp = container_of(dev, struct channel_path, dev); - chp_cfg_schedule(cp->chpid, val); - cfg_wait_idle(); - - return count; -} - -static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write); - -static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct channel_path *chp = container_of(dev, struct channel_path, dev); - - if (!chp) - return 0; - return sprintf(buf, "%x\n", chp->desc.desc); -} - -static DEVICE_ATTR(type, 0444, chp_type_show, NULL); - -static ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct channel_path *chp = to_channelpath(dev); - - if (!chp) - return 0; - if (chp->cmg == -1) /* channel measurements not available */ - return sprintf(buf, "unknown\n"); - return sprintf(buf, "%x\n", chp->cmg); -} - -static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL); - -static ssize_t chp_shared_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct channel_path *chp = to_channelpath(dev); - - if (!chp) - return 0; - if (chp->shared == -1) /* channel measurements not available */ - return sprintf(buf, "unknown\n"); - return sprintf(buf, "%x\n", chp->shared); -} - -static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); - -static struct attribute * chp_attrs[] = { - &dev_attr_status.attr, - &dev_attr_configure.attr, - &dev_attr_type.attr, - &dev_attr_cmg.attr, - &dev_attr_shared.attr, - NULL, -}; - -static struct attribute_group chp_attr_group = { - .attrs = chp_attrs, -}; - -static void chp_release(struct device *dev) -{ - struct channel_path *cp; - - cp = container_of(dev, struct channel_path, dev); - kfree(cp); -} - -/** - * chp_new - register a new channel-path - * @chpid - channel-path ID - * - * Create and register data structure representing new channel-path. Return - * zero on success, non-zero otherwise. - */ -int chp_new(struct chp_id chpid) -{ - struct channel_path *chp; - int ret; - - if (chp_is_registered(chpid)) - return 0; - chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL); - if (!chp) - return -ENOMEM; - - /* fill in status, etc. */ - chp->chpid = chpid; - chp->state = 1; - chp->dev.parent = &css[chpid.cssid]->device; - chp->dev.release = chp_release; - snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, - chpid.id); - - /* Obtain channel path description and fill it in. */ - ret = chsc_determine_channel_path_description(chpid, &chp->desc); - if (ret) - goto out_free; - if ((chp->desc.flags & 0x80) == 0) { - ret = -ENODEV; - goto out_free; - } - /* Get channel-measurement characteristics. */ - if (css_characteristics_avail && css_chsc_characteristics.scmc - && css_chsc_characteristics.secm) { - ret = chsc_get_channel_measurement_chars(chp); - if (ret) - goto out_free; - } else { - static int msg_done; - - if (!msg_done) { - printk(KERN_WARNING "cio: Channel measurements not " - "available, continuing.\n"); - msg_done = 1; - } - chp->cmg = -1; - } - - /* make it known to the system */ - ret = device_register(&chp->dev); - if (ret) { - printk(KERN_WARNING "%s: could not register %x.%02x\n", - __func__, chpid.cssid, chpid.id); - goto out_free; - } - ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); - if (ret) { - device_unregister(&chp->dev); - goto out_free; - } - mutex_lock(&css[chpid.cssid]->mutex); - if (css[chpid.cssid]->cm_enabled) { - ret = chp_add_cmg_attr(chp); - if (ret) { - sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); - device_unregister(&chp->dev); - mutex_unlock(&css[chpid.cssid]->mutex); - goto out_free; - } - } - css[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&css[chpid.cssid]->mutex); - return ret; -out_free: - kfree(chp); - return ret; -} - -/** - * chp_get_chp_desc - return newly allocated channel-path description - * @chpid: channel-path ID - * - * On success return a newly allocated copy of the channel-path description - * data associated with the given channel-path ID. Return %NULL on error. - */ -void *chp_get_chp_desc(struct chp_id chpid) -{ - struct channel_path *chp; - struct channel_path_desc *desc; - - chp = chpid_to_chp(chpid); - if (!chp) - return NULL; - desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); - if (!desc) - return NULL; - memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); - return desc; -} - -/** - * chp_process_crw - process channel-path status change - * @id: channel-path ID number - * @status: non-zero if channel-path has become available, zero otherwise - * - * Handle channel-report-words indicating that the status of a channel-path - * has changed. - */ -void chp_process_crw(int id, int status) -{ - struct chp_id chpid; - - chp_id_init(&chpid); - chpid.id = id; - if (status) { - if (!chp_is_registered(chpid)) - chp_new(chpid); - chsc_chp_online(chpid); - } else - chsc_chp_offline(chpid); -} - -static inline int info_bit_num(struct chp_id id) -{ - return id.id + id.cssid * (__MAX_CHPID + 1); -} - -/* Force chp_info refresh on next call to info_validate(). */ -static void info_expire(void) -{ - mutex_lock(&info_lock); - chp_info_expires = jiffies - 1; - mutex_unlock(&info_lock); -} - -/* Ensure that chp_info is up-to-date. */ -static int info_update(void) -{ - int rc; - - mutex_lock(&info_lock); - rc = 0; - if (time_after(jiffies, chp_info_expires)) { - /* Data is too old, update. */ - rc = sclp_chp_read_info(&chp_info); - chp_info_expires = jiffies + CHP_INFO_UPDATE_INTERVAL ; - } - mutex_unlock(&info_lock); - - return rc; -} - -/** - * chp_info_get_status - retrieve configure status of a channel-path - * @chpid: channel-path ID - * - * On success, return 0 for standby, 1 for configured, 2 for reserved, - * 3 for not recognized. Return negative error code on error. - */ -int chp_info_get_status(struct chp_id chpid) -{ - int rc; - int bit; - - rc = info_update(); - if (rc) - return rc; - - bit = info_bit_num(chpid); - mutex_lock(&info_lock); - if (!chp_test_bit(chp_info.recognized, bit)) - rc = CHP_STATUS_NOT_RECOGNIZED; - else if (chp_test_bit(chp_info.configured, bit)) - rc = CHP_STATUS_CONFIGURED; - else if (chp_test_bit(chp_info.standby, bit)) - rc = CHP_STATUS_STANDBY; - else - rc = CHP_STATUS_RESERVED; - mutex_unlock(&info_lock); - - return rc; -} - -/* Return configure task for chpid. */ -static enum cfg_task_t cfg_get_task(struct chp_id chpid) -{ - return chp_cfg_task[chpid.cssid][chpid.id]; -} - -/* Set configure task for chpid. */ -static void cfg_set_task(struct chp_id chpid, enum cfg_task_t cfg) -{ - chp_cfg_task[chpid.cssid][chpid.id] = cfg; -} - -/* Perform one configure/deconfigure request. Reschedule work function until - * last request. */ -static void cfg_func(struct work_struct *work) -{ - struct chp_id chpid; - enum cfg_task_t t; - - mutex_lock(&cfg_lock); - t = cfg_none; - chp_id_for_each(&chpid) { - t = cfg_get_task(chpid); - if (t != cfg_none) { - cfg_set_task(chpid, cfg_none); - break; - } - } - mutex_unlock(&cfg_lock); - - switch (t) { - case cfg_configure: - sclp_chp_configure(chpid); - info_expire(); - chsc_chp_online(chpid); - break; - case cfg_deconfigure: - sclp_chp_deconfigure(chpid); - info_expire(); - chsc_chp_offline(chpid); - break; - case cfg_none: - /* Get updated information after last change. */ - info_update(); - mutex_lock(&cfg_lock); - cfg_busy = 0; - mutex_unlock(&cfg_lock); - wake_up_interruptible(&cfg_wait_queue); - return; - } - queue_work(chp_wq, &cfg_work); -} - -/** - * chp_cfg_schedule - schedule chpid configuration request - * @chpid - channel-path ID - * @configure - Non-zero for configure, zero for deconfigure - * - * Schedule a channel-path configuration/deconfiguration request. - */ -void chp_cfg_schedule(struct chp_id chpid, int configure) -{ - CIO_MSG_EVENT(2, "chp_cfg_sched%x.%02x=%d\n", chpid.cssid, chpid.id, - configure); - mutex_lock(&cfg_lock); - cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure); - cfg_busy = 1; - mutex_unlock(&cfg_lock); - queue_work(chp_wq, &cfg_work); -} - -/** - * chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request - * @chpid - channel-path ID - * - * Cancel an active channel-path deconfiguration request if it has not yet - * been performed. - */ -void chp_cfg_cancel_deconfigure(struct chp_id chpid) -{ - CIO_MSG_EVENT(2, "chp_cfg_cancel:%x.%02x\n", chpid.cssid, chpid.id); - mutex_lock(&cfg_lock); - if (cfg_get_task(chpid) == cfg_deconfigure) - cfg_set_task(chpid, cfg_none); - mutex_unlock(&cfg_lock); -} - -static int cfg_wait_idle(void) -{ - if (wait_event_interruptible(cfg_wait_queue, !cfg_busy)) - return -ERESTARTSYS; - return 0; -} - -static int __init chp_init(void) -{ - struct chp_id chpid; - - chp_wq = create_singlethread_workqueue("cio_chp"); - if (!chp_wq) - return -ENOMEM; - INIT_WORK(&cfg_work, cfg_func); - init_waitqueue_head(&cfg_wait_queue); - if (info_update()) - return 0; - /* Register available channel-paths. */ - chp_id_for_each(&chpid) { - if (chp_info_get_status(chpid) != CHP_STATUS_NOT_RECOGNIZED) - chp_new(chpid); - } - - return 0; -} - -subsys_initcall(chp_init); diff --git a/trunk/drivers/s390/cio/chp.h b/trunk/drivers/s390/cio/chp.h deleted file mode 100644 index 65286563c592..000000000000 --- a/trunk/drivers/s390/cio/chp.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * drivers/s390/cio/chp.h - * - * Copyright IBM Corp. 2007 - * Author(s): Peter Oberparleiter - */ - -#ifndef S390_CHP_H -#define S390_CHP_H S390_CHP_H - -#include -#include -#include -#include "chsc.h" - -#define CHP_STATUS_STANDBY 0 -#define CHP_STATUS_CONFIGURED 1 -#define CHP_STATUS_RESERVED 2 -#define CHP_STATUS_NOT_RECOGNIZED 3 - -static inline int chp_test_bit(u8 *bitmap, int num) -{ - int byte = num >> 3; - int mask = 128 >> (num & 7); - - return (bitmap[byte] & mask) ? 1 : 0; -} - - -struct channel_path { - struct chp_id chpid; - int state; - struct channel_path_desc desc; - /* Channel-measurement related stuff: */ - int cmg; - int shared; - void *cmg_chars; - struct device dev; -}; - -int chp_get_status(struct chp_id chpid); -u8 chp_get_sch_opm(struct subchannel *sch); -int chp_is_registered(struct chp_id chpid); -void *chp_get_chp_desc(struct chp_id chpid); -void chp_process_crw(int id, int available); -void chp_remove_cmg_attr(struct channel_path *chp); -int chp_add_cmg_attr(struct channel_path *chp); -int chp_new(struct chp_id chpid); -void chp_cfg_schedule(struct chp_id chpid, int configure); -void chp_cfg_cancel_deconfigure(struct chp_id chpid); -int chp_info_get_status(struct chp_id chpid); - -#endif /* S390_CHP_H */ diff --git a/trunk/drivers/s390/cio/chsc.c b/trunk/drivers/s390/cio/chsc.c index ea92ac4d6577..6f05a44e3817 100644 --- a/trunk/drivers/s390/cio/chsc.c +++ b/trunk/drivers/s390/cio/chsc.c @@ -15,124 +15,202 @@ #include #include -#include #include "css.h" #include "cio.h" #include "cio_debug.h" #include "ioasm.h" -#include "chp.h" #include "chsc.h" static void *sei_page; -struct chsc_ssd_area { - struct chsc_header request; - u16 :10; - u16 ssid:2; - u16 :4; - u16 f_sch; /* first subchannel */ - u16 :16; - u16 l_sch; /* last subchannel */ - u32 :32; - struct chsc_header response; - u32 :32; - u8 sch_valid : 1; - u8 dev_valid : 1; - u8 st : 3; /* subchannel type */ - u8 zeroes : 3; - u8 unit_addr; /* unit address */ - u16 devno; /* device number */ - u8 path_mask; - u8 fla_valid_mask; - u16 sch; /* subchannel */ - u8 chpid[8]; /* chpids 0-7 */ - u16 fla[8]; /* full link addresses 0-7 */ -} __attribute__ ((packed)); +static int new_channel_path(int chpid); -int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) +static inline void +set_chp_logically_online(int chp, int onoff) { - unsigned long page; - struct chsc_ssd_area *ssd_area; - int ccode; - int ret; - int i; - int mask; + css[0]->chps[chp]->state = onoff; +} + +static int +get_chp_status(int chp) +{ + return (css[0]->chps[chp] ? css[0]->chps[chp]->state : -ENODEV); +} + +void +chsc_validate_chpids(struct subchannel *sch) +{ + int mask, chp; + + for (chp = 0; chp <= 7; chp++) { + mask = 0x80 >> chp; + if (!get_chp_status(sch->schib.pmcw.chpid[chp])) + /* disable using this path */ + sch->opm &= ~mask; + } +} + +void +chpid_is_actually_online(int chp) +{ + int state; + + state = get_chp_status(chp); + if (state < 0) { + need_rescan = 1; + queue_work(slow_path_wq, &slow_path_work); + } else + WARN_ON(!state); +} + +/* FIXME: this is _always_ called for every subchannel. shouldn't we + * process more than one at a time? */ +static int +chsc_get_sch_desc_irq(struct subchannel *sch, void *page) +{ + int ccode, j; + + struct { + struct chsc_header request; + u16 reserved1a:10; + u16 ssid:2; + u16 reserved1b:4; + u16 f_sch; /* first subchannel */ + u16 reserved2; + u16 l_sch; /* last subchannel */ + u32 reserved3; + struct chsc_header response; + u32 reserved4; + u8 sch_valid : 1; + u8 dev_valid : 1; + u8 st : 3; /* subchannel type */ + u8 zeroes : 3; + u8 unit_addr; /* unit address */ + u16 devno; /* device number */ + u8 path_mask; + u8 fla_valid_mask; + u16 sch; /* subchannel */ + u8 chpid[8]; /* chpids 0-7 */ + u16 fla[8]; /* full link addresses 0-7 */ + } __attribute__ ((packed)) *ssd_area; + + ssd_area = page; - page = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!page) - return -ENOMEM; - ssd_area = (struct chsc_ssd_area *) page; ssd_area->request.length = 0x0010; ssd_area->request.code = 0x0004; - ssd_area->ssid = schid.ssid; - ssd_area->f_sch = schid.sch_no; - ssd_area->l_sch = schid.sch_no; + + ssd_area->ssid = sch->schid.ssid; + ssd_area->f_sch = sch->schid.sch_no; + ssd_area->l_sch = sch->schid.sch_no; ccode = chsc(ssd_area); - /* Check response. */ if (ccode > 0) { - ret = (ccode == 3) ? -ENODEV : -EBUSY; - goto out_free; + pr_debug("chsc returned with ccode = %d\n", ccode); + return (ccode == 3) ? -ENODEV : -EBUSY; } - if (ssd_area->response.code != 0x0001) { - CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", - schid.ssid, schid.sch_no, + + switch (ssd_area->response.code) { + case 0x0001: /* everything ok */ + break; + case 0x0002: + CIO_CRW_EVENT(2, "Invalid command!\n"); + return -EINVAL; + case 0x0003: + CIO_CRW_EVENT(2, "Error in chsc request block!\n"); + return -EINVAL; + case 0x0004: + CIO_CRW_EVENT(2, "Model does not provide ssd\n"); + return -EOPNOTSUPP; + default: + CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", ssd_area->response.code); - ret = -EIO; - goto out_free; + return -EIO; } - if (!ssd_area->sch_valid) { - ret = -ENODEV; - goto out_free; + + /* + * ssd_area->st stores the type of the detected + * subchannel, with the following definitions: + * + * 0: I/O subchannel: All fields have meaning + * 1: CHSC subchannel: Only sch_val, st and sch + * have meaning + * 2: Message subchannel: All fields except unit_addr + * have meaning + * 3: ADM subchannel: Only sch_val, st and sch + * have meaning + * + * Other types are currently undefined. + */ + if (ssd_area->st > 3) { /* uhm, that looks strange... */ + CIO_CRW_EVENT(0, "Strange subchannel type %d" + " for sch 0.%x.%04x\n", ssd_area->st, + sch->schid.ssid, sch->schid.sch_no); + /* + * There may have been a new subchannel type defined in the + * time since this code was written; since we don't know which + * fields have meaning and what to do with it we just jump out + */ + return 0; + } else { + const char *type[4] = {"I/O", "chsc", "message", "ADM"}; + CIO_CRW_EVENT(6, "ssd: sch 0.%x.%04x is %s subchannel\n", + sch->schid.ssid, sch->schid.sch_no, + type[ssd_area->st]); + + sch->ssd_info.valid = 1; + sch->ssd_info.type = ssd_area->st; } - /* Copy data */ - ret = 0; - memset(ssd, 0, sizeof(struct chsc_ssd_info)); - if ((ssd_area->st != 0) && (ssd_area->st != 2)) - goto out_free; - ssd->path_mask = ssd_area->path_mask; - ssd->fla_valid_mask = ssd_area->fla_valid_mask; - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (ssd_area->path_mask & mask) { - chp_id_init(&ssd->chpid[i]); - ssd->chpid[i].id = ssd_area->chpid[i]; + + if (ssd_area->st == 0 || ssd_area->st == 2) { + for (j = 0; j < 8; j++) { + if (!((0x80 >> j) & ssd_area->path_mask & + ssd_area->fla_valid_mask)) + continue; + sch->ssd_info.chpid[j] = ssd_area->chpid[j]; + sch->ssd_info.fla[j] = ssd_area->fla[j]; } - if (ssd_area->fla_valid_mask & mask) - ssd->fla[i] = ssd_area->fla[i]; } -out_free: - free_page(page); - return ret; -} - -static int check_for_io_on_path(struct subchannel *sch, int mask) -{ - int cc; - - cc = stsch(sch->schid, &sch->schib); - if (cc) - return 0; - if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask) - return 1; return 0; } -static void terminate_internal_io(struct subchannel *sch) +int +css_get_ssd_info(struct subchannel *sch) { - if (cio_clear(sch)) { - /* Recheck device in case clear failed. */ - sch->lpm = 0; - if (device_trigger_verify(sch) != 0) - css_schedule_eval(sch->schid); - return; + int ret; + void *page; + + page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!page) + return -ENOMEM; + spin_lock_irq(sch->lock); + ret = chsc_get_sch_desc_irq(sch, page); + if (ret) { + static int cio_chsc_err_msg; + + if (!cio_chsc_err_msg) { + printk(KERN_ERR + "chsc_get_sch_descriptions:" + " Error %d while doing chsc; " + "processing some machine checks may " + "not work\n", ret); + cio_chsc_err_msg = 1; + } } - /* Request retry of internal operation. */ - device_set_intretry(sch); - /* Call handler. */ - if (sch->driver && sch->driver->termination) - sch->driver->termination(&sch->dev); + spin_unlock_irq(sch->lock); + free_page((unsigned long)page); + if (!ret) { + int j, chpid, mask; + /* Allocate channel path structures, if needed. */ + for (j = 0; j < 8; j++) { + mask = 0x80 >> j; + chpid = sch->ssd_info.chpid[j]; + if ((sch->schib.pmcw.pim & mask) && + (get_chp_status(chpid) < 0)) + new_channel_path(chpid); + } + } + return ret; } static int @@ -141,7 +219,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) int j; int mask; struct subchannel *sch; - struct chp_id *chpid; + struct channel_path *chpid; struct schib schib; sch = to_subchannel(dev); @@ -165,50 +243,106 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) if (sch->schib.pmcw.pim == 0x80) goto out_unreg; - if (check_for_io_on_path(sch, mask)) { - if (device_is_online(sch)) - device_kill_io(sch); - else { - terminate_internal_io(sch); - /* Re-start path verification. */ - if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); - } - } else { - /* trigger path verification. */ - if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); - else if (sch->lpm == mask) + if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && + (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && + (sch->schib.pmcw.lpum == mask)) { + int cc; + + cc = cio_clear(sch); + if (cc == -ENODEV) goto out_unreg; + /* Request retry of internal operation. */ + device_set_intretry(sch); + /* Call handler. */ + if (sch->driver && sch->driver->termination) + sch->driver->termination(&sch->dev); + goto out_unlock; } + /* trigger path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(&sch->dev); + else if (sch->lpm == mask) + goto out_unreg; +out_unlock: spin_unlock_irq(sch->lock); return 0; - out_unreg: - sch->lpm = 0; spin_unlock_irq(sch->lock); - css_schedule_eval(sch->schid); + sch->lpm = 0; + if (css_enqueue_subchannel_slow(sch->schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } return 0; } -void chsc_chp_offline(struct chp_id chpid) +static void +s390_set_chpid_offline( __u8 chpid) { char dbf_txt[15]; + struct device *dev; - sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id); + sprintf(dbf_txt, "chpr%x", chpid); CIO_TRACE_EVENT(2, dbf_txt); - if (chp_get_status(chpid) <= 0) + if (get_chp_status(chpid) <= 0) return; - bus_for_each_dev(&css_bus_type, NULL, &chpid, + dev = get_device(&css[0]->chps[chpid]->dev); + bus_for_each_dev(&css_bus_type, NULL, to_channelpath(dev), s390_subchannel_remove_chpid); + + if (need_rescan || css_slow_subchannels_exist()) + queue_work(slow_path_wq, &slow_path_work); + put_device(dev); +} + +struct res_acc_data { + struct channel_path *chp; + u32 fla_mask; + u16 fla; +}; + +static int +s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch) +{ + int found; + int chp; + int ccode; + + found = 0; + for (chp = 0; chp <= 7; chp++) + /* + * check if chpid is in information updated by ssd + */ + if (sch->ssd_info.valid && + sch->ssd_info.chpid[chp] == res_data->chp->id && + (sch->ssd_info.fla[chp] & res_data->fla_mask) + == res_data->fla) { + found = 1; + break; + } + + if (found == 0) + return 0; + + /* + * Do a stsch to update our subchannel structure with the + * new path information and eventually check for logically + * offline chpids. + */ + ccode = stsch(sch->schid, &sch->schib); + if (ccode > 0) + return 0; + + return 0x80 >> chp; } static int s390_process_res_acc_new_sch(struct subchannel_id schid) { struct schib schib; + int ret; /* * We don't know the device yet, but since a path * may be available now to the device we'll have @@ -219,35 +353,14 @@ s390_process_res_acc_new_sch(struct subchannel_id schid) */ if (stsch_err(schid, &schib)) /* We're through */ - return -ENXIO; + return need_rescan ? -EAGAIN : -ENXIO; /* Put it on the slow path. */ - css_schedule_eval(schid); - return 0; -} - -struct res_acc_data { - struct chp_id chpid; - u32 fla_mask; - u16 fla; -}; - -static int get_res_chpid_mask(struct chsc_ssd_info *ssd, - struct res_acc_data *data) -{ - int i; - int mask; - - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (!(ssd->path_mask & mask)) - continue; - if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid)) - continue; - if ((ssd->fla_valid_mask & mask) && - ((ssd->fla[i] & data->fla_mask) != data->fla)) - continue; - return mask; + ret = css_enqueue_subchannel_slow(schid); + if (ret) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + return -EAGAIN; } return 0; } @@ -266,11 +379,14 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) return s390_process_res_acc_new_sch(schid); spin_lock_irq(sch->lock); - chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); - if (chp_mask == 0) - goto out; - if (stsch(sch->schid, &sch->schib)) - goto out; + + chp_mask = s390_process_res_acc_sch(res_data, sch); + + if (chp_mask == 0) { + spin_unlock_irq(sch->lock); + put_device(&sch->dev); + return 0; + } old_lpm = sch->lpm; sch->lpm = ((sch->schib.pmcw.pim & sch->schib.pmcw.pam & @@ -280,18 +396,20 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); -out: + spin_unlock_irq(sch->lock); put_device(&sch->dev); return 0; } -static void s390_process_res_acc (struct res_acc_data *res_data) + +static int +s390_process_res_acc (struct res_acc_data *res_data) { + int rc; char dbf_txt[15]; - sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, - res_data->chpid.id); + sprintf(dbf_txt, "accpr%x", res_data->chp->id); CIO_TRACE_EVENT( 2, dbf_txt); if (res_data->fla != 0) { sprintf(dbf_txt, "fla%x", res_data->fla); @@ -305,7 +423,12 @@ static void s390_process_res_acc (struct res_acc_data *res_data) * The more information we have (info), the less scanning * will we have to do. */ - for_each_subchannel(__s390_process_res_acc, res_data); + rc = for_each_subchannel(__s390_process_res_acc, res_data); + if (css_slow_subchannels_exist()) + rc = -EAGAIN; + else if (rc != -EAGAIN) + rc = 0; + return rc; } static int @@ -357,45 +480,43 @@ struct chsc_sei_area { /* ccdf has to be big enough for a link-incident record */ } __attribute__ ((packed)); -static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) +static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) { - struct chp_id chpid; - int id; + int chpid; CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", sei_area->rs, sei_area->rsid); if (sei_area->rs != 4) - return; - id = __get_chpid_from_lir(sei_area->ccdf); - if (id < 0) + return 0; + chpid = __get_chpid_from_lir(sei_area->ccdf); + if (chpid < 0) CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); - else { - chp_id_init(&chpid); - chpid.id = id; - chsc_chp_offline(chpid); - } + else + s390_set_chpid_offline(chpid); + + return 0; } -static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) +static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { struct res_acc_data res_data; - struct chp_id chpid; + struct device *dev; int status; + int rc; CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); if (sei_area->rs != 4) - return; - chp_id_init(&chpid); - chpid.id = sei_area->rsid; + return 0; /* allocate a new channel path structure, if needed */ - status = chp_get_status(chpid); + status = get_chp_status(sei_area->rsid); if (status < 0) - chp_new(chpid); + new_channel_path(sei_area->rsid); else if (!status) - return; + return 0; + dev = get_device(&css[0]->chps[sei_area->rsid]->dev); memset(&res_data, 0, sizeof(struct res_acc_data)); - res_data.chpid = chpid; + res_data.chp = to_channelpath(dev); if ((sei_area->vf & 0xc0) != 0) { res_data.fla = sei_area->fla; if ((sei_area->vf & 0xc0) == 0xc0) @@ -405,82 +526,51 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) /* link address */ res_data.fla_mask = 0xff00; } - s390_process_res_acc(&res_data); -} + rc = s390_process_res_acc(&res_data); + put_device(dev); -struct chp_config_data { - u8 map[32]; - u8 op; - u8 pc; -}; - -static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) -{ - struct chp_config_data *data; - struct chp_id chpid; - int num; - - CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); - if (sei_area->rs != 0) - return; - data = (struct chp_config_data *) &(sei_area->ccdf); - chp_id_init(&chpid); - for (num = 0; num <= __MAX_CHPID; num++) { - if (!chp_test_bit(data->map, num)) - continue; - chpid.id = num; - printk(KERN_WARNING "cio: processing configure event %d for " - "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id); - switch (data->op) { - case 0: - chp_cfg_schedule(chpid, 1); - break; - case 1: - chp_cfg_schedule(chpid, 0); - break; - case 2: - chp_cfg_cancel_deconfigure(chpid); - break; - } - } + return rc; } -static void chsc_process_sei(struct chsc_sei_area *sei_area) +static int chsc_process_sei(struct chsc_sei_area *sei_area) { + int rc; + /* Check if we might have lost some information. */ - if (sei_area->flags & 0x40) { + if (sei_area->flags & 0x40) CIO_CRW_EVENT(2, "chsc: event overflow\n"); - css_schedule_eval_all(); - } /* which kind of information was stored? */ + rc = 0; switch (sei_area->cc) { case 1: /* link incident*/ - chsc_process_sei_link_incident(sei_area); + rc = chsc_process_sei_link_incident(sei_area); break; case 2: /* i/o resource accessibiliy */ - chsc_process_sei_res_acc(sei_area); - break; - case 8: /* channel-path-configuration notification */ - chsc_process_sei_chp_config(sei_area); + rc = chsc_process_sei_res_acc(sei_area); break; default: /* other stuff */ CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", sei_area->cc); break; } + + return rc; } -void chsc_process_crw(void) +int chsc_process_crw(void) { struct chsc_sei_area *sei_area; + int ret; + int rc; if (!sei_page) - return; + return 0; /* Access to sei_page is serialized through machine check handler * thread, so no need for locking. */ sei_area = sei_page; CIO_TRACE_EVENT( 2, "prcss"); + ret = 0; do { memset(sei_area, 0, sizeof(*sei_area)); sei_area->request.length = 0x0010; @@ -490,26 +580,37 @@ void chsc_process_crw(void) if (sei_area->response.code == 0x0001) { CIO_CRW_EVENT(4, "chsc: sei successful\n"); - chsc_process_sei(sei_area); + rc = chsc_process_sei(sei_area); + if (rc) + ret = rc; } else { CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", sei_area->response.code); + ret = 0; break; } } while (sei_area->flags & 0x80); + + return ret; } static int __chp_add_new_sch(struct subchannel_id schid) { struct schib schib; + int ret; if (stsch_err(schid, &schib)) /* We're through */ - return -ENXIO; + return need_rescan ? -EAGAIN : -ENXIO; /* Put it on the slow path. */ - css_schedule_eval(schid); + ret = css_enqueue_subchannel_slow(schid); + if (ret) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + return -EAGAIN; + } return 0; } @@ -518,10 +619,10 @@ static int __chp_add(struct subchannel_id schid, void *data) { int i, mask; - struct chp_id *chpid; + struct channel_path *chp; struct subchannel *sch; - chpid = data; + chp = data; sch = get_subchannel_by_schid(schid); if (!sch) /* Check if the subchannel is now available. */ @@ -530,7 +631,7 @@ __chp_add(struct subchannel_id schid, void *data) for (i=0; i<8; i++) { mask = 0x80 >> i; if ((sch->schib.pmcw.pim & mask) && - (sch->schib.pmcw.chpid[i] == chpid->id)) { + (sch->schib.pmcw.chpid[i] == chp->id)) { if (stsch(sch->schid, &sch->schib) != 0) { /* Endgame. */ spin_unlock_irq(sch->lock); @@ -556,58 +657,122 @@ __chp_add(struct subchannel_id schid, void *data) return 0; } -void chsc_chp_online(struct chp_id chpid) +static int +chp_add(int chpid) { + int rc; char dbf_txt[15]; + struct device *dev; - sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); + if (!get_chp_status(chpid)) + return 0; /* no need to do the rest */ + + sprintf(dbf_txt, "cadd%x", chpid); CIO_TRACE_EVENT(2, dbf_txt); - if (chp_get_status(chpid) != 0) - for_each_subchannel(__chp_add, &chpid); + dev = get_device(&css[0]->chps[chpid]->dev); + rc = for_each_subchannel(__chp_add, to_channelpath(dev)); + if (css_slow_subchannels_exist()) + rc = -EAGAIN; + if (rc != -EAGAIN) + rc = 0; + put_device(dev); + return rc; } -static void __s390_subchannel_vary_chpid(struct subchannel *sch, - struct chp_id chpid, int on) +/* + * Handling of crw machine checks with channel path source. + */ +int +chp_process_crw(int chpid, int on) +{ + if (on == 0) { + /* Path has gone. We use the link incident routine.*/ + s390_set_chpid_offline(chpid); + return 0; /* De-register is async anyway. */ + } + /* + * Path has come. Allocate a new channel path structure, + * if needed. + */ + if (get_chp_status(chpid) < 0) + new_channel_path(chpid); + /* Avoid the extra overhead in process_rec_acc. */ + return chp_add(chpid); +} + +static int check_for_io_on_path(struct subchannel *sch, int index) +{ + int cc; + + cc = stsch(sch->schid, &sch->schib); + if (cc) + return 0; + if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) + return 1; + return 0; +} + +static void terminate_internal_io(struct subchannel *sch) +{ + if (cio_clear(sch)) { + /* Recheck device in case clear failed. */ + sch->lpm = 0; + if (device_trigger_verify(sch) != 0) { + if(css_enqueue_subchannel_slow(sch->schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } + } + return; + } + /* Request retry of internal operation. */ + device_set_intretry(sch); + /* Call handler. */ + if (sch->driver && sch->driver->termination) + sch->driver->termination(&sch->dev); +} + +static void +__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) { int chp, old_lpm; - int mask; unsigned long flags; + if (!sch->ssd_info.valid) + return; + spin_lock_irqsave(sch->lock, flags); old_lpm = sch->lpm; for (chp = 0; chp < 8; chp++) { - mask = 0x80 >> chp; - if (!(sch->ssd_info.path_mask & mask)) - continue; - if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid)) + if (sch->ssd_info.chpid[chp] != chpid) continue; if (on) { - sch->opm |= mask; - sch->lpm |= mask; + sch->opm |= (0x80 >> chp); + sch->lpm |= (0x80 >> chp); if (!old_lpm) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); break; } - sch->opm &= ~mask; - sch->lpm &= ~mask; - if (check_for_io_on_path(sch, mask)) { + sch->opm &= ~(0x80 >> chp); + sch->lpm &= ~(0x80 >> chp); + if (check_for_io_on_path(sch, chp)) { if (device_is_online(sch)) /* Path verification is done after killing. */ device_kill_io(sch); - else { + else /* Kill and retry internal I/O. */ terminate_internal_io(sch); - /* Re-start path verification. */ - if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); - } } else if (!sch->lpm) { - if (device_trigger_verify(sch) != 0) - css_schedule_eval(sch->schid); + if (device_trigger_verify(sch) != 0) { + if (css_enqueue_subchannel_slow(sch->schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } + } } else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); break; @@ -615,10 +780,11 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, spin_unlock_irqrestore(sch->lock, flags); } -static int s390_subchannel_vary_chpid_off(struct device *dev, void *data) +static int +s390_subchannel_vary_chpid_off(struct device *dev, void *data) { struct subchannel *sch; - struct chp_id *chpid; + __u8 *chpid; sch = to_subchannel(dev); chpid = data; @@ -627,10 +793,11 @@ static int s390_subchannel_vary_chpid_off(struct device *dev, void *data) return 0; } -static int s390_subchannel_vary_chpid_on(struct device *dev, void *data) +static int +s390_subchannel_vary_chpid_on(struct device *dev, void *data) { struct subchannel *sch; - struct chp_id *chpid; + __u8 *chpid; sch = to_subchannel(dev); chpid = data; @@ -654,17 +821,40 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) /* We're through */ return -ENXIO; /* Put it on the slow path. */ - css_schedule_eval(schid); + if (css_enqueue_subchannel_slow(schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + return -EAGAIN; + } return 0; } -/** - * chsc_chp_vary - propagate channel-path vary operation to subchannels - * @chpid: channl-path ID - * @on: non-zero for vary online, zero for vary offline +/* + * Function: s390_vary_chpid + * Varies the specified chpid online or offline */ -int chsc_chp_vary(struct chp_id chpid, int on) +static int +s390_vary_chpid( __u8 chpid, int on) { + char dbf_text[15]; + int status; + + sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid); + CIO_TRACE_EVENT( 2, dbf_text); + + status = get_chp_status(chpid); + if (status < 0) { + printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid); + return -EINVAL; + } + + if (!on && !status) { + printk(KERN_ERR "chpid %x is already offline\n", chpid); + return -EINVAL; + } + + set_chp_logically_online(chpid, on); + /* * Redo PathVerification on the devices the chpid connects to */ @@ -675,9 +865,118 @@ int chsc_chp_vary(struct chp_id chpid, int on) if (on) /* Scan for new devices on varied on path. */ for_each_subchannel(__s390_vary_chpid_on, NULL); + if (need_rescan || css_slow_subchannels_exist()) + queue_work(slow_path_wq, &slow_path_work); return 0; } +/* + * Channel measurement related functions + */ +static ssize_t +chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + struct channel_path *chp; + unsigned int size; + + chp = to_channelpath(container_of(kobj, struct device, kobj)); + if (!chp->cmg_chars) + return 0; + + size = sizeof(struct cmg_chars); + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, chp->cmg_chars + off, count); + return count; +} + +static struct bin_attribute chp_measurement_chars_attr = { + .attr = { + .name = "measurement_chars", + .mode = S_IRUSR, + .owner = THIS_MODULE, + }, + .size = sizeof(struct cmg_chars), + .read = chp_measurement_chars_read, +}; + +static void +chp_measurement_copy_block(struct cmg_entry *buf, + struct channel_subsystem *css, int chpid) +{ + void *area; + struct cmg_entry *entry, reference_buf; + int idx; + + if (chpid < 128) { + area = css->cub_addr1; + idx = chpid; + } else { + area = css->cub_addr2; + idx = chpid - 128; + } + entry = area + (idx * sizeof(struct cmg_entry)); + do { + memcpy(buf, entry, sizeof(*entry)); + memcpy(&reference_buf, entry, sizeof(*entry)); + } while (reference_buf.values[0] != buf->values[0]); +} + +static ssize_t +chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct channel_path *chp; + struct channel_subsystem *css; + unsigned int size; + + chp = to_channelpath(container_of(kobj, struct device, kobj)); + css = to_css(chp->dev.parent); + + size = sizeof(struct cmg_entry); + + /* Only allow single reads. */ + if (off || count < size) + return 0; + chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id); + count = size; + return count; +} + +static struct bin_attribute chp_measurement_attr = { + .attr = { + .name = "measurement", + .mode = S_IRUSR, + .owner = THIS_MODULE, + }, + .size = sizeof(struct cmg_entry), + .read = chp_measurement_read, +}; + +static void +chsc_remove_chp_cmg_attr(struct channel_path *chp) +{ + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_attr); +} + +static int +chsc_add_chp_cmg_attr(struct channel_path *chp) +{ + int ret; + + ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); + if (ret) + return ret; + ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); + if (ret) + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); + return ret; +} + static void chsc_remove_cmg_attr(struct channel_subsystem *css) { @@ -686,7 +985,7 @@ chsc_remove_cmg_attr(struct channel_subsystem *css) for (i = 0; i <= __MAX_CHPID; i++) { if (!css->chps[i]) continue; - chp_remove_cmg_attr(css->chps[i]); + chsc_remove_chp_cmg_attr(css->chps[i]); } } @@ -699,7 +998,7 @@ chsc_add_cmg_attr(struct channel_subsystem *css) for (i = 0; i <= __MAX_CHPID; i++) { if (!css->chps[i]) continue; - ret = chp_add_cmg_attr(css->chps[i]); + ret = chsc_add_chp_cmg_attr(css->chps[i]); if (ret) goto cleanup; } @@ -708,11 +1007,12 @@ chsc_add_cmg_attr(struct channel_subsystem *css) for (--i; i >= 0; i--) { if (!css->chps[i]) continue; - chp_remove_cmg_attr(css->chps[i]); + chsc_remove_chp_cmg_attr(css->chps[i]); } return ret; } + static int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) { @@ -818,7 +1118,7 @@ chsc_secm(struct channel_subsystem *css, int enable) } else chsc_remove_cmg_attr(css); } - if (!css->cm_enabled) { + if (enable && !css->cm_enabled) { free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); } @@ -827,8 +1127,109 @@ chsc_secm(struct channel_subsystem *css, int enable) return ret; } -int chsc_determine_channel_path_description(struct chp_id chpid, - struct channel_path_desc *desc) +/* + * Files for the channel path entries. + */ +static ssize_t +chp_status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct channel_path *chp = container_of(dev, struct channel_path, dev); + + if (!chp) + return 0; + return (get_chp_status(chp->id) ? sprintf(buf, "online\n") : + sprintf(buf, "offline\n")); +} + +static ssize_t +chp_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct channel_path *cp = container_of(dev, struct channel_path, dev); + char cmd[10]; + int num_args; + int error; + + num_args = sscanf(buf, "%5s", cmd); + if (!num_args) + return count; + + if (!strnicmp(cmd, "on", 2)) + error = s390_vary_chpid(cp->id, 1); + else if (!strnicmp(cmd, "off", 3)) + error = s390_vary_chpid(cp->id, 0); + else + error = -EINVAL; + + return error < 0 ? error : count; + +} + +static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); + +static ssize_t +chp_type_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct channel_path *chp = container_of(dev, struct channel_path, dev); + + if (!chp) + return 0; + return sprintf(buf, "%x\n", chp->desc.desc); +} + +static DEVICE_ATTR(type, 0444, chp_type_show, NULL); + +static ssize_t +chp_cmg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct channel_path *chp = to_channelpath(dev); + + if (!chp) + return 0; + if (chp->cmg == -1) /* channel measurements not available */ + return sprintf(buf, "unknown\n"); + return sprintf(buf, "%x\n", chp->cmg); +} + +static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL); + +static ssize_t +chp_shared_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct channel_path *chp = to_channelpath(dev); + + if (!chp) + return 0; + if (chp->shared == -1) /* channel measurements not available */ + return sprintf(buf, "unknown\n"); + return sprintf(buf, "%x\n", chp->shared); +} + +static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); + +static struct attribute * chp_attrs[] = { + &dev_attr_status.attr, + &dev_attr_type.attr, + &dev_attr_cmg.attr, + &dev_attr_shared.attr, + NULL, +}; + +static struct attribute_group chp_attr_group = { + .attrs = chp_attrs, +}; + +static void +chp_release(struct device *dev) +{ + struct channel_path *cp; + + cp = container_of(dev, struct channel_path, dev); + kfree(cp); +} + +static int +chsc_determine_channel_path_description(int chpid, + struct channel_path_desc *desc) { int ccode, ret; @@ -851,8 +1252,8 @@ int chsc_determine_channel_path_description(struct chp_id chpid, scpd_area->request.length = 0x0010; scpd_area->request.code = 0x0002; - scpd_area->first_chpid = chpid.id; - scpd_area->last_chpid = chpid.id; + scpd_area->first_chpid = chpid; + scpd_area->last_chpid = chpid; ccode = chsc(scpd_area); if (ccode > 0) { @@ -915,7 +1316,8 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, } } -int chsc_get_channel_measurement_chars(struct channel_path *chp) +static int +chsc_get_channel_measurement_chars(struct channel_path *chp) { int ccode, ret; @@ -947,8 +1349,8 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) scmc_area->request.length = 0x0010; scmc_area->request.code = 0x0022; - scmc_area->first_chpid = chp->chpid.id; - scmc_area->last_chpid = chp->chpid.id; + scmc_area->first_chpid = chp->id; + scmc_area->last_chpid = chp->id; ccode = chsc(scmc_area); if (ccode > 0) { @@ -990,6 +1392,94 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) return ret; } +/* + * Entries for chpids on the system bus. + * This replaces /proc/chpids. + */ +static int +new_channel_path(int chpid) +{ + struct channel_path *chp; + int ret; + + chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL); + if (!chp) + return -ENOMEM; + + /* fill in status, etc. */ + chp->id = chpid; + chp->state = 1; + chp->dev.parent = &css[0]->device; + chp->dev.release = chp_release; + snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); + + /* Obtain channel path description and fill it in. */ + ret = chsc_determine_channel_path_description(chpid, &chp->desc); + if (ret) + goto out_free; + /* Get channel-measurement characteristics. */ + if (css_characteristics_avail && css_chsc_characteristics.scmc + && css_chsc_characteristics.secm) { + ret = chsc_get_channel_measurement_chars(chp); + if (ret) + goto out_free; + } else { + static int msg_done; + + if (!msg_done) { + printk(KERN_WARNING "cio: Channel measurements not " + "available, continuing.\n"); + msg_done = 1; + } + chp->cmg = -1; + } + + /* make it known to the system */ + ret = device_register(&chp->dev); + if (ret) { + printk(KERN_WARNING "%s: could not register %02x\n", + __func__, chpid); + goto out_free; + } + ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); + if (ret) { + device_unregister(&chp->dev); + goto out_free; + } + mutex_lock(&css[0]->mutex); + if (css[0]->cm_enabled) { + ret = chsc_add_chp_cmg_attr(chp); + if (ret) { + sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); + device_unregister(&chp->dev); + mutex_unlock(&css[0]->mutex); + goto out_free; + } + } + css[0]->chps[chpid] = chp; + mutex_unlock(&css[0]->mutex); + return ret; +out_free: + kfree(chp); + return ret; +} + +void * +chsc_get_chp_desc(struct subchannel *sch, int chp_no) +{ + struct channel_path *chp; + struct channel_path_desc *desc; + + chp = css[0]->chps[sch->schib.pmcw.chpid[chp_no]]; + if (!chp) + return NULL; + desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); + if (!desc) + return NULL; + memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); + return desc; +} + static int __init chsc_alloc_sei_area(void) { diff --git a/trunk/drivers/s390/cio/chsc.h b/trunk/drivers/s390/cio/chsc.h index 2ad81d11cf7b..0fb2b024208f 100644 --- a/trunk/drivers/s390/cio/chsc.h +++ b/trunk/drivers/s390/cio/chsc.h @@ -1,10 +1,9 @@ #ifndef S390_CHSC_H #define S390_CHSC_H -#include -#include -#include -#include "schid.h" +#define CHSC_SEI_ACC_CHPID 1 +#define CHSC_SEI_ACC_LINKADDR 2 +#define CHSC_SEI_ACC_FULLLINKADDR 3 #define CHSC_SDA_OC_MSS 0x2 @@ -34,9 +33,23 @@ struct channel_path_desc { u8 chpp; } __attribute__ ((packed)); -struct channel_path; +struct channel_path { + int id; + int state; + struct channel_path_desc desc; + /* Channel-measurement related stuff: */ + int cmg; + int shared; + void *cmg_chars; + struct device dev; +}; -extern void chsc_process_crw(void); +extern void s390_process_css( void ); +extern void chsc_validate_chpids(struct subchannel *); +extern void chpid_is_actually_online(int); +extern int css_get_ssd_info(struct subchannel *); +extern int chsc_process_crw(void); +extern int chp_process_crw(int, int); struct css_general_char { u64 : 41; @@ -69,26 +82,15 @@ struct css_chsc_char { extern struct css_general_char css_general_characteristics; extern struct css_chsc_char css_chsc_characteristics; -struct chsc_ssd_info { - u8 path_mask; - u8 fla_valid_mask; - struct chp_id chpid[8]; - u16 fla[8]; -}; -extern int chsc_get_ssd_info(struct subchannel_id schid, - struct chsc_ssd_info *ssd); extern int chsc_determine_css_characteristics(void); extern int css_characteristics_avail; +extern void *chsc_get_chp_desc(struct subchannel*, int); + extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); -int chsc_chp_vary(struct chp_id chpid, int on); -int chsc_determine_channel_path_description(struct chp_id chpid, - struct channel_path_desc *desc); -void chsc_chp_online(struct chp_id chpid); -void chsc_chp_offline(struct chp_id chpid); -int chsc_get_channel_measurement_chars(struct channel_path *chp); +#define to_channelpath(device) container_of(device, struct channel_path, dev) #endif diff --git a/trunk/drivers/s390/cio/cio.c b/trunk/drivers/s390/cio/cio.c index ea1defba5693..9cb129ab5be5 100644 --- a/trunk/drivers/s390/cio/cio.c +++ b/trunk/drivers/s390/cio/cio.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "airq.h" #include "cio.h" #include "css.h" @@ -30,7 +29,6 @@ #include "ioasm.h" #include "blacklist.h" #include "cio_debug.h" -#include "chp.h" #include "../s390mach.h" debug_info_t *cio_debug_msg_id; @@ -594,10 +592,9 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) err = -ENODEV; goto out; } - if (cio_is_console(sch->schid)) - sch->opm = 0xff; - else - sch->opm = chp_get_sch_opm(sch); + sch->opm = 0xff; + if (!cio_is_console(sch->schid)) + chsc_validate_chpids(sch); sch->lpm = sch->schib.pmcw.pam & sch->opm; CIO_DEBUG(KERN_INFO, 0, @@ -957,7 +954,6 @@ static void css_reset(void) { int i, ret; unsigned long long timeout; - struct chp_id chpid; /* Reset subchannels. */ for_each_subchannel(__shutdown_subchannel_easy, NULL); @@ -967,10 +963,8 @@ static void css_reset(void) __ctl_set_bit(14, 28); /* Temporarily reenable machine checks. */ local_mcck_enable(); - chp_id_init(&chpid); for (i = 0; i <= __MAX_CHPID; i++) { - chpid.id = i; - ret = rchp(chpid); + ret = rchp(i); if ((ret == 0) || (ret == 2)) /* * rchp either succeeded, or another rchp is already @@ -1054,19 +1048,37 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) do_reipl_asm(*((__u32*)&schid)); } -int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) +static struct schib __initdata ipl_schib; + +/* + * ipl_save_parameters gets called very early. It is not allowed to access + * anything in the bss section at all. The bss section is not cleared yet, + * but may contain some ipl parameters written by the firmware. + * These parameters (if present) are copied to 0x2000. + * To avoid corruption of the ipl parameters, all variables used by this + * function must reside on the stack or in the data section. + */ +void ipl_save_parameters(void) { struct subchannel_id schid; - struct schib schib; + unsigned int *ipl_ptr; + void *src, *dst; schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID; if (!schid.one) - return -ENODEV; - if (stsch(schid, &schib)) - return -ENODEV; - if (!schib.pmcw.dnv) - return -ENODEV; - iplinfo->devno = schib.pmcw.dev; - iplinfo->is_qdio = schib.pmcw.qf; - return 0; + return; + if (stsch(schid, &ipl_schib)) + return; + if (!ipl_schib.pmcw.dnv) + return; + ipl_devno = ipl_schib.pmcw.dev; + ipl_flags |= IPL_DEVNO_VALID; + if (!ipl_schib.pmcw.qf) + return; + ipl_flags |= IPL_PARMBLOCK_VALID; + ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR; + src = (void *)(unsigned long)*ipl_ptr; + dst = (void *)IPL_PARMBLOCK_ORIGIN; + memmove(dst, src, PAGE_SIZE); + *ipl_ptr = IPL_PARMBLOCK_ORIGIN; } diff --git a/trunk/drivers/s390/cio/cio.h b/trunk/drivers/s390/cio/cio.h index 7446c39951a7..35154a210357 100644 --- a/trunk/drivers/s390/cio/cio.h +++ b/trunk/drivers/s390/cio/cio.h @@ -1,11 +1,18 @@ #ifndef S390_CIO_H #define S390_CIO_H -#include -#include -#include -#include "chsc.h" #include "schid.h" +#include + +/* + * where we put the ssd info + */ +struct ssd_info { + __u8 valid:1; + __u8 type:7; /* subchannel type */ + __u8 chpid[8]; /* chpids */ + __u16 fla[8]; /* full link addresses */ +} __attribute__ ((packed)); /* * path management control word @@ -101,7 +108,7 @@ struct subchannel { struct schib schib; /* subchannel information block */ struct orb orb; /* operation request block */ struct ccw1 sense_ccw; /* static ccw for sense command */ - struct chsc_ssd_info ssd_info; /* subchannel description */ + struct ssd_info ssd_info; /* subchannel description */ struct device dev; /* entry in device tree */ struct css_driver *driver; } __attribute__ ((aligned(8))); diff --git a/trunk/drivers/s390/cio/cmf.c b/trunk/drivers/s390/cio/cmf.c index 28abd697be1a..90b22faabbf7 100644 --- a/trunk/drivers/s390/cio/cmf.c +++ b/trunk/drivers/s390/cio/cmf.c @@ -476,7 +476,7 @@ struct cmb_area { }; static struct cmb_area cmb_area = { - .lock = __SPIN_LOCK_UNLOCKED(cmb_area.lock), + .lock = SPIN_LOCK_UNLOCKED, .list = LIST_HEAD_INIT(cmb_area.list), .num_channels = 1024, }; diff --git a/trunk/drivers/s390/cio/css.c b/trunk/drivers/s390/cio/css.c index 27c6d9e55b23..fe0ace7aece8 100644 --- a/trunk/drivers/s390/cio/css.c +++ b/trunk/drivers/s390/cio/css.c @@ -20,9 +20,8 @@ #include "ioasm.h" #include "chsc.h" #include "device.h" -#include "idset.h" -#include "chp.h" +int need_rescan = 0; int css_init_done = 0; static int need_reprobe = 0; static int max_ssid = 0; @@ -126,52 +125,8 @@ void css_sch_device_unregister(struct subchannel *sch) mutex_unlock(&sch->reg_mutex); } -static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) -{ - int i; - int mask; - - memset(ssd, 0, sizeof(struct chsc_ssd_info)); - ssd->path_mask = pmcw->pim; - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (pmcw->pim & mask) { - chp_id_init(&ssd->chpid[i]); - ssd->chpid[i].id = pmcw->chpid[i]; - } - } -} - -static void ssd_register_chpids(struct chsc_ssd_info *ssd) -{ - int i; - int mask; - - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (ssd->path_mask & mask) - if (!chp_is_registered(ssd->chpid[i])) - chp_new(ssd->chpid[i]); - } -} - -void css_update_ssd_info(struct subchannel *sch) -{ - int ret; - - if (cio_is_console(sch->schid)) { - /* Console is initialized too early for functions requiring - * memory allocation. */ - ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); - } else { - ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info); - if (ret) - ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); - ssd_register_chpids(&sch->ssd_info); - } -} - -static int css_register_subchannel(struct subchannel *sch) +static int +css_register_subchannel(struct subchannel *sch) { int ret; @@ -180,7 +135,9 @@ static int css_register_subchannel(struct subchannel *sch) sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; - css_update_ssd_info(sch); + + css_get_ssd_info(sch); + /* make it known to the system */ ret = css_sch_device_register(sch); if (ret) { @@ -349,7 +306,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) return css_probe_device(schid); } -static void css_evaluate_subchannel(struct subchannel_id schid, int slow) +static int css_evaluate_subchannel(struct subchannel_id schid, int slow) { struct subchannel *sch; int ret; @@ -360,66 +317,53 @@ static void css_evaluate_subchannel(struct subchannel_id schid, int slow) put_device(&sch->dev); } else ret = css_evaluate_new_subchannel(schid, slow); - if (ret == -EAGAIN) - css_schedule_eval(schid); -} -static struct idset *slow_subchannel_set; -static spinlock_t slow_subchannel_lock; + return ret; +} -static int __init slow_subchannel_init(void) +static int +css_rescan_devices(struct subchannel_id schid, void *data) { - spin_lock_init(&slow_subchannel_lock); - slow_subchannel_set = idset_sch_new(); - if (!slow_subchannel_set) { - printk(KERN_WARNING "cio: could not allocate slow subchannel " - "set\n"); - return -ENOMEM; - } - return 0; + return css_evaluate_subchannel(schid, 1); } -subsys_initcall(slow_subchannel_init); - -static void css_slow_path_func(struct work_struct *unused) -{ +struct slow_subchannel { + struct list_head slow_list; struct subchannel_id schid; +}; +static LIST_HEAD(slow_subchannels_head); +static DEFINE_SPINLOCK(slow_subchannel_lock); + +static void +css_trigger_slow_path(struct work_struct *unused) +{ CIO_TRACE_EVENT(4, "slowpath"); + + if (need_rescan) { + need_rescan = 0; + for_each_subchannel(css_rescan_devices, NULL); + return; + } + spin_lock_irq(&slow_subchannel_lock); - init_subchannel_id(&schid); - while (idset_sch_get_first(slow_subchannel_set, &schid)) { - idset_sch_del(slow_subchannel_set, schid); + while (!list_empty(&slow_subchannels_head)) { + struct slow_subchannel *slow_sch = + list_entry(slow_subchannels_head.next, + struct slow_subchannel, slow_list); + + list_del_init(slow_subchannels_head.next); spin_unlock_irq(&slow_subchannel_lock); - css_evaluate_subchannel(schid, 1); + css_evaluate_subchannel(slow_sch->schid, 1); spin_lock_irq(&slow_subchannel_lock); + kfree(slow_sch); } spin_unlock_irq(&slow_subchannel_lock); } -static DECLARE_WORK(slow_path_work, css_slow_path_func); +DECLARE_WORK(slow_path_work, css_trigger_slow_path); struct workqueue_struct *slow_path_wq; -void css_schedule_eval(struct subchannel_id schid) -{ - unsigned long flags; - - spin_lock_irqsave(&slow_subchannel_lock, flags); - idset_sch_add(slow_subchannel_set, schid); - queue_work(slow_path_wq, &slow_path_work); - spin_unlock_irqrestore(&slow_subchannel_lock, flags); -} - -void css_schedule_eval_all(void) -{ - unsigned long flags; - - spin_lock_irqsave(&slow_subchannel_lock, flags); - idset_fill(slow_subchannel_set); - queue_work(slow_path_wq, &slow_path_work); - spin_unlock_irqrestore(&slow_subchannel_lock, flags); -} - /* Reprobe subchannel if unregistered. */ static int reprobe_subchannel(struct subchannel_id schid, void *data) { @@ -481,15 +425,34 @@ void css_schedule_reprobe(void) EXPORT_SYMBOL_GPL(css_schedule_reprobe); +/* + * Rescan for new devices. FIXME: This is slow. + * This function is called when we have lost CRWs due to overflows and we have + * to do subchannel housekeeping. + */ +void +css_reiterate_subchannels(void) +{ + css_clear_subchannel_slow_list(); + need_rescan = 1; +} + /* * Called from the machine check handler for subchannel report words. */ -void css_process_crw(int rsid1, int rsid2) +int +css_process_crw(int rsid1, int rsid2) { + int ret; struct subchannel_id mchk_schid; CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", rsid1, rsid2); + + if (need_rescan) + /* We need to iterate all subchannels anyway. */ + return -EAGAIN; + init_subchannel_id(&mchk_schid); mchk_schid.sch_no = rsid1; if (rsid2 != 0) @@ -500,7 +463,14 @@ void css_process_crw(int rsid1, int rsid2) * use stsch() to find out if the subchannel in question has come * or gone. */ - css_evaluate_subchannel(mchk_schid, 0); + ret = css_evaluate_subchannel(mchk_schid, 0); + if (ret == -EAGAIN) { + if (css_enqueue_subchannel_slow(mchk_schid)) { + css_clear_subchannel_slow_list(); + need_rescan = 1; + } + } + return ret; } static int __init @@ -775,6 +745,47 @@ struct bus_type css_bus_type = { subsys_initcall(init_channel_subsystem); +int +css_enqueue_subchannel_slow(struct subchannel_id schid) +{ + struct slow_subchannel *new_slow_sch; + unsigned long flags; + + new_slow_sch = kzalloc(sizeof(struct slow_subchannel), GFP_ATOMIC); + if (!new_slow_sch) + return -ENOMEM; + new_slow_sch->schid = schid; + spin_lock_irqsave(&slow_subchannel_lock, flags); + list_add_tail(&new_slow_sch->slow_list, &slow_subchannels_head); + spin_unlock_irqrestore(&slow_subchannel_lock, flags); + return 0; +} + +void +css_clear_subchannel_slow_list(void) +{ + unsigned long flags; + + spin_lock_irqsave(&slow_subchannel_lock, flags); + while (!list_empty(&slow_subchannels_head)) { + struct slow_subchannel *slow_sch = + list_entry(slow_subchannels_head.next, + struct slow_subchannel, slow_list); + + list_del_init(slow_subchannels_head.next); + kfree(slow_sch); + } + spin_unlock_irqrestore(&slow_subchannel_lock, flags); +} + + + +int +css_slow_subchannels_exist(void) +{ + return (!list_empty(&slow_subchannels_head)); +} + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(css_bus_type); EXPORT_SYMBOL_GPL(css_characteristics_avail); diff --git a/trunk/drivers/s390/cio/css.h b/trunk/drivers/s390/cio/css.h index 71fcfdc42800..ca2bab932a8a 100644 --- a/trunk/drivers/s390/cio/css.h +++ b/trunk/drivers/s390/cio/css.h @@ -4,11 +4,8 @@ #include #include #include -#include -#include #include -#include #include "schid.h" @@ -146,12 +143,13 @@ extern void css_sch_device_unregister(struct subchannel *); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); -extern void css_process_crw(int, int); +extern int css_process_crw(int, int); extern void css_reiterate_subchannels(void); -void css_update_ssd_info(struct subchannel *sch); #define __MAX_SUBCHANNEL 65535 #define __MAX_SSID 3 +#define __MAX_CHPID 255 +#define __MAX_CSSID 0 struct channel_subsystem { u8 cssid; @@ -187,12 +185,16 @@ int device_trigger_verify(struct subchannel *sch); void device_kill_pending_timer(struct subchannel *); /* Helper functions to build lists for the slow path. */ -void css_schedule_eval(struct subchannel_id schid); -void css_schedule_eval_all(void); +extern int css_enqueue_subchannel_slow(struct subchannel_id schid); +void css_walk_subchannel_slow_list(void (*fn)(unsigned long)); +void css_clear_subchannel_slow_list(void); +int css_slow_subchannels_exist(void); +extern int need_rescan; int sch_is_pseudo_sch(struct subchannel *); extern struct workqueue_struct *slow_path_wq; +extern struct work_struct slow_path_work; int subchannel_add_files (struct device *); extern struct attribute_group *subch_attr_groups[]; diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c index a23ff582db9d..e322111fb369 100644 --- a/trunk/drivers/s390/cio/device.c +++ b/trunk/drivers/s390/cio/device.c @@ -56,12 +56,13 @@ ccw_bus_match (struct device * dev, struct device_driver * drv) /* Store modalias string delimited by prefix/suffix string into buffer with * specified size. Return length of resulting string (excluding trailing '\0') * even if string doesn't fit buffer (snprintf semantics). */ -static int snprint_alias(char *buf, size_t size, +static int snprint_alias(char *buf, size_t size, const char *prefix, struct ccw_device_id *id, const char *suffix) { int len; - len = snprintf(buf, size, "ccw:t%04Xm%02X", id->cu_type, id->cu_model); + len = snprintf(buf, size, "%sccw:t%04Xm%02X", prefix, id->cu_type, + id->cu_model); if (len > size) return len; buf += len; @@ -84,40 +85,53 @@ static int ccw_uevent(struct device *dev, char **envp, int num_envp, struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); int i = 0; - int len = 0; - int ret; - char modalias_buf[30]; + int len; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); - if (ret) - return ret; + len = snprintf(buffer, buffer_size, "CU_TYPE=%04X", id->cu_type) + 1; + if (len > buffer_size || i >= num_envp) + return -ENOMEM; + envp[i++] = buffer; + buffer += len; + buffer_size -= len; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); - if (ret) - return ret; + len = snprintf(buffer, buffer_size, "CU_MODEL=%02X", id->cu_model) + 1; + if (len > buffer_size || i >= num_envp) + return -ENOMEM; + envp[i++] = buffer; + buffer += len; + buffer_size -= len; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); - if (ret) - return ret; + len = snprintf(buffer, buffer_size, "DEV_TYPE=%04X", id->dev_type) + 1; + if (len > buffer_size || i >= num_envp) + return -ENOMEM; + envp[i++] = buffer; + buffer += len; + buffer_size -= len; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); - if (ret) - return ret; + len = snprintf(buffer, buffer_size, "DEV_MODEL=%02X", + (unsigned char) id->dev_model) + 1; + if (len > buffer_size || i >= num_envp) + return -ENOMEM; + envp[i++] = buffer; + buffer += len; + buffer_size -= len; /* MODALIAS= */ - snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - return ret; + len = snprint_alias(buffer, buffer_size, "MODALIAS=", id, "") + 1; + if (len > buffer_size || i >= num_envp) + return -ENOMEM; + envp[i++] = buffer; + buffer += len; + buffer_size -= len; + + envp[i] = NULL; + + return 0; } struct bus_type ccw_bus_type; @@ -216,18 +230,12 @@ static ssize_t chpids_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); - struct chsc_ssd_info *ssd = &sch->ssd_info; + struct ssd_info *ssd = &sch->ssd_info; ssize_t ret = 0; int chp; - int mask; - for (chp = 0; chp < 8; chp++) { - mask = 0x80 >> chp; - if (ssd->path_mask & mask) - ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id); - else - ret += sprintf(buf + ret, "00 "); - } + for (chp = 0; chp < 8; chp++) + ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); ret += sprintf (buf+ret, "\n"); return min((ssize_t)PAGE_SIZE, ret); } @@ -272,7 +280,7 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf) struct ccw_device_id *id = &(cdev->id); int len; - len = snprint_alias(buf, PAGE_SIZE, id, "\n") + 1; + len = snprint_alias(buf, PAGE_SIZE, "", id, "\n") + 1; return len > PAGE_SIZE ? PAGE_SIZE : len; } @@ -290,10 +298,16 @@ int ccw_device_is_orphan(struct ccw_device *cdev) return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); } -static void ccw_device_unregister(struct ccw_device *cdev) +static void ccw_device_unregister(struct work_struct *work) { + struct ccw_device_private *priv; + struct ccw_device *cdev; + + priv = container_of(work, struct ccw_device_private, kick_work); + cdev = priv->cdev; if (test_and_clear_bit(1, &cdev->private->registered)) - device_del(&cdev->dev); + device_unregister(&cdev->dev); + put_device(&cdev->dev); } static void @@ -310,8 +324,11 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); - ccw_device_unregister(cdev); - put_device(&cdev->dev); + if (get_device(&cdev->dev)) { + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_unregister); + queue_work(ccw_device_work, &cdev->private->kick_work); + } return ; } sch = to_subchannel(cdev->dev.parent); @@ -396,60 +413,11 @@ ccw_device_set_online(struct ccw_device *cdev) return (ret == 0) ? -ENODEV : ret; } -static void online_store_handle_offline(struct ccw_device *cdev) -{ - if (cdev->private->state == DEV_STATE_DISCONNECTED) - ccw_device_remove_disconnected(cdev); - else if (cdev->drv && cdev->drv->set_offline) - ccw_device_set_offline(cdev); -} - -static int online_store_recog_and_online(struct ccw_device *cdev) -{ - int ret; - - /* Do device recognition, if needed. */ - if (cdev->id.cu_type == 0) { - ret = ccw_device_recognition(cdev); - if (ret) { - printk(KERN_WARNING"Couldn't start recognition " - "for device %s (ret=%d)\n", - cdev->dev.bus_id, ret); - return ret; - } - wait_event(cdev->private->wait_q, - cdev->private->flags.recog_done); - } - if (cdev->drv && cdev->drv->set_online) - ccw_device_set_online(cdev); - return 0; -} -static void online_store_handle_online(struct ccw_device *cdev, int force) -{ - int ret; - - ret = online_store_recog_and_online(cdev); - if (ret) - return; - if (force && cdev->private->state == DEV_STATE_BOXED) { - ret = ccw_device_stlck(cdev); - if (ret) { - printk(KERN_WARNING"ccw_device_stlck for device %s " - "returned %d!\n", cdev->dev.bus_id, ret); - return; - } - if (cdev->id.cu_type == 0) - cdev->private->state = DEV_STATE_NOT_OPER; - online_store_recog_and_online(cdev); - } - -} - -static ssize_t online_store (struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t +online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccw_device *cdev = to_ccwdev(dev); - int i, force; + int i, force, ret; char *tmp; if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) @@ -466,17 +434,51 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, force = 0; i = simple_strtoul(buf, &tmp, 16); } - - switch (i) { - case 0: - online_store_handle_offline(cdev); - break; - case 1: - online_store_handle_online(cdev, force); - break; - default: - count = -EINVAL; + if (i == 1) { + /* Do device recognition, if needed. */ + if (cdev->id.cu_type == 0) { + ret = ccw_device_recognition(cdev); + if (ret) { + printk(KERN_WARNING"Couldn't start recognition " + "for device %s (ret=%d)\n", + cdev->dev.bus_id, ret); + goto out; + } + wait_event(cdev->private->wait_q, + cdev->private->flags.recog_done); + } + if (cdev->drv && cdev->drv->set_online) + ccw_device_set_online(cdev); + } else if (i == 0) { + if (cdev->private->state == DEV_STATE_DISCONNECTED) + ccw_device_remove_disconnected(cdev); + else if (cdev->drv && cdev->drv->set_offline) + ccw_device_set_offline(cdev); + } + if (force && cdev->private->state == DEV_STATE_BOXED) { + ret = ccw_device_stlck(cdev); + if (ret) { + printk(KERN_WARNING"ccw_device_stlck for device %s " + "returned %d!\n", cdev->dev.bus_id, ret); + goto out; + } + /* Do device recognition, if needed. */ + if (cdev->id.cu_type == 0) { + cdev->private->state = DEV_STATE_NOT_OPER; + ret = ccw_device_recognition(cdev); + if (ret) { + printk(KERN_WARNING"Couldn't start recognition " + "for device %s (ret=%d)\n", + cdev->dev.bus_id, ret); + goto out; + } + wait_event(cdev->private->wait_q, + cdev->private->flags.recog_done); + } + if (cdev->drv && cdev->drv->set_online) + ccw_device_set_online(cdev); } + out: if (cdev->drv) module_put(cdev->drv->owner); atomic_set(&cdev->private->onoff, 0); @@ -546,10 +548,17 @@ static struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; -struct attribute_group *ccwdev_attr_groups[] = { - &ccwdev_attr_group, - NULL, -}; +static int +device_add_files (struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); +} + +static void +device_remove_files(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); +} /* this is a simple abstraction for device_register that sets the * correct bus type and adds the bus specific files */ @@ -564,6 +573,10 @@ static int ccw_device_register(struct ccw_device *cdev) return ret; set_bit(1, &cdev->private->registered); + if ((ret = device_add_files(dev))) { + if (test_and_clear_bit(1, &cdev->private->registered)) + device_del(dev); + } return ret; } @@ -635,6 +648,10 @@ ccw_device_add_changed(struct work_struct *work) return; } set_bit(1, &cdev->private->registered); + if (device_add_files(&cdev->dev)) { + if (test_and_clear_bit(1, &cdev->private->registered)) + device_unregister(&cdev->dev); + } } void ccw_device_do_unreg_rereg(struct work_struct *work) @@ -647,7 +664,9 @@ void ccw_device_do_unreg_rereg(struct work_struct *work) cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); - ccw_device_unregister(cdev); + device_remove_files(&cdev->dev); + if (test_and_clear_bit(1, &cdev->private->registered)) + device_del(&cdev->dev); PREPARE_WORK(&cdev->private->kick_work, ccw_device_add_changed); queue_work(ccw_device_work, &cdev->private->kick_work); @@ -686,7 +705,6 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, cdev->dev.parent = &sch->dev; cdev->dev.release = ccw_device_release; INIT_LIST_HEAD(&cdev->private->kick_work.entry); - cdev->dev.groups = ccwdev_attr_groups; /* Do first half of device_register. */ device_initialize(&cdev->dev); if (!get_device(&sch->dev)) { @@ -718,7 +736,6 @@ static int io_subchannel_recog(struct ccw_device *, struct subchannel *); static void sch_attach_device(struct subchannel *sch, struct ccw_device *cdev) { - css_update_ssd_info(sch); spin_lock_irq(sch->lock); sch->dev.driver_data = cdev; cdev->private->schid = sch->schid; @@ -854,7 +871,7 @@ io_subchannel_register(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); - css_update_ssd_info(sch); + /* * io_subchannel_register() will also be called after device * recognition has been done for a boxed device (which will already @@ -871,12 +888,6 @@ io_subchannel_register(struct work_struct *work) } goto out; } - /* - * Now we know this subchannel will stay, we can throw - * our delayed uevent. - */ - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); /* make it known to the system */ ret = ccw_device_register(cdev); if (ret) { @@ -1122,8 +1133,15 @@ io_subchannel_remove (struct subchannel *sch) sch->dev.driver_data = NULL; cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); - ccw_device_unregister(cdev); - put_device(&cdev->dev); + /* + * Put unregistration on workqueue to avoid livelocks on the css bus + * semaphore. + */ + if (get_device(&cdev->dev)) { + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_unregister); + queue_work(ccw_device_work, &cdev->private->kick_work); + } return 0; } diff --git a/trunk/drivers/s390/cio/device_fsm.c b/trunk/drivers/s390/cio/device_fsm.c index 898ec3b2bebb..089a3ddd6265 100644 --- a/trunk/drivers/s390/cio/device_fsm.c +++ b/trunk/drivers/s390/cio/device_fsm.c @@ -15,7 +15,6 @@ #include #include -#include #include "cio.h" #include "cio_debug.h" @@ -23,7 +22,6 @@ #include "device.h" #include "chsc.h" #include "ioasm.h" -#include "chp.h" int device_is_online(struct subchannel *sch) @@ -212,18 +210,14 @@ static void __recover_lost_chpids(struct subchannel *sch, int old_lpm) { int mask, i; - struct chp_id chpid; - chp_id_init(&chpid); for (i = 0; i<8; i++) { mask = 0x80 >> i; if (!(sch->lpm & mask)) continue; if (old_lpm & mask) continue; - chpid.id = sch->schib.pmcw.chpid[i]; - if (!chp_is_registered(chpid)) - css_schedule_eval_all(); + chpid_is_actually_online(sch->schib.pmcw.chpid[i]); } } diff --git a/trunk/drivers/s390/cio/device_ops.c b/trunk/drivers/s390/cio/device_ops.c index 16f59fcb66b1..7c7775aae38a 100644 --- a/trunk/drivers/s390/cio/device_ops.c +++ b/trunk/drivers/s390/cio/device_ops.c @@ -16,14 +16,12 @@ #include #include -#include #include "cio.h" #include "cio_debug.h" #include "css.h" #include "chsc.h" #include "device.h" -#include "chp.h" int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { @@ -608,12 +606,9 @@ void * ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) { struct subchannel *sch; - struct chp_id chpid; sch = to_subchannel(cdev->dev.parent); - chp_id_init(&chpid); - chpid.id = sch->schib.pmcw.chpid[chp_no]; - return chp_get_chp_desc(chpid); + return chsc_get_chp_desc(sch, chp_no); } // FIXME: these have to go: diff --git a/trunk/drivers/s390/cio/idset.c b/trunk/drivers/s390/cio/idset.c deleted file mode 100644 index 16ea828e99f7..000000000000 --- a/trunk/drivers/s390/cio/idset.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * drivers/s390/cio/idset.c - * - * Copyright IBM Corp. 2007 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include "idset.h" -#include "css.h" - -struct idset { - int num_ssid; - int num_id; - unsigned long bitmap[0]; -}; - -static inline unsigned long bitmap_size(int num_ssid, int num_id) -{ - return __BITOPS_WORDS(num_ssid * num_id) * sizeof(unsigned long); -} - -static struct idset *idset_new(int num_ssid, int num_id) -{ - struct idset *set; - - set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id), - GFP_KERNEL); - if (set) { - set->num_ssid = num_ssid; - set->num_id = num_id; - } - return set; -} - -void idset_free(struct idset *set) -{ - kfree(set); -} - -void idset_clear(struct idset *set) -{ - memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id)); -} - -void idset_fill(struct idset *set) -{ - memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id)); -} - -static inline void idset_add(struct idset *set, int ssid, int id) -{ - set_bit(ssid * set->num_id + id, set->bitmap); -} - -static inline void idset_del(struct idset *set, int ssid, int id) -{ - clear_bit(ssid * set->num_id + id, set->bitmap); -} - -static inline int idset_contains(struct idset *set, int ssid, int id) -{ - return test_bit(ssid * set->num_id + id, set->bitmap); -} - -static inline int idset_get_first(struct idset *set, int *ssid, int *id) -{ - int bitnum; - - bitnum = find_first_bit(set->bitmap, set->num_ssid * set->num_id); - if (bitnum >= set->num_ssid * set->num_id) - return 0; - *ssid = bitnum / set->num_id; - *id = bitnum % set->num_id; - return 1; -} - -struct idset *idset_sch_new(void) -{ - return idset_new(__MAX_SSID + 1, __MAX_SUBCHANNEL + 1); -} - -void idset_sch_add(struct idset *set, struct subchannel_id schid) -{ - idset_add(set, schid.ssid, schid.sch_no); -} - -void idset_sch_del(struct idset *set, struct subchannel_id schid) -{ - idset_del(set, schid.ssid, schid.sch_no); -} - -int idset_sch_contains(struct idset *set, struct subchannel_id schid) -{ - return idset_contains(set, schid.ssid, schid.sch_no); -} - -int idset_sch_get_first(struct idset *set, struct subchannel_id *schid) -{ - int ssid = 0; - int id = 0; - int rc; - - rc = idset_get_first(set, &ssid, &id); - if (rc) { - init_subchannel_id(schid); - schid->ssid = ssid; - schid->sch_no = id; - } - return rc; -} diff --git a/trunk/drivers/s390/cio/idset.h b/trunk/drivers/s390/cio/idset.h deleted file mode 100644 index 144466ab8c15..000000000000 --- a/trunk/drivers/s390/cio/idset.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * drivers/s390/cio/idset.h - * - * Copyright IBM Corp. 2007 - * Author(s): Peter Oberparleiter - */ - -#ifndef S390_IDSET_H -#define S390_IDSET_H S390_IDSET_H - -#include "schid.h" - -struct idset; - -void idset_free(struct idset *set); -void idset_clear(struct idset *set); -void idset_fill(struct idset *set); - -struct idset *idset_sch_new(void); -void idset_sch_add(struct idset *set, struct subchannel_id id); -void idset_sch_del(struct idset *set, struct subchannel_id id); -int idset_sch_contains(struct idset *set, struct subchannel_id id); -int idset_sch_get_first(struct idset *set, struct subchannel_id *id); - -#endif /* S390_IDSET_H */ diff --git a/trunk/drivers/s390/cio/ioasm.h b/trunk/drivers/s390/cio/ioasm.h index 7153dd959082..ad6d82940069 100644 --- a/trunk/drivers/s390/cio/ioasm.h +++ b/trunk/drivers/s390/cio/ioasm.h @@ -1,7 +1,6 @@ #ifndef S390_CIO_IOASM_H #define S390_CIO_IOASM_H -#include #include "schid.h" /* @@ -190,9 +189,9 @@ static inline int chsc(void *chsc_area) return cc; } -static inline int rchp(struct chp_id chpid) +static inline int rchp(int chpid) { - register struct chp_id reg1 asm ("1") = chpid; + register unsigned int reg1 asm ("1") = chpid; int ccode; asm volatile( diff --git a/trunk/drivers/s390/cio/qdio.c b/trunk/drivers/s390/cio/qdio.c index cba64e4cfcd4..05fac0733f3d 100644 --- a/trunk/drivers/s390/cio/qdio.c +++ b/trunk/drivers/s390/cio/qdio.c @@ -69,6 +69,7 @@ static const char version[] = "QDIO base support version 2"; static int qdio_performance_stats = 0; static int proc_perf_file_registration; +static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc; static struct qdio_perf_stats perf_stats; static int hydra_thinints; @@ -110,31 +111,6 @@ qdio_min(int a,int b) } /***************** SCRUBBER HELPER ROUTINES **********************/ -#ifdef CONFIG_64BIT -static inline void qdio_perf_stat_inc(atomic64_t *count) -{ - if (qdio_performance_stats) - atomic64_inc(count); -} - -static inline void qdio_perf_stat_dec(atomic64_t *count) -{ - if (qdio_performance_stats) - atomic64_dec(count); -} -#else /* CONFIG_64BIT */ -static inline void qdio_perf_stat_inc(atomic_t *count) -{ - if (qdio_performance_stats) - atomic_inc(count); -} - -static inline void qdio_perf_stat_dec(atomic_t *count) -{ - if (qdio_performance_stats) - atomic_dec(count); -} -#endif /* CONFIG_64BIT */ static inline __u64 qdio_get_micros(void) @@ -301,7 +277,8 @@ qdio_siga_sync(struct qdio_q *q, unsigned int gpr2, QDIO_DBF_TEXT4(0,trace,"sigasync"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); - qdio_perf_stat_inc(&perf_stats.siga_syncs); + if (qdio_performance_stats) + perf_stats.siga_syncs++; cc = do_siga_sync(q->schid, gpr2, gpr3); if (cc) @@ -346,7 +323,8 @@ qdio_siga_output(struct qdio_q *q) __u32 busy_bit; __u64 start_time=0; - qdio_perf_stat_inc(&perf_stats.siga_outs); + if (qdio_performance_stats) + perf_stats.siga_outs++; QDIO_DBF_TEXT4(0,trace,"sigaout"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -380,7 +358,8 @@ qdio_siga_input(struct qdio_q *q) QDIO_DBF_TEXT4(0,trace,"sigain"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); - qdio_perf_stat_inc(&perf_stats.siga_ins); + if (qdio_performance_stats) + perf_stats.siga_ins++; cc = do_siga_input(q->schid, q->mask); @@ -974,7 +953,8 @@ __qdio_outbound_processing(struct qdio_q *q) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - qdio_perf_stat_inc(&perf_stats.outbound_tl_runs_resched); + if (qdio_performance_stats) + o_p_c++; /* as we're sissies, we'll check next time */ if (likely(!atomic_read(&q->is_in_shutdown))) { qdio_mark_q(q); @@ -982,8 +962,10 @@ __qdio_outbound_processing(struct qdio_q *q) } return; } - qdio_perf_stat_inc(&perf_stats.outbound_tl_runs); - qdio_perf_stat_inc(&perf_stats.tl_runs); + if (qdio_performance_stats) { + o_p_nc++; + perf_stats.tl_runs++; + } /* see comment in qdio_kick_outbound_q */ siga_attempts=atomic_read(&q->busy_siga_counter); @@ -1157,6 +1139,17 @@ qdio_has_inbound_q_moved(struct qdio_q *q) { int i; + static int old_pcis=0; + static int old_thinints=0; + + if (qdio_performance_stats) { + if ((old_pcis==perf_stats.pcis)&& + (old_thinints==perf_stats.thinints)) + perf_stats.start_time_inbound=NOW; + else + old_pcis=perf_stats.pcis; + } + i=qdio_get_inbound_buffer_frontier(q); if ( (i!=GET_SAVED_FRONTIER(q)) || (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) { @@ -1344,7 +1337,10 @@ qdio_kick_inbound_handler(struct qdio_q *q) q->siga_error=0; q->error_status_flags=0; - qdio_perf_stat_inc(&perf_stats.inbound_cnt); + if (qdio_performance_stats) { + perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound; + perf_stats.inbound_cnt++; + } } static void @@ -1364,7 +1360,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) */ if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched); + if (qdio_performance_stats) + ii_p_c++; /* * as we might just be about to stop polling, we make * sure that we check again at least once more @@ -1372,7 +1369,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) tiqdio_sched_tl(); return; } - qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs); + if (qdio_performance_stats) + ii_p_nc++; if (unlikely(atomic_read(&q->is_in_shutdown))) { qdio_unmark_q(q); goto out; @@ -1414,7 +1412,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) for (i=0;ino_output_qs;i++) { oq = irq_ptr->output_qs[i]; if (!qdio_is_outbound_q_done(oq)) { - qdio_perf_stat_dec(&perf_stats.tl_runs); + if (qdio_performance_stats) + perf_stats.tl_runs--; __qdio_outbound_processing(oq); } } @@ -1453,7 +1452,8 @@ __qdio_inbound_processing(struct qdio_q *q) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - qdio_perf_stat_inc(&perf_stats.inbound_tl_runs_resched); + if (qdio_performance_stats) + i_p_c++; /* as we're sissies, we'll check next time */ if (likely(!atomic_read(&q->is_in_shutdown))) { qdio_mark_q(q); @@ -1461,8 +1461,10 @@ __qdio_inbound_processing(struct qdio_q *q) } return; } - qdio_perf_stat_inc(&perf_stats.inbound_tl_runs); - qdio_perf_stat_inc(&perf_stats.tl_runs); + if (qdio_performance_stats) { + i_p_nc++; + perf_stats.tl_runs++; + } again: if (qdio_has_inbound_q_moved(q)) { @@ -1508,7 +1510,8 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched); + if (qdio_performance_stats) + ii_p_c++; /* * as we might just be about to stop polling, we make * sure that we check again at least once more @@ -1599,7 +1602,8 @@ tiqdio_tl(unsigned long data) { QDIO_DBF_TEXT4(0,trace,"iqdio_tl"); - qdio_perf_stat_inc(&perf_stats.tl_runs); + if (qdio_performance_stats) + perf_stats.tl_runs++; tiqdio_inbound_checks(); } @@ -1910,7 +1914,10 @@ tiqdio_thinint_handler(void) { QDIO_DBF_TEXT4(0,trace,"thin_int"); - qdio_perf_stat_inc(&perf_stats.thinints); + if (qdio_performance_stats) { + perf_stats.thinints++; + perf_stats.start_time_inbound=NOW; + } /* SVS only when needed: * issue SVS to benefit from iqdio interrupt avoidance @@ -1965,12 +1972,17 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) int i; struct qdio_q *q; - qdio_perf_stat_inc(&perf_stats.pcis); + if (qdio_performance_stats) { + perf_stats.pcis++; + perf_stats.start_time_inbound=NOW; + } for (i=0;ino_input_qs;i++) { q=irq_ptr->input_qs[i]; if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT) qdio_mark_q(q); else { + if (qdio_performance_stats) + perf_stats.tl_runs--; __qdio_inbound_processing(q); } } @@ -1980,7 +1992,8 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) q=irq_ptr->output_qs[i]; if (qdio_is_outbound_q_done(q)) continue; - qdio_perf_stat_dec(&perf_stats.tl_runs); + if (qdio_performance_stats) + perf_stats.tl_runs--; if (!irq_ptr->sync_done_on_outb_pcis) SYNC_MEMORY; __qdio_outbound_processing(q); @@ -3450,12 +3463,18 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; /* This is the outbound handling of queues */ + if (qdio_performance_stats) + perf_stats.start_time_outbound=NOW; + qdio_do_qdio_fill_output(q,qidx,count,buffers); used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count; if (callflags&QDIO_FLAG_DONT_SIGA) { - qdio_perf_stat_inc(&perf_stats.outbound_cnt); + if (qdio_performance_stats) { + perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound; + perf_stats.outbound_cnt++; + } return; } if (q->is_iqdio_q) { @@ -3485,7 +3504,8 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, qdio_kick_outbound_q(q); } else { QDIO_DBF_TEXT3(0,trace, "fast-req"); - qdio_perf_stat_inc(&perf_stats.fast_reqs); + if (qdio_performance_stats) + perf_stats.fast_reqs++; } } /* @@ -3496,7 +3516,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, __qdio_outbound_processing(q); } - qdio_perf_stat_inc(&perf_stats.outbound_cnt); + if (qdio_performance_stats) { + perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound; + perf_stats.outbound_cnt++; + } } /* count must be 1 in iqdio */ @@ -3566,67 +3589,33 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset, return 0; #define _OUTP_IT(x...) c+=sprintf(buffer+c,x) -#ifdef CONFIG_64BIT - _OUTP_IT("Number of tasklet runs (total) : %li\n", - (long)atomic64_read(&perf_stats.tl_runs)); - _OUTP_IT("Inbound tasklet runs tried/retried : %li/%li\n", - (long)atomic64_read(&perf_stats.inbound_tl_runs), - (long)atomic64_read(&perf_stats.inbound_tl_runs_resched)); - _OUTP_IT("Inbound-thin tasklet runs tried/retried : %li/%li\n", - (long)atomic64_read(&perf_stats.inbound_thin_tl_runs), - (long)atomic64_read(&perf_stats.inbound_thin_tl_runs_resched)); - _OUTP_IT("Outbound tasklet runs tried/retried : %li/%li\n", - (long)atomic64_read(&perf_stats.outbound_tl_runs), - (long)atomic64_read(&perf_stats.outbound_tl_runs_resched)); + _OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c); + _OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c); + _OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c); + _OUTP_IT("Number of tasklet runs (total) : %lu\n", + perf_stats.tl_runs); _OUTP_IT("\n"); - _OUTP_IT("Number of SIGA sync's issued : %li\n", - (long)atomic64_read(&perf_stats.siga_syncs)); - _OUTP_IT("Number of SIGA in's issued : %li\n", - (long)atomic64_read(&perf_stats.siga_ins)); - _OUTP_IT("Number of SIGA out's issued : %li\n", - (long)atomic64_read(&perf_stats.siga_outs)); - _OUTP_IT("Number of PCIs caught : %li\n", - (long)atomic64_read(&perf_stats.pcis)); - _OUTP_IT("Number of adapter interrupts caught : %li\n", - (long)atomic64_read(&perf_stats.thinints)); - _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %li\n", - (long)atomic64_read(&perf_stats.fast_reqs)); + _OUTP_IT("Number of SIGA sync's issued : %lu\n", + perf_stats.siga_syncs); + _OUTP_IT("Number of SIGA in's issued : %lu\n", + perf_stats.siga_ins); + _OUTP_IT("Number of SIGA out's issued : %lu\n", + perf_stats.siga_outs); + _OUTP_IT("Number of PCIs caught : %lu\n", + perf_stats.pcis); + _OUTP_IT("Number of adapter interrupts caught : %lu\n", + perf_stats.thinints); + _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n", + perf_stats.fast_reqs); _OUTP_IT("\n"); - _OUTP_IT("Number of inbound transfers : %li\n", - (long)atomic64_read(&perf_stats.inbound_cnt)); - _OUTP_IT("Number of do_QDIOs outbound : %li\n", - (long)atomic64_read(&perf_stats.outbound_cnt)); -#else /* CONFIG_64BIT */ - _OUTP_IT("Number of tasklet runs (total) : %i\n", - atomic_read(&perf_stats.tl_runs)); - _OUTP_IT("Inbound tasklet runs tried/retried : %i/%i\n", - atomic_read(&perf_stats.inbound_tl_runs), - atomic_read(&perf_stats.inbound_tl_runs_resched)); - _OUTP_IT("Inbound-thin tasklet runs tried/retried : %i/%i\n", - atomic_read(&perf_stats.inbound_thin_tl_runs), - atomic_read(&perf_stats.inbound_thin_tl_runs_resched)); - _OUTP_IT("Outbound tasklet runs tried/retried : %i/%i\n", - atomic_read(&perf_stats.outbound_tl_runs), - atomic_read(&perf_stats.outbound_tl_runs_resched)); - _OUTP_IT("\n"); - _OUTP_IT("Number of SIGA sync's issued : %i\n", - atomic_read(&perf_stats.siga_syncs)); - _OUTP_IT("Number of SIGA in's issued : %i\n", - atomic_read(&perf_stats.siga_ins)); - _OUTP_IT("Number of SIGA out's issued : %i\n", - atomic_read(&perf_stats.siga_outs)); - _OUTP_IT("Number of PCIs caught : %i\n", - atomic_read(&perf_stats.pcis)); - _OUTP_IT("Number of adapter interrupts caught : %i\n", - atomic_read(&perf_stats.thinints)); - _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %i\n", - atomic_read(&perf_stats.fast_reqs)); - _OUTP_IT("\n"); - _OUTP_IT("Number of inbound transfers : %i\n", - atomic_read(&perf_stats.inbound_cnt)); - _OUTP_IT("Number of do_QDIOs outbound : %i\n", - atomic_read(&perf_stats.outbound_cnt)); -#endif /* CONFIG_64BIT */ + _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n", + perf_stats.inbound_time); + _OUTP_IT("Number of inbound transfers : %lu\n", + perf_stats.inbound_cnt); + _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n", + perf_stats.outbound_time); + _OUTP_IT("Number of do_QDIOs outbound : %lu\n", + perf_stats.outbound_cnt); _OUTP_IT("\n"); return c; @@ -3653,6 +3642,8 @@ qdio_add_procfs_entry(void) static void qdio_remove_procfs_entry(void) { + perf_stats.tl_runs=0; + if (!proc_perf_file_registration) /* means if it went ok earlier */ remove_proc_entry(QDIO_PERF,&proc_root); } @@ -3680,38 +3671,13 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count qdio_performance_stats = i; if (i==0) { /* reset perf. stat. info */ -#ifdef CONFIG_64BIT - atomic64_set(&perf_stats.tl_runs, 0); - atomic64_set(&perf_stats.outbound_tl_runs, 0); - atomic64_set(&perf_stats.inbound_tl_runs, 0); - atomic64_set(&perf_stats.inbound_tl_runs_resched, 0); - atomic64_set(&perf_stats.inbound_thin_tl_runs, 0); - atomic64_set(&perf_stats.inbound_thin_tl_runs_resched, - 0); - atomic64_set(&perf_stats.siga_outs, 0); - atomic64_set(&perf_stats.siga_ins, 0); - atomic64_set(&perf_stats.siga_syncs, 0); - atomic64_set(&perf_stats.pcis, 0); - atomic64_set(&perf_stats.thinints, 0); - atomic64_set(&perf_stats.fast_reqs, 0); - atomic64_set(&perf_stats.outbound_cnt, 0); - atomic64_set(&perf_stats.inbound_cnt, 0); -#else /* CONFIG_64BIT */ - atomic_set(&perf_stats.tl_runs, 0); - atomic_set(&perf_stats.outbound_tl_runs, 0); - atomic_set(&perf_stats.inbound_tl_runs, 0); - atomic_set(&perf_stats.inbound_tl_runs_resched, 0); - atomic_set(&perf_stats.inbound_thin_tl_runs, 0); - atomic_set(&perf_stats.inbound_thin_tl_runs_resched, 0); - atomic_set(&perf_stats.siga_outs, 0); - atomic_set(&perf_stats.siga_ins, 0); - atomic_set(&perf_stats.siga_syncs, 0); - atomic_set(&perf_stats.pcis, 0); - atomic_set(&perf_stats.thinints, 0); - atomic_set(&perf_stats.fast_reqs, 0); - atomic_set(&perf_stats.outbound_cnt, 0); - atomic_set(&perf_stats.inbound_cnt, 0); -#endif /* CONFIG_64BIT */ + i_p_nc = 0; + i_p_c = 0; + ii_p_nc = 0; + ii_p_c = 0; + o_p_nc = 0; + o_p_c = 0; + memset(&perf_stats, 0, sizeof(struct qdio_perf_stats)); } } else { QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); diff --git a/trunk/drivers/s390/cio/qdio.h b/trunk/drivers/s390/cio/qdio.h index 2895392eaae4..ec9af72b2afc 100644 --- a/trunk/drivers/s390/cio/qdio.h +++ b/trunk/drivers/s390/cio/qdio.h @@ -406,43 +406,21 @@ do_clear_global_summary(void) #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 struct qdio_perf_stats { -#ifdef CONFIG_64BIT - atomic64_t tl_runs; - atomic64_t outbound_tl_runs; - atomic64_t outbound_tl_runs_resched; - atomic64_t inbound_tl_runs; - atomic64_t inbound_tl_runs_resched; - atomic64_t inbound_thin_tl_runs; - atomic64_t inbound_thin_tl_runs_resched; - - atomic64_t siga_outs; - atomic64_t siga_ins; - atomic64_t siga_syncs; - atomic64_t pcis; - atomic64_t thinints; - atomic64_t fast_reqs; - - atomic64_t outbound_cnt; - atomic64_t inbound_cnt; -#else /* CONFIG_64BIT */ - atomic_t tl_runs; - atomic_t outbound_tl_runs; - atomic_t outbound_tl_runs_resched; - atomic_t inbound_tl_runs; - atomic_t inbound_tl_runs_resched; - atomic_t inbound_thin_tl_runs; - atomic_t inbound_thin_tl_runs_resched; - - atomic_t siga_outs; - atomic_t siga_ins; - atomic_t siga_syncs; - atomic_t pcis; - atomic_t thinints; - atomic_t fast_reqs; - - atomic_t outbound_cnt; - atomic_t inbound_cnt; -#endif /* CONFIG_64BIT */ + unsigned long tl_runs; + + unsigned long siga_outs; + unsigned long siga_ins; + unsigned long siga_syncs; + unsigned long pcis; + unsigned long thinints; + unsigned long fast_reqs; + + __u64 start_time_outbound; + unsigned long outbound_cnt; + unsigned long outbound_time; + __u64 start_time_inbound; + unsigned long inbound_cnt; + unsigned long inbound_time; }; /* unlikely as the later the better */ diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index 5aac0ec36368..bf37cdf43fae 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -423,25 +423,27 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int length; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); - if (retval) - return retval; - + envp[0] = buffer; + length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X", + ap_dev->device_type); + if (buffer_size - length <= 0) + return -ENOMEM; + buffer += length; + buffer_size -= length; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); - - envp[i] = NULL; - return retval; + envp[1] = buffer; + length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X", + ap_dev->device_type); + if (buffer_size - length <= 0) + return -ENOMEM; + envp[2] = NULL; + return 0; } static struct bus_type ap_bus_type = { diff --git a/trunk/drivers/s390/net/claw.c b/trunk/drivers/s390/net/claw.c index 6dd64d0c8d45..7809a79feec7 100644 --- a/trunk/drivers/s390/net/claw.c +++ b/trunk/drivers/s390/net/claw.c @@ -3525,8 +3525,8 @@ unpack_read(struct net_device *dev ) memcpy(skb_put(skb,len_of_data), privptr->p_mtc_envelope, len_of_data); + skb->mac.raw=skb->data; skb->dev=dev; - skb_reset_mac_header(skb); skb->protocol=htons(ETH_P_IP); skb->ip_summed=CHECKSUM_UNNECESSARY; privptr->stats.rx_packets++; diff --git a/trunk/drivers/s390/net/ctcmain.c b/trunk/drivers/s390/net/ctcmain.c index b20fd0681733..0d6d5fcc128b 100644 --- a/trunk/drivers/s390/net/ctcmain.c +++ b/trunk/drivers/s390/net/ctcmain.c @@ -455,7 +455,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) return; } skb_put(pskb, header->length); - skb_reset_mac_header(pskb); + pskb->mac.raw = pskb->data; len -= header->length; skb = dev_alloc_skb(pskb->len); if (!skb) { @@ -472,9 +472,8 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) privptr->stats.rx_dropped++; return; } - skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len), - pskb->len); - skb_reset_mac_header(skb); + memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len); + skb->mac.raw = skb->data; skb->dev = pskb->dev; skb->protocol = pskb->protocol; pskb->ip_summed = CHECKSUM_UNNECESSARY; @@ -707,8 +706,7 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg) spin_unlock(&ch->collect_lock); return; } - ch->trans_skb->data = ch->trans_skb_data; - skb_reset_tail_pointer(ch->trans_skb); + ch->trans_skb->tail = ch->trans_skb->data = ch->trans_skb_data; ch->trans_skb->len = 0; if (ch->prof.maxmulti < (ch->collect_len + 2)) ch->prof.maxmulti = ch->collect_len + 2; @@ -717,9 +715,8 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg) *((__u16 *) skb_put(ch->trans_skb, 2)) = ch->collect_len + 2; i = 0; while ((skb = skb_dequeue(&ch->collect_queue))) { - skb_copy_from_linear_data(skb, skb_put(ch->trans_skb, - skb->len), - skb->len); + memcpy(skb_put(ch->trans_skb, skb->len), skb->data, + skb->len); privptr->stats.tx_packets++; privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH; atomic_dec(&skb->users); @@ -834,8 +831,7 @@ ch_action_rx(fsm_instance * fi, int event, void *arg) ctc_unpack_skb(ch, skb); } again: - skb->data = ch->trans_skb_data; - skb_reset_tail_pointer(skb); + skb->data = skb->tail = ch->trans_skb_data; skb->len = 0; if (ctc_checkalloc_buffer(ch, 1)) return; @@ -1642,19 +1638,21 @@ add_channel(struct ccw_device *cdev, enum channel_types type) struct channel *ch; DBF_TEXT(trace, 2, __FUNCTION__); - ch = kzalloc(sizeof(struct channel), GFP_KERNEL); - if (!ch) { + if ((ch = + (struct channel *) kmalloc(sizeof (struct channel), + GFP_KERNEL)) == NULL) { ctc_pr_warn("ctc: Out of memory in add_channel\n"); return -1; } - /* assure all flags and counters are reset */ - ch->ccw = kzalloc(8 * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); - if (!ch->ccw) { + memset(ch, 0, sizeof (struct channel)); + if ((ch->ccw = kmalloc(8*sizeof(struct ccw1), + GFP_KERNEL | GFP_DMA)) == NULL) { kfree(ch); ctc_pr_warn("ctc: Out of memory in add_channel\n"); return -1; } + memset(ch->ccw, 0, 8*sizeof(struct ccw1)); // assure all flags and counters are reset /** * "static" ccws are used in the following way: @@ -1694,14 +1692,15 @@ add_channel(struct ccw_device *cdev, enum channel_types type) return -1; } fsm_newstate(ch->fsm, CH_STATE_IDLE); - ch->irb = kzalloc(sizeof(struct irb), GFP_KERNEL); - if (!ch->irb) { + if ((ch->irb = kmalloc(sizeof (struct irb), + GFP_KERNEL)) == NULL) { ctc_pr_warn("ctc: Out of memory in add_channel\n"); kfree_fsm(ch->fsm); kfree(ch->ccw); kfree(ch); return -1; } + memset(ch->irb, 0, sizeof (struct irb)); while (*c && less_than((*c)->id, ch->id)) c = &(*c)->next; if (*c && (!strncmp((*c)->id, ch->id, CTC_ID_SIZE))) { @@ -2227,8 +2226,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) * IDAL support in CTC is broken, so we have to * care about skb's above 2G ourselves. */ - hi = ((unsigned long)skb_tail_pointer(skb) + - LL_HEADER_LENGTH) >> 31; + hi = ((unsigned long) skb->tail + LL_HEADER_LENGTH) >> 31; if (hi) { nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!nskb) { @@ -2264,12 +2262,11 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) return -EBUSY; } - skb_reset_tail_pointer(ch->trans_skb); + ch->trans_skb->tail = ch->trans_skb->data; ch->trans_skb->len = 0; ch->ccw[1].count = skb->len; - skb_copy_from_linear_data(skb, skb_put(ch->trans_skb, - skb->len), - skb->len); + memcpy(skb_put(ch->trans_skb, skb->len), skb->data, + skb->len); atomic_dec(&skb->users); dev_kfree_skb_irq(skb); ccw_idx = 0; @@ -2748,13 +2745,14 @@ ctc_probe_device(struct ccwgroup_device *cgdev) if (!get_device(&cgdev->dev)) return -ENODEV; - priv = kzalloc(sizeof(struct ctc_priv), GFP_KERNEL); + priv = kmalloc(sizeof (struct ctc_priv), GFP_KERNEL); if (!priv) { ctc_pr_err("%s: Out of memory\n", __func__); put_device(&cgdev->dev); return -ENOMEM; } + memset(priv, 0, sizeof (struct ctc_priv)); rc = ctc_add_files(&cgdev->dev); if (rc) { kfree(priv); @@ -2795,9 +2793,10 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device, DBF_TEXT(setup, 3, __FUNCTION__); if (alloc_device) { - dev = kzalloc(sizeof(struct net_device), GFP_KERNEL); + dev = kmalloc(sizeof (struct net_device), GFP_KERNEL); if (!dev) return NULL; + memset(dev, 0, sizeof (struct net_device)); } dev->priv = privptr; diff --git a/trunk/drivers/s390/net/lcs.c b/trunk/drivers/s390/net/lcs.c index 08a994fdd1a4..ecca1046714e 100644 --- a/trunk/drivers/s390/net/lcs.c +++ b/trunk/drivers/s390/net/lcs.c @@ -1576,7 +1576,7 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, header->offset = card->tx_buffer->count; header->type = card->lan_type; header->slot = card->portno; - skb_copy_from_linear_data(skb, header + 1, skb->len); + memcpy(header + 1, skb->data, skb->len); spin_unlock(&card->lock); card->stats.tx_bytes += skb->len; card->stats.tx_packets++; @@ -1784,6 +1784,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) card->stats.rx_dropped++; return; } + skb->dev = card->dev; memcpy(skb_put(skb, skb_len), skb_data, skb_len); skb->protocol = card->lan_type_trans(skb, card->dev); card->stats.rx_bytes += skb_len; diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index e10e85e85c84..594320ca1b7c 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -635,7 +635,7 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, return; } skb_put(pskb, header->next); - skb_reset_mac_header(pskb); + pskb->mac.raw = pskb->data; skb = dev_alloc_skb(pskb->len); if (!skb) { PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n", @@ -645,9 +645,8 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, privptr->stats.rx_dropped++; return; } - skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len), - pskb->len); - skb_reset_mac_header(skb); + memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len); + skb->mac.raw = skb->data; skb->dev = pskb->dev; skb->protocol = pskb->protocol; pskb->ip_summed = CHECKSUM_UNNECESSARY; @@ -690,8 +689,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) msg->length, conn->max_buffsize); return; } - conn->rx_buff->data = conn->rx_buff->head; - skb_reset_tail_pointer(conn->rx_buff); + conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, msg->length, NULL); @@ -737,17 +735,14 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) } } } - conn->tx_buff->data = conn->tx_buff->head; - skb_reset_tail_pointer(conn->tx_buff); + conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; conn->tx_buff->len = 0; spin_lock_irqsave(&conn->collect_lock, saveflags); while ((skb = skb_dequeue(&conn->collect_queue))) { header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN; memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); - skb_copy_from_linear_data(skb, - skb_put(conn->tx_buff, skb->len), - skb->len); + memcpy(skb_put(conn->tx_buff, skb->len), skb->data, skb->len); txbytes += skb->len; txpackets++; stat_maxcq++; @@ -1169,8 +1164,8 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, * Copy the skb to a new allocated skb in lowmem only if the * data is located above 2G in memory or tailroom is < 2. */ - unsigned long hi = ((unsigned long)(skb_tail_pointer(skb) + - NETIUCV_HDRLEN)) >> 31; + unsigned long hi = + ((unsigned long)(skb->tail + NETIUCV_HDRLEN)) >> 31; int copied = 0; if (hi || (skb_tailroom(skb) < 2)) { nskb = alloc_skb(skb->len + NETIUCV_HDRLEN + diff --git a/trunk/drivers/s390/net/qeth.h b/trunk/drivers/s390/net/qeth.h index b34eb82edd98..84b108d7c7fd 100644 --- a/trunk/drivers/s390/net/qeth.h +++ b/trunk/drivers/s390/net/qeth.h @@ -288,7 +288,6 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) */ #define IF_NAME_LEN 16 #define QETH_TX_TIMEOUT 100 * HZ -#define QETH_RCD_TIMEOUT 60 * HZ #define QETH_HEADER_SIZE 32 #define MAX_PORTNO 15 #define QETH_FAKE_LL_LEN_ETH ETH_HLEN @@ -583,8 +582,6 @@ enum qeth_channel_states { CH_STATE_ACTIVATING, CH_STATE_HALTED, CH_STATE_STOPPED, - CH_STATE_RCD, - CH_STATE_RCD_DONE, }; /** * card state machine diff --git a/trunk/drivers/s390/net/qeth_eddp.c b/trunk/drivers/s390/net/qeth_eddp.c index dd7034fbfff8..7c735e1fe063 100644 --- a/trunk/drivers/s390/net/qeth_eddp.c +++ b/trunk/drivers/s390/net/qeth_eddp.c @@ -267,8 +267,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, QETH_DBF_TEXT(trace, 5, "eddpcdtc"); if (skb_shinfo(eddp->skb)->nr_frags == 0) { - skb_copy_from_linear_data_offset(eddp->skb, eddp->skb_offset, - dst, len); + memcpy(dst, eddp->skb->data + eddp->skb_offset, len); *hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len, *hcsum); eddp->skb_offset += len; @@ -417,7 +416,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, eddp->skb_offset += VLAN_HLEN; #endif /* CONFIG_QETH_VLAN */ } - tcph = tcp_hdr(eddp->skb); + tcph = eddp->skb->h.th; while (eddp->skb_offset < eddp->skb->len) { data_len = min((int)skb_shinfo(eddp->skb)->gso_size, (int)(eddp->skb->len - eddp->skb_offset)); @@ -474,24 +473,20 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, QETH_DBF_TEXT(trace, 5, "eddpficx"); /* create our segmentation headers and copy original headers */ if (skb->protocol == htons(ETH_P_IP)) - eddp = qeth_eddp_create_eddp_data(qhdr, - skb_network_header(skb), - ip_hdrlen(skb), - skb_transport_header(skb), - tcp_hdrlen(skb)); + eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph, + skb->nh.iph->ihl*4, + (u8 *)skb->h.th, skb->h.th->doff*4); else - eddp = qeth_eddp_create_eddp_data(qhdr, - skb_network_header(skb), - sizeof(struct ipv6hdr), - skb_transport_header(skb), - tcp_hdrlen(skb)); + eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h, + sizeof(struct ipv6hdr), + (u8 *)skb->h.th, skb->h.th->doff*4); if (eddp == NULL) { QETH_DBF_TEXT(trace, 2, "eddpfcnm"); return -ENOMEM; } if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { - skb_set_mac_header(skb, sizeof(struct qeth_hdr)); + skb->mac.raw = (skb->data) + sizeof(struct qeth_hdr); memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); #ifdef CONFIG_QETH_VLAN if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) { @@ -595,13 +590,12 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb, QETH_DBF_TEXT(trace, 5, "creddpct"); if (skb->protocol == htons(ETH_P_IP)) ctx = qeth_eddp_create_context_generic(card, skb, - (sizeof(struct qeth_hdr) + - ip_hdrlen(skb) + - tcp_hdrlen(skb))); + sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 + + skb->h.th->doff*4); else if (skb->protocol == htons(ETH_P_IPV6)) ctx = qeth_eddp_create_context_generic(card, skb, sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) + - tcp_hdrlen(skb)); + skb->h.th->doff*4); else QETH_DBF_TEXT(trace, 2, "cetcpinv"); diff --git a/trunk/drivers/s390/net/qeth_main.c b/trunk/drivers/s390/net/qeth_main.c index 6fd8870551d3..d8a86f5af379 100644 --- a/trunk/drivers/s390/net/qeth_main.c +++ b/trunk/drivers/s390/net/qeth_main.c @@ -315,8 +315,7 @@ qeth_alloc_card(void) } static long -__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm, - struct irb *irb) +__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb) { if (!IS_ERR(irb)) return 0; @@ -331,14 +330,6 @@ __qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm, PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); QETH_DBF_TEXT(trace, 2, "ckirberr"); QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT); - if (intparm == QETH_RCD_PARM) { - struct qeth_card *card = CARD_FROM_CDEV(cdev); - - if (card && (card->data.ccwdev == cdev)) { - card->data.state = CH_STATE_DOWN; - wake_up(&card->wait_q); - } - } break; default: PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), @@ -410,7 +401,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) QETH_DBF_TEXT(trace,5,"irq"); - if (__qeth_check_irb_error(cdev, intparm, irb)) + if (__qeth_check_irb_error(cdev, irb)) return; cstat = irb->scsw.cstat; dstat = irb->scsw.dstat; @@ -438,8 +429,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) channel->state = CH_STATE_HALTED; /*let's wake up immediately on data channel*/ - if ((channel == &card->data) && (intparm != 0) && - (intparm != QETH_RCD_PARM)) + if ((channel == &card->data) && (intparm != 0)) goto out; if (intparm == QETH_CLEAR_CHANNEL_PARM) { @@ -463,10 +453,6 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) HEXDUMP16(WARN,"irb: ",irb); HEXDUMP16(WARN,"sense data: ",irb->ecw); } - if (intparm == QETH_RCD_PARM) { - channel->state = CH_STATE_DOWN; - goto out; - } rc = qeth_get_problem(cdev,irb); if (rc) { qeth_schedule_recovery(card); @@ -474,10 +460,6 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } } - if (intparm == QETH_RCD_PARM) { - channel->state = CH_STATE_RCD_DONE; - goto out; - } if (intparm) { buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm); buffer->state = BUF_STATE_PROCESSED; @@ -1222,54 +1204,6 @@ qeth_probe_device(struct ccwgroup_device *gdev) } -static int qeth_read_conf_data(struct qeth_card *card, void **buffer, - int *length) -{ - struct ciw *ciw; - char *rcd_buf; - int ret; - struct qeth_channel *channel = &card->data; - unsigned long flags; - - /* - * scan for RCD command in extended SenseID data - */ - ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD); - if (!ciw || ciw->cmd == 0) - return -EOPNOTSUPP; - rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); - if (!rcd_buf) - return -ENOMEM; - - channel->ccw.cmd_code = ciw->cmd; - channel->ccw.cda = (__u32) __pa (rcd_buf); - channel->ccw.count = ciw->count; - channel->ccw.flags = CCW_FLAG_SLI; - channel->state = CH_STATE_RCD; - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); - ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw, - QETH_RCD_PARM, LPM_ANYPATH, 0, - QETH_RCD_TIMEOUT); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); - if (!ret) - wait_event(card->wait_q, - (channel->state == CH_STATE_RCD_DONE || - channel->state == CH_STATE_DOWN)); - if (channel->state == CH_STATE_DOWN) - ret = -EIO; - else - channel->state = CH_STATE_DOWN; - if (ret) { - kfree(rcd_buf); - *buffer = NULL; - *length = 0; - } else { - *length = ciw->count; - *buffer = rcd_buf; - } - return ret; -} - static int qeth_get_unitaddr(struct qeth_card *card) { @@ -1278,9 +1212,9 @@ qeth_get_unitaddr(struct qeth_card *card) int rc; QETH_DBF_TEXT(setup, 2, "getunit"); - rc = qeth_read_conf_data(card, (void **) &prcd, &length); + rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length); if (rc) { - PRINT_ERR("qeth_read_conf_data for device %s returned %i\n", + PRINT_ERR("read_conf_data for device %s returned %i\n", CARD_DDEV_ID(card), rc); return rc; } @@ -1289,7 +1223,6 @@ qeth_get_unitaddr(struct qeth_card *card) card->info.cula = prcd[63]; card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && (prcd[0x11] == _ascebc['M'])); - kfree(prcd); return 0; } @@ -2345,7 +2278,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) (card->info.link_type == QETH_LINK_TYPE_LANE_TR)) return tr_type_trans(skb,dev); #endif /* CONFIG_TR */ - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN ); eth = eth_hdr(skb); @@ -2373,9 +2306,9 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, struct iphdr *ip_hdr; QETH_DBF_TEXT(trace,5,"skbfktr"); - skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR); + skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR; /* this is a fake ethernet header */ - fake_hdr = tr_hdr(skb); + fake_hdr = (struct trh_hdr *) skb->mac.raw; /* the destination MAC address */ switch (skb->pkt_type){ @@ -2426,9 +2359,9 @@ qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb, struct iphdr *ip_hdr; QETH_DBF_TEXT(trace,5,"skbfketh"); - skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_ETH); + skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH; /* this is a fake ethernet header */ - fake_hdr = eth_hdr(skb); + fake_hdr = (struct ethhdr *) skb->mac.raw; /* the destination MAC address */ switch (skb->pkt_type){ @@ -2528,7 +2461,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, if (card->options.fake_ll) qeth_rebuild_skb_fake_ll(card, skb, hdr); else - skb_reset_mac_header(skb); + skb->mac.raw = skb->data; skb->ip_summed = card->options.checksum_type; if (card->options.checksum_type == HW_CHECKSUMMING){ if ( (hdr->hdr.l3.ext_flags & @@ -2568,8 +2501,7 @@ qeth_process_inbound_buffer(struct qeth_card *card, vlan_tag = qeth_rebuild_skb(card, skb, hdr); else { /*in case of OSN*/ skb_push(skb, sizeof(struct qeth_hdr)); - skb_copy_to_linear_data(skb, hdr, - sizeof(struct qeth_hdr)); + memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ @@ -3846,11 +3778,9 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) } /* try something else */ if (skb->protocol == ETH_P_IPV6) - return (skb_network_header(skb)[24] == 0xff) ? - RTN_MULTICAST : 0; + return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0; else if (skb->protocol == ETH_P_IP) - return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? - RTN_MULTICAST : 0; + return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0; /* ... */ if (!memcmp(skb->data, skb->dev->broadcast, 6)) return RTN_BROADCAST; @@ -3888,20 +3818,18 @@ qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, return card->info.is_multicast_different & (card->qdio.no_out_queues - 1); if (card->qdio.do_prio_queueing && (ipv == 4)) { - const u8 tos = ip_hdr(skb)->tos; - if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_TOS){ - if (tos & IP_TOS_NOTIMPORTANT) + if (skb->nh.iph->tos & IP_TOS_NOTIMPORTANT) return 3; - if (tos & IP_TOS_HIGHRELIABILITY) + if (skb->nh.iph->tos & IP_TOS_HIGHRELIABILITY) return 2; - if (tos & IP_TOS_HIGHTHROUGHPUT) + if (skb->nh.iph->tos & IP_TOS_HIGHTHROUGHPUT) return 1; - if (tos & IP_TOS_LOWDELAY) + if (skb->nh.iph->tos & IP_TOS_LOWDELAY) return 0; } if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_PREC) - return 3 - (tos >> 6); + return 3 - (skb->nh.iph->tos >> 6); } else if (card->qdio.do_prio_queueing && (ipv == 6)) { /* TODO: IPv6!!! */ } @@ -3938,9 +3866,9 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) * memcpys instead of one memmove to save cycles. */ skb_push(skb, VLAN_HLEN); - skb_copy_to_linear_data(skb, skb->data + 4, 4); - skb_copy_to_linear_data_offset(skb, 4, skb->data + 8, 4); - skb_copy_to_linear_data_offset(skb, 8, skb->data + 12, 4); + memcpy(skb->data, skb->data + 4, 4); + memcpy(skb->data + 4, skb->data + 8, 4); + memcpy(skb->data + 8, skb->data + 12, 4); tag = (u16 *)(skb->data + 12); /* * first two bytes = ETH_P_8021Q (0x8100) @@ -4111,8 +4039,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, *((u32 *) skb->dst->neighbour->primary_key); } else { /* fill in destination address used in ip header */ - *((u32 *)(&hdr->hdr.l3.dest_addr[12])) = - ip_hdr(skb)->daddr; + *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = skb->nh.iph->daddr; } } else if (ipv == 6) { /* IPv6 or passthru */ hdr->hdr.l3.flags = qeth_get_qeth_hdr_flags6(cast_type); @@ -4121,8 +4048,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, skb->dst->neighbour->primary_key, 16); } else { /* fill in destination address used in ip header */ - memcpy(hdr->hdr.l3.dest_addr, - &ipv6_hdr(skb)->daddr, 16); + memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16); } } else { /* passthrough */ if((skb->dev->type == ARPHRD_IEEE802_TR) && diff --git a/trunk/drivers/s390/net/qeth_mpc.h b/trunk/drivers/s390/net/qeth_mpc.h index d74bc43da72a..0477c47471c5 100644 --- a/trunk/drivers/s390/net/qeth_mpc.h +++ b/trunk/drivers/s390/net/qeth_mpc.h @@ -37,7 +37,6 @@ extern unsigned char IPA_PDU_HEADER[]; #define QETH_CLEAR_CHANNEL_PARM -10 #define QETH_HALT_CHANNEL_PARM -11 -#define QETH_RCD_PARM -12 /*****************************************************************************/ /* IP Assist related definitions */ diff --git a/trunk/drivers/s390/net/qeth_proc.c b/trunk/drivers/s390/net/qeth_proc.c index 89d56c8ecdd2..81f805cc5ee7 100644 --- a/trunk/drivers/s390/net/qeth_proc.c +++ b/trunk/drivers/s390/net/qeth_proc.c @@ -37,6 +37,7 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) struct device *dev = NULL; loff_t nr = 0; + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); if (*offset == 0) return SEQ_START_TOKEN; while (1) { @@ -52,6 +53,7 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) static void qeth_procfile_seq_stop(struct seq_file *s, void* it) { + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); } static void * diff --git a/trunk/drivers/s390/net/qeth_tso.h b/trunk/drivers/s390/net/qeth_tso.h index c20e923cf9ad..14504afb044e 100644 --- a/trunk/drivers/s390/net/qeth_tso.h +++ b/trunk/drivers/s390/net/qeth_tso.h @@ -40,8 +40,8 @@ qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb) QETH_DBF_TEXT(trace, 5, "tsofhdr"); hdr = (struct qeth_hdr_tso *) skb->data; - iph = ip_hdr(skb); - tcph = tcp_hdr(skb); + iph = skb->nh.iph; + tcph = skb->h.th; /*fix header to TSO values ...*/ hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; /*set values which are fix for the first approach ...*/ @@ -63,9 +63,13 @@ qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb) static inline void qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); - struct ipv6hdr *ip6h = ipv6_hdr(skb); - struct tcphdr *tcph = tcp_hdr(skb); + struct iphdr *iph; + struct ipv6hdr *ip6h; + struct tcphdr *tcph; + + iph = skb->nh.iph; + ip6h = skb->nh.ipv6h; + tcph = skb->h.th; tcph->check = 0; if (skb->protocol == ETH_P_IPV6) { diff --git a/trunk/drivers/s390/s390mach.c b/trunk/drivers/s390/s390mach.c index 644a06eba828..806bb1a921eb 100644 --- a/trunk/drivers/s390/s390mach.c +++ b/trunk/drivers/s390/s390mach.c @@ -21,7 +21,6 @@ #include "cio/cio.h" #include "cio/chsc.h" #include "cio/css.h" -#include "cio/chp.h" #include "s390mach.h" static struct semaphore m_sem; @@ -45,13 +44,14 @@ static int s390_collect_crw_info(void *param) { struct crw crw[2]; - int ccode; + int ccode, ret, slow; struct semaphore *sem; unsigned int chain; sem = (struct semaphore *)param; repeat: down_interruptible(sem); + slow = 0; chain = 0; while (1) { if (unlikely(chain > 1)) { @@ -84,8 +84,9 @@ s390_collect_crw_info(void *param) /* Check for overflows. */ if (crw[chain].oflw) { pr_debug("%s: crw overflow detected!\n", __FUNCTION__); - css_schedule_eval_all(); + css_reiterate_subchannels(); chain = 0; + slow = 1; continue; } switch (crw[chain].rsc) { @@ -93,7 +94,10 @@ s390_collect_crw_info(void *param) if (crw[0].chn && !chain) break; pr_debug("source is subchannel %04X\n", crw[0].rsid); - css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0); + ret = css_process_crw (crw[0].rsid, + chain ? crw[1].rsid : 0); + if (ret == -EAGAIN) + slow = 1; break; case CRW_RSC_MONITOR: pr_debug("source is monitoring facility\n"); @@ -112,23 +116,28 @@ s390_collect_crw_info(void *param) } switch (crw[0].erc) { case CRW_ERC_IPARM: /* Path has come. */ - chp_process_crw(crw[0].rsid, 1); + ret = chp_process_crw(crw[0].rsid, 1); break; case CRW_ERC_PERRI: /* Path has gone. */ case CRW_ERC_PERRN: - chp_process_crw(crw[0].rsid, 0); + ret = chp_process_crw(crw[0].rsid, 0); break; default: pr_debug("Don't know how to handle erc=%x\n", crw[0].erc); + ret = 0; } + if (ret == -EAGAIN) + slow = 1; break; case CRW_RSC_CONFIG: pr_debug("source is configuration-alert facility\n"); break; case CRW_RSC_CSS: pr_debug("source is channel subsystem\n"); - chsc_process_crw(); + ret = chsc_process_crw(); + if (ret == -EAGAIN) + slow = 1; break; default: pr_debug("unknown source\n"); @@ -137,6 +146,8 @@ s390_collect_crw_info(void *param) /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } + if (slow) + queue_work(slow_path_wq, &slow_path_work); goto repeat; return 0; } diff --git a/trunk/drivers/s390/scsi/zfcp_erp.c b/trunk/drivers/s390/scsi/zfcp_erp.c index c1f2d4b14c2b..421da1e7c0ea 100644 --- a/trunk/drivers/s390/scsi/zfcp_erp.c +++ b/trunk/drivers/s390/scsi/zfcp_erp.c @@ -186,7 +186,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) { fsf_req->timer.function = zfcp_fsf_request_timeout_handler; fsf_req->timer.data = (unsigned long) fsf_req->adapter; - fsf_req->timer.expires = jiffies + timeout; + fsf_req->timer.expires = timeout; add_timer(&fsf_req->timer); } diff --git a/trunk/drivers/s390/scsi/zfcp_fsf.c b/trunk/drivers/s390/scsi/zfcp_fsf.c index 4c0a59afd5c8..ef16f7ca4bb1 100644 --- a/trunk/drivers/s390/scsi/zfcp_fsf.c +++ b/trunk/drivers/s390/scsi/zfcp_fsf.c @@ -299,10 +299,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) } /* log additional information provided by FSF (if any) */ - if (likely(qtcb->header.log_length)) { + if (unlikely(qtcb->header.log_length)) { /* do not trust them ;-) */ - if (unlikely(qtcb->header.log_start > - sizeof(struct fsf_qtcb))) { + if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) { ZFCP_LOG_NORMAL ("bug: ULP (FSF logging) log data starts " "beyond end of packet header. Ignored. " @@ -311,9 +310,8 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) sizeof(struct fsf_qtcb)); goto forget_log; } - if (unlikely((size_t) (qtcb->header.log_start + - qtcb->header.log_length) > - sizeof(struct fsf_qtcb))) { + if ((size_t) (qtcb->header.log_start + qtcb->header.log_length) + > sizeof(struct fsf_qtcb)) { ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends " "beyond end of packet header. Ignored. " "(start=%i, length=%i, size=%li)\n", diff --git a/trunk/drivers/s390/sysinfo.c b/trunk/drivers/s390/sysinfo.c index 19343f9675c3..090743d2f914 100644 --- a/trunk/drivers/s390/sysinfo.c +++ b/trunk/drivers/s390/sysinfo.c @@ -357,24 +357,6 @@ static __init int create_proc_sysinfo(void) __initcall(create_proc_sysinfo); -int get_cpu_capability(unsigned int *capability) -{ - struct sysinfo_1_2_2 *info; - int rc; - - info = (void *) get_zeroed_page(GFP_KERNEL); - if (!info) - return -ENOMEM; - rc = stsi(info, 1, 2, 2); - if (rc == -ENOSYS) - goto out; - rc = 0; - *capability = info->capability; -out: - free_page((unsigned long) info); - return rc; -} - /* * CPU capability might have changed. Therefore recalculate loops_per_jiffy. */ diff --git a/trunk/drivers/sbus/char/envctrl.c b/trunk/drivers/sbus/char/envctrl.c index f2be2ead8742..2cea4f5d2084 100644 --- a/trunk/drivers/sbus/char/envctrl.c +++ b/trunk/drivers/sbus/char/envctrl.c @@ -726,7 +726,7 @@ static struct miscdevice envctrl_dev = { * Return: None. */ static void envctrl_set_mon(struct i2c_child_t *pchild, - const char *chnl_desc, + char *chnl_desc, int chnl_no) { /* Firmware only has temperature type. It does not distinguish @@ -763,8 +763,8 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp) { int i = 0, len; - const char *pos; - const unsigned int *pval; + char *pos; + unsigned int *pval; /* Firmware describe channels into a stream separated by a '\0'. */ pos = of_get_property(dp, "channels-description", &len); @@ -859,7 +859,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, { int len, i, tbls_size = 0; struct device_node *dp = edev_child->prom_node; - const void *pval; + void *pval; /* Get device address. */ pval = of_get_property(dp, "reg", &len); diff --git a/trunk/drivers/sbus/char/flash.c b/trunk/drivers/sbus/char/flash.c index 262f01e68592..6e99507aeb12 100644 --- a/trunk/drivers/sbus/char/flash.c +++ b/trunk/drivers/sbus/char/flash.c @@ -190,7 +190,7 @@ static int __init flash_init(void) } if (!sdev) { #ifdef CONFIG_PCI - const struct linux_prom_registers *ebus_regs; + struct linux_prom_registers *ebus_regs; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { diff --git a/trunk/drivers/sbus/char/openprom.c b/trunk/drivers/sbus/char/openprom.c index fbfeb89a6f32..eec28c142a59 100644 --- a/trunk/drivers/sbus/char/openprom.c +++ b/trunk/drivers/sbus/char/openprom.c @@ -44,6 +44,7 @@ #include #ifdef CONFIG_PCI #include +#include #endif MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"); @@ -140,7 +141,7 @@ static int copyout(void __user *info, struct openpromio *opp, int len) static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) { - const void *pval; + void *pval; int len; if (!dp || @@ -247,18 +248,18 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp if (bufsize >= 2*sizeof(int)) { #ifdef CONFIG_PCI struct pci_dev *pdev; - struct device_node *dp; - - pdev = pci_get_bus_and_slot (((int *) op->oprom_array)[0], + struct pcidev_cookie *pcp; + pdev = pci_find_slot (((int *) op->oprom_array)[0], ((int *) op->oprom_array)[1]); - dp = pci_device_to_OF_node(pdev); - data->current_node = dp; - *((int *)op->oprom_array) = dp->node; - op->oprom_size = sizeof(int); - err = copyout(argp, op, bufsize + sizeof(int)); - - pci_dev_put(pdev); + pcp = pdev->sysdata; + if (pcp != NULL) { + dp = pcp->prom_node; + data->current_node = dp; + *((int *)op->oprom_array) = dp->node; + op->oprom_size = sizeof(int); + err = copyout(argp, op, bufsize + sizeof(int)); + } #endif } @@ -408,7 +409,7 @@ static int opiocget(void __user *argp, DATA *data) struct opiocdesc op; struct device_node *dp; char *str; - const void *pval; + void *pval; int err, len; if (copy_from_user(&op, argp, sizeof(op))) diff --git a/trunk/drivers/sbus/char/vfc_dev.c b/trunk/drivers/sbus/char/vfc_dev.c index c3135e2fbd5a..8bfb67ccdcd4 100644 --- a/trunk/drivers/sbus/char/vfc_dev.c +++ b/trunk/drivers/sbus/char/vfc_dev.c @@ -259,10 +259,11 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp) if (copy_from_user(&inout, argp, sizeof(inout))) return -EFAULT; - buffer = kzalloc(inout.len, GFP_KERNEL); + buffer = kmalloc(inout.len, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; + memset(buffer,0,inout.len); vfc_lock_device(dev); inout.ret= vfc_i2c_recvbuf(dev,inout.addr & 0xff diff --git a/trunk/drivers/sbus/sbus.c b/trunk/drivers/sbus/sbus.c index 002643392d42..6349dd617f85 100644 --- a/trunk/drivers/sbus/sbus.c +++ b/trunk/drivers/sbus/sbus.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,7 @@ struct sbus_bus *sbus_root; static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { unsigned long base; - const void *pval; + void *pval; int len, err; sdev->prom_node = dp->node; @@ -85,7 +86,7 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) { - const void *pval; + void *pval; int len; pval = of_get_property(dp, "ranges", &len); diff --git a/trunk/drivers/scsi/BusLogic.c b/trunk/drivers/scsi/BusLogic.c index 96f4cab07614..e874b8944875 100644 --- a/trunk/drivers/scsi/BusLogic.c +++ b/trunk/drivers/scsi/BusLogic.c @@ -579,17 +579,17 @@ static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapt /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses. */ - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x330); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x334); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x230); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x234); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x130); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134) + if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) BusLogic_AppendProbeAddressISA(0x134); } @@ -795,9 +795,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd host adapters are probed. */ if (!BusLogic_ProbeOptions.NoProbeISA) - if (PrimaryProbeInfo->IO_Address == 0 && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe330)) { + if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) { PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; PrimaryProbeInfo->IO_Address = 0x330; @@ -807,25 +805,15 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd omitting the Primary I/O Address which has already been handled. */ if (!BusLogic_ProbeOptions.NoProbeISA) { - if (!StandardAddressSeen[1] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe334)) + if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) BusLogic_AppendProbeAddressISA(0x334); - if (!StandardAddressSeen[2] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe230)) + if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) BusLogic_AppendProbeAddressISA(0x230); - if (!StandardAddressSeen[3] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe234)) + if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) BusLogic_AppendProbeAddressISA(0x234); - if (!StandardAddressSeen[4] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe130)) + if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) BusLogic_AppendProbeAddressISA(0x130); - if (!StandardAddressSeen[5] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe134)) + if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) BusLogic_AppendProbeAddressISA(0x134); } /* @@ -2232,35 +2220,22 @@ static int __init BusLogic_init(void) HostAdapter->PCI_Device = ProbeInfo->PCI_Device; HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; - - /* - Make sure region is free prior to probing. - */ - if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, - "BusLogic")) - continue; /* Probe the Host Adapter. If unsuccessful, abort further initialization. */ - if (!BusLogic_ProbeHostAdapter(HostAdapter)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + if (!BusLogic_ProbeHostAdapter(HostAdapter)) continue; - } /* Hard Reset the Host Adapter. If unsuccessful, abort further initialization. */ - if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue; - } /* Check the Host Adapter. If unsuccessful, abort further initialization. */ - if (!BusLogic_CheckHostAdapter(HostAdapter)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); + if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; - } /* Initialize the Driver Options field if provided. */ @@ -2271,6 +2246,16 @@ static int __init BusLogic_init(void) and Electronic Mail Address. */ BusLogic_AnnounceDriver(HostAdapter); + /* + Register usage of the I/O Address range. From this point onward, any + failure will be assumed to be due to a problem with the Host Adapter, + rather than due to having mistakenly identified this port as belonging + to a BusLogic Host Adapter. The I/O Address range will not be + released, thereby preventing it from being incorrectly identified as + any other type of Host Adapter. + */ + if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic")) + continue; /* Register the SCSI Host structure. */ @@ -2295,12 +2280,6 @@ static int __init BusLogic_init(void) Acquire the System Resources necessary to use the Host Adapter, then Create the Initial CCBs, Initialize the Host Adapter, and finally perform Target Device Inquiry. - - From this point onward, any failure will be assumed to be due to a - problem with the Host Adapter, rather than due to having mistakenly - identified this port as belonging to a BusLogic Host Adapter. The - I/O Address range will not be released, thereby preventing it from - being incorrectly identified as any other type of Host Adapter. */ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && BusLogic_ReportHostAdapterConfiguration(HostAdapter) && @@ -3619,7 +3598,6 @@ static void __exit BusLogic_exit(void) __setup("BusLogic=", BusLogic_Setup); -#ifdef MODULE static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -3629,7 +3607,6 @@ static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } }; -#endif MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl); module_init(BusLogic_init); diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index 58c811d20eb2..4cd280e86966 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -241,12 +241,6 @@ config SCSI_SCAN_ASYNC You can override this choice by specifying "scsi_mod.scan=sync" or async on the kernel's command line. -config SCSI_WAIT_SCAN - tristate - default m - depends on SCSI - depends on MODULES - menu "SCSI Transports" depends on SCSI @@ -1200,6 +1194,17 @@ config SCSI_NCR53C8XX_SYNC There is no safe option other than using good cabling, right terminations and SCSI conformant devices. +config SCSI_NCR53C8XX_PROFILE + bool "enable profiling" + depends on SCSI_ZALON || SCSI_NCR_Q720 + help + This option allows you to enable profiling information gathering. + These statistics are not very accurate due to the low frequency + of the kernel clock (100 Hz on i386) and have performance impact + on systems that use very fast devices. + + The normal answer therefore is N. + config SCSI_NCR53C8XX_NO_DISCONNECT bool "not allow targets to disconnect" depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 @@ -1329,6 +1334,11 @@ config SCSI_SIM710 It currently supports Compaq EISA cards and NCR MCA cards +config 53C700_IO_MAPPED + bool + depends on SCSI_SIM710 + default y + config SCSI_SYM53C416 tristate "Symbios 53c416 SCSI support" depends on ISA && SCSI @@ -1639,7 +1649,7 @@ config OKTAGON_SCSI config ATARI_SCSI tristate "Atari native SCSI support" - depends on ATARI && SCSI + depends on ATARI && SCSI && BROKEN select SCSI_SPI_ATTRS ---help--- If you have an Atari with built-in NCR5380 SCSI controller (TT, @@ -1753,15 +1763,9 @@ config SUN3X_ESP The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. -config SCSI_ESP_CORE - tristate "ESP Scsi Driver Core" - depends on SCSI - select SCSI_SPI_ATTRS - config SCSI_SUNESP tristate "Sparc ESP Scsi Driver" depends on SBUS && SCSI - select SCSI_ESP_CORE help This is the driver for the Sun ESP SCSI host adapter. The ESP chipset is present in most SPARC SBUS-based computers. diff --git a/trunk/drivers/scsi/Makefile b/trunk/drivers/scsi/Makefile index 51e884fa10b0..79ecf4ebe6eb 100644 --- a/trunk/drivers/scsi/Makefile +++ b/trunk/drivers/scsi/Makefile @@ -106,8 +106,7 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o -obj-$(CONFIG_SCSI_ESP_CORE) += esp_scsi.o -obj-$(CONFIG_SCSI_SUNESP) += sun_esp.o +obj-$(CONFIG_SCSI_SUNESP) += esp.o obj-$(CONFIG_SCSI_GDTH) += gdth.o obj-$(CONFIG_SCSI_INITIO) += initio.o obj-$(CONFIG_SCSI_INIA100) += a100u2w.o @@ -146,7 +145,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o -obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o +obj-$(CONFIG_SCSI) += scsi_wait_scan.o scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ diff --git a/trunk/drivers/scsi/aacraid/aachba.c b/trunk/drivers/scsi/aacraid/aachba.c index 1e82c69b36b0..d789e61bdc49 100644 --- a/trunk/drivers/scsi/aacraid/aachba.c +++ b/trunk/drivers/scsi/aacraid/aachba.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -172,30 +172,6 @@ MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); - - -static inline int aac_valid_context(struct scsi_cmnd *scsicmd, - struct fib *fibptr) { - struct scsi_device *device; - - if (unlikely(!scsicmd || !scsicmd->scsi_done )) { - dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n")) -; - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return 0; - } - scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; - device = scsicmd->device; - if (unlikely(!device || !scsi_device_online(device))) { - dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n")); - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return 0; - } - return 1; -} - /** * aac_get_config_status - check the adapter configuration * @common: adapter to query @@ -282,10 +258,13 @@ int aac_get_containers(struct aac_dev *dev) u32 index; int status = 0; struct fib * fibptr; + unsigned instance; struct aac_get_container_count *dinfo; struct aac_get_container_count_resp *dresp; int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; + instance = dev->scsi_host_ptr->unique_id; + if (!(fibptr = aac_fib_alloc(dev))) return -ENOMEM; @@ -305,35 +284,88 @@ int aac_get_containers(struct aac_dev *dev) maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); aac_fib_complete(fibptr); } - aac_fib_free(fibptr); if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) maximum_num_containers = MAXIMUM_NUM_CONTAINERS; - fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers, - GFP_KERNEL); - if (!fsa_dev_ptr) + fsa_dev_ptr = kmalloc( + sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL); + if (!fsa_dev_ptr) { + aac_fib_free(fibptr); return -ENOMEM; + } memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers); dev->fsa_dev = fsa_dev_ptr; dev->maximum_num_containers = maximum_num_containers; - for (index = 0; index < dev->maximum_num_containers; ) { + for (index = 0; index < dev->maximum_num_containers; index++) { + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + fsa_dev_ptr[index].devname[0] = '\0'; - status = aac_probe_container(dev, index); + aac_fib_init(fibptr); + dinfo = (struct aac_query_mount *) fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(index); + dinfo->type = cpu_to_le32(FT_FILESYS); - if (status < 0) { + status = aac_fib_send(ContainerCommand, + fibptr, + sizeof (struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0 ) { printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); break; } + dresp = (struct aac_mount *)fib_data(fibptr); + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) { + dinfo->command = cpu_to_le32(VM_NameServe64); + dinfo->count = cpu_to_le32(index); + dinfo->type = cpu_to_le32(FT_FILESYS); + + if (aac_fib_send(ContainerCommand, + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL) < 0) + continue; + } else + dresp->mnt[0].capacityhigh = 0; + + dprintk ((KERN_DEBUG + "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n", + (int)index, (int)le32_to_cpu(dresp->status), + (int)le32_to_cpu(dresp->mnt[0].vol), + (int)le32_to_cpu(dresp->mnt[0].state), + ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + + (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32))); + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && + (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { + fsa_dev_ptr[index].valid = 1; + fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr[index].size + = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + + (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr[index].ro = 1; + } + aac_fib_complete(fibptr); /* * If there are no more containers, then stop asking. */ - if (++index >= status) + if ((index + 1) >= le32_to_cpu(dresp->count)){ break; + } } + aac_fib_free(fibptr); return status; } @@ -350,9 +382,8 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne buf = scsicmd->request_buffer; transfer_len = min(scsicmd->request_bufflen, len + offset); } - transfer_len -= offset; - if (buf && transfer_len) - memcpy(buf + offset, data, transfer_len); + + memcpy(buf + offset, data, transfer_len - offset); if (scsicmd->use_sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); @@ -365,9 +396,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr) struct scsi_cmnd * scsicmd; scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); BUG_ON(fibptr == NULL); @@ -402,7 +431,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr) /** * aac_get_container_name - get container name, none blocking. */ -static int aac_get_container_name(struct scsi_cmnd * scsicmd) +static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid) { int status; struct aac_get_name *dinfo; @@ -419,7 +448,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_READ_NAME); - dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); + dinfo->cid = cpu_to_le32(cid); dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data)); status = aac_fib_send(ContainerCommand, @@ -444,192 +473,85 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) return -1; } -static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd) -{ - struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; - - if (fsa_dev_ptr[scmd_id(scsicmd)].valid) - return aac_scsi_cmd(scsicmd); - - scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; -} - -static int _aac_probe_container2(void * context, struct fib * fibptr) +/** + * aac_probe_container - query a logical volume + * @dev: device to query + * @cid: container identifier + * + * Queries the controller about the given volume. The volume information + * is updated in the struct fsa_dev_info structure rather than returned. + */ + +int aac_probe_container(struct aac_dev *dev, int cid) { struct fsa_dev_info *fsa_dev_ptr; - int (*callback)(struct scsi_cmnd *); - struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; - - if (!aac_valid_context(scsicmd, fibptr)) - return 0; - - fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; - - scsicmd->SCp.Status = 0; - if (fsa_dev_ptr) { - struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr); - fsa_dev_ptr += scmd_id(scsicmd); - - if ((le32_to_cpu(dresp->status) == ST_OK) && - (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && - (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { - fsa_dev_ptr->valid = 1; - fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); - fsa_dev_ptr->size - = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + - (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); - fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0); - } - if ((fsa_dev_ptr->valid & 1) == 0) - fsa_dev_ptr->valid = 0; - scsicmd->SCp.Status = le32_to_cpu(dresp->count); - } - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); - scsicmd->SCp.ptr = NULL; - return (*callback)(scsicmd); -} - -static int _aac_probe_container1(void * context, struct fib * fibptr) -{ - struct scsi_cmnd * scsicmd; - struct aac_mount * dresp; - struct aac_query_mount *dinfo; int status; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; - dresp = (struct aac_mount *) fib_data(fibptr); - dresp->mnt[0].capacityhigh = 0; - if ((le32_to_cpu(dresp->status) != ST_OK) || - (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) - return _aac_probe_container2(context, fibptr); - scsicmd = (struct scsi_cmnd *) context; - scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; + fsa_dev_ptr = dev->fsa_dev; + if (!fsa_dev_ptr) + return -ENOMEM; + instance = dev->scsi_host_ptr->unique_id; - if (!aac_valid_context(scsicmd, fibptr)) - return 0; + if (!(fibptr = aac_fib_alloc(dev))) + return -ENOMEM; aac_fib_init(fibptr); dinfo = (struct aac_query_mount *)fib_data(fibptr); - dinfo->command = cpu_to_le32(VM_NameServe64); - dinfo->count = cpu_to_le32(scmd_id(scsicmd)); + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(cid); dinfo->type = cpu_to_le32(FT_FILESYS); status = aac_fib_send(ContainerCommand, - fibptr, - sizeof(struct aac_query_mount), - FsaNormal, - 0, 1, - (fib_callback) _aac_probe_container2, - (void *) scsicmd); - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); if (status < 0) { - /* Inherit results from VM_NameServe, if any */ - dresp->status = cpu_to_le32(ST_OK); - return _aac_probe_container2(context, fibptr); + printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n"); + goto error; } - return 0; -} - -static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)) -{ - struct fib * fibptr; - int status = -ENOMEM; - - if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) { - struct aac_query_mount *dinfo; - - aac_fib_init(fibptr); - dinfo = (struct aac_query_mount *)fib_data(fibptr); + dresp = (struct aac_mount *) fib_data(fibptr); - dinfo->command = cpu_to_le32(VM_NameServe); - dinfo->count = cpu_to_le32(scmd_id(scsicmd)); + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) { + dinfo->command = cpu_to_le32(VM_NameServe64); + dinfo->count = cpu_to_le32(cid); dinfo->type = cpu_to_le32(FT_FILESYS); - scsicmd->SCp.ptr = (char *)callback; - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof(struct aac_query_mount), - FsaNormal, - 0, 1, - (fib_callback) _aac_probe_container1, - (void *) scsicmd); - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - if (status < 0) { - scsicmd->SCp.ptr = NULL; - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - } - } - if (status < 0) { - struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; - if (fsa_dev_ptr) { - fsa_dev_ptr += scmd_id(scsicmd); - if ((fsa_dev_ptr->valid & 1) == 0) { - fsa_dev_ptr->valid = 0; - return (*callback)(scsicmd); - } - } - } - return status; -} + if (aac_fib_send(ContainerCommand, + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL) < 0) + goto error; + } else + dresp->mnt[0].capacityhigh = 0; -/** - * aac_probe_container - query a logical volume - * @dev: device to query - * @cid: container identifier - * - * Queries the controller about the given volume. The volume information - * is updated in the struct fsa_dev_info structure rather than returned. - */ -static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) -{ - scsicmd->device = NULL; - return 0; -} + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && + (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { + fsa_dev_ptr[cid].valid = 1; + fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr[cid].size + = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + + (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr[cid].ro = 1; + } -int aac_probe_container(struct aac_dev *dev, int cid) -{ - struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); - struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL); - int status; +error: + aac_fib_complete(fibptr); + aac_fib_free(fibptr); - if (!scsicmd || !scsidev) { - kfree(scsicmd); - kfree(scsidev); - return -ENOMEM; - } - scsicmd->list.next = NULL; - scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1; - - scsicmd->device = scsidev; - scsidev->sdev_state = 0; - scsidev->id = cid; - scsidev->host = dev->scsi_host_ptr; - - if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0) - while (scsicmd->device == scsidev) - schedule(); - kfree(scsidev); - status = scsicmd->SCp.Status; - kfree(scsicmd); return status; } @@ -1193,12 +1115,6 @@ int aac_get_adapter_info(struct aac_dev* dev) printk(KERN_INFO "%s%d: serial %x\n", dev->name, dev->id, le32_to_cpu(dev->adapter_info.serial[0])); - if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) { - printk(KERN_INFO "%s%d: TSID %.*s\n", - dev->name, dev->id, - (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), - dev->supplement_adapter_info.VpdInfo.Tsid); - } } dev->nondasd_support = 0; @@ -1325,9 +1241,7 @@ static void io_callback(void *context, struct fib * fibptr) u32 cid; scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dev = (struct aac_dev *)scsicmd->device->host->hostdata; cid = scmd_id(scsicmd); @@ -1403,7 +1317,7 @@ static void io_callback(void *context, struct fib * fibptr) scsicmd->scsi_done(scsicmd); } -static int aac_read(struct scsi_cmnd * scsicmd) +static int aac_read(struct scsi_cmnd * scsicmd, int cid) { u64 lba; u32 count; @@ -1417,7 +1331,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) */ switch (scsicmd->cmnd[0]) { case READ_6: - dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid)); lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; @@ -1427,7 +1341,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) count = 256; break; case READ_16: - dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 56) | ((u64)scsicmd->cmnd[3] << 48) | @@ -1441,7 +1355,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; break; case READ_12: - dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | @@ -1451,7 +1365,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; break; default: - dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | @@ -1491,7 +1405,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) return 0; } -static int aac_write(struct scsi_cmnd * scsicmd) +static int aac_write(struct scsi_cmnd * scsicmd, int cid) { u64 lba; u32 count; @@ -1510,7 +1424,7 @@ static int aac_write(struct scsi_cmnd * scsicmd) if (count == 0) count = 256; } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */ - dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 56) | ((u64)scsicmd->cmnd[3] << 48) | @@ -1522,14 +1436,14 @@ static int aac_write(struct scsi_cmnd * scsicmd) count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; } else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */ - dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; } else { - dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd))); + dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid)); lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; } @@ -1574,9 +1488,7 @@ static void synchronize_callback(void *context, struct fib *fibptr) struct scsi_cmnd *cmd; cmd = context; - - if (!aac_valid_context(cmd, fibptr)) - return; + cmd->SCp.phase = AAC_OWNER_MIDLEVEL; dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); @@ -1611,7 +1523,7 @@ static void synchronize_callback(void *context, struct fib *fibptr) cmd->scsi_done(cmd); } -static int aac_synchronize(struct scsi_cmnd *scsicmd) +static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid) { int status; struct fib *cmd_fibcontext; @@ -1656,7 +1568,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) synchronizecmd = fib_data(cmd_fibcontext); synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); - synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); + synchronizecmd->cid = cpu_to_le32(cid); synchronizecmd->count = cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); @@ -1734,12 +1646,29 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) case TEST_UNIT_READY: if (dev->in_reset) return -1; - return _aac_probe_container(scsicmd, - aac_probe_container_callback2); + spin_unlock_irq(host->host_lock); + aac_probe_container(dev, cid); + if ((fsa_dev_ptr[cid].valid & 1) == 0) + fsa_dev_ptr[cid].valid = 0; + spin_lock_irq(host->host_lock); + if (fsa_dev_ptr[cid].valid == 0) { + scsicmd->result = DID_NO_CONNECT << 16; + scsicmd->scsi_done(scsicmd); + return 0; + } default: break; } } + /* + * If the target container still doesn't exist, + * return failure + */ + if (fsa_dev_ptr[cid].valid == 0) { + scsicmd->result = DID_BAD_TARGET << 16; + scsicmd->scsi_done(scsicmd); + return 0; + } } else { /* check for physical non-dasd devices */ if ((dev->nondasd_support == 1) || expose_physicals) { if (dev->in_reset) @@ -1804,7 +1733,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); - return aac_get_container_name(scsicmd); + return aac_get_container_name(scsicmd, cid); } case SERVICE_ACTION_IN: if (!(dev->raw_io_interface) || @@ -1970,7 +1899,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) min(sizeof(fsa_dev_ptr[cid].devname), sizeof(scsicmd->request->rq_disk->disk_name) + 1)); - return aac_read(scsicmd); + return aac_read(scsicmd, cid); case WRITE_6: case WRITE_10: @@ -1978,11 +1907,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) case WRITE_16: if (dev->in_reset) return -1; - return aac_write(scsicmd); + return aac_write(scsicmd, cid); case SYNCHRONIZE_CACHE: /* Issue FIB to tell Firmware to flush it's cache */ - return aac_synchronize(scsicmd); + return aac_synchronize(scsicmd, cid); default: /* @@ -2129,10 +2058,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) struct scsi_cmnd *scsicmd; scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dev = (struct aac_dev *)scsicmd->device->host->hostdata; BUG_ON(fibptr == NULL); diff --git a/trunk/drivers/scsi/aacraid/aacraid.h b/trunk/drivers/scsi/aacraid/aacraid.h index 45ca3e801619..39ecd0d22eb0 100644 --- a/trunk/drivers/scsi/aacraid/aacraid.h +++ b/trunk/drivers/scsi/aacraid/aacraid.h @@ -12,8 +12,8 @@ *----------------------------------------------------------------------------*/ #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 2437 -# define AAC_DRIVER_BRANCH "-mh4" +# define AAC_DRIVER_BUILD 2423 +# define AAC_DRIVER_BRANCH "-mh3" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -48,13 +48,49 @@ struct diskparm /* - * Firmware constants + * DON'T CHANGE THE ORDER, this is set by the firmware */ #define CT_NONE 0 +#define CT_VOLUME 1 +#define CT_MIRROR 2 +#define CT_STRIPE 3 +#define CT_RAID5 4 +#define CT_SSRW 5 +#define CT_SSRO 6 +#define CT_MORPH 7 +#define CT_PASSTHRU 8 +#define CT_RAID4 9 +#define CT_RAID10 10 /* stripe of mirror */ +#define CT_RAID00 11 /* stripe of stripe */ +#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */ +#define CT_PSEUDO_RAID 13 /* really raid4 */ +#define CT_LAST_VOLUME_TYPE 14 #define CT_OK 218 + +/* + * Types of objects addressable in some fashion by the client. + * This is a superset of those objects handled just by the filesystem + * and includes "raw" objects that an administrator would use to + * configure containers and filesystems. + */ + +#define FT_REG 1 /* regular file */ +#define FT_DIR 2 /* directory */ +#define FT_BLK 3 /* "block" device - reserved */ +#define FT_CHR 4 /* "character special" device - reserved */ +#define FT_LNK 5 /* symbolic link */ +#define FT_SOCK 6 /* socket */ +#define FT_FIFO 7 /* fifo */ #define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ #define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/id/lun */ +#define FT_SLICE 10 /* virtual disk - raw volume - slice */ +#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */ +#define FT_VOLUME 12 /* Container - Volume Set */ +#define FT_STRIPE 13 /* Container - Stripe Set */ +#define FT_MIRROR 14 /* Container - Mirror Set */ +#define FT_RAID5 15 /* Container - Raid 5 Set */ +#define FT_DATABASE 16 /* Storage object with "foreign" content manager */ /* * Host side memory scatter gather list @@ -461,7 +497,6 @@ struct adapter_ops void (*adapter_enable_int)(struct aac_dev *dev); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); - int (*adapter_restart)(struct aac_dev *dev, int bled); /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); irqreturn_t (*adapter_intr)(int irq, void *dev_id); @@ -798,7 +833,7 @@ struct fib { */ struct list_head fiblink; void *data; - struct hw_fib *hw_fib_va; /* Actual shared object */ + struct hw_fib *hw_fib; /* Actual shared object */ dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ }; @@ -843,25 +878,10 @@ struct aac_supplement_adapter_info __le32 Version; __le32 FeatureBits; u8 SlotNumber; - u8 ReservedPad0[3]; + u8 ReservedPad0[0]; u8 BuildDate[12]; __le32 CurrentNumberPorts; - struct { - u8 AssemblyPn[8]; - u8 FruPn[8]; - u8 BatteryFruPn[8]; - u8 EcVersionString[8]; - u8 Tsid[12]; - } VpdInfo; - __le32 FlashFirmwareRevision; - __le32 FlashFirmwareBuild; - __le32 RaidTypeMorphOptions; - __le32 FlashFirmwareBootRevision; - __le32 FlashFirmwareBootBuild; - u8 MfgPcbaSerialNo[12]; - u8 MfgWWNName[8]; - __le32 MoreFeatureBits; - __le32 ReservedGrowth[1]; + __le32 ReservedGrowth[24]; }; #define AAC_FEATURE_FALCON 0x00000010 #define AAC_SIS_VERSION_V3 3 @@ -950,6 +970,7 @@ struct aac_dev struct fib *fibs; struct fib *free_fib; + struct fib *timeout_fib; spinlock_t fib_lock; struct aac_queue_block *queues; @@ -1039,9 +1060,6 @@ struct aac_dev #define aac_adapter_check_health(dev) \ (dev)->a_ops.adapter_check_health(dev) -#define aac_adapter_restart(dev,bled) \ - (dev)->a_ops.adapter_restart(dev,bled) - #define aac_adapter_ioremap(dev, size) \ (dev)->a_ops.adapter_ioremap(dev, size) @@ -1498,7 +1516,8 @@ struct aac_mntent { struct creation_info create_info; /* if applicable */ __le32 capacity; __le32 vol; /* substrate structure */ - __le32 obj; /* FT_FILESYS, etc. */ + __le32 obj; /* FT_FILESYS, + FT_DATABASE, etc. */ __le32 state; /* unready for mounting, readonly, etc. */ union aac_contentinfo fileinfo; /* Info specific to content @@ -1798,7 +1817,7 @@ int aac_fib_send(u16 command, struct fib * context, unsigned long size, int prio int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); int aac_fib_complete(struct fib * context); -#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data) +#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data) struct aac_dev *aac_init_adapter(struct aac_dev *dev); int aac_get_config_status(struct aac_dev *dev, int commit_flag); int aac_get_containers(struct aac_dev *dev); @@ -1821,11 +1840,8 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype); int aac_get_adapter_info(struct aac_dev* dev); int aac_send_shutdown(struct aac_dev *dev); int aac_probe_container(struct aac_dev *dev, int cid); -int _aac_rx_init(struct aac_dev *dev); -int aac_rx_select_comm(struct aac_dev *dev, int comm); extern int numacb; extern int acbsize; extern char aac_driver_version[]; extern int startup_timeout; extern int aif_timeout; -extern int expose_physicals; diff --git a/trunk/drivers/scsi/aacraid/commctrl.c b/trunk/drivers/scsi/aacraid/commctrl.c index 72b0393b4596..e21070f4eac1 100644 --- a/trunk/drivers/scsi/aacraid/commctrl.c +++ b/trunk/drivers/scsi/aacraid/commctrl.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,15 +64,12 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) unsigned size; int retval; - if (dev->in_reset) { - return -EBUSY; - } fibptr = aac_fib_alloc(dev); if(fibptr == NULL) { return -ENOMEM; } - kfib = fibptr->hw_fib_va; + kfib = fibptr->hw_fib; /* * First copy in the header so that we can check the size field. */ @@ -94,9 +91,9 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) goto cleanup; } /* Highjack the hw_fib */ - hw_fib = fibptr->hw_fib_va; + hw_fib = fibptr->hw_fib; hw_fib_pa = fibptr->hw_fib_pa; - fibptr->hw_fib_va = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa); + fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa); memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); memcpy(kfib, hw_fib, dev->max_fib_size); } @@ -140,7 +137,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) if (hw_fib) { pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa); fibptr->hw_fib_pa = hw_fib_pa; - fibptr->hw_fib_va = hw_fib; + fibptr->hw_fib = hw_fib; } if (retval != -EINTR) aac_fib_free(fibptr); @@ -285,15 +282,15 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) fib = list_entry(entry, struct fib, fiblink); fibctx->count--; spin_unlock_irqrestore(&dev->fib_lock, flags); - if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { - kfree(fib->hw_fib_va); + if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) { + kfree(fib->hw_fib); kfree(fib); return -EFAULT; } /* * Free the space occupied by this copy of the fib. */ - kfree(fib->hw_fib_va); + kfree(fib->hw_fib); kfree(fib); status = 0; } else { @@ -343,7 +340,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) /* * Free the space occupied by this copy of the fib. */ - kfree(fib->hw_fib_va); + kfree(fib->hw_fib); kfree(fib); } /* @@ -391,8 +388,10 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) /* * Extract the fibctx from the input parameters */ - if (fibctx->unique == (u32)(ptrdiff_t)arg) /* We found a winner */ + if (fibctx->unique == (u32)(unsigned long)arg) { + /* We found a winner */ break; + } entry = entry->next; fibctx = NULL; } @@ -466,20 +465,16 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) void *sg_list[32]; u32 sg_indx = 0; u32 byte_count = 0; - u32 actual_fibsize64, actual_fibsize = 0; + u32 actual_fibsize = 0; int i; - if (dev->in_reset) { - dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); - return -EBUSY; - } if (!capable(CAP_SYS_ADMIN)){ dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); return -EPERM; } /* - * Allocate and initialize a Fib then setup a SRB command + * Allocate and initialize a Fib then setup a BlockWrite command */ if (!(srbfib = aac_fib_alloc(dev))) { return -ENOMEM; @@ -546,183 +541,129 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + - ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); - actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * - (sizeof(struct sgentry64) - sizeof(struct sgentry)); - /* User made a mistake - should not continue */ - if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { - dprintk((KERN_DEBUG"aacraid: Bad Size specified in " - "Raw SRB command calculated fibsize=%lu;%lu " - "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " - "issued fibsize=%d\n", - actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, - sizeof(struct aac_srb), sizeof(struct sgentry), - sizeof(struct sgentry64), fibsize)); - rcode = -EINVAL; - goto cleanup; - } - if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { - dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); - rcode = -EINVAL; - goto cleanup; - } - byte_count = 0; - if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { + if (dev->dac_support == 1) { struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; + struct user_sgmap* usg; + byte_count = 0; /* * This should also catch if user used the 32 bit sgmap */ - if (actual_fibsize64 == fibsize) { - actual_fibsize = actual_fibsize64; - for (i = 0; i < upsg->count; i++) { - u64 addr; - void* p; - /* Does this really need to be GFP_DMA? */ - p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count,i,upsg->count)); - rcode = -ENOMEM; - goto cleanup; - } - addr = (u64)upsg->sg[i].addr[0]; - addr += ((u64)upsg->sg[i].addr[1]) << 32; - sg_user[i] = (void __user *)(ptrdiff_t)addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if( flags & SRB_DataOut ){ - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir); + actual_fibsize = sizeof(struct aac_srb) - + sizeof(struct sgentry) + + ((upsg->count & 0xff) * + sizeof(struct sgentry)); + if(actual_fibsize != fibsize){ // User made a mistake - should not continue + dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n")); + rcode = -EINVAL; + goto cleanup; + } + usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) + + sizeof(struct sgmap), GFP_KERNEL); + if (!usg) { + dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); + rcode = -ENOMEM; + goto cleanup; + } + memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) + + sizeof(struct sgmap)); + actual_fibsize = sizeof(struct aac_srb) - + sizeof(struct sgentry) + ((usg->count & 0xff) * + sizeof(struct sgentry64)); + if ((data_dir == DMA_NONE) && upsg->count) { + kfree (usg); + dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); + rcode = -EINVAL; + goto cleanup; + } - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); - } - } else { - struct user_sgmap* usg; - usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap), GFP_KERNEL); - if (!usg) { - dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); + for (i = 0; i < usg->count; i++) { + u64 addr; + void* p; + /* Does this really need to be GFP_DMA? */ + p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); + if(p == 0) { + kfree (usg); + dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + usg->sg[i].count,i,usg->count)); rcode = -ENOMEM; goto cleanup; } - memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap)); - actual_fibsize = actual_fibsize64; - - for (i = 0; i < usg->count; i++) { - u64 addr; - void* p; - /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { + sg_user[i] = (void __user *)(long)usg->sg[i].addr; + sg_list[i] = p; // save so we can clean up later + sg_indx = i; + + if( flags & SRB_DataOut ){ + if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ kfree (usg); - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); - rcode = -ENOMEM; + dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); + rcode = -EFAULT; goto cleanup; } - sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if( flags & SRB_DataOut ){ - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ - kfree (usg); - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); - - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); } - kfree (usg); + addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); + + psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); + psg->sg[i].addr[1] = cpu_to_le32(addr>>32); + psg->sg[i].count = cpu_to_le32(usg->sg[i].count); + byte_count += usg->sg[i].count; } + kfree (usg); + srbcmd->count = cpu_to_le32(byte_count); psg->count = cpu_to_le32(sg_indx+1); status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); } else { struct user_sgmap* upsg = &user_srbcmd->sg; struct sgmap* psg = &srbcmd->sg; - - if (actual_fibsize64 == fibsize) { - struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; - for (i = 0; i < upsg->count; i++) { - u64 addr; - void* p; - /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); - rcode = -ENOMEM; - goto cleanup; - } - addr = (u64)usg->sg[i].addr[0]; - addr += ((u64)usg->sg[i].addr[1]) << 32; - sg_user[i] = (void __user *)(ptrdiff_t)addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if( flags & SRB_DataOut ){ - if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); - - psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); - byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); + byte_count = 0; + + actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry)); + if(actual_fibsize != fibsize){ // User made a mistake - should not continue + dprintk((KERN_DEBUG"aacraid: Bad Size specified in " + "Raw SRB command calculated fibsize=%d " + "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d " + "issued fibsize=%d\n", + actual_fibsize, user_srbcmd->sg.count, + sizeof(struct aac_srb), sizeof(struct sgentry), + fibsize)); + rcode = -EINVAL; + goto cleanup; + } + if ((data_dir == DMA_NONE) && upsg->count) { + dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); + rcode = -EINVAL; + goto cleanup; + } + for (i = 0; i < upsg->count; i++) { + dma_addr_t addr; + void* p; + p = kmalloc(upsg->sg[i].count, GFP_KERNEL); + if(p == 0) { + dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", + upsg->sg[i].count, i, upsg->count)); + rcode = -ENOMEM; + goto cleanup; } - } else { - for (i = 0; i < upsg->count; i++) { - dma_addr_t addr; - void* p; - p = kmalloc(upsg->sg[i].count, GFP_KERNEL); - if(p == 0) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count, i, upsg->count)); - rcode = -ENOMEM; + sg_user[i] = (void __user *)(long)upsg->sg[i].addr; + sg_list[i] = p; // save so we can clean up later + sg_indx = i; + + if( flags & SRB_DataOut ){ + if(copy_from_user(p, sg_user[i], + upsg->sg[i].count)) { + dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); + rcode = -EFAULT; goto cleanup; } - sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if( flags & SRB_DataOut ){ - if(copy_from_user(p, sg_user[i], - upsg->sg[i].count)) { - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, - upsg->sg[i].count, data_dir); - - psg->sg[i].addr = cpu_to_le32(addr); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); } + addr = pci_map_single(dev->pdev, p, + upsg->sg[i].count, data_dir); + + psg->sg[i].addr = cpu_to_le32(addr); + psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); + byte_count += upsg->sg[i].count; } srbcmd->count = cpu_to_le32(byte_count); psg->count = cpu_to_le32(sg_indx+1); @@ -741,8 +682,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) if( flags & SRB_DataIn ) { for(i = 0 ; i <= sg_indx; i++){ - byte_count = le32_to_cpu( - (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) + byte_count = le32_to_cpu((dev->dac_support == 1) ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count : srbcmd->sg.sg[i].count); if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ diff --git a/trunk/drivers/scsi/aacraid/comminit.c b/trunk/drivers/scsi/aacraid/comminit.c index 33682ce96a5d..ae34768987a4 100644 --- a/trunk/drivers/scsi/aacraid/comminit.c +++ b/trunk/drivers/scsi/aacraid/comminit.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,7 +110,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co /* * Align the beginning of Headers to commalign */ - align = (commalign - ((ptrdiff_t)(base) & (commalign - 1))); + align = (commalign - ((unsigned long)(base) & (commalign - 1))); base = base + align; phys = phys + align; /* diff --git a/trunk/drivers/scsi/aacraid/commsup.c b/trunk/drivers/scsi/aacraid/commsup.c index 5824a757a753..1b97f60652ba 100644 --- a/trunk/drivers/scsi/aacraid/commsup.c +++ b/trunk/drivers/scsi/aacraid/commsup.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -94,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *dev) int aac_fib_setup(struct aac_dev * dev) { struct fib *fibptr; - struct hw_fib *hw_fib; + struct hw_fib *hw_fib_va; dma_addr_t hw_fib_pa; int i; @@ -106,24 +106,24 @@ int aac_fib_setup(struct aac_dev * dev) if (i<0) return -ENOMEM; - hw_fib = dev->hw_fib_va; + hw_fib_va = dev->hw_fib_va; hw_fib_pa = dev->hw_fib_pa; - memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); + memset(hw_fib_va, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); /* * Initialise the fibs */ for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) { fibptr->dev = dev; - fibptr->hw_fib_va = hw_fib; - fibptr->data = (void *) fibptr->hw_fib_va->data; + fibptr->hw_fib = hw_fib_va; + fibptr->data = (void *) fibptr->hw_fib->data; fibptr->next = fibptr+1; /* Forward chain the fibs */ init_MUTEX_LOCKED(&fibptr->event_wait); spin_lock_init(&fibptr->event_lock); - hw_fib->header.XferState = cpu_to_le32(0xffffffff); - hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); + hw_fib_va->header.XferState = cpu_to_le32(0xffffffff); + hw_fib_va->header.SenderSize = cpu_to_le16(dev->max_fib_size); fibptr->hw_fib_pa = hw_fib_pa; - hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size); + hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + dev->max_fib_size); hw_fib_pa = hw_fib_pa + dev->max_fib_size; } /* @@ -166,7 +166,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev) * Null out fields that depend on being zero at the start of * each I/O */ - fibptr->hw_fib_va->header.XferState = 0; + fibptr->hw_fib->header.XferState = 0; fibptr->callback = NULL; fibptr->callback_data = NULL; @@ -178,6 +178,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev) * @fibptr: fib to free up * * Frees up a fib and places it on the appropriate queue + * (either free or timed out) */ void aac_fib_free(struct fib *fibptr) @@ -185,15 +186,19 @@ void aac_fib_free(struct fib *fibptr) unsigned long flags; spin_lock_irqsave(&fibptr->dev->fib_lock, flags); - if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) { aac_config.fib_timeouts++; - if (fibptr->hw_fib_va->header.XferState != 0) { - printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", - (void*)fibptr, - le32_to_cpu(fibptr->hw_fib_va->header.XferState)); - } - fibptr->next = fibptr->dev->free_fib; - fibptr->dev->free_fib = fibptr; + fibptr->next = fibptr->dev->timeout_fib; + fibptr->dev->timeout_fib = fibptr; + } else { + if (fibptr->hw_fib->header.XferState != 0) { + printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", + (void*)fibptr, + le32_to_cpu(fibptr->hw_fib->header.XferState)); + } + fibptr->next = fibptr->dev->free_fib; + fibptr->dev->free_fib = fibptr; + } spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); } @@ -206,7 +211,7 @@ void aac_fib_free(struct fib *fibptr) void aac_fib_init(struct fib *fibptr) { - struct hw_fib *hw_fib = fibptr->hw_fib_va; + struct hw_fib *hw_fib = fibptr->hw_fib; hw_fib->header.StructType = FIB_MAGIC; hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size); @@ -226,7 +231,7 @@ void aac_fib_init(struct fib *fibptr) static void fib_dealloc(struct fib * fibptr) { - struct hw_fib *hw_fib = fibptr->hw_fib_va; + struct hw_fib *hw_fib = fibptr->hw_fib; BUG_ON(hw_fib->header.StructType != FIB_MAGIC); hw_fib->header.XferState = 0; } @@ -381,7 +386,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, void *callback_data) { struct aac_dev * dev = fibptr->dev; - struct hw_fib * hw_fib = fibptr->hw_fib_va; + struct hw_fib * hw_fib = fibptr->hw_fib; unsigned long flags = 0; unsigned long qflags; @@ -425,7 +430,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, */ hw_fib->header.Command = cpu_to_le16(command); hw_fib->header.XferState |= cpu_to_le32(SentFromHost); - fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/ + fibptr->hw_fib->header.Flags = 0; /* 0 the flags field - internal only*/ /* * Set the size of the Fib we want to send to the adapter */ @@ -457,7 +462,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command))); dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command))); dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState))); - dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va)); + dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib)); dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa)); dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr)); @@ -508,20 +513,22 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } udelay(5); } - } else - (void)down_interruptible(&fibptr->event_wait); - spin_lock_irqsave(&fibptr->event_lock, flags); - if (fibptr->done == 0) { - fibptr->done = 2; /* Tell interrupt we aborted */ + } else if (down_interruptible(&fibptr->event_wait)) { + spin_lock_irqsave(&fibptr->event_lock, flags); + if (fibptr->done == 0) { + fibptr->done = 2; /* Tell interrupt we aborted */ + spin_unlock_irqrestore(&fibptr->event_lock, flags); + return -EINTR; + } spin_unlock_irqrestore(&fibptr->event_lock, flags); - return -EINTR; } - spin_unlock_irqrestore(&fibptr->event_lock, flags); BUG_ON(fibptr->done == 0); - if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){ return -ETIMEDOUT; - return 0; + } else { + return 0; + } } /* * If the user does not want a response than return success otherwise @@ -617,7 +624,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) { - struct hw_fib * hw_fib = fibptr->hw_fib_va; + struct hw_fib * hw_fib = fibptr->hw_fib; struct aac_dev * dev = fibptr->dev; struct aac_queue * q; unsigned long nointr = 0; @@ -681,7 +688,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) int aac_fib_complete(struct fib *fibptr) { - struct hw_fib * hw_fib = fibptr->hw_fib_va; + struct hw_fib * hw_fib = fibptr->hw_fib; /* * Check for a fib which has already been completed @@ -767,8 +774,9 @@ void aac_printf(struct aac_dev *dev, u32 val) #define AIF_SNIFF_TIMEOUT (30*HZ) static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) { - struct hw_fib * hw_fib = fibptr->hw_fib_va; + struct hw_fib * hw_fib = fibptr->hw_fib; struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; + int busy; u32 container; struct scsi_device *device; enum { @@ -980,6 +988,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) * behind you. */ + busy = 0; + + /* * Find the scsi_device associated with the SCSI address, * and mark it as changed, invalidating the cache. This deals @@ -1024,6 +1035,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) static int _aac_reset_adapter(struct aac_dev *aac) { int index, quirks; + u32 ret; int retval; struct Scsi_Host *host; struct scsi_device *dev; @@ -1047,29 +1059,35 @@ static int _aac_reset_adapter(struct aac_dev *aac) * If a positive health, means in a known DEAD PANIC * state and the adapter could be reset to `try again'. */ - retval = aac_adapter_restart(aac, aac_adapter_check_health(aac)); + retval = aac_adapter_check_health(aac); + if (retval == 0) + retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS, + 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL); + if (retval) + retval = aac_adapter_sync_cmd(aac, IOP_RESET, + 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL); if (retval) goto out; + if (ret != 0x00000001) { + retval = -ENODEV; + goto out; + } /* * Loop through the fibs, close the synchronous FIBS */ - for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) { + for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) { struct fib *fib = &aac->fibs[index]; - if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) && - (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) { + if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) && + (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) { unsigned long flagv; spin_lock_irqsave(&fib->event_lock, flagv); up(&fib->event_wait); spin_unlock_irqrestore(&fib->event_lock, flagv); schedule(); - retval = 0; } } - /* Give some extra time for ioctls to complete. */ - if (retval == 0) - ssleep(2); index = aac->cardtype; /* @@ -1230,7 +1248,7 @@ int aac_check_health(struct aac_dev * aac) memset(hw_fib, 0, sizeof(struct hw_fib)); memset(fib, 0, sizeof(struct fib)); - fib->hw_fib_va = hw_fib; + fib->hw_fib = hw_fib; fib->dev = aac; aac_fib_init(fib); fib->type = FSAFS_NTC_FIB_CONTEXT; @@ -1336,11 +1354,11 @@ int aac_command_thread(void *data) * do anything at this point since we don't have * anything defined for this thread to do. */ - hw_fib = fib->hw_fib_va; + hw_fib = fib->hw_fib; memset(fib, 0, sizeof(struct fib)); fib->type = FSAFS_NTC_FIB_CONTEXT; fib->size = sizeof( struct fib ); - fib->hw_fib_va = hw_fib; + fib->hw_fib = hw_fib; fib->data = hw_fib->data; fib->dev = dev; /* @@ -1467,7 +1485,7 @@ int aac_command_thread(void *data) */ memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib)); memcpy(newfib, fib, sizeof(struct fib)); - newfib->hw_fib_va = hw_newfib; + newfib->hw_fib = hw_newfib; /* * Put the FIB onto the * fibctx's fibs diff --git a/trunk/drivers/scsi/aacraid/dpcsup.c b/trunk/drivers/scsi/aacraid/dpcsup.c index 42c7dcda6d9b..d38b628be1ad 100644 --- a/trunk/drivers/scsi/aacraid/dpcsup.c +++ b/trunk/drivers/scsi/aacraid/dpcsup.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -72,7 +73,7 @@ unsigned int aac_response_normal(struct aac_queue * q) u32 index = le32_to_cpu(entry->addr); fast = index & 0x01; fib = &dev->fibs[index >> 2]; - hwfib = fib->hw_fib_va; + hwfib = fib->hw_fib; aac_consumer_free(dev, q, HostNormRespQueue); /* @@ -83,13 +84,11 @@ unsigned int aac_response_normal(struct aac_queue * q) * continue. The caller has already been notified that * the fib timed out. */ - dev->queues->queue[AdapNormCmdQueue].numpending--; - - if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { - spin_unlock_irqrestore(q->lock, flags); - aac_fib_complete(fib); - aac_fib_free(fib); - spin_lock_irqsave(q->lock, flags); + if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + dev->queues->queue[AdapNormCmdQueue].numpending--; + else { + printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags); + printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib); continue; } spin_unlock_irqrestore(q->lock, flags); @@ -194,7 +193,7 @@ unsigned int aac_command_normal(struct aac_queue *q) INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; + fib->hw_fib = hw_fib; fib->data = hw_fib->data; fib->dev = dev; @@ -255,13 +254,12 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) return 1; } memset(hw_fib, 0, sizeof(struct hw_fib)); - memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) + - (index & ~0x00000002L)), sizeof(struct hw_fib)); + memcpy(hw_fib, (struct hw_fib *)(((unsigned long)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib)); memset(fib, 0, sizeof(struct fib)); INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; + fib->hw_fib = hw_fib; fib->data = hw_fib->data; fib->dev = dev; @@ -273,7 +271,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) } else { int fast = index & 0x01; struct fib * fib = &dev->fibs[index >> 2]; - struct hw_fib * hwfib = fib->hw_fib_va; + struct hw_fib * hwfib = fib->hw_fib; /* * Remove this fib from the Outstanding I/O queue. @@ -283,14 +281,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) * continue. The caller has already been notified that * the fib timed out. */ - dev->queues->queue[AdapNormCmdQueue].numpending--; - - if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { - aac_fib_complete(fib); - aac_fib_free(fib); + if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags); + printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib); return 0; } + dev->queues->queue[AdapNormCmdQueue].numpending--; + if (fast) { /* * Doctor the fib diff --git a/trunk/drivers/scsi/aacraid/linit.c b/trunk/drivers/scsi/aacraid/linit.c index 350ea7feb61d..0f948c2fb609 100644 --- a/trunk/drivers/scsi/aacraid/linit.c +++ b/trunk/drivers/scsi/aacraid/linit.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -82,6 +82,8 @@ static LIST_HEAD(aac_devices); static int aac_cfg_major = -1; char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; +extern int expose_physicals; + /* * Because of the way Linux names scsi devices, the order in this table has * become important. Check for on-board Raid first, add-in cards second. @@ -245,19 +247,7 @@ static struct aac_driver_ident aac_drivers[] = { static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - struct Scsi_Host *host = cmd->device->host; - struct aac_dev *dev = (struct aac_dev *)host->hostdata; - u32 count = 0; cmd->scsi_done = done; - for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &dev->fibs[count]; - struct scsi_cmnd * command; - if (fib->hw_fib_va->header.XferState && - ((command = fib->callback_data)) && - (command == cmd) && - (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) - return 0; /* Already owned by Adapter */ - } cmd->SCp.phase = AAC_OWNER_LOWLEVEL; return (aac_scsi_cmd(cmd) ? FAILED : 0); } @@ -456,40 +446,6 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) return aac_do_ioctl(dev, cmd, arg); } -static int aac_eh_abort(struct scsi_cmnd* cmd) -{ - struct scsi_device * dev = cmd->device; - struct Scsi_Host * host = dev->host; - struct aac_dev * aac = (struct aac_dev *)host->hostdata; - int count; - int ret = FAILED; - - printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n", - AAC_DRIVERNAME, - host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun); - switch (cmd->cmnd[0]) { - case SERVICE_ACTION_IN: - if (!(aac->raw_io_interface) || - !(aac->raw_io_64) || - ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) - break; - case INQUIRY: - case READ_CAPACITY: - case TEST_UNIT_READY: - /* Mark associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; - ret = SUCCESS; - } - } - } - return ret; -} - /* * aac_eh_reset - Reset command handling * @scsi_cmd: SCSI command block causing the reset @@ -501,20 +457,12 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) struct Scsi_Host * host = dev->host; struct scsi_cmnd * command; int count; - struct aac_dev * aac = (struct aac_dev *)host->hostdata; + struct aac_dev * aac; unsigned long flags; - /* Mark the associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; - } - } printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVERNAME); + aac = (struct aac_dev *)host->hostdata; if ((count = aac_check_health(aac))) return count; @@ -548,7 +496,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) ssleep(1); } printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); - return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ + return -ETIMEDOUT; } /** @@ -848,7 +796,6 @@ static struct scsi_host_template aac_driver_template = { .bios_param = aac_biosparm, .shost_attrs = aac_attrs, .slave_configure = aac_slave_configure, - .eh_abort_handler = aac_eh_abort, .eh_host_reset_handler = aac_eh_reset, .can_queue = AAC_NUM_IO_FIB, .this_id = MAXIMUM_NUM_CONTAINERS, diff --git a/trunk/drivers/scsi/aacraid/nark.c b/trunk/drivers/scsi/aacraid/nark.c index a8ace5677813..c76b611b6afb 100644 --- a/trunk/drivers/scsi/aacraid/nark.c +++ b/trunk/drivers/scsi/aacraid/nark.c @@ -74,6 +74,9 @@ static int aac_nark_ioremap(struct aac_dev * dev, u32 size) int aac_nark_init(struct aac_dev * dev) { + extern int _aac_rx_init(struct aac_dev *dev); + extern int aac_rx_select_comm(struct aac_dev *dev, int comm); + /* * Fill in the function dispatch table. */ diff --git a/trunk/drivers/scsi/aacraid/rkt.c b/trunk/drivers/scsi/aacraid/rkt.c index 9c5fcfb398c2..d953c3fe998a 100644 --- a/trunk/drivers/scsi/aacraid/rkt.c +++ b/trunk/drivers/scsi/aacraid/rkt.c @@ -45,6 +45,7 @@ static int aac_rkt_select_comm(struct aac_dev *dev, int comm) { int retval; + extern int aac_rx_select_comm(struct aac_dev *dev, int comm); retval = aac_rx_select_comm(dev, comm); if (comm == AAC_COMM_MESSAGE) { /* @@ -96,6 +97,8 @@ static int aac_rkt_ioremap(struct aac_dev * dev, u32 size) int aac_rkt_init(struct aac_dev *dev) { + extern int _aac_rx_init(struct aac_dev *dev); + /* * Fill in the function dispatch table. */ diff --git a/trunk/drivers/scsi/aacraid/rx.c b/trunk/drivers/scsi/aacraid/rx.c index 0c71315cbf1a..d242e2611d67 100644 --- a/trunk/drivers/scsi/aacraid/rx.c +++ b/trunk/drivers/scsi/aacraid/rx.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,25 +57,25 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) * been enabled. * Check to see if this is our interrupt. If it isn't just return */ - if (likely(intstat & ~(dev->OIMR))) { + if (intstat & ~(dev->OIMR)) { bellbits = rx_readl(dev, OutboundDoorbellReg); - if (unlikely(bellbits & DoorBellPrintfReady)) { + if (bellbits & DoorBellPrintfReady) { aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); } - else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) { + else if (bellbits & DoorBellAdapterNormCmdReady) { rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); } - else if (likely(bellbits & DoorBellAdapterNormRespReady)) { + else if (bellbits & DoorBellAdapterNormRespReady) { rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); aac_response_normal(&dev->queues->queue[HostNormRespQueue]); } - else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) { + else if (bellbits & DoorBellAdapterNormCmdNotFull) { rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); } - else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) { + else if (bellbits & DoorBellAdapterNormRespNotFull) { rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); } @@ -88,11 +88,11 @@ static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) { struct aac_dev *dev = dev_id; u32 Index = rx_readl(dev, MUnit.OutboundQueue); - if (unlikely(Index == 0xFFFFFFFFL)) + if (Index == 0xFFFFFFFFL) Index = rx_readl(dev, MUnit.OutboundQueue); - if (likely(Index != 0xFFFFFFFFL)) { + if (Index != 0xFFFFFFFFL) { do { - if (unlikely(aac_intr_normal(dev, Index))) { + if (aac_intr_normal(dev, Index)) { rx_writel(dev, MUnit.OutboundQueue, Index); rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); } @@ -204,7 +204,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, */ msleep(1); } - if (unlikely(ok != 1)) { + if (ok != 1) { /* * Restore interrupt mask even though we timed out */ @@ -294,7 +294,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) * Start up processing on an i960 based AAC adapter */ -static void aac_rx_start_adapter(struct aac_dev *dev) +void aac_rx_start_adapter(struct aac_dev *dev) { struct aac_init *init; @@ -319,12 +319,12 @@ static int aac_rx_check_health(struct aac_dev *dev) /* * Check to see if the board failed any self tests. */ - if (unlikely(status & SELF_TEST_FAILED)) + if (status & SELF_TEST_FAILED) return -1; /* * Check to see if the board panic'd. */ - if (unlikely(status & KERNEL_PANIC)) { + if (status & KERNEL_PANIC) { char * buffer; struct POSTSTATUS { __le32 Post_Command; @@ -333,15 +333,15 @@ static int aac_rx_check_health(struct aac_dev *dev) dma_addr_t paddr, baddr; int ret; - if (likely((status & 0xFF000000L) == 0xBC000000L)) + if ((status & 0xFF000000L) == 0xBC000000L) return (status >> 16) & 0xFF; buffer = pci_alloc_consistent(dev->pdev, 512, &baddr); ret = -2; - if (unlikely(buffer == NULL)) + if (buffer == NULL) return ret; post = pci_alloc_consistent(dev->pdev, sizeof(struct POSTSTATUS), &paddr); - if (unlikely(post == NULL)) { + if (post == NULL) { pci_free_consistent(dev->pdev, 512, buffer, baddr); return ret; } @@ -353,7 +353,7 @@ static int aac_rx_check_health(struct aac_dev *dev) NULL, NULL, NULL, NULL, NULL); pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), post, paddr); - if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { + if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) { ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); ret <<= 4; ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); @@ -364,7 +364,7 @@ static int aac_rx_check_health(struct aac_dev *dev) /* * Wait for the adapter to be up and running. */ - if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) + if (!(status & KERNEL_UP_AND_RUNNING)) return -3; /* * Everything is OK @@ -387,7 +387,7 @@ static int aac_rx_deliver_producer(struct fib * fib) unsigned long nointr = 0; spin_lock_irqsave(q->lock, qflags); - aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr); + aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr); q->numpending++; *(q->headers.producer) = cpu_to_le32(Index + 1); @@ -419,9 +419,9 @@ static int aac_rx_deliver_message(struct fib * fib) spin_unlock_irqrestore(q->lock, qflags); for(;;) { Index = rx_readl(dev, MUnit.InboundQueue); - if (unlikely(Index == 0xFFFFFFFFL)) + if (Index == 0xFFFFFFFFL) Index = rx_readl(dev, MUnit.InboundQueue); - if (likely(Index != 0xFFFFFFFFL)) + if (Index != 0xFFFFFFFFL) break; if (--count == 0) { spin_lock_irqsave(q->lock, qflags); @@ -437,7 +437,7 @@ static int aac_rx_deliver_message(struct fib * fib) device += sizeof(u32); writel((u32)(addr >> 32), device); device += sizeof(u32); - writel(le16_to_cpu(fib->hw_fib_va->header.Size), device); + writel(le16_to_cpu(fib->hw_fib->header.Size), device); rx_writel(dev, MUnit.InboundQueue, Index); return 0; } @@ -460,34 +460,22 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size) return 0; } -static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) +static int aac_rx_restart_adapter(struct aac_dev *dev) { u32 var; - if (bled) - printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", - dev->name, dev->id, bled); - else { - bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, - 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); - if (!bled && (var != 0x00000001)) - bled = -EINVAL; - } - if (bled && (bled != -ETIMEDOUT)) - bled = aac_adapter_sync_cmd(dev, IOP_RESET, - 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); - - if (bled && (bled != -ETIMEDOUT)) - return -EINVAL; - if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */ - rx_writel(dev, MUnit.reserved2, 3); - msleep(5000); /* Delay 5 seconds */ - var = 0x00000001; - } + printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", + dev->name, dev->id); + + if (aac_rx_check_health(dev) <= 0) + return 1; + if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0, + &var, NULL, NULL, NULL, NULL)) + return 1; if (var != 0x00000001) - return -EINVAL; + return 1; if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) - return -ENODEV; + return 1; return 0; } @@ -529,29 +517,24 @@ int _aac_rx_init(struct aac_dev *dev) { unsigned long start; unsigned long status; - int restart = 0; - int instance = dev->id; - const char * name = dev->name; + int instance; + const char * name; + + instance = dev->id; + name = dev->name; if (aac_adapter_ioremap(dev, dev->base_size)) { printk(KERN_WARNING "%s: unable to map adapter.\n", name); goto error_iounmap; } - /* Failure to reset here is an option ... */ - dev->OIMR = status = rx_readb (dev, MUnit.OIMR); - if ((((status & 0xff) != 0xff) || reset_devices) && - !aac_rx_restart_adapter(dev, 0)) - ++restart; /* * Check to see if the board panic'd while booting. */ status = rx_readl(dev, MUnit.OMRx[0]); - if (status & KERNEL_PANIC) { - if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev))) + if (status & KERNEL_PANIC) + if (aac_rx_restart_adapter(dev)) goto error_iounmap; - ++restart; - } /* * Check to see if the board failed any self tests. */ @@ -573,23 +556,12 @@ int _aac_rx_init(struct aac_dev *dev) */ while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING)) { - if ((restart && - (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || - time_after(jiffies, start+HZ*startup_timeout)) { + if(time_after(jiffies, start+startup_timeout*HZ)) + { printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", dev->name, instance, status); goto error_iounmap; } - if (!restart && - ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || - time_after(jiffies, start + HZ * - ((startup_timeout > 60) - ? (startup_timeout - 60) - : (startup_timeout / 2))))) { - if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))) - start = jiffies; - ++restart; - } msleep(1); } /* @@ -600,7 +572,6 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; - dev->a_ops.adapter_restart = aac_rx_restart_adapter; /* * First clear out all interrupts. Then enable the one's that we diff --git a/trunk/drivers/scsi/aacraid/sa.c b/trunk/drivers/scsi/aacraid/sa.c index f4b5e9742ab0..6f1a1780efce 100644 --- a/trunk/drivers/scsi/aacraid/sa.c +++ b/trunk/drivers/scsi/aacraid/sa.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/scsi/aha1542.c b/trunk/drivers/scsi/aha1542.c index cbbfbc9f3e0f..1d239f6c0103 100644 --- a/trunk/drivers/scsi/aha1542.c +++ b/trunk/drivers/scsi/aha1542.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/scsi/aic7xxx/Kconfig.aic79xx b/trunk/drivers/scsi/aic7xxx/Kconfig.aic79xx index 5e6620f8dabc..911ea1756e55 100644 --- a/trunk/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/trunk/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -57,6 +57,18 @@ config AIC79XX_BUILD_FIRMWARE or modify the assembler Makefile or the files it includes if your build environment is different than that of the author. +config AIC79XX_ENABLE_RD_STRM + bool "Enable Read Streaming for All Targets" + depends on SCSI_AIC79XX + default n + help + Read Streaming is a U320 protocol option that should enhance + performance. Early U320 drive firmware actually performs slower + with read streaming enabled so it is disabled by default. Read + Streaming can be configured in much the same way as tagged queueing + using the "rd_strm" command line option. See + drivers/scsi/aic7xxx/README.aic79xx for details. + config AIC79XX_DEBUG_ENABLE bool "Compile in Debugging Code" depends on SCSI_AIC79XX diff --git a/trunk/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/trunk/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 88da670a7915..cd93f9a8611f 100644 --- a/trunk/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/trunk/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -50,6 +50,16 @@ config AIC7XXX_RESET_DELAY_MS Default: 5000 (5 seconds) +config AIC7XXX_PROBE_EISA_VL + bool "Probe for EISA and VL AIC7XXX Adapters" + depends on SCSI_AIC7XXX && EISA + help + Probe for EISA and VLB Aic7xxx controllers. In many newer systems, + the invasive probes necessary to detect these controllers can cause + other devices to fail. For this reason, the non-PCI probe code is + disabled by default. The current value of this option can be "toggled" + via the no_probe kernel command line option. + config AIC7XXX_BUILD_FIRMWARE bool "Build Adapter Firmware with Kernel Build" depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD diff --git a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.c b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.c index 6054881f21f1..2be03e975d97 100644 --- a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -363,8 +363,6 @@ static int ahd_linux_run_command(struct ahd_softc*, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); static int aic79xx_setup(char *c); -static void ahd_freeze_simq(struct ahd_softc *ahd); -static void ahd_release_simq(struct ahd_softc *ahd); static int ahd_linux_unit; @@ -2018,13 +2016,13 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); } -static void +void ahd_freeze_simq(struct ahd_softc *ahd) { scsi_block_requests(ahd->platform_data->host); } -static void +void ahd_release_simq(struct ahd_softc *ahd) { scsi_unblock_requests(ahd->platform_data->host); diff --git a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h index 9218f29314fa..147c83c456a5 100644 --- a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -837,6 +837,8 @@ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg); void ahd_platform_free(struct ahd_softc *ahd); void ahd_platform_init(struct ahd_softc *ahd); void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); +void ahd_freeze_simq(struct ahd_softc *ahd); +void ahd_release_simq(struct ahd_softc *ahd); static __inline void ahd_freeze_scb(struct scb *scb) diff --git a/trunk/drivers/scsi/aic7xxx/aic7xxx.h b/trunk/drivers/scsi/aic7xxx/aic7xxx.h index e1bd57b9f23d..954c7c24501d 100644 --- a/trunk/drivers/scsi/aic7xxx/aic7xxx.h +++ b/trunk/drivers/scsi/aic7xxx/aic7xxx.h @@ -1278,6 +1278,11 @@ typedef enum { AHC_QUEUE_TAGGED } ahc_queue_alg; +void ahc_set_tags(struct ahc_softc *ahc, + struct scsi_cmnd *cmd, + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); + /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE void ahc_send_lstate_events(struct ahc_softc *, diff --git a/trunk/drivers/scsi/aic7xxx/aic7xxx_core.c b/trunk/drivers/scsi/aic7xxx/aic7xxx_core.c index 75733b09f27a..50ef785224de 100644 --- a/trunk/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/trunk/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -2073,7 +2073,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, /* * Update the current state of tagged queuing for a given target. */ -static void +void ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, ahc_queue_alg alg) { diff --git a/trunk/drivers/scsi/aic94xx/aic94xx_scb.c b/trunk/drivers/scsi/aic94xx/aic94xx_scb.c index db6ab1a3b81e..8f43ff772f23 100644 --- a/trunk/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/trunk/drivers/scsi/aic94xx/aic94xx_scb.c @@ -24,6 +24,7 @@ * */ +#include #include #include "aic94xx.h" diff --git a/trunk/drivers/scsi/arcmsr/arcmsr_attr.c b/trunk/drivers/scsi/arcmsr/arcmsr_attr.c index 03bfed61bffc..12497da5529d 100644 --- a/trunk/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/trunk/drivers/scsi/arcmsr/arcmsr_attr.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/scsi/atari_NCR5380.c b/trunk/drivers/scsi/atari_NCR5380.c index eff846ae0aff..0f920c84ac0f 100644 --- a/trunk/drivers/scsi/atari_NCR5380.c +++ b/trunk/drivers/scsi/atari_NCR5380.c @@ -1,19 +1,19 @@ -/* +/* * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor + * to implement 5380 SCSI drivers under Linux with a non-trantor * architecture. * * Note that these routines also work with NR53c400 family chips. * * Copyright 1993, Drew Eckhardt - * Visionary Computing + * Visionary Computing * (Unix and Linux consulting and custom programming) - * drew@colorado.edu + * drew@colorado.edu * +1 (303) 666-5836 * - * DISTRIBUTION RELEASE 6. + * DISTRIBUTION RELEASE 6. * - * For more information, please consult + * For more information, please consult * * NCR 5380 Family * SCSI Protocol Controller @@ -57,7 +57,7 @@ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA * and USLEEP, because these were messing up readability and will never be * needed for Atari SCSI. - * + * * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' * stuff), and 'main' is executed in a bottom half if awoken by an * interrupt. @@ -69,29 +69,21 @@ */ /* - * Further development / testing that should be done : - * 1. Test linked command handling code after Eric is ready with + * Further development / testing that should be done : + * 1. Test linked command handling code after Eric is ready with * the high level code. */ #include #include #if (NDEBUG & NDEBUG_LISTS) -#define LIST(x, y) \ - do { \ - printk("LINE:%d Adding %p to %p\n", \ - __LINE__, (void*)(x), (void*)(y)); \ - if ((x) == (y)) \ - udelay(5); \ - } while (0) -#define REMOVE(w, x, y, z) \ - do { \ - printk("LINE:%d Removing: %p->%p %p->%p \n", \ - __LINE__, (void*)(w), (void*)(x), \ - (void*)(y), (void*)(z)); \ - if ((x) == (y)) \ - udelay(5); \ - } while (0) +#define LIST(x,y) \ + { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ + if ((x)==(y)) udelay(5); } +#define REMOVE(w,x,y,z) \ + { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ + (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ + if ((x)==(y)) udelay(5); } #else #define LIST(x,y) #define REMOVE(w,x,y,z) @@ -111,62 +103,62 @@ * more difficult than it has to be. * * Also, many of the SCSI drivers were written before the command queuing - * routines were implemented, meaning their implementations of queued + * routines were implemented, meaning their implementations of queued * commands were hacked on rather than designed in from the start. * - * When I designed the Linux SCSI drivers I figured that + * When I designed the Linux SCSI drivers I figured that * while having two different SCSI boards in a system might be useful * for debugging things, two of the same type wouldn't be used. * Well, I was wrong and a number of users have mailed me about running * multiple high-performance SCSI boards in a server. * - * Finally, when I get questions from users, I have no idea what + * Finally, when I get questions from users, I have no idea what * revision of my driver they are running. * * This driver attempts to address these problems : - * This is a generic 5380 driver. To use it on a different platform, + * This is a generic 5380 driver. To use it on a different platform, * one simply writes appropriate system specific macros (ie, data - * transfer - some PC's will use the I/O bus, 68K's must use + * transfer - some PC's will use the I/O bus, 68K's must use * memory mapped) and drops this file in their 'C' wrapper. * - * As far as command queueing, two queues are maintained for + * As far as command queueing, two queues are maintained for * each 5380 in the system - commands that haven't been issued yet, - * and commands that are currently executing. This means that an - * unlimited number of commands may be queued, letting - * more commands propagate from the higher driver levels giving higher - * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, - * allowing multiple commands to propagate all the way to a SCSI-II device + * and commands that are currently executing. This means that an + * unlimited number of commands may be queued, letting + * more commands propagate from the higher driver levels giving higher + * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, + * allowing multiple commands to propagate all the way to a SCSI-II device * while a command is already executing. * - * To solve the multiple-boards-in-the-same-system problem, + * To solve the multiple-boards-in-the-same-system problem, * there is a separate instance structure for each instance * of a 5380 in the system. So, multiple NCR5380 drivers will * be able to coexist with appropriate changes to the high level - * SCSI code. + * SCSI code. * * A NCR5380_PUBLIC_REVISION macro is provided, with the release - * number (updated for each public release) printed by the - * NCR5380_print_options command, which should be called from the + * number (updated for each public release) printed by the + * NCR5380_print_options command, which should be called from the * wrapper detect function, so that I know what release of the driver * users are using. * - * Issues specific to the NCR5380 : + * Issues specific to the NCR5380 : * - * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead - * piece of hardware that requires you to sit in a loop polling for - * the REQ signal as long as you are connected. Some devices are - * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect + * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead + * piece of hardware that requires you to sit in a loop polling for + * the REQ signal as long as you are connected. Some devices are + * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect * while doing long seek operations. - * + * * The workaround for this is to keep track of devices that have * disconnected. If the device hasn't disconnected, for commands that - * should disconnect, we do something like + * should disconnect, we do something like * * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } - * - * Some tweaking of N and M needs to be done. An algorithm based + * + * Some tweaking of N and M needs to be done. An algorithm based * on "time to data" would give the best results as long as short time - * to datas (ie, on the same track) were considered, however these + * to datas (ie, on the same track) were considered, however these * broken devices are the exception rather than the rule and I'd rather * spend my time optimizing for the normal case. * @@ -175,9 +167,9 @@ * At the heart of the design is a coroutine, NCR5380_main, * which is started when not running by the interrupt handler, * timer, and queue command function. It attempts to establish - * I_T_L or I_T_L_Q nexuses by removing the commands from the - * issue queue and calling NCR5380_select() if a nexus - * is not established. + * I_T_L or I_T_L_Q nexuses by removing the commands from the + * issue queue and calling NCR5380_select() if a nexus + * is not established. * * Once a nexus is established, the NCR5380_information_transfer() * phase goes through the various phases as instructed by the target. @@ -191,10 +183,10 @@ * calling NCR5380_intr() which will in turn call NCR5380_reselect * to reestablish a nexus. This will run main if necessary. * - * On command termination, the done function will be called as + * On command termination, the done function will be called as * appropriate. * - * SCSI pointers are maintained in the SCp field of SCSI command + * SCSI pointers are maintained in the SCp field of SCSI command * structures, being initialized after the command is connected * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. * Note that in violation of the standard, an implicit SAVE POINTERS operation @@ -204,12 +196,12 @@ /* * Using this file : * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write an architecture specific functions + * of chips. To use it, you write an architecture specific functions * and macros and include this file in your driver. * - * These macros control options : + * These macros control options : * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. + * for commands that return with a CHECK CONDITION status. * * LINKED - if defined, linked commands are supported. * @@ -218,18 +210,18 @@ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible * * These macros MUST be defined : - * + * * NCR5380_read(register) - read from the specified register * - * NCR5380_write(register, value) - write to the specific register + * NCR5380_write(register, value) - write to the specific register * * Either real DMA *or* pseudo DMA may be implemented - * REAL functions : + * REAL functions : * NCR5380_REAL_DMA should be defined if real DMA is to be used. - * Note that the DMA setup functions should return the number of bytes + * Note that the DMA setup functions should return the number of bytes * that they were able to program the controller for. * - * Also note that generic i386/PC versions of these macros are + * Also note that generic i386/PC versions of these macros are * available as NCR5380_i386_dma_write_setup, * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. * @@ -242,14 +234,14 @@ * NCR5380_pread(instance, dst, count); * * If nothing specific to this implementation needs doing (ie, with external - * hardware), you must also define - * + * hardware), you must also define + * * NCR5380_queue_command * NCR5380_reset * NCR5380_abort * NCR5380_proc_info * - * to be the global entry points into the specific driver, ie + * to be the global entry points into the specific driver, ie * #define NCR5380_queue_command t128_queue_command. * * If this is not done, the routines will be defined as static functions @@ -257,7 +249,7 @@ * accessible wrapper function. * * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the + * after setting the appropriate host specific fields and ID. If the * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, * possible) function may be used. Before the specific driver initialization * code finishes, NCR5380_print_options should be called. @@ -272,9 +264,8 @@ static struct scsi_host_template *the_template = NULL; (struct NCR5380_hostdata *)(in)->hostdata #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) -#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble) -#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next)) -#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble) +#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->device->host->host_no @@ -321,34 +312,34 @@ static struct scsi_host_template *the_template = NULL; #define TAG_NONE 0xff typedef struct { - DECLARE_BITMAP(allocated, MAX_TAGS); - int nr_allocated; - int queue_size; + DECLARE_BITMAP(allocated, MAX_TAGS); + int nr_allocated; + int queue_size; } TAG_ALLOC; -static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ +static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ -static void __init init_tags(void) +static void __init init_tags( void ) { - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for (target = 0; target < 8; ++target) { - for (lun = 0; lun < 8; ++lun) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; - /* At the beginning, assume the maximum queue size we could - * support (MAX_TAGS). This value will be decreased if the target - * returns QUEUE_FULL status. - */ - ta->queue_size = MAX_TAGS; - } + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + bitmap_zero(ta->allocated, MAX_TAGS); + ta->nr_allocated = 0; + /* At the beginning, assume the maximum queue size we could + * support (MAX_TAGS). This value will be decreased if the target + * returns QUEUE_FULL status. + */ + ta->queue_size = MAX_TAGS; } + } } @@ -357,24 +348,24 @@ static void __init init_tags(void) * check that there is a free tag and the target's queue won't overflow. This * function should be called with interrupts disabled to avoid race * conditions. - */ + */ -static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged) +static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->device->host); - - if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) - return 1; - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) - return 0; - if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= - TagAlloc[cmd->device->id][cmd->device->lun].queue_size) { - TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - return 1; - } - return 0; + SETUP_HOSTDATA(cmd->device->host); + + if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) + return( 1 ); + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) + return( 0 ); + if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= + TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { + TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", + H_NO(cmd), cmd->device->id, cmd->device->lun ); + return( 1 ); + } + return( 0 ); } @@ -383,30 +374,31 @@ static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged) * untagged. */ -static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged) +static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->device->host); - - /* If we or the target don't support tagged queuing, allocate the LUN for - * an untagged command. - */ - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) { - cmd->tag = TAG_NONE; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun); - } else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - - cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS); - set_bit(cmd->tag, ta->allocated); - ta->nr_allocated++; - TAG_PRINTK("scsi%d: using tag %d for target %d lun %d " - "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->device->id, - cmd->device->lun, ta->nr_allocated); - } + SETUP_HOSTDATA(cmd->device->host); + + /* If we or the target don't support tagged queuing, allocate the LUN for + * an untagged command. + */ + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) { + cmd->tag = TAG_NONE; + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); + TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " + "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + + cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS ); + set_bit( cmd->tag, ta->allocated ); + ta->nr_allocated++; + TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " + "(now %d tags in use)\n", + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, + ta->nr_allocated ); + } } @@ -414,42 +406,44 @@ static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged) * unlock the LUN. */ -static void cmd_free_tag(Scsi_Cmnd *cmd) +static void cmd_free_tag( Scsi_Cmnd *cmd ) { - SETUP_HOSTDATA(cmd->device->host); - - if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - } else if (cmd->tag >= MAX_TAGS) { - printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", - H_NO(cmd), cmd->tag); - } else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - clear_bit(cmd->tag, ta->allocated); - ta->nr_allocated--; - TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun); - } + SETUP_HOSTDATA(cmd->device->host); + + if (cmd->tag == TAG_NONE) { + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", + H_NO(cmd), cmd->device->id, cmd->device->lun ); + } + else if (cmd->tag >= MAX_TAGS) { + printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", + H_NO(cmd), cmd->tag ); + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + clear_bit( cmd->tag, ta->allocated ); + ta->nr_allocated--; + TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); + } } -static void free_all_tags(void) +static void free_all_tags( void ) { - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for (target = 0; target < 8; ++target) { - for (lun = 0; lun < 8; ++lun) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; - } + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + bitmap_zero(ta->allocated, MAX_TAGS); + ta->nr_allocated = 0; } + } } #endif /* SUPPORT_TAGS */ @@ -467,94 +461,89 @@ static void free_all_tags(void) * assumed to be already transfered into ptr/this_residual. */ -static void merge_contiguous_buffers(Scsi_Cmnd *cmd) +static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) { - unsigned long endaddr; + unsigned long endaddr; #if (NDEBUG & NDEBUG_MERGING) - unsigned long oldlen = cmd->SCp.this_residual; - int cnt = 1; + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; #endif - for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; - cmd->SCp.buffers_residual && - virt_to_phys(page_address(cmd->SCp.buffer[1].page) + - cmd->SCp.buffer[1].offset) == endaddr;) { - MER_PRINTK("VTOP(%p) == %08lx -> merging\n", - page_address(cmd->SCp.buffer[1].page), endaddr); + for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; + cmd->SCp.buffers_residual && + virt_to_phys(page_address(cmd->SCp.buffer[1].page)+ + cmd->SCp.buffer[1].offset) == endaddr; ) { + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", + cmd->SCp.buffer[1].address, endaddr); #if (NDEBUG & NDEBUG_MERGING) - ++cnt; + ++cnt; #endif - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual += cmd->SCp.buffer->length; - endaddr += cmd->SCp.buffer->length; - } + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endaddr += cmd->SCp.buffer->length; + } #if (NDEBUG & NDEBUG_MERGING) - if (oldlen != cmd->SCp.this_residual) - MER_PRINTK("merged %d buffers from %p, new length %08x\n", - cnt, cmd->SCp.ptr, cmd->SCp.this_residual); + if (oldlen != cmd->SCp.this_residual) + MER_PRINTK("merged %d buffers from %p, new length %08x\n", + cnt, cmd->SCp.ptr, cmd->SCp.this_residual); #endif } /* * Function : void initialize_SCp(Scsi_Cmnd *cmd) * - * Purpose : initialize the saved data pointers for cmd to point to the + * Purpose : initialize the saved data pointers for cmd to point to the * start of the buffer. * * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. */ -static inline void initialize_SCp(Scsi_Cmnd *cmd) +static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) { - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. + /* + * Initialize the Scsi Pointer field so that all of the commands in the + * various queues are valid. + */ + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+ + cmd->SCp.buffer->offset; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + /* ++roman: Try to merge some scatter-buffers if they are at + * contiguous physical addresses. */ - - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) + - cmd->SCp.buffer->offset; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - /* ++roman: Try to merge some scatter-buffers if they are at - * contiguous physical addresses. - */ - merge_contiguous_buffers(cmd); - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; - } + merge_contiguous_buffers( cmd ); + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } } #include #if NDEBUG static struct { - unsigned char mask; - const char *name; -} signals[] = { - { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, - { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, - { SR_SEL, "SEL" }, {0, NULL} -}, basrs[] = { - {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL} -}, icrs[] = { - {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL} -}, mrs[] = { - {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, - "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, - {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL} -}; + unsigned char mask; + const char * name;} +signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, + { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, + { SR_SEL, "SEL" }, {0, NULL}}, +basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, +icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL}}, +mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, + "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL}}; /* * Function : void NCR5380_print(struct Scsi_Host *instance) @@ -564,47 +553,45 @@ static struct { * Input : instance - which NCR5380 */ -static void NCR5380_print(struct Scsi_Host *instance) -{ - unsigned char status, data, basr, mr, icr, i; - unsigned long flags; - - local_irq_save(flags); - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - local_irq_restore(flags); - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); +static void NCR5380_print(struct Scsi_Host *instance) { + unsigned char status, data, basr, mr, icr, i; + unsigned long flags; + + local_irq_save(flags); + data = NCR5380_read(CURRENT_SCSI_DATA_REG); + status = NCR5380_read(STATUS_REG); + mr = NCR5380_read(MODE_REG); + icr = NCR5380_read(INITIATOR_COMMAND_REG); + basr = NCR5380_read(BUS_AND_STATUS_REG); + local_irq_restore(flags); + printk("STATUS_REG: %02x ", status); + for (i = 0; signals[i].mask ; ++i) + if (status & signals[i].mask) + printk(",%s", signals[i].name); + printk("\nBASR: %02x ", basr); + for (i = 0; basrs[i].mask ; ++i) + if (basr & basrs[i].mask) + printk(",%s", basrs[i].name); + printk("\nICR: %02x ", icr); + for (i = 0; icrs[i].mask; ++i) + if (icr & icrs[i].mask) + printk(",%s", icrs[i].name); + printk("\nMODE: %02x ", mr); + for (i = 0; mrs[i].mask; ++i) + if (mr & mrs[i].mask) + printk(",%s", mrs[i].name); + printk("\n"); } static struct { - unsigned char value; - const char *name; + unsigned char value; + const char *name; } phases[] = { - {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, - {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, - {PHASE_UNKNOWN, "UNKNOWN"} -}; + {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"}}; -/* +/* * Function : void NCR5380_print_phase(struct Scsi_Host *instance) * * Purpose : print the current SCSI phase for debugging purposes @@ -614,35 +601,30 @@ static struct { static void NCR5380_print_phase(struct Scsi_Host *instance) { - unsigned char status; - int i; - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i) - ; - printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); - } + unsigned char status; + int i; + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && + (phases[i].value != (status & PHASE_MASK)); ++i); + printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); + } } #else /* !NDEBUG */ /* dummies... */ -static inline void NCR5380_print(struct Scsi_Host *instance) -{ -}; -static inline void NCR5380_print_phase(struct Scsi_Host *instance) -{ -}; +__inline__ void NCR5380_print(struct Scsi_Host *instance) { }; +__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; #endif /* * ++roman: New scheme of calling NCR5380_main() - * + * * If we're not in an interrupt, we can call our main directly, it cannot be * already running. Else, we queue it on a task queue, if not 'main_running' * tells us that a lower level is already executing it. This way, @@ -656,33 +638,33 @@ static inline void NCR5380_print_phase(struct Scsi_Host *instance) #include #include -static volatile int main_running; -static DECLARE_WORK(NCR5380_tqueue, NCR5380_main); +static volatile int main_running = 0; +static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL); -static inline void queue_main(void) +static __inline__ void queue_main(void) { - if (!main_running) { - /* If in interrupt and NCR5380_main() not already running, - queue it on the 'immediate' task queue, to be processed - immediately after the current interrupt processing has - finished. */ - schedule_work(&NCR5380_tqueue); - } - /* else: nothing to do: the running NCR5380_main() will pick up - any newly queued command. */ + if (!main_running) { + /* If in interrupt and NCR5380_main() not already running, + queue it on the 'immediate' task queue, to be processed + immediately after the current interrupt processing has + finished. */ + schedule_work(&NCR5380_tqueue); + } + /* else: nothing to do: the running NCR5380_main() will pick up + any newly queued command. */ } -static inline void NCR5380_all_init(void) +static inline void NCR5380_all_init (void) { - static int done = 0; - if (!done) { - INI_PRINTK("scsi : NCR5380_all_init()\n"); - done = 1; - } + static int done = 0; + if (!done) { + INI_PRINTK("scsi : NCR5380_all_init()\n"); + done = 1; + } } - + /* * Function : void NCR58380_print_options (struct Scsi_Host *instance) * @@ -692,23 +674,23 @@ static inline void NCR5380_all_init(void) * Inputs : instance, pointer to this instance. Unused. */ -static void __init NCR5380_print_options(struct Scsi_Host *instance) +static void __init NCR5380_print_options (struct Scsi_Host *instance) { - printk(" generic options" -#ifdef AUTOSENSE - " AUTOSENSE" + printk(" generic options" +#ifdef AUTOSENSE + " AUTOSENSE" #endif #ifdef REAL_DMA - " REAL DMA" + " REAL DMA" #endif #ifdef PARITY - " PARITY" + " PARITY" #endif #ifdef SUPPORT_TAGS - " SCSI-2 TAGGED QUEUING" + " SCSI-2 TAGGED QUEUING" #endif - ); - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); + ); + printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); } /* @@ -717,27 +699,27 @@ static void __init NCR5380_print_options(struct Scsi_Host *instance) * Purpose : print commands in the various queues, called from * NCR5380_abort and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Inputs : instance, pointer to this instance. */ -static void NCR5380_print_status(struct Scsi_Host *instance) +static void NCR5380_print_status (struct Scsi_Host *instance) { - char *pr_bfr; - char *start; - int len; - - NCR_PRINT(NDEBUG_ANY); - NCR_PRINT_PHASE(NDEBUG_ANY); - - pr_bfr = (char *)__get_free_page(GFP_ATOMIC); - if (!pr_bfr) { - printk("NCR5380_print_status: no memory for print buffer\n"); - return; - } - len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); - pr_bfr[len] = 0; - printk("\n%s\n", pr_bfr); - free_page((unsigned long)pr_bfr); + char *pr_bfr; + char *start; + int len; + + NCR_PRINT(NDEBUG_ANY); + NCR_PRINT_PHASE(NDEBUG_ANY); + + pr_bfr = (char *) __get_free_page(GFP_ATOMIC); + if (!pr_bfr) { + printk("NCR5380_print_status: no memory for print buffer\n"); + return; + } + len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); + free_page((unsigned long) pr_bfr); } @@ -756,478 +738,443 @@ static void NCR5380_print_status(struct Scsi_Host *instance) */ #undef SPRINTF -#define SPRINTF(fmt,args...) \ - do { \ - if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ - pos += sprintf(pos, fmt , ## args); \ - } while(0) -static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length); - -static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, - char **start, off_t offset, int length, int inout) +#define SPRINTF(fmt,args...) \ + do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ + pos += sprintf(pos, fmt , ## args); } while(0) +static +char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); + +static +int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, + int length, int inout) { - char *pos = buffer; - struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; - unsigned long flags; - off_t begin = 0; -#define check_offset() \ - do { \ - if (pos - buffer < offset - begin) { \ - begin += pos - buffer; \ - pos = buffer; \ - } \ - } while (0) - - hostdata = (struct NCR5380_hostdata *)instance->hostdata; - - if (inout) /* Has data been written to the file ? */ - return -ENOSYS; /* Currently this is a no-op */ - SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); + char *pos = buffer; + struct NCR5380_hostdata *hostdata; + Scsi_Cmnd *ptr; + unsigned long flags; + off_t begin = 0; +#define check_offset() \ + do { \ + if (pos - buffer < offset - begin) { \ + begin += pos - buffer; \ + pos = buffer; \ + } \ + } while (0) + + hostdata = (struct NCR5380_hostdata *)instance->hostdata; + + if (inout) { /* Has data been written to the file ? */ + return(-ENOSYS); /* Currently this is a no-op */ + } + SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); + check_offset(); + local_irq_save(flags); + SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); + check_offset(); + if (!hostdata->connected) + SPRINTF("scsi%d: no currently connected command\n", HOSTNO); + else + pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, + pos, buffer, length); + SPRINTF("scsi%d: issue_queue\n", HOSTNO); + check_offset(); + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); check_offset(); - local_irq_save(flags); - SPRINTF("NCR5380: coroutine is%s running.\n", - main_running ? "" : "n't"); - check_offset(); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", HOSTNO); - else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", HOSTNO); - check_offset(); - for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - check_offset(); - } + } - SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); + SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); + check_offset(); + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - check_offset(); - } + } - local_irq_restore(flags); - *start = buffer + (offset - begin); - if (pos - buffer < offset - begin) - return 0; - else if (pos - buffer - (offset - begin) < length) - return pos - buffer - (offset - begin); - return length; + local_irq_restore(flags); + *start = buffer + (offset - begin); + if (pos - buffer < offset - begin) + return 0; + else if (pos - buffer - (offset - begin) < length) + return pos - buffer - (offset - begin); + return length; } -static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +static char * +lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) { - int i, s; - unsigned char *command; - SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); - command = cmd->cmnd; - SPRINTF("%2d (0x%02x)", command[0], command[0]); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF(" %02x", command[i]); - SPRINTF("\n"); - return pos; + int i, s; + unsigned char *command; + SPRINTF("scsi%d: destination target %d, lun %d\n", + H_NO(cmd), cmd->device->id, cmd->device->lun); + SPRINTF(" command = "); + command = cmd->cmnd; + SPRINTF("%2d (0x%02x)", command[0], command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + SPRINTF(" %02x", command[i]); + SPRINTF("\n"); + return pos; } -/* +/* * Function : void NCR5380_init (struct Scsi_Host *instance) * * Purpose : initializes *instance and corresponding 5380 chip. * - * Inputs : instance - instantiation of the 5380 driver. + * Inputs : instance - instantiation of the 5380 driver. * * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. - * + * set correctly. I don't care about the irq and other fields. + * */ -static int NCR5380_init(struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { - int i; - SETUP_HOSTDATA(instance); - - NCR5380_all_init(); - - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - hostdata->id_higher_mask = 0; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; + int i; + SETUP_HOSTDATA(instance); + + NCR5380_all_init(); + + hostdata->aborted = 0; + hostdata->id_mask = 1 << instance->this_id; + hostdata->id_higher_mask = 0; + for (i = hostdata->id_mask; i <= 0x80; i <<= 1) + if (i > hostdata->id_mask) + hostdata->id_higher_mask |= i; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; #ifdef SUPPORT_TAGS - init_tags(); + init_tags(); #endif #if defined (REAL_DMA) - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; - - if (!the_template) { - the_template = instance->hostt; - first_instance = instance; - } + hostdata->targets_present = 0; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } + #ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) - printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", HOSTNO); + if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) + printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" + " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", HOSTNO); #endif /* def AUTOSENSE */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); - return 0; + return 0; } -/* - * our own old-style timeout update - */ -/* - * The strategy is to cause the timer code to call scsi_times_out() - * when the soonest timeout is pending. - * The arguments are used when we are queueing a new command, because - * we do not want to subtract the time used from this time, but when we - * set the timer, we want to take this value into account. - */ - -int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout) -{ - int rtn; - - /* - * We are using the new error handling code to actually register/deregister - * timers for timeout. - */ - - if (!timer_pending(&SCset->eh_timeout)) - rtn = 0; - else - rtn = SCset->eh_timeout.expires - jiffies; - - if (timeout == 0) { - del_timer(&SCset->eh_timeout); - SCset->eh_timeout.data = (unsigned long)NULL; - SCset->eh_timeout.expires = 0; - } else { - if (SCset->eh_timeout.data != (unsigned long)NULL) - del_timer(&SCset->eh_timeout); - SCset->eh_timeout.data = (unsigned long)SCset; - SCset->eh_timeout.expires = jiffies + timeout; - add_timer(&SCset->eh_timeout); - } - return rtn; -} - -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) +/* + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, + * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with * a pointer to the command descriptor. - * + * * Returns : 0 * - * Side effects : - * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the + * Side effects : + * cmd is added to the per instance issue_queue, with minor + * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * */ -static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static +int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { - SETUP_HOSTDATA(cmd->device->host); - Scsi_Cmnd *tmp; - int oldto; - unsigned long flags; - // extern int update_timeout(Scsi_Cmnd * SCset, int timeout); + SETUP_HOSTDATA(cmd->device->host); + Scsi_Cmnd *tmp; + int oldto; + unsigned long flags; + extern int update_timeout(Scsi_Cmnd * SCset, int timeout); #if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", - H_NO(cmd)); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", + H_NO(cmd)); + cmd->result = (DID_ERROR << 16); + done(cmd); + return 0; + } #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + #ifdef NCR5380_STATS # if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } + if (!hostdata->connected && !hostdata->issue_queue && + !hostdata->disconnected_queue) { + hostdata->timebase = jiffies; + } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) # endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; - hostdata->pendingr++; - break; - } -#endif - - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - SET_NEXT(cmd, NULL); - cmd->scsi_done = done; - - cmd->result = 0; - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - local_irq_save(flags); - /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. - * Otherwise a running NCR5380_main may steal the lock. - * Lock before actually inserting due to fairness reasons explained in - * atari_scsi.c. If we insert first, then it's impossible for this driver - * to release the lock. - * Stop timer for this command while waiting for the lock, or timeouts - * may happen (and they really do), and it's no good if the command doesn't - * appear in any of the queues. - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which would - * alter queues and touch the lock. - */ - if (!IS_A_TT()) { - oldto = atari_scsi_update_timeout(cmd, 0); - falcon_get_lock(); - atari_scsi_update_timeout(cmd, oldto); - } - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = cmd; - } else { - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; - NEXT(tmp); tmp = NEXT(tmp)) - ; - LIST(cmd, tmp); - SET_NEXT(tmp, cmd); + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->pendingw++; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->pendingr++; + break; } - local_irq_restore(flags); - - QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); +#endif - /* If queue_command() is called from an interrupt (real one or bottom - * half), we let queue_main() do the job of taking care about main. If it - * is already running, this is a no-op, else main will be queued. - * - * If we're not in an interrupt, we can call NCR5380_main() - * unconditionally, because it cannot be already running. - */ - if (in_interrupt() || ((flags >> 8) & 7) >= 6) - queue_main(); - else - NCR5380_main(NULL); - return 0; + /* + * We use the host_scribble field as a pointer to the next command + * in a queue + */ + + NEXT(cmd) = NULL; + cmd->scsi_done = done; + + cmd->result = 0; + + + /* + * Insert the cmd into the issue queue. Note that REQUEST SENSE + * commands are added to the head of the queue since any command will + * clear the contingent allegiance condition that exists and the + * sense data is only guaranteed to be valid while the condition exists. + */ + + local_irq_save(flags); + /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. + * Otherwise a running NCR5380_main may steal the lock. + * Lock before actually inserting due to fairness reasons explained in + * atari_scsi.c. If we insert first, then it's impossible for this driver + * to release the lock. + * Stop timer for this command while waiting for the lock, or timeouts + * may happen (and they really do), and it's no good if the command doesn't + * appear in any of the queues. + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which would + * alter queues and touch the lock. + */ + if (!IS_A_TT()) { + oldto = update_timeout(cmd, 0); + falcon_get_lock(); + update_timeout(cmd, oldto); + } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + NEXT(tmp); tmp = NEXT(tmp)) + ; + LIST(cmd, tmp); + NEXT(tmp) = cmd; + } + local_irq_restore(flags); + + QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); + + /* If queue_command() is called from an interrupt (real one or bottom + * half), we let queue_main() do the job of taking care about main. If it + * is already running, this is a no-op, else main will be queued. + * + * If we're not in an interrupt, we can call NCR5380_main() + * unconditionally, because it cannot be already running. + */ + if (in_interrupt() || ((flags >> 8) & 7) >= 6) + queue_main(); + else + NCR5380_main(NULL); + return 0; } /* - * Function : NCR5380_main (void) + * Function : NCR5380_main (void) * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it + * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * be done on the NCR5380 host adapters in a system. Both + * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. - * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should + * + * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. - */ - -static void NCR5380_main(struct work_struct *work) + */ + +static void NCR5380_main (void *bl) { - Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance = first_instance; - struct NCR5380_hostdata *hostdata = HOSTDATA(instance); - int done; - unsigned long flags; - - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we set main_running to 0 and exit. - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - * - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which can - * alter queues and touch the Falcon lock. - */ - - /* Tell int handlers main() is now already executing. Note that - no races are possible here. If an int comes in before - 'main_running' is set here, and queues/executes main via the - task queue, it doesn't do any harm, just this instance of main - won't find any work left to do. */ - if (main_running) - return; - main_running = 1; - - local_save_flags(flags); - do { - local_irq_disable(); /* Freeze request queues */ - done = 1; - - if (!hostdata->connected) { - MAIN_PRINTK("scsi%d: not connected\n", HOSTNO); - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance = first_instance; + struct NCR5380_hostdata *hostdata = HOSTDATA(instance); + int done; + unsigned long flags; + + /* + * We run (with interrupts disabled) until we're sure that none of + * the host adapters have anything that can be done, at which point + * we set main_running to 0 and exit. + * + * Interrupts are enabled before doing various other internal + * instructions, after we've decided that we need to run through + * the loop again. + * + * this should prevent any race conditions. + * + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which can + * alter queues and touch the Falcon lock. + */ + + /* Tell int handlers main() is now already executing. Note that + no races are possible here. If an int comes in before + 'main_running' is set here, and queues/executes main via the + task queue, it doesn't do any harm, just this instance of main + won't find any work left to do. */ + if (main_running) + return; + main_running = 1; + + local_save_flags(flags); + do { + local_irq_disable(); /* Freeze request queues */ + done = 1; + + if (!hostdata->connected) { + MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO ); + /* + * Search through the issue_queue for a command destined + * for a target that's not busy. + */ #if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; - tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) - ; - /*printk("%p ", tmp);*/ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); - /* else printk("\n"); */ + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; + tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) + ; + /*printk("%p ", tmp);*/ + if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ #endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) { + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { #if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", - tmp, tmp->device->id, hostdata->busy[tmp->device->id], - tmp->device->lun); + if (prev != tmp) + printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", + tmp, tmp->device->id, hostdata->busy[tmp->device->id], + tmp->device->lun); #endif - /* When we find one, remove it from the issue queue. */ - /* ++guenther: possible race with Falcon locking */ - if ( + /* When we find one, remove it from the issue queue. */ + /* ++guenther: possible race with Falcon locking */ + if ( #ifdef SUPPORT_TAGS - !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) + !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) #else - !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) + !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) #endif - ) { - /* ++guenther: just to be sure, this must be atomic */ - local_irq_disable(); - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); - hostdata->issue_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - falcon_dont_release++; - - /* reenable interrupts after finding one */ - local_irq_restore(flags); - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ - MAIN_PRINTK("scsi%d: main(): command for target %d " - "lun %d removed from issue_queue\n", - HOSTNO, tmp->device->id, tmp->device->lun); - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - /* ++roman: ...and the standard also requires that - * REQUEST SENSE command are untagged. - */ - + ) { + /* ++guenther: just to be sure, this must be atomic */ + local_irq_disable(); + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); + hostdata->issue_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + falcon_dont_release++; + + /* reenable interrupts after finding one */ + local_irq_restore(flags); + + /* + * Attempt to establish an I_T_L nexus here. + * On success, instance->hostdata->connected is set. + * On failure, we must add the command back to the + * issue queue so we can keep trying. + */ + MAIN_PRINTK("scsi%d: main(): command for target %d " + "lun %d removed from issue_queue\n", + HOSTNO, tmp->device->id, tmp->device->lun); + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + /* ++roman: ...and the standard also requires that + * REQUEST SENSE command are untagged. + */ + #ifdef SUPPORT_TAGS - cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE); + cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); #endif - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { - falcon_dont_release--; - /* release if target did not response! */ - falcon_release_lock_if_possible(hostdata); - break; - } else { - local_irq_disable(); - LIST(tmp, hostdata->issue_queue); - SET_NEXT(tmp, hostdata->issue_queue); - hostdata->issue_queue = tmp; + if (!NCR5380_select(instance, tmp, + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : + TAG_NEXT)) { + falcon_dont_release--; + /* release if target did not response! */ + falcon_release_lock_if_possible( hostdata ); + break; + } else { + local_irq_disable(); + LIST(tmp, hostdata->issue_queue); + NEXT(tmp) = hostdata->issue_queue; + hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS - cmd_free_tag(tmp); + cmd_free_tag( tmp ); #endif - falcon_dont_release--; - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main(): select() failed, " - "returned to issue_queue\n", HOSTNO); - if (hostdata->connected) - break; - } - } /* if target/lun/target queue is not busy */ - } /* for issue_queue */ - } /* if (!hostdata->connected) */ - - if (hostdata->connected + falcon_dont_release--; + local_irq_restore(flags); + MAIN_PRINTK("scsi%d: main(): select() failed, " + "returned to issue_queue\n", HOSTNO); + if (hostdata->connected) + break; + } + } /* if target/lun/target queue is not busy */ + } /* for issue_queue */ + } /* if (!hostdata->connected) */ + + if (hostdata->connected #ifdef REAL_DMA - && !hostdata->dma_len + && !hostdata->dma_len #endif - ) { - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main: performing information transfer\n", - HOSTNO); - NCR5380_information_transfer(instance); - MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); - done = 0; - } - } while (!done); + ) { + local_irq_restore(flags); + MAIN_PRINTK("scsi%d: main: performing information transfer\n", + HOSTNO); + NCR5380_information_transfer(instance); + MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); + done = 0; + } + } while (!done); - /* Better allow ints _after_ 'main_running' has been cleared, else - an interrupt could believe we'll pick up the work it left for - us, but we won't see it anymore here... */ - main_running = 0; - local_irq_restore(flags); + /* Better allow ints _after_ 'main_running' has been cleared, else + an interrupt could believe we'll pick up the work it left for + us, but we won't see it anymore here... */ + main_running = 0; + local_irq_restore(flags); } @@ -1236,1439 +1183,1441 @@ static void NCR5380_main(struct work_struct *work) * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) * * Purpose : Called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). + * mismatch occurs (which would finish the DMA transfer). * * Inputs : instance - this instance of the NCR5380. * */ -static void NCR5380_dma_complete(struct Scsi_Host *instance) +static void NCR5380_dma_complete( struct Scsi_Host *instance ) { - SETUP_HOSTDATA(instance); - int transfered, saved_data = 0, overrun = 0, cnt, toPIO; - unsigned char **data, p; - volatile int *count; - - if (!hostdata->connected) { - printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " - "no connected cmd\n", HOSTNO); - return; + SETUP_HOSTDATA(instance); + int transfered, saved_data = 0, overrun = 0, cnt, toPIO; + unsigned char **data, p; + volatile int *count; + + if (!hostdata->connected) { + printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " + "no connected cmd\n", HOSTNO); + return; + } + + if (atari_read_overruns) { + p = hostdata->connected->SCp.phase; + if (p & SR_IO) { + udelay(10); + if ((((NCR5380_read(BUS_AND_STATUS_REG)) & + (BASR_PHASE_MATCH|BASR_ACK)) == + (BASR_PHASE_MATCH|BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REG); + overrun = 1; + DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); + } } - - if (atari_read_overruns) { - p = hostdata->connected->SCp.phase; - if (p & SR_IO) { - udelay(10); - if ((NCR5380_read(BUS_AND_STATUS_REG) & - (BASR_PHASE_MATCH|BASR_ACK)) == - (BASR_PHASE_MATCH|BASR_ACK)) { - saved_data = NCR5380_read(INPUT_DATA_REG); - overrun = 1; - DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); - } - } - } - - DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", - HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - transfered = hostdata->dma_len - NCR5380_dma_residual(instance); - hostdata->dma_len = 0; - - data = (unsigned char **)&hostdata->connected->SCp.ptr; - count = &hostdata->connected->SCp.this_residual; - *data += transfered; - *count -= transfered; - - if (atari_read_overruns) { - if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { - cnt = toPIO = atari_read_overruns; - if (overrun) { - DMA_PRINTK("Got an input overrun, using saved byte\n"); - *(*data)++ = saved_data; - (*count)--; - cnt--; - toPIO--; - } - DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); - NCR5380_transfer_pio(instance, &p, &cnt, data); - *count -= toPIO - cnt; - } + } + + DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", + HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); + + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + transfered = hostdata->dma_len - NCR5380_dma_residual(instance); + hostdata->dma_len = 0; + + data = (unsigned char **) &(hostdata->connected->SCp.ptr); + count = &(hostdata->connected->SCp.this_residual); + *data += transfered; + *count -= transfered; + + if (atari_read_overruns) { + if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { + cnt = toPIO = atari_read_overruns; + if (overrun) { + DMA_PRINTK("Got an input overrun, using saved byte\n"); + *(*data)++ = saved_data; + (*count)--; + cnt--; + toPIO--; + } + DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); + NCR5380_transfer_pio(instance, &p, &cnt, data); + *count -= toPIO - cnt; } + } } #endif /* REAL_DMA */ /* * Function : void NCR5380_intr (int irq) - * + * * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() + * from the disconnected queue, and restarting NCR5380_main() * as required. * * Inputs : int irq, irq that caused this interrupt. * */ -static irqreturn_t NCR5380_intr(int irq, void *dev_id) +static irqreturn_t NCR5380_intr (int irq, void *dev_id) { - struct Scsi_Host *instance = first_instance; - int done = 1, handled = 0; - unsigned char basr; - - INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); - - /* Look for pending interrupts */ - basr = NCR5380_read(BUS_AND_STATUS_REG); - INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); - /* dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { - NCR_PRINT(NDEBUG_INTR); - if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { - done = 0; - ENABLE_IRQ(); - INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); - NCR5380_reselect(instance); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if (basr & BASR_PARITY_ERROR) { - INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { - INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { - /* - * The rest of the interrupt conditions can occur only during a - * DMA transfer - */ + struct Scsi_Host *instance = first_instance; + int done = 1, handled = 0; + unsigned char basr; + + INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); + + /* Look for pending interrupts */ + basr = NCR5380_read(BUS_AND_STATUS_REG); + INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); + /* dispatch to appropriate routine if found and done=0 */ + if (basr & BASR_IRQ) { + NCR_PRINT(NDEBUG_INTR); + if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { + done = 0; + ENABLE_IRQ(); + INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); + NCR5380_reselect(instance); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if (basr & BASR_PARITY_ERROR) { + INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { + INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else { + /* + * The rest of the interrupt conditions can occur only during a + * DMA transfer + */ #if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts if we have - * DMA enabled, so do a sanity check based on the current setting - * of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && - ((basr & BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { - - INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); - NCR5380_dma_complete( instance ); - done = 0; - ENABLE_IRQ(); - } else + /* + * We should only get PHASE MISMATCH and EOP interrupts if we have + * DMA enabled, so do a sanity check based on the current setting + * of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && + ((basr & BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + + INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); + NCR5380_dma_complete( instance ); + done = 0; + ENABLE_IRQ(); + } else #endif /* REAL_DMA */ - { + { /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ - if (basr & BASR_PHASE_MATCH) - printk(KERN_NOTICE "scsi%d: unknown interrupt, " - "BASR 0x%x, MR 0x%x, SR 0x%x\n", - HOSTNO, basr, NCR5380_read(MODE_REG), - NCR5380_read(STATUS_REG)); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - } /* if !(SELECTION || PARITY) */ - handled = 1; - } /* BASR & IRQ */ else { - printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " - "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, - NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - - if (!done) { - INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); - /* Put a call to NCR5380_main() on the queue... */ - queue_main(); - } - return IRQ_RETVAL(handled); + if (basr & BASR_PHASE_MATCH) + printk(KERN_NOTICE "scsi%d: unknown interrupt, " + "BASR 0x%x, MR 0x%x, SR 0x%x\n", + HOSTNO, basr, NCR5380_read(MODE_REG), + NCR5380_read(STATUS_REG)); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + } /* if !(SELECTION || PARITY) */ + handled = 1; + } /* BASR & IRQ */ + else { + printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " + "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, + NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + + if (!done) { + INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); + /* Put a call to NCR5380_main() on the queue... */ + queue_main(); + } + return IRQ_RETVAL(handled); } #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) +static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) # endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ - hostdata->pendingr--; - break; - } + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + hostdata->pendingr--; + break; + } } #endif -/* - * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, +/* + * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. + * including ARBITRATION, SELECTION, and initial message out for + * IDENTIFY and queue messages. * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * Inputs : instance - instantiation of the 5380 driver on which this + * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for + * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for * the command that is presently connected. - * + * * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. + * 0 if selection succeeded or failed because the target + * did not respond. * - * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * Side effects : + * If bus busy, arbitration failed, etc, NCR5380_select() will exit * with registers as they should have been on entry - ie * SELECT_ENABLE will be set appropriately, the NCR5380 * will cease to drive any SCSI bus signals. * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. + * If successful : I_T_L or I_T_L_Q nexus will be established, + * instance->connected will be set to cmd. + * SELECT interrupt will be disabled. * - * If failed (no target) : cmd->scsi_done() will be called, and the + * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. */ -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) { - SETUP_HOSTDATA(instance); - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - unsigned long flags; - - hostdata->restart_select = 0; - NCR_PRINT(NDEBUG_ARBITRATION); - ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, - instance->this_id); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - local_irq_save(flags); - if (hostdata->connected) { - local_irq_restore(flags); - return -1; - } - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - + SETUP_HOSTDATA(instance); + unsigned char tmp[3], phase; + unsigned char *data; + int len; + unsigned long timeout; + unsigned long flags; + + hostdata->restart_select = 0; + NCR_PRINT(NDEBUG_ARBITRATION); + ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, + instance->this_id); + + /* + * Set the phase bits to 0, otherwise the NCR5380 won't drive the + * data bus during SELECTION. + */ + + local_irq_save(flags); + if (hostdata->connected) { local_irq_restore(flags); - - /* Wait for arbitration logic to complete */ -#if defined(NCR_TIMEOUT) - { - unsigned long timeout = jiffies + 2*NCR_TIMEOUT; - - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && - time_before(jiffies, timeout) && !hostdata->connected) - ; - if (time_after_eq(jiffies, timeout)) { - printk("scsi : arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } + return -1; + } + NCR5380_write(TARGET_COMMAND_REG, 0); + + + /* + * Start arbitration. + */ + + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); + + local_irq_restore(flags); + + /* Wait for arbitration logic to complete */ +#if NCR_TIMEOUT + { + unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && time_before(jiffies, timeout) && !hostdata->connected) + ; + if (time_after_eq(jiffies, timeout)) + { + printk("scsi : arbitration timeout at %d\n", __LINE__); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } #else /* NCR_TIMEOUT */ - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && - !hostdata->connected) - ; + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && !hostdata->connected); #endif - ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - return -1; - } - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", - HOSTNO); - return -1; - } + ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + return -1; + } + /* + * The arbitration delay is 2.2us, but this is a minimum and there is + * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate + * the integral nature of udelay(). + * + */ + + udelay(3); + + /* Check for lost arbitration */ + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", + HOSTNO); + return -1; + } + + /* after/during arbitration, BSY should be asserted. + IBM DPES-31080 Version S31Q works now */ + /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | + ICR_ASSERT_BSY ) ; + + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", + HOSTNO); + return -1; + } - /* after/during arbitration, BSY should be asserted. - IBM DPES-31080 Version S31Q works now */ - /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ - NCR5380_write(INITIATOR_COMMAND_REG, - ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); - - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", - HOSTNO); - return -1; - } - - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ + /* + * Again, bus clear + bus settle time is 1.2us, however, this is + * a minimum so we'll udelay ceil(1.2) + */ #ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY - /* ++roman: But some targets (see above :-) seem to need a bit more... */ - udelay(15); + /* ++roman: But some targets (see above :-) seem to need a bit more... */ + udelay(15); #else - udelay(2); + udelay(2); #endif - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); - - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ - - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); - - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); + + if (hostdata->connected) { NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ - - if (hostdata->connected) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - NCR5380_write(SELECT_ENABLE_REG, 0); + ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ + /* + * Now that we have won arbitration, start Selection process, asserting + * the host and target ID's on the SCSI bus. + */ - udelay(1); + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after selection. + */ - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); + NCR5380_write(MODE_REG, MR_BASE); - timeout = jiffies + 25; + /* + * Reselect interrupts must be turned off prior to the dropping of BSY, + * otherwise we will trigger an interrupt. + */ - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ + if (hostdata->connected) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + + NCR5380_write(SELECT_ENABLE_REG, 0); + + /* + * The initiator shall then wait at least two deskew delays and release + * the BSY signal. + */ + udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ + + /* Reset BSY */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + + /* + * Something weird happens when we cease to drive BSY - looks + * like the board/chip is letting us do another read before the + * appropriate propagation delay has expired, and we're confusing + * a BSY signal from ourselves as the target's response to SELECTION. + * + * A small delay (the 'C++' frontend breaks the pipeline with an + * unnecessary jump, making it work on my 386-33/Trantor T128, the + * tighter 'C' code breaks and requires this) solves the problem - + * the 1 us delay is arbitrary, and only used because this delay will + * be the same on other platforms and since it works here, it should + * work there. + * + * wingel suggests that this could be due to failing to wait + * one deskew delay. + */ + + udelay(1); + + SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); + + /* + * The SCSI specification calls for a 250 ms timeout for the actual + * selection. + */ + + timeout = jiffies + 25; + + /* + * XXX very interesting - we're seeing a bounce where the BSY we + * asserted is being reflected / still asserted (propagation delay?) + * and it's detecting as true. Sigh. + */ #if 0 - /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert - * IO while SEL is true. But again, there are some disks out the in the - * world that do that nevertheless. (Somebody claimed that this announces - * reselection capability of the target.) So we better skip that test and - * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) - */ - - while (time_before(jiffies, timeout) && - !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))) - ; - - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk(KERN_ERR "scsi%d: reselection after won arbitration?\n", - HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } + /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert + * IO while SEL is true. But again, there are some disks out the in the + * world that do that nevertheless. (Somebody claimed that this announces + * reselection capability of the target.) So we better skip that test and + * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) + */ + + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & + (SR_BSY | SR_IO))); + + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == + (SR_SEL | SR_IO)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_reselect(instance); + printk (KERN_ERR "scsi%d: reselection after won arbitration?\n", + HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } #else - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)) - ; + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); #endif - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ + /* + * No less than two deskew delays after the initiator detects the + * BSY signal is true, it shall release the SEL signal and may + * change the DATA BUS. -wingel + */ - udelay(1); + udelay(1); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->device->id)) { - printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); - if (hostdata->restart_select) - printk(KERN_NOTICE "\trestart select\n"); - NCR_PRINT(NDEBUG_ANY); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; + if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + if (hostdata->targets_present & (1 << cmd->device->id)) { + printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); + if (hostdata->restart_select) + printk(KERN_NOTICE "\trestart select\n"); + NCR_PRINT(NDEBUG_ANY); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + cmd->result = DID_BAD_TARGET << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif #ifdef SUPPORT_TAGS - cmd_free_tag(cmd); + cmd_free_tag( cmd ); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - - hostdata->targets_present |= (1 << cmd->device->id); - - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ - - /* Wait for start of REQ/ACK handshake */ - while (!(NCR5380_read(STATUS_REG) & SR_REQ)) - ; - - SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->device->id); - tmp[0] = IDENTIFY(1, cmd->device->lun); + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return 0; + } + + hostdata->targets_present |= (1 << cmd->device->id); + + /* + * Since we followed the SCSI spec, and raised ATN while SEL + * was true but before BSY was false during selection, the information + * transfer phase should be a MESSAGE OUT phase so that we can send the + * IDENTIFY message. + * + * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG + * message (2 bytes) with a tag ID that we increment with every command + * until it wraps back to 0. + * + * XXX - it turns out that there are some broken SCSI-II devices, + * which claim to support tagged queuing but fail when more than + * some number of commands are issued at once. + */ + + /* Wait for start of REQ/ACK handshake */ + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + + SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", + HOSTNO, cmd->device->id); + tmp[0] = IDENTIFY(1, cmd->device->lun); #ifdef SUPPORT_TAGS - if (cmd->tag != TAG_NONE) { - tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; - tmp[2] = cmd->tag; - len = 3; - } else - len = 1; -#else + if (cmd->tag != TAG_NONE) { + tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; + tmp[2] = cmd->tag; + len = 3; + } else len = 1; - cmd->tag = 0; +#else + len = 1; + cmd->tag=0; #endif /* SUPPORT_TAGS */ - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); - SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); - /* XXX need to handle errors here */ - hostdata->connected = cmd; + /* Send message(s) */ + data = tmp; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(instance, &phase, &len, &data); + SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); + /* XXX need to handle errors here */ + hostdata->connected = cmd; #ifndef SUPPORT_TAGS - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); -#endif + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); +#endif - initialize_SCp(cmd); + initialize_SCp(cmd); - return 0; + + return 0; } -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, +/* + * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using polled I/O * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of * bytes to transfer, **data - pointer to data pointer. - * + * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes are transfered or exit * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * * XXX Note : handling for bus free may be useful. */ /* - * Note : this code is not as quick as it could be, however it + * Note : this code is not as quick as it could be, however it * IS 100% reliable, and for the actual data transfer where speed * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) +static int NCR5380_transfer_pio( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) { - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; - - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER + register unsigned char p = *phase, tmp; + register int c = *count; + register unsigned char *d = *data; + + /* + * The NCR5380 chip will only drive the SCSI bus when the + * phase specified in the appropriate bits of the TARGET COMMAND + * REGISTER match the STATUS REGISTER + */ + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + + do { + /* + * Wait for assertion of REQ, after which the phase bits will be + * valid */ + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - do { - /* - * Wait for assertion of REQ, after which the phase bits will be - * valid - */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) - ; - - HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); - - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { - PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); - NCR_PRINT_PHASE(NDEBUG_PIO); - break; - } + HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + /* Check for phase mismatch */ + if ((tmp & PHASE_MASK) != p) { + PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); + NCR_PRINT_PHASE(NDEBUG_PIO); + break; + } - ++d; + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); + else + *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ + ++d; - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } - - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; + /* + * The SCSI standard suggests that in MSGOUT phase, the initiator + * should drop ATN on the last byte of the message phase + * after REQ has been asserted for the handshake but before + * the initiator raises ACK. + */ - HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); + if (!(p & SR_IO)) { + if (!((p & SR_MSG) && c > 1)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ACK); + } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + } + } else { + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + } - /* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); + while (NCR5380_read(STATUS_REG) & SR_REQ); - PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); + HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - /* The phase read from the bus is valid if either REQ is (already) - * asserted or if ACK hasn't been released yet. The latter is the case if - * we're in MSGIN and all wanted bytes have been received. - */ - if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; +/* + * We have several special cases to consider during REQ/ACK handshaking : + * 1. We were in MSGOUT phase, and we are on the last byte of the + * message. ATN must be dropped as ACK is dropped. + * + * 2. We are in a MSGIN phase, and we are on the last byte of the + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. + * + * 3. ACK and ATN are clear and the target may proceed as normal. + */ + if (!(p == PHASE_MSGIN && c == 1)) { + if (p == PHASE_MSGOUT && c > 1) + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + else + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + } while (--c); + + PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); + + *count = c; + *data = d; + tmp = NCR5380_read(STATUS_REG); + /* The phase read from the bus is valid if either REQ is (already) + * asserted or if ACK hasn't been released yet. The latter is the case if + * we're in MSGIN and all wanted bytes have been received. */ + if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) + *phase = tmp & PHASE_MASK; + else + *phase = PHASE_UNKNOWN; + + if (!c || (*phase == p)) + return 0; + else + return -1; } /* * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * * Returns : 0 on success, -1 on failure. */ -static int do_abort(struct Scsi_Host *host) +static int do_abort (struct Scsi_Host *host) { - unsigned char tmp, *msgptr, phase; - int len; - - /* Request message out phase */ + unsigned char tmp, *msgptr, phase; + int len; + + /* Request message out phase */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + + /* + * Wait for the target to indicate a valid phase by asserting + * REQ. Once this happens, we'll have either a MSGOUT phase + * and can immediately send the ABORT message, or we'll have some + * other phase and will have to source/sink data. + * + * We really don't care what value was on the bus or what value + * the target sees, so we just handshake. + */ + + while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ) - ; - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - } - - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ - - return len ? -1 : 0; + } + + tmp = ABORT; + msgptr = &tmp; + len = 1; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio (host, &phase, &len, &msgptr); + + /* + * If we got here, and the command completed successfully, + * we're about to go into bus free state. + */ + + return len ? -1 : 0; } #if defined(REAL_DMA) -/* - * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, +/* + * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using either real * or pseudo DMA. * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of * bytes to transfer, **data - pointer to data pointer. - * + * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes or transfered or exit * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * */ -static int NCR5380_transfer_dma(struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) +static int NCR5380_transfer_dma( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) { - SETUP_HOSTDATA(instance); - register int c = *count; - register unsigned char p = *phase; - register unsigned char *d = *data; - unsigned char tmp; - unsigned long flags; - - if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { - *phase = tmp; - return -1; - } + SETUP_HOSTDATA(instance); + register int c = *count; + register unsigned char p = *phase; + register unsigned char *d = *data; + unsigned char tmp; + unsigned long flags; + + if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { + *phase = tmp; + return -1; + } - if (atari_read_overruns && (p & SR_IO)) - c -= atari_read_overruns; + if (atari_read_overruns && (p & SR_IO)) { + c -= atari_read_overruns; + } - DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", - HOSTNO, (p & SR_IO) ? "reading" : "writing", - c, (p & SR_IO) ? "to" : "from", d); + DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", + HOSTNO, (p & SR_IO) ? "reading" : "writing", + c, (p & SR_IO) ? "to" : "from", d); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #endif /* def REAL_DMA */ - if (IS_A_TT()) { - /* On the Medusa, it is a must to initialize the DMA before - * starting the NCR. This is also the cleaner way for the TT. - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - - if (p & SR_IO) - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR5380_write(START_DMA_SEND_REG, 0); - } - - if (!IS_A_TT()) { - /* On the Falcon, the DMA setup must be done after the last */ - /* NCR access, else the DMA setup gets trashed! - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - return 0; + if (IS_A_TT()) { + /* On the Medusa, it is a must to initialize the DMA before + * starting the NCR. This is also the cleaner way for the TT. + */ + local_irq_save(flags); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + local_irq_restore(flags); + } + + if (p & SR_IO) + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_write(START_DMA_SEND_REG, 0); + } + + if (!IS_A_TT()) { + /* On the Falcon, the DMA setup must be done after the last */ + /* NCR access, else the DMA setup gets trashed! + */ + local_irq_save(flags); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + local_irq_restore(flags); + } + return 0; } #endif /* defined(REAL_DMA) */ /* * Function : NCR5380_information_transfer (struct Scsi_Host *instance) * - * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, + * Purpose : run through the various SCSI phases and do as the target + * directs us to. Operates on the currently connected command, * instance->connected. * * Inputs : instance, instance for which we are doing commands * - * Side effects : SCSI things happen, the disconnected queue will be + * Side effects : SCSI things happen, the disconnected queue will be * modified if a command disconnects, *instance->connected will * change. * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. + * XXX Note : we need to watch for bus free or a reset condition here + * to recover from an unexpected bus free condition. */ - -static void NCR5380_information_transfer(struct Scsi_Host *instance) + +static void NCR5380_information_transfer (struct Scsi_Host *instance) { - SETUP_HOSTDATA(instance); - unsigned long flags; - unsigned char msgout = NOP; - int sink = 0; - int len; + SETUP_HOSTDATA(instance); + unsigned long flags; + unsigned char msgout = NOP; + int sink = 0; + int len; #if defined(REAL_DMA) - int transfersize; + int transfersize; #endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; - - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; - NCR_PRINT_PHASE(NDEBUG_INFORMATION); - } - - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 0; - continue; - } + unsigned char *data; + unsigned char phase, tmp, extended_msg[10], old_phase=0xff; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; - switch (phase) { - case PHASE_DATAOUT: + while (1) { + tmp = NCR5380_read(STATUS_REG); + /* We only have a valid SCSI phase when REQ is asserted */ + if (tmp & SR_REQ) { + phase = (tmp & PHASE_MASK); + if (phase != old_phase) { + old_phase = phase; + NCR_PRINT_PHASE(NDEBUG_INFORMATION); + } + + if (sink && (phase != PHASE_MSGOUT)) { + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 0; + continue; + } + + switch (phase) { + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " - "aborted\n", HOSTNO); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - return; + printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " + "aborted\n", HOSTNO); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + return; #endif - case PHASE_DATAIN: - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + - cmd->SCp.buffer->offset; - /* ++roman: Try to merge some scatter-buffers if - * they are at contiguous physical addresses. - */ - merge_contiguous_buffers(cmd); - INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", - HOSTNO, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } - - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ - - /* ++roman: I suggest, this should be - * #if def(REAL_DMA) - * instead of leaving REAL_DMA out. - */ + case PHASE_DATAIN: + /* + * If there is no room left in the current buffer in the + * scatter-gather list, move onto the next one. + */ + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+ + cmd->SCp.buffer->offset; + /* ++roman: Try to merge some scatter-buffers if + * they are at contiguous physical addresses. + */ + merge_contiguous_buffers( cmd ); + INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", + HOSTNO, cmd->SCp.this_residual, + cmd->SCp.buffers_residual); + } + + /* + * The preferred transfer method is going to be + * PSEUDO-DMA for systems that are strictly PIO, + * since we can let the hardware do the handshaking. + * + * For this to work, we need to know the transfersize + * ahead of time, since the pseudo-DMA code will sit + * in an unconditional loop. + */ + +/* ++roman: I suggest, this should be + * #if def(REAL_DMA) + * instead of leaving REAL_DMA out. + */ #if defined(REAL_DMA) - if (!cmd->device->borken && - (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { - len = transfersize; - cmd->SCp.phase = phase; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **)&cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future - * accesses to this device will use the - * polled-IO. */ - printk(KERN_NOTICE "scsi%d: switching target %d " - "lun %d to slow handshake\n", HOSTNO, - cmd->device->id, cmd->device->lun); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else { + if (!cmd->device->borken && + (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { + len = transfersize; + cmd->SCp.phase = phase; + if (NCR5380_transfer_dma(instance, &phase, + &len, (unsigned char **) &cmd->SCp.ptr)) { + /* + * If the watchdog timer fires, all future + * accesses to this device will use the + * polled-IO. */ + printk(KERN_NOTICE "scsi%d: switching target %d " + "lun %d to slow handshake\n", HOSTNO, + cmd->device->id, cmd->device->lun); + cmd->device->borken = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + /* XXX - need to source or sink data here, as appropriate */ + } else { #ifdef REAL_DMA - /* ++roman: When using real DMA, - * information_transfer() should return after - * starting DMA since it has nothing more to - * do. - */ - return; -#else - cmd->SCp.this_residual -= transfersize - len; + /* ++roman: When using real DMA, + * information_transfer() should return after + * starting DMA since it has nothing more to + * do. + */ + return; +#else + cmd->SCp.this_residual -= transfersize - len; #endif - } - } else + } + } else #endif /* defined(REAL_DMA) */ - NCR5380_transfer_pio(instance, &phase, - (int *)&cmd->SCp.this_residual, - (unsigned char **)&cmd->SCp.ptr); - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; - - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ + NCR5380_transfer_pio(instance, &phase, + (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); + break; + case PHASE_MSGIN: + len = 1; + data = &tmp; + NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Message = tmp; + + switch (tmp) { + /* + * Linking lets us reduce the time required to get the + * next command out to the device, hopefully this will + * mean we don't waste another revolution due to the delays + * required by ARBITRATION and another SELECTION. + * + * In the current implementation proposal, low level drivers + * merely have to start the next command, pointed to by + * next_link, done() is called as with unlinked commands. + */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Sanity check : A linked command should only terminate - * with one of these messages if there are more linked - * commands available. - */ - - if (!cmd->next_link) { - printk(KERN_NOTICE "scsi%d: target %d lun %d " - "linked command complete, no next_link\n", - HOSTNO, cmd->device->id, cmd->device->lun); - sink = 1; - do_abort(instance); - return; - } - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process; copy it - * and don't free it! */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - LNK_PRINTK("scsi%d: target %d lun %d linked request " - "done, calling scsi_done().\n", - HOSTNO, cmd->device->id, cmd->device->lun); + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + LNK_PRINTK("scsi%d: target %d lun %d linked command " + "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Sanity check : A linked command should only terminate + * with one of these messages if there are more linked + * commands available. + */ + + if (!cmd->next_link) { + printk(KERN_NOTICE "scsi%d: target %d lun %d " + "linked command complete, no next_link\n", + HOSTNO, cmd->device->id, cmd->device->lun); + sink = 1; + do_abort (instance); + return; + } + + initialize_SCp(cmd->next_link); + /* The next command is still part of this process; copy it + * and don't free it! */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + LNK_PRINTK("scsi%d: target %d lun %d linked request " + "done, calling scsi_done().\n", + HOSTNO, cmd->device->id, cmd->device->lun); #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; #endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* ++guenther: possible race with Falcon locking */ - falcon_dont_release++; - hostdata->connected = NULL; - QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); + case ABORT: + case COMMAND_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* ++guenther: possible race with Falcon locking */ + falcon_dont_release++; + hostdata->connected = NULL; + QU_PRINTK("scsi%d: command for target %d, lun %d " + "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); #ifdef SUPPORT_TAGS - cmd_free_tag(cmd); - if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { - /* Turn a QUEUE FULL status into BUSY, I think the - * mid level cannot handle QUEUE FULL :-( (The - * command is retried after BUSY). Also update our - * queue size to the number of currently issued - * commands now. - */ - /* ++Andreas: the mid level code knows about - QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - TAG_PRINTK("scsi%d: target %d lun %d returned " - "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->device->id, cmd->device->lun, - ta->nr_allocated); - if (ta->queue_size > ta->nr_allocated) - ta->nr_allocated = ta->queue_size; - } + cmd_free_tag( cmd ); + if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { + /* Turn a QUEUE FULL status into BUSY, I think the + * mid level cannot handle QUEUE FULL :-( (The + * command is retried after BUSY). Also update our + * queue size to the number of currently issued + * commands now. + */ + /* ++Andreas: the mid level code knows about + QUEUE_FULL now. */ + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + TAG_PRINTK("scsi%d: target %d lun %d returned " + "QUEUE_FULL after %d commands\n", + HOSTNO, cmd->device->id, cmd->device->lun, + ta->nr_allocated); + if (ta->queue_size > ta->nr_allocated) + ta->nr_allocated = ta->queue_size; + } #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way to - * differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the - * result code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (status_byte(cmd->SCp.Status) != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way to + * differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the + * result code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (status_byte(cmd->SCp.Status) != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + #ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { - ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - - cmd->use_sg = 0; - /* this is initialized from initialize_SCp - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - */ - cmd->request_buffer = (char *) cmd->sense_buffer; - cmd->request_bufflen = sizeof(cmd->sense_buffer); - - local_irq_save(flags); - LIST(cmd,hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = (Scsi_Cmnd *) cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: REQUEST SENSE added to head of " - "issue queue\n", H_NO(cmd)); - } else + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + ASEN_PRINTK("scsi%d: performing request sense\n", + HOSTNO); + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); + + cmd->use_sg = 0; + /* this is initialized from initialize_SCp + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + */ + cmd->request_buffer = (char *) cmd->sense_buffer; + cmd->request_bufflen = sizeof(cmd->sense_buffer); + + local_irq_save(flags); + LIST(cmd,hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + local_irq_restore(flags); + QU_PRINTK("scsi%d: REQUEST SENSE added to head of " + "issue queue\n", H_NO(cmd)); + } else #endif /* def AUTOSENSE */ - { + { #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - } - - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - - falcon_dont_release--; - /* ++roman: For Falcon SCSI, release the lock on the - * ST-DMA here if no other commands are waiting on the - * disconnected queue. - */ - falcon_release_lock_if_possible(hostdata); - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - /* The target obviously doesn't support tagged - * queuing, even though it announced this ability in - * its INQUIRY data ?!? (maybe only this LUN?) Ok, - * clear 'tagged_supported' and lock the LUN, since - * the command is treated as untagged further on. - */ - cmd->device->tagged_supported = 0; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - cmd->tag = TAG_NONE; - TAG_PRINTK("scsi%d: target %d lun %d rejected " - "QUEUE_TAG message; tagged queuing " - "disabled\n", - HOSTNO, cmd->device->id, cmd->device->lun); - break; - } - break; - case DISCONNECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - local_irq_save(flags); - cmd->device->disconnect = 1; - LIST(cmd,hostdata->disconnected_queue); - SET_NEXT(cmd, hostdata->disconnected_queue); - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: command for target %d lun %d was " - "moved from connected to the " - "disconnected_queue\n", HOSTNO, - cmd->device->id, cmd->device->lun); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - break; - case EXTENDED_MESSAGE: - /* - * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments - * - * Start the extended message buffer with the EXTENDED_MESSAGE - * byte, since spi_print_msg() wants the whole thing. - */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); - - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, - (int)extended_msg[1], (int)extended_msg[2]); - - if (!len && extended_msg[1] <= - (sizeof(extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; - - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: message received, residual %d\n", - HOSTNO, len); - - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk(KERN_NOTICE "scsi%d: error receiving " - "extended message\n", HOSTNO); - tmp = 0; - } else { - printk(KERN_NOTICE "scsi%d: extended message " - "code %02x length %d is too long\n", - HOSTNO, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); - spi_print_msg(extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->device->id, cmd->device->lun); - else - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "extended message " - "code %02x, length %d from target %d, lun %d\n", - HOSTNO, extended_msg[1], extended_msg[0], - cmd->device->id, cmd->device->lun); - - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { + cmd->scsi_done(cmd); + } + + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + + falcon_dont_release--; + /* ++roman: For Falcon SCSI, release the lock on the + * ST-DMA here if no other commands are waiting on the + * disconnected queue. + */ + falcon_release_lock_if_possible( hostdata ); + return; + case MESSAGE_REJECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + switch (hostdata->last_message) { + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* The target obviously doesn't support tagged + * queuing, even though it announced this ability in + * its INQUIRY data ?!? (maybe only this LUN?) Ok, + * clear 'tagged_supported' and lock the LUN, since + * the command is treated as untagged further on. + */ + cmd->device->tagged_supported = 0; + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); + cmd->tag = TAG_NONE; + TAG_PRINTK("scsi%d: target %d lun %d rejected " + "QUEUE_TAG message; tagged queuing " + "disabled\n", + HOSTNO, cmd->device->id, cmd->device->lun); + break; + } + break; + case DISCONNECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + local_irq_save(flags); + cmd->device->disconnect = 1; + LIST(cmd,hostdata->disconnected_queue); + NEXT(cmd) = hostdata->disconnected_queue; + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + local_irq_restore(flags); + QU_PRINTK("scsi%d: command for target %d lun %d was " + "moved from connected to the " + "disconnected_queue\n", HOSTNO, + cmd->device->id, cmd->device->lun); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + return; + /* + * The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. + */ + case SAVE_POINTERS: + case RESTORE_POINTERS: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + break; + case EXTENDED_MESSAGE: +/* + * Extended messages are sent in the following format : + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't + * include first two bytes) + * 2 code + * 3..length+1 arguments + * + * Start the extended message buffer with the EXTENDED_MESSAGE + * byte, since spi_print_msg() wants the whole thing. + */ + extended_msg[0] = EXTENDED_MESSAGE; + /* Accept first byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); + + len = 2; + data = extended_msg + 1; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, + (int)extended_msg[1], (int)extended_msg[2]); + + if (!len && extended_msg[1] <= + (sizeof (extended_msg) - 1)) { + /* Accept third byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = extended_msg[1] - 1; + data = extended_msg + 3; + phase = PHASE_MSGIN; + + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: message received, residual %d\n", + HOSTNO, len); + + switch (extended_msg[2]) { + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; + } + } else if (len) { + printk(KERN_NOTICE "scsi%d: error receiving " + "extended message\n", HOSTNO); + tmp = 0; + } else { + printk(KERN_NOTICE "scsi%d: extended message " + "code %02x length %d is too long\n", + HOSTNO, extended_msg[2], extended_msg[1]); + tmp = 0; + } + /* Fall through to reject message */ + + /* + * If we get something weird that we aren't expecting, + * reject it. + */ + default: + if (!tmp) { + printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); + spi_print_msg(extended_msg); + printk("\n"); + } else if (tmp != EXTENDED_MESSAGE) + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "message %02x from target %d, lun %d\n", + HOSTNO, tmp, cmd->device->id, cmd->device->lun); + else + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "extended message " + "code %02x, length %d from target %d, lun %d\n", + HOSTNO, extended_msg[1], extended_msg[0], + cmd->device->id, cmd->device->lun); + + + msgout = MESSAGE_REJECT; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + break; + } /* switch (tmp) */ + break; + case PHASE_MSGOUT: + len = 1; + data = &msgout; + hostdata->last_message = msgout; + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (msgout == ABORT) { #ifdef SUPPORT_TAGS - cmd_free_tag(cmd); + cmd_free_tag( cmd ); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; + hostdata->connected = NULL; + cmd->result = DID_ERROR << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - falcon_release_lock_if_possible(hostdata); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d: unknown phase\n", HOSTNO); - NCR_PRINT(NDEBUG_ANY); - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ - } /* while (1) */ + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + falcon_release_lock_if_possible( hostdata ); + return; + } + msgout = NOP; + break; + case PHASE_CMDOUT: + len = cmd->cmd_len; + data = cmd->cmnd; + /* + * XXX for performance reasons, on machines with a + * PSEUDO-DMA architecture we should probably + * use the dma transfer function. + */ + NCR5380_transfer_pio(instance, &phase, &len, + &data); + break; + case PHASE_STATIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Status = tmp; + break; + default: + printk("scsi%d: unknown phase\n", HOSTNO); + NCR_PRINT(NDEBUG_ANY); + } /* switch(phase) */ + } /* if (tmp * SR_REQ) */ + } /* while (1) */ } /* * Function : void NCR5380_reselect (struct Scsi_Host *instance) * - * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * Purpose : does reselection, initializing the instance->connected + * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q * nexus has been reestablished, - * + * * Inputs : instance - this instance of the NCR5380. * */ -static void NCR5380_reselect(struct Scsi_Host *instance) +static void NCR5380_reselect (struct Scsi_Host *instance) { - SETUP_HOSTDATA(instance); - unsigned char target_mask; - unsigned char lun, phase; - int len; + SETUP_HOSTDATA(instance); + unsigned char target_mask; + unsigned char lun, phase; + int len; #ifdef SUPPORT_TAGS - unsigned char tag; + unsigned char tag; #endif - unsigned char msg[3]; - unsigned char *data; - Scsi_Cmnd *tmp = NULL, *prev; -/* unsigned long flags; */ - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ - - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); - - RSL_PRINTK("scsi%d: reselect\n", HOSTNO); - - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - while (NCR5380_read(STATUS_REG) & SR_SEL) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - */ - - while (!(NCR5380_read(STATUS_REG) & SR_REQ)) - ; - - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - if (!(msg[0] & 0x80)) { - printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); - spi_print_msg(msg); - do_abort(instance); - return; - } - lun = (msg[0] & 0x07); + unsigned char msg[3]; + unsigned char *data; + Scsi_Cmnd *tmp = NULL, *prev; +/* unsigned long flags; */ + + /* + * Disable arbitration, etc. since the host adapter obviously + * lost, and tell an interrupted NCR5380_select() to restart. + */ + + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; + + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + + RSL_PRINTK("scsi%d: reselect\n", HOSTNO); + + /* + * At this point, we have detected that our SCSI ID is on the bus, + * SEL is true and BSY was false for at least one bus settle delay + * (400 ns). + * + * We must assert BSY ourselves, until the target drops the SEL + * signal. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + + while (NCR5380_read(STATUS_REG) & SR_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * Wait for target to go into MSGIN. + */ + + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + + if (!(msg[0] & 0x80)) { + printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); + spi_print_msg(msg); + do_abort(instance); + return; + } + lun = (msg[0] & 0x07); #ifdef SUPPORT_TAGS - /* If the phase is still MSGIN, the target wants to send some more - * messages. In case it supports tagged queuing, this is probably a - * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. - */ - tag = TAG_NONE; - if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { - /* Accept previous IDENTIFY message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = 2; - data = msg + 1; - if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && - msg[1] == SIMPLE_QUEUE_TAG) - tag = msg[2]; - TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " - "reselection\n", HOSTNO, target_mask, lun, tag); - } + /* If the phase is still MSGIN, the target wants to send some more + * messages. In case it supports tagged queuing, this is probably a + * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. + */ + tag = TAG_NONE; + if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { + /* Accept previous IDENTIFY message by clearing ACK */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + len = 2; + data = msg+1; + if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && + msg[1] == SIMPLE_QUEUE_TAG) + tag = msg[2]; + TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " + "reselection\n", HOSTNO, target_mask, lun, tag); + } #endif - - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = NEXT(tmp)) { - if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) + + /* + * Find the command corresponding to the I_T_L or I_T_L_Q nexus we + * just reestablished, and remove it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = NEXT(tmp) ) { + if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) #ifdef SUPPORT_TAGS - && (tag == tmp->tag) + && (tag == tmp->tag) #endif - ) { - /* ++guenther: prevent race with falcon_release_lock */ - falcon_dont_release++; - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); - hostdata->disconnected_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - break; - } + ) { + /* ++guenther: prevent race with falcon_release_lock */ + falcon_dont_release++; + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); + hostdata->disconnected_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + break; } - - if (!tmp) { - printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " + } + + if (!tmp) { + printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " #ifdef SUPPORT_TAGS - "tag %d " + "tag %d " #endif - "not in disconnected_queue.\n", - HOSTNO, target_mask, lun + "not in disconnected_queue.\n", + HOSTNO, target_mask, lun #ifdef SUPPORT_TAGS - , tag + , tag #endif - ); - /* - * Since we have an established nexus that we can't do anything - * with, we must abort it. - */ - do_abort(instance); - return; - } + ); + /* + * Since we have an established nexus that we can't do anything + * with, we must abort it. + */ + do_abort(instance); + return; + } - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - hostdata->connected = tmp; - RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); - falcon_dont_release--; + hostdata->connected = tmp; + RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", + HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); + falcon_dont_release--; } @@ -2677,361 +2626,362 @@ static void NCR5380_reselect(struct Scsi_Host *instance) * * Purpose : abort a command * - * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is + * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the + * host byte of the result field to, if zero DID_ABORTED is * used. * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * called where the loop started in NCR5380_main(). */ static -int NCR5380_abort(Scsi_Cmnd *cmd) +int NCR5380_abort (Scsi_Cmnd *cmd) { - struct Scsi_Host *instance = cmd->device->host; - SETUP_HOSTDATA(instance); - Scsi_Cmnd *tmp, **prev; - unsigned long flags; - - printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); - scsi_print_command(cmd); + struct Scsi_Host *instance = cmd->device->host; + SETUP_HOSTDATA(instance); + Scsi_Cmnd *tmp, **prev; + unsigned long flags; - NCR5380_print_status(instance); + printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); + scsi_print_command(cmd); - local_irq_save(flags); + NCR5380_print_status (instance); - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", - HOSTNO); + local_irq_save(flags); + + if (!IS_A_TT() && !falcon_got_lock) + printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", + HOSTNO); - ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, - NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); + ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, + NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); #if 1 - /* - * Case 1 : If the command is the currently executing command, - * we'll set the aborted flag and return control so that - * information transfer routine can exit cleanly. - */ +/* + * Case 1 : If the command is the currently executing command, + * we'll set the aborted flag and return control so that + * information transfer routine can exit cleanly. + */ - if (hostdata->connected == cmd) { + if (hostdata->connected == cmd) { - ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); - /* - * We should perform BSY checking, and make sure we haven't slipped - * into BUS FREE. - */ + ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); +/* + * We should perform BSY checking, and make sure we haven't slipped + * into BUS FREE. + */ - /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ - /* - * Since we can't change phases until we've completed the current - * handshake, we have to source or sink a byte of data if the current - * phase is not MSGOUT. - */ +/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ +/* + * Since we can't change phases until we've completed the current + * handshake, we have to source or sink a byte of data if the current + * phase is not MSGOUT. + */ - /* - * Return control to the executing NCR drive so we can clear the - * aborted flag and get back into our main loop. - */ +/* + * Return control to the executing NCR drive so we can clear the + * aborted flag and get back into our main loop. + */ - if (do_abort(instance) == 0) { - hostdata->aborted = 1; - hostdata->connected = NULL; - cmd->result = DID_ABORT << 16; + if (do_abort(instance) == 0) { + hostdata->aborted = 1; + hostdata->connected = NULL; + cmd->result = DID_ABORT << 16; #ifdef SUPPORT_TAGS - cmd_free_tag(cmd); + cmd_free_tag( cmd ); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - local_irq_restore(flags); - cmd->scsi_done(cmd); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } else { -/* local_irq_restore(flags); */ - printk("scsi%d: abort of connected command failed!\n", HOSTNO); - return SCSI_ABORT_ERROR; - } - } + local_irq_restore(flags); + cmd->scsi_done(cmd); + falcon_release_lock_if_possible( hostdata ); + return SCSI_ABORT_SUCCESS; + } else { +/* local_irq_restore(flags); */ + printk("scsi%d: abort of connected command failed!\n", HOSTNO); + return SCSI_ABORT_ERROR; + } + } #endif - /* - * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. - */ - for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue), - tmp = (Scsi_Cmnd *)hostdata->issue_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - (*prev) = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", - HOSTNO); - /* Tagged queuing note: no tag to free here, hasn't been assigned - * yet... */ - tmp->scsi_done(tmp); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } - } - - /* - * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); - return SCSI_ABORT_SNOOZE; +/* + * Case 2 : If the command hasn't been issued yet, we simply remove it + * from the issue queue. + */ + for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), + tmp = (Scsi_Cmnd *) hostdata->issue_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + (*prev) = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", + HOSTNO); + /* Tagged queuing note: no tag to free here, hasn't been assigned + * yet... */ + tmp->scsi_done(tmp); + falcon_release_lock_if_possible( hostdata ); + return SCSI_ABORT_SUCCESS; } - /* - * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send - * an abort message. - * - * This case is especially ugly. In order to reestablish the nexus, we - * need to call NCR5380_select(). The easiest way to implement this - * function was to abort if the bus was busy, and let the interrupt - * handler triggered on the SEL for reselect take care of lost arbitrations - * where necessary, meaning interrupts need to be enabled. - * - * When interrupts are enabled, the queues may change - so we - * can't remove it from the disconnected queue before selecting it - * because that could cause a failure in hashing the nexus if that - * device reselected. - * - * Since the queues may change, we can't use the pointers from when we - * first locate it. - * - * So, we must first locate the command, and if NCR5380_select() - * succeeds, then issue the abort, relocate the command and remove - * it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = NEXT(tmp)) { - if (cmd == tmp) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); - - if (NCR5380_select(instance, cmd, (int)cmd->tag)) - return SCSI_ABORT_BUSY; +/* + * Case 3 : If any commands are connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ - ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); + if (hostdata->connected) { + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); + return SCSI_ABORT_SNOOZE; + } - do_abort(instance); +/* + * Case 4: If the command is currently disconnected from the bus, and + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send + * an abort message. + * + * This case is especially ugly. In order to reestablish the nexus, we + * need to call NCR5380_select(). The easiest way to implement this + * function was to abort if the bus was busy, and let the interrupt + * handler triggered on the SEL for reselect take care of lost arbitrations + * where necessary, meaning interrupts need to be enabled. + * + * When interrupts are enabled, the queues may change - so we + * can't remove it from the disconnected queue before selecting it + * because that could cause a failure in hashing the nexus if that + * device reselected. + * + * Since the queues may change, we can't use the pointers from when we + * first locate it. + * + * So, we must first locate the command, and if NCR5380_select() + * succeeds, then issue the abort, relocate the command and remove + * it from the disconnected queue. + */ - local_irq_save(flags); - for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *)hostdata->disconnected_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - *prev = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - /* We must unlock the tag/LUN immediately here, since the - * target goes to BUS FREE and doesn't send us another - * message (COMMAND_COMPLETE or the like) - */ + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = NEXT(tmp)) + if (cmd == tmp) { + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); + + if (NCR5380_select (instance, cmd, (int) cmd->tag)) + return SCSI_ABORT_BUSY; + + ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); + + do_abort (instance); + + local_irq_save(flags); + for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), + tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + *prev = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + /* We must unlock the tag/LUN immediately here, since the + * target goes to BUS FREE and doesn't send us another + * message (COMMAND_COMPLETE or the like) + */ #ifdef SUPPORT_TAGS - cmd_free_tag(tmp); + cmd_free_tag( tmp ); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - local_irq_restore(flags); - tmp->scsi_done(tmp); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } - } + local_irq_restore(flags); + tmp->scsi_done(tmp); + falcon_release_lock_if_possible( hostdata ); + return SCSI_ABORT_SUCCESS; } } - /* - * Case 5 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ +/* + * Case 5 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case something really + * broke. + */ - local_irq_restore(flags); - printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" - KERN_INFO " before abortion\n", HOSTNO); + local_irq_restore(flags); + printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" + KERN_INFO " before abortion\n", HOSTNO); - /* Maybe it is sufficient just to release the ST-DMA lock... (if - * possible at all) At least, we should check if the lock could be - * released after the abort, in case it is kept due to some bug. - */ - falcon_release_lock_if_possible(hostdata); +/* Maybe it is sufficient just to release the ST-DMA lock... (if + * possible at all) At least, we should check if the lock could be + * released after the abort, in case it is kept due to some bug. + */ + falcon_release_lock_if_possible( hostdata ); - return SCSI_ABORT_NOT_RUNNING; + return SCSI_ABORT_NOT_RUNNING; } -/* +/* * Function : int NCR5380_reset (Scsi_Cmnd *cmd) - * + * * Purpose : reset the SCSI bus. * * Returns : SCSI_RESET_WAKEUP * - */ + */ -static int NCR5380_bus_reset(Scsi_Cmnd *cmd) +static int NCR5380_bus_reset( Scsi_Cmnd *cmd) { - SETUP_HOSTDATA(cmd->device->host); - int i; - unsigned long flags; + SETUP_HOSTDATA(cmd->device->host); + int i; + unsigned long flags; #if 1 - Scsi_Cmnd *connected, *disconnected_queue; + Scsi_Cmnd *connected, *disconnected_queue; #endif - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", - H_NO(cmd)); - - NCR5380_print_status(cmd->device->host); - - /* get in phase */ - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); - /* assert RST */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(40); - /* reset NCR registers */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); - /* ++roman: reset interrupt condition! otherwise no interrupts don't get - * through anymore ... */ - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - -#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ - /* XXX see below XXX */ - - /* MSch: old-style reset: actually abort all command processing here */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; to avoid problems with re-inserting the commands - * into the issue_queue (via scsi_done()), the aborted commands are - * remembered in local variables first. - */ - local_irq_save(flags); - connected = (Scsi_Cmnd *)hostdata->connected; - hostdata->connected = NULL; - disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; - hostdata->disconnected_queue = NULL; + if (!IS_A_TT() && !falcon_got_lock) + printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", + H_NO(cmd) ); + + NCR5380_print_status (cmd->device->host); + + /* get in phase */ + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + /* assert RST */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + udelay (40); + /* reset NCR registers */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_write( MODE_REG, MR_BASE ); + NCR5380_write( TARGET_COMMAND_REG, 0 ); + NCR5380_write( SELECT_ENABLE_REG, 0 ); + /* ++roman: reset interrupt condition! otherwise no interrupts don't get + * through anymore ... */ + (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + +#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ + /* XXX see below XXX */ + + /* MSch: old-style reset: actually abort all command processing here */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; to avoid problems with re-inserting the commands + * into the issue_queue (via scsi_done()), the aborted commands are + * remembered in local variables first. + */ + local_irq_save(flags); + connected = (Scsi_Cmnd *)hostdata->connected; + hostdata->connected = NULL; + disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; + hostdata->disconnected_queue = NULL; #ifdef SUPPORT_TAGS - free_all_tags(); + free_all_tags(); #endif - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; + for( i = 0; i < 8; ++i ) + hostdata->busy[i] = 0; #ifdef REAL_DMA - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - local_irq_restore(flags); - - /* In order to tell the mid-level code which commands were aborted, - * set the command status to DID_RESET and call scsi_done() !!! - * This ultimately aborts processing of these commands in the mid-level. - */ - - if ((cmd = connected)) { - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done(cmd); - } - - for (i = 0; (cmd = disconnected_queue); ++i) { - disconnected_queue = NEXT(cmd); - SET_NEXT(cmd, NULL); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done(cmd); - } - if (i > 0) - ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); - - /* The Falcon lock should be released after a reset... - */ - /* ++guenther: moved to atari_scsi_reset(), to prevent a race between - * unlocking and enabling dma interrupt. - */ -/* falcon_release_lock_if_possible( hostdata );*/ + local_irq_restore(flags); + + /* In order to tell the mid-level code which commands were aborted, + * set the command status to DID_RESET and call scsi_done() !!! + * This ultimately aborts processing of these commands in the mid-level. + */ + + if ((cmd = connected)) { + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } + + for (i = 0; (cmd = disconnected_queue); ++i) { + disconnected_queue = NEXT(cmd); + NEXT(cmd) = NULL; + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } + if (i > 0) + ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); + +/* The Falcon lock should be released after a reset... + */ +/* ++guenther: moved to atari_scsi_reset(), to prevent a race between + * unlocking and enabling dma interrupt. + */ +/* falcon_release_lock_if_possible( hostdata );*/ - /* since all commands have been explicitly terminated, we need to tell - * the midlevel code that the reset was SUCCESSFUL, and there is no - * need to 'wake up' the commands by a request_sense - */ - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + /* since all commands have been explicitly terminated, we need to tell + * the midlevel code that the reset was SUCCESSFUL, and there is no + * need to 'wake up' the commands by a request_sense + */ + return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; #else /* 1 */ - /* MSch: new-style reset handling: let the mid-level do what it can */ - - /* ++guenther: MID-LEVEL IS STILL BROKEN. - * Mid-level is supposed to requeue all commands that were active on the - * various low-level queues. In fact it does this, but that's not enough - * because all these commands are subject to timeout. And if a timeout - * happens for any removed command, *_abort() is called but all queues - * are now empty. Abort then gives up the falcon lock, which is fatal, - * since the mid-level will queue more commands and must have the lock - * (it's all happening inside timer interrupt handler!!). - * Even worse, abort will return NOT_RUNNING for all those commands not - * on any queue, so they won't be retried ... - * - * Conclusion: either scsi.c disables timeout for all resetted commands - * immediately, or we lose! As of linux-2.0.20 it doesn't. - */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; so clear the low-level status here to avoid - * conflicts when the mid-level code tries to wake up the affected - * commands! - */ - - if (hostdata->issue_queue) - ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); - if (hostdata->connected) - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - if (hostdata->disconnected_queue) - ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - - local_irq_save(flags); - hostdata->issue_queue = NULL; - hostdata->connected = NULL; - hostdata->disconnected_queue = NULL; + /* MSch: new-style reset handling: let the mid-level do what it can */ + + /* ++guenther: MID-LEVEL IS STILL BROKEN. + * Mid-level is supposed to requeue all commands that were active on the + * various low-level queues. In fact it does this, but that's not enough + * because all these commands are subject to timeout. And if a timeout + * happens for any removed command, *_abort() is called but all queues + * are now empty. Abort then gives up the falcon lock, which is fatal, + * since the mid-level will queue more commands and must have the lock + * (it's all happening inside timer interrupt handler!!). + * Even worse, abort will return NOT_RUNNING for all those commands not + * on any queue, so they won't be retried ... + * + * Conclusion: either scsi.c disables timeout for all resetted commands + * immediately, or we lose! As of linux-2.0.20 it doesn't. + */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; so clear the low-level status here to avoid + * conflicts when the mid-level code tries to wake up the affected + * commands! + */ + + if (hostdata->issue_queue) + ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); + if (hostdata->connected) + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + if (hostdata->disconnected_queue) + ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); + + local_irq_save(flags); + hostdata->issue_queue = NULL; + hostdata->connected = NULL; + hostdata->disconnected_queue = NULL; #ifdef SUPPORT_TAGS - free_all_tags(); + free_all_tags(); #endif - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; + for( i = 0; i < 8; ++i ) + hostdata->busy[i] = 0; #ifdef REAL_DMA - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - local_irq_restore(flags); + local_irq_restore(flags); - /* we did no complete reset of all commands, so a wakeup is required */ - return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; + /* we did no complete reset of all commands, so a wakeup is required */ + return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; #endif /* 1 */ } + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff --git a/trunk/drivers/scsi/atari_scsi.c b/trunk/drivers/scsi/atari_scsi.c index 6f8403b82ba1..642de7b2b7a2 100644 --- a/trunk/drivers/scsi/atari_scsi.c +++ b/trunk/drivers/scsi/atari_scsi.c @@ -69,9 +69,9 @@ #define NDEBUG (0) -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 +#define NDEBUG_ABORT 0x800000 +#define NDEBUG_TAGS 0x1000000 +#define NDEBUG_MERGING 0x2000000 #define AUTOSENSE /* For the Atari version, use only polled IO or REAL_DMA */ @@ -186,37 +186,38 @@ static inline void DISABLE_IRQ(void) /***************************** Prototypes *****************************/ #ifdef REAL_DMA -static int scsi_dma_is_ignored_buserr(unsigned char dma_stat); -static void atari_scsi_fetch_restbytes(void); -static long atari_scsi_dma_residual(struct Scsi_Host *instance); -static int falcon_classify_cmd(Scsi_Cmnd *cmd); -static unsigned long atari_dma_xfer_len(unsigned long wanted_len, - Scsi_Cmnd *cmd, int write_flag); +static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ); +static void atari_scsi_fetch_restbytes( void ); +static long atari_scsi_dma_residual( struct Scsi_Host *instance ); +static int falcon_classify_cmd( Scsi_Cmnd *cmd ); +static unsigned long atari_dma_xfer_len( unsigned long wanted_len, + Scsi_Cmnd *cmd, int write_flag ); #endif -static irqreturn_t scsi_tt_intr(int irq, void *dummy); -static irqreturn_t scsi_falcon_intr(int irq, void *dummy); -static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata); -static void falcon_get_lock(void); +static irqreturn_t scsi_tt_intr( int irq, void *dummy); +static irqreturn_t scsi_falcon_intr( int irq, void *dummy); +static void falcon_release_lock_if_possible( struct NCR5380_hostdata * + hostdata ); +static void falcon_get_lock( void ); #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -static void atari_scsi_reset_boot(void); +static void atari_scsi_reset_boot( void ); #endif -static unsigned char atari_scsi_tt_reg_read(unsigned char reg); -static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value); -static unsigned char atari_scsi_falcon_reg_read(unsigned char reg); -static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value); +static unsigned char atari_scsi_tt_reg_read( unsigned char reg ); +static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value); +static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ); +static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ); /************************* End of Prototypes **************************/ -static struct Scsi_Host *atari_scsi_host; -static unsigned char (*atari_scsi_reg_read)(unsigned char reg); -static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value); +static struct Scsi_Host *atari_scsi_host = NULL; +static unsigned char (*atari_scsi_reg_read)( unsigned char reg ); +static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value ); #ifdef REAL_DMA static unsigned long atari_dma_residual, atari_dma_startaddr; static short atari_dma_active; /* pointer to the dribble buffer */ -static char *atari_dma_buffer; +static char *atari_dma_buffer = NULL; /* precalculated physical address of the dribble buffer */ static unsigned long atari_dma_phys_buffer; /* != 0 tells the Falcon int handler to copy data from the dribble buffer */ @@ -232,7 +233,7 @@ static char *atari_dma_orig_addr; static unsigned long atari_dma_stram_mask; #define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0) /* number of bytes to cut from a transfer to handle NCR overruns */ -static int atari_read_overruns; +static int atari_read_overruns = 0; #endif static int setup_can_queue = -1; @@ -255,10 +256,10 @@ module_param(setup_hostid, int, 0); #if defined(REAL_DMA) -static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) +static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) { int i; - unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr; + unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr; if (dma_stat & 0x01) { @@ -266,14 +267,15 @@ static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) * physical memory chunk (DMA prefetch!), but that doesn't hurt. * Check for this case: */ - - for (i = 0; i < m68k_num_memory; ++i) { - end_addr = m68k_memory[i].addr + m68k_memory[i].size; + + for( i = 0; i < m68k_num_memory; ++i ) { + end_addr = m68k_memory[i].addr + + m68k_memory[i].size; if (end_addr <= addr && addr <= end_addr + 4) - return 1; + return( 1 ); } } - return 0; + return( 0 ); } @@ -282,27 +284,28 @@ static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has * to clear the DMA int pending bit before it allows other level 6 interrupts. */ -static void scsi_dma_buserr(int irq, void *dummy) +static void scsi_dma_buserr (int irq, void *dummy) { - unsigned char dma_stat = tt_scsi_dma.dma_ctrl; + unsigned char dma_stat = tt_scsi_dma.dma_ctrl; /* Don't do anything if a NCR interrupt is pending. Probably it's just * masked... */ - if (atari_irq_pending(IRQ_TT_MFP_SCSI)) + if (atari_irq_pending( IRQ_TT_MFP_SCSI )) return; - + printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr(dma_stat)) - printk("SCSI DMA bus error -- bad DMA programming!\n"); - } else { + if (!scsi_dma_is_ignored_buserr( dma_stat )) + printk( "SCSI DMA bus error -- bad DMA programming!\n" ); + } + else { /* Under normal circumstances we never should get to this point, * since both interrupts are triggered simultaneously and the 5380 * int has higher priority. When this irq is handled, that DMA * interrupt is cleared. So a warning message is printed here. */ - printk("SCSI DMA intr ?? -- this shouldn't happen!\n"); + printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" ); } } #endif @@ -310,7 +313,7 @@ static void scsi_dma_buserr(int irq, void *dummy) #endif -static irqreturn_t scsi_tt_intr(int irq, void *dummy) +static irqreturn_t scsi_tt_intr (int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; @@ -324,7 +327,7 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy) * is that a bus error occurred... */ if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr(dma_stat)) { + if (!scsi_dma_is_ignored_buserr( dma_stat )) { printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n", SCSI_DMA_READ_P(dma_addr)); printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!"); @@ -341,7 +344,8 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy) * data reg! */ if ((dma_stat & 0x02) && !(dma_stat & 0x40)) { - atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr); + atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) - + atari_dma_startaddr); DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", atari_dma_residual); @@ -349,30 +353,28 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy) if ((signed int)atari_dma_residual < 0) atari_dma_residual = 0; if ((dma_stat & 1) == 0) { - /* - * After read operations, we maybe have to - * transport some rest bytes - */ + /* After read operations, we maybe have to + transport some rest bytes */ atari_scsi_fetch_restbytes(); - } else { - /* - * There seems to be a nasty bug in some SCSI-DMA/NCR - * combinations: If a target disconnects while a write - * operation is going on, the address register of the - * DMA may be a few bytes farer than it actually read. - * This is probably due to DMA prefetching and a delay - * between DMA and NCR. Experiments showed that the - * dma_addr is 9 bytes to high, but this could vary. - * The problem is, that the residual is thus calculated - * wrong and the next transfer will start behind where - * it should. So we round up the residual to the next - * multiple of a sector size, if it isn't already a - * multiple and the originally expected transfer size - * was. The latter condition is there to ensure that - * the correction is taken only for "real" data - * transfers and not for, e.g., the parameters of some - * other command. These shouldn't disconnect anyway. - */ + } + else { + /* There seems to be a nasty bug in some SCSI-DMA/NCR + combinations: If a target disconnects while a write + operation is going on, the address register of the + DMA may be a few bytes farer than it actually read. + This is probably due to DMA prefetching and a delay + between DMA and NCR. Experiments showed that the + dma_addr is 9 bytes to high, but this could vary. + The problem is, that the residual is thus calculated + wrong and the next transfer will start behind where + it should. So we round up the residual to the next + multiple of a sector size, if it isn't already a + multiple and the originally expected transfer size + was. The latter condition is there to ensure that + the correction is taken only for "real" data + transfers and not for, e.g., the parameters of some + other command. These shouldn't disconnect anyway. + */ if (atari_dma_residual & 0x1ff) { DMA_PRINTK("SCSI DMA: DMA bug corrected, " "difference %ld bytes\n", @@ -392,18 +394,18 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy) } #endif /* REAL_DMA */ - - NCR5380_intr(0, 0); + + NCR5380_intr (0, 0, 0); #if 0 /* To be sure the int is not masked */ - atari_enable_irq(IRQ_TT_MFP_SCSI); + atari_enable_irq( IRQ_TT_MFP_SCSI ); #endif return IRQ_HANDLED; } -static irqreturn_t scsi_falcon_intr(int irq, void *dummy) +static irqreturn_t scsi_falcon_intr (int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; @@ -428,7 +430,7 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy) * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) */ if (atari_dma_active && (dma_stat & 0x02)) { - unsigned long transferred; + unsigned long transferred; transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; /* The ST-DMA address is incremented in 2-byte steps, but the @@ -443,7 +445,8 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy) atari_dma_residual = HOSTDATA_DMALEN - transferred; DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", atari_dma_residual); - } else + } + else atari_dma_residual = 0; atari_dma_active = 0; @@ -458,13 +461,13 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy) #endif /* REAL_DMA */ - NCR5380_intr(0, 0); + NCR5380_intr (0, 0, 0); return IRQ_HANDLED; } #ifdef REAL_DMA -static void atari_scsi_fetch_restbytes(void) +static void atari_scsi_fetch_restbytes( void ) { int nr; char *src, *dst; @@ -502,17 +505,19 @@ static int falcon_dont_release = 0; * again (but others waiting longer more probably will win). */ -static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) +static void +falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) { unsigned long flags; - - if (IS_A_TT()) - return; - + + if (IS_A_TT()) return; + local_irq_save(flags); - if (falcon_got_lock && !hostdata->disconnected_queue && - !hostdata->issue_queue && !hostdata->connected) { + if (falcon_got_lock && + !hostdata->disconnected_queue && + !hostdata->issue_queue && + !hostdata->connected) { if (falcon_dont_release) { #if 0 @@ -523,7 +528,7 @@ static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) } falcon_got_lock = 0; stdma_release(); - wake_up(&falcon_fairness_wait); + wake_up( &falcon_fairness_wait ); } local_irq_restore(flags); @@ -544,31 +549,31 @@ static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) * Complicated, complicated.... Sigh... */ -static void falcon_get_lock(void) +static void falcon_get_lock( void ) { unsigned long flags; - if (IS_A_TT()) - return; + if (IS_A_TT()) return; local_irq_save(flags); - while (!in_irq() && falcon_got_lock && stdma_others_waiting()) - sleep_on(&falcon_fairness_wait); + while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) + sleep_on( &falcon_fairness_wait ); while (!falcon_got_lock) { - if (in_irq()) - panic("Falcon SCSI hasn't ST-DMA lock in interrupt"); + if (in_interrupt()) + panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); if (!falcon_trying_lock) { falcon_trying_lock = 1; stdma_lock(scsi_falcon_intr, NULL); falcon_got_lock = 1; falcon_trying_lock = 0; - wake_up(&falcon_try_wait); - } else { - sleep_on(&falcon_try_wait); + wake_up( &falcon_try_wait ); } - } + else { + sleep_on( &falcon_try_wait ); + } + } local_irq_restore(flags); if (!falcon_got_lock) @@ -582,18 +587,18 @@ static void falcon_get_lock(void) */ #if 0 -int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { /* falcon_get_lock(); * ++guenther: moved to NCR5380_queue_command() to prevent * race condition, see there for an explanation. */ - return NCR5380_queue_command(cmd, done); + return( NCR5380_queue_command( cmd, done ) ); } #endif -int atari_scsi_detect(struct scsi_host_template *host) +int atari_scsi_detect (struct scsi_host_template *host) { static int called = 0; struct Scsi_Host *instance; @@ -601,7 +606,7 @@ int atari_scsi_detect(struct scsi_host_template *host) if (!MACH_IS_ATARI || (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || called) - return 0; + return( 0 ); host->proc_name = "Atari"; @@ -650,33 +655,32 @@ int atari_scsi_detect(struct scsi_host_template *host) !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); if (!atari_dma_buffer) { - printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " - "double buffer\n"); - return 0; + printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " + "double buffer\n" ); + return( 0 ); } - atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer); + atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer ); atari_dma_orig_addr = 0; } #endif - instance = scsi_register(host, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) { + instance = scsi_register (host, sizeof (struct NCR5380_hostdata)); + if(instance == NULL) + { atari_stram_free(atari_dma_buffer); atari_dma_buffer = 0; return 0; } atari_scsi_host = instance; - /* - * Set irq to 0, to avoid that the mid-level code disables our interrupt - * during queue_command calls. This is completely unnecessary, and even - * worse causes bad problems on the Falcon, where the int is shared with - * IDE and floppy! - */ + /* Set irq to 0, to avoid that the mid-level code disables our interrupt + * during queue_command calls. This is completely unnecessary, and even + * worse causes bad problems on the Falcon, where the int is shared with + * IDE and floppy! */ instance->irq = 0; #ifdef CONFIG_ATARI_SCSI_RESET_BOOT atari_scsi_reset_boot(); #endif - NCR5380_init(instance, 0); + NCR5380_init (instance, 0); if (IS_A_TT()) { @@ -723,10 +727,11 @@ int atari_scsi_detect(struct scsi_host_template *host) * the rest data bug is fixed, this can be lowered to 1. */ atari_read_overruns = 4; - } + } #endif /*REAL_DMA*/ - } else { /* ! IS_A_TT */ - + } + else { /* ! IS_A_TT */ + /* Nothing to do for the interrupt: the ST-DMA is initialized * already by atari_init_INTS() */ @@ -751,21 +756,23 @@ int atari_scsi_detect(struct scsi_host_template *host) setup_use_tagged_queuing ? "yes" : "no", #endif instance->hostt->this_id ); - NCR5380_print_options(instance); - printk("\n"); + NCR5380_print_options (instance); + printk ("\n"); called = 1; - return 1; + return( 1 ); } -int atari_scsi_release(struct Scsi_Host *sh) +#ifdef MODULE +int atari_scsi_release (struct Scsi_Host *sh) { if (IS_A_TT()) free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr); if (atari_dma_buffer) - atari_stram_free(atari_dma_buffer); + atari_stram_free (atari_dma_buffer); return 1; } +#endif void __init atari_scsi_setup(char *str, int *ints) { @@ -774,9 +781,9 @@ void __init atari_scsi_setup(char *str, int *ints) * Defaults depend on TT or Falcon, hostid determined at run time. * Negative values mean don't change. */ - + if (ints[0] < 1) { - printk("atari_scsi_setup: no arguments!\n"); + printk( "atari_scsi_setup: no arguments!\n" ); return; } @@ -802,7 +809,7 @@ void __init atari_scsi_setup(char *str, int *ints) if (ints[4] >= 0 && ints[4] <= 7) setup_hostid = ints[4]; else if (ints[4] > 7) - printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]); + printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] ); } #ifdef SUPPORT_TAGS if (ints[0] >= 5) { @@ -814,7 +821,7 @@ void __init atari_scsi_setup(char *str, int *ints) int atari_scsi_bus_reset(Scsi_Cmnd *cmd) { - int rv; + int rv; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)cmd->device->host->hostdata; @@ -824,12 +831,13 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) */ /* And abort a maybe active DMA transfer */ if (IS_A_TT()) { - atari_turnoff_irq(IRQ_TT_MFP_SCSI); + atari_turnoff_irq( IRQ_TT_MFP_SCSI ); #ifdef REAL_DMA tt_scsi_dma.dma_ctrl = 0; #endif /* REAL_DMA */ - } else { - atari_turnoff_irq(IRQ_MFP_FSCSI); + } + else { + atari_turnoff_irq( IRQ_MFP_FSCSI ); #ifdef REAL_DMA st_dma.dma_mode_status = 0x90; atari_dma_active = 0; @@ -841,51 +849,52 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) /* Re-enable ints */ if (IS_A_TT()) { - atari_turnon_irq(IRQ_TT_MFP_SCSI); - } else { - atari_turnon_irq(IRQ_MFP_FSCSI); + atari_turnon_irq( IRQ_TT_MFP_SCSI ); + } + else { + atari_turnon_irq( IRQ_MFP_FSCSI ); } if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS) falcon_release_lock_if_possible(hostdata); - return rv; + return( rv ); } - + #ifdef CONFIG_ATARI_SCSI_RESET_BOOT static void __init atari_scsi_reset_boot(void) { unsigned long end; - + /* * Do a SCSI reset to clean up the bus during initialization. No messing * with the queues, interrupts, or locks necessary here. */ - printk("Atari SCSI: resetting the SCSI bus..."); + printk( "Atari SCSI: resetting the SCSI bus..." ); /* get in phase */ - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); /* assert RST */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); /* The min. reset hold time is 25us, so 40us should be enough */ - udelay(50); + udelay( 50 ); /* reset RST and interrupt */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_read( RESET_PARITY_INTERRUPT_REG ); end = jiffies + AFTER_RESET_DELAY; while (time_before(jiffies, end)) barrier(); - printk(" done\n"); + printk( " done\n" ); } #endif -const char *atari_scsi_info(struct Scsi_Host *host) +const char * atari_scsi_info (struct Scsi_Host *host) { /* atari_scsi_detect() is verbose enough... */ static const char string[] = "Atari native SCSI"; @@ -895,10 +904,10 @@ const char *atari_scsi_info(struct Scsi_Host *host) #if defined(REAL_DMA) -unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, - unsigned long count, int dir) +unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, + unsigned long count, int dir ) { - unsigned long addr = virt_to_phys(data); + unsigned long addr = virt_to_phys( data ); DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, " "dir = %d\n", instance->host_no, data, addr, count, dir); @@ -910,37 +919,38 @@ unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, * wanted address. */ if (dir) - memcpy(atari_dma_buffer, data, count); + memcpy( atari_dma_buffer, data, count ); else atari_dma_orig_addr = data; addr = atari_dma_phys_buffer; } - + atari_dma_startaddr = addr; /* Needed for calculating residual later. */ - + /* Cache cleanup stuff: On writes, push any dirty cache out before sending * it to the peripheral. (Must be done before DMA setup, since at least * the ST-DMA begins to fill internal buffers right after setup. For * reads, invalidate any cache, may be altered after DMA without CPU * knowledge. - * + * * ++roman: For the Medusa, there's no need at all for that cache stuff, * because the hardware does bus snooping (fine!). */ - dma_cache_maintenance(addr, count, dir); + dma_cache_maintenance( addr, count, dir ); if (count == 0) printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n"); if (IS_A_TT()) { tt_scsi_dma.dma_ctrl = dir; - SCSI_DMA_WRITE_P(dma_addr, addr); - SCSI_DMA_WRITE_P(dma_cnt, count); + SCSI_DMA_WRITE_P( dma_addr, addr ); + SCSI_DMA_WRITE_P( dma_cnt, count ); tt_scsi_dma.dma_ctrl = dir | 2; - } else { /* ! IS_A_TT */ - + } + else { /* ! IS_A_TT */ + /* set address */ - SCSI_DMA_SETADR(addr); + SCSI_DMA_SETADR( addr ); /* toggle direction bit to clear FIFO and set DMA direction */ dir <<= 8; @@ -958,13 +968,13 @@ unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, atari_dma_active = 1; } - return count; + return( count ); } -static long atari_scsi_dma_residual(struct Scsi_Host *instance) +static long atari_scsi_dma_residual( struct Scsi_Host *instance ) { - return atari_dma_residual; + return( atari_dma_residual ); } @@ -972,13 +982,13 @@ static long atari_scsi_dma_residual(struct Scsi_Host *instance) #define CMD_SURELY_BYTE_MODE 1 #define CMD_MODE_UNKNOWN 2 -static int falcon_classify_cmd(Scsi_Cmnd *cmd) +static int falcon_classify_cmd( Scsi_Cmnd *cmd ) { unsigned char opcode = cmd->cmnd[0]; - + if (opcode == READ_DEFECT_DATA || opcode == READ_LONG || - opcode == READ_BUFFER) - return CMD_SURELY_BYTE_MODE; + opcode == READ_BUFFER) + return( CMD_SURELY_BYTE_MODE ); else if (opcode == READ_6 || opcode == READ_10 || opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE || opcode == RECOVER_BUFFERED_DATA) { @@ -986,11 +996,12 @@ static int falcon_classify_cmd(Scsi_Cmnd *cmd) * needed here: The transfer is block-mode only if the 'fixed' bit is * set! */ if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) - return CMD_SURELY_BYTE_MODE; + return( CMD_SURELY_BYTE_MODE ); else - return CMD_SURELY_BLOCK_MODE; - } else - return CMD_MODE_UNKNOWN; + return( CMD_SURELY_BLOCK_MODE ); + } + else + return( CMD_MODE_UNKNOWN ); } @@ -1003,18 +1014,19 @@ static int falcon_classify_cmd(Scsi_Cmnd *cmd) * the overrun problem, so this question is academic :-) */ -static unsigned long atari_dma_xfer_len(unsigned long wanted_len, - Scsi_Cmnd *cmd, int write_flag) +static unsigned long atari_dma_xfer_len( unsigned long wanted_len, + Scsi_Cmnd *cmd, + int write_flag ) { unsigned long possible_len, limit; #ifndef CONFIG_TT_DMA_EMUL if (MACH_IS_HADES) /* Hades has no SCSI DMA at all :-( Always force use of PIO */ - return 0; -#endif + return( 0 ); +#endif if (IS_A_TT()) /* TT SCSI DMA can transfer arbitrary #bytes */ - return wanted_len; + return( wanted_len ); /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. * 255*512 bytes, but this should be enough) @@ -1050,7 +1062,8 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len, * this). */ possible_len = wanted_len; - } else { + } + else { /* Read operations: if the wanted transfer length is not a multiple of * 512, we cannot use DMA, since the ST-DMA cannot split transfers * (no interrupt on DMA finished!) @@ -1060,15 +1073,15 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len, else { /* Now classify the command (see above) and decide whether it is * allowed to do DMA at all */ - switch (falcon_classify_cmd(cmd)) { - case CMD_SURELY_BLOCK_MODE: + switch( falcon_classify_cmd( cmd )) { + case CMD_SURELY_BLOCK_MODE: possible_len = wanted_len; break; - case CMD_SURELY_BYTE_MODE: + case CMD_SURELY_BYTE_MODE: possible_len = 0; /* DMA prohibited */ break; - case CMD_MODE_UNKNOWN: - default: + case CMD_MODE_UNKNOWN: + default: /* For unknown commands assume block transfers if the transfer * size/allocation length is >= 1024 */ possible_len = (wanted_len < 1024) ? 0 : wanted_len; @@ -1076,9 +1089,9 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len, } } } - + /* Last step: apply the hard limit on DMA transfers */ - limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ? + limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ? STRAM_BUFFER_SIZE : 255*512; if (possible_len > limit) possible_len = limit; @@ -1087,7 +1100,7 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len, DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes " "instead of %ld\n", possible_len, wanted_len); - return possible_len; + return( possible_len ); } @@ -1101,23 +1114,23 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len, * NCR5380_write call these functions via function pointers. */ -static unsigned char atari_scsi_tt_reg_read(unsigned char reg) +static unsigned char atari_scsi_tt_reg_read( unsigned char reg ) { - return tt_scsi_regp[reg * 2]; + return( tt_scsi_regp[reg * 2] ); } -static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value) +static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value ) { tt_scsi_regp[reg * 2] = value; } -static unsigned char atari_scsi_falcon_reg_read(unsigned char reg) +static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ) { dma_wd.dma_mode_status= (u_short)(0x88 + reg); - return (u_char)dma_wd.fdc_acces_seccount; + return( (u_char)dma_wd.fdc_acces_seccount ); } -static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value) +static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ) { dma_wd.dma_mode_status = (u_short)(0x88 + reg); dma_wd.fdc_acces_seccount = (u_short)value; diff --git a/trunk/drivers/scsi/atari_scsi.h b/trunk/drivers/scsi/atari_scsi.h index efadb8d567c2..f917bdd09b41 100644 --- a/trunk/drivers/scsi/atari_scsi.h +++ b/trunk/drivers/scsi/atari_scsi.h @@ -21,7 +21,11 @@ int atari_scsi_detect (struct scsi_host_template *); const char *atari_scsi_info (struct Scsi_Host *); int atari_scsi_reset (Scsi_Cmnd *, unsigned int); +#ifdef MODULE int atari_scsi_release (struct Scsi_Host *); +#else +#define atari_scsi_release NULL +#endif /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher * values should work, too; try it! (but cmd_per_lun costs memory!) */ @@ -59,32 +63,6 @@ int atari_scsi_release (struct Scsi_Host *); #define NCR5380_dma_xfer_len(i,cmd,phase) \ atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) -/* former generic SCSI error handling stuff */ - -#define SCSI_ABORT_SNOOZE 0 -#define SCSI_ABORT_SUCCESS 1 -#define SCSI_ABORT_PENDING 2 -#define SCSI_ABORT_BUSY 3 -#define SCSI_ABORT_NOT_RUNNING 4 -#define SCSI_ABORT_ERROR 5 - -#define SCSI_RESET_SNOOZE 0 -#define SCSI_RESET_PUNT 1 -#define SCSI_RESET_SUCCESS 2 -#define SCSI_RESET_PENDING 3 -#define SCSI_RESET_WAKEUP 4 -#define SCSI_RESET_NOT_RUNNING 5 -#define SCSI_RESET_ERROR 6 - -#define SCSI_RESET_SYNCHRONOUS 0x01 -#define SCSI_RESET_ASYNCHRONOUS 0x02 -#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 -#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 - -#define SCSI_RESET_BUS_RESET 0x100 -#define SCSI_RESET_HOST_RESET 0x200 -#define SCSI_RESET_ACTION 0xff - /* Debugging printk definitions: * * ARB -> arbitration @@ -113,58 +91,144 @@ int atari_scsi_release (struct Scsi_Host *); * */ -#define dprint(flg, format...) \ -({ \ - if (NDEBUG & (flg)) \ - printk(KERN_DEBUG format); \ -}) - +#if NDEBUG & NDEBUG_ARBITRATION #define ARB_PRINTK(format, args...) \ - dprint(NDEBUG_ARBITRATION, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define ARB_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_AUTOSENSE #define ASEN_PRINTK(format, args...) \ - dprint(NDEBUG_AUTOSENSE, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define ASEN_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_DMA #define DMA_PRINTK(format, args...) \ - dprint(NDEBUG_DMA, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define DMA_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_HANDSHAKE #define HSH_PRINTK(format, args...) \ - dprint(NDEBUG_HANDSHAKE, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define HSH_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INFORMATION #define INF_PRINTK(format, args...) \ - dprint(NDEBUG_INFORMATION, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define INF_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INIT #define INI_PRINTK(format, args...) \ - dprint(NDEBUG_INIT, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define INI_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INTR #define INT_PRINTK(format, args...) \ - dprint(NDEBUG_INTR, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define INT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_LINKED #define LNK_PRINTK(format, args...) \ - dprint(NDEBUG_LINKED, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define LNK_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_MAIN #define MAIN_PRINTK(format, args...) \ - dprint(NDEBUG_MAIN, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define MAIN_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_NO_DATAOUT #define NDAT_PRINTK(format, args...) \ - dprint(NDEBUG_NO_DATAOUT, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define NDAT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_NO_WRITE #define NWR_PRINTK(format, args...) \ - dprint(NDEBUG_NO_WRITE, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define NWR_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_PIO #define PIO_PRINTK(format, args...) \ - dprint(NDEBUG_PIO, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define PIO_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_PSEUDO_DMA #define PDMA_PRINTK(format, args...) \ - dprint(NDEBUG_PSEUDO_DMA, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define PDMA_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_QUEUES #define QU_PRINTK(format, args...) \ - dprint(NDEBUG_QUEUES, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define QU_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_RESELECTION #define RSL_PRINTK(format, args...) \ - dprint(NDEBUG_RESELECTION, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define RSL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_SELECTION #define SEL_PRINTK(format, args...) \ - dprint(NDEBUG_SELECTION, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define SEL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_USLEEP #define USL_PRINTK(format, args...) \ - dprint(NDEBUG_USLEEP, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define USL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_LAST_BYTE_SENT #define LBS_PRINTK(format, args...) \ - dprint(NDEBUG_LAST_BYTE_SENT, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define LBS_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_RESTART_SELECT #define RSS_PRINTK(format, args...) \ - dprint(NDEBUG_RESTART_SELECT, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define RSS_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_EXTENDED #define EXT_PRINTK(format, args...) \ - dprint(NDEBUG_EXTENDED, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define EXT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_ABORT #define ABRT_PRINTK(format, args...) \ - dprint(NDEBUG_ABORT, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define ABRT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_TAGS #define TAG_PRINTK(format, args...) \ - dprint(NDEBUG_TAGS, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define TAG_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_MERGING #define MER_PRINTK(format, args...) \ - dprint(NDEBUG_MERGING, format , ## args) + printk(KERN_DEBUG format , ## args) +#else +#define MER_PRINTK(format, args...) +#endif /* conditional macros for NCR5380_print_{,phase,status} */ diff --git a/trunk/drivers/scsi/constants.c b/trunk/drivers/scsi/constants.c index 2a458d66b6ff..61f6024b61ba 100644 --- a/trunk/drivers/scsi/constants.c +++ b/trunk/drivers/scsi/constants.c @@ -202,29 +202,31 @@ static const char * get_sa_name(const struct value_name_pair * arr, } /* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */ -static void print_opcode_name(unsigned char * cdbp, int cdb_len) +static void print_opcode_name(unsigned char * cdbp, int cdb_len, + int start_of_line) { int sa, len, cdb0; const char * name; + const char * leadin = start_of_line ? KERN_INFO : ""; cdb0 = cdbp[0]; switch(cdb0) { case VARIABLE_LENGTH_CMD: len = cdbp[7] + 8; if (len < 10) { - printk("short variable length command, " - "len=%d ext_len=%d", len, cdb_len); + printk("%sshort variable length command, " + "len=%d ext_len=%d", leadin, len, cdb_len); break; } sa = (cdbp[8] << 8) + cdbp[9]; name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa); if (name) { - printk("%s", name); + printk("%s%s", leadin, name); if ((cdb_len > 0) && (len != cdb_len)) printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); } else { - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); if ((cdb_len > 0) && (len != cdb_len)) printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); @@ -234,80 +236,83 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len) sa = cdbp[1] & 0x1f; name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; case MAINTENANCE_OUT: sa = cdbp[1] & 0x1f; name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; case SERVICE_ACTION_IN_12: sa = cdbp[1] & 0x1f; name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; case SERVICE_ACTION_OUT_12: sa = cdbp[1] & 0x1f; name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; case SERVICE_ACTION_IN_16: sa = cdbp[1] & 0x1f; name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; case SERVICE_ACTION_OUT_16: sa = cdbp[1] & 0x1f; name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa); if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; default: if (cdb0 < 0xc0) { name = cdb_byte0_names[cdb0]; if (name) - printk("%s", name); + printk("%s%s", leadin, name); else - printk("cdb[0]=0x%x (reserved)", cdb0); + printk("%scdb[0]=0x%x (reserved)", + leadin, cdb0); } else - printk("cdb[0]=0x%x (vendor)", cdb0); + printk("%scdb[0]=0x%x (vendor)", leadin, cdb0); break; } } #else /* ifndef CONFIG_SCSI_CONSTANTS */ -static void print_opcode_name(unsigned char * cdbp, int cdb_len) +static void print_opcode_name(unsigned char * cdbp, int cdb_len, + int start_of_line) { int sa, len, cdb0; + const char * leadin = start_of_line ? KERN_INFO : ""; cdb0 = cdbp[0]; switch(cdb0) { case VARIABLE_LENGTH_CMD: len = cdbp[7] + 8; if (len < 10) { - printk("short opcode=0x%x command, len=%d " - "ext_len=%d", cdb0, len, cdb_len); + printk("%sshort opcode=0x%x command, len=%d " + "ext_len=%d", leadin, cdb0, len, cdb_len); break; } sa = (cdbp[8] << 8) + cdbp[9]; - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); if (len != cdb_len) printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); break; @@ -318,48 +323,49 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len) case SERVICE_ACTION_IN_16: case SERVICE_ACTION_OUT_16: sa = cdbp[1] & 0x1f; - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); break; default: if (cdb0 < 0xc0) - printk("cdb[0]=0x%x", cdb0); + printk("%scdb[0]=0x%x", leadin, cdb0); else - printk("cdb[0]=0x%x (vendor)", cdb0); + printk("%scdb[0]=0x%x (vendor)", leadin, cdb0); break; } } #endif -void __scsi_print_command(unsigned char *cdb) +void __scsi_print_command(unsigned char *command) { int k, len; - print_opcode_name(cdb, 0); - if (VARIABLE_LENGTH_CMD == cdb[0]) - len = cdb[7] + 8; + print_opcode_name(command, 0, 1); + if (VARIABLE_LENGTH_CMD == command[0]) + len = command[7] + 8; else - len = COMMAND_SIZE(cdb[0]); + len = COMMAND_SIZE(command[0]); /* print out all bytes in cdb */ for (k = 0; k < len; ++k) - printk(" %02x", cdb[k]); + printk(" %02x", command[k]); printk("\n"); } EXPORT_SYMBOL(__scsi_print_command); -void scsi_print_command(struct scsi_cmnd *cmd) +/* This function (perhaps with the addition of peripheral device type) + * is more approriate than __scsi_print_command(). Perhaps that static + * can be dropped later if it replaces the __scsi_print_command version. + */ +static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line) { int k; - scmd_printk(KERN_INFO, cmd, "CDB: "); - print_opcode_name(cmd->cmnd, cmd->cmd_len); - + print_opcode_name(cdb, cdb_len, start_of_line); /* print out all bytes in cdb */ printk(":"); - for (k = 0; k < cmd->cmd_len; ++k) - printk(" %02x", cmd->cmnd[k]); + for (k = 0; k < cdb_len; ++k) + printk(" %02x", cdb[k]); printk("\n"); } -EXPORT_SYMBOL(scsi_print_command); /** * @@ -404,11 +410,7 @@ struct error_info { const char * text; }; -/* - * The canonical list of T10 Additional Sense Codes is available at: - * http://www.t10.org/lists/asc-num.txt - */ -static const struct error_info additional[] = +static struct error_info additional[] = { {0x0000, "No additional sense information"}, {0x0001, "Filemark detected"}, @@ -712,7 +714,6 @@ static const struct error_info additional[] = {0x2F00, "Commands cleared by another initiator"}, {0x2F01, "Commands cleared by power loss notification"}, - {0x2F02, "Commands cleared by device server"}, {0x3000, "Incompatible medium installed"}, {0x3001, "Cannot read medium - unknown format"}, @@ -1175,77 +1176,67 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) { } EXPORT_SYMBOL(scsi_extd_sense_format); -void +/* Print extended sense information; no leadin, no linefeed */ +static void scsi_show_extd_sense(unsigned char asc, unsigned char ascq) { - const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq); + const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq); if (extd_sense_fmt) { if (strstr(extd_sense_fmt, "%x")) { - printk("Add. Sense: "); + printk("Additional sense: "); printk(extd_sense_fmt, ascq); } else - printk("Add. Sense: %s", extd_sense_fmt); + printk("Additional sense: %s", extd_sense_fmt); } else { if (asc >= 0x80) - printk("<> ASC=0x%x ASCQ=0x%x", asc, - ascq); + printk("<> ASC=0x%x ASCQ=0x%x", asc, ascq); if (ascq >= 0x80) - printk("ASC=0x%x <> ASCQ=0x%x", asc, - ascq); + printk("ASC=0x%x <> ASCQ=0x%x", asc, ascq); else printk("ASC=0x%x ASCQ=0x%x", asc, ascq); } - - printk("\n"); } -EXPORT_SYMBOL(scsi_show_extd_sense); void -scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr) +scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) { const char *sense_txt; + /* An example of deferred is when an earlier write to disk cache + * succeeded, but now the disk discovers that it cannot write the + * data to the magnetic media. + */ + const char *error = scsi_sense_is_deferred(sshdr) ? + "<>" : "Current"; + printk(KERN_INFO "%s: %s", name, error); + if (sshdr->response_code >= 0x72) + printk(" [descriptor]"); sense_txt = scsi_sense_key_string(sshdr->sense_key); if (sense_txt) - printk("Sense Key : %s ", sense_txt); + printk(": sense key: %s\n", sense_txt); else - printk("Sense Key : 0x%x ", sshdr->sense_key); - - printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " : - "[current] "); - - if (sshdr->response_code >= 0x72) - printk("[descriptor]"); - - printk("\n"); -} -EXPORT_SYMBOL(scsi_show_sense_hdr); - -/* - * Print normalized SCSI sense header with a prefix. - */ -void -scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) -{ - printk(KERN_INFO "%s: ", name); - scsi_show_sense_hdr(sshdr); - printk(KERN_INFO "%s: ", name); + printk(": sense key=0x%x\n", sshdr->sense_key); + printk(KERN_INFO " "); scsi_show_extd_sense(sshdr->asc, sshdr->ascq); + printk("\n"); } EXPORT_SYMBOL(scsi_print_sense_hdr); +/* Print sense information */ void -scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, - struct scsi_sense_hdr *sshdr) +__scsi_print_sense(const char *name, const unsigned char *sense_buffer, + int sense_len) { int k, num, res; + unsigned int info; + struct scsi_sense_hdr ssh; - res = scsi_normalize_sense(sense_buffer, sense_len, sshdr); + res = scsi_normalize_sense(sense_buffer, sense_len, &ssh); if (0 == res) { /* this may be SCSI-1 sense data */ num = (sense_len < 32) ? sense_len : 32; - printk("Unrecognized sense data (in hex):"); + printk(KERN_INFO "Unrecognized sense data (in hex):"); for (k = 0; k < num; ++k) { if (0 == (k % 16)) { printk("\n"); @@ -1256,20 +1247,11 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, printk("\n"); return; } -} - -void -scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len, - struct scsi_sense_hdr *sshdr) -{ - int k, num, res; - - if (sshdr->response_code < 0x72) - { + scsi_print_sense_hdr(name, &ssh); + if (ssh.response_code < 0x72) { /* only decode extras for "fixed" format now */ char buff[80]; int blen, fixed_valid; - unsigned int info; fixed_valid = sense_buffer[0] & 0x80; info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | @@ -1299,13 +1281,13 @@ scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len, res += snprintf(buff + res, blen - res, "ILI"); } if (res > 0) - printk("%s\n", buff); - } else if (sshdr->additional_length > 0) { + printk(KERN_INFO "%s\n", buff); + } else if (ssh.additional_length > 0) { /* descriptor format with sense descriptors */ - num = 8 + sshdr->additional_length; + num = 8 + ssh.additional_length; num = (sense_len < num) ? sense_len : num; - printk("Descriptor sense data with sense descriptors " - "(in hex):"); + printk(KERN_INFO "Descriptor sense data with sense " + "descriptors (in hex):"); for (k = 0; k < num; ++k) { if (0 == (k % 16)) { printk("\n"); @@ -1313,42 +1295,29 @@ scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len, } printk("%02x ", sense_buffer[k]); } - printk("\n"); } - } +EXPORT_SYMBOL(__scsi_print_sense); -/* Normalize and print sense buffer with name prefix */ -void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, - int sense_len) +void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd) { - struct scsi_sense_hdr sshdr; - - printk(KERN_INFO "%s: ", name); - scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr); - scsi_show_sense_hdr(&sshdr); - scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr); - printk(KERN_INFO "%s: ", name); - scsi_show_extd_sense(sshdr.asc, sshdr.ascq); + const char *name = devclass; + + if (cmd->request->rq_disk) + name = cmd->request->rq_disk->disk_name; + __scsi_print_sense(name, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); } -EXPORT_SYMBOL(__scsi_print_sense); +EXPORT_SYMBOL(scsi_print_sense); -/* Normalize and print sense buffer in SCSI command */ -void scsi_print_sense(char *name, struct scsi_cmnd *cmd) +void scsi_print_command(struct scsi_cmnd *cmd) { - struct scsi_sense_hdr sshdr; - - scmd_printk(KERN_INFO, cmd, ""); - scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &sshdr); - scsi_show_sense_hdr(&sshdr); - scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &sshdr); - scmd_printk(KERN_INFO, cmd, ""); - scsi_show_extd_sense(sshdr.asc, sshdr.ascq); + /* Assume appended output (i.e. not at start of line) */ + sdev_printk("", cmd->device, "\n"); + printk(KERN_INFO " command: "); + scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0); } -EXPORT_SYMBOL(scsi_print_sense); +EXPORT_SYMBOL(scsi_print_command); #ifdef CONFIG_SCSI_CONSTANTS @@ -1358,6 +1327,25 @@ static const char * const hostbyte_table[]={ "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"}; #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) +void scsi_print_hostbyte(int scsiresult) +{ + int hb = host_byte(scsiresult); + + printk("Hostbyte=0x%02x", hb); + if (hb < NUM_HOSTBYTE_STRS) + printk("(%s) ", hostbyte_table[hb]); + else + printk("is invalid "); +} +#else +void scsi_print_hostbyte(int scsiresult) +{ + printk("Hostbyte=0x%02x ", host_byte(scsiresult)); +} +#endif + +#ifdef CONFIG_SCSI_CONSTANTS + static const char * const driverbyte_table[]={ "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; @@ -1368,35 +1356,19 @@ static const char * const driversuggest_table[]={"SUGGEST_OK", "SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"}; #define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table) -void scsi_show_result(int result) +void scsi_print_driverbyte(int scsiresult) { - int hb = host_byte(result); - int db = (driver_byte(result) & DRIVER_MASK); - int su = ((driver_byte(result) & SUGGEST_MASK) >> 4); + int dr = (driver_byte(scsiresult) & DRIVER_MASK); + int su = ((driver_byte(scsiresult) & SUGGEST_MASK) >> 4); - printk("Result: hostbyte=%s driverbyte=%s,%s\n", - (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"), - (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"), + printk("Driverbyte=0x%02x ", driver_byte(scsiresult)); + printk("(%s,%s) ", + (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"), (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid")); } - #else - -void scsi_show_result(int result) +void scsi_print_driverbyte(int scsiresult) { - printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n", - host_byte(result), driver_byte(result)); + printk("Driverbyte=0x%02x ", driver_byte(scsiresult)); } - #endif -EXPORT_SYMBOL(scsi_show_result); - - -void scsi_print_result(struct scsi_cmnd *cmd) -{ - scmd_printk(KERN_INFO, cmd, ""); - scsi_show_result(cmd->result); -} -EXPORT_SYMBOL(scsi_print_result); - - diff --git a/trunk/drivers/scsi/dpt/dpti_i2o.h b/trunk/drivers/scsi/dpt/dpti_i2o.h index 100b49baca7f..5a49216fe4cf 100644 --- a/trunk/drivers/scsi/dpt/dpti_i2o.h +++ b/trunk/drivers/scsi/dpt/dpti_i2o.h @@ -31,7 +31,7 @@ * Tunable parameters first */ -/* How many different OSM's are we allowing */ +/* How many different OSM's are we allowing */ #define MAX_I2O_MODULES 64 #define I2O_EVT_CAPABILITY_OTHER 0x01 @@ -63,7 +63,7 @@ struct i2o_message u16 size; u32 target_tid:12; u32 init_tid:12; - u32 function:8; + u32 function:8; u32 initiator_context; /* List follows */ }; @@ -77,7 +77,7 @@ struct i2o_device char dev_name[8]; /* linux /dev name if available */ i2o_lct_entry lct_data;/* Device LCT information */ - u32 flags; + u32 flags; struct proc_dir_entry* proc_entry; /* /proc dir */ struct adpt_device *owner; struct _adpt_hba *controller; /* Controlling IOP */ @@ -86,7 +86,7 @@ struct i2o_device /* * Each I2O controller has one of these objects */ - + struct i2o_controller { char name[16]; @@ -111,9 +111,9 @@ struct i2o_sys_tbl_entry u32 iop_id:12; u32 reserved2:20; u16 seg_num:12; - u16 i2o_version:4; - u8 iop_state; - u8 msg_type; + u16 i2o_version:4; + u8 iop_state; + u8 msg_type; u16 frame_size; u16 reserved3; u32 last_changed; @@ -124,14 +124,14 @@ struct i2o_sys_tbl_entry struct i2o_sys_tbl { - u8 num_entries; - u8 version; - u16 reserved1; + u8 num_entries; + u8 version; + u16 reserved1; u32 change_ind; u32 reserved2; u32 reserved3; struct i2o_sys_tbl_entry iops[0]; -}; +}; /* * I2O classes / subclasses @@ -146,7 +146,7 @@ struct i2o_sys_tbl /* Class code names * (from v1.5 Table 6-1 Class Code Assignments.) */ - + #define I2O_CLASS_EXECUTIVE 0x000 #define I2O_CLASS_DDM 0x001 #define I2O_CLASS_RANDOM_BLOCK_STORAGE 0x010 @@ -166,7 +166,7 @@ struct i2o_sys_tbl /* Rest of 0x092 - 0x09f reserved for peer-to-peer classes */ - + #define I2O_CLASS_MATCH_ANYCLASS 0xffffffff /* Subclasses @@ -175,7 +175,7 @@ struct i2o_sys_tbl #define I2O_SUBCLASS_i960 0x001 #define I2O_SUBCLASS_HDM 0x020 #define I2O_SUBCLASS_ISM 0x021 - + /* Operation functions */ #define I2O_PARAMS_FIELD_GET 0x0001 @@ -219,7 +219,7 @@ struct i2o_sys_tbl /* * Messaging API values */ - + #define I2O_CMD_ADAPTER_ASSIGN 0xB3 #define I2O_CMD_ADAPTER_READ 0xB2 #define I2O_CMD_ADAPTER_RELEASE 0xB5 @@ -284,16 +284,16 @@ struct i2o_sys_tbl #define I2O_PRIVATE_MSG 0xFF /* - * Init Outbound Q status + * Init Outbound Q status */ - + #define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01 #define I2O_CMD_OUTBOUND_INIT_REJECTED 0x02 #define I2O_CMD_OUTBOUND_INIT_FAILED 0x03 #define I2O_CMD_OUTBOUND_INIT_COMPLETE 0x04 /* - * I2O Get Status State values + * I2O Get Status State values */ #define ADAPTER_STATE_INITIALIZING 0x01 @@ -303,7 +303,7 @@ struct i2o_sys_tbl #define ADAPTER_STATE_OPERATIONAL 0x08 #define ADAPTER_STATE_FAILED 0x10 #define ADAPTER_STATE_FAULTED 0x11 - + /* I2O API function return values */ #define I2O_RTN_NO_ERROR 0 @@ -321,9 +321,9 @@ struct i2o_sys_tbl /* Reply message status defines for all messages */ -#define I2O_REPLY_STATUS_SUCCESS 0x00 -#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01 -#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 +#define I2O_REPLY_STATUS_SUCCESS 0x00 +#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01 +#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 #define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03 #define I2O_REPLY_STATUS_ERROR_DIRTY 0x04 #define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05 @@ -338,7 +338,7 @@ struct i2o_sys_tbl #define I2O_PARAMS_STATUS_SUCCESS 0x00 #define I2O_PARAMS_STATUS_BAD_KEY_ABORT 0x01 -#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02 +#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02 #define I2O_PARAMS_STATUS_BUFFER_FULL 0x03 #define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL 0x04 #define I2O_PARAMS_STATUS_FIELD_UNREADABLE 0x05 @@ -390,7 +390,7 @@ struct i2o_sys_tbl #define I2O_CLAIM_MANAGEMENT 0x02000000 #define I2O_CLAIM_AUTHORIZED 0x03000000 #define I2O_CLAIM_SECONDARY 0x04000000 - + /* Message header defines for VersionOffset */ #define I2OVER15 0x0001 #define I2OVER20 0x0002 diff --git a/trunk/drivers/scsi/dpt/dpti_ioctl.h b/trunk/drivers/scsi/dpt/dpti_ioctl.h index cc784e8f6e9d..82d24864be0c 100644 --- a/trunk/drivers/scsi/dpt/dpti_ioctl.h +++ b/trunk/drivers/scsi/dpt/dpti_ioctl.h @@ -99,7 +99,7 @@ typedef struct { uCHAR eataVersion; /* EATA Version */ uLONG cpLength; /* EATA Command Packet Length */ uLONG spLength; /* EATA Status Packet Length */ - uCHAR drqNum; /* DRQ Index (0,5,6,7) */ + uCHAR drqNum; /* DRQ Index (0,5,6,7) */ uCHAR flag1; /* EATA Flags 1 (Byte 9) */ uCHAR flag2; /* EATA Flags 2 (Byte 30) */ } CtrlInfo; diff --git a/trunk/drivers/scsi/dpt/dptsig.h b/trunk/drivers/scsi/dpt/dptsig.h index 94bc894d1200..4bf447792129 100644 --- a/trunk/drivers/scsi/dpt/dptsig.h +++ b/trunk/drivers/scsi/dpt/dptsig.h @@ -145,8 +145,8 @@ typedef unsigned long sigLONG; #define FT_LOGGER 12 /* Event Logger */ #define FT_INSTALL 13 /* An Install Program */ #define FT_LIBRARY 14 /* Storage Manager Real-Mode Calls */ -#define FT_RESOURCE 15 /* Storage Manager Resource File */ -#define FT_MODEM_DB 16 /* Storage Manager Modem Database */ +#define FT_RESOURCE 15 /* Storage Manager Resource File */ +#define FT_MODEM_DB 16 /* Storage Manager Modem Database */ /* Filetype flags - sigBYTE dsFiletypeFlags; FLAG BITS */ /* ------------------------------------------------------------------ */ diff --git a/trunk/drivers/scsi/dpt_i2o.c b/trunk/drivers/scsi/dpt_i2o.c index f7b9dbd64a96..cd36e81b2d93 100644 --- a/trunk/drivers/scsi/dpt_i2o.c +++ b/trunk/drivers/scsi/dpt_i2o.c @@ -195,6 +195,8 @@ static int adpt_detect(struct scsi_host_template* sht) pci_dev_get(pDev); } } + if (pDev) + pci_dev_put(pDev); /* In INIT state, Activate IOPs */ for (pHba = hba_chain; pHba; pHba = pHba->next) { diff --git a/trunk/drivers/scsi/eata_generic.h b/trunk/drivers/scsi/eata_generic.h index 5016af5cf860..635c14861f86 100644 --- a/trunk/drivers/scsi/eata_generic.h +++ b/trunk/drivers/scsi/eata_generic.h @@ -18,6 +18,13 @@ * Misc. definitions * *********************************************/ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + #define R_LIMIT 0x20000 #define MAXISA 4 diff --git a/trunk/drivers/scsi/esp.c b/trunk/drivers/scsi/esp.c new file mode 100644 index 000000000000..2c2fe80bc42a --- /dev/null +++ b/trunk/drivers/scsi/esp.c @@ -0,0 +1,4394 @@ +/* esp.c: ESP Sun SCSI driver. + * + * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net) + */ + +/* TODO: + * + * 1) Maybe disable parity checking in config register one for SCSI1 + * targets. (Gilmore says parity error on the SBus can lock up + * old sun4c's) + * 2) Add support for DMA2 pipelining. + * 3) Add tagged queueing. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "esp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __sparc_v9__ +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define DRV_VERSION "1.101" + +#define DEBUG_ESP +/* #define DEBUG_ESP_HME */ +/* #define DEBUG_ESP_DATA */ +/* #define DEBUG_ESP_QUEUE */ +/* #define DEBUG_ESP_DISCONNECT */ +/* #define DEBUG_ESP_STATUS */ +/* #define DEBUG_ESP_PHASES */ +/* #define DEBUG_ESP_WORKBUS */ +/* #define DEBUG_STATE_MACHINE */ +/* #define DEBUG_ESP_CMDS */ +/* #define DEBUG_ESP_IRQS */ +/* #define DEBUG_SDTR */ +/* #define DEBUG_ESP_SG */ + +/* Use the following to sprinkle debugging messages in a way which + * suits you if combinations of the above become too verbose when + * trying to track down a specific problem. + */ +/* #define DEBUG_ESP_MISC */ + +#if defined(DEBUG_ESP) +#define ESPLOG(foo) printk foo +#else +#define ESPLOG(foo) +#endif /* (DEBUG_ESP) */ + +#if defined(DEBUG_ESP_HME) +#define ESPHME(foo) printk foo +#else +#define ESPHME(foo) +#endif + +#if defined(DEBUG_ESP_DATA) +#define ESPDATA(foo) printk foo +#else +#define ESPDATA(foo) +#endif + +#if defined(DEBUG_ESP_QUEUE) +#define ESPQUEUE(foo) printk foo +#else +#define ESPQUEUE(foo) +#endif + +#if defined(DEBUG_ESP_DISCONNECT) +#define ESPDISC(foo) printk foo +#else +#define ESPDISC(foo) +#endif + +#if defined(DEBUG_ESP_STATUS) +#define ESPSTAT(foo) printk foo +#else +#define ESPSTAT(foo) +#endif + +#if defined(DEBUG_ESP_PHASES) +#define ESPPHASE(foo) printk foo +#else +#define ESPPHASE(foo) +#endif + +#if defined(DEBUG_ESP_WORKBUS) +#define ESPBUS(foo) printk foo +#else +#define ESPBUS(foo) +#endif + +#if defined(DEBUG_ESP_IRQS) +#define ESPIRQ(foo) printk foo +#else +#define ESPIRQ(foo) +#endif + +#if defined(DEBUG_SDTR) +#define ESPSDTR(foo) printk foo +#else +#define ESPSDTR(foo) +#endif + +#if defined(DEBUG_ESP_MISC) +#define ESPMISC(foo) printk foo +#else +#define ESPMISC(foo) +#endif + +/* Command phase enumeration. */ +enum { + not_issued = 0x00, /* Still in the issue_SC queue. */ + + /* Various forms of selecting a target. */ +#define in_slct_mask 0x10 + in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */ + in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */ + in_slct_msg = 0x12, /* select, then send a message */ + in_slct_tag = 0x13, /* select and send tagged queue msg */ + in_slct_sneg = 0x14, /* select and acquire sync capabilities */ + + /* Any post selection activity. */ +#define in_phases_mask 0x20 + in_datain = 0x20, /* Data is transferring from the bus */ + in_dataout = 0x21, /* Data is transferring to the bus */ + in_data_done = 0x22, /* Last DMA data operation done (maybe) */ + in_msgin = 0x23, /* Eating message from target */ + in_msgincont = 0x24, /* Eating more msg bytes from target */ + in_msgindone = 0x25, /* Decide what to do with what we got */ + in_msgout = 0x26, /* Sending message to target */ + in_msgoutdone = 0x27, /* Done sending msg out */ + in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */ + in_cmdend = 0x29, /* Done sending slow cmd */ + in_status = 0x2a, /* Was in status phase, finishing cmd */ + in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */ + in_the_dark = 0x2c, /* Don't know what bus phase we are in */ + + /* Special states, ie. not normal bus transitions... */ +#define in_spec_mask 0x80 + in_abortone = 0x80, /* Aborting one command currently */ + in_abortall = 0x81, /* Blowing away all commands we have */ + in_resetdev = 0x82, /* SCSI target reset in progress */ + in_resetbus = 0x83, /* SCSI bus reset in progress */ + in_tgterror = 0x84, /* Target did something stupid */ +}; + +enum { + /* Zero has special meaning, see skipahead[12]. */ +/*0*/ do_never, + +/*1*/ do_phase_determine, +/*2*/ do_reset_bus, +/*3*/ do_reset_complete, +/*4*/ do_work_bus, +/*5*/ do_intr_end +}; + +/* Forward declarations. */ +static irqreturn_t esp_intr(int irq, void *dev_id); + +/* Debugging routines */ +struct esp_cmdstrings { + u8 cmdchar; + char *text; +} esp_cmd_strings[] = { + /* Miscellaneous */ + { ESP_CMD_NULL, "ESP_NOP", }, + { ESP_CMD_FLUSH, "FIFO_FLUSH", }, + { ESP_CMD_RC, "RSTESP", }, + { ESP_CMD_RS, "RSTSCSI", }, + /* Disconnected State Group */ + { ESP_CMD_RSEL, "RESLCTSEQ", }, + { ESP_CMD_SEL, "SLCTNATN", }, + { ESP_CMD_SELA, "SLCTATN", }, + { ESP_CMD_SELAS, "SLCTATNSTOP", }, + { ESP_CMD_ESEL, "ENSLCTRESEL", }, + { ESP_CMD_DSEL, "DISSELRESEL", }, + { ESP_CMD_SA3, "SLCTATN3", }, + { ESP_CMD_RSEL3, "RESLCTSEQ", }, + /* Target State Group */ + { ESP_CMD_SMSG, "SNDMSG", }, + { ESP_CMD_SSTAT, "SNDSTATUS", }, + { ESP_CMD_SDATA, "SNDDATA", }, + { ESP_CMD_DSEQ, "DISCSEQ", }, + { ESP_CMD_TSEQ, "TERMSEQ", }, + { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, + { ESP_CMD_DCNCT, "DISC", }, + { ESP_CMD_RMSG, "RCVMSG", }, + { ESP_CMD_RCMD, "RCVCMD", }, + { ESP_CMD_RDATA, "RCVDATA", }, + { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, + /* Initiator State Group */ + { ESP_CMD_TI, "TRANSINFO", }, + { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, + { ESP_CMD_MOK, "MSGACCEPTED", }, + { ESP_CMD_TPAD, "TPAD", }, + { ESP_CMD_SATN, "SATN", }, + { ESP_CMD_RATN, "RATN", }, +}; +#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) + +/* Print textual representation of an ESP command */ +static inline void esp_print_cmd(u8 espcmd) +{ + u8 dma_bit = espcmd & ESP_CMD_DMA; + int i; + + espcmd &= ~dma_bit; + for (i = 0; i < NUM_ESP_COMMANDS; i++) + if (esp_cmd_strings[i].cmdchar == espcmd) + break; + if (i == NUM_ESP_COMMANDS) + printk("ESP_Unknown"); + else + printk("%s%s", esp_cmd_strings[i].text, + ((dma_bit) ? "+DMA" : "")); +} + +/* Print the status register's value */ +static inline void esp_print_statreg(u8 statreg) +{ + u8 phase; + + printk("STATUS<"); + phase = statreg & ESP_STAT_PMASK; + printk("%s,", (phase == ESP_DOP ? "DATA-OUT" : + (phase == ESP_DIP ? "DATA-IN" : + (phase == ESP_CMDP ? "COMMAND" : + (phase == ESP_STATP ? "STATUS" : + (phase == ESP_MOP ? "MSG-OUT" : + (phase == ESP_MIP ? "MSG_IN" : + "unknown"))))))); + if (statreg & ESP_STAT_TDONE) + printk("TRANS_DONE,"); + if (statreg & ESP_STAT_TCNT) + printk("TCOUNT_ZERO,"); + if (statreg & ESP_STAT_PERR) + printk("P_ERROR,"); + if (statreg & ESP_STAT_SPAM) + printk("SPAM,"); + if (statreg & ESP_STAT_INTR) + printk("IRQ,"); + printk(">"); +} + +/* Print the interrupt register's value */ +static inline void esp_print_ireg(u8 intreg) +{ + printk("INTREG< "); + if (intreg & ESP_INTR_S) + printk("SLCT_NATN "); + if (intreg & ESP_INTR_SATN) + printk("SLCT_ATN "); + if (intreg & ESP_INTR_RSEL) + printk("RSLCT "); + if (intreg & ESP_INTR_FDONE) + printk("FDONE "); + if (intreg & ESP_INTR_BSERV) + printk("BSERV "); + if (intreg & ESP_INTR_DC) + printk("DISCNCT "); + if (intreg & ESP_INTR_IC) + printk("ILL_CMD "); + if (intreg & ESP_INTR_SR) + printk("SCSI_BUS_RESET "); + printk(">"); +} + +/* Print the sequence step registers contents */ +static inline void esp_print_seqreg(u8 stepreg) +{ + stepreg &= ESP_STEP_VBITS; + printk("STEP<%s>", + (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : + (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : + (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : + (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : + (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" : + "UNKNOWN")))))); +} + +static char *phase_string(int phase) +{ + switch (phase) { + case not_issued: + return "UNISSUED"; + case in_slct_norm: + return "SLCTNORM"; + case in_slct_stop: + return "SLCTSTOP"; + case in_slct_msg: + return "SLCTMSG"; + case in_slct_tag: + return "SLCTTAG"; + case in_slct_sneg: + return "SLCTSNEG"; + case in_datain: + return "DATAIN"; + case in_dataout: + return "DATAOUT"; + case in_data_done: + return "DATADONE"; + case in_msgin: + return "MSGIN"; + case in_msgincont: + return "MSGINCONT"; + case in_msgindone: + return "MSGINDONE"; + case in_msgout: + return "MSGOUT"; + case in_msgoutdone: + return "MSGOUTDONE"; + case in_cmdbegin: + return "CMDBEGIN"; + case in_cmdend: + return "CMDEND"; + case in_status: + return "STATUS"; + case in_freeing: + return "FREEING"; + case in_the_dark: + return "CLUELESS"; + case in_abortone: + return "ABORTONE"; + case in_abortall: + return "ABORTALL"; + case in_resetdev: + return "RESETDEV"; + case in_resetbus: + return "RESETBUS"; + case in_tgterror: + return "TGTERROR"; + default: + return "UNKNOWN"; + }; +} + +#ifdef DEBUG_STATE_MACHINE +static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase) +{ + ESPLOG(("<%s>", phase_string(newphase))); + s->SCp.sent_command = s->SCp.phase; + s->SCp.phase = newphase; +} +#else +#define esp_advance_phase(__s, __newphase) \ + (__s)->SCp.sent_command = (__s)->SCp.phase; \ + (__s)->SCp.phase = (__newphase); +#endif + +#ifdef DEBUG_ESP_CMDS +static inline void esp_cmd(struct esp *esp, u8 cmd) +{ + esp->espcmdlog[esp->espcmdent] = cmd; + esp->espcmdent = (esp->espcmdent + 1) & 31; + sbus_writeb(cmd, esp->eregs + ESP_CMD); +} +#else +#define esp_cmd(__esp, __cmd) \ + sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD) +#endif + +#define ESP_INTSOFF(__dregs) \ + sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR) +#define ESP_INTSON(__dregs) \ + sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR) +#define ESP_IRQ_P(__dregs) \ + (sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR)) + +/* How we use the various Linux SCSI data structures for operation. + * + * struct scsi_cmnd: + * + * We keep track of the synchronous capabilities of a target + * in the device member, using sync_min_period and + * sync_max_offset. These are the values we directly write + * into the ESP registers while running a command. If offset + * is zero the ESP will use asynchronous transfers. + * If the borken flag is set we assume we shouldn't even bother + * trying to negotiate for synchronous transfer as this target + * is really stupid. If we notice the target is dropping the + * bus, and we have been allowing it to disconnect, we clear + * the disconnect flag. + */ + + +/* Manipulation of the ESP command queues. Thanks to the aha152x driver + * and its author, Juergen E. Fischer, for the methods used here. + * Note that these are per-ESP queues, not global queues like + * the aha152x driver uses. + */ +static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) +{ + struct scsi_cmnd *end; + + new_SC->host_scribble = (unsigned char *) NULL; + if (!*SC) + *SC = new_SC; + else { + for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } +} + +static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) +{ + new_SC->host_scribble = (unsigned char *) *SC; + *SC = new_SC; +} + +static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC) +{ + struct scsi_cmnd *ptr; + ptr = *SC; + if (ptr) + *SC = (struct scsi_cmnd *) (*SC)->host_scribble; + return ptr; +} + +static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun) +{ + struct scsi_cmnd *ptr, *prev; + + for (ptr = *SC, prev = NULL; + ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); + prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble) + ; + if (ptr) { + if (prev) + prev->host_scribble=ptr->host_scribble; + else + *SC=(struct scsi_cmnd *)ptr->host_scribble; + } + return ptr; +} + +/* Resetting various pieces of the ESP scsi driver chipset/buses. */ +static void esp_reset_dma(struct esp *esp) +{ + int can_do_burst16, can_do_burst32, can_do_burst64; + int can_do_sbus64; + u32 tmp; + + can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; + can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; + can_do_burst64 = 0; + can_do_sbus64 = 0; + if (sbus_can_dma_64bit(esp->sdev)) + can_do_sbus64 = 1; + if (sbus_can_burst64(esp->sdev)) + can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; + + /* Punt the DVMA into a known state. */ + if (esp->dma->revision != dvmahme) { + tmp = sbus_readl(esp->dregs + DMA_CSR); + sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR); + sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR); + } + switch (esp->dma->revision) { + case dvmahme: + /* This is the HME DVMA gate array. */ + + sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR); + sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); + + esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); + esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); + + if (can_do_burst64) + esp->prev_hme_dmacsr |= DMA_BRST64; + else if (can_do_burst32) + esp->prev_hme_dmacsr |= DMA_BRST32; + + if (can_do_sbus64) { + esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; + sbus_set_sbus64(esp->sdev, esp->bursts); + } + + /* This chip is horrible. */ + while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ) + udelay(1); + + sbus_writel(0, esp->dregs + DMA_CSR); + sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); + + /* This is necessary to avoid having the SCSI channel + * engine lock up on us. + */ + sbus_writel(0, esp->dregs + DMA_ADDR); + + break; + case dvmarev2: + /* This is the gate array found in the sun4m + * NCR SBUS I/O subsystem. + */ + if (esp->erev != esp100) { + tmp = sbus_readl(esp->dregs + DMA_CSR); + sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR); + } + break; + case dvmarev3: + tmp = sbus_readl(esp->dregs + DMA_CSR); + tmp &= ~DMA_3CLKS; + tmp |= DMA_2CLKS; + if (can_do_burst32) { + tmp &= ~DMA_BRST_SZ; + tmp |= DMA_BRST32; + } + sbus_writel(tmp, esp->dregs + DMA_CSR); + break; + case dvmaesc1: + /* This is the DMA unit found on SCSI/Ether cards. */ + tmp = sbus_readl(esp->dregs + DMA_CSR); + tmp |= DMA_ADD_ENABLE; + tmp &= ~DMA_BCNT_ENAB; + if (!can_do_burst32 && can_do_burst16) { + tmp |= DMA_ESC_BURST; + } else { + tmp &= ~(DMA_ESC_BURST); + } + sbus_writel(tmp, esp->dregs + DMA_CSR); + break; + default: + break; + }; + ESP_INTSON(esp->dregs); +} + +/* Reset the ESP chip, _not_ the SCSI bus. */ +static void __init esp_reset_esp(struct esp *esp) +{ + u8 family_code, version; + int i; + + /* Now reset the ESP chip */ + esp_cmd(esp, ESP_CMD_RC); + esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); + esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); + + /* Reload the configuration registers */ + sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT); + esp->prev_stp = 0; + sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); + esp->prev_soff = 0; + sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); + sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO); + + /* This is the only point at which it is reliable to read + * the ID-code for a fast ESP chip variants. + */ + esp->max_period = ((35 * esp->ccycle) / 1000); + if (esp->erev == fast) { + version = sbus_readb(esp->eregs + ESP_UID); + family_code = (version & 0xf8) >> 3; + if (family_code == 0x02) + esp->erev = fas236; + else if (family_code == 0x0a) + esp->erev = fashme; /* Version is usually '5'. */ + else + esp->erev = fas100a; + ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n", + esp->esp_id, + (esp->erev == fas236) ? "fas236" : + ((esp->erev == fas100a) ? "fas100a" : + "fasHME"), family_code, (version & 7))); + + esp->min_period = ((4 * esp->ccycle) / 1000); + } else { + esp->min_period = ((5 * esp->ccycle) / 1000); + } + esp->max_period = (esp->max_period + 3)>>2; + esp->min_period = (esp->min_period + 3)>>2; + + sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); + switch (esp->erev) { + case esp100: + /* nothing to do */ + break; + case esp100a: + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + break; + case esp236: + /* Slow 236 */ + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + esp->prev_cfg3 = esp->config3[0]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + break; + case fashme: + esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); + /* fallthrough... */ + case fas236: + /* Fast 236 or HME */ + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + for (i = 0; i < 16; i++) { + if (esp->erev == fashme) { + u8 cfg3; + + cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; + if (esp->scsi_id >= 8) + cfg3 |= ESP_CONFIG3_IDBIT3; + esp->config3[i] |= cfg3; + } else { + esp->config3[i] |= ESP_CONFIG3_FCLK; + } + } + esp->prev_cfg3 = esp->config3[0]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + if (esp->erev == fashme) { + esp->radelay = 80; + } else { + if (esp->diff) + esp->radelay = 0; + else + esp->radelay = 96; + } + break; + case fas100a: + /* Fast 100a */ + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + for (i = 0; i < 16; i++) + esp->config3[i] |= ESP_CONFIG3_FCLOCK; + esp->prev_cfg3 = esp->config3[0]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + esp->radelay = 32; + break; + default: + panic("esp: what could it be... I wonder..."); + break; + }; + + /* Eat any bitrot in the chip */ + sbus_readb(esp->eregs + ESP_INTRPT); + udelay(100); +} + +/* This places the ESP into a known state at boot time. */ +static void __init esp_bootup_reset(struct esp *esp) +{ + u8 tmp; + + /* Reset the DMA */ + esp_reset_dma(esp); + + /* Reset the ESP */ + esp_reset_esp(esp); + + /* Reset the SCSI bus, but tell ESP not to generate an irq */ + tmp = sbus_readb(esp->eregs + ESP_CFG1); + tmp |= ESP_CONFIG1_SRRDISAB; + sbus_writeb(tmp, esp->eregs + ESP_CFG1); + + esp_cmd(esp, ESP_CMD_RS); + udelay(400); + + sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); + + /* Eat any bitrot in the chip and we are done... */ + sbus_readb(esp->eregs + ESP_INTRPT); +} + +static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev) +{ + struct sbus_dev *sdev = esp->sdev; + struct sbus_dma *dma; + + if (dma_sdev != NULL) { + for_each_dvma(dma) { + if (dma->sdev == dma_sdev) + break; + } + } else { + for_each_dvma(dma) { + /* If allocated already, can't use it. */ + if (dma->allocated) + continue; + + if (dma->sdev == NULL) + break; + + /* If bus + slot are the same and it has the + * correct OBP name, it's ours. + */ + if (sdev->bus == dma->sdev->bus && + sdev->slot == dma->sdev->slot && + (!strcmp(dma->sdev->prom_name, "dma") || + !strcmp(dma->sdev->prom_name, "espdma"))) + break; + } + } + + /* If we don't know how to handle the dvma, + * do not use this device. + */ + if (dma == NULL) { + printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id); + return -1; + } + if (dma->allocated) { + printk("esp%d: can't use my espdma\n", esp->esp_id); + return -1; + } + dma->allocated = 1; + esp->dma = dma; + esp->dregs = dma->regs; + + return 0; +} + +static int __init esp_map_regs(struct esp *esp, int hme) +{ + struct sbus_dev *sdev = esp->sdev; + struct resource *res; + + /* On HME, two reg sets exist, first is DVMA, + * second is ESP registers. + */ + if (hme) + res = &sdev->resource[1]; + else + res = &sdev->resource[0]; + + esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers"); + + if (esp->eregs == 0) + return -1; + return 0; +} + +static int __init esp_map_cmdarea(struct esp *esp) +{ + struct sbus_dev *sdev = esp->sdev; + + esp->esp_command = sbus_alloc_consistent(sdev, 16, + &esp->esp_command_dvma); + if (esp->esp_command == NULL || + esp->esp_command_dvma == 0) + return -1; + return 0; +} + +static int __init esp_register_irq(struct esp *esp) +{ + esp->ehost->irq = esp->irq = esp->sdev->irqs[0]; + + /* We used to try various overly-clever things to + * reduce the interrupt processing overhead on + * sun4c/sun4m when multiple ESP's shared the + * same IRQ. It was too complex and messy to + * sanely maintain. + */ + if (request_irq(esp->ehost->irq, esp_intr, + IRQF_SHARED, "ESP SCSI", esp)) { + printk("esp%d: Cannot acquire irq line\n", + esp->esp_id); + return -1; + } + + printk("esp%d: IRQ %d ", esp->esp_id, + esp->ehost->irq); + + return 0; +} + +static void __init esp_get_scsi_id(struct esp *esp) +{ + struct sbus_dev *sdev = esp->sdev; + struct device_node *dp = sdev->ofdev.node; + + esp->scsi_id = of_getintprop_default(dp, + "initiator-id", + -1); + if (esp->scsi_id == -1) + esp->scsi_id = of_getintprop_default(dp, + "scsi-initiator-id", + -1); + if (esp->scsi_id == -1) + esp->scsi_id = (sdev->bus == NULL) ? 7 : + of_getintprop_default(sdev->bus->ofdev.node, + "scsi-initiator-id", + 7); + esp->ehost->this_id = esp->scsi_id; + esp->scsi_id_mask = (1 << esp->scsi_id); + +} + +static void __init esp_get_clock_params(struct esp *esp) +{ + struct sbus_dev *sdev = esp->sdev; + int prom_node = esp->prom_node; + int sbus_prom_node; + unsigned int fmhz; + u8 ccf; + + if (sdev != NULL && sdev->bus != NULL) + sbus_prom_node = sdev->bus->prom_node; + else + sbus_prom_node = 0; + + /* This is getting messy but it has to be done + * correctly or else you get weird behavior all + * over the place. We are trying to basically + * figure out three pieces of information. + * + * a) Clock Conversion Factor + * + * This is a representation of the input + * crystal clock frequency going into the + * ESP on this machine. Any operation whose + * timing is longer than 400ns depends on this + * value being correct. For example, you'll + * get blips for arbitration/selection during + * high load or with multiple targets if this + * is not set correctly. + * + * b) Selection Time-Out + * + * The ESP isn't very bright and will arbitrate + * for the bus and try to select a target + * forever if you let it. This value tells + * the ESP when it has taken too long to + * negotiate and that it should interrupt + * the CPU so we can see what happened. + * The value is computed as follows (from + * NCR/Symbios chip docs). + * + * (Time Out Period) * (Input Clock) + * STO = ---------------------------------- + * (8192) * (Clock Conversion Factor) + * + * You usually want the time out period to be + * around 250ms, I think we'll set it a little + * bit higher to account for fully loaded SCSI + * bus's and slow devices that don't respond so + * quickly to selection attempts. (yeah, I know + * this is out of spec. but there is a lot of + * buggy pieces of firmware out there so bite me) + * + * c) Imperical constants for synchronous offset + * and transfer period register values + * + * This entails the smallest and largest sync + * period we could ever handle on this ESP. + */ + + fmhz = prom_getintdefault(prom_node, "clock-frequency", -1); + if (fmhz == -1) + fmhz = (!sbus_prom_node) ? 0 : + prom_getintdefault(sbus_prom_node, "clock-frequency", -1); + + if (fmhz <= (5000000)) + ccf = 0; + else + ccf = (((5000000 - 1) + (fmhz))/(5000000)); + + if (!ccf || ccf > 8) { + /* If we can't find anything reasonable, + * just assume 20MHZ. This is the clock + * frequency of the older sun4c's where I've + * been unable to find the clock-frequency + * PROM property. All other machines provide + * useful values it seems. + */ + ccf = ESP_CCF_F4; + fmhz = (20000000); + } + + if (ccf == (ESP_CCF_F7 + 1)) + esp->cfact = ESP_CCF_F0; + else if (ccf == ESP_CCF_NEVER) + esp->cfact = ESP_CCF_F2; + else + esp->cfact = ccf; + esp->raw_cfact = ccf; + + esp->cfreq = fmhz; + esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); + esp->ctick = ESP_TICK(ccf, esp->ccycle); + esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); + esp->sync_defp = SYNC_DEFP_SLOW; + + printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ", + esp->scsi_id, (fmhz / 1000000), + (int)esp->ccycle, (int)ccf, (int) esp->neg_defp); +} + +static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma) +{ + struct sbus_dev *sdev = esp->sdev; + u8 bursts; + + bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff); + + if (dma) { + u8 tmp = prom_getintdefault(dma->prom_node, + "burst-sizes", 0xff); + if (tmp != 0xff) + bursts &= tmp; + } + + if (sdev->bus) { + u8 tmp = prom_getintdefault(sdev->bus->prom_node, + "burst-sizes", 0xff); + if (tmp != 0xff) + bursts &= tmp; + } + + if (bursts == 0xff || + (bursts & DMA_BURST16) == 0 || + (bursts & DMA_BURST32) == 0) + bursts = (DMA_BURST32 - 1); + + esp->bursts = bursts; +} + +static void __init esp_get_revision(struct esp *esp) +{ + u8 tmp; + + esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); + esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + + tmp = sbus_readb(esp->eregs + ESP_CFG2); + tmp &= ~ESP_CONFIG2_MAGIC; + if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { + /* If what we write to cfg2 does not come back, cfg2 + * is not implemented, therefore this must be a plain + * esp100. + */ + esp->erev = esp100; + printk("NCR53C90(esp100)\n"); + } else { + esp->config2 = 0; + esp->prev_cfg3 = esp->config3[0] = 5; + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + sbus_writeb(0, esp->eregs + ESP_CFG3); + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + + tmp = sbus_readb(esp->eregs + ESP_CFG3); + if (tmp != 5) { + /* The cfg2 register is implemented, however + * cfg3 is not, must be esp100a. + */ + esp->erev = esp100a; + printk("NCR53C90A(esp100a)\n"); + } else { + int target; + + for (target = 0; target < 16; target++) + esp->config3[target] = 0; + esp->prev_cfg3 = 0; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + + /* All of cfg{1,2,3} implemented, must be one of + * the fas variants, figure out which one. + */ + if (esp->raw_cfact > ESP_CCF_F5) { + esp->erev = fast; + esp->sync_defp = SYNC_DEFP_FAST; + printk("NCR53C9XF(espfast)\n"); + } else { + esp->erev = esp236; + printk("NCR53C9x(esp236)\n"); + } + esp->config2 = 0; + sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); + } + } +} + +static void __init esp_init_swstate(struct esp *esp) +{ + int i; + + /* Command queues... */ + esp->current_SC = NULL; + esp->disconnected_SC = NULL; + esp->issue_SC = NULL; + + /* Target and current command state... */ + esp->targets_present = 0; + esp->resetting_bus = 0; + esp->snip = 0; + + init_waitqueue_head(&esp->reset_queue); + + /* Debugging... */ + for(i = 0; i < 32; i++) + esp->espcmdlog[i] = 0; + esp->espcmdent = 0; + + /* MSG phase state... */ + for(i = 0; i < 16; i++) { + esp->cur_msgout[i] = 0; + esp->cur_msgin[i] = 0; + } + esp->prevmsgout = esp->prevmsgin = 0; + esp->msgout_len = esp->msgin_len = 0; + + /* Clear the one behind caches to hold unmatchable values. */ + esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; + esp->prev_hme_dmacsr = 0xffffffff; +} + +static int __init detect_one_esp(struct scsi_host_template *tpnt, + struct device *dev, + struct sbus_dev *esp_dev, + struct sbus_dev *espdma, + struct sbus_bus *sbus, + int hme) +{ + static int instance; + struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp)); + struct esp *esp; + + if (!esp_host) + return -ENOMEM; + + if (hme) + esp_host->max_id = 16; + esp = (struct esp *) esp_host->hostdata; + esp->ehost = esp_host; + esp->sdev = esp_dev; + esp->esp_id = instance; + esp->prom_node = esp_dev->prom_node; + prom_getstring(esp->prom_node, "name", esp->prom_name, + sizeof(esp->prom_name)); + + if (esp_find_dvma(esp, espdma) < 0) + goto fail_unlink; + if (esp_map_regs(esp, hme) < 0) { + printk("ESP registers unmappable"); + goto fail_dvma_release; + } + if (esp_map_cmdarea(esp) < 0) { + printk("ESP DVMA transport area unmappable"); + goto fail_unmap_regs; + } + if (esp_register_irq(esp) < 0) + goto fail_unmap_cmdarea; + + esp_get_scsi_id(esp); + + esp->diff = prom_getbool(esp->prom_node, "differential"); + if (esp->diff) + printk("Differential "); + + esp_get_clock_params(esp); + esp_get_bursts(esp, espdma); + esp_get_revision(esp); + esp_init_swstate(esp); + + esp_bootup_reset(esp); + + if (scsi_add_host(esp_host, dev)) + goto fail_free_irq; + + dev_set_drvdata(&esp_dev->ofdev.dev, esp); + + scsi_scan_host(esp_host); + instance++; + + return 0; + +fail_free_irq: + free_irq(esp->ehost->irq, esp); + +fail_unmap_cmdarea: + sbus_free_consistent(esp->sdev, 16, + (void *) esp->esp_command, + esp->esp_command_dvma); + +fail_unmap_regs: + sbus_iounmap(esp->eregs, ESP_REG_SIZE); + +fail_dvma_release: + esp->dma->allocated = 0; + +fail_unlink: + scsi_host_put(esp_host); + return -1; +} + +/* Detecting ESP chips on the machine. This is the simple and easy + * version. + */ +static int __devexit esp_remove_common(struct esp *esp) +{ + unsigned int irq = esp->ehost->irq; + + scsi_remove_host(esp->ehost); + + ESP_INTSOFF(esp->dregs); +#if 0 + esp_reset_dma(esp); + esp_reset_esp(esp); +#endif + + free_irq(irq, esp); + sbus_free_consistent(esp->sdev, 16, + (void *) esp->esp_command, esp->esp_command_dvma); + sbus_iounmap(esp->eregs, ESP_REG_SIZE); + esp->dma->allocated = 0; + + scsi_host_put(esp->ehost); + + return 0; +} + + +#ifdef CONFIG_SUN4 + +#include + +static struct sbus_dev sun4_esp_dev; + +static int __init esp_sun4_probe(struct scsi_host_template *tpnt) +{ + if (sun4_esp_physaddr) { + memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev)); + sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; + sun4_esp_dev.irqs[0] = 4; + sun4_esp_dev.resource[0].start = sun4_esp_physaddr; + sun4_esp_dev.resource[0].end = + sun4_esp_physaddr + ESP_REG_SIZE - 1; + sun4_esp_dev.resource[0].flags = IORESOURCE_IO; + + return detect_one_esp(tpnt, NULL, + &sun4_esp_dev, NULL, NULL, 0); + } + return 0; +} + +static int __devexit esp_sun4_remove(void) +{ + struct of_device *dev = &sun4_esp_dev.ofdev; + struct esp *esp = dev_get_drvdata(&dev->dev); + + return esp_remove_common(esp); +} + +#else /* !CONFIG_SUN4 */ + +static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct sbus_dev *sdev = to_sbus_device(&dev->dev); + struct device_node *dp = dev->node; + struct sbus_dev *dma_sdev = NULL; + int hme = 0; + + if (dp->parent && + (!strcmp(dp->parent->name, "espdma") || + !strcmp(dp->parent->name, "dma"))) + dma_sdev = sdev->parent; + else if (!strcmp(dp->name, "SUNW,fas")) { + dma_sdev = sdev; + hme = 1; + } + + return detect_one_esp(match->data, &dev->dev, + sdev, dma_sdev, sdev->bus, hme); +} + +static int __devexit esp_sbus_remove(struct of_device *dev) +{ + struct esp *esp = dev_get_drvdata(&dev->dev); + + return esp_remove_common(esp); +} + +#endif /* !CONFIG_SUN4 */ + +/* The info function will return whatever useful + * information the developer sees fit. If not provided, then + * the name field will be used instead. + */ +static const char *esp_info(struct Scsi_Host *host) +{ + struct esp *esp; + + esp = (struct esp *) host->hostdata; + switch (esp->erev) { + case esp100: + return "Sparc ESP100 (NCR53C90)"; + case esp100a: + return "Sparc ESP100A (NCR53C90A)"; + case esp236: + return "Sparc ESP236"; + case fas236: + return "Sparc ESP236-FAST"; + case fashme: + return "Sparc ESP366-HME"; + case fas100a: + return "Sparc ESP100A-FAST"; + default: + return "Bogon ESP revision"; + }; +} + +/* From Wolfgang Stanglmeier's NCR scsi driver. */ +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) +{ + struct scsi_device *sdev; + struct info_str info; + int i; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "Sparc ESP Host Adapter:\n"); + copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node); + copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name); + copy_info(&info, "\tESP Model\t\t"); + switch (esp->erev) { + case esp100: + copy_info(&info, "ESP100\n"); + break; + case esp100a: + copy_info(&info, "ESP100A\n"); + break; + case esp236: + copy_info(&info, "ESP236\n"); + break; + case fas236: + copy_info(&info, "FAS236\n"); + break; + case fas100a: + copy_info(&info, "FAS100A\n"); + break; + case fast: + copy_info(&info, "FAST\n"); + break; + case fashme: + copy_info(&info, "Happy Meal FAS\n"); + break; + case espunknown: + default: + copy_info(&info, "Unknown!\n"); + break; + }; + copy_info(&info, "\tDMA Revision\t\t"); + switch (esp->dma->revision) { + case dvmarev0: + copy_info(&info, "Rev 0\n"); + break; + case dvmaesc1: + copy_info(&info, "ESC Rev 1\n"); + break; + case dvmarev1: + copy_info(&info, "Rev 1\n"); + break; + case dvmarev2: + copy_info(&info, "Rev 2\n"); + break; + case dvmarev3: + copy_info(&info, "Rev 3\n"); + break; + case dvmarevplus: + copy_info(&info, "Rev 1+\n"); + break; + case dvmahme: + copy_info(&info, "Rev HME/FAS\n"); + break; + default: + copy_info(&info, "Unknown!\n"); + break; + }; + copy_info(&info, "\tLive Targets\t\t[ "); + for (i = 0; i < 15; i++) { + if (esp->targets_present & (1 << i)) + copy_info(&info, "%d ", i); + } + copy_info(&info, "]\n\n"); + + /* Now describe the state of each existing target. */ + copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n"); + + shost_for_each_device(sdev, esp->ehost) { + struct esp_device *esp_dev = sdev->hostdata; + uint id = sdev->id; + + if (!(esp->targets_present & (1 << id))) + continue; + + copy_info(&info, "%d\t\t", id); + copy_info(&info, "%08lx\t", esp->config3[id]); + copy_info(&info, "[%02lx,%02lx]\t\t\t", + esp_dev->sync_max_offset, + esp_dev->sync_min_period); + copy_info(&info, "%s\t\t", + esp_dev->disconnect ? "yes" : "no"); + copy_info(&info, "%s\n", + (esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no"); + } + return info.pos > info.offset? info.pos - info.offset : 0; +} + +/* ESP proc filesystem code. */ +static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) +{ + struct esp *esp = (struct esp *) host->hostdata; + + if (inout) + return -EINVAL; /* not yet */ + + if (start) + *start = buffer; + + return esp_host_info(esp, buffer, offset, length); +} + +static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) +{ + if (sp->use_sg == 0) { + sp->SCp.this_residual = sp->request_bufflen; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = 0; + if (sp->request_bufflen) { + sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer, + sp->SCp.this_residual, + sp->sc_data_direction); + sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); + } else { + sp->SCp.ptr = NULL; + } + } else { + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, + sp->SCp.buffer, + sp->use_sg, + sp->sc_data_direction); + sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer); + sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer)); + } +} + +static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp) +{ + if (sp->use_sg) { + sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg, + sp->sc_data_direction); + } else if (sp->request_bufflen) { + sbus_unmap_single(esp->sdev, + sp->SCp.have_data_in, + sp->request_bufflen, + sp->sc_data_direction); + } +} + +static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[sp->device->id]; + + sp->SCp.ptr = ep->saved_ptr; + sp->SCp.buffer = ep->saved_buffer; + sp->SCp.this_residual = ep->saved_this_residual; + sp->SCp.buffers_residual = ep->saved_buffers_residual; +} + +static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[sp->device->id]; + + ep->saved_ptr = sp->SCp.ptr; + ep->saved_buffer = sp->SCp.buffer; + ep->saved_this_residual = sp->SCp.this_residual; + ep->saved_buffers_residual = sp->SCp.buffers_residual; +} + +/* Some rules: + * + * 1) Never ever panic while something is live on the bus. + * If there is to be any chance of syncing the disks this + * rule is to be obeyed. + * + * 2) Any target that causes a foul condition will no longer + * have synchronous transfers done to it, no questions + * asked. + * + * 3) Keep register accesses to a minimum. Think about some + * day when we have Xbus machines this is running on and + * the ESP chip is on the other end of the machine on a + * different board from the cpu where this is running. + */ + +/* Fire off a command. We assume the bus is free and that the only + * case where we could see an interrupt is where we have disconnected + * commands active and they are trying to reselect us. + */ +static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp) +{ + switch (sp->cmd_len) { + case 6: + case 10: + case 12: + esp->esp_slowcmd = 0; + break; + + default: + esp->esp_slowcmd = 1; + esp->esp_scmdleft = sp->cmd_len; + esp->esp_scmdp = &sp->cmnd[0]; + break; + }; +} + +static inline void build_sync_nego_msg(struct esp *esp, int period, int offset) +{ + esp->cur_msgout[0] = EXTENDED_MESSAGE; + esp->cur_msgout[1] = 3; + esp->cur_msgout[2] = EXTENDED_SDTR; + esp->cur_msgout[3] = period; + esp->cur_msgout[4] = offset; + esp->msgout_len = 5; +} + +/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */ +static inline void build_wide_nego_msg(struct esp *esp, int size) +{ + esp->cur_msgout[0] = EXTENDED_MESSAGE; + esp->cur_msgout[1] = 2; + esp->cur_msgout[2] = EXTENDED_WDTR; + switch (size) { + case 32: + esp->cur_msgout[3] = 2; + break; + case 16: + esp->cur_msgout[3] = 1; + break; + case 8: + default: + esp->cur_msgout[3] = 0; + break; + }; + + esp->msgout_len = 4; +} + +static void esp_exec_cmd(struct esp *esp) +{ + struct scsi_cmnd *SCptr; + struct scsi_device *SDptr; + struct esp_device *esp_dev; + volatile u8 *cmdp = esp->esp_command; + u8 the_esp_command; + int lun, target; + int i; + + /* Hold off if we have disconnected commands and + * an IRQ is showing... + */ + if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs)) + return; + + /* Grab first member of the issue queue. */ + SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); + + /* Safe to panic here because current_SC is null. */ + if (!SCptr) + panic("esp: esp_exec_cmd and issue queue is NULL"); + + SDptr = SCptr->device; + esp_dev = SDptr->hostdata; + lun = SCptr->device->lun; + target = SCptr->device->id; + + esp->snip = 0; + esp->msgout_len = 0; + + /* Send it out whole, or piece by piece? The ESP + * only knows how to automatically send out 6, 10, + * and 12 byte commands. I used to think that the + * Linux SCSI code would never throw anything other + * than that to us, but then again there is the + * SCSI generic driver which can send us anything. + */ + esp_check_cmd(esp, SCptr); + + /* If arbitration/selection is successful, the ESP will leave + * ATN asserted, causing the target to go into message out + * phase. The ESP will feed the target the identify and then + * the target can only legally go to one of command, + * datain/out, status, or message in phase, or stay in message + * out phase (should we be trying to send a sync negotiation + * message after the identify). It is not allowed to drop + * BSY, but some buggy targets do and we check for this + * condition in the selection complete code. Most of the time + * we'll make the command bytes available to the ESP and it + * will not interrupt us until it finishes command phase, we + * cannot do this for command sizes the ESP does not + * understand and in this case we'll get interrupted right + * when the target goes into command phase. + * + * It is absolutely _illegal_ in the presence of SCSI-2 devices + * to use the ESP select w/o ATN command. When SCSI-2 devices are + * present on the bus we _must_ always go straight to message out + * phase with an identify message for the target. Being that + * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 + * selections should not confuse SCSI-1 we hope. + */ + + if (esp_dev->sync) { + /* this targets sync is known */ +#ifndef __sparc_v9__ +do_sync_known: +#endif + if (esp_dev->disconnect) + *cmdp++ = IDENTIFY(1, lun); + else + *cmdp++ = IDENTIFY(0, lun); + + if (esp->esp_slowcmd) { + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_stop); + } else { + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_norm); + } + } else if (!(esp->targets_present & (1<disconnect)) { + /* After the bootup SCSI code sends both the + * TEST_UNIT_READY and INQUIRY commands we want + * to at least attempt allowing the device to + * disconnect. + */ + ESPMISC(("esp: Selecting device for first time. target=%d " + "lun=%d\n", target, SCptr->device->lun)); + if (!SDptr->borken && !esp_dev->disconnect) + esp_dev->disconnect = 1; + + *cmdp++ = IDENTIFY(0, lun); + esp->prevmsgout = NOP; + esp_advance_phase(SCptr, in_slct_norm); + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + + /* Take no chances... */ + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + } else { + /* Sorry, I have had way too many problems with + * various CDROM devices on ESP. -DaveM + */ + int cdrom_hwbug_wkaround = 0; + +#ifndef __sparc_v9__ + /* Never allow disconnects or synchronous transfers on + * SparcStation1 and SparcStation1+. Allowing those + * to be enabled seems to lockup the machine completely. + */ + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { + /* But we are nice and allow tapes and removable + * disks (but not CDROMs) to disconnect. + */ + if(SDptr->type == TYPE_TAPE || + (SDptr->type != TYPE_ROM && SDptr->removable)) + esp_dev->disconnect = 1; + else + esp_dev->disconnect = 0; + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; + esp->snip = 0; + goto do_sync_known; + } +#endif /* !(__sparc_v9__) */ + + /* We've talked to this guy before, + * but never negotiated. Let's try, + * need to attempt WIDE first, before + * sync nego, as per SCSI 2 standard. + */ + if (esp->erev == fashme && !esp_dev->wide) { + if (!SDptr->borken && + SDptr->type != TYPE_ROM && + SDptr->removable == 0) { + build_wide_nego_msg(esp, 16); + esp_dev->wide = 1; + esp->wnip = 1; + goto after_nego_msg_built; + } else { + esp_dev->wide = 1; + /* Fall through and try sync. */ + } + } + + if (!SDptr->borken) { + if ((SDptr->type == TYPE_ROM)) { + /* Nice try sucker... */ + ESPMISC(("esp%d: Disabling sync for buggy " + "CDROM.\n", esp->esp_id)); + cdrom_hwbug_wkaround = 1; + build_sync_nego_msg(esp, 0, 0); + } else if (SDptr->removable != 0) { + ESPMISC(("esp%d: Not negotiating sync/wide but " + "allowing disconnect for removable media.\n", + esp->esp_id)); + build_sync_nego_msg(esp, 0, 0); + } else { + build_sync_nego_msg(esp, esp->sync_defp, 15); + } + } else { + build_sync_nego_msg(esp, 0, 0); + } + esp_dev->sync = 1; + esp->snip = 1; + +after_nego_msg_built: + /* A fix for broken SCSI1 targets, when they disconnect + * they lock up the bus and confuse ESP. So disallow + * disconnects for SCSI1 targets for now until we + * find a better fix. + * + * Addendum: This is funny, I figured out what was going + * on. The blotzed SCSI1 target would disconnect, + * one of the other SCSI2 targets or both would be + * disconnected as well. The SCSI1 target would + * stay disconnected long enough that we start + * up a command on one of the SCSI2 targets. As + * the ESP is arbitrating for the bus the SCSI1 + * target begins to arbitrate as well to reselect + * the ESP. The SCSI1 target refuses to drop it's + * ID bit on the data bus even though the ESP is + * at ID 7 and is the obvious winner for any + * arbitration. The ESP is a poor sport and refuses + * to lose arbitration, it will continue indefinitely + * trying to arbitrate for the bus and can only be + * stopped via a chip reset or SCSI bus reset. + * Therefore _no_ disconnects for SCSI1 targets + * thank you very much. ;-) + */ + if(((SDptr->scsi_level < 3) && + (SDptr->type != TYPE_TAPE) && + SDptr->removable == 0) || + cdrom_hwbug_wkaround || SDptr->borken) { + ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->disconnect = 0; + *cmdp++ = IDENTIFY(0, lun); + } else { + *cmdp++ = IDENTIFY(1, lun); + } + + /* ESP fifo is only so big... + * Make this look like a slow command. + */ + esp->esp_slowcmd = 1; + esp->esp_scmdleft = SCptr->cmd_len; + esp->esp_scmdp = &SCptr->cmnd[0]; + + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_msg); + } + + if (!esp->esp_slowcmd) + for (i = 0; i < SCptr->cmd_len; i++) + *cmdp++ = SCptr->cmnd[i]; + + /* HME sucks... */ + if (esp->erev == fashme) + sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT), + esp->eregs + ESP_BUSID); + else + sbus_writeb(target & 7, esp->eregs + ESP_BUSID); + if (esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[target])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp->prev_stp = esp_dev->sync_min_period; + sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); + sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); + if (esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[target]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + } + } + i = (cmdp - esp->esp_command); + + if (esp->erev == fashme) { + esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */ + + /* Set up the DMA and HME counters */ + sbus_writeb(i, esp->eregs + ESP_TCLOW); + sbus_writeb(0, esp->eregs + ESP_TCMED); + sbus_writeb(0, esp->eregs + FAS_RLO); + sbus_writeb(0, esp->eregs + FAS_RHI); + esp_cmd(esp, the_esp_command); + + /* Talk about touchy hardware... */ + esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | + (DMA_SCSI_DISAB | DMA_ENABLE)) & + ~(DMA_ST_WRITE)); + sbus_writel(16, esp->dregs + DMA_COUNT); + sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); + sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); + } else { + u32 tmp; + + /* Set up the DMA and ESP counters */ + sbus_writeb(i, esp->eregs + ESP_TCLOW); + sbus_writeb(0, esp->eregs + ESP_TCMED); + tmp = sbus_readl(esp->dregs + DMA_CSR); + tmp &= ~DMA_ST_WRITE; + tmp |= DMA_ENABLE; + sbus_writel(tmp, esp->dregs + DMA_CSR); + if (esp->dma->revision == dvmaesc1) { + if (i) /* Workaround ESC gate array SBUS rerun bug. */ + sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT); + } + sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); + + /* Tell ESP to "go". */ + esp_cmd(esp, the_esp_command); + } +} + +/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ +static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +{ + struct esp *esp; + + /* Set up func ptr and initial driver cmd-phase. */ + SCpnt->scsi_done = done; + SCpnt->SCp.phase = not_issued; + + /* We use the scratch area. */ + ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun)); + ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun)); + + esp = (struct esp *) SCpnt->device->host->hostdata; + esp_get_dmabufs(esp, SCpnt); + esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0xff; + SCpnt->SCp.sent_command = 0; + + /* Place into our queue. */ + if (SCpnt->cmnd[0] == REQUEST_SENSE) { + ESPQUEUE(("RQSENSE\n")); + prepend_SC(&esp->issue_SC, SCpnt); + } else { + ESPQUEUE(("\n")); + append_SC(&esp->issue_SC, SCpnt); + } + + /* Run it now if we can. */ + if (!esp->current_SC && !esp->resetting_bus) + esp_exec_cmd(esp); + + return 0; +} + +/* Dump driver state. */ +static void esp_dump_cmd(struct scsi_cmnd *SCptr) +{ + ESPLOG(("[tgt<%02x> lun<%02x> " + "pphase<%s> cphase<%s>]", + SCptr->device->id, SCptr->device->lun, + phase_string(SCptr->SCp.sent_command), + phase_string(SCptr->SCp.phase))); +} + +static void esp_dump_state(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; +#ifdef DEBUG_ESP_CMDS + int i; +#endif + + ESPLOG(("esp%d: dumping state\n", esp->esp_id)); + ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n", + esp->esp_id, + sbus_readl(esp->dregs + DMA_CSR), + sbus_readl(esp->dregs + DMA_ADDR))); + ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); + ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, + sbus_readb(esp->eregs + ESP_STATUS), + sbus_readb(esp->eregs + ESP_SSTEP), + sbus_readb(esp->eregs + ESP_INTRPT))); +#ifdef DEBUG_ESP_CMDS + printk("esp%d: last ESP cmds [", esp->esp_id); + i = (esp->espcmdent - 1) & 31; + printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); + i = (i - 1) & 31; + printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); + i = (i - 1) & 31; + printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); + i = (i - 1) & 31; + printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); + printk("]\n"); +#endif /* (DEBUG_ESP_CMDS) */ + + if (SCptr) { + ESPLOG(("esp%d: current command ", esp->esp_id)); + esp_dump_cmd(SCptr); + } + ESPLOG(("\n")); + SCptr = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected ", esp->esp_id)); + while (SCptr) { + esp_dump_cmd(SCptr); + SCptr = (struct scsi_cmnd *) SCptr->host_scribble; + } + ESPLOG(("\n")); +} + +/* Abort a command. The host_lock is acquired by caller. */ +static int esp_abort(struct scsi_cmnd *SCptr) +{ + struct esp *esp = (struct esp *) SCptr->device->host->hostdata; + int don; + + ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); + esp_dump_state(esp); + + /* Wheee, if this is the current command on the bus, the + * best we can do is assert ATN and wait for msgout phase. + * This should even fix a hung SCSI bus when we lose state + * in the driver and timeout because the eventual phase change + * will cause the ESP to (eventually) give an interrupt. + */ + if (esp->current_SC == SCptr) { + esp->cur_msgout[0] = ABORT; + esp->msgout_len = 1; + esp->msgout_ctr = 0; + esp_cmd(esp, ESP_CMD_SATN); + return SUCCESS; + } + + /* If it is still in the issue queue then we can safely + * call the completion routine and report abort success. + */ + don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB); + if (don) { + ESP_INTSOFF(esp->dregs); + } + if (esp->issue_SC) { + struct scsi_cmnd **prev, *this; + for (prev = (&esp->issue_SC), this = esp->issue_SC; + this != NULL; + prev = (struct scsi_cmnd **) &(this->host_scribble), + this = (struct scsi_cmnd *) this->host_scribble) { + + if (this == SCptr) { + *prev = (struct scsi_cmnd *) this->host_scribble; + this->host_scribble = NULL; + + esp_release_dmabufs(esp, this); + this->result = DID_ABORT << 16; + this->scsi_done(this); + + if (don) + ESP_INTSON(esp->dregs); + + return SUCCESS; + } + } + } + + /* Yuck, the command to abort is disconnected, it is not + * worth trying to abort it now if something else is live + * on the bus at this time. So, we let the SCSI code wait + * a little bit and try again later. + */ + if (esp->current_SC) { + if (don) + ESP_INTSON(esp->dregs); + return FAILED; + } + + /* It's disconnected, we have to reconnect to re-establish + * the nexus and tell the device to abort. However, we really + * cannot 'reconnect' per se. Don't try to be fancy, just + * indicate failure, which causes our caller to reset the whole + * bus. + */ + + if (don) + ESP_INTSON(esp->dregs); + + return FAILED; +} + +/* We've sent ESP_CMD_RS to the ESP, the interrupt had just + * arrived indicating the end of the SCSI bus reset. Our job + * is to clean out the command queues and begin re-execution + * of SCSI commands once more. + */ +static int esp_finish_reset(struct esp *esp) +{ + struct scsi_cmnd *sp = esp->current_SC; + + /* Clean up currently executing command, if any. */ + if (sp != NULL) { + esp->current_SC = NULL; + + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + + sp->scsi_done(sp); + } + + /* Clean up disconnected queue, they have been invalidated + * by the bus reset. + */ + if (esp->disconnected_SC) { + while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + + sp->scsi_done(sp); + } + } + + /* SCSI bus reset is complete. */ + esp->resetting_bus = 0; + wake_up(&esp->reset_queue); + + /* Ok, now it is safe to get commands going once more. */ + if (esp->issue_SC) + esp_exec_cmd(esp); + + return do_intr_end; +} + +static int esp_do_resetbus(struct esp *esp) +{ + ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); + esp->resetting_bus = 1; + esp_cmd(esp, ESP_CMD_RS); + + return do_intr_end; +} + +/* Reset ESP chip, reset hanging bus, then kill active and + * disconnected commands for targets without soft reset. + * + * The host_lock is acquired by caller. + */ +static int esp_reset(struct scsi_cmnd *SCptr) +{ + struct esp *esp = (struct esp *) SCptr->device->host->hostdata; + + spin_lock_irq(esp->ehost->host_lock); + (void) esp_do_resetbus(esp); + spin_unlock_irq(esp->ehost->host_lock); + + wait_event(esp->reset_queue, (esp->resetting_bus == 0)); + + return SUCCESS; +} + +/* Internal ESP done function. */ +static void esp_done(struct esp *esp, int error) +{ + struct scsi_cmnd *done_SC = esp->current_SC; + + esp->current_SC = NULL; + + esp_release_dmabufs(esp, done_SC); + done_SC->result = error; + + done_SC->scsi_done(done_SC); + + /* Bus is free, issue any commands in the queue. */ + if (esp->issue_SC && !esp->current_SC) + esp_exec_cmd(esp); + +} + +/* Wheee, ESP interrupt engine. */ + +/* Forward declarations. */ +static int esp_do_phase_determine(struct esp *esp); +static int esp_do_data_finale(struct esp *esp); +static int esp_select_complete(struct esp *esp); +static int esp_do_status(struct esp *esp); +static int esp_do_msgin(struct esp *esp); +static int esp_do_msgindone(struct esp *esp); +static int esp_do_msgout(struct esp *esp); +static int esp_do_cmdbegin(struct esp *esp); + +#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) +#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) + +/* Read any bytes found in the FAS366 fifo, storing them into + * the ESP driver software state structure. + */ +static void hme_fifo_read(struct esp *esp) +{ + u8 count = 0; + u8 status = esp->sreg; + + /* Cannot safely frob the fifo for these following cases, but + * we must always read the fifo when the reselect interrupt + * is pending. + */ + if (((esp->ireg & ESP_INTR_RSEL) == 0) && + (sreg_datainp(status) || + sreg_dataoutp(status) || + (esp->current_SC && + esp->current_SC->SCp.phase == in_data_done))) { + ESPHME(("")); + } else { + unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES; + + /* The HME stores bytes in multiples of 2 in the fifo. */ + ESPHME(("hme_fifo[fcnt=%d", (int)fcnt)); + while (fcnt) { + esp->hme_fifo_workaround_buffer[count++] = + sbus_readb(esp->eregs + ESP_FDATA); + esp->hme_fifo_workaround_buffer[count++] = + sbus_readb(esp->eregs + ESP_FDATA); + ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1])); + fcnt--; + } + if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) { + ESPHME(("")); + sbus_writeb(0, esp->eregs + ESP_FDATA); + esp->hme_fifo_workaround_buffer[count++] = + sbus_readb(esp->eregs + ESP_FDATA); + ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1])); + ESPHME(("CMD_FLUSH")); + esp_cmd(esp, ESP_CMD_FLUSH); + } else { + ESPHME(("no_xtra_byte")); + } + } + ESPHME(("wkarnd_cnt=%d]", (int)count)); + esp->hme_fifo_workaround_count = count; +} + +static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count) +{ + esp_cmd(esp, ESP_CMD_FLUSH); + while (count) { + u8 tmp = *bytes++; + sbus_writeb(tmp, esp->eregs + ESP_FDATA); + sbus_writeb(0, esp->eregs + ESP_FDATA); + count--; + } +} + +/* We try to avoid some interrupts by jumping ahead and see if the ESP + * has gotten far enough yet. Hence the following. + */ +static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp, + int prev_phase, int new_phase) +{ + if (scp->SCp.sent_command != prev_phase) + return 0; + if (ESP_IRQ_P(esp->dregs)) { + /* Yes, we are able to save an interrupt. */ + if (esp->erev == fashme) + esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); + esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); + esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); + if (esp->erev == fashme) { + /* This chip is really losing. */ + ESPHME(("HME[")); + /* Must latch fifo before reading the interrupt + * register else garbage ends up in the FIFO + * which confuses the driver utterly. + * Happy Meal indeed.... + */ + ESPHME(("fifo_workaround]")); + if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) + hme_fifo_read(esp); + } + if (!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp, + int prev_phase1, int prev_phase2, int new_phase) +{ + if (scp->SCp.sent_command != prev_phase1 && + scp->SCp.sent_command != prev_phase2) + return 0; + if (ESP_IRQ_P(esp->dregs)) { + /* Yes, we are able to save an interrupt. */ + if (esp->erev == fashme) + esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); + esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR)); + esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); + if (esp->erev == fashme) { + /* This chip is really losing. */ + ESPHME(("HME[")); + + /* Must latch fifo before reading the interrupt + * register else garbage ends up in the FIFO + * which confuses the driver utterly. + * Happy Meal indeed.... + */ + ESPHME(("fifo_workaround]")); + if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) + hme_fifo_read(esp); + } + if (!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +/* Now some dma helpers. */ +static void dma_setup(struct esp *esp, __u32 addr, int count, int write) +{ + u32 nreg = sbus_readl(esp->dregs + DMA_CSR); + + if (write) + nreg |= DMA_ST_WRITE; + else + nreg &= ~(DMA_ST_WRITE); + nreg |= DMA_ENABLE; + sbus_writel(nreg, esp->dregs + DMA_CSR); + if (esp->dma->revision == dvmaesc1) { + /* This ESC gate array sucks! */ + __u32 src = addr; + __u32 dest = src + count; + + if (dest & (PAGE_SIZE - 1)) + count = PAGE_ALIGN(count); + sbus_writel(count, esp->dregs + DMA_COUNT); + } + sbus_writel(addr, esp->dregs + DMA_ADDR); +} + +static void dma_drain(struct esp *esp) +{ + u32 tmp; + + if (esp->dma->revision == dvmahme) + return; + if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) { + switch (esp->dma->revision) { + default: + tmp |= DMA_FIFO_STDRAIN; + sbus_writel(tmp, esp->dregs + DMA_CSR); + + case dvmarev3: + case dvmaesc1: + while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN) + udelay(1); + }; + } +} + +static void dma_invalidate(struct esp *esp) +{ + u32 tmp; + + if (esp->dma->revision == dvmahme) { + sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); + + esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | + (DMA_PARITY_OFF | DMA_2CLKS | + DMA_SCSI_DISAB | DMA_INT_ENAB)) & + ~(DMA_ST_WRITE | DMA_ENABLE)); + + sbus_writel(0, esp->dregs + DMA_CSR); + sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); + + /* This is necessary to avoid having the SCSI channel + * engine lock up on us. + */ + sbus_writel(0, esp->dregs + DMA_ADDR); + } else { + while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ) + udelay(1); + + tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); + tmp |= DMA_FIFO_INV; + sbus_writel(tmp, esp->dregs + DMA_CSR); + tmp &= ~DMA_FIFO_INV; + sbus_writel(tmp, esp->dregs + DMA_CSR); + } +} + +static inline void dma_flashclear(struct esp *esp) +{ + dma_drain(esp); + dma_invalidate(esp); +} + +static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp) +{ + __u32 base, end, sz; + + if (esp->dma->revision == dvmarev3) { + sz = sp->SCp.this_residual; + if (sz > 0x1000000) + sz = 0x1000000; + } else { + base = ((__u32)((unsigned long)sp->SCp.ptr)); + base &= (0x1000000 - 1); + end = (base + sp->SCp.this_residual); + if (end > 0x1000000) + end = 0x1000000; + sz = (end - base); + } + return sz; +} + +/* Misc. esp helper macros. */ +#define esp_setcount(__eregs, __cnt, __hme) \ + sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \ + sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \ + if (__hme) { \ + sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \ + sbus_writeb(0, (__eregs) + FAS_RHI); \ + } + +#define esp_getcount(__eregs, __hme) \ + ((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \ + ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \ + ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0)) + +#define fcount(__esp) \ + (((__esp)->erev == fashme) ? \ + (__esp)->hme_fifo_workaround_count : \ + sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES) + +#define fnzero(__esp) \ + (((__esp)->erev == fashme) ? 0 : \ + sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO) + +/* XXX speculative nops unnecessary when continuing amidst a data phase + * XXX even on esp100!!! another case of flooding the bus with I/O reg + * XXX writes... + */ +#define esp_maybe_nop(__esp) \ + if ((__esp)->erev == esp100) \ + esp_cmd((__esp), ESP_CMD_NULL) + +#define sreg_to_dataphase(__sreg) \ + ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) + +/* The ESP100 when in synchronous data phase, can mistake a long final + * REQ pulse from the target as an extra byte, it places whatever is on + * the data lines into the fifo. For now, we will assume when this + * happens that the target is a bit quirky and we don't want to + * be talking synchronously to it anyways. Regardless, we need to + * tell the ESP to eat the extraneous byte so that we can proceed + * to the next phase. + */ +static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt) +{ + /* Do not touch this piece of code. */ + if ((!(esp->erev == esp100)) || + (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) && + !fifocnt) && + !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) { + if (sp->SCp.phase == in_dataout) + esp_cmd(esp, ESP_CMD_FLUSH); + return 0; + } else { + /* Async mode for this guy. */ + build_sync_nego_msg(esp, 0, 0); + + /* Ack the bogus byte, but set ATN first. */ + esp_cmd(esp, ESP_CMD_SATN); + esp_cmd(esp, ESP_CMD_MOK); + return 1; + } +} + +/* This closes the window during a selection with a reselect pending, because + * we use DMA for the selection process the FIFO should hold the correct + * contents if we get reselected during this process. So we just need to + * ack the possible illegal cmd interrupt pending on the esp100. + */ +static inline int esp100_reconnect_hwbug(struct esp *esp) +{ + u8 tmp; + + if (esp->erev != esp100) + return 0; + tmp = sbus_readb(esp->eregs + ESP_INTRPT); + if (tmp & ESP_INTR_SR) + return 1; + return 0; +} + +/* This verifies the BUSID bits during a reselection so that we know which + * target is talking to us. + */ +static inline int reconnect_target(struct esp *esp) +{ + int it, me = esp->scsi_id_mask, targ = 0; + + if (2 != fcount(esp)) + return -1; + if (esp->erev == fashme) { + /* HME does not latch it's own BUS ID bits during + * a reselection. Also the target number is given + * as an unsigned char, not as a sole bit number + * like the other ESP's do. + * Happy Meal indeed.... + */ + targ = esp->hme_fifo_workaround_buffer[0]; + } else { + it = sbus_readb(esp->eregs + ESP_FDATA); + if (!(it & me)) + return -1; + it &= ~me; + if (it & (it - 1)) + return -1; + while (!(it & 1)) + targ++, it >>= 1; + } + return targ; +} + +/* This verifies the identify from the target so that we know which lun is + * being reconnected. + */ +static inline int reconnect_lun(struct esp *esp) +{ + int lun; + + if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) + return -1; + if (esp->erev == fashme) + lun = esp->hme_fifo_workaround_buffer[1]; + else + lun = sbus_readb(esp->eregs + ESP_FDATA); + + /* Yes, you read this correctly. We report lun of zero + * if we see parity error. ESP reports parity error for + * the lun byte, and this is the only way to hope to recover + * because the target is connected. + */ + if (esp->sreg & ESP_STAT_PERR) + return 0; + + /* Check for illegal bits being set in the lun. */ + if ((lun & 0x40) || !(lun & 0x80)) + return -1; + + return lun & 7; +} + +/* This puts the driver in a state where it can revitalize a command that + * is being continued due to reselection. + */ +static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp) +{ + struct esp_device *esp_dev = sp->device->hostdata; + + if (esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[sp->device->id])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp->prev_stp = esp_dev->sync_min_period; + sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); + sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); + if (esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[sp->device->id]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + } + } + esp->current_SC = sp; +} + +/* This will place the current working command back into the issue queue + * if we are to receive a reselection amidst a selection attempt. + */ +static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp) +{ + if (!esp->disconnected_SC) + ESPLOG(("esp%d: Weird, being reselected but disconnected " + "command queue is empty.\n", esp->esp_id)); + esp->snip = 0; + esp->current_SC = NULL; + sp->SCp.phase = not_issued; + append_SC(&esp->issue_SC, sp); +} + +/* Begin message in phase. */ +static int esp_do_msgin(struct esp *esp) +{ + /* Must be very careful with the fifo on the HME */ + if ((esp->erev != fashme) || + !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY)) + esp_cmd(esp, ESP_CMD_FLUSH); + esp_maybe_nop(esp); + esp_cmd(esp, ESP_CMD_TI); + esp->msgin_len = 1; + esp->msgin_ctr = 0; + esp_advance_phase(esp->current_SC, in_msgindone); + return do_work_bus; +} + +/* This uses various DMA csr fields and the fifo flags count value to + * determine how many bytes were successfully sent/received by the ESP. + */ +static inline int esp_bytes_sent(struct esp *esp, int fifo_count) +{ + int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma; + + if (esp->dma->revision == dvmarev1) + rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11)); + return rval - fifo_count; +} + +static inline void advance_sg(struct scsi_cmnd *sp) +{ + ++sp->SCp.buffer; + --sp->SCp.buffers_residual; + sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer); + sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer)); +} + +/* Please note that the way I've coded these routines is that I _always_ + * check for a disconnect during any and all information transfer + * phases. The SCSI standard states that the target _can_ cause a BUS + * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note + * that during information transfer phases the target controls every + * change in phase, the only thing the initiator can do is "ask" for + * a message out phase by driving ATN true. The target can, and sometimes + * will, completely ignore this request so we cannot assume anything when + * we try to force a message out phase to abort/reset a target. Most of + * the time the target will eventually be nice and go to message out, so + * we may have to hold on to our state about what we want to tell the target + * for some period of time. + */ + +/* I think I have things working here correctly. Even partial transfers + * within a buffer or sub-buffer should not upset us at all no matter + * how bad the target and/or ESP fucks things up. + */ +static int esp_do_data(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + int thisphase, hmuch; + + ESPDATA(("esp_do_data: ")); + esp_maybe_nop(esp); + thisphase = sreg_to_dataphase(esp->sreg); + esp_advance_phase(SCptr, thisphase); + ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); + hmuch = dma_can_transfer(esp, SCptr); + if (hmuch > (64 * 1024) && (esp->erev != fashme)) + hmuch = (64 * 1024); + ESPDATA(("hmuch<%d> ", hmuch)); + esp->current_transfer_size = hmuch; + + if (esp->erev == fashme) { + u32 tmp = esp->prev_hme_dmacsr; + + /* Always set the ESP count registers first. */ + esp_setcount(esp->eregs, hmuch, 1); + + /* Get the DMA csr computed. */ + tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); + if (thisphase == in_datain) + tmp |= DMA_ST_WRITE; + else + tmp &= ~(DMA_ST_WRITE); + esp->prev_hme_dmacsr = tmp; + + ESPDATA(("DMA|TI --> do_intr_end\n")); + if (thisphase == in_datain) { + sbus_writel(hmuch, esp->dregs + DMA_COUNT); + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + } else { + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + sbus_writel(hmuch, esp->dregs + DMA_COUNT); + } + sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR); + sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); + } else { + esp_setcount(esp->eregs, hmuch, 0); + dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)), + hmuch, (thisphase == in_datain)); + ESPDATA(("DMA|TI --> do_intr_end\n")); + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + } + return do_intr_end; +} + +/* See how successful the data transfer was. */ +static int esp_do_data_finale(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; + + ESPDATA(("esp_do_data_finale: ")); + + if (SCptr->SCp.phase == in_datain) { + if (esp->sreg & ESP_STAT_PERR) { + /* Yuck, parity error. The ESP asserts ATN + * so that we can go to message out phase + * immediately and inform the target that + * something bad happened. + */ + ESPLOG(("esp%d: data bad parity detected.\n", + esp->esp_id)); + esp->cur_msgout[0] = INITIATOR_ERROR; + esp->msgout_len = 1; + } + dma_drain(esp); + } + dma_invalidate(esp); + + /* This could happen for the above parity error case. */ + if (esp->ireg != ESP_INTR_BSERV) { + /* Please go to msgout phase, please please please... */ + ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", + esp->esp_id)); + return esp_do_phase_determine(esp); + } + + /* Check for partial transfers and other horrible events. + * Note, here we read the real fifo flags register even + * on HME broken adapters because we skip the HME fifo + * workaround code in esp_handle() if we are doing data + * phase things. We don't want to fuck directly with + * the fifo like that, especially if doing synchronous + * transfers! Also, will need to double the count on + * HME if we are doing wide transfers, as the HME fifo + * will move and count 16-bit quantities during wide data. + * SMCC _and_ Qlogic can both bite me. + */ + fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES); + if (esp->erev != fashme) + ecount = esp_getcount(esp->eregs, 0); + bytes_sent = esp->current_transfer_size; + + ESPDATA(("trans_sz(%d), ", bytes_sent)); + if (esp->erev == fashme) { + if (!(esp->sreg & ESP_STAT_TCNT)) { + ecount = esp_getcount(esp->eregs, 1); + bytes_sent -= ecount; + } + + /* Always subtract any cruft remaining in the FIFO. */ + if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE) + fifocnt <<= 1; + if (SCptr->SCp.phase == in_dataout) + bytes_sent -= fifocnt; + + /* I have an IBM disk which exhibits the following + * behavior during writes to it. It disconnects in + * the middle of a partial transfer, the current sglist + * buffer is 1024 bytes, the disk stops data transfer + * at 512 bytes. + * + * However the FAS366 reports that 32 more bytes were + * transferred than really were. This is precisely + * the size of a fully loaded FIFO in wide scsi mode. + * The FIFO state recorded indicates that it is empty. + * + * I have no idea if this is a bug in the FAS366 chip + * or a bug in the firmware on this IBM disk. In any + * event the following seems to be a good workaround. -DaveM + */ + if (bytes_sent != esp->current_transfer_size && + SCptr->SCp.phase == in_dataout) { + int mask = (64 - 1); + + if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0) + mask >>= 1; + + if (bytes_sent & mask) + bytes_sent -= (bytes_sent & mask); + } + } else { + if (!(esp->sreg & ESP_STAT_TCNT)) + bytes_sent -= ecount; + if (SCptr->SCp.phase == in_dataout) + bytes_sent -= fifocnt; + } + + ESPDATA(("bytes_sent(%d), ", bytes_sent)); + + /* If we were in synchronous mode, check for peculiarities. */ + if (esp->erev == fashme) { + if (esp_dev->sync_max_offset) { + if (SCptr->SCp.phase == in_dataout) + esp_cmd(esp, ESP_CMD_FLUSH); + } else { + esp_cmd(esp, ESP_CMD_FLUSH); + } + } else { + if (esp_dev->sync_max_offset) + bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt); + else + esp_cmd(esp, ESP_CMD_FLUSH); + } + + /* Until we are sure of what has happened, we are certainly + * in the dark. + */ + esp_advance_phase(SCptr, in_the_dark); + + if (bytes_sent < 0) { + /* I've seen this happen due to lost state in this + * driver. No idea why it happened, but allowing + * this value to be negative caused things to + * lock up. This allows greater chance of recovery. + * In fact every time I've seen this, it has been + * a driver bug without question. + */ + ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); + ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", + esp->esp_id, + esp->current_transfer_size, fifocnt, ecount)); + ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", + esp->esp_id, + SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); + ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, + SCptr->device->id)); + SCptr->device->borken = 1; + esp_dev->sync = 0; + bytes_sent = 0; + } + + /* Update the state of our transfer. */ + SCptr->SCp.ptr += bytes_sent; + SCptr->SCp.this_residual -= bytes_sent; + if (SCptr->SCp.this_residual < 0) { + /* shit */ + ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); + SCptr->SCp.this_residual = 0; + } + + /* Maybe continue. */ + if (!bogus_data) { + ESPDATA(("!bogus_data, ")); + + /* NO MATTER WHAT, we advance the scatterlist, + * if the target should decide to disconnect + * in between scatter chunks (which is common) + * we could die horribly! I used to have the sg + * advance occur only if we are going back into + * (or are staying in) a data phase, you can + * imagine the hell I went through trying to + * figure this out. + */ + if (SCptr->use_sg && !SCptr->SCp.this_residual) + advance_sg(SCptr); + if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) { + ESPDATA(("to more data\n")); + return esp_do_data(esp); + } + ESPDATA(("to new phase\n")); + return esp_do_phase_determine(esp); + } + /* Bogus data, just wait for next interrupt. */ + ESPLOG(("esp%d: bogus_data during end of data phase\n", + esp->esp_id)); + return do_intr_end; +} + +/* We received a non-good status return at the end of + * running a SCSI command. This is used to decide if + * we should clear our synchronous transfer state for + * such a device when that happens. + * + * The idea is that when spinning up a disk or rewinding + * a tape, we don't want to go into a loop re-negotiating + * synchronous capabilities over and over. + */ +static int esp_should_clear_sync(struct scsi_cmnd *sp) +{ + u8 cmd = sp->cmnd[0]; + + /* These cases are for spinning up a disk and + * waiting for that spinup to complete. + */ + if (cmd == START_STOP) + return 0; + + if (cmd == TEST_UNIT_READY) + return 0; + + /* One more special case for SCSI tape drives, + * this is what is used to probe the device for + * completion of a rewind or tape load operation. + */ + if (sp->device->type == TYPE_TAPE) { + if (cmd == MODE_SENSE) + return 0; + } + + return 1; +} + +/* Either a command is completing or a target is dropping off the bus + * to continue the command in the background so we can do other work. + */ +static int esp_do_freebus(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int rval; + + rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing); + if (rval) + return rval; + if (esp->ireg != ESP_INTR_DC) { + ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id)); + return do_reset_bus; /* target will not drop BSY... */ + } + esp->msgout_len = 0; + esp->prevmsgout = NOP; + if (esp->prevmsgin == COMMAND_COMPLETE) { + /* Normal end of nexus. */ + if (esp->disconnected_SC || (esp->erev == fashme)) + esp_cmd(esp, ESP_CMD_ESEL); + + if (SCptr->SCp.Status != GOOD && + SCptr->SCp.Status != CONDITION_GOOD && + ((1<device->id) & esp->targets_present) && + esp_dev->sync && + esp_dev->sync_max_offset) { + /* SCSI standard says that the synchronous capabilities + * should be renegotiated at this point. Most likely + * we are about to request sense from this target + * in which case we want to avoid using sync + * transfers until we are sure of the current target + * state. + */ + ESPMISC(("esp: Status <%d> for target %d lun %d\n", + SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); + + /* But don't do this when spinning up a disk at + * boot time while we poll for completion as it + * fills up the console with messages. Also, tapes + * can report not ready many times right after + * loading up a tape. + */ + if (esp_should_clear_sync(SCptr) != 0) + esp_dev->sync = 0; + } + ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + esp_done(esp, ((SCptr->SCp.Status & 0xff) | + ((SCptr->SCp.Message & 0xff)<<8) | + (DID_OK << 16))); + } else if (esp->prevmsgin == DISCONNECT) { + /* Normal disconnect. */ + esp_cmd(esp, ESP_CMD_ESEL); + ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + append_SC(&esp->disconnected_SC, SCptr); + esp->current_SC = NULL; + if (esp->issue_SC) + esp_exec_cmd(esp); + } else { + /* Driver bug, we do not expect a disconnect here + * and should not have advanced the state engine + * to in_freeing. + */ + ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n", + esp->esp_id)); + return do_reset_bus; + } + return do_intr_end; +} + +/* When a reselect occurs, and we cannot find the command to + * reconnect to in our queues, we do this. + */ +static int esp_bad_reconnect(struct esp *esp) +{ + struct scsi_cmnd *sp; + + ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", + esp->esp_id)); + ESPLOG(("QUEUE DUMP\n")); + sp = esp->issue_SC; + ESPLOG(("esp%d: issue_SC[", esp->esp_id)); + while (sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (struct scsi_cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->current_SC; + ESPLOG(("esp%d: current_SC[", esp->esp_id)); + if (sp) + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + else + ESPLOG(("")); + ESPLOG(("]\n")); + sp = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); + while (sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (struct scsi_cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + return do_reset_bus; +} + +/* Do the needy when a target tries to reconnect to us. */ +static int esp_do_reconnect(struct esp *esp) +{ + int lun, target; + struct scsi_cmnd *SCptr; + + /* Check for all bogus conditions first. */ + target = reconnect_target(esp); + if (target < 0) { + ESPDISC(("bad bus bits\n")); + return do_reset_bus; + } + lun = reconnect_lun(esp); + if (lun < 0) { + ESPDISC(("target=%2x, bad identify msg\n", target)); + return do_reset_bus; + } + + /* Things look ok... */ + ESPDISC(("R<%02x,%02x>", target, lun)); + + /* Must not flush FIFO or DVMA on HME. */ + if (esp->erev != fashme) { + esp_cmd(esp, ESP_CMD_FLUSH); + if (esp100_reconnect_hwbug(esp)) + return do_reset_bus; + esp_cmd(esp, ESP_CMD_NULL); + } + + SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun); + if (!SCptr) + return esp_bad_reconnect(esp); + + esp_connect(esp, SCptr); + esp_cmd(esp, ESP_CMD_MOK); + + if (esp->erev == fashme) + sbus_writeb(((SCptr->device->id & 0xf) | + (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)), + esp->eregs + ESP_BUSID); + + /* Reconnect implies a restore pointers operation. */ + esp_restore_pointers(esp, SCptr); + + esp->snip = 0; + esp_advance_phase(SCptr, in_the_dark); + return do_intr_end; +} + +/* End of NEXUS (hopefully), pick up status + message byte then leave if + * all goes well. + */ +static int esp_do_status(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + int intr, rval; + + rval = skipahead1(esp, SCptr, in_the_dark, in_status); + if (rval) + return rval; + intr = esp->ireg; + ESPSTAT(("esp_do_status: ")); + if (intr != ESP_INTR_DC) { + int message_out = 0; /* for parity problems */ + + /* Ack the message. */ + ESPSTAT(("ack msg, ")); + esp_cmd(esp, ESP_CMD_MOK); + + if (esp->erev != fashme) { + dma_flashclear(esp); + + /* Wait till the first bits settle. */ + while (esp->esp_command[0] == 0xff) + udelay(1); + } else { + esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0]; + esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1]; + } + + ESPSTAT(("got something, ")); + /* ESP chimes in with one of + * + * 1) function done interrupt: + * both status and message in bytes + * are available + * + * 2) bus service interrupt: + * only status byte was acquired + * + * 3) Anything else: + * can't happen, but we test for it + * anyways + * + * ALSO: If bad parity was detected on either + * the status _or_ the message byte then + * the ESP has asserted ATN on the bus + * and we must therefore wait for the + * next phase change. + */ + if (intr & ESP_INTR_FDONE) { + /* We got it all, hallejulia. */ + ESPSTAT(("got both, ")); + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = esp->esp_command[1]; + esp->prevmsgin = SCptr->SCp.Message; + esp->cur_msgin[0] = SCptr->SCp.Message; + if (esp->sreg & ESP_STAT_PERR) { + /* There was bad parity for the + * message byte, the status byte + * was ok. + */ + message_out = MSG_PARITY_ERROR; + } + } else if (intr == ESP_INTR_BSERV) { + /* Only got status byte. */ + ESPLOG(("esp%d: got status only, ", esp->esp_id)); + if (!(esp->sreg & ESP_STAT_PERR)) { + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = 0xff; + } else { + /* The status byte had bad parity. + * we leave the scsi_pointer Status + * field alone as we set it to a default + * of CHECK_CONDITION in esp_queue. + */ + message_out = INITIATOR_ERROR; + } + } else { + /* This shouldn't happen ever. */ + ESPSTAT(("got bolixed\n")); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp); + } + + if (!message_out) { + ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status, + SCptr->SCp.Message)); + if (SCptr->SCp.Message == COMMAND_COMPLETE) { + ESPSTAT(("and was COMMAND_COMPLETE\n")); + esp_advance_phase(SCptr, in_freeing); + return esp_do_freebus(esp); + } else { + ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n", + esp->esp_id)); + esp->msgin_len = esp->msgin_ctr = 1; + esp_advance_phase(SCptr, in_msgindone); + return esp_do_msgindone(esp); + } + } else { + /* With luck we'll be able to let the target + * know that bad parity happened, it will know + * which byte caused the problems and send it + * again. For the case where the status byte + * receives bad parity, I do not believe most + * targets recover very well. We'll see. + */ + ESPLOG(("esp%d: bad parity somewhere mout=%2x\n", + esp->esp_id, message_out)); + esp->cur_msgout[0] = message_out; + esp->msgout_len = esp->msgout_ctr = 1; + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp); + } + } else { + /* If we disconnect now, all hell breaks loose. */ + ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp); + } +} + +static int esp_enter_status(struct esp *esp) +{ + u8 thecmd = ESP_CMD_ICCSEQ; + + esp_cmd(esp, ESP_CMD_FLUSH); + if (esp->erev != fashme) { + u32 tmp; + + esp->esp_command[0] = esp->esp_command[1] = 0xff; + sbus_writeb(2, esp->eregs + ESP_TCLOW); + sbus_writeb(0, esp->eregs + ESP_TCMED); + tmp = sbus_readl(esp->dregs + DMA_CSR); + tmp |= (DMA_ST_WRITE | DMA_ENABLE); + sbus_writel(tmp, esp->dregs + DMA_CSR); + if (esp->dma->revision == dvmaesc1) + sbus_writel(0x100, esp->dregs + DMA_COUNT); + sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); + thecmd |= ESP_CMD_DMA; + } + esp_cmd(esp, thecmd); + esp_advance_phase(esp->current_SC, in_status); + + return esp_do_status(esp); +} + +static int esp_disconnect_amidst_phases(struct esp *esp) +{ + struct scsi_cmnd *sp = esp->current_SC; + struct esp_device *esp_dev = sp->device->hostdata; + + /* This means real problems if we see this + * here. Unless we were actually trying + * to force the device to abort/reset. + */ + ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id)); + ESPLOG(("pphase<%s> cphase<%s>, ", + phase_string(sp->SCp.phase), + phase_string(sp->SCp.sent_command))); + + if (esp->disconnected_SC != NULL || (esp->erev == fashme)) + esp_cmd(esp, ESP_CMD_ESEL); + + switch (esp->cur_msgout[0]) { + default: + /* We didn't expect this to happen at all. */ + ESPLOG(("device is bolixed\n")); + esp_advance_phase(sp, in_tgterror); + esp_done(esp, (DID_ERROR << 16)); + break; + + case BUS_DEVICE_RESET: + ESPLOG(("device reset successful\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 0; + esp_advance_phase(sp, in_resetdev); + esp_done(esp, (DID_RESET << 16)); + break; + + case ABORT: + ESPLOG(("device abort successful\n")); + esp_advance_phase(sp, in_abortone); + esp_done(esp, (DID_ABORT << 16)); + break; + + }; + return do_intr_end; +} + +static int esp_enter_msgout(struct esp *esp) +{ + esp_advance_phase(esp->current_SC, in_msgout); + return esp_do_msgout(esp); +} + +static int esp_enter_msgin(struct esp *esp) +{ + esp_advance_phase(esp->current_SC, in_msgin); + return esp_do_msgin(esp); +} + +static int esp_enter_cmd(struct esp *esp) +{ + esp_advance_phase(esp->current_SC, in_cmdbegin); + return esp_do_cmdbegin(esp); +} + +static int esp_enter_badphase(struct esp *esp) +{ + ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, + esp->sreg & ESP_STAT_PMASK)); + return do_reset_bus; +} + +typedef int (*espfunc_t)(struct esp *); + +static espfunc_t phase_vector[] = { + esp_do_data, /* ESP_DOP */ + esp_do_data, /* ESP_DIP */ + esp_enter_cmd, /* ESP_CMDP */ + esp_enter_status, /* ESP_STATP */ + esp_enter_badphase, /* ESP_STAT_PMSG */ + esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ + esp_enter_msgout, /* ESP_MOP */ + esp_enter_msgin, /* ESP_MIP */ +}; + +/* The target has control of the bus and we have to see where it has + * taken us. + */ +static int esp_do_phase_determine(struct esp *esp) +{ + if ((esp->ireg & ESP_INTR_DC) != 0) + return esp_disconnect_amidst_phases(esp); + return phase_vector[esp->sreg & ESP_STAT_PMASK](esp); +} + +/* First interrupt after exec'ing a cmd comes here. */ +static int esp_select_complete(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int cmd_bytes_sent, fcnt; + + if (esp->erev != fashme) + esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS); + + if (esp->erev == fashme) + fcnt = esp->hme_fifo_workaround_count; + else + fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES); + + cmd_bytes_sent = esp_bytes_sent(esp, fcnt); + dma_invalidate(esp); + + /* Let's check to see if a reselect happened + * while we we're trying to select. This must + * be checked first. + */ + if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { + esp_reconnect(esp, SCptr); + return esp_do_reconnect(esp); + } + + /* Looks like things worked, we should see a bus service & + * a function complete interrupt at this point. Note we + * are doing a direct comparison because we don't want to + * be fooled into thinking selection was successful if + * ESP_INTR_DC is set, see below. + */ + if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { + /* target speaks... */ + esp->targets_present |= (1<device->id); + + /* What if the target ignores the sdtr? */ + if (esp->snip) + esp_dev->sync = 1; + + /* See how far, if at all, we got in getting + * the information out to the target. + */ + switch (esp->seqreg) { + default: + + case ESP_STEP_ASEL: + /* Arbitration won, target selected, but + * we are in some phase which is not command + * phase nor is it message out phase. + * + * XXX We've confused the target, obviously. + * XXX So clear it's state, but we also end + * XXX up clearing everyone elses. That isn't + * XXX so nice. I'd like to just reset this + * XXX target, but if I cannot even get it's + * XXX attention and finish selection to talk + * XXX to it, there is not much more I can do. + * XXX If we have a loaded bus we're going to + * XXX spend the next second or so renegotiating + * XXX for synchronous transfers. + */ + ESPLOG(("esp%d: STEP_ASEL for tgt %d\n", + esp->esp_id, SCptr->device->id)); + + case ESP_STEP_SID: + /* Arbitration won, target selected, went + * to message out phase, sent one message + * byte, then we stopped. ATN is asserted + * on the SCSI bus and the target is still + * there hanging on. This is a legal + * sequence step if we gave the ESP a select + * and stop command. + * + * XXX See above, I could set the borken flag + * XXX in the device struct and retry the + * XXX command. But would that help for + * XXX tagged capable targets? + */ + + case ESP_STEP_NCMD: + /* Arbitration won, target selected, maybe + * sent the one message byte in message out + * phase, but we did not go to command phase + * in the end. Actually, we could have sent + * only some of the message bytes if we tried + * to send out the entire identify and tag + * message using ESP_CMD_SA3. + */ + cmd_bytes_sent = 0; + break; + + case ESP_STEP_PPC: + /* No, not the powerPC pinhead. Arbitration + * won, all message bytes sent if we went to + * message out phase, went to command phase + * but only part of the command was sent. + * + * XXX I've seen this, but usually in conjunction + * XXX with a gross error which appears to have + * XXX occurred between the time I told the + * XXX ESP to arbitrate and when I got the + * XXX interrupt. Could I have misloaded the + * XXX command bytes into the fifo? Actually, + * XXX I most likely missed a phase, and therefore + * XXX went into never never land and didn't even + * XXX know it. That was the old driver though. + * XXX What is even more peculiar is that the ESP + * XXX showed the proper function complete and + * XXX bus service bits in the interrupt register. + */ + + case ESP_STEP_FINI4: + case ESP_STEP_FINI5: + case ESP_STEP_FINI6: + case ESP_STEP_FINI7: + /* Account for the identify message */ + if (SCptr->SCp.phase == in_slct_norm) + cmd_bytes_sent -= 1; + }; + + if (esp->erev != fashme) + esp_cmd(esp, ESP_CMD_NULL); + + /* Be careful, we could really get fucked during synchronous + * data transfers if we try to flush the fifo now. + */ + if ((esp->erev != fashme) && /* not a Happy Meal and... */ + !fcnt && /* Fifo is empty and... */ + /* either we are not doing synchronous transfers or... */ + (!esp_dev->sync_max_offset || + /* We are not going into data in phase. */ + ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) + esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */ + + /* See how far we got if this is not a slow command. */ + if (!esp->esp_slowcmd) { + if (cmd_bytes_sent < 0) + cmd_bytes_sent = 0; + if (cmd_bytes_sent != SCptr->cmd_len) { + /* Crapola, mark it as a slowcmd + * so that we have some chance of + * keeping the command alive with + * good luck. + * + * XXX Actually, if we didn't send it all + * XXX this means either we didn't set things + * XXX up properly (driver bug) or the target + * XXX or the ESP detected parity on one of + * XXX the command bytes. This makes much + * XXX more sense, and therefore this code + * XXX should be changed to send out a + * XXX parity error message or if the status + * XXX register shows no parity error then + * XXX just expect the target to bring the + * XXX bus into message in phase so that it + * XXX can send us the parity error message. + * XXX SCSI sucks... + */ + esp->esp_slowcmd = 1; + esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]); + esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent); + } + } + + /* Now figure out where we went. */ + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp); + } + + /* Did the target even make it? */ + if (esp->ireg == ESP_INTR_DC) { + /* wheee... nobody there or they didn't like + * what we told it to do, clean up. + */ + + /* If anyone is off the bus, but working on + * a command in the background for us, tell + * the ESP to listen for them. + */ + if (esp->disconnected_SC) + esp_cmd(esp, ESP_CMD_ESEL); + + if (((1<device->id) & esp->targets_present) && + esp->seqreg != 0 && + (esp->cur_msgout[0] == EXTENDED_MESSAGE) && + (SCptr->SCp.phase == in_slct_msg || + SCptr->SCp.phase == in_slct_stop)) { + /* shit */ + esp->snip = 0; + ESPLOG(("esp%d: Failed synchronous negotiation for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; /* so we don't negotiate again */ + + /* Run the command again, this time though we + * won't try to negotiate for synchronous transfers. + * + * XXX I'd like to do something like send an + * XXX INITIATOR_ERROR or ABORT message to the + * XXX target to tell it, "Sorry I confused you, + * XXX please come back and I will be nicer next + * XXX time". But that requires having the target + * XXX on the bus, and it has dropped BSY on us. + */ + esp->current_SC = NULL; + esp_advance_phase(SCptr, not_issued); + prepend_SC(&esp->issue_SC, SCptr); + esp_exec_cmd(esp); + return do_intr_end; + } + + /* Ok, this is normal, this is what we see during boot + * or whenever when we are scanning the bus for targets. + * But first make sure that is really what is happening. + */ + if (((1<device->id) & esp->targets_present)) { + ESPLOG(("esp%d: Warning, live target %d not responding to " + "selection.\n", esp->esp_id, SCptr->device->id)); + + /* This _CAN_ happen. The SCSI standard states that + * the target is to _not_ respond to selection if + * _it_ detects bad parity on the bus for any reason. + * Therefore, we assume that if we've talked successfully + * to this target before, bad parity is the problem. + */ + esp_done(esp, (DID_PARITY << 16)); + } else { + /* Else, there really isn't anyone there. */ + ESPMISC(("esp: selection failure, maybe nobody there?\n")); + ESPMISC(("esp: target %d lun %d\n", + SCptr->device->id, SCptr->device->lun)); + esp_done(esp, (DID_BAD_TARGET << 16)); + } + return do_intr_end; + } + + ESPLOG(("esp%d: Selection failure.\n", esp->esp_id)); + printk("esp%d: Currently -- ", esp->esp_id); + esp_print_ireg(esp->ireg); printk(" "); + esp_print_statreg(esp->sreg); printk(" "); + esp_print_seqreg(esp->seqreg); printk("\n"); + printk("esp%d: New -- ", esp->esp_id); + esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); + esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP); + esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); + esp_print_ireg(esp->ireg); printk(" "); + esp_print_statreg(esp->sreg); printk(" "); + esp_print_seqreg(esp->seqreg); printk("\n"); + ESPLOG(("esp%d: resetting bus\n", esp->esp_id)); + return do_reset_bus; /* ugh... */ +} + +/* Continue reading bytes for msgin phase. */ +static int esp_do_msgincont(struct esp *esp) +{ + if (esp->ireg & ESP_INTR_BSERV) { + /* in the right phase too? */ + if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) { + /* phew... */ + esp_cmd(esp, ESP_CMD_TI); + esp_advance_phase(esp->current_SC, in_msgindone); + return do_intr_end; + } + + /* We changed phase but ESP shows bus service, + * in this case it is most likely that we, the + * hacker who has been up for 20hrs straight + * staring at the screen, drowned in coffee + * smelling like retched cigarette ashes + * have miscoded something..... so, try to + * recover as best we can. + */ + ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); + } + esp_advance_phase(esp->current_SC, in_the_dark); + return do_phase_determine; +} + +static int check_singlebyte_msg(struct esp *esp) +{ + esp->prevmsgin = esp->cur_msgin[0]; + if (esp->cur_msgin[0] & 0x80) { + /* wheee... */ + ESPLOG(("esp%d: target sends identify amidst phases\n", + esp->esp_id)); + esp_advance_phase(esp->current_SC, in_the_dark); + return 0; + } else if (((esp->cur_msgin[0] & 0xf0) == 0x20) || + (esp->cur_msgin[0] == EXTENDED_MESSAGE)) { + esp->msgin_len = 2; + esp_advance_phase(esp->current_SC, in_msgincont); + return 0; + } + esp_advance_phase(esp->current_SC, in_the_dark); + switch (esp->cur_msgin[0]) { + default: + /* We don't want to hear about it. */ + ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id, + esp->cur_msgin[0])); + return MESSAGE_REJECT; + + case NOP: + ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id, + esp->current_SC->device->id)); + return 0; + + case RESTORE_POINTERS: + /* In this case we might also have to backup the + * "slow command" pointer. It is rare to get such + * a save/restore pointer sequence so early in the + * bus transition sequences, but cover it. + */ + if (esp->esp_slowcmd) { + esp->esp_scmdleft = esp->current_SC->cmd_len; + esp->esp_scmdp = &esp->current_SC->cmnd[0]; + } + esp_restore_pointers(esp, esp->current_SC); + return 0; + + case SAVE_POINTERS: + esp_save_pointers(esp, esp->current_SC); + return 0; + + case COMMAND_COMPLETE: + case DISCONNECT: + /* Freeing the bus, let it go. */ + esp->current_SC->SCp.phase = in_freeing; + return 0; + + case MESSAGE_REJECT: + ESPMISC(("msg reject, ")); + if (esp->prevmsgout == EXTENDED_MESSAGE) { + struct esp_device *esp_dev = esp->current_SC->device->hostdata; + + /* Doesn't look like this target can + * do synchronous or WIDE transfers. + */ + ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n")); + esp_dev->sync = 1; + esp_dev->wide = 1; + esp_dev->sync_min_period = 0; + esp_dev->sync_max_offset = 0; + return 0; + } else { + ESPMISC(("not sync nego, sending ABORT\n")); + return ABORT; + } + }; +} + +/* Target negotiates for synchronous transfers before we do, this + * is legal although very strange. What is even funnier is that + * the SCSI2 standard specifically recommends against targets doing + * this because so many initiators cannot cope with this occurring. + */ +static int target_with_ants_in_pants(struct esp *esp, + struct scsi_cmnd *SCptr, + struct esp_device *esp_dev) +{ + if (esp_dev->sync || SCptr->device->borken) { + /* sorry, no can do */ + ESPSDTR(("forcing to async, ")); + build_sync_nego_msg(esp, 0, 0); + esp_dev->sync = 1; + esp->snip = 1; + ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + /* Ok, we'll check them out... */ + return 0; +} + +static void sync_report(struct esp *esp) +{ + int msg3, msg4; + char *type; + + msg3 = esp->cur_msgin[3]; + msg4 = esp->cur_msgin[4]; + if (msg4) { + int hz = 1000000000 / (msg3 * 4); + int integer = hz / 1000000; + int fraction = (hz - (integer * 1000000)) / 10000; + if ((esp->erev == fashme) && + (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) { + type = "FAST-WIDE"; + integer <<= 1; + fraction <<= 1; + } else if ((msg3 * 4) < 200) { + type = "FAST"; + } else { + type = "synchronous"; + } + + /* Do not transform this back into one big printk + * again, it triggers a bug in our sparc64-gcc272 + * sibling call optimization. -DaveM + */ + ESPLOG((KERN_INFO "esp%d: target %d ", + esp->esp_id, esp->current_SC->device->id)); + ESPLOG(("[period %dns offset %d %d.%02dMHz ", + (int) msg3 * 4, (int) msg4, + integer, fraction)); + ESPLOG(("%s SCSI%s]\n", type, + (((msg3 * 4) < 200) ? "-II" : ""))); + } else { + ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", + esp->esp_id, esp->current_SC->device->id)); + } +} + +static int check_multibyte_msg(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + u8 regval = 0; + int message_out = 0; + + ESPSDTR(("chk multibyte msg: ")); + if (esp->cur_msgin[2] == EXTENDED_SDTR) { + int period = esp->cur_msgin[3]; + int offset = esp->cur_msgin[4]; + + ESPSDTR(("is sync nego response, ")); + if (!esp->snip) { + int rval; + + /* Target negotiates first! */ + ESPSDTR(("target jumps the gun, ")); + message_out = EXTENDED_MESSAGE; /* we must respond */ + rval = target_with_ants_in_pants(esp, SCptr, esp_dev); + if (rval) + return rval; + } + + ESPSDTR(("examining sdtr, ")); + + /* Offset cannot be larger than ESP fifo size. */ + if (offset > 15) { + ESPSDTR(("offset too big %2x, ", offset)); + offset = 15; + ESPSDTR(("sending back new offset\n")); + build_sync_nego_msg(esp, period, offset); + return EXTENDED_MESSAGE; + } + + if (offset && period > esp->max_period) { + /* Yeee, async for this slow device. */ + ESPSDTR(("period too long %2x, ", period)); + build_sync_nego_msg(esp, 0, 0); + ESPSDTR(("hoping for msgout\n")); + esp_advance_phase(esp->current_SC, in_the_dark); + return EXTENDED_MESSAGE; + } else if (offset && period < esp->min_period) { + ESPSDTR(("period too short %2x, ", period)); + period = esp->min_period; + if (esp->erev > esp236) + regval = 4; + else + regval = 5; + } else if (offset) { + int tmp; + + ESPSDTR(("period is ok, ")); + tmp = esp->ccycle / 1000; + regval = (((period << 2) + tmp - 1) / tmp); + if (regval && ((esp->erev == fas100a || + esp->erev == fas236 || + esp->erev == fashme))) { + if (period >= 50) + regval--; + } + } + + if (offset) { + u8 bit; + + esp_dev->sync_min_period = (regval & 0x1f); + esp_dev->sync_max_offset = (offset | esp->radelay); + if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) { + if ((esp->erev == fas100a) || (esp->erev == fashme)) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + if (period < 50) { + /* On FAS366, if using fast-20 synchronous transfers + * we need to make sure the REQ/ACK assert/deassert + * control bits are clear. + */ + if (esp->erev == fashme) + esp_dev->sync_max_offset &= ~esp->radelay; + esp->config3[SCptr->device->id] |= bit; + } else { + esp->config3[SCptr->device->id] &= ~bit; + } + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + } + esp->prev_soff = esp_dev->sync_max_offset; + esp->prev_stp = esp_dev->sync_min_period; + sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); + sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); + ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", + esp_dev->sync_max_offset, + esp_dev->sync_min_period, + esp->config3[SCptr->device->id])); + + esp->snip = 0; + } else if (esp_dev->sync_max_offset) { + u8 bit; + + /* back to async mode */ + ESPSDTR(("unaccaptable sync nego, forcing async\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp->prev_soff = 0; + esp->prev_stp = 0; + sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); + sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); + if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) { + if ((esp->erev == fas100a) || (esp->erev == fashme)) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + esp->config3[SCptr->device->id] &= ~bit; + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + } + } + + sync_report(esp); + + ESPSDTR(("chk multibyte msg: sync is known, ")); + esp_dev->sync = 1; + + if (message_out) { + ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n", + esp->esp_id)); + build_sync_nego_msg(esp, period, offset); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + ESPSDTR(("returning zero\n")); + esp_advance_phase(SCptr, in_the_dark); /* ...or else! */ + return 0; + } else if (esp->cur_msgin[2] == EXTENDED_WDTR) { + int size = 8 << esp->cur_msgin[3]; + + esp->wnip = 0; + if (esp->erev != fashme) { + ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n", + esp->esp_id)); + message_out = MESSAGE_REJECT; + } else if (size > 16) { + ESPLOG(("esp%d: AIEEE wide transfer for %d size " + "not supported.\n", esp->esp_id, size)); + message_out = MESSAGE_REJECT; + } else { + /* Things look good; let's see what we got. */ + if (size == 16) { + /* Set config 3 register for this target. */ + esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE; + } else { + /* Just make sure it was one byte sized. */ + if (size != 8) { + ESPLOG(("esp%d: Aieee, wide nego of %d size.\n", + esp->esp_id, size)); + message_out = MESSAGE_REJECT; + goto finish; + } + /* Pure paranoia. */ + esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE); + } + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); + + /* Regardless, next try for sync transfers. */ + build_sync_nego_msg(esp, esp->sync_defp, 15); + esp_dev->sync = 1; + esp->snip = 1; + message_out = EXTENDED_MESSAGE; + } + } else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) { + ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id)); + message_out = MESSAGE_REJECT; + } +finish: + esp_advance_phase(SCptr, in_the_dark); + return message_out; +} + +static int esp_do_msgindone(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + int message_out = 0, it = 0, rval; + + rval = skipahead1(esp, SCptr, in_msgin, in_msgindone); + if (rval) + return rval; + if (SCptr->SCp.sent_command != in_status) { + if (!(esp->ireg & ESP_INTR_DC)) { + if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) { + message_out = MSG_PARITY_ERROR; + esp_cmd(esp, ESP_CMD_FLUSH); + } else if (esp->erev != fashme && + (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) { + /* We certainly dropped the ball somewhere. */ + message_out = INITIATOR_ERROR; + esp_cmd(esp, ESP_CMD_FLUSH); + } else if (!esp->msgin_len) { + if (esp->erev == fashme) + it = esp->hme_fifo_workaround_buffer[0]; + else + it = sbus_readb(esp->eregs + ESP_FDATA); + esp_advance_phase(SCptr, in_msgincont); + } else { + /* it is ok and we want it */ + if (esp->erev == fashme) + it = esp->cur_msgin[esp->msgin_ctr] = + esp->hme_fifo_workaround_buffer[0]; + else + it = esp->cur_msgin[esp->msgin_ctr] = + sbus_readb(esp->eregs + ESP_FDATA); + esp->msgin_ctr++; + } + } else { + esp_advance_phase(SCptr, in_the_dark); + return do_work_bus; + } + } else { + it = esp->cur_msgin[0]; + } + if (!message_out && esp->msgin_len) { + if (esp->msgin_ctr < esp->msgin_len) { + esp_advance_phase(SCptr, in_msgincont); + } else if (esp->msgin_len == 1) { + message_out = check_singlebyte_msg(esp); + } else if (esp->msgin_len == 2) { + if (esp->cur_msgin[0] == EXTENDED_MESSAGE) { + if ((it + 2) >= 15) { + message_out = MESSAGE_REJECT; + } else { + esp->msgin_len = (it + 2); + esp_advance_phase(SCptr, in_msgincont); + } + } else { + message_out = MESSAGE_REJECT; /* foo on you */ + } + } else { + message_out = check_multibyte_msg(esp); + } + } + if (message_out < 0) { + return -message_out; + } else if (message_out) { + if (((message_out != 1) && + ((message_out < 0x20) || (message_out & 0x80)))) + esp->msgout_len = 1; + esp->cur_msgout[0] = message_out; + esp_cmd(esp, ESP_CMD_SATN); + esp_advance_phase(SCptr, in_the_dark); + esp->msgin_len = 0; + } + esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); + esp->sreg &= ~(ESP_STAT_INTR); + if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD)) + esp_cmd(esp, ESP_CMD_MOK); + if ((SCptr->SCp.sent_command == in_msgindone) && + (SCptr->SCp.phase == in_freeing)) + return esp_do_freebus(esp); + return do_intr_end; +} + +static int esp_do_cmdbegin(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + + esp_advance_phase(SCptr, in_cmdend); + if (esp->erev == fashme) { + u32 tmp = sbus_readl(esp->dregs + DMA_CSR); + int i; + + for (i = 0; i < esp->esp_scmdleft; i++) + esp->esp_command[i] = *esp->esp_scmdp++; + esp->esp_scmdleft = 0; + esp_cmd(esp, ESP_CMD_FLUSH); + esp_setcount(esp->eregs, i, 1); + esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI)); + tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); + tmp &= ~(DMA_ST_WRITE); + sbus_writel(i, esp->dregs + DMA_COUNT); + sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR); + sbus_writel(tmp, esp->dregs + DMA_CSR); + } else { + u8 tmp; + + esp_cmd(esp, ESP_CMD_FLUSH); + tmp = *esp->esp_scmdp++; + esp->esp_scmdleft--; + sbus_writeb(tmp, esp->eregs + ESP_FDATA); + esp_cmd(esp, ESP_CMD_TI); + } + return do_intr_end; +} + +static int esp_do_cmddone(struct esp *esp) +{ + if (esp->erev == fashme) + dma_invalidate(esp); + else + esp_cmd(esp, ESP_CMD_NULL); + + if (esp->ireg & ESP_INTR_BSERV) { + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp); + } + + ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n", + esp->esp_id)); + return do_reset_bus; +} + +static int esp_do_msgout(struct esp *esp) +{ + esp_cmd(esp, ESP_CMD_FLUSH); + switch (esp->msgout_len) { + case 1: + if (esp->erev == fashme) + hme_fifo_push(esp, &esp->cur_msgout[0], 1); + else + sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA); + + esp_cmd(esp, ESP_CMD_TI); + break; + + case 2: + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + + if (esp->erev == fashme) { + hme_fifo_push(esp, &esp->cur_msgout[0], 2); + esp_cmd(esp, ESP_CMD_TI); + } else { + dma_setup(esp, esp->esp_command_dvma, 2, 0); + esp_setcount(esp->eregs, 2, 0); + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 4: + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->snip = 1; + + if (esp->erev == fashme) { + hme_fifo_push(esp, &esp->cur_msgout[0], 4); + esp_cmd(esp, ESP_CMD_TI); + } else { + dma_setup(esp, esp->esp_command_dvma, 4, 0); + esp_setcount(esp->eregs, 4, 0); + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 5: + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->esp_command[4] = esp->cur_msgout[4]; + esp->snip = 1; + + if (esp->erev == fashme) { + hme_fifo_push(esp, &esp->cur_msgout[0], 5); + esp_cmd(esp, ESP_CMD_TI); + } else { + dma_setup(esp, esp->esp_command_dvma, 5, 0); + esp_setcount(esp->eregs, 5, 0); + esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + default: + /* whoops */ + ESPMISC(("bogus msgout sending NOP\n")); + esp->cur_msgout[0] = NOP; + + if (esp->erev == fashme) { + hme_fifo_push(esp, &esp->cur_msgout[0], 1); + } else { + sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA); + } + + esp->msgout_len = 1; + esp_cmd(esp, ESP_CMD_TI); + break; + }; + + esp_advance_phase(esp->current_SC, in_msgoutdone); + return do_intr_end; +} + +static int esp_do_msgoutdone(struct esp *esp) +{ + if (esp->msgout_len > 1) { + /* XXX HME/FAS ATN deassert workaround required, + * XXX no DMA flushing, only possible ESP_CMD_FLUSH + * XXX to kill the fifo. + */ + if (esp->erev != fashme) { + u32 tmp; + + while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ) + udelay(1); + tmp &= ~DMA_ENABLE; + sbus_writel(tmp, esp->dregs + DMA_CSR); + dma_invalidate(esp); + } else { + esp_cmd(esp, ESP_CMD_FLUSH); + } + } + if (!(esp->ireg & ESP_INTR_DC)) { + if (esp->erev != fashme) + esp_cmd(esp, ESP_CMD_NULL); + switch (esp->sreg & ESP_STAT_PMASK) { + case ESP_MOP: + /* whoops, parity error */ + ESPLOG(("esp%d: still in msgout, parity error assumed\n", + esp->esp_id)); + if (esp->msgout_len > 1) + esp_cmd(esp, ESP_CMD_SATN); + esp_advance_phase(esp->current_SC, in_msgout); + return do_work_bus; + + case ESP_DIP: + break; + + default: + /* Happy Meal fifo is touchy... */ + if ((esp->erev != fashme) && + !fcount(esp) && + !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset)) + esp_cmd(esp, ESP_CMD_FLUSH); + break; + + }; + } else { + ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id)); + return do_reset_bus; + } + + /* If we sent out a synchronous negotiation message, update + * our state. + */ + if (esp->cur_msgout[2] == EXTENDED_MESSAGE && + esp->cur_msgout[4] == EXTENDED_SDTR) { + esp->snip = 1; /* anal retentiveness... */ + } + + esp->prevmsgout = esp->cur_msgout[0]; + esp->msgout_len = 0; + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp); +} + +static int esp_bus_unexpected(struct esp *esp) +{ + ESPLOG(("esp%d: command in weird state %2x\n", + esp->esp_id, esp->current_SC->SCp.phase)); + return do_reset_bus; +} + +static espfunc_t bus_vector[] = { + esp_do_data_finale, + esp_do_data_finale, + esp_bus_unexpected, + esp_do_msgin, + esp_do_msgincont, + esp_do_msgindone, + esp_do_msgout, + esp_do_msgoutdone, + esp_do_cmdbegin, + esp_do_cmddone, + esp_do_status, + esp_do_freebus, + esp_do_phase_determine, + esp_bus_unexpected, + esp_bus_unexpected, + esp_bus_unexpected, +}; + +/* This is the second tier in our dual-level SCSI state machine. */ +static int esp_work_bus(struct esp *esp) +{ + struct scsi_cmnd *SCptr = esp->current_SC; + unsigned int phase; + + ESPBUS(("esp_work_bus: ")); + if (!SCptr) { + ESPBUS(("reconnect\n")); + return esp_do_reconnect(esp); + } + phase = SCptr->SCp.phase; + if ((phase & 0xf0) == in_phases_mask) + return bus_vector[(phase & 0x0f)](esp); + else if ((phase & 0xf0) == in_slct_mask) + return esp_select_complete(esp); + else + return esp_bus_unexpected(esp); +} + +static espfunc_t isvc_vector[] = { + NULL, + esp_do_phase_determine, + esp_do_resetbus, + esp_finish_reset, + esp_work_bus +}; + +/* Main interrupt handler for an esp adapter. */ +static void esp_handle(struct esp *esp) +{ + struct scsi_cmnd *SCptr; + int what_next = do_intr_end; + + SCptr = esp->current_SC; + + /* Check for errors. */ + esp->sreg = sbus_readb(esp->eregs + ESP_STATUS); + esp->sreg &= (~ESP_STAT_INTR); + if (esp->erev == fashme) { + esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2); + esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS); + } + + if (esp->sreg & (ESP_STAT_SPAM)) { + /* Gross error, could be due to one of: + * + * - top of fifo overwritten, could be because + * we tried to do a synchronous transfer with + * an offset greater than ESP fifo size + * + * - top of command register overwritten + * + * - DMA setup to go in one direction, SCSI + * bus points in the other, whoops + * + * - weird phase change during asynchronous + * data phase while we are initiator + */ + ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg)); + + /* If a command is live on the bus we cannot safely + * reset the bus, so we'll just let the pieces fall + * where they may. Here we are hoping that the + * target will be able to cleanly go away soon + * so we can safely reset things. + */ + if (!SCptr) { + ESPLOG(("esp%d: No current cmd during gross error, " + "resetting bus\n", esp->esp_id)); + what_next = do_reset_bus; + goto state_machine; + } + } + + if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) { + /* A DMA gate array error. Here we must + * be seeing one of two things. Either the + * virtual to physical address translation + * on the SBUS could not occur, else the + * translation it did get pointed to a bogus + * page. Ho hum... + */ + ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id, + sbus_readl(esp->dregs + DMA_CSR))); + + /* DMA gate array itself must be reset to clear the + * error condition. + */ + esp_reset_dma(esp); + + what_next = do_reset_bus; + goto state_machine; + } + + esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); /* Unlatch intr reg */ + + if (esp->erev == fashme) { + /* This chip is really losing. */ + ESPHME(("HME[")); + + ESPHME(("sreg2=%02x,", esp->sreg2)); + /* Must latch fifo before reading the interrupt + * register else garbage ends up in the FIFO + * which confuses the driver utterly. + */ + if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) { + ESPHME(("fifo_workaround]")); + hme_fifo_read(esp); + } else { + ESPHME(("no_fifo_workaround]")); + } + } + + /* No current cmd is only valid at this point when there are + * commands off the bus or we are trying a reset. + */ + if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) { + /* Panic is safe, since current_SC is null. */ + ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id)); + panic("esp_handle: current_SC == penguin within interrupt!"); + } + + if (esp->ireg & (ESP_INTR_IC)) { + /* Illegal command fed to ESP. Outside of obvious + * software bugs that could cause this, there is + * a condition with esp100 where we can confuse the + * ESP into an erroneous illegal command interrupt + * because it does not scrape the FIFO properly + * for reselection. See esp100_reconnect_hwbug() + * to see how we try very hard to avoid this. + */ + ESPLOG(("esp%d: invalid command\n", esp->esp_id)); + + esp_dump_state(esp); + + if (SCptr != NULL) { + /* Devices with very buggy firmware can drop BSY + * during a scatter list interrupt when using sync + * mode transfers. We continue the transfer as + * expected, the target drops the bus, the ESP + * gets confused, and we get a illegal command + * interrupt because the bus is in the disconnected + * state now and ESP_CMD_TI is only allowed when + * a nexus is alive on the bus. + */ + ESPLOG(("esp%d: Forcing async and disabling disconnect for " + "target %d\n", esp->esp_id, SCptr->device->id)); + SCptr->device->borken = 1; /* foo on you */ + } + + what_next = do_reset_bus; + } else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { + if (SCptr) { + unsigned int phase = SCptr->SCp.phase; + + if (phase & in_phases_mask) { + what_next = esp_work_bus(esp); + } else if (phase & in_slct_mask) { + what_next = esp_select_complete(esp); + } else { + ESPLOG(("esp%d: interrupt for no good reason...\n", + esp->esp_id)); + what_next = do_intr_end; + } + } else { + ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } else if (esp->ireg & ESP_INTR_SR) { + ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); + what_next = do_reset_complete; + } else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) { + ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", + esp->esp_id)); + what_next = do_reset_bus; + } else if (esp->ireg & ESP_INTR_RSEL) { + if (SCptr == NULL) { + /* This is ok. */ + what_next = esp_do_reconnect(esp); + } else if (SCptr->SCp.phase & in_slct_mask) { + /* Only selection code knows how to clean + * up properly. + */ + ESPDISC(("Reselected during selection attempt\n")); + what_next = esp_select_complete(esp); + } else { + ESPLOG(("esp%d: Reselected while bus is busy\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } + + /* This is tier-one in our dual level SCSI state machine. */ +state_machine: + while (what_next != do_intr_end) { + if (what_next >= do_phase_determine && + what_next < do_intr_end) { + what_next = isvc_vector[what_next](esp); + } else { + /* state is completely lost ;-( */ + ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } +} + +/* Service only the ESP described by dev_id. */ +static irqreturn_t esp_intr(int irq, void *dev_id) +{ + struct esp *esp = dev_id; + unsigned long flags; + + spin_lock_irqsave(esp->ehost->host_lock, flags); + if (ESP_IRQ_P(esp->dregs)) { + ESP_INTSOFF(esp->dregs); + + ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + ESP_INTSON(esp->dregs); + } + spin_unlock_irqrestore(esp->ehost->host_lock, flags); + + return IRQ_HANDLED; +} + +static int esp_slave_alloc(struct scsi_device *SDptr) +{ + struct esp_device *esp_dev = + kmalloc(sizeof(struct esp_device), GFP_ATOMIC); + + if (!esp_dev) + return -ENOMEM; + memset(esp_dev, 0, sizeof(struct esp_device)); + SDptr->hostdata = esp_dev; + return 0; +} + +static void esp_slave_destroy(struct scsi_device *SDptr) +{ + struct esp *esp = (struct esp *) SDptr->host->hostdata; + + esp->targets_present &= ~(1 << SDptr->id); + kfree(SDptr->hostdata); + SDptr->hostdata = NULL; +} + +static struct scsi_host_template esp_template = { + .module = THIS_MODULE, + .name = "esp", + .info = esp_info, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING, + .proc_name = "esp", + .proc_info = esp_proc_info, +}; + +#ifndef CONFIG_SUN4 +static struct of_device_id esp_match[] = { + { + .name = "SUNW,esp", + .data = &esp_template, + }, + { + .name = "SUNW,fas", + .data = &esp_template, + }, + { + .name = "esp", + .data = &esp_template, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, esp_match); + +static struct of_platform_driver esp_sbus_driver = { + .name = "esp", + .match_table = esp_match, + .probe = esp_sbus_probe, + .remove = __devexit_p(esp_sbus_remove), +}; +#endif + +static int __init esp_init(void) +{ +#ifdef CONFIG_SUN4 + return esp_sun4_probe(&esp_template); +#else + return of_register_driver(&esp_sbus_driver, &sbus_bus_type); +#endif +} + +static void __exit esp_exit(void) +{ +#ifdef CONFIG_SUN4 + esp_sun4_remove(); +#else + of_unregister_driver(&esp_sbus_driver); +#endif +} + +MODULE_DESCRIPTION("ESP Sun SCSI driver"); +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(esp_init); +module_exit(esp_exit); diff --git a/trunk/drivers/scsi/esp.h b/trunk/drivers/scsi/esp.h new file mode 100644 index 000000000000..a98cda9121fc --- /dev/null +++ b/trunk/drivers/scsi/esp.h @@ -0,0 +1,406 @@ +/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $ + * esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI + * Processor) driver under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_ESP_H +#define _SPARC_ESP_H + +/* For dvma controller register definitions. */ +#include + +/* The ESP SCSI controllers have their register sets in three + * "classes": + * + * 1) Registers which are both read and write. + * 2) Registers which are read only. + * 3) Registers which are write only. + * + * Yet, they all live within the same IO space. + */ + +/* All the ESP registers are one byte each and are accessed longwords + * apart with a big-endian ordering to the bytes. + */ + /* Access Description Offset */ +#define ESP_TCLOW 0x00UL /* rw Low bits of the transfer count 0x00 */ +#define ESP_TCMED 0x04UL /* rw Mid bits of the transfer count 0x04 */ +#define ESP_FDATA 0x08UL /* rw FIFO data bits 0x08 */ +#define ESP_CMD 0x0cUL /* rw SCSI command bits 0x0c */ +#define ESP_STATUS 0x10UL /* ro ESP status register 0x10 */ +#define ESP_BUSID ESP_STATUS /* wo Bus ID for select/reselect 0x10 */ +#define ESP_INTRPT 0x14UL /* ro Kind of interrupt 0x14 */ +#define ESP_TIMEO ESP_INTRPT /* wo Timeout value for select/resel 0x14 */ +#define ESP_SSTEP 0x18UL /* ro Sequence step register 0x18 */ +#define ESP_STP ESP_SSTEP /* wo Transfer period per sync 0x18 */ +#define ESP_FFLAGS 0x1cUL /* ro Bits of current FIFO info 0x1c */ +#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */ +#define ESP_CFG1 0x20UL /* rw First configuration register 0x20 */ +#define ESP_CFACT 0x24UL /* wo Clock conversion factor 0x24 */ +#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */ +#define ESP_CTEST 0x28UL /* wo Chip test register 0x28 */ +#define ESP_CFG2 0x2cUL /* rw Second configuration register 0x2c */ +#define ESP_CFG3 0x30UL /* rw Third configuration register 0x30 */ +#define ESP_TCHI 0x38UL /* rw High bits of transfer count 0x38 */ +#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */ +#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */ +#define ESP_FGRND 0x3cUL /* rw Data base for fifo 0x3c */ +#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */ +#define ESP_REG_SIZE 0x40UL + +/* Various revisions of the ESP board. */ +enum esp_rev { + esp100 = 0x00, /* NCR53C90 - very broken */ + esp100a = 0x01, /* NCR53C90A */ + esp236 = 0x02, + fas236 = 0x03, + fas100a = 0x04, + fast = 0x05, + fashme = 0x06, + espunknown = 0x07 +}; + +/* We allocate one of these for each scsi device and attach it to + * SDptr->hostdata for use in the driver + */ +struct esp_device { + unsigned char sync_min_period; + unsigned char sync_max_offset; + unsigned sync:1; + unsigned wide:1; + unsigned disconnect:1; +}; + +struct scsi_cmnd; + +/* We get one of these for each ESP probed. */ +struct esp { + void __iomem *eregs; /* ESP controller registers */ + void __iomem *dregs; /* DMA controller registers */ + struct sbus_dma *dma; /* DMA controller sw state */ + struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ + struct sbus_dev *sdev; /* Pointer to SBus entry */ + + /* ESP Configuration Registers */ + u8 config1; /* Copy of the 1st config register */ + u8 config2; /* Copy of the 2nd config register */ + u8 config3[16]; /* Copy of the 3rd config register */ + + /* The current command we are sending to the ESP chip. This esp_command + * ptr needs to be mapped in DVMA area so we can send commands and read + * from the ESP fifo without burning precious CPU cycles. Programmed I/O + * sucks when we have the DVMA to do it for us. The ESP is stupid and will + * only send out 6, 10, and 12 byte SCSI commands, others we need to send + * one byte at a time. esp_slowcmd being set says that we are doing one + * of the command types ESP doesn't understand, esp_scmdp keeps track of + * which byte we are sending, esp_scmdleft says how many bytes to go. + */ + volatile u8 *esp_command; /* Location of command (CPU view) */ + __u32 esp_command_dvma;/* Location of command (DVMA view) */ + unsigned char esp_clen; /* Length of this command */ + unsigned char esp_slowcmd; + unsigned char *esp_scmdp; + unsigned char esp_scmdleft; + + /* The following are used to determine the cause of an IRQ. Upon every + * IRQ entry we synchronize these with the hardware registers. + */ + u8 ireg; /* Copy of ESP interrupt register */ + u8 sreg; /* Copy of ESP status register */ + u8 seqreg; /* Copy of ESP sequence step register */ + u8 sreg2; /* Copy of HME status2 register */ + + /* To save register writes to the ESP, which can be expensive, we + * keep track of the previous value that various registers had for + * the last target we connected to. If they are the same for the + * current target, we skip the register writes as they are not needed. + */ + u8 prev_soff, prev_stp; + u8 prev_cfg3, __cache_pad; + + /* We also keep a cache of the previous FAS/HME DMA CSR register value. */ + u32 prev_hme_dmacsr; + + /* The HME is the biggest piece of shit I have ever seen. */ + u8 hme_fifo_workaround_buffer[16 * 2]; + u8 hme_fifo_workaround_count; + + /* For each target we keep track of save/restore data + * pointer information. This needs to be updated majorly + * when we add support for tagged queueing. -DaveM + */ + struct esp_pointers { + char *saved_ptr; + struct scatterlist *saved_buffer; + int saved_this_residual; + int saved_buffers_residual; + } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; + + /* Clock periods, frequencies, synchronization, etc. */ + unsigned int cfreq; /* Clock frequency in HZ */ + unsigned int cfact; /* Clock conversion factor */ + unsigned int raw_cfact; /* Raw copy from probing */ + unsigned int ccycle; /* One ESP clock cycle */ + unsigned int ctick; /* One ESP clock time */ + unsigned int radelay; /* FAST chip req/ack delay */ + unsigned int neg_defp; /* Default negotiation period */ + unsigned int sync_defp; /* Default sync transfer period */ + unsigned int max_period; /* longest our period can be */ + unsigned int min_period; /* shortest period we can withstand */ + + struct esp *next; /* Next ESP we probed or NULL */ + char prom_name[64]; /* Name of ESP device from prom */ + int prom_node; /* Prom node where ESP found */ + int esp_id; /* Unique per-ESP ID number */ + + /* For slow to medium speed input clock rates we shoot for 5mb/s, + * but for high input clock rates we try to do 10mb/s although I + * don't think a transfer can even run that fast with an ESP even + * with DMA2 scatter gather pipelining. + */ +#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ +#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ + + unsigned int snip; /* Sync. negotiation in progress */ + unsigned int wnip; /* WIDE negotiation in progress */ + unsigned int targets_present;/* targets spoken to before */ + + int current_transfer_size; /* Set at beginning of data dma */ + + u8 espcmdlog[32]; /* Log of current esp cmds sent. */ + u8 espcmdent; /* Current entry in esp cmd log. */ + + /* Misc. info about this ESP */ + enum esp_rev erev; /* ESP revision */ + int irq; /* SBus IRQ for this ESP */ + int scsi_id; /* Who am I as initiator? */ + int scsi_id_mask; /* Bitmask of 'me'. */ + int diff; /* Differential SCSI bus? */ + int bursts; /* Burst sizes our DVMA supports */ + + /* Our command queues, only one cmd lives in the current_SC queue. */ + struct scsi_cmnd *issue_SC; /* Commands to be issued */ + struct scsi_cmnd *current_SC; /* Who is currently working the bus */ + struct scsi_cmnd *disconnected_SC;/* Commands disconnected from the bus */ + + /* Message goo */ + u8 cur_msgout[16]; + u8 cur_msgin[16]; + u8 prevmsgout, prevmsgin; + u8 msgout_len, msgin_len; + u8 msgout_ctr, msgin_ctr; + + /* States that we cannot keep in the per cmd structure because they + * cannot be assosciated with any specific command. + */ + u8 resetting_bus; + wait_queue_head_t reset_queue; +}; + +/* Bitfield meanings for the above registers. */ + +/* ESP config reg 1, read-write, found on all ESP chips */ +#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ +#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ +#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ +#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ +#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ +#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ + +/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ +#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */ +#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */ +#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ +#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */ +#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ +#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ +#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ +#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */ +#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */ +#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ +#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */ +#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */ +#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ + +/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */ +#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */ +#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ +#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */ +#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ +#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */ +#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ +#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */ +#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ +#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ +#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ +#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ +#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ +#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ +#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ +#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ +#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ + +/* ESP command register read-write */ +/* Group 1 commands: These may be sent at any point in time to the ESP + * chip. None of them can generate interrupts 'cept + * the "SCSI bus reset" command if you have not disabled + * SCSI reset interrupts in the config1 ESP register. + */ +#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ +#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ +#define ESP_CMD_RC 0x02 /* Chip reset */ +#define ESP_CMD_RS 0x03 /* SCSI bus reset */ + +/* Group 2 commands: ESP must be an initiator and connected to a target + * for these commands to work. + */ +#define ESP_CMD_TI 0x10 /* Transfer Information */ +#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ +#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ +#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ +#define ESP_CMD_SATN 0x1a /* Set ATN */ +#define ESP_CMD_RATN 0x1b /* De-assert ATN */ + +/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected + * to a target as the initiator for these commands to work. + */ +#define ESP_CMD_SMSG 0x20 /* Send message */ +#define ESP_CMD_SSTAT 0x21 /* Send status */ +#define ESP_CMD_SDATA 0x22 /* Send data */ +#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ +#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ +#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ +#define ESP_CMD_DCNCT 0x27 /* Disconnect */ +#define ESP_CMD_RMSG 0x28 /* Receive Message */ +#define ESP_CMD_RCMD 0x29 /* Receive Command */ +#define ESP_CMD_RDATA 0x2a /* Receive Data */ +#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ + +/* Group 4 commands: The ESP must be in the disconnected state and must + * not be connected to any targets as initiator for + * these commands to work. + */ +#define ESP_CMD_RSEL 0x40 /* Reselect */ +#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ +#define ESP_CMD_SELA 0x42 /* Select w/ATN */ +#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ +#define ESP_CMD_ESEL 0x44 /* Enable selection */ +#define ESP_CMD_DSEL 0x45 /* Disable selections */ +#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ +#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ + +/* This bit enables the ESP's DMA on the SBus */ +#define ESP_CMD_DMA 0x80 /* Do DMA? */ + + +/* ESP status register read-only */ +#define ESP_STAT_PIO 0x01 /* IO phase bit */ +#define ESP_STAT_PCD 0x02 /* CD phase bit */ +#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ +#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ +#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ +#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ +#define ESP_STAT_PERR 0x20 /* Parity error */ +#define ESP_STAT_SPAM 0x40 /* Real bad error */ +/* This indicates the 'interrupt pending' condition on esp236, it is a reserved + * bit on other revs of the ESP. + */ +#define ESP_STAT_INTR 0x80 /* Interrupt */ + +/* HME only: status 2 register */ +#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */ +#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */ +#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */ +#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */ +#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */ +#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */ +#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */ +#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */ + +/* The status register can be masked with ESP_STAT_PMASK and compared + * with the following values to determine the current phase the ESP + * (at least thinks it) is in. For our purposes we also add our own + * software 'done' bit for our phase management engine. + */ +#define ESP_DOP (0) /* Data Out */ +#define ESP_DIP (ESP_STAT_PIO) /* Data In */ +#define ESP_CMDP (ESP_STAT_PCD) /* Command */ +#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ +#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ +#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ + +/* ESP interrupt register read-only */ +#define ESP_INTR_S 0x01 /* Select w/o ATN */ +#define ESP_INTR_SATN 0x02 /* Select w/ATN */ +#define ESP_INTR_RSEL 0x04 /* Reselected */ +#define ESP_INTR_FDONE 0x08 /* Function done */ +#define ESP_INTR_BSERV 0x10 /* Bus service */ +#define ESP_INTR_DC 0x20 /* Disconnect */ +#define ESP_INTR_IC 0x40 /* Illegal command given */ +#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ + +/* Interrupt status macros */ +#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) +#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) +#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) +#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) +#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ + (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) +#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) + +/* ESP sequence step register read-only */ +#define ESP_STEP_VBITS 0x07 /* Valid bits */ +#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ +#define ESP_STEP_SID 0x01 /* One msg byte sent */ +#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ +#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd + * bytes to be lost + */ +#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ + +/* Ho hum, some ESP's set the step register to this as well... */ +#define ESP_STEP_FINI5 0x05 +#define ESP_STEP_FINI6 0x06 +#define ESP_STEP_FINI7 0x07 + +/* ESP chip-test register read-write */ +#define ESP_TEST_TARG 0x01 /* Target test mode */ +#define ESP_TEST_INI 0x02 /* Initiator test mode */ +#define ESP_TEST_TS 0x04 /* Tristate test mode */ + +/* ESP unique ID register read-only, found on fas236+fas100a only */ +#define ESP_UID_F100A 0x00 /* ESP FAS100A */ +#define ESP_UID_F236 0x02 /* ESP FAS236 */ +#define ESP_UID_REV 0x07 /* ESP revision */ +#define ESP_UID_FAM 0xf8 /* ESP family */ + +/* ESP fifo flags register read-only */ +/* Note that the following implies a 16 byte FIFO on the ESP. */ +#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ +#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */ +#define ESP_FF_SSTEP 0xe0 /* Sequence step */ + +/* ESP clock conversion factor register write-only */ +#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ +#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ +#define ESP_CCF_F2 0x02 /* 10MHz */ +#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ +#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ +#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ +#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ +#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ + +/* HME only... */ +#define ESP_BUSID_RESELID 0x10 +#define ESP_BUSID_CTR32BIT 0x40 + +#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */ +#define ESP_TIMEO_CONST 8192 +#define ESP_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) +#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) +#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) + +#endif /* !(_SPARC_ESP_H) */ diff --git a/trunk/drivers/scsi/esp_scsi.c b/trunk/drivers/scsi/esp_scsi.c deleted file mode 100644 index 99ce03331b64..000000000000 --- a/trunk/drivers/scsi/esp_scsi.c +++ /dev/null @@ -1,2711 +0,0 @@ -/* esp_scsi.c: ESP SCSI driver. - * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "2.000" -#define DRV_MODULE_RELDATE "April 19, 2007" - -/* SCSI bus reset settle time in seconds. */ -static int esp_bus_reset_settle = 3; - -static u32 esp_debug; -#define ESP_DEBUG_INTR 0x00000001 -#define ESP_DEBUG_SCSICMD 0x00000002 -#define ESP_DEBUG_RESET 0x00000004 -#define ESP_DEBUG_MSGIN 0x00000008 -#define ESP_DEBUG_MSGOUT 0x00000010 -#define ESP_DEBUG_CMDDONE 0x00000020 -#define ESP_DEBUG_DISCONNECT 0x00000040 -#define ESP_DEBUG_DATASTART 0x00000080 -#define ESP_DEBUG_DATADONE 0x00000100 -#define ESP_DEBUG_RECONNECT 0x00000200 -#define ESP_DEBUG_AUTOSENSE 0x00000400 - -#define esp_log_intr(f, a...) \ -do { if (esp_debug & ESP_DEBUG_INTR) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_reset(f, a...) \ -do { if (esp_debug & ESP_DEBUG_RESET) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_msgin(f, a...) \ -do { if (esp_debug & ESP_DEBUG_MSGIN) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_msgout(f, a...) \ -do { if (esp_debug & ESP_DEBUG_MSGOUT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_cmddone(f, a...) \ -do { if (esp_debug & ESP_DEBUG_CMDDONE) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_disconnect(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DISCONNECT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_datastart(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DATASTART) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_datadone(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DATADONE) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_reconnect(f, a...) \ -do { if (esp_debug & ESP_DEBUG_RECONNECT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_autosense(f, a...) \ -do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \ - printk(f, ## a); \ -} while (0) - -#define esp_read8(REG) esp->ops->esp_read8(esp, REG) -#define esp_write8(VAL,REG) esp->ops->esp_write8(esp, VAL, REG) - -static void esp_log_fill_regs(struct esp *esp, - struct esp_event_ent *p) -{ - p->sreg = esp->sreg; - p->seqreg = esp->seqreg; - p->sreg2 = esp->sreg2; - p->ireg = esp->ireg; - p->select_state = esp->select_state; - p->event = esp->event; -} - -void scsi_esp_cmd(struct esp *esp, u8 val) -{ - struct esp_event_ent *p; - int idx = esp->esp_event_cur; - - p = &esp->esp_event_log[idx]; - p->type = ESP_EVENT_TYPE_CMD; - p->val = val; - esp_log_fill_regs(esp, p); - - esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - - esp_write8(val, ESP_CMD); -} -EXPORT_SYMBOL(scsi_esp_cmd); - -static void esp_event(struct esp *esp, u8 val) -{ - struct esp_event_ent *p; - int idx = esp->esp_event_cur; - - p = &esp->esp_event_log[idx]; - p->type = ESP_EVENT_TYPE_EVENT; - p->val = val; - esp_log_fill_regs(esp, p); - - esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - - esp->event = val; -} - -static void esp_dump_cmd_log(struct esp *esp) -{ - int idx = esp->esp_event_cur; - int stop = idx; - - printk(KERN_INFO PFX "esp%d: Dumping command log\n", - esp->host->unique_id); - do { - struct esp_event_ent *p = &esp->esp_event_log[idx]; - - printk(KERN_INFO PFX "esp%d: ent[%d] %s ", - esp->host->unique_id, idx, - p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT"); - - printk("val[%02x] sreg[%02x] seqreg[%02x] " - "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n", - p->val, p->sreg, p->seqreg, - p->sreg2, p->ireg, p->select_state, p->event); - - idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - } while (idx != stop); -} - -static void esp_flush_fifo(struct esp *esp) -{ - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP236) { - int lim = 1000; - - while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES " - "will not clear!\n", - esp->host->unique_id); - break; - } - udelay(1); - } - } -} - -static void hme_read_fifo(struct esp *esp) -{ - int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - int idx = 0; - - while (fcnt--) { - esp->fifo[idx++] = esp_read8(ESP_FDATA); - esp->fifo[idx++] = esp_read8(ESP_FDATA); - } - if (esp->sreg2 & ESP_STAT2_F1BYTE) { - esp_write8(0, ESP_FDATA); - esp->fifo[idx++] = esp_read8(ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } - esp->fifo_cnt = idx; -} - -static void esp_set_all_config3(struct esp *esp, u8 val) -{ - int i; - - for (i = 0; i < ESP_MAX_TARGET; i++) - esp->target[i].esp_config3 = val; -} - -/* Reset the ESP chip, _not_ the SCSI bus. */ -static void esp_reset_esp(struct esp *esp) -{ - u8 family_code, version; - - /* Now reset the ESP chip */ - scsi_esp_cmd(esp, ESP_CMD_RC); - scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - - /* Reload the configuration registers */ - esp_write8(esp->cfact, ESP_CFACT); - - esp->prev_stp = 0; - esp_write8(esp->prev_stp, ESP_STP); - - esp->prev_soff = 0; - esp_write8(esp->prev_soff, ESP_SOFF); - - esp_write8(esp->neg_defp, ESP_TIMEO); - - /* This is the only point at which it is reliable to read - * the ID-code for a fast ESP chip variants. - */ - esp->max_period = ((35 * esp->ccycle) / 1000); - if (esp->rev == FAST) { - version = esp_read8(ESP_UID); - family_code = (version & 0xf8) >> 3; - if (family_code == 0x02) - esp->rev = FAS236; - else if (family_code == 0x0a) - esp->rev = FASHME; /* Version is usually '5'. */ - else - esp->rev = FAS100A; - esp->min_period = ((4 * esp->ccycle) / 1000); - } else { - esp->min_period = ((5 * esp->ccycle) / 1000); - } - esp->max_period = (esp->max_period + 3)>>2; - esp->min_period = (esp->min_period + 3)>>2; - - esp_write8(esp->config1, ESP_CFG1); - switch (esp->rev) { - case ESP100: - /* nothing to do */ - break; - - case ESP100A: - esp_write8(esp->config2, ESP_CFG2); - break; - - case ESP236: - /* Slow 236 */ - esp_write8(esp->config2, ESP_CFG2); - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - break; - - case FASHME: - esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); - /* fallthrough... */ - - case FAS236: - /* Fast 236 or HME */ - esp_write8(esp->config2, ESP_CFG2); - if (esp->rev == FASHME) { - u8 cfg3 = esp->target[0].esp_config3; - - cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; - if (esp->scsi_id >= 8) - cfg3 |= ESP_CONFIG3_IDBIT3; - esp_set_all_config3(esp, cfg3); - } else { - u32 cfg3 = esp->target[0].esp_config3; - - cfg3 |= ESP_CONFIG3_FCLK; - esp_set_all_config3(esp, cfg3); - } - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - if (esp->rev == FASHME) { - esp->radelay = 80; - } else { - if (esp->flags & ESP_FLAG_DIFFERENTIAL) - esp->radelay = 0; - else - esp->radelay = 96; - } - break; - - case FAS100A: - /* Fast 100a */ - esp_write8(esp->config2, ESP_CFG2); - esp_set_all_config3(esp, - (esp->target[0].esp_config3 | - ESP_CONFIG3_FCLOCK)); - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - esp->radelay = 32; - break; - - default: - break; - } - - /* Eat any bitrot in the chip */ - esp_read8(ESP_INTRPT); - udelay(100); -} - -static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - struct scatterlist *sg = cmd->request_buffer; - int dir = cmd->sc_data_direction; - int total, i; - - if (dir == DMA_NONE) - return; - - BUG_ON(cmd->use_sg == 0); - - spriv->u.num_sg = esp->ops->map_sg(esp, sg, - cmd->use_sg, dir); - spriv->cur_residue = sg_dma_len(sg); - spriv->cur_sg = sg; - - total = 0; - for (i = 0; i < spriv->u.num_sg; i++) - total += sg_dma_len(&sg[i]); - spriv->tot_residue = total; -} - -static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - return ent->sense_dma + - (ent->sense_ptr - cmd->sense_buffer); - } - - return sg_dma_address(p->cur_sg) + - (sg_dma_len(p->cur_sg) - - p->cur_residue); -} - -static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - return SCSI_SENSE_BUFFERSIZE - - (ent->sense_ptr - cmd->sense_buffer); - } - return p->cur_residue; -} - -static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd, unsigned int len) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->sense_ptr += len; - return; - } - - p->cur_residue -= len; - p->tot_residue -= len; - if (p->cur_residue < 0 || p->tot_residue < 0) { - printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n", - esp->host->unique_id); - printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] " - "len[%u]\n", - esp->host->unique_id, - p->cur_residue, p->tot_residue, len); - p->cur_residue = 0; - p->tot_residue = 0; - } - if (!p->cur_residue && p->tot_residue) { - p->cur_sg++; - p->cur_residue = sg_dma_len(p->cur_sg); - } -} - -static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - int dir = cmd->sc_data_direction; - - if (dir == DMA_NONE) - return; - - esp->ops->unmap_sg(esp, cmd->request_buffer, - spriv->u.num_sg, dir); -} - -static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->saved_sense_ptr = ent->sense_ptr; - return; - } - ent->saved_cur_residue = spriv->cur_residue; - ent->saved_cur_sg = spriv->cur_sg; - ent->saved_tot_residue = spriv->tot_residue; -} - -static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->sense_ptr = ent->saved_sense_ptr; - return; - } - spriv->cur_residue = ent->saved_cur_residue; - spriv->cur_sg = ent->saved_cur_sg; - spriv->tot_residue = ent->saved_tot_residue; -} - -static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd) -{ - if (cmd->cmd_len == 6 || - cmd->cmd_len == 10 || - cmd->cmd_len == 12) { - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - } else { - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } -} - -static void esp_write_tgt_config3(struct esp *esp, int tgt) -{ - if (esp->rev > ESP100A) { - u8 val = esp->target[tgt].esp_config3; - - if (val != esp->prev_cfg3) { - esp->prev_cfg3 = val; - esp_write8(val, ESP_CFG3); - } - } -} - -static void esp_write_tgt_sync(struct esp *esp, int tgt) -{ - u8 off = esp->target[tgt].esp_offset; - u8 per = esp->target[tgt].esp_period; - - if (off != esp->prev_soff) { - esp->prev_soff = off; - esp_write8(off, ESP_SOFF); - } - if (per != esp->prev_stp) { - esp->prev_stp = per; - esp_write8(per, ESP_STP); - } -} - -static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) -{ - if (esp->rev == FASHME) { - /* Arbitrary segment boundaries, 24-bit counts. */ - if (dma_len > (1U << 24)) - dma_len = (1U << 24); - } else { - u32 base, end; - - /* ESP chip limits other variants by 16-bits of transfer - * count. Actually on FAS100A and FAS236 we could get - * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB - * in the ESP_CFG2 register but that causes other unwanted - * changes so we don't use it currently. - */ - if (dma_len > (1U << 16)) - dma_len = (1U << 16); - - /* All of the DMA variants hooked up to these chips - * cannot handle crossing a 24-bit address boundary. - */ - base = dma_addr & ((1U << 24) - 1U); - end = base + dma_len; - if (end > (1U << 24)) - end = (1U <<24); - dma_len = end - base; - } - return dma_len; -} - -static int esp_need_to_nego_wide(struct esp_target_data *tp) -{ - struct scsi_target *target = tp->starget; - - return spi_width(target) != tp->nego_goal_width; -} - -static int esp_need_to_nego_sync(struct esp_target_data *tp) -{ - struct scsi_target *target = tp->starget; - - /* When offset is zero, period is "don't care". */ - if (!spi_offset(target) && !tp->nego_goal_offset) - return 0; - - if (spi_offset(target) == tp->nego_goal_offset && - spi_period(target) == tp->nego_goal_period) - return 0; - - return 1; -} - -static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, - struct esp_lun_data *lp) -{ - if (!ent->tag[0]) { - /* Non-tagged, slot already taken? */ - if (lp->non_tagged_cmd) - return -EBUSY; - - if (lp->hold) { - /* We are being held by active tagged - * commands. - */ - if (lp->num_tagged) - return -EBUSY; - - /* Tagged commands completed, we can unplug - * the queue and run this untagged command. - */ - lp->hold = 0; - } else if (lp->num_tagged) { - /* Plug the queue until num_tagged decreases - * to zero in esp_free_lun_tag. - */ - lp->hold = 1; - return -EBUSY; - } - - lp->non_tagged_cmd = ent; - return 0; - } else { - /* Tagged command, see if blocked by a - * non-tagged one. - */ - if (lp->non_tagged_cmd || lp->hold) - return -EBUSY; - } - - BUG_ON(lp->tagged_cmds[ent->tag[1]]); - - lp->tagged_cmds[ent->tag[1]] = ent; - lp->num_tagged++; - - return 0; -} - -static void esp_free_lun_tag(struct esp_cmd_entry *ent, - struct esp_lun_data *lp) -{ - if (ent->tag[0]) { - BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent); - lp->tagged_cmds[ent->tag[1]] = NULL; - lp->num_tagged--; - } else { - BUG_ON(lp->non_tagged_cmd != ent); - lp->non_tagged_cmd = NULL; - } -} - -/* When a contingent allegiance conditon is created, we force feed a - * REQUEST_SENSE command to the device to fetch the sense data. I - * tried many other schemes, relying on the scsi error handling layer - * to send out the REQUEST_SENSE automatically, but this was difficult - * to get right especially in the presence of applications like smartd - * which use SG_IO to send out their own REQUEST_SENSE commands. - */ -static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct scsi_device *dev = cmd->device; - int tgt, lun; - u8 *p, val; - - tgt = dev->id; - lun = dev->lun; - - - if (!ent->sense_ptr) { - esp_log_autosense("esp%d: Doing auto-sense for " - "tgt[%d] lun[%d]\n", - esp->host->unique_id, tgt, lun); - - ent->sense_ptr = cmd->sense_buffer; - ent->sense_dma = esp->ops->map_single(esp, - ent->sense_ptr, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - } - ent->saved_sense_ptr = ent->sense_ptr; - - esp->active_cmd = ent; - - p = esp->command_block; - esp->msg_out_len = 0; - - *p++ = IDENTIFY(0, lun); - *p++ = REQUEST_SENSE; - *p++ = ((dev->scsi_level <= SCSI_2) ? - (lun << 5) : 0); - *p++ = 0; - *p++ = 0; - *p++ = SCSI_SENSE_BUFFERSIZE; - *p++ = 0; - - esp->select_state = ESP_SELECT_BASIC; - - val = tgt; - if (esp->rev == FASHME) - val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; - esp_write8(val, ESP_BUSID); - - esp_write_tgt_sync(esp, tgt); - esp_write_tgt_config3(esp, tgt); - - val = (p - esp->command_block); - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA); -} - -static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) -{ - struct esp_cmd_entry *ent; - - list_for_each_entry(ent, &esp->queued_cmds, list) { - struct scsi_cmnd *cmd = ent->cmd; - struct scsi_device *dev = cmd->device; - struct esp_lun_data *lp = dev->hostdata; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->tag[0] = 0; - ent->tag[1] = 0; - return ent; - } - - if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) { - ent->tag[0] = 0; - ent->tag[1] = 0; - } - - if (esp_alloc_lun_tag(ent, lp) < 0) - continue; - - return ent; - } - - return NULL; -} - -static void esp_maybe_execute_command(struct esp *esp) -{ - struct esp_target_data *tp; - struct esp_lun_data *lp; - struct scsi_device *dev; - struct scsi_cmnd *cmd; - struct esp_cmd_entry *ent; - int tgt, lun, i; - u32 val, start_cmd; - u8 *p; - - if (esp->active_cmd || - (esp->flags & ESP_FLAG_RESETTING)) - return; - - ent = find_and_prep_issuable_command(esp); - if (!ent) - return; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp_autosense(esp, ent); - return; - } - - cmd = ent->cmd; - dev = cmd->device; - tgt = dev->id; - lun = dev->lun; - tp = &esp->target[tgt]; - lp = dev->hostdata; - - list_del(&ent->list); - list_add(&ent->list, &esp->active_cmds); - - esp->active_cmd = ent; - - esp_map_dma(esp, cmd); - esp_save_pointers(esp, ent); - - esp_check_command_len(esp, cmd); - - p = esp->command_block; - - esp->msg_out_len = 0; - if (tp->flags & ESP_TGT_CHECK_NEGO) { - /* Need to negotiate. If the target is broken - * go for synchronous transfers and non-wide. - */ - if (tp->flags & ESP_TGT_BROKEN) { - tp->flags &= ~ESP_TGT_DISCONNECT; - tp->nego_goal_period = 0; - tp->nego_goal_offset = 0; - tp->nego_goal_width = 0; - tp->nego_goal_tags = 0; - } - - /* If the settings are not changing, skip this. */ - if (spi_width(tp->starget) == tp->nego_goal_width && - spi_period(tp->starget) == tp->nego_goal_period && - spi_offset(tp->starget) == tp->nego_goal_offset) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - goto build_identify; - } - - if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) { - esp->msg_out_len = - spi_populate_width_msg(&esp->msg_out[0], - (tp->nego_goal_width ? - 1 : 0)); - tp->flags |= ESP_TGT_NEGO_WIDE; - } else if (esp_need_to_nego_sync(tp)) { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - } else { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - } - - /* Process it like a slow command. */ - if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC)) - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } - -build_identify: - /* If we don't have a lun-data struct yet, we're probing - * so do not disconnect. Also, do not disconnect unless - * we have a tag on this command. - */ - if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0]) - *p++ = IDENTIFY(1, lun); - else - *p++ = IDENTIFY(0, lun); - - if (ent->tag[0] && esp->rev == ESP100) { - /* ESP100 lacks select w/atn3 command, use select - * and stop instead. - */ - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } - - if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) { - start_cmd = ESP_CMD_DMA | ESP_CMD_SELA; - if (ent->tag[0]) { - *p++ = ent->tag[0]; - *p++ = ent->tag[1]; - - start_cmd = ESP_CMD_DMA | ESP_CMD_SA3; - } - - for (i = 0; i < cmd->cmd_len; i++) - *p++ = cmd->cmnd[i]; - - esp->select_state = ESP_SELECT_BASIC; - } else { - esp->cmd_bytes_left = cmd->cmd_len; - esp->cmd_bytes_ptr = &cmd->cmnd[0]; - - if (ent->tag[0]) { - for (i = esp->msg_out_len - 1; - i >= 0; i--) - esp->msg_out[i + 2] = esp->msg_out[i]; - esp->msg_out[0] = ent->tag[0]; - esp->msg_out[1] = ent->tag[1]; - esp->msg_out_len += 2; - } - - start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS; - esp->select_state = ESP_SELECT_MSGOUT; - } - val = tgt; - if (esp->rev == FASHME) - val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; - esp_write8(val, ESP_BUSID); - - esp_write_tgt_sync(esp, tgt); - esp_write_tgt_config3(esp, tgt); - - val = (p - esp->command_block); - - if (esp_debug & ESP_DEBUG_SCSICMD) { - printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun); - for (i = 0; i < cmd->cmd_len; i++) - printk("%02x ", cmd->cmnd[i]); - printk("]\n"); - } - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - val, 16, 0, start_cmd); -} - -static struct esp_cmd_entry *esp_get_ent(struct esp *esp) -{ - struct list_head *head = &esp->esp_cmd_pool; - struct esp_cmd_entry *ret; - - if (list_empty(head)) { - ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC); - } else { - ret = list_entry(head->next, struct esp_cmd_entry, list); - list_del(&ret->list); - memset(ret, 0, sizeof(*ret)); - } - return ret; -} - -static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent) -{ - list_add(&ent->list, &esp->esp_cmd_pool); -} - -static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd, unsigned int result) -{ - struct scsi_device *dev = cmd->device; - int tgt = dev->id; - int lun = dev->lun; - - esp->active_cmd = NULL; - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, dev->hostdata); - cmd->result = result; - - if (ent->eh_done) { - complete(ent->eh_done); - ent->eh_done = NULL; - } - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - - /* Restore the message/status bytes to what we actually - * saw originally. Also, report that we are providing - * the sense data. - */ - cmd->result = ((DRIVER_SENSE << 24) | - (DID_OK << 16) | - (COMMAND_COMPLETE << 8) | - (SAM_STAT_CHECK_CONDITION << 0)); - - ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE; - if (esp_debug & ESP_DEBUG_AUTOSENSE) { - int i; - - printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ", - esp->host->unique_id, tgt, lun); - for (i = 0; i < 18; i++) - printk("%02x ", cmd->sense_buffer[i]); - printk("]\n"); - } - } - - cmd->scsi_done(cmd); - - list_del(&ent->list); - esp_put_ent(esp, ent); - - esp_maybe_execute_command(esp); -} - -static unsigned int compose_result(unsigned int status, unsigned int message, - unsigned int driver_code) -{ - return (status | (message << 8) | (driver_code << 16)); -} - -static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_device *dev = ent->cmd->device; - struct esp_lun_data *lp = dev->hostdata; - - scsi_track_queue_full(dev, lp->num_tagged - 1); -} - -static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct scsi_device *dev = cmd->device; - struct esp *esp = host_to_esp(dev->host); - struct esp_cmd_priv *spriv; - struct esp_cmd_entry *ent; - - ent = esp_get_ent(esp); - if (!ent) - return SCSI_MLQUEUE_HOST_BUSY; - - ent->cmd = cmd; - - cmd->scsi_done = done; - - spriv = ESP_CMD_PRIV(cmd); - spriv->u.dma_addr = ~(dma_addr_t)0x0; - - list_add_tail(&ent->list, &esp->queued_cmds); - - esp_maybe_execute_command(esp); - - return 0; -} - -static int esp_check_gross_error(struct esp *esp) -{ - if (esp->sreg & ESP_STAT_SPAM) { - /* Gross Error, could be one of: - * - top of fifo overwritten - * - top of command register overwritten - * - DMA programmed with wrong direction - * - improper phase change - */ - printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n", - esp->host->unique_id, esp->sreg); - /* XXX Reset the chip. XXX */ - return 1; - } - return 0; -} - -static int esp_check_spur_intr(struct esp *esp) -{ - switch (esp->rev) { - case ESP100: - case ESP100A: - /* The interrupt pending bit of the status register cannot - * be trusted on these revisions. - */ - esp->sreg &= ~ESP_STAT_INTR; - break; - - default: - if (!(esp->sreg & ESP_STAT_INTR)) { - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_SR) - return 1; - - /* If the DMA is indicating interrupt pending and the - * ESP is not, the only possibility is a DMA error. - */ - if (!esp->ops->dma_error(esp)) { - printk(KERN_ERR PFX "esp%d: Spurious irq, " - "sreg=%x.\n", - esp->host->unique_id, esp->sreg); - return -1; - } - - printk(KERN_ERR PFX "esp%d: DMA error\n", - esp->host->unique_id); - - /* XXX Reset the chip. XXX */ - return -1; - } - break; - } - - return 0; -} - -static void esp_schedule_reset(struct esp *esp) -{ - esp_log_reset("ESP: esp_schedule_reset() from %p\n", - __builtin_return_address(0)); - esp->flags |= ESP_FLAG_RESETTING; - esp_event(esp, ESP_EVENT_RESET); -} - -/* In order to avoid having to add a special half-reconnected state - * into the driver we just sit here and poll through the rest of - * the reselection process to get the tag message bytes. - */ -static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp, - struct esp_lun_data *lp) -{ - struct esp_cmd_entry *ent; - int i; - - if (!lp->num_tagged) { - printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n", - esp->host->unique_id); - return NULL; - } - - esp_log_reconnect("ESP: reconnect tag, "); - - for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) - break; - } - if (i == ESP_QUICKIRQ_LIMIT) { - printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n", - esp->host->unique_id); - return NULL; - } - - esp->sreg = esp_read8(ESP_STATUS); - esp->ireg = esp_read8(ESP_INTRPT); - - esp_log_reconnect("IRQ(%d:%x:%x), ", - i, esp->ireg, esp->sreg); - - if (esp->ireg & ESP_INTR_DC) { - printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n", - esp->host->unique_id); - return NULL; - } - - if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) { - printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n", - esp->host->unique_id, esp->sreg); - return NULL; - } - - /* DMA in the tag bytes... */ - esp->command_block[0] = 0xff; - esp->command_block[1] = 0xff; - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - 2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI); - - /* ACK the msssage. */ - scsi_esp_cmd(esp, ESP_CMD_MOK); - - for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) { - esp->sreg = esp_read8(ESP_STATUS); - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_FDONE) - break; - } - udelay(1); - } - if (i == ESP_RESELECT_TAG_LIMIT) { - printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n", - esp->host->unique_id); - return NULL; - } - esp->ops->dma_drain(esp); - esp->ops->dma_invalidate(esp); - - esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n", - i, esp->ireg, esp->sreg, - esp->command_block[0], - esp->command_block[1]); - - if (esp->command_block[0] < SIMPLE_QUEUE_TAG || - esp->command_block[0] > ORDERED_QUEUE_TAG) { - printk(KERN_ERR PFX "esp%d: Reconnect, bad tag " - "type %02x.\n", - esp->host->unique_id, esp->command_block[0]); - return NULL; - } - - ent = lp->tagged_cmds[esp->command_block[1]]; - if (!ent) { - printk(KERN_ERR PFX "esp%d: Reconnect, no entry for " - "tag %02x.\n", - esp->host->unique_id, esp->command_block[1]); - return NULL; - } - - return ent; -} - -static int esp_reconnect(struct esp *esp) -{ - struct esp_cmd_entry *ent; - struct esp_target_data *tp; - struct esp_lun_data *lp; - struct scsi_device *dev; - int target, lun; - - BUG_ON(esp->active_cmd); - if (esp->rev == FASHME) { - /* FASHME puts the target and lun numbers directly - * into the fifo. - */ - target = esp->fifo[0]; - lun = esp->fifo[1] & 0x7; - } else { - u8 bits = esp_read8(ESP_FDATA); - - /* Older chips put the lun directly into the fifo, but - * the target is given as a sample of the arbitration - * lines on the bus at reselection time. So we should - * see the ID of the ESP and the one reconnecting target - * set in the bitmap. - */ - if (!(bits & esp->scsi_id_mask)) - goto do_reset; - bits &= ~esp->scsi_id_mask; - if (!bits || (bits & (bits - 1))) - goto do_reset; - - target = ffs(bits) - 1; - lun = (esp_read8(ESP_FDATA) & 0x7); - - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP100) { - u8 ireg = esp_read8(ESP_INTRPT); - /* This chip has a bug during reselection that can - * cause a spurious illegal-command interrupt, which - * we simply ACK here. Another possibility is a bus - * reset so we must check for that. - */ - if (ireg & ESP_INTR_SR) - goto do_reset; - } - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - - esp_write_tgt_sync(esp, target); - esp_write_tgt_config3(esp, target); - - scsi_esp_cmd(esp, ESP_CMD_MOK); - - if (esp->rev == FASHME) - esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT, - ESP_BUSID); - - tp = &esp->target[target]; - dev = __scsi_device_lookup_by_target(tp->starget, lun); - if (!dev) { - printk(KERN_ERR PFX "esp%d: Reconnect, no lp " - "tgt[%u] lun[%u]\n", - esp->host->unique_id, target, lun); - goto do_reset; - } - lp = dev->hostdata; - - ent = lp->non_tagged_cmd; - if (!ent) { - ent = esp_reconnect_with_tag(esp, lp); - if (!ent) - goto do_reset; - } - - esp->active_cmd = ent; - - if (ent->flags & ESP_CMD_FLAG_ABORT) { - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - - esp_event(esp, ESP_EVENT_CHECK_PHASE); - esp_restore_pointers(esp, ent); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - -do_reset: - esp_schedule_reset(esp); - return 0; -} - -static int esp_finish_select(struct esp *esp) -{ - struct esp_cmd_entry *ent; - struct scsi_cmnd *cmd; - u8 orig_select_state; - - orig_select_state = esp->select_state; - - /* No longer selecting. */ - esp->select_state = ESP_SELECT_NONE; - - esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS; - ent = esp->active_cmd; - cmd = ent->cmd; - - if (esp->ops->dma_error(esp)) { - /* If we see a DMA error during or as a result of selection, - * all bets are off. - */ - esp_schedule_reset(esp); - esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16)); - return 0; - } - - esp->ops->dma_invalidate(esp); - - if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { - struct esp_target_data *tp = &esp->target[cmd->device->id]; - - /* Carefully back out of the selection attempt. Release - * resources (such as DMA mapping & TAG) and reset state (such - * as message out and command delivery variables). - */ - if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, cmd->device->hostdata); - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE); - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - esp->cmd_bytes_ptr = NULL; - esp->cmd_bytes_left = 0; - } else { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } - - /* Now that the state is unwound properly, put back onto - * the issue queue. This command is no longer active. - */ - list_del(&ent->list); - list_add(&ent->list, &esp->queued_cmds); - esp->active_cmd = NULL; - - /* Return value ignored by caller, it directly invokes - * esp_reconnect(). - */ - return 0; - } - - if (esp->ireg == ESP_INTR_DC) { - struct scsi_device *dev = cmd->device; - - /* Disconnect. Make sure we re-negotiate sync and - * wide parameters if this target starts responding - * again in the future. - */ - esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO; - - scsi_esp_cmd(esp, ESP_CMD_ESEL); - esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16)); - return 1; - } - - if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { - /* Selection successful. On pre-FAST chips we have - * to do a NOP and possibly clean out the FIFO. - */ - if (esp->rev <= ESP236) { - int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - scsi_esp_cmd(esp, ESP_CMD_NULL); - - if (!fcnt && - (!esp->prev_soff || - ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) - esp_flush_fifo(esp); - } - - /* If we are doing a slow command, negotiation, etc. - * we'll do the right thing as we transition to the - * next phase. - */ - esp_event(esp, ESP_EVENT_CHECK_PHASE); - return 0; - } - - printk("ESP: Unexpected selection completion ireg[%x].\n", - esp->ireg); - esp_schedule_reset(esp); - return 0; -} - -static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - int fifo_cnt, ecount, bytes_sent, flush_fifo; - - fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE) - fifo_cnt <<= 1; - - ecount = 0; - if (!(esp->sreg & ESP_STAT_TCNT)) { - ecount = ((unsigned int)esp_read8(ESP_TCLOW) | - (((unsigned int)esp_read8(ESP_TCMED)) << 8)); - if (esp->rev == FASHME) - ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16; - } - - bytes_sent = esp->data_dma_len; - bytes_sent -= ecount; - - if (!(ent->flags & ESP_CMD_FLAG_WRITE)) - bytes_sent -= fifo_cnt; - - flush_fifo = 0; - if (!esp->prev_soff) { - /* Synchronous data transfer, always flush fifo. */ - flush_fifo = 1; - } else { - if (esp->rev == ESP100) { - u32 fflags, phase; - - /* ESP100 has a chip bug where in the synchronous data - * phase it can mistake a final long REQ pulse from the - * target as an extra data byte. Fun. - * - * To detect this case we resample the status register - * and fifo flags. If we're still in a data phase and - * we see spurious chunks in the fifo, we return error - * to the caller which should reset and set things up - * such that we only try future transfers to this - * target in synchronous mode. - */ - esp->sreg = esp_read8(ESP_STATUS); - phase = esp->sreg & ESP_STAT_PMASK; - fflags = esp_read8(ESP_FFLAGS); - - if ((phase == ESP_DOP && - (fflags & ESP_FF_ONOTZERO)) || - (phase == ESP_DIP && - (fflags & ESP_FF_FBYTES))) - return -1; - } - if (!(ent->flags & ESP_CMD_FLAG_WRITE)) - flush_fifo = 1; - } - - if (flush_fifo) - esp_flush_fifo(esp); - - return bytes_sent; -} - -static void esp_setsync(struct esp *esp, struct esp_target_data *tp, - u8 scsi_period, u8 scsi_offset, - u8 esp_stp, u8 esp_soff) -{ - spi_period(tp->starget) = scsi_period; - spi_offset(tp->starget) = scsi_offset; - spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0; - - if (esp_soff) { - esp_stp &= 0x1f; - esp_soff |= esp->radelay; - if (esp->rev >= FAS236) { - u8 bit = ESP_CONFIG3_FSCSI; - if (esp->rev >= FAS100A) - bit = ESP_CONFIG3_FAST; - - if (scsi_period < 50) { - if (esp->rev == FASHME) - esp_soff &= ~esp->radelay; - tp->esp_config3 |= bit; - } else { - tp->esp_config3 &= ~bit; - } - esp->prev_cfg3 = tp->esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - } - } - - tp->esp_period = esp->prev_stp = esp_stp; - tp->esp_offset = esp->prev_soff = esp_soff; - - esp_write8(esp_soff, ESP_SOFF); - esp_write8(esp_stp, ESP_STP); - - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); - - spi_display_xfer_agreement(tp->starget); -} - -static void esp_msgin_reject(struct esp *esp) -{ - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - struct esp_target_data *tp; - int tgt; - - tgt = cmd->device->id; - tp = &esp->target[tgt]; - - if (tp->flags & ESP_TGT_NEGO_WIDE) { - tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE); - - if (!esp_need_to_nego_sync(tp)) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - scsi_esp_cmd(esp, ESP_CMD_RATN); - } else { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - return; - } - - if (tp->flags & ESP_TGT_NEGO_SYNC) { - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); - tp->esp_period = 0; - tp->esp_offset = 0; - esp_setsync(esp, tp, 0, 0, 0, 0); - scsi_esp_cmd(esp, ESP_CMD_RATN); - return; - } - - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) -{ - u8 period = esp->msg_in[3]; - u8 offset = esp->msg_in[4]; - u8 stp; - - if (!(tp->flags & ESP_TGT_NEGO_SYNC)) - goto do_reject; - - if (offset > 15) - goto do_reject; - - if (offset) { - int rounded_up, one_clock; - - if (period > esp->max_period) { - period = offset = 0; - goto do_sdtr; - } - if (period < esp->min_period) - goto do_reject; - - one_clock = esp->ccycle / 1000; - rounded_up = (period << 2); - rounded_up = (rounded_up + one_clock - 1) / one_clock; - stp = rounded_up; - if (stp && esp->rev >= FAS236) { - if (stp >= 50) - stp--; - } - } else { - stp = 0; - } - - esp_setsync(esp, tp, period, offset, stp, offset); - return; - -do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - return; - -do_sdtr: - tp->nego_goal_period = period; - tp->nego_goal_offset = offset; - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp) -{ - int size = 8 << esp->msg_in[3]; - u8 cfg3; - - if (esp->rev != FASHME) - goto do_reject; - - if (size != 8 && size != 16) - goto do_reject; - - if (!(tp->flags & ESP_TGT_NEGO_WIDE)) - goto do_reject; - - cfg3 = tp->esp_config3; - if (size == 16) { - tp->flags |= ESP_TGT_WIDE; - cfg3 |= ESP_CONFIG3_EWIDE; - } else { - tp->flags &= ~ESP_TGT_WIDE; - cfg3 &= ~ESP_CONFIG3_EWIDE; - } - tp->esp_config3 = cfg3; - esp->prev_cfg3 = cfg3; - esp_write8(cfg3, ESP_CFG3); - - tp->flags &= ~ESP_TGT_NEGO_WIDE; - - spi_period(tp->starget) = 0; - spi_offset(tp->starget) = 0; - if (!esp_need_to_nego_sync(tp)) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - scsi_esp_cmd(esp, ESP_CMD_RATN); - } else { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - return; - -do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_extended(struct esp *esp) -{ - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - struct esp_target_data *tp; - int tgt = cmd->device->id; - - tp = &esp->target[tgt]; - if (esp->msg_in[2] == EXTENDED_SDTR) { - esp_msgin_sdtr(esp, tp); - return; - } - if (esp->msg_in[2] == EXTENDED_WDTR) { - esp_msgin_wdtr(esp, tp); - return; - } - - printk("ESP: Unexpected extended msg type %x\n", - esp->msg_in[2]); - - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -/* Analyze msgin bytes received from target so far. Return non-zero - * if there are more bytes needed to complete the message. - */ -static int esp_msgin_process(struct esp *esp) -{ - u8 msg0 = esp->msg_in[0]; - int len = esp->msg_in_len; - - if (msg0 & 0x80) { - /* Identify */ - printk("ESP: Unexpected msgin identify\n"); - return 0; - } - - switch (msg0) { - case EXTENDED_MESSAGE: - if (len == 1) - return 1; - if (len < esp->msg_in[1] + 2) - return 1; - esp_msgin_extended(esp); - return 0; - - case IGNORE_WIDE_RESIDUE: { - struct esp_cmd_entry *ent; - struct esp_cmd_priv *spriv; - if (len == 1) - return 1; - - if (esp->msg_in[1] != 1) - goto do_reject; - - ent = esp->active_cmd; - spriv = ESP_CMD_PRIV(ent->cmd); - - if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) { - spriv->cur_sg--; - spriv->cur_residue = 1; - } else - spriv->cur_residue++; - spriv->tot_residue++; - return 0; - } - case NOP: - return 0; - case RESTORE_POINTERS: - esp_restore_pointers(esp, esp->active_cmd); - return 0; - case SAVE_POINTERS: - esp_save_pointers(esp, esp->active_cmd); - return 0; - - case COMMAND_COMPLETE: - case DISCONNECT: { - struct esp_cmd_entry *ent = esp->active_cmd; - - ent->message = msg0; - esp_event(esp, ESP_EVENT_FREE_BUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 0; - } - case MESSAGE_REJECT: - esp_msgin_reject(esp); - return 0; - - default: - do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - return 0; - } -} - -static int esp_process_event(struct esp *esp) -{ - int write; - -again: - write = 0; - switch (esp->event) { - case ESP_EVENT_CHECK_PHASE: - switch (esp->sreg & ESP_STAT_PMASK) { - case ESP_DOP: - esp_event(esp, ESP_EVENT_DATA_OUT); - break; - case ESP_DIP: - esp_event(esp, ESP_EVENT_DATA_IN); - break; - case ESP_STATP: - esp_flush_fifo(esp); - scsi_esp_cmd(esp, ESP_CMD_ICCSEQ); - esp_event(esp, ESP_EVENT_STATUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - - case ESP_MOP: - esp_event(esp, ESP_EVENT_MSGOUT); - break; - - case ESP_MIP: - esp_event(esp, ESP_EVENT_MSGIN); - break; - - case ESP_CMDP: - esp_event(esp, ESP_EVENT_CMD_START); - break; - - default: - printk("ESP: Unexpected phase, sreg=%02x\n", - esp->sreg); - esp_schedule_reset(esp); - return 0; - } - goto again; - break; - - case ESP_EVENT_DATA_IN: - write = 1; - /* fallthru */ - - case ESP_EVENT_DATA_OUT: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd); - unsigned int dma_len = esp_cur_dma_len(ent, cmd); - - if (esp->rev == ESP100) - scsi_esp_cmd(esp, ESP_CMD_NULL); - - if (write) - ent->flags |= ESP_CMD_FLAG_WRITE; - else - ent->flags &= ~ESP_CMD_FLAG_WRITE; - - dma_len = esp_dma_length_limit(esp, dma_addr, dma_len); - esp->data_dma_len = dma_len; - - if (!dma_len) { - printk(KERN_ERR PFX "esp%d: DMA length is zero!\n", - esp->host->unique_id); - printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n", - esp->host->unique_id, - (unsigned long long)esp_cur_dma_addr(ent, cmd), - esp_cur_dma_len(ent, cmd)); - esp_schedule_reset(esp); - return 0; - } - - esp_log_datastart("ESP: start data addr[%08llx] len[%u] " - "write(%d)\n", - (unsigned long long)dma_addr, dma_len, write); - - esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len, - write, ESP_CMD_DMA | ESP_CMD_TI); - esp_event(esp, ESP_EVENT_DATA_DONE); - break; - } - case ESP_EVENT_DATA_DONE: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - int bytes_sent; - - if (esp->ops->dma_error(esp)) { - printk("ESP: data done, DMA error, resetting\n"); - esp_schedule_reset(esp); - return 0; - } - - if (ent->flags & ESP_CMD_FLAG_WRITE) { - /* XXX parity errors, etc. XXX */ - - esp->ops->dma_drain(esp); - } - esp->ops->dma_invalidate(esp); - - if (esp->ireg != ESP_INTR_BSERV) { - /* We should always see exactly a bus-service - * interrupt at the end of a successful transfer. - */ - printk("ESP: data done, not BSERV, resetting\n"); - esp_schedule_reset(esp); - return 0; - } - - bytes_sent = esp_data_bytes_sent(esp, ent, cmd); - - esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n", - ent->flags, bytes_sent); - - if (bytes_sent < 0) { - /* XXX force sync mode for this target XXX */ - esp_schedule_reset(esp); - return 0; - } - - esp_advance_dma(esp, ent, cmd, bytes_sent); - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - break; - } - - case ESP_EVENT_STATUS: { - struct esp_cmd_entry *ent = esp->active_cmd; - - if (esp->ireg & ESP_INTR_FDONE) { - ent->status = esp_read8(ESP_FDATA); - ent->message = esp_read8(ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_MOK); - } else if (esp->ireg == ESP_INTR_BSERV) { - ent->status = esp_read8(ESP_FDATA); - ent->message = 0xff; - esp_event(esp, ESP_EVENT_MSGIN); - return 0; - } - - if (ent->message != COMMAND_COMPLETE) { - printk("ESP: Unexpected message %x in status\n", - ent->message); - esp_schedule_reset(esp); - return 0; - } - - esp_event(esp, ESP_EVENT_FREE_BUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - } - case ESP_EVENT_FREE_BUS: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - - if (ent->message == COMMAND_COMPLETE || - ent->message == DISCONNECT) - scsi_esp_cmd(esp, ESP_CMD_ESEL); - - if (ent->message == COMMAND_COMPLETE) { - esp_log_cmddone("ESP: Command done status[%x] " - "message[%x]\n", - ent->status, ent->message); - if (ent->status == SAM_STAT_TASK_SET_FULL) - esp_event_queue_full(esp, ent); - - if (ent->status == SAM_STAT_CHECK_CONDITION && - !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { - ent->flags |= ESP_CMD_FLAG_AUTOSENSE; - esp_autosense(esp, ent); - } else { - esp_cmd_is_done(esp, ent, cmd, - compose_result(ent->status, - ent->message, - DID_OK)); - } - } else if (ent->message == DISCONNECT) { - esp_log_disconnect("ESP: Disconnecting tgt[%d] " - "tag[%x:%x]\n", - cmd->device->id, - ent->tag[0], ent->tag[1]); - - esp->active_cmd = NULL; - esp_maybe_execute_command(esp); - } else { - printk("ESP: Unexpected message %x in freebus\n", - ent->message); - esp_schedule_reset(esp); - return 0; - } - if (esp->active_cmd) - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - } - case ESP_EVENT_MSGOUT: { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - if (esp_debug & ESP_DEBUG_MSGOUT) { - int i; - printk("ESP: Sending message [ "); - for (i = 0; i < esp->msg_out_len; i++) - printk("%02x ", esp->msg_out[i]); - printk("]\n"); - } - - if (esp->rev == FASHME) { - int i; - - /* Always use the fifo. */ - for (i = 0; i < esp->msg_out_len; i++) { - esp_write8(esp->msg_out[i], ESP_FDATA); - esp_write8(0, ESP_FDATA); - } - scsi_esp_cmd(esp, ESP_CMD_TI); - } else { - if (esp->msg_out_len == 1) { - esp_write8(esp->msg_out[0], ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_TI); - } else { - /* Use DMA. */ - memcpy(esp->command_block, - esp->msg_out, - esp->msg_out_len); - - esp->ops->send_dma_cmd(esp, - esp->command_block_dma, - esp->msg_out_len, - esp->msg_out_len, - 0, - ESP_CMD_DMA|ESP_CMD_TI); - } - } - esp_event(esp, ESP_EVENT_MSGOUT_DONE); - break; - } - case ESP_EVENT_MSGOUT_DONE: - if (esp->rev == FASHME) { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } else { - if (esp->msg_out_len > 1) - esp->ops->dma_invalidate(esp); - } - - if (!(esp->ireg & ESP_INTR_DC)) { - if (esp->rev != FASHME) - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - case ESP_EVENT_MSGIN: - if (esp->ireg & ESP_INTR_BSERV) { - if (esp->rev == FASHME) { - if (!(esp_read8(ESP_STATUS2) & - ESP_STAT2_FEMPTY)) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } else { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP100) - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - scsi_esp_cmd(esp, ESP_CMD_TI); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - } - if (esp->ireg & ESP_INTR_FDONE) { - u8 val; - - if (esp->rev == FASHME) - val = esp->fifo[0]; - else - val = esp_read8(ESP_FDATA); - esp->msg_in[esp->msg_in_len++] = val; - - esp_log_msgin("ESP: Got msgin byte %x\n", val); - - if (!esp_msgin_process(esp)) - esp->msg_in_len = 0; - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - scsi_esp_cmd(esp, ESP_CMD_MOK); - - if (esp->event != ESP_EVENT_FREE_BUS) - esp_event(esp, ESP_EVENT_CHECK_PHASE); - } else { - printk("ESP: MSGIN neither BSERV not FDON, resetting"); - esp_schedule_reset(esp); - return 0; - } - break; - case ESP_EVENT_CMD_START: - memcpy(esp->command_block, esp->cmd_bytes_ptr, - esp->cmd_bytes_left); - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - esp->cmd_bytes_left, 16, 0, - ESP_CMD_DMA | ESP_CMD_TI); - esp_event(esp, ESP_EVENT_CMD_DONE); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - case ESP_EVENT_CMD_DONE: - esp->ops->dma_invalidate(esp); - if (esp->ireg & ESP_INTR_BSERV) { - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - } - esp_schedule_reset(esp); - return 0; - break; - - case ESP_EVENT_RESET: - scsi_esp_cmd(esp, ESP_CMD_RS); - break; - - default: - printk("ESP: Unexpected event %x, resetting\n", - esp->event); - esp_schedule_reset(esp); - return 0; - break; - } - return 1; -} - -static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, cmd->device->hostdata); - cmd->result = DID_RESET << 16; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } - - cmd->scsi_done(cmd); - list_del(&ent->list); - esp_put_ent(esp, ent); -} - -static void esp_clear_hold(struct scsi_device *dev, void *data) -{ - struct esp_lun_data *lp = dev->hostdata; - - BUG_ON(lp->num_tagged); - lp->hold = 0; -} - -static void esp_reset_cleanup(struct esp *esp) -{ - struct esp_cmd_entry *ent, *tmp; - int i; - - list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) { - struct scsi_cmnd *cmd = ent->cmd; - - list_del(&ent->list); - cmd->result = DID_RESET << 16; - cmd->scsi_done(cmd); - esp_put_ent(esp, ent); - } - - list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) { - if (ent == esp->active_cmd) - esp->active_cmd = NULL; - esp_reset_cleanup_one(esp, ent); - } - - BUG_ON(esp->active_cmd != NULL); - - /* Force renegotiation of sync/wide transfers. */ - for (i = 0; i < ESP_MAX_TARGET; i++) { - struct esp_target_data *tp = &esp->target[i]; - - tp->esp_period = 0; - tp->esp_offset = 0; - tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE | - ESP_CONFIG3_FSCSI | - ESP_CONFIG3_FAST); - tp->flags &= ~ESP_TGT_WIDE; - tp->flags |= ESP_TGT_CHECK_NEGO; - - if (tp->starget) - starget_for_each_device(tp->starget, NULL, - esp_clear_hold); - } -} - -/* Runs under host->lock */ -static void __esp_interrupt(struct esp *esp) -{ - int finish_reset, intr_done; - u8 phase; - - esp->sreg = esp_read8(ESP_STATUS); - - if (esp->flags & ESP_FLAG_RESETTING) { - finish_reset = 1; - } else { - if (esp_check_gross_error(esp)) - return; - - finish_reset = esp_check_spur_intr(esp); - if (finish_reset < 0) - return; - } - - esp->ireg = esp_read8(ESP_INTRPT); - - if (esp->ireg & ESP_INTR_SR) - finish_reset = 1; - - if (finish_reset) { - esp_reset_cleanup(esp); - if (esp->eh_reset) { - complete(esp->eh_reset); - esp->eh_reset = NULL; - } - return; - } - - phase = (esp->sreg & ESP_STAT_PMASK); - if (esp->rev == FASHME) { - if (((phase != ESP_DIP && phase != ESP_DOP) && - esp->select_state == ESP_SELECT_NONE && - esp->event != ESP_EVENT_STATUS && - esp->event != ESP_EVENT_DATA_DONE) || - (esp->ireg & ESP_INTR_RSEL)) { - esp->sreg2 = esp_read8(ESP_STATUS2); - if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || - (esp->sreg2 & ESP_STAT2_F1BYTE)) - hme_read_fifo(esp); - } - } - - esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] " - "sreg2[%02x] ireg[%02x]\n", - esp->sreg, esp->seqreg, esp->sreg2, esp->ireg); - - intr_done = 0; - - if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) { - printk("ESP: unexpected IREG %02x\n", esp->ireg); - if (esp->ireg & ESP_INTR_IC) - esp_dump_cmd_log(esp); - - esp_schedule_reset(esp); - } else { - if (!(esp->ireg & ESP_INTR_RSEL)) { - /* Some combination of FDONE, BSERV, DC. */ - if (esp->select_state != ESP_SELECT_NONE) - intr_done = esp_finish_select(esp); - } else if (esp->ireg & ESP_INTR_RSEL) { - if (esp->active_cmd) - (void) esp_finish_select(esp); - intr_done = esp_reconnect(esp); - } - } - while (!intr_done) - intr_done = esp_process_event(esp); -} - -irqreturn_t scsi_esp_intr(int irq, void *dev_id) -{ - struct esp *esp = dev_id; - unsigned long flags; - irqreturn_t ret; - - spin_lock_irqsave(esp->host->host_lock, flags); - ret = IRQ_NONE; - if (esp->ops->irq_pending(esp)) { - ret = IRQ_HANDLED; - for (;;) { - int i; - - __esp_interrupt(esp); - if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK)) - break; - esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK; - - for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) - break; - } - if (i == ESP_QUICKIRQ_LIMIT) - break; - } - } - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return ret; -} -EXPORT_SYMBOL(scsi_esp_intr); - -static void __devinit esp_get_revision(struct esp *esp) -{ - u8 val; - - esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); - esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); - esp_write8(esp->config2, ESP_CFG2); - - val = esp_read8(ESP_CFG2); - val &= ~ESP_CONFIG2_MAGIC; - if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { - /* If what we write to cfg2 does not come back, cfg2 is not - * implemented, therefore this must be a plain esp100. - */ - esp->rev = ESP100; - } else { - esp->config2 = 0; - esp_set_all_config3(esp, 5); - esp->prev_cfg3 = 5; - esp_write8(esp->config2, ESP_CFG2); - esp_write8(0, ESP_CFG3); - esp_write8(esp->prev_cfg3, ESP_CFG3); - - val = esp_read8(ESP_CFG3); - if (val != 5) { - /* The cfg2 register is implemented, however - * cfg3 is not, must be esp100a. - */ - esp->rev = ESP100A; - } else { - esp_set_all_config3(esp, 0); - esp->prev_cfg3 = 0; - esp_write8(esp->prev_cfg3, ESP_CFG3); - - /* All of cfg{1,2,3} implemented, must be one of - * the fas variants, figure out which one. - */ - if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) { - esp->rev = FAST; - esp->sync_defp = SYNC_DEFP_FAST; - } else { - esp->rev = ESP236; - } - esp->config2 = 0; - esp_write8(esp->config2, ESP_CFG2); - } - } -} - -static void __devinit esp_init_swstate(struct esp *esp) -{ - int i; - - INIT_LIST_HEAD(&esp->queued_cmds); - INIT_LIST_HEAD(&esp->active_cmds); - INIT_LIST_HEAD(&esp->esp_cmd_pool); - - /* Start with a clear state, domain validation (via ->slave_configure, - * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged - * commands. - */ - for (i = 0 ; i < ESP_MAX_TARGET; i++) { - esp->target[i].flags = 0; - esp->target[i].nego_goal_period = 0; - esp->target[i].nego_goal_offset = 0; - esp->target[i].nego_goal_width = 0; - esp->target[i].nego_goal_tags = 0; - } -} - -/* This places the ESP into a known state at boot time. */ -static void __devinit esp_bootup_reset(struct esp *esp) -{ - u8 val; - - /* Reset the DMA */ - esp->ops->reset_dma(esp); - - /* Reset the ESP */ - esp_reset_esp(esp); - - /* Reset the SCSI bus, but tell ESP not to generate an irq */ - val = esp_read8(ESP_CFG1); - val |= ESP_CONFIG1_SRRDISAB; - esp_write8(val, ESP_CFG1); - - scsi_esp_cmd(esp, ESP_CMD_RS); - udelay(400); - - esp_write8(esp->config1, ESP_CFG1); - - /* Eat any bitrot in the chip and we are done... */ - esp_read8(ESP_INTRPT); -} - -static void __devinit esp_set_clock_params(struct esp *esp) -{ - int fmhz; - u8 ccf; - - /* This is getting messy but it has to be done correctly or else - * you get weird behavior all over the place. We are trying to - * basically figure out three pieces of information. - * - * a) Clock Conversion Factor - * - * This is a representation of the input crystal clock frequency - * going into the ESP on this machine. Any operation whose timing - * is longer than 400ns depends on this value being correct. For - * example, you'll get blips for arbitration/selection during high - * load or with multiple targets if this is not set correctly. - * - * b) Selection Time-Out - * - * The ESP isn't very bright and will arbitrate for the bus and try - * to select a target forever if you let it. This value tells the - * ESP when it has taken too long to negotiate and that it should - * interrupt the CPU so we can see what happened. The value is - * computed as follows (from NCR/Symbios chip docs). - * - * (Time Out Period) * (Input Clock) - * STO = ---------------------------------- - * (8192) * (Clock Conversion Factor) - * - * We use a time out period of 250ms (ESP_BUS_TIMEOUT). - * - * c) Imperical constants for synchronous offset and transfer period - * register values - * - * This entails the smallest and largest sync period we could ever - * handle on this ESP. - */ - fmhz = esp->cfreq; - - ccf = ((fmhz / 1000000) + 4) / 5; - if (ccf == 1) - ccf = 2; - - /* If we can't find anything reasonable, just assume 20MHZ. - * This is the clock frequency of the older sun4c's where I've - * been unable to find the clock-frequency PROM property. All - * other machines provide useful values it seems. - */ - if (fmhz <= 5000000 || ccf < 1 || ccf > 8) { - fmhz = 20000000; - ccf = 4; - } - - esp->cfact = (ccf == 8 ? 0 : ccf); - esp->cfreq = fmhz; - esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); - esp->ctick = ESP_TICK(ccf, esp->ccycle); - esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); - esp->sync_defp = SYNC_DEFP_SLOW; -} - -static const char *esp_chip_names[] = { - "ESP100", - "ESP100A", - "ESP236", - "FAS236", - "FAS100A", - "FAST", - "FASHME", -}; - -static struct scsi_transport_template *esp_transport_template; - -int __devinit scsi_esp_register(struct esp *esp, struct device *dev) -{ - static int instance; - int err; - - esp->host->transportt = esp_transport_template; - esp->host->max_lun = ESP_MAX_LUN; - esp->host->cmd_per_lun = 2; - - esp_set_clock_params(esp); - - esp_get_revision(esp); - - esp_init_swstate(esp); - - esp_bootup_reset(esp); - - printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n", - esp->host->unique_id, esp->regs, esp->dma_regs, - esp->host->irq); - printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n", - esp->host->unique_id, esp_chip_names[esp->rev], - esp->cfreq / 1000000, esp->cfact, esp->scsi_id); - - /* Let the SCSI bus reset settle. */ - ssleep(esp_bus_reset_settle); - - err = scsi_add_host(esp->host, dev); - if (err) - return err; - - esp->host->unique_id = instance++; - - scsi_scan_host(esp->host); - - return 0; -} -EXPORT_SYMBOL(scsi_esp_register); - -void __devexit scsi_esp_unregister(struct esp *esp) -{ - scsi_remove_host(esp->host); -} -EXPORT_SYMBOL(scsi_esp_unregister); - -static int esp_slave_alloc(struct scsi_device *dev) -{ - struct esp *esp = host_to_esp(dev->host); - struct esp_target_data *tp = &esp->target[dev->id]; - struct esp_lun_data *lp; - - lp = kzalloc(sizeof(*lp), GFP_KERNEL); - if (!lp) - return -ENOMEM; - dev->hostdata = lp; - - tp->starget = dev->sdev_target; - - spi_min_period(tp->starget) = esp->min_period; - spi_max_offset(tp->starget) = 15; - - if (esp->flags & ESP_FLAG_WIDE_CAPABLE) - spi_max_width(tp->starget) = 1; - else - spi_max_width(tp->starget) = 0; - - return 0; -} - -static int esp_slave_configure(struct scsi_device *dev) -{ - struct esp *esp = host_to_esp(dev->host); - struct esp_target_data *tp = &esp->target[dev->id]; - int goal_tags, queue_depth; - - goal_tags = 0; - - if (dev->tagged_supported) { - /* XXX make this configurable somehow XXX */ - goal_tags = ESP_DEFAULT_TAGS; - - if (goal_tags > ESP_MAX_TAG) - goal_tags = ESP_MAX_TAG; - } - - queue_depth = goal_tags; - if (queue_depth < dev->host->cmd_per_lun) - queue_depth = dev->host->cmd_per_lun; - - if (goal_tags) { - scsi_set_tag_type(dev, MSG_ORDERED_TAG); - scsi_activate_tcq(dev, queue_depth); - } else { - scsi_deactivate_tcq(dev, queue_depth); - } - tp->flags |= ESP_TGT_DISCONNECT; - - if (!spi_initial_dv(dev->sdev_target)) - spi_dv_device(dev); - - return 0; -} - -static void esp_slave_destroy(struct scsi_device *dev) -{ - struct esp_lun_data *lp = dev->hostdata; - - kfree(lp); - dev->hostdata = NULL; -} - -static int esp_eh_abort_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = host_to_esp(cmd->device->host); - struct esp_cmd_entry *ent, *tmp; - struct completion eh_done; - unsigned long flags; - - /* XXX This helps a lot with debugging but might be a bit - * XXX much for the final driver. - */ - spin_lock_irqsave(esp->host->host_lock, flags); - printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n", - esp->host->unique_id, cmd, cmd->cmnd[0]); - ent = esp->active_cmd; - if (ent) - printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - list_for_each_entry(ent, &esp->queued_cmds, list) { - printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - } - list_for_each_entry(ent, &esp->active_cmds, list) { - printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - } - esp_dump_cmd_log(esp); - spin_unlock_irqrestore(esp->host->host_lock, flags); - - spin_lock_irqsave(esp->host->host_lock, flags); - - ent = NULL; - list_for_each_entry(tmp, &esp->queued_cmds, list) { - if (tmp->cmd == cmd) { - ent = tmp; - break; - } - } - - if (ent) { - /* Easiest case, we didn't even issue the command - * yet so it is trivial to abort. - */ - list_del(&ent->list); - - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - - esp_put_ent(esp, ent); - - goto out_success; - } - - init_completion(&eh_done); - - ent = esp->active_cmd; - if (ent && ent->cmd == cmd) { - /* Command is the currently active command on - * the bus. If we already have an output message - * pending, no dice. - */ - if (esp->msg_out_len) - goto out_failure; - - /* Send out an abort, encouraging the target to - * go to MSGOUT phase by asserting ATN. - */ - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - ent->eh_done = &eh_done; - - scsi_esp_cmd(esp, ESP_CMD_SATN); - } else { - /* The command is disconnected. This is not easy to - * abort. For now we fail and let the scsi error - * handling layer go try a scsi bus reset or host - * reset. - * - * What we could do is put together a scsi command - * solely for the purpose of sending an abort message - * to the target. Coming up with all the code to - * cook up scsi commands, special case them everywhere, - * etc. is for questionable gain and it would be better - * if the generic scsi error handling layer could do at - * least some of that for us. - * - * Anyways this is an area for potential future improvement - * in this driver. - */ - goto out_failure; - } - - spin_unlock_irqrestore(esp->host->host_lock, flags); - - if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) { - spin_lock_irqsave(esp->host->host_lock, flags); - ent->eh_done = NULL; - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return FAILED; - } - - return SUCCESS; - -out_success: - spin_unlock_irqrestore(esp->host->host_lock, flags); - return SUCCESS; - -out_failure: - /* XXX This might be a good location to set ESP_TGT_BROKEN - * XXX since we know which target/lun in particular is - * XXX causing trouble. - */ - spin_unlock_irqrestore(esp->host->host_lock, flags); - return FAILED; -} - -static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = host_to_esp(cmd->device->host); - struct completion eh_reset; - unsigned long flags; - - init_completion(&eh_reset); - - spin_lock_irqsave(esp->host->host_lock, flags); - - esp->eh_reset = &eh_reset; - - /* XXX This is too simple... We should add lots of - * XXX checks here so that if we find that the chip is - * XXX very wedged we return failure immediately so - * XXX that we can perform a full chip reset. - */ - esp->flags |= ESP_FLAG_RESETTING; - scsi_esp_cmd(esp, ESP_CMD_RS); - - spin_unlock_irqrestore(esp->host->host_lock, flags); - - ssleep(esp_bus_reset_settle); - - if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) { - spin_lock_irqsave(esp->host->host_lock, flags); - esp->eh_reset = NULL; - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return FAILED; - } - - return SUCCESS; -} - -/* All bets are off, reset the entire device. */ -static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = host_to_esp(cmd->device->host); - unsigned long flags; - - spin_lock_irqsave(esp->host->host_lock, flags); - esp_bootup_reset(esp); - esp_reset_cleanup(esp); - spin_unlock_irqrestore(esp->host->host_lock, flags); - - ssleep(esp_bus_reset_settle); - - return SUCCESS; -} - -static const char *esp_info(struct Scsi_Host *host) -{ - return "esp"; -} - -struct scsi_host_template scsi_esp_template = { - .module = THIS_MODULE, - .name = "esp", - .info = esp_info, - .queuecommand = esp_queuecommand, - .slave_alloc = esp_slave_alloc, - .slave_configure = esp_slave_configure, - .slave_destroy = esp_slave_destroy, - .eh_abort_handler = esp_eh_abort_handler, - .eh_bus_reset_handler = esp_eh_bus_reset_handler, - .eh_host_reset_handler = esp_eh_host_reset_handler, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .use_clustering = ENABLE_CLUSTERING, - .max_sectors = 0xffff, - .skip_settle_delay = 1, -}; -EXPORT_SYMBOL(scsi_esp_template); - -static void esp_get_signalling(struct Scsi_Host *host) -{ - struct esp *esp = host_to_esp(host); - enum spi_signal_type type; - - if (esp->flags & ESP_FLAG_DIFFERENTIAL) - type = SPI_SIGNAL_HVD; - else - type = SPI_SIGNAL_SE; - - spi_signalling(host) = type; -} - -static void esp_set_offset(struct scsi_target *target, int offset) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = host_to_esp(host); - struct esp_target_data *tp = &esp->target[target->id]; - - tp->nego_goal_offset = offset; - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static void esp_set_period(struct scsi_target *target, int period) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = host_to_esp(host); - struct esp_target_data *tp = &esp->target[target->id]; - - tp->nego_goal_period = period; - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static void esp_set_width(struct scsi_target *target, int width) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = host_to_esp(host); - struct esp_target_data *tp = &esp->target[target->id]; - - tp->nego_goal_width = (width ? 1 : 0); - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static struct spi_function_template esp_transport_ops = { - .set_offset = esp_set_offset, - .show_offset = 1, - .set_period = esp_set_period, - .show_period = 1, - .set_width = esp_set_width, - .show_width = 1, - .get_signalling = esp_get_signalling, -}; - -static int __init esp_init(void) -{ - BUILD_BUG_ON(sizeof(struct scsi_pointer) < - sizeof(struct esp_cmd_priv)); - - esp_transport_template = spi_attach_transport(&esp_transport_ops); - if (!esp_transport_template) - return -ENODEV; - - return 0; -} - -static void __exit esp_exit(void) -{ - spi_release_transport(esp_transport_template); -} - -MODULE_DESCRIPTION("ESP SCSI driver core"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_param(esp_bus_reset_settle, int, 0); -MODULE_PARM_DESC(esp_bus_reset_settle, - "ESP scsi bus reset delay in seconds"); - -module_param(esp_debug, int, 0); -MODULE_PARM_DESC(esp_debug, -"ESP bitmapped debugging message enable value:\n" -" 0x00000001 Log interrupt events\n" -" 0x00000002 Log scsi commands\n" -" 0x00000004 Log resets\n" -" 0x00000008 Log message in events\n" -" 0x00000010 Log message out events\n" -" 0x00000020 Log command completion\n" -" 0x00000040 Log disconnects\n" -" 0x00000080 Log data start\n" -" 0x00000100 Log data done\n" -" 0x00000200 Log reconnects\n" -" 0x00000400 Log auto-sense data\n" -); - -module_init(esp_init); -module_exit(esp_exit); diff --git a/trunk/drivers/scsi/esp_scsi.h b/trunk/drivers/scsi/esp_scsi.h deleted file mode 100644 index 8d4a6690401f..000000000000 --- a/trunk/drivers/scsi/esp_scsi.h +++ /dev/null @@ -1,560 +0,0 @@ -/* esp_scsi.h: Defines and structures for the ESP drier. - * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) - */ - -#ifndef _ESP_SCSI_H -#define _ESP_SCSI_H - - /* Access Description Offset */ -#define ESP_TCLOW 0x00UL /* rw Low bits transfer count 0x00 */ -#define ESP_TCMED 0x01UL /* rw Mid bits transfer count 0x04 */ -#define ESP_FDATA 0x02UL /* rw FIFO data bits 0x08 */ -#define ESP_CMD 0x03UL /* rw SCSI command bits 0x0c */ -#define ESP_STATUS 0x04UL /* ro ESP status register 0x10 */ -#define ESP_BUSID ESP_STATUS /* wo BusID for sel/resel 0x10 */ -#define ESP_INTRPT 0x05UL /* ro Kind of interrupt 0x14 */ -#define ESP_TIMEO ESP_INTRPT /* wo Timeout for sel/resel 0x14 */ -#define ESP_SSTEP 0x06UL /* ro Sequence step register 0x18 */ -#define ESP_STP ESP_SSTEP /* wo Transfer period/sync 0x18 */ -#define ESP_FFLAGS 0x07UL /* ro Bits current FIFO info 0x1c */ -#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */ -#define ESP_CFG1 0x08UL /* rw First cfg register 0x20 */ -#define ESP_CFACT 0x09UL /* wo Clock conv factor 0x24 */ -#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */ -#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */ -#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */ -#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */ -#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */ -#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */ -#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */ -#define ESP_FGRND 0x0fUL /* rw Data base for fifo 0x3c */ -#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */ - -#define SBUS_ESP_REG_SIZE 0x40UL - -/* Bitfield meanings for the above registers. */ - -/* ESP config reg 1, read-write, found on all ESP chips */ -#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ -#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ -#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ -#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ -#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ -#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ - -/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ -#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */ -#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */ -#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ -#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tgtmode) */ -#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ -#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ -#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ -#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */ -#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,216) */ -#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (236) */ -#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */ -#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */ -#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ - -/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */ -#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */ -#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ -#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */ -#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ -#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */ -#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ -#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */ -#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ -#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ -#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ -#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ -#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ -#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ -#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ -#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ -#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ - -/* ESP command register read-write */ -/* Group 1 commands: These may be sent at any point in time to the ESP - * chip. None of them can generate interrupts 'cept - * the "SCSI bus reset" command if you have not disabled - * SCSI reset interrupts in the config1 ESP register. - */ -#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ -#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ -#define ESP_CMD_RC 0x02 /* Chip reset */ -#define ESP_CMD_RS 0x03 /* SCSI bus reset */ - -/* Group 2 commands: ESP must be an initiator and connected to a target - * for these commands to work. - */ -#define ESP_CMD_TI 0x10 /* Transfer Information */ -#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ -#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ -#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ -#define ESP_CMD_SATN 0x1a /* Set ATN */ -#define ESP_CMD_RATN 0x1b /* De-assert ATN */ - -/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected - * to a target as the initiator for these commands to work. - */ -#define ESP_CMD_SMSG 0x20 /* Send message */ -#define ESP_CMD_SSTAT 0x21 /* Send status */ -#define ESP_CMD_SDATA 0x22 /* Send data */ -#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ -#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ -#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ -#define ESP_CMD_DCNCT 0x27 /* Disconnect */ -#define ESP_CMD_RMSG 0x28 /* Receive Message */ -#define ESP_CMD_RCMD 0x29 /* Receive Command */ -#define ESP_CMD_RDATA 0x2a /* Receive Data */ -#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ - -/* Group 4 commands: The ESP must be in the disconnected state and must - * not be connected to any targets as initiator for - * these commands to work. - */ -#define ESP_CMD_RSEL 0x40 /* Reselect */ -#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ -#define ESP_CMD_SELA 0x42 /* Select w/ATN */ -#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ -#define ESP_CMD_ESEL 0x44 /* Enable selection */ -#define ESP_CMD_DSEL 0x45 /* Disable selections */ -#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ -#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ - -/* This bit enables the ESP's DMA on the SBus */ -#define ESP_CMD_DMA 0x80 /* Do DMA? */ - -/* ESP status register read-only */ -#define ESP_STAT_PIO 0x01 /* IO phase bit */ -#define ESP_STAT_PCD 0x02 /* CD phase bit */ -#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ -#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ -#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ -#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ -#define ESP_STAT_PERR 0x20 /* Parity error */ -#define ESP_STAT_SPAM 0x40 /* Real bad error */ -/* This indicates the 'interrupt pending' condition on esp236, it is a reserved - * bit on other revs of the ESP. - */ -#define ESP_STAT_INTR 0x80 /* Interrupt */ - -/* The status register can be masked with ESP_STAT_PMASK and compared - * with the following values to determine the current phase the ESP - * (at least thinks it) is in. For our purposes we also add our own - * software 'done' bit for our phase management engine. - */ -#define ESP_DOP (0) /* Data Out */ -#define ESP_DIP (ESP_STAT_PIO) /* Data In */ -#define ESP_CMDP (ESP_STAT_PCD) /* Command */ -#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ -#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ -#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ - -/* HME only: status 2 register */ -#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */ -#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */ -#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */ -#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */ -#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */ -#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */ -#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */ -#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */ - -/* ESP interrupt register read-only */ -#define ESP_INTR_S 0x01 /* Select w/o ATN */ -#define ESP_INTR_SATN 0x02 /* Select w/ATN */ -#define ESP_INTR_RSEL 0x04 /* Reselected */ -#define ESP_INTR_FDONE 0x08 /* Function done */ -#define ESP_INTR_BSERV 0x10 /* Bus service */ -#define ESP_INTR_DC 0x20 /* Disconnect */ -#define ESP_INTR_IC 0x40 /* Illegal command given */ -#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ - -/* ESP sequence step register read-only */ -#define ESP_STEP_VBITS 0x07 /* Valid bits */ -#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ -#define ESP_STEP_SID 0x01 /* One msg byte sent */ -#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ -#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd - * bytes to be lost - */ -#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ - -/* Ho hum, some ESP's set the step register to this as well... */ -#define ESP_STEP_FINI5 0x05 -#define ESP_STEP_FINI6 0x06 -#define ESP_STEP_FINI7 0x07 - -/* ESP chip-test register read-write */ -#define ESP_TEST_TARG 0x01 /* Target test mode */ -#define ESP_TEST_INI 0x02 /* Initiator test mode */ -#define ESP_TEST_TS 0x04 /* Tristate test mode */ - -/* ESP unique ID register read-only, found on fas236+fas100a only */ -#define ESP_UID_F100A 0x00 /* ESP FAS100A */ -#define ESP_UID_F236 0x02 /* ESP FAS236 */ -#define ESP_UID_REV 0x07 /* ESP revision */ -#define ESP_UID_FAM 0xf8 /* ESP family */ - -/* ESP fifo flags register read-only */ -/* Note that the following implies a 16 byte FIFO on the ESP. */ -#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ -#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */ -#define ESP_FF_SSTEP 0xe0 /* Sequence step */ - -/* ESP clock conversion factor register write-only */ -#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ -#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ -#define ESP_CCF_F2 0x02 /* 10MHz */ -#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ -#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ -#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ -#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ -#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ - -/* HME only... */ -#define ESP_BUSID_RESELID 0x10 -#define ESP_BUSID_CTR32BIT 0x40 - -#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */ -#define ESP_TIMEO_CONST 8192 -#define ESP_NEG_DEFP(mhz, cfact) \ - ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) -#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) -#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) - -/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high - * input clock rates we try to do 10mb/s although I don't think a transfer can - * even run that fast with an ESP even with DMA2 scatter gather pipelining. - */ -#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ -#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ - -struct esp_cmd_priv { - union { - dma_addr_t dma_addr; - int num_sg; - } u; - - unsigned int cur_residue; - struct scatterlist *cur_sg; - unsigned int tot_residue; -}; -#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp)) - -enum esp_rev { - ESP100 = 0x00, /* NCR53C90 - very broken */ - ESP100A = 0x01, /* NCR53C90A */ - ESP236 = 0x02, - FAS236 = 0x03, - FAS100A = 0x04, - FAST = 0x05, - FASHME = 0x06, -}; - -struct esp_cmd_entry { - struct list_head list; - - struct scsi_cmnd *cmd; - - unsigned int saved_cur_residue; - struct scatterlist *saved_cur_sg; - unsigned int saved_tot_residue; - - u8 flags; -#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */ -#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */ -#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ - - u8 tag[2]; - - u8 status; - u8 message; - - unsigned char *sense_ptr; - unsigned char *saved_sense_ptr; - dma_addr_t sense_dma; - - struct completion *eh_done; -}; - -/* XXX make this configurable somehow XXX */ -#define ESP_DEFAULT_TAGS 16 - -#define ESP_MAX_TARGET 16 -#define ESP_MAX_LUN 8 -#define ESP_MAX_TAG 256 - -struct esp_lun_data { - struct esp_cmd_entry *non_tagged_cmd; - int num_tagged; - int hold; - struct esp_cmd_entry *tagged_cmds[ESP_MAX_TAG]; -}; - -struct esp_target_data { - /* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which - * match the currently negotiated settings for this target. The SCSI - * protocol values are maintained in spi_{offset,period,wide}(starget). - */ - u8 esp_period; - u8 esp_offset; - u8 esp_config3; - - u8 flags; -#define ESP_TGT_WIDE 0x01 -#define ESP_TGT_DISCONNECT 0x02 -#define ESP_TGT_NEGO_WIDE 0x04 -#define ESP_TGT_NEGO_SYNC 0x08 -#define ESP_TGT_CHECK_NEGO 0x40 -#define ESP_TGT_BROKEN 0x80 - - /* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this - * device we will try to negotiate the following parameters. - */ - u8 nego_goal_period; - u8 nego_goal_offset; - u8 nego_goal_width; - u8 nego_goal_tags; - - struct scsi_target *starget; -}; - -struct esp_event_ent { - u8 type; -#define ESP_EVENT_TYPE_EVENT 0x01 -#define ESP_EVENT_TYPE_CMD 0x02 - u8 val; - - u8 sreg; - u8 seqreg; - u8 sreg2; - u8 ireg; - u8 select_state; - u8 event; - u8 __pad; -}; - -struct esp; -struct esp_driver_ops { - /* Read and write the ESP 8-bit registers. On some - * applications of the ESP chip the registers are at 4-byte - * instead of 1-byte intervals. - */ - void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg); - u8 (*esp_read8)(struct esp *esp, unsigned long reg); - - /* Map and unmap DMA memory. Eventually the driver will be - * converted to the generic DMA API as soon as SBUS is able to - * cope with that. At such time we can remove this. - */ - dma_addr_t (*map_single)(struct esp *esp, void *buf, - size_t sz, int dir); - int (*map_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - void (*unmap_single)(struct esp *esp, dma_addr_t addr, - size_t sz, int dir); - void (*unmap_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - - /* Return non-zero if there is an IRQ pending. Usually this - * status bit lives in the DMA controller sitting in front of - * the ESP. This has to be accurate or else the ESP interrupt - * handler will not run. - */ - int (*irq_pending)(struct esp *esp); - - /* Reset the DMA engine entirely. On return, ESP interrupts - * should be enabled. Often the interrupt enabling is - * controlled in the DMA engine. - */ - void (*reset_dma)(struct esp *esp); - - /* Drain any pending DMA in the DMA engine after a transfer. - * This is for writes to memory. - */ - void (*dma_drain)(struct esp *esp); - - /* Invalidate the DMA engine after a DMA transfer. */ - void (*dma_invalidate)(struct esp *esp); - - /* Setup an ESP command that will use a DMA transfer. - * The 'esp_count' specifies what transfer length should be - * programmed into the ESP transfer counter registers, whereas - * the 'dma_count' is the length that should be programmed into - * the DMA controller. Usually they are the same. If 'write' - * is non-zero, this transfer is a write into memory. 'cmd' - * holds the ESP command that should be issued by calling - * scsi_esp_cmd() at the appropriate time while programming - * the DMA hardware. - */ - void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count, - u32 dma_count, int write, u8 cmd); - - /* Return non-zero if the DMA engine is reporting an error - * currently. - */ - int (*dma_error)(struct esp *esp); -}; - -#define ESP_MAX_MSG_SZ 8 -#define ESP_EVENT_LOG_SZ 32 - -#define ESP_QUICKIRQ_LIMIT 100 -#define ESP_RESELECT_TAG_LIMIT 2500 - -struct esp { - void __iomem *regs; - void __iomem *dma_regs; - - const struct esp_driver_ops *ops; - - struct Scsi_Host *host; - void *dev; - - struct esp_cmd_entry *active_cmd; - - struct list_head queued_cmds; - struct list_head active_cmds; - - u8 *command_block; - dma_addr_t command_block_dma; - - unsigned int data_dma_len; - - /* The following are used to determine the cause of an IRQ. Upon every - * IRQ entry we synchronize these with the hardware registers. - */ - u8 sreg; - u8 seqreg; - u8 sreg2; - u8 ireg; - - u32 prev_hme_dmacsr; - u8 prev_soff; - u8 prev_stp; - u8 prev_cfg3; - u8 __pad; - - struct list_head esp_cmd_pool; - - struct esp_target_data target[ESP_MAX_TARGET]; - - int fifo_cnt; - u8 fifo[16]; - - struct esp_event_ent esp_event_log[ESP_EVENT_LOG_SZ]; - int esp_event_cur; - - u8 msg_out[ESP_MAX_MSG_SZ]; - int msg_out_len; - - u8 msg_in[ESP_MAX_MSG_SZ]; - int msg_in_len; - - u8 bursts; - u8 config1; - u8 config2; - - u8 scsi_id; - u32 scsi_id_mask; - - enum esp_rev rev; - - u32 flags; -#define ESP_FLAG_DIFFERENTIAL 0x00000001 -#define ESP_FLAG_RESETTING 0x00000002 -#define ESP_FLAG_DOING_SLOWCMD 0x00000004 -#define ESP_FLAG_WIDE_CAPABLE 0x00000008 -#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010 - - u8 select_state; -#define ESP_SELECT_NONE 0x00 /* Not selecting */ -#define ESP_SELECT_BASIC 0x01 /* Select w/o MSGOUT phase */ -#define ESP_SELECT_MSGOUT 0x02 /* Select with MSGOUT */ - - /* When we are not selecting, we are expecting an event. */ - u8 event; -#define ESP_EVENT_NONE 0x00 -#define ESP_EVENT_CMD_START 0x01 -#define ESP_EVENT_CMD_DONE 0x02 -#define ESP_EVENT_DATA_IN 0x03 -#define ESP_EVENT_DATA_OUT 0x04 -#define ESP_EVENT_DATA_DONE 0x05 -#define ESP_EVENT_MSGIN 0x06 -#define ESP_EVENT_MSGIN_MORE 0x07 -#define ESP_EVENT_MSGIN_DONE 0x08 -#define ESP_EVENT_MSGOUT 0x09 -#define ESP_EVENT_MSGOUT_DONE 0x0a -#define ESP_EVENT_STATUS 0x0b -#define ESP_EVENT_FREE_BUS 0x0c -#define ESP_EVENT_CHECK_PHASE 0x0d -#define ESP_EVENT_RESET 0x10 - - /* Probed in esp_get_clock_params() */ - u32 cfact; - u32 cfreq; - u32 ccycle; - u32 ctick; - u32 neg_defp; - u32 sync_defp; - - /* Computed in esp_reset_esp() */ - u32 max_period; - u32 min_period; - u32 radelay; - - /* Slow command state. */ - u8 *cmd_bytes_ptr; - int cmd_bytes_left; - - struct completion *eh_reset; - - struct sbus_dma *dma; -}; - -#define host_to_esp(host) ((struct esp *)(host)->hostdata) - -/* A front-end driver for the ESP chip should do the following in - * it's device probe routine: - * 1) Allocate the host and private area using scsi_host_alloc() - * with size 'sizeof(struct esp)'. The first argument to - * scsi_host_alloc() should be &scsi_esp_template. - * 2) Set host->max_id as appropriate. - * 3) Set esp->host to the scsi_host itself, and esp->dev - * to the device object pointer. - * 4) Hook up esp->ops to the front-end implementation. - * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE - * in esp->flags. - * 6) Map the DMA and ESP chip registers. - * 7) DMA map the ESP command block, store the DMA address - * in esp->command_block_dma. - * 8) Register the scsi_esp_intr() interrupt handler. - * 9) Probe for and provide the following chip properties: - * esp->scsi_id (assign to esp->host->this_id too) - * esp->scsi_id_mask - * If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL - * esp->cfreq - * DMA burst bit mask in esp->bursts, if necessary - * 10) Perform any actions necessary before the ESP device can - * be programmed for the first time. On some configs, for - * example, the DMA engine has to be reset before ESP can - * be programmed. - * 11) If necessary, call dev_set_drvdata() as needed. - * 12) Call scsi_esp_register() with prepared 'esp' structure - * and a device pointer if possible. - * 13) Check scsi_esp_register() return value, release all resources - * if an error was returned. - */ -extern struct scsi_host_template scsi_esp_template; -extern int scsi_esp_register(struct esp *, struct device *); - -extern void scsi_esp_unregister(struct esp *); -extern irqreturn_t scsi_esp_intr(int, void *); -extern void scsi_esp_cmd(struct esp *, u8); - -#endif /* !(_ESP_SCSI_H) */ diff --git a/trunk/drivers/scsi/hosts.c b/trunk/drivers/scsi/hosts.c index bd8e7f323c69..38c3a291efac 100644 --- a/trunk/drivers/scsi/hosts.c +++ b/trunk/drivers/scsi/hosts.c @@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) struct class_device *cdev; struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p; - down(&class->sem); + down_read(&class->subsys.rwsem); list_for_each_entry(cdev, &class->children, node) { p = class_to_shost(cdev); if (p->host_no == hostnum) { @@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) break; } } - up(&class->sem); + up_read(&class->subsys.rwsem); return shost; } diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c index b10eefe735c5..fbc1d5c3b0a7 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -85,7 +85,7 @@ static int max_id = 64; static int max_channel = 3; static int init_timeout = 5; -static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; +static int max_requests = 50; #define IBMVSCSI_VERSION "1.5.8" @@ -538,8 +538,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, int request_status; int rc; - /* If we have exhausted our request limit, just fail this request, - * unless it is for a reset or abort. + /* If we have exhausted our request limit, just fail this request. * Note that there are rare cases involving driver generated requests * (such as task management requests) that the mid layer may think we * can handle more requests (can_queue) when we actually can't @@ -552,30 +551,9 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, */ if (request_status < -1) goto send_error; - /* Otherwise, we may have run out of requests. */ - /* Abort and reset calls should make it through. - * Nothing except abort and reset should use the last two - * slots unless we had two or less to begin with. - */ - else if (request_status < 2 && - evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) { - /* In the case that we have less than two requests - * available, check the server limit as a combination - * of the request limit and the number of requests - * in-flight (the size of the send list). If the - * server limit is greater than 2, return busy so - * that the last two are reserved for reset and abort. - */ - int server_limit = request_status; - struct srp_event_struct *tmp_evt; - - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - server_limit++; - } - - if (server_limit > 2) - goto send_busy; - } + /* Otherwise, if we have run out of requests */ + else if (request_status < 0) + goto send_busy; } /* Copy the IU into the transfer area */ @@ -594,7 +572,6 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, printk(KERN_ERR "ibmvscsi: send error %d\n", rc); - atomic_inc(&hostdata->request_limit); goto send_error; } @@ -604,8 +581,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); - atomic_inc(&hostdata->request_limit); - return SCSI_MLQUEUE_HOST_BUSY; + return SCSI_MLQUEUE_HOST_BUSY; send_error: unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); @@ -855,16 +831,23 @@ static void login_rsp(struct srp_event_struct *evt_struct) printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); - if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0) - printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n"); + if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta > + (max_requests - 2)) + evt_struct->xfer_iu->srp.login_rsp.req_lim_delta = + max_requests - 2; - /* Now we know what the real request-limit is. - * This value is set rather than added to request_limit because - * request_limit could have been set to -1 by this client. - */ + /* Now we know what the real request-limit is */ atomic_set(&hostdata->request_limit, evt_struct->xfer_iu->srp.login_rsp.req_lim_delta); + hostdata->host->can_queue = + evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2; + + if (hostdata->host->can_queue < 1) { + printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); + return; + } + /* If we had any pending I/Os, kick them */ scsi_unblock_requests(hostdata->host); @@ -1354,27 +1337,6 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, return rc; } -/** - * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk. - * @sdev: struct scsi_device device to configure - * - * Enable allow_restart for a device if it is a disk. Adjust the - * queue_depth here also as is required by the documentation for - * struct scsi_host_template. - */ -static int ibmvscsi_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - unsigned long lock_flags = 0; - - spin_lock_irqsave(shost->host_lock, lock_flags); - if (sdev->type == TYPE_DISK) - sdev->allow_restart = 1; - scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); - spin_unlock_irqrestore(shost->host_lock, lock_flags); - return 0; -} - /* ------------------------------------------------------------ * sysfs attributes */ @@ -1520,9 +1482,8 @@ static struct scsi_host_template driver_template = { .queuecommand = ibmvscsi_queuecommand, .eh_abort_handler = ibmvscsi_eh_abort_handler, .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, - .slave_configure = ibmvscsi_slave_configure, .cmd_per_lun = 16, - .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, + .can_queue = 1, /* Updated after SRP_LOGIN */ .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, @@ -1542,7 +1503,6 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) vdev->dev.driver_data = NULL; - driver_template.can_queue = max_requests; host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); if (!host) { printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n"); diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h index 77cc1d40f5bb..5c6d93582929 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -44,8 +44,6 @@ struct Scsi_Host; */ #define MAX_INDIRECT_BUFS 10 -#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100 - /* ------------------------------------------------------------ * Data Structures */ diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c b/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c index 6d223dd76440..4368ca0e8270 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -35,7 +35,7 @@ #include "ibmvscsi.h" #define INITIAL_SRP_LIMIT 16 -#define DEFAULT_MAX_SECTORS 256 +#define DEFAULT_MAX_SECTORS 512 #define TGT_NAME "ibmvstgt" @@ -248,8 +248,8 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, md[i].va + mdone); if (err != H_SUCCESS) { - eprintk("rdma error %d %d %ld\n", dir, slen, err); - return -EIO; + eprintk("rdma error %d %d\n", dir, slen); + goto out; } mlen -= slen; @@ -265,35 +265,45 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, if (sidx > nsg) { eprintk("out of sg %p %d %d\n", iue, sidx, nsg); - return -EIO; + goto out; } } }; rest -= mlen; } +out: + return 0; } +static int ibmvstgt_transfer_data(struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)) +{ + struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; + int err; + + err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); + + done(sc); + + return err; +} + static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) { unsigned long flags; struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; struct srp_target *target = iue->target; - int err = 0; - - dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], - cmd->usg_sg); - if (sc->use_sg) - err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); + dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); spin_lock_irqsave(&target->lock, flags); list_del(&iue->ilist); spin_unlock_irqrestore(&target->lock, flags); - if (err|| sc->result != SAM_STAT_GOOD) { + if (sc->result != SAM_STAT_GOOD) { eprintk("operation failed %p %d %x\n", iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]); send_rsp(iue, sc, HARDWARE_ERROR, 0x00); @@ -493,8 +503,7 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target) { struct vio_port *vport = target_to_port(target); struct iu_entry *iue; - long err; - int done = 1; + long err, done; iue = srp_iu_get(target); if (!iue) { @@ -509,6 +518,7 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target) if (err != H_SUCCESS) { eprintk("%ld transferring data error %p\n", err, iue); + done = 1; goto out; } @@ -784,6 +794,7 @@ static struct scsi_host_template ibmvstgt_sht = { .use_clustering = DISABLE_CLUSTERING, .max_sectors = DEFAULT_MAX_SECTORS, .transfer_response = ibmvstgt_cmd_done, + .transfer_data = ibmvstgt_transfer_data, .eh_abort_handler = ibmvstgt_eh_abort_handler, .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, .shost_attrs = ibmvstgt_attrs, @@ -886,9 +897,9 @@ static int get_system_info(void) { struct device_node *rootdn; const char *id, *model, *name; - const unsigned int *num; + unsigned int *num; - rootdn = of_find_node_by_path("/"); + rootdn = find_path_device("/"); if (!rootdn) return -ENOENT; @@ -901,11 +912,10 @@ static int get_system_info(void) if (name) strncpy(partition_name, name, sizeof(partition_name)); - num = get_property(rootdn, "ibm,partition-no", NULL); + num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL); if (num) partition_number = *num; - of_node_put(rootdn); return 0; } diff --git a/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c b/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c index 0a533f398f52..227c0f2f4d74 100644 --- a/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -157,7 +157,7 @@ static void gather_partition_info(void) const unsigned int *p_number_ptr; /* Retrieve information about this partition */ - rootdn = of_find_node_by_path("/"); + rootdn = find_path_device("/"); if (!rootdn) { return; } @@ -169,7 +169,6 @@ static void gather_partition_info(void) p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL); if (p_number_ptr) partition_number = *p_number_ptr; - of_node_put(rootdn); } static void set_adapter_info(struct ibmvscsi_host_data *hostdata) diff --git a/trunk/drivers/scsi/ipr.c b/trunk/drivers/scsi/ipr.c index 2c7b77e833f9..95045e33710d 100644 --- a/trunk/drivers/scsi/ipr.c +++ b/trunk/drivers/scsi/ipr.c @@ -89,9 +89,10 @@ static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; static unsigned int ipr_max_speed = 1; static int ipr_testmode = 0; static unsigned int ipr_fastfail = 0; -static unsigned int ipr_transop_timeout = 0; +static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT; static unsigned int ipr_enable_cache = 1; static unsigned int ipr_debug = 0; +static int ipr_auto_create = 1; static DEFINE_SPINLOCK(ipr_driver_lock); /* This table describes the differences between DMA controller chips */ @@ -158,13 +159,15 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0); MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)"); module_param_named(debug, ipr_debug, int, 0); MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); +module_param_named(auto_create, ipr_auto_create, int, 0); +MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); /* A constant array of IOASCs/URCs/Error Messages */ static const struct ipr_error_table_t ipr_error_table[] = { - {0x00000000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x00000000, 1, 1, "8155: An unknown error was received"}, {0x00330000, 0, 0, "Soft underlength error"}, @@ -172,37 +175,37 @@ struct ipr_error_table_t ipr_error_table[] = { "Command to be cancelled not found"}, {0x00808000, 0, 0, "Qualified success"}, - {0x01080000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x01080000, 1, 1, "FFFE: Soft device bus error recovered by the IOA"}, - {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01088100, 0, 1, "4101: Soft device bus fabric error"}, - {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01170600, 0, 1, "FFF9: Device sector reassign successful"}, - {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01170900, 0, 1, "FFF7: Media error recovered by device rewrite procedures"}, - {0x01180200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01180200, 0, 1, "7001: IOA sector reassignment successful"}, - {0x01180500, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01180500, 0, 1, "FFF9: Soft media error. Sector reassignment recommended"}, - {0x01180600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01180600, 0, 1, "FFF7: Media error recovered by IOA rewrite procedures"}, - {0x01418000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01418000, 0, 1, "FF3D: Soft PCI bus error recovered by the IOA"}, - {0x01440000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x01440000, 1, 1, "FFF6: Device hardware error recovered by the IOA"}, - {0x01448100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01448100, 0, 1, "FFF6: Device hardware error recovered by the device"}, - {0x01448200, 1, IPR_DEFAULT_LOG_LEVEL, + {0x01448200, 1, 1, "FF3D: Soft IOA error recovered by the IOA"}, - {0x01448300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x01448300, 0, 1, "FFFA: Undefined device response recovered by the IOA"}, - {0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x014A0000, 1, 1, "FFF6: Device bus error, message or command phase"}, - {0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x014A8000, 0, 1, "FFFE: Task Management Function failed"}, - {0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x015D0000, 0, 1, "FFF6: Failure prediction threshold exceeded"}, - {0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x015D9200, 0, 1, "8009: Impending cache battery pack failure"}, {0x02040400, 0, 0, "34FF: Disk device format in progress"}, @@ -212,85 +215,85 @@ struct ipr_error_table_t ipr_error_table[] = { "No ready, IOA shutdown"}, {0x025A0000, 0, 0, "Not ready, IOA has been shutdown"}, - {0x02670100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x02670100, 0, 1, "3020: Storage subsystem configuration error"}, {0x03110B00, 0, 0, "FFF5: Medium error, data unreadable, recommend reassign"}, {0x03110C00, 0, 0, "7000: Medium error, data unreadable, do not reassign"}, - {0x03310000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x03310000, 0, 1, "FFF3: Disk media format bad"}, - {0x04050000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04050000, 0, 1, "3002: Addressed device failed to respond to selection"}, - {0x04080000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04080000, 1, 1, "3100: Device bus error"}, - {0x04080100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04080100, 0, 1, "3109: IOA timed out a device command"}, {0x04088000, 0, 0, "3120: SCSI bus is not operational"}, - {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04088100, 0, 1, "4100: Hard device bus fabric error"}, - {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04118000, 0, 1, "9000: IOA reserved area data check"}, - {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04118100, 0, 1, "9001: IOA reserved area invalid data pattern"}, - {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04118200, 0, 1, "9002: IOA reserved area LRC error"}, - {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04320000, 0, 1, "102E: Out of alternate sectors for disk storage"}, - {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04330000, 1, 1, "FFF4: Data transfer underlength error"}, - {0x04338000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04338000, 1, 1, "FFF4: Data transfer overlength error"}, - {0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x043E0100, 0, 1, "3400: Logical unit failure"}, - {0x04408500, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04408500, 0, 1, "FFF4: Device microcode is corrupt"}, - {0x04418000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04418000, 1, 1, "8150: PCI bus error"}, {0x04430000, 1, 0, "Unsupported device bus message received"}, - {0x04440000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04440000, 1, 1, "FFF4: Disk device problem"}, - {0x04448200, 1, IPR_DEFAULT_LOG_LEVEL, + {0x04448200, 1, 1, "8150: Permanent IOA failure"}, - {0x04448300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04448300, 0, 1, "3010: Disk device returned wrong response to IOA"}, - {0x04448400, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04448400, 0, 1, "8151: IOA microcode error"}, {0x04448500, 0, 0, "Device bus status error"}, - {0x04448600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04448600, 0, 1, "8157: IOA error requiring IOA reset to recover"}, {0x04448700, 0, 0, "ATA device status error"}, {0x04490000, 0, 0, "Message reject received from the device"}, - {0x04449200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04449200, 0, 1, "8008: A permanent cache battery pack failure occurred"}, - {0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x0444A000, 0, 1, "9090: Disk unit has been modified after the last known status"}, - {0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x0444A200, 0, 1, "9081: IOA detected device error"}, - {0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x0444A300, 0, 1, "9082: IOA detected device error"}, - {0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x044A0000, 1, 1, "3110: Device bus error, message or command phase"}, - {0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL, + {0x044A8000, 1, 1, "3110: SAS Command / Task Management Function failed"}, - {0x04670400, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04670400, 0, 1, "9091: Incorrect hardware configuration change has been detected"}, - {0x04678000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04678000, 0, 1, "9073: Invalid multi-adapter configuration"}, - {0x04678100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04678100, 0, 1, "4010: Incorrect connection between cascaded expanders"}, - {0x04678200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04678200, 0, 1, "4020: Connections exceed IOA design limits"}, - {0x04678300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04678300, 0, 1, "4030: Incorrect multipath connection"}, - {0x04679000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x04679000, 0, 1, "4110: Unsupported enclosure function"}, - {0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x046E0000, 0, 1, "FFF4: Command to logical unit failed"}, {0x05240000, 1, 0, "Illegal request, invalid request type or request packet"}, @@ -310,103 +313,101 @@ struct ipr_error_table_t ipr_error_table[] = { "Illegal request, command sequence error"}, {0x052C8000, 1, 0, "Illegal request, dual adapter support not enabled"}, - {0x06040500, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06040500, 0, 1, "9031: Array protection temporarily suspended, protection resuming"}, - {0x06040600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06040600, 0, 1, "9040: Array protection temporarily suspended, protection resuming"}, - {0x06288000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06288000, 0, 1, "3140: Device bus not ready to ready transition"}, - {0x06290000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06290000, 0, 1, "FFFB: SCSI bus was reset"}, {0x06290500, 0, 0, "FFFE: SCSI bus transition to single ended"}, {0x06290600, 0, 0, "FFFE: SCSI bus transition to LVD"}, - {0x06298000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06298000, 0, 1, "FFFB: SCSI bus was reset by another initiator"}, - {0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x063F0300, 0, 1, "3029: A device replacement has occurred"}, - {0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x064C8000, 0, 1, "9051: IOA cache data exists for a missing or failed device"}, - {0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x064C8100, 0, 1, "9055: Auxiliary cache IOA contains cache data needed by the primary IOA"}, - {0x06670100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06670100, 0, 1, "9025: Disk unit is not supported at its physical location"}, - {0x06670600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06670600, 0, 1, "3020: IOA detected a SCSI bus configuration error"}, - {0x06678000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678000, 0, 1, "3150: SCSI bus configuration error"}, - {0x06678100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678100, 0, 1, "9074: Asymmetric advanced function disk configuration"}, - {0x06678300, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678300, 0, 1, "4040: Incomplete multipath connection between IOA and enclosure"}, - {0x06678400, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678400, 0, 1, "4041: Incomplete multipath connection between enclosure and device"}, - {0x06678500, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678500, 0, 1, "9075: Incomplete multipath connection between IOA and remote IOA"}, - {0x06678600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06678600, 0, 1, "9076: Configuration error, missing remote IOA"}, - {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06679100, 0, 1, "4050: Enclosure does not support a required multipath function"}, - {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06690200, 0, 1, "9041: Array protection temporarily suspended"}, - {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x06698200, 0, 1, "9042: Corrupt array parity detected on specified device"}, - {0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B0200, 0, 1, "9030: Array no longer protected due to missing or failed disk unit"}, - {0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B8000, 0, 1, "9071: Link operational transition"}, - {0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B8100, 0, 1, "9072: Link not operational transition"}, - {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B8200, 0, 1, "9032: Array exposed but still protected"}, - {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1, - "70DD: Device forced failed by disrupt device command"}, - {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B9100, 0, 1, "4061: Multipath redundancy level got better"}, - {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x066B9200, 0, 1, "4060: Multipath redundancy level got worse"}, {0x07270000, 0, 0, "Failure due to other device"}, - {0x07278000, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278000, 0, 1, "9008: IOA does not support functions expected by devices"}, - {0x07278100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278100, 0, 1, "9010: Cache data associated with attached devices cannot be found"}, - {0x07278200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278200, 0, 1, "9011: Cache data belongs to devices other than those attached"}, - {0x07278400, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278400, 0, 1, "9020: Array missing 2 or more devices with only 1 device present"}, - {0x07278500, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278500, 0, 1, "9021: Array missing 2 or more devices with 2 or more devices present"}, - {0x07278600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278600, 0, 1, "9022: Exposed array is missing a required device"}, - {0x07278700, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278700, 0, 1, "9023: Array member(s) not at required physical locations"}, - {0x07278800, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278800, 0, 1, "9024: Array not functional due to present hardware configuration"}, - {0x07278900, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278900, 0, 1, "9026: Array not functional due to present hardware configuration"}, - {0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278A00, 0, 1, "9027: Array is missing a device and parity is out of sync"}, - {0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278B00, 0, 1, "9028: Maximum number of arrays already exist"}, - {0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278C00, 0, 1, "9050: Required cache data cannot be located for a disk unit"}, - {0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278D00, 0, 1, "9052: Cache data exists for a device that has been modified"}, - {0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07278F00, 0, 1, "9054: IOA resources not available due to previous problems"}, - {0x07279100, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279100, 0, 1, "9092: Disk unit requires initialization before use"}, - {0x07279200, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279200, 0, 1, "9029: Incorrect hardware configuration change has been detected"}, - {0x07279600, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279600, 0, 1, "9060: One or more disk pairs are missing from an array"}, - {0x07279700, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279700, 0, 1, "9061: One or more disks are missing from an array"}, - {0x07279800, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279800, 0, 1, "9062: One or more disks are missing from an array"}, - {0x07279900, 0, IPR_DEFAULT_LOG_LEVEL, + {0x07279900, 0, 1, "9063: Maximum number of functional arrays has been exceeded"}, {0x0B260000, 0, 0, "Aborted command, invalid descriptor"}, @@ -480,16 +481,12 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) { struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; - dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr); memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); ioarcb->write_data_transfer_length = 0; ioarcb->read_data_transfer_length = 0; ioarcb->write_ioadl_len = 0; ioarcb->read_ioadl_len = 0; - ioarcb->write_ioadl_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; ioasa->ioasc = 0; ioasa->residual_data_len = 0; ioasa->u.gata.status = 0; @@ -1613,7 +1610,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, /* Set indication we have logged an error */ ioa_cfg->errors_logged++; - if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam) + if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) return; if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw)) hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw)); @@ -3773,8 +3770,7 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, * Return value: * 0 on success / non-zero on failure **/ -static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes, - unsigned long deadline) +static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes) { struct ipr_sata_port *sata_port = ap->private_data; struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; @@ -3853,8 +3849,6 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; - if (ipr_cmd->qc) - ipr_cmd->done = ipr_sata_eh_done; if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; @@ -4235,14 +4229,6 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, sglist = scsi_cmd->request_buffer; - if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) { - ioadl = ioarcb->add_data.u.ioadl; - ioarcb->write_ioadl_addr = - cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) + - offsetof(struct ipr_ioarcb, add_data)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - } - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { ioadl[i].flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i])); @@ -4273,11 +4259,6 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, scsi_cmd->sc_data_direction); if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) { - ioadl = ioarcb->add_data.u.ioadl; - ioarcb->write_ioadl_addr = - cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) + - offsetof(struct ipr_ioarcb, add_data)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; ipr_cmd->dma_use_sg = 1; ioadl[0].flags_and_data_len = cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST); @@ -4364,9 +4345,11 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) **/ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) { - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; - dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr); + struct ipr_ioarcb *ioarcb; + struct ipr_ioasa *ioasa; + + ioarcb = &ipr_cmd->ioarcb; + ioasa = &ipr_cmd->ioasa; memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); ioarcb->write_data_transfer_length = 0; @@ -4375,9 +4358,6 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) ioarcb->read_ioadl_len = 0; ioasa->ioasc = 0; ioasa->residual_data_len = 0; - ioarcb->write_ioadl_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; } /** @@ -4476,13 +4456,12 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, { int i; u16 data_len; - u32 ioasc, fd_ioasc; + u32 ioasc; struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; __be32 *ioasa_data = (__be32 *)ioasa; int error_index; ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK; - fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK; if (0 == ioasc) return; @@ -4490,19 +4469,13 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) return; - if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc) - error_index = ipr_get_error(fd_ioasc); - else - error_index = ipr_get_error(ioasc); + error_index = ipr_get_error(ioasc); if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) { /* Don't log an error if the IOA already logged one */ if (ioasa->ilid != 0) return; - if (!ipr_is_gscsi(res)) - return; - if (ipr_error_table[error_index].log_ioasa == 0) return; } @@ -4662,11 +4635,11 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, return; } - if (!ipr_is_gscsi(res)) + if (ipr_is_gscsi(res)) + ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); + else ipr_gen_sense(ipr_cmd); - ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); - switch (ioasc & IPR_IOASC_IOASC_MASK) { case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: if (ipr_is_naca_model(res)) @@ -5147,7 +5120,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) struct ipr_ioarcb_ata_regs *regs; if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) - return AC_ERR_SYSTEM; + return -EIO; ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ioarcb = &ipr_cmd->ioarcb; @@ -5192,7 +5165,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) default: WARN_ON(1); - return AC_ERR_INVALID; + return -1; } mb(); @@ -6214,7 +6187,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n"); ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ); + ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ); ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout; ipr_cmd->done = ipr_reset_ioa_job; add_timer(&ipr_cmd->timer); @@ -6411,7 +6384,6 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc != PCIBIOS_SUCCESSFUL) { - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); rc = IPR_RC_JOB_CONTINUE; } else { @@ -7144,6 +7116,8 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, ioa_cfg->pdev = pdev; ioa_cfg->log_level = ipr_log_level; ioa_cfg->doorbell = IPR_DOORBELL; + if (!ipr_auto_create) + ioa_cfg->doorbell |= IPR_RUNTIME_RESET; sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER); sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL); sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL); @@ -7258,13 +7232,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto out_scsi_host_put; } - if (ipr_transop_timeout) - ioa_cfg->transop_timeout = ipr_transop_timeout; - else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) - ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT; - else - ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT; - ipr_regs_pci = pci_resource_start(pdev, 0); rc = pci_request_regions(pdev, IPR_NAME); @@ -7572,45 +7539,29 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); diff --git a/trunk/drivers/scsi/ipr.h b/trunk/drivers/scsi/ipr.h index bc53d7cebe0a..88f285de97bb 100644 --- a/trunk/drivers/scsi/ipr.h +++ b/trunk/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.3.2" -#define IPR_DRIVER_DATE "(March 23, 2007)" +#define IPR_DRIVER_VERSION "2.3.1" +#define IPR_DRIVER_DATE "(January 23, 2007)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -55,7 +55,6 @@ #define IPR_NUM_BASE_CMD_BLKS 100 #define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339 -#define PCI_DEVICE_ID_IBM_SCAMP_E 0x034A #define IPR_SUBS_DEV_ID_2780 0x0264 #define IPR_SUBS_DEV_ID_5702 0x0266 @@ -70,12 +69,8 @@ #define IPR_SUBS_DEV_ID_572A 0x02C1 #define IPR_SUBS_DEV_ID_572B 0x02C2 #define IPR_SUBS_DEV_ID_572F 0x02C3 -#define IPR_SUBS_DEV_ID_574D 0x030B -#define IPR_SUBS_DEV_ID_574E 0x030A #define IPR_SUBS_DEV_ID_575B 0x030D #define IPR_SUBS_DEV_ID_575C 0x0338 -#define IPR_SUBS_DEV_ID_575D 0x033E -#define IPR_SUBS_DEV_ID_57B3 0x033A #define IPR_SUBS_DEV_ID_57B7 0x0360 #define IPR_SUBS_DEV_ID_57B8 0x02C2 @@ -109,9 +104,6 @@ #define IPR_IOASC_IOA_WAS_RESET 0x10000001 #define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002 -/* Driver data flags */ -#define IPR_USE_LONG_TRANSOP_TIMEOUT 0x00000001 - #define IPR_DEFAULT_MAX_ERROR_DUMP 984 #define IPR_NUM_LOG_HCAMS 2 #define IPR_NUM_CFG_CHG_HCAMS 2 @@ -187,7 +179,6 @@ #define IPR_SET_SUP_DEVICE_TIMEOUT (2 * 60 * HZ) #define IPR_REQUEST_SENSE_TIMEOUT (10 * HZ) #define IPR_OPERATIONAL_TIMEOUT (5 * 60) -#define IPR_LONG_OPERATIONAL_TIMEOUT (12 * 60) #define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ) #define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) #define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) @@ -422,25 +413,9 @@ struct ipr_ioarcb_ata_regs { u8 ctl; }__attribute__ ((packed, aligned(4))); -struct ipr_ioadl_desc { - __be32 flags_and_data_len; -#define IPR_IOADL_FLAGS_MASK 0xff000000 -#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK) -#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff -#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK) -#define IPR_IOADL_FLAGS_READ 0x48000000 -#define IPR_IOADL_FLAGS_READ_LAST 0x49000000 -#define IPR_IOADL_FLAGS_WRITE 0x68000000 -#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000 -#define IPR_IOADL_FLAGS_LAST 0x01000000 - - __be32 address; -}__attribute__((packed, aligned (8))); - struct ipr_ioarcb_add_data { union { struct ipr_ioarcb_ata_regs regs; - struct ipr_ioadl_desc ioadl[5]; __be32 add_cmd_parms[10]; }u; }__attribute__ ((packed, aligned(4))); @@ -472,6 +447,21 @@ struct ipr_ioarcb { struct ipr_ioarcb_add_data add_data; }__attribute__((packed, aligned (4))); +struct ipr_ioadl_desc { + __be32 flags_and_data_len; +#define IPR_IOADL_FLAGS_MASK 0xff000000 +#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK) +#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff +#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK) +#define IPR_IOADL_FLAGS_READ 0x48000000 +#define IPR_IOADL_FLAGS_READ_LAST 0x49000000 +#define IPR_IOADL_FLAGS_WRITE 0x68000000 +#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000 +#define IPR_IOADL_FLAGS_LAST 0x01000000 + + __be32 address; +}__attribute__((packed, aligned (8))); + struct ipr_ioasa_vset { __be32 failing_lba_hi; __be32 failing_lba_lo; @@ -1129,7 +1119,6 @@ struct ipr_ioa_cfg { struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES]; - unsigned int transop_timeout; const struct ipr_chip_cfg_t *chip_cfg; void __iomem *hdw_dma_regs; /* iomapped PCI memory space */ diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index c9a3abf9e7b6..8f55e1431433 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -527,12 +527,12 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) * than 8K, but there are no targets that currently do this. * For now we fail until we find a vendor that needs it */ - if (ISCSI_DEF_MAX_RECV_SEG_LEN < + if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH < tcp_conn->in.datalen) { printk(KERN_ERR "iscsi_tcp: received buffer of len %u " "but conn buffer is only %u (opcode %0x)\n", tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode); rc = ISCSI_ERR_PROTO; break; } @@ -1762,7 +1762,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) * due to strange issues with iser these are not set * in iscsi_conn_setup */ - conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; + conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL); if (!tcp_conn) @@ -1777,24 +1777,14 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->tx_hash.flags = 0; - if (IS_ERR(tcp_conn->tx_hash.tfm)) { - printk(KERN_ERR "Could not create connection due to crc32c " - "loading error %ld. Make sure the crc32c module is " - "built as a module or into the kernel\n", - PTR_ERR(tcp_conn->tx_hash.tfm)); + if (IS_ERR(tcp_conn->tx_hash.tfm)) goto free_tcp_conn; - } tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->rx_hash.flags = 0; - if (IS_ERR(tcp_conn->rx_hash.tfm)) { - printk(KERN_ERR "Could not create connection due to crc32c " - "loading error %ld. Make sure the crc32c module is " - "built as a module or into the kernel\n", - PTR_ERR(tcp_conn->rx_hash.tfm)); + if (IS_ERR(tcp_conn->rx_hash.tfm)) goto free_tx_tfm; - } return cls_conn; @@ -2148,7 +2138,6 @@ static struct scsi_host_template iscsi_sht = { .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_XMIT_CMDS_MAX - 1, .sg_tablesize = ISCSI_SG_TABLESIZE, - .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_host_reset_handler = iscsi_eh_host_reset, diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index 3f5b9b445b29..7c75771c77ff 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -270,14 +269,14 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, goto out; } - senselen = be16_to_cpu(get_unaligned((__be16 *) data)); + senselen = be16_to_cpu(*(__be16 *)data); if (datalen < senselen) goto invalid_datalen; memcpy(sc->sense_buffer, data + 2, min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); debug_scsi("copied %d bytes of sense\n", - min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); + min(senselen, SCSI_SENSE_BUFFERSIZE)); } if (sc->sc_data_direction == DMA_TO_DEVICE) @@ -578,7 +577,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) } EXPORT_SYMBOL_GPL(iscsi_conn_failure); -static int iscsi_xmit_mtask(struct iscsi_conn *conn) +static int iscsi_xmit_imm_task(struct iscsi_conn *conn) { struct iscsi_hdr *hdr = conn->mtask->hdr; int rc, was_logout = 0; @@ -592,9 +591,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) if (rc) return rc; - /* done with this in-progress mtask */ - conn->mtask = NULL; - if (was_logout) { set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); return -ENODATA; @@ -647,9 +643,11 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) conn->ctask = NULL; } if (conn->mtask) { - rc = iscsi_xmit_mtask(conn); + rc = iscsi_xmit_imm_task(conn); if (rc) goto again; + /* done with this in-progress mtask */ + conn->mtask = NULL; } /* process immediate first */ @@ -660,10 +658,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); spin_unlock_bh(&conn->session->lock); - rc = iscsi_xmit_mtask(conn); + rc = iscsi_xmit_imm_task(conn); if (rc) goto again; } + /* done with this mtask */ + conn->mtask = NULL; } /* process command queue */ @@ -701,10 +701,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); spin_unlock_bh(&conn->session->lock); - rc = iscsi_xmit_mtask(conn); - if (rc) + rc = tt->xmit_mgmt_task(conn, conn->mtask); + if (rc) goto again; } + /* done with this mtask */ + conn->mtask = NULL; } return -ENODATA; @@ -1521,7 +1523,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) } spin_unlock_bh(&session->lock); - data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); + data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); if (!data) goto login_mtask_data_alloc_fail; conn->login_mtask->data = conn->data = data; @@ -1595,9 +1597,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) wake_up(&conn->ehwait); } - /* flush queued up work because we free the connection below */ - scsi_flush_work(session->host); - spin_lock_bh(&session->lock); kfree(conn->data); kfree(conn->persistent_address); diff --git a/trunk/drivers/scsi/libsas/sas_expander.c b/trunk/drivers/scsi/libsas/sas_expander.c index e34442e405e8..dc70c180e115 100644 --- a/trunk/drivers/scsi/libsas/sas_expander.c +++ b/trunk/drivers/scsi/libsas/sas_expander.c @@ -22,6 +22,7 @@ * */ +#include #include #include "sas_internal.h" diff --git a/trunk/drivers/scsi/libsrp.c b/trunk/drivers/scsi/libsrp.c index 5631c199a8eb..89403b00e042 100644 --- a/trunk/drivers/scsi/libsrp.c +++ b/trunk/drivers/scsi/libsrp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -224,7 +225,8 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, struct srp_direct_buf *md = NULL; struct scatterlist dummy, *sg = NULL; dma_addr_t token = 0; - int err = 0; + long err; + unsigned int done = 0; int nmd, nsg = 0, len; if (dma_map || ext_desc) { @@ -256,8 +258,8 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, sg_dma_address(&dummy) = token; err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, id->table_desc.len); - if (err) { - eprintk("Error copying indirect table %d\n", err); + if (err < 0) { + eprintk("Error copying indirect table %ld\n", err); goto free_mem; } } else { @@ -270,7 +272,6 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL); if (!nsg) { eprintk("fail to map %p %d\n", iue, sc->use_sg); - err = -EIO; goto free_mem; } len = min(sc->request_bufflen, id->len); @@ -286,7 +287,7 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, if (token && dma_map) dma_free_coherent(iue->target->dev, id->table_desc.len, md, token); - return err; + return done; } static int data_out_desc_size(struct srp_cmd *cmd) @@ -351,7 +352,7 @@ int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, break; default: eprintk("Unknown format %d %x\n", dir, format); - err = -EINVAL; + break; } return err; diff --git a/trunk/drivers/scsi/lpfc/lpfc_init.c b/trunk/drivers/scsi/lpfc/lpfc_init.c index dcf6106f557a..057fd7e0e379 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_init.c +++ b/trunk/drivers/scsi/lpfc/lpfc_init.c @@ -671,7 +671,7 @@ static int lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len) { uint8_t lenlo, lenhi; - int Length; + uint32_t Length; int i, j; int finished = 0; int index = 0; diff --git a/trunk/drivers/scsi/megaraid.c b/trunk/drivers/scsi/megaraid.c index 7fc6e06ea7e1..0aa3304f6b9b 100644 --- a/trunk/drivers/scsi/megaraid.c +++ b/trunk/drivers/scsi/megaraid.c @@ -2088,7 +2088,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) static inline int make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) { - *pdev = alloc_pci_dev(); + *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); if( *pdev == NULL ) return -1; diff --git a/trunk/drivers/scsi/osst.c b/trunk/drivers/scsi/osst.c index 08060fb478b6..a967fadb7439 100644 --- a/trunk/drivers/scsi/osst.c +++ b/trunk/drivers/scsi/osst.c @@ -87,7 +87,6 @@ MODULE_AUTHOR("Willem Riede"); MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); module_param(max_dev, int, 0444); MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); diff --git a/trunk/drivers/scsi/pci2000.h b/trunk/drivers/scsi/pci2000.h new file mode 100644 index 000000000000..0ebd8ce9e1de --- /dev/null +++ b/trunk/drivers/scsi/pci2000.h @@ -0,0 +1,197 @@ +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2000 device driver for Linux. + * + * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters + * + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. + * + * Technical updates and product information at: + * http://www.psidisk.com + * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support + * + ****************************************************************************/ +#ifndef _PCI2000_H +#define _PCI2000_H + +#include + +#ifndef PSI_EIDE_SCSIOP +#define PSI_EIDE_SCSIOP 1 + +#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s)) + +/************************************************/ +/* definition of standard data types */ +/************************************************/ +#define CHAR char +#define UCHAR unsigned char +#define SHORT short +#define USHORT unsigned short +#define BOOL long +#define LONG long +#define ULONG unsigned long +#define VOID void + +typedef CHAR *PCHAR; +typedef UCHAR *PUCHAR; +typedef SHORT *PSHORT; +typedef USHORT *PUSHORT; +typedef BOOL *PBOOL; +typedef LONG *PLONG; +typedef ULONG *PULONG; +typedef VOID *PVOID; + + +/************************************************/ +/* Misc. macros */ +/************************************************/ +#define ANY2SCSI(up, p) \ +((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \ +((UCHAR *)up)[1] = ((ULONG)(p)); + +#define SCSI2LONG(up) \ +( (((long)*(((UCHAR *)up))) << 16) \ ++ (((long)(((UCHAR *)up)[1])) << 8) \ ++ ((long)(((UCHAR *)up)[2])) ) + +#define XANY2SCSI(up, p) \ +((UCHAR *)up)[0] = ((long)(p)) >> 24; \ +((UCHAR *)up)[1] = ((long)(p)) >> 16; \ +((UCHAR *)up)[2] = ((long)(p)) >> 8; \ +((UCHAR *)up)[3] = ((long)(p)); + +#define XSCSI2LONG(up) \ +( (((long)(((UCHAR *)up)[0])) << 24) \ ++ (((long)(((UCHAR *)up)[1])) << 16) \ ++ (((long)(((UCHAR *)up)[2])) << 8) \ ++ ((long)(((UCHAR *)up)[3])) ) + +/************************************************/ +/* SCSI CDB operation codes */ +/************************************************/ +#define SCSIOP_TEST_UNIT_READY 0x00 +#define SCSIOP_REZERO_UNIT 0x01 +#define SCSIOP_REWIND 0x01 +#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 +#define SCSIOP_REQUEST_SENSE 0x03 +#define SCSIOP_FORMAT_UNIT 0x04 +#define SCSIOP_READ_BLOCK_LIMITS 0x05 +#define SCSIOP_REASSIGN_BLOCKS 0x07 +#define SCSIOP_READ6 0x08 +#define SCSIOP_RECEIVE 0x08 +#define SCSIOP_WRITE6 0x0A +#define SCSIOP_PRINT 0x0A +#define SCSIOP_SEND 0x0A +#define SCSIOP_SEEK6 0x0B +#define SCSIOP_TRACK_SELECT 0x0B +#define SCSIOP_SLEW_PRINT 0x0B +#define SCSIOP_SEEK_BLOCK 0x0C +#define SCSIOP_PARTITION 0x0D +#define SCSIOP_READ_REVERSE 0x0F +#define SCSIOP_WRITE_FILEMARKS 0x10 +#define SCSIOP_FLUSH_BUFFER 0x10 +#define SCSIOP_SPACE 0x11 +#define SCSIOP_INQUIRY 0x12 +#define SCSIOP_VERIFY6 0x13 +#define SCSIOP_RECOVER_BUF_DATA 0x14 +#define SCSIOP_MODE_SELECT 0x15 +#define SCSIOP_RESERVE_UNIT 0x16 +#define SCSIOP_RELEASE_UNIT 0x17 +#define SCSIOP_COPY 0x18 +#define SCSIOP_ERASE 0x19 +#define SCSIOP_MODE_SENSE 0x1A +#define SCSIOP_START_STOP_UNIT 0x1B +#define SCSIOP_STOP_PRINT 0x1B +#define SCSIOP_LOAD_UNLOAD 0x1B +#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C +#define SCSIOP_SEND_DIAGNOSTIC 0x1D +#define SCSIOP_MEDIUM_REMOVAL 0x1E +#define SCSIOP_READ_CAPACITY 0x25 +#define SCSIOP_READ 0x28 +#define SCSIOP_WRITE 0x2A +#define SCSIOP_SEEK 0x2B +#define SCSIOP_LOCATE 0x2B +#define SCSIOP_WRITE_VERIFY 0x2E +#define SCSIOP_VERIFY 0x2F +#define SCSIOP_SEARCH_DATA_HIGH 0x30 +#define SCSIOP_SEARCH_DATA_EQUAL 0x31 +#define SCSIOP_SEARCH_DATA_LOW 0x32 +#define SCSIOP_SET_LIMITS 0x33 +#define SCSIOP_READ_POSITION 0x34 +#define SCSIOP_SYNCHRONIZE_CACHE 0x35 +#define SCSIOP_COMPARE 0x39 +#define SCSIOP_COPY_COMPARE 0x3A +#define SCSIOP_WRITE_DATA_BUFF 0x3B +#define SCSIOP_READ_DATA_BUFF 0x3C +#define SCSIOP_CHANGE_DEFINITION 0x40 +#define SCSIOP_READ_SUB_CHANNEL 0x42 +#define SCSIOP_READ_TOC 0x43 +#define SCSIOP_READ_HEADER 0x44 +#define SCSIOP_PLAY_AUDIO 0x45 +#define SCSIOP_PLAY_AUDIO_MSF 0x47 +#define SCSIOP_PLAY_TRACK_INDEX 0x48 +#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 +#define SCSIOP_PAUSE_RESUME 0x4B +#define SCSIOP_LOG_SELECT 0x4C +#define SCSIOP_LOG_SENSE 0x4D +#define SCSIOP_MODE_SELECT10 0x55 +#define SCSIOP_MODE_SENSE10 0x5A +#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 +#define SCSIOP_MECHANISM_STATUS 0xBD +#define SCSIOP_READ_CD 0xBE + +// SCSI read capacity structure +typedef struct _READ_CAPACITY_DATA + { + ULONG blks; /* total blocks (converted to little endian) */ + ULONG blksiz; /* size of each (converted to little endian) */ + } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; + +// SCSI inquiry data +typedef struct _INQUIRYDATA + { + UCHAR DeviceType :5; + UCHAR DeviceTypeQualifier :3; + UCHAR DeviceTypeModifier :7; + UCHAR RemovableMedia :1; + UCHAR Versions; + UCHAR ResponseDataFormat; + UCHAR AdditionalLength; + UCHAR Reserved[2]; + UCHAR SoftReset :1; + UCHAR CommandQueue :1; + UCHAR Reserved2 :1; + UCHAR LinkedCommands :1; + UCHAR Synchronous :1; + UCHAR Wide16Bit :1; + UCHAR Wide32Bit :1; + UCHAR RelativeAddressing :1; + UCHAR VendorId[8]; + UCHAR ProductId[16]; + UCHAR ProductRevisionLevel[4]; + UCHAR VendorSpecific[20]; + UCHAR Reserved3[40]; + } INQUIRYDATA, *PINQUIRYDATA; + +#endif + +// function prototypes +int Pci2000_Detect (struct scsi_host_template *tpnt); +int Pci2000_Command (Scsi_Cmnd *SCpnt); +int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +int Pci2000_Abort (Scsi_Cmnd *SCpnt); +int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); +int Pci2000_Release (struct Scsi_Host *pshost); +int Pci2000_BiosParam (struct scsi_device *sdev, + struct block_device *bdev, + sector_t capacity, int geom[]); + +#endif diff --git a/trunk/drivers/scsi/pcmcia/Kconfig b/trunk/drivers/scsi/pcmcia/Kconfig index 7dd787f6ab27..eac8e179cfff 100644 --- a/trunk/drivers/scsi/pcmcia/Kconfig +++ b/trunk/drivers/scsi/pcmcia/Kconfig @@ -3,11 +3,11 @@ # menu "PCMCIA SCSI adapter support" - depends on SCSI!=n && PCMCIA!=n + depends on SCSI!=n && PCMCIA!=n && MODULES config PCMCIA_AHA152X tristate "Adaptec AHA152X PCMCIA support" - depends on !64BIT + depends on m && !64BIT select SCSI_SPI_ATTRS help Say Y here if you intend to attach this type of PCMCIA SCSI host @@ -18,6 +18,7 @@ config PCMCIA_AHA152X config PCMCIA_FDOMAIN tristate "Future Domain PCMCIA support" + depends on m help Say Y here if you intend to attach this type of PCMCIA SCSI host adapter to your computer. @@ -27,7 +28,7 @@ config PCMCIA_FDOMAIN config PCMCIA_NINJA_SCSI tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" - depends on !64BIT + depends on m && !64BIT help If you intend to attach this type of PCMCIA SCSI host adapter to your computer, say Y here and read @@ -61,6 +62,7 @@ config PCMCIA_NINJA_SCSI config PCMCIA_QLOGIC tristate "Qlogic PCMCIA support" + depends on m help Say Y here if you intend to attach this type of PCMCIA SCSI host adapter to your computer. @@ -70,6 +72,7 @@ config PCMCIA_QLOGIC config PCMCIA_SYM53C500 tristate "Symbios 53c500 PCMCIA support" + depends on m help Say Y here if you have a New Media Bus Toaster or other PCMCIA SCSI adapter based on the Symbios 53c500 controller. diff --git a/trunk/drivers/scsi/qla2xxx/qla_def.h b/trunk/drivers/scsi/qla2xxx/qla_def.h index e8948b679f5b..05f4f2a378eb 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_def.h +++ b/trunk/drivers/scsi/qla2xxx/qla_def.h @@ -1478,17 +1478,14 @@ typedef union { uint32_t b24 : 24; struct { -#ifdef __BIG_ENDIAN - uint8_t domain; - uint8_t area; - uint8_t al_pa; -#elif __LITTLE_ENDIAN + uint8_t d_id[3]; + uint8_t rsvd_1; + } r; + + struct { uint8_t al_pa; uint8_t area; uint8_t domain; -#else -#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!" -#endif uint8_t rsvd_1; } b; } port_id_t; diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index 3e296ab845b6..98c01cd5e1a8 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -11,11 +11,6 @@ #include "qla_devtbl.h" -#ifdef CONFIG_SPARC -#include -#include -#endif - /* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */ #ifndef EXT_IS_LUN_BIT_SET #define EXT_IS_LUN_BIT_SET(P,L) \ @@ -93,7 +88,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); - ha->isp_ops.nvram_config(ha); + rval = ha->isp_ops.nvram_config(ha); + if (rval) { + DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n", + ha->host_no)); + return rval; + } if (ha->flags.disable_serdes) { /* Mask HBA via NVRAM settings? */ @@ -1393,28 +1393,6 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de } } -/* On sparc systems, obtain port and node WWN from firmware - * properties. - */ -static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv) -{ -#ifdef CONFIG_SPARC - struct pci_dev *pdev = ha->pdev; - struct pcidev_cookie *pcp = pdev->sysdata; - struct device_node *dp = pcp->prom_node; - u8 *val; - int len; - - val = of_get_property(dp, "port-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->port_name, val, WWN_SIZE); - - val = of_get_property(dp, "node-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->node_name, val, WWN_SIZE); -#endif -} - /* * NVRAM configuration for ISP 2xxx * @@ -1431,7 +1409,6 @@ static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv) int qla2x00_nvram_config(scsi_qla_host_t *ha) { - int rval; uint8_t chksum = 0; uint16_t cnt; uint8_t *dptr1, *dptr2; @@ -1440,8 +1417,6 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) uint8_t *ptr = (uint8_t *)ha->request_ring; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - rval = QLA_SUCCESS; - /* Determine NVRAM starting address. */ ha->nvram_size = sizeof(nvram_t); ha->nvram_base = 0; @@ -1465,57 +1440,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); - qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " - "invalid -- WWPN) defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->parameter_block_version = ICB_VERSION; - - if (IS_QLA23XX(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->special_options[1] = BIT_7; - } else if (IS_QLA2200(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } else if (IS_QLA2100(ha)) { - nv->firmware_options[0] = BIT_3 | BIT_1; - nv->firmware_options[1] = BIT_5; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } - - nv->max_iocb_allocation = __constant_cpu_to_le16(256); - nv->execution_throttle = __constant_cpu_to_le16(16); - nv->retry_count = 8; - nv->retry_delay = 1; - - nv->port_name[0] = 33; - nv->port_name[3] = 224; - nv->port_name[4] = 139; - - qla2xxx_nvram_wwn_from_ofw(ha, nv); - - nv->login_timeout = 4; - - /* - * Set default host adapter parameters - */ - nv->host_p[1] = BIT_2; - nv->reset_delay = 5; - nv->port_down_retry_count = 8; - nv->max_luns_per_target = __constant_cpu_to_le16(8); - nv->link_down_timeout = 60; - - rval = 1; + return QLA_FUNCTION_FAILED; } #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) @@ -1728,11 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) } } - if (rval) { - DEBUG2_3(printk(KERN_WARNING - "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); - } - return (rval); + return QLA_SUCCESS; } static void @@ -3150,7 +3071,9 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_ops.get_flash_version(ha, ha->request_ring); - ha->isp_ops.nvram_config(ha); + rval = ha->isp_ops.nvram_config(ha); + if (rval) + goto isp_abort_retry; if (!qla2x00_restart_isp(ha)) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); @@ -3180,6 +3103,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } } } else { /* failed the ISP abort */ +isp_abort_retry: ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { if (ha->isp_abort_cnt == 0) { @@ -3366,32 +3290,9 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } -/* On sparc systems, obtain port and node WWN from firmware - * properties. - */ -static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv) -{ -#ifdef CONFIG_SPARC - struct pci_dev *pdev = ha->pdev; - struct pcidev_cookie *pcp = pdev->sysdata; - struct device_node *dp = pcp->prom_node; - u8 *val; - int len; - - val = of_get_property(dp, "port-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->port_name, val, WWN_SIZE); - - val = of_get_property(dp, "node-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->node_name, val, WWN_SIZE); -#endif -} - int qla24xx_nvram_config(scsi_qla_host_t *ha) { - int rval; struct init_cb_24xx *icb; struct nvram_24xx *nv; uint32_t *dptr; @@ -3399,7 +3300,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) uint32_t chksum; uint16_t cnt; - rval = QLA_SUCCESS; icb = (struct init_cb_24xx *)ha->init_cb; nv = (struct nvram_24xx *)ha->request_ring; @@ -3432,52 +3332,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], le16_to_cpu(nv->nvram_version)); - qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " - "invalid -- WWPN) defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); - nv->hard_address = __constant_cpu_to_le16(124); - nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); - nv->port_name[2] = 0x00; - nv->port_name[3] = 0xe0; - nv->port_name[4] = 0x8b; - nv->port_name[5] = 0x1c; - nv->port_name[6] = 0x55; - nv->port_name[7] = 0x86; - nv->node_name[0] = 0x20; - nv->node_name[1] = 0x00; - nv->node_name[2] = 0x00; - nv->node_name[3] = 0xe0; - nv->node_name[4] = 0x8b; - nv->node_name[5] = 0x1c; - nv->node_name[6] = 0x55; - nv->node_name[7] = 0x86; - qla24xx_nvram_wwn_from_ofw(ha, nv); - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); - nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); - nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(30); - - rval = 1; + return QLA_FUNCTION_FAILED; } /* Reset Initialization control block */ @@ -3624,11 +3479,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) ha->flags.process_response_queue = 1; } - if (rval) { - DEBUG2_3(printk(KERN_WARNING - "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); - } - return (rval); + return QLA_SUCCESS; } static int diff --git a/trunk/drivers/scsi/qla2xxx/qla_mbx.c b/trunk/drivers/scsi/qla2xxx/qla_mbx.c index 71e32a248528..83376f6ac3db 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mbx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mbx.c @@ -1280,14 +1280,14 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } else { if (name != NULL) { /* This function returns name in big endian. */ - name[0] = MSB(mcp->mb[2]); - name[1] = LSB(mcp->mb[2]); - name[2] = MSB(mcp->mb[3]); - name[3] = LSB(mcp->mb[3]); - name[4] = MSB(mcp->mb[6]); - name[5] = LSB(mcp->mb[6]); - name[6] = MSB(mcp->mb[7]); - name[7] = LSB(mcp->mb[7]); + name[0] = LSB(mcp->mb[2]); + name[1] = MSB(mcp->mb[2]); + name[2] = LSB(mcp->mb[3]); + name[3] = MSB(mcp->mb[3]); + name[4] = LSB(mcp->mb[6]); + name[5] = MSB(mcp->mb[6]); + name[6] = LSB(mcp->mb[7]); + name[7] = MSB(mcp->mb[7]); } DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n", diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index b78919a318e2..68f5d24b938b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(ql2xallocfwdump, "vary by ISP type. Default is 1 - allocate memory."); int ql2xextended_error_logging; -module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); +module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging. 1 - log errors."); @@ -157,8 +157,6 @@ static struct scsi_host_template qla24xx_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, - .scan_finished = qla2xxx_scan_finished, - .scan_start = qla2xxx_scan_start, .change_queue_depth = qla2x00_change_queue_depth, .change_queue_type = qla2x00_change_queue_type, .this_id = -1, @@ -1707,7 +1705,6 @@ qla2x00_remove_one(struct pci_dev *pdev) scsi_host_put(ha->host); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -1750,6 +1747,8 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->iobase) iounmap(ha->iobase); pci_release_regions(ha->pdev); + + pci_disable_device(ha->pdev); } static inline void diff --git a/trunk/drivers/scsi/qla2xxx/qla_sup.c b/trunk/drivers/scsi/qla2xxx/qla_sup.c index 206bda093da2..ff1dd4175a7f 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_sup.c +++ b/trunk/drivers/scsi/qla2xxx/qla_sup.c @@ -466,7 +466,6 @@ qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr) udelay(10); else rval = QLA_FUNCTION_TIMEOUT; - cond_resched(); } /* TODO: What happens if we time out? */ @@ -509,7 +508,6 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data) udelay(10); else rval = QLA_FUNCTION_TIMEOUT; - cond_resched(); } return rval; } @@ -1257,7 +1255,6 @@ qla2x00_poll_flash(scsi_qla_host_t *ha, uint32_t addr, uint8_t poll_data, } udelay(10); barrier(); - cond_resched(); } return status; } @@ -1406,7 +1403,6 @@ qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr, if (saddr % 100) udelay(10); *tmp_buf = data; - cond_resched(); } } @@ -1453,6 +1449,7 @@ uint8_t * qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, uint32_t offset, uint32_t length) { + unsigned long flags; uint32_t addr, midpoint; uint8_t *data; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -1461,6 +1458,7 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, qla2x00_suspend_hba(ha); /* Go with read. */ + spin_lock_irqsave(&ha->hardware_lock, flags); midpoint = ha->optrom_size / 2; qla2x00_flash_enable(ha); @@ -1475,6 +1473,7 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, *data = qla2x00_read_flash_byte(ha, addr); } qla2x00_flash_disable(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Resume HBA. */ qla2x00_resume_hba(ha); @@ -1488,6 +1487,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, { int rval; + unsigned long flags; uint8_t man_id, flash_id, sec_number, data; uint16_t wd; uint32_t addr, liter, sec_mask, rest_addr; @@ -1500,6 +1500,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, sec_number = 0; /* Reset ISP chip. */ + spin_lock_irqsave(&ha->hardware_lock, flags); WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); @@ -1688,10 +1689,10 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, rval = QLA_FUNCTION_FAILED; break; } - cond_resched(); } } while (0); qla2x00_flash_disable(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Resume HBA. */ qla2x00_resume_hba(ha); diff --git a/trunk/drivers/scsi/qla2xxx/qla_version.h b/trunk/drivers/scsi/qla2xxx/qla_version.h index dc85495c337f..61347aee55ce 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_version.h +++ b/trunk/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k6" +#define QLA2XXX_VERSION "8.01.07-k5" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 diff --git a/trunk/drivers/scsi/qlogicpti.c b/trunk/drivers/scsi/qlogicpti.c index c4195ea869e9..9f10689905a8 100644 --- a/trunk/drivers/scsi/qlogicpti.c +++ b/trunk/drivers/scsi/qlogicpti.c @@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi struct scsi_host_template *tpnt = match->data; struct Scsi_Host *host; struct qlogicpti *qpti; - const char *fcode; + char *fcode; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/trunk/drivers/scsi/scsi.c b/trunk/drivers/scsi/scsi.c index 4c1e31334765..1c89ee3e69ba 100644 --- a/trunk/drivers/scsi/scsi.c +++ b/trunk/drivers/scsi/scsi.c @@ -344,6 +344,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) void scsi_log_send(struct scsi_cmnd *cmd) { unsigned int level; + struct scsi_device *sdev; /* * If ML QUEUE log level is greater than or equal to: @@ -360,17 +361,22 @@ void scsi_log_send(struct scsi_cmnd *cmd) level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS); if (level > 1) { - scmd_printk(KERN_INFO, cmd, "Send: "); + sdev = cmd->device; + sdev_printk(KERN_INFO, sdev, "send "); if (level > 2) printk("0x%p ", cmd); - printk("\n"); + /* + * spaces to match disposition and cmd->result + * output in scsi_log_completion. + */ + printk(" "); scsi_print_command(cmd); if (level > 3) { printk(KERN_INFO "buffer = 0x%p, bufflen = %d," " done = 0x%p, queuecommand 0x%p\n", cmd->request_buffer, cmd->request_bufflen, cmd->done, - cmd->device->host->hostt->queuecommand); + sdev->host->hostt->queuecommand); } } @@ -380,6 +386,7 @@ void scsi_log_send(struct scsi_cmnd *cmd) void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) { unsigned int level; + struct scsi_device *sdev; /* * If ML COMPLETE log level is greater than or equal to: @@ -398,7 +405,8 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - scmd_printk(KERN_INFO, cmd, "Done: "); + sdev = cmd->device; + sdev_printk(KERN_INFO, sdev, "done "); if (level > 2) printk("0x%p ", cmd); /* @@ -407,35 +415,40 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) */ switch (disposition) { case SUCCESS: - printk("SUCCESS\n"); + printk("SUCCESS"); break; case NEEDS_RETRY: - printk("RETRY\n"); + printk("RETRY "); break; case ADD_TO_MLQUEUE: - printk("MLQUEUE\n"); + printk("MLQUEUE"); break; case FAILED: - printk("FAILED\n"); + printk("FAILED "); break; case TIMEOUT_ERROR: /* * If called via scsi_times_out. */ - printk("TIMEOUT\n"); + printk("TIMEOUT"); break; default: - printk("UNKNOWN\n"); + printk("UNKNOWN"); } - scsi_print_result(cmd); + printk(" %8x ", cmd->result); scsi_print_command(cmd); - if (status_byte(cmd->result) & CHECK_CONDITION) + if (status_byte(cmd->result) & CHECK_CONDITION) { + /* + * XXX The scsi_print_sense formatting/prefix + * doesn't match this function. + */ scsi_print_sense("", cmd); - if (level > 3) - scmd_printk(KERN_INFO, cmd, - "scsi host busy %d failed %d\n", - cmd->device->host->host_busy, - cmd->device->host->host_failed); + } + if (level > 3) { + printk(KERN_INFO "scsi host busy %d failed %d\n", + sdev->host->host_busy, + sdev->host->host_failed); + } } } } diff --git a/trunk/drivers/scsi/scsi_error.c b/trunk/drivers/scsi/scsi_error.c index 3963e7013bd9..918bb6019540 100644 --- a/trunk/drivers/scsi/scsi_error.c +++ b/trunk/drivers/scsi/scsi_error.c @@ -184,19 +184,10 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) **/ void scsi_times_out(struct scsi_cmnd *scmd) { - enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); - scsi_log_completion(scmd, TIMEOUT_ERROR); if (scmd->device->host->transportt->eh_timed_out) - eh_timed_out = scmd->device->host->transportt->eh_timed_out; - else if (scmd->device->host->hostt->eh_timed_out) - eh_timed_out = scmd->device->host->hostt->eh_timed_out; - else - eh_timed_out = NULL; - - if (eh_timed_out) - switch (eh_timed_out(scmd)) { + switch (scmd->device->host->transportt->eh_timed_out(scmd)) { case EH_HANDLED: __scsi_done(scmd); return; @@ -932,12 +923,10 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; if (scmd->device->allow_restart) { - int i, rtn = NEEDS_RETRY; - - for (i = 0; rtn == NEEDS_RETRY && i < 2; i++) - rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, - START_UNIT_TIMEOUT, 0); + int rtn; + rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, + START_UNIT_TIMEOUT, 0); if (rtn == SUCCESS) return 0; } diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 61fbcdcbb009..9f7482d0b594 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -31,7 +31,7 @@ #define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools) -#define SG_MEMPOOL_SIZE 2 +#define SG_MEMPOOL_SIZE 32 struct scsi_host_sg_pool { size_t size; @@ -848,8 +848,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) memcpy(req->sense, cmd->sense_buffer, len); req->sense_len = len; } - } - req->data_len = cmd->resid; + } else + req->data_len = cmd->resid; } /* @@ -968,7 +968,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } if (result) { if (!(req->cmd_flags & REQ_QUIET)) { - scsi_print_result(cmd); + scmd_printk(KERN_INFO, cmd, + "SCSI error: return code = 0x%08x\n", + result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } diff --git a/trunk/drivers/scsi/scsi_netlink.c b/trunk/drivers/scsi/scsi_netlink.c index 4bf9aa547c78..1b59b27e887f 100644 --- a/trunk/drivers/scsi/scsi_netlink.c +++ b/trunk/drivers/scsi/scsi_netlink.c @@ -50,7 +50,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) while (skb->len >= NLMSG_SPACE(0)) { err = 0; - nlh = nlmsg_hdr(skb); + nlh = (struct nlmsghdr *) skb->data; if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || (skb->len < nlh->nlmsg_len)) { printk(KERN_WARNING "%s: discarding partial skb\n", @@ -168,8 +168,7 @@ scsi_netlink_init(void) } scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT, - SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, - THIS_MODULE); + SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE); if (!scsi_nl_sock) { printk(KERN_ERR "%s: register of recieve handler failed\n", __FUNCTION__); diff --git a/trunk/drivers/scsi/scsi_scan.c b/trunk/drivers/scsi/scsi_scan.c index a67f315244d7..0949145304ea 100644 --- a/trunk/drivers/scsi/scsi_scan.c +++ b/trunk/drivers/scsi/scsi_scan.c @@ -181,8 +181,10 @@ int scsi_complete_async_scans(void) return 0; } +#ifdef MODULE /* Only exported for the benefit of scsi_wait_scan */ EXPORT_SYMBOL_GPL(scsi_complete_async_scans); +#endif /** * scsi_unlock_floptical - unlock device via a special MODE SENSE command diff --git a/trunk/drivers/scsi/scsi_sysfs.c b/trunk/drivers/scsi/scsi_sysfs.c index 67a38a1409ba..939de0de18bc 100644 --- a/trunk/drivers/scsi/scsi_sysfs.c +++ b/trunk/drivers/scsi/scsi_sysfs.c @@ -276,22 +276,8 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; - return 0; -} - static int scsi_bus_suspend(struct device * dev, pm_message_t state) { - struct device_driver *drv = dev->driver; struct scsi_device *sdev = to_scsi_device(dev); struct scsi_host_template *sht = sdev->host->hostt; int err; @@ -300,51 +286,28 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state) if (err) return err; - /* call HLD suspend first */ - if (drv && drv->suspend) { - err = drv->suspend(dev, state); - if (err) - return err; - } - - /* then, call host suspend */ - if (sht->suspend) { + if (sht->suspend) err = sht->suspend(sdev, state); - if (err) { - if (drv && drv->resume) - drv->resume(dev); - return err; - } - } - return 0; + return err; } static int scsi_bus_resume(struct device * dev) { - struct device_driver *drv = dev->driver; struct scsi_device *sdev = to_scsi_device(dev); struct scsi_host_template *sht = sdev->host->hostt; - int err = 0, err2 = 0; + int err = 0; - /* call host resume first */ if (sht->resume) err = sht->resume(sdev); - /* then, call HLD resume */ - if (drv && drv->resume) - err2 = drv->resume(dev); - scsi_device_resume(sdev); - - /* favor LLD failure */ - return err ? err : err2;; + return err; } struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, - .uevent = scsi_bus_uevent, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume, }; @@ -584,14 +547,6 @@ show_sdev_iostat(iorequest_cnt); show_sdev_iostat(iodone_cnt); show_sdev_iostat(ioerr_cnt); -static ssize_t -sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev; - sdev = to_scsi_device(dev); - return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type); -} -static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); /* Default template for device attributes. May NOT be modified */ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { @@ -611,7 +566,6 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_iorequest_cnt, &dev_attr_iodone_cnt, &dev_attr_ioerr_cnt, - &dev_attr_modalias, NULL }; diff --git a/trunk/drivers/scsi/scsi_tgt_if.c b/trunk/drivers/scsi/scsi_tgt_if.c index ca22ddf81746..0e08817fdecf 100644 --- a/trunk/drivers/scsi/scsi_tgt_if.c +++ b/trunk/drivers/scsi/scsi_tgt_if.c @@ -179,12 +179,10 @@ static int event_recv_msg(struct tgt_event *ev) switch (ev->hdr.type) { case TGT_UEVENT_CMD_RSP: err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, - ev->p.cmd_rsp.result, ev->p.cmd_rsp.tag, - ev->p.cmd_rsp.uaddr, + ev->p.cmd_rsp.result, ev->p.cmd_rsp.len, - ev->p.cmd_rsp.sense_uaddr, - ev->p.cmd_rsp.sense_len, + ev->p.cmd_rsp.uaddr, ev->p.cmd_rsp.rw); break; case TGT_UEVENT_TSK_MGMT_RSP: diff --git a/trunk/drivers/scsi/scsi_tgt_lib.c b/trunk/drivers/scsi/scsi_tgt_lib.c index 2570f48a69c7..d402aff5f314 100644 --- a/trunk/drivers/scsi/scsi_tgt_lib.c +++ b/trunk/drivers/scsi/scsi_tgt_lib.c @@ -28,6 +28,7 @@ #include #include #include +#include <../drivers/md/dm-bio-list.h> #include "scsi_tgt_priv.h" @@ -41,12 +42,16 @@ static struct kmem_cache *scsi_tgt_cmd_cache; struct scsi_tgt_cmd { /* TODO replace work with James b's code */ struct work_struct work; - /* TODO fix limits of some drivers */ - struct bio *bio; + /* TODO replace the lists with a large bio */ + struct bio_list xfer_done_list; + struct bio_list xfer_list; struct list_head hash_list; struct request *rq; u64 tag; + + void *buffer; + unsigned bufflen; }; #define TGT_HASH_ORDER 4 @@ -88,12 +93,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, if (!tcmd) goto put_dev; - /* - * The blk helpers are used to the READ/WRITE requests - * transfering data from a initiator point of view. Since - * we are in target mode we want the opposite. - */ - rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask); + rq = blk_get_request(shost->uspace_req_q, write, gfp_mask); if (!rq) goto free_tcmd; @@ -111,6 +111,8 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, rq->cmd_flags |= REQ_TYPE_BLOCK_PC; rq->end_io_data = tcmd; + bio_list_init(&tcmd->xfer_list); + bio_list_init(&tcmd->xfer_done_list); tcmd->rq = rq; return cmd; @@ -155,6 +157,22 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) } EXPORT_SYMBOL_GPL(scsi_host_put_command); +static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) +{ + struct bio *bio; + + /* must call bio_endio in case bio was bounced */ + while ((bio = bio_list_pop(&tcmd->xfer_done_list))) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + } + + while ((bio = bio_list_pop(&tcmd->xfer_list))) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + } +} + static void cmd_hashlist_del(struct scsi_cmnd *cmd) { struct request_queue *q = cmd->request->q; @@ -167,11 +185,6 @@ static void cmd_hashlist_del(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); } -static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) -{ - blk_rq_unmap_user(tcmd->bio); -} - static void scsi_tgt_cmd_destroy(struct work_struct *work) { struct scsi_tgt_cmd *tcmd = @@ -180,6 +193,16 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, rq_data_dir(cmd->request)); + /* + * We fix rq->cmd_flags here since when we told bio_map_user + * to write vm for WRITE commands, blk_rq_bio_prep set + * rq_data_dir the flags to READ. + */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cmd->request->cmd_flags |= REQ_RW; + else + cmd->request->cmd_flags &= ~REQ_RW; + scsi_unmap_user_pages(tcmd); scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); } @@ -192,7 +215,6 @@ static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, struct list_head *head; tcmd->tag = tag; - tcmd->bio = NULL; INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); spin_lock_irqsave(&qdata->cmd_hash_lock, flags); head = &qdata->cmd_hash[cmd_hashfn(tag)]; @@ -327,14 +349,10 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); scsi_tgt_uspace_send_status(cmd, tcmd->tag); - - if (cmd->request_buffer) - scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); - queue_work(scsi_tgtd, &tcmd->work); } -static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) +static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) { struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); int err; @@ -347,12 +365,30 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) case SCSI_MLQUEUE_DEVICE_BUSY: return -EAGAIN; } + return 0; } +static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + int err; + + err = __scsi_tgt_transfer_response(cmd); + if (!err) + return; + + cmd->result = DID_BUS_BUSY << 16; + err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); + if (err <= 0) + /* the eh will have to pick this up */ + printk(KERN_ERR "Could not send cmd %p status\n", cmd); +} + static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct request *rq = cmd->request; + struct scsi_tgt_cmd *tcmd = rq->end_io_data; int count; cmd->use_sg = rq->nr_phys_segments; @@ -362,54 +398,143 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) cmd->request_bufflen = rq->data_len; - dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq)); + dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg, + rq_data_dir(rq)); count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); if (likely(count <= cmd->use_sg)) { cmd->use_sg = count; return 0; } - eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); + eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg); scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); return -EINVAL; } /* TODO: test this crap and replace bio_map_user with new interface maybe */ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, - unsigned long uaddr, unsigned int len, int rw) + int rw) { struct request_queue *q = cmd->request->q; struct request *rq = cmd->request; + void *uaddr = tcmd->buffer; + unsigned int len = tcmd->bufflen; + struct bio *bio; int err; - dprintk("%lx %u\n", uaddr, len); - err = blk_rq_map_user(q, rq, (void *)uaddr, len); - if (err) { + while (len > 0) { + dprintk("%lx %u\n", (unsigned long) uaddr, len); + bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw); + if (IS_ERR(bio)) { + err = PTR_ERR(bio); + dprintk("fail to map %lx %u %d %x\n", + (unsigned long) uaddr, len, err, cmd->cmnd[0]); + goto unmap_bios; + } + + uaddr += bio->bi_size; + len -= bio->bi_size; + /* - * TODO: need to fixup sg_tablesize, max_segment_size, - * max_sectors, etc for modern HW and software drivers - * where this value is bogus. - * - * TODO2: we can alloc a reserve buffer of max size - * we can handle and do the slow copy path for really large - * IO. + * The first bio is added and merged. We could probably + * try to add others using scsi_merge_bio() but for now + * we keep it simple. The first bio should be pretty large + * (either hitting the 1 MB bio pages limit or a queue limit) + * already but for really large IO we may want to try and + * merge these. */ - eprintk("Could not handle request of size %u.\n", len); - return err; + if (!rq->bio) { + blk_rq_bio_prep(q, rq, bio); + rq->data_len = bio->bi_size; + } else + /* put list of bios to transfer in next go around */ + bio_list_add(&tcmd->xfer_list, bio); } - tcmd->bio = rq->bio; + cmd->offset = 0; err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); if (err) - goto unmap_rq; + goto unmap_bios; return 0; -unmap_rq: - scsi_unmap_user_pages(tcmd); +unmap_bios: + if (rq->bio) { + bio_unmap_user(rq->bio); + while ((bio = bio_list_pop(&tcmd->xfer_list))) + bio_unmap_user(bio); + } + return err; } +static int scsi_tgt_transfer_data(struct scsi_cmnd *); + +static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) +{ + struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; + struct bio *bio; + int err; + + /* should we free resources here on error ? */ + if (cmd->result) { +send_uspace_err: + err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); + if (err <= 0) + /* the tgt uspace eh will have to pick this up */ + printk(KERN_ERR "Could not send cmd %p status\n", cmd); + return; + } + + dprintk("cmd %p request_bufflen %u bufflen %u\n", + cmd, cmd->request_bufflen, tcmd->bufflen); + + scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + bio_list_add(&tcmd->xfer_done_list, cmd->request->bio); + + tcmd->buffer += cmd->request_bufflen; + cmd->offset += cmd->request_bufflen; + + if (!tcmd->xfer_list.head) { + scsi_tgt_transfer_response(cmd); + return; + } + + dprintk("cmd2 %p request_bufflen %u bufflen %u\n", + cmd, cmd->request_bufflen, tcmd->bufflen); + + bio = bio_list_pop(&tcmd->xfer_list); + BUG_ON(!bio); + + blk_rq_bio_prep(cmd->request->q, cmd->request, bio); + cmd->request->data_len = bio->bi_size; + err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC); + if (err) { + cmd->result = DID_ERROR << 16; + goto send_uspace_err; + } + + if (scsi_tgt_transfer_data(cmd)) { + cmd->result = DID_NO_CONNECT << 16; + goto send_uspace_err; + } +} + +static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) +{ + int err; + struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd); + + err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done); + switch (err) { + case SCSI_MLQUEUE_HOST_BUSY: + case SCSI_MLQUEUE_DEVICE_BUSY: + return -EAGAIN; + default: + return 0; + } +} + static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, unsigned len) { @@ -459,9 +584,8 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) return rq; } -int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, - unsigned long uaddr, u32 len, unsigned long sense_uaddr, - u32 sense_len, u8 rw) +int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, + unsigned long uaddr, u8 rw) { struct Scsi_Host *shost; struct scsi_cmnd *cmd; @@ -493,9 +617,8 @@ int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, } cmd = rq->special; - dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n", - cmd, cmd->cmnd[0], result, len, cmd->request_bufflen, - rq_data_dir(rq), cmd->cmnd[0]); + dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd, + result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]); if (result == TASK_ABORTED) { scsi_tgt_abort_cmd(shost, cmd); @@ -506,36 +629,36 @@ int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, * in the request_* values */ tcmd = cmd->request->end_io_data; + tcmd->buffer = (void *)uaddr; + tcmd->bufflen = len; cmd->result = result; - if (cmd->result == SAM_STAT_CHECK_CONDITION) - scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len); - - if (len) { - err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw); - if (err) { - /* - * user-space daemon bugs or OOM - * TODO: we can do better for OOM. - */ - struct scsi_tgt_queuedata *qdata; - struct list_head *head; - unsigned long flags; - - eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n", - cmd, err, uaddr, len, rw); - - qdata = shost->uspace_req_q->queuedata; - head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)]; + if (!tcmd->bufflen || cmd->request_buffer) { + err = __scsi_tgt_transfer_response(cmd); + goto done; + } - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - list_add(&tcmd->hash_list, head); - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); + /* + * TODO: Do we need to handle case where request does not + * align with LLD. + */ + err = scsi_map_user_pages(rq->end_io_data, cmd, rw); + if (err) { + eprintk("%p %d\n", cmd, err); + err = -EAGAIN; + goto done; + } - goto done; - } + /* userspace failure */ + if (cmd->result) { + if (status_byte(cmd->result) == CHECK_CONDITION) + scsi_tgt_copy_sense(cmd, uaddr, len); + err = __scsi_tgt_transfer_response(cmd); + goto done; } - err = scsi_tgt_transfer_response(cmd); + /* ask the target LLD to transfer the data to the buffer */ + err = scsi_tgt_transfer_data(cmd); + done: scsi_host_put(shost); return err; diff --git a/trunk/drivers/scsi/scsi_tgt_priv.h b/trunk/drivers/scsi/scsi_tgt_priv.h index e9e6db1c417f..84488c51ff62 100644 --- a/trunk/drivers/scsi/scsi_tgt_priv.h +++ b/trunk/drivers/scsi/scsi_tgt_priv.h @@ -18,9 +18,8 @@ extern int scsi_tgt_if_init(void); extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag); extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); -extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, - unsigned long uaddr, u32 len, unsigned long sense_uaddr, - u32 sense_len, u8 rw); +extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, + unsigned long uaddr, u8 rw); extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, struct scsi_lun *scsilun, void *data); extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); diff --git a/trunk/drivers/scsi/scsi_transport_fc.c b/trunk/drivers/scsi/scsi_transport_fc.c index 14c4f065b2b8..58afdb401703 100644 --- a/trunk/drivers/scsi/scsi_transport_fc.c +++ b/trunk/drivers/scsi/scsi_transport_fc.c @@ -200,8 +200,6 @@ static const struct { { FC_PORTSPEED_2GBIT, "2 Gbit" }, { FC_PORTSPEED_4GBIT, "4 Gbit" }, { FC_PORTSPEED_10GBIT, "10 Gbit" }, - { FC_PORTSPEED_8GBIT, "8 Gbit" }, - { FC_PORTSPEED_16GBIT, "16 Gbit" }, { FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" }, }; fc_bitfield_name_search(port_speed, fc_port_speed_names) diff --git a/trunk/drivers/scsi/scsi_transport_iscsi.c b/trunk/drivers/scsi/scsi_transport_iscsi.c index caf1836bbeca..ce0d14af33c8 100644 --- a/trunk/drivers/scsi/scsi_transport_iscsi.c +++ b/trunk/drivers/scsi/scsi_transport_iscsi.c @@ -49,7 +49,7 @@ struct iscsi_internal { struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1]; }; -static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ +static int iscsi_session_nr; /* sysfs session id for next new session */ /* * list of registered transports and lock that must @@ -300,7 +300,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) int err; ihost = shost->shost_data; - session->sid = atomic_add_return(1, &iscsi_session_nr); + session->sid = iscsi_session_nr++; session->target_id = target_id; snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", @@ -1081,7 +1081,7 @@ iscsi_if_rx(struct sock *sk, int len) struct nlmsghdr *nlh; struct iscsi_uevent *ev; - nlh = nlmsg_hdr(skb); + nlh = (struct nlmsghdr *)skb->data; if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) { break; @@ -1419,8 +1419,6 @@ static __init int iscsi_transport_init(void) printk(KERN_INFO "Loading iSCSI transport class v%s.\n", ISCSI_TRANSPORT_VERSION); - atomic_set(&iscsi_session_nr, 0); - err = class_register(&iscsi_transport_class); if (err) return err; @@ -1437,7 +1435,7 @@ static __init int iscsi_transport_init(void) if (err) goto unregister_conn_class; - nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL, + nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, THIS_MODULE); if (!nls) { err = -ENOBUFS; diff --git a/trunk/drivers/scsi/sd.c b/trunk/drivers/scsi/sd.c index 00e46662296f..5a8f55fea5ff 100644 --- a/trunk/drivers/scsi/sd.c +++ b/trunk/drivers/scsi/sd.c @@ -58,10 +58,16 @@ #include #include #include -#include #include "scsi_logging.h" +/* + * More than enough for everybody ;) The huge number of majors + * is a leftover from 16bit dev_t days, we don't really need that + * much numberspace. + */ +#define SD_MAJORS 16 + MODULE_AUTHOR("Eric Youngdale"); MODULE_DESCRIPTION("SCSI disk (sd) driver"); MODULE_LICENSE("GPL"); @@ -82,9 +88,45 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK); -MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD); -MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); + +/* + * This is limited by the naming scheme enforced in sd_probe, + * add another character to it if you really need more disks. + */ +#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) + +/* + * Time out in seconds for disks and Magneto-opticals (which are slower). + */ +#define SD_TIMEOUT (30 * HZ) +#define SD_MOD_TIMEOUT (75 * HZ) + +/* + * Number of allowed retries + */ +#define SD_MAX_RETRIES 5 +#define SD_PASSTHROUGH_RETRIES 1 + +/* + * Size of the initial data buffer for mode and read capacity data + */ +#define SD_BUF_SIZE 512 + +struct scsi_disk { + struct scsi_driver *driver; /* always &sd_template */ + struct scsi_device *device; + struct class_device cdev; + struct gendisk *disk; + unsigned int openers; /* protected by BKL for now, yuck */ + sector_t capacity; /* size in 512-byte sectors */ + u32 index; + u8 media_present; + u8 write_prot; + unsigned WCE : 1; /* state of disk WCE bit */ + unsigned RCD : 1; /* state of disk RCD bit, unused */ + unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ +}; +#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -94,6 +136,20 @@ static DEFINE_SPINLOCK(sd_index_lock); * object after last put) */ static DEFINE_MUTEX(sd_ref_mutex); +static int sd_revalidate_disk(struct gendisk *disk); +static void sd_rw_intr(struct scsi_cmnd * SCpnt); + +static int sd_probe(struct device *); +static int sd_remove(struct device *); +static void sd_shutdown(struct device *dev); +static void sd_rescan(struct device *); +static int sd_init_command(struct scsi_cmnd *); +static int sd_issue_flush(struct device *, sector_t *); +static void sd_prepare_flush(request_queue_t *, struct request *); +static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, + unsigned char *buffer); +static void scsi_disk_release(struct class_device *cdev); + static const char *sd_cache_types[] = { "write through", "none", "write back", "write back, no read (daft)" @@ -143,27 +199,13 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { if (scsi_sense_valid(&sshdr)) - sd_print_sense_hdr(sdkp, &sshdr); + scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr); return -EINVAL; } sd_revalidate_disk(sdkp->disk); return count; } -static ssize_t sd_store_manage_start_stop(struct class_device *cdev, - const char *buf, size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - struct scsi_device *sdp = sdkp->device; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - sdp->manage_start_stop = simple_strtoul(buf, NULL, 10); - - return count; -} - static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, size_t count) { @@ -196,14 +238,6 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); } -static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(cdev); - struct scsi_device *sdp = sdkp->device; - - return snprintf(buf, 20, "%u\n", sdp->manage_start_stop); -} - static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(cdev); @@ -217,8 +251,6 @@ static struct class_device_attribute sd_disk_attrs[] = { __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, sd_store_allow_restart), - __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, - sd_store_manage_start_stop), __ATTR_NULL, }; @@ -235,8 +267,6 @@ static struct scsi_driver sd_template = { .name = "sd", .probe = sd_probe, .remove = sd_remove, - .suspend = sd_suspend, - .resume = sd_resume, .shutdown = sd_shutdown, }, .rescan = sd_rescan, @@ -341,19 +371,15 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) unsigned int this_count = SCpnt->request_bufflen >> 9; unsigned int timeout = sdp->timeout; - SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_init_command: block=%llu, " - "count=%d\n", - (unsigned long long)block, - this_count)); + SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, " + "count=%d\n", disk->disk_name, + (unsigned long long)block, this_count)); if (!sdp || !scsi_device_online(sdp) || block + rq->nr_sectors > get_capacity(disk)) { - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Finishing %ld sectors\n", - rq->nr_sectors)); - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Retry with 0x%p\n", SCpnt)); + SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", + rq->nr_sectors)); + SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; } @@ -365,8 +391,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ return 0; } - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", - (unsigned long long)block)); + SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n", + disk->disk_name, (unsigned long long)block)); /* * If we have a 1K hardware sectorsize, prevent access to single @@ -381,8 +407,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) */ if (sdp->sector_size == 1024) { if ((block & 1) || (rq->nr_sectors & 1)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); + printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { block = block >> 1; @@ -391,8 +416,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (sdp->sector_size == 2048) { if ((block & 3) || (rq->nr_sectors & 3)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); + printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { block = block >> 2; @@ -401,8 +425,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (sdp->sector_size == 4096) { if ((block & 7) || (rq->nr_sectors & 7)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); + printk(KERN_ERR "sd: Bad block number requested"); return 0; } else { block = block >> 3; @@ -419,15 +442,13 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); + printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags); return 0; } - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "%s %d/%ld 512 byte blocks.\n", - (rq_data_dir(rq) == WRITE) ? - "writing" : "reading", this_count, - rq->nr_sectors)); + SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", + disk->disk_name, (rq_data_dir(rq) == WRITE) ? + "writing" : "reading", this_count, rq->nr_sectors)); SCpnt->cmnd[1] = 0; @@ -469,8 +490,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) * during operation and thus turned off * use_10_for_rw. */ - scmd_printk(KERN_ERR, SCpnt, - "FUA write on READ/WRITE(6) drive\n"); + printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n"); return 0; } @@ -529,7 +549,7 @@ static int sd_open(struct inode *inode, struct file *filp) return -ENXIO; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n")); + SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name)); sdev = sdkp->device; @@ -599,7 +619,7 @@ static int sd_release(struct inode *inode, struct file *filp) struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdev = sdkp->device; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); + SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name)); if (!--sdkp->openers && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) @@ -712,7 +732,8 @@ static int sd_media_changed(struct gendisk *disk) struct scsi_device *sdp = sdkp->device; int retval; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); + SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n", + disk->disk_name)); if (!sdp->removable) return 0; @@ -765,10 +786,9 @@ static int sd_media_changed(struct gendisk *disk) return 1; } -static int sd_sync_cache(struct scsi_disk *sdkp) +static int sd_sync_cache(struct scsi_device *sdp) { int retries, res; - struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr sshdr; if (!scsi_device_online(sdp)) @@ -789,27 +809,28 @@ static int sd_sync_cache(struct scsi_disk *sdkp) break; } - if (res) { - sd_print_result(sdkp, res); - if (driver_byte(res) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); + if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + scsi_print_sense_hdr("sd", &sshdr); } - if (res) - return -EIO; - return 0; + return res; } static int sd_issue_flush(struct device *dev, sector_t *error_sector) { int ret = 0; + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) return -ENODEV; if (sdkp->WCE) - ret = sd_sync_cache(sdkp); + ret = sd_sync_cache(sdp); scsi_disk_put(sdkp); return ret; } @@ -907,14 +928,12 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) sense_deferred = scsi_sense_is_deferred(&sshdr); } #ifdef CONFIG_SCSI_LOGGING - SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt)); + SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", + SCpnt->request->rq_disk->disk_name, result)); if (sense_valid) { - SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_rw_intr: sb[respc,sk,asc," - "ascq]=%x,%x,%x,%x\n", - sshdr.response_code, - sshdr.sense_key, sshdr.asc, - sshdr.ascq)); + SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc," + "ascq]=%x,%x,%x,%x\n", sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif if (driver_byte(result) != DRIVER_SENSE && @@ -1006,7 +1025,7 @@ static int media_not_present(struct scsi_disk *sdkp, * spinup disk - called only in sd_revalidate_disk() */ static void -sd_spinup_disk(struct scsi_disk *sdkp) +sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) { unsigned char cmd[10]; unsigned long spintime_expire = 0; @@ -1050,10 +1069,9 @@ sd_spinup_disk(struct scsi_disk *sdkp) if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { /* no sense, TUR either succeeded or failed * with a status error */ - if(!spintime && !scsi_status_is_good(the_result)) { - sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); - sd_print_result(sdkp, the_result); - } + if(!spintime && !scsi_status_is_good(the_result)) + printk(KERN_NOTICE "%s: Unit Not Ready, " + "error = 0x%x\n", diskname, the_result); break; } @@ -1078,7 +1096,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) */ } else if (sense_valid && sshdr.sense_key == NOT_READY) { if (!spintime) { - sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); + printk(KERN_NOTICE "%s: Spinning up disk...", + diskname); cmd[0] = START_STOP; cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); @@ -1111,8 +1130,9 @@ sd_spinup_disk(struct scsi_disk *sdkp) /* we don't understand the sense code, so it's * probably pointless to loop */ if(!spintime) { - sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); - sd_print_sense_hdr(sdkp, &sshdr); + printk(KERN_NOTICE "%s: Unit Not Ready, " + "sense:\n", diskname); + scsi_print_sense_hdr("", &sshdr); } break; } @@ -1131,7 +1151,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) * read disk capacity */ static void -sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) +sd_read_capacity(struct scsi_disk *sdkp, char *diskname, + unsigned char *buffer) { unsigned char cmd[16]; int the_result, retries; @@ -1170,12 +1191,18 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) } while (the_result && retries); if (the_result && !longrc) { - sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); - sd_print_result(sdkp, the_result); + printk(KERN_NOTICE "%s : READ CAPACITY failed.\n" + "%s : status=%x, message=%02x, host=%d, driver=%02x \n", + diskname, diskname, + status_byte(the_result), + msg_byte(the_result), + host_byte(the_result), + driver_byte(the_result)); + if (driver_byte(the_result) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); + scsi_print_sense_hdr("sd", &sshdr); else - sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); + printk("%s : sense not available. \n", diskname); /* Set dirty bit for removable devices if not ready - * sometimes drives will not report this properly. */ @@ -1191,10 +1218,16 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) return; } else if (the_result && longrc) { /* READ CAPACITY(16) has been failed */ - sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); - sd_print_result(sdkp, the_result); - sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n"); - + printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n" + "%s : status=%x, message=%02x, host=%d, driver=%02x \n", + diskname, diskname, + status_byte(the_result), + msg_byte(the_result), + host_byte(the_result), + driver_byte(the_result)); + printk(KERN_NOTICE "%s : use 0xffffffff as device size\n", + diskname); + sdkp->capacity = 1 + (sector_t) 0xffffffff; goto got_data; } @@ -1205,14 +1238,14 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) if (buffer[0] == 0xff && buffer[1] == 0xff && buffer[2] == 0xff && buffer[3] == 0xff) { if(sizeof(sdkp->capacity) > 4) { - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); + printk(KERN_NOTICE "%s : very big device. try to use" + " READ CAPACITY(16).\n", diskname); longrc = 1; goto repeat; } - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use " - "a kernel compiled with support for large " - "block devices.\n"); + printk(KERN_ERR "%s: too big for this kernel. Use a " + "kernel compiled with support for large block " + "devices.\n", diskname); sdkp->capacity = 0; goto got_data; } @@ -1251,8 +1284,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) got_data: if (sector_size == 0) { sector_size = 512; - sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " - "assuming 512.\n"); + printk(KERN_NOTICE "%s : sector size 0 reported, " + "assuming 512.\n", diskname); } if (sector_size != 512 && @@ -1260,8 +1293,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) sector_size != 2048 && sector_size != 4096 && sector_size != 256) { - sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n", - sector_size); + printk(KERN_NOTICE "%s : unsupported sector size " + "%d.\n", diskname, sector_size); /* * The user might want to re-format the drive with * a supported sectorsize. Once this happens, it @@ -1294,10 +1327,10 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) mb -= sz - 974; sector_div(mb, 1950); - sd_printk(KERN_NOTICE, sdkp, - "%llu %d-byte hardware sectors (%llu MB)\n", - (unsigned long long)sdkp->capacity, - hard_sector, (unsigned long long)mb); + printk(KERN_NOTICE "SCSI device %s: " + "%llu %d-byte hdwr sectors (%llu MB)\n", + diskname, (unsigned long long)sdkp->capacity, + hard_sector, (unsigned long long)mb); } /* Rescale capacity to 512-byte units */ @@ -1329,7 +1362,8 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, * called with buffer of length SD_BUF_SIZE */ static void -sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) +sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, + unsigned char *buffer) { int res; struct scsi_device *sdp = sdkp->device; @@ -1337,7 +1371,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) set_disk_ro(sdkp->disk, 0); if (sdp->skip_ms_page_3f) { - sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n"); + printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname); return; } @@ -1369,16 +1403,15 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) } if (!scsi_status_is_good(res)) { - sd_printk(KERN_WARNING, sdkp, - "Test WP failed, assume Write Enabled\n"); + printk(KERN_WARNING + "%s: test WP failed, assume Write Enabled\n", diskname); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); set_disk_ro(sdkp->disk, sdkp->write_prot); - sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", - sdkp->write_prot ? "on" : "off"); - sd_printk(KERN_DEBUG, sdkp, - "Mode Sense: %02x %02x %02x %02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); + printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname, + sdkp->write_prot ? "on" : "off"); + printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n", + diskname, buffer[0], buffer[1], buffer[2], buffer[3]); } } @@ -1387,7 +1420,8 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) * called with buffer of length SD_BUF_SIZE */ static void -sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) +sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, + unsigned char *buffer) { int len = 0, res; struct scsi_device *sdp = sdkp->device; @@ -1416,7 +1450,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (!data.header_length) { modepage = 6; - sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); + printk(KERN_ERR "%s: missing header in MODE_SENSE response\n", + diskname); } /* that went OK, now ask for the proper length */ @@ -1443,12 +1478,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) int offset = data.header_length + data.block_descriptor_length; if (offset >= SD_BUF_SIZE - 2) { - sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); + printk(KERN_ERR "%s: malformed MODE SENSE response", + diskname); goto defaults; } if ((buffer[offset] & 0x3f) != modepage) { - sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); + printk(KERN_ERR "%s: got wrong page\n", diskname); goto defaults; } @@ -1462,13 +1498,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->DPOFUA = (data.device_specific & 0x10) != 0; if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { - sd_printk(KERN_NOTICE, sdkp, - "Uses READ/WRITE(6), disabling FUA\n"); + printk(KERN_NOTICE "SCSI device %s: uses " + "READ/WRITE(6), disabling FUA\n", diskname); sdkp->DPOFUA = 0; } - sd_printk(KERN_NOTICE, sdkp, - "Write cache: %s, read cache: %s, %s\n", + printk(KERN_NOTICE "SCSI device %s: " + "write cache: %s, read cache: %s, %s\n", + diskname, sdkp->WCE ? "enabled" : "disabled", sdkp->RCD ? "disabled" : "enabled", sdkp->DPOFUA ? "supports DPO and FUA" @@ -1481,13 +1518,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST && sshdr.asc == 0x24 && sshdr.ascq == 0x0) - /* Invalid field in CDB */ - sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n"); + printk(KERN_NOTICE "%s: cache data unavailable\n", + diskname); /* Invalid field in CDB */ else - sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n"); + printk(KERN_ERR "%s: asking for cache data failed\n", + diskname); defaults: - sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n"); + printk(KERN_ERR "%s: assuming drive cache: write through\n", + diskname); sdkp->WCE = 0; sdkp->RCD = 0; sdkp->DPOFUA = 0; @@ -1505,8 +1544,7 @@ static int sd_revalidate_disk(struct gendisk *disk) unsigned char *buffer; unsigned ordered; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, - "sd_revalidate_disk\n")); + SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); /* * If the device is offline, don't try and read capacity or any @@ -1517,8 +1555,8 @@ static int sd_revalidate_disk(struct gendisk *disk) buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA); if (!buffer) { - sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory " - "allocation failure.\n"); + printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " + "failure.\n"); goto out; } @@ -1530,16 +1568,16 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp); + sd_spinup_disk(sdkp, disk->disk_name); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { - sd_read_capacity(sdkp, buffer); - sd_read_write_protect_flag(sdkp, buffer); - sd_read_cache_type(sdkp, buffer); + sd_read_capacity(sdkp, disk->disk_name, buffer); + sd_read_write_protect_flag(sdkp, disk->disk_name, buffer); + sd_read_cache_type(sdkp, disk->disk_name, buffer); } /* @@ -1671,8 +1709,8 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); add_disk(gd); - sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", - sdp->removable ? "removable " : ""); + sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n", + sdp->removable ? "removable " : "", gd->disk_name); return 0; @@ -1736,31 +1774,6 @@ static void scsi_disk_release(struct class_device *cdev) kfree(sdkp); } -static int sd_start_stop_device(struct scsi_disk *sdkp, int start) -{ - unsigned char cmd[6] = { START_STOP }; /* START_VALID */ - struct scsi_sense_hdr sshdr; - struct scsi_device *sdp = sdkp->device; - int res; - - if (start) - cmd[4] |= 1; /* START */ - - if (!scsi_device_online(sdp)) - return -ENODEV; - - res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES); - if (res) { - sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n"); - sd_print_result(sdkp, res); - if (driver_byte(res) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); - } - - return res; -} - /* * Send a SYNCHRONIZE CACHE instruction down to the device through * the normal SCSI command structure. Wait for the command to @@ -1768,62 +1781,20 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) */ static void sd_shutdown(struct device *dev) { + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) return; /* this can happen */ if (sdkp->WCE) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - sd_sync_cache(sdkp); - } - - if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); - sd_start_stop_device(sdkp, 0); + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", + sdkp->disk->disk_name); + sd_sync_cache(sdp); } - scsi_disk_put(sdkp); } -static int sd_suspend(struct device *dev, pm_message_t mesg) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - int ret; - - if (!sdkp) - return 0; /* this can happen */ - - if (sdkp->WCE) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - ret = sd_sync_cache(sdkp); - if (ret) - return ret; - } - - if (mesg.event == PM_EVENT_SUSPEND && - sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); - ret = sd_start_stop_device(sdkp, 0); - if (ret) - return ret; - } - - return 0; -} - -static int sd_resume(struct device *dev) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - - if (!sdkp->device->manage_start_stop) - return 0; - - sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); - - return sd_start_stop_device(sdkp, 1); -} - /** * init_sd - entry point for this driver (both when built in or when * a module). @@ -1881,19 +1852,3 @@ static void __exit exit_sd(void) module_init(init_sd); module_exit(exit_sd); - -static void sd_print_sense_hdr(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - sd_printk(KERN_INFO, sdkp, ""); - scsi_show_sense_hdr(sshdr); - sd_printk(KERN_INFO, sdkp, ""); - scsi_show_extd_sense(sshdr->asc, sshdr->ascq); -} - -static void sd_print_result(struct scsi_disk *sdkp, int result) -{ - sd_printk(KERN_INFO, sdkp, ""); - scsi_show_result(result); -} - diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index 570977cf9efb..81e3bc7b02a1 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -917,8 +917,6 @@ sg_ioctl(struct inode *inode, struct file *filp, return result; if (val < 0) return -EINVAL; - val = min_t(int, val, - sdp->device->request_queue->max_sectors * 512); if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; @@ -927,8 +925,7 @@ sg_ioctl(struct inode *inode, struct file *filp, } return 0; case SG_GET_RESERVED_SIZE: - val = min_t(int, sfp->reserve.bufflen, - sdp->device->request_queue->max_sectors * 512); + val = (int) sfp->reserve.bufflen; return put_user(val, ip); case SG_SET_COMMAND_Q: result = get_user(val, ip); @@ -1064,9 +1061,6 @@ sg_ioctl(struct inode *inode, struct file *filp, if (sdp->detached) return -ENODEV; return scsi_ioctl(sdp->device, cmd_in, p); - case BLKSECTGET: - return put_user(sdp->device->request_queue->max_sectors * 512, - ip); default: if (read_only) return -EPERM; /* don't know so take safe approach */ @@ -2345,7 +2339,6 @@ sg_add_sfp(Sg_device * sdp, int dev) { Sg_fd *sfp; unsigned long iflags; - int bufflen; sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); if (!sfp) @@ -2376,9 +2369,7 @@ sg_add_sfp(Sg_device * sdp, int dev) if (unlikely(sg_big_buff != def_reserved_size)) sg_big_buff = def_reserved_size; - bufflen = min_t(int, sg_big_buff, - sdp->device->request_queue->max_sectors * 512); - sg_build_reserve(sfp, bufflen); + sg_build_reserve(sfp, sg_big_buff); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); return sfp; diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index f9a52af7f5b4..1857d68e7195 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -62,8 +62,6 @@ MODULE_DESCRIPTION("SCSI cdrom (sr) driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM); -MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); #define SR_DISKS 256 diff --git a/trunk/drivers/scsi/st.c b/trunk/drivers/scsi/st.c index 55bfeccf68a2..98d8411bbccc 100644 --- a/trunk/drivers/scsi/st.c +++ b/trunk/drivers/scsi/st.c @@ -89,7 +89,6 @@ MODULE_AUTHOR("Kai Makisara"); MODULE_DESCRIPTION("SCSI tape (st) driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); /* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). diff --git a/trunk/drivers/scsi/sun_esp.c b/trunk/drivers/scsi/sun_esp.c deleted file mode 100644 index 8c766bcd1095..000000000000 --- a/trunk/drivers/scsi/sun_esp.c +++ /dev/null @@ -1,634 +0,0 @@ -/* sun_esp.c: ESP front-end for Sparc SBUS systems. - * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "sun_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "April 19, 2007" - -#define dma_read32(REG) \ - sbus_readl(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - sbus_writel((VAL), esp->dma_regs + (REG)) - -static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev) -{ - struct sbus_dev *sdev = esp->dev; - struct sbus_dma *dma; - - if (dma_sdev != NULL) { - for_each_dvma(dma) { - if (dma->sdev == dma_sdev) - break; - } - } else { - for_each_dvma(dma) { - if (dma->sdev == NULL) - break; - - /* If bus + slot are the same and it has the - * correct OBP name, it's ours. - */ - if (sdev->bus == dma->sdev->bus && - sdev->slot == dma->sdev->slot && - (!strcmp(dma->sdev->prom_name, "dma") || - !strcmp(dma->sdev->prom_name, "espdma"))) - break; - } - } - - if (dma == NULL) { - printk(KERN_ERR PFX "[%s] Cannot find dma.\n", - sdev->ofdev.node->full_name); - return -ENODEV; - } - esp->dma = dma; - esp->dma_regs = dma->regs; - - return 0; - -} - -static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) -{ - struct sbus_dev *sdev = esp->dev; - struct resource *res; - - /* On HME, two reg sets exist, first is DVMA, - * second is ESP registers. - */ - if (hme) - res = &sdev->resource[1]; - else - res = &sdev->resource[0]; - - esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); - if (!esp->regs) - return -ENOMEM; - - return 0; -} - -static int __devinit esp_sbus_map_command_block(struct esp *esp) -{ - struct sbus_dev *sdev = esp->dev; - - esp->command_block = sbus_alloc_consistent(sdev, 16, - &esp->command_block_dma); - if (!esp->command_block) - return -ENOMEM; - return 0; -} - -static int __devinit esp_sbus_register_irq(struct esp *esp) -{ - struct Scsi_Host *host = esp->host; - struct sbus_dev *sdev = esp->dev; - - host->irq = sdev->irqs[0]; - return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); -} - -static void __devinit esp_get_scsi_id(struct esp *esp) -{ - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - - esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); - if (esp->scsi_id != 0xff) - goto done; - - esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff); - if (esp->scsi_id != 0xff) - goto done; - - if (!sdev->bus) { - /* SUN4 */ - esp->scsi_id = 7; - goto done; - } - - esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node, - "scsi-initiator-id", 7); - -done: - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); -} - -static void __devinit esp_get_differential(struct esp *esp) -{ - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - - if (of_find_property(dp, "differential", NULL)) - esp->flags |= ESP_FLAG_DIFFERENTIAL; - else - esp->flags &= ~ESP_FLAG_DIFFERENTIAL; -} - -static void __devinit esp_get_clock_params(struct esp *esp) -{ - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - struct device_node *bus_dp; - int fmhz; - - bus_dp = NULL; - if (sdev != NULL && sdev->bus != NULL) - bus_dp = sdev->bus->ofdev.node; - - fmhz = of_getintprop_default(dp, "clock-frequency", 0); - if (fmhz == 0) - fmhz = (!bus_dp) ? 0 : - of_getintprop_default(bus_dp, "clock-frequency", 0); - - esp->cfreq = fmhz; -} - -static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma) -{ - struct sbus_dev *sdev = esp->dev; - struct device_node *dp = sdev->ofdev.node; - u8 bursts; - - bursts = of_getintprop_default(dp, "burst-sizes", 0xff); - if (dma) { - struct device_node *dma_dp = dma->ofdev.node; - u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - } - - if (sdev->bus) { - u8 val = of_getintprop_default(sdev->bus->ofdev.node, - "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - } - - if (bursts == 0xff || - (bursts & DMA_BURST16) == 0 || - (bursts & DMA_BURST32) == 0) - bursts = (DMA_BURST32 - 1); - - esp->bursts = bursts; -} - -static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma) -{ - esp_get_scsi_id(esp); - esp_get_differential(esp); - esp_get_clock_params(esp); - esp_get_bursts(esp, espdma); -} - -static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - sbus_writeb(val, esp->regs + (reg * 4UL)); -} - -static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) -{ - return sbus_readb(esp->regs + (reg * 4UL)); -} - -static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return sbus_map_single(esp->dev, buf, sz, dir); -} - -static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return sbus_map_sg(esp->dev, sg, num_sg, dir); -} - -static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - sbus_unmap_single(esp->dev, addr, sz, dir); -} - -static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - sbus_unmap_sg(esp->dev, sg, num_sg, dir); -} - -static int sbus_esp_irq_pending(struct esp *esp) -{ - if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) - return 1; - return 0; -} - -static void sbus_esp_reset_dma(struct esp *esp) -{ - int can_do_burst16, can_do_burst32, can_do_burst64; - int can_do_sbus64, lim; - u32 val; - - can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; - can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; - can_do_burst64 = 0; - can_do_sbus64 = 0; - if (sbus_can_dma_64bit(esp->dev)) - can_do_sbus64 = 1; - if (sbus_can_burst64(esp->sdev)) - can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; - - /* Put the DVMA into a known state. */ - if (esp->dma->revision != dvmahme) { - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_RST_SCSI, DMA_CSR); - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); - } - switch (esp->dma->revision) { - case dvmahme: - dma_write32(DMA_RESET_FAS366, DMA_CSR); - dma_write32(DMA_RST_SCSI, DMA_CSR); - - esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS | - DMA_SCSI_DISAB | DMA_INT_ENAB); - - esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE | - DMA_BRST_SZ); - - if (can_do_burst64) - esp->prev_hme_dmacsr |= DMA_BRST64; - else if (can_do_burst32) - esp->prev_hme_dmacsr |= DMA_BRST32; - - if (can_do_sbus64) { - esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; - sbus_set_sbus64(esp->dev, esp->bursts); - } - - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ " - "will not clear!\n", - esp->host->unique_id); - break; - } - udelay(1); - } - - dma_write32(0, DMA_CSR); - dma_write32(esp->prev_hme_dmacsr, DMA_CSR); - - dma_write32(0, DMA_ADDR); - break; - - case dvmarev2: - if (esp->rev != ESP100) { - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_3CLKS, DMA_CSR); - } - break; - - case dvmarev3: - val = dma_read32(DMA_CSR); - val &= ~DMA_3CLKS; - val |= DMA_2CLKS; - if (can_do_burst32) { - val &= ~DMA_BRST_SZ; - val |= DMA_BRST32; - } - dma_write32(val, DMA_CSR); - break; - - case dvmaesc1: - val = dma_read32(DMA_CSR); - val |= DMA_ADD_ENABLE; - val &= ~DMA_BCNT_ENAB; - if (!can_do_burst32 && can_do_burst16) { - val |= DMA_ESC_BURST; - } else { - val &= ~(DMA_ESC_BURST); - } - dma_write32(val, DMA_CSR); - break; - - default: - break; - } - - /* Enable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_INT_ENAB, DMA_CSR); -} - -static void sbus_esp_dma_drain(struct esp *esp) -{ - u32 csr; - int lim; - - if (esp->dma->revision == dvmahme) - return; - - csr = dma_read32(DMA_CSR); - if (!(csr & DMA_FIFO_ISDRAIN)) - return; - - if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1) - dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); - - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", - esp->host->unique_id); - break; - } - udelay(1); - } -} - -static void sbus_esp_dma_invalidate(struct esp *esp) -{ - if (esp->dma->revision == dvmahme) { - dma_write32(DMA_RST_SCSI, DMA_CSR); - - esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | - (DMA_PARITY_OFF | DMA_2CLKS | - DMA_SCSI_DISAB | DMA_INT_ENAB)) & - ~(DMA_ST_WRITE | DMA_ENABLE)); - - dma_write32(0, DMA_CSR); - dma_write32(esp->prev_hme_dmacsr, DMA_CSR); - - /* This is necessary to avoid having the SCSI channel - * engine lock up on us. - */ - dma_write32(0, DMA_ADDR); - } else { - u32 val; - int lim; - - lim = 1000; - while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not " - "invalidate!\n", esp->host->unique_id); - break; - } - udelay(1); - } - - val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - val |= DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - val &= ~DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - } -} - -static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - u32 csr; - - BUG_ON(!(cmd & ESP_CMD_DMA)); - - sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - if (esp->rev == FASHME) { - sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO); - sbus_esp_write8(esp, 0, FAS_RHI); - - scsi_esp_cmd(esp, cmd); - - csr = esp->prev_hme_dmacsr; - csr |= DMA_SCSI_DISAB | DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - esp->prev_hme_dmacsr = csr; - - dma_write32(dma_count, DMA_COUNT); - dma_write32(addr, DMA_ADDR); - dma_write32(csr, DMA_CSR); - } else { - csr = dma_read32(DMA_CSR); - csr |= DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - dma_write32(csr, DMA_CSR); - if (esp->dma->revision == dvmaesc1) { - u32 end = PAGE_ALIGN(addr + dma_count + 16U); - dma_write32(end - addr, DMA_COUNT); - } - dma_write32(addr, DMA_ADDR); - - scsi_esp_cmd(esp, cmd); - } - -} - -static int sbus_esp_dma_error(struct esp *esp) -{ - u32 csr = dma_read32(DMA_CSR); - - if (csr & DMA_HNDL_ERROR) - return 1; - - return 0; -} - -static const struct esp_driver_ops sbus_esp_ops = { - .esp_write8 = sbus_esp_write8, - .esp_read8 = sbus_esp_read8, - .map_single = sbus_esp_map_single, - .map_sg = sbus_esp_map_sg, - .unmap_single = sbus_esp_unmap_single, - .unmap_sg = sbus_esp_unmap_sg, - .irq_pending = sbus_esp_irq_pending, - .reset_dma = sbus_esp_reset_dma, - .dma_drain = sbus_esp_dma_drain, - .dma_invalidate = sbus_esp_dma_invalidate, - .send_dma_cmd = sbus_esp_send_dma_cmd, - .dma_error = sbus_esp_dma_error, -}; - -static int __devinit esp_sbus_probe_one(struct device *dev, - struct sbus_dev *esp_dev, - struct sbus_dev *espdma, - struct sbus_bus *sbus, - int hme) -{ - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - int err; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - - err = -ENOMEM; - if (!host) - goto fail; - - host->max_id = (hme ? 16 : 8); - esp = host_to_esp(host); - - esp->host = host; - esp->dev = esp_dev; - esp->ops = &sbus_esp_ops; - - if (hme) - esp->flags |= ESP_FLAG_WIDE_CAPABLE; - - err = esp_sbus_find_dma(esp, espdma); - if (err < 0) - goto fail_unlink; - - err = esp_sbus_map_regs(esp, hme); - if (err < 0) - goto fail_unlink; - - err = esp_sbus_map_command_block(esp); - if (err < 0) - goto fail_unmap_regs; - - err = esp_sbus_register_irq(esp); - if (err < 0) - goto fail_unmap_command_block; - - esp_sbus_get_props(esp, espdma); - - /* Before we try to touch the ESP chip, ESC1 dma can - * come up with the reset bit set, so make sure that - * is clear first. - */ - if (esp->dma->revision == dvmaesc1) { - u32 val = dma_read32(DMA_CSR); - - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); - } - - dev_set_drvdata(&esp_dev->ofdev.dev, esp); - - err = scsi_esp_register(esp, dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - sbus_free_consistent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs: - sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); -fail_unlink: - scsi_host_put(host); -fail: - return err; -} - -static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - struct device_node *dp = dev->node; - struct sbus_dev *dma_sdev = NULL; - int hme = 0; - - if (dp->parent && - (!strcmp(dp->parent->name, "espdma") || - !strcmp(dp->parent->name, "dma"))) - dma_sdev = sdev->parent; - else if (!strcmp(dp->name, "SUNW,fas")) { - dma_sdev = sdev; - hme = 1; - } - - return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev, - sdev->bus, hme); -} - -static int __devexit esp_sbus_remove(struct of_device *dev) -{ - struct esp *esp = dev_get_drvdata(&dev->dev); - unsigned int irq = esp->host->irq; - u32 val; - - scsi_esp_unregister(esp); - - /* Disable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); - - free_irq(irq, esp); - sbus_free_consistent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); - sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE); - - scsi_host_put(esp->host); - - return 0; -} - -static struct of_device_id esp_match[] = { - { - .name = "SUNW,esp", - }, - { - .name = "SUNW,fas", - }, - { - .name = "esp", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, esp_match); - -static struct of_platform_driver esp_sbus_driver = { - .name = "esp", - .match_table = esp_match, - .probe = esp_sbus_probe, - .remove = __devexit_p(esp_sbus_remove), -}; - -static int __init sunesp_init(void) -{ - return of_register_driver(&esp_sbus_driver, &sbus_bus_type); -} - -static void __exit sunesp_exit(void) -{ - of_unregister_driver(&esp_sbus_driver); -} - -MODULE_DESCRIPTION("Sun ESP SCSI driver"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_init(sunesp_init); -module_exit(sunesp_exit); diff --git a/trunk/drivers/scsi/tmscsim.c b/trunk/drivers/scsi/tmscsim.c index 3158949ffa62..a583e89238fc 100644 --- a/trunk/drivers/scsi/tmscsim.c +++ b/trunk/drivers/scsi/tmscsim.c @@ -2680,7 +2680,7 @@ static int __init dc390_module_init(void) printk (KERN_INFO "DC390: Using safe settings.\n"); } - return pci_register_driver(&dc390_driver); + return pci_module_init(&dc390_driver); } static void __exit dc390_module_exit(void) diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index 90621c3312bc..c129a0e8e807 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -1310,8 +1310,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) { unsigned int status = serial_in(up, UART_MSR); - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - up->port.info != NULL) { + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) { if (status & UART_MSR_TERI) up->port.icount.rng++; if (status & UART_MSR_DDSR) @@ -1334,9 +1333,8 @@ static inline void serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; - unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock(&up->port.lock); status = serial_inp(up, UART_LSR); @@ -1348,7 +1346,7 @@ serial8250_handle_port(struct uart_8250_port *up) if (status & UART_LSR_THRE) transmit_chars(up); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock(&up->port.lock); } /* diff --git a/trunk/drivers/serial/icom.c b/trunk/drivers/serial/icom.c index 246c5572667b..41431d0d5512 100644 --- a/trunk/drivers/serial/icom.c +++ b/trunk/drivers/serial/icom.c @@ -164,7 +164,7 @@ static void free_port_memory(struct icom_port *icom_port) } } -static int __devinit get_port_memory(struct icom_port *icom_port) +static int __init get_port_memory(struct icom_port *icom_port) { int index; unsigned long stgAddr; @@ -1380,7 +1380,7 @@ static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *i 0x8024 + 2 - 2 * (icom_port->port - 2); } } -static int __devinit icom_load_ports(struct icom_adapter *icom_adapter) +static int __init icom_load_ports(struct icom_adapter *icom_adapter) { struct icom_port *icom_port; int port_num; @@ -1473,7 +1473,7 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) } } - free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); + free_irq(icom_adapter->irq_number, (void *) icom_adapter); iounmap(icom_adapter->base_addr); icom_free_adapter(icom_adapter); pci_release_regions(icom_adapter->pci_dev); @@ -1539,6 +1539,7 @@ static int __devinit icom_probe(struct pci_dev *dev, } icom_adapter->base_addr_pci = pci_resource_start(dev, 0); + icom_adapter->irq_number = dev->irq; icom_adapter->pci_dev = dev; icom_adapter->version = ent->driver_data; icom_adapter->subsystem_id = ent->subdevice; @@ -1569,7 +1570,7 @@ static int __devinit icom_probe(struct pci_dev *dev, icom_port = &icom_adapter->port_info[index]; if (icom_port->status == ICOM_PORT_ACTIVE) { - icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq; + icom_port->uart_port.irq = icom_port->adapter->irq_number; icom_port->uart_port.type = PORT_ICOM; icom_port->uart_port.iotype = UPIO_MEM; icom_port->uart_port.membase = diff --git a/trunk/drivers/serial/icom.h b/trunk/drivers/serial/icom.h index e8578d8cd35e..798f1ef23712 100644 --- a/trunk/drivers/serial/icom.h +++ b/trunk/drivers/serial/icom.h @@ -258,6 +258,7 @@ struct icom_port { struct icom_adapter { void __iomem * base_addr; unsigned long base_addr_pci; + unsigned char irq_number; struct pci_dev *pci_dev; struct icom_port port_info[4]; int index; diff --git a/trunk/drivers/serial/pmac_zilog.c b/trunk/drivers/serial/pmac_zilog.c index be8d75721a85..752ef07516b9 100644 --- a/trunk/drivers/serial/pmac_zilog.c +++ b/trunk/drivers/serial/pmac_zilog.c @@ -1467,8 +1467,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) if (ZS_IS_IRDA(uap)) uap->port_type = PMAC_SCC_IRDA; if (ZS_IS_INTMODEM(uap)) { - struct device_node* i2c_modem = - of_find_node_by_name(NULL, "i2c-modem"); + struct device_node* i2c_modem = find_devices("i2c-modem"); if (i2c_modem) { const char* mid = get_property(i2c_modem, "modem-id", NULL); @@ -1483,7 +1482,6 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) } printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n", mid ? (*mid) : 0); - of_node_put(i2c_modem); } else { printk(KERN_INFO "pmac_zilog: serial modem detected\n"); } diff --git a/trunk/drivers/serial/sunsu.c b/trunk/drivers/serial/sunsu.c index bfd44177a215..96a852aa1903 100644 --- a/trunk/drivers/serial/sunsu.c +++ b/trunk/drivers/serial/sunsu.c @@ -1387,8 +1387,8 @@ static enum su_type __devinit su_get_type(struct device_node *dp) struct device_node *ap = of_find_node_by_path("/aliases"); if (ap) { - const char *keyb = of_get_property(ap, "keyboard", NULL); - const char *ms = of_get_property(ap, "mouse", NULL); + char *keyb = of_get_property(ap, "keyboard", NULL); + char *ms = of_get_property(ap, "mouse", NULL); if (keyb) { if (dp == of_find_node_by_path(keyb)) diff --git a/trunk/drivers/usb/Makefile b/trunk/drivers/usb/Makefile index f5de58a63f2b..8b7ff467d262 100644 --- a/trunk/drivers/usb/Makefile +++ b/trunk/drivers/usb/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_U132_HCD) += host/ +obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_OHCI_AT91) += host/ obj-$(CONFIG_USB_ACM) += class/ @@ -26,7 +27,10 @@ obj-$(CONFIG_USB) += storage/ obj-$(CONFIG_USB_ACECAD) += input/ obj-$(CONFIG_USB_AIPTEK) += input/ obj-$(CONFIG_USB_ATI_REMOTE) += input/ +obj-$(CONFIG_USB_HID) += input/ +obj-$(CONFIG_USB_KBD) += input/ obj-$(CONFIG_USB_KBTAB) += input/ +obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_WACOM) += input/ diff --git a/trunk/drivers/usb/atm/cxacru.c b/trunk/drivers/usb/atm/cxacru.c index 30b7bfbc985a..3dfa3e40e148 100644 --- a/trunk/drivers/usb/atm/cxacru.c +++ b/trunk/drivers/usb/atm/cxacru.c @@ -4,7 +4,6 @@ * * Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru) - * Copyright (C) 2007 Simon Arlott * * 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 @@ -35,14 +34,14 @@ #include #include #include -#include +#include /* FIXME: linux/firmware.h should include it itself */ #include #include #include "usbatm.h" -#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott" -#define DRIVER_VERSION "0.3" +#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands" +#define DRIVER_VERSION "0.2" #define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver" static const char cxacru_driver_name[] = "cxacru"; @@ -65,7 +64,7 @@ static const char cxacru_driver_name[] = "cxacru"; #define SDRAM_ENA 0x1 #define CMD_TIMEOUT 2000 /* msecs */ -#define POLL_INTERVAL 1 /* secs */ +#define POLL_INTERVAL 5000 /* msecs */ /* commands for interaction with the modem through the control channel before * firmware is loaded */ @@ -147,13 +146,6 @@ enum cxacru_info_idx { CXINF_MAX = 0x1c, }; -enum cxacru_poll_state { - CXPOLL_STOPPING, - CXPOLL_STOPPED, - CXPOLL_POLLING, - CXPOLL_SHUTDOWN -}; - struct cxacru_modem_type { u32 pll_f_clk; u32 pll_b_clk; @@ -166,12 +158,7 @@ struct cxacru_data { const struct cxacru_modem_type *modem_type; int line_status; - struct mutex adsl_state_serialize; - int adsl_status; struct delayed_work poll_work; - u32 card_info[CXINF_MAX]; - struct mutex poll_state_serialize; - int poll_state; /* contol handles */ struct mutex cm_serialize; @@ -183,275 +170,6 @@ struct cxacru_data { struct completion snd_done; }; -static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, - u8 *wdata, int wsize, u8 *rdata, int rsize); -static void cxacru_poll_status(struct work_struct *work); - -/* Card info exported through sysfs */ -#define CXACRU__ATTR_INIT(_name) \ -static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL) - -#define CXACRU_CMD_INIT(_name) \ -static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \ - cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name) - -#define CXACRU_ATTR_INIT(_value, _type, _name) \ -static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \ - struct cxacru_data *instance = usbatm_instance->driver_data; \ - return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \ -} \ -CXACRU__ATTR_INIT(_name) - -#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name) -#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) -#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) - -#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name) -#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) -#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) - -static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", value); -} - -static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", value); -} - -static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) -{ - if (unlikely(value < 0)) { - return snprintf(buf, PAGE_SIZE, "%d.%02u\n", - value / 100, -value % 100); - } else { - return snprintf(buf, PAGE_SIZE, "%d.%02u\n", - value / 100, value % 100); - } -} - -static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) -{ - switch (value) { - case 0: return snprintf(buf, PAGE_SIZE, "no\n"); - case 1: return snprintf(buf, PAGE_SIZE, "yes\n"); - default: return 0; - } -} - -static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) -{ - switch (value) { - case 1: return snprintf(buf, PAGE_SIZE, "not connected\n"); - case 2: return snprintf(buf, PAGE_SIZE, "connected\n"); - case 3: return snprintf(buf, PAGE_SIZE, "lost\n"); - default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value); - } -} - -static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) -{ - switch (value) { - case 0: return snprintf(buf, PAGE_SIZE, "down\n"); - case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n"); - case 2: return snprintf(buf, PAGE_SIZE, "training\n"); - case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n"); - case 4: return snprintf(buf, PAGE_SIZE, "exchange\n"); - case 5: return snprintf(buf, PAGE_SIZE, "up\n"); - case 6: return snprintf(buf, PAGE_SIZE, "waiting\n"); - case 7: return snprintf(buf, PAGE_SIZE, "initialising\n"); - default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value); - } -} - -static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) -{ - switch (value) { - case 0: return 0; - case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n"); - case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n"); - case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n"); - default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value); - } -} - -/* - * This could use MAC_ADDRESS_HIGH and MAC_ADDRESS_LOW, but since - * this data is already in atm_dev there's no point. - * - * MAC_ADDRESS_HIGH = 0x????5544 - * MAC_ADDRESS_LOW = 0x33221100 - * Where 00-55 are bytes 0-5 of the MAC. - */ -static ssize_t cxacru_sysfs_show_mac_address(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); - struct atm_dev *atm_dev = usbatm_instance->atm_dev; - - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2], - atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]); -} - -static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); - struct cxacru_data *instance = usbatm_instance->driver_data; - u32 value = instance->card_info[CXINF_LINE_STARTABLE]; - - switch (value) { - case 0: return snprintf(buf, PAGE_SIZE, "running\n"); - case 1: return snprintf(buf, PAGE_SIZE, "stopped\n"); - default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value); - } -} - -static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); - struct cxacru_data *instance = usbatm_instance->driver_data; - int ret; - int poll = -1; - char str_cmd[8]; - int len = strlen(buf); - - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - - ret = sscanf(buf, "%7s", str_cmd); - if (ret != 1) - return -EINVAL; - ret = 0; - - if (mutex_lock_interruptible(&instance->adsl_state_serialize)) - return -ERESTARTSYS; - - if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) { - ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0); - if (ret < 0) { - atm_err(usbatm_instance, "change adsl state:" - " CHIP_ADSL_LINE_STOP returned %d\n", ret); - - ret = -EIO; - } else { - ret = len; - poll = CXPOLL_STOPPED; - } - } - - /* Line status is only updated every second - * and the device appears to only react to - * START/STOP every second too. Wait 1.5s to - * be sure that restart will have an effect. */ - if (!strcmp(str_cmd, "restart")) - msleep(1500); - - if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) { - ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); - if (ret < 0) { - atm_err(usbatm_instance, "change adsl state:" - " CHIP_ADSL_LINE_START returned %d\n", ret); - - ret = -EIO; - } else { - ret = len; - poll = CXPOLL_POLLING; - } - } - - if (!strcmp(str_cmd, "poll")) { - ret = len; - poll = CXPOLL_POLLING; - } - - if (ret == 0) { - ret = -EINVAL; - poll = -1; - } - - if (poll == CXPOLL_POLLING) { - mutex_lock(&instance->poll_state_serialize); - switch (instance->poll_state) { - case CXPOLL_STOPPED: - /* start polling */ - instance->poll_state = CXPOLL_POLLING; - break; - - case CXPOLL_STOPPING: - /* abort stop request */ - instance->poll_state = CXPOLL_POLLING; - case CXPOLL_POLLING: - case CXPOLL_SHUTDOWN: - /* don't start polling */ - poll = -1; - } - mutex_unlock(&instance->poll_state_serialize); - } else if (poll == CXPOLL_STOPPED) { - mutex_lock(&instance->poll_state_serialize); - /* request stop */ - if (instance->poll_state == CXPOLL_POLLING) - instance->poll_state = CXPOLL_STOPPING; - mutex_unlock(&instance->poll_state_serialize); - } - - mutex_unlock(&instance->adsl_state_serialize); - - if (poll == CXPOLL_POLLING) - cxacru_poll_status(&instance->poll_work.work); - - return ret; -} - -/* - * All device attributes are included in CXACRU_ALL_FILES - * so that the same list can be used multiple times: - * INIT (define the device attributes) - * CREATE (create all the device files) - * REMOVE (remove all the device files) - * - * With the last two being defined as needed in the functions - * they are used in before calling CXACRU_ALL_FILES() - */ -#define CXACRU_ALL_FILES(_action) \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_RATE, u32, downstream_rate); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_RATE, u32, upstream_rate); \ -CXACRU_ATTR_##_action(CXINF_LINK_STATUS, LINK, link_status); \ -CXACRU_ATTR_##_action(CXINF_LINE_STATUS, LINE, line_status); \ -CXACRU__ATTR_##_action( mac_address); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_SNR_MARGIN, dB, upstream_snr_margin); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_SNR_MARGIN, dB, downstream_snr_margin); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_ATTENUATION, dB, upstream_attenuation); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_ATTENUATION, dB, downstream_attenuation); \ -CXACRU_ATTR_##_action(CXINF_TRANSMITTER_POWER, s8, transmitter_power); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_BITS_PER_FRAME, u32, upstream_bits_per_frame); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_BITS_PER_FRAME, u32, downstream_bits_per_frame); \ -CXACRU_ATTR_##_action(CXINF_STARTUP_ATTEMPTS, u32, startup_attempts); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_CRC_ERRORS, u32, upstream_crc_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_CRC_ERRORS, u32, downstream_crc_errors); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC_ERRORS, u32, upstream_fec_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS, u32, downstream_fec_errors); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS, u32, upstream_hec_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS, u32, downstream_hec_errors); \ -CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE, bool, line_startable); \ -CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \ -CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \ -CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \ -CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \ -CXACRU_CMD_##_action( adsl_state); - -CXACRU_ALL_FILES(INIT); - /* the following three functions are stolen from drivers/usb/core/message.c */ static void cxacru_blocking_completion(struct urb *urb) { @@ -629,6 +347,8 @@ static int cxacru_card_status(struct cxacru_data *instance) return 0; } +static void cxacru_poll_status(struct work_struct *work); + static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev) { @@ -637,7 +357,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev = usbatm_instance->atm_dev; */ int ret; - int start_polling = 1; dbg("cxacru_atm_start"); @@ -650,35 +369,14 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, } /* start ADSL */ - mutex_lock(&instance->adsl_state_serialize); ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); if (ret < 0) { atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret); - mutex_unlock(&instance->adsl_state_serialize); return ret; } /* Start status polling */ - mutex_lock(&instance->poll_state_serialize); - switch (instance->poll_state) { - case CXPOLL_STOPPED: - /* start polling */ - instance->poll_state = CXPOLL_POLLING; - break; - - case CXPOLL_STOPPING: - /* abort stop request */ - instance->poll_state = CXPOLL_POLLING; - case CXPOLL_POLLING: - case CXPOLL_SHUTDOWN: - /* don't start polling */ - start_polling = 0; - } - mutex_unlock(&instance->poll_state_serialize); - mutex_unlock(&instance->adsl_state_serialize); - - if (start_polling) - cxacru_poll_status(&instance->poll_work.work); + cxacru_poll_status(&instance->poll_work.work); return 0; } @@ -689,46 +387,14 @@ static void cxacru_poll_status(struct work_struct *work) u32 buf[CXINF_MAX] = {}; struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; - int keep_polling = 1; int ret; ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX); if (ret < 0) { - if (ret != -ESHUTDOWN) - atm_warn(usbatm, "poll status: error %d\n", ret); - - mutex_lock(&instance->poll_state_serialize); - if (instance->poll_state != CXPOLL_SHUTDOWN) { - instance->poll_state = CXPOLL_STOPPED; - - if (ret != -ESHUTDOWN) - atm_warn(usbatm, "polling disabled, set adsl_state" - " to 'start' or 'poll' to resume\n"); - } - mutex_unlock(&instance->poll_state_serialize); + atm_warn(usbatm, "poll status: error %d\n", ret); goto reschedule; } - memcpy(instance->card_info, buf, sizeof(instance->card_info)); - - if (instance->adsl_status != buf[CXINF_LINE_STARTABLE]) { - instance->adsl_status = buf[CXINF_LINE_STARTABLE]; - - switch (instance->adsl_status) { - case 0: - atm_printk(KERN_INFO, usbatm, "ADSL state: running\n"); - break; - - case 1: - atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n"); - break; - - default: - atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status); - break; - } - } - if (instance->line_status == buf[CXINF_LINE_STATUS]) goto reschedule; @@ -783,20 +449,7 @@ static void cxacru_poll_status(struct work_struct *work) break; } reschedule: - - mutex_lock(&instance->poll_state_serialize); - if (instance->poll_state == CXPOLL_STOPPING && - instance->adsl_status == 1 && /* stopped */ - instance->line_status == 0) /* down */ - instance->poll_state = CXPOLL_STOPPED; - - if (instance->poll_state == CXPOLL_STOPPED) - keep_polling = 0; - mutex_unlock(&instance->poll_state_serialize); - - if (keep_polling) - schedule_delayed_work(&instance->poll_work, - round_jiffies_relative(POLL_INTERVAL*HZ)); + schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL)); } static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, @@ -1031,14 +684,6 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, instance->usbatm = usbatm_instance; instance->modem_type = (struct cxacru_modem_type *) id->driver_info; - memset(instance->card_info, 0, sizeof(instance->card_info)); - - mutex_init(&instance->poll_state_serialize); - instance->poll_state = CXPOLL_STOPPED; - instance->line_status = -1; - instance->adsl_status = -1; - - mutex_init(&instance->adsl_state_serialize); instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->rcv_buf) { @@ -1065,13 +710,6 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, goto fail; } - #define CXACRU_DEVICE_CREATE_FILE(_name) \ - ret = device_create_file(&intf->dev, &dev_attr_##_name); \ - if (unlikely(ret)) \ - goto fail_sysfs; - CXACRU_ALL_FILES(CREATE); - #undef CXACRU_DEVICE_CREATE_FILE - usb_fill_int_urb(instance->rcv_urb, usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), instance->rcv_buf, PAGE_SIZE, @@ -1092,14 +730,6 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, return 0; - fail_sysfs: - dbg("cxacru_bind: device_create_file failed (%d)\n", ret); - - #define CXACRU_DEVICE_REMOVE_FILE(_name) \ - device_remove_file(&intf->dev, &dev_attr_##_name); - CXACRU_ALL_FILES(REMOVE); - #undef CXACRU_DEVICE_REVOVE_FILE - fail: free_page((unsigned long) instance->snd_buf); free_page((unsigned long) instance->rcv_buf); @@ -1114,7 +744,6 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, struct usb_interface *intf) { struct cxacru_data *instance = usbatm_instance->driver_data; - int is_polling = 1; dbg("cxacru_unbind entered"); @@ -1123,20 +752,8 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, return; } - mutex_lock(&instance->poll_state_serialize); - BUG_ON(instance->poll_state == CXPOLL_SHUTDOWN); - - /* ensure that status polling continues unless - * it has already stopped */ - if (instance->poll_state == CXPOLL_STOPPED) - is_polling = 0; - - /* stop polling from being stopped or started */ - instance->poll_state = CXPOLL_SHUTDOWN; - mutex_unlock(&instance->poll_state_serialize); - - if (is_polling) - cancel_rearming_delayed_work(&instance->poll_work); + while (!cancel_delayed_work(&instance->poll_work)) + flush_scheduled_work(); usb_kill_urb(instance->snd_urb); usb_kill_urb(instance->rcv_urb); @@ -1145,12 +762,6 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, free_page((unsigned long) instance->snd_buf); free_page((unsigned long) instance->rcv_buf); - - #define CXACRU_DEVICE_REMOVE_FILE(_name) \ - device_remove_file(&intf->dev, &dev_attr_##_name); - CXACRU_ALL_FILES(REMOVE); - #undef CXACRU_DEVICE_REVOVE_FILE - kfree(instance); usbatm_instance->driver_data = NULL; diff --git a/trunk/drivers/usb/atm/usbatm.c b/trunk/drivers/usb/atm/usbatm.c index b3f779f5933a..ec63b0ee0743 100644 --- a/trunk/drivers/usb/atm/usbatm.c +++ b/trunk/drivers/usb/atm/usbatm.c @@ -274,9 +274,6 @@ static void usbatm_complete(struct urb *urb) (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) || urb->status != -EILSEQ )) { - if (urb->status == -ESHUTDOWN) - return; - if (printk_ratelimit()) atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n", __func__, urb, urb->status); @@ -346,7 +343,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end); } - memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); + memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); __skb_put(sarb, ATM_CELL_PAYLOAD); if (pti & 1) { @@ -373,7 +370,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char goto out; } - if (crc32_be(~0, skb_tail_pointer(sarb) - pdu_length, pdu_length) != 0xc704dd7b) { + if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) { atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n", __func__, vcc); atomic_inc(&vcc->stats->rx_err); @@ -399,9 +396,7 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char goto out; /* atm_charge increments rx_drop */ } - skb_copy_to_linear_data(skb, - skb_tail_pointer(sarb) - pdu_length, - length); + memcpy(skb->data, sarb->tail - pdu_length, length); __skb_put(skb, length); vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u", @@ -489,7 +484,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance, ptr[4] = 0xec; ptr += ATM_CELL_HEADER; - skb_copy_from_linear_data(skb, ptr, data_len); + memcpy(ptr, skb->data, data_len); ptr += data_len; __skb_pull(skb, data_len); @@ -971,14 +966,6 @@ static int usbatm_atm_init(struct usbatm_data *instance) /* temp init ATM device, set to 128kbit */ atm_dev->link_rate = 128 * 1000 / 424; - ret = sysfs_create_link(&atm_dev->class_dev.kobj, - &instance->usb_intf->dev.kobj, "device"); - if (ret) { - atm_err(instance, "%s: sysfs_create_link failed: %d\n", - __func__, ret); - goto fail_sysfs; - } - if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) { atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret); goto fail; @@ -997,8 +984,6 @@ static int usbatm_atm_init(struct usbatm_data *instance) return 0; fail: - sysfs_remove_link(&atm_dev->class_dev.kobj, "device"); - fail_sysfs: instance->atm_dev = NULL; atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */ return ret; @@ -1331,10 +1316,8 @@ void usbatm_usb_disconnect(struct usb_interface *intf) kfree(instance->cell_buf); /* ATM finalize */ - if (instance->atm_dev) { - sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device"); + if (instance->atm_dev) atm_dev_deregister(instance->atm_dev); - } usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ } diff --git a/trunk/drivers/usb/class/cdc-acm.c b/trunk/drivers/usb/class/cdc-acm.c index 14de3b1b6a20..31ae661e586a 100644 --- a/trunk/drivers/usb/class/cdc-acm.c +++ b/trunk/drivers/usb/class/cdc-acm.c @@ -212,41 +212,7 @@ static int acm_write_start(struct acm *acm) } return rc; } -/* - * attributes exported through sysfs - */ -static ssize_t show_caps -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->ctrl_caps); -} -static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); - -static ssize_t show_country_codes -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - memcpy(buf, acm->country_codes, acm->country_code_size); - return acm->country_code_size; -} - -static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); - -static ssize_t show_country_rel_date -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->country_rel_date); -} -static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); /* * Interrupt handlers for various ACM device responses */ @@ -548,7 +514,6 @@ static void acm_tty_unregister(struct acm *acm) usb_free_urb(acm->writeurb); for (i = 0; i < nr; i++) usb_free_urb(acm->ru[i].urb); - kfree(acm->country_codes); kfree(acm); } @@ -796,7 +761,6 @@ static int acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; - struct usb_cdc_country_functional_desc *cfd = NULL; char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; @@ -860,9 +824,8 @@ static int acm_probe (struct usb_interface *intf, union_header = (struct usb_cdc_union_desc *) buffer; break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; + case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */ + break; /* for now we ignore it */ case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ case USB_CDC_ACM_TYPE: @@ -1020,34 +983,6 @@ static int acm_probe (struct usb_interface *intf, goto alloc_fail7; } - usb_set_intfdata (intf, acm); - - i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); - if (i < 0) - goto alloc_fail8; - - if (cfd) { /* export the country data */ - acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); - if (!acm->country_codes) - goto skip_countries; - acm->country_code_size = cfd->bLength - 4; - memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); - acm->country_rel_date = cfd->iCountryCodeRelDate; - - i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); - if (i < 0) { - kfree(acm->country_codes); - goto skip_countries; - } - - i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); - if (i < 0) { - kfree(acm->country_codes); - goto skip_countries; - } - } - -skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -1071,10 +1006,9 @@ static int acm_probe (struct usb_interface *intf, tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; - + usb_set_intfdata (intf, acm); return 0; -alloc_fail8: - usb_free_urb(acm->writeurb); + alloc_fail7: for (i = 0; i < num_rx_buf; i++) usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); @@ -1093,7 +1027,7 @@ static int acm_probe (struct usb_interface *intf, static void acm_disconnect(struct usb_interface *intf) { - struct acm *acm = usb_get_intfdata(intf); + struct acm *acm = usb_get_intfdata (intf); struct usb_device *usb_dev = interface_to_usbdev(intf); int i; @@ -1107,11 +1041,6 @@ static void acm_disconnect(struct usb_interface *intf) mutex_unlock(&open_mutex); return; } - if (acm->country_codes){ - device_remove_file(&intf->dev, &dev_attr_wCountryCodes); - device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate); - } - device_remove_file(&intf->dev, &dev_attr_bmCapabilities); acm->dev = NULL; usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); diff --git a/trunk/drivers/usb/class/cdc-acm.h b/trunk/drivers/usb/class/cdc-acm.h index 09f7765dbf8d..1bcaea32cfc1 100644 --- a/trunk/drivers/usb/class/cdc-acm.h +++ b/trunk/drivers/usb/class/cdc-acm.h @@ -91,9 +91,6 @@ struct acm { struct urb *ctrlurb, *writeurb; /* urbs */ u8 *ctrl_buffer; /* buffers of urbs */ dma_addr_t ctrl_dma; /* dma handles of buffers */ - u8 *country_codes; /* country codes from device */ - unsigned int country_code_size; /* size of this buffer */ - unsigned int country_rel_date; /* release date of version */ struct acm_wb wb[ACM_NW]; struct acm_ru ru[ACM_NR]; struct acm_rb rb[ACM_NR]; diff --git a/trunk/drivers/usb/core/Kconfig b/trunk/drivers/usb/core/Kconfig index f493fb1eaa27..2fc0f88a3d86 100644 --- a/trunk/drivers/usb/core/Kconfig +++ b/trunk/drivers/usb/core/Kconfig @@ -31,30 +31,7 @@ config USB_DEVICEFS For the format of the various /proc/bus/usb/ files, please read . - Usbfs files can't handle Access Control Lists (ACL), which are the - default way to grant access to USB devices for untrusted users of a - desktop system. The usbfs functionality is replaced by real - device-nodes managed by udev. These nodes live in /dev/bus/usb and - are used by libusb. - -config USB_DEVICE_CLASS - bool "USB device class-devices (DEPRECATED)" - depends on USB - default n - ---help--- - Userspace access to USB devices is granted by device-nodes exported - directly from the usbdev in sysfs. Old versions of the driver - core and udev needed additional class devices to export device nodes. - - These additional devices are difficult to handle in userspace, if - information about USB interfaces must be available. One device contains - the device node, the other device contains the interface data. Both - devices are at the same level in sysfs (siblings) and one can't access - the other. The device node created directly by the usbdev is the parent - device of the interface and therefore easily accessible from the interface - event. - - This option provides backward compatibility if needed. + Most users want to say Y here. config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation (EXPERIMENTAL)" diff --git a/trunk/drivers/usb/core/devices.c b/trunk/drivers/usb/core/devices.c index 6753ca059ee4..aefc7987120d 100644 --- a/trunk/drivers/usb/core/devices.c +++ b/trunk/drivers/usb/core/devices.c @@ -246,6 +246,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, if (start > end) return start; + down_read(&usb_bus_type.subsys.rwsem); if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name @@ -262,6 +263,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, desc->bInterfaceSubClass, desc->bInterfaceProtocol, driver_name); + up_read(&usb_bus_type.subsys.rwsem); return start; } diff --git a/trunk/drivers/usb/core/devio.c b/trunk/drivers/usb/core/devio.c index 927a181120a9..36e7a843bf91 100644 --- a/trunk/drivers/usb/core/devio.c +++ b/trunk/drivers/usb/core/devio.c @@ -57,6 +57,7 @@ #define USB_MAXBUS 64 #define USB_DEVICE_MAX USB_MAXBUS * 128 +static struct class *usb_device_class; /* Mutual exclusion for removal, open, and release */ DEFINE_MUTEX(usbfs_mutex); @@ -420,11 +421,14 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum) if (test_bit(ifnum, &ps->ifclaimed)) return 0; + /* lock against other changes to driver bindings */ + down_write(&usb_bus_type.subsys.rwsem); intf = usb_ifnum_to_if(dev, ifnum); if (!intf) err = -ENOENT; else err = usb_driver_claim_interface(&usbfs_driver, intf, ps); + up_write(&usb_bus_type.subsys.rwsem); if (err == 0) set_bit(ifnum, &ps->ifclaimed); return err; @@ -440,6 +444,8 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum) if (ifnum >= 8*sizeof(ps->ifclaimed)) return err; dev = ps->dev; + /* lock against other changes to driver bindings */ + down_write(&usb_bus_type.subsys.rwsem); intf = usb_ifnum_to_if(dev, ifnum); if (!intf) err = -ENOENT; @@ -447,6 +453,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum) usb_driver_release_interface(&usbfs_driver, intf); err = 0; } + up_write(&usb_bus_type.subsys.rwsem); return err; } @@ -513,25 +520,22 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig return ret; } -static int __match_minor(struct device *dev, void *data) +static struct usb_device *usbdev_lookup_minor(int minor) { - int minor = *((int *)data); + struct device *device; + struct usb_device *udev = NULL; - if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) - return 1; - return 0; -} - -static struct usb_device *usbdev_lookup_by_minor(int minor) -{ - struct device *dev; + down(&usb_device_class->sem); + list_for_each_entry(device, &usb_device_class->devices, node) { + if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + udev = device->platform_data; + break; + } + } + up(&usb_device_class->sem); - dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor); - if (!dev) - return NULL; - put_device(dev); - return container_of(dev, struct usb_device, dev); -} + return udev; +}; /* * file operations @@ -550,14 +554,11 @@ static int usbdev_open(struct inode *inode, struct file *file) goto out; ret = -ENOENT; - /* usbdev device-node */ + /* check if we are called from a real node or usbfs */ if (imajor(inode) == USB_DEVICE_MAJOR) - dev = usbdev_lookup_by_minor(iminor(inode)); -#ifdef CONFIG_USB_DEVICEFS - /* procfs file */ + dev = usbdev_lookup_minor(iminor(inode)); if (!dev) dev = inode->i_private; -#endif if (!dev) goto out; ret = usb_autoresume_device(dev); @@ -580,7 +581,7 @@ static int usbdev_open(struct inode *inode, struct file *file) ps->disccontext = NULL; ps->ifclaimed = 0; security_task_getsecid(current, &ps->secid); - smp_wmb(); + wmb(); list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; out: @@ -812,6 +813,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) if (copy_from_user(&gd, arg, sizeof(gd))) return -EFAULT; + down_read(&usb_bus_type.subsys.rwsem); intf = usb_ifnum_to_if(ps->dev, gd.interface); if (!intf || !intf->dev.driver) ret = -ENODATA; @@ -820,6 +822,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) sizeof(gd.driver)); ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); } + up_read(&usb_bus_type.subsys.rwsem); return ret; } @@ -1348,12 +1351,15 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: + + down_write(&usb_bus_type.subsys.rwsem); if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); dev_dbg (&intf->dev, "disconnect by usbfs\n"); usb_driver_release_interface(driver, intf); } else retval = -ENODATA; + up_write(&usb_bus_type.subsys.rwsem); break; /* let kernel drivers try to (re)bind to the interface */ @@ -1365,6 +1371,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) /* talk directly to the interface's driver */ default: + down_read(&usb_bus_type.subsys.rwsem); if (intf->dev.driver) driver = to_usb_driver(intf->dev.driver); if (driver == NULL || driver->ioctl == NULL) { @@ -1374,6 +1381,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } + up_read(&usb_bus_type.subsys.rwsem); } /* cleanup and return */ @@ -1575,7 +1583,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai return mask; } -const struct file_operations usbdev_file_operations = { +const struct file_operations usbfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1584,53 +1592,50 @@ const struct file_operations usbdev_file_operations = { .release = usbdev_release, }; -#ifdef CONFIG_USB_DEVICE_CLASS -static struct class *usb_classdev_class; - -static int usb_classdev_add(struct usb_device *dev) +static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->usb_classdev = device_create(usb_classdev_class, &dev->dev, + dev->usbfs_dev = device_create(usb_device_class, &dev->dev, MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - if (IS_ERR(dev->usb_classdev)) - return PTR_ERR(dev->usb_classdev); + if (IS_ERR(dev->usbfs_dev)) + return PTR_ERR(dev->usbfs_dev); + dev->usbfs_dev->platform_data = dev; return 0; } -static void usb_classdev_remove(struct usb_device *dev) +static void usbdev_remove(struct usb_device *dev) { - device_unregister(dev->usb_classdev); + device_unregister(dev->usbfs_dev); } -static int usb_classdev_notify(struct notifier_block *self, - unsigned long action, void *dev) +static int usbdev_notify(struct notifier_block *self, unsigned long action, + void *dev) { switch (action) { case USB_DEVICE_ADD: - if (usb_classdev_add(dev)) + if (usbdev_add(dev)) return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: - usb_classdev_remove(dev); + usbdev_remove(dev); break; } return NOTIFY_OK; } static struct notifier_block usbdev_nb = { - .notifier_call = usb_classdev_notify, + .notifier_call = usbdev_notify, }; -#endif static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE, }; -int __init usb_devio_init(void) +int __init usbdev_init(void) { int retval; @@ -1640,38 +1645,38 @@ int __init usb_devio_init(void) err("unable to register minors for usb_device"); goto out; } - cdev_init(&usb_device_cdev, &usbdev_file_operations); + cdev_init(&usb_device_cdev, &usbfs_device_file_operations); retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); if (retval) { err("unable to get usb_device major %d", USB_DEVICE_MAJOR); goto error_cdev; } -#ifdef CONFIG_USB_DEVICE_CLASS - usb_classdev_class = class_create(THIS_MODULE, "usb_device"); - if (IS_ERR(usb_classdev_class)) { + usb_device_class = class_create(THIS_MODULE, "usb_device"); + if (IS_ERR(usb_device_class)) { err("unable to register usb_device class"); - retval = PTR_ERR(usb_classdev_class); - cdev_del(&usb_device_cdev); - usb_classdev_class = NULL; - goto out; + retval = PTR_ERR(usb_device_class); + goto error_class; } usb_register_notify(&usbdev_nb); -#endif + out: return retval; +error_class: + usb_device_class = NULL; + cdev_del(&usb_device_cdev); + error_cdev: unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); goto out; } -void usb_devio_cleanup(void) +void usbdev_cleanup(void) { -#ifdef CONFIG_USB_DEVICE_CLASS usb_unregister_notify(&usbdev_nb); - class_destroy(usb_classdev_class); -#endif + class_destroy(usb_device_class); cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); } + diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index b9f7f90aef82..9e3e943f313c 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -287,9 +287,9 @@ static int usb_unbind_interface(struct device *dev) * way to bind to an interface is to return the private data from * the driver's probe() method. * - * Callers must own the device lock, so driver probe() entries don't need - * extra locking, but other call contexts may need to explicitly claim that - * lock. + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver probe() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) @@ -330,9 +330,9 @@ EXPORT_SYMBOL(usb_driver_claim_interface); * also causes the driver disconnect() method to be called. * * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the device lock, so driver disconnect() entries don't - * need extra locking, but other call contexts may need to explicitly claim - * that lock. + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver disconnect() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. */ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) @@ -574,10 +574,23 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG + +/* + * This sends an uevent to userspace, typically helping to load driver + * or other modules, configure the device, and more. Drivers can provide + * a MODULE_DEVICE_TABLE to help with module loading subtasks. + * + * We're called either from khubd (the typical case) or from root hub + * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle + * delays in event delivery. Use sysfs (and DEVPATH) to make sure the + * device (and this configuration!) are still present. + */ static int usb_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { + struct usb_interface *intf; struct usb_device *usb_dev; + struct usb_host_interface *alt; int i = 0; int length = 0; @@ -587,11 +600,13 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, /* driver is often null here; dev_dbg() would oops */ pr_debug ("usb %s: uevent\n", dev->bus_id); - if (is_usb_device(dev)) + if (is_usb_device(dev)) { usb_dev = to_usb_device(dev); - else { - struct usb_interface *intf = to_usb_interface(dev); + alt = NULL; + } else { + intf = to_usb_interface(dev); usb_dev = interface_to_usbdev(intf); + alt = intf->cur_altsetting; } if (usb_dev->devnum < 0) { @@ -606,7 +621,9 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, #ifdef CONFIG_USB_DEVICEFS /* If this is available, userspace programs can directly read * all the device descriptors we don't tell them about. Or - * act as usermode drivers. + * even act as usermode drivers. + * + * FIXME reduce hardwired intelligence here */ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, @@ -633,29 +650,44 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, + if (!is_usb_device(dev)) { + + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "BUSNUM=%03d", - usb_dev->bus->busnum)) - return -ENOMEM; + "INTERFACE=%d/%d/%d", + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DEVNUM=%03d", - usb_dev->devnum)) - return -ENOMEM; + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + le16_to_cpu(usb_dev->descriptor.bcdDevice), + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol)) + return -ENOMEM; + } envp[i] = NULL; + return 0; } #else static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) + int num_envp, char *buffer, int buffer_size) { return -ENODEV; } + #endif /* CONFIG_HOTPLUG */ /** @@ -840,10 +872,8 @@ static int usb_resume_device(struct usb_device *udev) done: // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - if (status == 0) { - udev->autoresume_disabled = 0; + if (status == 0) udev->dev.power.power_state.event = PM_EVENT_ON; - } return status; } @@ -932,7 +962,6 @@ static int autosuspend_check(struct usb_device *udev) { int i; struct usb_interface *intf; - unsigned long suspend_time; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -941,10 +970,9 @@ static int autosuspend_check(struct usb_device *udev) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->pm_usage_cnt > 0) return -EBUSY; - if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) + if (!udev->autosuspend_delay) return -EPERM; - suspend_time = udev->last_busy + udev->autosuspend_delay; if (udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; @@ -960,24 +988,6 @@ static int autosuspend_check(struct usb_device *udev) } } } - - /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. - */ - if (time_after(suspend_time, jiffies)) { - if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ - queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - suspend_time - jiffies); - } - return -EAGAIN; - } return 0; } @@ -1023,25 +1033,26 @@ static int autosuspend_check(struct usb_device *udev) * * This routine can run only in process context. */ -static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) +int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { int status = 0; int i = 0; struct usb_interface *intf; struct usb_device *parent = udev->parent; - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) - goto done; + cancel_delayed_work(&udev->autosuspend); + if (udev->state == USB_STATE_NOTATTACHED) + return 0; + if (udev->state == USB_STATE_SUSPENDED) + return 0; udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { status = autosuspend_check(udev); if (status < 0) - goto done; + return status; } - cancel_delayed_work(&udev->autosuspend); /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { @@ -1066,7 +1077,6 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } else if (parent) usb_autosuspend_device(parent); - done: // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; } @@ -1099,7 +1109,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * * This routine can run only in process context. */ -static int usb_resume_both(struct usb_device *udev) +int usb_resume_both(struct usb_device *udev) { int status = 0; int i; @@ -1107,17 +1117,11 @@ static int usb_resume_both(struct usb_device *udev) struct usb_device *parent = udev->parent; cancel_delayed_work(&udev->autosuspend); - if (udev->state == USB_STATE_NOTATTACHED) { - status = -ENODEV; - goto done; - } + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { - if (udev->auto_pm && udev->autoresume_disabled) { - status = -EPERM; - goto done; - } if (parent) { status = usb_autoresume_device(parent); if (status == 0) { @@ -1163,7 +1167,6 @@ static int usb_resume_both(struct usb_device *udev) } } - done: // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; } @@ -1178,34 +1181,20 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) int status = 0; usb_pm_lock(udev); - udev->auto_pm = 1; udev->pm_usage_cnt += inc_usage_cnt; WARN_ON(udev->pm_usage_cnt < 0); if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { - if (udev->state == USB_STATE_SUSPENDED) - status = usb_resume_both(udev); + udev->auto_pm = 1; + status = usb_resume_both(udev); if (status != 0) udev->pm_usage_cnt -= inc_usage_cnt; - else if (inc_usage_cnt) - udev->last_busy = jiffies; - } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { - if (inc_usage_cnt) - udev->last_busy = jiffies; - status = usb_suspend_both(udev, PMSG_SUSPEND); - } + } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + udev->autosuspend_delay); usb_pm_unlock(udev); return status; } -/* usb_autosuspend_work - callback routine to autosuspend a USB device */ -void usb_autosuspend_work(struct work_struct *work) -{ - struct usb_device *udev = - container_of(work, struct usb_device, autosuspend.work); - - usb_autopm_do_device(udev, 0); -} - /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces * @udev: the usb_device to autosuspend @@ -1297,20 +1286,15 @@ static int usb_autopm_do_interface(struct usb_interface *intf, if (intf->condition == USB_INTERFACE_UNBOUND) status = -ENODEV; else { - udev->auto_pm = 1; intf->pm_usage_cnt += inc_usage_cnt; if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { - if (udev->state == USB_STATE_SUSPENDED) - status = usb_resume_both(udev); + udev->auto_pm = 1; + status = usb_resume_both(udev); if (status != 0) intf->pm_usage_cnt -= inc_usage_cnt; - else if (inc_usage_cnt) - udev->last_busy = jiffies; - } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { - if (inc_usage_cnt) - udev->last_busy = jiffies; - status = usb_suspend_both(udev, PMSG_SUSPEND); - } + } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + udev->autosuspend_delay); } usb_pm_unlock(udev); return status; @@ -1369,14 +1353,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); * or @intf is unbound. A typical example would be a character-device * driver when its device file is opened. * - * - * The routine increments @intf's usage counter. (However if the - * autoresume fails then the counter is re-decremented.) So long as the - * counter is greater than 0, autosuspend will not be allowed for @intf - * or its usb_device. When the driver is finished using @intf it should - * call usb_autopm_put_interface() to decrement the usage counter and - * queue a delayed autosuspend request (if the counter is <= 0). - * + * The routine increments @intf's usage counter. So long as the counter + * is greater than 0, autosuspend will not be allowed for @intf or its + * usb_device. When the driver is finished using @intf it should call + * usb_autopm_put_interface() to decrement the usage counter and queue + * a delayed autosuspend request (if the counter is <= 0). * * Note that @intf->pm_usage_cnt is owned by the interface driver. The * core will not change its value other than the increment and decrement @@ -1424,96 +1405,50 @@ int usb_autopm_set_interface(struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usb_autopm_set_interface); -#else - -void usb_autosuspend_work(struct work_struct *work) -{} - #endif /* CONFIG_USB_SUSPEND */ -/** - * usb_external_suspend_device - external suspend of a USB device and its interfaces - * @udev: the usb_device to suspend - * @msg: Power Management message describing this state transition - * - * This routine handles external suspend requests: ones not generated - * internally by a USB driver (autosuspend) but rather coming from the user - * (via sysfs) or the PM core (system sleep). The suspend will be carried - * out regardless of @udev's usage counter or those of its interfaces, - * and regardless of whether or not remote wakeup is enabled. Of course, - * interface drivers still have the option of failing the suspend (if - * there are unsuspended children, for example). - * - * The caller must hold @udev's device lock. - */ -int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg) +static int usb_suspend(struct device *dev, pm_message_t message) { int status; - usb_pm_lock(udev); - udev->auto_pm = 0; - status = usb_suspend_both(udev, msg); - usb_pm_unlock(udev); + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); + + usb_pm_lock(udev); + udev->auto_pm = 0; + status = usb_suspend_both(udev, message); + usb_pm_unlock(udev); + } else + status = 0; return status; } -/** - * usb_external_resume_device - external resume of a USB device and its interfaces - * @udev: the usb_device to resume - * - * This routine handles external resume requests: ones not generated - * internally by a USB driver (autoresume) but rather coming from the user - * (via sysfs), the PM core (system resume), or the device itself (remote - * wakeup). @udev's usage counter is unaffected. - * - * The caller must hold @udev's device lock. - */ -int usb_external_resume_device(struct usb_device *udev) +static int usb_resume(struct device *dev) { int status; - usb_pm_lock(udev); - udev->auto_pm = 0; - status = usb_resume_both(udev); - usb_pm_unlock(udev); - - /* Now that the device is awake, we can start trying to autosuspend - * it again. */ - if (status == 0) - usb_try_autosuspend_device(udev); - return status; -} + if (is_usb_device(dev)) { + struct usb_device *udev = to_usb_device(dev); -static int usb_suspend(struct device *dev, pm_message_t message) -{ - if (!is_usb_device(dev)) /* Ignore PM for interfaces */ - return 0; - return usb_external_suspend_device(to_usb_device(dev), message); -} + usb_pm_lock(udev); + udev->auto_pm = 0; + status = usb_resume_both(udev); + usb_pm_unlock(udev); -static int usb_resume(struct device *dev) -{ - struct usb_device *udev; - - if (!is_usb_device(dev)) /* Ignore PM for interfaces */ - return 0; - udev = to_usb_device(dev); - if (udev->autoresume_disabled) - return -EPERM; - return usb_external_resume_device(udev); + /* Rebind drivers that had no suspend method? */ + } else + status = 0; + return status; } -#else - -#define usb_suspend NULL -#define usb_resume NULL - #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, +#ifdef CONFIG_PM .suspend = usb_suspend, .resume = usb_resume, +#endif }; diff --git a/trunk/drivers/usb/core/hcd.c b/trunk/drivers/usb/core/hcd.c index 40cf882293e6..b26c19e8d19f 100644 --- a/trunk/drivers/usb/core/hcd.c +++ b/trunk/drivers/usb/core/hcd.c @@ -37,7 +37,6 @@ #include #include #include -#include #include @@ -545,8 +544,6 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) unsigned long flags; char buffer[4]; /* Any root hubs with > 31 ports? */ - if (unlikely(!hcd->rh_registered)) - return; if (!hcd->uses_new_polling && !hcd->status_urb) return; @@ -1299,26 +1296,14 @@ int hcd_bus_resume (struct usb_bus *bus) return status; } -/* Workqueue routine for root-hub remote wakeup */ -static void hcd_resume_work(struct work_struct *work) -{ - struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work); - struct usb_device *udev = hcd->self.root_hub; - - usb_lock_device(udev); - usb_mark_last_busy(udev); - usb_external_resume_device(udev); - usb_unlock_device(udev); -} - /** * usb_hcd_resume_root_hub - called by HCD to resume its root hub * @hcd: host controller for this root hub * * The USB host controller calls this function when its root hub is * suspended (with the remote wakeup feature enabled) and a remote - * wakeup request is received. The routine submits a workqueue request - * to resume the root hub (that is, manage its downstream ports again). + * wakeup request is received. It queues a request for khubd to + * resume the root hub (that is, manage its downstream ports again). */ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) { @@ -1326,7 +1311,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) - queue_work(ksuspend_usb_wq, &hcd->wakeup_work); + usb_resume_root_hub (hcd->self.root_hub); spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); @@ -1515,9 +1500,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_PM - INIT_WORK(&hcd->wakeup_work, hcd_resume_work); -#endif hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : @@ -1684,20 +1666,16 @@ void usb_remove_hcd(struct usb_hcd *hcd) hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_PM - flush_workqueue(ksuspend_usb_wq); -#endif - mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); - hcd->driver->stop(hcd); - hcd->state = HC_STATE_HALT; - hcd->poll_rh = 0; del_timer_sync(&hcd->rh_timer); + hcd->driver->stop(hcd); + hcd->state = HC_STATE_HALT; + if (hcd->irq >= 0) free_irq(hcd->irq, hcd); usb_deregister_bus(&hcd->self); diff --git a/trunk/drivers/usb/core/hcd.h b/trunk/drivers/usb/core/hcd.h index ef50fa494e47..2a269ca20517 100644 --- a/trunk/drivers/usb/core/hcd.h +++ b/trunk/drivers/usb/core/hcd.h @@ -68,9 +68,6 @@ struct usb_hcd { struct timer_list rh_timer; /* drives root-hub polling */ struct urb *status_urb; /* the current status urb */ -#ifdef CONFIG_PM - struct work_struct wakeup_work; /* for remote wakeup */ -#endif /* * hardware info/state diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c index bde29ab2b504..b89a98e61323 100644 --- a/trunk/drivers/usb/core/hub.c +++ b/trunk/drivers/usb/core/hub.c @@ -119,7 +119,8 @@ MODULE_PARM_DESC(use_both_schemes, "first one fails"); -static inline char *portspeed(int portstatus) +#ifdef DEBUG +static inline char *portspeed (int portstatus) { if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) return "480 Mb/s"; @@ -128,6 +129,7 @@ static inline char *portspeed(int portstatus) else return "12 Mb/s"; } +#endif /* Note that hdev or one of its children must be locked! */ static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev) @@ -1367,15 +1369,11 @@ int usb_new_device(struct usb_device *udev) } #endif - /* export the usbdev device-node for libusb */ - udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, - (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); - /* Register the device. The device driver is responsible - * for adding the device files to sysfs and for configuring - * the device. + * for adding the device files to usbfs and sysfs and for + * configuring the device. */ - err = device_add(&udev->dev); + err = device_add (&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; @@ -1859,8 +1857,12 @@ static int remote_wakeup(struct usb_device *udev) usb_lock_device(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); - usb_mark_last_busy(udev); - status = usb_external_resume_device(udev); + status = usb_autoresume_device(udev); + + /* Give the interface drivers a chance to do something, + * then autosuspend the device again. */ + if (status == 0) + usb_autosuspend_device(udev); } usb_unlock_device(udev); return status; @@ -1984,6 +1986,13 @@ static inline int remote_wakeup(struct usb_device *udev) #define hub_resume NULL #endif +void usb_resume_root_hub(struct usb_device *hdev) +{ + struct usb_hub *hub = hdev_to_hub(hdev); + + kick_khubd(hub); +} + /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * diff --git a/trunk/drivers/usb/core/inode.c b/trunk/drivers/usb/core/inode.c index cddfc62c4611..11dad22da41c 100644 --- a/trunk/drivers/usb/core/inode.c +++ b/trunk/drivers/usb/core/inode.c @@ -662,7 +662,7 @@ static void usbfs_add_device(struct usb_device *dev) sprintf (name, "%03d", dev->devnum); dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, dev->bus->usbfs_dentry, dev, - &usbdev_file_operations, + &usbfs_device_file_operations, devuid, devgid); if (dev->usbfs_dentry == NULL) { err ("error creating usbfs device entry"); diff --git a/trunk/drivers/usb/core/message.c b/trunk/drivers/usb/core/message.c index b7434787db5f..217a3d6d0a06 100644 --- a/trunk/drivers/usb/core/message.c +++ b/trunk/drivers/usb/core/message.c @@ -412,24 +412,10 @@ int usb_sg_init ( io->urbs [i]->status = -EINPROGRESS; io->urbs [i]->actual_length = 0; - /* - * Some systems need to revert to PIO when DMA is temporarily - * unavailable. For their sakes, both transfer_buffer and - * transfer_dma are set when possible. However this can only - * work on systems without HIGHMEM, since DMA buffers located - * in high memory are not directly addressable by the CPU for - * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL - * to prevent stale pointers and to help spot bugs. - */ if (dma) { + /* hc may use _only_ transfer_dma */ io->urbs [i]->transfer_dma = sg_dma_address (sg + i); len = sg_dma_len (sg + i); -#ifdef CONFIG_HIGHMEM - io->urbs[i]->transfer_buffer = NULL; -#else - io->urbs[i]->transfer_buffer = - page_address(sg[i].page) + sg[i].offset; -#endif } else { /* hc may use _only_ transfer_buffer */ io->urbs [i]->transfer_buffer = @@ -1319,7 +1305,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = @@ -1329,67 +1315,6 @@ void usb_release_interface(struct device *dev) kfree(intf); } -#ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - struct usb_device *usb_dev; - struct usb_interface *intf; - struct usb_host_interface *alt; - int i = 0; - int length = 0; - - if (!dev) - return -ENODEV; - - /* driver is often null here; dev_dbg() would oops */ - pr_debug ("usb %s: uevent\n", dev->bus_id); - - intf = to_usb_interface(dev); - usb_dev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - envp[i] = NULL; - return 0; -} - -#else - -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) -{ - return -ENODEV; -} -#endif /* CONFIG_HOTPLUG */ - -struct device_type usb_if_device_type = { - .name = "usb_interface", - .release = usb_release_interface, - .uevent = usb_if_uevent, -}; - /* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated @@ -1424,7 +1349,7 @@ struct device_type usb_if_device_type = { * * This call is synchronous. The calling context must be able to sleep, * must own the device lock, and must not hold the driver model's USB - * bus mutex; usb device driver probe() methods cannot use this routine. + * bus rwsem; usb device driver probe() methods cannot use this routine. * * Returns zero on success, or else the status code returned by the * underlying call that failed. On successful completion, each interface @@ -1553,8 +1478,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration) intf->dev.parent = &dev->dev; intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; - intf->dev.type = &usb_if_device_type; intf->dev.dma_mask = dev->dev.dma_mask; + intf->dev.release = release_interface; device_initialize (&intf->dev); mark_quiesced(intf); sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", diff --git a/trunk/drivers/usb/core/quirks.c b/trunk/drivers/usb/core/quirks.c index 739f520908aa..f08ec85a6d64 100644 --- a/trunk/drivers/usb/core/quirks.c +++ b/trunk/drivers/usb/core/quirks.c @@ -42,7 +42,7 @@ static void usb_autosuspend_quirk(struct usb_device *udev) { #ifdef CONFIG_USB_SUSPEND /* disable autosuspend, but allow the user to re-enable it via sysfs */ - udev->autosuspend_disabled = 1; + udev->autosuspend_delay = 0; #endif } diff --git a/trunk/drivers/usb/core/sysfs.c b/trunk/drivers/usb/core/sysfs.c index e7c982377488..311d5df80386 100644 --- a/trunk/drivers/usb/core/sysfs.c +++ b/trunk/drivers/usb/core/sysfs.c @@ -11,7 +11,6 @@ #include -#include #include #include "usb.h" @@ -117,16 +116,6 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); -static ssize_t -show_busnum(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->bus->busnum); -} -static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL); - static ssize_t show_devnum(struct device *dev, struct device_attribute *attr, char *buf) { @@ -176,7 +165,7 @@ show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ); + return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ); } static ssize_t @@ -184,114 +173,38 @@ set_autosuspend(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); - int value; + unsigned value, old; - if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ || - value <= - INT_MAX/HZ) + if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ) return -EINVAL; value *= HZ; + old = udev->autosuspend_delay; udev->autosuspend_delay = value; - if (value >= 0) + if (value > 0 && old == 0) usb_try_autosuspend_device(udev); - else { - if (usb_autoresume_device(udev) == 0) - usb_autosuspend_device(udev); - } + return count; } static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, show_autosuspend, set_autosuspend); -static const char on_string[] = "on"; -static const char auto_string[] = "auto"; -static const char suspend_string[] = "suspend"; - -static ssize_t -show_level(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - const char *p = auto_string; - - if (udev->state == USB_STATE_SUSPENDED) { - if (udev->autoresume_disabled) - p = suspend_string; - } else { - if (udev->autosuspend_disabled) - p = on_string; - } - return sprintf(buf, "%s\n", p); -} - -static ssize_t -set_level(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int len = count; - char *cp; - int rc = 0; - - cp = memchr(buf, '\n', count); - if (cp) - len = cp - buf; - - usb_lock_device(udev); - - /* Setting the flags without calling usb_pm_lock is a subject to - * races, but who cares... - */ - if (len == sizeof on_string - 1 && - strncmp(buf, on_string, len) == 0) { - udev->autosuspend_disabled = 1; - udev->autoresume_disabled = 0; - rc = usb_external_resume_device(udev); - - } else if (len == sizeof auto_string - 1 && - strncmp(buf, auto_string, len) == 0) { - udev->autosuspend_disabled = 0; - udev->autoresume_disabled = 0; - rc = usb_external_resume_device(udev); - - } else if (len == sizeof suspend_string - 1 && - strncmp(buf, suspend_string, len) == 0) { - udev->autosuspend_disabled = 0; - udev->autoresume_disabled = 1; - rc = usb_external_suspend_device(udev, PMSG_SUSPEND); - - } else - rc = -EINVAL; - - usb_unlock_device(udev); - return (rc < 0 ? rc : count); -} - -static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); - static char power_group[] = "power"; static int add_power_attributes(struct device *dev) { int rc = 0; - if (is_usb_device(dev)) { + if (is_usb_device(dev)) rc = sysfs_add_file_to_group(&dev->kobj, &dev_attr_autosuspend.attr, power_group); - if (rc == 0) - rc = sysfs_add_file_to_group(&dev->kobj, - &dev_attr_level.attr, - power_group); - } return rc; } static void remove_power_attributes(struct device *dev) { - sysfs_remove_file_from_group(&dev->kobj, - &dev_attr_level.attr, - power_group); sysfs_remove_file_from_group(&dev->kobj, &dev_attr_autosuspend.attr, power_group); @@ -357,7 +270,6 @@ static struct attribute *dev_attrs[] = { &dev_attr_bNumConfigurations.attr, &dev_attr_bMaxPacketSize0.attr, &dev_attr_speed.attr, - &dev_attr_busnum.attr, &dev_attr_devnum.attr, &dev_attr_version.attr, &dev_attr_maxchild.attr, diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c index dfd1b5c87ca3..54b42ce311c1 100644 --- a/trunk/drivers/usb/core/usb.c +++ b/trunk/drivers/usb/core/usb.c @@ -49,13 +49,12 @@ const char *usbcore_name = "usbcore"; static int nousb; /* Disable USB when built into kernel image */ -/* Workqueue for autosuspend and for remote wakeup of root hubs */ -struct workqueue_struct *ksuspend_usb_wq; +struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */ #ifdef CONFIG_USB_SUSPEND static int usb_autosuspend_delay = 2; /* Default delay value, * in seconds */ -module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); +module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644); MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); #else @@ -197,11 +196,6 @@ static void usb_release_dev(struct device *dev) kfree(udev); } -struct device_type usb_device_type = { - .name = "usb_device", - .release = usb_release_dev, -}; - #ifdef CONFIG_PM static int ksuspend_usb_init(void) @@ -217,6 +211,27 @@ static void ksuspend_usb_cleanup(void) destroy_workqueue(ksuspend_usb_wq); } +#ifdef CONFIG_USB_SUSPEND + +/* usb_autosuspend_work - callback routine to autosuspend a USB device */ +static void usb_autosuspend_work(struct work_struct *work) +{ + struct usb_device *udev = + container_of(work, struct usb_device, autosuspend.work); + + usb_pm_lock(udev); + udev->auto_pm = 1; + usb_suspend_both(udev, PMSG_SUSPEND); + usb_pm_unlock(udev); +} + +#else + +static void usb_autosuspend_work(struct work_struct *work) +{} + +#endif /* CONFIG_USB_SUSPEND */ + #else #define ksuspend_usb_init() 0 @@ -252,10 +267,13 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; - dev->dev.type = &usb_device_type; dev->dev.dma_mask = bus->controller->dma_mask; + dev->dev.release = usb_release_dev; dev->state = USB_STATE_ATTACHED; + /* This magic assignment distinguishes devices from interfaces */ + dev->dev.platform_data = &usb_generic_driver; + INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; @@ -884,9 +902,9 @@ static int __init usb_init(void) retval = usb_register(&usbfs_driver); if (retval) goto driver_register_failed; - retval = usb_devio_init(); + retval = usbdev_init(); if (retval) - goto usb_devio_init_failed; + goto usbdevice_init_failed; retval = usbfs_init(); if (retval) goto fs_init_failed; @@ -901,8 +919,8 @@ static int __init usb_init(void) hub_init_failed: usbfs_cleanup(); fs_init_failed: - usb_devio_cleanup(); -usb_devio_init_failed: + usbdev_cleanup(); +usbdevice_init_failed: usb_deregister(&usbfs_driver); driver_register_failed: usb_major_cleanup(); @@ -929,7 +947,7 @@ static void __exit usb_exit(void) usb_major_cleanup(); usbfs_cleanup(); usb_deregister(&usbfs_driver); - usb_devio_cleanup(); + usbdev_cleanup(); usb_hub_cleanup(); usb_host_cleanup(); bus_unregister(&usb_bus_type); diff --git a/trunk/drivers/usb/core/usb.h b/trunk/drivers/usb/core/usb.h index bf2eb0dae2ec..08b5a04e3755 100644 --- a/trunk/drivers/usb/core/usb.h +++ b/trunk/drivers/usb/core/usb.h @@ -21,6 +21,7 @@ extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_kick_khubd(struct usb_device *dev); +extern void usb_resume_root_hub(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, const struct usb_device_id *id); @@ -33,12 +34,10 @@ extern void usb_host_cleanup(void); #ifdef CONFIG_PM -extern void usb_autosuspend_work(struct work_struct *work); +extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg); +extern int usb_resume_both(struct usb_device *udev); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); -extern int usb_external_suspend_device(struct usb_device *udev, - pm_message_t msg); -extern int usb_external_resume_device(struct usb_device *udev); static inline void usb_pm_lock(struct usb_device *udev) { @@ -52,6 +51,11 @@ static inline void usb_pm_unlock(struct usb_device *udev) #else +#define usb_suspend_both(udev, msg) 0 +static inline int usb_resume_both(struct usb_device *udev) +{ + return 0; +} #define usb_port_suspend(dev) 0 #define usb_port_resume(dev) 0 static inline void usb_pm_lock(struct usb_device *udev) {} @@ -78,13 +82,15 @@ static inline int usb_autoresume_device(struct usb_device *udev) extern struct workqueue_struct *ksuspend_usb_wq; extern struct bus_type usb_bus_type; -extern struct device_type usb_device_type; -extern struct device_type usb_if_device_type; extern struct usb_device_driver usb_generic_driver; +/* Here's how we tell apart devices and interfaces. Luckily there's + * no such thing as a platform USB device, so we can steal the use + * of the platform_data field. */ + static inline int is_usb_device(const struct device *dev) { - return dev->type == &usb_device_type; + return dev->platform_data == &usb_generic_driver; } /* Do the same for device drivers and interface drivers. */ @@ -120,11 +126,11 @@ extern const char *usbcore_name; extern struct mutex usbfs_mutex; extern struct usb_driver usbfs_driver; extern const struct file_operations usbfs_devices_fops; -extern const struct file_operations usbdev_file_operations; +extern const struct file_operations usbfs_device_file_operations; extern void usbfs_conn_disc_event(void); -extern int usb_devio_init(void); -extern void usb_devio_cleanup(void); +extern int usbdev_init(void); +extern void usbdev_cleanup(void); struct dev_state { struct list_head list; /* state list */ diff --git a/trunk/drivers/usb/gadget/Kconfig b/trunk/drivers/usb/gadget/Kconfig index 8065f2b53701..4097a86c4b5e 100644 --- a/trunk/drivers/usb/gadget/Kconfig +++ b/trunk/drivers/usb/gadget/Kconfig @@ -68,27 +68,6 @@ choice Many controller drivers are platform-specific; these often need board-specific hooks. -config USB_GADGET_FSL_USB2 - boolean "Freescale Highspeed USB DR Peripheral Controller" - depends on MPC834x || PPC_MPC831x - select USB_GADGET_DUALSPEED - help - Some of Freescale PowerPC processors have a High Speed - Dual-Role(DR) USB controller, which supports device mode. - - The number of programmable endpoints is different through - SOC revisions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fsl_usb2_udc" and force - all gadget drivers to also be dynamically linked. - -config USB_FSL_USB2 - tristate - depends on USB_GADGET_FSL_USB2 - default USB_GADGET - select USB_GADGET_SELECTED - config USB_GADGET_NET2280 boolean "NetChip 228x" depends on PCI @@ -391,7 +370,6 @@ config USB_GADGETFS config USB_FILE_STORAGE tristate "File-backed Storage Gadget" - depends on BLOCK help The File-backed Storage Gadget acts as a USB Mass Storage disk drive. As its storage repository it can use a regular diff --git a/trunk/drivers/usb/gadget/Makefile b/trunk/drivers/usb/gadget/Makefile index 5db19396631c..e71e086a1cfa 100644 --- a/trunk/drivers/usb/gadget/Makefile +++ b/trunk/drivers/usb/gadget/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o -obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o # # USB gadget drivers diff --git a/trunk/drivers/usb/gadget/ether.c b/trunk/drivers/usb/gadget/ether.c index 1dd8b57f4420..04e6b8508fb6 100644 --- a/trunk/drivers/usb/gadget/ether.c +++ b/trunk/drivers/usb/gadget/ether.c @@ -282,9 +282,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define DEV_CONFIG_CDC -#endif /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -1738,8 +1735,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) defer_kevent (dev, WORK_RX_MEMORY); if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); - if (skb) - dev_kfree_skb_any(skb); + dev_kfree_skb_any (skb); spin_lock(&dev->req_lock); list_add (&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); @@ -1770,6 +1766,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) break; } + skb->dev = dev->net; skb->protocol = eth_type_trans (skb, dev->net); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; diff --git a/trunk/drivers/usb/gadget/fsl_usb2_udc.c b/trunk/drivers/usb/gadget/fsl_usb2_udc.c deleted file mode 100644 index 157054ea3978..000000000000 --- a/trunk/drivers/usb/gadget/fsl_usb2_udc.c +++ /dev/null @@ -1,2500 +0,0 @@ -/* - * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved. - * - * Author: Li Yang - * Jiang Bo - * - * Description: - * Freescale high-speed USB SOC DR module device controller driver. - * This can be found on MPC8349E/MPC8313E cpus. - * The driver is previously named as mpc_udc. Based on bare board - * code from Dave Liu and Shlomi Gridish. - * - * 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. - */ - -#undef VERBOSE - -#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 "fsl_usb2_udc.h" - -#define DRIVER_DESC "Freescale High-Speed USB SOC Device Controller driver" -#define DRIVER_AUTHOR "Li Yang/Jiang Bo" -#define DRIVER_VERSION "Apr 20, 2007" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -static const char driver_name[] = "fsl-usb2-udc"; -static const char driver_desc[] = DRIVER_DESC; - -volatile static struct usb_dr_device *dr_regs = NULL; -volatile static struct usb_sys_interface *usb_sys_regs = NULL; - -/* it is initialized in probe() */ -static struct fsl_udc *udc_controller = NULL; - -static const struct usb_endpoint_descriptor -fsl_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, -}; - -static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state); -static int fsl_udc_resume(struct platform_device *pdev); -static void fsl_ep_fifo_flush(struct usb_ep *_ep); - -#ifdef CONFIG_PPC32 -#define fsl_readl(addr) in_le32(addr) -#define fsl_writel(addr, val32) out_le32(val32, addr) -#else -#define fsl_readl(addr) readl(addr) -#define fsl_writel(addr, val32) writel(addr, val32) -#endif - -/******************************************************************** - * Internal Used Function -********************************************************************/ -/*----------------------------------------------------------------- - * done() - retire a request; caller blocked irqs - * @status : request status to be set, only works when - * request is still in progress. - *--------------------------------------------------------------*/ -static void done(struct fsl_ep *ep, struct fsl_req *req, int status) -{ - struct fsl_udc *udc = NULL; - unsigned char stopped = ep->stopped; - struct ep_td_struct *curr_td, *next_td; - int j; - - udc = (struct fsl_udc *)ep->udc; - /* Removed the req from fsl_ep->queue */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { - curr_td = next_td; - if (j != req->dtd_count - 1) { - next_td = curr_td->next_td_virt; - } - dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); - } - - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - - if (status && (status != -ESHUTDOWN)) - VDBG("complete %s req %p stat %d len %u/%u", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - ep->stopped = 1; - - spin_unlock(&ep->udc->lock); - /* complete() is from gadget layer, - * eg fsg->bulk_in_complete() */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&ep->udc->lock); - ep->stopped = stopped; -} - -/*----------------------------------------------------------------- - * nuke(): delete all requests related to this ep - * called with spinlock held - *--------------------------------------------------------------*/ -static void nuke(struct fsl_ep *ep, int status) -{ - ep->stopped = 1; - - /* Flush fifo */ - fsl_ep_fifo_flush(&ep->ep); - - /* Whether this eq has request linked */ - while (!list_empty(&ep->queue)) { - struct fsl_req *req = NULL; - - req = list_entry(ep->queue.next, struct fsl_req, queue); - done(ep, req, status); - } -} - -/*------------------------------------------------------------------ - Internal Hardware related function - ------------------------------------------------------------------*/ - -static int dr_controller_setup(struct fsl_udc *udc) -{ - unsigned int tmp = 0, portctrl = 0, ctrl = 0; - unsigned long timeout; -#define FSL_UDC_RESET_TIMEOUT 1000 - - /* before here, make sure dr_regs has been initialized */ - if (!udc) - return -EINVAL; - - /* Stop and reset the usb controller */ - tmp = fsl_readl(&dr_regs->usbcmd); - tmp &= ~USB_CMD_RUN_STOP; - fsl_writel(tmp, &dr_regs->usbcmd); - - tmp = fsl_readl(&dr_regs->usbcmd); - tmp |= USB_CMD_CTRL_RESET; - fsl_writel(tmp, &dr_regs->usbcmd); - - /* Wait for reset to complete */ - timeout = jiffies + FSL_UDC_RESET_TIMEOUT; - while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { - if (time_after(jiffies, timeout)) { - ERR("udc reset timeout! \n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - /* Set the controller as device mode */ - tmp = fsl_readl(&dr_regs->usbmode); - tmp |= USB_MODE_CTRL_MODE_DEVICE; - /* Disable Setup Lockout */ - tmp |= USB_MODE_SETUP_LOCK_OFF; - fsl_writel(tmp, &dr_regs->usbmode); - - /* Clear the setup status */ - fsl_writel(0, &dr_regs->usbsts); - - tmp = udc->ep_qh_dma; - tmp &= USB_EP_LIST_ADDRESS_MASK; - fsl_writel(tmp, &dr_regs->endpointlistaddr); - - VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x", - (int)udc->ep_qh, (int)tmp, - fsl_readl(&dr_regs->endpointlistaddr)); - - /* Config PHY interface */ - portctrl = fsl_readl(&dr_regs->portsc1); - portctrl &= ~PORTSCX_PHY_TYPE_SEL; - switch (udc->phy_mode) { - case FSL_USB2_PHY_ULPI: - portctrl |= PORTSCX_PTS_ULPI; - break; - case FSL_USB2_PHY_UTMI: - case FSL_USB2_PHY_UTMI_WIDE: - portctrl |= PORTSCX_PTS_UTMI; - break; - case FSL_USB2_PHY_SERIAL: - portctrl |= PORTSCX_PTS_FSLS; - break; - default: - return -EINVAL; - } - fsl_writel(portctrl, &dr_regs->portsc1); - - /* Config control enable i/o output, cpu endian register */ - ctrl = __raw_readl(&usb_sys_regs->control); - ctrl |= USB_CTRL_IOENB; - __raw_writel(ctrl, &usb_sys_regs->control); - -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - /* Turn on cache snooping hardware, since some PowerPC platforms - * wholly rely on hardware to deal with cache coherent. */ - - /* Setup Snooping for all the 4GB space */ - tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */ - __raw_writel(tmp, &usb_sys_regs->snoop1); - tmp |= 0x80000000; /* starts from 0x8000000, size 2G */ - __raw_writel(tmp, &usb_sys_regs->snoop2); -#endif - - return 0; -} - -/* Enable DR irq and set controller to run state */ -static void dr_controller_run(struct fsl_udc *udc) -{ - u32 temp; - - /* Enable DR irq reg */ - temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN - | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN - | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; - - fsl_writel(temp, &dr_regs->usbintr); - - /* Clear stopped bit */ - udc->stopped = 0; - - /* Set the controller as device mode */ - temp = fsl_readl(&dr_regs->usbmode); - temp |= USB_MODE_CTRL_MODE_DEVICE; - fsl_writel(temp, &dr_regs->usbmode); - - /* Set controller to Run */ - temp = fsl_readl(&dr_regs->usbcmd); - temp |= USB_CMD_RUN_STOP; - fsl_writel(temp, &dr_regs->usbcmd); - - return; -} - -static void dr_controller_stop(struct fsl_udc *udc) -{ - unsigned int tmp; - - /* disable all INTR */ - fsl_writel(0, &dr_regs->usbintr); - - /* Set stopped bit for isr */ - udc->stopped = 1; - - /* disable IO output */ -/* usb_sys_regs->control = 0; */ - - /* set controller to Stop */ - tmp = fsl_readl(&dr_regs->usbcmd); - tmp &= ~USB_CMD_RUN_STOP; - fsl_writel(tmp, &dr_regs->usbcmd); - - return; -} - -void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type) -{ - unsigned int tmp_epctrl = 0; - - tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (dir) { - if (ep_num) - tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; - tmp_epctrl |= EPCTRL_TX_ENABLE; - tmp_epctrl |= ((unsigned int)(ep_type) - << EPCTRL_TX_EP_TYPE_SHIFT); - } else { - if (ep_num) - tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; - tmp_epctrl |= EPCTRL_RX_ENABLE; - tmp_epctrl |= ((unsigned int)(ep_type) - << EPCTRL_RX_EP_TYPE_SHIFT); - } - - fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); -} - -static void -dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value) -{ - u32 tmp_epctrl = 0; - - tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - - if (value) { - /* set the stall bit */ - if (dir) - tmp_epctrl |= EPCTRL_TX_EP_STALL; - else - tmp_epctrl |= EPCTRL_RX_EP_STALL; - } else { - /* clear the stall bit and reset data toggle */ - if (dir) { - tmp_epctrl &= ~EPCTRL_TX_EP_STALL; - tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; - } else { - tmp_epctrl &= ~EPCTRL_RX_EP_STALL; - tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; - } - } - fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); -} - -/* Get stall status of a specific ep - Return: 0: not stalled; 1:stalled */ -static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir) -{ - u32 epctrl; - - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (dir) - return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0; - else - return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0; -} - -/******************************************************************** - Internal Structure Build up functions -********************************************************************/ - -/*------------------------------------------------------------------ -* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH - * @zlt: Zero Length Termination Select (1: disable; 0: enable) - * @mult: Mult field - ------------------------------------------------------------------*/ -static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, - unsigned char dir, unsigned char ep_type, - unsigned int max_pkt_len, - unsigned int zlt, unsigned char mult) -{ - struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir]; - unsigned int tmp = 0; - - /* set the Endpoint Capabilites in QH */ - switch (ep_type) { - case USB_ENDPOINT_XFER_CONTROL: - /* Interrupt On Setup (IOS). for control ep */ - tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | EP_QUEUE_HEAD_IOS; - break; - case USB_ENDPOINT_XFER_ISOC: - tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | (mult << EP_QUEUE_HEAD_MULT_POS); - break; - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; - break; - default: - VDBG("error ep type is %d", ep_type); - return; - } - if (zlt) - tmp |= EP_QUEUE_HEAD_ZLT_SEL; - p_QH->max_pkt_length = cpu_to_le32(tmp); - - return; -} - -/* Setup qh structure and ep register for ep0. */ -static void ep0_setup(struct fsl_udc *udc) -{ - /* the intialization of an ep includes: fields in QH, Regs, - * fsl_ep struct */ - struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, - USB_MAX_CTRL_PAYLOAD, 0, 0); - struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, - USB_MAX_CTRL_PAYLOAD, 0, 0); - dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); - dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); - - return; - -} - -/*********************************************************************** - Endpoint Management Functions -***********************************************************************/ - -/*------------------------------------------------------------------------- - * when configurations are set, or when interface settings change - * for example the do_set_interface() in gadget layer, - * the driver will enable or disable the relevant endpoints - * ep0 doesn't use this routine. It is always enabled. --------------------------------------------------------------------------*/ -static int fsl_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fsl_udc *udc = NULL; - struct fsl_ep *ep = NULL; - unsigned short max = 0; - unsigned char mult = 0, zlt; - int retval = -EINVAL; - unsigned long flags = 0; - - ep = container_of(_ep, struct fsl_ep, ep); - - /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc - || (desc->bDescriptorType != USB_DT_ENDPOINT)) - return -EINVAL; - - udc = ep->udc; - - if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - max = le16_to_cpu(desc->wMaxPacketSize); - - /* Disable automatic zlp generation. Driver is reponsible to indicate - * explicitly through req->req.zero. This is needed to enable multi-td - * request. */ - zlt = 1; - - /* Assume the max packet size from gadget is always correct */ - switch (desc->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - /* mult = 0. Execute N Transactions as demonstrated by - * the USB variable length packet protocol where N is - * computed using the Maximum Packet Length (dQH) and - * the Total Bytes field (dTD) */ - mult = 0; - break; - case USB_ENDPOINT_XFER_ISOC: - /* Calculate transactions needed for high bandwidth iso */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto en_done; - break; - default: - goto en_done; - } - - spin_lock_irqsave(&udc->lock, flags); - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - - /* Controller related setup */ - /* Init EPx Queue Head (Ep Capabilites field in QH - * according to max, zlt, mult) */ - struct_ep_qh_setup(udc, (unsigned char) ep_index(ep), - (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) - ? USB_SEND : USB_RECV), - (unsigned char) (desc->bmAttributes - & USB_ENDPOINT_XFERTYPE_MASK), - max, zlt, mult); - - /* Init endpoint ctrl register */ - dr_ep_setup((unsigned char) ep_index(ep), - (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) - ? USB_SEND : USB_RECV), - (unsigned char) (desc->bmAttributes - & USB_ENDPOINT_XFERTYPE_MASK)); - - spin_unlock_irqrestore(&udc->lock, flags); - retval = 0; - - VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name, - ep->desc->bEndpointAddress & 0x0f, - (desc->bEndpointAddress & USB_DIR_IN) - ? "in" : "out", max); -en_done: - return retval; -} - -/*--------------------------------------------------------------------- - * @ep : the ep being unconfigured. May not be ep0 - * Any pending and uncomplete req will complete with status (-ESHUTDOWN) -*---------------------------------------------------------------------*/ -static int fsl_ep_disable(struct usb_ep *_ep) -{ - struct fsl_udc *udc = NULL; - struct fsl_ep *ep = NULL; - unsigned long flags = 0; - u32 epctrl; - int ep_num; - - ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || !ep->desc) { - VDBG("%s not enabled", _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - /* disable ep on controller */ - ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - - udc = (struct fsl_udc *)ep->udc; - spin_lock_irqsave(&udc->lock, flags); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = 0; - ep->stopped = 1; - spin_unlock_irqrestore(&udc->lock, flags); - - VDBG("disabled %s OK", _ep->name); - return 0; -} - -/*--------------------------------------------------------------------- - * allocate a request object used by this endpoint - * the main operation is to insert the req->queue to the eq->queue - * Returns the request, or null if one could not be allocated -*---------------------------------------------------------------------*/ -static struct usb_request * -fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct fsl_req *req = NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fsl_req *req = NULL; - - req = container_of(_req, struct fsl_req, req); - - if (_req) - kfree(req); -} - -/*------------------------------------------------------------------ - * Allocate an I/O buffer -*---------------------------------------------------------------------*/ -static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, gfp_t gfp_flags) -{ - struct fsl_ep *ep; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - - return dma_alloc_coherent(ep->udc->gadget.dev.parent, - bytes, dma, gfp_flags); -} - -/*------------------------------------------------------------------ - * frees an i/o buffer -*---------------------------------------------------------------------*/ -static void fsl_free_buffer(struct usb_ep *_ep, void *buf, - dma_addr_t dma, unsigned bytes) -{ - struct fsl_ep *ep; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - - dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma); -} - -/*-------------------------------------------------------------------------*/ -static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) -{ - int i = ep_index(ep) * 2 + ep_is_in(ep); - u32 temp, bitmask, tmp_stat; - struct ep_queue_head *dQH = &ep->udc->ep_qh[i]; - - /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); - VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ - - bitmask = ep_is_in(ep) - ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - /* Add td to the end */ - struct fsl_req *lastreq; - lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); - lastreq->tail->next_td_ptr = - cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK); - /* Read prime bit, if 1 goto done */ - if (fsl_readl(&dr_regs->endpointprime) & bitmask) - goto out; - - do { - /* Set ATDTW bit in USBCMD */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd); - - /* Read correct status bit */ - tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask; - - } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW)); - - /* Write ATDTW bit to 0 */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); - - if (tmp_stat) - goto out; - } - - /* Write dQH next pointer and terminate bit to 0 */ - temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - dQH->next_dtd_ptr = cpu_to_le32(temp); - - /* Clear active and halt bit */ - temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE - | EP_QUEUE_HEAD_STATUS_HALT)); - dQH->size_ioc_int_sts &= temp; - - /* Prime endpoint by writing 1 to ENDPTPRIME */ - temp = ep_is_in(ep) - ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))); - fsl_writel(temp, &dr_regs->endpointprime); -out: - return 0; -} - -/* Fill in the dTD structure - * @req: request that the transfer belongs to - * @length: return actually data length of the dTD - * @dma: return dma address of the dTD - * @is_last: return flag if it is the last dTD of the request - * return: pointer to the built dTD */ -static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, - dma_addr_t *dma, int *is_last) -{ - u32 swap_temp; - struct ep_td_struct *dtd; - - /* how big will this transfer be? */ - *length = min(req->req.length - req->req.actual, - (unsigned)EP_MAX_LENGTH_TRANSFER); - - dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma); - if (dtd == NULL) - return dtd; - - dtd->td_dma = *dma; - /* Clear reserved field */ - swap_temp = cpu_to_le32(dtd->size_ioc_sts); - swap_temp &= ~DTD_RESERVED_FIELDS; - dtd->size_ioc_sts = cpu_to_le32(swap_temp); - - /* Init all of buffer page pointers */ - swap_temp = (u32) (req->req.dma + req->req.actual); - dtd->buff_ptr0 = cpu_to_le32(swap_temp); - dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000); - dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000); - dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000); - dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000); - - req->req.actual += *length; - - /* zlp is needed if req->req.zero is set */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) - *is_last = 1; - else - *is_last = 0; - - if ((*is_last) == 0) - VDBG("multi-dtd request!\n"); - /* Fill in the transfer size; set active bit */ - swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); - - /* Enable interrupt for the last dtd of a request */ - if (*is_last && !req->req.no_interrupt) - swap_temp |= DTD_IOC; - - dtd->size_ioc_sts = cpu_to_le32(swap_temp); - - mb(); - - VDBG("length = %d address= 0x%x", *length, (int)*dma); - - return dtd; -} - -/* Generate dtd chain for a request */ -static int fsl_req_to_dtd(struct fsl_req *req) -{ - unsigned count; - int is_last; - int is_first =1; - struct ep_td_struct *last_dtd = NULL, *dtd; - dma_addr_t dma; - - do { - dtd = fsl_build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->next_td_ptr = cpu_to_le32(dma); - last_dtd->next_td_virt = dtd; - } - last_dtd = dtd; - - req->dtd_count++; - } while (!is_last); - - dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE); - - req->tail = dtd; - - return 0; -} - -/* queues (submits) an I/O request to an endpoint */ -static int -fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); - struct fsl_req *req = container_of(_req, struct fsl_req, req); - struct fsl_udc *udc; - unsigned long flags; - int is_iso = 0; - - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - VDBG("%s, bad params\n", __FUNCTION__); - return -EINVAL; - } - if (!_ep || (!ep->desc && ep_index(ep))) { - VDBG("%s, bad ep\n", __FUNCTION__); - return -EINVAL; - } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - is_iso = 1; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - req->ep = ep; - - /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* build dtds and push them to device queue */ - if (!fsl_req_to_dtd(req)) { - fsl_queue_td(ep, req); - } else { - spin_unlock_irqrestore(&udc->lock, flags); - return -ENOMEM; - } - - /* Update ep0 state */ - if ((ep_index(ep) == 0)) - udc->ep0_state = DATA_STATE_XMIT; - - /* irq handler advances the queue */ - if (req != NULL) - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); - struct fsl_req *req; - unsigned long flags; - int ep_num, stopped, ret = 0; - u32 epctrl; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - stopped = ep->stopped; - - /* Stop the ep before we deal with the queue */ - ep->stopped = 1; - ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - ret = -EINVAL; - goto out; - } - - /* The request is in progress, or completed but not dequeued */ - if (ep->queue.next == &req->queue) { - _req->status = -ECONNRESET; - fsl_ep_fifo_flush(_ep); /* flush current transfer */ - - /* The request isn't the last request in this ep queue */ - if (req->queue.next != &ep->queue) { - struct ep_queue_head *qh; - struct fsl_req *next_req; - - qh = ep->qh; - next_req = list_entry(req->queue.next, struct fsl_req, - queue); - - /* Point the QH to the first TD of next request */ - fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); - } - - /* The request hasn't been processed, patch up the TD chain */ - } else { - struct fsl_req *prev_req; - - prev_req = list_entry(req->queue.prev, struct fsl_req, queue); - fsl_writel(fsl_readl(&req->tail->next_td_ptr), - &prev_req->tail->next_td_ptr); - - } - - done(ep, req, -ECONNRESET); - - /* Enable EP */ -out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl |= EPCTRL_TX_ENABLE; - else - epctrl |= EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return ret; -} - -/*-------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------- - * modify the endpoint halt feature - * @ep: the non-isochronous endpoint being stalled - * @value: 1--set halt 0--clear halt - * Returns zero, or a negative error code. -*----------------------------------------------------------------*/ -static int fsl_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct fsl_ep *ep = NULL; - unsigned long flags = 0; - int status = -EOPNOTSUPP; /* operation not supported */ - unsigned char ep_dir = 0, ep_num = 0; - struct fsl_udc *udc = NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - udc = ep->udc; - if (!_ep || !ep->desc) { - status = -EINVAL; - goto out; - } - - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - status = -EOPNOTSUPP; - goto out; - } - - /* Attempt to halt IN ep will fail if any transfer requests - * are still queue */ - if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - status = 0; - ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; - ep_num = (unsigned char)(ep_index(ep)); - spin_lock_irqsave(&ep->udc->lock, flags); - dr_ep_change_stall(ep_num, ep_dir, value); - spin_unlock_irqrestore(&ep->udc->lock, flags); - - if (ep_index(ep) == 0) { - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = 0; - } -out: - VDBG(" %s %s halt stat %d", ep->ep.name, - value ? "set" : "clear", status); - - return status; -} - -static void fsl_ep_fifo_flush(struct usb_ep *_ep) -{ - struct fsl_ep *ep; - int ep_num, ep_dir; - u32 bits; - unsigned long timeout; -#define FSL_UDC_FLUSH_TIMEOUT 1000 - - if (!_ep) { - return; - } else { - ep = container_of(_ep, struct fsl_ep, ep); - if (!ep->desc) - return; - } - ep_num = ep_index(ep); - ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; - - if (ep_num == 0) - bits = (1 << 16) | 1; - else if (ep_dir == USB_SEND) - bits = 1 << (16 + ep_num); - else - bits = 1 << ep_num; - - timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT; - do { - fsl_writel(bits, &dr_regs->endptflush); - - /* Wait until flush complete */ - while (fsl_readl(&dr_regs->endptflush)) { - if (time_after(jiffies, timeout)) { - ERR("ep flush timeout\n"); - return; - } - cpu_relax(); - } - /* See if we need to flush again */ - } while (fsl_readl(&dr_regs->endptstatus) & bits); -} - -static struct usb_ep_ops fsl_ep_ops = { - .enable = fsl_ep_enable, - .disable = fsl_ep_disable, - - .alloc_request = fsl_alloc_request, - .free_request = fsl_free_request, - - .alloc_buffer = fsl_alloc_buffer, - .free_buffer = fsl_free_buffer, - - .queue = fsl_ep_queue, - .dequeue = fsl_ep_dequeue, - - .set_halt = fsl_ep_set_halt, - .fifo_flush = fsl_ep_fifo_flush, /* flush fifo */ -}; - -/*------------------------------------------------------------------------- - Gadget Driver Layer Operations --------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------- - * Get the current frame number (from DR frame_index Reg ) - *----------------------------------------------------------------------*/ -static int fsl_get_frame(struct usb_gadget *gadget) -{ - return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS); -} - -/*----------------------------------------------------------------------- - * Tries to wake up the host connected to this gadget - -----------------------------------------------------------------------*/ -static int fsl_wakeup(struct usb_gadget *gadget) -{ - struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget); - u32 portsc; - - /* Remote wakeup feature not enabled by host */ - if (!udc->remote_wakeup) - return -ENOTSUPP; - - portsc = fsl_readl(&dr_regs->portsc1); - /* not suspended? */ - if (!(portsc & PORTSCX_PORT_SUSPEND)) - return 0; - /* trigger force resume */ - portsc |= PORTSCX_PORT_FORCE_RESUME; - fsl_writel(portsc, &dr_regs->portsc1); - return 0; -} - -static int can_pullup(struct fsl_udc *udc) -{ - return udc->driver && udc->softconnect && udc->vbus_active; -} - -/* Notify controller that VBUS is powered, Called by whatever - detects VBUS sessions */ -static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct fsl_udc *udc; - unsigned long flags; - - udc = container_of(gadget, struct fsl_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - VDBG("VBUS %s\n", is_active ? "on" : "off"); - udc->vbus_active = (is_active != 0); - if (can_pullup(udc)) - fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - else - fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ -#ifdef CONFIG_USB_OTG - struct fsl_udc *udc; - - udc = container_of(gadget, struct fsl_udc, gadget); - - if (udc->transceiver) - return otg_set_power(udc->transceiver, mA); -#endif - return -ENOTSUPP; -} - -/* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnet - */ -static int fsl_pullup(struct usb_gadget *gadget, int is_on) -{ - struct fsl_udc *udc; - - udc = container_of(gadget, struct fsl_udc, gadget); - udc->softconnect = (is_on != 0); - if (can_pullup(udc)) - fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - else - fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - - return 0; -} - -/* defined in usb_gadget.h */ -static struct usb_gadget_ops fsl_gadget_ops = { - .get_frame = fsl_get_frame, - .wakeup = fsl_wakeup, -/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */ - .vbus_session = fsl_vbus_session, - .vbus_draw = fsl_vbus_draw, - .pullup = fsl_pullup, -}; - -/* Set protocol stall on ep0, protocol stall will automatically be cleared - on new transaction */ -static void ep0stall(struct fsl_udc *udc) -{ - u32 tmp; - - /* must set tx and rx to stall at the same time */ - tmp = fsl_readl(&dr_regs->endptctrl[0]); - tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; - fsl_writel(tmp, &dr_regs->endptctrl[0]); - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = 0; -} - -/* Prime a status phase for ep0 */ -static int ep0_prime_status(struct fsl_udc *udc, int direction) -{ - struct fsl_req *req = udc->status_req; - struct fsl_ep *ep; - int status = 0; - - if (direction == EP_DIR_IN) - udc->ep0_dir = USB_DIR_IN; - else - udc->ep0_dir = USB_DIR_OUT; - - ep = &udc->eps[0]; - udc->ep0_state = WAIT_FOR_OUT_STATUS; - - req->ep = ep; - req->req.length = 0; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - if (fsl_req_to_dtd(req) == 0) - status = fsl_queue_td(ep, req); - else - return -ENOMEM; - - if (status) - ERR("Can't queue ep0 status request \n"); - list_add_tail(&req->queue, &ep->queue); - - return status; -} - -static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) -{ - struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - - if (!ep->name) - return 0; - - nuke(ep, -ESHUTDOWN); - - return 0; -} - -/* - * ch9 Set address - */ -static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length) -{ - /* Save the new address to device struct */ - udc->device_address = (u8) value; - /* Update usb state */ - udc->usb_state = USB_STATE_ADDRESS; - /* Status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); -} - -/* - * ch9 Get status - */ -static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, - u16 index, u16 length) -{ - u16 tmp = 0; /* Status, cpu endian */ - - struct fsl_req *req; - struct fsl_ep *ep; - int status = 0; - - ep = &udc->eps[0]; - - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Get device status */ - tmp = 1 << USB_DEVICE_SELF_POWERED; - tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* Get interface status */ - /* We don't have interface information in udc driver */ - tmp = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* Get endpoint status */ - struct fsl_ep *target_ep; - - target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); - - /* stall if endpoint doesn't exist */ - if (!target_ep->desc) - goto stall; - tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) - << USB_ENDPOINT_HALT; - } - - udc->ep0_dir = USB_DIR_IN; - /* Borrow the per device status_req */ - req = udc->status_req; - /* Fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(tmp); - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - /* prime the data phase */ - if ((fsl_req_to_dtd(req) == 0)) - status = fsl_queue_td(ep, req); - else /* no mem */ - goto stall; - - if (status) { - ERR("Can't respond to getstatus request \n"); - goto stall; - } - list_add_tail(&req->queue, &ep->queue); - udc->ep0_state = DATA_STATE_XMIT; - return; -stall: - ep0stall(udc); -} - -static void setup_received_irq(struct fsl_udc *udc, - struct usb_ctrlrequest *setup) -{ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - - udc_reset_ep_queue(udc, 0); - - switch (setup->bRequest) { - /* Request that need Data+Status phase from udc */ - case USB_REQ_GET_STATUS: - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength); - break; - - /* Requests that need Status phase from udc */ - case USB_REQ_SET_ADDRESS: - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD - | USB_RECIP_DEVICE)) - break; - ch9setaddress(udc, wValue, wIndex, wLength); - break; - - /* Handled by udc, no data, status by udc */ - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - { /* status transaction */ - int rc = -EOPNOTSUPP; - - if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_ENDPOINT) { - int pipe = get_pipe_by_windex(wIndex); - struct fsl_ep *ep; - - if (wValue != 0 || wLength != 0 || pipe > udc->max_ep) - break; - ep = get_ep_by_pipe(udc, pipe); - - spin_unlock(&udc->lock); - rc = fsl_ep_set_halt(&ep->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&udc->lock); - - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_DEVICE) { - /* Note: The driver has not include OTG support yet. - * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) - break; - else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) - udc->gadget.b_hnp_enable = 1; - else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) - udc->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) - udc->gadget.a_alt_hnp_support = 1; - rc = 0; - } - if (rc == 0) { - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); - } - break; - } - /* Requests handled by gadget */ - default: - if (wLength) { - /* Data phase from gadget, status phase from udc */ - udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - - } else { - /* No data phase, IN status from gadget */ - udc->ep0_dir = USB_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } - break; - } -} - -/* Process request for Data or Status phase of ep0 - * prime status phase if needed */ -static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0, - struct fsl_req *req) -{ - if (udc->usb_state == USB_STATE_ADDRESS) { - /* Set the new address */ - u32 new_address = (u32) udc->device_address; - fsl_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS, - &dr_regs->deviceaddr); - } - - done(ep0, req, 0); - - switch (udc->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (ep0_prime_status(udc, EP_DIR_OUT)) - ep0stall(udc); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); - break; - case WAIT_FOR_OUT_STATUS: - udc->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - ERR("Unexpect ep0 packets \n"); - break; - default: - ep0stall(udc); - break; - } -} - -/* Tripwire mechanism to ensure a setup packet payload is extracted without - * being corrupted by another incoming setup packet */ -static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr) -{ - u32 temp; - struct ep_queue_head *qh; - - qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT]; - - /* Clear bit in ENDPTSETUPSTAT */ - temp = fsl_readl(&dr_regs->endptsetupstat); - fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat); - - /* while a hazard exists when setup package arrives */ - do { - /* Set Setup Tripwire */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd); - - /* Copy the setup packet to local buffer */ - memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8); - } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW)); - - /* Clear Setup Tripwire */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd); -} - -/* process-ep_req(): free the completed Tds for this req */ -static int process_ep_req(struct fsl_udc *udc, int pipe, - struct fsl_req *curr_req) -{ - struct ep_td_struct *curr_td; - int td_complete, actual, remaining_length, j, tmp; - int status = 0; - int errors = 0; - struct ep_queue_head *curr_qh = &udc->ep_qh[pipe]; - int direction = pipe % 2; - - curr_td = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - for (j = 0; j < curr_req->dtd_count; j++) { - remaining_length = (le32_to_cpu(curr_td->size_ioc_sts) - & DTD_PACKET_SIZE) - >> DTD_LENGTH_BIT_POS; - actual -= remaining_length; - - if ((errors = le32_to_cpu(curr_td->size_ioc_sts) & - DTD_ERROR_MASK)) { - if (errors & DTD_STATUS_HALTED) { - ERR("dTD error %08x QH=%d\n", errors, pipe); - /* Clear the errors and Halt condition */ - tmp = le32_to_cpu(curr_qh->size_ioc_int_sts); - tmp &= ~errors; - curr_qh->size_ioc_int_sts = cpu_to_le32(tmp); - status = -EPIPE; - /* FIXME: continue with next queued TD? */ - - break; - } - if (errors & DTD_STATUS_DATA_BUFF_ERR) { - VDBG("Transfer overflow"); - status = -EPROTO; - break; - } else if (errors & DTD_STATUS_TRANSACTION_ERR) { - VDBG("ISO error"); - status = -EILSEQ; - break; - } else - ERR("Unknown error has occured (0x%x)!\r\n", - errors); - - } else if (le32_to_cpu(curr_td->size_ioc_sts) - & DTD_STATUS_ACTIVE) { - VDBG("Request not complete"); - status = REQ_UNCOMPLETE; - return status; - } else if (remaining_length) { - if (direction) { - VDBG("Transmit dTD remaining length not zero"); - status = -EPROTO; - break; - } else { - td_complete++; - break; - } - } else { - td_complete++; - VDBG("dTD transmitted successful "); - } - - if (j != curr_req->dtd_count - 1) - curr_td = (struct ep_td_struct *)curr_td->next_td_virt; - } - - if (status) - return status; - - curr_req->req.actual = actual; - - return 0; -} - -/* Process a DTD completion interrupt */ -static void dtd_complete_irq(struct fsl_udc *udc) -{ - u32 bit_pos; - int i, ep_num, direction, bit_mask, status; - struct fsl_ep *curr_ep; - struct fsl_req *curr_req, *temp_req; - - /* Clear the bits in the register */ - bit_pos = fsl_readl(&dr_regs->endptcomplete); - fsl_writel(bit_pos, &dr_regs->endptcomplete); - - if (!bit_pos) - return; - - for (i = 0; i < udc->max_ep * 2; i++) { - ep_num = i >> 1; - direction = i % 2; - - bit_mask = 1 << (ep_num + 16 * direction); - - if (!(bit_pos & bit_mask)) - continue; - - curr_ep = get_ep_by_pipe(udc, i); - - /* If the ep is configured */ - if (curr_ep->name == NULL) { - WARN("Invalid EP?"); - continue; - } - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue, - queue) { - status = process_ep_req(udc, i, curr_req); - - VDBG("status of process_ep_req= %d, ep = %d", - status, ep_num); - if (status == REQ_UNCOMPLETE) - break; - /* write back status to req */ - curr_req->req.status = status; - - if (ep_num == 0) { - ep0_req_complete(udc, curr_ep, curr_req); - break; - } else - done(curr_ep, curr_req, status); - } - } -} - -/* Process a port change interrupt */ -static void port_change_irq(struct fsl_udc *udc) -{ - u32 speed; - - if (udc->bus_reset) - udc->bus_reset = 0; - - /* Bus resetting is finished */ - if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { - /* Get the speed */ - speed = (fsl_readl(&dr_regs->portsc1) - & PORTSCX_PORT_SPEED_MASK); - switch (speed) { - case PORTSCX_PORT_SPEED_HIGH: - udc->gadget.speed = USB_SPEED_HIGH; - break; - case PORTSCX_PORT_SPEED_FULL: - udc->gadget.speed = USB_SPEED_FULL; - break; - case PORTSCX_PORT_SPEED_LOW: - udc->gadget.speed = USB_SPEED_LOW; - break; - default: - udc->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - } - - /* Update USB state */ - if (!udc->resume_state) - udc->usb_state = USB_STATE_DEFAULT; -} - -/* Process suspend interrupt */ -static void suspend_irq(struct fsl_udc *udc) -{ - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver, serial.c does not support this */ - if (udc->driver->suspend) - udc->driver->suspend(&udc->gadget); -} - -static void bus_resume(struct fsl_udc *udc) -{ - udc->usb_state = udc->resume_state; - udc->resume_state = 0; - - /* report resume to the driver, serial.c does not support this */ - if (udc->driver->resume) - udc->driver->resume(&udc->gadget); -} - -/* Clear up all ep queues */ -static int reset_queues(struct fsl_udc *udc) -{ - u8 pipe; - - for (pipe = 0; pipe < udc->max_pipes; pipe++) - udc_reset_ep_queue(udc, pipe); - - /* report disconnect; the driver is already quiesced */ - udc->driver->disconnect(&udc->gadget); - - return 0; -} - -/* Process reset interrupt */ -static void reset_irq(struct fsl_udc *udc) -{ - u32 temp; - unsigned long timeout; - - /* Clear the device address */ - temp = fsl_readl(&dr_regs->deviceaddr); - fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr); - - udc->device_address = 0; - - /* Clear usb state */ - udc->resume_state = 0; - udc->ep0_dir = 0; - udc->ep0_state = WAIT_FOR_SETUP; - udc->remote_wakeup = 0; /* default to 0 on reset */ - udc->gadget.b_hnp_enable = 0; - udc->gadget.a_hnp_support = 0; - udc->gadget.a_alt_hnp_support = 0; - - /* Clear all the setup token semaphores */ - temp = fsl_readl(&dr_regs->endptsetupstat); - fsl_writel(temp, &dr_regs->endptsetupstat); - - /* Clear all the endpoint complete status bits */ - temp = fsl_readl(&dr_regs->endptcomplete); - fsl_writel(temp, &dr_regs->endptcomplete); - - timeout = jiffies + 100; - while (fsl_readl(&dr_regs->endpointprime)) { - /* Wait until all endptprime bits cleared */ - if (time_after(jiffies, timeout)) { - ERR("Timeout for reset\n"); - break; - } - cpu_relax(); - } - - /* Write 1s to the flush register */ - fsl_writel(0xffffffff, &dr_regs->endptflush); - - if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { - VDBG("Bus reset"); - /* Bus is reseting */ - udc->bus_reset = 1; - /* Reset all the queues, include XD, dTD, EP queue - * head and TR Queue */ - reset_queues(udc); - udc->usb_state = USB_STATE_DEFAULT; - } else { - VDBG("Controller reset"); - /* initialize usb hw reg except for regs for EP, not - * touch usbintr reg */ - dr_controller_setup(udc); - - /* Reset all internal used Queues */ - reset_queues(udc); - - ep0_setup(udc); - - /* Enable DR IRQ reg, Set Run bit, change udc state */ - dr_controller_run(udc); - udc->usb_state = USB_STATE_ATTACHED; - } -} - -/* - * USB device controller interrupt handler - */ -static irqreturn_t fsl_udc_irq(int irq, void *_udc) -{ - struct fsl_udc *udc = _udc; - u32 irq_src; - irqreturn_t status = IRQ_NONE; - unsigned long flags; - - /* Disable ISR for OTG host mode */ - if (udc->stopped) - return IRQ_NONE; - spin_lock_irqsave(&udc->lock, flags); - irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); - /* Clear notification bits */ - fsl_writel(irq_src, &dr_regs->usbsts); - - /* VDBG("irq_src [0x%8x]", irq_src); */ - - /* Need to resume? */ - if (udc->usb_state == USB_STATE_SUSPENDED) - if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0) - bus_resume(udc); - - /* USB Interrupt */ - if (irq_src & USB_STS_INT) { - VDBG("Packet int"); - /* Setup package, we only support ep0 as control ep */ - if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) { - tripwire_handler(udc, 0, - (u8 *) (&udc->local_setup_buff)); - setup_received_irq(udc, &udc->local_setup_buff); - status = IRQ_HANDLED; - } - - /* completion of dtd */ - if (fsl_readl(&dr_regs->endptcomplete)) { - dtd_complete_irq(udc); - status = IRQ_HANDLED; - } - } - - /* SOF (for ISO transfer) */ - if (irq_src & USB_STS_SOF) { - status = IRQ_HANDLED; - } - - /* Port Change */ - if (irq_src & USB_STS_PORT_CHANGE) { - port_change_irq(udc); - status = IRQ_HANDLED; - } - - /* Reset Received */ - if (irq_src & USB_STS_RESET) { - reset_irq(udc); - status = IRQ_HANDLED; - } - - /* Sleep Enable (Suspend) */ - if (irq_src & USB_STS_SUSPEND) { - suspend_irq(udc); - status = IRQ_HANDLED; - } - - if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { - VDBG("Error IRQ %x ", irq_src); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return status; -} - -/*----------------------------------------------------------------* - * Hook to gadget drivers - * Called by initialization code of gadget drivers -*----------------------------------------------------------------*/ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - int retval = -ENODEV; - unsigned long flags = 0; - - if (!udc_controller) - return -ENODEV; - - if (!driver || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) - || !driver->bind || !driver->disconnect - || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; - - /* lock is needed but whether should use this lock or another */ - spin_lock_irqsave(&udc_controller->lock, flags); - - driver->driver.bus = 0; - /* hook up the driver */ - udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* bind udc driver to gadget driver */ - retval = driver->bind(&udc_controller->gadget); - if (retval) { - VDBG("bind to %s --> %d", driver->driver.name, retval); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - goto out; - } - - /* Enable DR IRQ reg and Set usbcmd reg Run bit */ - dr_controller_run(udc_controller); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - printk(KERN_INFO "%s: bind to driver %s \n", - udc_controller->gadget.name, driver->driver.name); - -out: - if (retval) - printk("retval %d \n", retval); - return retval; -} -EXPORT_SYMBOL(usb_gadget_register_driver); - -/* Disconnect from gadget driver */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct fsl_ep *loop_ep; - unsigned long flags; - - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver || !driver->unbind) - return -EINVAL; - -#ifdef CONFIG_USB_OTG - if (udc_controller->transceiver) - (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif - - /* stop DR, disable intr */ - dr_controller_stop(udc_controller); - - /* in fact, no needed */ - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - - /* stand operation */ - spin_lock_irqsave(&udc_controller->lock, flags); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc_controller->eps[0], -ESHUTDOWN); - list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, - ep.ep_list) - nuke(loop_ep, -ESHUTDOWN); - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - - printk("unregistered gadget driver '%s'\r\n", driver->driver.name); - return 0; -} -EXPORT_SYMBOL(usb_gadget_unregister_driver); - -/*------------------------------------------------------------------------- - PROC File System Support --------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -#include - -static const char proc_filename[] = "driver/fsl_usb2_udc"; - -static int fsl_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *_dev) -{ - char *buf = page; - char *next = buf; - unsigned size = count; - unsigned long flags; - int t, i; - u32 tmp_reg; - struct fsl_ep *ep = NULL; - struct fsl_req *req; - - struct fsl_udc *udc = udc_controller; - if (off != 0) - return 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* ------basic driver infomation ---- */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n\n", - driver_name, DRIVER_VERSION, - udc->driver ? udc->driver->driver.name : "(none)"); - size -= t; - next += t; - - /* ------ DR Registers ----- */ - tmp_reg = fsl_readl(&dr_regs->usbcmd); - t = scnprintf(next, size, - "USBCMD reg:\n" - "SetupTW: %d\n" - "Run/Stop: %s\n\n", - (tmp_reg & USB_CMD_SUTW) ? 1 : 0, - (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbsts); - t = scnprintf(next, size, - "USB Status Reg:\n" - "Dr Suspend: %d" "Reset Received: %d" "System Error: %s" - "USB Error Interrupt: %s\n\n", - (tmp_reg & USB_STS_SUSPEND) ? 1 : 0, - (tmp_reg & USB_STS_RESET) ? 1 : 0, - (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal", - (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbintr); - t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" - "Sleep Enable: %d" "SOF Received Enable: %d" - "Reset Enable: %d\n" - "System Error Enable: %d" - "Port Change Dectected Enable: %d\n" - "USB Error Intr Enable: %d" "USB Intr Enable: %d\n\n", - (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0, - (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0, - (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0, - (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0, - (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0, - (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0, - (tmp_reg & USB_INTR_INT_EN) ? 1 : 0); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->frindex); - t = scnprintf(next, size, - "USB Frame Index Reg:" "Frame Number is 0x%x\n\n", - (tmp_reg & USB_FRINDEX_MASKS)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->deviceaddr); - t = scnprintf(next, size, - "USB Device Address Reg:" "Device Addr is 0x%x\n\n", - (tmp_reg & USB_DEVICE_ADDRESS_MASK)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->endpointlistaddr); - t = scnprintf(next, size, - "USB Endpoint List Address Reg:" - "Device Addr is 0x%x\n\n", - (tmp_reg & USB_EP_LIST_ADDRESS_MASK)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->portsc1); - t = scnprintf(next, size, - "USB Port Status&Control Reg:\n" - "Port Transceiver Type : %s" "Port Speed: %s \n" - "PHY Low Power Suspend: %s" "Port Reset: %s" - "Port Suspend Mode: %s \n" "Over-current Change: %s" - "Port Enable/Disable Change: %s\n" - "Port Enabled/Disabled: %s" - "Current Connect Status: %s\n\n", ( { - char *s; - switch (tmp_reg & PORTSCX_PTS_FSLS) { - case PORTSCX_PTS_UTMI: - s = "UTMI"; break; - case PORTSCX_PTS_ULPI: - s = "ULPI "; break; - case PORTSCX_PTS_FSLS: - s = "FS/LS Serial"; break; - default: - s = "None"; break; - } - s;} ), ( { - char *s; - switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) { - case PORTSCX_PORT_SPEED_FULL: - s = "Full Speed"; break; - case PORTSCX_PORT_SPEED_LOW: - s = "Low Speed"; break; - case PORTSCX_PORT_SPEED_HIGH: - s = "High Speed"; break; - default: - s = "Undefined"; break; - } - s; - } ), - (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? - "Normal PHY mode" : "Low power mode", - (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : - "Not in Reset", - (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in", - (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" : - "No", - (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" : - "Not change", - (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" : - "Not correct", - (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ? - "Attached" : "Not-Att"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbmode); - t = scnprintf(next, size, - "USB Mode Reg:" "Controller Mode is : %s\n\n", ( { - char *s; - switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) { - case USB_MODE_CTRL_MODE_IDLE: - s = "Idle"; break; - case USB_MODE_CTRL_MODE_DEVICE: - s = "Device Controller"; break; - case USB_MODE_CTRL_MODE_HOST: - s = "Host Controller"; break; - default: - s = "None"; break; - } - s; - } )); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->endptsetupstat); - t = scnprintf(next, size, - "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n", - (tmp_reg & EP_SETUP_STATUS_MASK)); - size -= t; - next += t; - - for (i = 0; i < udc->max_ep / 2; i++) { - tmp_reg = fsl_readl(&dr_regs->endptctrl[i]); - t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n", - i, tmp_reg); - size -= t; - next += t; - } - tmp_reg = fsl_readl(&dr_regs->endpointprime); - t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg); - size -= t; - next += t; - - tmp_reg = usb_sys_regs->snoop1; - t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg); - size -= t; - next += t; - - tmp_reg = usb_sys_regs->control; - t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n", - tmp_reg); - size -= t; - next += t; - - /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ - ep = &udc->eps[0]; - t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n", - ep->ep.name, ep_maxpacket(ep), ep_index(ep)); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length 0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - /* other gadget->eplist ep */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - t = scnprintf(next, size, - "\nFor %s Maxpkt is 0x%x " - "index is 0x%x\n", - ep->ep.name, ep_maxpacket(ep), - ep_index(ep)); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, - "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length" - "0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } /* end for each_entry of ep req */ - } /* end for else */ - } /* end for if(ep->queue) */ - } /* end (ep->desc) */ - - spin_unlock_irqrestore(&udc->lock, flags); - - *eof = 1; - return count - size; -} - -#define create_proc_file() create_proc_read_entry(proc_filename, \ - 0, NULL, fsl_proc_read, NULL) - -#define remove_proc_file() remove_proc_entry(proc_filename, NULL) - -#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ - -#define create_proc_file() do {} while (0) -#define remove_proc_file() do {} while (0) - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/*-------------------------------------------------------------------------*/ - -/* Release udc structures */ -static void fsl_udc_release(struct device *dev) -{ - complete(udc_controller->done); - dma_free_coherent(dev, udc_controller->ep_qh_size, - udc_controller->ep_qh, udc_controller->ep_qh_dma); - kfree(udc_controller); -} - -/****************************************************************** - Internal structure setup functions -*******************************************************************/ -/*------------------------------------------------------------------ - * init resource for globle controller - * Return the udc handle on success or NULL on failure - ------------------------------------------------------------------*/ -static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev) -{ - struct fsl_udc *udc; - struct fsl_usb2_platform_data *pdata; - size_t size; - - udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc == NULL) { - ERR("malloc udc failed\n"); - return NULL; - } - - pdata = pdev->dev.platform_data; - udc->phy_mode = pdata->phy_mode; - /* max_ep_nr is bidirectional ep number, max_ep doubles the number */ - udc->max_ep = pdata->max_ep_nr * 2; - - udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); - if (!udc->eps) { - ERR("malloc fsl_ep failed\n"); - goto cleanup; - } - - /* initialized QHs, take care of alignment */ - size = udc->max_ep * sizeof(struct ep_queue_head); - if (size < QH_ALIGNMENT) - size = QH_ALIGNMENT; - else if ((size % QH_ALIGNMENT) != 0) { - size += QH_ALIGNMENT + 1; - size &= ~(QH_ALIGNMENT - 1); - } - udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, - &udc->ep_qh_dma, GFP_KERNEL); - if (!udc->ep_qh) { - ERR("malloc QHs for udc failed\n"); - kfree(udc->eps); - goto cleanup; - } - - udc->ep_qh_size = size; - - /* Initialize ep0 status request structure */ - /* FIXME: fsl_alloc_request() ignores ep argument */ - udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), - struct fsl_req, req); - /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); - udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf); - - udc->resume_state = USB_STATE_NOTATTACHED; - udc->usb_state = USB_STATE_POWERED; - udc->ep0_dir = 0; - udc->remote_wakeup = 0; /* default to 0 on reset */ - spin_lock_init(&udc->lock); - - return udc; - -cleanup: - kfree(udc); - return NULL; -} - -/*---------------------------------------------------------------- - * Setup the fsl_ep struct for eps - * Link fsl_ep->ep to gadget->ep_list - * ep0out is not used so do nothing here - * ep0in should be taken care - *--------------------------------------------------------------*/ -static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, - char *name, int link) -{ - struct fsl_ep *ep = &udc->eps[index]; - - ep->udc = udc; - strcpy(ep->name, name); - ep->ep.name = ep->name; - - ep->ep.ops = &fsl_ep_ops; - ep->stopped = 0; - - /* for ep0: maxP defined in desc - * for other eps, maxP is set by epautoconfig() called by gadget layer - */ - ep->ep.maxpacket = (unsigned short) ~0; - - /* the queue lists any req for this ep */ - INIT_LIST_HEAD(&ep->queue); - - /* gagdet.ep_list used for ep_autoconfig so no ep0 */ - if (link) - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->gadget = &udc->gadget; - ep->qh = &udc->ep_qh[index]; - - return 0; -} - -/* Driver probe function - * all intialize operations implemented here except enabling usb_intr reg - */ -static int __init fsl_udc_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret = -ENODEV; - unsigned int i; - - if (strcmp(pdev->name, driver_name)) { - VDBG("Wrong device\n"); - return -ENODEV; - } - - /* board setup should have been done in the platform code */ - - /* Initialize the udc structure including QH member and other member */ - udc_controller = struct_udc_setup(pdev); - if (!udc_controller) { - VDBG("udc_controller is NULL \n"); - return -ENOMEM; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!request_mem_region(res->start, res->end - res->start + 1, - driver_name)) { - ERR("request mem region for %s failed \n", pdev->name); - return -EBUSY; - } - - dr_regs = ioremap(res->start, res->end - res->start + 1); - if (!dr_regs) { - ret = -ENOMEM; - goto err1; - } - - usb_sys_regs = (struct usb_sys_interface *) - ((u32)dr_regs + USB_DR_SYS_OFFSET); - - udc_controller->irq = platform_get_irq(pdev, 0); - if (!udc_controller->irq) { - ret = -ENODEV; - goto err2; - } - - ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ, - driver_name, udc_controller); - if (ret != 0) { - ERR("cannot request irq %d err %d \n", - udc_controller->irq, ret); - goto err2; - } - - /* initialize usb hw reg except for regs for EP, - * leave usbintr reg untouched */ - dr_controller_setup(udc_controller); - - /* Setup gadget structure */ - udc_controller->gadget.ops = &fsl_gadget_ops; - udc_controller->gadget.is_dualspeed = 1; - udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; - INIT_LIST_HEAD(&udc_controller->gadget.ep_list); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - udc_controller->gadget.name = driver_name; - - /* Setup gadget.dev and register with kernel */ - strcpy(udc_controller->gadget.dev.bus_id, "gadget"); - udc_controller->gadget.dev.release = fsl_udc_release; - udc_controller->gadget.dev.parent = &pdev->dev; - ret = device_register(&udc_controller->gadget.dev); - if (ret < 0) - goto err3; - - /* setup QH and epctrl for ep0 */ - ep0_setup(udc_controller); - - /* setup udc->eps[] for ep0 */ - struct_ep_setup(udc_controller, 0, "ep0", 0); - /* for ep0: the desc defined here; - * for other eps, gadget layer called ep_enable with defined desc - */ - udc_controller->eps[0].desc = &fsl_ep0_desc; - udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; - - /* setup the udc->eps[] for non-control endpoints and link - * to gadget.ep_list */ - for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) { - char name[14]; - - sprintf(name, "ep%dout", i); - struct_ep_setup(udc_controller, i * 2, name, 1); - sprintf(name, "ep%din", i); - struct_ep_setup(udc_controller, i * 2 + 1, name, 1); - } - - /* use dma_pool for TD management */ - udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, - sizeof(struct ep_td_struct), - DTD_ALIGNMENT, UDC_DMA_BOUNDARY); - if (udc_controller->td_pool == NULL) { - ret = -ENOMEM; - goto err4; - } - create_proc_file(); - return 0; - -err4: - device_unregister(&udc_controller->gadget.dev); -err3: - free_irq(udc_controller->irq, udc_controller); -err2: - iounmap(dr_regs); -err1: - release_mem_region(res->start, res->end - res->start + 1); - return ret; -} - -/* Driver removal function - * Free resources and finish pending transactions - */ -static int __exit fsl_udc_remove(struct platform_device *pdev) -{ - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - DECLARE_COMPLETION(done); - - if (!udc_controller) - return -ENODEV; - udc_controller->done = &done; - - /* DR has been stopped in usb_gadget_unregister_driver() */ - remove_proc_file(); - - /* Free allocated memory */ - kfree(udc_controller->status_req->req.buf); - kfree(udc_controller->status_req); - kfree(udc_controller->eps); - - dma_pool_destroy(udc_controller->td_pool); - free_irq(udc_controller->irq, udc_controller); - iounmap(dr_regs); - release_mem_region(res->start, res->end - res->start + 1); - - device_unregister(&udc_controller->gadget.dev); - /* free udc --wait for the release() finished */ - wait_for_completion(&done); - - return 0; -} - -/*----------------------------------------------------------------- - * Modify Power management attributes - * Used by OTG statemachine to disable gadget temporarily - -----------------------------------------------------------------*/ -static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) -{ - dr_controller_stop(udc_controller); - return 0; -} - -/*----------------------------------------------------------------- - * Invoked on USB resume. May be called in_interrupt. - * Here we start the DR controller and enable the irq - *-----------------------------------------------------------------*/ -static int fsl_udc_resume(struct platform_device *pdev) -{ - /* Enable DR irq reg and set controller Run */ - if (udc_controller->stopped) { - dr_controller_setup(udc_controller); - dr_controller_run(udc_controller); - } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - return 0; -} - -/*------------------------------------------------------------------------- - Register entry point for the peripheral controller driver ---------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .remove = __exit_p(fsl_udc_remove), - /* these suspend and resume are not usb suspend and resume */ - .suspend = fsl_udc_suspend, - .resume = fsl_udc_resume, - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - }, -}; - -static int __init udc_init(void) -{ - printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, fsl_udc_probe); -} - -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); - printk("%s unregistered \n", driver_desc); -} - -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/gadget/fsl_usb2_udc.h b/trunk/drivers/usb/gadget/fsl_usb2_udc.h deleted file mode 100644 index c6291e046507..000000000000 --- a/trunk/drivers/usb/gadget/fsl_usb2_udc.h +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Freescale USB device/endpoint management registers - */ -#ifndef __FSL_USB2_UDC_H -#define __FSL_USB2_UDC_H - -/* ### define USB registers here - */ -#define USB_MAX_CTRL_PAYLOAD 64 -#define USB_DR_SYS_OFFSET 0x400 - - /* USB DR device mode registers (Little Endian) */ -struct usb_dr_device { - /* Capability register */ - u8 res1[256]; - u16 caplength; /* Capability Register Length */ - u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structual Parameters */ - u32 hccparams; /* Host Controller Capability Parameters */ - u8 res2[20]; - u32 dciversion; /* Device Controller Interface Version */ - u32 dccparams; /* Device Controller Capability Parameters */ - u8 res3[24]; - /* Operation register */ - u32 usbcmd; /* USB Command Register */ - u32 usbsts; /* USB Status Register */ - u32 usbintr; /* USB Interrupt Enable Register */ - u32 frindex; /* Frame Index Register */ - u8 res4[4]; - u32 deviceaddr; /* Device Address */ - u32 endpointlistaddr; /* Endpoint List Address Register */ - u8 res5[4]; - u32 burstsize; /* Master Interface Data Burst Size Register */ - u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ - u8 res6[24]; - u32 configflag; /* Configure Flag Register */ - u32 portsc1; /* Port 1 Status and Control Register */ - u8 res7[28]; - u32 otgsc; /* On-The-Go Status and Control */ - u32 usbmode; /* USB Mode Register */ - u32 endptsetupstat; /* Endpoint Setup Status Register */ - u32 endpointprime; /* Endpoint Initialization Register */ - u32 endptflush; /* Endpoint Flush Register */ - u32 endptstatus; /* Endpoint Status Register */ - u32 endptcomplete; /* Endpoint Complete Register */ - u32 endptctrl[6]; /* Endpoint Control Registers */ -}; - - /* USB DR host mode registers (Little Endian) */ -struct usb_dr_host { - /* Capability register */ - u8 res1[256]; - u16 caplength; /* Capability Register Length */ - u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structual Parameters */ - u32 hccparams; /* Host Controller Capability Parameters */ - u8 res2[20]; - u32 dciversion; /* Device Controller Interface Version */ - u32 dccparams; /* Device Controller Capability Parameters */ - u8 res3[24]; - /* Operation register */ - u32 usbcmd; /* USB Command Register */ - u32 usbsts; /* USB Status Register */ - u32 usbintr; /* USB Interrupt Enable Register */ - u32 frindex; /* Frame Index Register */ - u8 res4[4]; - u32 periodiclistbase; /* Periodic Frame List Base Address Register */ - u32 asynclistaddr; /* Current Asynchronous List Address Register */ - u8 res5[4]; - u32 burstsize; /* Master Interface Data Burst Size Register */ - u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ - u8 res6[24]; - u32 configflag; /* Configure Flag Register */ - u32 portsc1; /* Port 1 Status and Control Register */ - u8 res7[28]; - u32 otgsc; /* On-The-Go Status and Control */ - u32 usbmode; /* USB Mode Register */ - u32 endptsetupstat; /* Endpoint Setup Status Register */ - u32 endpointprime; /* Endpoint Initialization Register */ - u32 endptflush; /* Endpoint Flush Register */ - u32 endptstatus; /* Endpoint Status Register */ - u32 endptcomplete; /* Endpoint Complete Register */ - u32 endptctrl[6]; /* Endpoint Control Registers */ -}; - - /* non-EHCI USB system interface registers (Big Endian) */ -struct usb_sys_interface { - u32 snoop1; - u32 snoop2; - u32 age_cnt_thresh; /* Age Count Threshold Register */ - u32 pri_ctrl; /* Priority Control Register */ - u32 si_ctrl; /* System Interface Control Register */ - u8 res[236]; - u32 control; /* General Purpose Control Register */ -}; - -/* ep0 transfer state */ -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -/* Frame Index Register Bit Masks */ -#define USB_FRINDEX_MASKS 0x3fff -/* USB CMD Register Bit Masks */ -#define USB_CMD_RUN_STOP 0x00000001 -#define USB_CMD_CTRL_RESET 0x00000002 -#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010 -#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020 -#define USB_CMD_INT_AA_DOORBELL 0x00000040 -#define USB_CMD_ASP 0x00000300 -#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800 -#define USB_CMD_SUTW 0x00002000 -#define USB_CMD_ATDTW 0x00004000 -#define USB_CMD_ITC 0x00FF0000 - -/* bit 15,3,2 are frame list size */ -#define USB_CMD_FRAME_SIZE_1024 0x00000000 -#define USB_CMD_FRAME_SIZE_512 0x00000004 -#define USB_CMD_FRAME_SIZE_256 0x00000008 -#define USB_CMD_FRAME_SIZE_128 0x0000000C -#define USB_CMD_FRAME_SIZE_64 0x00008000 -#define USB_CMD_FRAME_SIZE_32 0x00008004 -#define USB_CMD_FRAME_SIZE_16 0x00008008 -#define USB_CMD_FRAME_SIZE_8 0x0000800C - -/* bit 9-8 are async schedule park mode count */ -#define USB_CMD_ASP_00 0x00000000 -#define USB_CMD_ASP_01 0x00000100 -#define USB_CMD_ASP_10 0x00000200 -#define USB_CMD_ASP_11 0x00000300 -#define USB_CMD_ASP_BIT_POS 8 - -/* bit 23-16 are interrupt threshold control */ -#define USB_CMD_ITC_NO_THRESHOLD 0x00000000 -#define USB_CMD_ITC_1_MICRO_FRM 0x00010000 -#define USB_CMD_ITC_2_MICRO_FRM 0x00020000 -#define USB_CMD_ITC_4_MICRO_FRM 0x00040000 -#define USB_CMD_ITC_8_MICRO_FRM 0x00080000 -#define USB_CMD_ITC_16_MICRO_FRM 0x00100000 -#define USB_CMD_ITC_32_MICRO_FRM 0x00200000 -#define USB_CMD_ITC_64_MICRO_FRM 0x00400000 -#define USB_CMD_ITC_BIT_POS 16 - -/* USB STS Register Bit Masks */ -#define USB_STS_INT 0x00000001 -#define USB_STS_ERR 0x00000002 -#define USB_STS_PORT_CHANGE 0x00000004 -#define USB_STS_FRM_LST_ROLL 0x00000008 -#define USB_STS_SYS_ERR 0x00000010 -#define USB_STS_IAA 0x00000020 -#define USB_STS_RESET 0x00000040 -#define USB_STS_SOF 0x00000080 -#define USB_STS_SUSPEND 0x00000100 -#define USB_STS_HC_HALTED 0x00001000 -#define USB_STS_RCL 0x00002000 -#define USB_STS_PERIODIC_SCHEDULE 0x00004000 -#define USB_STS_ASYNC_SCHEDULE 0x00008000 - -/* USB INTR Register Bit Masks */ -#define USB_INTR_INT_EN 0x00000001 -#define USB_INTR_ERR_INT_EN 0x00000002 -#define USB_INTR_PTC_DETECT_EN 0x00000004 -#define USB_INTR_FRM_LST_ROLL_EN 0x00000008 -#define USB_INTR_SYS_ERR_EN 0x00000010 -#define USB_INTR_ASYN_ADV_EN 0x00000020 -#define USB_INTR_RESET_EN 0x00000040 -#define USB_INTR_SOF_EN 0x00000080 -#define USB_INTR_DEVICE_SUSPEND 0x00000100 - -/* Device Address bit masks */ -#define USB_DEVICE_ADDRESS_MASK 0xFE000000 -#define USB_DEVICE_ADDRESS_BIT_POS 25 - -/* endpoint list address bit masks */ -#define USB_EP_LIST_ADDRESS_MASK 0xfffff800 - -/* PORTSCX Register Bit Masks */ -#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001 -#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002 -#define PORTSCX_PORT_ENABLE 0x00000004 -#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008 -#define PORTSCX_OVER_CURRENT_ACT 0x00000010 -#define PORTSCX_OVER_CURRENT_CHG 0x00000020 -#define PORTSCX_PORT_FORCE_RESUME 0x00000040 -#define PORTSCX_PORT_SUSPEND 0x00000080 -#define PORTSCX_PORT_RESET 0x00000100 -#define PORTSCX_LINE_STATUS_BITS 0x00000C00 -#define PORTSCX_PORT_POWER 0x00001000 -#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000 -#define PORTSCX_PORT_TEST_CTRL 0x000F0000 -#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000 -#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000 -#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000 -#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000 -#define PORTSCX_PORT_FORCE_FULL_SPEED 0x01000000 -#define PORTSCX_PORT_SPEED_MASK 0x0C000000 -#define PORTSCX_PORT_WIDTH 0x10000000 -#define PORTSCX_PHY_TYPE_SEL 0xC0000000 - -/* bit 11-10 are line status */ -#define PORTSCX_LINE_STATUS_SE0 0x00000000 -#define PORTSCX_LINE_STATUS_JSTATE 0x00000400 -#define PORTSCX_LINE_STATUS_KSTATE 0x00000800 -#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00 -#define PORTSCX_LINE_STATUS_BIT_POS 10 - -/* bit 15-14 are port indicator control */ -#define PORTSCX_PIC_OFF 0x00000000 -#define PORTSCX_PIC_AMBER 0x00004000 -#define PORTSCX_PIC_GREEN 0x00008000 -#define PORTSCX_PIC_UNDEF 0x0000C000 -#define PORTSCX_PIC_BIT_POS 14 - -/* bit 19-16 are port test control */ -#define PORTSCX_PTC_DISABLE 0x00000000 -#define PORTSCX_PTC_JSTATE 0x00010000 -#define PORTSCX_PTC_KSTATE 0x00020000 -#define PORTSCX_PTC_SEQNAK 0x00030000 -#define PORTSCX_PTC_PACKET 0x00040000 -#define PORTSCX_PTC_FORCE_EN 0x00050000 -#define PORTSCX_PTC_BIT_POS 16 - -/* bit 27-26 are port speed */ -#define PORTSCX_PORT_SPEED_FULL 0x00000000 -#define PORTSCX_PORT_SPEED_LOW 0x04000000 -#define PORTSCX_PORT_SPEED_HIGH 0x08000000 -#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000 -#define PORTSCX_SPEED_BIT_POS 26 - -/* bit 28 is parallel transceiver width for UTMI interface */ -#define PORTSCX_PTW 0x10000000 -#define PORTSCX_PTW_8BIT 0x00000000 -#define PORTSCX_PTW_16BIT 0x10000000 - -/* bit 31-30 are port transceiver select */ -#define PORTSCX_PTS_UTMI 0x00000000 -#define PORTSCX_PTS_ULPI 0x80000000 -#define PORTSCX_PTS_FSLS 0xC0000000 -#define PORTSCX_PTS_BIT_POS 30 - -/* otgsc Register Bit Masks */ -#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001 -#define OTGSC_CTRL_VUSB_CHARGE 0x00000002 -#define OTGSC_CTRL_OTG_TERM 0x00000008 -#define OTGSC_CTRL_DATA_PULSING 0x00000010 -#define OTGSC_STS_USB_ID 0x00000100 -#define OTGSC_STS_A_VBUS_VALID 0x00000200 -#define OTGSC_STS_A_SESSION_VALID 0x00000400 -#define OTGSC_STS_B_SESSION_VALID 0x00000800 -#define OTGSC_STS_B_SESSION_END 0x00001000 -#define OTGSC_STS_1MS_TOGGLE 0x00002000 -#define OTGSC_STS_DATA_PULSING 0x00004000 -#define OTGSC_INTSTS_USB_ID 0x00010000 -#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000 -#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000 -#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000 -#define OTGSC_INTSTS_B_SESSION_END 0x00100000 -#define OTGSC_INTSTS_1MS 0x00200000 -#define OTGSC_INTSTS_DATA_PULSING 0x00400000 -#define OTGSC_INTR_USB_ID 0x01000000 -#define OTGSC_INTR_A_VBUS_VALID 0x02000000 -#define OTGSC_INTR_A_SESSION_VALID 0x04000000 -#define OTGSC_INTR_B_SESSION_VALID 0x08000000 -#define OTGSC_INTR_B_SESSION_END 0x10000000 -#define OTGSC_INTR_1MS_TIMER 0x20000000 -#define OTGSC_INTR_DATA_PULSING 0x40000000 - -/* USB MODE Register Bit Masks */ -#define USB_MODE_CTRL_MODE_IDLE 0x00000000 -#define USB_MODE_CTRL_MODE_DEVICE 0x00000002 -#define USB_MODE_CTRL_MODE_HOST 0x00000003 -#define USB_MODE_CTRL_MODE_RSV 0x00000001 -#define USB_MODE_SETUP_LOCK_OFF 0x00000008 -#define USB_MODE_STREAM_DISABLE 0x00000010 -/* Endpoint Flush Register */ -#define EPFLUSH_TX_OFFSET 0x00010000 -#define EPFLUSH_RX_OFFSET 0x00000000 - -/* Endpoint Setup Status bit masks */ -#define EP_SETUP_STATUS_MASK 0x0000003F -#define EP_SETUP_STATUS_EP0 0x00000001 - -/* ENDPOINTCTRLx Register Bit Masks */ -#define EPCTRL_TX_ENABLE 0x00800000 -#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */ -#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */ -#define EPCTRL_TX_TYPE 0x000C0000 -#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */ -#define EPCTRL_TX_EP_STALL 0x00010000 -#define EPCTRL_RX_ENABLE 0x00000080 -#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */ -#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */ -#define EPCTRL_RX_TYPE 0x0000000C -#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */ -#define EPCTRL_RX_EP_STALL 0x00000001 - -/* bit 19-18 and 3-2 are endpoint type */ -#define EPCTRL_EP_TYPE_CONTROL 0 -#define EPCTRL_EP_TYPE_ISO 1 -#define EPCTRL_EP_TYPE_BULK 2 -#define EPCTRL_EP_TYPE_INTERRUPT 3 -#define EPCTRL_TX_EP_TYPE_SHIFT 18 -#define EPCTRL_RX_EP_TYPE_SHIFT 2 - -/* SNOOPn Register Bit Masks */ -#define SNOOP_ADDRESS_MASK 0xFFFFF000 -#define SNOOP_SIZE_ZERO 0x00 /* snooping disable */ -#define SNOOP_SIZE_4KB 0x0B /* 4KB snoop size */ -#define SNOOP_SIZE_8KB 0x0C -#define SNOOP_SIZE_16KB 0x0D -#define SNOOP_SIZE_32KB 0x0E -#define SNOOP_SIZE_64KB 0x0F -#define SNOOP_SIZE_128KB 0x10 -#define SNOOP_SIZE_256KB 0x11 -#define SNOOP_SIZE_512KB 0x12 -#define SNOOP_SIZE_1MB 0x13 -#define SNOOP_SIZE_2MB 0x14 -#define SNOOP_SIZE_4MB 0x15 -#define SNOOP_SIZE_8MB 0x16 -#define SNOOP_SIZE_16MB 0x17 -#define SNOOP_SIZE_32MB 0x18 -#define SNOOP_SIZE_64MB 0x19 -#define SNOOP_SIZE_128MB 0x1A -#define SNOOP_SIZE_256MB 0x1B -#define SNOOP_SIZE_512MB 0x1C -#define SNOOP_SIZE_1GB 0x1D -#define SNOOP_SIZE_2GB 0x1E /* 2GB snoop size */ - -/* pri_ctrl Register Bit Masks */ -#define PRI_CTRL_PRI_LVL1 0x0000000C -#define PRI_CTRL_PRI_LVL0 0x00000003 - -/* si_ctrl Register Bit Masks */ -#define SI_CTRL_ERR_DISABLE 0x00000010 -#define SI_CTRL_IDRC_DISABLE 0x00000008 -#define SI_CTRL_RD_SAFE_EN 0x00000004 -#define SI_CTRL_RD_PREFETCH_DISABLE 0x00000002 -#define SI_CTRL_RD_PREFEFETCH_VAL 0x00000001 - -/* control Register Bit Masks */ -#define USB_CTRL_IOENB 0x00000004 -#define USB_CTRL_ULPI_INT0EN 0x00000001 - -/* Endpoint Queue Head data struct - * Rem: all the variables of qh are LittleEndian Mode - * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr - */ -struct ep_queue_head { - u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len - and IOS(15) */ - u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */ - u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */ - u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15), - MultO(11-10), STS (7-0) */ - u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */ - u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */ - u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */ - u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */ - u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */ - u32 res1; - u8 setup_buffer[8]; /* Setup data 8 bytes */ - u32 res2[4]; -}; - -/* Endpoint Queue Head Bit Masks */ -#define EP_QUEUE_HEAD_MULT_POS 30 -#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000 -#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16 -#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) -#define EP_QUEUE_HEAD_IOS 0x00008000 -#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001 -#define EP_QUEUE_HEAD_IOC 0x00008000 -#define EP_QUEUE_HEAD_MULTO 0x00000C00 -#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040 -#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080 -#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF -#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0 -#define EP_QUEUE_FRINDEX_MASK 0x000007FF -#define EP_MAX_LENGTH_TRANSFER 0x4000 - -/* Endpoint Transfer Descriptor data struct */ -/* Rem: all the variables of td are LittleEndian Mode */ -struct ep_td_struct { - u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set - indicate invalid */ - u32 size_ioc_sts; /* Total bytes (30-16), IOC (15), - MultO(11-10), STS (7-0) */ - u32 buff_ptr0; /* Buffer pointer Page 0 */ - u32 buff_ptr1; /* Buffer pointer Page 1 */ - u32 buff_ptr2; /* Buffer pointer Page 2 */ - u32 buff_ptr3; /* Buffer pointer Page 3 */ - u32 buff_ptr4; /* Buffer pointer Page 4 */ - u32 res; - /* 32 bytes */ - dma_addr_t td_dma; /* dma address for this td */ - /* virtual address of next td specified in next_td_ptr */ - struct ep_td_struct *next_td_virt; -}; - -/* Endpoint Transfer Descriptor bit Masks */ -#define DTD_NEXT_TERMINATE 0x00000001 -#define DTD_IOC 0x00008000 -#define DTD_STATUS_ACTIVE 0x00000080 -#define DTD_STATUS_HALTED 0x00000040 -#define DTD_STATUS_DATA_BUFF_ERR 0x00000020 -#define DTD_STATUS_TRANSACTION_ERR 0x00000008 -#define DTD_RESERVED_FIELDS 0x80007300 -#define DTD_ADDR_MASK 0xFFFFFFE0 -#define DTD_PACKET_SIZE 0x7FFF0000 -#define DTD_LENGTH_BIT_POS 16 -#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \ - DTD_STATUS_DATA_BUFF_ERR | \ - DTD_STATUS_TRANSACTION_ERR) -/* Alignment requirements; must be a power of two */ -#define DTD_ALIGNMENT 0x20 -#define QH_ALIGNMENT 2048 - -/* Controller dma boundary */ -#define UDC_DMA_BOUNDARY 0x1000 - -/* -----------------------------------------------------------------------*/ -/* ##### enum data -*/ -typedef enum { - e_ULPI, - e_UTMI_8BIT, - e_UTMI_16BIT, - e_SERIAL -} e_PhyInterface; - -/*-------------------------------------------------------------------------*/ - -/* ### driver private data - */ -struct fsl_req { - struct usb_request req; - struct list_head queue; - /* ep_queue() func will add - a request->queue into a udc_ep->queue 'd tail */ - struct fsl_ep *ep; - unsigned mapped:1; - - struct ep_td_struct *head, *tail; /* For dTD List - cpu endian Virtual addr */ - unsigned int dtd_count; -}; - -#define REQ_UNCOMPLETE 1 - -struct fsl_ep { - struct usb_ep ep; - struct list_head queue; - struct fsl_udc *udc; - struct ep_queue_head *qh; - const struct usb_endpoint_descriptor *desc; - struct usb_gadget *gadget; - - char name[14]; - unsigned stopped:1; -}; - -#define EP_DIR_IN 1 -#define EP_DIR_OUT 0 - -struct fsl_udc { - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct fsl_ep *eps; - unsigned int max_ep; - unsigned int irq; - - struct usb_ctrlrequest local_setup_buff; - spinlock_t lock; - struct otg_transceiver *transceiver; - unsigned softconnect:1; - unsigned vbus_active:1; - unsigned stopped:1; - unsigned remote_wakeup:1; - - struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ - struct fsl_req *status_req; /* ep0 status request */ - struct dma_pool *td_pool; /* dma pool for DTD */ - enum fsl_usb2_phy_modes phy_mode; - - size_t ep_qh_size; /* size after alignment adjustment*/ - dma_addr_t ep_qh_dma; /* dma address of QH */ - - u32 max_pipes; /* Device max pipes */ - u32 max_use_endpts; /* Max endpointes to be used */ - u32 bus_reset; /* Device is bus reseting */ - u32 resume_state; /* USB state to resume */ - u32 usb_state; /* USB current state */ - u32 usb_next_state; /* USB next state */ - u32 ep0_state; /* Endpoint zero state */ - u32 ep0_dir; /* Endpoint zero direction: can be - USB_DIR_IN or USB_DIR_OUT */ - u32 usb_sof_count; /* SOF count */ - u32 errors; /* USB ERRORs count */ - u8 device_address; /* Device USB address */ - - struct completion *done; /* to make sure release() is done */ -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \ - __FUNCTION__, ## args) -#else -#define DBG(fmt, args...) do{}while(0) -#endif - -#if 0 -static void dump_msg(const char *label, const u8 * buf, unsigned int length) -{ - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG("%s, length %u:\n", label, length); - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; - } -} -#endif - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) - -/*-------------------------------------------------------------------------*/ - -/* ### Add board specific defines here - */ - -/* - * ### pipe direction macro from device view - */ -#define USB_RECV 0 /* OUT EP */ -#define USB_SEND 1 /* IN EP */ - -/* - * ### internal used help routines. - */ -#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF) -#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ - USB_DIR_IN ):((EP)->desc->bEndpointAddress \ - & USB_DIR_IN)==USB_DIR_IN) -#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \ - &udc->eps[pipe]) -#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \ - * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) -#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) - -#endif diff --git a/trunk/drivers/usb/gadget/gadget_chips.h b/trunk/drivers/usb/gadget/gadget_chips.h index d041b919e7b8..2e3d6620d216 100644 --- a/trunk/drivers/usb/gadget/gadget_chips.h +++ b/trunk/drivers/usb/gadget/gadget_chips.h @@ -99,12 +99,6 @@ #define gadget_is_imx(g) 0 #endif -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name) -#else -#define gadget_is_fsl_usb2(g) 0 -#endif - /* Mentor high speed function controller */ #ifdef CONFIG_USB_GADGET_MUSBHSFC #define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name) @@ -183,7 +177,5 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x17; else if (gadget_is_husb2dev(gadget)) return 0x18; - else if (gadget_is_fsl_usb2(gadget)) - return 0x19; return -ENOENT; } diff --git a/trunk/drivers/usb/gadget/pxa2xx_udc.c b/trunk/drivers/usb/gadget/pxa2xx_udc.c index 2c043a1ea156..f01890dc8751 100644 --- a/trunk/drivers/usb/gadget/pxa2xx_udc.c +++ b/trunk/drivers/usb/gadget/pxa2xx_udc.c @@ -71,7 +71,7 @@ * by the host to interact with this device, and allocates endpoints to * the different protocol interfaces. The controller driver virtualizes * usb hardware so that the gadget drivers will be more portable. - * + * * This UDC hardware wants to implement a bit too much USB protocol, so * it constrains the sorts of USB configuration change events that work. * The errata for these chips are misleading; some "fixed" bugs from @@ -141,7 +141,7 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode"); #endif /* --------------------------------------------------------------------------- - * endpoint related parts of the api to the usb controller hardware, + * endpoint related parts of the api to the usb controller hardware, * used by gadget driver; and the inner talker-to-hardware core. * --------------------------------------------------------------------------- */ @@ -293,7 +293,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, #ifdef USE_DMA /* for (some) bulk and ISO endpoints, try to get a DMA channel and - * bind it to the endpoint. otherwise use PIO. + * bind it to the endpoint. otherwise use PIO. */ switch (ep->bmAttributes) { case USB_ENDPOINT_XFER_ISOC: @@ -304,7 +304,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, if (!use_dma || !ep->reg_drcmr) break; ep->dma = pxa_request_dma ((char *)_ep->name, - (le16_to_cpu (desc->wMaxPacketSize) > 64) + (le16_to_cpu (desc->wMaxPacketSize) > 64) ? DMA_PRIO_MEDIUM /* some iso */ : DMA_PRIO_LOW, dma_nodesc_handler, ep); @@ -361,7 +361,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) */ /* - * pxa2xx_ep_alloc_request - allocate a request data structure + * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) @@ -378,7 +378,7 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) /* - * pxa2xx_ep_free_request - deallocate a request data structure + * pxa2xx_ep_free_request - deallocate a request data structure */ static void pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) @@ -1031,7 +1031,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* - * nuke - dequeue ALL requests + * nuke - dequeue ALL requests */ static void nuke(struct pxa2xx_ep *ep, int status) { @@ -1136,16 +1136,16 @@ static int pxa2xx_ep_set_halt(struct usb_ep *_ep, int value) ep->dev->req_pending = 0; ep->dev->ep0state = EP0_STALL; - /* and bulk/intr endpoints like dropping stalls too */ - } else { - unsigned i; - for (i = 0; i < 1000; i += 20) { - if (*ep->reg_udccs & UDCCS_BI_SST) - break; - udelay(20); - } - } - local_irq_restore(flags); + /* and bulk/intr endpoints like dropping stalls too */ + } else { + unsigned i; + for (i = 0; i < 1000; i += 20) { + if (*ep->reg_udccs & UDCCS_BI_SST) + break; + udelay(20); + } + } + local_irq_restore(flags); DBG(DBG_VERBOSE, "%s halt\n", _ep->name); return 0; @@ -1216,7 +1216,7 @@ static struct usb_ep_ops pxa2xx_ep_ops = { /* --------------------------------------------------------------------------- - * device-scoped parts of the api to the usb controller hardware + * device-scoped parts of the api to the usb controller hardware * --------------------------------------------------------------------------- */ @@ -1239,7 +1239,7 @@ static void udc_enable (struct pxa2xx_udc *); static void udc_disable(struct pxa2xx_udc *); /* We disable the UDC -- and its 48 MHz clock -- whenever it's not - * in active use. + * in active use. */ static int pullup(struct pxa2xx_udc *udc, int is_active) { @@ -1464,10 +1464,24 @@ udc_proc_read(char *page, char **start, off_t off, int count, #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ +/* "function" sysfs attribute */ +static ssize_t +show_function (struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct pxa2xx_udc *dev = dev_get_drvdata (_dev); + + if (!dev->driver + || !dev->driver->function + || strlen (dev->driver->function) > PAGE_SIZE) + return 0; + return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function); +} +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); + /*-------------------------------------------------------------------------*/ /* - * udc_disable - disable USB device controller + * udc_disable - disable USB device controller */ static void udc_disable(struct pxa2xx_udc *dev) { @@ -1493,7 +1507,7 @@ static void udc_disable(struct pxa2xx_udc *dev) /* - * udc_reinit - initialize software state + * udc_reinit - initialize software state */ static void udc_reinit(struct pxa2xx_udc *dev) { @@ -1621,20 +1635,18 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev->gadget.dev.driver = &driver->driver; dev->pullup = 1; - retval = device_add (&dev->gadget.dev); - if (retval) { -fail: - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } + device_add (&dev->gadget.dev); retval = driver->bind(&dev->gadget); if (retval) { DMSG("bind to driver %s --> error %d\n", driver->driver.name, retval); device_del (&dev->gadget.dev); - goto fail; + + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + return retval; } + device_create_file(dev->dev, &dev_attr_function); /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -1692,6 +1704,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dev->driver = NULL; device_del (&dev->gadget.dev); + device_remove_file(dev->dev, &dev_attr_function); DMSG("unregistered gadget driver '%s'\n", driver->driver.name); dump_state(dev); @@ -2461,12 +2474,12 @@ static struct pxa2xx_udc memory = { #define IXP465_AD 0x00000200 /* - * probe - binds to the platform device + * probe - binds to the platform device */ static int __init pxa2xx_udc_probe(struct platform_device *pdev) { struct pxa2xx_udc *dev = &memory; - int retval, out_dma = 1, vbus_irq, irq; + int retval, out_dma = 1, vbus_irq; u32 chiprev; /* insist on Intel/ARM/XScale */ @@ -2509,11 +2522,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; - - pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq, + pr_debug("%s: IRQ %d%s%s%s\n", driver_name, IRQ_USB, dev->has_cfr ? "" : " (!cfr)", out_dma ? "" : " (broken dma-out)", SIZE_STR DMASTR @@ -2561,11 +2570,11 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) dev->vbus = is_vbus_present(); /* irq setup after old hardware state is cleaned up */ - retval = request_irq(irq, pxa2xx_udc_irq, + retval = request_irq(IRQ_USB, pxa2xx_udc_irq, IRQF_DISABLED, driver_name, dev); if (retval != 0) { - printk(KERN_ERR "%s: can't get irq %d, err %d\n", - driver_name, irq, retval); + printk(KERN_ERR "%s: can't get irq %i, err %d\n", + driver_name, IRQ_USB, retval); return -EBUSY; } dev->got_irq = 1; @@ -2580,7 +2589,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_DISC_IRQ, retval); lubbock_fail0: - free_irq(irq, dev); + free_irq(IRQ_USB, dev); return -EBUSY; } retval = request_irq(LUBBOCK_USB_IRQ, @@ -2607,7 +2616,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, vbus_irq, retval); - free_irq(irq, dev); + free_irq(IRQ_USB, dev); return -EBUSY; } } @@ -2632,7 +2641,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) remove_proc_files(); if (dev->got_irq) { - free_irq(platform_get_irq(pdev, 0), dev); + free_irq(IRQ_USB, dev); dev->got_irq = 0; } #ifdef CONFIG_ARCH_LUBBOCK @@ -2659,7 +2668,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) * * For now, we punt and forcibly disconnect from the USB host when PXA * enters any suspend state. While we're disconnected, we always disable - * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. + * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. * Boards without software pullup control shouldn't use those states. * VBUS IRQs should probably be ignored so that the PXA device just acts * "dead" to USB hosts until system resume. @@ -2692,6 +2701,7 @@ static int pxa2xx_udc_resume(struct platform_device *dev) /*-------------------------------------------------------------------------*/ static struct platform_driver udc_driver = { + .probe = pxa2xx_udc_probe, .shutdown = pxa2xx_udc_shutdown, .remove = __exit_p(pxa2xx_udc_remove), .suspend = pxa2xx_udc_suspend, @@ -2705,7 +2715,7 @@ static struct platform_driver udc_driver = { static int __init udc_init(void) { printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, pxa2xx_udc_probe); + return platform_driver_register(&udc_driver); } module_init(udc_init); diff --git a/trunk/drivers/usb/gadget/rndis.h b/trunk/drivers/usb/gadget/rndis.h index 397b149f3ca7..4c3c7259f019 100644 --- a/trunk/drivers/usb/gadget/rndis.h +++ b/trunk/drivers/usb/gadget/rndis.h @@ -195,7 +195,7 @@ struct rndis_packet_msg_type __le32 PerPacketInfoLength; __le32 VcHandle; __le32 Reserved; -} __attribute__ ((packed)); +}; struct rndis_config_parameter { diff --git a/trunk/drivers/usb/host/Makefile b/trunk/drivers/usb/host/Makefile index 2ff396bd180f..a2e58c86849f 100644 --- a/trunk/drivers/usb/host/Makefile +++ b/trunk/drivers/usb/host/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o +obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o diff --git a/trunk/drivers/usb/host/ehci-fsl.h b/trunk/drivers/usb/host/ehci-fsl.h index f28736a917e4..caac0d1967d0 100644 --- a/trunk/drivers/usb/host/ehci-fsl.h +++ b/trunk/drivers/usb/host/ehci-fsl.h @@ -31,7 +31,7 @@ #define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */ #define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */ #define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */ -#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */ -#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */ +#define FSL_SOC_USB_SICTRL 0x40c /* NOTE: big-endian */ +#define FSL_SOC_USB_PRICTRL 0x410 /* NOTE: big-endian */ #define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */ #endif /* _EHCI_FSL_H */ diff --git a/trunk/drivers/usb/host/ehci-hub.c b/trunk/drivers/usb/host/ehci-hub.c index f4d301bc83b9..1813b7cac294 100644 --- a/trunk/drivers/usb/host/ehci-hub.c +++ b/trunk/drivers/usb/host/ehci-hub.c @@ -136,10 +136,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /* restore CMD_RUN, framelist size, and irq threshold */ ehci_writel(ehci, ehci->command, &ehci->regs->command); - /* Some controller/firmware combinations need a delay during which - * they set up the port statuses. See Bugzilla #8190. */ - mdelay(8); - /* manually resume the ports we suspended during bus_suspend() */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { diff --git a/trunk/drivers/usb/host/hc_crisv10.c b/trunk/drivers/usb/host/hc_crisv10.c new file mode 100644 index 000000000000..32f7caf24747 --- /dev/null +++ b/trunk/drivers/usb/host/hc_crisv10.c @@ -0,0 +1,4550 @@ +/* + * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) + * + * Copyright (c) 2002, 2003 Axis Communications AB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +/* Ugly include because we don't live with the other host drivers. */ +#include <../drivers/usb/core/hcd.h> +#include <../drivers/usb/core/usb.h> + +#include "hc_crisv10.h" + +#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR +#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR +#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR + +static const char *usb_hcd_version = "$Revision: 1.2 $"; + +#undef KERN_DEBUG +#define KERN_DEBUG "" + + +#undef USB_DEBUG_RH +#undef USB_DEBUG_EPID +#undef USB_DEBUG_SB +#undef USB_DEBUG_DESC +#undef USB_DEBUG_URB +#undef USB_DEBUG_TRACE +#undef USB_DEBUG_BULK +#undef USB_DEBUG_CTRL +#undef USB_DEBUG_INTR +#undef USB_DEBUG_ISOC + +#ifdef USB_DEBUG_RH +#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg) +#else +#define dbg_rh(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_EPID +#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg) +#else +#define dbg_epid(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_SB +#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg) +#else +#define dbg_sb(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_CTRL +#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg) +#else +#define dbg_ctrl(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_BULK +#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg) +#else +#define dbg_bulk(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_INTR +#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg) +#else +#define dbg_intr(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_ISOC +#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg) +#else +#define dbg_isoc(format, arg...) do {} while (0) +#endif + +#ifdef USB_DEBUG_TRACE +#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__)) +#define DBFEXIT (printk(": Exiting: %s\n", __FUNCTION__)) +#else +#define DBFENTER do {} while (0) +#define DBFEXIT do {} while (0) +#endif + +#define usb_pipeslow(pipe) (((pipe) >> 26) & 1) + +/*------------------------------------------------------------------- + Virtual Root Hub + -------------------------------------------------------------------*/ + +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __le16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __le16 idVendor; */ + 0x00, + 0x00, /* __le16 idProduct; */ + 0x00, + 0x00, /* __le16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __le16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __le16 ep_wMaxPacketSize; 8 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static __u8 root_hub_hub_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x02, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +static DEFINE_TIMER(bulk_start_timer, NULL, 0, 0); +static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0); + +/* We want the start timer to expire before the eot timer, because the former might start + traffic, thus making it unnecessary for the latter to time out. */ +#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */ +#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */ + +#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break +#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ +{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} + +#define SLAB_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) +#define KMALLOC_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) + +/* Most helpful debugging aid */ +#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) + +/* Alternative assert define which stops after a failed assert. */ +/* +#define assert(expr) \ +{ \ + if (!(expr)) { \ + err("assert failed at line %d",__LINE__); \ + while (1); \ + } \ +} +*/ + + +/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically? + To adjust it dynamically we would have to get an interrupt when we reach the end + of the rx descriptor list, or when we get close to the end, and then allocate more + descriptors. */ + +#define NBR_OF_RX_DESC 512 +#define RX_DESC_BUF_SIZE 1024 +#define RX_BUF_SIZE (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE) + +/* The number of epids is, among other things, used for pre-allocating + ctrl, bulk and isoc EP descriptors (one for each epid). + Assumed to be > 1 when initiating the DMA lists. */ +#define NBR_OF_EPIDS 32 + +/* Support interrupt traffic intervals up to 128 ms. */ +#define MAX_INTR_INTERVAL 128 + +/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table + must be "invalid". By this we mean that we shouldn't care about epid attentions + for this epid, or at least handle them differently from epid attentions for "valid" + epids. This define determines which one to use (don't change it). */ +#define INVALID_EPID 31 +/* A special epid for the bulk dummys. */ +#define DUMMY_EPID 30 + +/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */ +static __u32 epid_usage_bitmask; + +/* A bitfield to keep information on in/out traffic is needed to uniquely identify + an endpoint on a device, since the most significant bit which indicates traffic + direction is lacking in the ep_id field (ETRAX epids can handle both in and + out traffic on endpoints that are otherwise identical). The USB framework, however, + relies on them to be handled separately. For example, bulk IN and OUT urbs cannot + be queued in the same list, since they would block each other. */ +static __u32 epid_out_traffic; + +/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line. + Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */ +static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32))); +static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); + +/* Pointers into RxDescList. */ +static volatile USB_IN_Desc_t *myNextRxDesc; +static volatile USB_IN_Desc_t *myLastRxDesc; +static volatile USB_IN_Desc_t *myPrevRxDesc; + +/* EP descriptors must be 32-bit aligned. */ +static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4))); +static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4))); +/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set, + causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which + gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the + EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors + in each frame. */ +static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4))); + +static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4))); +static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4))); + +static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4))); +static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); + +/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting + this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0 + results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point + it to this buffer. */ +static int zout_buffer[4] __attribute__ ((aligned (4))); + +/* Cache for allocating new EP and SB descriptors. */ +static struct kmem_cache *usb_desc_cache; + +/* Cache for the registers allocated in the top half. */ +static struct kmem_cache *top_half_reg_cache; + +/* Cache for the data allocated in the isoc descr top half. */ +static struct kmem_cache *isoc_compl_cache; + +static struct usb_bus *etrax_usb_bus; + +/* This is a circular (double-linked) list of the active urbs for each epid. + The head is never removed, and new urbs are linked onto the list as + urb_entry_t elements. Don't reference urb_list directly; use the wrapper + functions instead. Note that working with these lists might require spinlock + protection. */ +static struct list_head urb_list[NBR_OF_EPIDS]; + +/* Read about the need and usage of this lock in submit_ctrl_urb. */ +static spinlock_t urb_list_lock; + +/* Used when unlinking asynchronously. */ +static struct list_head urb_unlink_list; + +/* for returning string descriptors in UTF-16LE */ +static int ascii2utf (char *ascii, __u8 *utf, int utfmax) +{ + int retval; + + for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { + *utf++ = *ascii++ & 0x7f; + *utf++ = 0; + } + return retval; +} + +static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) +{ + char buf [30]; + + // assert (len > (2 * (sizeof (buf) + 1))); + // assert (strlen (type) <= 8); + + // language ids + if (id == 0) { + *data++ = 4; *data++ = 3; /* 4 bytes data */ + *data++ = 0; *data++ = 0; /* some language id */ + return 4; + + // serial number + } else if (id == 1) { + sprintf (buf, "%x", serial); + + // product description + } else if (id == 2) { + sprintf (buf, "USB %s Root Hub", type); + + // id 3 == vendor description + + // unsupported IDs --> "stall" + } else + return 0; + + data [0] = 2 + ascii2utf (buf, data + 2, len - 2); + data [1] = 3; + return data [0]; +} + +/* Wrappers around the list functions (include/linux/list.h). */ + +static inline int urb_list_empty(int epid) +{ + return list_empty(&urb_list[epid]); +} + +/* Returns first urb for this epid, or NULL if list is empty. */ +static inline struct urb *urb_list_first(int epid) +{ + struct urb *first_urb = 0; + + if (!urb_list_empty(epid)) { + /* Get the first urb (i.e. head->next). */ + urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list); + first_urb = urb_entry->urb; + } + return first_urb; +} + +/* Adds an urb_entry last in the list for this epid. */ +static inline void urb_list_add(struct urb *urb, int epid) +{ + urb_entry_t *urb_entry = kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG); + assert(urb_entry); + + urb_entry->urb = urb; + list_add_tail(&urb_entry->list, &urb_list[epid]); +} + +/* Search through the list for an element that contains this urb. (The list + is expected to be short and the one we are about to delete will often be + the first in the list.) */ +static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid) +{ + struct list_head *entry; + struct list_head *tmp; + urb_entry_t *urb_entry; + + list_for_each_safe(entry, tmp, &urb_list[epid]) { + urb_entry = list_entry(entry, urb_entry_t, list); + assert(urb_entry); + assert(urb_entry->urb); + + if (urb_entry->urb == urb) { + return urb_entry; + } + } + return 0; +} + +/* Delete an urb from the list. */ +static inline void urb_list_del(struct urb *urb, int epid) +{ + urb_entry_t *urb_entry = __urb_list_entry(urb, epid); + assert(urb_entry); + + /* Delete entry and free. */ + list_del(&urb_entry->list); + kfree(urb_entry); +} + +/* Move an urb to the end of the list. */ +static inline void urb_list_move_last(struct urb *urb, int epid) +{ + urb_entry_t *urb_entry = __urb_list_entry(urb, epid); + assert(urb_entry); + + list_move_tail(&urb_entry->list, &urb_list[epid]); +} + +/* Get the next urb in the list. */ +static inline struct urb *urb_list_next(struct urb *urb, int epid) +{ + urb_entry_t *urb_entry = __urb_list_entry(urb, epid); + + assert(urb_entry); + + if (urb_entry->list.next != &urb_list[epid]) { + struct list_head *elem = urb_entry->list.next; + urb_entry = list_entry(elem, urb_entry_t, list); + return urb_entry->urb; + } else { + return NULL; + } +} + + + +/* For debug purposes only. */ +static inline void urb_list_dump(int epid) +{ + struct list_head *entry; + struct list_head *tmp; + urb_entry_t *urb_entry; + int i = 0; + + info("Dumping urb list for epid %d", epid); + + list_for_each_safe(entry, tmp, &urb_list[epid]) { + urb_entry = list_entry(entry, urb_entry_t, list); + info(" entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb); + } +} + +static void init_rx_buffers(void); +static int etrax_rh_unlink_urb(struct urb *urb); +static void etrax_rh_send_irq(struct urb *urb); +static void etrax_rh_init_int_timer(struct urb *urb); +static void etrax_rh_int_timer_do(unsigned long ptr); + +static int etrax_usb_setup_epid(struct urb *urb); +static int etrax_usb_lookup_epid(struct urb *urb); +static int etrax_usb_allocate_epid(void); +static void etrax_usb_free_epid(int epid); + +static int etrax_remove_from_sb_list(struct urb *urb); + +static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma); +static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); + +static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid); +static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid); +static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid); +static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid); + +static int etrax_usb_submit_bulk_urb(struct urb *urb); +static int etrax_usb_submit_ctrl_urb(struct urb *urb); +static int etrax_usb_submit_intr_urb(struct urb *urb); +static int etrax_usb_submit_isoc_urb(struct urb *urb); + +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags); +static int etrax_usb_unlink_urb(struct urb *urb, int status); +static int etrax_usb_get_frame_number(struct usb_device *usb_dev); + +static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc); +static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc); +static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc); +static void etrax_usb_hc_interrupt_bottom_half(void *data); + +static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data); + + +/* The following is a list of interrupt handlers for the host controller interrupts we use. + They are called from etrax_usb_hc_interrupt_bottom_half. */ +static void etrax_usb_hc_isoc_eof_interrupt(void); +static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced); +static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg); +static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg); +static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg); + +static int etrax_rh_submit_urb (struct urb *urb); + +/* Forward declaration needed because they are used in the rx interrupt routine. */ +static void etrax_usb_complete_urb(struct urb *urb, int status); +static void etrax_usb_complete_bulk_urb(struct urb *urb, int status); +static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status); +static void etrax_usb_complete_intr_urb(struct urb *urb, int status); +static void etrax_usb_complete_isoc_urb(struct urb *urb, int status); + +static int etrax_usb_hc_init(void); +static void etrax_usb_hc_cleanup(void); + +static struct usb_operations etrax_usb_device_operations = +{ + .get_frame_number = etrax_usb_get_frame_number, + .submit_urb = etrax_usb_submit_urb, + .unlink_urb = etrax_usb_unlink_urb, + .buffer_alloc = etrax_usb_buffer_alloc, + .buffer_free = etrax_usb_buffer_free +}; + +/* Note that these functions are always available in their "__" variants, for use in + error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/ + USB_DEBUG_URB macros. */ +static void __dump_urb(struct urb* purb) +{ + printk("\nurb :0x%08lx\n", (unsigned long)purb); + printk("dev :0x%08lx\n", (unsigned long)purb->dev); + printk("pipe :0x%08x\n", purb->pipe); + printk("status :%d\n", purb->status); + printk("transfer_flags :0x%08x\n", purb->transfer_flags); + printk("transfer_buffer :0x%08lx\n", (unsigned long)purb->transfer_buffer); + printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length); + printk("actual_length :%d\n", purb->actual_length); + printk("setup_packet :0x%08lx\n", (unsigned long)purb->setup_packet); + printk("start_frame :%d\n", purb->start_frame); + printk("number_of_packets :%d\n", purb->number_of_packets); + printk("interval :%d\n", purb->interval); + printk("error_count :%d\n", purb->error_count); + printk("context :0x%08lx\n", (unsigned long)purb->context); + printk("complete :0x%08lx\n\n", (unsigned long)purb->complete); +} + +static void __dump_in_desc(volatile USB_IN_Desc_t *in) +{ + printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in); + printk(" sw_len : 0x%04x (%d)\n", in->sw_len, in->sw_len); + printk(" command : 0x%04x\n", in->command); + printk(" next : 0x%08lx\n", in->next); + printk(" buf : 0x%08lx\n", in->buf); + printk(" hw_len : 0x%04x (%d)\n", in->hw_len, in->hw_len); + printk(" status : 0x%04x\n\n", in->status); +} + +static void __dump_sb_desc(volatile USB_SB_Desc_t *sb) +{ + char tt = (sb->command & 0x30) >> 4; + char *tt_string; + + switch (tt) { + case 0: + tt_string = "zout"; + break; + case 1: + tt_string = "in"; + break; + case 2: + tt_string = "out"; + break; + case 3: + tt_string = "setup"; + break; + default: + tt_string = "unknown (weird)"; + } + + printk("\n USB_SB_Desc at 0x%08lx\n", (unsigned long)sb); + printk(" command : 0x%04x\n", sb->command); + printk(" rem : %d\n", (sb->command & 0x3f00) >> 8); + printk(" full : %d\n", (sb->command & 0x40) >> 6); + printk(" tt : %d (%s)\n", tt, tt_string); + printk(" intr : %d\n", (sb->command & 0x8) >> 3); + printk(" eot : %d\n", (sb->command & 0x2) >> 1); + printk(" eol : %d\n", sb->command & 0x1); + printk(" sw_len : 0x%04x (%d)\n", sb->sw_len, sb->sw_len); + printk(" next : 0x%08lx\n", sb->next); + printk(" buf : 0x%08lx\n\n", sb->buf); +} + + +static void __dump_ep_desc(volatile USB_EP_Desc_t *ep) +{ + printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep); + printk(" command : 0x%04x\n", ep->command); + printk(" ep_id : %d\n", (ep->command & 0x1f00) >> 8); + printk(" enable : %d\n", (ep->command & 0x10) >> 4); + printk(" intr : %d\n", (ep->command & 0x8) >> 3); + printk(" eof : %d\n", (ep->command & 0x2) >> 1); + printk(" eol : %d\n", ep->command & 0x1); + printk(" hw_len : 0x%04x (%d)\n", ep->hw_len, ep->hw_len); + printk(" next : 0x%08lx\n", ep->next); + printk(" sub : 0x%08lx\n\n", ep->sub); +} + +static inline void __dump_ep_list(int pipe_type) +{ + volatile USB_EP_Desc_t *ep; + volatile USB_EP_Desc_t *first_ep; + volatile USB_SB_Desc_t *sb; + + switch (pipe_type) + { + case PIPE_BULK: + first_ep = &TxBulkEPList[0]; + break; + case PIPE_CONTROL: + first_ep = &TxCtrlEPList[0]; + break; + case PIPE_INTERRUPT: + first_ep = &TxIntrEPList[0]; + break; + case PIPE_ISOCHRONOUS: + first_ep = &TxIsocEPList[0]; + break; + default: + warn("Cannot dump unknown traffic type"); + return; + } + ep = first_ep; + + printk("\n\nDumping EP list...\n\n"); + + do { + __dump_ep_desc(ep); + /* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */ + sb = ep->sub ? phys_to_virt(ep->sub) : 0; + while (sb) { + __dump_sb_desc(sb); + sb = sb->next ? phys_to_virt(sb->next) : 0; + } + ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next)); + + } while (ep != first_ep); +} + +static inline void __dump_ept_data(int epid) +{ + unsigned long flags; + __u32 r_usb_ept_data; + + if (epid < 0 || epid > 31) { + printk("Cannot dump ept data for invalid epid %d\n", epid); + return; + } + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid); + if (r_usb_ept_data == 0) { + /* No need for more detailed printing. */ + return; + } + printk(" valid : %d\n", (r_usb_ept_data & 0x80000000) >> 31); + printk(" hold : %d\n", (r_usb_ept_data & 0x40000000) >> 30); + printk(" error_count_in : %d\n", (r_usb_ept_data & 0x30000000) >> 28); + printk(" t_in : %d\n", (r_usb_ept_data & 0x08000000) >> 27); + printk(" low_speed : %d\n", (r_usb_ept_data & 0x04000000) >> 26); + printk(" port : %d\n", (r_usb_ept_data & 0x03000000) >> 24); + printk(" error_code : %d\n", (r_usb_ept_data & 0x00c00000) >> 22); + printk(" t_out : %d\n", (r_usb_ept_data & 0x00200000) >> 21); + printk(" error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19); + printk(" max_len : %d\n", (r_usb_ept_data & 0x0003f800) >> 11); + printk(" ep : %d\n", (r_usb_ept_data & 0x00000780) >> 7); + printk(" dev : %d\n", (r_usb_ept_data & 0x0000003f)); +} + +static inline void __dump_ept_data_list(void) +{ + int i; + + printk("Dumping the whole R_USB_EPT_DATA list\n"); + + for (i = 0; i < 32; i++) { + __dump_ept_data(i); + } +} +#ifdef USB_DEBUG_DESC +#define dump_in_desc(...) __dump_in_desc(...) +#define dump_sb_desc(...) __dump_sb_desc(...) +#define dump_ep_desc(...) __dump_ep_desc(...) +#else +#define dump_in_desc(...) do {} while (0) +#define dump_sb_desc(...) do {} while (0) +#define dump_ep_desc(...) do {} while (0) +#endif + +#ifdef USB_DEBUG_URB +#define dump_urb(x) __dump_urb(x) +#else +#define dump_urb(x) do {} while (0) +#endif + +static void init_rx_buffers(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = 0; + RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + + /* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc + for the relevant fields.) */ + prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]); + + } + + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); + RxDescList[i].next = virt_to_phys(&RxDescList[0]); + RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); + RxDescList[i].hw_len = 0; + RxDescList[i].status = 0; + + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + + *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); + *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); + + DBFEXIT; +} + +static void init_tx_bulk_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { + CHECK_ALIGN(&TxBulkEPList[i]); + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]); + + /* Initiate two EPs, disabled and with the eol flag set. No need for any + preserved epid. */ + + /* The first one has the intr flag set so we get an interrupt when the DMA + channel is about to become disabled. */ + CHECK_ALIGN(&TxBulkDummyEPList[i][0]); + TxBulkDummyEPList[i][0].hw_len = 0; + TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) | + IO_STATE(USB_EP_command, eol, yes) | + IO_STATE(USB_EP_command, intr, yes)); + TxBulkDummyEPList[i][0].sub = 0; + TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]); + + /* The second one. */ + CHECK_ALIGN(&TxBulkDummyEPList[i][1]); + TxBulkDummyEPList[i][1].hw_len = 0; + TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) | + IO_STATE(USB_EP_command, eol, yes)); + TxBulkDummyEPList[i][1].sub = 0; + /* The last dummy's next pointer is the same as the current EP's next pointer. */ + TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]); + } + + /* Configure the last one. */ + CHECK_ALIGN(&TxBulkEPList[i]); + TxBulkEPList[i].hw_len = 0; + TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i)); + TxBulkEPList[i].sub = 0; + TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]); + + /* No need configuring dummy EPs for the last one as it will never be used for + bulk traffic (i == INVALD_EPID at this point). */ + + /* Set up to start on the last EP so we will enable it when inserting traffic + for the first time (imitating the situation where the DMA has stopped + because there was no more traffic). */ + *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]); + /* No point in starting the bulk channel yet. + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */ + DBFEXIT; +} + +static void init_tx_ctrl_ep(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { + CHECK_ALIGN(&TxCtrlEPList[i]); + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]); + } + + CHECK_ALIGN(&TxCtrlEPList[i]); + TxCtrlEPList[i].hw_len = 0; + TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, i)); + + TxCtrlEPList[i].sub = 0; + TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]); + + *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + DBFEXIT; +} + + +static void init_tx_intr_ep(void) +{ + int i; + + DBFENTER; + + /* Read comment at zout_buffer declaration for an explanation to this. */ + TxIntrSB_zout.sw_len = 1; + TxIntrSB_zout.next = 0; + TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]); + TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { + CHECK_ALIGN(&TxIntrEPList[i]); + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = + (IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, INVALID_EPID)); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]); + } + + CHECK_ALIGN(&TxIntrEPList[i]); + TxIntrEPList[i].hw_len = 0; + TxIntrEPList[i].command = + (IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, eol, yes) | + IO_STATE(USB_EP_command, enable, yes) | + IO_FIELD(USB_EP_command, epid, INVALID_EPID)); + TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); + TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]); + + *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + DBFEXIT; +} + +static void init_tx_isoc_ep(void) +{ + int i; + + DBFENTER; + + /* Read comment at zout_buffer declaration for an explanation to this. */ + TxIsocSB_zout.sw_len = 1; + TxIsocSB_zout.next = 0; + TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]); + TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + /* The last isochronous EP descriptor is a dummy. */ + + for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { + CHECK_ALIGN(&TxIsocEPList[i]); + TxIsocEPList[i].hw_len = 0; + TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i); + TxIsocEPList[i].sub = 0; + TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]); + } + + CHECK_ALIGN(&TxIsocEPList[i]); + TxIsocEPList[i].hw_len = 0; + + /* Must enable the last EP descr to get eof interrupt. */ + TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) | + IO_STATE(USB_EP_command, eof, yes) | + IO_STATE(USB_EP_command, eol, yes) | + IO_FIELD(USB_EP_command, epid, INVALID_EPID)); + TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout); + TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]); + + *R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]); + *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start); + + DBFEXIT; +} + +static void etrax_usb_unlink_intr_urb(struct urb *urb) +{ + volatile USB_EP_Desc_t *first_ep; /* First EP in the list. */ + volatile USB_EP_Desc_t *curr_ep; /* Current EP, the iterator. */ + volatile USB_EP_Desc_t *next_ep; /* The EP after current. */ + volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */ + + int epid; + + /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */ + + DBFENTER; + + epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid; + + first_ep = &TxIntrEPList[0]; + curr_ep = first_ep; + + + /* Note that this loop removes all EP descriptors with this epid. This assumes + that all EP descriptors belong to the one and only urb for this epid. */ + + do { + next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next); + + if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) { + + dbg_intr("Found EP to unlink for epid %d", epid); + + /* This is the one we should unlink. */ + unlink_ep = next_ep; + + /* Actually unlink the EP from the DMA list. */ + curr_ep->next = unlink_ep->next; + + /* Wait until the DMA is no longer at this descriptor. */ + while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep)); + + /* Now we are free to remove it and its SB descriptor. + Note that it is assumed here that there is only one sb in the + sb list for this ep. */ + kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub)); + kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep); + } + + curr_ep = phys_to_virt(curr_ep->next); + + } while (curr_ep != first_ep); + urb->hcpriv = NULL; +} + +void etrax_usb_do_intr_recover(int epid) +{ + USB_EP_Desc_t *first_ep, *tmp_ep; + + DBFENTER; + + first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); + tmp_ep = first_ep; + + /* What this does is simply to walk the list of interrupt + ep descriptors and enable those that are disabled. */ + + do { + if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && + !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { + tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); + } + + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next); + + } while (tmp_ep != first_ep); + + + DBFEXIT; +} + +static int etrax_rh_unlink_urb (struct urb *urb) +{ + etrax_hc_t *hc; + + DBFENTER; + + hc = urb->dev->bus->hcpriv; + + if (hc->rh.urb == urb) { + hc->rh.send = 0; + del_timer(&hc->rh.rh_int_timer); + } + + DBFEXIT; + return 0; +} + +static void etrax_rh_send_irq(struct urb *urb) +{ + __u16 data = 0; + etrax_hc_t *hc = urb->dev->bus->hcpriv; + DBFENTER; + +/* + dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); + dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING); +*/ + + data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; + data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; + + *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); + /* FIXME: Why is actual_length set to 1 when data is 2 bytes? + Since only 1 byte is used, why not declare data as __u8? */ + urb->actual_length = 1; + urb->status = 0; + + if (hc->rh.send && urb->complete) { + dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); + dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); + + urb->complete(urb, NULL); + } + + DBFEXIT; +} + +static void etrax_rh_init_int_timer(struct urb *urb) +{ + etrax_hc_t *hc; + + DBFENTER; + + hc = urb->dev->bus->hcpriv; + hc->rh.interval = urb->interval; + init_timer(&hc->rh.rh_int_timer); + hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; + hc->rh.rh_int_timer.data = (unsigned long)urb; + /* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped + to 0, and the rest to the nearest lower 10 ms. */ + hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); + add_timer(&hc->rh.rh_int_timer); + + DBFEXIT; +} + +static void etrax_rh_int_timer_do(unsigned long ptr) +{ + struct urb *urb; + etrax_hc_t *hc; + + DBFENTER; + + urb = (struct urb*)ptr; + hc = urb->dev->bus->hcpriv; + + if (hc->rh.send) { + etrax_rh_send_irq(urb); + } + + DBFEXIT; +} + +static int etrax_usb_setup_epid(struct urb *urb) +{ + int epid; + char devnum, endpoint, out_traffic, slow; + int maxlen; + unsigned long flags; + + DBFENTER; + + epid = etrax_usb_lookup_epid(urb); + if ((epid != -1)){ + /* An epid that fits this urb has been found. */ + DBFEXIT; + return epid; + } + + /* We must find and initiate a new epid for this urb. */ + epid = etrax_usb_allocate_epid(); + + if (epid == -1) { + /* Failed to allocate a new epid. */ + DBFEXIT; + return epid; + } + + /* We now have a new epid to use. Initiate it. */ + set_bit(epid, (void *)&epid_usage_bitmask); + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + /* We want both IN and OUT control traffic to be put on the same EP/SB list. */ + out_traffic = 1; + } else { + out_traffic = usb_pipeout(urb->pipe); + } + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + *R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) | + /* FIXME: Change any to the actual port? */ + IO_STATE(R_USB_EPT_DATA_ISO, port, any) | + IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) | + IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) | + IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum); + } else { + *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | + IO_FIELD(R_USB_EPT_DATA, low_speed, slow) | + /* FIXME: Change any to the actual port? */ + IO_STATE(R_USB_EPT_DATA, port, any) | + IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) | + IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | + IO_FIELD(R_USB_EPT_DATA, dev, devnum); + } + + restore_flags(flags); + + if (out_traffic) { + set_bit(epid, (void *)&epid_out_traffic); + } else { + clear_bit(epid, (void *)&epid_out_traffic); + } + + dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)", + epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN"); + + DBFEXIT; + return epid; +} + +static void etrax_usb_free_epid(int epid) +{ + unsigned long flags; + + DBFENTER; + + if (!test_bit(epid, (void *)&epid_usage_bitmask)) { + warn("Trying to free unused epid %d", epid); + DBFEXIT; + return; + } + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)); + /* This will, among other things, set the valid field to 0. */ + *R_USB_EPT_DATA = 0; + restore_flags(flags); + + clear_bit(epid, (void *)&epid_usage_bitmask); + + + dbg_epid("Freed epid %d", epid); + + DBFEXIT; +} + +static int etrax_usb_lookup_epid(struct urb *urb) +{ + int i; + __u32 data; + char devnum, endpoint, slow, out_traffic; + int maxlen; + unsigned long flags; + + DBFENTER; + + devnum = usb_pipedevice(urb->pipe); + endpoint = usb_pipeendpoint(urb->pipe); + slow = usb_pipeslow(urb->pipe); + maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + /* We want both IN and OUT control traffic to be put on the same EP/SB list. */ + out_traffic = 1; + } else { + out_traffic = usb_pipeout(urb->pipe); + } + + /* Step through att epids. */ + for (i = 0; i < NBR_OF_EPIDS; i++) { + if (test_bit(i, (void *)&epid_usage_bitmask) && + test_bit(i, (void *)&epid_out_traffic) == out_traffic) { + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); + nop(); + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + data = *R_USB_EPT_DATA_ISO; + restore_flags(flags); + + if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) && + (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) && + (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) && + (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) { + dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)", + i, devnum, endpoint, out_traffic ? "OUT" : "IN"); + DBFEXIT; + return i; + } + } else { + data = *R_USB_EPT_DATA; + restore_flags(flags); + + if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && + (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && + (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && + (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && + (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) { + dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)", + i, devnum, endpoint, out_traffic ? "OUT" : "IN"); + DBFEXIT; + return i; + } + } + } + } + + DBFEXIT; + return -1; +} + +static int etrax_usb_allocate_epid(void) +{ + int i; + + DBFENTER; + + for (i = 0; i < NBR_OF_EPIDS; i++) { + if (!test_bit(i, (void *)&epid_usage_bitmask)) { + dbg_epid("Found free epid %d", i); + DBFEXIT; + return i; + } + } + + dbg_epid("Found no free epids"); + DBFEXIT; + return -1; +} + +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags) +{ + etrax_hc_t *hc; + int ret = -EINVAL; + + DBFENTER; + + if (!urb->dev || !urb->dev->bus) { + return -ENODEV; + } + if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) { + info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe); + return -EMSGSIZE; + } + + if (urb->timeout) { + /* FIXME. */ + warn("urb->timeout specified, ignoring."); + } + + hc = (etrax_hc_t*)urb->dev->bus->hcpriv; + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + /* This request is for the Virtual Root Hub. */ + ret = etrax_rh_submit_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + + ret = etrax_usb_submit_bulk_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + + ret = etrax_usb_submit_ctrl_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + int bustime; + + if (urb->bandwidth == 0) { + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + ret = bustime; + } else { + ret = etrax_usb_submit_intr_urb(urb); + if (ret == 0) + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + } + } else { + /* Bandwidth already set. */ + ret = etrax_usb_submit_intr_urb(urb); + } + + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int bustime; + + if (urb->bandwidth == 0) { + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + ret = bustime; + } else { + ret = etrax_usb_submit_isoc_urb(urb); + if (ret == 0) + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + } + } else { + /* Bandwidth already set. */ + ret = etrax_usb_submit_isoc_urb(urb); + } + } + + DBFEXIT; + + if (ret != 0) + printk("Submit URB error %d\n", ret); + + return ret; +} + +static int etrax_usb_unlink_urb(struct urb *urb, int status) +{ + etrax_hc_t *hc; + etrax_urb_priv_t *urb_priv; + int epid; + unsigned int flags; + + DBFENTER; + + if (!urb) { + return -EINVAL; + } + + /* Disable interrupts here since a descriptor interrupt for the isoc epid + will modify the sb list. This could possibly be done more granular, but + unlink_urb should not be used frequently anyway. + */ + + save_flags(flags); + cli(); + + if (!urb->dev || !urb->dev->bus) { + restore_flags(flags); + return -ENODEV; + } + if (!urb->hcpriv) { + /* This happens if a device driver calls unlink on an urb that + was never submitted (lazy driver) or if the urb was completed + while unlink was being called. */ + restore_flags(flags); + return 0; + } + if (urb->transfer_flags & URB_ASYNC_UNLINK) { + /* FIXME. */ + /* If URB_ASYNC_UNLINK is set: + unlink + move to a separate urb list + call complete at next sof with ECONNRESET + + If not: + wait 1 ms + unlink + call complete with ENOENT + */ + warn("URB_ASYNC_UNLINK set, ignoring."); + } + + /* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking, + but that doesn't work for interrupt and isochronous traffic since they are completed + repeatedly, and urb->status is set then. That may in itself be a bug though. */ + + hc = urb->dev->bus->hcpriv; + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + epid = urb_priv->epid; + + /* Set the urb status (synchronous unlink). */ + urb->status = -ENOENT; + urb_priv->urb_state = UNLINK; + + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { + int ret; + ret = etrax_rh_unlink_urb(urb); + DBFEXIT; + restore_flags(flags); + return ret; + + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + + dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb); + + if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait. */ + TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + + /* Ah, the luxury of busy-wait. */ + while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); + } + /* Kicking dummy list out of the party. */ + TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]); + + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + + dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb); + + if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait. */ + TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + + /* Ah, the luxury of busy-wait. */ + while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); + } + + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + + dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb); + + /* Separate function because it's a tad more complicated. */ + etrax_usb_unlink_intr_urb(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + + dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb); + + if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait. */ + TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + + /* Ah, the luxury of busy-wait. */ + while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])); + } + } + + /* Note that we need to remove the urb from the urb list *before* removing its SB + descriptors. (This means that the isoc eof handler might get a null urb when we + are unlinking the last urb.) */ + + if (usb_pipetype(urb->pipe) == PIPE_BULK) { + + urb_list_del(urb, epid); + TxBulkEPList[epid].sub = 0; + etrax_remove_from_sb_list(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + + urb_list_del(urb, epid); + TxCtrlEPList[epid].sub = 0; + etrax_remove_from_sb_list(urb); + + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + + urb_list_del(urb, epid); + /* Sanity check (should never happen). */ + assert(urb_list_empty(epid)); + + /* Release allocated bandwidth. */ + usb_release_bandwidth(urb->dev, urb, 0); + + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + + if (usb_pipeout(urb->pipe)) { + + USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb; + + if (__urb_list_entry(urb, epid)) { + + urb_list_del(urb, epid); + iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0; + prev_sb = 0; + while (iter_sb && (iter_sb != urb_priv->first_sb)) { + prev_sb = iter_sb; + iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0; + } + + if (iter_sb == 0) { + /* Unlink of the URB currently being transmitted. */ + prev_sb = 0; + iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0; + } + + while (iter_sb && (iter_sb != urb_priv->last_sb)) { + iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0; + } + if (iter_sb) { + next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0; + } else { + /* This should only happen if the DMA has completed + processing the SB list for this EP while interrupts + are disabled. */ + dbg_isoc("Isoc urb not found, already sent?"); + next_sb = 0; + } + if (prev_sb) { + prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0; + } else { + TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0; + } + + etrax_remove_from_sb_list(urb); + if (urb_list_empty(epid)) { + TxIsocEPList[epid].sub = 0; + dbg_isoc("Last isoc out urb epid %d", epid); + } else if (next_sb || prev_sb) { + dbg_isoc("Re-enable isoc out epid %d", epid); + + TxIsocEPList[epid].hw_len = 0; + TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + } else { + TxIsocEPList[epid].sub = 0; + dbg_isoc("URB list non-empty and no SB list, EP disabled"); + } + } else { + dbg_isoc("Urb 0x%p not found, completed already?", urb); + } + } else { + + urb_list_del(urb, epid); + + /* For in traffic there is only one SB descriptor for each EP even + though there may be several urbs (all urbs point at the same SB). */ + if (urb_list_empty(epid)) { + /* No more urbs, remove the SB. */ + TxIsocEPList[epid].sub = 0; + etrax_remove_from_sb_list(urb); + } else { + TxIsocEPList[epid].hw_len = 0; + TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + } + } + /* Release allocated bandwidth. */ + usb_release_bandwidth(urb->dev, urb, 1); + } + /* Free the epid if urb list is empty. */ + if (urb_list_empty(epid)) { + etrax_usb_free_epid(epid); + } + restore_flags(flags); + + /* Must be done before calling completion handler. */ + kfree(urb_priv); + urb->hcpriv = 0; + + if (urb->complete) { + urb->complete(urb, NULL); + } + + DBFEXIT; + return 0; +} + +static int etrax_usb_get_frame_number(struct usb_device *usb_dev) +{ + DBFENTER; + DBFEXIT; + return (*R_USB_FM_NUMBER & 0x7ff); +} + +static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc) +{ + DBFENTER; + + /* This interrupt handler could be used when unlinking EP descriptors. */ + + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { + USB_EP_Desc_t *ep; + + //dbg_bulk("dma8_sub0_descr (BULK) intr."); + + /* It should be safe clearing the interrupt here, since we don't expect to get a new + one until we restart the bulk channel. */ + *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); + + /* Wait while the DMA is running (though we don't expect it to be). */ + while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd)); + + /* Advance the DMA to the next EP descriptor. */ + ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP); + + //dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep); + + /* ep->next is already a physical address; no need for a virt_to_phys. */ + *R_DMA_CH8_SUB0_EP = ep->next; + + /* Start the DMA bulk channel again. */ + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { + struct urb *urb; + int epid; + etrax_urb_priv_t *urb_priv; + unsigned long int flags; + + dbg_ctrl("dma8_sub1_descr (CTRL) intr."); + *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); + + /* The complete callback gets called so we cli. */ + save_flags(flags); + cli(); + + for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) { + if ((TxCtrlEPList[epid].sub == 0) || + (epid == DUMMY_EPID) || + (epid == INVALID_EPID)) { + /* Nothing here to see. */ + continue; + } + + /* Get the first urb (if any). */ + urb = urb_list_first(epid); + + if (urb) { + + /* Sanity check. */ + assert(usb_pipetype(urb->pipe) == PIPE_CONTROL); + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) { + assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable))); + + etrax_usb_complete_urb(urb, 0); + } + } + } + restore_flags(flags); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { + dbg_intr("dma8_sub2_descr (INTR) intr."); + *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); + } + if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { + struct urb *urb; + int epid; + int epid_done; + etrax_urb_priv_t *urb_priv; + USB_SB_Desc_t *sb_desc; + + usb_isoc_complete_data_t *comp_data = NULL; + + /* One or more isoc out transfers are done. */ + dbg_isoc("dma8_sub3_descr (ISOC) intr."); + + /* For each isoc out EP search for the first sb_desc with the intr flag + set. This descriptor must be the last packet from an URB. Then + traverse the URB list for the EP until the URB with urb_priv->last_sb + matching the intr-marked sb_desc is found. All URBs before this have + been sent. + */ + + for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) { + /* Skip past epids with no SB lists, epids used for in traffic, + and special (dummy, invalid) epids. */ + if ((TxIsocEPList[epid].sub == 0) || + (test_bit(epid, (void *)&epid_out_traffic) == 0) || + (epid == DUMMY_EPID) || + (epid == INVALID_EPID)) { + /* Nothing here to see. */ + continue; + } + sb_desc = phys_to_virt(TxIsocEPList[epid].sub); + + /* Find the last descriptor of the currently active URB for this ep. + This is the first descriptor in the sub list marked for a descriptor + interrupt. */ + while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) { + sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0; + } + assert(sb_desc); + + dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p", + epid, + phys_to_virt(TxIsocEPList[epid].sub), + sb_desc); + + epid_done = 0; + + /* Get the first urb (if any). */ + urb = urb_list_first(epid); + assert(urb); + + while (urb && !epid_done) { + + /* Sanity check. */ + assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS); + + if (!usb_pipeout(urb->pipe)) { + /* descr interrupts are generated only for out pipes. */ + epid_done = 1; + continue; + } + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + if (sb_desc != urb_priv->last_sb) { + + /* This urb has been sent. */ + dbg_isoc("out URB 0x%p sent", urb); + + urb_priv->urb_state = TRANSFER_DONE; + + } else if ((sb_desc == urb_priv->last_sb) && + !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + + assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes)); + assert(sb_desc->next == 0); + + dbg_isoc("out URB 0x%p last in list, epid disabled", urb); + TxIsocEPList[epid].sub = 0; + TxIsocEPList[epid].hw_len = 0; + urb_priv->urb_state = TRANSFER_DONE; + + epid_done = 1; + + } else { + epid_done = 1; + } + if (!epid_done) { + urb = urb_list_next(urb, epid); + } + } + + } + + *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); + + comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC); + assert(comp_data != NULL); + + INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data); + schedule_work(&comp_data->usb_bh); + } + + DBFEXIT; + return IRQ_HANDLED; +} + +static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data) +{ + usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data; + + struct urb *urb; + int epid; + int epid_done; + etrax_urb_priv_t *urb_priv; + + DBFENTER; + + dbg_isoc("dma8_sub3_descr (ISOC) bottom half."); + + for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) { + unsigned long flags; + + save_flags(flags); + cli(); + + epid_done = 0; + + /* The descriptor interrupt handler has marked all transmitted isoch. out + URBs with TRANSFER_DONE. Now we traverse all epids and for all that + have isoch. out traffic traverse its URB list and complete the + transmitted URB. + */ + + while (!epid_done) { + + /* Get the first urb (if any). */ + urb = urb_list_first(epid); + if (urb == 0) { + epid_done = 1; + continue; + } + + if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) { + epid_done = 1; + continue; + } + + if (!usb_pipeout(urb->pipe)) { + /* descr interrupts are generated only for out pipes. */ + epid_done = 1; + continue; + } + + dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub); + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + if (urb_priv->urb_state == TRANSFER_DONE) { + int i; + struct usb_iso_packet_descriptor *packet; + + /* This urb has been sent. */ + dbg_isoc("Completing isoc out URB 0x%p", urb); + + for (i = 0; i < urb->number_of_packets; i++) { + packet = &urb->iso_frame_desc[i]; + packet->status = 0; + packet->actual_length = packet->length; + } + + etrax_usb_complete_isoc_urb(urb, 0); + + if (urb_list_empty(epid)) { + etrax_usb_free_epid(epid); + epid_done = 1; + } + } else { + epid_done = 1; + } + } + restore_flags(flags); + + } + kmem_cache_free(isoc_compl_cache, comp_data); + + DBFEXIT; +} + + + +static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc) +{ + struct urb *urb; + etrax_urb_priv_t *urb_priv; + int epid = 0; + unsigned long flags; + + /* Isoc diagnostics. */ + static int curr_fm = 0; + static int prev_fm = 0; + + DBFENTER; + + /* Clear this interrupt. */ + *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); + + /* Note that this while loop assumes that all packets span only + one rx descriptor. */ + + /* The reason we cli here is that we call the driver's callback functions. */ + save_flags(flags); + cli(); + + while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { + + epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); + urb = urb_list_first(epid); + + //printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb); + + if (!urb) { + err("No urb for epid %d in rx interrupt", epid); + __dump_ept_data(epid); + goto skip_out; + } + + /* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since + ctrl pipes are not. */ + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { + __u32 r_usb_ept_data; + int no_error = 0; + + assert(test_bit(epid, (void *)&epid_usage_bitmask)); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + r_usb_ept_data = *R_USB_EPT_DATA_ISO; + + if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) && + (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) && + (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) { + /* Not an error, just a failure to receive an expected iso + in packet in this frame. This is not documented + in the designers reference. + */ + no_error++; + } else { + warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data); + } + } else { + r_usb_ept_data = *R_USB_EPT_DATA; + warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data); + } + + if (!no_error){ + warn("error in rx desc->status, epid %d, first urb = 0x%lx", + epid, (unsigned long)urb); + __dump_in_desc(myNextRxDesc); + + warn("R_USB_STATUS = 0x%x", *R_USB_STATUS); + + /* Check that ept was disabled when error occurred. */ + switch (usb_pipetype(urb->pipe)) { + case PIPE_BULK: + assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))); + break; + case PIPE_CONTROL: + assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))); + break; + case PIPE_INTERRUPT: + assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable))); + break; + case PIPE_ISOCHRONOUS: + assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))); + break; + default: + warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p", + usb_pipetype(urb->pipe), + urb); + } + etrax_usb_complete_urb(urb, -EPROTO); + goto skip_out; + } + } + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + if ((usb_pipetype(urb->pipe) == PIPE_BULK) || + (usb_pipetype(urb->pipe) == PIPE_CONTROL) || + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { + /* We get nodata for empty data transactions, and the rx descriptor's + hw_len field is not valid in that case. No data to copy in other + words. */ + } else { + /* Make sure the data fits in the buffer. */ + assert(urb_priv->rx_offset + myNextRxDesc->hw_len + <= urb->transfer_buffer_length); + + memcpy(urb->transfer_buffer + urb_priv->rx_offset, + phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); + urb_priv->rx_offset += myNextRxDesc->hw_len; + } + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { + if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) && + ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) == + IO_STATE(USB_EP_command, enable, yes))) { + /* The EP is still enabled, so the OUT packet used to ack + the in data is probably not processed yet. If the EP + sub pointer has not moved beyond urb_priv->last_sb mark + it for a descriptor interrupt and complete the urb in + the descriptor interrupt handler. + */ + USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0; + + while ((sub != NULL) && (sub != urb_priv->last_sb)) { + sub = sub->next ? phys_to_virt(sub->next) : 0; + } + if (sub != NULL) { + /* The urb has not been fully processed. */ + urb_priv->urb_state = WAITING_FOR_DESCR_INTR; + } else { + warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub); + etrax_usb_complete_urb(urb, 0); + } + } else { + etrax_usb_complete_urb(urb, 0); + } + } + + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + + struct usb_iso_packet_descriptor *packet; + + if (urb_priv->urb_state == UNLINK) { + info("Ignoring rx data for urb being unlinked."); + goto skip_out; + } else if (urb_priv->urb_state == NOT_STARTED) { + info("What? Got rx data for urb that isn't started?"); + goto skip_out; + } + + packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter]; + packet->status = 0; + + if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { + /* We get nodata for empty data transactions, and the rx descriptor's + hw_len field is not valid in that case. We copy 0 bytes however to + stay in synch. */ + packet->actual_length = 0; + } else { + packet->actual_length = myNextRxDesc->hw_len; + /* Make sure the data fits in the buffer. */ + assert(packet->actual_length <= packet->length); + memcpy(urb->transfer_buffer + packet->offset, + phys_to_virt(myNextRxDesc->buf), packet->actual_length); + } + + /* Increment the packet counter. */ + urb_priv->isoc_packet_counter++; + + /* Note that we don't care about the eot field in the rx descriptor's status. + It will always be set for isoc traffic. */ + if (urb->number_of_packets == urb_priv->isoc_packet_counter) { + + /* Out-of-synch diagnostics. */ + curr_fm = (*R_USB_FM_NUMBER & 0x7ff); + if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) { + /* This test is wrong, if there is more than one isoc + in endpoint active it will always calculate wrong + since prev_fm is shared by all endpoints. + + FIXME Make this check per URB using urb->start_frame. + */ + dbg_isoc("Out of synch? Previous frame = %d, current frame = %d", + prev_fm, curr_fm); + + } + prev_fm = curr_fm; + + /* Complete the urb with status OK. */ + etrax_usb_complete_isoc_urb(urb, 0); + } + } + + skip_out: + + /* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr + has the same layout as USB_IN_Desc for the relevant fields.) */ + prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc); + + myPrevRxDesc = myNextRxDesc; + myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); + myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); + myLastRxDesc = myPrevRxDesc; + + myNextRxDesc->status = 0; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + } + + restore_flags(flags); + + DBFEXIT; + + return IRQ_HANDLED; +} + + +/* This function will unlink the SB descriptors associated with this urb. */ +static int etrax_remove_from_sb_list(struct urb *urb) +{ + USB_SB_Desc_t *next_sb, *first_sb, *last_sb; + etrax_urb_priv_t *urb_priv; + int i = 0; + + DBFENTER; + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + /* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor + doesn't really need to be disabled, it's just that we expect it to be. */ + if (usb_pipetype(urb->pipe) == PIPE_BULK) { + assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable))); + } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable))); + } + + first_sb = urb_priv->first_sb; + last_sb = urb_priv->last_sb; + + assert(first_sb); + assert(last_sb); + + while (first_sb != last_sb) { + next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next); + kmem_cache_free(usb_desc_cache, first_sb); + first_sb = next_sb; + i++; + } + kmem_cache_free(usb_desc_cache, last_sb); + i++; + dbg_sb("%d SB descriptors freed", i); + /* Compare i with urb->number_of_packets for Isoc traffic. + Should be same when calling unlink_urb */ + + DBFEXIT; + + return i; +} + +static int etrax_usb_submit_bulk_urb(struct urb *urb) +{ + int epid; + int empty; + unsigned long flags; + etrax_urb_priv_t *urb_priv; + + DBFENTER; + + /* Epid allocation, empty check and list add must be protected. + Read about this in etrax_usb_submit_ctrl_urb. */ + + spin_lock_irqsave(&urb_list_lock, flags); + epid = etrax_usb_setup_epid(urb); + if (epid == -1) { + DBFEXIT; + spin_unlock_irqrestore(&urb_list_lock, flags); + return -ENOMEM; + } + empty = urb_list_empty(epid); + urb_list_add(urb, epid); + spin_unlock_irqrestore(&urb_list_lock, flags); + + dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d", + usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid); + + /* Mark the urb as being in progress. */ + urb->status = -EINPROGRESS; + + /* Setup the hcpriv data. */ + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + assert(urb_priv != NULL); + /* This sets rx_offset to 0. */ + urb_priv->urb_state = NOT_STARTED; + urb->hcpriv = urb_priv; + + if (empty) { + etrax_usb_add_to_bulk_sb_list(urb, epid); + } + + DBFEXIT; + + return 0; +} + +static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid) +{ + USB_SB_Desc_t *sb_desc; + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + unsigned long flags; + char maxlen; + + DBFENTER; + + dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb); + + maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + + sb_desc = kmem_cache_zalloc(usb_desc_cache, SLAB_FLAG); + assert(sb_desc != NULL); + + + if (usb_pipeout(urb->pipe)) { + + dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid); + + /* This is probably a sanity check of the bulk transaction length + not being larger than 64 kB. */ + if (urb->transfer_buffer_length > 0xffff) { + panic("urb->transfer_buffer_length > 0xffff"); + } + + sb_desc->sw_len = urb->transfer_buffer_length; + + /* The rem field is don't care if it's not a full-length transfer, so setting + it shouldn't hurt. Also, rem isn't used for OUT traffic. */ + sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + /* The full field is set to yes, even if we don't actually check that this is + a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0). + Setting full prevents the USB controller from sending an empty packet in + that case. However, if URB_ZERO_PACKET was set we want that. */ + if (!(urb->transfer_flags & URB_ZERO_PACKET)) { + sb_desc->command |= IO_STATE(USB_SB_command, full, yes); + } + + sb_desc->buf = virt_to_phys(urb->transfer_buffer); + sb_desc->next = 0; + + } else if (usb_pipein(urb->pipe)) { + + dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid); + + sb_desc->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + + /* The rem field is don't care if it's not a full-length transfer, so setting + it shouldn't hurt. */ + sb_desc->command = + (IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + sb_desc->buf = 0; + sb_desc->next = 0; + } + + urb_priv->first_sb = sb_desc; + urb_priv->last_sb = sb_desc; + urb_priv->epid = epid; + + urb->hcpriv = urb_priv; + + /* Reset toggle bits and reset error count. */ + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + + /* FIXME: Is this a special case since the hold field is checked, + or should we check hold in a lot of other cases as well? */ + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s", __FUNCTION__); + } + + /* Reset error counters (regardless of which direction this traffic is). */ + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out)); + + /* Software must preset the toggle bits. */ + if (usb_pipeout(urb->pipe)) { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); + } else { + char toggle = + usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); + *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); + } + + /* Assert that the EP descriptor is disabled. */ + assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))); + + /* The reason we set the EP's sub pointer directly instead of + walking the SB list and linking it last in the list is that we only + have one active urb at a time (the rest are queued). */ + + /* Note that we cannot have interrupts running when we have set the SB descriptor + but the EP is not yet enabled. If a bulk eot happens for another EP, we will + find this EP disabled and with a SB != 0, which will make us think that it's done. */ + TxBulkEPList[epid].sub = virt_to_phys(sb_desc); + TxBulkEPList[epid].hw_len = 0; + /* Note that we don't have to fill in the ep_id field since this + was done when we allocated the EP descriptors in init_tx_bulk_ep. */ + + /* Check if the dummy list is already with us (if several urbs were queued). */ + if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) { + + dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d", + (unsigned long)urb, epid); + + /* The last EP in the dummy list already has its next pointer set to + TxBulkEPList[epid].next. */ + + /* We don't need to check if the DMA is at this EP or not before changing the + next pointer, since we will do it in one 32-bit write (EP descriptors are + 32-bit aligned). */ + TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]); + } + /* Enable the EP descr. */ + dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid); + TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + + /* Everything is set up, safe to enable interrupts again. */ + restore_flags(flags); + + /* If the DMA bulk channel isn't running, we need to restart it if it + has stopped at the last EP descriptor (DMA stopped because there was + no more traffic) or if it has stopped at a dummy EP with the intr flag + set (DMA stopped because we were too slow in inserting new traffic). */ + if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { + + USB_EP_Desc_t *ep; + ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP); + dbg_bulk("DMA channel not running in add"); + dbg_bulk("DMA is at 0x%lx", (unsigned long)ep); + + if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) || + (ep->command & 0x8) >> 3) { + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + /* Update/restart the bulk start timer since we just started the channel. */ + mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL); + /* Update/restart the bulk eot timer since we just inserted traffic. */ + mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL); + } + } + + DBFEXIT; +} + +static void etrax_usb_complete_bulk_urb(struct urb *urb, int status) +{ + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + int epid = urb_priv->epid; + unsigned long flags; + + DBFENTER; + + if (status) + warn("Completing bulk urb with status %d.", status); + + dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid); + + /* Update the urb list. */ + urb_list_del(urb, epid); + + /* For an IN pipe, we always set the actual length, regardless of whether there was + an error or not (which means the device driver can use the data if it wants to). */ + if (usb_pipein(urb->pipe)) { + urb->actual_length = urb_priv->rx_offset; + } else { + /* Set actual_length for OUT urbs also; the USB mass storage driver seems + to want that. We wouldn't know of any partial writes if there was an error. */ + if (status == 0) { + urb->actual_length = urb->transfer_buffer_length; + } else { + urb->actual_length = 0; + } + } + + /* FIXME: Is there something of the things below we shouldn't do if there was an error? + Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + + /* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */ + if (usb_pipeout(urb->pipe)) { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); + } else { + char toggle = + IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); + } + restore_flags(flags); + + /* Remember to free the SBs. */ + etrax_remove_from_sb_list(urb); + kfree(urb_priv); + urb->hcpriv = 0; + + /* If there are any more urb's in the list we'd better start sending */ + if (!urb_list_empty(epid)) { + + struct urb *new_urb; + + /* Get the first urb. */ + new_urb = urb_list_first(epid); + assert(new_urb); + + dbg_bulk("More bulk for epid %d", epid); + + etrax_usb_add_to_bulk_sb_list(new_urb, epid); + } + + urb->status = status; + + /* We let any non-zero status from the layer above have precedence. */ + if (status == 0) { + /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length) + is to be treated as an error. */ + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + if (usb_pipein(urb->pipe) && + (urb->actual_length != + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) { + urb->status = -EREMOTEIO; + } + } + } + + if (urb->complete) { + urb->complete(urb, NULL); + } + + if (urb_list_empty(epid)) { + /* This means that this EP is now free, deconfigure it. */ + etrax_usb_free_epid(epid); + + /* No more traffic; time to clean up. + Must set sub pointer to 0, since we look at the sub pointer when handling + the bulk eot interrupt. */ + + dbg_bulk("No bulk for epid %d", epid); + + TxBulkEPList[epid].sub = 0; + + /* Unlink the dummy list. */ + + dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d", + (unsigned long)urb, epid); + + /* No need to wait for the DMA before changing the next pointer. + The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use + the last one (INVALID_EPID) for actual traffic. */ + TxBulkEPList[epid].next = + virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]); + } + + DBFEXIT; +} + +static int etrax_usb_submit_ctrl_urb(struct urb *urb) +{ + int epid; + int empty; + unsigned long flags; + etrax_urb_priv_t *urb_priv; + + DBFENTER; + + /* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */ + + /* Epid allocation, empty check and list add must be protected. + + Epid allocation because if we find an existing epid for this endpoint an urb might be + completed (emptying the list) before we add the new urb to the list, causing the epid + to be de-allocated. We would then start the transfer with an invalid epid -> epid attn. + + Empty check and add because otherwise we might conclude that the list is not empty, + after which it becomes empty before we add the new urb to the list, causing us not to + insert the new traffic into the SB list. */ + + spin_lock_irqsave(&urb_list_lock, flags); + epid = etrax_usb_setup_epid(urb); + if (epid == -1) { + spin_unlock_irqrestore(&urb_list_lock, flags); + DBFEXIT; + return -ENOMEM; + } + empty = urb_list_empty(epid); + urb_list_add(urb, epid); + spin_unlock_irqrestore(&urb_list_lock, flags); + + dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d", + (unsigned long)urb, empty ? "empty" : "", epid); + + /* Mark the urb as being in progress. */ + urb->status = -EINPROGRESS; + + /* Setup the hcpriv data. */ + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + assert(urb_priv != NULL); + /* This sets rx_offset to 0. */ + urb_priv->urb_state = NOT_STARTED; + urb->hcpriv = urb_priv; + + if (empty) { + etrax_usb_add_to_ctrl_sb_list(urb, epid); + } + + DBFEXIT; + + return 0; +} + +static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid) +{ + USB_SB_Desc_t *sb_desc_setup; + USB_SB_Desc_t *sb_desc_data; + USB_SB_Desc_t *sb_desc_status; + + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + + unsigned long flags; + char maxlen; + + DBFENTER; + + maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + + sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + assert(sb_desc_setup != NULL); + sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + assert(sb_desc_status != NULL); + + /* Initialize the mandatory setup SB descriptor (used only in control transfers) */ + sb_desc_setup->sw_len = 8; + sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, setup) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes)); + + sb_desc_setup->buf = virt_to_phys(urb->setup_packet); + + if (usb_pipeout(urb->pipe)) { + dbg_ctrl("Transfer for epid %d is OUT", epid); + + /* If this Control OUT transfer has an optional data stage we add an OUT token + before the mandatory IN (status) token, hence the reordered SB list */ + + sb_desc_setup->next = virt_to_phys(sb_desc_status); + if (urb->transfer_buffer) { + + dbg_ctrl("This OUT transfer has an extra data stage"); + + sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + assert(sb_desc_data != NULL); + + sb_desc_setup->next = virt_to_phys(sb_desc_data); + + sb_desc_data->sw_len = urb->transfer_buffer_length; + sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes)); + sb_desc_data->buf = virt_to_phys(urb->transfer_buffer); + sb_desc_data->next = virt_to_phys(sb_desc_status); + } + + sb_desc_status->sw_len = 1; + sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, intr, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + sb_desc_status->buf = 0; + sb_desc_status->next = 0; + + } else if (usb_pipein(urb->pipe)) { + + dbg_ctrl("Transfer for epid %d is IN", epid); + dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); + + sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + assert(sb_desc_data != NULL); + + sb_desc_setup->next = virt_to_phys(sb_desc_data); + + sb_desc_data->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + dbg_ctrl("sw_len got %d", sb_desc_data->sw_len); + + sb_desc_data->command = + (IO_FIELD(USB_SB_command, rem, + urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes)); + + sb_desc_data->buf = 0; + sb_desc_data->next = virt_to_phys(sb_desc_status); + + /* Read comment at zout_buffer declaration for an explanation to this. */ + sb_desc_status->sw_len = 1; + sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, full, yes) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, intr, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + sb_desc_status->buf = virt_to_phys(&zout_buffer[0]); + sb_desc_status->next = 0; + } + + urb_priv->first_sb = sb_desc_setup; + urb_priv->last_sb = sb_desc_status; + urb_priv->epid = epid; + + urb_priv->urb_state = STARTED; + + /* Reset toggle bits and reset error count, remember to di and ei */ + /* Warning: it is possible that this locking doesn't work with bottom-halves */ + + save_flags(flags); + cli(); + + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { + panic("Hold was set in %s", __FUNCTION__); + } + + + /* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits + are set to a specific value. Why the difference? Read "Transfer and Toggle Bits + in Designer's Reference, p. 8 - 11. */ + *R_USB_EPT_DATA &= + ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | + IO_MASK(R_USB_EPT_DATA, error_count_out) | + IO_MASK(R_USB_EPT_DATA, t_in) | + IO_MASK(R_USB_EPT_DATA, t_out)); + + /* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now + (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */ + restore_flags(flags); + + /* Assert that the EP descriptor is disabled. */ + assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))); + + /* Set up and enable the EP descriptor. */ + TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup); + TxCtrlEPList[epid].hw_len = 0; + TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + + /* We start the DMA sub channel without checking if it's running or not, because: + 1) If it's already running, issuing the start command is a nop. + 2) We avoid a test-and-set race condition. */ + *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); + + DBFEXIT; +} + +static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status) +{ + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + int epid = urb_priv->epid; + + DBFENTER; + + if (status) + warn("Completing ctrl urb with status %d.", status); + + dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb); + + /* Remove this urb from the list. */ + urb_list_del(urb, epid); + + /* For an IN pipe, we always set the actual length, regardless of whether there was + an error or not (which means the device driver can use the data if it wants to). */ + if (usb_pipein(urb->pipe)) { + urb->actual_length = urb_priv->rx_offset; + } + + /* FIXME: Is there something of the things below we shouldn't do if there was an error? + Like, maybe we shouldn't insert more traffic. */ + + /* Remember to free the SBs. */ + etrax_remove_from_sb_list(urb); + kfree(urb_priv); + urb->hcpriv = 0; + + /* If there are any more urbs in the list we'd better start sending. */ + if (!urb_list_empty(epid)) { + struct urb *new_urb; + + /* Get the first urb. */ + new_urb = urb_list_first(epid); + assert(new_urb); + + dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb); + + etrax_usb_add_to_ctrl_sb_list(new_urb, epid); + } + + urb->status = status; + + /* We let any non-zero status from the layer above have precedence. */ + if (status == 0) { + /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length) + is to be treated as an error. */ + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + if (usb_pipein(urb->pipe) && + (urb->actual_length != + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) { + urb->status = -EREMOTEIO; + } + } + } + + if (urb->complete) { + urb->complete(urb, NULL); + } + + if (urb_list_empty(epid)) { + /* No more traffic. Time to clean up. */ + etrax_usb_free_epid(epid); + /* Must set sub pointer to 0. */ + dbg_ctrl("No ctrl for epid %d", epid); + TxCtrlEPList[epid].sub = 0; + } + + DBFEXIT; +} + +static int etrax_usb_submit_intr_urb(struct urb *urb) +{ + + int epid; + + DBFENTER; + + if (usb_pipeout(urb->pipe)) { + /* Unsupported transfer type. + We don't support interrupt out traffic. (If we do, we can't support + intervals for neither in or out traffic, but are forced to schedule all + interrupt traffic in one frame.) */ + return -EINVAL; + } + + epid = etrax_usb_setup_epid(urb); + if (epid == -1) { + DBFEXIT; + return -ENOMEM; + } + + if (!urb_list_empty(epid)) { + /* There is already a queued urb for this endpoint. */ + etrax_usb_free_epid(epid); + return -ENXIO; + } + + urb->status = -EINPROGRESS; + + dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid); + + urb_list_add(urb, epid); + etrax_usb_add_to_intr_sb_list(urb, epid); + + return 0; + + DBFEXIT; +} + +static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid) +{ + + volatile USB_EP_Desc_t *tmp_ep; + volatile USB_EP_Desc_t *first_ep; + + char maxlen; + int interval; + int i; + + etrax_urb_priv_t *urb_priv; + + DBFENTER; + + maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + interval = urb->interval; + + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + assert(urb_priv != NULL); + urb->hcpriv = urb_priv; + + first_ep = &TxIntrEPList[0]; + + /* Round of the interval to 2^n, it is obvious that this code favours + smaller numbers, but that is actually a good thing */ + /* FIXME: The "rounding error" for larger intervals will be quite + large. For in traffic this shouldn't be a problem since it will only + mean that we "poll" more often. */ + for (i = 0; interval; i++) { + interval = interval >> 1; + } + interval = 1 << (i - 1); + + dbg_intr("Interval rounded to %d", interval); + + tmp_ep = first_ep; + i = 0; + do { + if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { + if ((i % interval) == 0) { + /* Insert the traffic ep after tmp_ep */ + USB_EP_Desc_t *ep_desc; + USB_SB_Desc_t *sb_desc; + + dbg_intr("Inserting EP for epid %d", epid); + + ep_desc = (USB_EP_Desc_t *) + kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + sb_desc = (USB_SB_Desc_t *) + kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + assert(ep_desc != NULL); + CHECK_ALIGN(ep_desc); + assert(sb_desc != NULL); + + ep_desc->sub = virt_to_phys(sb_desc); + ep_desc->hw_len = 0; + ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) | + IO_STATE(USB_EP_command, enable, yes)); + + + /* Round upwards the number of packets of size maxlen + that this SB descriptor should receive. */ + sb_desc->sw_len = urb->transfer_buffer_length ? + (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; + sb_desc->next = 0; + sb_desc->buf = 0; + sb_desc->command = + (IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) | + IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + ep_desc->next = tmp_ep->next; + tmp_ep->next = virt_to_phys(ep_desc); + } + i++; + } + tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next); + } while (tmp_ep != first_ep); + + + /* Note that first_sb/last_sb doesn't apply to interrupt traffic. */ + urb_priv->epid = epid; + + /* We start the DMA sub channel without checking if it's running or not, because: + 1) If it's already running, issuing the start command is a nop. + 2) We avoid a test-and-set race condition. */ + *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); + + DBFEXIT; +} + + + +static void etrax_usb_complete_intr_urb(struct urb *urb, int status) +{ + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + int epid = urb_priv->epid; + + DBFENTER; + + if (status) + warn("Completing intr urb with status %d.", status); + + dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb); + + urb->status = status; + urb->actual_length = urb_priv->rx_offset; + + dbg_intr("interrupt urb->actual_length = %d", urb->actual_length); + + /* We let any non-zero status from the layer above have precedence. */ + if (status == 0) { + /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length) + is to be treated as an error. */ + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + if (urb->actual_length != + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) { + urb->status = -EREMOTEIO; + } + } + } + + /* The driver will resubmit the URB so we need to remove it first */ + etrax_usb_unlink_urb(urb, 0); + if (urb->complete) { + urb->complete(urb, NULL); + } + + DBFEXIT; +} + + +static int etrax_usb_submit_isoc_urb(struct urb *urb) +{ + int epid; + unsigned long flags; + + DBFENTER; + + dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb); + + /* Epid allocation, empty check and list add must be protected. + Read about this in etrax_usb_submit_ctrl_urb. */ + + spin_lock_irqsave(&urb_list_lock, flags); + /* Is there an active epid for this urb ? */ + epid = etrax_usb_setup_epid(urb); + if (epid == -1) { + DBFEXIT; + spin_unlock_irqrestore(&urb_list_lock, flags); + return -ENOMEM; + } + + /* Ok, now we got valid endpoint, lets insert some traffic */ + + urb->status = -EINPROGRESS; + + /* Find the last urb in the URB_List and add this urb after that one. + Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list. This + is important to make this in "real time" since isochronous traffic is + time sensitive. */ + + dbg_isoc("Adding isoc urb to (possibly empty) list"); + urb_list_add(urb, epid); + etrax_usb_add_to_isoc_sb_list(urb, epid); + spin_unlock_irqrestore(&urb_list_lock, flags); + + DBFEXIT; + + return 0; +} + +static void etrax_usb_check_error_isoc_ep(const int epid) +{ + unsigned long int flags; + int error_code; + __u32 r_usb_ept_data; + + /* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof, + bulk_eot and epid_attn interrupts. So we just check the status of + the epid without testing if for it in R_USB_EPID_ATTN. */ + + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + /* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO + registers, they are located at the same address and are of the same size. + In other words, this read should be ok for isoc also. */ + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data); + + if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { + warn("Hold was set for epid %d.", epid); + return; + } + + if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) { + + /* This indicates that the SB list of the ept was completed before + new data was appended to it. This is not an error, but indicates + large system or USB load and could possibly cause trouble for + very timing sensitive USB device drivers so we log it. + */ + info("Isoc. epid %d disabled with no error", epid); + return; + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) { + /* Not really a protocol error, just says that the endpoint gave + a stall response. Note that error_code cannot be stall for isoc. */ + panic("Isoc traffic cannot stall"); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) { + /* Two devices responded to a transaction request. Must be resolved + by software. FIXME: Reset ports? */ + panic("Bus error for epid %d." + " Two devices responded to transaction request", + epid); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { + /* DMA overrun or underrun. */ + warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid); + + /* It seems that error_code = buffer_error in + R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS + are the same error. */ + } +} + + +static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) +{ + + int i = 0; + + etrax_urb_priv_t *urb_priv; + USB_SB_Desc_t *prev_sb_desc, *next_sb_desc, *temp_sb_desc; + + DBFENTER; + + prev_sb_desc = next_sb_desc = temp_sb_desc = NULL; + + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC); + assert(urb_priv != NULL); + + urb->hcpriv = urb_priv; + urb_priv->epid = epid; + + if (usb_pipeout(urb->pipe)) { + + if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n"); + + dbg_isoc("Transfer for epid %d is OUT", epid); + dbg_isoc("%d packets in URB", urb->number_of_packets); + + /* Create one SB descriptor for each packet and link them together. */ + for (i = 0; i < urb->number_of_packets; i++) { + if (!urb->iso_frame_desc[i].length) + continue; + + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); + assert(next_sb_desc != NULL); + + if (urb->iso_frame_desc[i].length > 0) { + + next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) | + IO_STATE(USB_SB_command, eot, yes)); + + next_sb_desc->sw_len = urb->iso_frame_desc[i].length; + next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset); + + /* Check if full length transfer. */ + if (urb->iso_frame_desc[i].length == + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) { + next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes); + } + } else { + dbg_isoc("zero len packet"); + next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) | + IO_STATE(USB_SB_command, tt, zout) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, full, yes)); + + next_sb_desc->sw_len = 1; + next_sb_desc->buf = virt_to_phys(&zout_buffer[0]); + } + + /* First SB descriptor that belongs to this urb */ + if (i == 0) + urb_priv->first_sb = next_sb_desc; + else + prev_sb_desc->next = virt_to_phys(next_sb_desc); + + prev_sb_desc = next_sb_desc; + } + + next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) | + IO_STATE(USB_SB_command, eol, yes)); + next_sb_desc->next = 0; + urb_priv->last_sb = next_sb_desc; + + } else if (usb_pipein(urb->pipe)) { + + dbg_isoc("Transfer for epid %d is IN", epid); + dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length); + dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length); + + /* Note that in descriptors for periodic traffic are not consumed. This means that + the USB controller never propagates in the SB list. In other words, if there already + is an SB descriptor in the list for this EP we don't have to do anything. */ + if (TxIsocEPList[epid].sub == 0) { + dbg_isoc("Isoc traffic not already running, allocating SB"); + + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); + assert(next_sb_desc != NULL); + + next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) | + IO_STATE(USB_SB_command, eot, yes) | + IO_STATE(USB_SB_command, eol, yes)); + + next_sb_desc->next = 0; + next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant + for periodic in traffic as long as it is more + than zero. Set to 1 always. */ + next_sb_desc->buf = 0; + + /* The rem field is don't care for isoc traffic, so we don't set it. */ + + /* Only one SB descriptor that belongs to this urb. */ + urb_priv->first_sb = next_sb_desc; + urb_priv->last_sb = next_sb_desc; + + } else { + + dbg_isoc("Isoc traffic already running, just setting first/last_sb"); + + /* Each EP for isoc in will have only one SB descriptor, setup when submitting the + already active urb. Note that even though we may have several first_sb/last_sb + pointing at the same SB descriptor, they are freed only once (when the list has + become empty). */ + urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub); + urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub); + return; + } + + } + + /* Find the spot to insert this urb and add it. */ + if (TxIsocEPList[epid].sub == 0) { + /* First SB descriptor inserted in this list (in or out). */ + dbg_isoc("Inserting SB desc first in list"); + TxIsocEPList[epid].hw_len = 0; + TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb); + + } else { + /* Isochronous traffic is already running, insert new traffic last (only out). */ + dbg_isoc("Inserting SB desc last in list"); + temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub); + while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) != + IO_STATE(USB_SB_command, eol, yes)) { + assert(temp_sb_desc->next); + temp_sb_desc = phys_to_virt(temp_sb_desc->next); + } + dbg_isoc("Appending list on desc 0x%p", temp_sb_desc); + + /* Next pointer must be set before eol is removed. */ + temp_sb_desc->next = virt_to_phys(urb_priv->first_sb); + /* Clear the previous end of list flag since there is a new in the + added SB descriptor list. */ + temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol); + + if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) { + /* 8.8.5 in Designer's Reference says we should check for and correct + any errors in the EP here. That should not be necessary if epid_attn + is handled correctly, so we assume all is ok. */ + dbg_isoc("EP disabled"); + etrax_usb_check_error_isoc_ep(epid); + + /* The SB list was exhausted. */ + if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) { + /* The new sublist did not get processed before the EP was + disabled. Setup the EP again. */ + dbg_isoc("Set EP sub to new list"); + TxIsocEPList[epid].hw_len = 0; + TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb); + } + } + } + + if (urb->transfer_flags & URB_ISO_ASAP) { + /* The isoc transfer should be started as soon as possible. The start_frame + field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER + with a USB Chief trace shows that the first isoc IN token is sent 2 frames + later. I'm not sure how this affects usage of the start_frame field by the + device driver, or how it affects things when USB_ISO_ASAP is not set, so + therefore there's no compensation for the 2 frame "lag" here. */ + urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff); + TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + urb_priv->urb_state = STARTED; + dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame); + } else { + /* Not started yet. */ + urb_priv->urb_state = NOT_STARTED; + dbg_isoc("urb_priv->urb_state set to NOT_STARTED"); + } + + /* We start the DMA sub channel without checking if it's running or not, because: + 1) If it's already running, issuing the start command is a nop. + 2) We avoid a test-and-set race condition. */ + *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start); + + DBFEXIT; +} + +static void etrax_usb_complete_isoc_urb(struct urb *urb, int status) +{ + etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + int epid = urb_priv->epid; + int auto_resubmit = 0; + + DBFENTER; + dbg_isoc("complete urb 0x%p, status %d", urb, status); + + if (status) + warn("Completing isoc urb with status %d.", status); + + if (usb_pipein(urb->pipe)) { + int i; + + /* Make that all isoc packets have status and length set before + completing the urb. */ + for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = -EPROTO; + } + + urb_list_del(urb, epid); + + if (!list_empty(&urb_list[epid])) { + ((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED; + } else { + unsigned long int flags; + if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + /* The EP was enabled, disable it and wait. */ + TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); + + /* Ah, the luxury of busy-wait. */ + while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])); + } + + etrax_remove_from_sb_list(urb); + TxIsocEPList[epid].sub = 0; + TxIsocEPList[epid].hw_len = 0; + + save_flags(flags); + cli(); + etrax_usb_free_epid(epid); + restore_flags(flags); + } + + urb->hcpriv = 0; + kfree(urb_priv); + + /* Release allocated bandwidth. */ + usb_release_bandwidth(urb->dev, urb, 0); + } else if (usb_pipeout(urb->pipe)) { + int freed_descr; + + dbg_isoc("Isoc out urb complete 0x%p", urb); + + /* Update the urb list. */ + urb_list_del(urb, epid); + + freed_descr = etrax_remove_from_sb_list(urb); + dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets); + assert(freed_descr == urb->number_of_packets); + urb->hcpriv = 0; + kfree(urb_priv); + + /* Release allocated bandwidth. */ + usb_release_bandwidth(urb->dev, urb, 0); + } + + urb->status = status; + if (urb->complete) { + urb->complete(urb, NULL); + } + + if (auto_resubmit) { + /* Check that urb was not unlinked by the complete callback. */ + if (__urb_list_entry(urb, epid)) { + /* Move this one down the list. */ + urb_list_move_last(urb, epid); + + /* Mark the now first urb as started (may already be). */ + ((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED; + + /* Must set this to 0 since this urb is still active after + completion. */ + urb_priv->isoc_packet_counter = 0; + } else { + warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb); + } + } + + DBFEXIT; +} + +static void etrax_usb_complete_urb(struct urb *urb, int status) +{ + switch (usb_pipetype(urb->pipe)) { + case PIPE_BULK: + etrax_usb_complete_bulk_urb(urb, status); + break; + case PIPE_CONTROL: + etrax_usb_complete_ctrl_urb(urb, status); + break; + case PIPE_INTERRUPT: + etrax_usb_complete_intr_urb(urb, status); + break; + case PIPE_ISOCHRONOUS: + etrax_usb_complete_isoc_urb(urb, status); + break; + default: + err("Unknown pipetype"); + } +} + + + +static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc) +{ + usb_interrupt_registers_t *reg; + unsigned long flags; + __u32 irq_mask; + __u8 status; + __u32 epid_attn; + __u16 port_status_1; + __u16 port_status_2; + __u32 fm_number; + + DBFENTER; + + /* Read critical registers into local variables, do kmalloc afterwards. */ + save_flags(flags); + cli(); + + irq_mask = *R_USB_IRQ_MASK_READ; + /* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS + must be read before R_USB_EPID_ATTN since reading the latter clears the + ourun and perror fields of R_USB_STATUS. */ + status = *R_USB_STATUS; + + /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */ + epid_attn = *R_USB_EPID_ATTN; + + /* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the + port_status interrupt. */ + port_status_1 = *R_USB_RH_PORT_STATUS_1; + port_status_2 = *R_USB_RH_PORT_STATUS_2; + + /* Reading R_USB_FM_NUMBER clears the sof interrupt. */ + /* Note: the lower 11 bits contain the actual frame number, sent with each sof. */ + fm_number = *R_USB_FM_NUMBER; + + restore_flags(flags); + + reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, GFP_ATOMIC); + + assert(reg != NULL); + + reg->hc = (etrax_hc_t *)vhc; + + /* Now put register values into kmalloc'd area. */ + reg->r_usb_irq_mask_read = irq_mask; + reg->r_usb_status = status; + reg->r_usb_epid_attn = epid_attn; + reg->r_usb_rh_port_status_1 = port_status_1; + reg->r_usb_rh_port_status_2 = port_status_2; + reg->r_usb_fm_number = fm_number; + + INIT_WORK(®->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg); + schedule_work(®->usb_bh); + + DBFEXIT; + + return IRQ_HANDLED; +} + +static void etrax_usb_hc_interrupt_bottom_half(void *data) +{ + usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data; + __u32 irq_mask = reg->r_usb_irq_mask_read; + + DBFENTER; + + /* Interrupts are handled in order of priority. */ + if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) { + etrax_usb_hc_epid_attn_interrupt(reg); + } + if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { + etrax_usb_hc_port_status_interrupt(reg); + } + if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) { + etrax_usb_hc_ctl_status_interrupt(reg); + } + if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) { + etrax_usb_hc_isoc_eof_interrupt(); + } + if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) { + /* Update/restart the bulk start timer since obviously the channel is running. */ + mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL); + /* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */ + mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL); + + etrax_usb_hc_bulk_eot_interrupt(0); + } + + kmem_cache_free(top_half_reg_cache, reg); + + DBFEXIT; +} + + +void etrax_usb_hc_isoc_eof_interrupt(void) +{ + struct urb *urb; + etrax_urb_priv_t *urb_priv; + int epid; + unsigned long flags; + + DBFENTER; + + /* Do not check the invalid epid (it has a valid sub pointer). */ + for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) { + + /* Do not check the invalid epid (it has a valid sub pointer). */ + if ((epid == DUMMY_EPID) || (epid == INVALID_EPID)) + continue; + + /* Disable interrupts to block the isoc out descriptor interrupt handler + from being called while the isoc EPID list is being checked. + */ + save_flags(flags); + cli(); + + if (TxIsocEPList[epid].sub == 0) { + /* Nothing here to see. */ + restore_flags(flags); + continue; + } + + /* Get the first urb (if any). */ + urb = urb_list_first(epid); + if (urb == 0) { + warn("Ignoring NULL urb"); + restore_flags(flags); + continue; + } + if (usb_pipein(urb->pipe)) { + + /* Sanity check. */ + assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS); + + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + if (urb_priv->urb_state == NOT_STARTED) { + + /* If ASAP is not set and urb->start_frame is the current frame, + start the transfer. */ + if (!(urb->transfer_flags & URB_ISO_ASAP) && + (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) { + + dbg_isoc("Enabling isoc IN EP descr for epid %d", epid); + TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); + + /* This urb is now active. */ + urb_priv->urb_state = STARTED; + continue; + } + } + } + restore_flags(flags); + } + + DBFEXIT; + +} + +void etrax_usb_hc_bulk_eot_interrupt(int timer_induced) +{ + int epid; + + /* The technique is to run one urb at a time, wait for the eot interrupt at which + point the EP descriptor has been disabled. */ + + DBFENTER; + dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : ""); + + for (epid = 0; epid < NBR_OF_EPIDS; epid++) { + + if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) && + (TxBulkEPList[epid].sub != 0)) { + + struct urb *urb; + etrax_urb_priv_t *urb_priv; + unsigned long flags; + __u32 r_usb_ept_data; + + /* Found a disabled EP descriptor which has a non-null sub pointer. + Verify that this ctrl EP descriptor got disabled no errors. + FIXME: Necessary to check error_code? */ + dbg_bulk("for epid %d?", epid); + + /* Get the first urb. */ + urb = urb_list_first(epid); + + /* FIXME: Could this happen for valid reasons? Why did it disappear? Because of + wrong unlinking? */ + if (!urb) { + warn("NULL urb for epid %d", epid); + continue; + } + + assert(urb); + urb_priv = (etrax_urb_priv_t *)urb->hcpriv; + assert(urb_priv); + + /* Sanity checks. */ + assert(usb_pipetype(urb->pipe) == PIPE_BULK); + if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) { + err("bulk endpoint got disabled before reaching last sb"); + } + + /* For bulk IN traffic, there seems to be a race condition between + between the bulk eot and eop interrupts, or rather an uncertainty regarding + the order in which they happen. Normally we expect the eop interrupt from + DMA channel 9 to happen before the eot interrupt. + + Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */ + + if (usb_pipein(urb->pipe)) { + dbg_bulk("in urb, continuing"); + continue; + } + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == + IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + /* This means that the endpoint has no error, is disabled + and had inserted traffic, i.e. transfer successfully completed. */ + etrax_usb_complete_bulk_urb(urb, 0); + } else { + /* Shouldn't happen. We expect errors to be caught by epid attention. */ + err("Found disabled bulk EP desc, error_code != no_error"); + } + } + } + + /* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer. + However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may + not. Also, we might find two disabled EPs when handling an eot interrupt, and then find + none the next time. */ + + DBFEXIT; + +} + +void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg) +{ + /* This function handles the epid attention interrupt. There are a variety of reasons + for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details): + + invalid ep_id - Invalid epid in an EP (EP disabled). + stall - Not strictly an error condition (EP disabled). + 3rd error - Three successive transaction errors (EP disabled). + buffer ourun - Buffer overrun or underrun (EP disabled). + past eof1 - Intr or isoc transaction proceeds past EOF1. + near eof - Intr or isoc transaction would not fit inside the frame. + zout transfer - If zout transfer for a bulk endpoint (EP disabled). + setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */ + + int epid; + + + DBFENTER; + + assert(reg != NULL); + + /* Note that we loop through all epids. We still want to catch errors for + the invalid one, even though we might handle them differently. */ + for (epid = 0; epid < NBR_OF_EPIDS; epid++) { + + if (test_bit(epid, (void *)®->r_usb_epid_attn)) { + + struct urb *urb; + __u32 r_usb_ept_data; + unsigned long flags; + int error_code; + + save_flags(flags); + cli(); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); + nop(); + /* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO + registers, they are located at the same address and are of the same size. + In other words, this read should be ok for isoc also. */ + r_usb_ept_data = *R_USB_EPT_DATA; + restore_flags(flags); + + /* First some sanity checks. */ + if (epid == INVALID_EPID) { + /* FIXME: What if it became disabled? Could seriously hurt interrupt + traffic. (Use do_intr_recover.) */ + warn("Got epid_attn for INVALID_EPID (%d).", epid); + err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data); + err("R_USB_STATUS = 0x%x", reg->r_usb_status); + continue; + } else if (epid == DUMMY_EPID) { + /* We definitely don't care about these ones. Besides, they are + always disabled, so any possible disabling caused by the + epid attention interrupt is irrelevant. */ + warn("Got epid_attn for DUMMY_EPID (%d).", epid); + continue; + } + + /* Get the first urb in the urb list for this epid. We blatantly assume + that only the first urb could have caused the epid attention. + (For bulk and ctrl, only one urb is active at any one time. For intr + and isoc we remove them once they are completed.) */ + urb = urb_list_first(epid); + + if (urb == NULL) { + err("Got epid_attn for epid %i with no urb.", epid); + err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data); + err("R_USB_STATUS = 0x%x", reg->r_usb_status); + continue; + } + + switch (usb_pipetype(urb->pipe)) { + case PIPE_BULK: + warn("Got epid attn for bulk endpoint, epid %d", epid); + break; + case PIPE_CONTROL: + warn("Got epid attn for control endpoint, epid %d", epid); + break; + case PIPE_INTERRUPT: + warn("Got epid attn for interrupt endpoint, epid %d", epid); + break; + case PIPE_ISOCHRONOUS: + warn("Got epid attn for isochronous endpoint, epid %d", epid); + break; + } + + if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) { + if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { + warn("Hold was set for epid %d.", epid); + continue; + } + } + + /* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and + R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data); + } else { + error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data); + } + + /* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */ + if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { + + /* Isoc traffic doesn't have error_count_in/error_count_out. */ + if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) && + (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 || + IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) { + /* 3rd error. */ + warn("3rd error for epid %i", epid); + etrax_usb_complete_urb(urb, -EPROTO); + + } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + + warn("Perror for epid %d", epid); + + if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { + /* invalid ep_id */ + panic("Perror because of invalid epid." + " Deconfigured too early?"); + } else { + /* past eof1, near eof, zout transfer, setup transfer */ + + /* Dump the urb and the relevant EP descriptor list. */ + + __dump_urb(urb); + __dump_ept_data(epid); + __dump_ep_list(usb_pipetype(urb->pipe)); + + panic("Something wrong with DMA descriptor contents." + " Too much traffic inserted?"); + } + } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + /* buffer ourun */ + panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid); + } + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { + /* Not really a protocol error, just says that the endpoint gave + a stall response. Note that error_code cannot be stall for isoc. */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + panic("Isoc traffic cannot stall"); + } + + warn("Stall for epid %d", epid); + etrax_usb_complete_urb(urb, -EPIPE); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { + /* Two devices responded to a transaction request. Must be resolved + by software. FIXME: Reset ports? */ + panic("Bus error for epid %d." + " Two devices responded to transaction request", + epid); + + } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { + /* DMA overrun or underrun. */ + warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid); + + /* It seems that error_code = buffer_error in + R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS + are the same error. */ + etrax_usb_complete_urb(urb, -EPROTO); + } + } + } + + DBFEXIT; + +} + +void etrax_usb_bulk_start_timer_func(unsigned long dummy) +{ + + /* We might enable an EP descriptor behind the current DMA position when it's about + to decide that there are no more bulk traffic and it should stop the bulk channel. + Therefore we periodically check if the bulk channel is stopped and there is an + enabled bulk EP descriptor, in which case we start the bulk channel. */ + dbg_bulk("bulk_start_timer timed out."); + + if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { + int epid; + + dbg_bulk("Bulk DMA channel not running."); + + for (epid = 0; epid < NBR_OF_EPIDS; epid++) { + if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { + dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n", + epid); + *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); + + /* Restart the bulk eot timer since we just started the bulk channel. */ + mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL); + + /* No need to search any further. */ + break; + } + } + } else { + dbg_bulk("Bulk DMA channel running."); + } +} + +void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg) +{ + etrax_hc_t *hc = reg->hc; + __u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; + __u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; + + DBFENTER; + + /* The Etrax RH does not include a wPortChange register, so this has to be handled in software + (by saving the old port status value for comparison when the port status interrupt happens). + See section 11.16.2.6.2 in the USB 1.1 spec for details. */ + + dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1); + dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2); + dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1); + dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2); + + /* C_PORT_CONNECTION is set on any transition. */ + hc->rh.wPortChange_1 |= + ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + hc->rh.wPortChange_2 |= + ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != + (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? + (1 << RH_PORT_CONNECTION) : 0; + + /* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when + the port is disabled, not when it's enabled. */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) + && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? + (1 << RH_PORT_ENABLE) : 0; + + /* C_PORT_SUSPEND is set to one when the device has transitioned out + of the suspended state, i.e. when suspend goes from one to zero. */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND)) + && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ? + (1 << RH_PORT_SUSPEND) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND)) + && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ? + (1 << RH_PORT_SUSPEND) : 0; + + + /* C_PORT_RESET is set when reset processing on this port is complete. */ + hc->rh.wPortChange_1 |= + ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) + && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ? + (1 << RH_PORT_RESET) : 0; + + hc->rh.wPortChange_2 |= + ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) + && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ? + (1 << RH_PORT_RESET) : 0; + + /* Save the new values for next port status change. */ + hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; + hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; + + dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1); + dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2); + + DBFEXIT; + +} + +void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg) +{ + DBFENTER; + + /* FIXME: What should we do if we get ourun or perror? Dump the EP and SB + list for the corresponding epid? */ + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { + panic("USB controller got ourun."); + } + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { + + /* Before, etrax_usb_do_intr_recover was called on this epid if it was + an interrupt pipe. I don't see how re-enabling all EP descriptors + will help if there was a programming error. */ + panic("USB controller got perror."); + } + + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) { + /* We should never operate in device mode. */ + panic("USB controller in device mode."); + } + + /* These if-statements could probably be nested. */ + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) { + info("USB controller in host mode."); + } + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) { + info("USB controller started."); + } + if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) { + info("USB controller running."); + } + + DBFEXIT; + +} + + +static int etrax_rh_submit_urb(struct urb *urb) +{ + struct usb_device *usb_dev = urb->dev; + etrax_hc_t *hc = usb_dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; + void *data = urb->transfer_buffer; + int leni = urb->transfer_buffer_length; + int len = 0; + int stat = 0; + + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + + DBFENTER; + + /* FIXME: What is this interrupt urb that is sent to the root hub? */ + if (usb_pipetype (pipe) == PIPE_INTERRUPT) { + dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); + hc->rh.urb = urb; + hc->rh.send = 1; + /* FIXME: We could probably remove this line since it's done + in etrax_rh_init_int_timer. (Don't remove it from + etrax_rh_init_int_timer though.) */ + hc->rh.interval = urb->interval; + etrax_rh_init_int_timer(urb); + DBFEXIT; + + return 0; + } + + bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8); + wValue = le16_to_cpu(cmd->wValue); + wIndex = le16_to_cpu(cmd->wIndex); + wLength = le16_to_cpu(cmd->wLength); + + dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq); + dbg_rh("wValue : 0x%04x (%d)", wValue, wValue); + dbg_rh("wIndex : 0x%04x (%d)", wIndex, wIndex); + dbg_rh("wLength : 0x%04x (%d)", wLength, wLength); + + switch (bmRType_bReq) { + + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(__u16 *) data = cpu_to_le16 (1); + OK (2); + + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *) data = cpu_to_le16 (0); + OK (2); + + case RH_GET_STATUS | RH_CLASS: + *(__u32 *) data = cpu_to_le32 (0); + OK (4); /* hub power ** */ + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + if (wIndex == 1) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); + } else if (wIndex == 2) { + *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); + *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); + } else { + dbg_rh("RH_GET_STATUS whith invalid wIndex!"); + OK(0); + } + + OK(4); + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + OK (0); + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case (RH_C_HUB_OVER_CURRENT): + OK (0); /* hub power over current ** */ + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_ENABLE): + if (wIndex == 1) { + + dbg_rh("trying to do disable port 1"); + + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); + + while (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); + dbg_rh("Port 1 is disabled"); + + } else if (wIndex == 2) { + + dbg_rh("trying to do disable port 2"); + + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); + + while (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); + dbg_rh("Port 2 is disabled"); + + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " + "with invalid wIndex == %d!", wIndex); + } + + OK (0); + case (RH_PORT_SUSPEND): + /* Opposite to suspend should be resume, so we'll do a resume. */ + /* FIXME: USB 1.1, 11.16.2.2 says: + "Clearing the PORT_SUSPEND feature causes a host-initiated resume + on the specified port. If the port is not in the Suspended state, + the hub should treat this request as a functional no-operation." + Shouldn't we check if the port is in a suspended state before + resuming? */ + + /* Make sure the controller isn't busy. */ + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, resume) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, resume) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " + "with invalid wIndex == %d!", wIndex); + } + + OK (0); + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_C_PORT_CONNECTION): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); + } else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " + "with invalid wIndex == %d!", wIndex); + } + + OK (0); + case (RH_C_PORT_ENABLE): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); + } else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " + "with invalid wIndex == %d!", wIndex); + } + OK (0); + case (RH_C_PORT_SUSPEND): +/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ + OK (0); + case (RH_C_PORT_OVER_CURRENT): + OK (0); /* port power over current ** */ + case (RH_C_PORT_RESET): + if (wIndex == 1) { + hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); + } else if (wIndex == 2) { + hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); + } else { + dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " + "with invalid index == %d!", wIndex); + } + + OK (0); + + } + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_SUSPEND): + + /* Make sure the controller isn't busy. */ + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + if (wIndex == 1) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else if (wIndex == 2) { + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, suspend) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + } else { + dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND " + "with invalid wIndex == %d!", wIndex); + } + + OK (0); + case (RH_PORT_RESET): + if (wIndex == 1) { + + port_1_reset: + dbg_rh("Doing reset of port 1"); + + /* Make sure the controller isn't busy. */ + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port1) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + + /* We must wait at least 10 ms for the device to recover. + 15 ms should be enough. */ + udelay(15000); + + /* Wait for reset bit to go low (should be done by now). */ + while (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes)); + + /* If the port status is + 1) connected and enabled then there is a device and everything is fine + 2) neither connected nor enabled then there is no device, also fine + 3) connected and not enabled then we try again + (Yes, there are other port status combinations besides these.) */ + + if ((hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) && + (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) { + dbg_rh("Connected device on port 1, but port not enabled?" + " Trying reset again."); + goto port_2_reset; + } + + /* Diagnostic printouts. */ + if ((hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) && + (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) { + dbg_rh("No connected device on port 1"); + } else if ((hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) && + (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) { + dbg_rh("Connected device on port 1, port 1 enabled"); + } + + } else if (wIndex == 2) { + + port_2_reset: + dbg_rh("Doing reset of port 2"); + + /* Make sure the controller isn't busy. */ + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Issue the reset command. */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, port2) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); + + /* We must wait at least 10 ms for the device to recover. + 15 ms should be enough. */ + udelay(15000); + + /* Wait for reset bit to go low (should be done by now). */ + while (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes)); + + /* If the port status is + 1) connected and enabled then there is a device and everything is fine + 2) neither connected nor enabled then there is no device, also fine + 3) connected and not enabled then we try again + (Yes, there are other port status combinations besides these.) */ + + if ((hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) && + (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) { + dbg_rh("Connected device on port 2, but port not enabled?" + " Trying reset again."); + goto port_2_reset; + } + + /* Diagnostic printouts. */ + if ((hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) && + (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) { + dbg_rh("No connected device on port 2"); + } else if ((hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) && + (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) { + dbg_rh("Connected device on port 2, port 2 enabled"); + } + + } else { + dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex); + } + + /* Make sure the controller isn't busy. */ + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* If all enabled ports were disabled the host controller goes down into + started mode, so we need to bring it back into the running state. + (This is safe even if it's already in the running state.) */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, nop) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + dbg_rh("...Done"); + OK(0); + + case (RH_PORT_POWER): + OK (0); /* port power ** */ + case (RH_PORT_ENABLE): + /* There is no port enable command in the host controller, so if the + port is already enabled, we do nothing. If not, we reset the port + (with an ugly goto). */ + + if (wIndex == 1) { + if (hc->rh.prev_wPortStatus_1 & + IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) { + goto port_1_reset; + } + } else if (wIndex == 2) { + if (hc->rh.prev_wPortStatus_2 & + IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) { + goto port_2_reset; + } + } else { + dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex); + } + OK (0); + } + break; + + case RH_SET_ADDRESS: + hc->rh.devnum = wValue; + dbg_rh("RH address set to: %d", hc->rh.devnum); + OK (0); + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength)); + memcpy (data, root_hub_dev_des, len); + OK (len); + case (0x02): /* configuration descriptor */ + len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength)); + memcpy (data, root_hub_config_des, len); + OK (len); + case (0x03): /* string descriptors */ + len = usb_root_hub_string (wValue & 0xff, + 0xff, "ETRAX 100LX", + data, wLength); + if (len > 0) { + OK(min(leni, len)); + } else { + stat = -EPIPE; + } + + } + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + root_hub_hub_des[2] = hc->rh.numports; + len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength)); + memcpy (data, root_hub_hub_des, len); + OK (len); + + case RH_GET_CONFIGURATION: + *(__u8 *) data = 0x01; + OK (1); + + case RH_SET_CONFIGURATION: + OK (0); + + default: + stat = -EPIPE; + } + + urb->actual_length = len; + urb->status = stat; + urb->dev = NULL; + if (urb->complete) { + urb->complete(urb, NULL); + } + DBFEXIT; + + return 0; +} + +static void +etrax_usb_bulk_eot_timer_func(unsigned long dummy) +{ + /* Because of a race condition in the top half, we might miss a bulk eot. + This timer "simulates" a bulk eot if we don't get one for a while, hopefully + correcting the situation. */ + dbg_bulk("bulk_eot_timer timed out."); + etrax_usb_hc_bulk_eot_interrupt(1); +} + +static void* +etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma) +{ + return kmalloc(size, mem_flags); +} + +static void +etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma) +{ + kfree(addr); +} + + +static struct device fake_device; + +static int __init etrax_usb_hc_init(void) +{ + static etrax_hc_t *hc; + struct usb_bus *bus; + struct usb_device *usb_rh; + int i; + + DBFENTER; + + info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version); + + hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); + assert(hc != NULL); + + /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ + /* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate + SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) == + sizeof(USB_SB_Desc_t). */ + + usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, + SLAB_HWCACHE_ALIGN, 0, 0); + assert(usb_desc_cache != NULL); + + top_half_reg_cache = kmem_cache_create("top_half_reg_cache", + sizeof(usb_interrupt_registers_t), + 0, SLAB_HWCACHE_ALIGN, 0, 0); + assert(top_half_reg_cache != NULL); + + isoc_compl_cache = kmem_cache_create("isoc_compl_cache", + sizeof(usb_isoc_complete_data_t), + 0, SLAB_HWCACHE_ALIGN, 0, 0); + assert(isoc_compl_cache != NULL); + + etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); + hc->bus = bus; + bus->bus_name="ETRAX 100LX"; + bus->hcpriv = hc; + + /* Initialize RH to the default address. + And make sure that we have no status change indication */ + hc->rh.numports = 2; /* The RH has two ports */ + hc->rh.devnum = 1; + hc->rh.wPortChange_1 = 0; + hc->rh.wPortChange_2 = 0; + + /* Also initate the previous values to zero */ + hc->rh.prev_wPortStatus_1 = 0; + hc->rh.prev_wPortStatus_2 = 0; + + /* Initialize the intr-traffic flags */ + /* FIXME: This isn't used. (Besides, the error field isn't initialized.) */ + hc->intr.sleeping = 0; + hc->intr.wq = NULL; + + epid_usage_bitmask = 0; + epid_out_traffic = 0; + + /* Mark the invalid epid as being used. */ + set_bit(INVALID_EPID, (void *)&epid_usage_bitmask); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID); + nop(); + /* The valid bit should still be set ('invalid' is in our world; not the hardware's). */ + *R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) | + IO_FIELD(R_USB_EPT_DATA, max_len, 1)); + + /* Mark the dummy epid as being used. */ + set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask); + *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID); + nop(); + *R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) | + IO_FIELD(R_USB_EPT_DATA, max_len, 1)); + + /* Initialize the urb list by initiating a head for each list. */ + for (i = 0; i < NBR_OF_EPIDS; i++) { + INIT_LIST_HEAD(&urb_list[i]); + } + spin_lock_init(&urb_list_lock); + + INIT_LIST_HEAD(&urb_unlink_list); + + + /* Initiate the bulk start timer. */ + init_timer(&bulk_start_timer); + bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL; + bulk_start_timer.function = etrax_usb_bulk_start_timer_func; + add_timer(&bulk_start_timer); + + + /* Initiate the bulk eot timer. */ + init_timer(&bulk_eot_timer); + bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL; + bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func; + add_timer(&bulk_eot_timer); + + /* Set up the data structures for USB traffic. Note that this must be done before + any interrupt that relies on sane DMA list occurrs. */ + init_rx_buffers(); + init_tx_bulk_ep(); + init_tx_ctrl_ep(); + init_tx_intr_ep(); + init_tx_isoc_ep(); + + device_initialize(&fake_device); + kobject_set_name(&fake_device.kobj, "etrax_usb"); + kobject_add(&fake_device.kobj); + kobject_uevent(&fake_device.kobj, KOBJ_ADD); + hc->bus->controller = &fake_device; + usb_register_bus(hc->bus); + + *R_IRQ_MASK2_SET = + /* Note that these interrupts are not used. */ + IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | + /* Sub channel 1 (ctrl) descr. interrupts are used. */ + IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | + IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | + /* Sub channel 3 (isoc) descr. interrupts are used. */ + IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); + + /* Note that the dma9_descr interrupt is not used. */ + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); + + /* FIXME: Enable iso_eof only when isoc traffic is running. */ + *R_USB_IRQ_MASK_SET = + IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) | + IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) | + IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | + IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) | + IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set); + + + if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0, + "ETRAX 100LX built-in USB (HC)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, + "ETRAX 100LX built-in USB (Rx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0, + "ETRAX 100LX built-in USB (Tx)", hc)) { + err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ); + etrax_usb_hc_cleanup(); + DBFEXIT; + return -1; + } + + /* R_USB_COMMAND: + USB commands in host mode. The fields in this register should all be + written to in one write. Do not read-modify-write one field at a time. A + write to this register will trigger events in the USB controller and an + incomplete command may lead to unpredictable results, and in worst case + even to a deadlock in the controller. + (Note however that the busy field is read-only, so no need to write to it.) */ + + /* Check the busy bit before writing to R_USB_COMMAND. */ + + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Reset the USB interface. */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, nop) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, reset); + + /* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800), + to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may + allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation. + + While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK + behaviour, it doesn't solve this problem. What happens is that a control transfer will not + be interrupted in its data stage when PSTART happens (the point at which periodic traffic + is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before + PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done, + there may be too little time left for an isochronous transfer, causing an epid attention + interrupt due to perror. The work-around for this is to let the control transfers run at the + end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't + fit into the frame. However, since there will *always* be a control transfer at the beginning + of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer + which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to + this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make + sure that the periodic transfers that are inserted will always fit in the frame. + + The idea was suggested that a control transfer could be split up into several 8 byte transfers, + so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this + hasn't been implemented. + + The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra + for possible bit stuffing. */ + + *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960); + +#ifdef CONFIG_ETRAX_USB_HOST_PORT1 + *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); +#endif + +#ifdef CONFIG_ETRAX_USB_HOST_PORT2 + *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); +#endif + + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Configure the USB interface as a host controller. */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, nop) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config); + + /* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled + sequence of resetting the ports. If we reset both ports now, and there are devices + on both ports, we will get a bus error because both devices will answer the set address + request. */ + + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + /* Start processing of USB traffic. */ + *R_USB_COMMAND = + IO_STATE(R_USB_COMMAND, port_sel, nop) | + IO_STATE(R_USB_COMMAND, port_cmd, reset) | + IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); + + while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); + + usb_rh = usb_alloc_dev(NULL, hc->bus, 0); + hc->bus->root_hub = usb_rh; + usb_rh->state = USB_STATE_ADDRESS; + usb_rh->speed = USB_SPEED_FULL; + usb_rh->devnum = 1; + hc->bus->devnum_next = 2; + usb_rh->ep0.desc.wMaxPacketSize = __const_cpu_to_le16(64); + usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE); + usb_new_device(usb_rh); + + DBFEXIT; + + return 0; +} + +static void etrax_usb_hc_cleanup(void) +{ + DBFENTER; + + free_irq(ETRAX_USB_HC_IRQ, NULL); + free_irq(ETRAX_USB_RX_IRQ, NULL); + free_irq(ETRAX_USB_TX_IRQ, NULL); + + usb_deregister_bus(etrax_usb_bus); + + /* FIXME: call kmem_cache_destroy here? */ + + DBFEXIT; +} + +module_init(etrax_usb_hc_init); +module_exit(etrax_usb_hc_cleanup); diff --git a/trunk/drivers/usb/host/hc_crisv10.h b/trunk/drivers/usb/host/hc_crisv10.h new file mode 100644 index 000000000000..62f77111d418 --- /dev/null +++ b/trunk/drivers/usb/host/hc_crisv10.h @@ -0,0 +1,289 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H + +#include +#include + +typedef struct USB_IN_Desc { + volatile __u16 sw_len; + volatile __u16 command; + volatile unsigned long next; + volatile unsigned long buf; + volatile __u16 hw_len; + volatile __u16 status; +} USB_IN_Desc_t; + +typedef struct USB_SB_Desc { + volatile __u16 sw_len; + volatile __u16 command; + volatile unsigned long next; + volatile unsigned long buf; + __u32 dummy; +} USB_SB_Desc_t; + +typedef struct USB_EP_Desc { + volatile __u16 hw_len; + volatile __u16 command; + volatile unsigned long sub; + volatile unsigned long next; + __u32 dummy; +} USB_EP_Desc_t; + +struct virt_root_hub { + int devnum; + void *urb; + void *int_addr; + int send; + int interval; + int numports; + struct timer_list rh_int_timer; + volatile __u16 wPortChange_1; + volatile __u16 wPortChange_2; + volatile __u16 prev_wPortStatus_1; + volatile __u16 prev_wPortStatus_2; +}; + +struct etrax_usb_intr_traffic { + int sleeping; + int error; + struct wait_queue *wq; +}; + +typedef struct etrax_usb_hc { + struct usb_bus *bus; + struct virt_root_hub rh; + struct etrax_usb_intr_traffic intr; +} etrax_hc_t; + +typedef enum { + STARTED, + NOT_STARTED, + UNLINK, + TRANSFER_DONE, + WAITING_FOR_DESCR_INTR +} etrax_usb_urb_state_t; + + + +typedef struct etrax_usb_urb_priv { + /* The first_sb field is used for freeing all SB descriptors belonging + to an urb. The corresponding ep descriptor's sub pointer cannot be + used for this since the DMA advances the sub pointer as it processes + the sb list. */ + USB_SB_Desc_t *first_sb; + /* The last_sb field referes to the last SB descriptor that belongs to + this urb. This is important to know so we can free the SB descriptors + that ranges between first_sb and last_sb. */ + USB_SB_Desc_t *last_sb; + + /* The rx_offset field is used in ctrl and bulk traffic to keep track + of the offset in the urb's transfer_buffer where incoming data should be + copied to. */ + __u32 rx_offset; + + /* Counter used in isochronous transfers to keep track of the + number of packets received/transmitted. */ + __u32 isoc_packet_counter; + + /* This field is used to pass information about the urb's current state between + the various interrupt handlers (thus marked volatile). */ + volatile etrax_usb_urb_state_t urb_state; + + /* Connection between the submitted urb and ETRAX epid number */ + __u8 epid; + + /* The rx_data_list field is used for periodic traffic, to hold + received data for later processing in the the complete_urb functions, + where the data us copied to the urb's transfer_buffer. Basically, we + use this intermediate storage because we don't know when it's safe to + reuse the transfer_buffer (FIXME?). */ + struct list_head rx_data_list; +} etrax_urb_priv_t; + +/* This struct is for passing data from the top half to the bottom half. */ +typedef struct usb_interrupt_registers +{ + etrax_hc_t *hc; + __u32 r_usb_epid_attn; + __u8 r_usb_status; + __u16 r_usb_rh_port_status_1; + __u16 r_usb_rh_port_status_2; + __u32 r_usb_irq_mask_read; + __u32 r_usb_fm_number; + struct work_struct usb_bh; +} usb_interrupt_registers_t; + +/* This struct is for passing data from the isoc top half to the isoc bottom half. */ +typedef struct usb_isoc_complete_data +{ + struct urb *urb; + struct work_struct usb_bh; +} usb_isoc_complete_data_t; + +/* This struct holds data we get from the rx descriptors for DMA channel 9 + for periodic traffic (intr and isoc). */ +typedef struct rx_data +{ + void *data; + int length; + struct list_head list; +} rx_data_t; + +typedef struct urb_entry +{ + struct urb *urb; + struct list_head list; +} urb_entry_t; + +/* --------------------------------------------------------------------------- + Virtual Root HUB + ------------------------------------------------------------------------- */ +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +/* Field definitions for */ + +#define USB_IN_command__eol__BITNR 0 /* command macros */ +#define USB_IN_command__eol__WIDTH 1 +#define USB_IN_command__eol__no 0 +#define USB_IN_command__eol__yes 1 + +#define USB_IN_command__intr__BITNR 3 +#define USB_IN_command__intr__WIDTH 1 +#define USB_IN_command__intr__no 0 +#define USB_IN_command__intr__yes 1 + +#define USB_IN_status__eop__BITNR 1 /* status macros. */ +#define USB_IN_status__eop__WIDTH 1 +#define USB_IN_status__eop__no 0 +#define USB_IN_status__eop__yes 1 + +#define USB_IN_status__eot__BITNR 5 +#define USB_IN_status__eot__WIDTH 1 +#define USB_IN_status__eot__no 0 +#define USB_IN_status__eot__yes 1 + +#define USB_IN_status__error__BITNR 6 +#define USB_IN_status__error__WIDTH 1 +#define USB_IN_status__error__no 0 +#define USB_IN_status__error__yes 1 + +#define USB_IN_status__nodata__BITNR 7 +#define USB_IN_status__nodata__WIDTH 1 +#define USB_IN_status__nodata__no 0 +#define USB_IN_status__nodata__yes 1 + +#define USB_IN_status__epid__BITNR 8 +#define USB_IN_status__epid__WIDTH 5 + +#define USB_EP_command__eol__BITNR 0 +#define USB_EP_command__eol__WIDTH 1 +#define USB_EP_command__eol__no 0 +#define USB_EP_command__eol__yes 1 + +#define USB_EP_command__eof__BITNR 1 +#define USB_EP_command__eof__WIDTH 1 +#define USB_EP_command__eof__no 0 +#define USB_EP_command__eof__yes 1 + +#define USB_EP_command__intr__BITNR 3 +#define USB_EP_command__intr__WIDTH 1 +#define USB_EP_command__intr__no 0 +#define USB_EP_command__intr__yes 1 + +#define USB_EP_command__enable__BITNR 4 +#define USB_EP_command__enable__WIDTH 1 +#define USB_EP_command__enable__no 0 +#define USB_EP_command__enable__yes 1 + +#define USB_EP_command__hw_valid__BITNR 5 +#define USB_EP_command__hw_valid__WIDTH 1 +#define USB_EP_command__hw_valid__no 0 +#define USB_EP_command__hw_valid__yes 1 + +#define USB_EP_command__epid__BITNR 8 +#define USB_EP_command__epid__WIDTH 5 + +#define USB_SB_command__eol__BITNR 0 /* command macros. */ +#define USB_SB_command__eol__WIDTH 1 +#define USB_SB_command__eol__no 0 +#define USB_SB_command__eol__yes 1 + +#define USB_SB_command__eot__BITNR 1 +#define USB_SB_command__eot__WIDTH 1 +#define USB_SB_command__eot__no 0 +#define USB_SB_command__eot__yes 1 + +#define USB_SB_command__intr__BITNR 3 +#define USB_SB_command__intr__WIDTH 1 +#define USB_SB_command__intr__no 0 +#define USB_SB_command__intr__yes 1 + +#define USB_SB_command__tt__BITNR 4 +#define USB_SB_command__tt__WIDTH 2 +#define USB_SB_command__tt__zout 0 +#define USB_SB_command__tt__in 1 +#define USB_SB_command__tt__out 2 +#define USB_SB_command__tt__setup 3 + + +#define USB_SB_command__rem__BITNR 8 +#define USB_SB_command__rem__WIDTH 6 + +#define USB_SB_command__full__BITNR 6 +#define USB_SB_command__full__WIDTH 1 +#define USB_SB_command__full__no 0 +#define USB_SB_command__full__yes 1 + +#endif diff --git a/trunk/drivers/usb/host/ohci-hcd.c b/trunk/drivers/usb/host/ohci-hcd.c index e8bbe8bc2598..f0d29eda3c6d 100644 --- a/trunk/drivers/usb/host/ohci-hcd.c +++ b/trunk/drivers/usb/host/ohci-hcd.c @@ -486,6 +486,9 @@ static int ohci_run (struct ohci_hcd *ohci) * or if bus glue did the same (e.g. for PCI add-in cards with * PCI PM support). */ + ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n", + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), + ohci_readl (ohci, &ohci->regs->control)); if ((ohci->hc_control & OHCI_CTRL_RWC) != 0 && !device_may_wakeup(hcd->self.controller)) device_init_wakeup(hcd->self.controller, 1); @@ -741,6 +744,9 @@ static void ohci_stop (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); + ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n", + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), + hcd->state); ohci_dump (ohci, 1); flush_scheduled_work(); diff --git a/trunk/drivers/usb/host/ohci-pci.c b/trunk/drivers/usb/host/ohci-pci.c index 79705609fd0c..b331ac4d0d62 100644 --- a/trunk/drivers/usb/host/ohci-pci.c +++ b/trunk/drivers/usb/host/ohci-pci.c @@ -20,16 +20,10 @@ /*-------------------------------------------------------------------------*/ -static int broken_suspend(struct usb_hcd *hcd) -{ - device_init_wakeup(&hcd->self.root_hub->dev, 0); - return 0; -} - /* AMD 756, for most chips (early revs), corrupts register * values on read ... so enable the vendor workaround. */ -static int ohci_quirk_amd756(struct usb_hcd *hcd) +static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -37,14 +31,16 @@ static int ohci_quirk_amd756(struct usb_hcd *hcd) ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); /* also erratum 10 (suspend/resume issues) */ - return broken_suspend(hcd); + device_init_wakeup(&hcd->self.root_hub->dev, 0); + + return 0; } /* Apple's OHCI driver has a lot of bizarre workarounds * for this chip. Evidently control and bulk lists * can get confused. (B&W G3 models, and ...) */ -static int ohci_quirk_opti(struct usb_hcd *hcd) +static int __devinit ohci_quirk_opti(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -57,7 +53,7 @@ static int ohci_quirk_opti(struct usb_hcd *hcd) * identify the USB (fn2). This quirk might apply to more or * even all NSC stuff. */ -static int ohci_quirk_ns(struct usb_hcd *hcd) +static int __devinit ohci_quirk_ns(struct usb_hcd *hcd) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct pci_dev *b; @@ -79,7 +75,7 @@ static int ohci_quirk_ns(struct usb_hcd *hcd) * delays before control or bulk queues get re-activated * in finish_unlinks() */ -static int ohci_quirk_zfmicro(struct usb_hcd *hcd) +static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -92,7 +88,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) /* Check for Toshiba SCC OHCI which has big endian registers * and little endian in memory data structures */ -static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) +static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -133,18 +129,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), .driver_data = (unsigned long)ohci_quirk_toshiba_scc, }, - { - /* Toshiba portege 4000 */ - .vendor = PCI_VENDOR_ID_AL, - .device = 0x5237, - .subvendor = PCI_VENDOR_ID_TOSHIBA_2, - .subdevice = 0x0004, - .driver_data = (unsigned long) broken_suspend, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152), - .driver_data = (unsigned long) broken_suspend, - }, /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. */ diff --git a/trunk/drivers/usb/host/uhci-q.c b/trunk/drivers/usb/host/uhci-q.c index 4aed305982ec..19a0cc02b9a2 100644 --- a/trunk/drivers/usb/host/uhci-q.c +++ b/trunk/drivers/usb/host/uhci-q.c @@ -123,14 +123,10 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) { - if (!list_empty(&td->list)) { + if (!list_empty(&td->list)) dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); - WARN_ON(1); - } - if (!list_empty(&td->fl_list)) { + if (!list_empty(&td->fl_list)) dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); - WARN_ON(1); - } dma_pool_free(uhci->td_pool, td, td->dma_handle); } @@ -295,10 +291,8 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { WARN_ON(qh->state != QH_STATE_IDLE && qh->udev); - if (!list_empty(&qh->queue)) { + if (!list_empty(&qh->queue)) dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh); - WARN_ON(1); - } list_del(&qh->node); if (qh->udev) { @@ -746,11 +740,9 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, { struct uhci_td *td, *tmp; - if (!list_empty(&urbp->node)) { + if (!list_empty(&urbp->node)) dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", urbp->urb); - WARN_ON(1); - } list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { uhci_remove_td_from_urbp(td); diff --git a/trunk/drivers/usb/input/Kconfig b/trunk/drivers/usb/input/Kconfig index a792e42f58af..69a9f3b6d0a9 100644 --- a/trunk/drivers/usb/input/Kconfig +++ b/trunk/drivers/usb/input/Kconfig @@ -4,6 +4,151 @@ comment "USB Input Devices" depends on USB +config USB_HID + tristate "USB Human Interface Device (full HID) support" + default y + depends on USB && INPUT + select HID + ---help--- + Say Y here if you want full HID support to connect USB keyboards, + mice, joysticks, graphic tablets, or any other HID based devices + to your computer via USB, as well as Uninterruptible Power Supply + (UPS) and monitor control devices. + + You can't use this driver and the HIDBP (Boot Protocol) keyboard + and mouse drivers at the same time. More information is available: + . + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called usbhid. + +comment "Input core support is needed for USB HID input layer or HIDBP support" + depends on USB_HID && INPUT=n + +config USB_HIDINPUT_POWERBOOK + bool "Enable support for iBook/PowerBook special keys" + default n + depends on USB_HID + help + Say Y here if you want support for the special keys (Fn, Numlock) on + Apple iBooks and PowerBooks. + + If unsure, say N. + +config HID_FF + bool "Force feedback support (EXPERIMENTAL)" + depends on USB_HID && EXPERIMENTAL + help + Say Y here is you want force feedback support for a few HID devices. + See below for a list of supported devices. + + See for a description of the force + feedback API. + + If unsure, say N. + +config HID_PID + bool "PID device support" + depends on HID_FF + help + Say Y here if you have a PID-compliant device and wish to enable force + feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such + devices. + +config LOGITECH_FF + bool "Logitech devices support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have one of these devices: + - Logitech WingMan Cordless RumblePad + - Logitech WingMan Cordless RumblePad 2 + - Logitech WingMan Force 3D + - Logitech Formula Force EX + - Logitech MOMO Force wheel + + and if you want to enable force feedback for them. + Note: if you say N here, this device will still be supported, but without + force feedback. + +config PANTHERLORD_FF + bool "PantherLord USB/PS2 2in1 Adapter support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want + to enable force feedback support for it. + +config THRUSTMASTER_FF + bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" + depends on HID_FF && EXPERIMENTAL + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, + and want to enable force feedback support for it. + Note: if you say N here, this device will still be supported, but without + force feedback. + +config ZEROPLUS_FF + bool "Zeroplus based game controller support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a Zeroplus based game controller and want to + enable force feedback for it. + +config USB_HIDDEV + bool "/dev/hiddev raw HID device support" + depends on USB_HID + help + Say Y here if you want to support HID devices (from the USB + specification standpoint) that aren't strictly user interface + devices, like monitor controls and Uninterruptable Power Supplies. + + This module supports these devices separately using a separate + event interface on /dev/usb/hiddevX (char 180:96 to 180:111). + + If unsure, say Y. + +menu "USB HID Boot Protocol drivers" + depends on USB!=n && USB_HID!=y + +config USB_KBD + tristate "USB HIDBP Keyboard (simple Boot) support" + depends on USB && INPUT + ---help--- + Say Y here only if you are absolutely sure that you don't want + to use the generic HID driver for your USB keyboard and prefer + to use the keyboard in its limited Boot Protocol mode instead. + + This is almost certainly not what you want. This is mostly + useful for embedded applications or simple keyboards. + + To compile this driver as a module, choose M here: the + module will be called usbkbd. + + If even remotely unsure, say N. + +config USB_MOUSE + tristate "USB HIDBP Mouse (simple Boot) support" + depends on USB && INPUT + ---help--- + Say Y here only if you are absolutely sure that you don't want + to use the generic HID driver for your USB mouse and prefer + to use the mouse in its limited Boot Protocol mode instead. + + This is almost certainly not what you want. This is mostly + useful for embedded applications or simple mice. + + To compile this driver as a module, choose M here: the + module will be called usbmouse. + + If even remotely unsure, say N. + +endmenu + config USB_AIPTEK tristate "Aiptek 6000U/8000U tablet support" depends on USB && INPUT diff --git a/trunk/drivers/usb/input/Makefile b/trunk/drivers/usb/input/Makefile index 284a0734e0cd..a9d206c945e9 100644 --- a/trunk/drivers/usb/input/Makefile +++ b/trunk/drivers/usb/input/Makefile @@ -4,12 +4,43 @@ # Multipart objects. wacom-objs := wacom_wac.o wacom_sys.o +usbhid-objs := hid-core.o + +# Optional parts of multipart objects. + +ifeq ($(CONFIG_USB_HIDDEV),y) + usbhid-objs += hiddev.o +endif +ifeq ($(CONFIG_HID_PID),y) + usbhid-objs += hid-pidff.o +endif +ifeq ($(CONFIG_LOGITECH_FF),y) + usbhid-objs += hid-lgff.o +endif +ifeq ($(CONFIG_PANTHERLORD_FF),y) + usbhid-objs += hid-plff.o +endif +ifeq ($(CONFIG_THRUSTMASTER_FF),y) + usbhid-objs += hid-tmff.o +endif +ifeq ($(CONFIG_ZEROPLUS_FF),y) + usbhid-objs += hid-zpff.o +endif +ifeq ($(CONFIG_HID_FF),y) + usbhid-objs += hid-ff.o +endif obj-$(CONFIG_USB_AIPTEK) += aiptek.o obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o +obj-$(CONFIG_USB_HID) += usbhid.o +obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o +obj-$(CONFIG_USB_MOUSE) += usbmouse.o +obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o +obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o +obj-$(CONFIG_USB_EGALAX) += touchkitusb.o obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o @@ -17,7 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o -obj-$(CONFIG_USB_GTCO) += gtco.o +obj-$(CONFIG_USB_GTCO) += gtco.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/trunk/drivers/usb/input/acecad.c b/trunk/drivers/usb/input/acecad.c index be8e9243c062..909138e5aa04 100644 --- a/trunk/drivers/usb/input/acecad.c +++ b/trunk/drivers/usb/input/acecad.c @@ -111,7 +111,7 @@ static void usb_acecad_irq(struct urb *urb) static int usb_acecad_open(struct input_dev *dev) { - struct usb_acecad *acecad = input_get_drvdata(dev); + struct usb_acecad *acecad = dev->private; acecad->irq->dev = acecad->usbdev; if (usb_submit_urb(acecad->irq, GFP_KERNEL)) @@ -122,7 +122,7 @@ static int usb_acecad_open(struct input_dev *dev) static void usb_acecad_close(struct input_dev *dev) { - struct usb_acecad *acecad = input_get_drvdata(dev); + struct usb_acecad *acecad = dev->private; usb_kill_urb(acecad->irq); } @@ -135,7 +135,6 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ struct usb_acecad *acecad; struct input_dev *input_dev; int pipe, maxp; - int err = -ENOMEM; if (interface->desc.bNumEndpoints != 1) return -ENODEV; @@ -150,22 +149,16 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL); input_dev = input_allocate_device(); - if (!acecad || !input_dev) { - err = -ENOMEM; + if (!acecad || !input_dev) goto fail1; - } acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma); - if (!acecad->data) { - err= -ENOMEM; + if (!acecad->data) goto fail1; - } acecad->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!acecad->irq) { - err = -ENOMEM; + if (!acecad->irq) goto fail2; - } acecad->usbdev = dev; acecad->input = input_dev; @@ -185,9 +178,8 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ input_dev->name = acecad->name; input_dev->phys = acecad->phys; usb_to_input_id(dev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, acecad); + input_dev->cdev.dev = &intf->dev; + input_dev->private = acecad; input_dev->open = usb_acecad_open; input_dev->close = usb_acecad_close; @@ -229,9 +221,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ acecad->irq->transfer_dma = acecad->data_dma; acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - err = input_register_device(acecad->input); - if (err) - goto fail2; + input_register_device(acecad->input); usb_set_intfdata(intf, acecad); @@ -240,7 +230,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma); fail1: input_free_device(input_dev); kfree(acecad); - return err; + return -ENOMEM; } static void usb_acecad_disconnect(struct usb_interface *intf) diff --git a/trunk/drivers/usb/input/aiptek.c b/trunk/drivers/usb/input/aiptek.c index cc0a498763d8..f857935e615c 100644 --- a/trunk/drivers/usb/input/aiptek.c +++ b/trunk/drivers/usb/input/aiptek.c @@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(usb, aiptek_ids); */ static int aiptek_open(struct input_dev *inputdev) { - struct aiptek *aiptek = input_get_drvdata(inputdev); + struct aiptek *aiptek = inputdev->private; aiptek->urb->dev = aiptek->usbdev; if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) @@ -812,7 +812,7 @@ static int aiptek_open(struct input_dev *inputdev) */ static void aiptek_close(struct input_dev *inputdev) { - struct aiptek *aiptek = input_get_drvdata(inputdev); + struct aiptek *aiptek = inputdev->private; usb_kill_urb(aiptek->urb); } @@ -1972,7 +1972,6 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) AIPTEK_PROGRAMMABLE_DELAY_200, AIPTEK_PROGRAMMABLE_DELAY_300 }; - int err = -ENOMEM; /* programmableDelay is where the command-line specified * delay is kept. We make it the first element of speeds[], @@ -2044,10 +2043,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) inputdev->name = "Aiptek"; inputdev->phys = aiptek->features.usbPath; usb_to_input_id(usbdev, &inputdev->id); - inputdev->dev.parent = &intf->dev; - - input_set_drvdata(inputdev, aiptek); - + inputdev->cdev.dev = &intf->dev; + inputdev->private = aiptek; inputdev->open = aiptek_open; inputdev->close = aiptek_close; @@ -2136,9 +2133,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Register the tablet as an Input Device */ - err = input_register_device(aiptek->inputdev); - if (err) - goto fail2; + input_register_device(aiptek->inputdev); /* We now will look for the evdev device which is mapped to * the tablet. The partial name is kept in the link list of @@ -2170,13 +2165,23 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) return 0; - fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, +fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); - fail1: input_free_device(inputdev); +fail1: input_free_device(inputdev); kfree(aiptek); - return err; + return -ENOMEM; } +/* Forward declaration */ +static void aiptek_disconnect(struct usb_interface *intf); + +static struct usb_driver aiptek_driver = { + .name = "aiptek", + .probe = aiptek_probe, + .disconnect = aiptek_disconnect, + .id_table = aiptek_ids, +}; + /*********************************************************************** * Deal with tablet disconnecting from the system. */ @@ -2201,13 +2206,6 @@ static void aiptek_disconnect(struct usb_interface *intf) } } -static struct usb_driver aiptek_driver = { - .name = "aiptek", - .probe = aiptek_probe, - .disconnect = aiptek_disconnect, - .id_table = aiptek_ids, -}; - static int __init aiptek_init(void) { int result = usb_register(&aiptek_driver); diff --git a/trunk/drivers/usb/input/appletouch.c b/trunk/drivers/usb/input/appletouch.c index e3215267db11..c77291d3d063 100644 --- a/trunk/drivers/usb/input/appletouch.c +++ b/trunk/drivers/usb/input/appletouch.c @@ -466,7 +466,7 @@ static void atp_complete(struct urb* urb) static int atp_open(struct input_dev *input) { - struct atp *dev = input_get_drvdata(input); + struct atp *dev = input->private; if (usb_submit_urb(dev->urb, GFP_ATOMIC)) return -EIO; @@ -477,7 +477,7 @@ static int atp_open(struct input_dev *input) static void atp_close(struct input_dev *input) { - struct atp *dev = input_get_drvdata(input); + struct atp *dev = input->private; usb_kill_urb(dev->urb); dev->open = 0; @@ -491,7 +491,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int int_in_endpointAddr = 0; - int i, error = -ENOMEM; + int i, retval = -ENOMEM; + /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ @@ -566,13 +567,17 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id } dev->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urb) + if (!dev->urb) { + retval = -ENOMEM; goto err_free_devs; + } dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, &dev->urb->transfer_dma); - if (!dev->data) + if (!dev->data) { + retval = -ENOMEM; goto err_free_urb; + } usb_fill_int_urb(dev->urb, udev, usb_rcvintpipe(udev, int_in_endpointAddr), @@ -584,10 +589,9 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id input_dev->name = "appletouch"; input_dev->phys = dev->phys; usb_to_input_id(dev->udev, &input_dev->id); - input_dev->dev.parent = &iface->dev; - - input_set_drvdata(input_dev, dev); + input_dev->cdev.dev = &iface->dev; + input_dev->private = dev; input_dev->open = atp_open; input_dev->close = atp_close; @@ -629,25 +633,20 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); set_bit(BTN_LEFT, input_dev->keybit); - error = input_register_device(dev->input); - if (error) - goto err_free_buffer; + input_register_device(dev->input); /* save our data pointer in this interface device */ usb_set_intfdata(iface, dev); return 0; - err_free_buffer: - usb_buffer_free(dev->udev, dev->datalen, - dev->data, dev->urb->transfer_dma); err_free_urb: usb_free_urb(dev->urb); err_free_devs: usb_set_intfdata(iface, NULL); kfree(dev); input_free_device(input_dev); - return error; + return retval; } static void atp_disconnect(struct usb_interface *iface) diff --git a/trunk/drivers/usb/input/ati_remote.c b/trunk/drivers/usb/input/ati_remote.c index 471aab206443..b724e36f7b92 100644 --- a/trunk/drivers/usb/input/ati_remote.c +++ b/trunk/drivers/usb/input/ati_remote.c @@ -120,7 +120,6 @@ * behaviour. */ #define FILTER_TIME 60 /* msec */ -#define REPEAT_DELAY 500 /* msec */ static unsigned long channel_mask; module_param(channel_mask, ulong, 0644); @@ -134,10 +133,6 @@ static int repeat_filter = FILTER_TIME; module_param(repeat_filter, int, 0644); MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); -static int repeat_delay = REPEAT_DELAY; -module_param(repeat_delay, int, 0644); -MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); - #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) @@ -179,8 +174,6 @@ struct ati_remote { unsigned char old_data[2]; /* Detect duplicate events */ unsigned long old_jiffies; unsigned long acc_jiffies; /* handle acceleration */ - unsigned long first_jiffies; - unsigned int repeat_count; char name[NAME_BUFSIZE]; @@ -325,7 +318,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len) */ static int ati_remote_open(struct input_dev *inputdev) { - struct ati_remote *ati_remote = input_get_drvdata(inputdev); + struct ati_remote *ati_remote = inputdev->private; /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; @@ -343,7 +336,7 @@ static int ati_remote_open(struct input_dev *inputdev) */ static void ati_remote_close(struct input_dev *inputdev) { - struct ati_remote *ati_remote = input_get_drvdata(inputdev); + struct ati_remote *ati_remote = inputdev->private; usb_kill_urb(ati_remote->irq_urb); } @@ -508,31 +501,21 @@ static void ati_remote_input_report(struct urb *urb) } if (ati_remote_tbl[index].kind == KIND_FILTERED) { - unsigned long now = jiffies; - /* Filter duplicate events which happen "too close" together. */ if (ati_remote->old_data[0] == data[1] && ati_remote->old_data[1] == data[2] && - time_before(now, ati_remote->old_jiffies + - msecs_to_jiffies(repeat_filter))) { + time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) { ati_remote->repeat_count++; } else { ati_remote->repeat_count = 0; - ati_remote->first_jiffies = now; } ati_remote->old_data[0] = data[1]; ati_remote->old_data[1] = data[2]; - ati_remote->old_jiffies = now; + ati_remote->old_jiffies = jiffies; - /* Ensure we skip at least the 4 first duplicate events (generated - * by a single keypress), and continue skipping until repeat_delay - * msecs have passed - */ if (ati_remote->repeat_count > 0 && - (ati_remote->repeat_count < 5 || - time_before(now, ati_remote->first_jiffies + - msecs_to_jiffies(repeat_delay)))) + ati_remote->repeat_count < 5) return; @@ -670,8 +653,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) if (ati_remote_tbl[i].type == EV_KEY) set_bit(ati_remote_tbl[i].code, idev->keybit); - input_set_drvdata(idev, ati_remote); - + idev->private = ati_remote; idev->open = ati_remote_open; idev->close = ati_remote_close; @@ -679,7 +661,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->phys = ati_remote->phys; usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev.parent = &ati_remote->udev->dev; + idev->cdev.dev = &ati_remote->udev->dev; } static int ati_remote_initialize(struct ati_remote *ati_remote) @@ -790,17 +772,15 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de goto fail3; /* Set up and register input device */ - err = input_register_device(ati_remote->idev); - if (err) - goto fail3; + input_register_device(ati_remote->idev); usb_set_intfdata(interface, ati_remote); return 0; - fail3: usb_kill_urb(ati_remote->irq_urb); +fail3: usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); - fail2: ati_remote_free_buffers(ati_remote); - fail1: input_free_device(input_dev); +fail2: ati_remote_free_buffers(ati_remote); +fail1: input_free_device(input_dev); kfree(ati_remote); return err; } diff --git a/trunk/drivers/usb/input/ati_remote2.c b/trunk/drivers/usb/input/ati_remote2.c index a9032aa3465f..83f1f79db7c7 100644 --- a/trunk/drivers/usb/input/ati_remote2.c +++ b/trunk/drivers/usb/input/ati_remote2.c @@ -2,7 +2,6 @@ * ati_remote2 - ATI/Philips USB RF remote driver * * Copyright (C) 2005 Ville Syrjala - * Copyright (C) 2007 Peter Stokes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -12,29 +11,13 @@ #include #define DRIVER_DESC "ATI/Philips USB RF remote driver" -#define DRIVER_VERSION "0.2" +#define DRIVER_VERSION "0.1" MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR("Ville Syrjala "); MODULE_LICENSE("GPL"); -/* - * ATI Remote Wonder II Channel Configuration - * - * The remote control can by assigned one of sixteen "channels" in order to facilitate - * the use of multiple remote controls within range of each other. - * A remote's "channel" may be altered by pressing and holding the "PC" button for - * approximately 3 seconds, after which the button will slowly flash the count of the - * currently configured "channel", using the numeric keypad enter a number between 1 and - * 16 and then the "PC" button again, the button will slowly flash the count of the - * newly configured "channel". - */ - -static unsigned int channel_mask = 0xFFFF; -module_param(channel_mask, uint, 0644); -MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>"); - static unsigned int mode_mask = 0x1F; module_param(mode_mask, uint, 0644); MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>"); @@ -131,7 +114,7 @@ static struct usb_driver ati_remote2_driver = { static int ati_remote2_open(struct input_dev *idev) { - struct ati_remote2 *ar2 = input_get_drvdata(idev); + struct ati_remote2 *ar2 = idev->private; int r; r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); @@ -153,7 +136,7 @@ static int ati_remote2_open(struct input_dev *idev) static void ati_remote2_close(struct input_dev *idev) { - struct ati_remote2 *ar2 = input_get_drvdata(idev); + struct ati_remote2 *ar2 = idev->private; usb_kill_urb(ar2->urb[0]); usb_kill_urb(ar2->urb[1]); @@ -163,23 +146,15 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2) { struct input_dev *idev = ar2->idev; u8 *data = ar2->buf[0]; - int channel, mode; - - channel = data[0] >> 4; - - if (!((1 << channel) & channel_mask)) - return; - mode = data[0] & 0x0F; - - if (mode > 4) { + if (data[0] > 4) { dev_err(&ar2->intf[0]->dev, "Unknown mode byte (%02x %02x %02x %02x)\n", data[3], data[2], data[1], data[0]); return; } - if (!((1 << mode) & mode_mask)) + if (!((1 << data[0]) & mode_mask)) return; input_event(idev, EV_REL, REL_X, (s8) data[1]); @@ -202,16 +177,9 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) { struct input_dev *idev = ar2->idev; u8 *data = ar2->buf[1]; - int channel, mode, hw_code, index; - - channel = data[0] >> 4; - - if (!((1 << channel) & channel_mask)) - return; + int hw_code, index; - mode = data[0] & 0x0F; - - if (mode > 4) { + if (data[0] > 4) { dev_err(&ar2->intf[1]->dev, "Unknown mode byte (%02x %02x %02x %02x)\n", data[3], data[2], data[1], data[0]); @@ -231,16 +199,16 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) * events for the mouse pad so we filter out any subsequent * events from the same mode key. */ - if (ar2->mode == mode) + if (ar2->mode == data[0]) return; if (data[1] == 0) - ar2->mode = mode; + ar2->mode = data[0]; - hw_code |= mode << 8; + hw_code |= data[0] << 8; } - if (!((1 << mode) & mode_mask)) + if (!((1 << data[0]) & mode_mask)) return; index = ati_remote2_lookup(hw_code); @@ -337,14 +305,14 @@ static void ati_remote2_complete_key(struct urb *urb) static int ati_remote2_input_init(struct ati_remote2 *ar2) { struct input_dev *idev; - int i, retval; + int i; idev = input_allocate_device(); if (!idev) return -ENOMEM; ar2->idev = idev; - input_set_drvdata(idev, ar2); + idev->private = ar2; idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL); idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); @@ -362,13 +330,13 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) idev->phys = ar2->phys; usb_to_input_id(ar2->udev, &idev->id); - idev->dev.parent = &ar2->udev->dev; + idev->cdev.dev = &ar2->udev->dev; - retval = input_register_device(idev); - if (retval) + i = input_register_device(idev); + if (i) input_free_device(idev); - return retval; + return i; } static int ati_remote2_urb_init(struct ati_remote2 *ar2) @@ -411,41 +379,6 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2) } } -static int ati_remote2_setup(struct ati_remote2 *ar2) -{ - int r, i, channel; - - /* - * Configure receiver to only accept input from remote "channel" - * channel == 0 -> Accept input from any remote channel - * channel == 1 -> Only accept input from remote channel 1 - * channel == 2 -> Only accept input from remote channel 2 - * ... - * channel == 16 -> Only accept input from remote channel 16 - */ - - channel = 0; - for (i = 0; i < 16; i++) { - if ((1 << i) & channel_mask) { - if (!(~(1 << i) & 0xFFFF & channel_mask)) - channel = i + 1; - break; - } - } - - r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0), - 0x20, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (r) { - dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n", - __FUNCTION__, r); - return r; - } - - return 0; -} - static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); @@ -476,10 +409,6 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d if (r) goto fail2; - r = ati_remote2_setup(ar2); - if (r) - goto fail2; - usb_make_path(udev, ar2->phys, sizeof(ar2->phys)); strlcat(ar2->phys, "/input0", sizeof(ar2->phys)); diff --git a/trunk/drivers/usb/input/gtco.c b/trunk/drivers/usb/input/gtco.c index b2ca10f2fe0e..203cdc1bbba4 100644 --- a/trunk/drivers/usb/input/gtco.c +++ b/trunk/drivers/usb/input/gtco.c @@ -187,6 +187,7 @@ struct hid_descriptor /* + * * This is an abbreviated parser for the HID Report Descriptor. We * know what devices we are talking to, so this is by no means meant * to be generic. We can make some safe assumptions: @@ -203,7 +204,7 @@ struct hid_descriptor static void parse_hid_report_descriptor(struct gtco *device, char * report, int length) { - int x, i = 0; + int x,i=0; /* Tag primitive vars */ __u8 prefix; @@ -214,6 +215,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, __u16 data16 = 0; __u32 data32 = 0; + /* For parsing logic */ int inputnum = 0; __u32 usage = 0; @@ -223,46 +225,46 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, __u32 oldval[TAG_GLOB_MAX]; /* Debug stuff */ - char maintype = 'x'; + char maintype='x'; char globtype[12]; - int indent = 0; - char indentstr[10] = ""; + int indent=0; + char indentstr[10]=""; + dbg("======>>>>>>PARSE<<<<<<======"); /* Walk this report and pull out the info we need */ - while (i < length) { - prefix = report[i]; + while (imax_X == 0) { + dbg("GER: X Usage: 0x%x",usage); + if (device->max_X == 0){ device->max_X = globalval[TAG_GLOB_LOG_MAX]; device->min_X = globalval[TAG_GLOB_LOG_MIN]; } - break; + break; case 1: /* Y coord */ - dbg("GER: Y Usage: 0x%x", usage); - if (device->max_Y == 0) { + dbg("GER: Y Usage: 0x%x",usage); + if (device->max_Y == 0){ device->max_Y = globalval[TAG_GLOB_LOG_MAX]; device->min_Y = globalval[TAG_GLOB_LOG_MIN]; } break; - default: /* Tilt X */ - if (usage == DIGITIZER_USAGE_TILT_X) { - if (device->maxtilt_X == 0) { + if (usage == DIGITIZER_USAGE_TILT_X){ + if (device->maxtilt_X == 0){ device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; } } /* Tilt Y */ - if (usage == DIGITIZER_USAGE_TILT_Y) { - if (device->maxtilt_Y == 0) { + if (usage == DIGITIZER_USAGE_TILT_Y){ + if (device->maxtilt_Y == 0){ device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; } } + /* Pressure */ - if (usage == DIGITIZER_USAGE_TIP_PRESSURE) { - if (device->maxpressure == 0) { + if (usage == DIGITIZER_USAGE_TIP_PRESSURE){ + if (device->maxpressure == 0){ device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; device->minpressure = globalval[TAG_GLOB_LOG_MIN]; } @@ -337,226 +341,214 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, } inputnum++; - break; + + break; case TAG_MAIN_OUTPUT: - maintype = 'O'; + maintype='O'; break; - case TAG_MAIN_FEATURE: - maintype = 'F'; + maintype='F'; break; - case TAG_MAIN_COL_START: - maintype = 'S'; + maintype='S'; - if (data == 0) { + if (data==0){ dbg("======>>>>>> Physical"); - strcpy(globtype, "Physical"); - } else + strcpy(globtype,"Physical"); + }else{ dbg("======>>>>>>"); + } /* Indent the debug output */ indent++; - for (x = 0; x < indent; x++) - indentstr[x] = '-'; - indentstr[x] = 0; + for (x=0;xusage == 0) + if (device->usage == 0){ device->usage = data; - - strcpy(globtype, "USAGE"); + } + strcpy(globtype,"USAGE"); break; - - case TAG_GLOB_LOG_MIN: - strcpy(globtype, "LOG_MIN"); + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"LOG_MIN"); break; - - case TAG_GLOB_LOG_MAX: - strcpy(globtype, "LOG_MAX"); + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"LOG_MAX"); break; - - case TAG_GLOB_PHYS_MIN: - strcpy(globtype, "PHYS_MIN"); + case TAG_GLOB_PHYS_MIN : + strcpy(globtype,"PHYS_MIN"); break; - - case TAG_GLOB_PHYS_MAX: - strcpy(globtype, "PHYS_MAX"); + case TAG_GLOB_PHYS_MAX : + strcpy(globtype,"PHYS_MAX"); break; - - case TAG_GLOB_UNIT_EXP: - strcpy(globtype, "EXP"); + case TAG_GLOB_UNIT_EXP : + strcpy(globtype,"EXP"); break; - - case TAG_GLOB_UNIT: - strcpy(globtype, "UNIT"); + case TAG_GLOB_UNIT : + strcpy(globtype,"UNIT"); break; - - case TAG_GLOB_REPORT_SZ: - strcpy(globtype, "REPORT_SZ"); + case TAG_GLOB_REPORT_SZ : + strcpy(globtype,"REPORT_SZ"); break; - - case TAG_GLOB_REPORT_ID: - strcpy(globtype, "REPORT_ID"); + case TAG_GLOB_REPORT_ID : + strcpy(globtype,"REPORT_ID"); /* New report, restart numbering */ - inputnum = 0; + inputnum=0; break; - case TAG_GLOB_REPORT_CNT: - strcpy(globtype, "REPORT_CNT"); + strcpy(globtype,"REPORT_CNT"); break; - - case TAG_GLOB_PUSH: - strcpy(globtype, "PUSH"); + case TAG_GLOB_PUSH : + strcpy(globtype,"PUSH"); break; - case TAG_GLOB_POP: - strcpy(globtype, "POP"); + strcpy(globtype,"POP"); break; } + /* Check to make sure we have a good tag number so we don't overflow array */ - if (tag < TAG_GLOB_MAX) { - switch (size) { + if (tag < TAG_GLOB_MAX){ + switch (size){ case 1: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data); - globalval[tag] = data; + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data); + globalval[tag]=data; break; - case 2: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data16); - globalval[tag] = data16; + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16); + globalval[tag]=data16; break; - case 4: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data32); - globalval[tag] = data32; + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32); + globalval[tag]=data32; break; } - } else { + }else{ dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ", - indentstr, tag, size); + indentstr,tag,size); } + + break; case TYPE_LOCAL: - switch (tag) { + switch(tag){ case TAG_GLOB_USAGE: - strcpy(globtype, "USAGE"); + strcpy(globtype,"USAGE"); /* Always 1 byte */ usage = data; break; - - case TAG_GLOB_LOG_MIN: - strcpy(globtype, "MIN"); + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"MIN"); break; - - case TAG_GLOB_LOG_MAX: - strcpy(globtype, "MAX"); + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"MAX"); break; - default: - strcpy(globtype, "UNKNOWN"); - break; + strcpy(globtype,"UNKNOWN"); } - switch (size) { + switch (size){ case 1: dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data); + indentstr,tag,globtype,size,data); break; - case 2: dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data16); + indentstr,tag,globtype,size,data16); break; - case 4: dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data32); + indentstr,tag,globtype,size,data32); break; } break; } + } + } + + /* INPUT DRIVER Routines */ + /* - * Called when opening the input device. This will submit the URB to - * the usb system so we start getting reports + * Called when opening the input device. This will submit the URB to + * the usb system so we start getting reports */ static int gtco_input_open(struct input_dev *inputdev) { - struct gtco *device = input_get_drvdata(inputdev); + struct gtco *device; + device = inputdev->private; device->urbinfo->dev = device->usbdev; - if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) + if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) { return -EIO; - + } return 0; } -/* - * Called when closing the input device. This will unlink the URB - */ +/** + Called when closing the input device. This will unlink the URB +*/ static void gtco_input_close(struct input_dev *inputdev) { - struct gtco *device = input_get_drvdata(inputdev); + struct gtco *device = inputdev->private; usb_kill_urb(device->urbinfo); + } @@ -568,16 +560,19 @@ static void gtco_input_close(struct input_dev *inputdev) * placed in the struct gtco structure * */ -static void gtco_setup_caps(struct input_dev *inputdev) +static void gtco_setup_caps(struct input_dev *inputdev) { - struct gtco *device = input_get_drvdata(inputdev); + struct gtco *device = inputdev->private; + /* Which events */ inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + /* Misc event menu block */ inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ; + /* Absolute values based on HID report info */ input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, 0, 0); @@ -595,12 +590,17 @@ static void gtco_setup_caps(struct input_dev *inputdev) input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, device->maxpressure, 0, 0); + /* Transducer */ - input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0); + input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0); + } + + /* USB Routines */ + /* * URB callback routine. Called when we get IRQ reports from the * digitizer. @@ -610,7 +610,9 @@ static void gtco_setup_caps(struct input_dev *inputdev) */ static void gtco_urb_callback(struct urb *urbinfo) { - struct gtco *device = urbinfo->context; + + + struct gtco *device = urbinfo->context; struct input_dev *inputdev; int rc; u32 val = 0; @@ -619,20 +621,19 @@ static void gtco_urb_callback(struct urb *urbinfo) inputdev = device->inputdevice; + /* Was callback OK? */ - if (urbinfo->status == -ECONNRESET || - urbinfo->status == -ENOENT || - urbinfo->status == -ESHUTDOWN) { + if ((urbinfo->status == -ECONNRESET ) || + (urbinfo->status == -ENOENT ) || + (urbinfo->status == -ESHUTDOWN )){ /* Shutdown is occurring. Return and don't queue up any more */ return; } - if (urbinfo->status != 0) { - /* - * Some unknown error. Hopefully temporary. Just go and - * requeue an URB - */ + if (urbinfo->status != 0 ) { + /* Some unknown error. Hopefully temporary. Just go and */ + /* requeue an URB */ goto resubmit; } @@ -641,9 +642,10 @@ static void gtco_urb_callback(struct urb *urbinfo) */ /* PID dependent when we interpret the report */ - if (inputdev->id.product == PID_1000 || - inputdev->id.product == PID_1001 || - inputdev->id.product == PID_1002) { + if ((inputdev->id.product == PID_1000 )|| + (inputdev->id.product == PID_1001 )|| + (inputdev->id.product == PID_1002 )) + { /* * Switch on the report ID @@ -651,10 +653,10 @@ static void gtco_urb_callback(struct urb *urbinfo) * the report number. We can just fall through the case * statements if we start with the highest number report */ - switch (device->buffer[0]) { + switch(device->buffer[0]){ case 5: /* Pressure is 9 bits */ - val = ((u16)(device->buffer[8]) << 1); + val = ((u16)(device->buffer[8]) << 1); val |= (u16)(device->buffer[7] >> 7); input_report_abs(inputdev, ABS_PRESSURE, device->buffer[8]); @@ -662,6 +664,7 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Mask out the Y tilt value used for pressure */ device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); + /* Fall thru */ case 4: /* Tilt */ @@ -681,10 +684,11 @@ static void gtco_urb_callback(struct urb *urbinfo) input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); /* Fall thru */ + case 2: case 3: /* Convert buttons, only 5 bits possible */ - val = (device->buffer[5]) & MASK_BUTTON; + val = (device->buffer[5])&MASK_BUTTON; /* We don't apply any meaning to the bitmask, just report */ @@ -692,109 +696,132 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Fall thru */ case 1: + /* All reports have X and Y coords in the same place */ - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1]))); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3]))); input_report_abs(inputdev, ABS_Y, val); + /* Ditto for proximity bit */ - val = device->buffer[5] & MASK_INRANGE ? 1 : 0; + if (device->buffer[5]& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } input_report_abs(inputdev, ABS_DISTANCE, val); + /* Report 1 is an exception to how we handle buttons */ /* Buttons are an index, not a bitmask */ - if (device->buffer[0] == 1) { + if (device->buffer[0] == 1){ - /* - * Convert buttons, 5 bit index - * Report value of index set as one, - * the rest as 0 - */ - val = device->buffer[5] & MASK_BUTTON; + /* Convert buttons, 5 bit index */ + /* Report value of index set as one, + the rest as 0 */ + val = device->buffer[5]& MASK_BUTTON; dbg("======>>>>>>REPORT 1: val 0x%X(%d)", - val, val); + val,val); /* * We don't apply any meaning to the button * index, just report it */ input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + } - break; + break; case 7: /* Menu blocks */ input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); + + break; + } - } + + } /* Other pid class */ - if (inputdev->id.product == PID_400 || - inputdev->id.product == PID_401) { + if ((inputdev->id.product == PID_400 )|| + (inputdev->id.product == PID_401 )) + { /* Report 2 */ - if (device->buffer[0] == 2) { + if (device->buffer[0] == 2){ /* Menu blocks */ - input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); } /* Report 1 */ - if (device->buffer[0] == 1) { + if (device->buffer[0] == 1){ char buttonbyte; + /* IF X max > 64K, we still a bit from the y report */ - if (device->max_X > 0x10000) { + if (device->max_X > 0x10000){ - val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]); - val |= (u32)(((u8)device->buffer[3] & 0x1) << 16); + val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1]))); + val |= (u32)(((u8)device->buffer[3]&0x1)<< 16); input_report_abs(inputdev, ABS_X, val); - le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1); - le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7); + le_buffer[0] = (u8)((u8)(device->buffer[3])>>1); + le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7); + + le_buffer[1] = (u8)(device->buffer[4]>>1); + le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7); - le_buffer[1] = (u8)(device->buffer[4] >> 1); - le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); + val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer))); - val = le16_to_cpu(get_unaligned((__le16 *)le_buffer)); input_report_abs(inputdev, ABS_Y, val); + /* * Shift the button byte right by one to * make it look like the standard report */ - buttonbyte = device->buffer[5] >> 1; - } else { + buttonbyte = (device->buffer[5])>>1; + }else{ - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1])))); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3])))); input_report_abs(inputdev, ABS_Y, val); buttonbyte = device->buffer[5]; + } + /* BUTTONS and PROXIMITY */ - val = buttonbyte & MASK_INRANGE ? 1 : 0; + if (buttonbyte& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } input_report_abs(inputdev, ABS_DISTANCE, val); /* Convert buttons, only 4 bits possible */ - val = buttonbyte & 0x0F; + val = buttonbyte&0x0F; #ifdef USE_BUTTONS - for (i = 0; i < 5; i++) - input_report_key(inputdev, BTN_DIGI + i, val & (1 << i)); + for ( i=0;i<5;i++){ + input_report_key(inputdev, BTN_DIGI+i,val&(1<buffer[6]); + } } @@ -806,8 +833,10 @@ static void gtco_urb_callback(struct urb *urbinfo) resubmit: rc = usb_submit_urb(urbinfo, GFP_ATOMIC); - if (rc != 0) - err("usb_submit_urb failed rc=0x%x", rc); + if (rc != 0) { + err("usb_submit_urb failed rc=0x%x",rc); + } + } /* @@ -825,46 +854,58 @@ static int gtco_probe(struct usb_interface *usbinterface, const struct usb_device_id *id) { - struct gtco *gtco; - struct input_dev *input_dev; + struct gtco *device = NULL; + char path[PATHLENGTH]; + struct input_dev *inputdev; struct hid_descriptor *hid_desc; - char *report = NULL; - int result = 0, retry; - int error; + char *report; + int result=0, retry; struct usb_endpoint_descriptor *endpoint; /* Allocate memory for device structure */ - gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!gtco || !input_dev) { + device = kzalloc(sizeof(struct gtco), GFP_KERNEL); + if (device == NULL) { err("No more memory"); - error = -ENOMEM; - goto err_free_devs; + return -ENOMEM; } - /* Set pointer to the input device */ - gtco->inputdevice = input_dev; + + device->inputdevice = input_allocate_device(); + if (!device->inputdevice){ + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Get pointer to the input device */ + inputdev = device->inputdevice; /* Save interface information */ - gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + /* Allocate some data for incoming reports */ - gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE, - GFP_KERNEL, >co->buf_dma); - if (!gtco->buffer) { - err("No more memory for us buffers"); - error = -ENOMEM; - goto err_free_devs; + device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE, + GFP_KERNEL, &(device->buf_dma)); + if (!device->buffer){ + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; } /* Allocate URB for reports */ - gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL); - if (!gtco->urbinfo) { - err("Failed to allocate URB"); + device->urbinfo = usb_alloc_urb(0, GFP_KERNEL); + if (!device->urbinfo) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); return -ENOMEM; - goto err_free_buf; } + /* * The endpoint is always altsetting 0, we know this since we know * this device only has one interrupt endpoint @@ -872,43 +913,51 @@ static int gtco_probe(struct usb_interface *usbinterface, endpoint = &usbinterface->altsetting[0].endpoint[0].desc; /* Some debug */ - dbg("gtco # interfaces: %d", usbinterface->num_altsetting); - dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints); - dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass); - dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType); + dbg("gtco # interfaces: %d",usbinterface->num_altsetting); + dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints); + dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass); + dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType); if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) dbg("endpoint: we have interrupt endpoint\n"); - dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen); + dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen); + + /* * Find the HID descriptor so we can find out the size of the * HID report descriptor */ if (usb_get_extra_descriptor(usbinterface->cur_altsetting, - HID_DEVICE_TYPE, &hid_desc) != 0){ + HID_DEVICE_TYPE,&hid_desc) != 0){ err("Can't retrieve exta USB descriptor to get hid report descriptor length"); - error = -EIO; - goto err_free_urb; + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + return -EIO; } dbg("Extra descriptor success: type:%d len:%d", hid_desc->bDescriptorType, hid_desc->wDescriptorLength); - report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); - if (!report) { - err("No more memory for report"); - error = -ENOMEM; - goto err_free_urb; + if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; } /* Couple of tries to get reply */ - for (retry = 0; retry < 3; retry++) { - result = usb_control_msg(gtco->usbdev, - usb_rcvctrlpipe(gtco->usbdev, 0), + for (retry=0;retry<3;retry++) { + result = usb_control_msg(device->usbdev, + usb_rcvctrlpipe(device->usbdev, 0), USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, - REPORT_DEVICE_TYPE << 8, + (REPORT_DEVICE_TYPE << 8), 0, /* interface */ report, hid_desc->wDescriptorLength, @@ -920,76 +969,72 @@ static int gtco_probe(struct usb_interface *usbinterface, /* If we didn't get the report, fail */ dbg("usb_control_msg result: :%d", result); - if (result != hid_desc->wDescriptorLength) { + if (result != hid_desc->wDescriptorLength){ + kfree(report); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); err("Failed to get HID Report Descriptor of size: %d", hid_desc->wDescriptorLength); - error = -EIO; - goto err_free_urb; + return -EIO; } + /* Now we parse the report */ - parse_hid_report_descriptor(gtco, report, result); + parse_hid_report_descriptor(device,report,result); /* Now we delete it */ kfree(report); /* Create a device file node */ - usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath)); - strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath)); + usb_make_path(device->usbdev, path, PATHLENGTH); + sprintf(device->usbpath, "%s/input0", path); + /* Set Input device functions */ - input_dev->open = gtco_input_open; - input_dev->close = gtco_input_close; + inputdev->open = gtco_input_open; + inputdev->close = gtco_input_close; /* Set input device information */ - input_dev->name = "GTCO_CalComp"; - input_dev->phys = gtco->usbpath; + inputdev->name = "GTCO_CalComp"; + inputdev->phys = device->usbpath; + inputdev->private = device; - input_set_drvdata(input_dev, gtco); /* Now set up all the input device capabilities */ - gtco_setup_caps(input_dev); + gtco_setup_caps(inputdev); /* Set input device required ID information */ - usb_to_input_id(gtco->usbdev, &input_dev->id); - input_dev->dev.parent = &usbinterface->dev; + usb_to_input_id(device->usbdev, &device->inputdevice->id); + inputdev->cdev.dev = &usbinterface->dev; /* Setup the URB, it will be posted later on open of input device */ endpoint = &usbinterface->altsetting[0].endpoint[0].desc; - usb_fill_int_urb(gtco->urbinfo, - gtco->usbdev, - usb_rcvintpipe(gtco->usbdev, + usb_fill_int_urb(device->urbinfo, + device->usbdev, + usb_rcvintpipe(device->usbdev, endpoint->bEndpointAddress), - gtco->buffer, + device->buffer, REPORT_MAX_SIZE, gtco_urb_callback, - gtco, + device, endpoint->bInterval); - gtco->urbinfo->transfer_dma = gtco->buf_dma; - gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + device->urbinfo->transfer_dma = device->buf_dma; + device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + - /* Save gtco pointer in USB interface gtco */ - usb_set_intfdata(usbinterface, gtco); + /* Save device pointer in USB interface device */ + usb_set_intfdata(usbinterface, device); /* All done, now register the input device */ - error = input_register_device(input_dev); - if (error) - goto err_free_urb; + input_register_device(inputdev); + info( "gtco driver created usb: %s\n", path); return 0; - err_free_urb: - usb_free_urb(gtco->urbinfo); - err_free_buf: - usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE, - gtco->buffer, gtco->buf_dma); - err_free_devs: - kfree(report); - input_free_device(input_dev); - kfree(gtco); - return error; } /* @@ -999,46 +1044,50 @@ static int gtco_probe(struct usb_interface *usbinterface, */ static void gtco_disconnect(struct usb_interface *interface) { + /* Grab private device ptr */ - struct gtco *gtco = usb_get_intfdata(interface); + struct gtco *device = usb_get_intfdata (interface); + struct input_dev *inputdev; + + inputdev = device->inputdevice; /* Now reverse all the registration stuff */ - if (gtco) { - input_unregister_device(gtco->inputdevice); - usb_kill_urb(gtco->urbinfo); - usb_free_urb(gtco->urbinfo); - usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE, - gtco->buffer, gtco->buf_dma); - kfree(gtco); + if (device) { + input_unregister_device(inputdev); + usb_kill_urb(device->urbinfo); + usb_free_urb(device->urbinfo); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + kfree(device); } info("gtco driver disconnected"); } + /* STANDARD MODULE LOAD ROUTINES */ static struct usb_driver gtco_driverinfo_table = { - .name = "gtco", - .id_table = gtco_usbid_table, - .probe = gtco_probe, - .disconnect = gtco_disconnect, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + .owner = THIS_MODULE, +#endif + .name = "gtco", + .id_table = gtco_usbid_table, + .probe = gtco_probe, + .disconnect = gtco_disconnect, }; - /* * Register this module with the USB subsystem */ static int __init gtco_init(void) { - int error; - - error = usb_register(>co_driverinfo_table); - if (error) { - err("usb_register() failed rc=0x%x", error); - return error; + int rc; + rc = usb_register(>co_driverinfo_table); + if (rc) { + err("usb_register() failed rc=0x%x", rc); } - - printk("GTCO usb driver version: %s", GTCO_VERSION); - return 0; + printk("GTCO usb driver version: %s",GTCO_VERSION); + return rc; } /* @@ -1049,7 +1098,7 @@ static void __exit gtco_exit(void) usb_deregister(>co_driverinfo_table); } -module_init(gtco_init); -module_exit(gtco_exit); +module_init (gtco_init); +module_exit (gtco_exit); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/hid/usbhid/hid-core.c b/trunk/drivers/usb/input/hid-core.c similarity index 57% rename from trunk/drivers/hid/usbhid/hid-core.c rename to trunk/drivers/usb/input/hid-core.c index 91d610358d57..827a75a186ba 100644 --- a/trunk/drivers/hid/usbhid/hid-core.c +++ b/trunk/drivers/usb/input/hid-core.c @@ -39,7 +39,7 @@ */ #define DRIVER_VERSION "v2.6" -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina" +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" #define DRIVER_DESC "USB HID core driver" #define DRIVER_LICENSE "GPL" @@ -53,13 +53,6 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -/* Quirks specified at module load time */ -static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; -module_param_array_named(quirks, quirks_param, charp, NULL, 0444); -MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " - " quirks=vendorID:productID:quirks" - " where vendorID, productID, and quirks are all in" - " 0x-prefixed hex"); /* * Input submission and I/O error handler. */ @@ -151,11 +144,6 @@ static void hid_io_error(struct hid_device *hid) if (usb_get_intfdata(usbhid->intf) == NULL) goto done; - /* If it has been a while since the last error, we'll assume - * this a brand new error and reset the retry timeout. */ - if (time_after(jiffies, usbhid->stop_retry + HZ/2)) - usbhid->retry_delay = 0; - /* When an error occurs, retry at increasing intervals */ if (usbhid->retry_delay == 0) { usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ @@ -520,6 +508,12 @@ void usbhid_close(struct hid_device *hid) usb_kill_urb(usbhid->urbin); } +#define USB_VENDOR_ID_PANJIT 0x134c + +#define USB_VENDOR_ID_TURBOX 0x062a +#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 +#define USB_VENDOR_ID_CIDC 0x1677 + /* * Initialize all reports */ @@ -551,43 +545,410 @@ void usbhid_init_reports(struct hid_device *hid) warn("timeout initializing reports"); } +#define USB_VENDOR_ID_GTCO 0x078c +#define USB_DEVICE_ID_GTCO_90 0x0090 +#define USB_DEVICE_ID_GTCO_100 0x0100 +#define USB_DEVICE_ID_GTCO_101 0x0101 +#define USB_DEVICE_ID_GTCO_103 0x0103 +#define USB_DEVICE_ID_GTCO_104 0x0104 +#define USB_DEVICE_ID_GTCO_105 0x0105 +#define USB_DEVICE_ID_GTCO_106 0x0106 +#define USB_DEVICE_ID_GTCO_107 0x0107 +#define USB_DEVICE_ID_GTCO_108 0x0108 +#define USB_DEVICE_ID_GTCO_200 0x0200 +#define USB_DEVICE_ID_GTCO_201 0x0201 +#define USB_DEVICE_ID_GTCO_202 0x0202 +#define USB_DEVICE_ID_GTCO_203 0x0203 +#define USB_DEVICE_ID_GTCO_204 0x0204 +#define USB_DEVICE_ID_GTCO_205 0x0205 +#define USB_DEVICE_ID_GTCO_206 0x0206 +#define USB_DEVICE_ID_GTCO_207 0x0207 +#define USB_DEVICE_ID_GTCO_300 0x0300 +#define USB_DEVICE_ID_GTCO_301 0x0301 +#define USB_DEVICE_ID_GTCO_302 0x0302 +#define USB_DEVICE_ID_GTCO_303 0x0303 +#define USB_DEVICE_ID_GTCO_304 0x0304 +#define USB_DEVICE_ID_GTCO_305 0x0305 +#define USB_DEVICE_ID_GTCO_306 0x0306 +#define USB_DEVICE_ID_GTCO_307 0x0307 +#define USB_DEVICE_ID_GTCO_308 0x0308 +#define USB_DEVICE_ID_GTCO_309 0x0309 +#define USB_DEVICE_ID_GTCO_400 0x0400 +#define USB_DEVICE_ID_GTCO_401 0x0401 +#define USB_DEVICE_ID_GTCO_402 0x0402 +#define USB_DEVICE_ID_GTCO_403 0x0403 +#define USB_DEVICE_ID_GTCO_404 0x0404 +#define USB_DEVICE_ID_GTCO_405 0x0405 +#define USB_DEVICE_ID_GTCO_500 0x0500 +#define USB_DEVICE_ID_GTCO_501 0x0501 +#define USB_DEVICE_ID_GTCO_502 0x0502 +#define USB_DEVICE_ID_GTCO_503 0x0503 +#define USB_DEVICE_ID_GTCO_504 0x0504 +#define USB_DEVICE_ID_GTCO_1000 0x1000 +#define USB_DEVICE_ID_GTCO_1001 0x1001 +#define USB_DEVICE_ID_GTCO_1002 0x1002 +#define USB_DEVICE_ID_GTCO_1003 0x1003 +#define USB_DEVICE_ID_GTCO_1004 0x1004 +#define USB_DEVICE_ID_GTCO_1005 0x1005 +#define USB_DEVICE_ID_GTCO_1006 0x1006 + +#define USB_VENDOR_ID_WACOM 0x056a + +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 +#define USB_DEVICE_ID_ACECAD_302 0x0008 + +#define USB_VENDOR_ID_KBGEAR 0x084e +#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 + +#define USB_VENDOR_ID_AIPTEK 0x08ca +#define USB_DEVICE_ID_AIPTEK_01 0x0001 +#define USB_DEVICE_ID_AIPTEK_10 0x0010 +#define USB_DEVICE_ID_AIPTEK_20 0x0020 +#define USB_DEVICE_ID_AIPTEK_21 0x0021 +#define USB_DEVICE_ID_AIPTEK_22 0x0022 +#define USB_DEVICE_ID_AIPTEK_23 0x0023 +#define USB_DEVICE_ID_AIPTEK_24 0x0024 + +#define USB_VENDOR_ID_GRIFFIN 0x077d +#define USB_DEVICE_ID_POWERMATE 0x0410 +#define USB_DEVICE_ID_SOUNDKNOB 0x04AA + +#define USB_VENDOR_ID_ATEN 0x0557 +#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 +#define USB_DEVICE_ID_ATEN_CS124U 0x2202 +#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 +#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 +#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 + +#define USB_VENDOR_ID_TOPMAX 0x0663 +#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 + +#define USB_VENDOR_ID_HAPP 0x078b +#define USB_DEVICE_ID_UGCI_DRIVING 0x0010 +#define USB_DEVICE_ID_UGCI_FLYING 0x0020 +#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 + +#define USB_VENDOR_ID_MGE 0x0463 +#define USB_DEVICE_ID_MGE_UPS 0xffff +#define USB_DEVICE_ID_MGE_UPS1 0x0001 + +#define USB_VENDOR_ID_ONTRAK 0x0a07 +#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 + +#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f +#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 + +#define USB_VENDOR_ID_A4TECH 0x09da +#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 + +#define USB_VENDOR_ID_AASHIMA 0x06d6 +#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 +#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026 + +#define USB_VENDOR_ID_CYPRESS 0x04b4 +#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 +#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 +#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 + +#define USB_VENDOR_ID_BERKSHIRE 0x0c98 +#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 + +#define USB_VENDOR_ID_ALPS 0x0433 +#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 + +#define USB_VENDOR_ID_SAITEK 0x06a3 +#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 + +#define USB_VENDOR_ID_NEC 0x073e +#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 + +#define USB_VENDOR_ID_CHIC 0x05fe +#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 + +#define USB_VENDOR_ID_GLAB 0x06c2 +#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 +#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 +#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 +#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044 +#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 +#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051 +#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 +#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 + +#define USB_VENDOR_ID_WISEGROUP 0x0925 +#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 +#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 +#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 +#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 + +#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677 +#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 + +#define USB_VENDOR_ID_CODEMERCS 0x07c0 +#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff + +#define USB_VENDOR_ID_DELORME 0x1163 +#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 +#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 + +#define USB_VENDOR_ID_MCC 0x09db +#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 +#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a + +#define USB_VENDOR_ID_VERNIER 0x08f7 +#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 +#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 +#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 +#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 + +#define USB_VENDOR_ID_LD 0x0f11 +#define USB_DEVICE_ID_LD_CASSY 0x1000 +#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 +#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 +#define USB_DEVICE_ID_LD_JWM 0x1080 +#define USB_DEVICE_ID_LD_DMMP 0x1081 +#define USB_DEVICE_ID_LD_UMIP 0x1090 +#define USB_DEVICE_ID_LD_XRAY1 0x1100 +#define USB_DEVICE_ID_LD_XRAY2 0x1101 +#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 +#define USB_DEVICE_ID_LD_COM3LAB 0x2000 +#define USB_DEVICE_ID_LD_TELEPORT 0x2010 +#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 +#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 +#define USB_DEVICE_ID_LD_MACHINETEST 0x2040 + +#define USB_VENDOR_ID_APPLE 0x05ac +#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 +#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e +#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f +#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 +#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215 +#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216 +#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217 +#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218 +#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219 +#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a +#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b +#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c +#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a +#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IR 0x8240 + +#define USB_VENDOR_ID_CHERRY 0x046a +#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 + +#define USB_VENDOR_ID_YEALINK 0x6993 +#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 + +#define USB_VENDOR_ID_ALCOR 0x058f +#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 + +#define USB_VENDOR_ID_SUN 0x0430 +#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab + +#define USB_VENDOR_ID_AIRCABLE 0x16CA +#define USB_DEVICE_ID_AIRCABLE1 0x1502 + +#define USB_VENDOR_ID_LOGITECH 0x046d +#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 +#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517 +#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 + +#define USB_VENDOR_ID_IMATION 0x0718 +#define USB_DEVICE_ID_DISC_STAKKA 0xd000 + +#define USB_VENDOR_ID_PANTHERLORD 0x0810 +#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 + +#define USB_VENDOR_ID_SONY 0x054c +#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + /* - * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01). + * Alphabetically sorted blacklist by quirk type. */ -static int hid_find_field_early(struct hid_device *hid, unsigned int page, - unsigned int hid_code, struct hid_field **pfield) -{ - struct hid_report *report; - struct hid_field *field; - struct hid_usage *usage; - int i, j; - - list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - field = report->field[i]; - for (j = 0; j < field->maxusage; j++) { - usage = &field->usage[j]; - if ((usage->hid & HID_USAGE_PAGE) == page && - (usage->hid & 0xFFFF) == hid_code) { - *pfield = field; - return j; - } - } - } - } - return -1; -} -static void usbhid_set_leds(struct hid_device *hid) -{ - struct hid_field *field; - int offset; - - if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) { - hid_set_field(field, offset, 0); - usbhid_submit_report(hid, field->report, USB_DIR_OUT); - } -} +static const struct hid_blacklist { + __u16 idVendor; + __u16 idProduct; + unsigned quirks; +} hid_blacklist[] = { + + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, + + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, + + { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, + + { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, + + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR }, + + { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + + { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + + { 0, 0 } +}; /* * Traverse the supplied list of reports and find the longest @@ -677,16 +1038,16 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) } /* - * Certain Logitech keyboards send in report #3 keys which are far + * Logitech S510 keyboard sends in report #3 keys which are far * above the logical maximum described in descriptor. This extends * the original value of 0x28c of logical maximum to 0x104d */ -static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) +static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize) { if (rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { - info("Fixing up Logitech keyboard report descriptor"); + info("Fixing up Logitech S510 report descriptor"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } @@ -698,14 +1059,24 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_device *hid; - u32 quirks = 0; - unsigned rsize = 0; + unsigned quirks = 0, rsize = 0; char *rdesc; int n, len, insize = 0; struct usbhid_device *usbhid; - quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + /* Ignore all Wacom devices */ + if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) + return NULL; + /* ignore all Code Mercenaries IOWarrior devices */ + if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS) + if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST && + le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) + return NULL; + + for (n = 0; hid_blacklist[n].idVendor; n++) + if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && + (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct))) + quirks = hid_blacklist[n].quirks; /* Many keyboards and mice don't like to be polled for reports, * so we will always set the HID_QUIRK_NOGET flag for them. */ @@ -755,8 +1126,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if ((quirks & HID_QUIRK_CYMOTION)) hid_fixup_cymotion_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) - hid_fixup_logitech_descriptor(rdesc, rsize); + if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR) + hid_fixup_s510_descriptor(rdesc, rsize); #ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); @@ -963,8 +1334,6 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) usbhid_init_reports(hid); hid_dump_device(hid); - if (hid->quirks & HID_QUIRK_RESET_LEDS) - usbhid_set_leds(hid); if (!hidinput_connect(hid)) hid->claimed |= HID_CLAIMED_INPUT; @@ -1079,9 +1448,6 @@ static struct usb_driver hid_driver = { static int __init hid_init(void) { int retval; - retval = usbhid_quirks_init(quirks_param); - if (retval) - goto usbhid_quirks_init_fail; retval = hiddev_init(); if (retval) goto hiddev_init_fail; @@ -1094,8 +1460,6 @@ static int __init hid_init(void) usb_register_fail: hiddev_exit(); hiddev_init_fail: - usbhid_quirks_exit(); -usbhid_quirks_init_fail: return retval; } @@ -1103,7 +1467,6 @@ static void __exit hid_exit(void) { usb_deregister(&hid_driver); hiddev_exit(); - usbhid_quirks_exit(); } module_init(hid_init); diff --git a/trunk/drivers/hid/usbhid/hid-ff.c b/trunk/drivers/usb/input/hid-ff.c similarity index 96% rename from trunk/drivers/hid/usbhid/hid-ff.c rename to trunk/drivers/usb/input/hid-ff.c index 23431fbbc3d7..e431faaa6abc 100644 --- a/trunk/drivers/hid/usbhid/hid-ff.c +++ b/trunk/drivers/usb/input/hid-ff.c @@ -56,7 +56,6 @@ static struct hid_ff_initializer inits[] = { { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ - { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */ { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */ { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ @@ -65,7 +64,6 @@ static struct hid_ff_initializer inits[] = { { 0x810, 0x0001, hid_plff_init }, #endif #ifdef CONFIG_THRUSTMASTER_FF - { 0x44f, 0xb300, hid_tmff_init }, { 0x44f, 0xb304, hid_tmff_init }, #endif #ifdef CONFIG_ZEROPLUS_FF diff --git a/trunk/drivers/hid/usbhid/hid-lgff.c b/trunk/drivers/usb/input/hid-lgff.c similarity index 99% rename from trunk/drivers/hid/usbhid/hid-lgff.c rename to trunk/drivers/usb/input/hid-lgff.c index 92d2553f17b6..e6f3af3e66d1 100644 --- a/trunk/drivers/hid/usbhid/hid-lgff.c +++ b/trunk/drivers/usb/input/hid-lgff.c @@ -52,7 +52,6 @@ static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, - { 0x046d, 0xc286, ff_joystick }, { 0x046d, 0xc294, ff_joystick }, { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_joystick }, diff --git a/trunk/drivers/hid/usbhid/hid-pidff.c b/trunk/drivers/usb/input/hid-pidff.c similarity index 100% rename from trunk/drivers/hid/usbhid/hid-pidff.c rename to trunk/drivers/usb/input/hid-pidff.c diff --git a/trunk/drivers/hid/usbhid/hid-plff.c b/trunk/drivers/usb/input/hid-plff.c similarity index 100% rename from trunk/drivers/hid/usbhid/hid-plff.c rename to trunk/drivers/usb/input/hid-plff.c diff --git a/trunk/drivers/hid/usbhid/hid-tmff.c b/trunk/drivers/usb/input/hid-tmff.c similarity index 100% rename from trunk/drivers/hid/usbhid/hid-tmff.c rename to trunk/drivers/usb/input/hid-tmff.c diff --git a/trunk/drivers/hid/usbhid/hid-zpff.c b/trunk/drivers/usb/input/hid-zpff.c similarity index 100% rename from trunk/drivers/hid/usbhid/hid-zpff.c rename to trunk/drivers/usb/input/hid-zpff.c diff --git a/trunk/drivers/hid/usbhid/hiddev.c b/trunk/drivers/usb/input/hiddev.c similarity index 100% rename from trunk/drivers/hid/usbhid/hiddev.c rename to trunk/drivers/usb/input/hiddev.c diff --git a/trunk/drivers/usb/input/itmtouch.c b/trunk/drivers/usb/input/itmtouch.c new file mode 100644 index 000000000000..aac968aab860 --- /dev/null +++ b/trunk/drivers/usb/input/itmtouch.c @@ -0,0 +1,271 @@ +/****************************************************************************** + * itmtouch.c -- Driver for ITM touchscreen panel + * + * 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. + * + * Based upon original work by Chris Collins . + * + * Kudos to ITM for providing me with the datasheet for the panel, + * even though it was a day later than I had finished writing this + * driver. + * + * It has meant that I've been able to correct my interpretation of the + * protocol packets however. + * + * CC -- 2003/9/29 + * + * History + * 1.0 & 1.1 2003 (CC) vojtech@suse.cz + * Original version for 2.4.x kernels + * + * 1.2 02/03/2005 (HCE) hc@mivu.no + * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints. + * Unfortunately no calibration support at this time. + * + * 1.2.1 09/03/2005 (HCE) hc@mivu.no + * Code cleanup and adjusting syntax to start matching kernel standards + * + * 1.2.2 10/05/2006 (MJA) massad@gmail.com + * Flag for detecting if the screen was being touch was incorrectly + * inverted, so no touch events were being detected. + * + *****************************************************************************/ + +#include +#include +#include +#include +#include + +/* only an 8 byte buffer necessary for a single packet */ +#define ITM_BUFSIZE 8 +#define PATH_SIZE 64 + +#define USB_VENDOR_ID_ITMINC 0x0403 +#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9 + +#define DRIVER_AUTHOR "Hans-Christian Egtvedt " +#define DRIVER_VERSION "v1.2.2" +#define DRIVER_DESC "USB ITM Inc Touch Panel Driver" +#define DRIVER_LICENSE "GPL" + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE( DRIVER_LICENSE ); + +struct itmtouch_dev { + struct usb_device *usbdev; /* usb device */ + struct input_dev *inputdev; /* input device */ + struct urb *readurb; /* urb */ + char rbuf[ITM_BUFSIZE]; /* data */ + int users; + char name[128]; + char phys[64]; +}; + +static struct usb_device_id itmtouch_ids [] = { + { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) }, + { } +}; + +static void itmtouch_irq(struct urb *urb) +{ + struct itmtouch_dev *itmtouch = urb->context; + unsigned char *data = urb->transfer_buffer; + struct input_dev *dev = itmtouch->inputdev; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIME: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + /* if pressure has been released, then don't report X/Y */ + if (!(data[7] & 0x20)) { + input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); + input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F)); + } + + input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F)); + input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20); + input_sync(dev); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + printk(KERN_ERR "%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int itmtouch_open(struct input_dev *input) +{ + struct itmtouch_dev *itmtouch = input->private; + + itmtouch->readurb->dev = itmtouch->usbdev; + + if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void itmtouch_close(struct input_dev *input) +{ + struct itmtouch_dev *itmtouch = input->private; + + usb_kill_urb(itmtouch->readurb); +} + +static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct itmtouch_dev *itmtouch; + struct input_dev *input_dev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + unsigned int pipe; + unsigned int maxp; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!itmtouch || !input_dev) { + err("%s - Out of memory.", __FUNCTION__); + goto fail; + } + + itmtouch->usbdev = udev; + itmtouch->inputdev = input_dev; + + if (udev->manufacturer) + strlcpy(itmtouch->name, udev->manufacturer, sizeof(itmtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(itmtouch->name, " ", sizeof(itmtouch->name)); + strlcat(itmtouch->name, udev->product, sizeof(itmtouch->name)); + } + + if (!strlen(itmtouch->name)) + sprintf(itmtouch->name, "USB ITM touchscreen"); + + usb_make_path(udev, itmtouch->phys, sizeof(itmtouch->phys)); + strlcpy(itmtouch->phys, "/input0", sizeof(itmtouch->phys)); + + input_dev->name = itmtouch->name; + input_dev->phys = itmtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = itmtouch; + + input_dev->open = itmtouch_open; + input_dev->close = itmtouch_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + /* device limits */ + /* as specified by the ITM datasheet, X and Y are 12bit, + * Z (pressure) is 8 bit. However, the fields are defined up + * to 14 bits for future possible expansion. + */ + input_set_abs_params(input_dev, ABS_X, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x0FFF, 2, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFF, 2, 0); + + /* initialise the URB so we can read from the transport stream */ + pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + + if (maxp > ITM_BUFSIZE) + maxp = ITM_BUFSIZE; + + itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); + if (!itmtouch->readurb) { + dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); + goto fail; + } + + usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf, + maxp, itmtouch_irq, itmtouch, endpoint->bInterval); + + input_register_device(itmtouch->inputdev); + + usb_set_intfdata(intf, itmtouch); + + return 0; + + fail: input_free_device(input_dev); + kfree(itmtouch); + return -ENOMEM; +} + +static void itmtouch_disconnect(struct usb_interface *intf) +{ + struct itmtouch_dev *itmtouch = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (itmtouch) { + input_unregister_device(itmtouch->inputdev); + usb_kill_urb(itmtouch->readurb); + usb_free_urb(itmtouch->readurb); + kfree(itmtouch); + } +} + +MODULE_DEVICE_TABLE(usb, itmtouch_ids); + +static struct usb_driver itmtouch_driver = { + .name = "itmtouch", + .probe = itmtouch_probe, + .disconnect = itmtouch_disconnect, + .id_table = itmtouch_ids, +}; + +static int __init itmtouch_init(void) +{ + info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_AUTHOR); + return usb_register(&itmtouch_driver); +} + +static void __exit itmtouch_exit(void) +{ + usb_deregister(&itmtouch_driver); +} + +module_init(itmtouch_init); +module_exit(itmtouch_exit); diff --git a/trunk/drivers/usb/input/kbtab.c b/trunk/drivers/usb/input/kbtab.c index c4781b9d1297..fedbcb127c21 100644 --- a/trunk/drivers/usb/input/kbtab.c +++ b/trunk/drivers/usb/input/kbtab.c @@ -100,7 +100,7 @@ MODULE_DEVICE_TABLE(usb, kbtab_ids); static int kbtab_open(struct input_dev *dev) { - struct kbtab *kbtab = input_get_drvdata(dev); + struct kbtab *kbtab = dev->private; kbtab->irq->dev = kbtab->usbdev; if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) @@ -111,7 +111,7 @@ static int kbtab_open(struct input_dev *dev) static void kbtab_close(struct input_dev *dev) { - struct kbtab *kbtab = input_get_drvdata(dev); + struct kbtab *kbtab = dev->private; usb_kill_urb(kbtab->irq); } @@ -122,7 +122,6 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_endpoint_descriptor *endpoint; struct kbtab *kbtab; struct input_dev *input_dev; - int error = -ENOMEM; kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL); input_dev = input_allocate_device(); @@ -146,9 +145,8 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i input_dev->name = "KB Gear Tablet"; input_dev->phys = kbtab->phys; usb_to_input_id(dev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, kbtab); + input_dev->cdev.dev = &intf->dev; + input_dev->private = kbtab; input_dev->open = kbtab_open; input_dev->close = kbtab_close; @@ -170,19 +168,15 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->irq->transfer_dma = kbtab->data_dma; kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(kbtab->dev); - if (error) - goto fail3; + input_register_device(kbtab->dev); usb_set_intfdata(intf, kbtab); - return 0; - fail3: usb_free_urb(kbtab->irq); - fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); - fail1: input_free_device(input_dev); +fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma); +fail1: input_free_device(input_dev); kfree(kbtab); - return error; + return -ENOMEM; } static void kbtab_disconnect(struct usb_interface *intf) diff --git a/trunk/drivers/usb/input/keyspan_remote.c b/trunk/drivers/usb/input/keyspan_remote.c index 1bffc9fa98c2..98bd323369c7 100644 --- a/trunk/drivers/usb/input/keyspan_remote.c +++ b/trunk/drivers/usb/input/keyspan_remote.c @@ -394,7 +394,7 @@ static void keyspan_irq_recv(struct urb *urb) static int keyspan_open(struct input_dev *dev) { - struct usb_keyspan *remote = input_get_drvdata(dev); + struct usb_keyspan *remote = dev->private; remote->irq_urb->dev = remote->udev; if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) @@ -405,7 +405,7 @@ static int keyspan_open(struct input_dev *dev) static void keyspan_close(struct input_dev *dev) { - struct usb_keyspan *remote = input_get_drvdata(dev); + struct usb_keyspan *remote = dev->private; usb_kill_urb(remote->irq_urb); } @@ -437,7 +437,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic struct usb_endpoint_descriptor *endpoint; struct usb_keyspan *remote; struct input_dev *input_dev; - int i, error; + int i, retval; endpoint = keyspan_get_in_endpoint(interface->cur_altsetting); if (!endpoint) @@ -446,7 +446,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote = kzalloc(sizeof(*remote), GFP_KERNEL); input_dev = input_allocate_device(); if (!remote || !input_dev) { - error = -ENOMEM; + retval = -ENOMEM; goto fail1; } @@ -458,19 +458,19 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); if (!remote->in_buffer) { - error = -ENOMEM; + retval = -ENOMEM; goto fail1; } remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if (!remote->irq_urb) { - error = -ENOMEM; + retval = -ENOMEM; goto fail2; } - error = keyspan_setup(udev); - if (error) { - error = -ENODEV; + retval = keyspan_setup(udev); + if (retval) { + retval = -ENODEV; goto fail3; } @@ -495,15 +495,14 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic input_dev->name = remote->name; input_dev->phys = remote->phys; usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &interface->dev; + input_dev->cdev.dev = &interface->dev; input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) if (keyspan_key_table[i] != KEY_RESERVED) set_bit(keyspan_key_table[i], input_dev->keybit); - input_set_drvdata(input_dev, remote); - + input_dev->private = remote; input_dev->open = keyspan_open; input_dev->close = keyspan_close; @@ -518,9 +517,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* we can register the device now, as it is ready */ - error = input_register_device(remote->input); - if (error) - goto fail3; + input_register_device(remote->input); /* save our data pointer in this interface device */ usb_set_intfdata(interface, remote); @@ -532,7 +529,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic fail1: kfree(remote); input_free_device(input_dev); - return error; + return retval; } /* diff --git a/trunk/drivers/usb/input/mtouchusb.c b/trunk/drivers/usb/input/mtouchusb.c new file mode 100644 index 000000000000..92c4e07da4c8 --- /dev/null +++ b/trunk/drivers/usb/input/mtouchusb.c @@ -0,0 +1,332 @@ +/****************************************************************************** + * mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens + * + * 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. + * + * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl) + * (http://freshmeat.net/projects/3mtouchscreendriver) + * + * History + * + * 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com + * Updated to 2.4.18, then 2.4.19 + * Old version still relied on stealing a minor + * + * 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com + * Complete rewrite using Linux Input in 2.6.3 + * Unfortunately no calibration support at this time + * + * 1.4 04/25/2004 (TEJ) tejohnson@yahoo.com + * Changed reset from standard USB dev reset to vendor reset + * Changed data sent to host from compensated to raw coordinates + * Eliminated vendor/product module params + * Performed multiple successful tests with an EXII-5010UC + * + * 1.5 02/27/2005 ddstreet@ieee.org + * Added module parameter to select raw or hw-calibrated coordinate reporting + * + *****************************************************************************/ + +#include +#include +#include +#include +#include + +#define MTOUCHUSB_MIN_XC 0x0 +#define MTOUCHUSB_MAX_RAW_XC 0x4000 +#define MTOUCHUSB_MAX_CALIB_XC 0xffff +#define MTOUCHUSB_XC_FUZZ 0x0 +#define MTOUCHUSB_XC_FLAT 0x0 +#define MTOUCHUSB_MIN_YC 0x0 +#define MTOUCHUSB_MAX_RAW_YC 0x4000 +#define MTOUCHUSB_MAX_CALIB_YC 0xffff +#define MTOUCHUSB_YC_FUZZ 0x0 +#define MTOUCHUSB_YC_FLAT 0x0 + +#define MTOUCHUSB_ASYNC_REPORT 1 +#define MTOUCHUSB_RESET 7 +#define MTOUCHUSB_REPORT_DATA_SIZE 11 +#define MTOUCHUSB_REQ_CTRLLR_ID 10 + +#define MTOUCHUSB_GET_RAW_XC(data) (data[8]<<8 | data[7]) +#define MTOUCHUSB_GET_CALIB_XC(data) (data[4]<<8 | data[3]) +#define MTOUCHUSB_GET_RAW_YC(data) (data[10]<<8 | data[9]) +#define MTOUCHUSB_GET_CALIB_YC(data) (data[6]<<8 | data[5]) +#define MTOUCHUSB_GET_XC(data) (raw_coordinates ? \ + MTOUCHUSB_GET_RAW_XC(data) : \ + MTOUCHUSB_GET_CALIB_XC(data)) +#define MTOUCHUSB_GET_YC(data) (raw_coordinates ? \ + MTOUCHUSB_GET_RAW_YC(data) : \ + MTOUCHUSB_GET_CALIB_YC(data)) +#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0) + +#define DRIVER_VERSION "v1.5" +#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com" +#define DRIVER_DESC "3M USB Touchscreen Driver" +#define DRIVER_LICENSE "GPL" + +static int raw_coordinates = 1; + +module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)"); + +struct mtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + struct urb *irq; + struct usb_device *udev; + struct input_dev *input; + char name[128]; + char phys[64]; +}; + +static struct usb_device_id mtouchusb_devices[] = { + { USB_DEVICE(0x0596, 0x0001) }, + { } +}; + +static void mtouchusb_irq(struct urb *urb) +{ + struct mtouch_usb *mtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIME: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + input_report_key(mtouch->input, BTN_TOUCH, + MTOUCHUSB_GET_TOUCHED(mtouch->data)); + input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data)); + input_report_abs(mtouch->input, ABS_Y, + (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) + - MTOUCHUSB_GET_YC(mtouch->data)); + input_sync(mtouch->input); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int mtouchusb_open(struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + mtouch->irq->dev = mtouch->udev; + + if (usb_submit_urb(mtouch->irq, GFP_ATOMIC)) + return -EIO; + + return 0; +} + +static void mtouchusb_close(struct input_dev *input) +{ + struct mtouch_usb *mtouch = input->private; + + usb_kill_urb(mtouch->irq); +} + +static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, + GFP_ATOMIC, &mtouch->data_dma); + + if (!mtouch->data) + return -1; + + return 0; +} + +static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) +{ + dbg("%s - called", __FUNCTION__); + + if (mtouch->data) + usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE, + mtouch->data, mtouch->data_dma); +} + +static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct mtouch_usb *mtouch; + struct input_dev *input_dev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + int nRet; + + dbg("%s - called", __FUNCTION__); + + dbg("%s - setting interface", __FUNCTION__); + interface = intf->cur_altsetting; + + dbg("%s - setting endpoint", __FUNCTION__); + endpoint = &interface->endpoint[0].desc; + + mtouch = kzalloc(sizeof(struct mtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!mtouch || !input_dev) { + err("%s - Out of memory.", __FUNCTION__); + goto fail1; + } + + dbg("%s - allocating buffers", __FUNCTION__); + if (mtouchusb_alloc_buffers(udev, mtouch)) + goto fail2; + + mtouch->udev = udev; + mtouch->input = input_dev; + + if (udev->manufacturer) + strlcpy(mtouch->name, udev->manufacturer, sizeof(mtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(mtouch->name, " ", sizeof(mtouch->name)); + strlcat(mtouch->name, udev->product, sizeof(mtouch->name)); + } + + if (!strlen(mtouch->name)) + snprintf(mtouch->name, sizeof(mtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, mtouch->phys, sizeof(mtouch->phys)); + strlcpy(mtouch->phys, "/input0", sizeof(mtouch->phys)); + + input_dev->name = mtouch->name; + input_dev->phys = mtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = mtouch; + + input_dev->open = mtouchusb_open; + input_dev->close = mtouchusb_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, MTOUCHUSB_MIN_XC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC, + MTOUCHUSB_XC_FUZZ, MTOUCHUSB_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, MTOUCHUSB_MIN_YC, + raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC, + MTOUCHUSB_YC_FUZZ, MTOUCHUSB_YC_FLAT); + + nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), + MTOUCHUSB_RESET, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", + __FUNCTION__, nRet); + + dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); + mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!mtouch->irq) { + dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); + goto fail2; + } + + dbg("%s - usb_fill_int_urb", __FUNCTION__); + usb_fill_int_urb(mtouch->irq, mtouch->udev, + usb_rcvintpipe(mtouch->udev, 0x81), + mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE, + mtouchusb_irq, mtouch, endpoint->bInterval); + + dbg("%s - input_register_device", __FUNCTION__); + input_register_device(mtouch->input); + + nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0), + MTOUCHUSB_ASYNC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", + __FUNCTION__, nRet); + + usb_set_intfdata(intf, mtouch); + return 0; + +fail2: mtouchusb_free_buffers(udev, mtouch); +fail1: input_free_device(input_dev); + kfree(mtouch); + return -ENOMEM; +} + +static void mtouchusb_disconnect(struct usb_interface *intf) +{ + struct mtouch_usb *mtouch = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + usb_set_intfdata(intf, NULL); + if (mtouch) { + dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); + usb_kill_urb(mtouch->irq); + input_unregister_device(mtouch->input); + usb_free_urb(mtouch->irq); + mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); + kfree(mtouch); + } +} + +MODULE_DEVICE_TABLE(usb, mtouchusb_devices); + +static struct usb_driver mtouchusb_driver = { + .name = "mtouchusb", + .probe = mtouchusb_probe, + .disconnect = mtouchusb_disconnect, + .id_table = mtouchusb_devices, +}; + +static int __init mtouchusb_init(void) +{ + dbg("%s - called", __FUNCTION__); + return usb_register(&mtouchusb_driver); +} + +static void __exit mtouchusb_cleanup(void) +{ + dbg("%s - called", __FUNCTION__); + usb_deregister(&mtouchusb_driver); +} + +module_init(mtouchusb_init); +module_exit(mtouchusb_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/input/powermate.c b/trunk/drivers/usb/input/powermate.c index 4f93a760faee..fea97e5437f8 100644 --- a/trunk/drivers/usb/input/powermate.c +++ b/trunk/drivers/usb/input/powermate.c @@ -252,7 +252,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value) { unsigned int command = (unsigned int)_value; - struct powermate_device *pm = input_get_drvdata(dev); + struct powermate_device *pm = dev->private; if (type == EV_MSC && code == MSC_PULSELED){ /* @@ -308,7 +308,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i struct powermate_device *pm; struct input_dev *input_dev; int pipe, maxp; - int error = -ENOMEM; + int err = -ENOMEM; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; @@ -359,9 +359,8 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i input_dev->phys = pm->phys; usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, pm); + input_dev->cdev.dev = &intf->dev; + input_dev->private = pm; input_dev->event = powermate_input_event; @@ -388,14 +387,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i /* register our interrupt URB with the USB system */ if (usb_submit_urb(pm->irq, GFP_KERNEL)) { - error = -EIO; + err = -EIO; goto fail4; } - error = input_register_device(pm->input); - if (error) - goto fail5; - + input_register_device(pm->input); /* force an update of everything */ pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; @@ -404,13 +400,12 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i usb_set_intfdata(intf, pm); return 0; - fail5: usb_kill_urb(pm->irq); - fail4: usb_free_urb(pm->config); - fail3: usb_free_urb(pm->irq); - fail2: powermate_free_buffers(udev, pm); - fail1: input_free_device(input_dev); +fail4: usb_free_urb(pm->config); +fail3: usb_free_urb(pm->irq); +fail2: powermate_free_buffers(udev, pm); +fail1: input_free_device(input_dev); kfree(pm); - return error; + return err; } /* Called when a USB device we've accepted ownership of is removed */ diff --git a/trunk/drivers/usb/input/touchkitusb.c b/trunk/drivers/usb/input/touchkitusb.c new file mode 100644 index 000000000000..2a314b065922 --- /dev/null +++ b/trunk/drivers/usb/input/touchkitusb.c @@ -0,0 +1,392 @@ +/****************************************************************************** + * touchkitusb.c -- Driver for eGalax TouchKit USB Touchscreens + * + * Copyright (C) 2004-2005 by Daniel Ritz + * Copyright (C) by Todd E. Johnson (mtouchusb.c) + * + * 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. + * + * Based upon mtouchusb.c + * + *****************************************************************************/ + +//#define DEBUG + +#include +#include +#include +#include +#include + +#define TOUCHKIT_MIN_XC 0x0 +#define TOUCHKIT_MAX_XC 0x07ff +#define TOUCHKIT_XC_FUZZ 0x0 +#define TOUCHKIT_XC_FLAT 0x0 +#define TOUCHKIT_MIN_YC 0x0 +#define TOUCHKIT_MAX_YC 0x07ff +#define TOUCHKIT_YC_FUZZ 0x0 +#define TOUCHKIT_YC_FLAT 0x0 +#define TOUCHKIT_REPORT_DATA_SIZE 16 + +#define TOUCHKIT_DOWN 0x01 + +#define TOUCHKIT_PKT_TYPE_MASK 0xFE +#define TOUCHKIT_PKT_TYPE_REPT 0x80 +#define TOUCHKIT_PKT_TYPE_DIAG 0x0A + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Daniel Ritz " +#define DRIVER_DESC "eGalax TouchKit USB HID Touchscreen Driver" + +static int swap_xy; +module_param(swap_xy, bool, 0644); +MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); + +struct touchkit_usb { + unsigned char *data; + dma_addr_t data_dma; + char buffer[TOUCHKIT_REPORT_DATA_SIZE]; + int buf_len; + struct urb *irq; + struct usb_device *udev; + struct input_dev *input; + char name[128]; + char phys[64]; +}; + +static struct usb_device_id touchkit_devices[] = { + {USB_DEVICE(0x3823, 0x0001)}, + {USB_DEVICE(0x0123, 0x0001)}, + {USB_DEVICE(0x0eef, 0x0001)}, + {USB_DEVICE(0x0eef, 0x0002)}, + {} +}; + +/* helpers to read the data */ +static inline int touchkit_get_touched(char *data) +{ + return (data[0] & TOUCHKIT_DOWN) ? 1 : 0; +} + +static inline int touchkit_get_x(char *data) +{ + return ((data[3] & 0x0F) << 7) | (data[4] & 0x7F); +} + +static inline int touchkit_get_y(char *data) +{ + return ((data[1] & 0x0F) << 7) | (data[2] & 0x7F); +} + + +/* processes one input packet. */ +static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt) +{ + int x, y; + + /* only process report packets */ + if ((pkt[0] & TOUCHKIT_PKT_TYPE_MASK) != TOUCHKIT_PKT_TYPE_REPT) + return; + + if (swap_xy) { + y = touchkit_get_x(pkt); + x = touchkit_get_y(pkt); + } else { + x = touchkit_get_x(pkt); + y = touchkit_get_y(pkt); + } + + input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt)); + input_report_abs(touchkit->input, ABS_X, x); + input_report_abs(touchkit->input, ABS_Y, y); + input_sync(touchkit->input); +} + + +static int touchkit_get_pkt_len(char *buf) +{ + switch (buf[0] & TOUCHKIT_PKT_TYPE_MASK) { + case TOUCHKIT_PKT_TYPE_REPT: + return 5; + + case TOUCHKIT_PKT_TYPE_DIAG: + return buf[1] + 2; + } + + return 0; +} + +static void touchkit_process(struct touchkit_usb *touchkit, int len) +{ + char *buffer; + int pkt_len, buf_len, pos; + + /* if the buffer contains data, append */ + if (unlikely(touchkit->buf_len)) { + int tmp; + + /* if only 1 byte in buffer, add another one to get length */ + if (touchkit->buf_len == 1) + touchkit->buffer[1] = touchkit->data[0]; + + pkt_len = touchkit_get_pkt_len(touchkit->buffer); + + /* unknown packet: drop everything */ + if (!pkt_len) + return; + + /* append, process */ + tmp = pkt_len - touchkit->buf_len; + memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp); + touchkit_process_pkt(touchkit, touchkit->buffer); + + buffer = touchkit->data + tmp; + buf_len = len - tmp; + } else { + buffer = touchkit->data; + buf_len = len; + } + + /* only one byte left in buffer */ + if (unlikely(buf_len == 1)) { + touchkit->buffer[0] = buffer[0]; + touchkit->buf_len = 1; + return; + } + + /* loop over the buffer */ + pos = 0; + while (pos < buf_len) { + /* get packet len */ + pkt_len = touchkit_get_pkt_len(buffer + pos); + + /* unknown packet: drop everything */ + if (unlikely(!pkt_len)) + return; + + /* full packet: process */ + if (likely(pkt_len <= buf_len)) { + touchkit_process_pkt(touchkit, buffer + pos); + } else { + /* incomplete packet: save in buffer */ + memcpy(touchkit->buffer, buffer + pos, buf_len - pos); + touchkit->buf_len = buf_len - pos; + } + pos += pkt_len; + } +} + + +static void touchkit_irq(struct urb *urb) +{ + struct touchkit_usb *touchkit = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIME: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + touchkit_process(touchkit, urb->actual_length); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int touchkit_open(struct input_dev *input) +{ + struct touchkit_usb *touchkit = input->private; + + touchkit->irq->dev = touchkit->udev; + + if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) + return -EIO; + + return 0; +} + +static void touchkit_close(struct input_dev *input) +{ + struct touchkit_usb *touchkit = input->private; + + usb_kill_urb(touchkit->irq); +} + +static int touchkit_alloc_buffers(struct usb_device *udev, + struct touchkit_usb *touchkit) +{ + touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE, + GFP_ATOMIC, &touchkit->data_dma); + + if (!touchkit->data) + return -1; + + return 0; +} + +static void touchkit_free_buffers(struct usb_device *udev, + struct touchkit_usb *touchkit) +{ + if (touchkit->data) + usb_buffer_free(udev, TOUCHKIT_REPORT_DATA_SIZE, + touchkit->data, touchkit->data_dma); +} + +static int touchkit_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct touchkit_usb *touchkit; + struct input_dev *input_dev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + touchkit = kzalloc(sizeof(struct touchkit_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!touchkit || !input_dev) + goto out_free; + + if (touchkit_alloc_buffers(udev, touchkit)) + goto out_free; + + touchkit->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!touchkit->irq) { + dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__); + goto out_free_buffers; + } + + touchkit->udev = udev; + touchkit->input = input_dev; + + if (udev->manufacturer) + strlcpy(touchkit->name, udev->manufacturer, sizeof(touchkit->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(touchkit->name, " ", sizeof(touchkit->name)); + strlcat(touchkit->name, udev->product, sizeof(touchkit->name)); + } + + if (!strlen(touchkit->name)) + snprintf(touchkit->name, sizeof(touchkit->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, touchkit->phys, sizeof(touchkit->phys)); + strlcpy(touchkit->phys, "/input0", sizeof(touchkit->phys)); + + input_dev->name = touchkit->name; + input_dev->phys = touchkit->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = touchkit; + input_dev->open = touchkit_open; + input_dev->close = touchkit_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, TOUCHKIT_MIN_XC, TOUCHKIT_MAX_XC, + TOUCHKIT_XC_FUZZ, TOUCHKIT_XC_FLAT); + input_set_abs_params(input_dev, ABS_Y, TOUCHKIT_MIN_YC, TOUCHKIT_MAX_YC, + TOUCHKIT_YC_FUZZ, TOUCHKIT_YC_FLAT); + + usb_fill_int_urb(touchkit->irq, touchkit->udev, + usb_rcvintpipe(touchkit->udev, 0x81), + touchkit->data, TOUCHKIT_REPORT_DATA_SIZE, + touchkit_irq, touchkit, endpoint->bInterval); + + touchkit->irq->transfer_dma = touchkit->data_dma; + touchkit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + input_register_device(touchkit->input); + + usb_set_intfdata(intf, touchkit); + return 0; + +out_free_buffers: + touchkit_free_buffers(udev, touchkit); +out_free: + input_free_device(input_dev); + kfree(touchkit); + return -ENOMEM; +} + +static void touchkit_disconnect(struct usb_interface *intf) +{ + struct touchkit_usb *touchkit = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + + if (!touchkit) + return; + + dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__); + usb_set_intfdata(intf, NULL); + usb_kill_urb(touchkit->irq); + input_unregister_device(touchkit->input); + usb_free_urb(touchkit->irq); + touchkit_free_buffers(interface_to_usbdev(intf), touchkit); + kfree(touchkit); +} + +MODULE_DEVICE_TABLE(usb, touchkit_devices); + +static struct usb_driver touchkit_driver = { + .name = "touchkitusb", + .probe = touchkit_probe, + .disconnect = touchkit_disconnect, + .id_table = touchkit_devices, +}; + +static int __init touchkit_init(void) +{ + return usb_register(&touchkit_driver); +} + +static void __exit touchkit_cleanup(void) +{ + usb_deregister(&touchkit_driver); +} + +module_init(touchkit_init); +module_exit(touchkit_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/hid/usbhid/usbhid.h b/trunk/drivers/usb/input/usbhid.h similarity index 100% rename from trunk/drivers/hid/usbhid/usbhid.h rename to trunk/drivers/usb/input/usbhid.h diff --git a/trunk/drivers/hid/usbhid/usbkbd.c b/trunk/drivers/usb/input/usbkbd.c similarity index 98% rename from trunk/drivers/hid/usbhid/usbkbd.c rename to trunk/drivers/usb/input/usbkbd.c index 65aa12e8d7b3..3749f4a235f9 100644 --- a/trunk/drivers/hid/usbhid/usbkbd.c +++ b/trunk/drivers/usb/input/usbkbd.c @@ -228,7 +228,6 @@ static int usb_kbd_probe(struct usb_interface *iface, struct usb_kbd *kbd; struct input_dev *input_dev; int i, pipe, maxp; - int error = -ENOMEM; interface = iface->cur_altsetting; @@ -307,19 +306,15 @@ static int usb_kbd_probe(struct usb_interface *iface, kbd->led->transfer_dma = kbd->leds_dma; kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - error = input_register_device(kbd->dev); - if (error) - goto fail2; + input_register_device(kbd->dev); usb_set_intfdata(iface, kbd); return 0; -fail2: - usb_kbd_free_mem(dev, kbd); -fail1: - input_free_device(input_dev); +fail2: usb_kbd_free_mem(dev, kbd); +fail1: input_free_device(input_dev); kfree(kbd); - return error; + return -ENOMEM; } static void usb_kbd_disconnect(struct usb_interface *intf) diff --git a/trunk/drivers/hid/usbhid/usbmouse.c b/trunk/drivers/usb/input/usbmouse.c similarity index 96% rename from trunk/drivers/hid/usbhid/usbmouse.c rename to trunk/drivers/usb/input/usbmouse.c index 573776d865e1..692fd6087779 100644 --- a/trunk/drivers/hid/usbhid/usbmouse.c +++ b/trunk/drivers/usb/input/usbmouse.c @@ -120,7 +120,6 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i struct usb_mouse *mouse; struct input_dev *input_dev; int pipe, maxp; - int error = -ENOMEM; interface = intf->cur_altsetting; @@ -189,21 +188,15 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i mouse->irq->transfer_dma = mouse->data_dma; mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(mouse->dev); - if (error) - goto fail3; + input_register_device(mouse->dev); usb_set_intfdata(intf, mouse); return 0; -fail3: - usb_free_urb(mouse->irq); -fail2: - usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); -fail1: - input_free_device(input_dev); +fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); +fail1: input_free_device(input_dev); kfree(mouse); - return error; + return -ENOMEM; } static void usb_mouse_disconnect(struct usb_interface *intf) diff --git a/trunk/drivers/usb/input/usbtouchscreen.c b/trunk/drivers/usb/input/usbtouchscreen.c index e0829413336b..86e37a20f8e5 100644 --- a/trunk/drivers/usb/input/usbtouchscreen.c +++ b/trunk/drivers/usb/input/usbtouchscreen.c @@ -647,7 +647,7 @@ static void usbtouch_irq(struct urb *urb) static int usbtouch_open(struct input_dev *input) { - struct usbtouch_usb *usbtouch = input_get_drvdata(input); + struct usbtouch_usb *usbtouch = input->private; usbtouch->irq->dev = usbtouch->udev; @@ -659,7 +659,7 @@ static int usbtouch_open(struct input_dev *input) static void usbtouch_close(struct input_dev *input) { - struct usbtouch_usb *usbtouch = input_get_drvdata(input); + struct usbtouch_usb *usbtouch = input->private; usb_kill_urb(usbtouch->irq); } @@ -740,10 +740,8 @@ static int usbtouch_probe(struct usb_interface *intf, input_dev->name = usbtouch->name; input_dev->phys = usbtouch->phys; usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, usbtouch); - + input_dev->cdev.dev = &intf->dev; + input_dev->private = usbtouch; input_dev->open = usbtouch_open; input_dev->close = usbtouch_close; diff --git a/trunk/drivers/usb/input/wacom_sys.c b/trunk/drivers/usb/input/wacom_sys.c index 1fe48208c2f4..12b42746ded8 100644 --- a/trunk/drivers/usb/input/wacom_sys.c +++ b/trunk/drivers/usb/input/wacom_sys.c @@ -122,7 +122,7 @@ void wacom_input_sync(void *wcombo) static int wacom_open(struct input_dev *dev) { - struct wacom *wacom = input_get_drvdata(dev); + struct wacom *wacom = dev->private; wacom->irq->dev = wacom->usbdev; if (usb_submit_urb(wacom->irq, GFP_KERNEL)) @@ -133,7 +133,7 @@ static int wacom_open(struct input_dev *dev) static void wacom_close(struct input_dev *dev) { - struct wacom *wacom = input_get_drvdata(dev); + struct wacom *wacom = dev->private; usb_kill_urb(wacom->irq); } @@ -201,7 +201,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct wacom *wacom; struct wacom_wac *wacom_wac; struct input_dev *input_dev; - int error = -ENOMEM; char rep_data[2], limit = 0; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); @@ -230,10 +229,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->wacom_wac = wacom_wac; usb_to_input_id(dev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, wacom); - + input_dev->cdev.dev = &intf->dev; + input_dev->private = wacom; input_dev->open = wacom_open; input_dev->close = wacom_close; @@ -255,9 +252,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(wacom->dev); - if (error) - goto fail3; + input_register_device(wacom->dev); /* Ask the tablet to report tablet data. Repeat until it succeeds */ do { @@ -270,12 +265,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_set_intfdata(intf, wacom); return 0; - fail3: usb_free_urb(wacom->irq); - fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); - fail1: input_free_device(input_dev); +fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma); +fail1: input_free_device(input_dev); kfree(wacom); kfree(wacom_wac); - return error; + return -ENOMEM; } static void wacom_disconnect(struct usb_interface *intf) diff --git a/trunk/drivers/usb/input/xpad.c b/trunk/drivers/usb/input/xpad.c index 735723912950..e4bc76ebc835 100644 --- a/trunk/drivers/usb/input/xpad.c +++ b/trunk/drivers/usb/input/xpad.c @@ -267,7 +267,7 @@ static void xpad_irq_in(struct urb *urb) static int xpad_open (struct input_dev *dev) { - struct usb_xpad *xpad = input_get_drvdata(dev); + struct usb_xpad *xpad = dev->private; xpad->irq_in->dev = xpad->udev; if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) @@ -278,7 +278,7 @@ static int xpad_open (struct input_dev *dev) static void xpad_close (struct input_dev *dev) { - struct usb_xpad *xpad = input_get_drvdata(dev); + struct usb_xpad *xpad = dev->private; usb_kill_urb(xpad->irq_in); } @@ -312,7 +312,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; int i; - int error = -ENOMEM; for (i = 0; xpad_device[i].idVendor; i++) { if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && @@ -345,10 +344,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->name = xpad_device[i].name; input_dev->phys = xpad->phys; usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, xpad); - + input_dev->cdev.dev = &intf->dev; + input_dev->private = xpad; input_dev->open = xpad_open; input_dev->close = xpad_close; @@ -376,18 +373,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(xpad->dev); - if (error) - goto fail3; + input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; - fail3: usb_free_urb(xpad->irq_in); - fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); - fail1: input_free_device(input_dev); +fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +fail1: input_free_device(input_dev); kfree(xpad); - return error; + return -ENOMEM; } diff --git a/trunk/drivers/usb/input/yealink.c b/trunk/drivers/usb/input/yealink.c index c54f1a5dcb4a..caff8e6d7448 100644 --- a/trunk/drivers/usb/input/yealink.c +++ b/trunk/drivers/usb/input/yealink.c @@ -502,7 +502,7 @@ static int input_ev(struct input_dev *dev, unsigned int type, static int input_open(struct input_dev *dev) { - struct yealink_dev *yld = input_get_drvdata(dev); + struct yealink_dev *yld = dev->private; int i, ret; dbg("%s", __FUNCTION__); @@ -529,7 +529,7 @@ static int input_open(struct input_dev *dev) static void input_close(struct input_dev *dev) { - struct yealink_dev *yld = input_get_drvdata(dev); + struct yealink_dev *yld = dev->private; usb_kill_urb(yld->urb_ctl); usb_kill_urb(yld->urb_irq); @@ -937,10 +937,9 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) input_dev->name = nfo->name; input_dev->phys = yld->phys; usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, yld); + input_dev->cdev.dev = &intf->dev; + input_dev->private = yld; input_dev->open = input_open; input_dev->close = input_close; /* input_dev->event = input_ev; TODO */ @@ -956,9 +955,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) } } - ret = input_register_device(yld->idev); - if (ret) - return usb_cleanup(yld, ret); + input_register_device(yld->idev); usb_set_intfdata(intf, yld); diff --git a/trunk/drivers/usb/misc/adutux.c b/trunk/drivers/usb/misc/adutux.c index 77145f9db043..75bfab95ab3c 100644 --- a/trunk/drivers/usb/misc/adutux.c +++ b/trunk/drivers/usb/misc/adutux.c @@ -285,24 +285,23 @@ static int adu_open(struct inode *inode, struct file *file) /* save device in the file's private structure */ file->private_data = dev; - if (dev->open_count == 1) { - /* initialize in direction */ - dev->read_buffer_length = 0; + /* initialize in direction */ + dev->read_buffer_length = 0; + + /* fixup first read by having urb waiting for it */ + usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, + usb_rcvintpipe(dev->udev, + dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), + adu_interrupt_in_callback, dev, + dev->interrupt_in_endpoint->bInterval); + /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ + dev->read_urb_finished = 0; + usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + /* we ignore failure */ + /* end of fixup for first read */ - /* fixup first read by having urb waiting for it */ - usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), - adu_interrupt_in_callback, dev, - dev->interrupt_in_endpoint->bInterval); - /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ - dev->read_urb_finished = 0; - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); - if (retval) - --dev->open_count; - } up(&dev->sem); exit_no_device: @@ -470,7 +469,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, adu_interrupt_in_callback, dev, dev->interrupt_in_endpoint->bInterval); - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); if (!retval) { spin_unlock_irqrestore(&dev->buflock, flags); dbg(2," %s : submitted OK", __FUNCTION__); @@ -540,7 +539,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, size_t bytes_written = 0; size_t bytes_to_write; size_t buffer_size; - int retval; + int retval = 0; int timeout = 0; dbg(2," %s : enter, count = %Zd", __FUNCTION__, count); @@ -548,9 +547,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, dev = file->private_data; /* lock this object */ - retval = down_interruptible(&dev->sem); - if (retval) - goto exit_nolock; + down_interruptible(&dev->sem); /* verify that the device wasn't unplugged */ if (dev->udev == NULL || dev->minor == 0) { @@ -578,11 +575,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, } up(&dev->sem); timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout); - retval = down_interruptible(&dev->sem); - if (retval) { - retval = bytes_written ? bytes_written : retval; - goto exit_nolock; - } + down_interruptible(&dev->sem); if (timeout > 0) { break; } @@ -644,7 +637,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, exit: /* unlock the device */ up(&dev->sem); -exit_nolock: dbg(2," %s : leave, return value %d", __FUNCTION__, retval); diff --git a/trunk/drivers/usb/misc/cypress_cy7c63.c b/trunk/drivers/usb/misc/cypress_cy7c63.c index d721380b242d..b63b5f34b2aa 100644 --- a/trunk/drivers/usb/misc/cypress_cy7c63.c +++ b/trunk/drivers/usb/misc/cypress_cy7c63.c @@ -246,13 +246,11 @@ static void cypress_disconnect(struct usb_interface *interface) struct cypress *dev; dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); /* remove device attribute files */ device_remove_file(&interface->dev, &dev_attr_port0); device_remove_file(&interface->dev, &dev_attr_port1); - /* the intfdata can be set to NULL only after the - * device files have been removed */ - usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); diff --git a/trunk/drivers/usb/misc/ftdi-elan.c b/trunk/drivers/usb/misc/ftdi-elan.c index e2172e5cf152..bc3327e3dd78 100644 --- a/trunk/drivers/usb/misc/ftdi-elan.c +++ b/trunk/drivers/usb/misc/ftdi-elan.c @@ -2304,6 +2304,7 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) #define OHCI_QUIRK_SUPERIO 0x02 #define OHCI_QUIRK_INITRESET 0x04 #define OHCI_BIG_ENDIAN 0x08 +#define OHCI_QUIRK_ZFMICRO 0x10 #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ OHCI_INTR_WDH) @@ -2909,28 +2910,24 @@ static int __init ftdi_elan_init(void) INIT_LIST_HEAD(&ftdi_static_list); status_queue = create_singlethread_workqueue("ftdi-status-control"); if (!status_queue) - goto err_status_queue; + goto err1; command_queue = create_singlethread_workqueue("ftdi-command-engine"); if (!command_queue) - goto err_command_queue; + goto err2; respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); if (!respond_queue) - goto err_respond_queue; + goto err3; result = usb_register(&ftdi_elan_driver); - if (result) { - destroy_workqueue(status_queue); - destroy_workqueue(command_queue); - destroy_workqueue(respond_queue); + if (result) printk(KERN_ERR "usb_register failed. Error number %d\n", result); - } return result; - err_respond_queue: + err3: destroy_workqueue(command_queue); - err_command_queue: + err2: destroy_workqueue(status_queue); - err_status_queue: + err1: printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); return -ENOMEM; } diff --git a/trunk/drivers/usb/misc/iowarrior.c b/trunk/drivers/usb/misc/iowarrior.c index fc51207b71b8..d69665c8de02 100644 --- a/trunk/drivers/usb/misc/iowarrior.c +++ b/trunk/drivers/usb/misc/iowarrior.c @@ -118,7 +118,7 @@ static int usb_get_report(struct usb_device *dev, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, inter->desc.bInterfaceNumber, buf, size, - GET_TIMEOUT*HZ); + GET_TIMEOUT); } //#endif @@ -133,7 +133,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, intf->cur_altsetting->desc.bInterfaceNumber, buf, - size, HZ); + size, 1); } /*---------------------*/ @@ -417,14 +417,14 @@ static ssize_t iowarrior_write(struct file *file, if (!int_out_urb) { retval = -ENOMEM; dbg("%s Unable to allocate urb ", __func__); - goto error_no_urb; + goto error; } buf = usb_buffer_alloc(dev->udev, dev->report_size, GFP_KERNEL, &int_out_urb->transfer_dma); if (!buf) { retval = -ENOMEM; dbg("%s Unable to allocate buffer ", __func__); - goto error_no_buffer; + goto error; } usb_fill_int_urb(int_out_urb, dev->udev, usb_sndintpipe(dev->udev, @@ -459,9 +459,7 @@ static ssize_t iowarrior_write(struct file *file, error: usb_buffer_free(dev->udev, dev->report_size, buf, int_out_urb->transfer_dma); -error_no_buffer: usb_free_urb(int_out_urb); -error_no_urb: atomic_dec(&dev->write_busy); wake_up_interruptible(&dev->write_wait); exit: @@ -750,6 +748,7 @@ static int iowarrior_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *endpoint; int i; int retval = -ENOMEM; + int idele = 0; /* allocate memory for our device state and intialize it */ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); @@ -825,10 +824,11 @@ static int iowarrior_probe(struct usb_interface *interface, /* Set the idle timeout to 0, if this is interface 0 */ if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x0A, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0A, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("idele = %d", idele); } /* allow device read and ioctl */ dev->present = 1; diff --git a/trunk/drivers/usb/misc/ldusb.c b/trunk/drivers/usb/misc/ldusb.c index 11555bde655b..788a11e6772f 100644 --- a/trunk/drivers/usb/misc/ldusb.c +++ b/trunk/drivers/usb/misc/ldusb.c @@ -62,8 +62,6 @@ #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 -#define USB_VENDOR_ID_MICROCHIP 0x04d8 -#define USB_DEVICE_ID_PICDEM 0x000c #ifdef CONFIG_USB_DYNAMIC_MINORS #define USB_LD_MINOR_BASE 0 @@ -91,7 +89,6 @@ static struct usb_device_id ld_usb_table [] = { { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, - { USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, ld_usb_table); diff --git a/trunk/drivers/usb/misc/usblcd.c b/trunk/drivers/usb/misc/usblcd.c index 887ef953f3d8..ada2ebc464ae 100644 --- a/trunk/drivers/usb/misc/usblcd.c +++ b/trunk/drivers/usb/misc/usblcd.c @@ -47,7 +47,6 @@ struct usb_lcd { #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) static struct usb_driver lcd_driver; -static DEFINE_MUTEX(usb_lcd_open_mutex); static void lcd_delete(struct kref *kref) @@ -69,7 +68,6 @@ static int lcd_open(struct inode *inode, struct file *file) subminor = iminor(inode); - mutex_lock(&usb_lcd_open_mutex); interface = usb_find_interface(&lcd_driver, subminor); if (!interface) { err ("USBLCD: %s - error, can't find device for minor %d", @@ -91,7 +89,6 @@ static int lcd_open(struct inode *inode, struct file *file) file->private_data = dev; exit: - mutex_unlock(&usb_lcd_open_mutex); return retval; } @@ -350,7 +347,7 @@ static void lcd_disconnect(struct usb_interface *interface) int minor = interface->minor; /* prevent skel_open() from racing skel_disconnect() */ - mutex_lock(&usb_lcd_open_mutex); + lock_kernel(); dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); @@ -358,7 +355,7 @@ static void lcd_disconnect(struct usb_interface *interface) /* give back our minor */ usb_deregister_dev(interface, &lcd_class); - mutex_unlock(&usb_lcd_open_mutex); + unlock_kernel(); /* decrement our usage count */ kref_put(&dev->kref, lcd_delete); diff --git a/trunk/drivers/usb/mon/mon_bin.c b/trunk/drivers/usb/mon/mon_bin.c index 0af11a66207c..b2bedd974ac3 100644 --- a/trunk/drivers/usb/mon/mon_bin.c +++ b/trunk/drivers/usb/mon/mon_bin.c @@ -356,10 +356,8 @@ static inline char mon_bin_get_setup(unsigned char *setupb, if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; @@ -371,8 +369,7 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, unsigned int offset, struct urb *urb, unsigned int length) { - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) { mon_dmapeek_vec(rp, offset, urb->transfer_dma, length); return 0; } @@ -443,7 +440,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, /* We use the fact that usb_pipein() returns 0x80 */ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); ep->devnum = usb_pipedevice(urb->pipe); - ep->busnum = urb->dev->bus->busnum; + ep->busnum = rp->r.m_bus->u_bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; @@ -503,7 +500,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error) /* We use the fact that usb_pipein() returns 0x80 */ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); ep->devnum = usb_pipedevice(urb->pipe); - ep->busnum = urb->dev->bus->busnum; + ep->busnum = rp->r.m_bus->u_bus->busnum; ep->id = (unsigned long) urb; ep->status = error; @@ -518,6 +515,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error) static int mon_bin_open(struct inode *inode, struct file *file) { struct mon_bus *mbus; + struct usb_bus *ubus; struct mon_reader_bin *rp; size_t size; int rc; @@ -527,7 +525,7 @@ static int mon_bin_open(struct inode *inode, struct file *file) mutex_unlock(&mon_lock); return -ENODEV; } - if (mbus != &mon_bus0 && mbus->u_bus == NULL) { + if ((ubus = mbus->u_bus) == NULL) { printk(KERN_ERR TAG ": consistency error on open\n"); mutex_unlock(&mon_lock); return -ENODEV; diff --git a/trunk/drivers/usb/mon/mon_main.c b/trunk/drivers/usb/mon/mon_main.c index 8a1df2c9c73e..c9739e7b35e5 100644 --- a/trunk/drivers/usb/mon/mon_main.c +++ b/trunk/drivers/usb/mon/mon_main.c @@ -16,6 +16,8 @@ #include "usb_mon.h" #include "../core/hcd.h" +static void mon_submit(struct usb_bus *ubus, struct urb *urb); +static void mon_complete(struct usb_bus *ubus, struct urb *urb); static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); @@ -23,7 +25,6 @@ static void mon_bus_init(struct usb_bus *ubus); DEFINE_MUTEX(mon_lock); -struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ /* @@ -34,19 +35,22 @@ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) { unsigned long flags; - struct list_head *p; + struct usb_bus *ubus; spin_lock_irqsave(&mbus->lock, flags); if (mbus->nreaders == 0) { - if (mbus == &mon_bus0) { - list_for_each (p, &mon_buses) { - struct mon_bus *m1; - m1 = list_entry(p, struct mon_bus, bus_link); - m1->u_bus->monitored = 1; - } - } else { - mbus->u_bus->monitored = 1; + ubus = mbus->u_bus; + if (ubus->monitored) { + /* + * Something is really broken, refuse to go on and + * possibly corrupt ops pointers or worse. + */ + printk(KERN_ERR TAG ": bus %d is already monitored\n", + ubus->busnum); + spin_unlock_irqrestore(&mbus->lock, flags); + return; } + ubus->monitored = 1; } mbus->nreaders++; list_add_tail(&r->r_link, &mbus->r_list); @@ -76,79 +80,77 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r) /* */ -static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) +static void mon_submit(struct usb_bus *ubus, struct urb *urb) { + struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; + mbus = ubus->mon_bus; + if (mbus == NULL) + goto out_unlocked; + spin_lock_irqsave(&mbus->lock, flags); + if (mbus->nreaders == 0) + goto out_locked; + mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_submit(r->r_data, urb); } + spin_unlock_irqrestore(&mbus->lock, flags); return; -} - -static void mon_submit(struct usb_bus *ubus, struct urb *urb) -{ - struct mon_bus *mbus; - if ((mbus = ubus->mon_bus) != NULL) - mon_bus_submit(mbus, urb); - mon_bus_submit(&mon_bus0, urb); +out_locked: + spin_unlock_irqrestore(&mbus->lock, flags); +out_unlocked: + return; } /* */ -static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) +static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) { + struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; + mbus = ubus->mon_bus; + if (mbus == NULL) + goto out_unlocked; + spin_lock_irqsave(&mbus->lock, flags); + if (mbus->nreaders == 0) + goto out_locked; + mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_error(r->r_data, urb, error); } + spin_unlock_irqrestore(&mbus->lock, flags); return; -} -static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) -{ - struct mon_bus *mbus; - - if ((mbus = ubus->mon_bus) != NULL) - mon_bus_submit_error(mbus, urb, error); - mon_bus_submit_error(&mon_bus0, urb, error); +out_locked: + spin_unlock_irqrestore(&mbus->lock, flags); +out_unlocked: + return; } /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb) { + struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; - spin_lock_irqsave(&mbus->lock, flags); - mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); - } - spin_unlock_irqrestore(&mbus->lock, flags); -} - -static void mon_complete(struct usb_bus *ubus, struct urb *urb) -{ - struct mon_bus *mbus; - mbus = ubus->mon_bus; if (mbus == NULL) { /* @@ -160,8 +162,13 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) return; } - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + spin_lock_irqsave(&mbus->lock, flags); + mbus->cnt_events++; + list_for_each (pos, &mbus->r_list) { + r = list_entry(pos, struct mon_reader, r_link); + r->rnf_complete(r->r_data, urb); + } + spin_unlock_irqrestore(&mbus->lock, flags); } /* int (*unlink_urb) (struct urb *urb, int status); */ @@ -172,26 +179,14 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) static void mon_stop(struct mon_bus *mbus) { struct usb_bus *ubus = mbus->u_bus; - struct list_head *p; - if (mbus == &mon_bus0) { - list_for_each (p, &mon_buses) { - mbus = list_entry(p, struct mon_bus, bus_link); - /* - * We do not change nreaders here, so rely on mon_lock. - */ - if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL) - ubus->monitored = 0; - } - } else { - /* - * A stop can be called for a dissolved mon_bus in case of - * a reader staying across an rmmod foo_hcd, so test ->u_bus. - */ - if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) { - ubus->monitored = 0; - mb(); - } + /* + * A stop can be called for a dissolved mon_bus in case of + * a reader staying across an rmmod foo_hcd. + */ + if (ubus != NULL) { + ubus->monitored = 0; + mb(); } } @@ -204,10 +199,6 @@ static void mon_stop(struct mon_bus *mbus) static void mon_bus_add(struct usb_bus *ubus) { mon_bus_init(ubus); - mutex_lock(&mon_lock); - if (mon_bus0.nreaders != 0) - ubus->monitored = 1; - mutex_unlock(&mon_lock); } /* @@ -259,7 +250,12 @@ static struct usb_mon_operations mon_ops_0 = { static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) { + /* + * Never happens, but... + */ if (ubus->monitored) { + printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n", + ubus->busnum); ubus->monitored = 0; mb(); } @@ -267,8 +263,6 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) ubus->mon_bus = NULL; mbus->u_bus = NULL; mb(); - - /* We want synchronize_irq() here, but that needs an argument. */ } /* @@ -301,8 +295,9 @@ static void mon_bus_init(struct usb_bus *ubus) */ mbus->u_bus = ubus; ubus->mon_bus = mbus; + mbus->uses_dma = ubus->uses_dma; - mbus->text_inited = mon_text_add(mbus, ubus->busnum); + mbus->text_inited = mon_text_add(mbus, ubus); // mon_bin_add(...) mutex_lock(&mon_lock); @@ -314,18 +309,6 @@ static void mon_bus_init(struct usb_bus *ubus) return; } -static void mon_bus0_init(void) -{ - struct mon_bus *mbus = &mon_bus0; - - kref_init(&mbus->ref); - spin_lock_init(&mbus->lock); - INIT_LIST_HEAD(&mbus->r_list); - - mbus->text_inited = mon_text_add(mbus, 0); - // mbus->bin_inited = mon_bin_add(mbus, 0); -} - /* * Search a USB bus by number. Notice that USB bus numbers start from one, * which we may later use to identify "all" with zero. @@ -339,9 +322,6 @@ struct mon_bus *mon_bus_lookup(unsigned int num) struct list_head *p; struct mon_bus *mbus; - if (num == 0) { - return &mon_bus0; - } list_for_each (p, &mon_buses) { mbus = list_entry(p, struct mon_bus, bus_link); if (mbus->u_bus->busnum == num) { @@ -361,8 +341,6 @@ static int __init mon_init(void) if ((rc = mon_bin_init()) != 0) goto err_bin; - mon_bus0_init(); - if (usb_mon_register(&mon_ops_0) != 0) { printk(KERN_NOTICE TAG ": unable to register with the core\n"); rc = -ENODEV; @@ -396,7 +374,6 @@ static void __exit mon_exit(void) usb_mon_deregister(); mutex_lock(&mon_lock); - while (!list_empty(&mon_buses)) { p = mon_buses.next; mbus = list_entry(p, struct mon_bus, bus_link); @@ -420,11 +397,6 @@ static void __exit mon_exit(void) mon_dissolve(mbus, mbus->u_bus); kref_put(&mbus->ref, mon_bus_drop); } - - mbus = &mon_bus0; - if (mbus->text_inited) - mon_text_del(mbus); - mutex_unlock(&mon_lock); mon_text_exit(); diff --git a/trunk/drivers/usb/mon/mon_text.c b/trunk/drivers/usb/mon/mon_text.c index ec0cc51e39ac..494ee3b9a226 100644 --- a/trunk/drivers/usb/mon/mon_text.c +++ b/trunk/drivers/usb/mon/mon_text.c @@ -31,21 +31,9 @@ * to a local DoS. But we have to keep to root in order to prevent * password sniffing from HID devices. */ -#define EVENT_MAX (4*PAGE_SIZE / sizeof(struct mon_event_text)) +#define EVENT_MAX (2*PAGE_SIZE / sizeof(struct mon_event_text)) -/* - * Potentially unlimited number; we limit it for similar allocations. - * The usbfs limits this to 128, but we're not quite as generous. - */ -#define ISODESC_MAX 5 - -#define PRINTF_DFL 250 /* with 5 ISOs segs */ - -struct mon_iso_desc { - int status; - unsigned int offset; - unsigned int length; /* Unsigned here, signed in URB. Historic. */ -}; +#define PRINTF_DFL 160 struct mon_event_text { struct list_head e_link; @@ -53,16 +41,10 @@ struct mon_event_text { unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; - int busnum; int length; /* Depends on type: xfer length or act length */ int status; - int interval; - int start_frame; - int error_count; char setup_flag; char data_flag; - int numdesc; /* Full number */ - struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; unsigned char data[DATA_MAX]; }; @@ -86,28 +68,6 @@ static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); -struct mon_text_ptr { - int cnt, limit; - char *pbuf; -}; - -static struct mon_event_text * - mon_text_read_wait(struct mon_reader_text *rp, struct file *file); -static void mon_text_read_head_t(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_head_u(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_statset(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_intstat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_isostat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_isodesc(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_data(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); - /* * mon_text_submit * mon_text_complete @@ -124,10 +84,8 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ @@ -146,10 +104,10 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, len = DATA_MAX; if (usb_pipein(pipe)) { - if (ev_type != 'C') + if (ev_type == 'S') return '<'; } else { - if (ev_type != 'S') + if (ev_type == 'C') return '>'; } @@ -162,10 +120,8 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, * contain non-NULL garbage in case the upper level promised to * set DMA for the HCD. */ - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) return mon_dmapeek(ep->data, urb->transfer_dma, len); - } if (urb->transfer_buffer == NULL) return 'Z'; /* '0' would be not as pretty. */ @@ -190,9 +146,6 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, { struct mon_event_text *ep; unsigned int stamp; - struct usb_iso_packet_descriptor *fp; - struct mon_iso_desc *dp; - int i, ndesc; stamp = mon_get_timestamp(); @@ -205,36 +158,12 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, ep->type = ev_type; ep->pipe = urb->pipe; ep->id = (unsigned long) urb; - ep->busnum = urb->dev->bus->busnum; ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; - if (usb_pipeint(urb->pipe)) { - ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { - ep->interval = urb->interval; - ep->start_frame = urb->start_frame; - ep->error_count = urb->error_count; - } - ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { - if ((ndesc = urb->number_of_packets) > ISODESC_MAX) - ndesc = ISODESC_MAX; - fp = urb->iso_frame_desc; - dp = ep->isodesc; - for (i = 0; i < ndesc; i++) { - dp->status = fp->status; - dp->offset = fp->offset; - dp->length = (ev_type == 'S') ? - fp->length : fp->actual_length; - fp++; - dp++; - } - } - ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus); ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type, rp->r.m_bus); @@ -270,7 +199,6 @@ static void mon_text_error(void *data, struct urb *urb, int error) ep->type = 'E'; ep->pipe = urb->pipe; ep->id = (unsigned long) urb; - ep->busnum = 0; ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -309,11 +237,13 @@ static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp, static int mon_text_open(struct inode *inode, struct file *file) { struct mon_bus *mbus; + struct usb_bus *ubus; struct mon_reader_text *rp; int rc; mutex_lock(&mon_lock); mbus = inode->i_private; + ubus = mbus->u_bus; rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); if (rp == NULL) { @@ -337,7 +267,8 @@ static int mon_text_open(struct inode *inode, struct file *file) rp->r.rnf_error = mon_text_error; rp->r.rnf_complete = mon_text_complete; - snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); + snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum, + (long)rp); rp->e_slab = kmem_cache_create(rp->slab_name, sizeof(struct mon_event_text), sizeof(long), 0, mon_text_ctor, NULL); @@ -369,75 +300,17 @@ static int mon_text_open(struct inode *inode, struct file *file) * dd if=/dbg/usbmon/0t bs=10 * Also, we do not allow seeks and do not bother advancing the offset. */ -static ssize_t mon_text_read_t(struct file *file, char __user *buf, +static ssize_t mon_text_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { struct mon_reader_text *rp = file->private_data; - struct mon_event_text *ep; - struct mon_text_ptr ptr; - - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - return PTR_ERR(ep); - mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - - mon_text_read_head_t(rp, &ptr, ep); - mon_text_read_statset(rp, &ptr, ep); - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; - mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; -} - -static ssize_t mon_text_read_u(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct mon_reader_text *rp = file->private_data; - struct mon_event_text *ep; - struct mon_text_ptr ptr; - - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - return PTR_ERR(ep); - mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - - mon_text_read_head_u(rp, &ptr, ep); - if (ep->type == 'E') { - mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { - mon_text_read_isostat(rp, &ptr, ep); - mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { - mon_text_read_intstat(rp, &ptr, ep); - } else { - mon_text_read_statset(rp, &ptr, ep); - } - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; - mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; -} - -static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, - struct file *file) -{ struct mon_bus *mbus = rp->r.m_bus; DECLARE_WAITQUEUE(waita, current); struct mon_event_text *ep; + int cnt, limit; + char *pbuf; + char udir, utype; + int data_len, i; add_wait_queue(&rp->wait, &waita); set_current_state(TASK_INTERRUPTIBLE); @@ -445,7 +318,7 @@ static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, if (file->f_flags & O_NONBLOCK) { set_current_state(TASK_RUNNING); remove_wait_queue(&rp->wait, &waita); - return ERR_PTR(-EWOULDBLOCK); + return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ } /* * We do not count nwaiters, because ->release is supposed @@ -454,19 +327,17 @@ static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, schedule(); if (signal_pending(current)) { remove_wait_queue(&rp->wait, &waita); - return ERR_PTR(-EINTR); + return -EINTR; } set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); remove_wait_queue(&rp->wait, &waita); - return ep; -} -static void mon_text_read_head_t(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - char udir, utype; + mutex_lock(&rp->printf_lock); + cnt = 0; + pbuf = rp->printf_buf; + limit = rp->printf_size; udir = usb_pipein(ep->pipe) ? 'i' : 'o'; switch (usb_pipetype(ep->pipe)) { @@ -475,38 +346,13 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, case PIPE_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); -} - -static void mon_text_read_head_u(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - char udir, utype; - - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; - default: /* PIPE_BULK */ utype = 'B'; - } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - "%lx %u %c %c%c:%d:%03u:%u", - ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); -} - -static void mon_text_read_statset(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ + utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); if (ep->setup_flag == 0) { /* Setup packet is present and captured */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, " s %02x %02x %04x %04x %04x", ep->setup[0], ep->setup[1], @@ -514,86 +360,40 @@ static void mon_text_read_statset(struct mon_reader_text *rp, (ep->setup[5] << 8) | ep->setup[4], (ep->setup[7] << 8) | ep->setup[6]); } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, " %c __ __ ____ ____ ____", ep->setup_flag); } else { /* No setup for this kind of URB */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d", ep->status); + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status); } -} - -static void mon_text_read_intstat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d", ep->status, ep->interval); -} - -static void mon_text_read_isostat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - if (ep->type == 'S') { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d:%d", ep->status, ep->interval, ep->start_frame); - } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d:%d:%d", - ep->status, ep->interval, ep->start_frame, ep->error_count); - } -} - -static void mon_text_read_isodesc(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - int ndesc; /* Display this many */ - int i; - const struct mon_iso_desc *dp; - - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d", ep->numdesc); - ndesc = ep->numdesc; - if (ndesc > ISODESC_MAX) - ndesc = ISODESC_MAX; - if (ndesc < 0) - ndesc = 0; - dp = ep->isodesc; - for (i = 0; i < ndesc; i++) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%u:%u", dp->status, dp->offset, dp->length); - dp++; - } -} - -static void mon_text_read_data(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - int data_len, i; + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length); if ((data_len = ep->length) > 0) { if (ep->data_flag == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " ="); + cnt += snprintf(pbuf + cnt, limit - cnt, " ="); if (data_len >= DATA_MAX) data_len = DATA_MAX; for (i = 0; i < data_len; i++) { if (i % 4 == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, - p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, " "); } - p->cnt += snprintf(p->pbuf + p->cnt, - p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, "%02x", ep->data[i]); } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - "\n"); + cnt += snprintf(pbuf + cnt, limit - cnt, "\n"); } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, + cnt += snprintf(pbuf + cnt, limit - cnt, " %c\n", ep->data_flag); } } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n"); + cnt += snprintf(pbuf + cnt, limit - cnt, "\n"); } + + if (copy_to_user(buf, rp->printf_buf, cnt)) + cnt = -EFAULT; + mutex_unlock(&rp->printf_lock); + kmem_cache_free(rp->e_slab, ep); + return cnt; } static int mon_text_release(struct inode *inode, struct file *file) @@ -639,46 +439,34 @@ static int mon_text_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations mon_fops_text_t = { +static const struct file_operations mon_fops_text = { .owner = THIS_MODULE, .open = mon_text_open, .llseek = no_llseek, - .read = mon_text_read_t, + .read = mon_text_read, + /* .write = mon_text_write, */ + /* .poll = mon_text_poll, */ + /* .ioctl = mon_text_ioctl, */ .release = mon_text_release, }; -static const struct file_operations mon_fops_text_u = { - .owner = THIS_MODULE, - .open = mon_text_open, - .llseek = no_llseek, - .read = mon_text_read_u, - .release = mon_text_release, -}; - -int mon_text_add(struct mon_bus *mbus, int busnum) +int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) { struct dentry *d; enum { NAMESZ = 10 }; char name[NAMESZ]; int rc; - rc = snprintf(name, NAMESZ, "%dt", busnum); + rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); if (rc <= 0 || rc >= NAMESZ) goto err_print_t; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t); + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text); if (d == NULL) goto err_create_t; mbus->dent_t = d; - rc = snprintf(name, NAMESZ, "%du", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_u; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u); - if (d == NULL) - goto err_create_u; - mbus->dent_u = d; - - rc = snprintf(name, NAMESZ, "%ds", busnum); + /* XXX The stats do not belong to here (text API), but oh well... */ + rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); if (rc <= 0 || rc >= NAMESZ) goto err_print_s; d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); @@ -690,10 +478,6 @@ int mon_text_add(struct mon_bus *mbus, int busnum) err_create_s: err_print_s: - debugfs_remove(mbus->dent_u); - mbus->dent_u = NULL; -err_create_u: -err_print_u: debugfs_remove(mbus->dent_t); mbus->dent_t = NULL; err_create_t: @@ -703,7 +487,6 @@ int mon_text_add(struct mon_bus *mbus, int busnum) void mon_text_del(struct mon_bus *mbus) { - debugfs_remove(mbus->dent_u); debugfs_remove(mbus->dent_t); debugfs_remove(mbus->dent_s); } diff --git a/trunk/drivers/usb/mon/usb_mon.h b/trunk/drivers/usb/mon/usb_mon.h index 13d63255283e..efdfd8993d9e 100644 --- a/trunk/drivers/usb/mon/usb_mon.h +++ b/trunk/drivers/usb/mon/usb_mon.h @@ -22,7 +22,7 @@ struct mon_bus { int text_inited; struct dentry *dent_s; /* Debugging file */ struct dentry *dent_t; /* Text interface file */ - struct dentry *dent_u; /* Second text interface file */ + int uses_dma; /* Ref */ int nreaders; /* Under mon_lock AND mbus->lock */ @@ -52,7 +52,7 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); struct mon_bus *mon_bus_lookup(unsigned int num); -int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum); +int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus); void mon_text_del(struct mon_bus *mbus); // void mon_bin_add(struct mon_bus *); @@ -81,6 +81,4 @@ extern struct mutex mon_lock; extern const struct file_operations mon_fops_stat; -extern struct mon_bus mon_bus0; /* Only for redundant checks */ - #endif /* __USB_MON_H */ diff --git a/trunk/drivers/usb/net/asix.c b/trunk/drivers/usb/net/asix.c index d5ef97bc4d01..5808ea082459 100644 --- a/trunk/drivers/usb/net/asix.c +++ b/trunk/drivers/usb/net/asix.c @@ -298,7 +298,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (ax_skb) { ax_skb->len = size; ax_skb->data = packet; - skb_set_tail_pointer(ax_skb, size); + ax_skb->tail = packet + size; usbnet_skb_return(dev, ax_skb); } else { return 0; @@ -338,7 +338,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, && ((headroom + tailroom) >= (4 + padlen))) { if ((headroom < 4) || (tailroom < padlen)) { skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); + skb->tail = skb->data + skb->len; } } else { struct sk_buff *skb2; @@ -352,11 +352,11 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_push(skb, 4); packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); cpu_to_le32s(&packet_len); - skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); + memcpy(skb->data, &packet_len, sizeof(packet_len)); if ((skb->len % 512) == 0) { cpu_to_le32s(&padbytes); - memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); + memcpy( skb->tail, &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); } return skb; diff --git a/trunk/drivers/usb/net/catc.c b/trunk/drivers/usb/net/catc.c index 86e90c59d551..4852012735f6 100644 --- a/trunk/drivers/usb/net/catc.c +++ b/trunk/drivers/usb/net/catc.c @@ -255,6 +255,7 @@ static void catc_rx_done(struct urb *urb) if (!(skb = dev_alloc_skb(pkt_len))) return; + skb->dev = catc->netdev; eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0); skb_put(skb, pkt_len); @@ -355,7 +356,7 @@ static void catc_irq_done(struct urb *urb) * Transmit routines. */ -static int catc_tx_run(struct catc *catc) +static void catc_tx_run(struct catc *catc) { int status; @@ -373,14 +374,12 @@ static int catc_tx_run(struct catc *catc) catc->tx_ptr = 0; catc->netdev->trans_start = jiffies; - return status; } static void catc_tx_done(struct urb *urb) { struct catc *catc = urb->context; unsigned long flags; - int r; if (urb->status == -ECONNRESET) { dbg("Tx Reset."); @@ -399,13 +398,10 @@ static void catc_tx_done(struct urb *urb) spin_lock_irqsave(&catc->tx_lock, flags); - if (catc->tx_ptr) { - r = catc_tx_run(catc); - if (unlikely(r < 0)) - clear_bit(TX_RUNNING, &catc->flags); - } else { + if (catc->tx_ptr) + catc_tx_run(catc); + else clear_bit(TX_RUNNING, &catc->flags); - } netif_wake_queue(catc->netdev); @@ -416,7 +412,6 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct catc *catc = netdev_priv(netdev); unsigned long flags; - int r = 0; char *tx_buf; spin_lock_irqsave(&catc->tx_lock, flags); @@ -424,14 +419,11 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); - skb_copy_from_linear_data(skb, tx_buf + 2, skb->len); + memcpy(tx_buf + 2, skb->data, skb->len); catc->tx_ptr += skb->len + 2; - if (!test_and_set_bit(TX_RUNNING, &catc->flags)) { - r = catc_tx_run(catc); - if (r < 0) - clear_bit(TX_RUNNING, &catc->flags); - } + if (!test_and_set_bit(TX_RUNNING, &catc->flags)) + catc_tx_run(catc); if ((catc->is_f5u011 && catc->tx_ptr) || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) @@ -439,10 +431,8 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) spin_unlock_irqrestore(&catc->tx_lock, flags); - if (r >= 0) { - catc->stats.tx_bytes += skb->len; - catc->stats.tx_packets++; - } + catc->stats.tx_bytes += skb->len; + catc->stats.tx_packets++; dev_kfree_skb(skb); diff --git a/trunk/drivers/usb/net/dm9601.c b/trunk/drivers/usb/net/dm9601.c index a67638601477..5130cc7eb314 100644 --- a/trunk/drivers/usb/net/dm9601.c +++ b/trunk/drivers/usb/net/dm9601.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -86,7 +85,7 @@ static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) usb_sndctrlpipe(dev->udev, 0), DM_WRITE_REG, USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT); + value, reg, 0, 0, USB_CTRL_SET_TIMEOUT); } static void dm_write_async_callback(struct urb *urb) @@ -172,7 +171,7 @@ static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), - (void *)req, NULL, 0, dm_write_async_callback, req); + (void *)req, 0, 0, dm_write_async_callback, req); status = usb_submit_urb(urb, GFP_ATOMIC); if (status < 0) { diff --git a/trunk/drivers/usb/net/gl620a.c b/trunk/drivers/usb/net/gl620a.c index 031cf5ca4dbb..d257a8e026d6 100644 --- a/trunk/drivers/usb/net/gl620a.c +++ b/trunk/drivers/usb/net/gl620a.c @@ -157,7 +157,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { skb->data = memmove(skb->head + (4 + 4*1), skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); + skb->tail = skb->data + skb->len; } } else { struct sk_buff *skb2; diff --git a/trunk/drivers/usb/net/kaweth.c b/trunk/drivers/usb/net/kaweth.c index 60d29440f316..de95268ae4b8 100644 --- a/trunk/drivers/usb/net/kaweth.c +++ b/trunk/drivers/usb/net/kaweth.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -635,6 +636,8 @@ static void kaweth_usb_receive(struct urb *urb) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + skb->dev = net; + eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0); skb_put(skb, pkt_len); diff --git a/trunk/drivers/usb/net/net1080.c b/trunk/drivers/usb/net/net1080.c index 19bf8dae70c9..ccebfdef4751 100644 --- a/trunk/drivers/usb/net/net1080.c +++ b/trunk/drivers/usb/net/net1080.c @@ -520,7 +520,7 @@ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) skb->data = memmove(skb->head + sizeof (struct nc_header), skb->data, skb->len); - skb_set_tail_pointer(skb, len); + skb->tail = skb->data + len; goto encapsulate; } } diff --git a/trunk/drivers/usb/net/pegasus.c b/trunk/drivers/usb/net/pegasus.c index a05fd97e5bc2..d48c024cff59 100644 --- a/trunk/drivers/usb/net/pegasus.c +++ b/trunk/drivers/usb/net/pegasus.c @@ -316,7 +316,6 @@ static int update_eth_regs_async(pegasus_t * pegasus) return ret; } -/* Returns 0 on success, error on failure */ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) { int i; @@ -575,6 +574,7 @@ static void fill_skb_pool(pegasus_t * pegasus) */ if (pegasus->rx_pool[i] == NULL) return; + pegasus->rx_pool[i]->dev = pegasus->net; skb_reserve(pegasus->rx_pool[i], 2); } } @@ -847,6 +847,10 @@ static void intr_callback(struct urb *urb) * d[0].NO_CARRIER kicks in only with failed TX. * ... so monitoring with MII may be safest. */ + if (d[0] & NO_CARRIER) + netif_carrier_off(net); + else + netif_carrier_on(net); /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; @@ -879,7 +883,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) netif_stop_queue(net); ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); - skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len); + memcpy(pegasus->tx_buff + 2, skb->data, skb->len); usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, usb_sndbulkpipe(pegasus->usb, 2), pegasus->tx_buff, count, @@ -946,7 +950,7 @@ static void set_carrier(struct net_device *net) pegasus_t *pegasus = netdev_priv(net); u16 tmp; - if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) + if (!read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) return; if (tmp & BMSR_LSTATUS) @@ -1404,10 +1408,8 @@ static void pegasus_disconnect(struct usb_interface *intf) unlink_all_urbs(pegasus); free_all_urbs(pegasus); free_skb_pool(pegasus); - if (pegasus->rx_skb != NULL) { + if (pegasus->rx_skb) dev_kfree_skb(pegasus->rx_skb); - pegasus->rx_skb = NULL; - } free_netdev(pegasus->net); } diff --git a/trunk/drivers/usb/net/rndis_host.c b/trunk/drivers/usb/net/rndis_host.c index 980e4aaa97aa..39a21c74fdf4 100644 --- a/trunk/drivers/usb/net/rndis_host.c +++ b/trunk/drivers/usb/net/rndis_host.c @@ -253,7 +253,6 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */ * of that mess as possible. */ #define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101) -#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106) #define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e) /* @@ -350,7 +349,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) case RNDIS_MSG_INDICATE: { /* fault */ // struct rndis_indicate *msg = (void *)buf; dev_info(&info->control->dev, - "rndis fault indication\n"); + "rndis fault indication\n"); } break; case RNDIS_MSG_KEEPALIVE: { /* ping */ @@ -388,71 +387,6 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) return -ETIMEDOUT; } -/* - * rndis_query: - * - * Performs a query for @oid along with 0 or more bytes of payload as - * specified by @in_len. If @reply_len is not set to -1 then the reply - * length is checked against this value, resulting in an error if it - * doesn't match. - * - * NOTE: Adding a payload exactly or greater than the size of the expected - * response payload is an evident requirement MSFT added for ActiveSync. - * - * The only exception is for OIDs that return a variably sized response, - * in which case no payload should be added. This undocumented (and - * nonsensical!) issue was found by sniffing protocol requests from the - * ActiveSync 4.1 Windows driver. - */ -static int rndis_query(struct usbnet *dev, struct usb_interface *intf, - void *buf, u32 oid, u32 in_len, - void **reply, int *reply_len) -{ - int retval; - union { - void *buf; - struct rndis_msg_hdr *header; - struct rndis_query *get; - struct rndis_query_c *get_c; - } u; - u32 off, len; - - u.buf = buf; - - memset(u.get, 0, sizeof *u.get + in_len); - u.get->msg_type = RNDIS_MSG_QUERY; - u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); - u.get->oid = oid; - u.get->len = cpu_to_le32(in_len); - u.get->offset = ccpu2(20); - - retval = rndis_command(dev, u.header); - if (unlikely(retval < 0)) { - dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", - oid, retval); - return retval; - } - - off = le32_to_cpu(u.get_c->offset); - len = le32_to_cpu(u.get_c->len); - if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) - goto response_error; - - if (*reply_len != -1 && len != *reply_len) - goto response_error; - - *reply = (unsigned char *) &u.get_c->request_id + off; - *reply_len = len; - - return retval; - -response_error: - dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " - "invalid response - off %d len %d\n", - oid, off, len); - return -EDOM; -} - static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) { int retval; @@ -469,8 +403,6 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) struct rndis_set_c *set_c; } u; u32 tmp; - int reply_len; - unsigned char *bp; /* we can't rely on i/o from stack working, or stack allocation */ u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); @@ -489,12 +421,6 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) * TX we'll stick to one Ethernet packet plus RNDIS framing. * For RX we handle drivers that zero-pad to end-of-packet. * Don't let userspace change these settings. - * - * NOTE: there still seems to be wierdness here, as if we need - * to do some more things to make sure WinCE targets accept this. - * They default to jumbograms of 8KB or 16KB, which is absurd - * for such low data rates and which is also more than Linux - * can usually expect to allocate for SKB data... */ net->hard_header_len += sizeof (struct rndis_data_hdr); dev->hard_mtu = net->mtu + net->hard_header_len; @@ -508,7 +434,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); - goto fail_and_release; + goto fail_and_release; } tmp = le32_to_cpu(u.init_c->max_transfer_size); if (tmp < dev->hard_mtu) { @@ -524,15 +450,34 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) dev->hard_mtu, tmp, dev->rx_urb_size, 1 << le32_to_cpu(u.init_c->packet_alignment)); - /* Get designated host ethernet address */ - reply_len = ETH_ALEN; - retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, - 48, (void **) &bp, &reply_len); - if (unlikely(retval< 0)) { + /* Get designated host ethernet address. + * + * Adding a payload exactly the same size as the expected response + * payload is an evident requirement MSFT added for ActiveSync. + * This undocumented (and nonsensical) issue was found by sniffing + * protocol requests from the ActiveSync 4.1 Windows driver. + */ + memset(u.get, 0, sizeof *u.get + 48); + u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_len = ccpu2(sizeof *u.get + 48); + u.get->oid = OID_802_3_PERMANENT_ADDRESS; + u.get->len = ccpu2(48); + u.get->offset = ccpu2(20); + + retval = rndis_command(dev, u.header); + if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); goto fail_and_release; } - memcpy(net->dev_addr, bp, ETH_ALEN); + tmp = le32_to_cpu(u.get_c->offset); + if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN) + || u.get_c->len != ccpu2(ETH_ALEN))) { + dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", + tmp, le32_to_cpu(u.get_c->len)); + retval = -EDOM; + goto fail_and_release; + } + memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); /* set a nonzero filter to enable data transfers */ memset(u.set, 0, sizeof *u.set); @@ -557,7 +502,6 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) fail_and_release: usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); - info->data = NULL; fail: kfree(u.buf); return retval; @@ -644,7 +588,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) if (likely((sizeof *hdr) <= room)) { skb->data = memmove(skb->head + sizeof *hdr, skb->data, len); - skb_set_tail_pointer(skb, len); + skb->tail = skb->data + len; goto fill; } } @@ -674,7 +618,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) static const struct driver_info rndis_info = { .description = "RNDIS device", - .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_ETHER | FLAG_FRAMING_RN, .bind = rndis_bind, .unbind = rndis_unbind, .status = rndis_status, diff --git a/trunk/drivers/usb/net/rtl8150.c b/trunk/drivers/usb/net/rtl8150.c index fa598f0340cf..ea153dc9b0ac 100644 --- a/trunk/drivers/usb/net/rtl8150.c +++ b/trunk/drivers/usb/net/rtl8150.c @@ -646,6 +646,7 @@ static void fill_skb_pool(rtl8150_t *dev) if (!skb) { return; } + skb->dev = dev->netdev; skb_reserve(skb, 2); dev->rx_skb_pool[i] = skb; } diff --git a/trunk/drivers/usb/net/usbnet.c b/trunk/drivers/usb/net/usbnet.c index f9cd42d058b0..de69b183bd2f 100644 --- a/trunk/drivers/usb/net/usbnet.c +++ b/trunk/drivers/usb/net/usbnet.c @@ -203,6 +203,7 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { int status; + skb->dev = dev->net; skb->protocol = eth_type_trans (skb, dev->net); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -734,7 +735,8 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { struct usbnet *dev = netdev_priv(net); - strncpy (info->driver, dev->driver_name, sizeof info->driver); + /* REVISIT don't always return "usbnet" */ + strncpy (info->driver, driver_name, sizeof info->driver); strncpy (info->version, DRIVER_VERSION, sizeof info->version); strncpy (info->fw_version, dev->driver_info->description, sizeof info->fw_version); @@ -1114,12 +1116,10 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct driver_info *info; struct usb_device *xdev; int status; - const char *name; - name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; if (!info) { - dev_dbg (&udev->dev, "blacklisted by %s\n", name); + dev_dbg (&udev->dev, "blacklisted by %s\n", driver_name); return -ENODEV; } xdev = interface_to_usbdev (udev); @@ -1139,7 +1139,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev = netdev_priv(net); dev->udev = xdev; dev->driver_info = info; - dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); skb_queue_head_init (&dev->rxq); diff --git a/trunk/drivers/usb/net/usbnet.h b/trunk/drivers/usb/net/usbnet.h index cbb53e065d6c..07c70abbe0ec 100644 --- a/trunk/drivers/usb/net/usbnet.h +++ b/trunk/drivers/usb/net/usbnet.h @@ -29,7 +29,6 @@ struct usbnet { /* housekeeping */ struct usb_device *udev; struct driver_info *driver_info; - const char *driver_name; wait_queue_head_t *wait; struct mutex phy_mutex; diff --git a/trunk/drivers/usb/serial/Kconfig b/trunk/drivers/usb/serial/Kconfig index ba5d1dc03036..2f4d303ee36f 100644 --- a/trunk/drivers/usb/serial/Kconfig +++ b/trunk/drivers/usb/serial/Kconfig @@ -423,11 +423,11 @@ config USB_SERIAL_MCT_U232 module will be called mct_u232. config USB_SERIAL_MOS7720 - tristate "USB Moschip 7720 Serial Driver" + tristate "USB Moschip 7720 Single Port Serial Driver" depends on USB_SERIAL ---help--- - Say Y here if you want to use USB Serial single and double - port adapters from Moschip Semiconductor Tech. + Say Y here if you want to use a USB Serial single port adapter from + Moschip Semiconductor Tech. To compile this driver as a module, choose M here: the module will be called mos7720. diff --git a/trunk/drivers/usb/serial/aircable.c b/trunk/drivers/usb/serial/aircable.c index b675735bfbee..11dad42c3c60 100644 --- a/trunk/drivers/usb/serial/aircable.c +++ b/trunk/drivers/usb/serial/aircable.c @@ -209,7 +209,6 @@ static void aircable_send(struct usb_serial_port *port) int count, result; struct aircable_private *priv = usb_get_serial_port_data(port); unsigned char* buf; - u16 *dbuf; dbg("%s - port %d", __FUNCTION__, port->number); if (port->write_urb_busy) return; @@ -227,8 +226,8 @@ static void aircable_send(struct usb_serial_port *port) buf[0] = TX_HEADER_0; buf[1] = TX_HEADER_1; - dbuf = (u16 *)&buf[2]; - *dbuf = cpu_to_le16((u16)count); + buf[2] = (unsigned char)count; + buf[3] = (unsigned char)(count >> 8); serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE); memcpy(port->write_urb->transfer_buffer, buf, @@ -435,7 +434,7 @@ static void aircable_write_bulk_callback(struct urb *urb) __FUNCTION__, urb->status); port->write_urb->transfer_buffer_length = 1; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + result = usb_submit_urb(port->write_urb, GFP_KERNEL); if (result) dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", diff --git a/trunk/drivers/usb/serial/ark3116.c b/trunk/drivers/usb/serial/ark3116.c index ea2175bb2274..edd685791a6b 100644 --- a/trunk/drivers/usb/serial/ark3116.c +++ b/trunk/drivers/usb/serial/ark3116.c @@ -341,7 +341,7 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp) result = usb_serial_generic_open(port, filp); if (result) - goto err_out; + return result; /* open */ ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf); @@ -372,7 +372,6 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp) if (port->tty) ark3116_set_termios(port, &tmp_termios); -err_out: kfree(buf); return result; diff --git a/trunk/drivers/usb/serial/cp2101.c b/trunk/drivers/usb/serial/cp2101.c index e831cb7f64fd..d7d0ba986a80 100644 --- a/trunk/drivers/usb/serial/cp2101.c +++ b/trunk/drivers/usb/serial/cp2101.c @@ -58,11 +58,9 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ - { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ - { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index 95a1805b064f..8ff9d54b21e6 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -342,7 +342,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, @@ -1434,7 +1433,6 @@ static int ftdi_write (struct usb_serial_port *port, dbg("%s - write limit hit\n", __FUNCTION__); return 0; } - priv->tx_outstanding_urbs++; spin_unlock_irqrestore(&priv->tx_lock, flags); data_offset = priv->write_offset; @@ -1452,15 +1450,14 @@ static int ftdi_write (struct usb_serial_port *port, buffer = kmalloc (transfer_size, GFP_ATOMIC); if (!buffer) { err("%s ran out of kernel memory for urb ...", __FUNCTION__); - count = -ENOMEM; - goto error_no_buffer; + return -ENOMEM; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { err("%s - no more free urbs", __FUNCTION__); - count = -ENOMEM; - goto error_no_urb; + kfree (buffer); + return -ENOMEM; } /* Copy data */ @@ -1502,9 +1499,10 @@ static int ftdi_write (struct usb_serial_port *port, if (status) { err("%s - failed submitting write urb, error %d", __FUNCTION__, status); count = status; - goto error; + kfree (buffer); } else { spin_lock_irqsave(&priv->tx_lock, flags); + ++priv->tx_outstanding_urbs; priv->tx_outstanding_bytes += count; priv->tx_bytes += count; spin_unlock_irqrestore(&priv->tx_lock, flags); @@ -1512,19 +1510,10 @@ static int ftdi_write (struct usb_serial_port *port, /* we are done with this urb, so let the host driver * really free it when it is finished with it */ - usb_free_urb(urb); + usb_free_urb (urb); dbg("%s write returning: %d", __FUNCTION__, count); return count; -error: - usb_free_urb(urb); -error_no_urb: - kfree (buffer); -error_no_buffer: - spin_lock_irqsave(&priv->tx_lock, flags); - priv->tx_outstanding_urbs--; - spin_unlock_irqrestore(&priv->tx_lock, flags); - return count; } /* ftdi_write */ diff --git a/trunk/drivers/usb/serial/ftdi_sio.h b/trunk/drivers/usb/serial/ftdi_sio.h index 77ad0a09b384..513cfe1b768b 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.h +++ b/trunk/drivers/usb/serial/ftdi_sio.h @@ -31,7 +31,6 @@ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ -#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 */ /* www.canusb.com Lawicel CANUSB device */ diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index 18f74ac76565..6a26a2e683a6 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -111,7 +111,7 @@ struct edgeport_port { struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */ struct urb *write_urb; /* write URB for this port */ - bool write_in_progress; /* 'true' while a write URB is outstanding */ + char write_in_progress; /* TRUE while a write URB is outstanding */ spinlock_t ep_lock; __u8 shadowLCR; /* last LCR value received */ @@ -123,11 +123,11 @@ struct edgeport_port { __u8 validDataMask; __u32 baudRate; - bool open; - bool openPending; - bool commandPending; - bool closePending; - bool chaseResponsePending; + char open; + char openPending; + char commandPending; + char closePending; + char chaseResponsePending; wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ @@ -156,7 +156,7 @@ struct edgeport_serial { __u8 bulk_in_endpoint; /* the bulk in endpoint handle */ unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */ struct urb * read_urb; /* our bulk read urb */ - bool read_in_progress; + int read_in_progress; spinlock_t es_lock; __u8 bulk_out_endpoint; /* the bulk out endpoint handle */ @@ -212,7 +212,7 @@ static int debug; static int low_latency = 1; /* tty low latency flag, on by default */ -static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */ +static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */ /* local function prototypes */ @@ -631,14 +631,14 @@ static void edge_interrupt_callback (struct urb *urb) if (edge_serial->rxBytesAvail > 0 && !edge_serial->read_in_progress) { dbg("%s - posting a read", __FUNCTION__); - edge_serial->read_in_progress = true; + edge_serial->read_in_progress = TRUE; /* we have pending bytes on the bulk in pipe, send a request */ edge_serial->read_urb->dev = edge_serial->serial->dev; result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result); - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; } } spin_unlock(&edge_serial->es_lock); @@ -695,13 +695,13 @@ static void edge_bulk_in_callback (struct urb *urb) if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; return; } if (urb->actual_length == 0) { dbg("%s - read bulk callback with no data", __FUNCTION__); - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; return; } @@ -725,10 +725,10 @@ static void edge_bulk_in_callback (struct urb *urb) status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (status) { dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status); - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; } } else { - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; } spin_unlock(&edge_serial->es_lock); @@ -759,7 +759,7 @@ static void edge_bulk_out_data_callback (struct urb *urb) } // Release the Write URB - edge_port->write_in_progress = false; + edge_port->write_in_progress = FALSE; // Check if more data needs to be sent send_more_port_data((struct edgeport_serial *)(usb_get_serial_data(edge_port->port->serial)), edge_port); @@ -779,8 +779,8 @@ static void edge_bulk_out_cmd_callback (struct urb *urb) dbg("%s", __FUNCTION__); - atomic_dec(&CmdUrbs); - dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs)); + CmdUrbs--; + dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs); /* clean up the transfer buffer */ @@ -802,7 +802,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb) tty_wakeup(tty); /* we have completed the command */ - edge_port->commandPending = false; + edge_port->commandPending = FALSE; wake_up(&edge_port->wait_command); } @@ -868,7 +868,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) port0->bulk_in_buffer, edge_serial->read_urb->transfer_buffer_length, edge_bulk_in_callback, edge_serial); - edge_serial->read_in_progress = false; + edge_serial->read_in_progress = FALSE; /* start interrupt read for this edgeport * this interrupt will continue as long as the edgeport is connected */ @@ -890,26 +890,26 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) /* initialize our port settings */ edge_port->txCredits = 0; /* Can't send any data yet */ edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */ - edge_port->chaseResponsePending = false; + edge_port->chaseResponsePending = FALSE; /* send a open port command */ - edge_port->openPending = true; - edge_port->open = false; + edge_port->openPending = TRUE; + edge_port->open = FALSE; response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { dev_err(&port->dev, "%s - error sending open port command\n", __FUNCTION__); - edge_port->openPending = false; + edge_port->openPending = FALSE; return -ENODEV; } /* now wait for the port to be completely opened */ - wait_event_timeout(edge_port->wait_open, !edge_port->openPending, OPEN_TIMEOUT); + wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT); - if (!edge_port->open) { + if (edge_port->open == FALSE) { /* open timed out */ dbg("%s - open timedout", __FUNCTION__); - edge_port->openPending = false; + edge_port->openPending = FALSE; return -ENODEV; } @@ -928,7 +928,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) /* Allocate a URB for the write */ edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL); - edge_port->write_in_progress = false; + edge_port->write_in_progress = FALSE; if (!edge_port->write_urb) { dbg("%s - no memory", __FUNCTION__); @@ -966,7 +966,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) lastCredits = edge_port->txCredits; // Did we get our Chase response - if (!edge_port->chaseResponsePending) { + if (edge_port->chaseResponsePending == FALSE) { dbg("%s - Got Chase Response", __FUNCTION__); // did we get all of our credit back? @@ -985,7 +985,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port) // No activity.. count down. loop--; if (loop == 0) { - edge_port->chaseResponsePending = false; + edge_port->chaseResponsePending = FALSE; dbg("%s - Chase TIMEOUT", __FUNCTION__); return; } @@ -1068,13 +1068,13 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) // block until tx is empty block_until_tx_empty(edge_port); - edge_port->closePending = true; + edge_port->closePending = TRUE; if ((!edge_serial->is_epic) || ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPChase))) { /* flush and chase */ - edge_port->chaseResponsePending = true; + edge_port->chaseResponsePending = TRUE; dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); @@ -1082,7 +1082,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) // block until chase finished block_until_chase_response(edge_port); } else { - edge_port->chaseResponsePending = false; + edge_port->chaseResponsePending = FALSE; } } @@ -1094,10 +1094,10 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); } - //port->close = true; - edge_port->closePending = false; - edge_port->open = false; - edge_port->openPending = false; + //port->close = TRUE; + edge_port->closePending = FALSE; + edge_port->open = FALSE; + edge_port->openPending = FALSE; usb_kill_urb(edge_port->write_urb); @@ -1247,7 +1247,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge } // lock this write - edge_port->write_in_progress = true; + edge_port->write_in_progress = TRUE; // get a pointer to the write_urb urb = edge_port->write_urb; @@ -1261,7 +1261,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__); - edge_port->write_in_progress = false; + edge_port->write_in_progress = FALSE; goto exit_send; } buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count); @@ -1301,7 +1301,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge if (status) { /* something went wrong */ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status); - edge_port->write_in_progress = false; + edge_port->write_in_progress = FALSE; /* revert the credits as something bad happened. */ edge_port->txCredits += count; @@ -1332,7 +1332,7 @@ static int edge_write_room (struct usb_serial_port *port) if (edge_port == NULL) return -ENODEV; - if (edge_port->closePending) + if (edge_port->closePending == TRUE) return -ENODEV; dbg("%s - port %d", __FUNCTION__, port->number); @@ -1371,7 +1371,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port) if (edge_port == NULL) return -ENODEV; - if (edge_port->closePending) + if (edge_port->closePending == TRUE) return -ENODEV; if (!edge_port->open) { @@ -1762,7 +1762,7 @@ static void edge_break (struct usb_serial_port *port, int break_state) ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPChase))) { /* flush and chase */ - edge_port->chaseResponsePending = true; + edge_port->chaseResponsePending = TRUE; dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); @@ -1770,7 +1770,7 @@ static void edge_break (struct usb_serial_port *port, int break_state) // block until chase finished block_until_chase_response(edge_port); } else { - edge_port->chaseResponsePending = false; + edge_port->chaseResponsePending = FALSE; } } @@ -1952,13 +1952,13 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 // Also, we currently clear flag and close the port regardless of content of above's Byte3. // We could choose to do something else when Byte3 says Timeout on Chase from Edgeport, // like wait longer in block_until_chase_response, but for now we don't. - edge_port->chaseResponsePending = false; + edge_port->chaseResponsePending = FALSE; wake_up (&edge_port->wait_chase); return; case IOSP_EXT_STATUS_RX_CHECK_RSP: dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 ); - //Port->RxCheckRsp = true; + //Port->RxCheckRsp = TRUE; return; } } @@ -1974,8 +1974,8 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 change_port_settings (edge_port, edge_port->port->tty->termios); /* we have completed the open */ - edge_port->openPending = false; - edge_port->open = true; + edge_port->openPending = FALSE; + edge_port->open = TRUE; wake_up(&edge_port->wait_open); return; } @@ -1983,7 +1983,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 // If port is closed, silently discard all rcvd status. We can // have cases where buffered status is received AFTER the close // port command is sent to the Edgeport. - if (!edge_port->open || edge_port->closePending) { + if ((!edge_port->open ) || (edge_port->closePending)) { return; } @@ -1991,14 +1991,14 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 // Not currently sent by Edgeport case IOSP_STATUS_LSR: dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2); - handle_new_lsr(edge_port, false, byte2, 0); + handle_new_lsr (edge_port, FALSE, byte2, 0); break; case IOSP_STATUS_LSR_DATA: dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3); // byte2 is LSR Register // byte3 is broken data byte - handle_new_lsr(edge_port, true, byte2, byte3); + handle_new_lsr (edge_port, TRUE, byte2, byte3); break; // // case IOSP_EXT_4_STATUS: @@ -2317,14 +2317,14 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer if (!urb) return -ENOMEM; - atomic_inc(&CmdUrbs); - dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs)); + CmdUrbs++; + dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs); usb_fill_bulk_urb (urb, edge_serial->serial->dev, usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint), buffer, length, edge_bulk_out_cmd_callback, edge_port); - edge_port->commandPending = true; + edge_port->commandPending = TRUE; status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { @@ -2332,16 +2332,16 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status); usb_kill_urb(urb); usb_free_urb(urb); - atomic_dec(&CmdUrbs); + CmdUrbs--; return status; } // wait for command to finish timeout = COMMAND_TIMEOUT; #if 0 - wait_event (&edge_port->wait_command, !edge_port->commandPending); + wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE)); - if (edge_port->commandPending) { + if (edge_port->commandPending == TRUE) { /* command timed out */ dbg("%s - command timed out", __FUNCTION__); status = -EINVAL; @@ -2524,8 +2524,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi dbg("%s - port %d", __FUNCTION__, edge_port->port->number); - if (!edge_port->open && - !edge_port->openPending) { + if ((!edge_port->open) && + (!edge_port->openPending)) { dbg("%s - port not opened", __FUNCTION__); return; } @@ -2836,9 +2836,9 @@ static int edge_startup (struct usb_serial *serial) struct usb_device *dev; int i, j; int response; - bool interrupt_in_found; - bool bulk_in_found; - bool bulk_out_found; + int interrupt_in_found; + int bulk_in_found; + int bulk_out_found; static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, EDGE_COMPATIBILITY_MASK1, EDGE_COMPATIBILITY_MASK2 }; @@ -2936,14 +2936,14 @@ static int edge_startup (struct usb_serial *serial) if (edge_serial->is_epic) { /* EPIC thing, set up our interrupt polling now and our read urb, so * that the device knows it really is connected. */ - interrupt_in_found = bulk_in_found = bulk_out_found = false; + interrupt_in_found = bulk_in_found = bulk_out_found = FALSE; for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) { struct usb_endpoint_descriptor *endpoint; int buffer_size; endpoint = &serial->interface->altsetting[0].endpoint[i].desc; buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - if (!interrupt_in_found && + if ((!interrupt_in_found) && (usb_endpoint_is_int_in(endpoint))) { /* we found a interrupt in endpoint */ dbg("found interrupt in"); @@ -2972,10 +2972,10 @@ static int edge_startup (struct usb_serial *serial) edge_serial, endpoint->bInterval); - interrupt_in_found = true; + interrupt_in_found = TRUE; } - if (!bulk_in_found && + if ((!bulk_in_found) && (usb_endpoint_is_bulk_in(endpoint))) { /* we found a bulk in endpoint */ dbg("found bulk in"); @@ -3001,19 +3001,19 @@ static int edge_startup (struct usb_serial *serial) endpoint->wMaxPacketSize, edge_bulk_in_callback, edge_serial); - bulk_in_found = true; + bulk_in_found = TRUE; } - if (!bulk_out_found && + if ((!bulk_out_found) && (usb_endpoint_is_bulk_out(endpoint))) { /* we found a bulk out endpoint */ dbg("found bulk out"); edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; - bulk_out_found = true; + bulk_out_found = TRUE; } } - if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) { + if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) { err ("Error - the proper endpoints were not found!"); return -ENODEV; } @@ -3083,7 +3083,6 @@ static int __init edgeport_init(void) retval = usb_register(&io_driver); if (retval) goto failed_usb_register; - atomic_set(&CmdUrbs, 0); info(DRIVER_DESC " " DRIVER_VERSION); return 0; diff --git a/trunk/drivers/usb/serial/io_edgeport.h b/trunk/drivers/usb/serial/io_edgeport.h index cb201c1f67f9..29a913a6daca 100644 --- a/trunk/drivers/usb/serial/io_edgeport.h +++ b/trunk/drivers/usb/serial/io_edgeport.h @@ -19,6 +19,12 @@ #define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */ /* typedefs that the insideout headers need */ +#ifndef TRUE + #define TRUE (1) +#endif +#ifndef FALSE + #define FALSE (0) +#endif #ifndef LOW8 #define LOW8(a) ((unsigned char)(a & 0xff)) #endif diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 4df0ec74e0b1..d16e2e1764ad 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -255,7 +255,6 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */ { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ - { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index 7b085f334ceb..b2097c45a235 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -238,7 +238,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, if (rc < 0) err("Reading line status failed (error = %d)", rc); else { - status = le16_to_cpu(*(u16 *)status_buf); + status = status_buf[0] + (status_buf[1]<<8); info("%s - read status %x %x", __FUNCTION__, status_buf[0], status_buf[1]); @@ -257,7 +257,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, static int klsi_105_startup (struct usb_serial *serial) { struct klsi_105_private *priv; - int i, j; + int i; /* check if we support the product id (see keyspan.c) * FIXME @@ -265,12 +265,12 @@ static int klsi_105_startup (struct usb_serial *serial) /* allocate the private data structure */ for (i=0; inum_ports; i++) { + int j; priv = kmalloc(sizeof(struct klsi_105_private), GFP_KERNEL); if (!priv) { dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__); - i--; - goto err_cleanup; + return -ENOMEM; } /* set initial values for control structures */ priv->cfg.pktlen = 5; @@ -292,14 +292,15 @@ static int klsi_105_startup (struct usb_serial *serial) priv->write_urb_pool[j] = urb; if (urb == NULL) { err("No more urbs???"); - goto err_cleanup; + continue; } + urb->transfer_buffer = NULL; urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { err("%s - out of memory for urb buffers.", __FUNCTION__); - goto err_cleanup; + continue; } } @@ -307,20 +308,7 @@ static int klsi_105_startup (struct usb_serial *serial) init_waitqueue_head(&serial->port[i]->write_wait); } - return 0; - -err_cleanup: - for (; i >= 0; i--) { - priv = usb_get_serial_port_data(serial->port[i]); - for (j=0; j < NUM_URBS; j++) { - if (priv->write_urb_pool[j]) { - kfree(priv->write_urb_pool[j]->transfer_buffer); - usb_free_urb(priv->write_urb_pool[j]); - } - } - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; + return (0); } /* klsi_105_startup */ diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index 3db1adc25f84..4cd839b1407f 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -438,21 +438,17 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp) if (retval) { err("usb_submit_urb(read bulk) failed pipe 0x%x err %d", port->read_urb->pipe, retval); - goto error; + goto exit; } port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (retval) { - usb_kill_urb(port->read_urb); + if (retval) err(" usb_submit_urb(read int) failed pipe 0x%x err %d", port->interrupt_in_urb->pipe, retval); - goto error; - } - return 0; -error: - return retval; +exit: + return 0; } /* mct_u232_open */ diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index b563e2ad8728..19bf403f9db2 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -103,9 +103,11 @@ static void mos7720_interrupt_callback(struct urb *urb) { int result; int length; - __u8 *data; + __u32 *data; + unsigned int status; __u8 sp1; __u8 sp2; + __u8 st; dbg("%s"," : Entering\n"); @@ -139,19 +141,18 @@ static void mos7720_interrupt_callback(struct urb *urb) * Byte 2 IIR Port 2 (port.number is 1) * Byte 3 -------------- * Byte 4 FIFO status for both */ - - /* the above description is inverted - * oneukum 2007-03-14 */ - - if (unlikely(length != 4)) { + if (length && length > 4) { dbg("Wrong data !!!"); return; } - sp1 = data[3]; - sp2 = data[2]; + status = *data; + + sp1 = (status & 0xff000000)>>24; + sp2 = (status & 0x00ff0000)>>16; + st = status & 0x000000ff; - if ((sp1 | sp2) & 0x01) { + if ((sp1 & 0x01) || (sp2 & 0x01)) { /* No Interrupt Pending in both the ports */ dbg("No Interrupt !!!"); } else { @@ -332,7 +333,6 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp) int response; int port_number; char data; - int allocated_urbs = 0; int j; serial = port->serial; @@ -353,7 +353,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp) /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0,GFP_KERNEL); + urb = usb_alloc_urb(0,GFP_ATOMIC); mos7720_port->write_urb_pool[j] = urb; if (urb == NULL) { @@ -365,16 +365,10 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp) GFP_KERNEL); if (!urb->transfer_buffer) { err("%s-out of memory for urb buffers.", __FUNCTION__); - usb_free_urb(mos7720_port->write_urb_pool[j]); - mos7720_port->write_urb_pool[j] = NULL; continue; } - allocated_urbs++; } - if (!allocated_urbs) - return -ENOMEM; - /* Initialize MCS7720 -- Write Init values to corresponding Registers * * Register Index @@ -532,7 +526,7 @@ static int mos7720_chars_in_buffer(struct usb_serial_port *port) } for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) + if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) chars += URB_TRANSFER_BUFFER_SIZE; } dbg("%s - returns %d", __FUNCTION__, chars); @@ -635,7 +629,7 @@ static int mos7720_write_room(struct usb_serial_port *port) } for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) room += URB_TRANSFER_BUFFER_SIZE; } @@ -670,7 +664,7 @@ static int mos7720_write(struct usb_serial_port *port, urb = NULL; for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { urb = mos7720_port->write_urb_pool[i]; dbg("URB:%d",i); break; diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 2366e7b63ece..c6cca859af45 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -176,12 +176,9 @@ struct moschip_port { int port_num; /*Actual port number in the device(1,2,etc) */ struct urb *write_urb; /* write URB for this port */ struct urb *read_urb; /* read URB for this port */ - struct urb *int_urb; __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ char open; - char open_ports; - char zombie; wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ int delta_msr_cond; @@ -194,17 +191,17 @@ struct moschip_port { __u8 DcrRegOffset; //for processing control URBS in interrupt context struct urb *control_urb; - struct usb_ctrlrequest *dr; char *ctrl_buf; int MsrLsr; - spinlock_t pool_lock; struct urb *write_urb_pool[NUM_URBS]; - char busy[NUM_URBS]; }; static int debug; +static int mos7840_num_ports; //this says the number of ports in the device +static int mos7840_num_open_ports; + /* * mos7840_set_reg_sync @@ -257,7 +254,7 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, struct usb_device *dev = port->serial->dev; val = val & 0x00ff; // For the UART control registers, the application number need to be Or'ed - if (port->serial->num_ports == 4) { + if (mos7840_num_ports == 4) { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; @@ -297,7 +294,7 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, //dbg("application number is %4x \n",(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); /*Wval is same as application number */ - if (port->serial->num_ports == 4) { + if (mos7840_num_ports == 4) { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; @@ -355,7 +352,7 @@ static inline struct moschip_port *mos7840_get_port_private(struct return (struct moschip_port *)usb_get_serial_port_data(port); } -static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) +static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) { struct moschip_port *mos7840_port; struct async_icount *icount; @@ -369,24 +366,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) /* update input line counters */ if (new_msr & MOS_MSR_DELTA_CTS) { icount->cts++; - smp_wmb(); } if (new_msr & MOS_MSR_DELTA_DSR) { icount->dsr++; - smp_wmb(); } if (new_msr & MOS_MSR_DELTA_CD) { icount->dcd++; - smp_wmb(); } if (new_msr & MOS_MSR_DELTA_RI) { icount->rng++; - smp_wmb(); } } + + return 0; } -static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) +static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) { struct async_icount *icount; @@ -405,20 +400,18 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) icount = &port->icount; if (new_lsr & SERIAL_LSR_BI) { icount->brk++; - smp_wmb(); } if (new_lsr & SERIAL_LSR_OE) { icount->overrun++; - smp_wmb(); } if (new_lsr & SERIAL_LSR_PE) { icount->parity++; - smp_wmb(); } if (new_lsr & SERIAL_LSR_FE) { icount->frame++; - smp_wmb(); } + + return 0; } /************************************************************************/ @@ -433,15 +426,12 @@ static void mos7840_control_callback(struct urb *urb) unsigned char *data; struct moschip_port *mos7840_port; __u8 regval = 0x0; - int result = 0; if (!urb) { dbg("%s", "Invalid Pointer !!!!:\n"); return; } - mos7840_port = (struct moschip_port *)urb->context; - switch (urb->status) { case 0: /* success */ @@ -459,6 +449,8 @@ static void mos7840_control_callback(struct urb *urb) goto exit; } + mos7840_port = (struct moschip_port *)urb->context; + dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length); dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__, mos7840_port->MsrLsr, mos7840_port->port_num); @@ -470,26 +462,21 @@ static void mos7840_control_callback(struct urb *urb) else if (mos7840_port->MsrLsr == 1) mos7840_handle_new_lsr(mos7840_port, regval); -exit: - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) - result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); - spin_unlock(&mos7840_port->pool_lock); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __FUNCTION__, result); - } + exit: + return; } static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, __u16 * val) { struct usb_device *dev = mcs->port->serial->dev; - struct usb_ctrlrequest *dr = mcs->dr; - unsigned char *buffer = mcs->ctrl_buf; - int ret; + struct usb_ctrlrequest *dr = NULL; + unsigned char *buffer = NULL; + int ret = 0; + buffer = (__u8 *) mcs->ctrl_buf; +// dr=(struct usb_ctrlrequest *)(buffer); + dr = (void *)(buffer + 2); dr->bRequestType = MCS_RD_RTYPE; dr->bRequest = MCS_RDREQ; dr->wValue = cpu_to_le16(Wval); //0; @@ -519,8 +506,8 @@ static void mos7840_interrupt_callback(struct urb *urb) __u16 Data; unsigned char *data; __u8 sp[5], st; - int i, rv = 0; - __u16 wval, wreg = 0; + int i; + __u16 wval; dbg("%s", " : Entering\n"); if (!urb) { @@ -582,34 +569,31 @@ static void mos7840_interrupt_callback(struct urb *urb) dbg("Serial Port %d: Receiver status error or ", i); dbg("address bit detected in 9-bit mode\n"); mos7840_port->MsrLsr = 1; - wreg = LINE_STATUS_REGISTER; + mos7840_get_reg(mos7840_port, wval, + LINE_STATUS_REGISTER, + &Data); break; case SERIAL_IIR_MS: dbg("Serial Port %d: Modem status change\n", i); mos7840_port->MsrLsr = 0; - wreg = MODEM_STATUS_REGISTER; + mos7840_get_reg(mos7840_port, wval, + MODEM_STATUS_REGISTER, + &Data); break; } - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) { - rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); - } else { - spin_unlock(&mos7840_port->pool_lock); - return; - } - spin_unlock(&mos7840_port->pool_lock); } } } - if (!(rv < 0)) /* the completion handler for the control urb will resubmit */ - return; -exit: + exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { dev_err(&urb->dev->dev, "%s - Error %d submitting interrupt urb\n", __FUNCTION__, result); } + + return; + } static int mos7840_port_paranoia_check(struct usb_serial_port *port, @@ -650,8 +634,7 @@ static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port, if (!port || mos7840_port_paranoia_check(port, function) || mos7840_serial_paranoia_check(port->serial, function)) { - /* then say that we don't have a valid usb_serial thing, which will - * end up genrating -ENODEV return values */ + /* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */ return NULL; } @@ -716,7 +699,6 @@ static void mos7840_bulk_in_callback(struct urb *urb) tty_flip_buffer_push(tty); } mos7840_port->icount.rx += urb->actual_length; - smp_wmb(); dbg("mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx); } @@ -726,14 +708,15 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } + if (mos7840_port->read_urb->status != -EINPROGRESS) { + mos7840_port->read_urb->dev = serial->dev; - mos7840_port->read_urb->dev = serial->dev; - - status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); + status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); - if (status) { - dbg(" usb_submit_urb(read bulk) failed, status = %d", - status); + if (status) { + dbg(" usb_submit_urb(read bulk) failed, status = %d", + status); + } } } @@ -747,28 +730,17 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) { struct moschip_port *mos7840_port; struct tty_struct *tty; - int i; - if (!urb) { dbg("%s", "Invalid Pointer !!!!:\n"); return; } - mos7840_port = (struct moschip_port *)urb->context; - spin_lock(&mos7840_port->pool_lock); - for (i = 0; i < NUM_URBS; i++) { - if (urb == mos7840_port->write_urb_pool[i]) { - mos7840_port->busy[i] = 0; - break; - } - } - spin_unlock(&mos7840_port->pool_lock); - if (urb->status) { dbg("nonzero write bulk status received:%d\n", urb->status); return; } + mos7840_port = (struct moschip_port *)urb->context; if (!mos7840_port) { dbg("%s", "NULL mos7840_port pointer \n"); return; @@ -820,13 +792,13 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) __u16 Data; int status; struct moschip_port *mos7840_port; - struct moschip_port *port0; if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Port Paranoia failed \n"); return -ENODEV; } + mos7840_num_open_ports++; serial = port->serial; if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) { @@ -835,18 +807,16 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) } mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - if (mos7840_port == NULL || port0 == NULL) + if (mos7840_port == NULL) return -ENODEV; usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - port0->open_ports++; /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->write_urb_pool[j] = urb; if (urb == NULL) { @@ -854,10 +824,10 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) continue; } - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + urb->transfer_buffer = NULL; + urb->transfer_buffer = + kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { - usb_free_urb(urb); - mos7840_port->write_urb_pool[j] = NULL; err("%s-out of memory for urb buffers.", __FUNCTION__); continue; } @@ -909,7 +879,9 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) } Data |= 0x08; //Driver done bit Data |= 0x20; //rx_disable - status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); + status = 0; + status = + mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); if (status < 0) { dbg("writing Controlreg failed\n"); return -1; @@ -921,6 +893,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) //////////////////////////////////// Data = 0x00; + status = 0; status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (status < 0) { dbg("disableing interrupts failed\n"); @@ -928,6 +901,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) } // Set FIFO_CONTROL_REGISTER to the default value Data = 0x00; + status = 0; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { dbg("Writing FIFO_CONTROL_REGISTER failed\n"); @@ -935,6 +909,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) } Data = 0xcf; + status = 0; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { dbg("Writing FIFO_CONTROL_REGISTER failed\n"); @@ -942,18 +917,22 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) } Data = 0x03; + status = 0; status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); mos7840_port->shadowLCR = Data; Data = 0x0b; + status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); mos7840_port->shadowMCR = Data; Data = 0x00; + status = 0; status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); mos7840_port->shadowLCR = Data; Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80 + status = 0; status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); Data = 0x0c; @@ -1020,7 +999,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) /* Check to see if we've set up our endpoint info yet * * (can't set it up in mos7840_startup as the structures * * were not set up at that time.) */ - if (port0->open_ports == 1) { + if (mos7840_num_open_ports == 1) { if (serial->port[0]->interrupt_in_buffer == NULL) { /* set up interrupt urb */ @@ -1118,7 +1097,6 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port) { int i; int chars = 0; - unsigned long flags; struct moschip_port *mos7840_port; dbg("%s \n", " mos7840_chars_in_buffer:entering ..........."); @@ -1134,15 +1112,13 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port) return -1; } - spin_lock_irqsave(&mos7840_port->pool_lock,flags); for (i = 0; i < NUM_URBS; ++i) { - if (mos7840_port->busy[i]) { + if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) { chars += URB_TRANSFER_BUFFER_SIZE; } } - spin_unlock_irqrestore(&mos7840_port->pool_lock,flags); dbg("%s - returns %d", __FUNCTION__, chars); - return chars; + return (chars); } @@ -1196,7 +1172,6 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial; struct moschip_port *mos7840_port; - struct moschip_port *port0; int j; __u16 Data; @@ -1214,10 +1189,10 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp) } mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - if (mos7840_port == NULL || port0 == NULL) + if (mos7840_port == NULL) { return; + } for (j = 0; j < NUM_URBS; ++j) usb_kill_urb(mos7840_port->write_urb_pool[j]); @@ -1259,13 +1234,12 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp) } // if(mos7840_port->ctrl_buf != NULL) // kfree(mos7840_port->ctrl_buf); - port0->open_ports--; + mos7840_num_open_ports--; dbg("mos7840_num_open_ports in close%d:in port%d\n", - port0->open_ports, port->number); - if (port0->open_ports == 0) { + mos7840_num_open_ports, port->number); + if (mos7840_num_open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { dbg("%s", "Shutdown interrupt_in_urb\n"); - usb_kill_urb(serial->port[0]->interrupt_in_urb); } } @@ -1394,7 +1368,6 @@ static int mos7840_write_room(struct usb_serial_port *port) { int i; int room = 0; - unsigned long flags; struct moschip_port *mos7840_port; dbg("%s \n", " mos7840_write_room:entering ..........."); @@ -1411,17 +1384,14 @@ static int mos7840_write_room(struct usb_serial_port *port) return -1; } - spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { - if (!mos7840_port->busy[i]) { + if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) { room += URB_TRANSFER_BUFFER_SIZE; } } - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1; dbg("%s - returns %d", __FUNCTION__, room); - return room; + return (room); } @@ -1440,7 +1410,6 @@ static int mos7840_write(struct usb_serial_port *port, int i; int bytes_sent = 0; int transfer_size; - unsigned long flags; struct moschip_port *mos7840_port; struct usb_serial *serial; @@ -1507,16 +1476,13 @@ static int mos7840_write(struct usb_serial_port *port, /* try to find a free urb in the list */ urb = NULL; - spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { - if (!mos7840_port->busy[i]) { - mos7840_port->busy[i] = 1; + if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) { urb = mos7840_port->write_urb_pool[i]; dbg("\nURB:%d", i); break; } } - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); if (urb == NULL) { dbg("%s - no more free urbs", __FUNCTION__); @@ -1552,7 +1518,6 @@ static int mos7840_write(struct usb_serial_port *port, status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - mos7840_port->busy[i] = 0; err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status); bytes_sent = status; @@ -1560,7 +1525,6 @@ static int mos7840_write(struct usb_serial_port *port, } bytes_sent = transfer_size; mos7840_port->icount.tx += transfer_size; - smp_wmb(); dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); exit: @@ -2526,7 +2490,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, if (signal_pending(current)) return -ERESTARTSYS; cnow = mos7840_port->icount; - smp_rmb(); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) return -EIO; /* no change => error */ @@ -2543,7 +2506,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, case TIOCGICOUNT: cnow = mos7840_port->icount; - smp_rmb(); icount.cts = cnow.cts; icount.dsr = cnow.dsr; icount.rng = cnow.rng; @@ -2573,18 +2535,19 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, static int mos7840_calc_num_ports(struct usb_serial *serial) { - int mos7840_num_ports = 0; dbg("numberofendpoints: %d \n", (int)serial->interface->cur_altsetting->desc.bNumEndpoints); dbg("numberofendpoints: %d \n", (int)serial->interface->altsetting->desc.bNumEndpoints); if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) { - mos7840_num_ports = serial->num_ports = 2; + mos7840_num_ports = 2; + serial->type->num_ports = 2; } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) { - serial->num_bulk_in = 4; - serial->num_bulk_out = 4; - mos7840_num_ports = serial->num_ports = 4; + mos7840_num_ports = 4; + serial->type->num_bulk_in = 4; + serial->type->num_bulk_out = 4; + serial->type->num_ports = 4; } return mos7840_num_ports; @@ -2620,9 +2583,7 @@ static int mos7840_startup(struct usb_serial *serial) mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); if (mos7840_port == NULL) { err("%s - Out of memory", __FUNCTION__); - status = -ENOMEM; - i--; /* don't follow NULL pointer cleaning up */ - goto error; + return -ENOMEM; } /* Initialize all port interrupt end point to port 0 int endpoint * @@ -2630,7 +2591,6 @@ static int mos7840_startup(struct usb_serial *serial) mos7840_port->port = serial->port[i]; mos7840_set_port_private(serial->port[i], mos7840_port); - spin_lock_init(&mos7840_port->pool_lock); mos7840_port->port_num = ((serial->port[i]->number - (serial->port[i]->serial->minor)) + @@ -2641,22 +2601,22 @@ static int mos7840_startup(struct usb_serial *serial) mos7840_port->ControlRegOffset = 0x1; mos7840_port->DcrRegOffset = 0x4; } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 4)) { + && (mos7840_num_ports == 4)) { mos7840_port->SpRegOffset = 0x8; mos7840_port->ControlRegOffset = 0x9; mos7840_port->DcrRegOffset = 0x16; } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 2)) { + && (mos7840_num_ports == 2)) { mos7840_port->SpRegOffset = 0xa; mos7840_port->ControlRegOffset = 0xb; mos7840_port->DcrRegOffset = 0x19; } else if ((mos7840_port->port_num == 3) - && (serial->num_ports == 4)) { + && (mos7840_num_ports == 4)) { mos7840_port->SpRegOffset = 0xa; mos7840_port->ControlRegOffset = 0xb; mos7840_port->DcrRegOffset = 0x19; } else if ((mos7840_port->port_num == 4) - && (serial->num_ports == 4)) { + && (mos7840_num_ports == 4)) { mos7840_port->SpRegOffset = 0xc; mos7840_port->ControlRegOffset = 0xd; mos7840_port->DcrRegOffset = 0x1c; @@ -2741,19 +2701,21 @@ static int mos7840_startup(struct usb_serial *serial) dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status); Data = 0x20; + status = 0; status = mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER, Data); if (status < 0) { dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n", status); - goto error; + break; } else dbg("CLK_MULTI_REGISTER Writing success status%d\n", status); //write value 0x0 to scratchpad register Data = 0x00; + status = 0; status = mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER, Data); @@ -2767,7 +2729,7 @@ static int mos7840_startup(struct usb_serial *serial) //Zero Length flag register if ((mos7840_port->port_num != 1) - && (serial->num_ports == 2)) { + && (mos7840_num_ports == 2)) { Data = 0xff; status = 0; @@ -2808,17 +2770,14 @@ static int mos7840_startup(struct usb_serial *serial) i + 1, status); } - mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); + mos7840_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); - mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || !mos7840_port->dr) { - status = -ENOMEM; - goto error; - } + } //Zero Length flag enable Data = 0x0f; + status = 0; status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); if (status < 0) { dbg("Writing ZLP_REG5 failed status-0x%x\n", status); @@ -2830,17 +2789,6 @@ static int mos7840_startup(struct usb_serial *serial) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ); return 0; -error: - for (/* nothing */; i >= 0; i--) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - - kfree(mos7840_port->dr); - kfree(mos7840_port->ctrl_buf); - usb_free_urb(mos7840_port->control_urb); - kfree(mos7840_port); - serial->port[i] = NULL; - } - return status; } /**************************************************************************** @@ -2851,7 +2799,6 @@ static int mos7840_startup(struct usb_serial *serial) static void mos7840_shutdown(struct usb_serial *serial) { int i; - unsigned long flags; struct moschip_port *mos7840_port; dbg("%s \n", " shutdown :entering.........."); @@ -2867,12 +2814,8 @@ static void mos7840_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { mos7840_port = mos7840_get_port_private(serial->port[i]); - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - mos7840_port->zombie = 1; - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - usb_kill_urb(mos7840_port->control_urb); kfree(mos7840_port->ctrl_buf); - kfree(mos7840_port->dr); + usb_kill_urb(mos7840_port->control_urb); kfree(mos7840_port); mos7840_set_port_private(serial->port[i], NULL); } diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index 4adfab988e86..0216ac12a27d 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -69,7 +69,6 @@ static void omninet_write_bulk_callback (struct urb *urb); static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room (struct usb_serial_port *port); static void omninet_shutdown (struct usb_serial *serial); -static int omninet_attach (struct usb_serial *serial); static struct usb_device_id id_table [] = { { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, @@ -100,7 +99,6 @@ static struct usb_serial_driver zyxel_omninet_device = { .num_bulk_in = 1, .num_bulk_out = 2, .num_ports = 1, - .attach = omninet_attach, .open = omninet_open, .close = omninet_close, .write = omninet_write, @@ -147,30 +145,22 @@ struct omninet_data __u8 od_outseq; // Sequence number for bulk_out URBs }; -static int omninet_attach (struct usb_serial *serial) -{ - struct omninet_data *od; - struct usb_serial_port *port = serial->port[0]; - - od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); - if( !od ) { - err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); - return -ENOMEM; - } - usb_set_serial_port_data(port, od); - return 0; -} - static int omninet_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; struct usb_serial_port *wport; - struct omninet_data *od = usb_get_serial_port_data(port); + struct omninet_data *od; int result = 0; dbg("%s - port %d", __FUNCTION__, port->number); od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + if( !od ) { + err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); + return -ENOMEM; + } + + usb_set_serial_port_data(port, od); wport = serial->port[1]; wport->tty = port->tty; @@ -180,17 +170,24 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, omninet_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { + if (result) err("%s - failed submitting read urb, error %d", __FUNCTION__, result); - } return result; } static void omninet_close (struct usb_serial_port *port, struct file * filp) { + struct usb_serial *serial = port->serial; + struct usb_serial_port *wport; + dbg("%s - port %d", __FUNCTION__, port->number); + + wport = serial->port[1]; + usb_kill_urb(wport->write_urb); usb_kill_urb(port->read_urb); + + kfree(usb_get_serial_port_data(port)); } @@ -329,12 +326,7 @@ static void omninet_write_bulk_callback (struct urb *urb) static void omninet_shutdown (struct usb_serial *serial) { - struct usb_serial_port *wport = serial->port[1]; - struct usb_serial_port *port = serial->port[0]; dbg ("%s", __FUNCTION__); - - usb_kill_urb(wport->write_urb); - kfree(usb_get_serial_port_data(port)); } diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index 8c3f55b080b4..e178e6f40319 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -113,12 +113,6 @@ static int option_send_setup(struct usb_serial_port *port); #define ANYDATA_VENDOR_ID 0x16d5 #define ANYDATA_PRODUCT_ID 0x6501 -#define BANDRICH_VENDOR_ID 0x1A8D -#define BANDRICH_PRODUCT_C100_1 0x1002 -#define BANDRICH_PRODUCT_C100_2 0x1003 - -#define DELL_VENDOR_ID 0x413C - static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -171,9 +165,6 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, - { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -600,6 +591,12 @@ static int option_open(struct usb_serial_port *port, struct file *filp) return (0); } +static inline void stop_urb(struct urb *urb) +{ + if (urb && urb->status == -EINPROGRESS) + usb_kill_urb(urb); +} + static void option_close(struct usb_serial_port *port, struct file *filp) { int i; @@ -617,9 +614,9 @@ static void option_close(struct usb_serial_port *port, struct file *filp) /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); + stop_urb(portdata->in_urbs[i]); for (i = 0; i < N_OUT_URB; i++) - usb_kill_urb(portdata->out_urbs[i]); + stop_urb(portdata->out_urbs[i]); } port->tty = NULL; } @@ -750,9 +747,9 @@ static void option_shutdown(struct usb_serial *serial) port = serial->port[i]; portdata = usb_get_serial_port_data(port); for (j = 0; j < N_IN_URB; j++) - usb_kill_urb(portdata->in_urbs[j]); + stop_urb(portdata->in_urbs[j]); for (j = 0; j < N_OUT_URB; j++) - usb_kill_urb(portdata->out_urbs[j]); + stop_urb(portdata->out_urbs[j]); } /* Now free them */ diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 644607de4c11..ecedd833818d 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -456,6 +456,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) return (0); } +static inline void stop_urb(struct urb *urb) +{ + if (urb && urb->status == -EINPROGRESS) + usb_kill_urb(urb); +} + static void sierra_close(struct usb_serial_port *port, struct file *filp) { int i; @@ -473,9 +479,9 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp) /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) - usb_unlink_urb(portdata->in_urbs[i]); + stop_urb(portdata->in_urbs[i]); for (i = 0; i < N_OUT_URB; i++) - usb_unlink_urb(portdata->out_urbs[i]); + stop_urb(portdata->out_urbs[i]); } port->tty = NULL; } @@ -577,26 +583,17 @@ static void sierra_shutdown(struct usb_serial *serial) /* Stop reading/writing urbs */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (!port) - continue; portdata = usb_get_serial_port_data(port); - if (!portdata) - continue; - for (j = 0; j < N_IN_URB; j++) - usb_unlink_urb(portdata->in_urbs[j]); + stop_urb(portdata->in_urbs[j]); for (j = 0; j < N_OUT_URB; j++) - usb_unlink_urb(portdata->out_urbs[j]); + stop_urb(portdata->out_urbs[j]); } /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (!port) - continue; portdata = usb_get_serial_port_data(port); - if (!portdata) - continue; for (j = 0; j < N_IN_URB; j++) { if (portdata->in_urbs[j]) { @@ -615,8 +612,6 @@ static void sierra_shutdown(struct usb_serial *serial) /* Now free per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!port) - continue; kfree(usb_get_serial_port_data(port)); } } diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index ffbe601cde2a..2f59ff226e2c 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -384,21 +384,19 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf, dbg("%s - write limit hit\n", __FUNCTION__); return 0; } - priv->outstanding_urbs++; spin_unlock_irqrestore(&priv->lock, flags); buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { dev_err(&port->dev, "out of memory\n"); - count = -ENOMEM; - goto error_no_buffer; + return -ENOMEM; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { dev_err(&port->dev, "no more free urbs\n"); - count = -ENOMEM; - goto error_no_urb; + kfree (buffer); + return -ENOMEM; } memcpy (buffer, buf, count); @@ -417,26 +415,18 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf, dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __FUNCTION__, status); count = status; - goto error; + kfree (buffer); } else { spin_lock_irqsave(&priv->lock, flags); + ++priv->outstanding_urbs; priv->bytes_out += count; spin_unlock_irqrestore(&priv->lock, flags); } /* we are done with this urb, so let the host driver * really free it when it is finished with it */ - usb_free_urb(urb); + usb_free_urb (urb); - return count; -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&priv->lock, flags); - --priv->outstanding_urbs; - spin_unlock_irqrestore(&priv->lock, flags); return count; } diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 27c5f8f9a2d5..bf16e9e1d84e 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -1109,7 +1109,7 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 * command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); spin_lock_irqsave(&command_info->lock, flags); - command_info->command_finished = false; + command_info->command_finished = FALSE; transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer; transfer_buffer[0] = command; @@ -1124,12 +1124,12 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 * spin_unlock_irqrestore(&command_info->lock, flags); /* wait for the command to complete */ - wait_event_interruptible_timeout(command_info->wait_command, - (bool)command_info->command_finished, COMMAND_TIMEOUT); + wait_event_interruptible_timeout(command_info->wait_command, + (command_info->command_finished != FALSE), COMMAND_TIMEOUT); spin_lock_irqsave(&command_info->lock, flags); - if (command_info->command_finished == false) { + if (command_info->command_finished == FALSE) { dbg("%s - command timed out.", __FUNCTION__); retval = -ETIMEDOUT; goto exit; diff --git a/trunk/drivers/usb/serial/whiteheat.h b/trunk/drivers/usb/serial/whiteheat.h index f16079705664..d714eff58dc0 100644 --- a/trunk/drivers/usb/serial/whiteheat.h +++ b/trunk/drivers/usb/serial/whiteheat.h @@ -20,6 +20,10 @@ #define __LINUX_USB_SERIAL_WHITEHEAT_H +#define FALSE 0 +#define TRUE 1 + + /* WhiteHEAT commands */ #define WHITEHEAT_OPEN 1 /* open the port */ #define WHITEHEAT_CLOSE 2 /* close the port */ diff --git a/trunk/drivers/usb/storage/libusual.c b/trunk/drivers/usb/storage/libusual.c index 06d1107dbd47..599ad10a761b 100644 --- a/trunk/drivers/usb/storage/libusual.c +++ b/trunk/drivers/usb/storage/libusual.c @@ -117,7 +117,6 @@ EXPORT_SYMBOL_GPL(usb_usual_check_type); static int usu_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int rc; unsigned long type; struct task_struct* task; unsigned long flags; @@ -136,7 +135,7 @@ static int usu_probe(struct usb_interface *intf, task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type); if (IS_ERR(task)) { - rc = PTR_ERR(task); + int rc = PTR_ERR(task); printk(KERN_WARNING "libusual: " "Unable to start the thread for %s: %d\n", bias_names[type], rc); diff --git a/trunk/drivers/usb/storage/unusual_devs.h b/trunk/drivers/usb/storage/unusual_devs.h index 8b3145ab7757..4a9d0d5c7282 100644 --- a/trunk/drivers/usb/storage/unusual_devs.h +++ b/trunk/drivers/usb/storage/unusual_devs.h @@ -1371,6 +1371,15 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* This prevents the kernel from detecting the virtual cd-drive with the + * Windows drivers. +*/ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff, + "HUAWEI", + "E220 USB-UMTS Install", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE), + /* Reported by Vilius Bilinkevicius PAGE_SIZE and the number of packets in a page - is an integer 512 is the largest possible packet on EHCI */ #define WRITES_IN_FLIGHT 8 -/* arbitrarily chosen */ /* Structure to hold all of our device specific stuff */ struct usb_skel { - struct usb_device *udev; /* the usb device for this device */ - struct usb_interface *interface; /* the interface for this device */ + struct usb_device *dev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ struct semaphore limit_sem; /* limiting the number of writes in progress */ unsigned char *bulk_in_buffer; /* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ @@ -83,10 +76,8 @@ static int skel_open(struct inode *inode, struct file *file) subminor = iminor(inode); - mutex_lock(&skel_open_lock); interface = usb_find_interface(&skel_driver, subminor); if (!interface) { - mutex_unlock(&skel_open_lock); err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; @@ -95,15 +86,12 @@ static int skel_open(struct inode *inode, struct file *file) dev = usb_get_intfdata(interface); if (!dev) { - mutex_unlock(&skel_open_lock); retval = -ENODEV; goto exit; } /* increment our usage count for the device */ kref_get(&dev->kref); - /* now we can drop the lock */ - mutex_unlock(&skel_open_lock); /* prevent the device from being autosuspended */ retval = usb_autopm_get_interface(interface); @@ -213,6 +201,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou goto exit; } + mutex_lock(&dev->io_mutex); + if (!dev->interface) { /* disconnect() was called */ + retval = -ENODEV; + goto error; + } + /* create a urb, and a buffer for it, and copy the data to the urb */ urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { @@ -231,14 +225,6 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou goto error; } - /* this lock makes sure we don't submit URBs to gone devices */ - mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* disconnect() was called */ - mutex_unlock(&dev->io_mutex); - retval = -ENODEV; - goto error; - } - /* initialize the urb properly */ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), @@ -247,7 +233,6 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou /* send the data out the bulk port */ retval = usb_submit_urb(urb, GFP_KERNEL); - mutex_unlock(&dev->io_mutex); if (retval) { err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); goto error; @@ -256,7 +241,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou /* release our reference to this urb, the USB core will eventually free it entirely */ usb_free_urb(urb); - + mutex_unlock(&dev->io_mutex); return writesize; error: @@ -264,6 +249,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); usb_free_urb(urb); } + mutex_unlock(&dev->io_mutex); up(&dev->limit_sem); exit: @@ -358,7 +344,6 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i error: if (dev) - /* this frees allocated memory */ kref_put(&dev->kref, skel_delete); return retval; } @@ -369,21 +354,20 @@ static void skel_disconnect(struct usb_interface *interface) int minor = interface->minor; /* prevent skel_open() from racing skel_disconnect() */ - mutex_lock(&skel_open_lock); + lock_kernel(); dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); /* give back our minor */ usb_deregister_dev(interface, &skel_class); - mutex_unlock(&skel_open_lock); /* prevent more I/O from starting */ mutex_lock(&dev->io_mutex); dev->interface = NULL; mutex_unlock(&dev->io_mutex); - + unlock_kernel(); /* decrement our usage count */ kref_put(&dev->kref, skel_delete); @@ -396,7 +380,6 @@ static struct usb_driver skel_driver = { .probe = skel_probe, .disconnect = skel_disconnect, .id_table = skel_table, - .supports_autosuspend = 1, }; static int __init usb_skel_init(void) diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index d18b51f989c9..e4f0dd00ae85 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -139,7 +139,7 @@ config FB_TILEBLITTING This is particularly important to one driver, matroxfb. If unsure, say N. -comment "Frame buffer hardware drivers" +comment "Frambuffer hardware drivers" depends on FB config FB_CIRRUS @@ -389,17 +389,14 @@ config FB_ARC config FB_ATARI bool "Atari native chipset support" - depends on (FB = y) && ATARI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + depends on (FB = y) && ATARI && BROKEN help This is the frame buffer device driver for the builtin graphics chipset found in Ataris. config FB_OF bool "Open Firmware frame buffer device support" - depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI) + depends on (FB = y) && (PPC64 || PPC_OF) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/trunk/drivers/video/Makefile b/trunk/drivers/video/Makefile index 869351785ee8..760305c8a841 100644 --- a/trunk/drivers/video/Makefile +++ b/trunk/drivers/video/Makefile @@ -63,8 +63,7 @@ obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_ACORN) += acornfb.o -obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \ - atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o +obj-$(CONFIG_FB_ATARI) += atafb.o obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_IGA) += igafb.o diff --git a/trunk/drivers/video/atafb.c b/trunk/drivers/video/atafb.c index 0038a0541c7e..bffe2b946344 100644 --- a/trunk/drivers/video/atafb.c +++ b/trunk/drivers/video/atafb.c @@ -2,7 +2,7 @@ * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device * * Copyright (C) 1994 Martin Schaller & Roman Hodek - * + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -70,8 +70,14 @@ #include #include -#include "c2p.h" -#include "atafb.h" +#include